Very early KDE 6 release.

This commit is contained in:
wackyideas 2024-08-09 03:20:25 +02:00
parent 7cc4ccabbc
commit 686046d4f7
6272 changed files with 140920 additions and 529657 deletions

View file

@ -0,0 +1,228 @@
/*
SPDX-FileCopyrightText: 2018 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils as KCM
/**
* A copy of Kirigami.AboutPage adapted to KPluginMetadata instead of KAboutData
*/
KCM.SimpleKCM {
id: page
title: i18n("About")
property var metaData: Plasmoid.metaData
Component {
id: personDelegate
RowLayout {
height: implicitHeight + (Kirigami.Units.smallSpacing * 2)
spacing: Kirigami.Units.smallSpacing * 2
Kirigami.Icon {
width: Kirigami.Units.iconSizes.smallMedium
height: width
source: "user"
}
QQC2.Label {
text: modelData.name
textFormat: Text.PlainText
}
Row {
// Group action buttons together
spacing: 0
QQC2.ToolButton {
visible: modelData.emailAddress
width: height
icon.name: "mail-sent"
display: QQC2.AbstractButton.IconOnly
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Send an email to %1", modelData.emailAddress)
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
onClicked: Qt.openUrlExternally("mailto:%1".arg(modelData.emailAddress))
}
QQC2.ToolButton {
visible: modelData.webAddress
width: height
icon.name: "globe"
display: QQC2.AbstractButton.IconOnly
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@info:tooltip %1 url", "Open website %1", modelData.webAddress)
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: modelData.webAddress
onClicked: Qt.openUrlExternally(modelData.webAddress)
}
}
}
}
Component {
id: licenseComponent
Kirigami.OverlaySheet {
property alias text: licenseLabel.text
onClosed: destroy()
Kirigami.SelectableLabel {
id: licenseLabel
implicitWidth: Math.max(Kirigami.Units.gridUnit * 25, Math.round(page.width / 2), contentWidth)
wrapMode: Text.WordWrap
}
Component.onCompleted: open();
}
}
Item {
height: childrenRect.height
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Kirigami.Units.largeSpacing
GridLayout {
columns: 2
Layout.fillWidth: true
Kirigami.Icon {
Layout.rowSpan: 2
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
Layout.preferredWidth: height
Layout.maximumWidth: page.width / 3;
Layout.rightMargin: Kirigami.Units.largeSpacing
source: page.metaData.iconName || page.metaData.pluginId
fallback: "application-x-plasma"
}
Kirigami.Heading {
Layout.fillWidth: true
text: page.metaData.name + " " + page.metaData.version
textFormat: Text.PlainText
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 15
level: 2
wrapMode: Text.WordWrap
text: page.metaData.description
textFormat: Text.PlainText
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
Kirigami.Heading {
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Copyright")
textFormat: Text.PlainText
}
ColumnLayout {
spacing: Kirigami.Units.smallSpacing
Layout.leftMargin: Kirigami.Units.smallSpacing
QQC2.Label {
text: page.metaData.copyrightText
textFormat: Text.PlainText
visible: text.length > 0
}
Kirigami.UrlButton {
url: page.metaData.website
visible: url.length > 0
}
RowLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "License:")
textFormat: Text.PlainText
}
Kirigami.LinkButton {
text: page.metaData.license
Accessible.description: i18ndc("plasma_shell_org.kde.plasma.desktop", "@info:whatsthis", "View license text")
onClicked: {
licenseComponent.incubateObject(page.Window.window.contentItem, {
"text": page.metaData.licenseText,
"title": page.metaData.license,
}, Qt.Asynchronous);
}
}
}
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Authors")
textFormat: Text.PlainText
visible: page.metaData.authors.length > 0
}
Repeater {
model: page.metaData.authors
delegate: personDelegate
}
Kirigami.Heading {
height: visible ? implicitHeight : 0
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Credits")
textFormat: Text.PlainText
visible: repCredits.count > 0
}
Repeater {
id: repCredits
model: page.metaData.otherContributors
delegate: personDelegate
}
Kirigami.Heading {
height: visible ? implicitHeight : 0
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Translators")
textFormat: Text.PlainText
visible: repTranslators.count > 0
}
Repeater {
id: repTranslators
model: page.metaData.translators
delegate: personDelegate
}
Item {
Layout.fillWidth: true
}
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
icon.name: "tools-report-bug"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Report a Bug…")
visible: page.metaData.bugReportUrl.length > 0
onClicked: Qt.openUrlExternally(page.metaData.bugReportUrl)
}
}
}
}

View file

@ -0,0 +1,452 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-FileCopyrightText: 2022-2023 ivan tkachenko <me@ratijas.tk>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami as Kirigami
import org.kde.kitemmodels 1.0 as KItemModels
import org.kde.plasma.configuration 2.0
import org.kde.plasma.plasmoid 2.0
Rectangle {
id: root
implicitWidth: Kirigami.Units.gridUnit * 40
implicitHeight: Kirigami.Units.gridUnit * 30
Layout.minimumWidth: Kirigami.Units.gridUnit * 30
Layout.minimumHeight: Kirigami.Units.gridUnit * 21
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
color: Kirigami.Theme.backgroundColor
property bool isContainment: false
property ConfigModel globalConfigModel: globalAppletConfigModel
property url currentSource
function closing() {
if (applyButton.enabled) {
messageDialog.item = null;
messageDialog.open();
return false;
}
return true;
}
function saveConfig() {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const cfgKey = "cfg_" + key;
if (cfgKey in app.pageStack.currentItem) {
config[key] = app.pageStack.currentItem[cfgKey];
}
})
plasmoid.configuration.writeConfig();
// For ConfigurationContainmentActions.qml
if (app.pageStack.currentItem.hasOwnProperty("saveConfig")) {
app.pageStack.currentItem.saveConfig()
}
}
Connections {
target: configDialog
function onClosing(event) {
event.accepted = closing();
}
}
ConfigModel {
id: globalAppletConfigModel
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Keyboard Shortcuts")
icon: "preferences-desktop-keyboard"
source: Qt.resolvedUrl("ConfigurationShortcuts.qml")
}
}
KItemModels.KSortFilterProxyModel {
id: configDialogFilterModel
sourceModel: configDialog.configModel
filterRowCallback: (row, parent) => {
return sourceModel.data(sourceModel.index(row, 0), ConfigModel.VisibleRole);
}
}
function settingValueChanged() {
applyButton.enabled = true;
}
function pushReplace(item, config) {
let page;
if (app.pageStack.depth === 0) {
page = app.pageStack.push(item, config);
} else {
page = app.pageStack.replace(item, config);
}
app.currentConfigPage = page;
}
Component {
id: configurationKcmPageComponent
ConfigurationKcmPage {
}
}
function open(item) {
app.isAboutPage = false;
root.currentSource = item.source
if (item.source) {
app.isAboutPage = item.source === Qt.resolvedUrl("AboutPlugin.qml");
if (isContainment) {
pushReplace(Qt.resolvedUrl("ConfigurationAppletPage.qml"), {configItem: item});
} else {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
const props = {
"title": item.name
};
config.keys().forEach(key => {
props["cfg_" + key] = config[key];
});
pushReplace(item.source, props);
}
} else if (item.kcm) {
pushReplace(configurationKcmPageComponent, {kcm: item.kcm, internalPage: item.kcm.mainUi});
} else {
app.pageStack.pop();
}
applyButton.enabled = false
}
Connections {
target: app.currentConfigPage
function onSettingValueChanged() {
applyButton.enabled = true;
}
}
Connections {
target: app.pageStack
function onCurrentItemChanged() {
if (app.pageStack.currentItem !== null && !isContainment) {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const changedSignal = app.pageStack.currentItem["cfg_" + key + "Changed"];
if (changedSignal) {
changedSignal.connect(() => root.settingValueChanged());
}
});
const configurationChangedSignal = app.pageStack.currentItem.configurationChanged;
if (configurationChangedSignal) {
configurationChangedSignal.connect(() => root.settingValueChanged());
}
}
}
}
Component.onCompleted: {
// if we are a containment then the first item will be ConfigurationContainmentAppearance
// if the applet does not have own configs then the first item will be Shortcuts
if (isContainment || !configDialog.configModel || configDialog.configModel.count === 0) {
open(root.globalConfigModel.get(0))
} else {
open(configDialog.configModel.get(0))
}
}
function applicationWindow() {
return app;
}
QQC2.ScrollView {
id: categoriesScroll
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
width: Kirigami.Units.gridUnit * 7
contentWidth: availableWidth
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
activeFocusOnTab: true
focus: true
Accessible.role: Accessible.MenuBar
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}
Keys.onUpPressed: {
const buttons = categories.children
let foundPrevious = false
for (let i = buttons.length - 1; i >= 0; --i) {
const button = buttons[i];
if (!button.hasOwnProperty("highlighted")) {
// not a ConfigCategoryDelegate
continue;
}
if (foundPrevious) {
categories.openCategory(button.item)
categoriesScroll.forceActiveFocus(Qt.TabFocusReason)
return
} else if (button.highlighted) {
foundPrevious = true
}
}
event.accepted = false
}
Keys.onDownPressed: {
const buttons = categories.children
let foundNext = false
for (let i = 0, length = buttons.length; i < length; ++i) {
const button = buttons[i];
if (!button.hasOwnProperty("highlighted")) {
continue;
}
if (foundNext) {
categories.openCategory(button.item)
categoriesScroll.forceActiveFocus(Qt.TabFocusReason)
return
} else if (button.highlighted) {
foundNext = true
}
}
event.accepted = false
}
ColumnLayout {
id: categories
spacing: 0
width: categoriesScroll.contentWidth
focus: true
function openCategory(item) {
if (applyButton.enabled) {
messageDialog.item = item;
messageDialog.open();
return;
}
open(item)
}
Component {
id: categoryDelegate
ConfigCategoryDelegate {
id: delegate
onActivated: categories.openCategory(model);
highlighted: {
if (app.pageStack.currentItem) {
if (model.kcm && app.pageStack.currentItem.kcm) {
return model.kcm == app.pageStack.currentItem.kcm
} else {
return root.currentSource == model.source
}
}
return false
}
item: model
}
}
Repeater {
Layout.fillWidth: true
model: root.isContainment ? globalConfigModel : undefined
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: configDialogFilterModel
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: !root.isContainment ? globalConfigModel : undefined
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: ConfigModel {
ConfigCategory{
name: i18nd("plasma_shell_org.kde.plasma.desktop", "About")
icon: "help-about"
source: Qt.resolvedUrl("AboutPlugin.qml")
}
}
delegate: categoryDelegate
}
}
}
Kirigami.Separator {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
z: 1
}
Kirigami.Separator {
id: verticalSeparator
anchors {
top: parent.top
left: categoriesScroll.right
bottom: parent.bottom
}
z: 1
}
Kirigami.ApplicationItem {
id: app
anchors {
top: parent.top
left: verticalSeparator.right
right: parent.right
bottom: parent.bottom
}
pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.Breadcrumb
wideScreen: true
pageStack.globalToolBar.separatorVisible: bottomSeparator.visible
pageStack.globalToolBar.colorSet: Kirigami.Theme.Window
property var currentConfigPage: null
property bool isAboutPage: false
Kirigami.PromptDialog {
id: messageDialog
property var item
title: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply Settings")
subtitle: i18nd("plasma_shell_org.kde.plasma.desktop", "The settings of the current module have changed. Do you want to apply the changes or discard them?")
standardButtons: Kirigami.Dialog.Apply | Kirigami.Dialog.Discard | Kirigami.Dialog.Cancel
onApplied: {
applyAction.trigger()
discarded();
}
onDiscarded: {
if (item) {
root.open(item);
messageDialog.close();
} else {
applyButton.enabled = false;
configDialog.close();
}
}
}
footer: QQC2.Pane {
padding: Kirigami.Units.largeSpacing
contentItem: RowLayout {
id: buttonsRow
spacing: Kirigami.Units.smallSpacing
Item {
Layout.fillWidth: true
}
QQC2.Button {
icon.name: "dialog-ok"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "OK")
onClicked: acceptAction.trigger()
KeyNavigation.tab: categories
}
QQC2.Button {
id: applyButton
enabled: false
icon.name: "dialog-ok-apply"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply")
visible: !app.isAboutPage && app.pageStack.currentItem && (!app.pageStack.currentItem.kcm || app.pageStack.currentItem.kcm.buttons & 4) // 4 = Apply button
onClicked: applyAction.trigger()
}
QQC2.Button {
icon.name: "dialog-cancel"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Cancel")
onClicked: cancelAction.trigger()
visible: !app.isAboutPage
}
}
background: Item {
Kirigami.Separator {
id: bottomSeparator
visible: app.pageStack.currentItem
&& app.pageStack.currentItem.flickable
&& !(app.pageStack.currentItem.flickable.atYBeginning
&& app.pageStack.currentItem.flickable.atYEnd)
anchors {
left: parent.left
right: parent.right
top: parent.top
}
}
}
}
QQC2.Action {
id: acceptAction
onTriggered: {
applyAction.trigger();
configDialog.close();
}
}
QQC2.Action {
id: applyAction
onTriggered: {
if (isContainment) {
app.pageStack.get(0).saveConfig()
} else {
root.saveConfig()
}
applyButton.enabled = false;
}
}
QQC2.Action {
id: cancelAction
onTriggered: {
if (root.closing()) {
configDialog.close();
}
}
}
Keys.onReturnPressed: acceptAction.trigger();
Keys.onEscapePressed: cancelAction.trigger();
}
}

View file

@ -0,0 +1,71 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Window 2.2
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kirigami 2.5 as Kirigami
QQC2.ItemDelegate {
id: delegate
signal activated()
//BEGIN properties
Layout.fillWidth: true
hoverEnabled: true
Accessible.role: Accessible.MenuItem
Accessible.name: model.name
Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open configuration page")
Accessible.onPressAction: delegate.clicked()
property var item
//END properties
//BEGIN connections
onClicked: {
if (highlighted) {
return;
}
activated()
}
//END connections
//BEGIN UI components
contentItem: ColumnLayout {
id: delegateContents
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
source: model.icon
selected: Window.active && (delegate.highlighted || delegate.pressed)
}
QQC2.Label {
id: nameLabel
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
text: model.name
textFormat: Text.PlainText
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
color: Window.active && (delegate.highlighted || delegate.pressed) ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
font.bold: delegate.highlighted && delegate.parent.activeFocus
Accessible.ignored: true
}
}
//END UI components
}

View file

