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 <miikka.heikkinen@qt.io>
Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miina Puuronen
2021-08-24 12:43:51 +03:00
parent d6cc280920
commit d0a4fc4b2c
12 changed files with 441 additions and 99 deletions

View File

@@ -41,7 +41,7 @@ Item {
anchors.topMargin: 1 anchors.topMargin: 1
anchors.fill: parent anchors.fill: parent
color: StudioTheme.Values.themePanelBackground color: mouseRegion.containsMouse ? StudioTheme.Values.themeControlBackgroundHover : StudioTheme.Values.themePanelBackground
Image { Image {
id: itemIcon // to be set by model id: itemIcon // to be set by model

View File

@@ -73,7 +73,7 @@ itemLibraryModel [
] ]
*/ */
ScrollView { Item {
id: itemsView id: itemsView
property string importToRemove: "" property string importToRemove: ""
@@ -81,6 +81,11 @@ ScrollView {
property var currentItem: null property var currentItem: null
property var currentCategory: null property var currentCategory: null
property var currentImport: 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 // called from C++ to close context menu on focus out
function closeContextMenu() function closeContextMenu()
@@ -91,15 +96,21 @@ ScrollView {
function showImportCategories() 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()) if (!itemLibraryModel.getIsAnyCategoryHidden())
itemLibraryModel.isAnyCategoryHidden = false itemLibraryModel.isAnyCategoryHidden = false
} }
onContentHeightChanged: { onWidthChanged: {
var maxPosition = Math.max(contentHeight - height, 0) itemsView.isHorizontalView = itemsView.width > widthLimit
if (contentY > maxPosition)
contentY = maxPosition
} }
Item { Item {
@@ -112,66 +123,68 @@ ScrollView {
property int cellVerticalMargin: 4 property int cellVerticalMargin: 4
// the following depend on the actual shape of the item delegate // the following depend on the actual shape of the item delegate
property int cellWidth: textWidth + 2 * cellHorizontalMargin property int cellWidth: styleConstants.textWidth + 2 * styleConstants.cellHorizontalMargin
property int cellHeight: itemLibraryIconHeight + textHeight + property int cellHeight: itemLibraryIconHeight + styleConstants.textHeight +
2 * cellVerticalMargin + cellVerticalSpacing 2 * styleConstants.cellVerticalMargin + styleConstants.cellVerticalSpacing
StudioControls.Menu { StudioControls.Menu {
id: moduleContextMenu id: moduleContextMenu
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Remove Module") text: qsTr("Remove Module")
visible: currentCategory === null visible: itemsView.currentCategory === null
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
enabled: importToRemove !== "" enabled: itemsView.importToRemove !== ""
onTriggered: { onTriggered: {
showImportCategories() showImportCategories()
rootView.removeImport(importToRemove) rootView.removeImport(itemsView.importToRemove)
} }
} }
StudioControls.MenuSeparator { StudioControls.MenuSeparator {
visible: currentCategory === null visible: itemsView.currentCategory === null
height: StudioTheme.Values.border height: StudioTheme.Values.border
} }
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Expand All") text: qsTr("Expand All")
visible: currentCategory === null visible: itemsView.currentCategory === null
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onTriggered: itemLibraryModel.expandAll() onTriggered: itemLibraryModel.expandAll()
} }
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Collapse All") text: qsTr("Collapse All")
visible: currentCategory === null visible: itemsView.currentCategory === null
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onTriggered: itemLibraryModel.collapseAll() onTriggered: itemLibraryModel.collapseAll()
} }
StudioControls.MenuSeparator { StudioControls.MenuSeparator {
visible: currentCategory === null visible: itemsView.currentCategory === null
height: StudioTheme.Values.border height: StudioTheme.Values.border
} }
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Hide Category") text: qsTr("Hide Category")
visible: currentCategory visible: itemsView.currentCategory
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
onTriggered: { onTriggered: {
itemLibraryModel.isAnyCategoryHidden = true itemLibraryModel.isAnyCategoryHidden = true
currentCategory.categoryVisible = false itemsView.currentCategory.categoryVisible = false
itemsView.currentCategory.categorySelected = false
itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
} }
} }
StudioControls.MenuSeparator { StudioControls.MenuSeparator {
visible: currentCategory visible: itemsView.currentCategory
height: StudioTheme.Values.border height: StudioTheme.Values.border
} }
StudioControls.MenuItem { StudioControls.MenuItem {
text: qsTr("Show Module Hidden Categories") text: qsTr("Show Module Hidden Categories")
enabled: currentImport && !currentImport.importCatVisibleState enabled: itemsView.currentImport && !itemsView.currentImport.importCatVisibleState
onTriggered: showImportCategories() onTriggered: showImportCategories()
} }
@@ -179,6 +192,12 @@ ScrollView {
text: qsTr("Show All Hidden Categories") text: qsTr("Show All Hidden Categories")
enabled: itemLibraryModel.isAnyCategoryHidden enabled: itemLibraryModel.isAnyCategoryHidden
onTriggered: { onTriggered: {
if (itemLibraryModel.isAllCategoriesHidden()) {
itemLibraryModel.showHiddenCategories()
itemsView.selectedCategory = itemLibraryModel.selectImportFirstVisibleCategory()
itemLibraryModel.isAnyCategoryHidden = false
}
itemLibraryModel.isAnyCategoryHidden = false itemLibraryModel.isAnyCategoryHidden = false
itemLibraryModel.showHiddenCategories() itemLibraryModel.showHiddenCategories()
} }
@@ -192,94 +211,117 @@ ScrollView {
StudioControls.MenuItem { StudioControls.MenuItem {
id: importMenuItem id: importMenuItem
text: qsTr("Add Module: ") + importToAdd text: qsTr("Add Module: ") + itemsView.importToAdd
enabled: importToAdd !== "" enabled: itemsView.importToAdd !== ""
onTriggered: rootView.addImportForItem(importToAdd) onTriggered: rootView.addImportForItem(itemsView.importToAdd)
} }
} }
} }
Column { Loader {
spacing: 2 anchors.fill: parent
Repeater { sourceComponent: itemsView.isHorizontalView ? horizontalView : verticalView
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
onToggleExpand: { Component {
if (categoryModel.rowCount() > 0) id: verticalView
importExpanded = !importExpanded
}
onShowContextMenu: {
importToRemove = importRemovable ? importUrl : ""
currentImport = model
currentCategory = null
if (!rootView.isSearchActive())
moduleContextMenu.popup()
}
Column { ScrollView {
spacing: 2 id: verticalScrollView
property var currentImportModel: model // allows accessing the import model from inside the category section width: itemsView.width
Repeater { height: itemsView.height
model: categoryModel onContentHeightChanged: {
delegate: Section { var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0)
width: itemsView.width - if (contentY > maxPosition)
(itemsView.verticalScrollBarVisible ? itemsView.verticalThickness : 0) contentY = maxPosition
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()
}
Grid { Column {
id: itemGrid 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 Column {
property int flexibleWidth: (itemGrid.actualWidth / columns) - styleConstants.cellWidth 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 Grid {
rightPadding: 6 id: itemGrid
columns: itemGrid.actualWidth / styleConstants.cellWidth
Repeater { property real actualWidth: parent.width - itemGrid.leftPadding -itemGrid.rightPadding
model: itemModel property int flexibleWidth: (itemGrid.actualWidth / columns) - styleConstants.cellWidth
delegate: ItemDelegate {
visible: itemVisible leftPadding: 6
textColor: importUnimported ? StudioTheme.Values.themeUnimportedModuleColor rightPadding: 6
: StudioTheme.Values.themeTextColor columns: itemGrid.actualWidth / styleConstants.cellWidth
width: styleConstants.cellWidth + itemGrid.flexibleWidth rowSpacing: 7
height: styleConstants.cellHeight
onShowContextMenu: { Repeater {
if (!itemUsable) { model: itemModel
importToAdd = itemRequiredImport delegate: ItemDelegate {
itemContextMenu.popup() 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()
}
}
}
}
}
}
}
}
} }

View File

@@ -144,6 +144,17 @@ void ItemLibraryCategoriesModel::resetModel()
endResetModel(); 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) void ItemLibraryCategoriesModel::showAllCategories(bool show)
{ {
for (const auto &category : std::as_const(m_categoryList)) { for (const auto &category : std::as_const(m_categoryList)) {
@@ -153,9 +164,43 @@ void ItemLibraryCategoriesModel::showAllCategories(bool show)
category->ownerImport()->importName()); category->ownerImport()->importName());
} }
} }
emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")}); 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() void ItemLibraryCategoriesModel::addRoleNames()
{ {
int role = 0; int role = 0;

View File

@@ -52,9 +52,13 @@ public:
const QList<QPointer<ItemLibraryCategory>> &categorySections() const; const QList<QPointer<ItemLibraryCategory>> &categorySections() const;
bool isAllCategoriesHidden() const;
void sortCategorySections(); void sortCategorySections();
void resetModel(); void resetModel();
void showAllCategories(bool show = true); void showAllCategories(bool show = true);
void clearSelectedCategories();
QObject *selectFirstVisibleCategory();
void selectCategory(int categoryIndex);
private: private:
void addRoleNames(); void addRoleNames();

View File

@@ -26,6 +26,7 @@
#include "itemlibrarycategory.h" #include "itemlibrarycategory.h"
#include "itemlibraryitem.h" #include "itemlibraryitem.h"
#include "itemlibrarywidget.h"
namespace QmlDesigner { namespace QmlDesigner {
@@ -46,6 +47,11 @@ bool ItemLibraryCategory::categoryExpanded() const
return m_categoryExpanded; return m_categoryExpanded;
} }
bool ItemLibraryCategory::categorySelected() const
{
return m_categorySelected;
}
QString ItemLibraryCategory::sortingName() const QString ItemLibraryCategory::sortingName() const
{ {
if (ItemLibraryModel::categorySortingHash.contains(categoryName())) if (ItemLibraryModel::categorySortingHash.contains(categoryName()))
@@ -84,6 +90,10 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *
hasVisibleItems = true; 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 // expand category if it has an item matching search criteria
if (!searchText.isEmpty() && hasVisibleItems && !categoryExpanded()) if (!searchText.isEmpty() && hasVisibleItems && !categoryExpanded())
setExpanded(true); setExpanded(true);
@@ -124,4 +134,9 @@ void ItemLibraryCategory::setExpanded(bool expanded)
m_categoryExpanded = expanded; m_categoryExpanded = expanded;
} }
void ItemLibraryCategory::setCategorySelected(bool selected)
{
m_categorySelected = selected;
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -39,6 +39,7 @@ class ItemLibraryCategory : public QObject
Q_PROPERTY(QString categoryName READ categoryName FINAL) Q_PROPERTY(QString categoryName READ categoryName FINAL)
Q_PROPERTY(bool categoryVisible READ isCategoryVisible WRITE setCategoryVisible NOTIFY categoryVisibilityChanged 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 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) Q_PROPERTY(QObject *itemModel READ itemModel NOTIFY itemModelChanged FINAL)
public: public:
@@ -46,6 +47,7 @@ public:
QString categoryName() const; QString categoryName() const;
bool categoryExpanded() const; bool categoryExpanded() const;
bool categorySelected() const;
QString sortingName() const; QString sortingName() const;
void addItem(ItemLibraryItem *item); void addItem(ItemLibraryItem *item);
@@ -60,6 +62,7 @@ public:
void sortItems(); void sortItems();
void setExpanded(bool expanded); void setExpanded(bool expanded);
void setCategorySelected(bool selected);
ItemLibraryImport *ownerImport() const { return m_ownerImport; } ItemLibraryImport *ownerImport() const { return m_ownerImport; }
@@ -68,6 +71,7 @@ signals:
void visibilityChanged(); void visibilityChanged();
void expandedChanged(); void expandedChanged();
void categoryVisibilityChanged(); void categoryVisibilityChanged();
void categorySelectedChanged();
private: private:
ItemLibraryItemsModel m_itemModel; ItemLibraryItemsModel m_itemModel;
@@ -75,6 +79,7 @@ private:
QString m_name; QString m_name;
bool m_categoryExpanded = true; bool m_categoryExpanded = true;
bool m_isVisible = true; bool m_isVisible = true;
bool m_categorySelected = false;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -138,6 +138,26 @@ void ItemLibraryImport::showAllCategories(bool show)
m_categoryModel.showAllCategories(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 Import ItemLibraryImport::importEntry() const
{ {
return m_import; return m_import;

View File

@@ -68,6 +68,7 @@ public:
bool importCatVisibleState() const; bool importCatVisibleState() const;
bool hasCategories() const; bool hasCategories() const;
bool hasSingleCategory() const; bool hasSingleCategory() const;
bool isAllCategoriesHidden() const;
ItemLibraryCategory *getCategorySection(const QString &categoryName) const; ItemLibraryCategory *getCategorySection(const QString &categoryName) const;
void addCategory(ItemLibraryCategory *category); void addCategory(ItemLibraryCategory *category);
@@ -80,6 +81,9 @@ public:
void setImportCatVisibleState(bool show); void setImportCatVisibleState(bool show);
void expandCategories(bool expand = true); void expandCategories(bool expand = true);
void showAllCategories(bool show = true); void showAllCategories(bool show = true);
void selectCategory(int categoryIndex);
QObject *selectFirstVisibleCategory();
void clearSelectedCategories();
static QString userComponentsTitle(); static QString userComponentsTitle();
static QString quick3DAssetsTitle(); static QString quick3DAssetsTitle();

View File

@@ -90,6 +90,40 @@ bool ItemLibraryModel::getIsAnyCategoryHidden() const
return false; 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<ItemLibraryImport> &import : std::as_const(m_importList)) {
if (!import->isAllCategoriesHidden())
return import->selectFirstVisibleCategory();
}
return nullptr;
}
bool ItemLibraryModel::isAnyCategoryHidden() const bool ItemLibraryModel::isAnyCategoryHidden() const
{ {
return m_isAnyCategoryHidden; return m_isAnyCategoryHidden;

View File

@@ -77,6 +77,9 @@ public:
Q_INVOKABLE void collapseAll(); Q_INVOKABLE void collapseAll();
Q_INVOKABLE void showHiddenCategories(); Q_INVOKABLE void showHiddenCategories();
Q_INVOKABLE bool getIsAnyCategoryHidden() const; 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); Import entryToImport(const ItemLibraryEntry &entry);

View File

@@ -143,6 +143,11 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
} }
void ItemLibraryWidget::resizeEvent(QResizeEvent *event)
{
isHorizontalLayout = event->size().width() >= HORIZONTAL_LAYOUT_WIDTH_LIMIT;
}
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache, AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache) SynchronousImageCache &synchronousFontImageCache)
@@ -196,6 +201,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
{{"itemLibraryIconWidth"}, m_itemIconSize.width()}, {{"itemLibraryIconWidth"}, m_itemIconSize.width()},
{{"itemLibraryIconHeight"}, m_itemIconSize.height()}, {{"itemLibraryIconHeight"}, m_itemIconSize.height()},
{{"rootView"}, QVariant::fromValue(this)}, {{"rootView"}, QVariant::fromValue(this)},
{{"widthLimit"}, HORIZONTAL_LAYOUT_WIDTH_LIMIT},
{{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()}, {{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()},
}); });

View File

@@ -92,6 +92,8 @@ public:
void setFlowMode(bool b); void setFlowMode(bool b);
static QPair<QString, QByteArray> getAssetTypeAndData(const QString &assetPath); static QPair<QString, QByteArray> getAssetTypeAndData(const QString &assetPath);
inline static bool isHorizontalLayout = false;
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void removeImport(const QString &importUrl); Q_INVOKABLE void removeImport(const QString &importUrl);
@@ -110,6 +112,7 @@ signals:
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
private: private:
void reloadQmlSource(); void reloadQmlSource();
@@ -149,6 +152,8 @@ private:
bool m_updateRetry = false; bool m_updateRetry = false;
QString m_filterText; QString m_filterText;
QPoint m_dragStartPoint; QPoint m_dragStartPoint;
inline static int HORIZONTAL_LAYOUT_WIDTH_LIMIT = 600;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner