forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -52,9 +52,13 @@ public:
|
||||
|
||||
const QList<QPointer<ItemLibraryCategory>> &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();
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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<ItemLibraryImport> &import : std::as_const(m_importList)) {
|
||||
if (!import->isAllCategoriesHidden())
|
||||
return import->selectFirstVisibleCategory();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ItemLibraryModel::isAnyCategoryHidden() const
|
||||
{
|
||||
return m_isAnyCategoryHidden;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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()},
|
||||
});
|
||||
|
||||
|
@@ -92,6 +92,8 @@ public:
|
||||
void setFlowMode(bool b);
|
||||
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 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
|
||||
|
Reference in New Issue
Block a user