@ -0,0 +1,81 @@
/*
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.10 as Kirigami
Kirigami.ScrollablePage {
id: root
title: configItem.name
required property var configItem
signal settingValueChanged()
function saveConfig() {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const cfgKey = "cfg_" + key;
if (cfgKey in loader.item) {
config[key] = loader.item[cfgKey];
}
})
Plasmoid.configuration.writeConfig();
// For ConfigurationContainmentActions.qml
if (loader.item.hasOwnProperty("saveConfig")) {
loader.item.saveConfig()
}
}
implicitHeight: loader.height
padding: configItem.includeMargins ? Kirigami.Units.largeSpacing : 0
bottomPadding: 0
Loader {
id: loader
width: parent.width
// HACK the height of the loader is based on the implicitHeight of the content.
// Unfortunately not all content items have a sensible implicitHeight.
// If it is zero fall back to the height of its children
// Also make it at least as high as the page itself. Some existing configs assume they fill the whole space
// TODO KF6 clean this up by making all configs based on SimpleKCM/ScrollViewKCM/GridViewKCM
height: Math.max(root.availableHeight, item.implicitHeight ? item.implicitHeight : item.childrenRect.height)
Component.onCompleted: {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
const props = {};
config.keys().forEach(key => {
props["cfg_" + key] = config[key];
});
setSource(configItem.source, props);
}
onLoaded: {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const changedSignal = item["cfg_" + key + "Changed"];
if (changedSignal) {
changedSignal.connect(() => root.settingValueChanged());
}
});
const configurationChangedSignal = item.configurationChanged;
if (configurationChangedSignal) {
configurationChangedSignal.connect(() => root.settingValueChanged());
}
}
}
}

View file

@ -0,0 +1,190 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.0
import org.kde.kirigami 2.20 as Kirigami
Item {
id: root
signal configurationChanged
implicitWidth: mainColumn.implicitWidth
implicitHeight: mainColumn.implicitHeight
property var prettyStrings: {
"LeftButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Left-Button"),
"RightButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Right-Button"),
"MiddleButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Middle-Button"),
"BackButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Back-Button"),
"ForwardButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Forward-Button"),
"wheel:Vertical": i18nd("plasma_shell_org.kde.plasma.desktop", "Vertical-Scroll"),
"wheel:Horizontal": i18nd("plasma_shell_org.kde.plasma.desktop", "Horizontal-Scroll"),
"ShiftModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Shift"),
"ControlModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Ctrl"),
"AltModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Alt"),
"MetaModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Meta")
}
function saveConfig() {
configDialog.currentContainmentActionsModel.save();
}
Connections {
target: configDialog.currentContainmentActionsModel
function onConfigurationChanged() {
root.configurationChanged()
}
}
Component {
id: aboutComponent
Kirigami.OverlaySheet {
id: internalAboutDialog
property alias metaData: aboutPluginPage.metaData
width: Math.round(root.width * 0.8)
onClosed: destroy()
AboutPlugin {
id: aboutPluginPage
metaData: internalAboutDialog.metaData
}
Component.onCompleted: open();
}
}
GridLayout {
id: mainColumn
flow: GridLayout.TopToBottom
y: 25
width: parent.width
Repeater {
id: actionsRepeater
model: configDialog.currentContainmentActionsModel
MouseEventInputButton {
Layout.column: 0
Layout.row: index
Layout.fillWidth: true
Layout.minimumWidth: implicitWidth
defaultText: {
var splitAction = model.action.split(';');
var button = splitAction[0];
var modifiers = (splitAction[1] || "").split('|').filter(function (item) {
return item !== "NoModifier";
});
var parts = modifiers;
modifiers.push(button);
return parts.map(function (item) {
return prettyStrings[item] || item;
}).join(i18ndc("plasma_shell_org.kde.plasma.desktop", "Concatenation sign for shortcuts, e.g. Ctrl+Shift", "+"));
}
eventString: model.action
onEventStringChanged: {
configDialog.currentContainmentActionsModel.update(index, eventString, model.pluginName);
}
}
}
Repeater {
model: configDialog.currentContainmentActionsModel
QQC2.ComboBox {
id: pluginsCombo
// "index" argument of onActivated shadows the model index
readonly property int pluginIndex: index
Layout.fillWidth: true
Layout.column: 1
Layout.row: index
// both MouseEventInputButton and this ComboBox have fillWidth for a uniform layout
// however, their implicit sizes is taken into account and they compete against
// each other for available space. By setting an insane preferredWidth we give
// ComboBox a greater share of the available space
Layout.preferredWidth: 9000
model: configDialog.containmentActionConfigModel
textRole: "name"
property bool initialized: false
Component.onCompleted: {
for (var i = 0; i < configDialog.containmentActionConfigModel.count; ++i) {
if (configDialog.containmentActionConfigModel.get(i).pluginName === pluginName) {
pluginsCombo.currentIndex = i;
break;
}
}
pluginsCombo.initialized = true;
}
onActivated: {
if (initialized) {
var newPluginName = configDialog.containmentActionConfigModel.get(index).pluginName;
if (newPluginName !== pluginName) {
configDialog.currentContainmentActionsModel.update(pluginIndex, action, newPluginName);
}
}
}
}
}
Repeater {
model: configDialog.currentContainmentActionsModel
RowLayout {
Layout.column: 2
Layout.row: index
QQC2.Button {
icon.name: "configure"
width: height
enabled: model.hasConfigurationInterface
onClicked: {
configDialog.currentContainmentActionsModel.showConfiguration(index, this);
}
}
QQC2.Button {
icon.name: "dialog-information"
width: height
onClicked: {
const metaData = configDialog.currentContainmentActionsModel.aboutMetaData(index);
if (!metaData) {
return;
}
aboutComponent.incubateObject(root.Window.window.contentItem, {
"metaData": metaData,
"title": i18ndc("plasma_shell_org.kde.plasma.desktop", "@title", "About"),
}, Qt.Asynchronous);
}
}
QQC2.Button {
icon.name: "list-remove"
width: height
onClicked: {
configDialog.currentContainmentActionsModel.remove(index);
}
}
}
}
MouseEventInputButton {
defaultText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Action");
icon.name: checked ? "input-mouse-symbolic" : "list-add"
onEventStringChanged: {
configDialog.currentContainmentActionsModel.append(eventString, "org.kde.contextmenu");
}
}
}
}

View file

@ -0,0 +1,213 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.configuration 2.0
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.1
import QtQml 2.15
import org.kde.newstuff 1.62 as NewStuff
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.configuration 2.0
Item {
id: appearanceRoot
signal configurationChanged
property int formAlignment: wallpaperComboBox.Kirigami.ScenePosition.x - appearanceRoot.Kirigami.ScenePosition.x + Kirigami.Units.smallSpacing
property string currentWallpaper: ""
property string containmentPlugin: ""
property alias parentLayout: parentLayout
function saveConfig() {
if (main.currentItem.saveConfig) {
main.currentItem.saveConfig()
}
configDialog.currentWallpaper = appearanceRoot.currentWallpaper;
for (var key in configDialog.wallpaperConfiguration) {
if (main.currentItem["cfg_"+key] !== undefined) {
configDialog.wallpaperConfiguration[key] = main.currentItem["cfg_"+key]
}
}
configDialog.applyWallpaper()
configDialog.containmentPlugin = appearanceRoot.containmentPlugin
}
ColumnLayout {
width: root.availableWidth
height: Math.max(implicitHeight, root.availableHeight)
spacing: 0 // unless it's 0 there will be an additional gap between two FormLayouts
Component.onCompleted: {
for (var i = 0; i < configDialog.containmentPluginsConfigModel.count; ++i) {
var pluginName = configDialog.containmentPluginsConfigModel.data(configDialog.containmentPluginsConfigModel.index(i, 0), ConfigModel.PluginNameRole);
if (configDialog.containmentPlugin === pluginName) {
pluginComboBox.currentIndex = i
pluginComboBox.activated(i);
break;
}
}
for (var i = 0; i < configDialog.wallpaperConfigModel.count; ++i) {
var pluginName = configDialog.wallpaperConfigModel.data(configDialog.wallpaperConfigModel.index(i, 0), ConfigModel.PluginNameRole);
if (configDialog.currentWallpaper === pluginName) {
wallpaperComboBox.currentIndex = i
wallpaperComboBox.activated(i);
break;
}
}
}
Kirigami.InlineMessage {
visible: Plasmoid.immutable || animating
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes have been restricted by the system administrator")
showCloseButton: true
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing * 2 // we need this because ColumnLayout's spacing is 0
}
Kirigami.FormLayout {
id: parentLayout // needed for twinFormLayouts to work in wallpaper plugins
twinFormLayouts: main.currentItem.formLayout || []
Layout.fillWidth: true
QQC2.ComboBox {
id: pluginComboBox
Layout.preferredWidth: Math.max(implicitWidth, wallpaperComboBox.implicitWidth)
Kirigami.FormData.label: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout:")
enabled: !Plasmoid.immutable
model: configDialog.containmentPluginsConfigModel
textRole: "name"
onActivated: {
var model = configDialog.containmentPluginsConfigModel.get(currentIndex)
appearanceRoot.containmentPlugin = model.pluginName
appearanceRoot.configurationChanged()
}
}
RowLayout {
Layout.fillWidth: true
enabled: main.currentItem.objectName !== "switchContainmentWarningItem"
Kirigami.FormData.label: i18nd("plasma_shell_org.kde.plasma.desktop", "Wallpaper type:")
QQC2.ComboBox {
id: wallpaperComboBox
Layout.preferredWidth: Math.max(implicitWidth, pluginComboBox.implicitWidth)
model: configDialog.wallpaperConfigModel
textRole: "name"
onActivated: {
var idx = configDialog.wallpaperConfigModel.index(currentIndex, 0)
var pluginName = configDialog.wallpaperConfigModel.data(idx, ConfigModel.PluginNameRole)
if (appearanceRoot.currentWallpaper === pluginName) {
return;
}
appearanceRoot.currentWallpaper = pluginName
configDialog.currentWallpaper = pluginName
main.sourceFile = configDialog.wallpaperConfigModel.data(idx, ConfigModel.SourceRole)
appearanceRoot.configurationChanged()
}
}
NewStuff.Button {
configFile: "wallpaperplugin.knsrc"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Get New Plugins…")
visibleWhenDisabled: true // don't hide on disabled
Layout.preferredHeight: wallpaperComboBox.height
}
}
}
Item {
id: emptyConfig
}
QQC2.StackView {
id: main
implicitHeight: main.empty ? 0 : currentItem.implicitHeight
Layout.fillHeight: true;
Layout.fillWidth: true;
// Bug 360862: if wallpaper has no config, sourceFile will be ""
// so we wouldn't load emptyConfig and break all over the place
// hence set it to some random value initially
property string sourceFile: "tbd"
onSourceFileChanged: loadSourceFile()
function loadSourceFile() {
const wallpaperConfig = configDialog.wallpaperConfiguration
// BUG 407619: wallpaperConfig can be null before calling `ContainmentItem::loadWallpaper()`
if (wallpaperConfig && sourceFile) {
var props = {
"configDialog": configDialog
}
for (var key in wallpaperConfig) {
props["cfg_" + key] = wallpaperConfig[key]
}
var newItem = replace(Qt.resolvedUrl(sourceFile), props)
for (var key in wallpaperConfig) {
var changedSignal = newItem["cfg_" + key + "Changed"]
if (changedSignal) {
changedSignal.connect(appearanceRoot.configurationChanged)
}
}
const configurationChangedSignal = newItem.configurationChanged
if (configurationChangedSignal) {
configurationChangedSignal.connect(appearanceRoot.configurationChanged)
}
} else {
replace(emptyConfig)
}
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
}
Component {
id: switchContainmentWarning
Item {
objectName: "switchContainmentWarningItem"
Kirigami.PlaceholderMessage {
id: message
width: parent.width - Kirigami.Units.largeSpacing * 8
anchors.centerIn: parent
icon.name: "documentinfo"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes must be applied before other changes can be made")
helpfulAction: QQC2.Action {
icon.name: "dialog-ok-apply"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply Now")
onTriggered: saveConfig()
}
}
}
}
onContainmentPluginChanged: {
if (configDialog.containmentPlugin !== appearanceRoot.containmentPlugin) {
main.push(switchContainmentWarning);
categoriesScroll.enabled = false;
} else if (main.currentItem.objectName === "switchContainmentWarningItem") {
main.pop();
categoriesScroll.enabled = true;
}
}
}

View file

@ -0,0 +1,74 @@
/*
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6
import org.kde.kirigami 2.5 as Kirigami
Kirigami.Page {
id: container
required property QtObject kcm
required property Item internalPage
signal settingValueChanged()
title: kcm.name
topPadding: 0
leftPadding: 0
rightPadding: 0
bottomPadding: 0
flickable: internalPage.flickable
actions: internalPage.actions
onInternalPageChanged: {
internalPage.parent = contentItem;
internalPage.anchors.fill = contentItem;
}
onActiveFocusChanged: {
if (activeFocus) {
internalPage.forceActiveFocus();
}
}
Component.onCompleted: {
kcm.load()
}
function saveConfig() {
kcm.save();
}
data: [
Connections {
target: kcm
onPagePushed: {
app.pageStack.push(configurationKcmPageComponent.createObject(app.pageStack, {"kcm": kcm, "internalPage": page}));
}
onPageRemoved: app.pageStack.pop();
},
Connections {
target: app.pageStack
onPageRemoved: {
if (kcm.needsSave) {
kcm.save()
}
if (page == container) {
page.destroy();
}
}
}
]
Connections {
target: kcm
function onNeedsSaveChanged() {
if (kcm.needsSave) {
container.settingValueChanged()
}
}
}
}

View file

@ -0,0 +1,46 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.0
import org.kde.kquickcontrols 2.0
import org.kde.kirigami 2.14 as Kirigami
import org.kde.plasma.plasmoid 2.0
import org.kde.kcmutils as KCM
KCM.SimpleKCM {
id: root
title: i18n("Shortcuts")
signal configurationChanged
function saveConfig() {
Plasmoid.globalShortcut = button.keySequence
}
ColumnLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
Layout.fillWidth: true
text: i18nd("plasma_shell_org.kde.plasma.desktop", "This shortcut will activate the applet as though it had been clicked.")
textFormat: Text.PlainText
wrapMode: Text.WordWrap
}
KeySequenceItem {
id: button
keySequence: Plasmoid.globalShortcut
modifierOnlyAllowed: true
onCaptureFinished: {
if (keySequence !== Plasmoid.globalShortcut) {
root.configurationChanged();
}
}
}
}
}

View file

@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.0
import org.kde.kirigami 2.15 as Kirigami
import org.kde.plasma.configuration 2.0
import org.kde.plasma.plasmoid 2.0
AppletConfiguration {
id: root
isContainment: true
Layout.minimumWidth: Kirigami.Units.gridUnit * 35
Layout.minimumHeight: Kirigami.Units.gridUnit * 30
Layout.preferredWidth: Kirigami.Units.gridUnit * 32
Layout.preferredHeight: Kirigami.Units.gridUnit * 36
//BEGIN model
globalConfigModel: globalContainmentConfigModel
ConfigModel {
id: globalContainmentConfigModel
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Wallpaper")
icon: "preferences-desktop-wallpaper"
source: "ConfigurationContainmentAppearance.qml"
includeMargins: false
}
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Mouse Actions")
icon: "preferences-desktop-mouse"
source: "ConfigurationContainmentActions.qml"
}
}
//END model
}

View file

@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Controls 2.3 as QQC2
QQC2.Button {
id: mouseInputButton
property string defaultText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Action")
text: defaultText
checkable: true
property string eventString
onCheckedChanged: {
if (checked) {
text = i18nd("plasma_shell_org.kde.plasma.desktop", "Input Here");
mouseInputArea.enabled = true;
}
}
MouseArea {
id: mouseInputArea
anchors.fill: parent
acceptedButtons: Qt.AllButtons
enabled: false
onClicked: {
var newEventString = configDialog.currentContainmentActionsModel.mouseEventString(mouse.button, mouse.modifiers);
if (eventString === newEventString || !configDialog.currentContainmentActionsModel.isTriggerUsed(newEventString)) {
eventString = newEventString;
mouseInputButton.text = defaultText;
mouseInputButton.checked = false;
enabled = false;
}
}
onWheel: {
var newEventString = configDialog.currentContainmentActionsModel.wheelEventString(wheel);
if (eventString === newEventString || !configDialog.currentContainmentActionsModel.isTriggerUsed(newEventString)) {
eventString = newEventString;
mouseInputButton.text = defaultText;
mouseInputButton.checked = false;
enabled = false;
}
}
}
}

View file

@ -0,0 +1,632 @@
/*
SPDX-FileCopyrightText: 2023 Niccolò Venerandi <niccolo.venerandi@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
import "panelconfiguration"
ColumnLayout {
id: dialogRoot
spacing: Kirigami.Units.largeSpacing * 2
signal closeContextMenu
required property QtObject panelConfiguration
property bool vertical: (panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge)
readonly property int headingLevel: 2
property Item panelRuler: Ruler {
id: ruler
prefix: {
switch (panel.location) {
case PlasmaCore.Types.TopEdge:
return "north"
case PlasmaCore.Types.LeftEdge:
return "west"
case PlasmaCore.Types.RightEdge:
return "east"
case PlasmaCore.Types.BottomEdge:
default:
return "south"
}
}
Item {
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus && dialogRoot.Window.window && dialogRoot.Window.window.visible) {
dialogRoot.Window.window.requestActivate()
}
}
}
// This item is used to "pass" focus to the main window when we're at the last of the control of the ruler
Item {
parent: dialogRoot.parent // Used to not take space in the ColumnLayout
activeFocusOnTab: true
onActiveFocusChanged: {
let window = dialogRoot.Window.window
if (activeFocus && window && window.visible) {
window.requestActivate()
}
}
}
}
Connections {
target: panel
function onOffsetChanged() {
ruler.offset = panel.offset
}
function onMinimumLengthChanged() {
ruler.minimumLength = panel.minimumLength
}
function onMaximumLengthChanged() {
ruler.maximumLength = panel.maximumLength
}
}
Component.onCompleted: {
if (panel.lengthMode === Panel.Global.Custom) {
Qt.callLater(()=> {
panelConfiguration.panelRulerView.visible = true
})
}
}
PlasmaExtras.PlasmoidHeading {
RowLayout {
anchors.fill: parent
spacing: Kirigami.Units.largeSpacing
Kirigami.Heading {
Layout.leftMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Settings")
textFormat: Text.PlainText
}
Item { Layout.fillWidth: true }
PC3.ToolButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Spacer")
icon.name: "distribute-horizontal-x"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add spacer widget to the panel")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: configDialog.addPanelSpacer()
}
PC3.ToolButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Widgets…")
icon.name: "list-add"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Open the widget selector to drag and drop widgets to the panel")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: {
configDialog.close()
configDialog.showAddWidgetDialog()
}
}
}
}
GridLayout {
Layout.leftMargin: columnSpacing
Layout.rightMargin: columnSpacing
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: (positionRepresentation.implicitWidth + columnSpacing) * columns + columnSpacing
rowSpacing: dialogRoot.spacing
columnSpacing: Kirigami.Units.smallSpacing
rows: 2
columns: 3
uniformCellWidths: true
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Position")
textFormat: Text.PlainText
}
PanelRepresentation {
id: positionRepresentation
text: (panel.location === PlasmaCore.Types.TopEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Top") :
panel.location === PlasmaCore.Types.RightEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Right") :
panel.location === PlasmaCore.Types.LeftEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Left") :
i18nd("plasma_shell_org.kde.plasma.desktop", "Bottom"))
Layout.alignment: Qt.AlignHCenter
alignment: (panel.location === PlasmaCore.Types.TopEdge ? Qt.AlignHCenter | Qt.AlignTop :
panel.location === PlasmaCore.Types.RightEdge ? Qt.AlignVCenter | Qt.AlignRight :
panel.location === PlasmaCore.Types.LeftEdge ? Qt.AlignVCenter | Qt.AlignLeft :
Qt.AlignHCenter | Qt.AlignBottom)
isVertical: dialogRoot.vertical
mainIconSource: (panel.location === PlasmaCore.Types.TopEdge ? "arrow-up" :
panel.location === PlasmaCore.Types.RightEdge ? "arrow-right" :
panel.location === PlasmaCore.Types.LeftEdge ? "arrow-left": "arrow-down")
onClicked: {
setPositionButton.checked = !setPositionButton.checked
setPositionButton.forceActiveFocus()
}
}
PC3.Button {
id: setPositionButton
Layout.minimumHeight: transparencyBox.height
Layout.minimumWidth: positionRepresentation.width
Layout.alignment: Qt.AlignHCenter
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Set Position…")
checkable: true
function moveTo(newLocation: int, associatedWindow = null) {
if (!setPositionButton.checked) {
return;
}
panel.location = newLocation;
if (associatedWindow !== null) {
panel.screenToFollow = dialogRoot.panelConfiguration.screenFromWindow(associatedWindow);
}
setPositionButton.checked = false;
}
Keys.onLeftPressed: moveTo(PlasmaCore.Types.LeftEdge)
Keys.onRightPressed: moveTo(PlasmaCore.Types.RightEdge)
Keys.onUpPressed: moveTo(PlasmaCore.Types.TopEdge)
Keys.onDownPressed: moveTo(PlasmaCore.Types.BottomEdge)
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Alignment")
textFormat: Text.PlainText
}
PanelRepresentation {
id: alignmentRepresentation
Layout.alignment: Qt.AlignHCenter
mainIconSource: {
if (dialogRoot.vertical) {
if (alignmentBox.previewIndex === 0) {
return "align-vertical-top"
} else if (alignmentBox.previewIndex === 1) {
return "align-vertical-center"
} else {
return "align-vertical-bottom"
}
} else {
if (alignmentBox.previewIndex === 0) {
return "align-horizontal-left"
} else if (alignmentBox.previewIndex === 1) {
return "align-horizontal-center"
} else {
return "align-horizontal-right"
}
}
}
alignment: {
let first, second;
if (dialogRoot.vertical) {
if (alignmentBox.previewIndex === 0) {
first = Qt.AlignTop
} else if (alignmentBox.previewIndex === 1) {
first = Qt.AlignVCenter
} else {
first = Qt.AlignBottom
}
if (panel.location === PlasmaCore.Types.LeftEdge) {
second = Qt.AlignLeft
} else {
second = Qt.AlignRight
}
} else {
if (alignmentBox.previewIndex === 0) {
first = Qt.AlignLeft
} else if (alignmentBox.previewIndex === 1) {
first = Qt.AlignHCenter
} else {
first = Qt.AlignRight
}
if (panel.location === PlasmaCore.Types.TopEdge) {
second = Qt.AlignTop
} else {
second = Qt.AlignBottom
}
}
return first | second;
}
onClicked: alignmentBox.popup.visible = true
isVertical: dialogRoot.vertical
}
PC3.ComboBox {
id: alignmentBox
property int previewIndex: highlightedIndex > -1 ? highlightedIndex : currentIndex
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: alignmentRepresentation.width
model: [
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Top") : i18nd("plasma_shell_org.kde.plasma.desktop", "Left"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Center"),
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Bottom") : i18nd("plasma_shell_org.kde.plasma.desktop", "Right")
]
currentIndex: (panel.alignment === Qt.AlignLeft ? 0 :
panel.alignment === Qt.AlignCenter ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.alignment = Qt.AlignLeft
} else if (index === 1) {
panel.alignment = Qt.AlignCenter
} else {
panel.alignment = Qt.AlignRight
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
level: dialogRoot.headingLevel
Layout.alignment: Qt.AlignHCenter
text: dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Height")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Width")
textFormat: Text.PlainText
}
PanelRepresentation {
id: lengthRepresentation
Layout.alignment: Qt.AlignHCenter
mainIconSource: (widthBox.previewIndex === 1 ? "gnumeric-ungroup" :
widthBox.previewIndex === 0 ? (dialogRoot.vertical ? "panel-fit-height" : "panel-fit-width") : "kdenlive-custom-effect")
isVertical: dialogRoot.vertical
alignment: positionRepresentation.alignment
fillAvailable: widthBox.previewIndex === 0
onClicked: widthBox.popup.visible = true
}
PC3.ComboBox {
id: widthBox
property int previewIndex: highlightedIndex > -1 ? highlightedIndex : currentIndex
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: lengthRepresentation.width
model: [
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Fill height") : i18nd("plasma_shell_org.kde.plasma.desktop", "Fill width"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Fit content"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Custom")
]
currentIndex: (panel.lengthMode === Panel.Global.FillAvailable ? 0 :
panel.lengthMode === Panel.Global.FitContent ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.lengthMode = Panel.Global.FillAvailable
panelConfiguration.panelRulerView.visible = false
} else if (index === 1) {
panel.lengthMode = Panel.Global.FitContent
panelConfiguration.panelRulerView.visible = false
} else {
panel.lengthMode = Panel.Global.Custom
panelConfiguration.panelRulerView.visible = true
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Visibility")
textFormat: Text.PlainText
}
PanelRepresentation {
id: visibilityRepresentation
Layout.alignment: Qt.AlignHCenter
sunkenPanel: autoHideBox.previewIndex !== 0
onClicked: autoHideBox.popup.visible = true
}
PC3.ComboBox {
id: autoHideBox
property int previewIndex: popup.visible ? highlightedIndex : currentIndex
model: [
i18nd("plasma_shell_org.kde.plasma.desktop", "Always visible"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Auto hide"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Dodge windows"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Windows Go Below"),
]
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: visibilityRepresentation.width
currentIndex: {
switch (panel.visibilityMode) {
case Panel.Global.AutoHide:
return 1;
case Panel.Global.DodgeWindows:
return 2;
case Panel.Global.WindowsGoBelow:
return 3;
case Panel.Global.NormalPanel:
default:
return 0;
}
}
onActivated: (index) => {
switch (index) {
case 1:
panel.visibilityMode = Panel.Global.AutoHide;
break;
case 2:
panel.visibilityMode = Panel.Global.DodgeWindows;
break;
case 3:
panel.visibilityMode = Panel.Global.WindowsGoBelow;
break;
case 0:
default:
panel.visibilityMode = Panel.Global.NormalPanel;
break;
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Opacity")
textFormat: Text.PlainText
}
PanelRepresentation {
id: opacityRepresentation
Layout.alignment: Qt.AlignHCenter
adaptivePanel: transparencyBox.previewIndex === 0
translucentPanel: transparencyBox.previewIndex === 2
onClicked: transparencyBox.popup.visible = true
}
PC3.ComboBox {
id: transparencyBox
readonly property int previewIndex: popup.visible ? highlightedIndex : currentIndex
model: [
i18nd("plasma_shell_org.kde.plasma.desktop", "Adaptive"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Opaque"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Translucent")
]
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: opacityRepresentation.width
currentIndex: (panel.opacityMode === Panel.Global.Adaptive ? 0 :
panel.opacityMode === Panel.Global.Opaque ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.opacityMode = Panel.Global.Adaptive
} else if (index === 1) {
panel.opacityMode = Panel.Global.Opaque
} else {
panel.opacityMode = Panel.Global.Translucent
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Action {
id: floatingAction
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Floating")
checkable: true
checked: panel.floating
onToggled: source => {
panel.floating = checked;
}
}
Kirigami.Heading {
level: dialogRoot.headingLevel
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Style")
textFormat: Text.PlainText
}
PanelRepresentation {
Layout.alignment: Qt.AlignHCenter
floatingGap: Kirigami.Units.smallSpacing * floatingSwitch.checked
onClicked: floatingAction.toggle(this)
}
PC3.Switch {
id: floatingSwitch
Layout.alignment: Qt.AlignHCenter
Layout.minimumHeight: transparencyBox.height
action: floatingAction
}
}
}
Instantiator {
active: setPositionButton.checked
asynchronous: true
model: Application.screens
Item {
width: 0
height: 0
required property var modelData
component Indicator : PlasmaCore.Dialog {
id: root
property string iconSource
property var onClickedLocation
flags: Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint
location: PlasmaCore.Types.Floating
visible: setPositionButton.checked && (panel.location !== onClickedLocation || modelData.name !== panel.screenToFollow.name)
x: modelData.virtualX + Kirigami.Units.largeSpacing
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
mainItem: PC3.ToolButton {
width: Kirigami.Units.iconSizes.enormous
height: Kirigami.Units.iconSizes.enormous
icon.name: root.iconSource
onClicked: setPositionButton.moveTo(root.onClickedLocation, Window.window)
}
}
Indicator {
x: modelData.virtualX + Kirigami.Units.largeSpacing
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
iconSource: "arrow-left"
onClickedLocation: PlasmaCore.Types.LeftEdge
}
Indicator {
x: modelData.virtualX + modelData.width - Kirigami.Units.largeSpacing - margins.left - margins.right - mainItem.width
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
iconSource: "arrow-right"
onClickedLocation: PlasmaCore.Types.RightEdge
}
Indicator {
x: modelData.virtualX + modelData.width / 2 - mainItem.width / 2 - margins.left
y: modelData.virtualY + Kirigami.Units.largeSpacing
iconSource: "arrow-up"
onClickedLocation: PlasmaCore.Types.TopEdge
}
Indicator {
x: modelData.virtualX + modelData.width / 2 - mainItem.width / 2 - margins.left
y: modelData.virtualY + modelData.height - mainItem.height - margins.top - margins.bottom - Kirigami.Units.largeSpacing
iconSource: "arrow-down"
onClickedLocation: PlasmaCore.Types.BottomEdge
}
}
}
GridLayout {
Layout.alignment: Qt.AlignHCenter
rowSpacing: Kirigami.Units.largeSpacing
columnSpacing: Kirigami.Units.largeSpacing
rows: 2
columns: 2
PC3.Label {
id: spinBoxLabel
Layout.alignment: Qt.AlignRight
wrapMode: Text.Wrap
text: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge
? i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Width:")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Height:")
textFormat: Text.PlainText
}
PC3.SpinBox {
id: spinBox
editable: true
focus: !Kirigami.InputMethod.willShowOnActive
from: Math.max(20, panel.minThickness) // below this size, the panel is mostly unusable
to: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge
? panel.screenToFollow.geometry.width / 2
: panel.screenToFollow.geometry.height / 2
stepSize: 2
value: panel.thickness
onValueModified: {
panel.thickness = value
}
}
PC3.Label {
Layout.alignment: Qt.AlignRight
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Focus shortcut:")
textFormat: Text.PlainText
visible: panel.adaptiveOpacityEnabled
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
PC3.ToolTip {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Press this keyboard shortcut to move focus to the Panel")
visible: mouseArea.containsMouse
}
}
KeySequenceItem {
id: button
keySequence: plasmoid.globalShortcut
onCaptureFinished: {
plasmoid.globalShortcut = button.keySequence
}
}
}
PlasmaExtras.PlasmoidHeading {
position: PlasmaExtras.PlasmoidHeading.Footer
Layout.topMargin: Kirigami.Units.smallSpacing
topPadding: Kirigami.Units.smallSpacing * 2
leftPadding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
Layout.fillWidth: true
RowLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
spacing: Kirigami.Units.largeSpacing
PC3.ToolButton {
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button Delete the panel", "Delete Panel")
icon.name: "delete"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove this panel; this action is undo-able")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: plasmoid.internalAction("remove").trigger()
}
Item {Layout.fillWidth: true}
PC3.ToolButton {
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button Done configuring the panel", "Done")
icon.name: "dialog-ok-symbolic"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Close Panel Settings window and exit Edit Mode")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: plasmoid.containment.corona.editMode = false
}
}
}
// This item is used to "pass" focus to the ruler with tab when we're at the last of the control of this window
Item {
parent: dialogRoot.parent // Used to not take space in the ColumnLayout
activeFocusOnTab: true
onActiveFocusChanged: {
let window = ruler.Window.window
if (activeFocus && window && window.visible) {
window.requestActivate()
}
}
}
}

View file

@ -0,0 +1,85 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.15
import org.kde.kirigami 2.13 as Kirigami
import "shellcontainmentconfiguration"
Kirigami.AbstractApplicationWindow {
id: root
title: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel and Desktop Management")
width: Kirigami.Units.gridUnit * 40
height: Kirigami.Units.gridUnit * 32
minimumWidth: Kirigami.Units.gridUnit * 30
minimumHeight: Kirigami.Units.gridUnit * 25
header: QQC2.ToolBar {
anchors {
left: parent.left
right: parent.right
}
contentItem: QQC2.Label {
Layout.fillWidth: parent
text: i18nd("plasma_shell_org.kde.plasma.desktop", "You can drag Panels and Desktops around to move them to different screens.")
textFormat: Text.PlainText
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
footer: QQC2.Control {
contentItem: QQC2.DialogButtonBox {
QQC2.Button {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Close")
onClicked: Window.window.close()
}
}
background: Item {
// FIXME: automate that somehow?
Kirigami.Separator {
anchors {
left: parent.left
top: parent.top
right: parent.right
}
visible: mainPage.flickable.contentHeight > mainPage.flickable.height
}
}
}
Kirigami.ScrollablePage {
id: mainPage
anchors.fill: parent
leftPadding: 0
topPadding: 0
rightPadding: 0
bottomPadding: 0
Flow {
id: mainGrid
width: mainPage.flickable.width
spacing: 0
Repeater {
id: repeater
model: ShellContainmentModel
delegate: Delegate {
viewPort: mainPage
}
}
}
}
}

View file

@ -0,0 +1,174 @@
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.components as PC3
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras as PlasmaExtras
import org.kde.ksvg as KSvg
import org.kde.plasma.shell.panel as Panel
import org.kde.kirigami as Kirigami
Item {
id: root
property string text
property /*Qt::Alignment*/int alignment: Qt.AlignHCenter | Qt.AlignBottom
property string tooltip
property bool isVertical: false
property bool checked: false
property bool windowVisible: false
property bool panelVisible: true
property bool translucentPanel: false
property bool sunkenPanel: false
property bool adaptivePanel: false
property bool fillAvailable: false
property int floatingGap: 0
property int windowZ: 0
property var mainIconSource: null
property int screenHeight: Math.round(screenRect.height / 2)
readonly property bool iconAndLabelsShouldlookSelected: checked || mouseArea.pressed
signal clicked()
implicitHeight: mainItem.height
implicitWidth: mainItem.width
PC3.ToolTip {
text: root.tooltip
visible: mouseArea.containsMouse && text.length > 0
}
PlasmaExtras.Highlight {
anchors.fill: parent
anchors.margins: -Kirigami.Units.smallSpacing
hovered: mouseArea.containsMouse
pressed: root.iconAndLabelsShouldlookSelected
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked()
}
ColumnLayout {
id: mainItem
spacing: Kirigami.Units.smallSpacing
Rectangle {
id: screenRect
Layout.alignment: Qt.AlignHCenter
implicitWidth: Math.round(Math.min(Kirigami.Units.gridUnit * 6, Screen.width * 0.1))
implicitHeight: Math.round(Math.min(Kirigami.Units.gridUnit * 4, Screen.width * 0.1))
color: Qt.tint(Kirigami.Theme.backgroundColor, Qt.rgba(1, 1, 1, 0.3))
border.color: Kirigami.Theme.highlightColor
radius: Kirigami.Units.cornerRadius
clip: root.sunkenPanel
RowLayout {
anchors.fill: parent
Rectangle {
id: panelImage
implicitWidth: root.isVertical ? Math.round(parent.width / 6) : Math.round(parent.width * (root.fillAvailable ? 1 : 0.8))
implicitHeight: root.isVertical ? Math.round(parent.height * (root.fillAvailable ? 1 : 0.8)) : Math.round(parent.height / 4)
Layout.alignment: root.alignment
Layout.bottomMargin: root.sunkenPanel * -Math.round(height / 2) + root.floatingGap
color: root.translucentPanel ? screenRect.color : Kirigami.Theme.backgroundColor
opacity: root.translucentPanel ? 0.8 : 1.0
border.color: "transparent"
visible: root.panelVisible
clip: root.adaptivePanel
radius: Kirigami.Units.cornerRadius
z: 1
Loader {
id: horizontalAdaptivePanelLoader
active: root.adaptivePanel && !root.isVertical
sourceComponent: Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Math.round(panelImage.width / 3)
color: Qt.lighter(screenRect.color)
border.color: Kirigami.Theme.highlightColor
width: panelImage.width
height: Math.round(panelImage.height * 4)
radius: Math.round(height / 2)
rotation: 45
}
}
Loader {
id: verticalAdaptivePanelLoader
active: root.adaptivePanel && root.isVertical
sourceComponent: Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Math.round(panelImage.height / 4)
color: Qt.lighter(screenRect.color)
border.color: Kirigami.Theme.highlightColor
width: Math.round(panelImage.width * 2)
height: panelImage.height
radius: Math.round(height / 2)
rotation: 45
}
}
Rectangle {
id: panelBorder
anchors.fill: parent
color: "transparent"
border.color: Kirigami.Theme.highlightColor
radius: panelImage.radius
}
}
}
Rectangle {
id: window
width: Math.round(parent.width / 2)
height: Math.round(parent.height / 2)
visible: root.windowVisible
radius: 5
color: Kirigami.Theme.highlightColor
border.color: "transparent"
x: root.isVertical ? Math.round(panelImage.x + panelImage.width / 2) : Math.round(screenRect.width / 2 - width / 2) + Kirigami.Units.gridUnit
y: root.isVertical ? Math.round(screenRect.height / 2 - height / 2) : Math.round(panelImage.y - height + panelImage.height / 2)
z: root.windowZ
Row {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
Repeater {
model: 3
delegate: Rectangle {
width: Math.round(Kirigami.Units.gridUnit / 6)
height: width
radius: Math.round(height / 2)
color: Kirigami.Theme.textColor
}
}
}
}
Kirigami.Icon {
id: mainIcon
visible: valid
anchors.centerIn: parent
transform: Translate {
y: root.isVertical ? 0 : Math.round((mainIcon.y - panelImage.y) / 4)
x: root.isVertical ? Math.round((mainIcon.x - panelImage.x) / 4) : 0
}
height: parent.height / 2
source: root.mainIconSource
}
}
}
}

View file

