diff --git a/share/qtcreator/qmldesigner/designericons.json b/share/qtcreator/qmldesigner/designericons.json new file mode 100644 index 00000000000..e4201291c64 --- /dev/null +++ b/share/qtcreator/qmldesigner/designericons.json @@ -0,0 +1,81 @@ +{ + "ContextMenuArea": { + "size": "28x28", + "Off": { + "Disabled": { "color": "DSiconColorDisabled" }, + "Hovered": { "color": "DSnavigatorIconHover" }, + "Normal": { "color": "DSnavigatorIcon" }, + "Selected": { "color": "DSnavigatorIconSelected" } + }, + "On": { + "Disabled": { "color": "DSiconColorDisabled" }, + "Hovered": { "color": "DSnavigatorIconHover" }, + "Normal": { "color": "DSnavigatorIcon" }, + "Selected": { "color": "DSnavigatorIconSelected" } + } + }, + "AddMouseAreaIcon": { + "iconName": "s_mouseArea" + }, + "AnchorsIcon": { + "iconName": "s_anchors" + }, + "AnnotationIcon": { + "iconName": "s_annotations" + }, + "ArrangeIcon": { + "iconName": "s_arrange" + }, + "ConnectionsIcon": { + "iconName": "s_connections" + }, + "EditIcon": { + "iconName": "s_edit" + }, + "EnterComponentIcon": { + "iconName": "s_enterComponent" + }, + "EventListIcon": { + "iconName": "s_eventList" + }, + "GroupSelectionIcon": { + "iconName": "s_group" + }, + "LayoutsIcon": { + "iconName": "s_layouts" + }, + "MakeComponentIcon": { + "iconName": "s_component" + }, + "MergeWithTemplateIcon": { + "iconName": "s_merging" + }, + "PositionsersIcon": { + "iconName": "s_positioners" + }, + "SelecionIcon": { + "iconName": "s_selection" + }, + "ShowBoundsIcon": { + "Off": { + "iconName": "visibilityOff" + }, + "On": { + "iconName": "visibilityOn" + } + }, + "SnappingIcon": { + "iconName": "s_snapping" + }, + "TimelineIcon": { + "iconName": "s_timeline" + }, + "VisibilityIcon": { + "Off": { + "iconName": "visibilityOff" + }, + "On": { + "iconName": "visibilityOn" + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 9339fda0daa..cdad4b7e1a7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -95,82 +95,109 @@ QtObject { readonly property string gridView: "\u0070" readonly property string idAliasOff: "\u0071" readonly property string idAliasOn: "\u0072" - readonly property string infinity: "\u0073" - readonly property string keyframe: "\u0074" - readonly property string linkTriangle: "\u0075" - readonly property string linked: "\u0076" - readonly property string listView: "\u0077" - readonly property string lockOff: "\u0078" - readonly property string lockOn: "\u0079" - readonly property string materialPreviewEnvironment: "\u007A" - readonly property string materialPreviewModel: "\u007B" - readonly property string mergeCells: "\u007C" - readonly property string minus: "\u007D" - readonly property string mirror: "\u007E" - readonly property string newMaterial: "\u007F" - readonly property string openLink: "\u0080" - readonly property string openMaterialBrowser: "\u0081" - readonly property string orientation: "\u0082" - readonly property string paddingEdge: "\u0083" - readonly property string paddingFrame: "\u0084" - readonly property string pasteStyle: "\u0085" - readonly property string pause: "\u0086" - readonly property string pin: "\u0087" - readonly property string play: "\u0088" - readonly property string plus: "\u0089" - readonly property string promote: "\u008A" - readonly property string readOnly: "\u008B" - readonly property string redo: "\u008C" - readonly property string rotationFill: "\u008D" - readonly property string rotationOutline: "\u008E" - readonly property string search: "\u008F" - readonly property string sectionToggle: "\u0090" - readonly property string splitColumns: "\u0091" - readonly property string splitRows: "\u0092" - readonly property string startNode: "\u0093" - readonly property string testIcon: "\u0094" - readonly property string textAlignBottom: "\u0095" - readonly property string textAlignCenter: "\u0096" - readonly property string textAlignJustified: "\u0097" - readonly property string textAlignLeft: "\u0098" - readonly property string textAlignMiddle: "\u0099" - readonly property string textAlignRight: "\u009A" - readonly property string textAlignTop: "\u009B" - readonly property string textBulletList: "\u009D" - readonly property string textFullJustification: "\u009E" - readonly property string textNumberedList: "\u009F" - readonly property string tickIcon: "\u00A0" - readonly property string translationCreateFiles: "\u00A1" - readonly property string translationCreateReport: "\u00A2" - readonly property string translationExport: "\u00A3" - readonly property string translationImport: "\u00A4" - readonly property string translationSelectLanguages: "\u00A5" - readonly property string translationTest: "\u00A6" - readonly property string transparent: "\u00A7" - readonly property string triState: "\u00A8" - readonly property string triangleArcA: "\u00A9" - readonly property string triangleArcB: "\u00AA" - readonly property string triangleCornerA: "\u00AB" - readonly property string triangleCornerB: "\u00AC" - readonly property string unLinked: "\u00AE" - readonly property string undo: "\u00AF" - readonly property string unpin: "\u00B0" - readonly property string upDownIcon: "\u00B1" - readonly property string upDownSquare2: "\u00B2" - readonly property string visibilityOff: "\u00B3" - readonly property string visibilityOn: "\u00B4" - readonly property string wildcard: "\u00B5" - readonly property string wizardsAutomotive: "\u00B6" - readonly property string wizardsDesktop: "\u00B7" - readonly property string wizardsGeneric: "\u00B8" - readonly property string wizardsMcuEmpty: "\u00B9" - readonly property string wizardsMcuGraph: "\u00BA" - readonly property string wizardsMobile: "\u00BB" - readonly property string wizardsUnknown: "\u00BC" - readonly property string zoomAll: "\u00BD" - readonly property string zoomIn: "\u00BE" - readonly property string zoomOut: "\u00BF" - readonly property string zoomSelection: "\u00C0" + readonly property string imported: "\u0073" + readonly property string infinity: "\u0074" + readonly property string keyframe: "\u0075" + readonly property string linkTriangle: "\u0076" + readonly property string linked: "\u0077" + readonly property string listView: "\u0078" + readonly property string lockOff: "\u0079" + readonly property string lockOn: "\u007A" + readonly property string materialPreviewEnvironment: "\u007B" + readonly property string materialPreviewModel: "\u007C" + readonly property string mergeCells: "\u007D" + readonly property string minus: "\u007E" + readonly property string mirror: "\u007F" + readonly property string newMaterial: "\u0080" + readonly property string openLink: "\u0081" + readonly property string openMaterialBrowser: "\u0082" + readonly property string orientation: "\u0083" + readonly property string paddingEdge: "\u0084" + readonly property string paddingFrame: "\u0085" + readonly property string pasteStyle: "\u0086" + readonly property string pause: "\u0087" + readonly property string pin: "\u0088" + readonly property string play: "\u0089" + readonly property string plus: "\u008A" + readonly property string promote: "\u008B" + readonly property string readOnly: "\u008C" + readonly property string redo: "\u008D" + readonly property string rotationFill: "\u008E" + readonly property string rotationOutline: "\u008F" + readonly property string s_anchors: "\u0090" + readonly property string s_annotations: "\u0091" + readonly property string s_arrange: "\u0092" + readonly property string s_boundingBox: "\u0093" + readonly property string s_component: "\u0094" + readonly property string s_connections: "\u0095" + readonly property string s_edit: "\u0096" + readonly property string s_enterComponent: "\u0097" + readonly property string s_eventList: "\u0098" + readonly property string s_group: "\u0099" + readonly property string s_layouts: "\u009A" + readonly property string s_merging: "\u009B" + readonly property string s_mouseArea: "\u009D" + readonly property string s_positioners: "\u009E" + readonly property string s_selection: "\u009F" + readonly property string s_snapping: "\u00A0" + readonly property string s_timeline: "\u00A1" + readonly property string s_visibility: "\u00A2" + readonly property string search: "\u00A3" + readonly property string sectionToggle: "\u00A4" + readonly property string splitColumns: "\u00A5" + readonly property string splitRows: "\u00A6" + readonly property string startNode: "\u00A7" + readonly property string testIcon: "\u00A8" + readonly property string textAlignBottom: "\u00A9" + readonly property string textAlignCenter: "\u00AA" + readonly property string textAlignJustified: "\u00AB" + readonly property string textAlignLeft: "\u00AC" + readonly property string textAlignMiddle: "\u00AE" + readonly property string textAlignRight: "\u00AF" + readonly property string textAlignTop: "\u00B0" + readonly property string textBulletList: "\u00B1" + readonly property string textFullJustification: "\u00B2" + readonly property string textNumberedList: "\u00B3" + readonly property string tickIcon: "\u00B4" + readonly property string topToolbar_annotations: "\u00B5" + readonly property string topToolbar_closeFile: "\u00B6" + readonly property string topToolbar_designMode: "\u00B7" + readonly property string topToolbar_enterComponent: "\u00B8" + readonly property string topToolbar_home: "\u00B9" + readonly property string topToolbar_makeComponent: "\u00BA" + readonly property string topToolbar_navFile: "\u00BB" + readonly property string topToolbar_runProject: "\u00BC" + readonly property string translationCreateFiles: "\u00BD" + readonly property string translationCreateReport: "\u00BE" + readonly property string translationExport: "\u00BF" + readonly property string translationImport: "\u00C0" + readonly property string translationSelectLanguages: "\u00C1" + readonly property string translationTest: "\u00C2" + readonly property string transparent: "\u00C3" + readonly property string triState: "\u00C4" + readonly property string triangleArcA: "\u00C5" + readonly property string triangleArcB: "\u00C6" + readonly property string triangleCornerA: "\u00C7" + readonly property string triangleCornerB: "\u00C8" + readonly property string unLinked: "\u00C9" + readonly property string undo: "\u00CA" + readonly property string unpin: "\u00CB" + readonly property string upDownIcon: "\u00CC" + readonly property string upDownSquare2: "\u00CD" + readonly property string visibilityOff: "\u00CE" + readonly property string visibilityOn: "\u00CF" + readonly property string wildcard: "\u00D0" + readonly property string wizardsAutomotive: "\u00D1" + readonly property string wizardsDesktop: "\u00D2" + readonly property string wizardsGeneric: "\u00D3" + readonly property string wizardsMcuEmpty: "\u00D4" + readonly property string wizardsMcuGraph: "\u00D5" + readonly property string wizardsMobile: "\u00D6" + readonly property string wizardsUnknown: "\u00D7" + readonly property string zoomAll: "\u00D8" + readonly property string zoomIn: "\u00D9" + readonly property string zoomOut: "\u00DA" + readonly property string zoomSelection: "\u00DB" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index acd8df6ce3f..cacd0c3cb9f 100644 Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index ce772baf43c..a3f0fbbf6f6 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -609,6 +609,7 @@ extend_qtc_plugin(QmlDesigner crumblebar.cpp crumblebar.h designeractionmanager.cpp designeractionmanager.h designeractionmanagerview.cpp designeractionmanagerview.h + designericons.cpp designericons.h findimplementation.cpp findimplementation.h layoutingridlayout.cpp layoutingridlayout.h modelnodecontextmenu.cpp modelnodecontextmenu.h diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index dd07f433ca5..5f952319f16 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -6,6 +6,7 @@ #include "anchoraction.h" #include "changestyleaction.h" #include "designeractionmanagerview.h" +#include "designericons.h" #include "designermcumanager.h" #include "formatoperation.h" #include "modelnodecontextmenu_helper.h" @@ -286,14 +287,19 @@ QHash DesignerActionManager::handleExternalAssetsDrop(cons return addedCategoryFiles; } +QIcon DesignerActionManager::contextIcon(int contextId) const +{ + return m_designerIcons->icon(DesignerIcons::IconId(contextId), DesignerIcons::ContextMenuArea); +} + class VisiblityModelNodeAction : public ModelNodeContextMenuAction { public: - VisiblityModelNodeAction(const QByteArray &id, const QString &description, const QByteArray &category, const QKeySequence &key, int priority, + VisiblityModelNodeAction(const QByteArray &id, const QString &description, const QIcon &icon, const QByteArray &category, const QKeySequence &key, int priority, SelectionContextOperation action, SelectionContextPredicate enabled = &SelectionContextFunctors::always, SelectionContextPredicate visibility = &SelectionContextFunctors::always) : - ModelNodeContextMenuAction(id, description, {}, category, key, priority, action, enabled, visibility) + ModelNodeContextMenuAction(id, description, icon, category, key, priority, action, enabled, visibility) {} void updateContext() override @@ -376,9 +382,9 @@ public: class SelectionModelNodeAction : public ActionGroup { public: - SelectionModelNodeAction(const QString &displayName, const QByteArray &menuId, int priority) : - ActionGroup(displayName, menuId, priority, - &SelectionContextFunctors::always, &SelectionContextFunctors::selectionEnabled) + SelectionModelNodeAction(const QString &displayName, const QByteArray &menuId, const QIcon &icon, int priority) : + ActionGroup(displayName, menuId, icon, priority, + &SelectionContextFunctors::always, &SelectionContextFunctors::selectionEnabled) {} @@ -599,9 +605,10 @@ void removeSignal(SignalHandlerProperty signalHandler) class ConnectionsModelNodeActionGroup : public ActionGroup { public: - ConnectionsModelNodeActionGroup(const QString &displayName, const QByteArray &menuId, int priority) + ConnectionsModelNodeActionGroup(const QString &displayName, const QByteArray &menuId, const QIcon &icon, int priority) : ActionGroup(displayName, menuId, + icon, priority, &SelectionContextFunctors::always, &SelectionContextFunctors::selectionEnabled) @@ -968,8 +975,8 @@ bool isFlowTargetOrTransition(const SelectionContext &context) class FlowActionConnectAction : public ActionGroup { public: - FlowActionConnectAction(const QString &displayName, const QByteArray &menuId, int priority) : - ActionGroup(displayName, menuId, priority, + FlowActionConnectAction(const QString &displayName, const QByteArray &menuId, const QIcon &icon, int priority) : + ActionGroup(displayName, menuId, icon, priority, &isFlowActionItemItem, &flowOptionVisible) {} @@ -1341,16 +1348,19 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new SelectionModelNodeAction( selectionCategoryDisplayName, selectionCategory, + contextIcon(DesignerIcons::SelecionIcon), Priorities::SelectionCategory)); addDesignerAction(new ConnectionsModelNodeActionGroup( connectionsCategoryDisplayName, connectionsCategory, + contextIcon(DesignerIcons::ConnectionsIcon), Priorities::ConnectionsCategory)); addDesignerAction(new ActionGroup( arrangeCategoryDisplayName, arrangeCategory, + contextIcon(DesignerIcons::ArrangeIcon), Priorities::ArrangeCategory, &selectionNotEmpty)); @@ -1408,7 +1418,11 @@ void DesignerActionManager::createDefaultDesignerActions() &reverse, &multiSelectionAndHasSameParent)); - addDesignerAction(new ActionGroup(editCategoryDisplayName, editCategory, Priorities::EditCategory, &selectionNotEmpty)); + addDesignerAction(new ActionGroup(editCategoryDisplayName, + editCategory, + contextIcon(DesignerIcons::EditIcon), + Priorities::EditCategory, + &selectionNotEmpty)); addDesignerAction(new SeperatorDesignerAction(editCategory, 30)); @@ -1491,6 +1505,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new VisiblityModelNodeAction( visiblityCommandId, visibilityDisplayName, + contextIcon(DesignerIcons::VisibilityIcon), rootCategory, QKeySequence("Ctrl+g"), Priorities::Visibility, @@ -1499,6 +1514,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ActionGroup(anchorsCategoryDisplayName, anchorsCategory, + contextIcon(DesignerIcons::AnchorsIcon), Priorities::AnchorsCategory, &anchorsMenuEnabled)); @@ -1596,18 +1612,21 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ActionGroup( positionerCategoryDisplayName, positionerCategory, + contextIcon(DesignerIcons::PositionsersIcon), Priorities::PositionCategory, &positionOptionVisible)); addDesignerAction(new ActionGroup( layoutCategoryDisplayName, layoutCategory, + contextIcon(DesignerIcons::LayoutsIcon), Priorities::LayoutCategory, &layoutOptionVisible)); addDesignerAction(new ActionGroup( snappingCategoryDisplayName, snappingCategory, + contextIcon(DesignerIcons::SnappingIcon), Priorities::SnappingCategory, &selectionEnabled, &selectionEnabled)); @@ -1615,12 +1634,14 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ActionGroup( groupCategoryDisplayName, groupCategory, + contextIcon(DesignerIcons::GroupSelectionIcon), Priorities::Group, &studioComponentsAvailableAndSelectionCanBeLayouted)); addDesignerAction(new ActionGroup( flowCategoryDisplayName, flowCategory, + {}, Priorities::FlowCategory, &isFlowTargetOrTransition, &flowOptionVisible)); @@ -1629,6 +1650,7 @@ void DesignerActionManager::createDefaultDesignerActions() auto effectMenu = new ActionGroup( flowEffectCategoryDisplayName, flowEffectCategory, + {}, Priorities::FlowCategory, &isFlowTransitionItem, &flowOptionVisible); @@ -1660,9 +1682,10 @@ void DesignerActionManager::createDefaultDesignerActions() &flowOptionVisible)); addDesignerAction(new FlowActionConnectAction( - flowConnectionCategoryDisplayName, - flowConnectionCategory, - Priorities::FlowCategory)); + flowConnectionCategoryDisplayName, + flowConnectionCategory, + {}, + Priorities::FlowCategory)); const QList transitionTypes = {"FlowFadeEffect", @@ -1688,6 +1711,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ActionGroup( stackedContainerCategoryDisplayName, stackedContainerCategory, + {}, Priorities::StackedContainerCategory, &isStackedContainer)); @@ -1888,7 +1912,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ModelNodeContextMenuAction( goIntoComponentCommandId, enterComponentDisplayName, - {}, + contextIcon(DesignerIcons::EnterComponentIcon), rootCategory, QKeySequence(Qt::Key_F2), Priorities::ComponentActions + 2, @@ -1898,7 +1922,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ModelNodeContextMenuAction( editAnnotationsCommandId, editAnnotationsDisplayName, - {}, + contextIcon(DesignerIcons::AnnotationIcon), rootCategory, QKeySequence(), Priorities::EditAnnotations, @@ -1907,15 +1931,15 @@ void DesignerActionManager::createDefaultDesignerActions() &singleSelection)); addDesignerAction(new ModelNodeContextMenuAction( - addMouseAreaFillCommandId, - addMouseAreaFillDisplayName, - {}, - rootCategory, - QKeySequence(), - Priorities::AddMouseArea, - &addMouseAreaFill, - &addMouseAreaFillCheck, - &singleSelection)); + addMouseAreaFillCommandId, + addMouseAreaFillDisplayName, + contextIcon(DesignerIcons::AddMouseAreaIcon), + rootCategory, + QKeySequence(), + Priorities::AddMouseArea, + &addMouseAreaFill, + &addMouseAreaFillCheck, + &singleSelection)); const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); @@ -1943,7 +1967,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ModelNodeContextMenuAction( makeComponentCommandId, makeComponentDisplayName, - {}, + contextIcon(DesignerIcons::MakeComponentIcon), rootCategory, QKeySequence(), Priorities::ComponentActions + 1, @@ -1954,7 +1978,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ModelNodeContextMenuAction( editMaterialCommandId, editMaterialDisplayName, - {}, + contextIcon(DesignerIcons::EditIcon), rootCategory, QKeySequence(), 44, @@ -1974,6 +1998,7 @@ void DesignerActionManager::createDefaultDesignerActions() addDesignerAction(new ActionGroup( "", genericToolBarCategory, + {}, Priorities::GenericToolBar)); addDesignerAction(new ChangeStyleAction()); @@ -2114,6 +2139,7 @@ DesignerActionManager::DesignerActionManager(DesignerActionManagerView *designer : m_designerActionManagerView(designerActionManagerView) , m_externalDependencies(externalDependencies) { + setupIcons(); } DesignerActionManager::~DesignerActionManager() = default; @@ -2145,6 +2171,20 @@ void DesignerActionManager::addCustomTransitionEffectAction() &isFlowTransitionItem)); } +void DesignerActionManager::setupIcons() +{ + m_designerIcons.reset(new DesignerIcons("qtds_propertyIconFont.ttf", designerIconResourcesPath())); +} + +QString DesignerActionManager::designerIconResourcesPath() const +{ +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/designericons.json"; +#endif + return Core::ICore::resourcePath("qmldesigner/designericons.json").toString(); +} + DesignerActionToolBar::DesignerActionToolBar(QWidget *parentWidget) : Utils::StyledBar(parentWidget), m_toolBar(new QToolBar("ActionToolBar", this)) { diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 928d136a02e..41bf7b83876 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -23,6 +23,7 @@ QT_END_NAMESPACE namespace QmlDesigner { class DesignerActionManagerView; +class DesignerIcons; using AddResourceOperation = std::function; using ModelNodePreviewImageOperation = std::function; @@ -118,16 +119,20 @@ public: ModelNodePreviewImageOperation modelNodePreviewOperation(const ModelNode &node) const; bool externalDragHasSupportedAssets(const QMimeData *data) const; QHash handleExternalAssetsDrop(const QMimeData *data) const; + QIcon contextIcon(int contextId) const; private: void addTransitionEffectAction(const TypeName &typeName); void addCustomTransitionEffectAction(); + void setupIcons(); + QString designerIconResourcesPath() const; QList > m_designerActions; DesignerActionManagerView *m_designerActionManagerView; QList m_addResourceHandler; QList m_modelNodePreviewImageHandlers; ExternalDependenciesInterface &m_externalDependencies; + QScopedPointer m_designerIcons; }; } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.cpp b/src/plugins/qmldesigner/components/componentcore/designericons.cpp new file mode 100644 index 00000000000..ce604d6d8cd --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/designericons.cpp @@ -0,0 +1,418 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "designericons.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace QmlDesigner; +namespace { // Blank namespace + +template +struct DesignerIconEnums +{ + typedef EType EnumType; + static QString toString(const EnumType &enumValue); + static EnumType value(const QString &keyStr, bool *ok = nullptr); + + static const QMetaEnum metaEnum; + static const QString keyName; +}; + +template +struct DesignerEnumConfidentType +{ + typedef EType EnumType; +}; + +template <> +struct DesignerEnumConfidentType +{ + typedef DesignerIcons::Mode EnumType; +}; + +template <> +struct DesignerEnumConfidentType +{ + typedef DesignerIcons::State EnumType; +}; + +template +QString getEnumName() { + QMetaEnum metaEnum = QMetaEnum::fromType(); + QString enumName = QString::fromLatin1(metaEnum.enumName()); + if (enumName.size() && enumName.at(0).isUpper()) + enumName.replace(0, 1, enumName.at(0).toLower()); + return enumName; +}; + +template <> +QString getEnumName() { + return QLatin1String("iconName"); +}; + +template +const QMetaEnum DesignerIconEnums::metaEnum = + QMetaEnum::fromType::EnumType>(); + +template +const QString DesignerIconEnums::keyName = + getEnumName::EnumType>(); + +template +QString DesignerIconEnums::toString(const EType &enumValue) +{ + return QString::fromLatin1(metaEnum.valueToKey(enumValue)); +} + +template +EType DesignerIconEnums::value(const QString &keyStr, bool *ok) +{ + return static_cast(metaEnum.keyToValue(keyStr.toLatin1(), ok)); +} + +Q_GLOBAL_STATIC(QStringList, _iconFontMandatoryKeys); + +const QStringList & iconFontMandatoryKeys() +{ + if (_iconFontMandatoryKeys->isEmpty()) { + *_iconFontMandatoryKeys + << DesignerIconEnums::keyName + << DesignerIconEnums::keyName + << DesignerIconEnums::keyName + << DesignerIconEnums::keyName + << "size"; + } + return *_iconFontMandatoryKeys; +} + +QJsonObject mergeJsons(const QJsonObject &prior, const QJsonObject &joiner) +{ + QJsonObject object = prior; + const QStringList joinerKeys = joiner.keys(); + for (const QString &joinerKey : joinerKeys) { + if (!object.contains(joinerKey)) { + object.insert(joinerKey, joiner.value(joinerKey)); + } else { + QJsonValue ov = object.value(joinerKey); + QJsonValue jv = joiner.value(joinerKey); + if (ov.isObject() && jv.isObject()) { + QJsonObject mg = mergeJsons(ov.toObject(), jv.toObject()); + object.insert(joinerKey, mg); + } + } + } + return object; +} + +inline QString toJsonSize(const QSize &size) +{ + return QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height()); +} + +template +void pushSimpleEnumValue(QJsonObject &object, const EnumType &enumVal) +{ + const QString &enumKey = DesignerIconEnums::keyName; + QString enumValue = DesignerIconEnums::toString(enumVal); + object.insert(enumKey, enumValue); +} + +template +T jsonSafeValue(const QJsonObject &jsonObject, const QString &symbolName, + std::function validityCheck = [](const T&) -> bool {return true;}) +{ + if (!jsonObject.contains(symbolName)) + throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, symbolName.toLatin1()); + + QVariant symbolVar = jsonObject.value(symbolName); + T extractedVal = symbolVar.value(); + if (!validityCheck(extractedVal)) + throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, symbolName.toLatin1()); + + return extractedVal; +} + +QSize jsonSafeSize(const QJsonObject &jsonObject, const QString &symbolName) +{ + QString extractedVal = jsonSafeValue(jsonObject, symbolName); + QStringList dims = extractedVal.split("x"); + if (dims.size() == 2) { + bool wOk; + bool hOk; + int cWidth = dims.first().toInt(&wOk); + int cHeight = dims.last().toInt(&hOk); + if (wOk && hOk) + return {cWidth, cHeight}; + } + throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, symbolName.toLatin1()); + return {}; +} + +template +T jsonSafeMetaEnum(const QJsonObject &jsonObject, const QString &symbolName = DesignerIconEnums::keyName) +{ + QString extractedVal = jsonSafeValue(jsonObject, symbolName); + bool ok; + T enumIndex = static_cast (DesignerIconEnums::value(extractedVal, &ok)); + if (ok) + return enumIndex; + + throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, symbolName.toLatin1()); + return {}; +} + +template +struct JsonMap +{}; + +template <> +struct JsonMap +{ + static IconFontHelper value(const QJsonObject &jsonObject, const QJsonObject &telescopingMap) + { + QJsonObject fontHelperJson = mergeJsons(jsonObject, telescopingMap); + return IconFontHelper::fromJson(fontHelperJson); + } + + static QJsonObject json(const IconFontHelper &iconFontHelper) + { + QJsonObject object; + pushSimpleEnumValue(object, iconFontHelper.themeIcon()); + pushSimpleEnumValue(object, iconFontHelper.themeColor()); + object.insert("size", toJsonSize(iconFontHelper.size())); + return object; + } +}; + +template +struct JsonMap> +{ + typedef QMap MapType; + static MapType value(const QJsonObject &mapObject, const QJsonObject &telescopingMap) + { + typedef typename MapType::key_type KeyType; + typedef typename MapType::mapped_type ValueType; + + QMap output; + QJsonObject curObject = mergeJsons(mapObject, telescopingMap); + const QStringList keyList = curObject.keys(); + QStringList validKeys; + QString keyTypeStr = DesignerIconEnums::keyName; + QJsonObject nextTelescopingMap = telescopingMap; + + for (const QString &jsonKey : keyList) { + bool keyAvailable = false; + DesignerIconEnums::value(jsonKey, &keyAvailable); + if (keyAvailable) + validKeys.append(jsonKey); + else + nextTelescopingMap.insert(jsonKey, curObject.value(jsonKey)); + } + + for (const QString &jsonKey : validKeys) { + bool keyAvailable = false; + const KeyType key = DesignerIconEnums::value(jsonKey, &keyAvailable); + QJsonValue jsonValue = curObject.value(jsonKey); + + nextTelescopingMap.insert(keyTypeStr, jsonKey); + if (!jsonValue.isObject()) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Value of the" << jsonKey << "should be a json object."; + continue; + } + output.insert(key, JsonMap::value(jsonValue.toObject(), nextTelescopingMap)); + } + + return output; + } + + static QJsonObject json(const QMap &map) + { + QJsonObject output; + for (const auto &[key, val] : map.asKeyValueRange()) + output[DesignerIconEnums::toString(key)] = JsonMap::json(val); + + return output; + } +}; + +} // End of blank namespace + +class QmlDesigner::DesignerIconsPrivate +{ +public: + DesignerIconsPrivate(const QString &fontName) + : mFontName(fontName) {} + + QString mFontName; + DesignerIcons::IconsMap icons; + static QCache cache; +}; + +QCache DesignerIconsPrivate::cache(100); + +IconFontHelper::IconFontHelper(Theme::Icon themeIcon, Theme::Color color, const QSize &size, QIcon::Mode mode, QIcon::State state) + : Super(Theme::getIconUnicode(themeIcon), + Theme::getColor(color), + size, + mode, state) + , mThemeIcon(themeIcon) + , mThemeColor(color) +{} + +IconFontHelper IconFontHelper::fromJson(const QJsonObject &jsonObject) +{ + try { + Theme::Icon iconName = jsonSafeMetaEnum(jsonObject); + Theme::Color iconColor = jsonSafeMetaEnum(jsonObject); + QSize iconSize = jsonSafeSize(jsonObject, "size"); + QIcon::Mode iconMode = jsonSafeMetaEnum(jsonObject); + QIcon::State iconState = jsonSafeMetaEnum(jsonObject); + return IconFontHelper(iconName, iconColor, iconSize, iconMode, iconState); + } catch (const Exception &exception) { + exception.showException("Faild to load IconFontHelper"); + return {}; + } +} + +QJsonObject IconFontHelper::toJson() const +{ + QJsonObject jsonObject; + pushSimpleEnumValue(jsonObject, themeIcon()); + pushSimpleEnumValue(jsonObject, themeColor()); + pushSimpleEnumValue(jsonObject, mode()); + pushSimpleEnumValue(jsonObject, state()); + jsonObject.insert("size", toJsonSize(size())); + return jsonObject; +} + +Theme::Icon IconFontHelper::themeIcon() const +{ + return mThemeIcon; +} + +Theme::Color IconFontHelper::themeColor() const +{ + return mThemeColor; +} + +IconFontHelper::IconFontHelper() + : IconFontHelper({}, {}, {}, {}, {}) {} + +DesignerIcons::DesignerIcons(const QString &fontName, const QString &iconDatabase) + : d(new DesignerIconsPrivate(fontName)) +{ + if (iconDatabase.size()) + loadIconSettings(iconDatabase); +} + +DesignerIcons::~DesignerIcons() +{ + delete d; +} + +QIcon DesignerIcons::icon(IconId icon, Area area) const +{ + return Utils::StyleHelper::getIconFromIconFont(d->mFontName, helperList(icon, area)); +} + +void DesignerIcons::loadIconSettings(const QString &fileName) +{ + if (d->cache.contains(fileName)) { + d->icons = *d->cache.object(fileName); + return; + } + + QFile designerIconFile(fileName); + + if (!designerIconFile.open(QFile::ReadOnly)) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can not open file:" << fileName << designerIconFile.errorString(); + return; + } + + if (designerIconFile.size() > 100e3) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Large File:" << fileName; + return; + } + + QJsonParseError parseError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(designerIconFile.readAll(), &parseError); + + if (parseError.error != QJsonParseError::NoError) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Json Parse Error - " << parseError.errorString() << "---\t File: " << fileName; + return; + } + + if (!jsonDoc.isObject()) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Invalid Json Array in file: " << fileName; + return; + } + + clearAll(); + d->icons = JsonMap::value(jsonDoc.object(), {}); + d->cache.insert(fileName, new IconsMap(d->icons), 1); +} + +void DesignerIcons::exportSettings(const QString &fileName) const +{ + QFile outFile(fileName); + if (!outFile.open(QFile::WriteOnly)) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can not open file for writing:" << fileName; + return; + } + + QJsonDocument jsonDocument; + jsonDocument.setObject(JsonMap::json(d->icons)); + + outFile.write(jsonDocument.toJson()); + outFile.close(); +} + +void DesignerIcons::clearAll() +{ + d->icons.clear(); +} + +void DesignerIcons::addIcon(const IconId &iconId, const Area &area, const IconFontHelper &fontHelper) +{ + AreaMap &areaMap = d->icons[iconId]; + IconMap &iconMap = areaMap[area]; + ModeMap &modeMap = iconMap[static_cast(fontHelper.state())]; + modeMap.insert(static_cast(fontHelper.mode()), fontHelper); +} + +void DesignerIcons::addIcon(IconId iconId, + Area area, + QIcon::Mode mode, + QIcon::State state, + Theme::Icon themeIcon, + Theme::Color color, + const QSize &size) +{ + addIcon(iconId, area, {themeIcon, color, size, mode, state}); +} + +void DesignerIcons::addIcon(IconId iconId, Area area, Theme::Icon themeIcon, Theme::Color color, const QSize &size) +{ + addIcon(iconId, area, {themeIcon, color, size}); +} + +QList DesignerIcons::helperList(const IconId &iconId, + const Area &area) const +{ + QList helperList; + const IconMap &iconMap = d->icons.value(iconId).value(area); + for (const ModeMap &modMap : iconMap) { + for (const IconFontHelper &iconFontHelper : modMap) + helperList.append(iconFontHelper); + } + return helperList; +} diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.h b/src/plugins/qmldesigner/components/componentcore/designericons.h new file mode 100644 index 00000000000..342016b77c1 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/designericons.h @@ -0,0 +1,133 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "theme.h" + +#include + +#include + +namespace QmlDesigner { + +class DesignerIconsPrivate; + +class IconFontHelper : public Utils::StyleHelper::IconFontHelper +{ + typedef Utils::StyleHelper::IconFontHelper Super; + +public: + IconFontHelper(Theme::Icon themeIcon, + Theme::Color color, + const QSize &size, + QIcon::Mode mode = QIcon::Normal, + QIcon::State state = QIcon::Off); + + static IconFontHelper fromJson(const QJsonObject &jsonObject); + QJsonObject toJson() const; + Theme::Icon themeIcon() const; + Theme::Color themeColor() const; + +private: + IconFontHelper(); + + Theme::Icon mThemeIcon; + Theme::Color mThemeColor; +}; + +class DesignerIcons +{ + Q_GADGET + friend DesignerIconsPrivate; + +public: + enum IconId { + AddMouseAreaIcon, + AlignBottomIcon, + AlignLeftIcon, + AlignRightIcon, + AlignTopIcon, + AnchorsIcon, + AnnotationIcon, + ArrangeIcon, + ConnectionsIcon, + EditIcon, + EnterComponentIcon, + EventListIcon, + GroupSelectionIcon, + LayoutsIcon, + MakeComponentIcon, + MergeWithTemplateIcon, + PositionsersIcon, + SelecionIcon, + SnappingIcon, + TimelineIcon, + ShowBoundsIcon, + VisibilityIcon + }; + Q_ENUM(IconId) + + enum Area { + TopToolbarArea, + ContextMenuArea + }; + Q_ENUM(Area) + + enum Mode { + Normal = QIcon::Normal, + Disabled = QIcon::Disabled, + Hovered = QIcon::Active, + Selected = QIcon::Selected + }; + + Q_ENUM(Mode) + + enum State { + Off = QIcon::Off, + On = QIcon::On + }; + Q_ENUM(State) + + typedef QMap ModeMap; + typedef QMap IconMap; + typedef QMap AreaMap; + typedef QMap IconsMap; + + explicit DesignerIcons(const QString &fontName, + const QString &iconDatabase = QString()); + + ~DesignerIcons(); + + QIcon icon(IconId icon, Area area) const; + + void loadIconSettings(const QString &fileName); + void exportSettings(const QString &fileName) const; + + void clearAll(); + void addIcon(const IconId &iconId, + const Area &area, + const IconFontHelper &fontHelper); + + void addIcon(IconId iconId, + Area area, + QIcon::Mode mode, + QIcon::State state, + Theme::Icon themeIcon, + Theme::Color color, + const QSize &size); + + void addIcon(IconId iconId, + Area area, + Theme::Icon themeIcon, + Theme::Color color, + const QSize &size); + +private: + QList helperList(const IconId &iconId, + const Area &area) const; + + DesignerIconsPrivate *d = nullptr; +}; + +} diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp index ebe51d8a3a8..2e36fe6f926 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp @@ -60,7 +60,7 @@ void populateMenu(QSet &actionInterfaces, || actionInterface->type() == ActionInterface::FormEditorAction) { QAction* action = actionInterface->action(); actionInterface->currentContextChanged(selectionContext); - action->setIconVisibleInMenu(false); + action->setIconVisibleInMenu(true); menu->addAction(action); } } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h index a32f5e8d154..a948d7479af 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h @@ -141,7 +141,7 @@ public: class ActionGroup : public AbstractActionGroup { public: - ActionGroup(const QString &displayName, const QByteArray &menuId, int priority, + ActionGroup(const QString &displayName, const QByteArray &menuId, const QIcon &icon, int priority, SelectionContextPredicate enabled = &SelectionContextFunctors::always, SelectionContextPredicate visibility = &SelectionContextFunctors::always) : AbstractActionGroup(displayName), @@ -150,6 +150,7 @@ public: m_enabled(enabled), m_visibility(visibility) { + menu()->setIcon(icon); } bool isVisible(const SelectionContext &m_selectionState) const override { return m_visibility(m_selectionState); } diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h index 4864e6e4c94..23b9039ed95 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.h +++ b/src/plugins/qmldesigner/components/componentcore/theme.h @@ -103,6 +103,7 @@ public: gridView, idAliasOff, idAliasOn, + imported, infinity, keyframe, linkTriangle, @@ -131,6 +132,24 @@ public: redo, rotationFill, rotationOutline, + s_anchors, + s_annotations, + s_arrange, + s_boundingBox, + s_component, + s_connections, + s_edit, + s_enterComponent, + s_eventList, + s_group, + s_layouts, + s_merging, + s_mouseArea, + s_positioners, + s_selection, + s_snapping, + s_timeline, + s_visibility, search, sectionToggle, splitColumns, @@ -148,6 +167,14 @@ public: textFullJustification, textNumberedList, tickIcon, + topToolbar_annotations, + topToolbar_closeFile, + topToolbar_designMode, + topToolbar_enterComponent, + topToolbar_home, + topToolbar_makeComponent, + topToolbar_navFile, + topToolbar_runProject, translationCreateFiles, translationCreateReport, translationExport, diff --git a/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp b/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp index f45d609d927..9124d65475f 100644 --- a/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp +++ b/src/plugins/qmldesigner/components/eventlist/eventlistpluginview.cpp @@ -3,6 +3,7 @@ #include "eventlistpluginview.h" #include "assigneventdialog.h" #include "connectsignaldialog.h" +#include "designericons.h" #include "eventlistactions.h" #include "eventlistdialog.h" @@ -45,6 +46,7 @@ void EventListPluginView::registerActions() designerActionManager.addDesignerAction(new ActionGroup(tr("Event List"), ComponentCoreConstants::eventListCategory, + designerActionManager.contextIcon(DesignerIcons::EventListIcon), ComponentCoreConstants::Priorities::EventListCategory, &SelectionContextFunctors::always, &SelectionContextFunctors::always)); diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index 331f7fbe97b..07638ba5389 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -3,6 +3,7 @@ #include "formeditorwidget.h" #include "designeractionmanager.h" +#include "designericons.h" #include "designersettings.h" #include "formeditoritem.h" #include "formeditorscene.h" @@ -104,6 +105,7 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) m_showBoundingRectAction = new QAction(tr("Show Bounds"), this); m_showBoundingRectAction->setCheckable(true); m_showBoundingRectAction->setChecked(false); + m_showBoundingRectAction->setIcon(DesignerActionManager::instance().contextIcon(DesignerIcons::ShowBoundsIcon)); registerActionAsCommand(m_showBoundingRectAction, Constants::FORMEDITOR_NO_SHOW_BOUNDING_RECTANGLE, QKeySequence(Qt::Key_A), diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp index 6249ce94484..13958695d08 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelineview.cpp @@ -3,6 +3,7 @@ #include "timelineview.h" +#include "designericons.h" #include "easingcurve.h" #include "timelineactions.h" #include "timelineconstants.h" @@ -584,6 +585,7 @@ void TimelineView::registerActions() actionManager.addDesignerAction(new ActionGroup(TimelineConstants::timelineCategoryDisplayName, TimelineConstants::timelineCategory, + actionManager.contextIcon(DesignerIcons::TimelineIcon), ComponentCoreConstants::Priorities::TimelineCategory, timelineEnabled, &SelectionContextFunctors::always)); diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp index fb7296ec947..3ff9242ce5c 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.cpp @@ -40,6 +40,7 @@ QmlPreviewWidgetPlugin::QmlPreviewWidgetPlugin() designerActionManager.addDesignerAction(new ActionGroup( QString(), ComponentCoreConstants::qmlPreviewCategory, + {}, ComponentCoreConstants::Priorities::QmlPreviewCategory, &SelectionContextFunctors::always)); s_previewPlugin = getPreviewPlugin();