diff --git a/src/controls/ActionToolBar.qml b/src/controls/ActionToolBar.qml index ea1f3c92..22dc4b2b 100644 --- a/src/controls/ActionToolBar.qml +++ b/src/controls/ActionToolBar.qml @@ -1,213 +1,213 @@ /* * Copyright 2018 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.2 as Controls import org.kde.kirigami 2.5 as Kirigami import "private" /** * This is a simple toolbar built out of a list of actions * each action is represented by a ToolButton, those that won't fit * the size will go in a menu under a button with the overflow ... icon * * @inherits Item * @since 2.5 */ Item { id: root /** * actions: list * if the card should provide clickable actions, put them in this property, * they will be put in the footer as a list of ToolButtons plus an optional * overflow menu, when not all of them will fit in the available Card width. */ property list actions /** * actions: hiddenActions * This list of actions is for those you always want in the menu, even if there * is enough space. * @since 2.6 */ property list hiddenActions /** * flat: bool * Wether we want our buttons to have a flat appearance. Default: true */ property bool flat: true /** * display: enum * This controls the label position regarding the icon, is the same value to control individual Button components, * permitted values are: * * Button.IconOnly * * Button.TextOnly * * Button.TextBesideIcon * * Button.TextUnderIcon */ property int display: Controls.Button.TextBesideIcon /** * position enum * This property holds the position of the toolbar. * if this ActionToolBar is the contentItem of a QQC2 Toolbar, the position is binded to the ToolBar's position * * permitted values are: * *ToolBar.Header: The toolbar is at the top, as a window or page header. * *ToolBar.Footer: The toolbar is at the bottom, as a window or page footer. */ property int position: parent && parent.hasOwnProperty("position") ? parent.position - : Controls.ToolBar.Footer + : Controls.ToolBar.Header implicitHeight: actionsLayout.implicitHeight implicitWidth: actionsLayout.implicitWidth Layout.minimumWidth: moreButton.implicitWidth Layout.fillWidth: true RowLayout { id: actionsLayout anchors.fill: parent //anchors.rightMargin: moreButton.width spacing: Kirigami.Units.smallSpacing property var overflowSet: [] // TODO use Array.findIndex once we depend on Qt 5.9 function findIndex(array, cb) { for (var i = 0, length = array.length; i < length; ++i) { if (cb(array[i])) { return i; } } return -1; } RowLayout { Layout.minimumWidth: 0 Layout.fillHeight: true Repeater { model: root.actions delegate: PrivateActionToolButton { id: actionDelegate flat: root.flat opacity: x + width <= parent.width display: root.display visible: modelData.visible Layout.fillWidth: false Layout.alignment: Qt.AlignVCenter Layout.minimumWidth: implicitWidth kirigamiAction: modelData onOpacityChanged: updateOverflowSet() function updateOverflowSet() { var index = actionsLayout.findIndex(actionsLayout.overflowSet, function(act) { return act === modelData}); if ((opacity > 0 || !modelData.visible) && index > -1) { actionsLayout.overflowSet.splice(index, 1); } else if (opacity === 0 && modelData.visible && index === -1) { actionsLayout.overflowSet.push(modelData); } actionsLayout.overflowSetChanged(); } Connections { target: modelData onVisibleChanged: actionDelegate.updateOverflowSet(); } Component.onCompleted: { actionDelegate.updateOverflowSet(); } } } } Item { Layout.fillWidth: true visible: root.Layout.fillWidth } Controls.ToolButton { id: moreButton Layout.alignment: Qt.AlignRight Kirigami.Icon { anchors.centerIn: parent source: "overflow-menu" width: Kirigami.Units.iconSizes.smallMedium height: width } //checkable: true checked: menu.visible visible: hiddenActions.length > 0 || actionsLayout.overflowSet.length > 0; onClicked: menu.visible ? menu.close() : menu.open() ActionsMenu { id: menu y: root.position == Controls.ToolBar.Footer ? -height : moreButton.height x: -width + moreButton.width actions: root.actions submenuComponent: Component { ActionsMenu {} } itemDelegate: ActionMenuItem { visible: actionsLayout.findIndex(actionsLayout.overflowSet, function(act) {return act === ourAction}) > -1 && (ourAction.visible === undefined || ourAction.visible) } Instantiator { model: root.hiddenActions delegate: QtObject { readonly property QtObject action: modelData property QtObject item: null Component.onDestruction: if (item) item.destroy() function create() { if (!action.children || action.children.length === 0) { item = menu.itemDelegate.createObject(null, { ourAction: action }); menu.addItem(item) } else if (menu.submenuComponent) { item = menu.submenuComponent.createObject(null, { title: action.text, actions: action.children }); menu.addMenu(item) } //break the binding item.visible = true; } function remove() { if (!action.children || action.children.length === 0) { menu.removeItem(item) } else if (menu.submenuComponent) { menu.removeMenu(item) } } } onObjectAdded: object.create() onObjectRemoved: object.remove() } } } } } diff --git a/src/controls/Card.qml b/src/controls/Card.qml index 67d8dc61..f5f893fd 100644 --- a/src/controls/Card.qml +++ b/src/controls/Card.qml @@ -1,108 +1,109 @@ /* * Copyright 2018 Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.6 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.0 as Controls import org.kde.kirigami 2.5 as Kirigami import "private" /** * This is the standard layout of a Card. * It is recommended to use this class when the concept of Cards is needed * in the application. * This Card has default items as header and footer. The header is an * image that can contain an optional title and icon, accessible via the * banner grouped property. * The footer will show a series of toolbuttons (and eventual overflow menu) * representing the actions list accessible with the list property actions. * It is possible even tough is discouraged to override the footer: * in this case the actions property shouldn't be used. * * @inherits AbstractCard * @since 2.4 */ Kirigami.AbstractCard { id: root /** * actions: list * if the card should provide clickable actions, put them in this property, * they will be put in the footer as a list of ToolButtons plus an optional * overflow menu, when not all of them will fit in the available Card width. */ property list actions /** * actions: hiddenActions * This list of actions is for those you always want in the menu, even if there * is enough space. * @since 2.6 */ property list hiddenActions /** * banner: Image * Gropuped property to control the banner image present in the header, it * has the following sub properties: * * url source: the source for the image, it understands any url * valid for an Image component * * string title: the title for the banner, shown as contrasting * text over the image * * Qt.Alignment titleAlignment: the alignment of the title inside the image, * a combination of flags is supported * (default: Qt.AlignTop | Qt.AlignLeft) * * string titleIcon: the optional icon to put in the banner: * it can be either a freedesktop-compatible icon name (recommended) * or any url supported by Image * * titleLevel: The Kirigami Heading level for the title, it controls the font size, default 1 * * wrapMode: if the header should be able to do wrapping * * It also has the full set of properties a QML Image has, such as sourceSize and fillMode */ readonly property alias banner: bannerImage header: BannerImage { id: bannerImage anchors.leftMargin: -root.leftPadding anchors.topMargin: -root.topPadding anchors.rightMargin: root.headerOrientation == Qt.Vertical ? -root.rightPadding : 0 anchors.bottomMargin: root.headerOrientation == Qt.Horizontal ? -root.bottomPadding : 0 height: Layout.preferredHeight implicitWidth: root.headerOrientation == Qt.Horizontal ? sourceSize.width : Layout.preferredWidth } onHeaderChanged: { if (!header) { return; } header.anchors.leftMargin = Qt.binding(function() {return -root.leftPadding}); header.anchors.topMargin = Qt.binding(function() {return -root.topPadding}); header.anchors.rightMargin = Qt.binding(function() {return root.headerOrientation == Qt.Vertical ? -root.rightPadding : 0}); header.anchors.bottomMargin = Qt.binding(function() {return root.headerOrientation == Qt.Horizontal ? -root.bottomPadding : 0}); } footer: Kirigami.ActionToolBar { id: actionsToolBar actions: root.actions + position: Controls.ToolBar.Footer hiddenActions: root.hiddenActions visible: root.footer == actionsToolBar } }