@ -0,0 +1,241 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
KSvg.FrameSvgItem {
id: root
anchors.fill: parent
//Those properties get updated by PanelConfiguration.qml whenever a value in the panel changes
property alias offset: offsetHandle.value
property alias minimumLength: rightMinimumLengthHandle.value
property alias maximumLength: rightMaximumLengthHandle.value
property bool isHorizontal: root.prefix[0] === 'north' || root.prefix[0] === 'south'
property string maximumText: (dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change maximum height.") : i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change maximum width.")) + "\n" + i18nd("plasma_shell_org.kde.plasma.desktop", "Double click to reset.")
property string minimumText: (dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change minimum height.") : i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change minimum width.")) + "\n" + i18nd("plasma_shell_org.kde.plasma.desktop", "Double click to reset.")
imagePath: "widgets/containment-controls"
implicitWidth: Math.max(offsetHandle.width, rightMinimumLengthHandle.width + rightMaximumLengthHandle.width)
implicitHeight: Math.max(offsetHandle.height, rightMinimumLengthHandle.height + rightMaximumLengthHandle.height)
onMinimumLengthChanged: rightMinimumLengthHandle.value = leftMinimumLengthHandle.value = minimumLength
onMaximumLengthChanged: rightMaximumLengthHandle.value = leftMaximumLengthHandle.value = maximumLength
/* As offset and length have a different meaning in all alignments, the panel shifts on alignment change.
* This could result in wrong panel positions (e.g. panel shifted over monitor border).
* The fancy version would be a recalculation of all values, so that the panel stays at it's current position,
* but this would be error prone and complicated. As the panel alignment is rarely changed, it's not worth it.
* The more easy approach is just setting the panel offset to zero. This makes sure the panel has a valid position and size.
*/
Connections {
target: panel
function onAlignmentChanged() {
offset = 0
}
}
Component.onCompleted: {
offsetHandle.value = panel.offset
rightMinimumLengthHandle.value = panel.minimumLength
rightMaximumLengthHandle.value = panel.maximumLength
leftMinimumLengthHandle.value = panel.minimumLength
leftMaximumLengthHandle.value = panel.maximumLength
}
KSvg.SvgItem {
id: centerMark
imagePath: "widgets/containment-controls"
elementId: dialogRoot.vertical ? "vertical-centerindicator" : "horizontal-centerindicator"
visible: panel.alignment === Qt.AlignCenter
width: dialogRoot.vertical ? parent.width : naturalSize.width
height: dialogRoot.vertical ? naturalSize.height : parent.height
anchors.centerIn: parent
}
SliderHandle {
id: offsetHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
graphicElementName: "offsetslider"
description: i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change position on this screen edge.\nDouble click to reset.")
offset: panel.alignment === Qt.AlignCenter ? 0 : (dialogRoot.vertical ? panel.height : panel.width) / 2
property int position: (dialogRoot.vertical) ? y + height / 2 : x + width / 2
onPositionChanged: {
if (!offsetHandle.hasEverBeenMoved) return;
let panelLength = dialogRoot.vertical ? panel.height : panel.width
let rootLength = dialogRoot.vertical ? root.height : root.width
// Snap at the center
if (Math.abs(position - rootLength / 2) < 5) {
if (panel.alignment !== Qt.AlignCenter) {
panel.alignment = Qt.AlignCenter
// Coordinate change: since we switch from measuring the min/max
// length from the side of the panel to the center of the panel,
// we need to double the distance between the min/max indicators
// and the panel side.
panel.minimumLength += panel.minimumLength - panelLength
panel.maximumLength += panel.maximumLength - panelLength
}
panel.offset = 0
} else if (position > rootLength / 2) {
if (panel.alignment === Qt.AlignCenter) {
// This is the opposite of the previous comment, as we are
// cutting in half the distance between the min/max indicators
// and the side of the panel.
panel.minimumLength -= (panel.minimumLength - panelLength) / 2
panel.maximumLength -= (panel.maximumLength - panelLength) / 2
}
panel.alignment = Qt.AlignRight
panel.offset = Math.round(rootLength - position - offset)
} else if (position <= rootLength / 2) {
if (panel.alignment === Qt.AlignCenter) {
panel.minimumLength -= (panel.minimumLength - panelLength) / 2
panel.maximumLength -= (panel.maximumLength - panelLength) / 2
}
panel.alignment = Qt.AlignLeft
panel.offset = Math.round(position - offset)
}
}
/* The maximum/minimumPosition values are needed to prevent the user from moving a panel with
* center alignment to the left and then drag the position handle to the left.
* This would make the panel to go off the monitor:
* |<- V -> |
* | -> | <- |
* ^move this slider to the left
*/
minimumPosition: {
var size = dialogRoot.vertical ? height : width
switch(panel.alignment){
case Qt.AlignLeft:
return -size / 2 + offset
case Qt.AlignRight:
return leftMaximumLengthHandle.value - size / 2 - offset
default:
return panel.maximumLength / 2 - size / 2
}
}
//Needed for the same reason as above
maximumPosition: {
var size = dialogRoot.vertical ? height : width
var rootSize = dialogRoot.vertical ? root.height : root.width
switch(panel.alignment){
case Qt.AlignLeft:
return rootSize - rightMaximumLengthHandle.value - size / 2 + offset
case Qt.AlignRight:
return rootSize - size / 2 - offset
default:
return rootSize - panel.maximumLength / 2 - size / 2
}
}
function defaultPosition(): int /*override*/ {
return 0;
}
}
/* The maximumPosition value for the right handles and the minimumPosition value for the left handles are
* needed to prevent the user from moving a panel with center alignment to the left (right) and then pull one of the
* right (left) sliders to the right (left).
* Because the left and right sliders are coupled, this would make the left (right) sliders to go off the monitor.
*
* |<- V -> |
* | -> | <- |
* ^move this slider to the right
*
* The other max/min Position values just set a minimum panel size
*/
SliderHandle {
id: rightMinimumLengthHandle
anchors {
left: !root.isHorizontal ? root.left : undefined
top: root.isHorizontal ? root.top : undefined
}
description: root.minimumText
alignment: panel.alignment | Qt.AlignLeft
visible: panel.alignment !== Qt.AlignRight
offset: panel.offset
graphicElementName: "minslider"
onValueChanged: panel.minimumLength = value
minimumPosition: offsetHandle.position + Kirigami.Units.gridUnit * 3
maximumPosition: {
var rootSize = dialogRoot.vertical ? root.height : root.width
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.min(rootSize - size/2, rootSize + offset * 2 - size/2) : rootSize - size/2
}
}
SliderHandle {
id: rightMaximumLengthHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
description: root.maximumText
alignment: panel.alignment | Qt.AlignLeft
visible: panel.alignment !== Qt.AlignRight
offset: panel.offset
graphicElementName: "maxslider"
onValueChanged: panel.maximumLength = value
minimumPosition: offsetHandle.position + Kirigami.Units.gridUnit * 3
maximumPosition: {
var rootSize = dialogRoot.vertical ? root.height : root.width
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.min(rootSize - size/2, rootSize + offset * 2 - size/2) : rootSize - size/2
}
}
SliderHandle {
id: leftMinimumLengthHandle
anchors {
left: !root.isHorizontal ? root.left : undefined
top: root.isHorizontal ? root.top : undefined
}
description: root.minimumText
alignment: panel.alignment | Qt.AlignRight
visible: panel.alignment !== Qt.AlignLeft
offset: panel.offset
graphicElementName: "maxslider"
onValueChanged: panel.minimumLength = value
maximumPosition: offsetHandle.position - Kirigami.Units.gridUnit * 3
minimumPosition: {
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2
}
}
SliderHandle {
id: leftMaximumLengthHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
description: root.maximumText
alignment: panel.alignment | Qt.AlignRight
visible: panel.alignment !== Qt.AlignLeft
offset: panel.offset
graphicElementName: "minslider"
onValueChanged: panel.maximumLength = value
maximumPosition: offsetHandle.position - Kirigami.Units.gridUnit * 3
minimumPosition: {
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2
}
}
}

View file

