diff --git a/package/contents/config/main.xml b/package/contents/config/main.xml index 4fbc298..8b38b91 100644 --- a/package/contents/config/main.xml +++ b/package/contents/config/main.xml @@ -1,231 +1,234 @@ buttons|icon|title|menu 5.0 - + 0 true true - + 0 - + 0 true true - + 0 - + 0 true true - + 0 - + 0 true true + + 0 + 0 false false 0.2 0.0 true 0 0 0 false ^(.*)\s*[—–\-:]\s*(Mozilla )?([^—–\-:]+)$ $3 — $1 Plasma Desktop :: %activity% false 1000 0 1 false false false false close|maximize|minimize|pin false 10 0.5 0 true false false 1 true 0.1 1.0 true 0 0 false 0 diff --git a/package/contents/ui/AppMenu.qml b/package/contents/ui/AppMenu.qml index 6f672b4..5a64640 100644 --- a/package/contents/ui/AppMenu.qml +++ b/package/contents/ui/AppMenu.qml @@ -1,159 +1,159 @@ 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 MouseArea { id: appmenu property bool mouseInWidget: appmenuOpened || appmenu.containsMouse property bool appmenuEnabled: plasmoid.configuration.controlPartMenuShowOnMouseIn || plasmoid.configuration.controlPartMenuShowOnMouseOut property bool appmenuFillHeight: plasmoid.configuration.appmenuFillHeight property bool appmenuFontBold: plasmoid.configuration.appmenuFontBold property bool appmenuEnabledAndNonEmpty: appmenuEnabled && appMenuModel !== null && appMenuModel.menuAvailable property bool appmenuOpened: appmenuEnabled && plasmoid.nativeInterface.currentIndex > -1 property var appMenuModel: null visible: appmenuEnabledAndNonEmpty && !main.noWindowActive property bool showItem - property double recommendedWidth + property double recommendedMaxWidth opacity: showItem ? 1 : 0 - width: recommendedWidth + width: recommendedMaxWidth hoverEnabled: true GridLayout { id: buttonGrid Layout.minimumWidth: implicitWidth Layout.minimumHeight: implicitHeight flow: GridLayout.LeftToRight rowSpacing: 0 columnSpacing: 0 anchors.top: parent.top anchors.left: parent.left 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: main.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' } } } } 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/WindowTitle.qml b/package/contents/ui/WindowTitle.qml index d5db510..9a051ac 100644 --- a/package/contents/ui/WindowTitle.qml +++ b/package/contents/ui/WindowTitle.qml @@ -1,67 +1,75 @@ 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 properHeight: parent.height property int fontBold: plasmoid.configuration.textFontBold property string fontFamily: plasmoid.configuration.fontFamily property int fitText: plasmoid.configuration.fitText property bool noElide: fitText === 2 || (fitText === 1 && mainMouseArea.containsMouse) property int allowFontSizeChange: 3 property int minimumPixelSize: 8 property bool limitTextWidth: plasmoid.configuration.limitTextWidth property int textWidthLimit: plasmoid.configuration.textWidthLimit - property double recommendedWidth + property double recommendedMaxWidth + property bool useUpPossibleWidth: main.useUpWidthItem === 0 + property bool doNotRestrictWidth: useUpPossibleWidth && autoFillWidth - onRecommendedWidthChanged: { - if (limitTextWidth) { + onRecommendedMaxWidthChanged: { + var maxWidth = limitTextWidth ? Math.min(textWidthLimit, recommendedMaxWidth) : recommendedMaxWidth + width = undefined + if (useUpPossibleWidth || (limitTextWidth && implicitWidth > maxWidth)) { + width = maxWidth + } + } + + onUseUpPossibleWidthChanged: recommendedMaxWidthChanged() + + onDoNotRestrictWidthChanged: { + if (doNotRestrictWidth) { width = undefined - if (implicitWidth > textWidthLimit) { - width = textWidthLimit - } else { - width = recommendedWidth - } } else { - width = recommendedWidth + recommendedMaxWidthChanged() } } verticalAlignment: Text.AlignVCenter + horizontalAlignment: plasmoid.configuration.controlPartTitleHorizontalAlignment === 0 ? Text.AlignLeft : Text.AlignRight text: plasmoid.configuration.noWindowText wrapMode: Text.Wrap - width: recommendedWidth + //width: recommendedMaxWidth height: properHeight elide: noElide ? Text.ElideNone : Text.ElideRight font.pixelSize: fontPixelSize font.pointSize: -1 font.weight: fontBold === 1 || (fontBold === 2 && menuItem.showItem) ? Font.Bold : theme.defaultFont.weight font.family: fontFamily || theme.defaultFont.family opacity: menuItem.showItem ? plasmoid.configuration.appmenuIconAndTextOpacity : 1 onTextChanged: { font.pixelSize = fontPixelSize allowFontSizeChange = 3 - recommendedWidthChanged() + recommendedMaxWidthChanged() } 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/ConfigLayout.qml b/package/contents/ui/config/ConfigLayout.qml index 1e6903c..a0fddee 100644 --- a/package/contents/ui/config/ConfigLayout.qml +++ b/package/contents/ui/config/ConfigLayout.qml @@ -1,395 +1,421 @@ import QtQuick 2.2 import QtQuick.Controls 1.3 import QtQuick.Layouts 1.1 import QtQml.Models 2.1 Item { id: configLayout property string cfg_controlPartOrder property alias cfg_controlPartSpacing: controlPartSpacing.value + property alias cfg_useUpWidthItem: useUpWidthItem.currentIndex // GENERATED config (start) - property alias cfg_controlPartIconPosition: controlPartIconPosition.currentIndex property alias cfg_controlPartIconShowOnMouseIn: controlPartIconShowOnMouseIn.checked property alias cfg_controlPartIconShowOnMouseOut: controlPartIconShowOnMouseOut.checked + property alias cfg_controlPartIconPosition: controlPartIconPosition.currentIndex 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_controlPartTitlePosition: controlPartTitlePosition.currentIndex property alias cfg_controlPartTitleHorizontalAlignment: controlPartTitleHorizontalAlignment.currentIndex - property alias cfg_controlPartButtonsPosition: controlPartButtonsPosition.currentIndex property alias cfg_controlPartButtonsShowOnMouseIn: controlPartButtonsShowOnMouseIn.checked property alias cfg_controlPartButtonsShowOnMouseOut: controlPartButtonsShowOnMouseOut.checked + property alias cfg_controlPartButtonsPosition: controlPartButtonsPosition.currentIndex property alias cfg_controlPartButtonsHorizontalAlignment: controlPartButtonsHorizontalAlignment.currentIndex - property alias cfg_controlPartMenuPosition: controlPartMenuPosition.currentIndex property alias cfg_controlPartMenuShowOnMouseIn: controlPartMenuShowOnMouseIn.checked property alias cfg_controlPartMenuShowOnMouseOut: controlPartMenuShowOnMouseOut.checked + property alias cfg_controlPartMenuPosition: controlPartMenuPosition.currentIndex property alias cfg_controlPartMenuHorizontalAlignment: controlPartMenuHorizontalAlignment.currentIndex // GENERATED config (end) property alias cfg_controlPartMouseAreaRestrictedToWidget: controlPartMouseAreaRestrictedToWidget.checked property alias cfg_autoFillWidth: autoFillWidth.checked property alias cfg_horizontalScreenWidthPercent: horizontalScreenWidthPercent.value property alias cfg_widthFineTuning: widthFineTuning.value 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('Plasmoid version: ') + '1.8.0-git' Layout.alignment: Qt.AlignRight Layout.columnSpan: 3 } Item { width: 2 height: units.largeSpacing Layout.columnSpan: 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 } + Label { + text: i18n('Item to use up all possible width:') + } + ComboBox { + id: useUpWidthItem + model: [i18n('Title'), i18n('Menu'), i18n('None')] + Layout.columnSpan: 2 + } + // GENERATED controls (start) GridLayout { columns: 2 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 - } + GridLayout { + columns: 2 + Layout.columnSpan: 2 + enabled: controlPartIconShowOnMouseIn.checked || controlPartIconShowOnMouseOut.checked - ComboBox { - id: controlPartIconHorizontalAlignment - model: [i18n('Left'), i18n('Right')] + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartIconPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } + + Label { + text: i18n('Align:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartIconHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } } 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 - } + GridLayout { + columns: 2 + Layout.columnSpan: 2 + enabled: controlPartButtonsShowOnMouseIn.checked || controlPartButtonsShowOnMouseOut.checked + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartButtonsPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } - ComboBox { - id: controlPartButtonsHorizontalAlignment - model: [i18n('Left'), i18n('Right')] + Label { + text: i18n('Align:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartButtonsHorizontalAlignment + 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 - } + GridLayout { + columns: 2 + Layout.columnSpan: 2 + enabled: controlPartTitleShowOnMouseIn.checked || controlPartTitleShowOnMouseOut.checked + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartTitlePosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } - ComboBox { - id: controlPartTitleHorizontalAlignment - model: [i18n('Left'), i18n('Right')] + Label { + text: i18n('Align:') + 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 - } + GridLayout { + columns: 2 + Layout.columnSpan: 2 + enabled: controlPartMenuShowOnMouseIn.checked || controlPartMenuShowOnMouseOut.checked + + Label { + text: i18n('Position:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartMenuPosition + model: [i18n('Occupy'), i18n('Floating layer'), i18n('Absolute')] + } - ComboBox { - id: controlPartMenuHorizontalAlignment - model: [i18n('Left'), i18n('Right')] + Label { + text: i18n('Align:') + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + } + ComboBox { + id: controlPartMenuHorizontalAlignment + model: [i18n('Left'), i18n('Right')] + } } } // GENERATED controls (end) Item { width: units.largeSpacing height: units.largeSpacing Layout.columnSpan: 3 } CheckBox { id: controlPartMouseAreaRestrictedToWidget text: i18n('Restrict mouse area to widget') Layout.columnSpan: 3 } Item { width: units.largeSpacing height: units.largeSpacing Layout.columnSpan: 3 } Label { text: i18n("Width in horizontal panel:") font.bold: true Layout.alignment: Qt.AlignLeft Layout.columnSpan: 3 } CheckBox { id: autoFillWidth text: i18n("Fill width") Layout.columnSpan: 3 } GridLayout { columns: 2 Layout.columnSpan: 3 enabled: !autoFillWidth.checked Slider { id: horizontalScreenWidthPercent stepSize: 0.001 minimumValue: 0.001 maximumValue: 1 Layout.preferredWidth: configLayout.width Layout.columnSpan: 2 } Label { text: i18n("Fine tuning:") Layout.alignment: Qt.AlignRight } SpinBox { id: widthFineTuning decimals: 1 stepSize: 0.5 minimumValue: -100 maximumValue: 100 } } } Component.onCompleted: { sortPartOrder() } } diff --git a/package/contents/ui/config/ConfigTitleAndIcon.qml b/package/contents/ui/config/ConfigTitleAndIcon.qml index 0cb9dc0..a932631 100644 --- a/package/contents/ui/config/ConfigTitleAndIcon.qml +++ b/package/contents/ui/config/ConfigTitleAndIcon.qml @@ -1,233 +1,233 @@ import QtQuick 2.2 import QtQuick.Controls 1.3 import QtQuick.Layouts 1.1 import org.kde.plasma.core 2.0 as PlasmaCore Item { property alias cfg_textType: textTypeCombo.currentIndex property alias cfg_fitText: fitTextCombo.currentIndex property alias cfg_tooltipTextType: tooltipTextTypeCombo.currentIndex property alias cfg_useWindowTitleReplace: useWindowTitleReplace.checked property alias cfg_replaceTextRegex: replaceTextRegex.text property alias cfg_replaceTextReplacement: replaceTextReplacement.text property alias cfg_noWindowText: noWindowText.text property string cfg_noWindowIcon: plasmoid.configuration.noWindowIcon property alias cfg_limitTextWidth: limitTextWidth.checked property alias cfg_textWidthLimit: textWidthLimit.value property alias cfg_textFontBold: textFontBoldCombo.currentIndex property string cfg_fontFamily property alias cfg_fontSizeScale: fontSizeScale.value /* copied from /usr/share/plasma/plasmoids/org.kde.plasma.digitalclock/contents/ui/configAppearance.qml */ onCfg_fontFamilyChanged: { // HACK by the time we populate our model and/or the ComboBox is finished the value is still undefined if (cfg_fontFamily) { for (var i = 0, j = fontsModel.count; i < j; ++i) { if (fontsModel.get(i).value == cfg_fontFamily) { fontFamilyComboBox.currentIndex = i break } } } } ListModel { id: fontsModel Component.onCompleted: { var arr = [ {text: i18nc("Use default font", "Default"), value: ""} ] Qt.fontFamilies().forEach(function (font) { arr.push({text: font, value: font}) }) append(arr) cfg_fontFamilyChanged(); } } GridLayout { columns: 2 Label { text: i18n('Text') Layout.alignment: Qt.AlignLeft font.bold: true Layout.columnSpan: 2 } Label { text: i18n('Text type:') Layout.alignment: Qt.AlignRight } ComboBox { id: textTypeCombo model: [i18n('Window title'), i18n('Application name')] } Label { text: i18n('Fit text:') Layout.alignment: Qt.AlignRight } ComboBox { id: fitTextCombo model: [i18n('Just elide'), i18n('Fit on hover'), i18n('Always fit')] } Label { text: i18n('Tooltip text:') Layout.alignment: Qt.AlignRight } ComboBox { id: tooltipTextTypeCombo model: [i18n('No tooltip'), i18n('Window title'), i18n('Application name')] } Item { width: 2 height: units.largeSpacing Layout.columnSpan: 2 } Label { text: i18n('Bold text:') Layout.alignment: Qt.AlignRight } ComboBox { id: textFontBoldCombo // ComboBox's sizing is just utterly broken Layout.minimumWidth: units.gridUnit * 10 model: [i18n('Never'), i18n('Always'), i18n('When appmenu is displayed')] } Label { text: i18n('Text font:') Layout.alignment: Qt.AlignRight } ComboBox { id: fontFamilyComboBox // ComboBox's sizing is just utterly broken Layout.minimumWidth: units.gridUnit * 10 model: fontsModel // doesn't autodeduce from model because we manually populate it textRole: "text" onCurrentIndexChanged: { var current = model.get(currentIndex) if (current) { cfg_fontFamily = current.value //appearancePage.configurationChanged() console.log('change: ' + cfg_fontFamily) } } } Label { text: i18n("Font size scale:") Layout.alignment: Qt.AlignVCenter|Qt.AlignRight } SpinBox { id: fontSizeScale decimals: 2 stepSize: 0.05 minimumValue: 0 maximumValue: 3 } CheckBox { id: limitTextWidth text: i18n('Limit text width') Layout.alignment: Qt.AlignRight } SpinBox { id: textWidthLimit decimals: 0 stepSize: 10 minimumValue: 0 maximumValue: 10000 enabled: limitTextWidth.checked suffix: i18nc('Abbreviation for pixels', 'px') } Item { width: 2 height: units.largeSpacing Layout.columnSpan: 2 } CheckBox { id: useWindowTitleReplace text: '"' + i18n('Window title') + '".replace(/' Layout.alignment: Qt.AlignRight } GridLayout { columns: 4 TextField { id: replaceTextRegex placeholderText: '^(.*)\\s+[—–\\-:]\\s+([^—–\\-:]+)$' - Layout.preferredWidth: 300 + Layout.preferredWidth: 270 onTextChanged: cfg_replaceTextRegex = text enabled: useWindowTitleReplace.checked } Label { text: '/, "' } TextField { id: replaceTextReplacement placeholderText: '$2 — $1' Layout.preferredWidth: 100 onTextChanged: cfg_replaceTextReplacement = text enabled: useWindowTitleReplace.checked } Label { text: '");' } } Label { text: i18n('No window text:') Layout.alignment: Qt.AlignRight } GridLayout { columns: 2 TextField { id: noWindowText placeholderText: 'Plasma Desktop :: %activity%' onTextChanged: cfg_noWindowText = text - Layout.preferredWidth: 300 + Layout.preferredWidth: 270 } Label { text: i18n('Use %activity% placeholder to show current activity name.') - Layout.preferredWidth: 200 + Layout.preferredWidth: 150 wrapMode: Text.Wrap } } Item { width: 2 height: units.largeSpacing Layout.columnSpan: 2 } Label { text: i18n('Icon') Layout.alignment: Qt.AlignLeft font.bold: true Layout.columnSpan: 2 } Label { text: i18n("No window icon:") Layout.alignment: Qt.AlignRight } IconPicker { currentIcon: cfg_noWindowIcon defaultIcon: '' onIconChanged: cfg_noWindowIcon = iconName } } } diff --git a/package/contents/ui/main.qml b/package/contents/ui/main.qml index 42b228c..700a99e 100644 --- a/package/contents/ui/main.qml +++ b/package/contents/ui/main.qml @@ -1,561 +1,600 @@ /* * 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 bool autoFillWidth: plasmoid.configuration.autoFillWidth property double widthForHorizontalPanel: (Screen.width * horizontalScreenWidthPercent + plasmoid.configuration.widthFineTuning) + property int useUpWidthItem: plasmoid.configuration.useUpWidthItem + property int textType: plasmoid.configuration.textType property int tooltipTextType: plasmoid.configuration.tooltipTextType property string tooltipText: '' property double fontPixelSize: theme.defaultFont.pixelSize * plasmoid.configuration.fontSizeScale property bool noWindowActive: true property bool currentWindowMaximized: false 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 textColorLight: ((theme.textColor.r + theme.textColor.g + theme.textColor.b) / 3) > 0.5 property bool isActiveWindowPinned: false property bool isActiveWindowMaximized: false property bool controlPartMouseAreaRestrictedToWidget: plasmoid.configuration.controlPartMouseAreaRestrictedToWidget property var activeTaskLocal: null property int activityActionCount: 0 property var itemPartOrder: [] property bool mouseInWidget: mainMouseArea.containsMouse || buttonsItem.mouseInWidget || menuItem.mouseInWidget anchors.fill: parent - Layout.fillWidth: plasmoid.configuration.autoFillWidth + Layout.fillWidth: 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 Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation Plasmoid.status: { if (menuItem.appmenuOpened) { return PlasmaCore.Types.NeedsAttentionStatus; } 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 } function updateTooltip() { if (tooltipTextType === 1) { tooltipText = replaceTitle(activeTask().display || '') } else if (tooltipTextType === 2) { tooltipText = activeTask().AppName || '' } else { tooltipText = '' } } onTooltipTextTypeChanged: updateTooltip() 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 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) { titleItem.text = composeNoWindowText() iconItem.source = plasmoid.configuration.noWindowIcon } else { 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() } } function getConfigName(itemName) { return itemName.substring(0, 1).toUpperCase() + itemName.substring(1) } /* * Position can be: * 0 ... occupy * 1 ... floating layer (second occupy) * 2 ... absolute */ function getPosition(itemName) { var configName = getConfigName(itemName) print('getPosition: ' + configName) print('POS: ' + plasmoid.configuration['controlPart' + configName + 'Position']) return plasmoid.configuration['controlPart' + configName + 'Position'] } + /* + * Alignment can be: + * 0 ... left + * 1 ... right + */ + function getAlignment(itemName) { + var configName = getConfigName(itemName) + print('getAlignment: ' + configName) + print('ALI: ' + plasmoid.configuration['controlPart' + configName + 'HorizontalAlignment']) + return plasmoid.configuration['controlPart' + configName + 'HorizontalAlignment'] + } + 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 + var mouseInConfigName = 'controlPart' + configName + 'ShowOnMouseIn' + var mouseOutConfigName = 'controlPart' + configName + 'ShowOnMouseOut' + return plasmoid.configuration[mouseInConfigName] || plasmoid.configuration[mouseOutConfigName] } function getItem(itemName) { if (itemName === 'icon') { return iconItem } if (itemName === 'title') { return titleItem } if (itemName === 'menu') { return menuItem } if (itemName === 'buttons') { return buttonsItem } return null } function getItemWidth(itemName) { + if (itemName === 'title' && !titleItem.useUpPossibleWidth) { + return getItem(itemName).implicitWidth + } return getItem(itemName).width } function getLeftMargin(itemName) { var itemPosition = getPosition(itemName) + var itemAlignment = getAlignment(itemName) print('position of ' + itemName + ' is ' + itemPosition) if (itemPosition === 2) { return 0 } var anchorSize = 0 - itemPartOrder.some(function (iName, index) { + var itemPartOrderArray = itemAlignment === 0 ? itemPartOrder : itemPartOrder.slice().reverse() + itemPartOrderArray.some(function (iName, index) { print('iterating: ' + iName) if (iName === itemName) { return true } - if (getPosition(iName) === itemPosition && isRelevant(iName)) { + if (getPosition(iName) === itemPosition && getAlignment(iName) === itemAlignment && isRelevant(iName)) { var currentItemWidth = getItemWidth(iName) print('width of ' + iName + ' is ' + currentItemWidth) anchorSize += currentItemWidth anchorSize += plasmoid.configuration.controlPartSpacing } }); + if (itemAlignment === 1) { + var computedWidth = autoFillWidth ? main.width : widthForHorizontalPanel + anchorSize = computedWidth - anchorSize - getItemWidth(itemName) + } print('leftMargin of ' + itemName + ' is ' + anchorSize) return anchorSize } - function getWidth(itemName) { + function getMaxWidth(itemName) { var itemPosition = getPosition(itemName) - print('getWidth(): position of ' + itemName + ' is ' + itemPosition) + print('getMaxWidth(): position of ' + itemName + ' is ' + itemPosition) if (itemPosition === 2) { return 0 } - var computedWidth = widthForHorizontalPanel + var computedWidth = autoFillWidth ? main.width : widthForHorizontalPanel itemPartOrder.forEach(function (iName, index) { print('iterating: ' + iName) if (iName === itemName) { return; } if (getPosition(iName) === itemPosition && isRelevant(iName)) { var currentItemWidth = getItemWidth(iName) print('width of ' + iName + ' is ' + currentItemWidth) computedWidth -= currentItemWidth computedWidth -= plasmoid.configuration.controlPartSpacing } }); print('computedWidth of ' + itemName + ' is ' + computedWidth) return computedWidth } function refreshItemPosition() { - titleItem.recommendedWidth = getWidth('title') - menuItem.recommendedWidth = getWidth('menu') + if (titleItem.useUpPossibleWidth) { + titleItem.recommendedMaxWidth = getMaxWidth('title') + menuItem.recommendedMaxWidth = getMaxWidth('menu') + } else { + titleItem.recommendedMaxWidth = getMaxWidth('title') + menuItem.recommendedMaxWidth = getMaxWidth('menu') + } iconItem.x = getLeftMargin('icon') titleItem.x = getLeftMargin('title') menuItem.x = getLeftMargin('menu') buttonsItem.x = getLeftMargin('buttons') textSeparator.x = getLeftMargin('menu') - (plasmoid.configuration.controlPartSpacing / 2) } function replaceTitle(title) { if (!plasmoid.configuration.useWindowTitleReplace) { return title } return title.replace(new RegExp(plasmoid.configuration.replaceTextRegex), plasmoid.configuration.replaceTextReplacement); } + onWidthChanged: { + if (autoFillWidth) { + refreshItemPosition(); + } + } onWidthForHorizontalPanelChanged: refreshItemPosition() MouseArea { id: mainMouseArea anchors.fill: parent hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.MiddleButton 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) 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 visible: ((mouseInWidget && plasmoid.configuration.controlPartIconShowOnMouseIn) || (!mouseInWidget && plasmoid.configuration.controlPartIconShowOnMouseOut)) onWidthChanged: refreshItemPosition() } WindowTitle { id: titleItem visible: ((mouseInWidget && plasmoid.configuration.controlPartTitleShowOnMouseIn) || (!mouseInWidget && plasmoid.configuration.controlPartTitleShowOnMouseOut)) + + onImplicitWidthChanged: { + if (!titleItem.useUpPossibleWidth) { + refreshItemPosition() + } + } + + onUseUpPossibleWidthChanged: refreshItemPosition() } AppMenu { id: menuItem property bool mouseIn: controlPartMouseAreaRestrictedToWidget ? menuItem.mouseInWidget : main.mouseInWidget height: main.height showItem: !noWindowActive && ((mouseIn && plasmoid.configuration.controlPartMenuShowOnMouseIn) || (!mouseIn && plasmoid.configuration.controlPartMenuShowOnMouseOut)) } ControlButtons { id: buttonsItem property bool mouseIn: controlPartMouseAreaRestrictedToWidget ? buttonsItem.mouseInWidget : main.mouseInWidget showItem: !noWindowActive && ((mouseIn && plasmoid.configuration.controlPartButtonsShowOnMouseIn) || (!mouseIn && plasmoid.configuration.controlPartButtonsShowOnMouseOut)) onWidthChanged: refreshItemPosition() } Rectangle { id: textSeparator x: 0 anchors.verticalCenter: main.verticalCenter height: 0.8 * parent.height width: 1 visible: plasmoid.configuration.appmenuSeparatorEnabled && menuItem.showItem color: theme.textColor opacity: 0.4 } 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() + onUseUpWidthItemChanged: 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) refreshItemPosition() } Component.onCompleted: { refreshControlPartOrder() refreshItemPosition() updateActiveWindowInfo() // actions 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() } 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 } } }