diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index 88774a1b434..1a2775e8f1b 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -41,7 +41,7 @@ Item { anchors.topMargin: 1 anchors.fill: parent - color: StudioTheme.Values.themePanelBackground + color: mouseRegion.containsMouse ? StudioTheme.Values.themeControlBackgroundHover : StudioTheme.Values.themePanelBackground Image { id: itemIcon // to be set by model diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 79ab72f1233..de9d50f0429 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -73,7 +73,7 @@ itemLibraryModel [ ] */ -ScrollView { +Item { id: itemsView property string importToRemove: "" @@ -81,6 +81,11 @@ ScrollView { property var currentItem: null property var currentCategory: null property var currentImport: null + property bool isHorizontalView: false + + // horizontal component lib variables + property var selectedCategory: null + property var selectedCategoryImport: null // called from C++ to close context menu on focus out function closeContextMenu() @@ -91,15 +96,21 @@ ScrollView { function showImportCategories() { - currentImport.importCatVisibleState = true + if (itemLibraryModel.isAllCategoriesHidden()) { + itemsView.currentImport.importCatVisibleState = true + if (!itemLibraryModel.getIsAnyCategoryHidden()) + itemLibraryModel.isAnyCategoryHidden = false + + itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory() + } + + itemsView.currentImport.importCatVisibleState = true if (!itemLibraryModel.getIsAnyCategoryHidden()) itemLibraryModel.isAnyCategoryHidden = false } - onContentHeightChanged: { - var maxPosition = Math.max(contentHeight - height, 0) - if (contentY > maxPosition) - contentY = maxPosition + onWidthChanged: { + itemsView.isHorizontalView = itemsView.width > widthLimit } Item { @@ -112,66 +123,68 @@ ScrollView { property int cellVerticalMargin: 4 // the following depend on the actual shape of the item delegate - property int cellWidth: textWidth + 2 * cellHorizontalMargin - property int cellHeight: itemLibraryIconHeight + textHeight + - 2 * cellVerticalMargin + cellVerticalSpacing + property int cellWidth: styleConstants.textWidth + 2 * styleConstants.cellHorizontalMargin + property int cellHeight: itemLibraryIconHeight + styleConstants.textHeight + + 2 * styleConstants.cellVerticalMargin + styleConstants.cellVerticalSpacing StudioControls.Menu { id: moduleContextMenu StudioControls.MenuItem { text: qsTr("Remove Module") - visible: currentCategory === null + visible: itemsView.currentCategory === null height: visible ? implicitHeight : 0 - enabled: importToRemove !== "" + enabled: itemsView.importToRemove !== "" onTriggered: { showImportCategories() - rootView.removeImport(importToRemove) + rootView.removeImport(itemsView.importToRemove) } } StudioControls.MenuSeparator { - visible: currentCategory === null + visible: itemsView.currentCategory === null height: StudioTheme.Values.border } StudioControls.MenuItem { text: qsTr("Expand All") - visible: currentCategory === null + visible: itemsView.currentCategory === null height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.expandAll() } StudioControls.MenuItem { text: qsTr("Collapse All") - visible: currentCategory === null + visible: itemsView.currentCategory === null height: visible ? implicitHeight : 0 onTriggered: itemLibraryModel.collapseAll() } StudioControls.MenuSeparator { - visible: currentCategory === null + visible: itemsView.currentCategory === null height: StudioTheme.Values.border } StudioControls.MenuItem { text: qsTr("Hide Category") - visible: currentCategory + visible: itemsView.currentCategory height: visible ? implicitHeight : 0 onTriggered: { itemLibraryModel.isAnyCategoryHidden = true - currentCategory.categoryVisible = false + itemsView.currentCategory.categoryVisible = false + itemsView.currentCategory.categorySelected = false + itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory() } } StudioControls.MenuSeparator { - visible: currentCategory + visible: itemsView.currentCategory height: StudioTheme.Values.border } StudioControls.MenuItem { text: qsTr("Show Module Hidden Categories") - enabled: currentImport && !currentImport.importCatVisibleState + enabled: itemsView.currentImport && !itemsView.currentImport.importCatVisibleState onTriggered: showImportCategories() } @@ -179,6 +192,12 @@ ScrollView { text: qsTr("Show All Hidden Categories") enabled: itemLibraryModel.isAnyCategoryHidden onTriggered: { + if (itemLibraryModel.isAllCategoriesHidden()) { + itemLibraryModel.showHiddenCategories() + itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory() + itemLibraryModel.isAnyCategoryHidden = false + } + itemLibraryModel.isAnyCategoryHidden = false itemLibraryModel.showHiddenCategories() } @@ -192,94 +211,117 @@ ScrollView { StudioControls.MenuItem { id: importMenuItem - text: qsTr("Add Module: ") + importToAdd - enabled: importToAdd !== "" - onTriggered: rootView.addImportForItem(importToAdd) + text: qsTr("Add Module: ") + itemsView.importToAdd + enabled: itemsView.importToAdd !== "" + onTriggered: rootView.addImportForItem(itemsView.importToAdd) } } } - Column { - spacing: 2 - Repeater { - model: itemLibraryModel // to be set in Qml context - delegate: Section { - width: itemsView.width - - (itemsView.verticalScrollBarVisible ? itemsView.verticalThickness : 0) - caption: importName - visible: importVisible - sectionHeight: 30 - sectionFontSize: 15 - showArrow: categoryModel.rowCount() > 0 - labelColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor - : StudioTheme.Values.themeTextColor - leftPadding: 0 - rightPadding: 0 - expanded: importExpanded - expandOnClick: false - useDefaulContextMenu: false + Loader { + anchors.fill: parent + sourceComponent: itemsView.isHorizontalView ? horizontalView : verticalView + } - onToggleExpand: { - if (categoryModel.rowCount() > 0) - importExpanded = !importExpanded - } - onShowContextMenu: { - importToRemove = importRemovable ? importUrl : "" - currentImport = model - currentCategory = null - if (!rootView.isSearchActive()) - moduleContextMenu.popup() - } + Component { + id: verticalView - Column { - spacing: 2 - property var currentImportModel: model // allows accessing the import model from inside the category section - Repeater { - model: categoryModel - delegate: Section { - width: itemsView.width - - (itemsView.verticalScrollBarVisible ? itemsView.verticalThickness : 0) - sectionBackgroundColor: "transparent" - showTopSeparator: index > 0 - hideHeader: categoryModel.rowCount() <= 1 - leftPadding: 0 - rightPadding: 0 - addTopPadding: categoryModel.rowCount() > 1 - addBottomPadding: index != categoryModel.rowCount() - 1 - caption: categoryName + " (" + itemModel.rowCount() + ")" - visible: categoryVisible - expanded: categoryExpanded - expandOnClick: false - onToggleExpand: categoryExpanded = !categoryExpanded - onShowContextMenu: { - currentCategory = model - currentImport = parent.currentImportModel - if (!rootView.isSearchActive()) - moduleContextMenu.popup() - } + ScrollView { + id: verticalScrollView + width: itemsView.width + height: itemsView.height + onContentHeightChanged: { + var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0) + if (contentY > maxPosition) + contentY = maxPosition + } - Grid { - id: itemGrid + Column { + spacing: 2 + Repeater { + model: itemLibraryModel // to be set in Qml context + delegate: Section { + width: itemsView.width - + (verticalScrollView.verticalScrollBarVisible + ? verticalScrollView.verticalThickness : 0) + caption: importName + visible: importVisible + sectionHeight: 30 + sectionFontSize: 15 + showArrow: categoryModel.rowCount() > 0 + labelColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor + : StudioTheme.Values.themeTextColor + leftPadding: 0 + rightPadding: 0 + expanded: importExpanded + expandOnClick: false + useDefaulContextMenu: false + onToggleExpand: { + if (categoryModel.rowCount() > 0) + importExpanded = !importExpanded + } + onShowContextMenu: { + itemsView.importToRemove = importRemovable ? importUrl : "" + itemsView.currentImport = model + itemsView.currentCategory = null + if (!rootView.isSearchActive()) + moduleContextMenu.popup() + } - property real actualWidth: parent.width - itemGrid.leftPadding -itemGrid.rightPadding - property int flexibleWidth: (itemGrid.actualWidth / columns) - styleConstants.cellWidth + Column { + spacing: 2 + property var currentImportModel: model // allows accessing the import model from inside the category section + Repeater { + model: categoryModel + delegate: Section { + width: itemsView.width - + (verticalScrollView.verticalScrollBarVisible + ? verticalScrollView.verticalThickness : 0) + sectionBackgroundColor: "transparent" + showTopSeparator: index > 0 + hideHeader: categoryModel.rowCount() <= 1 + leftPadding: 0 + rightPadding: 0 + addTopPadding: categoryModel.rowCount() > 1 + addBottomPadding: index !== categoryModel.rowCount() - 1 + caption: categoryName + " (" + itemModel.rowCount() + ")" + visible: categoryVisible + expanded: categoryExpanded + expandOnClick: false + onToggleExpand: categoryExpanded = !categoryExpanded + useDefaulContextMenu: false + onShowContextMenu: { + itemsView.currentCategory = model + itemsView.currentImport = parent.currentImportModel + if (!rootView.isSearchActive()) + moduleContextMenu.popup() + } - leftPadding: 6 - rightPadding: 6 - columns: itemGrid.actualWidth / styleConstants.cellWidth + Grid { + id: itemGrid - Repeater { - model: itemModel - delegate: ItemDelegate { - visible: itemVisible - textColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor - : StudioTheme.Values.themeTextColor - width: styleConstants.cellWidth + itemGrid.flexibleWidth - height: styleConstants.cellHeight - onShowContextMenu: { - if (!itemUsable) { - importToAdd = itemRequiredImport - itemContextMenu.popup() + property real actualWidth: parent.width - itemGrid.leftPadding -itemGrid.rightPadding + property int flexibleWidth: (itemGrid.actualWidth / columns) - styleConstants.cellWidth + + leftPadding: 6 + rightPadding: 6 + columns: itemGrid.actualWidth / styleConstants.cellWidth + rowSpacing: 7 + + Repeater { + model: itemModel + delegate: ItemDelegate { + visible: itemVisible + textColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor + : StudioTheme.Values.themeTextColor + width: styleConstants.cellWidth + itemGrid.flexibleWidth + height: styleConstants.cellHeight + onShowContextMenu: { + if (!itemUsable) { + itemsView.importToAdd = itemRequiredImport + itemContextMenu.popup() + } + } } } } @@ -291,4 +333,163 @@ ScrollView { } } } + + Component { + id: horizontalView + + Row { + padding: 5 + + ScrollView { + id: horizontalScrollView + width: 270 + height: itemsView.height + onContentHeightChanged: { + var maxPosition = Math.max(contentHeight - horizontalScrollView.height, 0) + if (contentY > maxPosition) + contentY = maxPosition + } + + Column { + width: parent.width + spacing: 2 + Repeater { + model: itemLibraryModel // to be set in Qml context + delegate: Section { + width: 265 - + (horizontalScrollView.verticalScrollBarVisible + ? horizontalScrollView.verticalThickness : 0) + caption: importName + visible: importVisible + sectionHeight: 30 + sectionFontSize: 15 + showArrow: categoryModel.rowCount() > 0 + labelColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor + : StudioTheme.Values.themeTextColor + leftPadding: 0 + rightPadding: 0 + expanded: importExpanded + expandOnClick: false + useDefaulContextMenu: false + onToggleExpand: { + if (categoryModel.rowCount() > 0) + importExpanded = !importExpanded + } + onShowContextMenu: { + itemsView.importToRemove = importRemovable ? importUrl : "" + itemsView.currentImport = model + itemsView.currentCategory = null + if (!rootView.isSearchActive()) + moduleContextMenu.popup() + } + + Column { + spacing: 2 + property var currentImportModel: model // allows accessing the import model from inside the category section + Repeater { + model: categoryModel + delegate: Rectangle { + width: 265 - + (horizontalScrollView.verticalScrollBarVisible + ? horizontalScrollView.verticalThickness : 0) + height: 25 + visible: categoryVisible + border.width: StudioTheme.Values.border + border.color: StudioTheme.Values.themeControlOutline + color: categorySelected + ? StudioTheme.Values.themeControlBackgroundHover + : categoryMouseArea.containsMouse ? Qt.darker(StudioTheme.Values.themeControlBackgroundHover, 1.5) + : StudioTheme.Values.themeControlBackground + + Text { + anchors.fill: parent + text: categoryName + color: StudioTheme.Values.themeTextColor + font.pixelSize: 13 + font.capitalization: Font.AllUppercase + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + + MouseArea { + id: categoryMouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + + onClicked: (mouse) => { + itemLibraryModel.selectImportCategory(parent.parent.currentImportModel.importUrl, model.index) + itemsView.selectedCategory = model + itemsView.selectedCategoryImport = parent.parent.currentImportModel + + if (mouse.button === Qt.RightButton && !rootView.isSearchActive() && categoryModel.rowCount() !== 1) { + itemsView.currentCategory = model + itemsView.currentImport = parent.parent.currentImportModel + moduleContextMenu.popup() + } + } + Component.onCompleted: { + if (categorySelected) + categorySelected = !categorySelected + itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory() + if (itemsView.selectedCategory === categorySelected) + itemsView.selectedCategoryImport = itemsView.selectedCategory.parent.currentImportModel + } + } + } + } + } + } + } + } + } + + Rectangle { // separator between import/category column and item grid + id: separatingLine + height: itemsView.height - 10 + width: 1 + color: StudioTheme.Values.themeControlOutline + } + + ScrollView { + id: itemScrollView + width: itemsView.width - 275 + height: itemsView.height + onContentHeightChanged: { + var maxPosition = Math.max(contentHeight - itemScrollView.height, 0) + if (contentY > maxPosition) + contentY = maxPosition + } + + Grid { + id: hItemGrid + property real actualWidth: itemsView.width - 294 + property int flexibleWidth: (hItemGrid.actualWidth / hItemGrid.columns) - styleConstants.cellWidth + + leftPadding: 9 + rightPadding: 9 + bottomPadding: 15 + columns: hItemGrid.actualWidth / styleConstants.cellWidth + rowSpacing: 7 + + Repeater { + model: itemsView.selectedCategory ? itemsView.selectedCategory.itemModel : null + delegate: ItemDelegate { + visible: itemVisible + textColor: itemsView.selectedCategoryImport && itemsView.selectedCategoryImport.importUnimported + ? StudioTheme.Values.themeUnimportedModuleColor : StudioTheme.Values.themeTextColor + width: styleConstants.cellWidth + hItemGrid.flexibleWidth + height: styleConstants.cellHeight + onShowContextMenu: { + if (!itemUsable) { + itemsView.importToAdd = itemRequiredImport + itemContextMenu.popup() + } + } + } + } + } + } + } + } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp index 2677eb94ae9..d351232e36b 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.cpp @@ -144,6 +144,17 @@ void ItemLibraryCategoriesModel::resetModel() endResetModel(); } +bool ItemLibraryCategoriesModel::isAllCategoriesHidden() const +{ + for (const auto &category : std::as_const(m_categoryList)) { + // ignore "All Other Components" as its categoryVisible is always true + if (category->isCategoryVisible() && category->categoryName() != "All Other Components") + return false; + } + + return true; +} + void ItemLibraryCategoriesModel::showAllCategories(bool show) { for (const auto &category : std::as_const(m_categoryList)) { @@ -153,9 +164,43 @@ void ItemLibraryCategoriesModel::showAllCategories(bool show) category->ownerImport()->importName()); } } + emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")}); } +QObject *ItemLibraryCategoriesModel::selectFirstVisibleCategory() +{ + for (int i = 0; i < m_categoryList.length(); ++i) { + const auto category = m_categoryList.at(i); + + if (category->isCategoryVisible()) { + category->setCategorySelected(true); + emit dataChanged(index(i),index(i), {m_roleNames.key("categorySelected")}); + return category; + } + } + + return nullptr; +} + +void ItemLibraryCategoriesModel::clearSelectedCategories() +{ + for (const auto &category : std::as_const(m_categoryList)) + category->setCategorySelected(false); + + emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categorySelected")}); +} + +void ItemLibraryCategoriesModel::selectCategory(int categoryIndex) +{ + const auto category = m_categoryList.at(categoryIndex); + if (!category->categorySelected()) { + clearSelectedCategories(); + category->setCategorySelected(true); + emit dataChanged(index(categoryIndex),index(categoryIndex), {m_roleNames.key("categorySelected")}); + } +} + void ItemLibraryCategoriesModel::addRoleNames() { int role = 0; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h index 276d47ac480..9433af804f9 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategoriesmodel.h @@ -52,9 +52,13 @@ public: const QList> &categorySections() const; + bool isAllCategoriesHidden() const; void sortCategorySections(); void resetModel(); void showAllCategories(bool show = true); + void clearSelectedCategories(); + QObject *selectFirstVisibleCategory(); + void selectCategory(int categoryIndex); private: void addRoleNames(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp index 464f56ca103..0744b7b2b3f 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.cpp @@ -26,6 +26,7 @@ #include "itemlibrarycategory.h" #include "itemlibraryitem.h" +#include "itemlibrarywidget.h" namespace QmlDesigner { @@ -46,6 +47,11 @@ bool ItemLibraryCategory::categoryExpanded() const return m_categoryExpanded; } +bool ItemLibraryCategory::categorySelected() const +{ + return m_categorySelected; +} + QString ItemLibraryCategory::sortingName() const { if (ItemLibraryModel::categorySortingHash.contains(categoryName())) @@ -84,6 +90,10 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool * hasVisibleItems = true; } + // update item model in horizontal view so search text matches item grid + if (ItemLibraryWidget::isHorizontalLayout) + m_itemModel.resetModel(); + // expand category if it has an item matching search criteria if (!searchText.isEmpty() && hasVisibleItems && !categoryExpanded()) setExpanded(true); @@ -124,4 +134,9 @@ void ItemLibraryCategory::setExpanded(bool expanded) m_categoryExpanded = expanded; } +void ItemLibraryCategory::setCategorySelected(bool selected) +{ + m_categorySelected = selected; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h index 6e5da446108..e1af69e5fa6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarycategory.h @@ -39,6 +39,7 @@ class ItemLibraryCategory : public QObject Q_PROPERTY(QString categoryName READ categoryName FINAL) Q_PROPERTY(bool categoryVisible READ isCategoryVisible WRITE setCategoryVisible NOTIFY categoryVisibilityChanged FINAL) Q_PROPERTY(bool categoryExpanded READ categoryExpanded WRITE setExpanded NOTIFY expandedChanged FINAL) + Q_PROPERTY(bool categorySelected READ categorySelected WRITE setCategorySelected NOTIFY categorySelectedChanged FINAL) Q_PROPERTY(QObject *itemModel READ itemModel NOTIFY itemModelChanged FINAL) public: @@ -46,6 +47,7 @@ public: QString categoryName() const; bool categoryExpanded() const; + bool categorySelected() const; QString sortingName() const; void addItem(ItemLibraryItem *item); @@ -60,6 +62,7 @@ public: void sortItems(); void setExpanded(bool expanded); + void setCategorySelected(bool selected); ItemLibraryImport *ownerImport() const { return m_ownerImport; } @@ -68,6 +71,7 @@ signals: void visibilityChanged(); void expandedChanged(); void categoryVisibilityChanged(); + void categorySelectedChanged(); private: ItemLibraryItemsModel m_itemModel; @@ -75,6 +79,7 @@ private: QString m_name; bool m_categoryExpanded = true; bool m_isVisible = true; + bool m_categorySelected = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index 76138ed0745..7e696e43ef4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -138,6 +138,26 @@ void ItemLibraryImport::showAllCategories(bool show) m_categoryModel.showAllCategories(show); } +void ItemLibraryImport::selectCategory(int categoryIndex) +{ + m_categoryModel.selectCategory(categoryIndex); +} + +QObject *ItemLibraryImport::selectFirstVisibleCategory() +{ + return m_categoryModel.selectFirstVisibleCategory(); +} + +void ItemLibraryImport::clearSelectedCategories() +{ + m_categoryModel.clearSelectedCategories(); +} + +bool ItemLibraryImport::isAllCategoriesHidden() const +{ + return m_categoryModel.isAllCategoriesHidden(); +} + Import ItemLibraryImport::importEntry() const { return m_import; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h index 81717439f9a..f5a1cd02791 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.h @@ -68,6 +68,7 @@ public: bool importCatVisibleState() const; bool hasCategories() const; bool hasSingleCategory() const; + bool isAllCategoriesHidden() const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const; void addCategory(ItemLibraryCategory *category); @@ -80,6 +81,9 @@ public: void setImportCatVisibleState(bool show); void expandCategories(bool expand = true); void showAllCategories(bool show = true); + void selectCategory(int categoryIndex); + QObject *selectFirstVisibleCategory(); + void clearSelectedCategories(); static QString userComponentsTitle(); static QString quick3DAssetsTitle(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 85d367fb77c..ebef71f63f5 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -90,6 +90,40 @@ bool ItemLibraryModel::getIsAnyCategoryHidden() const return false; } +void ItemLibraryModel::selectImportCategory(const QString importUrl, int categoryIndex) +{ + ItemLibraryImport *selectedCategoryImport = importByUrl(importUrl); + + for (int i = 0; i < m_importList.length(); ++i) { + const auto importToSelect = m_importList.at(i); + + if (selectedCategoryImport == importToSelect) + importToSelect->selectCategory(categoryIndex); + else + importToSelect->clearSelectedCategories(); + } +} + +bool ItemLibraryModel::isAllCategoriesHidden() const +{ + for (int i = 0; i < m_importList.length(); ++i) { + if (!m_importList.at(i)->isAllCategoriesHidden()) + return false; + } + + return true; +} + +QObject *ItemLibraryModel::selectImportFirstVisibleCategory() +{ + for (const QPointer &import : std::as_const(m_importList)) { + if (!import->isAllCategoriesHidden()) + return import->selectFirstVisibleCategory(); + } + + return nullptr; +} + bool ItemLibraryModel::isAnyCategoryHidden() const { return m_isAnyCategoryHidden; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h index f2e5786f302..ad9803821ff 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h @@ -77,6 +77,9 @@ public: Q_INVOKABLE void collapseAll(); Q_INVOKABLE void showHiddenCategories(); Q_INVOKABLE bool getIsAnyCategoryHidden() const; + Q_INVOKABLE void selectImportCategory(const QString importUrl, int categoryIndex); + Q_INVOKABLE QObject *selectImportFirstVisibleCategory(); + Q_INVOKABLE bool isAllCategoriesHidden() const; Import entryToImport(const ItemLibraryEntry &entry); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 3c8a76597bd..de15fde7cf3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -143,6 +143,11 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) return QObject::eventFilter(obj, event); } +void ItemLibraryWidget::resizeEvent(QResizeEvent *event) +{ + isHorizontalLayout = event->size().width() >= HORIZONTAL_LAYOUT_WIDTH_LIMIT; +} + ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, AsynchronousImageCache &asynchronousFontImageCache, SynchronousImageCache &synchronousFontImageCache) @@ -196,6 +201,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, {{"itemLibraryIconWidth"}, m_itemIconSize.width()}, {{"itemLibraryIconHeight"}, m_itemIconSize.height()}, {{"rootView"}, QVariant::fromValue(this)}, + {{"widthLimit"}, HORIZONTAL_LAYOUT_WIDTH_LIMIT}, {{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()}, }); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index 4910fedc182..6695c01da5a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -92,6 +92,8 @@ public: void setFlowMode(bool b); static QPair getAssetTypeAndData(const QString &assetPath); + inline static bool isHorizontalLayout = false; + Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); @@ -110,6 +112,7 @@ signals: protected: bool eventFilter(QObject *obj, QEvent *event) override; + void resizeEvent(QResizeEvent *event) override; private: void reloadQmlSource(); @@ -149,6 +152,8 @@ private: bool m_updateRetry = false; QString m_filterText; QPoint m_dragStartPoint; + + inline static int HORIZONTAL_LAYOUT_WIDTH_LIMIT = 600; }; } // namespace QmlDesigner