@ -0,0 +1,237 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
KSvg.SvgItem {
id: root
//Those properties get updated by PanelConfiguration.qml whenever a value changes
imagePath: "widgets/containment-controls"
elementId: parent.prefix + '-' + graphicElementName
width: naturalSize.width
height: naturalSize.height
//value expressed by this slider, this is the distance to offset
property int value
//name of the graphics to load
property string graphicElementName
//where the point "0" is
property int offset: 0
/*handle type: behave in different ways based on the alignment:
* alignment === Qt.AlignRight: Panel aligned to right and handle value relative to the right
* alignment === Qt.AlignLeft: Panel aligned to left and handle relative to the left
* (alignment !== Qt.AlignRight) && (alignment & Qt.AlignRight): Panel aligned to the center and handle right of offset and value doubled
* (alignment !== Qt.AlignLeft) && (alignment & Qt.AlignLeft): Panel aligned to the center and handle left of offset and value doubled
* else: Panel aligned to center and handle relative to the center
* Note that right/left and top/bottom are interchangeable
*/
property int alignment: panel.alignment
//The maximum/minimum Position (X/Y) the silder can be moved to
property int minimumPosition
property int maximumPosition
//Provide default position for "reset" action.
function defaultPosition(): int {
var dialogSize, panelSize;
if (dialogRoot.vertical) {
dialogSize = dialogRoot.height;
panelSize = panel.height;
} else {
dialogSize = dialogRoot.width;
panelSize = panel.width;
}
return (value === panelSize) ? dialogSize : panelSize;
}
// Handle name displayed as a tooltip.
property string description
property bool hasEverBeenMoved: false
function syncPos() {
if (dialogRoot.vertical) {
if (alignment === Qt.AlignRight) {
y = root.parent.height - (value + offset + root.height/2)
} else if (alignment === Qt.AlignLeft) {
y = value + offset - root.height/2
} else {
if (root.alignment & Qt.AlignRight) {
y = root.parent.height/2 - value/2 + offset - root.height/2
} else if (root.alignment & Qt.AlignLeft) {
y = root.parent.height/2 + value/2 + offset - root.height/2
} else {
y = root.parent.height/2 + value + offset -root.height/2
}
}
} else {
if (alignment === Qt.AlignRight) {
x = root.parent.width - (value + offset + root.width/2)
} else if (alignment === Qt.AlignLeft) {
x = value + offset - root.width/2
} else {
if (root.alignment & Qt.AlignRight) {
x = root.parent.width/2 - value/2 + offset - root.width/2
} else if (root.alignment & Qt.AlignLeft) {
x = root.parent.width/2 + value/2 + offset -root.width/2
} else {
x = root.parent.width/2 + value + offset -root.width/2
}
}
}
}
onValueChanged: syncPos()
onOffsetChanged: syncPos()
onAlignmentChanged: syncPos()
Connections {
target: root.parent
function onWidthChanged() {
syncPos()
}
function onHeightChanged() {
syncPos()
}
}
PC3.ToolTip {
text: root.description
visible: root.description !== "" && ((area.containsMouse && !area.containsPress) || area.activeFocus)
}
MouseArea {
id: area
drag {
target: parent
axis: (dialogRoot.vertical) ? Drag.YAxis : Drag.XAxis
minimumX: root.minimumPosition
minimumY: root.minimumPosition
maximumX: root.maximumPosition
maximumY: root.maximumPosition
}
anchors {
fill: parent
leftMargin: (dialogRoot.vertical) ? 0 : -Kirigami.Units.gridUnit
rightMargin: (dialogRoot.vertical) ? 0 : -Kirigami.Units.gridUnit
topMargin: (dialogRoot.vertical) ? -Kirigami.Units.gridUnit : 0
bottomMargin: (dialogRoot.vertical) ? -Kirigami.Units.gridUnit : 0
}
readonly property int keyboardMoveStepSize: Math.ceil((root.maximumPosition - root.minimumPosition) / 20)
activeFocusOnTab: true
hoverEnabled: true
cursorShape: dialogRoot.vertical ? Qt.SizeVerCursor : Qt.SizeHorCursor
Accessible.description: root.description
Keys.onEnterPressed: doubleClicked(null);
Keys.onReturnPressed: doubleClicked(null);
Keys.onSpacePressed: doubleClicked(null);
// BEGIN Arrow keys
Keys.onUpPressed: if (dialogRoot.vertical) {
root.y = Math.max(root.minimumPosition, root.y - ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onDownPressed: if (dialogRoot.vertical) {
root.y = Math.min(root.maximumPosition, root.y + ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onLeftPressed: if (!dialogRoot.vertical) {
root.x = Math.max(root.minimumPosition, root.x - ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onRightPressed: if (!dialogRoot.vertical) {
root.x = Math.min(root.maximumPosition, root.x + ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
// END Arrow keys
onPositionChanged: {
if (!drag.active) {
return;
}
changePosition();
}
onDoubleClicked: {
root.value = root.defaultPosition();
}
function changePosition() {
root.hasEverBeenMoved = true
if (dialogRoot.vertical) {
if (root.alignment === Qt.AlignRight) {
root.value = root.parent.height - (root.y + offset + root.height/2)
} else if (alignment === Qt.AlignLeft) {
root.value = root.y - offset + root.height/2
//Center
} else {
if (root.alignment & Qt.AlignRight) {
root.value = (root.parent.height/2 - root.y + offset)*2 - root.height
} else if (root.alignment & Qt.AlignLeft) {
root.value = (root.y - offset - root.parent.height/2)*2 + root.height
} else {
var value = root.y - root.parent.height/2 - offset + root.height/2
//Snap
if (Math.abs(value) < 5) {
root.value = 0
} else {
root.value = value
}
}
}
} else {
if (root.alignment === Qt.AlignRight) {
root.value = root.parent.width - (root.x + offset + root.width/2)
} else if (alignment === Qt.AlignLeft) {
root.value = root.x - offset + root.width/2
//Center
} else {
if (root.alignment & Qt.AlignRight) {
root.value = (root.parent.width/2 - root.x + offset)*2 - root.width
} else if (root.alignment & Qt.AlignLeft) {
root.value = (root.x - offset - root.parent.width/2)*2 + root.width
} else {
var value = root.x - root.parent.width/2 - offset + root.width/2
//Snap
if (Math.abs(value) < 5) {
root.value = 0
} else {
root.value = value
}
}
}
}
}
PlasmaExtras.Highlight {
anchors.fill: parent
visible: parent.activeFocus
hovered: true
}
}
}

View file

@ -0,0 +1,273 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-FileCopyrightText: 2022 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.15
import org.kde.kirigami 2.13 as Kirigami
QQC2.Control {
id: delegate
property Item viewPort
readonly property string screenName: model.screenName
readonly property int screenId: model.screenId
property bool containsDrag
property alias contentsLayout: contentsLayout
width: Math.min(Kirigami.Units.gridUnit * 25, Math.floor(viewPort.width / Math.min(repeater.count, Math.floor(viewPort.width / (Kirigami.Units.gridUnit * 12)))))
contentItem: ColumnLayout {
id: contentsLayout
width: Math.min(parent.width, Kirigami.Units.gridUnit * 15)
Rectangle {
id: screenRect
Layout.fillWidth: true
Layout.preferredHeight: width / 1.6
color: Kirigami.Theme.backgroundColor
border.color: Kirigami.Theme.textColor
Rectangle {
anchors.fill: parent
z: 9
color: "black"
opacity: delegate.containsDrag ? 0.3 : 0
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
Repeater {
id: containmentRepeater
model: containments
Rectangle {
id: contRect
property real homeX
property real homeY
property string oldState
readonly property int edgeDistance: {
return (state === "left" || state === "right" ? width : height) * model.edgePosition;
}
width: moveButton.width
height: moveButton.height
border.color: Kirigami.Theme.textColor
color: Kirigami.Theme.backgroundColor
state: model.edge
z: state === "floating" ? 0 : 1
visible: !model.isDestroyed
HoverHandler {
cursorShape: Qt.OpenHandCursor
}
DragHandler {
id: dragHandler
property QQC2.Control targetDelegate
cursorShape: Qt.ClosedHandCursor
onActiveChanged: {
if (active) {
delegate.z = 1;
} else {
if (targetDelegate) {
resetAnim.restart();
containmentRepeater.model.moveContainementToScreen(model.containmentId, targetDelegate.screenId)
targetDelegate.containsDrag = false;
targetDelegate = null;
} else {
resetAnim.restart();
}
}
}
onTranslationChanged: {
if (!active) {
if (targetDelegate) {
targetDelegate.containsDrag = false;
targetDelegate = null;
}
return;
}
let pos = contRect.mapToItem(delegate.parent, dragHandler.centroid.position.x, dragHandler.centroid.position.y);
let otherDelegate = delegate.parent.childAt(pos.x, pos.y);
if (targetDelegate && targetDelegate !== otherDelegate) {
targetDelegate.containsDrag = false;
}
if (!otherDelegate || otherDelegate === delegate) {
targetDelegate = null;
} else if (otherDelegate && otherDelegate !== delegate
&& otherDelegate.hasOwnProperty("screenId")
&& otherDelegate.hasOwnProperty("containsDrag")) {
targetDelegate = otherDelegate;
targetDelegate.containsDrag = true;
}
}
}
SequentialAnimation {
id: resetAnim
property var targetDelegatePos: dragHandler.targetDelegate
? dragHandler.targetDelegate.contentsLayout.mapToItem(delegate.contentsLayout, 0, 0)
: Qt.point(0, 0)
ParallelAnimation {
XAnimator {
target: contRect
from: contRect.x
to: contRect.homeX + resetAnim.targetDelegatePos.x
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
YAnimator {
target: contRect
from: contRect.y
to: contRect.homeY + resetAnim.targetDelegatePos.y
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
PropertyAction {
target: delegate
property: "z"
value: 0
}
}
Image {
id: containmentImage
anchors {
fill: parent
margins: 1
}
// It needs to reload the image from disk when the file changes
cache: false
source: model.imageSource
fillMode: model.edge == "floating" ? Image.PreserveAspectCrop : Image.PreserveAspectFit
}
QQC2.Button {
id: moveButton
icon.name: "open-menu-symbolic"
checked: contextMenu.visible
anchors {
right: parent.right
top: parent.top
topMargin: model.edge == "floating"
? model.panelCountAtTop * moveButton.height + Kirigami.Units.largeSpacing
: 0
rightMargin: model.edge == "floating"
? (moveButton.LayoutMirroring.enabled ? model.panelCountAtLeft : model.panelCountAtRight) * moveButton.height + Kirigami.Units.largeSpacing
: 0
}
onClicked: {
contextMenu.open()
}
QQC2.Menu {
id: contextMenu
y: moveButton.height
Repeater {
model: ShellContainmentModel
QQC2.MenuItem {
text: edge == "floating"
? i18nd("plasma_shell_org.kde.plasma.desktop", "Swap with Desktop on Screen %1", model.screenName)
: i18nd("plasma_shell_org.kde.plasma.desktop", "Move to Screen %1", model.screenName)
visible: model.screenName !== delegate.screenName
height: visible ? implicitHeight : 0
onTriggered: {
containmentRepeater.model.moveContainementToScreen(containmentId, screenId)
}
}
}
QQC2.MenuSeparator {
visible: removeItem.visible
}
QQC2.MenuItem {
id: removeItem
text: contRect.state === "floating"
? i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Desktop")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Panel")
icon.name: "edit-delete"
onTriggered: {
if (contRect.state === "floating") {
ShellContainmentModel.remove(screenId);
} else {
containments.remove(containmentId);
}
}
visible: contRect.state !== "floating" || !model.active
}
}
}
states: [
State {
name: "floating"
PropertyChanges {
target: contRect;
width: screenRect.width
height: screenRect.height
color: "transparent"
}
},
State {
name: "top"
PropertyChanges {
target: contRect;
width: screenRect.width
y: homeY
homeX: 0
homeY: contRect.edgeDistance
}
},
State {
name: "right"
PropertyChanges {
target: contRect;
x: homeX
homeX: screenRect.width - contRect.width - contRect.edgeDistance;
height: screenRect.height
homeY: 0
}
},
State {
name: "bottom"
PropertyChanges {
target: contRect;
y: homeY
homeX: 0
homeY: screenRect.height - contRect.height - contRect.edgeDistance;
width: screenRect.width
}
},
State {
name: "left"
PropertyChanges {
target: contRect;
height: screenRect.height
x: homeX
homeX: contRect.edgeDistance
homeY: 0
}
}
]
}
}
}
QQC2.Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: model.isPrimary
? i18nd("plasma_shell_org.kde.plasma.desktop", "%1 (primary)", model.screenName)
: model.screenName
textFormat: Text.PlainText
}
}
}

View file

@ -0,0 +1,35 @@
/*
SPDX-FileCopyrightText: 2014 Aaron Seigo <aseigo@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.private.shell 2.0
Item {
id: main
property string scriptPath
property alias mode: interactiveConsole.mode
signal visibleChanged(bool visible)
onScriptPathChanged: {
interactiveConsole.loadScript(scriptPath);
}
InteractiveConsoleWindow {
id: interactiveConsole
onVisibleChanged: {
main.visibleChanged(visible);
}
}
Component.onCompleted: {
interactiveConsole.scriptEngine = scriptEngine;
interactiveConsole.visible = true;
}
}

View file

@ -0,0 +1,397 @@
/*
SPDX-FileCopyrightText: 2014-2020 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.activityswitcher as ActivitySwitcher
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils // KCMLauncher
import "static.js" as S
Item {
id: root
property int innerPadding : Kirigami.Units.gridUnit
property bool current : false
property bool selected : false
property bool stoppable : true
property alias title : title.text
property alias icon : icon.source
property alias hasWindows : hasWindowsIndicator.visible
z : current ? 10 :
selected ? 5 : 0
property string activityId : ""
property string background : ""
onBackgroundChanged: if (background[0] !== '#') {
// We have a proper wallpaper, hurroo!
backgroundColor.visible = false;
} else {
// We have only a color
backgroundColor.color = background;
backgroundColor.visible = true;
}
signal clicked
width : 200
height : width * 9.0 / 16.0
Item {
anchors {
fill: parent
}
// Background until we get something real
Rectangle {
id: backgroundColor
anchors.fill: parent
// This is intentional - while waiting for the wallpaper,
// we are showing a semi-transparent black background
color: "black"
opacity: root.selected ? .8 : .5
}
Image {
id: backgroundWallpaper
anchors.fill: parent
visible: !backgroundColor.visible
source: "image://wallpaperthumbnail/" + background
sourceSize: Qt.size(width, height)
}
// Title and the icon
Rectangle {
id: shade
width: parent.height
height: parent.width
anchors.centerIn: parent
rotation: 90
gradient: Gradient {
GradientStop { position: 1.0; color: "black" }
GradientStop { position: 0.0; color: "transparent" }
}
opacity : root.selected ? 0.5 : 1.0
}
Rectangle {
id: currentActivityHighlight
visible: root.current
border.width: root.current ? Kirigami.Units.smallSpacing : 0
border.color: Kirigami.Theme.highlightColor
z: 10
anchors {
fill: parent
// Hide the rounding error on the bottom of the rectangle
bottomMargin: -1
}
color: "transparent"
}
Item {
id: titleBar
anchors {
top : parent.top
left : parent.left
right : parent.right
leftMargin : 2 * Kirigami.Units.smallSpacing + 2
topMargin : 2 * Kirigami.Units.smallSpacing
}
Text {
id: title
color : "white"
elide : Text.ElideRight
visible : shade.visible
font.bold : true
anchors {
top : parent.top
left : parent.left
right : icon.left
}
}
Text {
id: description
color : "white"
elide : Text.ElideRight
text : model.description
opacity : .6
anchors {
top : title.bottom
left : parent.left
right : icon.left
}
}
Kirigami.Icon {
id: icon
width : Kirigami.Units.iconSizes.medium
height : width
anchors {
right : parent.right
rightMargin : 2 * Kirigami.Units.smallSpacing
}
}
}
Column {
id: statsBar
height: childrenRect.height + Kirigami.Units.smallSpacing
anchors {
bottom : controlBar.top
left : parent.left
right : parent.right
leftMargin : 2 * Kirigami.Units.smallSpacing + 2
rightMargin : 2 * Kirigami.Units.smallSpacing
bottomMargin : Kirigami.Units.smallSpacing
}
Kirigami.Icon {
id : hasWindowsIndicator
source : "window-duplicate"
width : 16
height : width
opacity : .6
visible : false
}
Text {
id: lastUsedDate
color : "white"
elide : Text.ElideRight
opacity : .6
text: root.current ?
i18nd("plasma_shell_org.kde.plasma.desktop", "Currently being used") :
model.lastTimeUsedString
}
}
Rectangle {
id: dropHighlight
visible: moveDropAction.isHovered || copyDropAction.isHovered
onVisibleChanged: {
ActivitySwitcher.Backend.setDropMode(visible);
if (visible) {
root.state = "dropAreasShown";
} else {
root.state = "plain";
}
}
anchors {
fill: parent
topMargin: icon.height + 3 * Kirigami.Units.smallSpacing
}
opacity: .75
color: Kirigami.Theme.backgroundColor
}
TaskDropArea {
id: moveDropAction
anchors {
right: parent.horizontalCenter
left: parent.left
top: parent.top
bottom: parent.bottom
}
topPadding: icon.height + 3 * Kirigami.Units.smallSpacing
actionVisible: dropHighlight.visible
actionTitle: i18nd("plasma_shell_org.kde.plasma.desktop", "Move to\nthis activity")
onTaskDropped: {
ActivitySwitcher.Backend.dropMove(mimeData, root.activityId);
}
onClicked: {
root.clicked();
}
onEntered: {
S.showActivityItemActionsBar(root);
}
visible: ActivitySwitcher.Backend.dropEnabled
}
TaskDropArea {
id: copyDropAction
topPadding: icon.height + 3 * Kirigami.Units.smallSpacing
actionVisible: dropHighlight.visible
anchors {
right: parent.right
left: parent.horizontalCenter
top: parent.top
bottom: parent.bottom
}
actionTitle: i18nd("plasma_shell_org.kde.plasma.desktop", "Show also\nin this activity")
onTaskDropped: {
ActivitySwitcher.Backend.dropCopy(mimeData, root.activityId);
}
onClicked: {
root.clicked();
}
onEntered: {
S.showActivityItemActionsBar(root);
}
visible: ActivitySwitcher.Backend.dropEnabled
}
// Controls
Item {
id: controlBar
height: root.state == "showingControls" ?
(configButton.height + 4 * Kirigami.Units.smallSpacing) :
0
Behavior on height {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.shortDuration
}
}
clip: true
anchors {
bottom : parent.bottom
left : parent.left
right : parent.right
}
Rectangle {
anchors {
fill: parent
margins: - 2 * Kirigami.Units.smallSpacing
}
opacity: .75
color: Kirigami.Theme.backgroundColor
}
PlasmaComponents.Button {
id: configButton
icon.name: "configure"
PlasmaComponents.ToolTip.delay: Kirigami.Units.toolTipDelay
PlasmaComponents.ToolTip.visible: hovered
PlasmaComponents.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Configure")
onClicked: KCMLauncher.openSystemSettings("kcm_activities", root.activityId);
anchors {
left : parent.left
top : parent.top
leftMargin : 2 * Kirigami.Units.smallSpacing + 2
topMargin : 2 * Kirigami.Units.smallSpacing
}
}
PlasmaComponents.Button {
id: stopButton
visible: stoppable
icon.name: "process-stop"
PlasmaComponents.ToolTip.delay: Kirigami.Units.toolTipDelay
PlasmaComponents.ToolTip.visible: hovered
PlasmaComponents.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Stop activity")
onClicked: ActivitySwitcher.Backend.stopActivity(activityId);
anchors {
right : parent.right
top : parent.top
rightMargin : 2 * Kirigami.Units.smallSpacing + 2
topMargin : 2 * Kirigami.Units.smallSpacing
}
}
}
}
states: [
State {
name: "plain"
PropertyChanges { target: shade; visible: true }
PropertyChanges { target: controlBar; opacity: 0 }
},
State {
name: "showingControls"
PropertyChanges { target: shade; visible: true }
PropertyChanges { target: controlBar; opacity: 1 }
},
State {
name: "dropAreasShown"
// PropertyChanges { target: shade; visible: false }
PropertyChanges { target: statsBar; visible: false }
PropertyChanges { target: controlBar; opacity: 0 }
}
]
transitions: [
Transition {
NumberAnimation {
properties : "opacity"
duration : Kirigami.Units.shortDuration
}
}
]
}

View file

@ -0,0 +1,197 @@
/* vim:set foldmethod=marker:
SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.2
import org.kde.kirigami 2.20 as Kirigami
import org.kde.activities 0.1 as Activities
import org.kde.plasma.activityswitcher as ActivitySwitcher
Flickable {
id: root
// contentWidth: content.width
contentHeight: content.height
property var model: ActivitySwitcher.Backend.runningActivitiesModel()
property string filterString: ""
property bool showSwitcherOnly: false
property int itemsWidth: 0
property int selectedIndex: -1
function _selectRelativeToCurrent(distance)
{
var startingWithSelected = selectedIndex;
do {
selectedIndex += distance;
if (selectedIndex >= activitiesList.count) {
selectedIndex = 0;
}
if (selectedIndex < 0) {
selectedIndex = activitiesList.count - 1;
}
// Searching for the first item that is visible, or back to the one
// that we started with
} while (!activitiesList.itemAt(selectedIndex).visible
&& startingWithSelected !== selectedIndex);
_updateSelectedItem();
}
function selectNext()
{
_selectRelativeToCurrent(1);
}
function selectPrevious()
{
_selectRelativeToCurrent(-1);
}
function _updateSelectedItem()
{
for (var i = 0; i < activitiesList.count; i++) {
activitiesList.itemAt(i).selected = (i === selectedIndex);
}
}
function openSelected()
{
var selectedItem = null;
if (selectedIndex >= 0 && selectedIndex < activitiesList.count) {
selectedItem = activitiesList.itemAt(selectedIndex);
} else if (root.filterString != "") {
// If we have only one item shown, activate it. It doesn't matter
// that it is not really selected
for (var i = 0; i < activitiesList.count; i++) {
var item = activitiesList.itemAt(i);
if (item.visible) {
selectedItem = item;
break;
}
}
}
if (selectedItem !== null) {
ActivitySwitcher.Backend.setCurrentActivity(selectedItem.activityId);
}
}
Column {
id: content
// width: root.width - (root.width % 10)
width: root.itemsWidth
spacing: Kirigami.Units.smallSpacing * 2
// Running activities
Repeater {
id: activitiesList
model: ActivitySwitcher.Backend.runningActivitiesModel()
ActivityItem {
width: content.width
visible : (root.filterString == "") ||
(title.toLowerCase().indexOf(root.filterString) != -1)
activityId : model.id
title : model.name
icon : model.iconSource
background : model.background
current : model.isCurrent
hasWindows : model.hasWindows
innerPadding : 2 * Kirigami.Units.smallSpacing
stoppable : activitiesList.count > 1
onClicked : {
ActivitySwitcher.Backend.setCurrentActivity(model.id);
}
}
}
// Stopped activities
Item {
// spacer
width : parent.width
height : Kirigami.Units.gridUnit
}
Kirigami.Heading {
id: stoppedActivitiesHeading
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Stopped activities:")
textFormat: Text.PlainText
level: 3
visible: !root.showSwitcherOnly && stoppedActivitiesList.count > 0
}
Repeater {
id: stoppedActivitiesList
model: root.showSwitcherOnly ? null : ActivitySwitcher.Backend.stoppedActivitiesModel()
delegate: StoppedActivityItem {
id: stoppedActivityItem
width: parent.width
visible : (root.filterString == "") ||
(title.toLowerCase().indexOf(root.filterString) != -1)
activityId : model.id
title : model.name
icon : model.iconSource
innerPadding : 2 * Kirigami.Units.smallSpacing
onClicked: {
ActivitySwitcher.Backend.setCurrentActivity(model.id)
}
}
}
Item {
// spacer
width : parent.width
height : Kirigami.Units.gridUnit * 2
visible: stoppedActivitiesHeading.visible
}
add: Transition {
NumberAnimation {
properties: "x"
from: -100
duration: Kirigami.Units.shortDuration
}
}
move: Transition {
NumberAnimation {
id: animation
properties: "y"
duration: Kirigami.Units.longDuration
}
}
}
}

View file

@ -0,0 +1,152 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kirigami 2.20 as Kirigami
import org.kde.config as KConfig // KAuthorized
import org.kde.kcmutils // KCMLauncher
FocusScope {
id: root
signal closed()
function parentClosed() {
activityBrowser.parentClosed();
}
//this is used to perfectly align the filter field and delegates
property int cellWidth: Kirigami.Units.iconSizes.sizeForLabels * 30
property int spacing: 2 * Kirigami.Units.smallSpacing
property bool showSwitcherOnly: false
width: Kirigami.Units.gridUnit * 16
Item {
id: activityBrowser
property int spacing: 2 * Kirigami.Units.smallSpacing
signal closeRequested()
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
if (heading.searchString.length > 0) {
heading.searchString = "";
} else {
activityBrowser.closeRequested();
}
} else if (event.key === Qt.Key_Up) {
activityList.selectPrevious();
} else if (event.key === Qt.Key_Down) {
activityList.selectNext();
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
activityList.openSelected();
} else if (event.key === Qt.Key_Tab) {
// console.log("TAB KEY");
} else {
// console.log("OTHER KEY");
// event.accepted = false;
// heading.forceActiveFocus();
}
}
// Rectangle {
// anchors.fill : parent
// opacity : .4
// color : "white"
// }
Heading {
id: heading
anchors {
top: parent.top
left: parent.left
right: parent.right
leftMargin: Kirigami.Units.smallSpacing
rightMargin: Kirigami.Units.smallSpacing
}
visible: !root.showSwitcherOnly
onCloseRequested: activityBrowser.closeRequested()
}
PlasmaComponents.ScrollView {
anchors {
top: heading.visible ? heading.bottom : parent.top
bottom: bottomPanel.visible ? bottomPanel.top : parent.bottom
left: parent.left
right: parent.right
topMargin: activityBrowser.spacing
}
ActivityList {
id: activityList
showSwitcherOnly: root.showSwitcherOnly
filterString: heading.searchString.toLowerCase()
itemsWidth: root.width - Kirigami.Units.smallSpacing
}
}
Item {
id: bottomPanel
height: newActivityButton.height + Kirigami.Units.gridUnit
visible: !root.showSwitcherOnly
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
PlasmaComponents.ToolButton {
id: newActivityButton
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Create activity…")
icon.name: "list-add"
width: parent.width
onClicked: KCMLauncher.openSystemSettings("kcm_activities", "newActivity")
visible: KConfig.KAuthorized.authorize("plasma-desktop/add_activities")
opacity: newActivityDialog.status == Loader.Ready ?
1 - newActivityDialog.item.opacity : 1
}
Loader {
id: newActivityDialog
z: 100
anchors.bottom: newActivityButton.bottom
anchors.left: newActivityButton.left
anchors.right: newActivityButton.right
}
}
onCloseRequested: root.closed()
anchors.fill: parent
}
}

View file

@ -0,0 +1,108 @@
/* vim:set foldmethod=marker:
SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.2
import QtQuick.Layouts 1.2
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils as KCM
import org.kde.config as KConfig
Item {
id: root
property alias searchString: searchText.text
property bool showingSearch: false
signal closeRequested
function focusSearch() {
searchText.forceActiveFocus()
}
onShowingSearchChanged: if (!showingSearch) searchText.text = ""
Keys.onPressed: {
if (event.key === Qt.Key_Escape) {
if (root.showingSearch) {
event.accepted = true;
root.showingSearch = false;
}
}
}
height: childrenRect.height
RowLayout {
id: buttonRow
anchors {
top: parent.top
left: parent.left
right: parent.right
}
Item {
Kirigami.Heading {
id: heading
anchors.fill: parent
level: 1
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Activities")
textFormat: Text.PlainText
elide: Text.ElideRight
visible: !root.showingSearch
}
PlasmaExtras.SearchField {
id: searchText
anchors.fill: parent
focus: true
visible: root.showingSearch
onTextChanged: if (text != "") root.showingSearch = true
}
Layout.fillWidth: true
Layout.fillHeight: true
}
PlasmaComponents.ToolButton {
id: searchButton
icon.name: "edit-find"
// checkable: true
// onClicked: root.closeRequested()
onClicked: root.showingSearch = !root.showingSearch
checked: root.showingSearch
}
PlasmaComponents.ToolButton {
id: configureButton
icon.name: "configure"
visible: KConfig.KAuthorized.authorizeControlModule("kcm_activities")
onClicked: {
KCM.KCMLauncher.openSystemSettings("kcm_activities");
root.closeRequested();
}
}
PlasmaComponents.ToolButton {
id: closeButton
icon.name: "window-close"
onClicked: root.closeRequested()
}
}
}

View file

@ -0,0 +1,190 @@
/* vim:set foldmethod=marker:
SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.2
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.ksvg 1.0 as KSvg
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils // KCMLauncher
import org.kde.config // KAuthorized
import org.kde.plasma.activityswitcher as ActivitySwitcher
import "static.js" as S
Item {
id: root
property int innerPadding: Kirigami.Units.smallSpacing
property string activityId : ""
property alias title : title.text
property alias icon : icon.source
signal clicked
width : 200
height : icon.height + 2 * Kirigami.Units.smallSpacing
// Background until we get something real
KSvg.FrameSvgItem {
id: highlight
imagePath: "widgets/viewitem"
visible: rootArea.containsMouse
anchors {
fill: parent
rightMargin: -highlight.margins.right
bottomMargin: -highlight.margins.bottom
}
prefix: "normal"
}
Item {
anchors {
fill: parent
leftMargin: highlight.margins.left
topMargin: highlight.margins.top
}
// Title and the icon
Kirigami.Icon {
id: icon
width : Kirigami.Units.iconSizes.medium
height : width
anchors {
left : parent.left
margins : root.innerPadding
verticalCenter: parent.verticalCenter
}
}
PlasmaComponents.Label {
id: title
elide : Text.ElideRight
anchors {
left : icon.right
right : parent.right
margins : root.innerPadding * 2
verticalCenter: parent.verticalCenter
}
textFormat: Text.PlainText
}
// Controls
MouseArea {
id: rootArea
anchors.fill : parent
hoverEnabled : true
Accessible.name : root.title
Accessible.role : Accessible.Button
Accessible.selectable : false
Accessible.onPressAction : root.clicked()
onClicked : root.clicked()
onEntered : S.showActivityItemActionsBar(root)
}
Item {
id: controlBar
height: root.state == "showingControls" ?
root.height :
0
Behavior on height {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.shortDuration
}
}
clip: true
anchors {
left : parent.left
right : parent.right
bottom : parent.bottom
}
PlasmaComponents.Button {
id: configButton
icon.name: "configure"
PlasmaComponents.ToolTip.delay: Kirigami.Units.toolTipDelay
PlasmaComponents.ToolTip.visible: hovered
PlasmaComponents.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Configure activity")
onClicked: KCMLauncher.openSystemSettings("kcm_activities", root.activityId)
anchors {
right : deleteButton.left
rightMargin : 2 * Kirigami.Units.smallSpacing
verticalCenter: parent.verticalCenter
}
}
PlasmaComponents.Button {
id: deleteButton
icon.name: "edit-delete"
PlasmaComponents.ToolTip.delay: Kirigami.Units.toolTipDelay
PlasmaComponents.ToolTip.visible: hovered
PlasmaComponents.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Delete")
onClicked: ActivitySwitcher.Backend.removeActivity(root.activityId)
visible: KAuthorized.authorize("plasma-desktop/add_activities")
anchors {
right : parent.right
rightMargin : 2 * Kirigami.Units.smallSpacing + 2
verticalCenter: parent.verticalCenter
}
}
}
}
states: [
State {
name: "plain"
PropertyChanges { target: controlBar; opacity: 0 }
},
State {
name: "showingControls"
PropertyChanges { target: controlBar; opacity: 1 }
}
]
transitions: [
Transition {
NumberAnimation {
properties : "opacity"
duration : Kirigami.Units.shortDuration
}
}
]
}

View file

@ -0,0 +1,88 @@
/*
SPDX-FileCopyrightText: 2020 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.draganddrop 2.0 as DND
import org.kde.plasma.extras 2.0 as PlasmaExtras
DND.DropArea {
id: root
signal taskDropped(variant mimeData, variant modifiers)
signal clicked()
signal entered()
property int topPadding: 0
property string activityName: ""
property bool selected: false
property string actionTitle: ""
property bool isHovered: false
property bool actionVisible: false
PlasmaExtras.Highlight {
id: dropHighlight
anchors {
fill: parent
// topMargin: icon.height + 3 * Kirigami.Units.smallSpacing
topMargin: root.topPadding
}
visible: root.isHovered
z: -1
}
Text {
id: dropAreaLeftText
anchors {
fill: dropHighlight
leftMargin: Kirigami.Units.gridUnit
rightMargin: Kirigami.Units.gridUnit
}
color: Kirigami.Theme.textColor
visible: root.actionVisible
text: root.actionTitle
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
maximumLineCount: 3
}
anchors {
left: parent.left
right: parent.horizontalCenter
top: parent.top
bottom: parent.bottom
}
preventStealing: true
enabled: true
onDrop: {
root.taskDropped(event.mimeData, event.modifiers);
}
onDragEnter: {
root.isHovered = true;
}
onDragLeave: {
root.isHovered = false;
}
MouseArea {
anchors.fill : parent
onClicked : root.clicked()
hoverEnabled : true
onEntered : root.entered()
Accessible.name : root.activityName
Accessible.role : Accessible.Button
Accessible.selected : root.selected
Accessible.onPressAction : root.clicked()
}
}

View file

@ -0,0 +1,61 @@
/* vim:set foldmethod=marker:
SPDX-FileCopyrightText: 2014 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.2
import org.kde.kirigami as Kirigami
Image {
id: main
width: 480
height: 425
source: "images/window2.png"
anchors.centerIn: parent
Item {
id: title
width: titleText.width + 32
height: titleText.height + 32
Rectangle {
anchors.fill: parent
color: "black"
radius: Kirigami.Units.cornerRadius
opacity: .7
}
Text {
id: titleText
color: "white"
text: "Firefox"
font.pointSize: 24
anchors.centerIn: parent
}
}
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: 32
Drag.hotSpot.y: 32
MouseArea {
id: mouseArea
anchors.fill: parent
drag {
target: title
}
}
}

View file

@ -0,0 +1,26 @@
/* vim:set foldmethod=marker:
SPDX-FileCopyrightText: 2015 Ivan Cukic <ivan.cukic(at)kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
.pragma library
var currentlyHoveredActivityItem = null
function showActivityItemActionsBar(
activityItem
)
{
if (activityItem == currentlyHoveredActivityItem) {
return;
}
if (currentlyHoveredActivityItem != null) {
currentlyHoveredActivityItem.state = "plain"
}
currentlyHoveredActivityItem = activityItem;
currentlyHoveredActivityItem.state = "showingControls";
}

View file

@ -0,0 +1,261 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.plasmoid 2.0
PlasmoidItem {
id: root
enum LayoutType {
HorizontalPanel,
VerticalPanel,
Desktop,
DesktopCompact
}
property var errorInformation
readonly property real minimumPreferredWidth: Kirigami.Units.gridUnit * 12
readonly property real minimumPreferredHeight: Kirigami.Units.gridUnit * 12
// To properly show the error message in panel
readonly property int layoutForm: {
if (fullRepresentationItem.width >= root.minimumPreferredWidth) {
if (fullRepresentationItem.height >= root.minimumPreferredHeight) {
return AppletError.Desktop;
} else if (fullRepresentationItem.height >= Kirigami.Units.iconSizes.huge + root.fullRepresentationItem.buttonLayout.implicitHeight) {
return AppletError.DesktopCompact;
}
}
return Plasmoid.formFactor === PlasmaCore.Types.Vertical ? AppletError.VerticalPanel : AppletError.HorizontalPanel;
}
preloadFullRepresentation: true
fullRepresentation: GridLayout {
id: fullRep
property alias buttonLayout: buttonLayout
Layout.minimumWidth: {
switch (root.layoutForm) {
case AppletError.Desktop:
case AppletError.DesktopCompact:
// [Icon] [Text]
// [Button]
// [Information]
return Math.max(root.minimumPreferredWidth, buttonLayout.implicitWidth);
case AppletError.VerticalPanel:
// [Icon]
// [Copy]
// [Open]
return Math.max(headerIcon.implicitWidth, buttonLayout.implicitWidth);
case AppletError.HorizontalPanel:
// [Icon] [Copy] [Open]
return headingLayout.implicitWidth + rowSpacing + buttonLayout.implicitWidth;
}
}
Layout.minimumHeight: {
switch (root.layoutForm) {
case AppletError.Desktop:
return headingLayout.implicitHeight + fullRep.columnSpacing + buttonLayout.implicitHeight + fullRep.columnSpacing + fullContentView.implicitHeight;
case AppletError.DesktopCompact:
return Math.max(headingLayout.implicitHeight, buttonLayout.implicitHeight);
case AppletError.VerticalPanel:
return headingLayout.implicitHeight + fullRep.columnSpacing + buttonLayout.implicitHeight;
case AppletError.HorizontalPanel:
return Math.max(headingLayout.implicitHeight, buttonLayout.implicitHeight);
}
}
// Same as systray popups
Layout.preferredWidth: Kirigami.Units.gridUnit * 24
Layout.preferredHeight: Kirigami.Units.gridUnit * 24
Layout.maximumWidth: Kirigami.Units.gridUnit * 34
Layout.maximumHeight: Kirigami.Units.gridUnit * 34
rowSpacing: textArea.topPadding
columnSpacing: rowSpacing
flow: {
switch (root.layoutForm) {
case AppletError.HorizontalPanel:
return GridLayout.LeftToRight;
default:
return GridLayout.TopToBottom;
}
}
RowLayout {
id: headingLayout
Layout.margins: root.layoutForm !== AppletError.Desktop ? 0 : Kirigami.Units.gridUnit
Layout.maximumWidth: fullRep.width
spacing: 0
Layout.fillWidth: true
Kirigami.Icon {
id: headerIcon
implicitWidth: Math.min(Kirigami.Units.iconSizes.huge, fullRep.width, fullRep.height)
implicitHeight: implicitWidth
activeFocusOnTab: true
source: "dialog-error"
Accessible.description: heading.text
PlasmaCore.ToolTipArea {
anchors.fill: parent
enabled: !heading.visible || heading.truncated
mainText: heading.text
textFormat: Text.PlainText
}
}
Kirigami.Heading {
id: heading
visible: root.layoutForm !== AppletError.VerticalPanel
// Descent is equal to the amount of space above and below capital letters.
// Add descent to the sides to make the spacing around Latin text look more even.
leftPadding: headingFontMetrics.descent
rightPadding: headingFontMetrics.descent
text: root.errorInformation ? root.errorInformation.compactError : "No error information."
textFormat: Text.PlainText
level: 2
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
Layout.fillWidth: true
Layout.maximumHeight: headerIcon.implicitHeight
FontMetrics {
id: headingFontMetrics
font: heading.font
}
}
}
GridLayout {
id: buttonLayout
Layout.alignment: Qt.AlignCenter
rowSpacing: fullRep.rowSpacing
columnSpacing: parent.columnSpacing
flow: {
switch (root.layoutForm) {
case AppletError.HorizontalPanel:
case AppletError.VerticalPanel:
return fullRep.flow;
default:
return GridLayout.LeftToRight;
}
}
PC3.Button {
id: copyButton
display: root.layoutForm === AppletError.HorizontalPanel || root.layoutForm === AppletError.VerticalPanel ? PC3.AbstractButton.IconOnly : PC3.AbstractButton.TextBesideIcon
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Copy to Clipboard")
icon.name: "edit-copy"
onClicked: {
textArea.selectAll()
textArea.copy()
textArea.deselect()
}
PlasmaCore.ToolTipArea {
anchors.fill: parent
enabled: parent.display === PC3.AbstractButton.IconOnly
mainText: parent.text
textFormat: Text.PlainText
}
}
Loader {
id: compactContentLoader
active: root.layoutForm !== AppletError.Desktop
visible: active
sourceComponent: PC3.Button {
display: copyButton.display
icon.name: "window-new"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "View Error Details…")
checked: dialog.visible
onClicked: dialog.visible = !dialog.visible
PlasmaCore.ToolTipArea {
anchors.fill: parent
enabled: parent.display === PC3.AbstractButton.IconOnly
mainText: parent.text
textFormat: Text.PlainText
}
QQC2.ApplicationWindow {
id: dialog
flags: Qt.Dialog | Qt.WindowStaysOnTopHint | Qt.WindowMinMaxButtonsHint | Qt.WindowCloseButtonHint
minimumWidth: dialogFontMetrics.height * 12
+ dialogTextArea.leftPadding + dialogTextArea.rightPadding
minimumHeight: dialogFontMetrics.height * 12
+ dialogTextArea.topPadding + dialogTextArea.bottomPadding
width: Kirigami.Units.gridUnit * 24
height: Kirigami.Units.gridUnit * 24
color: palette.base
QQC2.ScrollView {
id: dialogScrollView
anchors.fill: parent
QQC2.TextArea {
id: dialogTextArea
// HACK: silence binding loop warnings.
// contentWidth seems to be causing the binding loop,
// but contentWidth is read-only and we have no control
// over how it is calculated.
implicitWidth: 0
wrapMode: TextEdit.Wrap
text: textArea.text
font.family: "monospace"
readOnly: true
selectByMouse: true
background: null
FontMetrics {
id: dialogFontMetrics
font: dialogTextArea.font
}
}
background: null
}
}
}
}
}
PC3.ScrollView {
id: fullContentView
// Not handled by a Loader because we need
// TextEdit::copy() to copy to clipboard.
visible: !compactContentLoader.active
Layout.fillHeight: true
Layout.fillWidth: true
PC3.TextArea {
id: textArea
// HACK: silence binding loop warnings.
// contentWidth seems to be causing the binding loop,
// but contentWidth is read-only and we have no control
// over how it is calculated.
implicitWidth: 0
wrapMode: TextEdit.Wrap
text: root.errorInformation && root.errorInformation.errors ?
root.errorInformation.errors.join("\n\n")
// This is just to suppress warnings. Users should never see this.
: "No error information."
font.family: "monospace"
readOnly: true
selectByMouse: true
}
}
}
}

View file

@ -0,0 +1,334 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Window 2.15
import org.kde.plasma.core as PlasmaCore
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.plasmoid 2.0
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kirigami 2.20 as Kirigami
PlasmaCore.ToolTipArea {
id: root
objectName: "org.kde.desktop-CompactApplet"
anchors.fill: parent
mainText: plasmoidItem ? plasmoidItem.toolTipMainText : ""
subText: plasmoidItem ? plasmoidItem.toolTipSubText : ""
location: Plasmoid.location
active: plasmoidItem ? !plasmoidItem.expanded : false
textFormat: plasmoidItem ? plasmoidItem.toolTipTextFormat : 0
mainItem: plasmoidItem && plasmoidItem.toolTipItem ? plasmoidItem.toolTipItem : null
readonly property bool vertical: location === PlasmaCore.Types.RightEdge || location === PlasmaCore.Types.LeftEdge
property Item fullRepresentation
property Item compactRepresentation
property Item expandedFeedback: expandedItem
property PlasmoidItem plasmoidItem
onCompactRepresentationChanged: {
if (compactRepresentation) {
compactRepresentation.anchors.fill = null;
compactRepresentation.parent = compactRepresentationParent;
compactRepresentation.anchors.fill = compactRepresentationParent;
compactRepresentation.visible = true;
}
root.visible = true;
}
onFullRepresentationChanged: {
if (fullRepresentation) {
fullRepresentation.anchors.fill = null;
fullRepresentation.parent = appletParent;
fullRepresentation.anchors.fill = appletParent;
}
}
FocusScope {
id: compactRepresentationParent
anchors.fill: parent
activeFocusOnTab: true
onActiveFocusChanged: {
// When the scope gets the active focus, try to focus its first descendant,
// if there is on which has activeFocusOnTab
if (!activeFocus) {
return;
}
let nextItem = nextItemInFocusChain();
let candidate = nextItem;
while (candidate.parent) {
if (candidate === compactRepresentationParent) {
nextItem.forceActiveFocus();
return;
}
candidate = candidate.parent;
}
}
objectName: "expandApplet"
Accessible.name: root.mainText
Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open %1", root.subText)
Accessible.role: Accessible.Button
Accessible.onPressAction: Plasmoid.activated()
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Select:
Plasmoid.activated();
break;
}
}
}
KSvg.FrameSvgItem {
id: expandedItem
z: -100
property var containerMargins: {
let item = root;
while (item.parent) {
item = item.parent;
if (item.isAppletContainer) {
return item.getMargins;
}
}
return undefined;
}
anchors {
fill: parent
property bool returnAllMargins: true
// The above makes sure margin is returned even for side margins, that
// would be otherwise turned off.
bottomMargin: !vertical && containerMargins ? -containerMargins('bottom', returnAllMargins) : 0;
topMargin: !vertical && containerMargins ? -containerMargins('top', returnAllMargins) : 0;
leftMargin: vertical && containerMargins ? -containerMargins('left', returnAllMargins) : 0;
rightMargin: vertical && containerMargins ? -containerMargins('right', returnAllMargins) : 0;
}
imagePath: "widgets/tabbar"
visible: false//opacity > 0
prefix: {
let prefix;
switch (Plasmoid.location) {
case PlasmaCore.Types.LeftEdge:
prefix = "west-active-tab";
break;
case PlasmaCore.Types.TopEdge:
prefix = "north-active-tab";
break;
case PlasmaCore.Types.RightEdge:
prefix = "east-active-tab";
break;
default:
prefix = "south-active-tab";
}
if (!hasElementPrefix(prefix)) {
prefix = "active-tab";
}
return prefix;
}
opacity: plasmoidItem && plasmoidItem.expanded ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: Kirigami.Units.shortDuration
easing.type: Easing.InOutQuad
}
}
}
Timer {
id: expandedSync
interval: 100
onTriggered: plasmoidItem.expanded = dialog.visible;
}
Connections {
target: Plasmoid.internalAction("configure")
function onTriggered() {
if (root.plasmoidItem.hideOnWindowDeactivate) {
plasmoidItem.expanded = false
}
}
}
Connections {
target: root.Plasmoid
function onContextualActionsAboutToShow() { root.hideImmediately() }
}
PlasmaCore.AppletPopup {
id: dialog
objectName: "popupWindow"
popupDirection: switch (Plasmoid.location) {
case PlasmaCore.Types.TopEdge:
return Qt.BottomEdge
case PlasmaCore.Types.LeftEdge:
return Qt.RightEdge
case PlasmaCore.Types.RightEdge:
return Qt.LeftEdge
default:
return Qt.TopEdge
}
margin: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersFloatingApplets) ? Kirigami.Units.largeSpacing : 0
floating: Plasmoid.location == PlasmaCore.Types.Floating
removeBorderStrategy: Plasmoid.location === PlasmaCore.Types.Floating
? PlasmaCore.AppletPopup.AtScreenEdges
: PlasmaCore.AppletPopup.AtScreenEdges | PlasmaCore.AppletPopup.AtPanelEdges
hideOnWindowDeactivate: root.plasmoidItem && root.plasmoidItem.hideOnWindowDeactivate
visible: root.plasmoidItem && root.plasmoidItem.expanded && fullRepresentation
visualParent: root.compactRepresentation
backgroundHints: (Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersOpaqueBackground) ? PlasmaCore.AppletPopup.SolidBackground : PlasmaCore.AppletPopup.StandardBackground
appletInterface: root.plasmoidItem
property var oldStatus: PlasmaCore.Types.UnknownStatus
onVisibleChanged: {
if (!visible) {
expandedSync.restart();
Plasmoid.status = oldStatus;
} else {
oldStatus = Plasmoid.status;
Plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus;
// This call currently fails and complains at runtime:
// QWindow::setWindowState: QWindow::setWindowState does not accept Qt::WindowActive
dialog.requestActivate();
}
}
//It's a MouseEventListener to get all the events, so the eventfilter will be able to catch them
mainItem: MouseEventListener {
id: appletParent
focus: true
Keys.onEscapePressed: {
root.plasmoidItem.expanded = false;
}
Layout.minimumWidth: fullRepresentation ? fullRepresentation.Layout.minimumWidth : 0
Layout.minimumHeight: fullRepresentation ? fullRepresentation.Layout.minimumHeight : 0
Layout.maximumWidth: fullRepresentation ? fullRepresentation.Layout.maximumWidth : Infinity
Layout.maximumHeight: fullRepresentation ? fullRepresentation.Layout.maximumHeight : Infinity
implicitWidth: {
if (root.fullRepresentation !== null) {
/****/ if (root.fullRepresentation.Layout.preferredWidth > 0) {
return root.fullRepresentation.Layout.preferredWidth;
} else if (root.fullRepresentation.implicitWidth > 0) {
return root.fullRepresentation.implicitWidth;
}
}
return Kirigami.Units.iconSizes.sizeForLabels * 35;
}
implicitHeight: {
if (root.fullRepresentation !== null) {
/****/ if (fullRepresentation.Layout.preferredHeight > 0) {
return fullRepresentation.Layout.preferredHeight;
} else if (fullRepresentation.implicitHeight > 0) {
return fullRepresentation.implicitHeight;
}
}
return Kirigami.Units.iconSizes.sizeForLabels * 25;
}
onActiveFocusChanged: {
if (activeFocus && fullRepresentation) {
fullRepresentation.forceActiveFocus()
}
}
// Draws a line between the applet dialog and the panel
KSvg.SvgItem {
id: separator
// Only draw for popups of panel applets, not desktop applets
visible: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.LeftEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge]
.includes(Plasmoid.location) && !dialog.margin
anchors {
topMargin: -dialog.topPadding
leftMargin: -dialog.leftPadding
rightMargin: -dialog.rightPadding
bottomMargin: -dialog.bottomPadding
}
z: 999 /* Draw the line on top of the applet */
elementId: (Plasmoid.location === PlasmaCore.Types.TopEdge || Plasmoid.location === PlasmaCore.Types.BottomEdge) ? "horizontal-line" : "vertical-line"
imagePath: "widgets/line"
states: [
State {
when: Plasmoid.location === PlasmaCore.Types.TopEdge
AnchorChanges {
target: separator
anchors {
top: separator.parent.top
left: separator.parent.left
right: separator.parent.right
}
}
PropertyChanges {
target: separator
height: 1
}
},
State {
when: Plasmoid.location === PlasmaCore.Types.LeftEdge
AnchorChanges {
target: separator
anchors {
left: separator.parent.left
top: separator.parent.top
bottom: separator.parent.bottom
}
}
PropertyChanges {
target: separator
width: 1
}
},
State {
when: Plasmoid.location === PlasmaCore.Types.RightEdge
AnchorChanges {
target: separator
anchors {
top: separator.parent.top
right: separator.parent.right
bottom: separator.parent.bottom
}
}
PropertyChanges {
target: separator
width: 1
}
},
State {
when: Plasmoid.location === PlasmaCore.Types.BottomEdge
AnchorChanges {
target: separator
anchors {
left: separator.parent.left
right: separator.parent.right
bottom: separator.parent.bottom
}
}
PropertyChanges {
target: separator
height: 1
}
}
]
}
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
}
}
}

View file

@ -0,0 +1,72 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
Kirigami.Icon {
property PlasmoidItem plasmoidItem
readonly property bool inPanel: [PlasmaCore.Types.TopEdge, PlasmaCore.Types.RightEdge, PlasmaCore.Types.BottomEdge, PlasmaCore.Types.LeftEdge]
.includes(Plasmoid.location)
Layout.minimumWidth: {
switch (Plasmoid.formFactor) {
case PlasmaCore.Types.Vertical:
return 0;
case PlasmaCore.Types.Horizontal:
return height;
default:
return Kirigami.Units.gridUnit * 3;
}
}
Layout.minimumHeight: {
switch (Plasmoid.formFactor) {
case PlasmaCore.Types.Vertical:
return width;
case PlasmaCore.Types.Horizontal:
return 0;
default:
return Kirigami.Units.gridUnit * 3;
}
}
source: Plasmoid.icon || "plasma"
active: mouseArea.containsMouse
activeFocusOnTab: true
Keys.onPressed: event => {
switch (event.key) {
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Select:
Plasmoid.activated();
event.accepted = true; // BUG 481393: Prevent system tray from receiving the event
break;
}
}
Accessible.name: Plasmoid.title
Accessible.description: plasmoidItem.toolTipSubText ?? ""
Accessible.role: Accessible.Button
MouseArea {
id: mouseArea
property bool wasExpanded: false
anchors.fill: parent
hoverEnabled: true
onPressed: wasExpanded = plasmoidItem.expanded
onClicked: plasmoidItem.expanded = !wasExpanded
}
}

View file

@ -0,0 +1,48 @@
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.3
import org.kde.plasma.core 2.0 as PlasmaCore
TextField {
id: root
signal clicked
activeFocusOnTab: true
Keys.priority: Keys.AfterItem
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Return) {
root.clicked();
}
}
onAccepted: {
root.clicked();
}
color: "black"
padding: 4
background: Rectangle {
color: "#2c628b"
radius: 3
implicitWidth: 100
implicitHeight: 24
border.color: "#7FFFFFFF"
border.width: 1
Rectangle {
anchors.fill: parent
anchors.margins: 1
color: "white"
radius: 2
implicitWidth: 100
implicitHeight: 24
border.color: "#2c628b"
border.width: 1
}
}
}

View file

@ -0,0 +1,30 @@
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents3
GenericButton {
id: root
implicitWidth: 38
implicitHeight: 28
focusPolicy: Qt.NoFocus
iconSource: "access"
/*PlasmaCore.IconItem {
id: elementIcon
anchors.centerIn: root
width: PlasmaCore.Units.iconSizes.smallMedium
height: width
animated: false
usesPlasmaTheme: false
source: "access"
}*/
}

View file

@ -0,0 +1,87 @@
import QtQuick 2.4
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import Qt5Compat.GraphicalEffects
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg as KSvg
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
Control {
id: genericButton
signal clicked
property string text: "";
property var iconSource: "";
property int iconSize: Kirigami.Units.iconSizes.smallMedium;
property alias label: btnLabel
Keys.priority: Keys.AfterItem
Keys.onPressed: (event) => {
if(event.key == Qt.Key_Return) {
genericButton.clicked();
}
}
KSvg.FrameSvgItem {
id: texture
z: -1
anchors.fill: parent
imagePath: Qt.resolvedUrl("../images/button.svg");
prefix: {
var result = "";
if(genericButton.focus) result = "focus-";
if(buttonMA.containsPress) result = "pressed";
else if(buttonMA.containsMouse) result += "hover";
else result += "normal";
return result;
}
}
MouseArea {
id: buttonMA
z: 99
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton;
onClicked: {
genericButton.clicked();
}
}
Kirigami.Icon {
id: btnIcon
z: 0
anchors.centerIn: genericButton
width: genericButton.iconSize
height: width
animated: false
//usesPlasmaTheme: false
source: genericButton.iconSource
visible: genericButton.iconSource !== ""
}
PlasmaComponents.Label {
id: btnLabel
z: 0
anchors.fill: parent
text: genericButton.text
visible: genericButton.text !== ""
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
renderType: Text.NativeRendering
font.hintingPreference: Font.PreferFullHinting
font.kerning: false
layer.enabled: genericButton.text !== ""
layer.effect: DropShadow {
//visible: !softwareRendering
horizontalOffset: 0
verticalOffset: 1
radius: 6
samples: 14
spread: 0.0001
color: "#bf000000"
}
}
}

View file

@ -0,0 +1,25 @@
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
Image {
id: root
property alias containsMouse: mouseArea.containsMouse
signal clicked
activeFocusOnTab: true
source: mouseArea.containsPress ? "../images/gopressed.png" : (activeFocus || containsMouse ? "../images/gohover.png" : "../images/go.png")
MouseArea {
id: mouseArea
hoverEnabled: true
onClicked: root.clicked()
anchors.fill: parent
}
}

View file

@ -0,0 +1,22 @@
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.components 3.0 as PlasmaComponents3
GenericButton {
id: root
implicitWidth: 45
implicitHeight: 28
focusPolicy: Qt.TabFocus
Accessible.description: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard")
//iconSource: "../images/osk.png"
Image {
anchors.centerIn: root
source: "../images/osk.png"
}
}

View file

@ -0,0 +1,64 @@
/*
SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.kirigami 2.20 as Kirigami
import Qt5Compat.GraphicalEffects
Item {
id: root
property string avatarPath
property string iconSource: "user-symbolic"
implicitWidth: 190
implicitHeight: 190
Item {
id: imageSource
anchors.centerIn: root
width: 126
height: 126
Image {
id: face
source: avatarPath
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
}
LinearGradient {
id: gradient
anchors.fill: parent
z: -1
start: Qt.point(0,0)
end: Qt.point(gradient.width, gradient.height)
gradient: Gradient {
GradientStop { position: 0.0; color: "#eeecee" }
GradientStop { position: 1.0; color: "#a39ea3" }
}
}
Kirigami.Icon {
id: faceIcon
source: iconSource
visible: (face.status == Image.Error || face.status == Image.Null)
anchors.fill: parent
anchors.margins: Kirigami.Units.gridUnit * 0.5 // because mockup says so...
//colorGroup: PlasmaCore.ColorScope.colorGroup
}
}
Image {
id: imageFrame
anchors.fill: root
source: "../images/pfpframe.png"
}
}

View file

@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2016 David Edmundson <davidedmundson@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.15
import Qt5Compat.GraphicalEffects
RowLayout {
id: root
property string statusText
property int spinnum: 0
property bool speen
spacing: 8
Image {
id: loadingspinner
source: "../images/100/spin"+spinnum+".png"
}
Label {
id: welcomeLbl
z: 1
text: statusText
color: "#FFFFFF"
font.pointSize: 18
renderType: Text.NativeRendering
font.hintingPreference: Font.PreferFullHinting
font.kerning: false
layer.enabled: true
layer.effect: DropShadow {
//visible: !softwareRendering
horizontalOffset: 0
verticalOffset: 1
radius: 6
samples: 14
spread: 0.0001
color: "#bf000000"
}
}
SequentialAnimation {
id: spinner
running: speen
loops: Animation.Infinite
NumberAnimation { target: root; property: "spinnum"; to: 17; duration: 900 }
NumberAnimation { target: root; property: "spinnum"; to: 0; duration: 0 }
}
}

View file

@ -0,0 +1,72 @@
/*
SPDX-FileCopyrightText: 2017 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.VirtualKeyboard 2.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
InputPanel {
id: inputPanel
property bool activated: false
active: activated && Qt.inputMethod.visible
width: parent.width
states: [
State {
name: "visible"
when: inputPanel.active
PropertyChanges {
target: inputPanel
y: inputPanel.parent.height - inputPanel.height
opacity: 1
visible: true
}
},
State {
name: "hidden"
when: !inputPanel.active
PropertyChanges {
target: inputPanel
y: inputPanel.parent.height
opacity: 0
visible:false
}
}
]
transitions: [
Transition {
to: "visible"
ParallelAnimation {
YAnimator {
// NOTE this is necessary as otherwise the keyboard always starts the transition with Y as 0, due to the internal reparenting happening when becomes active
from: inputPanel.parent.height
duration: Kirigami.Units.longDuration
easing.type: Easing.OutQuad
}
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.OutQuad
}
}
},
Transition {
to: "hidden"
ParallelAnimation {
YAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InQuad
}
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InQuad
}
}
}
]
}

View file

@ -0,0 +1,25 @@
/*
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick 2.15
import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards
Item {
id: inputPanel
readonly property bool active: Keyboards.KWinVirtualKeyboard.visible
property bool activated: false
visible: Keyboards.KWinVirtualKeyboard.visible
x: Qt.inputMethod.keyboardRectangle.x
y: Qt.inputMethod.keyboardRectangle.y
height: Qt.inputMethod.keyboardRectangle.height
width: Qt.inputMethod.keyboardRectangle.width
onActivatedChanged: if (activated) {
Keyboards.KWinVirtualKeyboard.enabled = true
}
}

View file

@ -0,0 +1,228 @@
/*
SPDX-FileCopyrightText: 2018 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils as KCM
/**
* A copy of Kirigami.AboutPage adapted to KPluginMetadata instead of KAboutData
*/
KCM.SimpleKCM {
id: page
title: i18n("About")
property var metaData: Plasmoid.metaData
Component {
id: personDelegate
RowLayout {
height: implicitHeight + (Kirigami.Units.smallSpacing * 2)
spacing: Kirigami.Units.smallSpacing * 2
Kirigami.Icon {
width: Kirigami.Units.iconSizes.smallMedium
height: width
source: "user"
}
QQC2.Label {
text: modelData.name
textFormat: Text.PlainText
}
Row {
// Group action buttons together
spacing: 0
QQC2.ToolButton {
visible: modelData.emailAddress
width: height
icon.name: "mail-sent"
display: QQC2.AbstractButton.IconOnly
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Send an email to %1", modelData.emailAddress)
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: text
onClicked: Qt.openUrlExternally("mailto:%1".arg(modelData.emailAddress))
}
QQC2.ToolButton {
visible: modelData.webAddress
width: height
icon.name: "globe"
display: QQC2.AbstractButton.IconOnly
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@info:tooltip %1 url", "Open website %1", modelData.webAddress)
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
QQC2.ToolTip.visible: hovered
QQC2.ToolTip.text: modelData.webAddress
onClicked: Qt.openUrlExternally(modelData.webAddress)
}
}
}
}
Component {
id: licenseComponent
Kirigami.OverlaySheet {
property alias text: licenseLabel.text
onClosed: destroy()
Kirigami.SelectableLabel {
id: licenseLabel
implicitWidth: Math.max(Kirigami.Units.gridUnit * 25, Math.round(page.width / 2), contentWidth)
wrapMode: Text.WordWrap
}
Component.onCompleted: open();
}
}
Item {
height: childrenRect.height
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Kirigami.Units.largeSpacing
GridLayout {
columns: 2
Layout.fillWidth: true
Kirigami.Icon {
Layout.rowSpan: 2
Layout.preferredHeight: Kirigami.Units.iconSizes.huge
Layout.preferredWidth: height
Layout.maximumWidth: page.width / 3;
Layout.rightMargin: Kirigami.Units.largeSpacing
source: page.metaData.iconName || page.metaData.pluginId
fallback: "application-x-plasma"
}
Kirigami.Heading {
Layout.fillWidth: true
text: page.metaData.name + " " + page.metaData.version
textFormat: Text.PlainText
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.maximumWidth: Kirigami.Units.gridUnit * 15
level: 2
wrapMode: Text.WordWrap
text: page.metaData.description
textFormat: Text.PlainText
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
Kirigami.Heading {
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Copyright")
textFormat: Text.PlainText
}
ColumnLayout {
spacing: Kirigami.Units.smallSpacing
Layout.leftMargin: Kirigami.Units.smallSpacing
QQC2.Label {
text: page.metaData.copyrightText
textFormat: Text.PlainText
visible: text.length > 0
}
Kirigami.UrlButton {
url: page.metaData.website
visible: url.length > 0
}
RowLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "License:")
textFormat: Text.PlainText
}
Kirigami.LinkButton {
text: page.metaData.license
Accessible.description: i18ndc("plasma_shell_org.kde.plasma.desktop", "@info:whatsthis", "View license text")
onClicked: {
licenseComponent.incubateObject(page.Window.window.contentItem, {
"text": page.metaData.licenseText,
"title": page.metaData.license,
}, Qt.Asynchronous);
}
}
}
}
Kirigami.Heading {
Layout.fillWidth: true
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Authors")
textFormat: Text.PlainText
visible: page.metaData.authors.length > 0
}
Repeater {
model: page.metaData.authors
delegate: personDelegate
}
Kirigami.Heading {
height: visible ? implicitHeight : 0
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Credits")
textFormat: Text.PlainText
visible: repCredits.count > 0
}
Repeater {
id: repCredits
model: page.metaData.otherContributors
delegate: personDelegate
}
Kirigami.Heading {
height: visible ? implicitHeight : 0
Layout.topMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Translators")
textFormat: Text.PlainText
visible: repTranslators.count > 0
}
Repeater {
id: repTranslators
model: page.metaData.translators
delegate: personDelegate
}
Item {
Layout.fillWidth: true
}
QQC2.Button {
Layout.alignment: Qt.AlignHCenter
icon.name: "tools-report-bug"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Report a Bug…")
visible: page.metaData.bugReportUrl.length > 0
onClicked: Qt.openUrlExternally(page.metaData.bugReportUrl)
}
}
}
}

