From d0a4fc4b2cc3cc2f43aab490ef85d1764f4f4c00 Mon Sep 17 00:00:00 2001 From: Miina Puuronen Date: Tue, 24 Aug 2021 12:43:51 +0300 Subject: [PATCH] QmlDesigner: Implement a horizontal layout for Component Library The view from vertical to horizontal is changed with Loader, depending on Library's width. Vertical layout (old) is mostly the same as before. Added new property categorySelected for categories. Items are also now hoverable. Task-number: QDS-4764 Change-Id: I031f3916f0d011fd76a963b247c238997d7a55d8 Reviewed-by: Miikka Heikkinen Reviewed-by: Samuel Ghinet Reviewed-by: Thomas Hartmann --- .../itemLibraryQmlSources/ItemDelegate.qml | 2 +- .../itemLibraryQmlSources/ItemsView.qml | 397 +++++++++++++----- .../itemlibrarycategoriesmodel.cpp | 45 ++ .../itemlibrary/itemlibrarycategoriesmodel.h | 4 + .../itemlibrary/itemlibrarycategory.cpp | 15 + .../itemlibrary/itemlibrarycategory.h | 5 + .../itemlibrary/itemlibraryimport.cpp | 20 + .../itemlibrary/itemlibraryimport.h | 4 + .../itemlibrary/itemlibrarymodel.cpp | 34 ++ .../components/itemlibrary/itemlibrarymodel.h | 3 + .../itemlibrary/itemlibrarywidget.cpp | 6 + .../itemlibrary/itemlibrarywidget.h | 5 + 12 files changed, 441 insertions(+), 99 deletions(-) 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