forked from qt-creator/qt-creator
QmlDesigner: Add some states view improvements
- Added a gray border around unselected states. - States resize to fit view height. - States are centered vertically in the view. - Removed collapse option, auto collapse when space is small. - scroll bar always at the bottom. - Overshoot list ends. - Added margins around the states. - Add states button: make it small and docked to the bottom right. - Add states button doesnt take space from the view. Change-Id: I4fc96f4341a6e4a0c70509240b7aed9c7890ec4d Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Samuel Ghinet <samuel.ghinet@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -33,11 +33,8 @@ import StudioTheme 1.0 as StudioTheme
|
||||
Rectangle {
|
||||
id: myRoot
|
||||
|
||||
color: baseColor
|
||||
|
||||
property bool isBaseState
|
||||
property bool isCurrentState
|
||||
property color baseColor
|
||||
property string delegateStateName
|
||||
property string delegateStateImageSource
|
||||
property bool delegateHasWhenCondition
|
||||
@@ -47,14 +44,14 @@ Rectangle {
|
||||
property int bottomAreaHeight
|
||||
property int stateMargin
|
||||
property int previewMargin
|
||||
property int columnSpacing
|
||||
|
||||
readonly property bool isDefaultState: isDefault
|
||||
|
||||
property int closeButtonMargin: 6
|
||||
property int textFieldMargin: 4
|
||||
|
||||
signal delegateInteraction
|
||||
property int scrollBarH: 0
|
||||
property int listMargin: 0
|
||||
|
||||
function autoComplete(text, pos, explicitComplete, filter) {
|
||||
var stringList = statesEditorModel.autoComplete(text, pos, explicitComplete)
|
||||
@@ -65,14 +62,19 @@ Rectangle {
|
||||
return statesEditorModel.hasAnnotation(internalNodeId)
|
||||
}
|
||||
|
||||
color: isCurrentState ? StudioTheme.Values.themeInteraction
|
||||
: StudioTheme.Values.themeControlBackgroundInteraction
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenterOffset: -.5 * (scrollBarH + listMargin)
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
focus = true
|
||||
root.currentStateInternalId = internalNodeId
|
||||
contextMenu.dismiss() // close potentially open context menu
|
||||
myRoot.delegateInteraction()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +91,6 @@ Rectangle {
|
||||
visible: !isBaseState && isCurrentState
|
||||
|
||||
onClicked: {
|
||||
myRoot.delegateInteraction()
|
||||
if (isDefaultState)
|
||||
statesEditorModel.resetDefaultState()
|
||||
|
||||
@@ -254,9 +255,8 @@ Rectangle {
|
||||
|
||||
Rectangle { // separator
|
||||
width: column.width
|
||||
height: myRoot.columnSpacing
|
||||
height: 2
|
||||
color: StudioTheme.Values.themeStateSeparator
|
||||
visible: expanded
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -264,7 +264,6 @@ Rectangle {
|
||||
width: myRoot.width - 2 * myRoot.stateMargin
|
||||
height: myRoot.bottomAreaHeight
|
||||
color: StudioTheme.Values.themeStateBackground
|
||||
visible: expanded
|
||||
|
||||
Image {
|
||||
anchors.fill: stateImageBackground
|
||||
|
@@ -33,27 +33,24 @@ import StudioTheme 1.0 as StudioTheme
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
property int delegateTopAreaHeight: StudioTheme.Values.height + 8
|
||||
property int delegateBottomAreaHeight: delegateHeight - 2 * delegateStateMargin - delegateTopAreaHeight - delegateColumnSpacing
|
||||
property int delegateColumnSpacing: 2
|
||||
property int delegateStateMargin: 16
|
||||
property int delegatePreviewMargin: 10
|
||||
property int effectiveHeight: root.expanded ? Math.max(85, Math.min(287, root.height)) : 85 // height of the states area
|
||||
readonly property int delegateTopAreaHeight: StudioTheme.Values.height + 8
|
||||
readonly property int delegateBottomAreaHeight: delegateHeight - 2 * delegateStateMargin - delegateTopAreaHeight - 2
|
||||
readonly property int delegateStateMargin: 16
|
||||
readonly property int delegatePreviewMargin: 10
|
||||
readonly property int effectiveHeight: root.height < 130 ? 89 : Math.min(root.height, 287)
|
||||
|
||||
readonly property int scrollBarH: statesListView.ScrollBar.horizontal.scrollBarVisible ? StudioTheme.Values.scrollBarThickness : 0
|
||||
readonly property int listMargin: 10
|
||||
readonly property int delegateWidth: 264
|
||||
readonly property int delegateHeight: Math.max(effectiveHeight - scrollBarH - 2 * listMargin, 69)
|
||||
readonly property int innerSpacing: 2
|
||||
|
||||
property int currentStateInternalId: 0
|
||||
|
||||
signal createNewState
|
||||
signal deleteState(int internalNodeId)
|
||||
signal duplicateCurrentState
|
||||
|
||||
property int padding: 2
|
||||
property int delegateWidth: 264
|
||||
property int delegateHeight: effectiveHeight
|
||||
- StudioTheme.Values.scrollBarThickness
|
||||
- 2 * (root.padding + StudioTheme.Values.border)
|
||||
property int innerSpacing: 2
|
||||
property int currentStateInternalId: 0
|
||||
|
||||
property bool expanded: true
|
||||
|
||||
Connections {
|
||||
target: statesEditorModel
|
||||
function onChangedToState(n) { root.currentStateInternalId = n }
|
||||
@@ -65,69 +62,32 @@ FocusScope {
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
onClicked: function(mouse) {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
contextMenu.dismiss()
|
||||
focus = true
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
contextMenu.popup()
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.Menu {
|
||||
id: contextMenu
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: root.expanded ? qsTr("Collapse") : qsTr("Expand")
|
||||
onTriggered: root.expanded = !root.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractButton {
|
||||
id: addStateButton
|
||||
|
||||
buttonIcon: root.expanded ? qsTr("Create New State") : StudioTheme.Constants.plus
|
||||
iconFont: root.expanded ? StudioTheme.Constants.font : StudioTheme.Constants.iconFont
|
||||
iconSize: root.expanded ? StudioTheme.Values.myFontSize : StudioTheme.Values.myIconFontSize
|
||||
iconItalic: root.expanded
|
||||
buttonIcon: StudioTheme.Constants.plus
|
||||
iconFont: StudioTheme.Constants.iconFont
|
||||
iconSize: StudioTheme.Values.myIconFontSize
|
||||
tooltip: qsTr("Add a new state.")
|
||||
visible: canAddNewStates
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
y: (Math.min(effectiveHeight, root.height) - height) / 2
|
||||
width: root.expanded ? 140 : 18
|
||||
height: root.expanded ? 60 : 18
|
||||
anchors.rightMargin: 4
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 4 + scrollBarH
|
||||
width: 30
|
||||
height: 30
|
||||
|
||||
onClicked: {
|
||||
contextMenu.dismiss()
|
||||
root.createNewState()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { // separator lines between state items
|
||||
color: StudioTheme.Values.themeStateSeparator
|
||||
x: root.padding
|
||||
y: root.padding
|
||||
width: statesListView.width
|
||||
height: root.delegateHeight
|
||||
onClicked: root.createNewState()
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: statesListView
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
clip: true
|
||||
|
||||
x: root.padding
|
||||
y: root.padding
|
||||
width: Math.min(root.delegateWidth * statesListView.count + root.innerSpacing * (statesListView.count - 1),
|
||||
root.width - addStateButton.width - root.padding - 16) // 16 = 2 * 8 (addStateButton margin)
|
||||
height: root.delegateHeight + StudioTheme.Values.scrollBarThickness
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: listMargin
|
||||
anchors.leftMargin: listMargin
|
||||
anchors.rightMargin: listMargin
|
||||
|
||||
model: statesEditorModel
|
||||
orientation: ListView.Horizontal
|
||||
@@ -139,20 +99,18 @@ FocusScope {
|
||||
height: root.delegateHeight
|
||||
isBaseState: 0 === internalNodeId
|
||||
isCurrentState: root.currentStateInternalId === internalNodeId
|
||||
baseColor: isCurrentState ? StudioTheme.Values.themeInteraction : background.color
|
||||
delegateStateName: stateName
|
||||
delegateStateImageSource: stateImageSource
|
||||
delegateHasWhenCondition: hasWhenCondition
|
||||
delegateWhenConditionString: whenConditionString
|
||||
onDelegateInteraction: contextMenu.dismiss()
|
||||
|
||||
columnSpacing: root.delegateColumnSpacing
|
||||
topAreaHeight: root.delegateTopAreaHeight
|
||||
bottomAreaHeight: root.delegateBottomAreaHeight
|
||||
stateMargin: root.delegateStateMargin
|
||||
previewMargin: root.delegatePreviewMargin
|
||||
scrollBarH: root.scrollBarH
|
||||
listMargin: root.listMargin
|
||||
}
|
||||
|
||||
ScrollBar.horizontal: HorizontalScrollBar {}
|
||||
}
|
||||
}
|
||||
|
@@ -85,12 +85,6 @@ void StatesEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorV
|
||||
checkForStatesAvailability();
|
||||
}
|
||||
|
||||
void StatesEditorView::toggleStatesViewExpanded()
|
||||
{
|
||||
if (m_statesEditorWidget)
|
||||
m_statesEditorWidget->toggleStatesViewExpanded();
|
||||
}
|
||||
|
||||
void StatesEditorView::removeState(int nodeId)
|
||||
{
|
||||
try {
|
||||
@@ -102,6 +96,22 @@ void StatesEditorView::removeState(int nodeId)
|
||||
if (modelState.isValid()) {
|
||||
QStringList lockedTargets;
|
||||
const auto propertyChanges = modelState.propertyChanges();
|
||||
|
||||
// confirm removing not empty states
|
||||
if (!propertyChanges.isEmpty()) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setTextFormat(Qt::RichText);
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setWindowTitle(tr("Remove State"));
|
||||
msgBox.setText(tr("This state is not empty. Are you sure you want to remove it?"));
|
||||
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
|
||||
msgBox.setDefaultButton(QMessageBox::Yes);
|
||||
|
||||
if (msgBox.exec() == QMessageBox::Cancel)
|
||||
return;
|
||||
}
|
||||
|
||||
// confirm removing states with locked targets
|
||||
for (const QmlPropertyChanges &change : propertyChanges) {
|
||||
const ModelNode target = change.target();
|
||||
QTC_ASSERT(target.isValid(), continue);
|
||||
|
@@ -87,8 +87,6 @@ public:
|
||||
|
||||
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
|
||||
|
||||
void toggleStatesViewExpanded();
|
||||
|
||||
public slots:
|
||||
void synchonizeCurrentStateFromWidget();
|
||||
void createNewState();
|
||||
|
@@ -133,13 +133,6 @@ QString StatesEditorWidget::qmlSourcesPath()
|
||||
return Core::ICore::resourcePath("qmldesigner/statesEditorQmlSources").toString();
|
||||
}
|
||||
|
||||
void StatesEditorWidget::toggleStatesViewExpanded()
|
||||
{
|
||||
QTC_ASSERT(rootObject(), return);
|
||||
bool expanded = rootObject()->property("expanded").toBool();
|
||||
rootObject()->setProperty("expanded", !expanded);
|
||||
}
|
||||
|
||||
void StatesEditorWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
QQuickWidget::showEvent(event);
|
||||
@@ -168,18 +161,6 @@ void StatesEditorWidget::reloadQmlSource()
|
||||
connect(rootObject(), SIGNAL(createNewState()), m_statesEditorView.data(), SLOT(createNewState()));
|
||||
connect(rootObject(), SIGNAL(deleteState(int)), m_statesEditorView.data(), SLOT(removeState(int)));
|
||||
m_statesEditorView.data()->synchonizeCurrentStateFromWidget();
|
||||
|
||||
if (!DesignerSettings::getValue(DesignerSettingsKey::STATESEDITOR_EXPANDED).toBool())
|
||||
toggleStatesViewExpanded();
|
||||
|
||||
connect(rootObject(), SIGNAL(expandedChanged()), this, SLOT(handleExpandedChanged()));
|
||||
}
|
||||
|
||||
void StatesEditorWidget::handleExpandedChanged()
|
||||
{
|
||||
QTC_ASSERT(rootObject(), return);
|
||||
|
||||
bool expanded = rootObject()->property("expanded").toBool();
|
||||
DesignerSettings::setValue(DesignerSettingsKey::STATESEDITOR_EXPANDED, expanded);
|
||||
}
|
||||
}
|
||||
} // QmlDesigner
|
||||
|
@@ -57,14 +57,11 @@ public:
|
||||
|
||||
static QString qmlSourcesPath();
|
||||
|
||||
void toggleStatesViewExpanded();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *) override;
|
||||
|
||||
private:
|
||||
void reloadQmlSource();
|
||||
Q_SLOT void handleExpandedChanged();
|
||||
|
||||
private:
|
||||
QPointer<StatesEditorView> m_statesEditorView;
|
||||
|
@@ -94,8 +94,6 @@ public:
|
||||
DesignerActionManager &designerActionManager();
|
||||
const DesignerActionManager &designerActionManager() const;
|
||||
|
||||
void toggleStatesViewExpanded();
|
||||
|
||||
void qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const;
|
||||
DesignDocument *currentDesignDocument() const;
|
||||
|
||||
|
@@ -405,11 +405,6 @@ const DesignerActionManager &ViewManager::designerActionManager() const
|
||||
return d->designerActionManagerView.designerActionManager();
|
||||
}
|
||||
|
||||
void ViewManager::toggleStatesViewExpanded()
|
||||
{
|
||||
d->statesEditorView.toggleStatesViewExpanded();
|
||||
}
|
||||
|
||||
void ViewManager::qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const
|
||||
{
|
||||
d->textEditorView.qmlJSEditorContextHelp(callback);
|
||||
|
@@ -72,7 +72,6 @@ void DesignerSettings::fromSettings(QSettings *settings)
|
||||
restoreValue(settings, DesignerSettingsKey::FORWARD_PUPPET_OUTPUT, QString());
|
||||
restoreValue(settings, DesignerSettingsKey::REFORMAT_UI_QML_FILES, true);
|
||||
restoreValue(settings, DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO, false);
|
||||
restoreValue(settings, DesignerSettingsKey::STATESEDITOR_EXPANDED, true);
|
||||
restoreValue(settings, DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS, true);
|
||||
restoreValue(settings, DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, false);
|
||||
restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false);
|
||||
|
@@ -60,7 +60,6 @@ const char ENABLE_MODEL_EXCEPTION_OUTPUT[] = "WarnException";
|
||||
const char PUPPET_KILL_TIMEOUT[] = "PuppetKillTimeout";
|
||||
const char DEBUG_PUPPET[] = "DebugPuppet";
|
||||
const char FORWARD_PUPPET_OUTPUT[] = "ForwardPuppetOutput";
|
||||
const char STATESEDITOR_EXPANDED[] = "StatesEditorExpanded";
|
||||
const char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems";
|
||||
const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder";
|
||||
const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */
|
||||
|
@@ -69,7 +69,6 @@ ShortCutManager::ShortCutManager()
|
||||
m_copyAction(tr("&Copy")),
|
||||
m_pasteAction(tr("&Paste")),
|
||||
m_selectAllAction(tr("Select &All")),
|
||||
m_collapseExpandStatesAction(tr("Toggle States")),
|
||||
m_escapeAction(this)
|
||||
{
|
||||
|
||||
@@ -97,10 +96,6 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
|
||||
|
||||
connect(&m_selectAllAction,&QAction::triggered, this, &ShortCutManager::selectAll);
|
||||
|
||||
connect(&m_collapseExpandStatesAction, &QAction::triggered, [] {
|
||||
QmlDesignerPlugin::instance()->viewManager().toggleStatesViewExpanded();
|
||||
});
|
||||
|
||||
// Revert to saved
|
||||
Core::EditorManager *em = Core::EditorManager::instance();
|
||||
Core::ActionManager::registerAction(&m_revertToSavedAction,Core::Constants::REVERTTOSAVED, qmlDesignerMainContext);
|
||||
@@ -188,13 +183,6 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
|
||||
command->setDefaultKeySequence(QKeySequence::SelectAll);
|
||||
editMenu->addAction(command, Core::Constants::G_EDIT_SELECTALL);
|
||||
|
||||
Core::ActionContainer *viewsMenu = Core::ActionManager::actionContainer(Core::Constants::M_VIEW_VIEWS);
|
||||
|
||||
command = Core::ActionManager::registerAction(&m_collapseExpandStatesAction, Constants::TOGGLE_STATES_EDITOR, qmlDesignerMainContext);
|
||||
command->setAttribute(Core::Command::CA_Hide);
|
||||
command->setDefaultKeySequence(QKeySequence("Ctrl+Alt+s"));
|
||||
viewsMenu->addAction(command);
|
||||
|
||||
/* Registering disabled action for Escape, because Qt Quick does not support shortcut overrides. */
|
||||
command = Core::ActionManager::registerAction(&m_escapeAction, Core::Constants::S_RETURNTOEDITOR, qmlDesignerMainContext);
|
||||
command->setDefaultKeySequence(QKeySequence(Qt::Key_Escape));
|
||||
|
@@ -83,7 +83,6 @@ private:
|
||||
QAction m_copyAction;
|
||||
QAction m_pasteAction;
|
||||
QAction m_selectAllAction;
|
||||
QAction m_collapseExpandStatesAction;
|
||||
QAction m_escapeAction;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user