View file

@ -0,0 +1,514 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-FileCopyrightText: 2022-2023 ivan tkachenko <me@ratijas.tk>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Layouts 1.15
import org.kde.kirigami as Kirigami
import org.kde.kitemmodels 1.0 as KItemModels
import org.kde.plasma.configuration 2.0
import org.kde.plasma.plasmoid 2.0
Rectangle {
id: root
implicitWidth: Kirigami.Units.gridUnit * 40
implicitHeight: Kirigami.Units.gridUnit * 30
Layout.minimumWidth: Kirigami.Units.gridUnit * 30
Layout.minimumHeight: Kirigami.Units.gridUnit * 21
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
color: Kirigami.Theme.backgroundColor
property bool isContainment: false
property ConfigModel globalConfigModel: globalAppletConfigModel
property url currentSource
function closing() {
if (applyButton.enabled) {
messageDialog.item = null;
messageDialog.open();
return false;
}
return true;
}
function saveConfig() {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const cfgKey = "cfg_" + key;
if (cfgKey in app.pageStack.currentItem) {
config[key] = app.pageStack.currentItem[cfgKey];
}
})
plasmoid.configuration.writeConfig();
// For ConfigurationContainmentActions.qml
if (app.pageStack.currentItem.hasOwnProperty("saveConfig")) {
app.pageStack.currentItem.saveConfig()
}
}
Connections {
target: configDialog
function onClosing(event) {
event.accepted = closing();
}
}
ConfigModel {
id: globalAppletConfigModel
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Keyboard Shortcuts")
icon: "preferences-desktop-keyboard"
source: Qt.resolvedUrl("ConfigurationShortcuts.qml")
}
}
KItemModels.KSortFilterProxyModel {
id: configDialogFilterModel
sourceModel: configDialog.configModel
filterRowCallback: (row, parent) => {
return sourceModel.data(sourceModel.index(row, 0), ConfigModel.VisibleRole);
}
}
function settingValueChanged() {
applyButton.enabled = true;
}
function pushReplace(item, config) {
let page;
if (app.pageStack.depth === 0) {
page = app.pageStack.push(item, config);
} else {
page = app.pageStack.replace(item, config);
}
app.currentConfigPage = page;
}
Component {
id: configurationKcmPageComponent
ConfigurationKcmPage {
}
}
function open(item) {
app.isAboutPage = false;
root.currentSource = item.source
if (item.source) {
app.isAboutPage = item.source === Qt.resolvedUrl("AboutPlugin.qml");
if (isContainment) {
pushReplace(Qt.resolvedUrl("ConfigurationAppletPage.qml"), {configItem: item});
} else {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
const props = {
"title": item.name
};
config.keys().forEach(key => {
props["cfg_" + key] = config[key];
});
pushReplace(item.source, props);
}
} else if (item.kcm) {
pushReplace(configurationKcmPageComponent, {kcm: item.kcm, internalPage: item.kcm.mainUi});
} else {
app.pageStack.pop();
}
applyButton.enabled = false
}
Connections {
target: app.currentConfigPage
function onSettingValueChanged() {
applyButton.enabled = true;
}
}
Connections {
target: app.pageStack
function onCurrentItemChanged() {
if (app.pageStack.currentItem !== null && !isContainment) {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const changedSignal = app.pageStack.currentItem["cfg_" + key + "Changed"];
if (changedSignal) {
changedSignal.connect(() => root.settingValueChanged());
}
});
const configurationChangedSignal = app.pageStack.currentItem.configurationChanged;
if (configurationChangedSignal) {
configurationChangedSignal.connect(() => root.settingValueChanged());
}
}
}
}
Component.onCompleted: {
// if we are a containment then the first item will be ConfigurationContainmentAppearance
// if the applet does not have own configs then the first item will be Shortcuts
if (isContainment || !configDialog.configModel || configDialog.configModel.count === 0) {
open(root.globalConfigModel.get(0))
} else {
open(configDialog.configModel.get(0))
}
}
function applicationWindow() {
return app;
}
QQC2.ScrollView {
id: categoriesScroll
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
width: Kirigami.Units.gridUnit * 10
contentWidth: availableWidth
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
activeFocusOnTab: true
focus: true
Accessible.role: Accessible.MenuBar
background: Rectangle {
color: Kirigami.Theme.backgroundColor
}
Image {
source: "rsrc/bg.png"
anchors.fill: parent
smooth: true
}
Keys.onUpPressed: event => {
const buttons = categories.children
let foundPrevious = false
for (let i = buttons.length - 1; i >= 0; --i) {
const button = buttons[i];
if (!button.hasOwnProperty("highlighted")) {
// not a ConfigCategoryDelegate
continue;
}
if (foundPrevious) {
categories.openCategory(button.item)
categoriesScroll.forceActiveFocus(Qt.TabFocusReason)
return
} else if (button.highlighted) {
foundPrevious = true
}
}
event.accepted = false
}
Keys.onDownPressed: event => {
const buttons = categories.children
let foundNext = false
for (let i = 0, length = buttons.length; i < length; ++i) {
const button = buttons[i];
if (!button.hasOwnProperty("highlighted")) {
continue;
}
if (foundNext) {
categories.openCategory(button.item)
categoriesScroll.forceActiveFocus(Qt.TabFocusReason)
return
} else if (button.highlighted) {
foundNext = true
}
}
event.accepted = false
}
ColumnLayout {
id: categories
spacing: Kirigami.Units.largeSpacing
width: categoriesScroll.contentWidth
focus: true
function openCategory(item) {
if (applyButton.enabled) {
messageDialog.item = item;
messageDialog.open();
return;
}
open(item)
}
Item {
id: paddingItem
Layout.preferredHeight: Kirigami.Units.iconSizes.small
}
Component {
id: categoryDelegate
RowLayout {
id: delegate
required property var model
property var item: model
Accessible.role: Accessible.MenuItem
Accessible.name: model.name
Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open configuration page")
Accessible.onPressAction: ma.clicked(null)
Layout.leftMargin: Kirigami.Units.largeSpacing
spacing: Kirigami.Units.largeSpacing
property bool highlighted: {
if (app.pageStack.currentItem) {
if (model.kcm && app.pageStack.currentItem.kcm) {
return model.kcm == app.pageStack.currentItem.kcm
} else {
return root.currentSource == model.source
}
}
return false
}
Kirigami.Icon {
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
implicitWidth: Kirigami.Units.iconSizes.small
implicitHeight: Kirigami.Units.iconSizes.small
source: delegate.model.icon
}
Text {
color: ma.containsMouse ? "#074ae5" : "#151c55"
font.underline: ma.containsMouse
font.bold: parent.highlighted || delegate.focus
text: parent.model.name
wrapMode: Text.WordWrap
MouseArea {
id: ma
anchors.fill: parent
enabled: !highlighted
hoverEnabled: true
onClicked: categories.openCategory(model);
cursorShape: delegate.highlighted ? Qt.ArrowCursor : Qt.PointingHandCursor
}
}
}
/*ConfigCategoryDelegate {
id: delegate
onActivated: categories.openCategory(model);
highlighted: {
if (app.pageStack.currentItem) {
if (model.kcm && app.pageStack.currentItem.kcm) {
return model.kcm == app.pageStack.currentItem.kcm
} else {
return root.currentSource == model.source
}
}
return false
}
item: model
}*/
}
Repeater {
Layout.fillWidth: true
model: root.isContainment ? globalConfigModel : undefined
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: configDialogFilterModel
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: !root.isContainment ? globalConfigModel : undefined
delegate: categoryDelegate
}
Repeater {
Layout.fillWidth: true
model: ConfigModel {
ConfigCategory{
name: i18nd("plasma_shell_org.kde.plasma.desktop", "About")
icon: "help-about"
source: Qt.resolvedUrl("AboutPlugin.qml")
}
}
delegate: categoryDelegate
}
}
}
Kirigami.Separator {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
z: 1
}
Kirigami.Separator {
id: verticalSeparator
anchors {
top: parent.top
left: categoriesScroll.right
bottom: parent.bottom
}
z: 1
}
Kirigami.ApplicationItem {
id: app
anchors {
top: parent.top
left: verticalSeparator.right
right: parent.right
bottom: parent.bottom
}
pageStack.globalToolBar.style: Kirigami.ApplicationHeaderStyle.Breadcrumb
wideScreen: true
pageStack.globalToolBar.separatorVisible: bottomSeparator.visible
pageStack.globalToolBar.colorSet: Kirigami.Theme.View
property var currentConfigPage: null
onCurrentConfigPageChanged: {
if(currentConfigPage) {
currentConfigPage.Kirigami.Theme.colorSet = Kirigami.Theme.View
}
}
property bool isAboutPage: false
Kirigami.PromptDialog {
id: messageDialog
property var item
title: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply Settings")
subtitle: i18nd("plasma_shell_org.kde.plasma.desktop", "The settings of the current module have changed. Do you want to apply the changes or discard them?")
standardButtons: Kirigami.Dialog.Apply | Kirigami.Dialog.Discard | Kirigami.Dialog.Cancel
onApplied: {
applyAction.trigger()
discarded();
}
onDiscarded: {
if (item) {
root.open(item);
messageDialog.close();
} else {
applyButton.enabled = false;
configDialog.close();
}
}
}
footer: QQC2.Pane {
padding: Kirigami.Units.largeSpacing
contentItem: RowLayout {
id: buttonsRow
spacing: Kirigami.Units.smallSpacing
Kirigami.Theme.colorSet: Kirigami.Theme.View
Item {
Layout.fillWidth: true
}
QQC2.Button {
icon.name: "dialog-ok"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "OK")
onClicked: acceptAction.trigger()
KeyNavigation.tab: categories
}
QQC2.Button {
id: applyButton
enabled: false
icon.name: "dialog-ok-apply"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply")
visible: !app.isAboutPage && app.pageStack.currentItem && (!app.pageStack.currentItem.kcm || app.pageStack.currentItem.kcm.buttons & 4) // 4 = Apply button
onClicked: applyAction.trigger()
}
QQC2.Button {
icon.name: "dialog-cancel"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Cancel")
onClicked: cancelAction.trigger()
visible: !app.isAboutPage
}
}
background: Item {
Kirigami.Separator {
id: bottomSeparator
visible: app.pageStack.currentItem
&& app.pageStack.currentItem.flickable
&& !(app.pageStack.currentItem.flickable.atYBeginning
&& app.pageStack.currentItem.flickable.atYEnd)
anchors {
left: parent.left
right: parent.right
top: parent.top
}
}
}
}
QQC2.Action {
id: acceptAction
onTriggered: {
applyAction.trigger();
configDialog.close();
}
}
QQC2.Action {
id: applyAction
onTriggered: {
if (isContainment) {
app.pageStack.get(0).saveConfig()
} else {
root.saveConfig()
}
applyButton.enabled = false;
}
}
QQC2.Action {
id: cancelAction
onTriggered: {
if (root.closing()) {
configDialog.close();
}
}
}
Keys.onReturnPressed: acceptAction.trigger();
Keys.onEscapePressed: cancelAction.trigger();
}
}

View file

@ -0,0 +1,71 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Window 2.2
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kirigami 2.5 as Kirigami
QQC2.ItemDelegate {
id: delegate
signal activated()
//BEGIN properties
Layout.fillWidth: true
hoverEnabled: true
Accessible.role: Accessible.MenuItem
Accessible.name: model.name
Accessible.description: i18nd("plasma_shell_org.kde.plasma.desktop", "Open configuration page")
Accessible.onPressAction: delegate.clicked()
property var item
//END properties
//BEGIN connections
onClicked: {
if (highlighted) {
return;
}
activated()
}
//END connections
//BEGIN UI components
contentItem: ColumnLayout {
id: delegateContents
spacing: Kirigami.Units.smallSpacing
Kirigami.Icon {
Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.iconSizes.medium
implicitHeight: Kirigami.Units.iconSizes.medium
source: model.icon
selected: Window.active && (delegate.highlighted || delegate.pressed)
}
QQC2.Label {
id: nameLabel
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
text: model.name
textFormat: Text.PlainText
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
color: Window.active && (delegate.highlighted || delegate.pressed) ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
font.bold: delegate.highlighted && delegate.parent.activeFocus
Accessible.ignored: true
}
}
//END UI components
}

View file

