diff --git a/src/controls/private/ActionToolBarLayoutDetails.qml b/src/controls/private/ActionToolBarLayoutDetails.qml index 99b9e64d..53b76a16 100644 --- a/src/controls/private/ActionToolBarLayoutDetails.qml +++ b/src/controls/private/ActionToolBarLayoutDetails.qml @@ -1,160 +1,178 @@ /* * SPDX-FileCopyrightText: 2018 Marco Martin * SPDX-FileCopyrightText: 2019 Arjen Hiemstra * * SPDX-License-Identifier: LGPL-2.0-or-later */ import QtQuick 2.7 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.4 as Controls import org.kde.kirigami 2.5 as Kirigami /** * This fairly complex thing determines the layout of ActionToolBar, that is, * which actions should be displayed in full width toolbutton form, which should * be displayed in an icon-only reduced size and which should be placed in the * overflow menu. * * It makes use of two fairly static layouts, one contains all actions in expanded * full-size form, the other in reduced icon-only form. The items in these layouts * determine if they should be visible based on their relative position and size * and some properties of the action. The update function then goes through these * items, adding the actions to the relevant lists, so they can be used by the * ActionToolBar to determine which action should be visible in what state. * * The reason for using two separate layouts from ActionToolBar's main layout is * so that we can use the actual geometry of the buttons to calculate the * visibility, completely disregarding any other layouting quirks. We can then * use that information so only the relevant things in the ActionToolBar are * visible. This allows the main ActionToolBar to use normal layout features for * things like the positioning of the visible actions. */ Item { id: details property var actions property var visibleActions: [] property var hiddenActions: [] property var iconOnlyActions: [] property bool flat: false property int display: Controls.Button.TextBesideIcon property real spacing: Kirigami.Units.smallSpacing property real leftPadding: 0 property real rightPadding: 0 property real iconOnlyWidth: 0 readonly property real iconLayoutWidth: width - rightPadding readonly property real fullLayoutWidth: iconLayoutWidth - iconOnlyWidth readonly property real maximumWidth: fullSizePlaceholderLayout.width + leftPadding + rightPadding enabled: false opacity: 0 // Cannot use visible: false because then relayout doesn't happen correctly function update() { var visible = [] var hidden = [] var iconOnly = [] var iconsWidth = 0 for (var i = 0; i < root.actions.length; ++i) { var item = fullSizePlaceholderRepeater.itemAt(i) var iconOnlyItem = iconOnlyPlaceholderRepeater.itemAt(i) if (item.actionVisible) { visible.push(item.kirigamiAction) } else if (iconOnlyItem.actionVisible) { visible.push(item.kirigamiAction) iconOnly.push(item.kirigamiAction) iconsWidth += iconOnlyItem.width + details.spacing } else { hidden.push(item.kirigamiAction) } } visibleActions = visible hiddenActions = hidden iconOnlyActions = iconOnly iconOnlyWidth = iconsWidth } onWidthChanged: Qt.callLater(update) Component.onCompleted: Qt.callLater(update) RowLayout { id: fullSizePlaceholderLayout spacing: details.spacing // This binding is here to take care of things like visibility changes onWidthChanged: Qt.callLater(details.update) Repeater { id: fullSizePlaceholderRepeater model: details.actions Loader { property var kirigamiAction: modelData sourceComponent: { if (modelData.displayComponent && !modelData.displayHintSet(Kirigami.Action.DisplayHint.IconOnly)) { return modelData.displayComponent } return toolButtonDelegate } - visible: (modelData.visible === undefined || modelData.visible) - && (modelData.displayHint !== undefined && !modelData.displayHintSet(Kirigami.Action.DisplayHint.AlwaysHide)) + visible: { + if (modelData.hasOwnProperty("visible") && !modelData.visible) { + return false + } + + if (modelData.hasOwnProperty("displayHint") && + modelData.displayHintSet(Kirigami.Action.DisplayHint.AlwaysHide)) { + return false + } + + return true + } property bool actionVisible: visible && (x + width < details.fullLayoutWidth) onLoaded: { if (sourceComponent == toolButtonDelegate) { item.kirigamiAction = modelData } } } } } Component { id: toolButtonDelegate PrivateActionToolButton { flat: details.flat && !kirigamiAction.icon.color.a display: details.display menu.actions: { if (kirigamiAction.displayComponent && kirigamiAction.displayHintSet(Kirigami.Action.DisplayHint.IconOnly)) { return [kirigamiAction] } if (kirigamiAction.children) { return kirigamiAction.children } return [] } } } RowLayout { id: iconOnlyPlaceholderLayout spacing: details.spacing Repeater { id: iconOnlyPlaceholderRepeater model: details.actions PrivateActionToolButton { flat: details.flat && !modelData.icon.color.a display: Controls.Button.IconOnly - visible: (modelData.visible === undefined || modelData.visible) - && (modelData.displayHint !== undefined && modelData.displayHintSet(Kirigami.Action.DisplayHint.KeepVisible)) + visible: { + if (modelData.hasOwnProperty("visible") && !modelData.visible) { + return false + } + if (modelData.hasOwnProperty("displayHint") + && modelData.displayHintSet(Kirigami.Action.DisplayHint.KeepVisible)) { + return true + } + return false + } kirigamiAction: modelData property bool actionVisible: visible && (iconOnlyPlaceholderRepeater.count === 1 || (x + width < details.iconLayoutWidth)) } } } } diff --git a/src/controls/private/PrivateActionToolButton.qml b/src/controls/private/PrivateActionToolButton.qml index eaf1c8f4..dced4c1b 100644 --- a/src/controls/private/PrivateActionToolButton.qml +++ b/src/controls/private/PrivateActionToolButton.qml @@ -1,131 +1,131 @@ /* * SPDX-FileCopyrightText: 2016 Marco Martin * * SPDX-License-Identifier: LGPL-2.0-or-later */ import QtQuick 2.7 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.4 as Controls import org.kde.kirigami 2.4 Controls.ToolButton { id: control signal menuAboutToShow implicitWidth: menuArrow.visible || (showText && ( kirigamiAction ? kirigamiAction.text.length > 0 : text.length > 0)) ? Math.max(layout.implicitWidth + Units.largeSpacing*2, background.implicitWidth) : implicitHeight Theme.colorSet: Theme.Button Theme.inherit: kirigamiAction && kirigamiAction.icon.color.a === 0 Theme.backgroundColor: kirigamiAction && kirigamiAction.icon.color.a ? kirigamiAction.icon.color : undefined Theme.textColor: kirigamiAction && !flat && kirigamiAction.icon.color.a ? Theme.highlightedTextColor : undefined hoverEnabled: true flat: !control.kirigamiAction || !control.kirigamiAction.icon.color.a //TODO: replace with upstream action when we depend on Qt 5.10 //TODO: upstream action makes the style to re-draw the content, it'd be ideal except for the custom dropDown icon needed for actionsMenu property Controls.Action kirigamiAction property bool showText: !(kirigamiAction && kirigamiAction.displayHint !== undefined && kirigamiAction.displayHintSet(Action.DisplayHint.IconOnly)) property bool showMenuArrow: !(kirigamiAction && kirigamiAction.displayHint !== undefined && kirigamiAction.displayHintSet(Action.DisplayHint.HideChildIndicator)) property alias menu: menu //we need our own text delegate text: "" checkable: (kirigamiAction && kirigamiAction.checkable) || (menu.actions && menu.actions.length > 0) checked: (kirigamiAction && kirigamiAction.checked) enabled: kirigamiAction && kirigamiAction.enabled opacity: enabled ? 1 : 0.4 - visible: kirigamiAction && kirigamiAction.visible + visible: (kirigamiAction && kirigamiAction.hasOwnProperty("visible")) ? kirigamiAction.visible : true onClicked: { if (kirigamiAction) { kirigamiAction.trigger(); } } onToggled: { if (menu.actions.length > 0) { if (checked) { control.menuAboutToShow(); menu.popup(control, 0, control.height) } else { menu.dismiss() } } } ActionsMenu { id: menu y: control.height actions: control.kirigamiAction && kirigamiAction.hasOwnProperty("children") ? control.kirigamiAction.children : null // Important: We handle the press on parent in the parent, so ignore it here. closePolicy: Controls.Popup.CloseOnEscape | Controls.Popup.CloseOnPressOutsideParent submenuComponent: Component { ActionsMenu {} } onClosed: { control.checked = false } } contentItem: MouseArea { hoverEnabled: true onPressed: mouse.accepted = false Theme.colorSet: checked && (control.kirigamiAction && control.kirigamiAction.icon.color.a) ? Theme.Selection : control.Theme.colorSet Theme.inherit: control.kirigamiAction && Theme.colorSet != Theme.Selection && control.kirigamiAction.icon.color.a === 0 implicitWidth: layout.implicitWidth implicitHeight: layout.implicitHeight GridLayout { id: layout columns: control.display == Controls.ToolButton.TextUnderIcon ? 1 : 2 + (menuArrow.visible ? 1 : 0) rows: control.display == Controls.ToolButton.TextUnderIcon ? 2 : 1 anchors.centerIn: parent Icon { id: mainIcon Layout.alignment: Qt.AlignCenter Layout.minimumWidth: Units.iconSizes.smallMedium Layout.minimumHeight: Units.iconSizes.smallMedium source: control.kirigamiAction ? (control.kirigamiAction.icon ? control.kirigamiAction.icon.name : control.kirigamiAction.iconName) : "" visible: control.kirigamiAction && control.kirigamiAction.iconName != "" && control.display != Controls.ToolButton.TextOnly color: control.flat && control.kirigamiAction && control.kirigamiAction.icon && control.kirigamiAction.icon.color.a > 0 ? control.kirigamiAction.icon.color : label.color } Controls.Label { id: label MnemonicData.enabled: control.enabled MnemonicData.controlType: MnemonicData.ActionElement MnemonicData.label: control.kirigamiAction ? control.kirigamiAction.text : "" text: MnemonicData.richTextLabel visible: control.showText && text.length > 0 && control.display != Controls.ToolButton.IconOnly Shortcut { sequence: label.MnemonicData.sequence onActivated: control.clicked() } } Icon { id: menuArrow Layout.minimumWidth: Units.iconSizes.small Layout.minimumHeight: Units.iconSizes.small color: mainIcon.color source: "arrow-down" visible: showMenuArrow && menu.actions && menu.actions.length > 0 } } } Controls.ToolTip { visible: control.hovered && text.length > 0 && !menu.visible && !control.pressed - text: kirigamiAction ? (kirigamiAction.tooltip.length ? kirigamiAction.tooltip : kirigamiAction.text) : "" + text: kirigamiAction ? (kirigamiAction.tooltip && kirigamiAction.tooltip.length ? kirigamiAction.tooltip : kirigamiAction.text) : "" delay: Units.toolTipDelay timeout: 5000 y: control.height } }