mirror of
https://gitgud.io/wackyideas/aerothemeplasma.git
synced 2024-08-15 00:43:43 +00:00
290 lines
8.8 KiB
QML
Executable file
290 lines
8.8 KiB
QML
Executable file
/*
|
|
SPDX-FileCopyrightText: 2012-2013 Eike Hein <hein@kde.org>
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
import QtQuick 2.4
|
|
import QtQuick.Window 2.2
|
|
|
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
|
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
|
import org.kde.draganddrop 2.0
|
|
|
|
import "code/layout.js" as LayoutManager
|
|
|
|
PlasmaCore.Dialog {
|
|
id: groupDialog
|
|
visible: false
|
|
|
|
type: PlasmaCore.Dialog.PopupMenu
|
|
flags: Qt.WindowStaysOnTopHint
|
|
hideOnWindowDeactivate: true
|
|
location: plasmoid.location
|
|
|
|
readonly property int preferredWidth: Screen.width / (3 * Screen.devicePixelRatio)
|
|
readonly property int preferredHeight: Screen.height / (2 * Screen.devicePixelRatio)
|
|
readonly property int contentWidth: scrollArea.overflowing ? mainItem.width - (PlasmaCore.Units.smallSpacing * 3) : mainItem.width
|
|
readonly property TextMetrics textMetrics: TextMetrics {}
|
|
property alias overflowing: scrollArea.overflowing
|
|
property alias activeTask: focusActiveTaskTimer.targetIndex
|
|
property var _oldAppletStatus: PlasmaCore.Types.UnknownStatus
|
|
|
|
function selectTask(task) {
|
|
if (!task) {
|
|
return;
|
|
}
|
|
|
|
task.forceActiveFocus();
|
|
scrollArea.ensureItemVisible(task);
|
|
}
|
|
|
|
mainItem: MouseHandler {
|
|
id: mouseHandler
|
|
|
|
target: taskList
|
|
handleWheelEvents: !scrollArea.overflowing
|
|
|
|
Timer {
|
|
id: focusActiveTaskTimer
|
|
|
|
property var targetIndex: null
|
|
|
|
interval: 0
|
|
repeat: false
|
|
|
|
onTriggered: {
|
|
// Now we can home in on the previously active task
|
|
// collected in groupDialog.onVisibleChanged.
|
|
|
|
if (targetIndex != null) {
|
|
for (var i = 0; i < groupRepeater.count; ++i) {
|
|
var task = groupRepeater.itemAt(i);
|
|
|
|
if (task.modelIndex() === targetIndex) {
|
|
selectTask(task);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PlasmaExtras.ScrollArea {
|
|
id: scrollArea
|
|
|
|
anchors.fill: parent
|
|
|
|
readonly property bool overflowing: (viewport.height < contentItem.height)
|
|
|
|
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
|
|
|
|
/*ScrollBar.horizontal.visible: false;
|
|
ScrollBar.vertical.visible: false;*/
|
|
|
|
function ensureItemVisible(item) {
|
|
var itemTop = item.y;
|
|
var itemBottom = (item.y + item.height);
|
|
|
|
if (itemTop < flickableItem.contentY) {
|
|
flickableItem.contentY = itemTop;
|
|
}
|
|
|
|
if ((itemBottom - flickableItem.contentY) > viewport.height) {
|
|
flickableItem.contentY = Math.abs(viewport.height - itemBottom);
|
|
}
|
|
}
|
|
|
|
TaskList {
|
|
id: taskList
|
|
|
|
width: parent.width
|
|
|
|
add: Transition {
|
|
// We trigger a null-interval timer in the first add
|
|
// transition after setting the model so onTriggered
|
|
// will run after the Flow has positioned items.
|
|
|
|
ScriptAction {
|
|
script: {
|
|
if (groupRepeater.aboutToPopulate) {
|
|
focusActiveTaskTimer.restart();
|
|
groupRepeater.aboutToPopulate = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onAnimatingChanged: {
|
|
if (!animating) {
|
|
Qt.callLater(updateSize);
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: groupRepeater
|
|
|
|
property bool aboutToPopulate: false
|
|
|
|
function currentIndex() {
|
|
for (var i = 0; i < count; ++i) {
|
|
if (itemAt(i).activeFocus) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
onItemAdded: {
|
|
item.labelTextChanged.connect(updateSize);
|
|
Qt.callLater(updateSize)
|
|
}
|
|
|
|
onItemRemoved: {
|
|
if (groupDialog.visible && index > 0 && index == count) {
|
|
Qt.callLater(updateSize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
flickableItem.boundsBehavior = Flickable.StopAtBounds;
|
|
}
|
|
}
|
|
|
|
Keys.onUpPressed: {
|
|
var currentIndex = groupRepeater.currentIndex();
|
|
// In doubt focus the last item, so we start at the bottom when user
|
|
// initially presses up.
|
|
if (currentIndex === -1) {
|
|
selectTask(groupRepeater.itemAt(groupRepeater.count - 1));
|
|
return;
|
|
}
|
|
|
|
var previousIndex = currentIndex - 1;
|
|
if (previousIndex < 0) {
|
|
previousIndex = groupRepeater.count - 1;
|
|
}
|
|
|
|
selectTask(groupRepeater.itemAt(previousIndex));
|
|
}
|
|
|
|
Keys.onDownPressed: {
|
|
var currentIndex = groupRepeater.currentIndex();
|
|
// In doubt focus the first item, also wrap around.
|
|
if (currentIndex === -1 || currentIndex + 1 >= groupRepeater.count) {
|
|
selectTask(groupRepeater.itemAt(0));
|
|
return;
|
|
}
|
|
|
|
selectTask(groupRepeater.itemAt(currentIndex + 1));
|
|
}
|
|
|
|
Keys.onEscapePressed: groupDialog.visible = false;
|
|
}
|
|
|
|
data: [
|
|
VisualDataModel {
|
|
id: groupFilter
|
|
|
|
delegate: Task {
|
|
visible: true
|
|
inPopup: true
|
|
}
|
|
}
|
|
]
|
|
|
|
onVisualParentChanged: {
|
|
if (visible && visualParent) {
|
|
attachModel();
|
|
} else {
|
|
visible = false;
|
|
}
|
|
}
|
|
|
|
onVisibleChanged: {
|
|
if (visible && visualParent) {
|
|
_oldAppletStatus = plasmoid.status;
|
|
plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus;
|
|
|
|
attachModel();
|
|
|
|
groupDialog.requestActivate();
|
|
mouseHandler.forceActiveFocus();
|
|
} else {
|
|
plasmoid.status = _oldAppletStatus;
|
|
visualParent = null;
|
|
groupRepeater.model = undefined;
|
|
groupFilter.model = undefined;
|
|
groupFilter.rootIndex = undefined;
|
|
}
|
|
}
|
|
|
|
function attachModel() {
|
|
if (!visualParent) {
|
|
return;
|
|
}
|
|
|
|
if (!groupFilter.model) {
|
|
groupFilter.model = tasksModel;
|
|
}
|
|
|
|
groupRepeater.aboutToPopulate = true;
|
|
|
|
groupFilter.rootIndex = tasksModel.makeModelIndex(visualParent.itemIndex);
|
|
|
|
if (!groupRepeater.model) {
|
|
groupRepeater.model = groupFilter;
|
|
}
|
|
}
|
|
|
|
function updateSize() {
|
|
if (!visible) {
|
|
return;
|
|
}
|
|
|
|
if (!visualParent) {
|
|
visible = false;
|
|
return;
|
|
}
|
|
|
|
if (!visualParent.childCount) {
|
|
visible = false;
|
|
// Setting VisualDataModel.rootIndex drops groupRepeater.count to 0
|
|
// before the actual row count. updateSize is therefore invoked twice;
|
|
// only update size once the repeater count matches the model role.
|
|
} else if (!groupRepeater.aboutToPopulate || visualParent.childCount === groupRepeater.count) {
|
|
var task;
|
|
var maxWidth = 0;
|
|
var maxHeight = 0;
|
|
|
|
backend.cancelHighlightWindows();
|
|
|
|
for (var i = 0; i < taskList.children.length - 1; ++i) {
|
|
task = taskList.children[i];
|
|
|
|
textMetrics.text = task.labelText;
|
|
var textWidth = textMetrics.boundingRect.width;
|
|
|
|
if (textWidth > maxWidth) {
|
|
maxWidth = textWidth;
|
|
}
|
|
}
|
|
|
|
maxHeight = groupRepeater.count * (LayoutManager.verticalMargins() + Math.max(theme.mSize(theme.defaultFont).height, PlasmaCore.Units.iconSizes.medium));
|
|
|
|
maxWidth += LayoutManager.horizontalMargins() + PlasmaCore.Units.iconSizes.medium + 2 * PlasmaCore.Units.smallSpacing;
|
|
|
|
// Add horizontal space for scrollbar if needed.
|
|
// FIXME TODO HACK: Use actual scrollbar width instead of a good guess.
|
|
if (maxHeight > preferredHeight) {
|
|
maxWidth += (PlasmaCore.Units.smallSpacing * 3);
|
|
}
|
|
|
|
mainItem.height = Math.min(preferredHeight, maxHeight);
|
|
mainItem.width = Math.min(preferredWidth, (tasks.vertical ? Math.max(maxWidth, tasks.width) : Math.min(maxWidth, tasks.width)));
|
|
}
|
|
}
|
|
}
|