@ -0,0 +1,81 @@
/*
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.10 as Kirigami
Kirigami.ScrollablePage {
id: root
title: configItem.name
required property var configItem
signal settingValueChanged()
function saveConfig() {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const cfgKey = "cfg_" + key;
if (cfgKey in loader.item) {
config[key] = loader.item[cfgKey];
}
})
Plasmoid.configuration.writeConfig();
// For ConfigurationContainmentActions.qml
if (loader.item.hasOwnProperty("saveConfig")) {
loader.item.saveConfig()
}
}
implicitHeight: loader.height
padding: configItem.includeMargins ? Kirigami.Units.largeSpacing : 0
bottomPadding: 0
Loader {
id: loader
width: parent.width
// HACK the height of the loader is based on the implicitHeight of the content.
// Unfortunately not all content items have a sensible implicitHeight.
// If it is zero fall back to the height of its children
// Also make it at least as high as the page itself. Some existing configs assume they fill the whole space
// TODO KF6 clean this up by making all configs based on SimpleKCM/ScrollViewKCM/GridViewKCM
height: Math.max(root.availableHeight, item.implicitHeight ? item.implicitHeight : item.childrenRect.height)
Component.onCompleted: {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
const props = {};
config.keys().forEach(key => {
props["cfg_" + key] = config[key];
});
setSource(configItem.source, props);
}
onLoaded: {
const config = Plasmoid.configuration; // type: KConfigPropertyMap
config.keys().forEach(key => {
const changedSignal = item["cfg_" + key + "Changed"];
if (changedSignal) {
changedSignal.connect(() => root.settingValueChanged());
}
});
const configurationChangedSignal = item.configurationChanged;
if (configurationChangedSignal) {
configurationChangedSignal.connect(() => root.settingValueChanged());
}
}
}
}

View file

@ -0,0 +1,190 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.0
import org.kde.kirigami 2.20 as Kirigami
Item {
id: root
signal configurationChanged
implicitWidth: mainColumn.implicitWidth
implicitHeight: mainColumn.implicitHeight
property var prettyStrings: {
"LeftButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Left-Button"),
"RightButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Right-Button"),
"MiddleButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Middle-Button"),
"BackButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Back-Button"),
"ForwardButton": i18nd("plasma_shell_org.kde.plasma.desktop", "Forward-Button"),
"wheel:Vertical": i18nd("plasma_shell_org.kde.plasma.desktop", "Vertical-Scroll"),
"wheel:Horizontal": i18nd("plasma_shell_org.kde.plasma.desktop", "Horizontal-Scroll"),
"ShiftModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Shift"),
"ControlModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Ctrl"),
"AltModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Alt"),
"MetaModifier": i18nd("plasma_shell_org.kde.plasma.desktop", "Meta")
}
function saveConfig() {
configDialog.currentContainmentActionsModel.save();
}
Connections {
target: configDialog.currentContainmentActionsModel
function onConfigurationChanged() {
root.configurationChanged()
}
}
Component {
id: aboutComponent
Kirigami.OverlaySheet {
id: internalAboutDialog
property alias metaData: aboutPluginPage.metaData
width: Math.round(root.width * 0.8)
onClosed: destroy()
AboutPlugin {
id: aboutPluginPage
metaData: internalAboutDialog.metaData
}
Component.onCompleted: open();
}
}
GridLayout {
id: mainColumn
flow: GridLayout.TopToBottom
y: 25
width: parent.width
Repeater {
id: actionsRepeater
model: configDialog.currentContainmentActionsModel
MouseEventInputButton {
Layout.column: 0
Layout.row: index
Layout.fillWidth: true
Layout.minimumWidth: implicitWidth
defaultText: {
var splitAction = model.action.split(';');
var button = splitAction[0];
var modifiers = (splitAction[1] || "").split('|').filter(function (item) {
return item !== "NoModifier";
});
var parts = modifiers;
modifiers.push(button);
return parts.map(function (item) {
return prettyStrings[item] || item;
}).join(i18ndc("plasma_shell_org.kde.plasma.desktop", "Concatenation sign for shortcuts, e.g. Ctrl+Shift", "+"));
}
eventString: model.action
onEventStringChanged: {
configDialog.currentContainmentActionsModel.update(index, eventString, model.pluginName);
}
}
}
Repeater {
model: configDialog.currentContainmentActionsModel
QQC2.ComboBox {
id: pluginsCombo
// "index" argument of onActivated shadows the model index
readonly property int pluginIndex: index
Layout.fillWidth: true
Layout.column: 1
Layout.row: index
// both MouseEventInputButton and this ComboBox have fillWidth for a uniform layout
// however, their implicit sizes is taken into account and they compete against
// each other for available space. By setting an insane preferredWidth we give
// ComboBox a greater share of the available space
Layout.preferredWidth: 9000
model: configDialog.containmentActionConfigModel
textRole: "name"
property bool initialized: false
Component.onCompleted: {
for (var i = 0; i < configDialog.containmentActionConfigModel.count; ++i) {
if (configDialog.containmentActionConfigModel.get(i).pluginName === pluginName) {
pluginsCombo.currentIndex = i;
break;
}
}
pluginsCombo.initialized = true;
}
onActivated: {
if (initialized) {
var newPluginName = configDialog.containmentActionConfigModel.get(index).pluginName;
if (newPluginName !== pluginName) {
configDialog.currentContainmentActionsModel.update(pluginIndex, action, newPluginName);
}
}
}
}
}
Repeater {
model: configDialog.currentContainmentActionsModel
RowLayout {
Layout.column: 2
Layout.row: index
QQC2.Button {
icon.name: "configure"
width: height
enabled: model.hasConfigurationInterface
onClicked: {
configDialog.currentContainmentActionsModel.showConfiguration(index, this);
}
}
QQC2.Button {
icon.name: "dialog-information"
width: height
onClicked: {
const metaData = configDialog.currentContainmentActionsModel.aboutMetaData(index);
if (!metaData) {
return;
}
aboutComponent.incubateObject(root.Window.window.contentItem, {
"metaData": metaData,
"title": i18ndc("plasma_shell_org.kde.plasma.desktop", "@title", "About"),
}, Qt.Asynchronous);
}
}
QQC2.Button {
icon.name: "list-remove"
width: height
onClicked: {
configDialog.currentContainmentActionsModel.remove(index);
}
}
}
}
MouseEventInputButton {
defaultText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Action");
icon.name: checked ? "input-mouse-symbolic" : "list-add"
onEventStringChanged: {
configDialog.currentContainmentActionsModel.append(eventString, "org.kde.contextmenu");
}
}
}
}

View file

@ -0,0 +1,213 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.configuration 2.0
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.1
import QtQml 2.15
import org.kde.newstuff 1.62 as NewStuff
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kcmutils
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.configuration 2.0
Item {
id: appearanceRoot
signal configurationChanged
property int formAlignment: wallpaperComboBox.Kirigami.ScenePosition.x - appearanceRoot.Kirigami.ScenePosition.x + Kirigami.Units.smallSpacing
property string currentWallpaper: ""
property string containmentPlugin: ""
property alias parentLayout: parentLayout
function saveConfig() {
if (main.currentItem.saveConfig) {
main.currentItem.saveConfig()
}
configDialog.currentWallpaper = appearanceRoot.currentWallpaper;
for (var key in configDialog.wallpaperConfiguration) {
if (main.currentItem["cfg_"+key] !== undefined) {
configDialog.wallpaperConfiguration[key] = main.currentItem["cfg_"+key]
}
}
configDialog.applyWallpaper()
configDialog.containmentPlugin = appearanceRoot.containmentPlugin
}
ColumnLayout {
width: root.availableWidth
height: Math.max(implicitHeight, root.availableHeight)
spacing: 0 // unless it's 0 there will be an additional gap between two FormLayouts
Component.onCompleted: {
for (var i = 0; i < configDialog.containmentPluginsConfigModel.count; ++i) {
var pluginName = configDialog.containmentPluginsConfigModel.data(configDialog.containmentPluginsConfigModel.index(i, 0), ConfigModel.PluginNameRole);
if (configDialog.containmentPlugin === pluginName) {
pluginComboBox.currentIndex = i
pluginComboBox.activated(i);
break;
}
}
for (var i = 0; i < configDialog.wallpaperConfigModel.count; ++i) {
var pluginName = configDialog.wallpaperConfigModel.data(configDialog.wallpaperConfigModel.index(i, 0), ConfigModel.PluginNameRole);
if (configDialog.currentWallpaper === pluginName) {
wallpaperComboBox.currentIndex = i
wallpaperComboBox.activated(i);
break;
}
}
}
Kirigami.InlineMessage {
visible: Plasmoid.immutable || animating
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes have been restricted by the system administrator")
showCloseButton: true
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing * 2 // we need this because ColumnLayout's spacing is 0
}
Kirigami.FormLayout {
id: parentLayout // needed for twinFormLayouts to work in wallpaper plugins
twinFormLayouts: main.currentItem.formLayout || []
Layout.fillWidth: true
QQC2.ComboBox {
id: pluginComboBox
Layout.preferredWidth: Math.max(implicitWidth, wallpaperComboBox.implicitWidth)
Kirigami.FormData.label: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout:")
enabled: !Plasmoid.immutable
model: configDialog.containmentPluginsConfigModel
textRole: "name"
onActivated: {
var model = configDialog.containmentPluginsConfigModel.get(currentIndex)
appearanceRoot.containmentPlugin = model.pluginName
appearanceRoot.configurationChanged()
}
}
RowLayout {
Layout.fillWidth: true
enabled: main.currentItem.objectName !== "switchContainmentWarningItem"
Kirigami.FormData.label: i18nd("plasma_shell_org.kde.plasma.desktop", "Wallpaper type:")
QQC2.ComboBox {
id: wallpaperComboBox
Layout.preferredWidth: Math.max(implicitWidth, pluginComboBox.implicitWidth)
model: configDialog.wallpaperConfigModel
textRole: "name"
onActivated: {
var idx = configDialog.wallpaperConfigModel.index(currentIndex, 0)
var pluginName = configDialog.wallpaperConfigModel.data(idx, ConfigModel.PluginNameRole)
if (appearanceRoot.currentWallpaper === pluginName) {
return;
}
appearanceRoot.currentWallpaper = pluginName
configDialog.currentWallpaper = pluginName
main.sourceFile = configDialog.wallpaperConfigModel.data(idx, ConfigModel.SourceRole)
appearanceRoot.configurationChanged()
}
}
NewStuff.Button {
configFile: "wallpaperplugin.knsrc"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Get New Plugins…")
visibleWhenDisabled: true // don't hide on disabled
Layout.preferredHeight: wallpaperComboBox.height
}
}
}
Item {
id: emptyConfig
}
QQC2.StackView {
id: main
implicitHeight: main.empty ? 0 : currentItem.implicitHeight
Layout.fillHeight: true;
Layout.fillWidth: true;
// Bug 360862: if wallpaper has no config, sourceFile will be ""
// so we wouldn't load emptyConfig and break all over the place
// hence set it to some random value initially
property string sourceFile: "tbd"
onSourceFileChanged: loadSourceFile()
function loadSourceFile() {
const wallpaperConfig = configDialog.wallpaperConfiguration
// BUG 407619: wallpaperConfig can be null before calling `ContainmentItem::loadWallpaper()`
if (wallpaperConfig && sourceFile) {
var props = {
"configDialog": configDialog
}
for (var key in wallpaperConfig) {
props["cfg_" + key] = wallpaperConfig[key]
}
var newItem = replace(Qt.resolvedUrl(sourceFile), props)
for (var key in wallpaperConfig) {
var changedSignal = newItem["cfg_" + key + "Changed"]
if (changedSignal) {
changedSignal.connect(appearanceRoot.configurationChanged)
}
}
const configurationChangedSignal = newItem.configurationChanged
if (configurationChangedSignal) {
configurationChangedSignal.connect(appearanceRoot.configurationChanged)
}
} else {
replace(emptyConfig)
}
}
}
Kirigami.Separator {
Layout.fillWidth: true
}
}
Component {
id: switchContainmentWarning
Item {
objectName: "switchContainmentWarningItem"
Kirigami.PlaceholderMessage {
id: message
width: parent.width - Kirigami.Units.largeSpacing * 8
anchors.centerIn: parent
icon.name: "documentinfo"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes must be applied before other changes can be made")
helpfulAction: QQC2.Action {
icon.name: "dialog-ok-apply"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Apply Now")
onTriggered: saveConfig()
}
}
}
}
onContainmentPluginChanged: {
if (configDialog.containmentPlugin !== appearanceRoot.containmentPlugin) {
main.push(switchContainmentWarning);
categoriesScroll.enabled = false;
} else if (main.currentItem.objectName === "switchContainmentWarningItem") {
main.pop();
categoriesScroll.enabled = true;
}
}
}

View file

@ -0,0 +1,74 @@
/*
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6
import org.kde.kirigami 2.5 as Kirigami
Kirigami.Page {
id: container
required property QtObject kcm
required property Item internalPage
signal settingValueChanged()
title: kcm.name
topPadding: 0
leftPadding: 0
rightPadding: 0
bottomPadding: 0
flickable: internalPage.flickable
actions: internalPage.actions
onInternalPageChanged: {
internalPage.parent = contentItem;
internalPage.anchors.fill = contentItem;
}
onActiveFocusChanged: {
if (activeFocus) {
internalPage.forceActiveFocus();
}
}
Component.onCompleted: {
kcm.load()
}
function saveConfig() {
kcm.save();
}
data: [
Connections {
target: kcm
onPagePushed: {
app.pageStack.push(configurationKcmPageComponent.createObject(app.pageStack, {"kcm": kcm, "internalPage": page}));
}
onPageRemoved: app.pageStack.pop();
},
Connections {
target: app.pageStack
onPageRemoved: {
if (kcm.needsSave) {
kcm.save()
}
if (page == container) {
page.destroy();
}
}
}
]
Connections {
target: kcm
function onNeedsSaveChanged() {
if (kcm.needsSave) {
container.settingValueChanged()
}
}
}
}

View file

@ -0,0 +1,46 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.0
import org.kde.kquickcontrols 2.0
import org.kde.kirigami 2.14 as Kirigami
import org.kde.plasma.plasmoid 2.0
import org.kde.kcmutils as KCM
KCM.SimpleKCM {
id: root
title: i18n("Shortcuts")
signal configurationChanged
function saveConfig() {
Plasmoid.globalShortcut = button.keySequence
}
ColumnLayout {
spacing: Kirigami.Units.smallSpacing
QQC2.Label {
Layout.fillWidth: true
text: i18nd("plasma_shell_org.kde.plasma.desktop", "This shortcut will activate the applet as though it had been clicked.")
textFormat: Text.PlainText
wrapMode: Text.WordWrap
}
KeySequenceItem {
id: button
keySequence: Plasmoid.globalShortcut
modifierOnlyAllowed: true
onCaptureFinished: {
if (keySequence !== Plasmoid.globalShortcut) {
root.configurationChanged();
}
}
}
}
}

View file

@ -0,0 +1,40 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.0
import org.kde.kirigami 2.15 as Kirigami
import org.kde.plasma.configuration 2.0
import org.kde.plasma.plasmoid 2.0
AppletConfiguration {
id: root
isContainment: true
Layout.minimumWidth: Kirigami.Units.gridUnit * 35
Layout.minimumHeight: Kirigami.Units.gridUnit * 30
Layout.preferredWidth: Kirigami.Units.gridUnit * 32
Layout.preferredHeight: Kirigami.Units.gridUnit * 36
//BEGIN model
globalConfigModel: globalContainmentConfigModel
ConfigModel {
id: globalContainmentConfigModel
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Wallpaper")
icon: "preferences-desktop-wallpaper"
source: "ConfigurationContainmentAppearance.qml"
includeMargins: false
}
ConfigCategory {
name: i18nd("plasma_shell_org.kde.plasma.desktop", "Mouse Actions")
icon: "preferences-desktop-mouse"
source: "ConfigurationContainmentActions.qml"
}
}
//END model
}

View file

@ -0,0 +1,53 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Controls 2.3 as QQC2
QQC2.Button {
id: mouseInputButton
property string defaultText: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Action")
text: defaultText
checkable: true
property string eventString
onCheckedChanged: {
if (checked) {
text = i18nd("plasma_shell_org.kde.plasma.desktop", "Input Here");
mouseInputArea.enabled = true;
}
}
MouseArea {
id: mouseInputArea
anchors.fill: parent
acceptedButtons: Qt.AllButtons
enabled: false
onClicked: {
var newEventString = configDialog.currentContainmentActionsModel.mouseEventString(mouse.button, mouse.modifiers);
if (eventString === newEventString || !configDialog.currentContainmentActionsModel.isTriggerUsed(newEventString)) {
eventString = newEventString;
mouseInputButton.text = defaultText;
mouseInputButton.checked = false;
enabled = false;
}
}
onWheel: {
var newEventString = configDialog.currentContainmentActionsModel.wheelEventString(wheel);
if (eventString === newEventString || !configDialog.currentContainmentActionsModel.isTriggerUsed(newEventString)) {
eventString = newEventString;
mouseInputButton.text = defaultText;
mouseInputButton.checked = false;
enabled = false;
}
}
}
}

View file

@ -0,0 +1,632 @@
/*
SPDX-FileCopyrightText: 2023 Niccolò Venerandi <niccolo.venerandi@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
import "panelconfiguration"
ColumnLayout {
id: dialogRoot
spacing: Kirigami.Units.largeSpacing * 2
signal closeContextMenu
required property QtObject panelConfiguration
property bool vertical: (panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge)
readonly property int headingLevel: 2
property Item panelRuler: Ruler {
id: ruler
prefix: {
switch (panel.location) {
case PlasmaCore.Types.TopEdge:
return "north"
case PlasmaCore.Types.LeftEdge:
return "west"
case PlasmaCore.Types.RightEdge:
return "east"
case PlasmaCore.Types.BottomEdge:
default:
return "south"
}
}
Item {
activeFocusOnTab: true
onActiveFocusChanged: {
if (activeFocus && dialogRoot.Window.window && dialogRoot.Window.window.visible) {
dialogRoot.Window.window.requestActivate()
}
}
}
// This item is used to "pass" focus to the main window when we're at the last of the control of the ruler
Item {
parent: dialogRoot.parent // Used to not take space in the ColumnLayout
activeFocusOnTab: true
onActiveFocusChanged: {
let window = dialogRoot.Window.window
if (activeFocus && window && window.visible) {
window.requestActivate()
}
}
}
}
Connections {
target: panel
function onOffsetChanged() {
ruler.offset = panel.offset
}
function onMinimumLengthChanged() {
ruler.minimumLength = panel.minimumLength
}
function onMaximumLengthChanged() {
ruler.maximumLength = panel.maximumLength
}
}
Component.onCompleted: {
if (panel.lengthMode === Panel.Global.Custom) {
Qt.callLater(()=> {
panelConfiguration.panelRulerView.visible = true
})
}
}
PlasmaExtras.PlasmoidHeading {
RowLayout {
anchors.fill: parent
spacing: Kirigami.Units.largeSpacing
Kirigami.Heading {
Layout.leftMargin: Kirigami.Units.smallSpacing
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Settings")
textFormat: Text.PlainText
}
Item { Layout.fillWidth: true }
PC3.ToolButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Spacer")
icon.name: "distribute-horizontal-x"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add spacer widget to the panel")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: configDialog.addPanelSpacer()
}
PC3.ToolButton {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Add Widgets…")
icon.name: "list-add"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Open the widget selector to drag and drop widgets to the panel")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: {
configDialog.close()
configDialog.showAddWidgetDialog()
}
}
}
}
GridLayout {
Layout.leftMargin: columnSpacing
Layout.rightMargin: columnSpacing
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: (positionRepresentation.implicitWidth + columnSpacing) * columns + columnSpacing
rowSpacing: dialogRoot.spacing
columnSpacing: Kirigami.Units.smallSpacing
rows: 2
columns: 3
uniformCellWidths: true
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Position")
textFormat: Text.PlainText
}
PanelRepresentation {
id: positionRepresentation
text: (panel.location === PlasmaCore.Types.TopEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Top") :
panel.location === PlasmaCore.Types.RightEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Right") :
panel.location === PlasmaCore.Types.LeftEdge ? i18nd("plasma_shell_org.kde.plasma.desktop", "Left") :
i18nd("plasma_shell_org.kde.plasma.desktop", "Bottom"))
Layout.alignment: Qt.AlignHCenter
alignment: (panel.location === PlasmaCore.Types.TopEdge ? Qt.AlignHCenter | Qt.AlignTop :
panel.location === PlasmaCore.Types.RightEdge ? Qt.AlignVCenter | Qt.AlignRight :
panel.location === PlasmaCore.Types.LeftEdge ? Qt.AlignVCenter | Qt.AlignLeft :
Qt.AlignHCenter | Qt.AlignBottom)
isVertical: dialogRoot.vertical
mainIconSource: (panel.location === PlasmaCore.Types.TopEdge ? "arrow-up" :
panel.location === PlasmaCore.Types.RightEdge ? "arrow-right" :
panel.location === PlasmaCore.Types.LeftEdge ? "arrow-left": "arrow-down")
onClicked: {
setPositionButton.checked = !setPositionButton.checked
setPositionButton.forceActiveFocus()
}
}
PC3.Button {
id: setPositionButton
Layout.minimumHeight: transparencyBox.height
Layout.minimumWidth: positionRepresentation.width
Layout.alignment: Qt.AlignHCenter
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Set Position…")
checkable: true
function moveTo(newLocation: int, associatedWindow = null) {
if (!setPositionButton.checked) {
return;
}
panel.location = newLocation;
if (associatedWindow !== null) {
panel.screenToFollow = dialogRoot.panelConfiguration.screenFromWindow(associatedWindow);
}
setPositionButton.checked = false;
}
Keys.onLeftPressed: moveTo(PlasmaCore.Types.LeftEdge)
Keys.onRightPressed: moveTo(PlasmaCore.Types.RightEdge)
Keys.onUpPressed: moveTo(PlasmaCore.Types.TopEdge)
Keys.onDownPressed: moveTo(PlasmaCore.Types.BottomEdge)
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Alignment")
textFormat: Text.PlainText
}
PanelRepresentation {
id: alignmentRepresentation
Layout.alignment: Qt.AlignHCenter
mainIconSource: {
if (dialogRoot.vertical) {
if (alignmentBox.previewIndex === 0) {
return "align-vertical-top"
} else if (alignmentBox.previewIndex === 1) {
return "align-vertical-center"
} else {
return "align-vertical-bottom"
}
} else {
if (alignmentBox.previewIndex === 0) {
return "align-horizontal-left"
} else if (alignmentBox.previewIndex === 1) {
return "align-horizontal-center"
} else {
return "align-horizontal-right"
}
}
}
alignment: {
let first, second;
if (dialogRoot.vertical) {
if (alignmentBox.previewIndex === 0) {
first = Qt.AlignTop
} else if (alignmentBox.previewIndex === 1) {
first = Qt.AlignVCenter
} else {
first = Qt.AlignBottom
}
if (panel.location === PlasmaCore.Types.LeftEdge) {
second = Qt.AlignLeft
} else {
second = Qt.AlignRight
}
} else {
if (alignmentBox.previewIndex === 0) {
first = Qt.AlignLeft
} else if (alignmentBox.previewIndex === 1) {
first = Qt.AlignHCenter
} else {
first = Qt.AlignRight
}
if (panel.location === PlasmaCore.Types.TopEdge) {
second = Qt.AlignTop
} else {
second = Qt.AlignBottom
}
}
return first | second;
}
onClicked: alignmentBox.popup.visible = true
isVertical: dialogRoot.vertical
}
PC3.ComboBox {
id: alignmentBox
property int previewIndex: highlightedIndex > -1 ? highlightedIndex : currentIndex
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: alignmentRepresentation.width
model: [
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Top") : i18nd("plasma_shell_org.kde.plasma.desktop", "Left"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Center"),
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Bottom") : i18nd("plasma_shell_org.kde.plasma.desktop", "Right")
]
currentIndex: (panel.alignment === Qt.AlignLeft ? 0 :
panel.alignment === Qt.AlignCenter ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.alignment = Qt.AlignLeft
} else if (index === 1) {
panel.alignment = Qt.AlignCenter
} else {
panel.alignment = Qt.AlignRight
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
level: dialogRoot.headingLevel
Layout.alignment: Qt.AlignHCenter
text: dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Height")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Width")
textFormat: Text.PlainText
}
PanelRepresentation {
id: lengthRepresentation
Layout.alignment: Qt.AlignHCenter
mainIconSource: (widthBox.previewIndex === 1 ? "gnumeric-ungroup" :
widthBox.previewIndex === 0 ? (dialogRoot.vertical ? "panel-fit-height" : "panel-fit-width") : "kdenlive-custom-effect")
isVertical: dialogRoot.vertical
alignment: positionRepresentation.alignment
fillAvailable: widthBox.previewIndex === 0
onClicked: widthBox.popup.visible = true
}
PC3.ComboBox {
id: widthBox
property int previewIndex: highlightedIndex > -1 ? highlightedIndex : currentIndex
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: lengthRepresentation.width
model: [
dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Fill height") : i18nd("plasma_shell_org.kde.plasma.desktop", "Fill width"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Fit content"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Custom")
]
currentIndex: (panel.lengthMode === Panel.Global.FillAvailable ? 0 :
panel.lengthMode === Panel.Global.FitContent ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.lengthMode = Panel.Global.FillAvailable
panelConfiguration.panelRulerView.visible = false
} else if (index === 1) {
panel.lengthMode = Panel.Global.FitContent
panelConfiguration.panelRulerView.visible = false
} else {
panel.lengthMode = Panel.Global.Custom
panelConfiguration.panelRulerView.visible = true
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Visibility")
textFormat: Text.PlainText
}
PanelRepresentation {
id: visibilityRepresentation
Layout.alignment: Qt.AlignHCenter
sunkenPanel: autoHideBox.previewIndex !== 0
onClicked: autoHideBox.popup.visible = true
}
PC3.ComboBox {
id: autoHideBox
property int previewIndex: popup.visible ? highlightedIndex : currentIndex
model: [
i18nd("plasma_shell_org.kde.plasma.desktop", "Always visible"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Auto hide"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Dodge windows"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Windows Go Below"),
]
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: visibilityRepresentation.width
currentIndex: {
switch (panel.visibilityMode) {
case Panel.Global.AutoHide:
return 1;
case Panel.Global.DodgeWindows:
return 2;
case Panel.Global.WindowsGoBelow:
return 3;
case Panel.Global.NormalPanel:
default:
return 0;
}
}
onActivated: (index) => {
switch (index) {
case 1:
panel.visibilityMode = Panel.Global.AutoHide;
break;
case 2:
panel.visibilityMode = Panel.Global.DodgeWindows;
break;
case 3:
panel.visibilityMode = Panel.Global.WindowsGoBelow;
break;
case 0:
default:
panel.visibilityMode = Panel.Global.NormalPanel;
break;
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Heading {
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
level: dialogRoot.headingLevel
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Opacity")
textFormat: Text.PlainText
}
PanelRepresentation {
id: opacityRepresentation
Layout.alignment: Qt.AlignHCenter
adaptivePanel: transparencyBox.previewIndex === 0
translucentPanel: transparencyBox.previewIndex === 2
onClicked: transparencyBox.popup.visible = true
}
PC3.ComboBox {
id: transparencyBox
readonly property int previewIndex: popup.visible ? highlightedIndex : currentIndex
model: [
i18nd("plasma_shell_org.kde.plasma.desktop", "Adaptive"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Opaque"),
i18nd("plasma_shell_org.kde.plasma.desktop", "Translucent")
]
Layout.alignment: Qt.AlignHCenter
Layout.minimumWidth: opacityRepresentation.width
currentIndex: (panel.opacityMode === Panel.Global.Adaptive ? 0 :
panel.opacityMode === Panel.Global.Opaque ? 1 : 2)
onActivated: (index) => {
if (index === 0) {
panel.opacityMode = Panel.Global.Adaptive
} else if (index === 1) {
panel.opacityMode = Panel.Global.Opaque
} else {
panel.opacityMode = Panel.Global.Translucent
}
}
}
}
ColumnLayout {
Layout.alignment: Qt.AlignHCenter
spacing: Kirigami.Units.mediumSpacing
Kirigami.Action {
id: floatingAction
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Floating")
checkable: true
checked: panel.floating
onToggled: source => {
panel.floating = checked;
}
}
Kirigami.Heading {
level: dialogRoot.headingLevel
Layout.alignment: Qt.AlignTop | Qt.AlignHCenter
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Style")
textFormat: Text.PlainText
}
PanelRepresentation {
Layout.alignment: Qt.AlignHCenter
floatingGap: Kirigami.Units.smallSpacing * floatingSwitch.checked
onClicked: floatingAction.toggle(this)
}
PC3.Switch {
id: floatingSwitch
Layout.alignment: Qt.AlignHCenter
Layout.minimumHeight: transparencyBox.height
action: floatingAction
}
}
}
Instantiator {
active: setPositionButton.checked
asynchronous: true
model: Application.screens
Item {
width: 0
height: 0
required property var modelData
component Indicator : PlasmaCore.Dialog {
id: root
property string iconSource
property var onClickedLocation
flags: Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint
location: PlasmaCore.Types.Floating
visible: setPositionButton.checked && (panel.location !== onClickedLocation || modelData.name !== panel.screenToFollow.name)
x: modelData.virtualX + Kirigami.Units.largeSpacing
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
mainItem: PC3.ToolButton {
width: Kirigami.Units.iconSizes.enormous
height: Kirigami.Units.iconSizes.enormous
icon.name: root.iconSource
onClicked: setPositionButton.moveTo(root.onClickedLocation, Window.window)
}
}
Indicator {
x: modelData.virtualX + Kirigami.Units.largeSpacing
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
iconSource: "arrow-left"
onClickedLocation: PlasmaCore.Types.LeftEdge
}
Indicator {
x: modelData.virtualX + modelData.width - Kirigami.Units.largeSpacing - margins.left - margins.right - mainItem.width
y: modelData.virtualY + modelData.height / 2 - mainItem.height / 2 - margins.top
iconSource: "arrow-right"
onClickedLocation: PlasmaCore.Types.RightEdge
}
Indicator {
x: modelData.virtualX + modelData.width / 2 - mainItem.width / 2 - margins.left
y: modelData.virtualY + Kirigami.Units.largeSpacing
iconSource: "arrow-up"
onClickedLocation: PlasmaCore.Types.TopEdge
}
Indicator {
x: modelData.virtualX + modelData.width / 2 - mainItem.width / 2 - margins.left
y: modelData.virtualY + modelData.height - mainItem.height - margins.top - margins.bottom - Kirigami.Units.largeSpacing
iconSource: "arrow-down"
onClickedLocation: PlasmaCore.Types.BottomEdge
}
}
}
GridLayout {
Layout.alignment: Qt.AlignHCenter
rowSpacing: Kirigami.Units.largeSpacing
columnSpacing: Kirigami.Units.largeSpacing
rows: 2
columns: 2
PC3.Label {
id: spinBoxLabel
Layout.alignment: Qt.AlignRight
wrapMode: Text.Wrap
text: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge
? i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Width:")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel Height:")
textFormat: Text.PlainText
}
PC3.SpinBox {
id: spinBox
editable: true
focus: !Kirigami.InputMethod.willShowOnActive
from: Math.max(20, panel.minThickness) // below this size, the panel is mostly unusable
to: panel.location === PlasmaCore.Types.LeftEdge || panel.location === PlasmaCore.Types.RightEdge
? panel.screenToFollow.geometry.width / 2
: panel.screenToFollow.geometry.height / 2
stepSize: 2
value: panel.thickness
onValueModified: {
panel.thickness = value
}
}
PC3.Label {
Layout.alignment: Qt.AlignRight
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Focus shortcut:")
textFormat: Text.PlainText
visible: panel.adaptiveOpacityEnabled
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
}
PC3.ToolTip {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Press this keyboard shortcut to move focus to the Panel")
visible: mouseArea.containsMouse
}
}
KeySequenceItem {
id: button
keySequence: plasmoid.globalShortcut
onCaptureFinished: {
plasmoid.globalShortcut = button.keySequence
}
}
}
PlasmaExtras.PlasmoidHeading {
position: PlasmaExtras.PlasmoidHeading.Footer
Layout.topMargin: Kirigami.Units.smallSpacing
topPadding: Kirigami.Units.smallSpacing * 2
leftPadding: Kirigami.Units.smallSpacing
rightPadding: Kirigami.Units.smallSpacing
bottomPadding: Kirigami.Units.smallSpacing
Layout.fillWidth: true
RowLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
spacing: Kirigami.Units.largeSpacing
PC3.ToolButton {
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button Delete the panel", "Delete Panel")
icon.name: "delete"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove this panel; this action is undo-able")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: plasmoid.internalAction("remove").trigger()
}
Item {Layout.fillWidth: true}
PC3.ToolButton {
text: i18ndc("plasma_shell_org.kde.plasma.desktop", "@action:button Done configuring the panel", "Done")
icon.name: "dialog-ok-symbolic"
PC3.ToolTip.text: i18nd("plasma_shell_org.kde.plasma.desktop", "Close Panel Settings window and exit Edit Mode")
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
PC3.ToolTip.visible: hovered
onClicked: plasmoid.containment.corona.editMode = false
}
}
}
// This item is used to "pass" focus to the ruler with tab when we're at the last of the control of this window
Item {
parent: dialogRoot.parent // Used to not take space in the ColumnLayout
activeFocusOnTab: true
onActiveFocusChanged: {
let window = ruler.Window.window
if (activeFocus && window && window.visible) {
window.requestActivate()
}
}
}
}

View file

@ -0,0 +1,85 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.15
import org.kde.kirigami 2.13 as Kirigami
import "shellcontainmentconfiguration"
Kirigami.AbstractApplicationWindow {
id: root
title: i18nd("plasma_shell_org.kde.plasma.desktop", "Panel and Desktop Management")
width: Kirigami.Units.gridUnit * 40
height: Kirigami.Units.gridUnit * 32
minimumWidth: Kirigami.Units.gridUnit * 30
minimumHeight: Kirigami.Units.gridUnit * 25
header: QQC2.ToolBar {
anchors {
left: parent.left
right: parent.right
}
contentItem: QQC2.Label {
Layout.fillWidth: parent
text: i18nd("plasma_shell_org.kde.plasma.desktop", "You can drag Panels and Desktops around to move them to different screens.")
textFormat: Text.PlainText
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
footer: QQC2.Control {
contentItem: QQC2.DialogButtonBox {
QQC2.Button {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Close")
onClicked: Window.window.close()
}
}
background: Item {
// FIXME: automate that somehow?
Kirigami.Separator {
anchors {
left: parent.left
top: parent.top
right: parent.right
}
visible: mainPage.flickable.contentHeight > mainPage.flickable.height
}
}
}
Kirigami.ScrollablePage {
id: mainPage
anchors.fill: parent
leftPadding: 0
topPadding: 0
rightPadding: 0
bottomPadding: 0
Flow {
id: mainGrid
width: mainPage.flickable.width
spacing: 0
Repeater {
id: repeater
model: ShellContainmentModel
delegate: Delegate {
viewPort: mainPage
}
}
}
}
}

View file

@ -0,0 +1,174 @@
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.components as PC3
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras as PlasmaExtras
import org.kde.ksvg as KSvg
import org.kde.plasma.shell.panel as Panel
import org.kde.kirigami as Kirigami
Item {
id: root
property string text
property /*Qt::Alignment*/int alignment: Qt.AlignHCenter | Qt.AlignBottom
property string tooltip
property bool isVertical: false
property bool checked: false
property bool windowVisible: false
property bool panelVisible: true
property bool translucentPanel: false
property bool sunkenPanel: false
property bool adaptivePanel: false
property bool fillAvailable: false
property int floatingGap: 0
property int windowZ: 0
property var mainIconSource: null
property int screenHeight: Math.round(screenRect.height / 2)
readonly property bool iconAndLabelsShouldlookSelected: checked || mouseArea.pressed
signal clicked()
implicitHeight: mainItem.height
implicitWidth: mainItem.width
PC3.ToolTip {
text: root.tooltip
visible: mouseArea.containsMouse && text.length > 0
}
PlasmaExtras.Highlight {
anchors.fill: parent
anchors.margins: -Kirigami.Units.smallSpacing
hovered: mouseArea.containsMouse
pressed: root.iconAndLabelsShouldlookSelected
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked()
}
ColumnLayout {
id: mainItem
spacing: Kirigami.Units.smallSpacing
Rectangle {
id: screenRect
Layout.alignment: Qt.AlignHCenter
implicitWidth: Math.round(Math.min(Kirigami.Units.gridUnit * 6, Screen.width * 0.1))
implicitHeight: Math.round(Math.min(Kirigami.Units.gridUnit * 4, Screen.width * 0.1))
color: Qt.tint(Kirigami.Theme.backgroundColor, Qt.rgba(1, 1, 1, 0.3))
border.color: Kirigami.Theme.highlightColor
radius: Kirigami.Units.cornerRadius
clip: root.sunkenPanel
RowLayout {
anchors.fill: parent
Rectangle {
id: panelImage
implicitWidth: root.isVertical ? Math.round(parent.width / 6) : Math.round(parent.width * (root.fillAvailable ? 1 : 0.8))
implicitHeight: root.isVertical ? Math.round(parent.height * (root.fillAvailable ? 1 : 0.8)) : Math.round(parent.height / 4)
Layout.alignment: root.alignment
Layout.bottomMargin: root.sunkenPanel * -Math.round(height / 2) + root.floatingGap
color: root.translucentPanel ? screenRect.color : Kirigami.Theme.backgroundColor
opacity: root.translucentPanel ? 0.8 : 1.0
border.color: "transparent"
visible: root.panelVisible
clip: root.adaptivePanel
radius: Kirigami.Units.cornerRadius
z: 1
Loader {
id: horizontalAdaptivePanelLoader
active: root.adaptivePanel && !root.isVertical
sourceComponent: Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Math.round(panelImage.width / 3)
color: Qt.lighter(screenRect.color)
border.color: Kirigami.Theme.highlightColor
width: panelImage.width
height: Math.round(panelImage.height * 4)
radius: Math.round(height / 2)
rotation: 45
}
}
Loader {
id: verticalAdaptivePanelLoader
active: root.adaptivePanel && root.isVertical
sourceComponent: Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: Math.round(panelImage.height / 4)
color: Qt.lighter(screenRect.color)
border.color: Kirigami.Theme.highlightColor
width: Math.round(panelImage.width * 2)
height: panelImage.height
radius: Math.round(height / 2)
rotation: 45
}
}
Rectangle {
id: panelBorder
anchors.fill: parent
color: "transparent"
border.color: Kirigami.Theme.highlightColor
radius: panelImage.radius
}
}
}
Rectangle {
id: window
width: Math.round(parent.width / 2)
height: Math.round(parent.height / 2)
visible: root.windowVisible
radius: 5
color: Kirigami.Theme.highlightColor
border.color: "transparent"
x: root.isVertical ? Math.round(panelImage.x + panelImage.width / 2) : Math.round(screenRect.width / 2 - width / 2) + Kirigami.Units.gridUnit
y: root.isVertical ? Math.round(screenRect.height / 2 - height / 2) : Math.round(panelImage.y - height + panelImage.height / 2)
z: root.windowZ
Row {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Kirigami.Units.smallSpacing
spacing: Kirigami.Units.smallSpacing
Repeater {
model: 3
delegate: Rectangle {
width: Math.round(Kirigami.Units.gridUnit / 6)
height: width
radius: Math.round(height / 2)
color: Kirigami.Theme.textColor
}
}
}
}
Kirigami.Icon {
id: mainIcon
visible: valid
anchors.centerIn: parent
transform: Translate {
y: root.isVertical ? 0 : Math.round((mainIcon.y - panelImage.y) / 4)
x: root.isVertical ? Math.round((mainIcon.x - panelImage.x) / 4) : 0
}
height: parent.height / 2
source: root.mainIconSource
}
}
}
}

