diff --git a/.gitignore b/.gitignore index 005acb4..f950fa0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ -build/ +build* update-translations.sh +*.kdev4 diff --git a/generate_code.sh b/generate_code.sh new file mode 100755 index 0000000..9c85fc9 --- /dev/null +++ b/generate_code.sh @@ -0,0 +1,65 @@ +#!/usr/bin/bash + +itemTitles=("Buttons" "Icon" "Title" "Menu") + +settingsLines="" +for name in ${itemTitles[@]}; do + settingsLines="$settingsLines\n property alias cfg_controlPart${name}Position: controlPart${name}Position.currentIndex" + settingsLines="$settingsLines\n property alias cfg_controlPart${name}ShowOnMouseIn: controlPart${name}ShowOnMouseIn.checked" + settingsLines="$settingsLines\n property alias cfg_controlPart${name}ShowOnMouseOut: controlPart${name}ShowOnMouseOut.checked" + settingsLines="$settingsLines\n property alias cfg_controlPart${name}HorizontalAlignment: controlPart${name}HorizontalAlignment.currentIndex\n" +done + +echo -e "$settingsLines" + +controlLines="" +for name in ${itemTitles[@]}; do + controlLines="$controlLines + Item { + width: 2 + height: units.smallSpacing + Layout.columnSpan: 2 + } + + Label { + text: i18n('${name}') + font.bold: true + Layout.columnSpan: 2 + } + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPart${name}Position + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + CheckBox { + id: controlPart${name}ShowOnMouseIn + text: i18n('Show on mouse in') + Layout.columnSpan: 2 + } + + CheckBox { + id: controlPart${name}ShowOnMouseOut + text: i18n('Show on mouse out') + Layout.columnSpan: 2 + } + + Label { + text: i18n('Horizontal alignment:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPart${name}HorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } + +" +done + +echo -e "$controlLines" diff --git a/package/contents/config/config.qml b/package/contents/config/config.qml index f798d17..1966dd9 100644 --- a/package/contents/config/config.qml +++ b/package/contents/config/config.qml @@ -1,30 +1,35 @@ import QtQuick 2.2 import org.kde.plasma.configuration 2.0 ConfigModel { + ConfigCategory { + name: i18n("Layout") + icon: "preferences-desktop-color" + source: "config/ConfigLayout.qml" + } ConfigCategory { name: i18n("Appearance") icon: "preferences-desktop-color" source: "config/ConfigAppearance.qml" } ConfigCategory { name: i18n("Behaviour") icon: "preferences-desktop" source: "config/ConfigBehaviour.qml" } ConfigCategory { name: i18n("Buttons") icon: "preferences-activities" source: "config/ConfigButtons.qml" } ConfigCategory { name: i18n("Mouse Control") icon: "preferences-desktop-mouse" source: "config/ConfigMouseControl.qml" } ConfigCategory { name: i18n("Application Menu") icon: "application-menu" source: "config/ConfigAppMenu.qml" } } diff --git a/package/contents/config/main.xml b/package/contents/config/main.xml index fae991c..d1559e2 100644 --- a/package/contents/config/main.xml +++ b/package/contents/config/main.xml @@ -1,207 +1,275 @@ + + + buttons|icon|title|menu + + + 5.0 + + + 0 + + + true + + + true + + + 0 + + + 0 + + + true + + + true + + + 0 + + + 0 + + + true + + + true + + + 0 + + + 0 + + + true + + + true + + + 0 + + + + true false false false close|maximize|minimize|pin true false false false false false false 0 false 0.5 10 false 0.2 0.0 true 0 0 0 false ^(.*)\s*[—–\-:]\s*(Mozilla )?([^—–\-:]+)$ $3 — $1 Plasma Desktop :: %activity% false 1000 true false false 5 1 false false false false false false false false true false 0 0.1 1.0 true 0 0 false 0 diff --git a/package/contents/ui/AppMenu.qml b/package/contents/ui/AppMenu.qml index 35dcd79..eb4df62 100644 --- a/package/contents/ui/AppMenu.qml +++ b/package/contents/ui/AppMenu.qml @@ -1,176 +1,179 @@ import QtQuick 2.2 import QtQuick.Layouts 1.1 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.components 2.0 as PlasmaComponents Item { id: appmenu anchors.fill: parent + property bool mouseInWidget: false + property bool appmenuEnabled: plasmoid.configuration.appmenuEnabled property bool appmenuNextToButtons: plasmoid.configuration.appmenuNextToButtons property bool appmenuFillHeight: plasmoid.configuration.appmenuFillHeight property bool appmenuFontBold: plasmoid.configuration.appmenuFontBold property bool appmenuDoNotHide: plasmoid.configuration.appmenuDoNotHide property bool appmenuEnabledAndNonEmpty: appmenuEnabled && appMenuModel !== null && appMenuModel.menuAvailable property bool appmenuOpened: appmenuEnabled && plasmoid.nativeInterface.currentIndex > -1 property var appMenuModel: null property bool appmenuButtonsOffsetEnabled: !buttonsStandalone && appmenuNextToButtons && childrenRect.width > 0 property double appmenuOffsetWidth: visible && appmenuNextToIconAndText && !appmenuSwitchSidesWithIconAndText - ? appmenu.childrenRect.width + (appmenuButtonsOffsetEnabled ? controlButtonsArea.width : 0) + appmenuSideMargin*2 + ? appmenu.childrenRect.width + (appmenuButtonsOffsetEnabled ? buttonsItem.width : 0) + appmenuSideMargin*2 : 0 - visible: appmenuEnabledAndNonEmpty && !noWindowActive && (appmenuDoNotHide || mouseHover || appmenuOpened) + visible: appmenuEnabledAndNonEmpty && !noWindowActive && (appmenuDoNotHide || main.mouseHover || appmenuOpened) GridLayout { id: buttonGrid Layout.minimumWidth: implicitWidth Layout.minimumHeight: implicitHeight flow: GridLayout.LeftToRight rowSpacing: 0 columnSpacing: 0 anchors.top: parent.top anchors.left: parent.left - property double placementOffsetButtons: appmenuNextToButtons && controlButtonsArea.visible ? controlButtonsArea.width + appmenuSideMargin : 0 + property double placementOffsetButtons: appmenuNextToButtons && buttonsItem.visible ? buttonsItem.width + appmenuSideMargin : 0 property double placementOffset: appmenuNextToIconAndText && appmenuSwitchSidesWithIconAndText - ? activeWindowListView.anchors.leftMargin + windowTitleText.anchors.leftMargin + windowTitleText.contentWidth + appmenuSideMargin + //? activeWindowListView.anchors.leftMargin + windowTitle.anchors.leftMargin + + ? windowTitle.anchors.leftMargin + windowTitle.contentWidthwindowTitle.contentWidth + appmenuSideMargin : placementOffsetButtons anchors.leftMargin: (bp === 1 || bp === 3) ? parent.width - width - placementOffset : placementOffset anchors.topMargin: (bp === 2 || bp === 3) ? 0 : parent.height - height Component.onCompleted: { plasmoid.nativeInterface.buttonGrid = buttonGrid plasmoid.nativeInterface.enabled = appmenuEnabled } Connections { target: plasmoid.nativeInterface onRequestActivateIndex: { var idx = Math.max(0, Math.min(buttonRepeater.count - 1, index)) var button = buttonRepeater.itemAt(index) if (button) { button.clicked(null) } } } Repeater { id: buttonRepeater model: null MouseArea { id: appmenuButton hoverEnabled: true readonly property int buttonIndex: index property bool menuOpened: plasmoid.nativeInterface.currentIndex === index Layout.preferredWidth: appmenuButtonBackground.width Layout.preferredHeight: appmenuButtonBackground.height Rectangle { id: appmenuButtonBackground border.color: 'transparent' width: appmenuButtonTitle.implicitWidth + units.smallSpacing * 3 height: appmenuFillHeight ? appmenu.height : appmenuButtonTitle.implicitHeight + units.smallSpacing color: menuOpened ? theme.highlightColor : 'transparent' radius: units.smallSpacing / 2 } PlasmaComponents.Label { id: appmenuButtonTitle anchors.top: appmenuButtonBackground.top anchors.bottom: appmenuButtonBackground.bottom verticalAlignment: Text.AlignVCenter anchors.horizontalCenter: appmenuButtonBackground.horizontalCenter font.pixelSize: fontPixelSize * plasmoid.configuration.appmenuButtonTextSizeScale text: activeMenu.replace('&', '') font.weight: appmenuFontBold ? Font.Bold : theme.defaultFont.weight } onClicked: { plasmoid.nativeInterface.trigger(this, index) } onEntered: { appmenuButtonBackground.border.color = theme.highlightColor } onExited: { appmenuButtonBackground.border.color = 'transparent' } } } } Rectangle { id: separator anchors.left: buttonGrid.left anchors.leftMargin: appmenuSwitchSidesWithIconAndText ? - appmenuSideMargin * 0.5 : buttonGrid.width + appmenuSideMargin * 0.5 anchors.verticalCenter: buttonGrid.verticalCenter height: 0.8 * parent.height width: 1 visible: appmenuNextToIconAndText && plasmoid.configuration.appmenuSeparatorEnabled color: theme.textColor opacity: 0.4 } function initializeAppModel() { if (appMenuModel !== null) { return } print('initializing appMenuModel...') try { appMenuModel = Qt.createQmlObject( 'import QtQuick 2.2;\ import org.kde.plasma.plasmoid 2.0;\ import org.kde.private.activeWindowControl 1.0 as ActiveWindowControlPrivate;\ ActiveWindowControlPrivate.AppMenuModel {\ id: appMenuModel;\ Component.onCompleted: {\ plasmoid.nativeInterface.model = appMenuModel\ }\ }', main) } catch (e) { print('appMenuModel failed to initialize: ' + e) } print('initializing appmenu...DONE ' + appMenuModel) if (appMenuModel !== null) { resetAppmenuModel() } } function resetAppmenuModel() { if (appmenuEnabled) { initializeAppModel() if (appMenuModel === null) { return } print('setting model in QML: ' + appMenuModel) for (var key in appMenuModel) { print(' ' + key + ' -> ' + appMenuModel[key]) } plasmoid.nativeInterface.model = appMenuModel buttonRepeater.model = appMenuModel } else { plasmoid.nativeInterface.model = null buttonRepeater.model = null } } onAppmenuEnabledChanged: { appmenu.resetAppmenuModel() if (appMenuModel !== null) { plasmoid.nativeInterface.enabled = appmenuEnabled } } } \ No newline at end of file diff --git a/package/contents/ui/ControlButton.qml b/package/contents/ui/ControlButton.qml index cb87f03..9458eaa 100644 --- a/package/contents/ui/ControlButton.qml +++ b/package/contents/ui/ControlButton.qml @@ -1,69 +1,74 @@ /* * Copyright 2015 Martin Kotelnik * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.2 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore MouseArea { id: controlButton - height: controlButtonsArea.height - width: controlButtonsArea.controlButtonsHeight + height: controlButtons.height + width: controlButtons.controlButtonsHeight property bool mouseInside: false property bool iconActive: (iconName !== 'alldesktops' && iconName !== 'maximize') || (iconName === 'alldesktops' && main.isActiveWindowPinned) || (iconName === 'maximize' && main.currentWindowMaximized) property string themeName: textColorLight ? 'breeze-dark' : 'default' property string customAuroraeThemePath: main.automaticButtonThemeEnabled ? plasmoid.nativeInterface.auroraeThemePath : manualAuroraeThemePathResolved property string customAuroraeImageExt: main.automaticButtonThemeEnabled ? plasmoid.nativeInterface.auroraeThemeType : manualAuroraeThemeExtension property bool usingAuroraeTheme: customAuroraeThemePath ? true : false property string buttonImagePath: customAuroraeThemePath ? customAuroraeThemePath + '/' + iconName + '.' + customAuroraeImageExt : Qt.resolvedUrl('../icons/' + themeName + '/' + iconName + '.svg') property string svgElementId: usingAuroraeTheme ? (iconActive && iconName === 'alldesktops') ? (mouseInside ? 'pressed-center' : 'pressed-center') : (mouseInside ? 'hover-center' : 'active-center') : iconActive ? (mouseInside ? 'active-hover' : 'active-idle') : (mouseInside ? 'inactive-hover' : 'inactive-idle') PlasmaCore.Svg { id: buttonSvg imagePath: buttonImagePath } // icon PlasmaCore.SvgItem { id: svgItem width: parent.width height: width svg: buttonSvg elementId: svgElementId anchors.verticalCenter: parent.verticalCenter } hoverEnabled: true onEntered: { mouseInside = true + controlButtons.mouseInWidget = true } onExited: { mouseInside = false + controlButtons.mouseInWidget = false } // trigger active window action onClicked: { - controlButtonsArea.mouseInWidget = true + if (!controlButtons.showItem) { + return; + } + controlButtons.mouseInWidget = true main.performActiveWindowAction(windowOperation) } } diff --git a/package/contents/ui/ControlButtons.qml b/package/contents/ui/ControlButtons.qml new file mode 100644 index 0000000..4599e53 --- /dev/null +++ b/package/contents/ui/ControlButtons.qml @@ -0,0 +1,37 @@ +import QtQuick 2.2 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +Item { + id: controlButtons + + property bool mouseInWidget: false + property var controlButtonsModel + + property double controlButtonsHeight: parent.height * plasmoid.configuration.buttonSize + property bool showItem + + opacity: showItem ? 1 : 0 + + height: main.buttonsVerticalCenter ? parent.height : controlButtonsHeight + width: controlButtonsHeight + ((model.count - 1) * (controlButtonsHeight + main.controlButtonsSpacing)) + + ListView { + + orientation: ListView.Horizontal + + spacing: main.controlButtonsSpacing + + visible: true + + model: controlButtonsModel + + anchors.fill: parent + + delegate: ControlButton { } + + } +} + diff --git a/package/contents/ui/WindowIcon.qml b/package/contents/ui/WindowIcon.qml new file mode 100644 index 0000000..554fcae --- /dev/null +++ b/package/contents/ui/WindowIcon.qml @@ -0,0 +1,15 @@ +import QtQuick 2.2 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +PlasmaCore.IconItem { + id: iconItem + + width: parent.height + height: parent.height + + source: plasmoid.configuration.noWindowIcon + visible: plasmoid.configuration.showWindowIcon +} diff --git a/package/contents/ui/WindowTitle.qml b/package/contents/ui/WindowTitle.qml new file mode 100644 index 0000000..5e246d1 --- /dev/null +++ b/package/contents/ui/WindowTitle.qml @@ -0,0 +1,49 @@ +import QtQuick 2.2 +import QtGraphicalEffects 1.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +PlasmaComponents.Label { + id: titleItem + + property double iconMargin: (plasmoid.configuration.showWindowIcon ? iconItem.width : 0) + property double properWidth: parent.width - iconMargin - iconAndTextSpacing + property double properHeight: parent.height + property bool noElide: fitText === 2 || (fitText === 1 && mouseHover) + property int allowFontSizeChange: 3 + property int minimumPixelSize: 8 + property bool limitTextWidth: plasmoid.configuration.limitTextWidth + property int textWidthLimit: plasmoid.configuration.textWidthLimit + property double computedWidth: (limitTextWidth ? (implicitWidth > textWidthLimit ? textWidthLimit : implicitWidth) : properWidth)// - activeWindowListView.buttonsBetweenAddition + + verticalAlignment: Text.AlignVCenter + text: plasmoid.configuration.noWindowText + wrapMode: Text.Wrap + width: computedWidth + elide: noElide ? Text.ElideNone : Text.ElideRight + visible: plasmoid.configuration.showWindowTitle + font.pixelSize: fontPixelSize + font.pointSize: -1 + font.weight: fontBold || (appmenuBoldTitleWhenMenuDisplayed && appmenu.visible) ? Font.Bold : theme.defaultFont.weight + font.family: fontFamily || theme.defaultFont.family + + onTextChanged: { + font.pixelSize = fontPixelSize + allowFontSizeChange = 3 + } + + onNoElideChanged: { + font.pixelSize = fontPixelSize + allowFontSizeChange = 3 + } + + onPaintedHeightChanged: { + if (allowFontSizeChange > 0 && noElide && paintedHeight > properHeight) { + var newPixelSize = (properHeight / paintedHeight) * fontPixelSize + font.pixelSize = newPixelSize < minimumPixelSize ? minimumPixelSize : newPixelSize + } + allowFontSizeChange-- + } +} \ No newline at end of file diff --git a/package/contents/ui/config/ConfigButtons.qml b/package/contents/ui/config/ConfigButtons.qml index b9ae6aa..787bc47 100644 --- a/package/contents/ui/config/ConfigButtons.qml +++ b/package/contents/ui/config/ConfigButtons.qml @@ -1,313 +1,317 @@ import QtQuick 2.2 import QtQuick.Controls 1.3 import QtQuick.Layouts 1.1 import QtQml.Models 2.1 Item { property alias cfg_showControlButtons: showControlButtons.checked property alias cfg_doNotHideControlButtons: doNotHideControlButtons.checked property int cfg_buttonsPosition property alias cfg_buttonsVerticalCenter: buttonsVerticalCenter.checked property alias cfg_buttonsStandalone: buttonsStandalone.checked property alias cfg_buttonsBetweenIconAndText: buttonsBetweenIconAndText.checked property alias cfg_buttonsDynamicWidth: buttonsDynamicWidth.checked property alias cfg_slidingIconAndText: slidingIconAndText.checked property alias cfg_showButtonOnlyWhenMaximized: showButtonOnlyWhenMaximized.checked property alias cfg_showMinimize: showMinimize.checked property alias cfg_showMaximize: showMaximize.checked property alias cfg_showPinToAllDesktops: showPinToAllDesktops.checked property alias cfg_buttonSize: buttonSize.value property alias cfg_controlButtonsSpacing: controlButtonsSpacing.value property string cfg_buttonOrder property alias cfg_automaticButtonThemeEnabled: automaticButtonThemeEnabled.checked property alias cfg_customAuroraeThemePath: customAuroraeThemePath.text onCfg_buttonsPositionChanged: { switch (cfg_buttonsPosition) { case 0: buttonsPositionGroup.current = upperLeftRadio; break; case 1: buttonsPositionGroup.current = upperRightRadio; break; case 2: buttonsPositionGroup.current = bottomLeftRadio; break; case 3: buttonsPositionGroup.current = bottomRightRadio; break; default: buttonsPositionGroup.current = upperLeftRadio; } } Component.onCompleted: { cfg_buttonsPositionChanged() sortButtonOrder() } ListModel { id: buttonsToSpend ListElement { - text: "close" + name: 'close' + iconName: 'close' } ListElement { - text: "minimize" + name: 'minimize' + iconName: 'minimize' } ListElement { - text: "maximize" + name: 'maximize' + iconName: 'maximize' } ListElement { - text: "alldesktops" + name: 'alldesktops' + iconName: 'alldesktops' } } function sortButtonOrder() { - cfg_buttonOrder.split('|').forEach(function (buttonName, index) { - if (buttonName === 'close') { - print('adding ' + buttonName); + cfg_buttonOrder.split('|').forEach(function (itemId, index) { + if (itemId === 'close') { + print('adding ' + itemId); buttonOrder.model.insert(index, buttonsToSpend.get(0)); - } else if (buttonName === 'minimize') { + } else if (itemId === 'minimize') { buttonOrder.model.insert(index, buttonsToSpend.get(1)); - print('adding ' + buttonName); - } else if (buttonName === 'maximize') { + print('adding ' + itemId); + } else if (itemId === 'maximize') { buttonOrder.model.insert(index, buttonsToSpend.get(2)); - print('adding ' + buttonName); - } else if (buttonName === 'pin' || buttonName === 'alldesktops') { + print('adding ' + itemId); + } else if (itemId === 'pin' || itemId === 'alldesktops') { buttonOrder.model.insert(index, buttonsToSpend.get(3)); - print('adding ' + buttonName); + print('adding ' + itemId); } }); } ExclusiveGroup { id: buttonsPositionGroup } GroupBox { id: showControlButtons title: i18n("Enable Control Buttons") checkable: true flat: true GridLayout { columns: 2 Item { width: 2 height: 10 Layout.columnSpan: 2 } Item { width: 2 height: 2 Layout.rowSpan: 3 } CheckBox { id: showMinimize text: i18n("Show minimize button") } CheckBox { id: showMaximize text: i18n("Show maximize button") } CheckBox { id: showPinToAllDesktops text: i18n("Show pin to all desktops") } Item { width: 2 height: 10 Layout.columnSpan: 2 } Label { text: i18n("Button order:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } OrderableListView { id: buttonOrder height: units.gridUnit * 2 width: height * 4 model: ListModel { // will be filled initially by sortButtonOrder() method } orientation: ListView.Horizontal itemWidth: width / 4 itemHeight: itemWidth onModelOrderChanged: { var orderStr = ''; for (var i = 0; i < model.count; i++) { var item = model.get(i) if (orderStr.length > 0) { orderStr += '|'; } - orderStr += item.text; + orderStr += item.name; } cfg_buttonOrder = orderStr; print('written: ' + cfg_buttonOrder); } } Item { width: 2 height: 10 Layout.columnSpan: 2 } Label { text: i18n("Behaviour:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } CheckBox { id: doNotHideControlButtons text: i18n("Do not hide on mouse out") } Item { width: 2 height: 2 Layout.rowSpan: 5 } CheckBox { id: showButtonOnlyWhenMaximized text: i18n("Show only when maximized") } CheckBox { id: buttonsStandalone text: i18n("Buttons next to icon and text") } CheckBox { id: buttonsBetweenIconAndText text: i18n("Buttons between icon and text") enabled: buttonsStandalone.checked } CheckBox { id: buttonsDynamicWidth text: i18n("Dynamic width") enabled: buttonsStandalone.checked } CheckBox { id: slidingIconAndText text: i18n("Sliding icon and text") enabled: buttonsStandalone.checked } Item { width: 2 height: 10 Layout.columnSpan: 2 } Label { text: i18n("Position:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } RadioButton { id: upperLeftRadio exclusiveGroup: buttonsPositionGroup text: i18n("Upper left") onCheckedChanged: if (checked) cfg_buttonsPosition = 0; } Item { width: 2 height: 2 Layout.rowSpan: 4 } RadioButton { id: upperRightRadio exclusiveGroup: buttonsPositionGroup text: i18n("Upper right") onCheckedChanged: if (checked) cfg_buttonsPosition = 1; } RadioButton { id: bottomLeftRadio exclusiveGroup: buttonsPositionGroup text: i18n("Bottom left") onCheckedChanged: if (checked) cfg_buttonsPosition = 2; } RadioButton { id: bottomRightRadio exclusiveGroup: buttonsPositionGroup text: i18n("Bottom right") onCheckedChanged: if (checked) cfg_buttonsPosition = 3; } CheckBox { id: buttonsVerticalCenter text: i18n("Vertical center") } Item { width: 2 height: 10 Layout.columnSpan: 2 } Label { text: i18n("Button size:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } Slider { id: buttonSize stepSize: 0.1 minimumValue: 0.1 tickmarksEnabled: true width: parent.width } Label { text: i18n("Buttons spacing:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } Slider { id: controlButtonsSpacing stepSize: 1 minimumValue: 0 maximumValue: 20 tickmarksEnabled: true width: parent.width } Item { width: 2 height: 10 Layout.columnSpan: 2 } Label { text: i18n("Theme") Layout.columnSpan: parent.columns font.bold: true } CheckBox { id: automaticButtonThemeEnabled text: i18n("Automatic") } TextField { id: customAuroraeThemePath placeholderText: i18n("Absolute path to aurorae button theme folder") Layout.preferredWidth: 350 onTextChanged: cfg_customAuroraeThemePath = text enabled: !automaticButtonThemeEnabled.checked } } } } diff --git a/package/contents/ui/config/ConfigLayout.qml b/package/contents/ui/config/ConfigLayout.qml new file mode 100644 index 0000000..c29784c --- /dev/null +++ b/package/contents/ui/config/ConfigLayout.qml @@ -0,0 +1,318 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.3 +import QtQuick.Layouts 1.1 +import QtQml.Models 2.1 + +Item { + + property string cfg_controlPartOrder + property alias cfg_controlPartSpacing: controlPartSpacing.value + + // GENERATED config (start) + property alias cfg_controlPartButtonsPosition: controlPartButtonsPosition.currentIndex + property alias cfg_controlPartButtonsShowOnMouseIn: controlPartButtonsShowOnMouseIn.checked + property alias cfg_controlPartButtonsShowOnMouseOut: controlPartButtonsShowOnMouseOut.checked + property alias cfg_controlPartButtonsHorizontalAlignment: controlPartButtonsHorizontalAlignment.currentIndex + + property alias cfg_controlPartIconPosition: controlPartIconPosition.currentIndex + property alias cfg_controlPartIconShowOnMouseIn: controlPartIconShowOnMouseIn.checked + property alias cfg_controlPartIconShowOnMouseOut: controlPartIconShowOnMouseOut.checked + property alias cfg_controlPartIconHorizontalAlignment: controlPartIconHorizontalAlignment.currentIndex + + property alias cfg_controlPartTitlePosition: controlPartTitlePosition.currentIndex + property alias cfg_controlPartTitleShowOnMouseIn: controlPartTitleShowOnMouseIn.checked + property alias cfg_controlPartTitleShowOnMouseOut: controlPartTitleShowOnMouseOut.checked + property alias cfg_controlPartTitleHorizontalAlignment: controlPartTitleHorizontalAlignment.currentIndex + + property alias cfg_controlPartMenuPosition: controlPartMenuPosition.currentIndex + property alias cfg_controlPartMenuShowOnMouseIn: controlPartMenuShowOnMouseIn.checked + property alias cfg_controlPartMenuShowOnMouseOut: controlPartMenuShowOnMouseOut.checked + property alias cfg_controlPartMenuHorizontalAlignment: controlPartMenuHorizontalAlignment.currentIndex + // GENERATED config (end) + + ListModel { + id: partsToSpend + ListElement { + name: 'icon' + text: 'Icon' + } + ListElement { + name: 'title' + text: 'Title' + } + ListElement { + name: 'buttons' + text: 'Buttons' + } + ListElement { + name: 'menu' + text: 'Menu' + } + } + + function sortPartOrder() { + buttonOrder.model.clear() + cfg_controlPartOrder.split('|').forEach(function (itemId, index) { + var partIndex = -1 + print('adding ' + itemId); + if (itemId === 'icon') { + partIndex = 0 + } else if (itemId === 'title') { + partIndex = 1 + } else if (itemId === 'buttons') { + partIndex = 2 + } else if (itemId === 'menu') { + partIndex = 3 + } + if (partIndex >= 0) { + buttonOrder.model.append(partsToSpend.get(partIndex)); + } + }); + print('model count: ' + buttonOrder.model.count) + } + + GridLayout { + columns: 3 + + Label { + text: i18n("Item order:") + } + + OrderableListView { + id: buttonOrder + Layout.columnSpan: 2 + itemHeight: units.gridUnit * 2 + itemWidth: units.gridUnit * 4 + height: itemHeight + width: itemWidth * 4 + model: ListModel { + // will be filled initially by sortButtonOrder() method + } + orientation: ListView.Horizontal + + onModelOrderChanged: { + var orderStr = ''; + for (var i = 0; i < model.count; i++) { + var item = model.get(i) + if (orderStr.length > 0) { + orderStr += '|'; + } + orderStr += item.name; + } + cfg_controlPartOrder = orderStr; + print('written: ' + cfg_controlPartOrder); + } + } + + Label { + text: i18n("Item spacing:") + } + SpinBox { + id: controlPartSpacing + decimals: 1 + stepSize: 0.5 + minimumValue: 0.5 + maximumValue: 300 + Layout.columnSpan: 2 + } + + // GENERATED controls (start) + GridLayout { + columns: 2 + + Item { + width: 2 + height: units.largeSpacing + Layout.columnSpan: 2 + } + + Label { + text: i18n('Buttons') + font.bold: true + Layout.columnSpan: 2 + } + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartButtonsPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + CheckBox { + id: controlPartButtonsShowOnMouseIn + text: i18n('Show on mouse in') + Layout.columnSpan: 2 + } + + CheckBox { + id: controlPartButtonsShowOnMouseOut + text: i18n('Show on mouse out') + Layout.columnSpan: 2 + } + + Label { + text: i18n('Horizontal alignment:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartButtonsHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } + + + Item { + width: 2 + height: units.largeSpacing + Layout.columnSpan: 2 + } + + Label { + text: i18n('Icon') + font.bold: true + Layout.columnSpan: 2 + } + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartIconPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + CheckBox { + id: controlPartIconShowOnMouseIn + text: i18n('Show on mouse in') + Layout.columnSpan: 2 + } + + CheckBox { + id: controlPartIconShowOnMouseOut + text: i18n('Show on mouse out') + Layout.columnSpan: 2 + } + + Label { + text: i18n('Horizontal alignment:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartIconHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } + } + + Item { + width: units.largeSpacing + height: units.largeSpacing + } + + GridLayout { + columns: 2 + + Item { + width: 2 + height: units.largeSpacing + Layout.columnSpan: 2 + } + + Label { + text: i18n('Title') + font.bold: true + Layout.columnSpan: 2 + } + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartTitlePosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + CheckBox { + id: controlPartTitleShowOnMouseIn + text: i18n('Show on mouse in') + Layout.columnSpan: 2 + } + + CheckBox { + id: controlPartTitleShowOnMouseOut + text: i18n('Show on mouse out') + Layout.columnSpan: 2 + } + + Label { + text: i18n('Horizontal alignment:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartTitleHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } + + + Item { + width: 2 + height: units.largeSpacing + Layout.columnSpan: 2 + } + + Label { + text: i18n('Menu') + font.bold: true + Layout.columnSpan: 2 + } + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartMenuPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + CheckBox { + id: controlPartMenuShowOnMouseIn + text: i18n('Show on mouse in') + Layout.columnSpan: 2 + } + + CheckBox { + id: controlPartMenuShowOnMouseOut + text: i18n('Show on mouse out') + Layout.columnSpan: 2 + } + + Label { + text: i18n('Horizontal alignment:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + + ComboBox { + id: controlPartMenuHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } + } + // GENERATED controls (end) + + } + + Component.onCompleted: { + sortPartOrder() + } + +} diff --git a/package/contents/ui/config/OrderableListView.qml b/package/contents/ui/config/OrderableListView.qml index 2ffa887..01b44d7 100644 --- a/package/contents/ui/config/OrderableListView.qml +++ b/package/contents/ui/config/OrderableListView.qml @@ -1,63 +1,87 @@ import QtQuick 2.6 import QtQuick.Controls 1.3 +import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore Item { id: mainContent property var model property int orientation property double itemWidth property double itemHeight property bool interactive width: itemWidth * (orientation == ListView.Vertical ? 1 : model.count) height: itemHeight * (orientation == ListView.Horizontal ? 1 : model.count) SystemPalette { id: palette } // theme + svg property bool textColorLight: ((palette.text.r + palette.text.g + palette.text.b) / 3) > 0.5 property string themeName: textColorLight ? 'breeze-dark' : 'default' signal modelOrderChanged() ListView { id: listView anchors.fill: parent model: mainContent.model orientation: mainContent.orientation delegate: OrderableItem { listViewParent: listView.parent Item { - height: itemWidth - width: itemHeight + height: itemHeight + width: itemWidth PlasmaCore.Svg { id: buttonSvg - imagePath: Qt.resolvedUrl('../../icons/' + themeName + '/' + model.text + '.svg') + imagePath: Qt.resolvedUrl('../../icons/' + themeName + '/' + model.iconName + '.svg') + } + + // item border + Rectangle { + border.width: 1 + border.color: theme.textColor + radius: units.gridUnit / 4 + color: 'transparent' + opacity: 0.5 + anchors.fill: parent } // icon PlasmaCore.SvgItem { id: svgItem - anchors.fill: parent + anchors.left: parent.left + anchors.top: parent.top + anchors.bottom: parent.bottom width: parent.width height: width svg: buttonSvg elementId: 'active-idle' + visible: !!model.iconName + } + + // text + Label { + text: model.text + anchors.fill: parent + anchors.leftMargin: svgItem.visible ? svgItem.width + units.smallSpacing : 0 + visible: !!model.text + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter } } onMoveItemRequested: { mainContent.model.move(from, to, 1); mainContent.modelOrderChanged() } } } } diff --git a/package/contents/ui/main.qml b/package/contents/ui/main.qml index 2014542..abc1c3a 100644 --- a/package/contents/ui/main.qml +++ b/package/contents/ui/main.qml @@ -1,632 +1,696 @@ /* * Copyright 2015 Martin Kotelnik * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.2 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.1 import QtQuick.Window 2.2 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.taskmanager 0.1 as TaskManager import org.kde.activities 0.1 as Activities Item { id: main property bool vertical: (plasmoid.formFactor == PlasmaCore.Types.Vertical) property double horizontalScreenWidthPercent: plasmoid.configuration.horizontalScreenWidthPercent - property double buttonSize: plasmoid.configuration.buttonSize +// property double buttonSize: plasmoid.configuration.buttonSize property bool autoFillWidth: plasmoid.configuration.autoFillWidth - property double widthForHorizontalPanel: (Screen.width * horizontalScreenWidthPercent + plasmoid.configuration.widthFineTuning) - ((!controlButtonsArea.visible && buttonsStandalone && plasmoid.configuration.buttonsDynamicWidth) ? controlButtonsArea.width : 0) + property double widthForHorizontalPanel: (Screen.width * horizontalScreenWidthPercent + plasmoid.configuration.widthFineTuning) - ((!buttonsItem.visible && buttonsStandalone && plasmoid.configuration.buttonsDynamicWidth) ? buttonsItem.width : 0) anchors.fill: parent Layout.fillWidth: plasmoid.configuration.autoFillWidth Layout.preferredWidth: autoFillWidth ? -1 : (vertical ? parent.width : (widthForHorizontalPanel > 0 ? widthForHorizontalPanel : 0.0001)) Layout.minimumWidth: Layout.preferredWidth Layout.maximumWidth: Layout.preferredWidth Layout.preferredHeight: parent === null ? 0 : vertical ? Math.min(theme.defaultFont.pointSize * 4, parent.width) : parent.height Layout.minimumHeight: Layout.preferredHeight Layout.maximumHeight: Layout.preferredHeight property int textType: plasmoid.configuration.textType property int fitText: plasmoid.configuration.fitText property int tooltipTextType: plasmoid.configuration.tooltipTextType property string tooltipText: '' property bool windowIconOnTheRight: plasmoid.configuration.windowIconOnTheRight property double iconAndTextSpacing: plasmoid.configuration.iconAndTextSpacing property bool slidingIconAndText: plasmoid.configuration.slidingIconAndText property double fontPixelSize: theme.defaultFont.pixelSize * plasmoid.configuration.fontSizeScale property bool fontBold: plasmoid.configuration.boldFontWeight property string fontFamily: plasmoid.configuration.fontFamily property bool noWindowActive: true property bool currentWindowMaximized: false property bool canShowButtonsAccordingMaximized: showButtonOnlyWhenMaximized ? currentWindowMaximized : true property int controlButtonsSpacing: plasmoid.configuration.controlButtonsSpacing property int bp: plasmoid.configuration.buttonsPosition; property bool buttonsVerticalCenter: plasmoid.configuration.buttonsVerticalCenter property bool showControlButtons: plasmoid.configuration.showControlButtons property bool showButtonOnlyWhenMaximized: plasmoid.configuration.showButtonOnlyWhenMaximized property bool showMinimize: showControlButtons && plasmoid.configuration.showMinimize property bool showMaximize: showControlButtons && plasmoid.configuration.showMaximize property bool showPinToAllDesktops: showControlButtons && plasmoid.configuration.showPinToAllDesktops property string buttonOrder: plasmoid.configuration.buttonOrder property bool doubleClickMaximizes: plasmoid.configuration.doubleClickMaximizes property int leftClickAction: plasmoid.configuration.leftClickAction property string chosenLeftClickSource: leftClickAction === 1 ? shortcutDS.presentWindows : leftClickAction === 2 ? shortcutDS.presentWindowsAll : leftClickAction === 3 ? shortcutDS.presentWindowsClass : '' property bool middleClickClose: plasmoid.configuration.middleClickAction === 1 property bool middleClickFullscreen: plasmoid.configuration.middleClickAction === 2 property bool wheelUpMaximizes: plasmoid.configuration.wheelUpMaximizes property bool wheelDownMinimizes: plasmoid.configuration.wheelDownAction === 1 property bool wheelDownUnmaximizes: plasmoid.configuration.wheelDownAction === 2 property bool buttonsStandalone: showControlButtons && plasmoid.configuration.buttonsStandalone property bool buttonsBetweenIconAndText: buttonsStandalone && plasmoid.configuration.buttonsBetweenIconAndText property bool doNotHideControlButtons: showControlButtons && plasmoid.configuration.doNotHideControlButtons property bool textColorLight: ((theme.textColor.r + theme.textColor.g + theme.textColor.b) / 3) > 0.5 property bool mouseHover: false property bool isActiveWindowPinned: false property bool isActiveWindowMaximized: false property bool appmenuNextToIconAndText: plasmoid.configuration.appmenuNextToIconAndText property double appmenuSideMargin: plasmoid.configuration.appmenuOuterSideMargin property bool appmenuSwitchSidesWithIconAndText: plasmoid.configuration.appmenuSwitchSidesWithIconAndText property bool appmenuBoldTitleWhenMenuDisplayed: plasmoid.configuration.appmenuBoldTitleWhenMenuDisplayed property var activeTaskLocal: null property int activityActionCount: 0 property bool automaticButtonThemeEnabled: plasmoid.configuration.automaticButtonThemeEnabled property string manualAuroraeThemePath: plasmoid.configuration.customAuroraeThemePath property string manualAuroraeThemePathResolved: '' property string manualAuroraeThemeExtension: 'svg' + property var itemPartOrder: [] + Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation Plasmoid.status: { - if (appmenu.appmenuOpened) { + if (menuItem.appmenuOpened) { return PlasmaCore.Types.NeedsAttentionStatus; - } else if (!appmenu.appmenuOpened && appmenu.appmenuEnabledAndNonEmpty){ + } else if (!menuItem.appmenuOpened && menuItem.appmenuEnabledAndNonEmpty){ return PlasmaCore.Types.ActiveStatus; } else { return PlasmaCore.Types.PassiveStatus; } } // // MODEL // TaskManager.TasksModel { id: tasksModel sortMode: TaskManager.TasksModel.SortVirtualDesktop groupMode: TaskManager.TasksModel.GroupDisabled screenGeometry: plasmoid.screenGeometry filterByScreen: plasmoid.configuration.showForCurrentScreenOnly onActiveTaskChanged: { updateActiveWindowInfo() } onDataChanged: { updateActiveWindowInfo() } onCountChanged: { updateActiveWindowInfo() } } TaskManager.ActivityInfo { id: activityInfo onCurrentActivityChanged: { if (noWindowActive) { updateActiveWindowInfo(); } reAddActivityActions() } onNumberOfRunningActivitiesChanged: { reAddActivityActions() } } Activities.ActivityModel { id: activityModel } function activeTask() { return activeTaskLocal } function activeTaskExists() { return activeTaskLocal.display !== undefined } onTooltipTextTypeChanged: updateTooltip() function updateTooltip() { if (tooltipTextType === 1) { tooltipText = replaceTitle(activeTask().display || '') } else if (tooltipTextType === 2) { tooltipText = activeTask().AppName || '' } else { tooltipText = '' } } function composeNoWindowText() { return plasmoid.configuration.noWindowText.replace('%activity%', activityInfo.activityName(activityInfo.currentActivity)) } function updateActiveWindowInfo() { var activeTaskIndex = tasksModel.activeTask // fallback for Plasma 5.8 var abstractTasksModel = TaskManager.AbstractTasksModel || {} var isActive = abstractTasksModel.IsActive || 271 var appName = abstractTasksModel.AppName || 258 var isMaximized = abstractTasksModel.IsMaximized || 276 var virtualDesktop = abstractTasksModel.VirtualDesktop || 286 - if (!tasksModel.data(activeTaskIndex, isActive)) { - activeTaskLocal = {} - } else { + activeTaskLocal = {} + if (tasksModel.data(activeTaskIndex, isActive)) { activeTaskLocal = { display: tasksModel.data(activeTaskIndex, Qt.DisplayRole), decoration: tasksModel.data(activeTaskIndex, Qt.DecorationRole), AppName: tasksModel.data(activeTaskIndex, appName), IsMaximized: tasksModel.data(activeTaskIndex, isMaximized), VirtualDesktop: tasksModel.data(activeTaskIndex, virtualDesktop) } } var actTask = activeTask() noWindowActive = !activeTaskExists() currentWindowMaximized = !noWindowActive && actTask.IsMaximized === true isActiveWindowPinned = actTask.VirtualDesktop === -1; if (noWindowActive) { - windowTitleText.text = composeNoWindowText() + titleItem.text = composeNoWindowText() iconItem.source = plasmoid.configuration.noWindowIcon } else { - windowTitleText.text = (textType === 1 ? actTask.AppName : null) || replaceTitle(actTask.display) + titleItem.text = (textType === 1 ? actTask.AppName : null) || replaceTitle(actTask.display) iconItem.source = actTask.decoration } updateTooltip() } function toggleMaximized() { tasksModel.requestToggleMaximized(tasksModel.activeTask); } function toggleMinimized() { tasksModel.requestToggleMinimized(tasksModel.activeTask); } function toggleClose() { tasksModel.requestClose(tasksModel.activeTask); } function toggleFullscreen() { tasksModel.requestToggleFullScreen(tasksModel.activeTask); } function togglePinToAllDesktops() { tasksModel.requestVirtualDesktop(tasksModel.activeTask, 0); } function setMaximized(maximized) { if ((maximized && !activeTask().IsMaximized) || (!maximized && activeTask().IsMaximized)) { print('toggle maximized') toggleMaximized() } } function setMinimized() { if (!activeTask().IsMinimized) { toggleMinimized() } } // // ACTIVE WINDOW INFO // - Item { - id: activeWindowListView - - anchors.top: parent.top - anchors.bottom: parent.bottom - - property double appmenuOffsetLeft: (bp === 0 || bp === 2) ? appmenu.appmenuOffsetWidth : 0 - property double appmenuOffsetRight: (bp === 1 || bp === 3) ? appmenu.appmenuOffsetWidth : 0 - property double controlButtonsAreaWidth: noWindowActive ? 0 : controlButtonsArea.width - property bool buttonsVisible: buttonsStandalone && (!slidingIconAndText || controlButtonsArea.mouseInWidget || doNotHideControlButtons) && (canShowButtonsAccordingMaximized || !slidingIconAndText) - property double buttonsBetweenAddition: buttonsVisible && buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing : 0 - - anchors.left: parent.left - anchors.leftMargin: buttonsVisible && (bp === 0 || bp === 2) && !buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing + appmenuOffsetLeft : 0 + appmenuOffsetLeft - anchors.right: parent.right - anchors.rightMargin: buttonsVisible && (bp === 1 || bp === 3) && !buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing + appmenuOffsetRight : 0 + appmenuOffsetRight - - Behavior on anchors.leftMargin { - NumberAnimation { - duration: 150 - easing.type: Easing.Linear - } +// Item { +// id: activeWindowListView +// +// anchors.top: parent.top +// anchors.bottom: parent.bottom +// +// property double appmenuOffsetLeft: (bp === 0 || bp === 2) ? appmenu.appmenuOffsetWidth : 0 +// property double appmenuOffsetRight: (bp === 1 || bp === 3) ? appmenu.appmenuOffsetWidth : 0 +// property double controlButtonsAreaWidth: noWindowActive ? 0 : buttonsItem.width +// property bool buttonsVisible: buttonsStandalone && (!slidingIconAndText || buttonsItem.mouseInWidget || doNotHideControlButtons) && (canShowButtonsAccordingMaximized || !slidingIconAndText) +// property double buttonsBetweenAddition: buttonsVisible && buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing : 0 +// +// anchors.left: parent.left +// anchors.leftMargin: buttonsVisible && (bp === 0 || bp === 2) && !buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing + appmenuOffsetLeft : 0 + appmenuOffsetLeft +// anchors.right: parent.right +// anchors.rightMargin: buttonsVisible && (bp === 1 || bp === 3) && !buttonsBetweenIconAndText ? controlButtonsAreaWidth + iconAndTextSpacing + appmenuOffsetRight : 0 + appmenuOffsetRight +// +// Behavior on anchors.leftMargin { +// NumberAnimation { +// duration: 150 +// easing.type: Easing.Linear +// } +// } +// Behavior on anchors.rightMargin { +// NumberAnimation { +// duration: 150 +// easing.type: Easing.Linear +// } +// } +// +// width: parent.width - anchors.leftMargin - anchors.rightMargin +// +// opacity: appmenu.visible && !appmenuNextToIconAndText ? plasmoid.configuration.appmenuIconAndTextOpacity : 1 +// +// Item { +// width: parent.width +// height: main.height +// +// WindowIcon { +// id: iconItem +// +// anchors.left: parent.left +// anchors.leftMargin: windowIconOnTheRight ? parent.width - iconItem.width : 0 +// } +// +// WindowTitle { +// id: titleItem +// +// property double iconMarginForAnchor: noWindowActive && plasmoid.configuration.noWindowIcon === '' ? 0 : iconMargin +// +// anchors.left: parent.left +// anchors.leftMargin: windowIconOnTheRight ? 0 : iconMarginForAnchor + iconAndTextSpacing + activeWindowListView.buttonsBetweenAddition +// anchors.top: parent.top +// anchors.bottom: parent.bottom +// } +// +// } +// } + + function getConfigName(itemName) { + return itemName.substring(0, 1).toUpperCase() + itemName.substring(1) + } + + function getPosition(itemName) { + var configName = getConfigName(itemName) + print('getPosition: ' + configName) + print('POS: ' + plasmoid.configuration['controlPart' + configName + 'Position']) + return plasmoid.configuration['controlPart' + configName + 'Position'] + } + + function isRelevant(itemName) { + var configName = getConfigName(itemName) + print('isRelevant: ' + configName) + print('1IR: ' + plasmoid.configuration['controlPart' + configName + 'ShowOnMouseIn']) + print('2IR: ' + plasmoid.configuration['controlPart' + configName + 'ShowOnMouseOut']) + var result = plasmoid.configuration['controlPart' + configName + 'ShowOnMouseIn'] || plasmoid.configuration['controlPart' + configName + 'ShowOnMouseOut'] + print('res: ' + result) + return result + } + + function getItem(itemName) { + if (itemName === 'icon') { + return iconItem } - Behavior on anchors.rightMargin { - NumberAnimation { - duration: 150 - easing.type: Easing.Linear - } + if (itemName === 'title') { + return titleItem } + if (itemName === 'menu') { + return menuItem + } + if (itemName === 'buttons') { + return buttonsItem + } + return null + } - width: parent.width - anchors.leftMargin - anchors.rightMargin - - opacity: appmenu.visible && !appmenuNextToIconAndText ? plasmoid.configuration.appmenuIconAndTextOpacity : 1 - - Item { - width: parent.width - height: main.height - - // window icon - PlasmaCore.IconItem { - id: iconItem - - anchors.left: parent.left - anchors.leftMargin: windowIconOnTheRight ? parent.width - iconItem.width : 0 - - width: parent.height - height: parent.height + function getItemWidth(itemName) { + return getItem().width + } - source: plasmoid.configuration.noWindowIcon - visible: plasmoid.configuration.showWindowIcon + function anchorsLeftMargin(itemName) { + var itemPosition = getPosition(itemName) + print('position of ' + itemName + ' is ' + itemPosition) + if (itemPosition === 2) { + return 0 + } + var anchorSize = 0 + itemPartOrder.some(function (iName, index) { + print('iterating: ' + iName) + if (iName === itemName) { + return true } - - // window title - PlasmaComponents.Label { - id: windowTitleText - - property double iconMargin: (plasmoid.configuration.showWindowIcon ? iconItem.width : 0) - property double properWidth: parent.width - iconMargin - iconAndTextSpacing - property double properHeight: parent.height - property bool noElide: fitText === 2 || (fitText === 1 && mouseHover) - property int allowFontSizeChange: 3 - property int minimumPixelSize: 8 - property double iconMarginForAnchor: noWindowActive && plasmoid.configuration.noWindowIcon === '' ? 0 : iconMargin - property bool limitTextWidth: plasmoid.configuration.limitTextWidth - property int textWidthLimit: plasmoid.configuration.textWidthLimit - property double computedWidth: (limitTextWidth ? (implicitWidth > textWidthLimit ? textWidthLimit : implicitWidth) : properWidth) - activeWindowListView.buttonsBetweenAddition - - anchors.left: parent.left - anchors.leftMargin: windowIconOnTheRight ? 0 : iconMarginForAnchor + iconAndTextSpacing + activeWindowListView.buttonsBetweenAddition - anchors.top: parent.top - anchors.bottom: parent.bottom - verticalAlignment: Text.AlignVCenter - text: plasmoid.configuration.noWindowText - wrapMode: Text.Wrap - width: computedWidth - elide: noElide ? Text.ElideNone : Text.ElideRight - visible: plasmoid.configuration.showWindowTitle - font.pixelSize: fontPixelSize - font.pointSize: -1 - font.weight: fontBold || (appmenuBoldTitleWhenMenuDisplayed && appmenu.visible) ? Font.Bold : theme.defaultFont.weight - font.family: fontFamily || theme.defaultFont.family - - onTextChanged: { - font.pixelSize = fontPixelSize - allowFontSizeChange = 3 - } - - onNoElideChanged: { - font.pixelSize = fontPixelSize - allowFontSizeChange = 3 - } - - onPaintedHeightChanged: { - if (allowFontSizeChange > 0 && noElide && paintedHeight > properHeight) { - var newPixelSize = (properHeight / paintedHeight) * fontPixelSize - font.pixelSize = newPixelSize < minimumPixelSize ? minimumPixelSize : newPixelSize - } - allowFontSizeChange-- - } + if (getPosition(iName) === itemPosition && isRelevant(iName)) { + var currentItemWidth = getItemWidth(iName) + print('width of ' + iName + ' is ' + currentItemWidth) + anchorSize += currentItemWidth + anchorSize += plasmoid.configuration.controlPartSpacing } + }); + print('leftMargin of ' + itemName + ' is ' + anchorSize) + return anchorSize + } - } + function refreshItemMargin() { + iconItem.anchors.leftMargin = anchorsLeftMargin('icon') + titleItem.anchors.leftMargin = anchorsLeftMargin('title') + menuItem.anchors.leftMargin = anchorsLeftMargin('menu') + buttonsItem.anchors.leftMargin = anchorsLeftMargin('buttons') } function replaceTitle(title) { if (!plasmoid.configuration.useWindowTitleReplace) { return title } return title.replace(new RegExp(plasmoid.configuration.replaceTextRegex), plasmoid.configuration.replaceTextReplacement); } MouseArea { anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.MiddleButton onEntered: { mouseHover = true - controlButtonsArea.mouseInWidget = showControlButtons && !noWindowActive + buttonsItem.mouseInWidget = showControlButtons && !noWindowActive } onExited: { mouseHover = false - controlButtonsArea.mouseInWidget = false + buttonsItem.mouseInWidget = false } onWheel: { if (wheel.angleDelta.y > 0) { if (wheelUpMaximizes) { setMaximized(true) } } else { if (wheelDownMinimizes) { setMinimized() } else if (wheelDownUnmaximizes) { setMaximized(false) } } } onDoubleClicked: { if (doubleClickMaximizes && mouse.button == Qt.LeftButton) { toggleMaximized() } } onClicked: { if (chosenLeftClickSource !== '' && !doubleClickMaximizes && mouse.button == Qt.LeftButton) { shortcutDS.connectedSources.push(chosenLeftClickSource) - controlButtonsArea.mouseInWidget = false + buttonsItem.mouseInWidget = false return } if (mouse.button == Qt.MiddleButton) { if (middleClickFullscreen) { toggleFullscreen() } else if (middleClickClose) { toggleClose() } } } PlasmaCore.ToolTipArea { anchors.fill: parent active: tooltipTextType > 0 && tooltipText !== '' interactive: true location: plasmoid.location mainItem: Row { spacing: 0 Layout.minimumWidth: fullText.width + units.largeSpacing Layout.minimumHeight: childrenRect.height Layout.maximumWidth: Layout.minimumWidth Layout.maximumHeight: Layout.minimumHeight Item { width: units.largeSpacing / 2 height: 2 } PlasmaComponents.Label { id: fullText text: tooltipText } } } + } + + ListModel { + id: controlButtonsModel + } + + WindowIcon { + id: iconItem - AppMenu { - id: appmenu - } + x: anchorsLeftMargin('icon') - ListView { - id: controlButtonsArea + visible: ((mouseHover && plasmoid.configuration.controlPartIconShowOnMouseIn) + || (!mouseHover && plasmoid.configuration.controlPartIconShowOnMouseOut)) - property bool mouseInWidget: false - property double controlButtonsHeight: parent.height * buttonSize - property double buttonsBetweenMargin: buttonsBetweenIconAndText ? activeWindowListView.appmenuOffsetLeft + activeWindowListView.appmenuOffsetRight + iconItem.width + iconAndTextSpacing : 0 + onWidthChanged: refreshItemMargin() + } - orientation: ListView.Horizontal - visible: showControlButtons && (doNotHideControlButtons || mouseInWidget || appmenu.appmenuOpened) && (currentWindowMaximized || !showButtonOnlyWhenMaximized) && !noWindowActive + WindowTitle { + id: titleItem - spacing: controlButtonsSpacing + x: anchorsLeftMargin('title') + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right - height: buttonsVerticalCenter ? parent.height : controlButtonsHeight - width: controlButtonsHeight + ((controlButtonsModel.count - 1) * (controlButtonsHeight + controlButtonsSpacing)) + visible: ((mouseHover && plasmoid.configuration.controlPartTitleShowOnMouseIn) + || (!mouseHover && plasmoid.configuration.controlPartTitleShowOnMouseOut)) + } + + AppMenu { + id: menuItem - anchors.top: parent.top - anchors.left: parent.left + x: anchorsLeftMargin('menu') - anchors.leftMargin: buttonsBetweenIconAndText ? (windowIconOnTheRight ? parent.width - width - buttonsBetweenMargin : buttonsBetweenMargin) : ((bp === 1 || bp === 3) ? parent.width - width : 0) - anchors.topMargin: (bp === 2 || bp === 3) ? parent.height - height : 0 + visible: ((mouseHover && plasmoid.configuration.controlPartMenuShowOnMouseIn) + || (!mouseHover && plasmoid.configuration.controlPartMenuShowOnMouseOut)) + } - model: controlButtonsModel + ControlButtons { + id: buttonsItem - delegate: ControlButton { } - } + x: anchorsLeftMargin('buttons') + + visible: true + + controlButtonsModel: controlButtonsModel + + showItem: ((mouseInWidget && plasmoid.configuration.controlPartButtonsShowOnMouseIn) + || (!mouseInWidget && plasmoid.configuration.controlPartButtonsShowOnMouseOut)) } - ListModel { - id: controlButtonsModel + property bool mouseInWidget: mouseHover || buttonsItem.mouseInWidget || menuItem.mouseInWidget + + onMouseHoverChanged: { + print('mouse hover changed: ' + mouseHover); + } + + onMouseInWidgetChanged: { + print('mouseInWidget: ' + mouseInWidget); } onManualAuroraeThemePathChanged: { manualAuroraeThemeExtension = plasmoid.nativeInterface.extensionForTheme(manualAuroraeThemePath); manualAuroraeThemePathResolved = plasmoid.nativeInterface.translateThemePath(manualAuroraeThemePath); print('manualAuroraeThemePath=' + manualAuroraeThemePath) print('manualAuroraeThemePathResolved=' + manualAuroraeThemePathResolved) print('manualAuroraeThemeExtension=' + manualAuroraeThemeExtension) } function addButton(preparedArray, buttonName) { if (buttonName === 'close') { preparedArray.push({ iconName: 'close', windowOperation: 'close' }); } else if (buttonName === 'maximize' && showMaximize) { preparedArray.push({ iconName: 'maximize', windowOperation: 'toggleMaximized' }); } else if (buttonName === 'minimize' && showMinimize) { preparedArray.push({ iconName: 'minimize', windowOperation: 'toggleMinimized' }); } else if ((buttonName === 'pin' || buttonName === 'alldesktops') && showPinToAllDesktops) { preparedArray.push({ iconName: 'alldesktops', windowOperation: 'togglePinToAllDesktops' }); } } function initializeControlButtonsModel() { var preparedArray = [] buttonOrder.split('|').forEach(function (buttonName) { addButton(preparedArray, buttonName); }); controlButtonsModel.clear() - if (bp === 1 || bp === 3) { - for (var i = preparedArray.length - 1; i >= 0; i--) { - controlButtonsModel.append(preparedArray[i]) - } - } else { - for (var i = 0; i < preparedArray.length; i++) { - controlButtonsModel.append(preparedArray[i]) - } - } + preparedArray.forEach(function (item) { + print('adding item to buttons: ' + item.iconName); + controlButtonsModel.append(item); + }); } function performActiveWindowAction(windowOperation) { - if (bp === 4 || !controlButtonsArea.visible) { + if (bp === 4) { return; } if (windowOperation === 'close') { toggleClose() } else if (windowOperation === 'toggleMaximized') { toggleMaximized() } else if (windowOperation === 'toggleMinimized') { toggleMinimized() } else if (windowOperation === 'togglePinToAllDesktops') { togglePinToAllDesktops() } } function action_close() { toggleClose() } function action_maximise() { toggleMaximized() } function action_minimise() { toggleMinimized() } function action_pinToAllDesktops() { togglePinToAllDesktops() } function action_reloadTheme() { plasmoid.nativeInterface.refreshAuroraeTheme(); } function actionTriggered(actionName) { if (actionName.indexOf("switchToActivity_") == 0) { var activityIndex = actionName.replace("switchToActivity_", "") var activityId = activityInfo.runningActivities()[activityIndex] activityModel.setCurrentActivity(activityId, function() {}); } } function reAddActivityActions() { plasmoid.removeAction("separator1") for (var i = 0; i < activityActionCount; i++) { plasmoid.removeAction('switchToActivity_' + i) } plasmoid.removeAction("separator2") var runningActivities = activityInfo.runningActivities() activityActionCount = runningActivities.length if (activityActionCount === 0) { return } plasmoid.setActionSeparator("separator1") activityInfo.runningActivities().forEach(function (activityId, index) { if (activityId === activityInfo.currentActivity) { return; } var activityName = activityInfo.activityName(activityId) plasmoid.setAction('switchToActivity_' + index, i18n('Switch to activity: %1', activityName), 'preferences-activities') }) plasmoid.setActionSeparator("separator2") } + property string controlPartOrder: plasmoid.configuration.controlPartOrder + + onControlPartOrderChanged: refreshControlPartOrder() + + function refreshControlPartOrder() { + itemPartOrder.length = 0 + plasmoid.configuration.controlPartOrder.split('|').forEach(function (itemName, index) { + print('itemOrder: ' + itemName) + itemPartOrder.push(itemName) + print('itemZ: ' + index) + getItem(itemName).z = index + }); + print('itemPartOrder initialized: ' + itemPartOrder) + } + Component.onCompleted: { + refreshControlPartOrder() + refreshItemMargin() initializeControlButtonsModel() updateActiveWindowInfo() plasmoid.setAction('close', i18n('Close'), 'window-close'); plasmoid.setAction('maximise', i18n('Toggle Maximise'), 'arrow-up-double'); plasmoid.setAction('minimise', i18n('Minimise'), 'draw-arrow-down'); plasmoid.setAction('pinToAllDesktops', i18n('Toggle Pin To All Desktops'), 'window-pin'); plasmoid.setActionSeparator("separator0") plasmoid.setAction('reloadTheme', i18n('Reload Theme'), 'system-reboot'); reAddActivityActions() } onShowMaximizeChanged: initializeControlButtonsModel() onShowMinimizeChanged: initializeControlButtonsModel() onShowPinToAllDesktopsChanged: initializeControlButtonsModel() onBpChanged: initializeControlButtonsModel() onButtonOrderChanged: initializeControlButtonsModel() PlasmaCore.DataSource { id: shortcutDS engine: 'executable' property string presentWindows: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "Expose"' property string presentWindowsAll: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "ExposeAll"' property string presentWindowsClass: 'qdbus org.kde.kglobalaccel /component/kwin invokeShortcut "ExposeClass"' connectedSources: [] onNewData: { connectedSources.length = 0 } } }