View file

@ -0,0 +1,241 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
KSvg.FrameSvgItem {
id: root
anchors.fill: parent
//Those properties get updated by PanelConfiguration.qml whenever a value in the panel changes
property alias offset: offsetHandle.value
property alias minimumLength: rightMinimumLengthHandle.value
property alias maximumLength: rightMaximumLengthHandle.value
property bool isHorizontal: root.prefix[0] === 'north' || root.prefix[0] === 'south'
property string maximumText: (dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change maximum height.") : i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change maximum width.")) + "\n" + i18nd("plasma_shell_org.kde.plasma.desktop", "Double click to reset.")
property string minimumText: (dialogRoot.vertical ? i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change minimum height.") : i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change minimum width.")) + "\n" + i18nd("plasma_shell_org.kde.plasma.desktop", "Double click to reset.")
imagePath: "widgets/containment-controls"
implicitWidth: Math.max(offsetHandle.width, rightMinimumLengthHandle.width + rightMaximumLengthHandle.width)
implicitHeight: Math.max(offsetHandle.height, rightMinimumLengthHandle.height + rightMaximumLengthHandle.height)
onMinimumLengthChanged: rightMinimumLengthHandle.value = leftMinimumLengthHandle.value = minimumLength
onMaximumLengthChanged: rightMaximumLengthHandle.value = leftMaximumLengthHandle.value = maximumLength
/* As offset and length have a different meaning in all alignments, the panel shifts on alignment change.
* This could result in wrong panel positions (e.g. panel shifted over monitor border).
* The fancy version would be a recalculation of all values, so that the panel stays at it's current position,
* but this would be error prone and complicated. As the panel alignment is rarely changed, it's not worth it.
* The more easy approach is just setting the panel offset to zero. This makes sure the panel has a valid position and size.
*/
Connections {
target: panel
function onAlignmentChanged() {
offset = 0
}
}
Component.onCompleted: {
offsetHandle.value = panel.offset
rightMinimumLengthHandle.value = panel.minimumLength
rightMaximumLengthHandle.value = panel.maximumLength
leftMinimumLengthHandle.value = panel.minimumLength
leftMaximumLengthHandle.value = panel.maximumLength
}
KSvg.SvgItem {
id: centerMark
imagePath: "widgets/containment-controls"
elementId: dialogRoot.vertical ? "vertical-centerindicator" : "horizontal-centerindicator"
visible: panel.alignment === Qt.AlignCenter
width: dialogRoot.vertical ? parent.width : naturalSize.width
height: dialogRoot.vertical ? naturalSize.height : parent.height
anchors.centerIn: parent
}
SliderHandle {
id: offsetHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
graphicElementName: "offsetslider"
description: i18nd("plasma_shell_org.kde.plasma.desktop", "Drag to change position on this screen edge.\nDouble click to reset.")
offset: panel.alignment === Qt.AlignCenter ? 0 : (dialogRoot.vertical ? panel.height : panel.width) / 2
property int position: (dialogRoot.vertical) ? y + height / 2 : x + width / 2
onPositionChanged: {
if (!offsetHandle.hasEverBeenMoved) return;
let panelLength = dialogRoot.vertical ? panel.height : panel.width
let rootLength = dialogRoot.vertical ? root.height : root.width
// Snap at the center
if (Math.abs(position - rootLength / 2) < 5) {
if (panel.alignment !== Qt.AlignCenter) {
panel.alignment = Qt.AlignCenter
// Coordinate change: since we switch from measuring the min/max
// length from the side of the panel to the center of the panel,
// we need to double the distance between the min/max indicators
// and the panel side.
panel.minimumLength += panel.minimumLength - panelLength
panel.maximumLength += panel.maximumLength - panelLength
}
panel.offset = 0
} else if (position > rootLength / 2) {
if (panel.alignment === Qt.AlignCenter) {
// This is the opposite of the previous comment, as we are
// cutting in half the distance between the min/max indicators
// and the side of the panel.
panel.minimumLength -= (panel.minimumLength - panelLength) / 2
panel.maximumLength -= (panel.maximumLength - panelLength) / 2
}
panel.alignment = Qt.AlignRight
panel.offset = Math.round(rootLength - position - offset)
} else if (position <= rootLength / 2) {
if (panel.alignment === Qt.AlignCenter) {
panel.minimumLength -= (panel.minimumLength - panelLength) / 2
panel.maximumLength -= (panel.maximumLength - panelLength) / 2
}
panel.alignment = Qt.AlignLeft
panel.offset = Math.round(position - offset)
}
}
/* The maximum/minimumPosition values are needed to prevent the user from moving a panel with
* center alignment to the left and then drag the position handle to the left.
* This would make the panel to go off the monitor:
* |<- V -> |
* | -> | <- |
* ^move this slider to the left
*/
minimumPosition: {
var size = dialogRoot.vertical ? height : width
switch(panel.alignment){
case Qt.AlignLeft:
return -size / 2 + offset
case Qt.AlignRight:
return leftMaximumLengthHandle.value - size / 2 - offset
default:
return panel.maximumLength / 2 - size / 2
}
}
//Needed for the same reason as above
maximumPosition: {
var size = dialogRoot.vertical ? height : width
var rootSize = dialogRoot.vertical ? root.height : root.width
switch(panel.alignment){
case Qt.AlignLeft:
return rootSize - rightMaximumLengthHandle.value - size / 2 + offset
case Qt.AlignRight:
return rootSize - size / 2 - offset
default:
return rootSize - panel.maximumLength / 2 - size / 2
}
}
function defaultPosition(): int /*override*/ {
return 0;
}
}
/* The maximumPosition value for the right handles and the minimumPosition value for the left handles are
* needed to prevent the user from moving a panel with center alignment to the left (right) and then pull one of the
* right (left) sliders to the right (left).
* Because the left and right sliders are coupled, this would make the left (right) sliders to go off the monitor.
*
* |<- V -> |
* | -> | <- |
* ^move this slider to the right
*
* The other max/min Position values just set a minimum panel size
*/
SliderHandle {
id: rightMinimumLengthHandle
anchors {
left: !root.isHorizontal ? root.left : undefined
top: root.isHorizontal ? root.top : undefined
}
description: root.minimumText
alignment: panel.alignment | Qt.AlignLeft
visible: panel.alignment !== Qt.AlignRight
offset: panel.offset
graphicElementName: "minslider"
onValueChanged: panel.minimumLength = value
minimumPosition: offsetHandle.position + Kirigami.Units.gridUnit * 3
maximumPosition: {
var rootSize = dialogRoot.vertical ? root.height : root.width
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.min(rootSize - size/2, rootSize + offset * 2 - size/2) : rootSize - size/2
}
}
SliderHandle {
id: rightMaximumLengthHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
description: root.maximumText
alignment: panel.alignment | Qt.AlignLeft
visible: panel.alignment !== Qt.AlignRight
offset: panel.offset
graphicElementName: "maxslider"
onValueChanged: panel.maximumLength = value
minimumPosition: offsetHandle.position + Kirigami.Units.gridUnit * 3
maximumPosition: {
var rootSize = dialogRoot.vertical ? root.height : root.width
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.min(rootSize - size/2, rootSize + offset * 2 - size/2) : rootSize - size/2
}
}
SliderHandle {
id: leftMinimumLengthHandle
anchors {
left: !root.isHorizontal ? root.left : undefined
top: root.isHorizontal ? root.top : undefined
}
description: root.minimumText
alignment: panel.alignment | Qt.AlignRight
visible: panel.alignment !== Qt.AlignLeft
offset: panel.offset
graphicElementName: "maxslider"
onValueChanged: panel.minimumLength = value
maximumPosition: offsetHandle.position - Kirigami.Units.gridUnit * 3
minimumPosition: {
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2
}
}
SliderHandle {
id: leftMaximumLengthHandle
anchors {
right: !root.isHorizontal ? root.right : undefined
bottom: root.isHorizontal ? root.bottom : undefined
}
description: root.maximumText
alignment: panel.alignment | Qt.AlignRight
visible: panel.alignment !== Qt.AlignLeft
offset: panel.offset
graphicElementName: "minslider"
onValueChanged: panel.maximumLength = value
maximumPosition: offsetHandle.position - Kirigami.Units.gridUnit * 3
minimumPosition: {
var size = dialogRoot.vertical ? height : width
panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2
}
}
}

View file

@ -0,0 +1,237 @@
/*
SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.4 as QQC2
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.shell.panel 0.1 as Panel
import org.kde.kquickcontrols 2.0
KSvg.SvgItem {
id: root
//Those properties get updated by PanelConfiguration.qml whenever a value changes
imagePath: "widgets/containment-controls"
elementId: parent.prefix + '-' + graphicElementName
width: naturalSize.width
height: naturalSize.height
//value expressed by this slider, this is the distance to offset
property int value
//name of the graphics to load
property string graphicElementName
//where the point "0" is
property int offset: 0
/*handle type: behave in different ways based on the alignment:
* alignment === Qt.AlignRight: Panel aligned to right and handle value relative to the right
* alignment === Qt.AlignLeft: Panel aligned to left and handle relative to the left
* (alignment !== Qt.AlignRight) && (alignment & Qt.AlignRight): Panel aligned to the center and handle right of offset and value doubled
* (alignment !== Qt.AlignLeft) && (alignment & Qt.AlignLeft): Panel aligned to the center and handle left of offset and value doubled
* else: Panel aligned to center and handle relative to the center
* Note that right/left and top/bottom are interchangeable
*/
property int alignment: panel.alignment
//The maximum/minimum Position (X/Y) the silder can be moved to
property int minimumPosition
property int maximumPosition
//Provide default position for "reset" action.
function defaultPosition(): int {
var dialogSize, panelSize;
if (dialogRoot.vertical) {
dialogSize = dialogRoot.height;
panelSize = panel.height;
} else {
dialogSize = dialogRoot.width;
panelSize = panel.width;
}
return (value === panelSize) ? dialogSize : panelSize;
}
// Handle name displayed as a tooltip.
property string description
property bool hasEverBeenMoved: false
function syncPos() {
if (dialogRoot.vertical) {
if (alignment === Qt.AlignRight) {
y = root.parent.height - (value + offset + root.height/2)
} else if (alignment === Qt.AlignLeft) {
y = value + offset - root.height/2
} else {
if (root.alignment & Qt.AlignRight) {
y = root.parent.height/2 - value/2 + offset - root.height/2
} else if (root.alignment & Qt.AlignLeft) {
y = root.parent.height/2 + value/2 + offset - root.height/2
} else {
y = root.parent.height/2 + value + offset -root.height/2
}
}
} else {
if (alignment === Qt.AlignRight) {
x = root.parent.width - (value + offset + root.width/2)
} else if (alignment === Qt.AlignLeft) {
x = value + offset - root.width/2
} else {
if (root.alignment & Qt.AlignRight) {
x = root.parent.width/2 - value/2 + offset - root.width/2
} else if (root.alignment & Qt.AlignLeft) {
x = root.parent.width/2 + value/2 + offset -root.width/2
} else {
x = root.parent.width/2 + value + offset -root.width/2
}
}
}
}
onValueChanged: syncPos()
onOffsetChanged: syncPos()
onAlignmentChanged: syncPos()
Connections {
target: root.parent
function onWidthChanged() {
syncPos()
}
function onHeightChanged() {
syncPos()
}
}
PC3.ToolTip {
text: root.description
visible: root.description !== "" && ((area.containsMouse && !area.containsPress) || area.activeFocus)
}
MouseArea {
id: area
drag {
target: parent
axis: (dialogRoot.vertical) ? Drag.YAxis : Drag.XAxis
minimumX: root.minimumPosition
minimumY: root.minimumPosition
maximumX: root.maximumPosition
maximumY: root.maximumPosition
}
anchors {
fill: parent
leftMargin: (dialogRoot.vertical) ? 0 : -Kirigami.Units.gridUnit
rightMargin: (dialogRoot.vertical) ? 0 : -Kirigami.Units.gridUnit
topMargin: (dialogRoot.vertical) ? -Kirigami.Units.gridUnit : 0
bottomMargin: (dialogRoot.vertical) ? -Kirigami.Units.gridUnit : 0
}
readonly property int keyboardMoveStepSize: Math.ceil((root.maximumPosition - root.minimumPosition) / 20)
activeFocusOnTab: true
hoverEnabled: true
cursorShape: dialogRoot.vertical ? Qt.SizeVerCursor : Qt.SizeHorCursor
Accessible.description: root.description
Keys.onEnterPressed: doubleClicked(null);
Keys.onReturnPressed: doubleClicked(null);
Keys.onSpacePressed: doubleClicked(null);
// BEGIN Arrow keys
Keys.onUpPressed: if (dialogRoot.vertical) {
root.y = Math.max(root.minimumPosition, root.y - ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onDownPressed: if (dialogRoot.vertical) {
root.y = Math.min(root.maximumPosition, root.y + ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onLeftPressed: if (!dialogRoot.vertical) {
root.x = Math.max(root.minimumPosition, root.x - ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
Keys.onRightPressed: if (!dialogRoot.vertical) {
root.x = Math.min(root.maximumPosition, root.x + ((event.modifiers & Qt.ShiftModifier) ? 1 : keyboardMoveStepSize));
changePosition();
} else {
event.accepted = false;
}
// END Arrow keys
onPositionChanged: {
if (!drag.active) {
return;
}
changePosition();
}
onDoubleClicked: {
root.value = root.defaultPosition();
}
function changePosition() {
root.hasEverBeenMoved = true
if (dialogRoot.vertical) {
if (root.alignment === Qt.AlignRight) {
root.value = root.parent.height - (root.y + offset + root.height/2)
} else if (alignment === Qt.AlignLeft) {
root.value = root.y - offset + root.height/2
//Center
} else {
if (root.alignment & Qt.AlignRight) {
root.value = (root.parent.height/2 - root.y + offset)*2 - root.height
} else if (root.alignment & Qt.AlignLeft) {
root.value = (root.y - offset - root.parent.height/2)*2 + root.height
} else {
var value = root.y - root.parent.height/2 - offset + root.height/2
//Snap
if (Math.abs(value) < 5) {
root.value = 0
} else {
root.value = value
}
}
}
} else {
if (root.alignment === Qt.AlignRight) {
root.value = root.parent.width - (root.x + offset + root.width/2)
} else if (alignment === Qt.AlignLeft) {
root.value = root.x - offset + root.width/2
//Center
} else {
if (root.alignment & Qt.AlignRight) {
root.value = (root.parent.width/2 - root.x + offset)*2 - root.width
} else if (root.alignment & Qt.AlignLeft) {
root.value = (root.x - offset - root.parent.width/2)*2 + root.width
} else {
var value = root.x - root.parent.width/2 - offset + root.width/2
//Snap
if (Math.abs(value) < 5) {
root.value = 0
} else {
root.value = value
}
}
}
}
}
PlasmaExtras.Highlight {
anchors.fill: parent
visible: parent.activeFocus
hovered: true
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -0,0 +1,273 @@
/*
SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>
SPDX-FileCopyrightText: 2022 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.4 as QQC2
import QtQuick.Layouts 1.3
import QtQuick.Window 2.15
import org.kde.kirigami 2.13 as Kirigami
QQC2.Control {
id: delegate
property Item viewPort
readonly property string screenName: model.screenName
readonly property int screenId: model.screenId
property bool containsDrag
property alias contentsLayout: contentsLayout
width: Math.min(Kirigami.Units.gridUnit * 25, Math.floor(viewPort.width / Math.min(repeater.count, Math.floor(viewPort.width / (Kirigami.Units.gridUnit * 12)))))
contentItem: ColumnLayout {
id: contentsLayout
width: Math.min(parent.width, Kirigami.Units.gridUnit * 15)
Rectangle {
id: screenRect
Layout.fillWidth: true
Layout.preferredHeight: width / 1.6
color: Kirigami.Theme.backgroundColor
border.color: Kirigami.Theme.textColor
Rectangle {
anchors.fill: parent
z: 9
color: "black"
opacity: delegate.containsDrag ? 0.3 : 0
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
Repeater {
id: containmentRepeater
model: containments
Rectangle {
id: contRect
property real homeX
property real homeY
property string oldState
readonly property int edgeDistance: {
return (state === "left" || state === "right" ? width : height) * model.edgePosition;
}
width: moveButton.width
height: moveButton.height
border.color: Kirigami.Theme.textColor
color: Kirigami.Theme.backgroundColor
state: model.edge
z: state === "floating" ? 0 : 1
visible: !model.isDestroyed
HoverHandler {
cursorShape: Qt.OpenHandCursor
}
DragHandler {
id: dragHandler
property QQC2.Control targetDelegate
cursorShape: Qt.ClosedHandCursor
onActiveChanged: {
if (active) {
delegate.z = 1;
} else {
if (targetDelegate) {
resetAnim.restart();
containmentRepeater.model.moveContainementToScreen(model.containmentId, targetDelegate.screenId)
targetDelegate.containsDrag = false;
targetDelegate = null;
} else {
resetAnim.restart();
}
}
}
onTranslationChanged: {
if (!active) {
if (targetDelegate) {
targetDelegate.containsDrag = false;
targetDelegate = null;
}
return;
}
let pos = contRect.mapToItem(delegate.parent, dragHandler.centroid.position.x, dragHandler.centroid.position.y);
let otherDelegate = delegate.parent.childAt(pos.x, pos.y);
if (targetDelegate && targetDelegate !== otherDelegate) {
targetDelegate.containsDrag = false;
}
if (!otherDelegate || otherDelegate === delegate) {
targetDelegate = null;
} else if (otherDelegate && otherDelegate !== delegate
&& otherDelegate.hasOwnProperty("screenId")
&& otherDelegate.hasOwnProperty("containsDrag")) {
targetDelegate = otherDelegate;
targetDelegate.containsDrag = true;
}
}
}
SequentialAnimation {
id: resetAnim
property var targetDelegatePos: dragHandler.targetDelegate
? dragHandler.targetDelegate.contentsLayout.mapToItem(delegate.contentsLayout, 0, 0)
: Qt.point(0, 0)
ParallelAnimation {
XAnimator {
target: contRect
from: contRect.x
to: contRect.homeX + resetAnim.targetDelegatePos.x
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
YAnimator {
target: contRect
from: contRect.y
to: contRect.homeY + resetAnim.targetDelegatePos.y
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
PropertyAction {
target: delegate
property: "z"
value: 0
}
}
Image {
id: containmentImage
anchors {
fill: parent
margins: 1
}
// It needs to reload the image from disk when the file changes
cache: false
source: model.imageSource
fillMode: model.edge == "floating" ? Image.PreserveAspectCrop : Image.PreserveAspectFit
}
QQC2.Button {
id: moveButton
icon.name: "open-menu-symbolic"
checked: contextMenu.visible
anchors {
right: parent.right
top: parent.top
topMargin: model.edge == "floating"
? model.panelCountAtTop * moveButton.height + Kirigami.Units.largeSpacing
: 0
rightMargin: model.edge == "floating"
? (moveButton.LayoutMirroring.enabled ? model.panelCountAtLeft : model.panelCountAtRight) * moveButton.height + Kirigami.Units.largeSpacing
: 0
}
onClicked: {
contextMenu.open()
}
QQC2.Menu {
id: contextMenu
y: moveButton.height
Repeater {
model: ShellContainmentModel
QQC2.MenuItem {
text: edge == "floating"
? i18nd("plasma_shell_org.kde.plasma.desktop", "Swap with Desktop on Screen %1", model.screenName)
: i18nd("plasma_shell_org.kde.plasma.desktop", "Move to Screen %1", model.screenName)
visible: model.screenName !== delegate.screenName
height: visible ? implicitHeight : 0
onTriggered: {
containmentRepeater.model.moveContainementToScreen(containmentId, screenId)
}
}
}
QQC2.MenuSeparator {
visible: removeItem.visible
}
QQC2.MenuItem {
id: removeItem
text: contRect.state === "floating"
? i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Desktop")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Remove Panel")
icon.name: "edit-delete"
onTriggered: {
if (contRect.state === "floating") {
ShellContainmentModel.remove(screenId);
} else {
containments.remove(containmentId);
}
}
visible: contRect.state !== "floating" || !model.active
}
}
}
states: [
State {
name: "floating"
PropertyChanges {
target: contRect;
width: screenRect.width
height: screenRect.height
color: "transparent"
}
},
State {
name: "top"
PropertyChanges {
target: contRect;
width: screenRect.width
y: homeY
homeX: 0
homeY: contRect.edgeDistance
}
},
State {
name: "right"
PropertyChanges {
target: contRect;
x: homeX
homeX: screenRect.width - contRect.width - contRect.edgeDistance;
height: screenRect.height
homeY: 0
}
},
State {
name: "bottom"
PropertyChanges {
target: contRect;
y: homeY
homeX: 0
homeY: screenRect.height - contRect.height - contRect.edgeDistance;
width: screenRect.width
}
},
State {
name: "left"
PropertyChanges {
target: contRect;
height: screenRect.height
x: homeX
homeX: contRect.edgeDistance
homeY: 0
}
}
]
}
}
}
QQC2.Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: model.isPrimary
? i18nd("plasma_shell_org.kde.plasma.desktop", "%1 (primary)", model.screenName)
: model.screenName
textFormat: Text.PlainText
}
}
}

View file

@ -0,0 +1,14 @@
[Desktop]
Containment=org.kde.plasma.folder
ToolBox=
RuntimePlatform=Desktop
[Desktop][ContainmentActions]
RightButton;NoModifier=org.kde.contextmenu
MiddleButton;NoModifier=org.kde.paste
[Panel]
Containment=org.kde.panel
ToolBox=org.kde.paneltoolbox
[Panel][ContainmentActions]
RightButton;NoModifier=org.kde.contextmenu

View file

@ -0,0 +1,204 @@
/*
SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.5 as QQC2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.plasmoid
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.shell 2.0
PlasmaCore.Dialog {
id: dialog
visualParent: alternativesHelper.applet
location: alternativesHelper.applet.Plasmoid.location
hideOnWindowDeactivate: true
backgroundHints: (alternativesHelper.applet.Plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentPrefersOpaqueBackground) ? PlasmaCore.Dialog.SolidBackground : PlasmaCore.Dialog.StandardBackground
Component.onCompleted: {
flags = flags | Qt.WindowStaysOnTopHint;
dialog.show();
}
ColumnLayout {
id: root
signal configurationChanged
Layout.minimumWidth: Kirigami.Units.gridUnit * 20
Layout.minimumHeight: Math.min(Screen.height - Kirigami.Units.gridUnit * 10, implicitHeight)
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
property string currentPlugin: ""
Shortcut {
sequence: "Escape"
onActivated: dialog.close()
}
Shortcut {
sequence: "Return"
onActivated: root.savePluginAndClose()
}
Shortcut {
sequence: "Enter"
onActivated: root.savePluginAndClose()
}
WidgetExplorer {
id: widgetExplorer
provides: alternativesHelper.appletProvides
}
PlasmaExtras.PlasmoidHeading {
Kirigami.Heading {
id: heading
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Alternative Widgets")
textFormat: Text.PlainText
}
}
// This timer checks with a short delay whether a new item in the list has been hovered by the cursor.
// If not, then the cursor has left the view and thus no item should be selected.
Timer {
id: resetCurrentIndex
property string oldPlugin
interval: 100
onTriggered: {
if (root.currentPlugin === oldPlugin) {
mainList.currentIndex = -1
root.currentPlugin = ""
}
}
}
function savePluginAndClose() {
alternativesHelper.loadAlternative(currentPlugin);
dialog.close();
}
PlasmaComponents3.ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: mainList.contentHeight
focus: true
ListView {
id: mainList
focus: dialog.visible
model: widgetExplorer.widgetsModel
boundsBehavior: Flickable.StopAtBounds
highlight: PlasmaExtras.Highlight {
pressed: mainList.currentItem && mainList.currentItem.pressed
}
highlightMoveDuration : 0
highlightResizeDuration: 0
height: contentHeight+Kirigami.Units.smallSpacing
delegate: PlasmaComponents3.ItemDelegate {
id: listItem
implicitHeight: contentLayout.implicitHeight + Kirigami.Units.smallSpacing * 2
width: ListView.view.width
onHoveredChanged: {
if (hovered) {
resetCurrentIndex.stop()
mainList.currentIndex = index
} else {
resetCurrentIndex.oldPlugin = model.pluginName
resetCurrentIndex.restart()
}
}
Connections {
target: mainList
function onCurrentIndexChanged() {
if (mainList.currentIndex === index) {
root.currentPlugin = model.pluginName
}
}
}
onClicked: root.savePluginAndClose()
Component.onCompleted: {
if (model.pluginName === alternativesHelper.currentPlugin) {
root.currentPlugin = model.pluginName
setAsCurrent.restart()
}
}
// we don't want to select any entry by default
// this cannot be set in Component.onCompleted
Timer {
id: setAsCurrent
interval: 100
onTriggered: {
mainList.currentIndex = index
}
}
contentItem: RowLayout {
id: contentLayout
spacing: Kirigami.Units.largeSpacing
Kirigami.Icon {
implicitWidth: Kirigami.Units.iconSizes.huge
implicitHeight: Kirigami.Units.iconSizes.huge
source: model.decoration
}
ColumnLayout {
id: labelLayout
readonly property color textColor: listItem.pressed ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
Layout.fillHeight: true
Layout.fillWidth: true
spacing: 0 // The labels bring their own bottom margins
Kirigami.Heading {
level: 4
Layout.fillWidth: true
text: model.name
textFormat: Text.PlainText
elide: Text.ElideRight
type: model.pluginName === alternativesHelper.currentPlugin ? PlasmaExtras.Heading.Type.Primary : PlasmaExtras.Heading.Type.Normal
color: labelLayout.textColor
}
PlasmaComponents3.Label {
Layout.fillWidth: true
text: model.description
textFormat: Text.PlainText
font.pointSize: Kirigami.Theme.smallFont.pointSize
font.family: Kirigami.Theme.smallFont.family
font.bold: model.pluginName === alternativesHelper.currentPlugin
opacity: 0.6
maximumLineCount: 2
wrapMode: Text.WordWrap
elide: Text.ElideRight
color: labelLayout.textColor
}
}
}
}
}
}
}
}

View file

@ -0,0 +1,247 @@
/*
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.1
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.core as PlasmaCore
import org.kde.kwindowsystem
import org.kde.kirigami 2.20 as Kirigami
import org.kde.graphicaleffects as KGraphicalEffects
Item {
id: delegate
readonly property string pluginName: model.pluginName
readonly property bool pendingUninstall: pendingUninstallTimer.applets.indexOf(pluginName) > -1
readonly property bool pressed: tapHandler.pressed
width: list.cellWidth
height: list.cellHeight
HoverHandler {
id: hoverHandler
onHoveredChanged: if (hovered) delegate.GridView.view.currentIndex = index
}
TapHandler {
id: tapHandler
enabled: !delegate.pendingUninstall && model.isSupported
onTapped: widgetExplorer.addApplet(delegate.pluginName)
}
PlasmaCore.ToolTipArea {
anchors.fill: parent
visible: !model.isSupported
mainText: i18n("Unsupported Widget")
subText: model.unsupportedMessage
}
// Avoid repositioning delegate item after dragFinished
Item {
anchors.fill: parent
enabled: model.isSupported
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.MoveAction | Qt.LinkAction
Drag.mimeData: {
"text/x-plasmoidservicename" : delegate.pluginName,
}
Drag.onDragStarted: {
KWindowSystem.showingDesktop = true;
main.draggingWidget = true;
}
Drag.onDragFinished: {
main.draggingWidget = false;
}
DragHandler {
id: dragHandler
enabled: !delegate.pendingUninstall && model.isSupported
onActiveChanged: if (active) {
iconContainer.grabToImage(function(result) {
if (!dragHandler.active) {
return;
}
parent.Drag.imageSource = result.url;
parent.Drag.active = dragHandler.active;
}, Qt.size(Kirigami.Units.iconSizes.huge, Kirigami.Units.iconSizes.huge));
} else {
parent.Drag.active = false;
parent.Drag.imageSource = "";
}
}
}
ColumnLayout {
id: mainLayout
readonly property color textColor: tapHandler.pressed ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
spacing: Kirigami.Units.smallSpacing
anchors {
left: parent.left
right: parent.right
//bottom: parent.bottom
margins: Kirigami.Units.smallSpacing * 2
rightMargin: Kirigami.Units.smallSpacing * 2 // don't cram the text to the border too much
top: parent.top
}
Item {
id: iconContainer
width: Kirigami.Units.iconSizes.enormous
height: width
Layout.alignment: Qt.AlignHCenter
opacity: delegate.pendingUninstall ? 0.6 : 1
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
Item {
id: iconWidget
anchors.fill: parent
Kirigami.Icon {
anchors.fill: parent
source: model.decoration
visible: model.screenshot === ""
selected: tapHandler.pressed
enabled: model.isSupported
}
Image {
width: Kirigami.Units.iconSizes.enormous
height: width
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: model.screenshot
}
}
Item {
id: badgeMask
anchors.fill: parent
Rectangle {
x: Math.round(-Kirigami.Units.smallSpacing * 1.5 / 2)
y: x
width: runningBadge.width + Math.round(Kirigami.Units.smallSpacing * 1.5)
height: width
radius: height
visible: running && delegate.GridView.isCurrentItem
}
}
KGraphicalEffects.BadgeEffect {
anchors.fill: parent
source: ShaderEffectSource {
sourceItem: iconWidget
hideSource: true
live: false
}
mask: ShaderEffectSource {
id: maskShaderSource
sourceItem: badgeMask
hideSource: true
live: false
}
}
Rectangle {
id: runningBadge
width: height
height: Math.round(Kirigami.Units.iconSizes.sizeForLabels * 1.3)
radius: height
color: Kirigami.Theme.highlightColor
visible: running && delegate.GridView.isCurrentItem
onVisibleChanged: maskShaderSource.scheduleUpdate()
PlasmaComponents.Label {
id: countLabel
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: running
textFormat: Text.PlainText
}
}
PlasmaComponents.ToolButton {
id: uninstallButton
anchors {
top: parent.top
right: parent.right
}
icon.name: delegate.pendingUninstall ? "edit-undo" : "edit-delete"
// we don't really "undo" anything but we'll pretend to the user that we do
PlasmaComponents.ToolTip.delay: Kirigami.Units.toolTipDelay
PlasmaComponents.ToolTip.visible: hovered
PlasmaComponents.ToolTip.text: delegate.pendingUninstall ? i18nd("plasma_shell_org.kde.plasma.desktop", "Undo uninstall")
: i18nd("plasma_shell_org.kde.plasma.desktop", "Uninstall widget")
flat: false
visible: model.local && delegate.GridView.isCurrentItem && !dragHandler.active
onHoveredChanged: {
if (hovered) {
// hovering the uninstall button triggers onExited of the main mousearea
delegate.GridView.view.currentIndex = index
}
}
onClicked: {
var pending = pendingUninstallTimer.applets
if (delegate.pendingUninstall) {
var index = pending.indexOf(pluginName)
if (index > -1) {
pending.splice(index, 1)
}
} else {
pending.push(pluginName)
}
pendingUninstallTimer.applets = pending
if (pending.length) {
pendingUninstallTimer.restart()
} else {
pendingUninstallTimer.stop()
}
}
}
}
Kirigami.Heading {
id: heading
Layout.fillWidth: true
level: 4
text: model.name
textFormat: Text.PlainText
elide: Text.ElideRight
wrapMode: Text.WordWrap
maximumLineCount: 2
lineHeight: 0.95
horizontalAlignment: Text.AlignHCenter
color: mainLayout.textColor
}
PlasmaComponents.Label {
Layout.fillWidth: true
// otherwise causes binding loop due to the way the Plasma sets the height
height: implicitHeight
text: model.description
textFormat: Text.PlainText
font: Kirigami.Theme.smallFont
wrapMode: Text.WordWrap
elide: Text.ElideRight
maximumLineCount: heading.lineCount === 1 ? 3 : 2
horizontalAlignment: Text.AlignHCenter
color: mainLayout.textColor
}
}
}

View file

@ -0,0 +1,142 @@
/*
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.1
import QtQuick.Layouts 1.0 as Layouts
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.kirigami 2.20 as Kirigami
MouseArea {
id: main
hoverEnabled: true
onEntered: toolTipHideTimer.running = false
onExited: toolTipHideTimer.running = true
width: Kirigami.Units.iconSizes.sizeForLabels * 35
height: Kirigami.Units.iconSizes.sizeForLabels * 16
property variant icon
property string title
property string description
property string author
property string email
property string license
property string pluginName
property bool local
onClicked: tooltipDialog.visible = false
Connections {
target: tooltipDialog
function onAppletDelegateChanged() {
if (!tooltipDialog.appletDelegate) {
return
}
icon = tooltipDialog.appletDelegate.icon
title = tooltipDialog.appletDelegate.title
description = tooltipDialog.appletDelegate.description
author = tooltipDialog.appletDelegate.author
email = tooltipDialog.appletDelegate.email
license = tooltipDialog.appletDelegate.license
pluginName = tooltipDialog.appletDelegate.pluginName
local = tooltipDialog.appletDelegate.local
}
}
Kirigami.Icon {
id: tooltipIconWidget
anchors {
left: parent.left
top: parent.top
margins: 8
}
width: Kirigami.Units.iconSizes.huge
height: width
source: main.icon
}
Column {
id: nameColumn
spacing: 8
anchors {
left: tooltipIconWidget.right
margins: 8
top: parent.top
right: parent.right
}
Kirigami.Heading {
text: title
level: 2
anchors.left: parent.left
anchors.right: parent.right
height: paintedHeight
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
PlasmaComponents.Label {
text: description
textFormat: Text.PlainText
anchors.left: parent.left
anchors.right: parent.right
wrapMode: Text.Wrap
}
}
Layouts.GridLayout {
columns: 2
anchors {
top: (nameColumn.height > tooltipIconWidget.height) ? nameColumn.bottom : tooltipIconWidget.bottom
topMargin: 16
horizontalCenter: parent.horizontalCenter
}
PlasmaComponents.Label {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "License:")
textFormat: Text.PlainText
Layouts.Layout.alignment: Qt.AlignVCenter|Qt.AlignRight
}
PlasmaComponents.Label {
id: licenseText
text: license
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
PlasmaComponents.Label {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Author:")
textFormat: Text.PlainText
Layouts.Layout.alignment: Qt.AlignVCenter|Qt.AlignRight
}
PlasmaComponents.Label {
text: author
textFormat: Text.PlainText
wrapMode: Text.Wrap
}
PlasmaComponents.Label {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Email:")
textFormat: Text.PlainText
Layouts.Layout.alignment: Qt.AlignVCenter|Qt.AlignRight
}
PlasmaComponents.Label {
text: email
textFormat: Text.PlainText
}
}
PlasmaComponents.Button {
id: uninstallButton
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
opacity: local ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: Kirigami.Units.longDuration }
}
iconSource: "application-exit"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Uninstall")
onClicked: {
widgetExplorer.uninstall(pluginName)
tooltipDialog.visible = false
}
}
}

View file

@ -0,0 +1,309 @@
/*
SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.7
import QtQuick.Controls 2.5 as QQC2
import org.kde.plasma.components 3.0 as PC3
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kwindowsystem 1.0
import org.kde.kirigami 2.20 as Kirigami
import QtQuick.Window 2.1
import QtQuick.Layouts 1.1
import org.kde.plasma.private.shell 2.0
PC3.Page {
id: main
width: Math.max(heading.paintedWidth, Kirigami.Units.iconSizes.enormous * 3 + Kirigami.Units.smallSpacing * 4 + Kirigami.Units.gridUnit * 2)
height: 800//Screen.height
opacity: draggingWidget ? 0.3 : 1
property QtObject containment
property PlasmaCore.Dialog sidePanel
//external drop events can cause a raise event causing us to lose focus and
//therefore get deleted whilst we are still in a drag exec()
//this is a clue to the owning dialog that hideOnWindowDeactivate should be deleted
//See https://bugs.kde.org/show_bug.cgi?id=332733
property bool preventWindowHide: draggingWidget || categoriesDialog.status !== PlasmaExtras.Menu.Closed
|| getWidgetsDialog.status !== PlasmaExtras.Menu.Closed
// We might've lost focus during the widget drag and drop or whilst using
// the "get widgets" dialog; however we prevented the sidebar to hide.
// This might get the sidebar stuck, since we only hide when losing focus.
// To avoid this we reclaim focus as soon as the drag and drop is done,
// or the get widgets window is closed.
onPreventWindowHideChanged: {
if (!preventWindowHide && !sidePanel.active) {
sidePanel.requestActivate()
}
}
property bool outputOnly: draggingWidget
property Item categoryButton
property bool draggingWidget: false
signal closed()
onVisibleChanged: {
if (!visible) {
KWindowSystem.showingDesktop = false
}
}
Component.onCompleted: {
if (!root.widgetExplorer) {
root.widgetExplorer = widgetExplorerComponent.createObject(root)
}
root.widgetExplorer.containment = main.containment
}
Component.onDestruction: {
if (pendingUninstallTimer.running) {
// we're not being destroyed so at least reset the filters
widgetExplorer.widgetsModel.filterQuery = ""
widgetExplorer.widgetsModel.filterType = ""
widgetExplorer.widgetsModel.searchTerm = ""
} else {
root.widgetExplorer.destroy()
root.widgetExplorer = null
}
}
function addCurrentApplet() {
var pluginName = list.currentItem ? list.currentItem.pluginName : ""
if (pluginName) {
widgetExplorer.addApplet(pluginName)
}
}
QQC2.Action {
shortcut: "Escape"
onTriggered: {
if (searchInput.length > 0) {
searchInput.text = ""
} else {
main.closed()
}
}
}
QQC2.Action {
shortcut: "Enter"
onTriggered: addCurrentApplet()
}
QQC2.Action {
shortcut: "Return"
onTriggered: addCurrentApplet()
}
Component {
id: widgetExplorerComponent
WidgetExplorer {
//view: desktop
onShouldClose: main.closed();
}
}
PlasmaExtras.ModelContextMenu {
id: categoriesDialog
visualParent: categoryButton
// model set on first invocation
onClicked: {
list.contentX = 0
list.contentY = 0
categoryButton.text = (model.filterData ? model.display : i18nd("plasma_shell_org.kde.plasma.desktop", "All Widgets"))
widgetExplorer.widgetsModel.filterQuery = model.filterData
widgetExplorer.widgetsModel.filterType = model.filterType
}
}
PlasmaExtras.ModelContextMenu {
id: getWidgetsDialog
visualParent: getWidgetsButton
placement: PlasmaExtras.Menu.TopPosedLeftAlignedPopup
// model set on first invocation
onClicked: model.trigger()
}
header: PlasmaExtras.PlasmoidHeading {
ColumnLayout {
id: header
anchors.fill: parent
spacing: Kirigami.Units.smallSpacing
RowLayout {
spacing: Kirigami.Units.smallSpacing
Kirigami.Heading {
id: heading
level: 1
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Widgets")
textFormat: Text.PlainText
elide: Text.ElideRight
Layout.fillWidth: true
}
PC3.ToolButton {
id: getWidgetsButton
icon.name: "get-hot-new-stuff"
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Get New Widgets…")
KeyNavigation.right: closeButton
KeyNavigation.down: searchInput
onClicked: {
getWidgetsDialog.model = widgetExplorer.widgetsMenuActions
getWidgetsDialog.openRelative()
}
}
PC3.ToolButton {
id: closeButton
icon.name: "window-close"
KeyNavigation.down: categoryButton
onClicked: main.closed()
}
}
RowLayout {
spacing: Kirigami.Units.smallSpacing
PlasmaExtras.SearchField {
id: searchInput
Layout.fillWidth: true
KeyNavigation.down: list
KeyNavigation.right: categoryButton
onTextChanged: {
list.positionViewAtBeginning()
list.currentIndex = -1
widgetExplorer.widgetsModel.searchTerm = text
}
Component.onCompleted: if (!Kirigami.InputMethod.willShowOnActive) { forceActiveFocus() }
}
PC3.ToolButton {
id: categoryButton
text: i18nd("plasma_shell_org.kde.plasma.desktop", "All Widgets")
icon.name: "view-filter"
KeyNavigation.down: list
onClicked: {
categoriesDialog.model = widgetExplorer.filterModel
categoriesDialog.open(0, categoryButton.height)
}
PC3.ToolTip {
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Categories")
}
}
}
}
}
footer: PlasmaExtras.PlasmoidHeading {
position: PC3.ToolBar.Footer
visible: pendingUninstallTimer.applets.length > 0
contentItem: PC3.Button {
text: i18ndp("plasma_shell_org.kde.plasma.desktop", "Confirm Removal Of One Widget", "Confirm Removal Of %1 Widgets", pendingUninstallTimer.applets.length)
onClicked: pendingUninstallTimer.uninstall()
}
}
Timer {
id: setModelTimer
interval: 20
running: true
onTriggered: list.model = widgetExplorer.widgetsModel
}
PC3.ScrollView {
anchors.fill: parent
anchors.rightMargin: - main.sidePanel.margins.right
// hide the flickering by fading in nicely
opacity: setModelTimer.running ? 0 : 1
Behavior on opacity {
OpacityAnimator {
duration: Kirigami.Units.longDuration
easing.type: Easing.InOutQuad
}
}
GridView {
id: list
// model set delayed by Timer above
activeFocusOnTab: true
cellWidth: Math.floor(width / 3)
cellHeight: cellWidth + Kirigami.Units.gridUnit * 4 + Kirigami.Units.smallSpacing * 2
delegate: AppletDelegate {}
highlight: PlasmaExtras.Highlight {
pressed: list.currentItem && list.currentItem.pressed
}
highlightMoveDuration: 0
//highlightResizeDuration: 0
//slide in to view from the left
add: Transition {
NumberAnimation {
properties: "x"
from: -list.width
duration: Kirigami.Units.shortDuration
}
}
//slide out of view to the right
remove: Transition {
NumberAnimation {
properties: "x"
to: list.width
duration: Kirigami.Units.shortDuration
}
}
//if we are adding other items into the view use the same animation as normal adding
//this makes everything slide in together
//if we make it move everything ends up weird
addDisplaced: list.add
//moved due to filtering
displaced: Transition {
NumberAnimation {
properties: "x,y"
duration: Kirigami.Units.shortDuration
}
}
KeyNavigation.up: searchInput
}
}
PlasmaExtras.PlaceholderMessage {
anchors.centerIn: parent
width: parent.width - (Kirigami.Units.gridUnit * 4)
iconName: "edit-none"
text: searchInput.text.length > 0 ? i18nd("plasma_shell_org.kde.plasma.desktop", "No widgets matched the search terms") : i18nd("plasma_shell_org.kde.plasma.desktop", "No widgets available")
visible: list.count == 0 && !setModelTimer.running
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Some files were not shown because too many files have changed in this diff Show more