rebrand!: Antergos NeXT -> Euri Linux

This commit is contained in:
2026-08-21 21:43:47 +02:00
parent 7256fd331a
commit 0cfc149d37
1452 changed files with 599 additions and 597 deletions
@@ -0,0 +1,2 @@
// Cannot package without this file due to a bug in kpackagetool6
// This file is empty on purpose, the implementation is done in the ui/main.qml file instead
@@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0 http://www.kde.org/standards/kcfg/1.0/kcfg.xsd">
<kcfgfile name=""/>
<group name="">
<entry name="defaultTiler" type="Int">
<default>0</default>
</entry>
<entry name="centerInTileMode" type="Int">
<default>0</default>
</entry>
<entry name="rememberTiler" type="Bool">
<default>false</default>
</entry>
<entry name="restoreSize" type="Bool">
<default>false</default>
</entry>
<entry name="allowTransient" type="Bool">
<default>false</default>
</entry>
<entry name="allowModal" type="Bool">
<default>false</default>
</entry>
<entry name="tilerVisibility" type="Int">
<default>0</default>
</entry>
<entry name="revealMargin" type="Int">
<default>200</default>
</entry>
<entry name="displayAs" type="Int">
<default>0</default>
</entry>
<entry name="windowVisibility" type="Int">
<default>0</default>
</entry>
<entry name="theme" type="Int">
<default>0</default>
</entry>
<entry name="tileMargin" type="Int">
<default>0</default>
</entry>
<entry name="screenMargin" type="Int">
<default>0</default>
</entry>
<entry name="defaultInput" type="Int">
<default>0</default>
</entry>
<entry name="showOverlayTextHint" type="Bool">
<default>true</default>
</entry>
<entry name="overlayLayout" type="String">
<default>4x2</default>
</entry>
<entry name="overlayScreenEdgeMargin" type="Int">
<default>0</default>
</entry>
<entry name="overlayPollingRate" type="Int">
<default>100</default>
</entry>
<entry name="rememberAllLayouts" type="Bool">
<default>false</default>
</entry>
<entry name="showTargetTileHint" type="Bool">
<default>true</default>
</entry>
<entry name="showTextHint" type="Bool">
<default>true</default>
</entry>
<entry name="gridTilerOpacity" type="Int">
<default>100</default>
<min>0</min>
<max>100</max>
</entry>
<entry name="popupGridAt" type="Int">
<default>0</default>
</entry>
<entry name="horizontalAlignment" type="Int">
<default>1</default>
</entry>
<entry name="verticalAlignment" type="Int">
<default>1</default>
</entry>
<entry name="gridColumns" type="Int">
<default>3</default>
</entry>
<entry name="gridAllColumns" type="Int">
<default>6</default>
</entry>
<entry name="gridSpacing" type="Int">
<default>10</default>
</entry>
<entry name="gridWidth" type="Int">
<default>130</default>
</entry>
<entry name="gridHeight" type="Int">
<default>70</default>
</entry>
<entry name="popupGridPollingRate" type="Int">
<default>100</default>
</entry>
<entry name="virtualDesktopVisibility" type="Int">
<default>0</default>
</entry>
<entry name="virtualDesktopDropAction" type="Int">
<default>0</default>
</entry>
<entry name="virtualDesktopHoverTime" type="Int">
<default>500</default>
</entry>
<entry name="moveBackOnDrop" type="Bool">
<default>false</default>
</entry>
<entry name="moveBackOnTile" type="Bool">
<default>false</default>
</entry>
<entry name="showAddVirtualDesktopButton" type="Bool">
<default>true</default>
</entry>
<entry name="autoRemoveEmptyVirtualDesktops" type="Bool">
<default>false</default>
</entry>
<entry name="popupLayout" type="String">
<default>1x1
2x1
3x1
SPECIAL_SPLIT_HORIZONTAL
0,0,75,100+25,0,75,100+25,0,50,100
4x1
2x2
SPECIAL_FILL
4x2
SPECIAL_AUTO_TILER_1
SPECIAL_AUTO_TILER_2
SPECIAL_AUTO_TILER_3</default>
</entry>
<entry name="allPopupLayouts" type="String">
<default>SPECIAL_FILL
SPECIAL_SPLIT_VERTICAL
SPECIAL_SPLIT_HORIZONTAL
SPECIAL_MAXIMIZE
SPECIAL_MINIMIZE
SPECIAL_FULLSCREEN
0,0,50,100+50,0,50,50+50,50,50,50
0,0,50,50+0,50,50,50+50,0,50,100
0,0,25,50+0,50,25,50+25,0,50,100+75,0,25,50+75,50,25,50
0,0,25,50+0,50,25,50+25,0,50,50+25,50,50,50+75,0,25,50+75,50,25,50
SPECIAL_KEEP_ABOVE
SPECIAL_KEEP_BELOW
0,0,50,100+50,0,25,50+50,50,25,50+75,0,25,50+75,50,25,50
0,0,25,50+0,50,25,50+25,0,25,50+25,50,25,50+50,0,50,100
0,0,50,50+0,50,50,50+50,0,25,50+50,50,25,50+75,0,25,50+75,50,25,50
0,0,25,50+0,50,25,50+25,0,25,50+25,50,25,50+50,0,50,50+50,50,50,50
SPECIAL_NO_TITLEBAR_AND_FRAME
SPECIAL_CLOSE
1x1
2x1
3x1
4x1
5x1
6x1
1x2
1x3
1x4
1x5
0,0,75,100+25,0,75,100+25,0,50,100
0,0,75,50+25,0,75,50+25,0,50,50+0,50,75,50+25,50,75,50+25,50,50,50
2x2
3x2
4x2
5x2
0,0,67,100+33,0,67,100+17,0,66,100
0,0,67,50+33,0,67,50+17,0,66,50+0,50,67,50+33,50,67,50+17,50,66,50
2x3
3x3
4x3
5x3
1x1+17,0,66,100+33,0,34,100
1x2+17,0,66,50+33,0,34,50+17,50,66,50+33,50,34,50
11,25,26,50+37,25,26,50+63,25,26,50
11,0,26,100+37,0,26,100+63,0,26,100
11,0,26,50+37,0,26,50+63,0,26,50 + 11,50,26,50+37,50,26,50+63,50,26,50
11,0,26,100+37,0,26,100+63,0,26,100 + 11,12,26,76+37,12,26,76+63,12,26,76 + 11,25,26,50+37,25,26,50+63,25,26,50
1x1+12,0,76,100+25,0,50,100+37,0,26,100
1x2+12,0,76,50+25,0,50,50+37,0,26,50+12,50,76,50+25,50,50,50+37,50,26,50
0,25,37,50+37,25,26,50+63,25,37,50
0,0,37,100+37,0,26,100+63,0,37,100
0,0,37,50+37,0,26,50+63,0,37,50 + 0,50,37,50+37,50,26,50+63,50,37,50
0,0,37,100+37,0,26,100+63,0,37,100 + 0,12,37,76+37,12,26,76+63,12,37,76 + 0,25,37,50+37,25,26,50+63,25,37,50
1x1+17,17,66,66+33,33,34,34
1x1+12,12,76,76+25,25,50,50+37,37,26,26
0,0,25,100+75,0,25,100+25,0,50,100
0,0,25,67+75,0,25,67+25,0,50,67+0,67,25,33+75,67,25,33+25,67,50,33
0,0,25,33+75,0,25,33+25,0,50,33+0,33,25,67+75,33,25,67+25,33,50,67
0,0,25,67+75,0,25,67+25,0,50,67+0,33,25,67+75,33,25,67+25,33,50,67
0,0,33,67+33,0,34,67+67,0,33,67+0,67,33,33+33,67,34,33+67,67,33,33
0,0,33,33+33,0,34,33+67,0,33,33+0,33,33,67+33,33,34,67+67,33,33,67
0,0,67,100+67,0,33,100
0,0,33,100+33,0,67,100
0,0,67,100+67,0,33,50+67,50,33,50
0,0,33,50+0,50,33,50+33,0,67,100
0,0,67,50+67,0,33,50+0,50,67,50+67,50,33,50
0,0,33,50+33,0,67,50+0,50,33,50+33,50,67,50
SPECIAL_AUTO_TILER_TOGGLE
SPECIAL_AUTO_TILER_1
SPECIAL_AUTO_TILER_2
SPECIAL_AUTO_TILER_3</default>
</entry>
<entry name="shortcutChangeMode" type="String">
<default>Meta+Ctrl+Space</default>
</entry>
<entry name="shortcutShowAllSpan" type="String">
<default>Ctrl+Space</default>
</entry>
<entry name="shortcutVisibility" type="String">
<default>Meta+Space</default>
</entry>
<entry name="shortcutInputType" type="String">
<default>Ctrl+Alt+I</default>
</entry>
<entry name="shortcutCenterInTile" type="String">
<default>Meta+Ctrl+C</default>
</entry>
<entry name="shortcutMoveOnDrop" type="String">
<default>Meta+Ctrl+V</default>
</entry>
<entry name="shortcutToggleTilingSuggestions" type="String">
<default>Meta+Ctrl+S</default>
</entry>
<entry name="hintChangeMode" type="Bool">
<default>true</default>
</entry>
<entry name="hintShowAllSpan" type="Bool">
<default>true</default>
</entry>
<entry name="hintVisibility" type="Bool">
<default>true</default>
</entry>
<entry name="hintInputType" type="Bool">
<default>true</default>
</entry>
<entry name="hintCenterInTile" type="Bool">
<default>true</default>
</entry>
<entry name="hintMoveOnDrop" type="Bool">
<default>true</default>
</entry>
<entry name="hintToggleTilingSuggestions" type="Bool">
<default>true</default>
</entry>
<entry name="showHintHint" type="Bool">
<default>true</default>
</entry>
<entry name="debugLogs" type="Bool">
<default>false</default>
</entry>
<entry name="showPositionHint" type="Bool">
<default>false</default>
</entry>
<entry name="positionHintFormat" type="Int">
<default>0</default>
</entry>
<entry name="showSizeHint" type="Bool">
<default>false</default>
</entry>
<entry name="sizeHintFormat" type="Int">
<default>0</default>
</entry>
<entry name="autoTileNewWindows" type="Bool">
<default>false</default>
</entry>
<entry name="autoTilerEdgeScroll" type="Bool">
<default>true</default>
</entry>
<entry name="autoTileMinimizedMaximized" type="Bool">
<default>true</default>
</entry>
<entry name="autoTileRestoreSize" type="Bool">
<default>false</default>
</entry>
<entry name="autoTileRestoreSizeAndPosition" type="Bool">
<default>true</default>
</entry>
<entry name="autoTileToggleBehavior" type="Int">
<default>0</default>
</entry>
<entry name="autoTileIds" type="String">
<default></default>
</entry>
<entry name="autoTileBlacklist" type="String">
<default>krunner,kded,polkit,plasmashell,yakuake,spectacle,org.kde.spectacle,kded5,xwaylandvideobridge,ksplashqml,org.kde.plasmashell,org.kde.polkit-kde-authentication-agent-1,org.kde.kruler,kruler,kwin_wayland,kwin,ksmserver-logout-greeter,ksmserver</default>
</entry>
<entry name="autoTileWindowAction" type="Int">
<default>0</default>
</entry>
<entry name="autoTileWindowIndex" type="Int">
<default>0</default>
</entry>
<entry name="autoTileFocusAction" type="Int">
<default>0</default>
</entry>
<entry name="autoTileFocusIndex" type="Int">
<default>0</default>
</entry>
<entry name="autoTileMinimizedFocusAction" type="Int">
<default>0</default>
</entry>
<entry name="autoTileMinimizedFocusIndex" type="Int">
<default>0</default>
</entry>
<entry name="autoTileDragSwapAction" type="Int">
<default>0</default>
</entry>
<entry name="autoTileLayer" type="Int">
<default>2</default>
</entry>
<entry name="maxAutoTileDelay" type="Int">
<default>5</default>
</entry>
<entry name="maxAutoTileDelaySessionStart" type="Int">
<default>10</default>
</entry>
<entry name="autoTilerMode1" type="Int">
<default>8</default>
</entry>
<entry name="autoTilerMode2" type="Int">
<default>1</default>
</entry>
<entry name="autoTilerMode3" type="Int">
<default>12</default>
</entry>
<entry name="autoTilerCustom1" type="String">
<default>0:0,0,100,100
0:0,0,50,100+1:50,0,50,100
0:0,0,50,100+1:50,0,50,50+2:50,50,50,50
0:0,0,50,50+3:0,50,50,50+1:50,0,50,50+2:50,50,50,50</default>
</entry>
<entry name="autoTilerCustom2" type="String">
<default>{"carousel":true}
0:0,0,100,100</default>
</entry>
<entry name="autoTilerCustom3" type="String">
<default>0:0,0,67,100
0:0,0,67,100+1:67,0,33,100
0:0,0,67,100+1:67,0,33,50+2:67,50,33,50</default>
</entry>
<entry name="autoTilerCarousel1" type="Bool">
<default>false</default>
</entry>
<entry name="autoTilerCarousel2" type="Bool">
<default>false</default>
</entry>
<entry name="autoTilerCarousel3" type="Bool">
<default>false</default>
</entry>
<entry name="suggestionsVisibility" type="Int">
<default>0</default>
</entry>
<entry name="suggestionsMode" type="Int">
<default>0</default>
</entry>
<entry name="suggestOtherScreens" type="Bool">
<default>false</default>
</entry>
<entry name="suggestOtherDesktops" type="Bool">
<default>false</default>
</entry>
<entry name="suggestOtherActivities" type="Bool">
<default>false</default>
</entry>
<entry name="suggestAutoTiled" type="Bool">
<default>false</default>
</entry>
<entry name="suggestMinimized" type="Bool">
<default>false</default>
</entry>
</group>
</kcfg>
@@ -0,0 +1,239 @@
import QtQuick
import org.kde.kirigami as Kirigami
Item {
Kirigami.Theme.colorSet: Kirigami.Theme.View
property bool lightTheme: {
return Kirigami.ColorUtils.brightnessForColor(Kirigami.Theme.backgroundColor) === Kirigami.ColorUtils.Light;
}
property var backgroundColor: {
switch (config.theme) {
case 1:
return "#161925";
case 2:
return "#110B00";
case 3:
return "#FFFFFF";
case 4:
return "#110000";
case 5:
return "#020900";
case 6:
return "#0A0010";
case 7:
return "#001100";
case 8:
return "#111100";
case 9:
return "#000710";
default:
return Kirigami.Theme.backgroundColor;
}
}
property var borderColor: {
switch (config.theme) {
case 1:
return "#666666";
case 2:
return "#7F4F00";
case 3:
return "#777777";
case 4:
return "#780000";
case 5:
return "#587C00";
case 6:
return "#4A0076";
case 7:
return "#225522";
case 8:
return "#555500";
case 9:
return "#004093";
default:
if (lightTheme) {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.2);
} else {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.2);
}
}
}
property var textColor: {
switch (config.theme) {
case 1:
return "white";
case 2:
return "white";
case 3:
return "black";
case 4:
return "white";
case 5:
return "white";
case 6:
return "white";
case 7:
return "white";
case 8:
return "white";
case 9:
return "white";
default:
return lightTheme ? "black" : "white";
}
}
property var overlayTextColor: {
switch (config.theme) {
case 1:
return "white";
case 2:
return "white";
case 3:
return "black";
case 4:
return "black";
case 5:
return "black";
case 6:
return "white";
case 7:
return "black";
case 8:
return "black";
case 9:
return "white";
default:
return lightTheme ? "black" : "white";
}
}
property var hintBackgroundColor: {
switch (config.theme) {
case 1:
return "#590099FF";
case 2:
return "#59FF9F00";
case 3:
return "#59FF0000";
case 4:
return "#59FF0000";
case 5:
return "#59B5FF00";
case 6:
return "#599F00FF";
case 7:
return "#5900FF00";
case 8:
return "#59FFFF00";
case 9:
return "#590067FF";
default:
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.35);
}
}
property var tileBorderColor: {
switch (config.theme) {
case 1:
return "#0099FF";
case 2:
return "#FF9F00";
case 3:
return "#FF0000";
case 4:
return "#FF0000";
case 5:
return "#B5FF00";
case 6:
return "#9F00FF";
case 7:
return "#00FF00";
case 8:
return "#FFFF00";
case 9:
return "#0067FF";
default:
return Kirigami.Theme.highlightColor;
}
}
property var tileBackgroundColor: {
switch (config.theme) {
case 1:
return "#0C0099FF";
case 2:
return "#0CFF9F00";
case 3:
return "#3CFF0000";
case 4:
return "#3CFF0000";
case 5:
return "#3CB5FF00";
case 6:
return "#3C9F00FF";
case 7:
return "#3C00FF00";
case 8:
return "#3CFFFF00";
case 9:
return "#3C0067FF";
default:
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.05);
}
}
property var tileBackgroundColorIntense: {
switch (config.theme) {
case 1:
return "#3C0099FF";
case 2:
return "#3CFF9F00";
case 3:
return "#3CFF0000";
case 4:
return "#3CFF0000";
case 5:
return "#3CB5FF00";
case 6:
return "#3C9F00FF";
case 7:
return "#3C00FF00";
case 8:
return "#3CFFFF00";
case 9:
return "#3C0067FF";
default:
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.23);
}
}
property var tileBackgroundColorActive: {
switch (config.theme) {
case 1:
return "#BE0099FF";
case 2:
return "#BEFF9F00";
case 3:
return "#BEFF0000";
case 4:
return "#BEFF0000";
case 5:
return "#BEB5FF00";
case 6:
return "#BE9F00FF";
case 7:
return "#BE00FF00";
case 8:
return "#BEFFFF00";
case 9:
return "#BE0067FF";
default:
return Kirigami.ColorUtils.tintWithAlpha("transparent", Kirigami.Theme.highlightColor, 0.75);
}
}
}
@@ -0,0 +1,182 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.kwin
import org.kde.kirigami as Kirigami
// import QtWebView
ApplicationWindow {
property var overrides: {}
property var currentOverrides: {}
property var currentApplications: []
property var currentWindows: []
property var defaultConfig: {}
property var currentApplicationIndex: -1
property var currentWindowIndex: -1
// property var isX11: Qt.platform.pluginName == 'xcb'
property var mouseStartX
property var mouseStartY
property var windowStartX
property var windowStartY
Kirigami.Theme.colorSet: Kirigami.Theme.Window
property var lightTheme: {
return Kirigami.ColorUtils.brightnessForColor(Kirigami.Theme.backgroundColor) === Kirigami.ColorUtils.Light;
}
property var headerColor: {
if (lightTheme) {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.4);
} else {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.3);
}
}
property var headerBorderColor: {
if (lightTheme) {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "black", 0.2);
} else {
return Kirigami.ColorUtils.tintWithAlpha(Kirigami.Theme.backgroundColor, "white", 0.2);
}
}
id: mainMenuRoot
width: 1000
height: 734
title: "Mouse Tiler Configuration"
color: Kirigami.Theme.backgroundColor
flags: Qt.FramelessWindowHint | Qt.Window | Qt.BypassWindowManagerHint
// flags: ixX11 ? Qt.X11BypassWindowManagerHint : flags
// x: isX11 ? Workspace.virtualScreenSize.width / 2 - width / 2 : x
// y: isX11 ? Workspace.virtualScreenSize.height / 2 - height / 2 : y
x: Workspace.virtualScreenSize.width / 2 - width / 2
y: Workspace.virtualScreenSize.height / 2 - height / 2
function initMainMenu() {
}
Rectangle {
color: headerColor
height: 34
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
border.color: headerBorderColor
border.width: 1
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onPressed: {
mouseStartX = Workspace.cursorPos.x;
mouseStartY = Workspace.cursorPos.y;
windowStartX = mainMenuRoot.x;
windowStartY = mainMenuRoot.y;
}
onPositionChanged: {
mainMenuRoot.x = windowStartX + (Workspace.cursorPos.x - mouseStartX);
mainMenuRoot.y = windowStartY + (Workspace.cursorPos.y - mouseStartY);
}
onReleased: {
mainMenuRoot.x = windowStartX + (Workspace.cursorPos.x - mouseStartX);
mainMenuRoot.y = windowStartY + (Workspace.cursorPos.y - mouseStartY);
}
Label {
text: "Mouse Tiler Configuration"
anchors.centerIn: parent
}
Button {
text: "X"
flat: true
width: 26
height: 26
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 4
onClicked: root.closeMainMenu()
}
}
}
GroupBox {
id: mainGroupBox
anchors.fill: parent
anchors.topMargin: 35
// WebView {
// id: webView
// anchors.fill: parent
// url: "https://rxweb.epizy.com/mousetiler/editor.html"
// }
ColumnLayout {
id: mainChoice
visible: true
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
GroupBox {
spacing: 5
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
text: "This was meant to be the UI designer. However it is a lot of work to implement it, probaly at least 1-2 weeks full time. Sadly I got rent to pay and a 3 year old son to feed and based on my previous project Remember Window Positions, I will not be able to feed us from my contributions to Linux. (After over 3 months full time work I earned $100 total which I apreciate but it's not possible to survive on). I might implement it in the future if the situation changes."
wrapMode: Text.WordWrap
}
// Label {
// Layout.fillWidth: true
// text: "Not implemented yet"
// wrapMode: Text.WordWrap
// }
}
}
// GroupBox {
// spacing: 5
// Layout.fillWidth: true
// ColumnLayout {
// anchors.fill: parent
// Label {
// Layout.fillWidth: true
// horizontalAlignment: Text.AlignHCenter
// text: "."
// wrapMode: Text.WordWrap
// }
// Button {
// id: selectWindowButton
// text: "Select Application/Window"
// Layout.fillWidth: true
// onClicked: selectWindow()
// }
// Button {
// text: "Edit Saved Applications and Windows"
// Layout.fillWidth: true
// onClicked: editSavedAppOrWindow()
// }
// }
// }
}
}
}
@@ -0,0 +1,319 @@
import QtQuick
import org.kde.kwin
import org.kde.plasma.core as PlasmaCore
// Window {
PlasmaCore.Dialog {
id: overlayTiler
property var activeScreen: null
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
property var tilePadding: 2
property int activeIndex: -1
property int spanFromIndex: -1
property int minSpanX: -1
property int minSpanY: -1
property int maxSpanX: -1
property int maxSpanY: -1
property var convertedOverlay: ([])
// Workaround for plasma 6.6 and earlier - needed by Window and Plasma Dialog - replaced by Qt.WindowTransparentForInput in Plasma 6.7
property bool outputOnly: true
width: clientArea.width - root.config.overlayScreenEdgeMargin * 2
height: clientArea.height - root.config.overlayScreenEdgeMargin * 2
x: clientArea.x + root.config.overlayScreenEdgeMargin
y: clientArea.y + root.config.overlayScreenEdgeMargin
// flags: Qt.Popup | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
flags: (root.config.displayAs == 0 ? 0 : Qt.Popup) | (Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowTransparentForInput)
// color: "transparent" // Window
visible: false
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
// outputOnly: true // PlasmaCore.Dialog
// type: PlasmaCore.Dialog.OnScreenDisplay
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
function reset() {
activeScreen = null;
spanFromIndex = -1;
activeIndex = -1;
updateSpan();
}
function startAnimations() {
overlayTiler.opacity = 0;
showOverlayTilerAnimation.start();
}
function updateScreen() {
if (activeScreen != Workspace.activeScreen) {
autoTiler.updateShouldShowScreenEdges();
root.logE('updateScreen ' + Workspace.virtualScreenSize);
reset();
activeScreen = Workspace.activeScreen;
clientArea = Workspace.clientArea(KWin.FullScreenArea, activeScreen, Workspace.currentDesktop);
convertLayoutToScreen();
}
}
function convertLayoutToScreen() {
let layout = root.config.overlay;
let converted = [];
for (let i = 0; i < layout.length; i++) {
let tile = layout[i];
let width = (tile.pxW == undefined ? tile.w / 100 * mainItem.width : tile.pxW);
let height = (tile.pxH == undefined ? tile.h / 100 * mainItem.height : tile.pxH);
converted.push({
pxX: (tile.pxX == undefined ? tile.x / 100 * mainItem.width : tile.pxX) - (tile.aX == undefined ? 0 : tile.aX * width / 100),
pxY: (tile.pxY == undefined ? tile.y / 100 * mainItem.height : tile.pxY) - (tile.aY == undefined ? 0 : tile.aY * height / 100),
pxW: width,
pxH: height
});
}
convertedOverlay = converted;
}
function toggleSpan() {
if (spanFromIndex != activeIndex && spanFromIndex == -1) {
spanFromIndex = activeIndex;
updateSpan();
} else if (spanFromIndex >= 0) {
spanFromIndex = -1;
updateSpan();
}
}
function updateSpan() {
if (activeIndex == -1 || spanFromIndex == -1) {
minSpanX = -1;
minSpanY = -1;
maxSpanX = -1;
maxSpanY = -1;
} else {
let itemActive = tileRepeater.itemAt(activeIndex);
let itemSpan = tileRepeater.itemAt(spanFromIndex);
minSpanX = Math.min(itemActive.x, itemSpan.x);
minSpanY = Math.min(itemActive.y, itemSpan.y);
maxSpanX = Math.max(itemActive.x + itemActive.width, itemSpan.x + itemSpan.width);
maxSpanY = Math.max(itemActive.y + itemActive.height, itemSpan.y + itemSpan.height);
}
root.log('Span activeIndex: ' + activeIndex + ' spanFromIndex: ' + spanFromIndex + ' minSpanX: ' + minSpanX + ' minSpanY: ' + minSpanY + ' maxSpanX: ' + maxSpanX + ' maxSpanY: ' + maxSpanY);
}
function getGeometry() {
if (activeIndex >= 0) {
let x, y, width, height;
if (spanFromIndex >= 0) {
x = clientArea.x + minSpanX;
y = clientArea.y + minSpanY;
width = maxSpanX - minSpanX;
height = maxSpanY - minSpanY;
} else {
let item = tileRepeater.itemAt(activeIndex);
x = clientArea.x + item.x;
y = clientArea.y + item.y;
width = item.width;
height = item.height;
}
if (root.centerInTile) {
return {
x: x + width / 2 - root.currentlyMovedWindow.width / 2,
y: y + height / 2 - root.currentlyMovedWindow.height / 2,
width: root.currentlyMovedWindow.width,
height: root.currentlyMovedWindow.height
};
} else {
return {
x: x,
y: y,
width: width,
height: height
};
}
}
return null;
}
function getActiveVirtualDesktopIndex() {
return -1;
}
Item {
id: mainItem
width: popupTiler.width
height: popupTiler.height
SequentialAnimation {
id: showOverlayTilerAnimation
running: false
NumberAnimation {
target: overlayTiler;
property: "opacity";
from: 0;
to: 0;
duration: 32;
}
NumberAnimation {
target: overlayTiler;
property: "opacity";
from: 1;
to: 1;
duration: 1;
}
onFinished: {
root.updateWindowVisibility();
}
}
Colors {
id: colors
}
Repeater {
id: tileRepeater
model: overlayTiler.convertedOverlay
Item {
id: tile
property bool active: activeIndex == index
property bool spanned: !active && Math.ceil(modelData.pxX) >= Math.floor(minSpanX) && Math.floor(modelData.pxX) + Math.floor(modelData.pxW) <= Math.ceil(maxSpanX) && Math.ceil(modelData.pxY) >= Math.floor(minSpanY) && Math.floor(modelData.pxY) + Math.floor(modelData.pxH) <= Math.ceil(maxSpanY)
property bool spannedFrom: spanFromIndex == index
x: modelData.pxX
y: modelData.pxY
width: modelData.pxW
height: modelData.pxH
Rectangle {
anchors.fill: parent
anchors.margins: tilePadding
border.color: colors.tileBorderColor
border.width: 2
color: "transparent"
radius: 12
Rectangle {
anchors.fill: parent
radius: 12
color: active || spanned ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
}
Text {
anchors.centerIn: parent
color: colors.overlayTextColor
textFormat: Text.StyledText
text: {
let defaultHint = "";
let insertExtraBreak = false;
if (root.config.showHintHint) {
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Configure tiler visibility and these hints in settings.";
insertExtraBreak = true;
}
if (root.config.hintShowAllSpan) {
if (insertExtraBreak) {
defaultHint += "<br>";
insertExtraBreak = false;
}
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + (spannedFrom ? "Stop spanning (<b>" + root.config.shortcutShowAllSpan + "</b>)" : "Span from this tile (<b>" + root.config.shortcutShowAllSpan + "</b>)");
insertExtraBreak = true;
}
if (root.config.hintVisibility) {
if (insertExtraBreak) {
defaultHint += "<br>";
insertExtraBreak = false;
}
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Toggle visibility (<b>" + root.config.shortcutVisibility + "</b>)";
}
if (root.config.hintInputType) {
if (insertExtraBreak) {
defaultHint += "<br>";
insertExtraBreak = false;
}
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Input type: " + (root.useMouseCursor ? "Mouse" : "Window") + " (<b>" + root.config.shortcutInputType + "</b>)";
}
if (root.config.hintCenterInTile) {
if (insertExtraBreak) {
defaultHint += "<br>";
insertExtraBreak = false;
}
defaultHint += (defaultHint.length > 0 ? "<br>" : "") + "Center in tile: " + (root.centerInTile ? "Enabled" : "Disabled") + " (<b>" + root.config.shortcutCenterInTile + "</b>)";
}
if (root.config.hintChangeMode) {
insertExtraBreak = false;
defaultHint += (defaultHint.length > 0 ? "<br><br>" : "") + "Switch mode (<b>" + root.config.shortcutChangeMode + "</b>)";
}
if (root.centerInTile) {
return (spannedFrom ? "<b>Center in spanned tiles</b><br><br>" : "<b>Center in this tile</b><br><br>") + defaultHint;
} else {
return defaultHint;
}
return defaultHint;
}
font.pixelSize: 16
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
visible: root.config.showOverlayTextHint && (active && spanFromIndex == -1 || spannedFrom)
}
}
}
}
Rectangle {
id: popupWindowCursor
anchors.left: parent.left
anchors.leftMargin: root.getCursorPosition().x - clientArea.x - 6
anchors.top: parent.top
anchors.topMargin: root.getCursorPosition().y - clientArea.y - 6
width: 12
height: 12
border.color: colors.tileBorderColor
border.width: 2
color: colors.tileBackgroundColorActive
radius: 6
visible: !root.useMouseCursor
Rectangle {
anchors.centerIn: parent
width: 2
height: 2
color: colors.textColor
radius: 1
opacity: 0.8
}
}
Timer {
interval: root.config.overlayPollingRate
repeat: true
running: overlayTiler.visible
onTriggered: {
updateScreen();
let localCursorPos = Workspace.activeScreen.mapFromGlobal(root.getCursorPosition());
let x = localCursorPos.x - root.config.overlayScreenEdgeMargin;
let y = localCursorPos.y - root.config.overlayScreenEdgeMargin;
let index = -1;
for (let i = 0; i < tileRepeater.count; i++) {
let item = tileRepeater.itemAt(i);
if (item.x <= x && item.x + item.width >= x && item.y <= y && item.y + item.height >= y) {
index = i;
break;
}
}
if (index != activeIndex) {
activeIndex = index;
updateSpan();
}
}
}
}
}
@@ -0,0 +1,978 @@
import QtQuick
import QtQuick.Layouts
import org.kde.kwin
import org.kde.plasma.core as PlasmaCore
// Window {
PlasmaCore.Dialog {
id: popupTiler
property var activeScreen: null
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
property int tilePadding: 2
property int borderOffset: 2
property int activeLayoutIndex: -1
property int activeTileIndex: -1
property int positionX: 0
property int positionY: 0
property bool showAll: false
property bool lastShowAll: false
property var hint: null
property bool showPopupDropHint: false
property bool hasValidPopupDropHint: false
property var popupDropHintX: 0
property var popupDropHintY: 0
property var popupDropHintWidth: 0
property var popupDropHintHeight: 0
property bool popupDropHintIsCenterInTile: false
property bool sizeEstablished: false
property var revealBox: null
property bool revealed: false
property bool currentlyHovered: false
property int activeVirtualDesktopIndex: -1
property var activeVirtualDesktopHoverTime: -1
property bool virtualDesktopVisibilityOverride: false
// property bool shouldShowAutoTileScroll: false
// property var scrollLeftTime: 0
// property var scrollRightTime: 0
// Workaround for plasma 6.6 and earlier - needed by Window and Plasma Dialog - replaced by Qt.WindowTransparentForInput in Plasma 6.7
property bool outputOnly: true
width: clientArea.width
height: clientArea.height
x: clientArea.x
y: clientArea.y
//flags: Qt.Popup | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
flags: (root.config.displayAs == 0 ? 0 : Qt.Popup) | (Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowTransparentForInput)
// color: "transparent" // Window
visible: false
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
// outputOnly: true // PlasmaCore.Dialog
// type: PlasmaCore.Dialog.OnScreenDisplay
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
function reset() {
activeScreen = null;
activeLayoutIndex = -1;
activeTileIndex = -1;
hint = null;
showPopupDropHint = false;
updateHintContent();
}
function resetShowAll() {
showAll = false;
lastShowAll = false;
}
function startAnimations() {
popupTiler.opacity = 0;
showPopupTilerAnimation.start();
}
function updateScreen(forceUpdate = false) {
if (forceUpdate || activeScreen != Workspace.activeScreen) {
root.logE('updateScreen ' + Workspace.virtualScreenSize);
if (activeScreen != Workspace.activeScreen) {
autoTiler.updateAutoTilersInPopupTiler();
}
autoTiler.updateShouldShowScreenEdges();
// shouldShowAutoTileScroll = autoTiler.shouldShowAutoTileScroll();
activeScreen = Workspace.activeScreen;
clientArea = Workspace.clientArea(KWin.FullScreenArea, Workspace.activeScreen, Workspace.currentDesktop);
let localCursorPos = Workspace.activeScreen.mapFromGlobal(root.getCursorPosition());
let visibleHeight = virtualDesktopVisibilityOverride || root.config.virtualDesktopVisibility != 1 ? layouts.height : 0;
if (root.config.popupGridAt == 0) {
switch (root.config.horizontalAlignment) {
default:
positionX = localCursorPos.x - root.config.gridWidth / 2 - root.config.gridSpacing;
break;
case 1:
positionX = localCursorPos.x - layouts.width / 2;
break;
case 2:
positionX = localCursorPos.x - layouts.width + root.config.gridWidth / 2 + root.config.gridSpacing;
break;
}
if (visibleHeight == 0) {
positionY = localCursorPos.y;
} else {
switch (root.config.verticalAlignment) {
default:
positionY = localCursorPos.y - root.config.gridHeight / 2 - root.config.gridSpacing;
break;
case 1:
positionY = localCursorPos.y - layouts.height / 2;
break;
case 2:
positionY = localCursorPos.y - layouts.height + root.config.gridHeight / 2 + root.config.gridSpacing;
break;
}
}
} else {
switch (root.config.horizontalAlignment) {
default:
positionX = 0;
break;
case 1:
positionX = clientArea.width / 2 - layouts.width / 2;
break;
case 2:
positionX = clientArea.width - layouts.width;
break;
}
switch (root.config.verticalAlignment) {
default:
positionY = 0;
break;
case 1:
positionY = clientArea.height / 2 - visibleHeight / 2;
break;
case 2:
positionY = clientArea.height - visibleHeight;
break;
}
}
// positionX = localCursorPos.x - layouts.width / 2;
// positionY = localCursorPos.y - (layouts.height + popupHint.height + 2) / 2;
if (positionX < 0) {
positionX = 0;
} else if (positionX + layouts.width > popupTiler.width) {
positionX = popupTiler.width - layouts.width;
}
let totalHeight = visibleHeight;
if (root.virtualDesktopVisibile) {
if (totalHeight > 0) {
totalHeight += 2;
}
totalHeight += virtualDesktop.height;
}
if (root.config.showTextHint) {
totalHeight += popupHint.height + 2;
}
if (positionY < 0) {
positionY = 0;
} else if (positionY + totalHeight > popupTiler.height) {
positionY = popupTiler.height - totalHeight;
}
if (root.config.tilerVisibility == 3) {
let triggerLeft = Math.max(positionX - config.revealMargin, 0);
let triggerRight = Math.min(positionX + layouts.width + config.revealMargin, popupTiler.width);
let triggerTop = Math.max(positionY - config.revealMargin, 0);
let triggerBottom = Math.min(positionY + totalHeight + config.revealMargin, popupTiler.height);
let leftTop = Workspace.activeScreen.mapToGlobal(Qt.point(triggerLeft, triggerTop));
let rightBottom = Workspace.activeScreen.mapToGlobal(Qt.point(triggerRight, triggerBottom));
revealBox = { left: leftTop.x, right: rightBottom.x, top: leftTop.y, bottom: rightBottom.y };
updateRevealed(true);
} else {
revealBox = null;
updateRevealed(true);
}
}
}
function getGeometry() {
if (activeLayoutIndex >= 0 && activeTileIndex >= 0) {
if (root.centerInTile && hasValidPopupDropHint) {
return {
x: clientArea.x + popupDropHintX,
y: clientArea.y + popupDropHintY,
width: popupDropHintWidth,
height: popupDropHintHeight
};
} else if (layoutRepeater.model[activeLayoutIndex].special) {
return {
special: layoutRepeater.model[activeLayoutIndex].special,
specialMode: activeTileIndex
};
} else if (!root.centerInTile) {
return {
x: clientArea.x + popupDropHintX,
y: clientArea.y + popupDropHintY,
width: popupDropHintWidth,
height: popupDropHintHeight,
defaultLayouts: !showAll,
layoutIndex: activeLayoutIndex,
tileIndex: activeTileIndex
};
}
}
return null;
}
function getActiveVirtualDesktopIndex() {
return activeVirtualDesktopIndex;
}
function resetVirtualDesktopOverride() {
virtualDesktopVisibilityOverride = false;
}
function toggleShowAll() {
reset();
if (root.config.virtualDesktopVisibility == 1 && !virtualDesktopVisibilityOverride) {
virtualDesktopVisibilityOverride = true;
} else {
showAll = !showAll;
updateHintContent();
}
}
function updateAndShowPopupDropHint() {
let shouldShowPopupDropHint = false;
let special = layoutRepeater.model[activeLayoutIndex].special;
let geometry = null;
switch (special) {
case 'SPECIAL_FILL':
if (root.currentlyMovedWindow != null) {
geometry = root.getFillGeometry(root.currentlyMovedWindow, activeTileIndex == 0);
}
break;
case 'SPECIAL_SPLIT_VERTICAL':
if (root.currentlyMovedWindow != null) {
geometry = splitAndMoveSplitted(root.currentlyMovedWindow, true, activeTileIndex == 0, false);
}
break;
case 'SPECIAL_SPLIT_HORIZONTAL':
if (root.currentlyMovedWindow != null) {
geometry = splitAndMoveSplitted(root.currentlyMovedWindow, false, activeTileIndex == 0, false);
}
break;
case 'SPECIAL_NO_TITLEBAR_AND_FRAME':
case 'SPECIAL_KEEP_ABOVE':
case 'SPECIAL_KEEP_BELOW':
case 'SPECIAL_EMPTY':
case 'SPECIAL_MINIMIZE':
case 'SPECIAL_CLOSE':
case 'SPECIAL_AUTO_TILER_TOGGLE':
break;
case 'SPECIAL_AUTO_TILER_1':
case 'SPECIAL_AUTO_TILER_2':
case 'SPECIAL_AUTO_TILER_3':
if (!layoutRepeater.model[activeLayoutIndex].activeAutoTiler) {
break;
}
default:
let layout = layoutRepeater.model[activeLayoutIndex].tiles[activeTileIndex];
let hintWidth = layout.w == undefined ? layout.pxW : layout.w / 100 * clientArea.width;
let hintHeight = layout.h == undefined ? layout.pxH : layout.h / 100 * clientArea.height;
let hintX = (layout.x == undefined ? layout.pxX : layout.x / 100 * clientArea.width) - (layout.aX == undefined ? 0 : layout.aX * hintWidth / 100);
let hintY = (layout.y == undefined ? layout.pxY : layout.y / 100 * clientArea.height) - (layout.aY == undefined ? 0 : layout.aY * hintHeight / 100);
if (root.centerInTile) {
popupDropHintWidth = root.currentlyMovedWindow.width;
popupDropHintHeight = root.currentlyMovedWindow.height;
popupDropHintX = hintX + hintWidth / 2 - root.currentlyMovedWindow.width / 2;
popupDropHintY = hintY + hintHeight / 2 - root.currentlyMovedWindow.height / 2;
} else {
popupDropHintWidth = hintWidth;
popupDropHintHeight = hintHeight;
popupDropHintX = hintX;
popupDropHintY = hintY;
}
showPopupDropHint = root.config.showTargetTileHint;
hasValidPopupDropHint = true;
return; // Force return to avoid hiding popup
}
if (geometry != null) {
if (root.centerInTile) {
popupDropHintX = (geometry.x - clientArea.x) + geometry.width / 2 - root.currentlyMovedWindow.width / 2;
popupDropHintY = (geometry.y - clientArea.y) + geometry.height / 2 - root.currentlyMovedWindow.height / 2;
popupDropHintWidth = root.currentlyMovedWindow.width;
popupDropHintHeight = root.currentlyMovedWindow.height;
shouldShowPopupDropHint = true;
} else {
popupDropHintX = geometry.x - clientArea.x;
popupDropHintY = geometry.y - clientArea.y;
popupDropHintWidth = geometry.width;
popupDropHintHeight = geometry.height;
shouldShowPopupDropHint = true;
}
}
if (root.config.showTargetTileHint) {
showPopupDropHint = shouldShowPopupDropHint;
} else {
showPopupDropHint = false;
}
hasValidPopupDropHint = shouldShowPopupDropHint;
}
function updateHintContent() {
if (activeVirtualDesktopIndex >= 0) {
hasValidPopupDropHint = false;
showPopupDropHint = false;
if (root.virtualDesktops[activeVirtualDesktopIndex].isAdd) {
switch (config.virtualDesktopDropAction) {
case 0:
if (root.moveToVirtualDesktopOnDrop) {
// hint = '<b>Drop</b> - Switch to a new virtual desktop, and move window';
hint = '<b>Drop</b> - Move window to a new virtual desktop, and switch to it';
} else {
// hint = '<b>Drop</b> - Add new virtual desktop, and move window';
// hint = '<b>Drop</b> - Move window to a new virtual desktop without switching';
hint = '<b>Drop</b> - Move window to a new virtual desktop then go back to ' + root.virtualDesktopAtMoveStart.name;
}
break;
case 1:
if (root.moveToVirtualDesktopOnDrop) {
// hint = '<b>Drop</b> - Switch to a new virtual desktop, and maximize window';
hint = '<b>Drop</b> - Maximize window on a new virtual desktop, and switch to it';
} else {
// hint = '<b>Drop</b> - Add new virtual desktop, and maximize window';
// hint = '<b>Drop</b> - Maximize window on a new virtual desktop without switching';
hint = '<b>Drop</b> - Maximize window on a new virtual desktop then go back to ' + root.virtualDesktopAtMoveStart.name;
}
break;
}
if (root.config.hintMoveOnDrop) {
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
}
} else {
let virtualDesktopName = root.virtualDesktops[activeVirtualDesktopIndex].desktop.name;
let virtualDesktopHoverChanged = activeVirtualDesktopIndex != root.virtualDesktopIndexAtMoveStart;
switch (config.virtualDesktopDropAction) {
case 0:
if (!virtualDesktopHoverChanged) {
hint = '<b>Drop</b> - Cancel move';
} else if (root.moveToVirtualDesktopOnDrop) {
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window, and switch to ' + virtualDesktopName;
hint = '<b>Drop</b> - Move window to ' + virtualDesktopName + ', and switch to it';
} else {
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window to ' + virtualDesktopName;
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Move window to ' + virtualDesktopName + ' without switching';
hint = '<b>Drop</b> - Move window to ' + virtualDesktopName + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
}
break;
case 1:
if (!virtualDesktopHoverChanged) {
hint = '<b>Drop</b> - Maximize window on current virtual desktop';
} else if (root.moveToVirtualDesktopOnDrop) {
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on, and switch to ' + virtualDesktopName;
hint = '<b>Drop</b> - Maximize window on ' + virtualDesktopName + ', and switch to it';
} else {
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on ' + virtualDesktopName;
// hint = '<b>Hover</b> - Switch to ' + virtualDesktopName + '<br><b>Drop</b> - Maximize window on ' + virtualDesktopName + ' without switching';
hint = '<b>Drop</b> - Maximize window on ' + virtualDesktopName + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
}
break;
}
if (virtualDesktopHoverChanged && root.config.hintMoveOnDrop) {
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
}
if (root.currentVirtualDesktopIndex != activeVirtualDesktopIndex) {
hint += '<br><b>Hover</b> - Switch to ' + virtualDesktopName;
}
}
} else if (!virtualDesktopVisibilityOverride && root.config.virtualDesktopVisibility == 1) {
hint = "Show tiler (<b>" + root.config.shortcutShowAllSpan + "</b>)";
hasValidPopupDropHint = false;
showPopupDropHint = false;
} else if (activeLayoutIndex >= 0 && activeTileIndex >= 0) {
updateAndShowPopupDropHint();
popupDropHintIsCenterInTile = root.centerInTile;
let special = layoutRepeater.model[activeLayoutIndex].special;
let tile = layoutRepeater.model[activeLayoutIndex].tiles[activeTileIndex];
if (root.centerInTile && hasValidPopupDropHint) {
hint = '<b>Center in tile</b> - will not resize the window' + (root.config.hintCenterInTile ? '<br>Toggle with <b>' + root.config.shortcutCenterInTile + '</b>' : '');
} else if (tile.hint) {
switch (special) {
case 'SPECIAL_KEEP_ABOVE':
hint = tile.hint + '<br>Currently <b>' + (root.currentlyMovedWindow.keepAbove ? 'Enabled' : 'Disabled') + '</b>';
break;
case 'SPECIAL_KEEP_BELOW':
hint = tile.hint + '<br>Currently <b>' + (root.currentlyMovedWindow.keepBelow ? 'Enabled' : 'Disabled') + '</b>';
break;
case 'SPECIAL_FILL':
hint = hasValidPopupDropHint ? tile.hint : '<font color="orange">⚠</font> No free space available';
break;
case 'SPECIAL_SPLIT_HORIZONTAL':
case 'SPECIAL_SPLIT_VERTICAL':
hint = hasValidPopupDropHint ? tile.hint : '<font color="orange">⚠</font> No window available for splitting';
break;
case 'SPECIAL_AUTO_TILER_TOGGLE':
hint = root.currentlyMovedWindow.mt_auto == undefined ? '<b>Enable</b> auto-tiling for this window' : '<b>Disable</b> auto-tiling for this window';
break;
default:
hint = tile.hint;
break;
}
} else if (layoutRepeater.model[activeLayoutIndex].activeAutoTiler == true && tile.t != '*') {
hint = 'Auto-tile in this tile<br>Cycle auto-tiled windows with Ctrl+Alt+Left or Right';
} else if (root.virtualDesktopChangedSinceMoveStart) {
if (root.moveToVirtualDesktopOnTile) {
hint = 'Tile window on current virtual dekstop';
} else {
hint = 'Tile window on ' + Workspace.currentDesktop.name + ' then go back to ' + root.virtualDesktopAtMoveStart.name;
}
if (root.config.hintMoveOnDrop) {
hint += ' (<b>' + root.config.shortcutMoveOnDrop + '</b>)';
}
} else if ((root.config.showSizeHint || root.config.showPositionHint) && !special) {
hint = '';
if (root.config.showPositionHint) {
if (root.config.showPositionHintInPixels) {
hint += 'X: <b>' + Math.round(popupDropHintX) + '</b> Y: <b>' + Math.round(popupDropHintY) + '</b>';
} else {
hint += 'X: <b>' + Math.round(100 * popupDropHintX / clientArea.width) + '</b>% Y: <b>' + Math.round(100 * popupDropHintY / clientArea.height) + '</b>%';
}
}
if (root.config.showSizeHint) {
if (hint.length > 0) {
hint += '<br>';
}
if (root.config.showSizeHintInPixels) {
hint += 'W: <b>' + Math.round(popupDropHintWidth) + '</b> H: <b>' + Math.round(popupDropHintHeight) + '</b>';
} else {
hint += 'W: <b>' + Math.round(100 * popupDropHintWidth / clientArea.width) + '</b>% H: <b>' + Math.round(100 * popupDropHintHeight / clientArea.height) + '</b>%';
}
}
} else {
hint = null;
}
} else {
hasValidPopupDropHint = false;
showPopupDropHint = false;
hint = null;
}
if (hint == null) {
let defaultHint = "";
let hasShortcutHint = false;
if (root.config.showHintHint) {
defaultHint += (defaultHint.length > 0 ? " " : "") + "Configure tiler visibility and these hints in settings.<br>";
}
if (root.config.hintShowAllSpan) {
defaultHint += (hasShortcutHint ? " - " : "") + (showAll ? "Show default (<b>" + root.config.shortcutShowAllSpan + "</b>)" : "Show all (<b>" + root.config.shortcutShowAllSpan + "</b>)");
hasShortcutHint = true;
}
if (root.config.hintVisibility) {
defaultHint += (hasShortcutHint ? " - " : "") + "Visibility (<b>" + root.config.shortcutVisibility + "</b>)";
hasShortcutHint = true;
}
if (root.config.hintChangeMode) {
defaultHint += (hasShortcutHint ? " - " : "") + "Mode (<b>" + root.config.shortcutChangeMode + "</b>)";
hasShortcutHint = true;
}
if (root.config.hintInputType) {
defaultHint += (hasShortcutHint ? " - " : "") + "Input type (<b>" + root.config.shortcutInputType + "</b>)";
hasShortcutHint = true;
}
if (root.config.hintCenterInTile) {
defaultHint += (hasShortcutHint ? " - " : "") + "Center in tile (<b>" + root.config.shortcutCenterInTile + "</b>)";
hasShortcutHint = true;
}
if (root.config.hintToggleTilingSuggestions) {
defaultHint += (hasShortcutHint ? " - " : "") + "Suggestions: <b>" + (settings.showTilingSuggestions ? "Enabled": "Disabled") + "</b> (<b>" + root.config.shortcutToggleTilingSuggestions + "</b>)";
hasShortcutHint = true;
}
if (defaultHint.length > 0) {
hint = defaultHint;
}
}
if (root.useAutoTilerPreview) {
if (root.validAutoTilerPreview) {
hint = 'Valid auto tile configuration - good job! :)';
} else {
hint = '<font color="orange">⚠</font> <b>WARNING</b> <font color="orange">⚠</font> INVALID AUTO TILE CONFIGURATION';
}
}
}
function updateRevealed(forceUpdate = false) {
var updatedRevealed;
if (revealBox == null) {
updatedRevealed = true;
} else {
let x = root.getCursorPosition().x;
let y = root.getCursorPosition().y;
updatedRevealed = revealBox.left <= x && revealBox.right >= x && revealBox.top <= y && revealBox.bottom >= y;
}
if (forceUpdate || updatedRevealed != revealed) {
revealed = updatedRevealed;
root.updateWindowVisibility();
}
}
Item {
id: mainItem
width: popupTiler.width
height: popupTiler.height
visible: revealed
SequentialAnimation {
id: showPopupTilerAnimation
running: false
NumberAnimation {
target: popupTiler;
property: "opacity";
from: 0;
to: 0;
duration: 32;
}
NumberAnimation {
target: popupTiler;
property: "opacity";
from: 1;
to: 1;
duration: 1;
}
onFinished: {
root.updateWindowVisibility();
}
}
Colors {
id: colors
}
Rectangle {
id: popupDropHint
anchors.left: parent.left
anchors.leftMargin: popupDropHintX
anchors.top: parent.top
anchors.topMargin: popupDropHintY
width: popupDropHintWidth
height: popupDropHintHeight
border.color: colors.tileBorderColor
border.width: 2
color: "transparent"
radius: 12
visible: showPopupDropHint
Rectangle {
anchors.fill: parent
color: colors.hintBackgroundColor
radius: 12
}
}
Rectangle {
id: layouts
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
height: layoutGrid.implicitHeight + layoutGrid.rowSpacing * 2
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
border.color: colors.borderColor
border.width: 1
radius: 8
visible: virtualDesktopVisibilityOverride || root.config.virtualDesktopVisibility != 1
anchors.left: parent.left
anchors.leftMargin: positionX
anchors.top: parent.top
anchors.topMargin: positionY
GridLayout {
id: layoutGrid
columns: showAll ? root.config.gridAllColumns : root.config.gridColumns
columnSpacing: root.config.gridSpacing
rowSpacing: root.config.gridSpacing
anchors.fill: parent
anchors.margins: root.config.gridSpacing
uniformCellWidths: true
uniformCellHeights: true
Repeater {
id: layoutRepeater
model: showAll ? root.popupGridAllLayouts : root.popupGridLayouts
Rectangle {
id: tiles
width: root.config.gridWidth
height: root.config.gridHeight
color: "transparent"
border.color: modelData.activeAutoTiler ? colors.tileBorderColor : colors.borderColor
border.width: 1
radius: 8
clip: modelData.clip == true
property bool layoutActive: activeLayoutIndex == index
Repeater {
id: tileRepeater
model: modelData.tiles
Item {
id: tile
property bool tileActive: activeTileIndex == index
property bool tileDisabled: modelData.d ? true : false
width: (modelData.w == undefined ? modelData.pxW / clientArea.width : modelData.w / 100) * (tiles.width - borderOffset * 2)
height: (modelData.h == undefined ? modelData.pxH / clientArea.height : modelData.h / 100) * (tiles.height - borderOffset * 2)
x: (modelData.x == undefined ? modelData.pxX / clientArea.width : modelData.x / 100) * (tiles.width - borderOffset * 2) + borderOffset - (modelData.aX == undefined ? 0 : modelData.aX * width / 100)
y: (modelData.y == undefined ? modelData.pxY / clientArea.height : modelData.y / 100) * (tiles.height - borderOffset * 2) + borderOffset - (modelData.aY == undefined ? 0 : modelData.aY * height / 100)
Rectangle {
anchors.fill: parent
anchors.margins: tilePadding
border.color: colors.tileBorderColor
border.width: 1
// color: "#152030"
color: "transparent"
radius: 6
opacity: tileDisabled ? 0.3 : 1
Rectangle {
anchors.fill: parent
color: layoutActive && tileActive ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
radius: 6
}
Text {
anchors.centerIn: parent
color: colors.textColor
textFormat: Text.StyledText
// ⸰ ·
text: root.centerInTile && layoutActive && tileActive && hasValidPopupDropHint ? "⸰" : (modelData.t && modelData.t.length > 0 ? modelData.t : "")
font.pixelSize: 14
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
visible: root.centerInTile && layoutActive && tileActive && hasValidPopupDropHint ? true : (modelData.t ? modelData.t : false)
}
}
}
}
}
}
}
}
// Rectangle {
// id: autoTilerScrollLeft
// width: 34 + layoutGrid.columnSpacing * 2
// height: 34 + layoutGrid.columnSpacing * 2
// color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
// border.color: colors.borderColor
// border.width: 1
// radius: 8
// visible: layouts.visible
// anchors.verticalCenter: layouts.verticalCenter
// anchors.right: layouts.left
// anchors.rightMargin: 2
// Text {
// anchors.centerIn: parent
// color: colors.textColor
// textFormat: Text.StyledText
// text: "◀"
// font.pixelSize: 14
// font.family: "Noto Sans"
// horizontalAlignment: Text.AlignHCenter
// }
// }
// Rectangle {
// id: autoTilerScrollRight
// width: 34 + layoutGrid.columnSpacing * 2
// height: 34 + layoutGrid.columnSpacing * 2
// color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
// border.color: colors.borderColor
// border.width: 1
// radius: 8
// visible: layouts.visible
// anchors.verticalCenter: layouts.verticalCenter
// anchors.left: layouts.right
// anchors.leftMargin: 2
// Text {
// anchors.centerIn: parent
// color: colors.textColor
// textFormat: Text.StyledText
// text: "▶"
// font.pixelSize: 14
// font.family: "Noto Sans"
// horizontalAlignment: Text.AlignHCenter
// }
// }
Rectangle {
id: virtualDesktop
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
height: virtualDesktopLayout.implicitHeight + layoutGrid.rowSpacing * 2
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
border.color: colors.borderColor
border.width: 1
radius: 8
visible: root.virtualDesktopVisibile
anchors.left: parent.left
anchors.leftMargin: positionX
anchors.top: layouts.visible ? layouts.bottom : parent.top
anchors.topMargin: layouts.visible ? 2 : positionY
GridLayout {
id: virtualDesktopLayout
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
rowSpacing: 1
columnSpacing: 1
columns: layoutGrid.implicitWidth / 35
Repeater {
id: virtualDesktopRepeater
model: root.virtualDesktops
Item {
id: virtualDesktop
property bool currentVirtualDesktop: root.currentVirtualDesktopIndex == index
property bool activeVirtualDesktop: activeVirtualDesktopIndex == index
width: 34
height: 34
Rectangle {
anchors.fill: parent
anchors.margins: tilePadding
border.color: colors.tileBorderColor
border.width: 1
color: "transparent"
radius: 6
Rectangle {
anchors.fill: parent
color: activeVirtualDesktop ? colors.tileBackgroundColorActive : colors.tileBackgroundColor
radius: 6
}
Text {
anchors.centerIn: parent
color: colors.textColor
textFormat: Text.StyledText
text: modelData.isAdd ? "+" : "⸰"
font.pixelSize: 14
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
visible: modelData.isAdd || currentVirtualDesktop
}
}
}
}
}
}
Rectangle {
id: popupHint
width: layoutGrid.implicitWidth + layoutGrid.columnSpacing * 2
height: popupHintText.implicitHeight + layoutGrid.rowSpacing * 2
color: root.config.gridTilerOpacity != 1 ? Qt.alpha(colors.backgroundColor, root.config.gridTilerOpacity) : colors.backgroundColor
border.color: colors.borderColor
border.width: 1
radius: 8
visible: root.config.showTextHint && hint != null
anchors.left: parent.left
anchors.leftMargin: positionX
anchors.top: virtualDesktop.visible ? virtualDesktop.bottom : layouts.bottom
anchors.topMargin: 2
Text {
id: popupHintText
width: parent.width - 4
anchors.centerIn: parent
color: colors.textColor
textFormat: Text.StyledText
text: hint != null ? hint : ""
font.pixelSize: 12
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
Rectangle {
id: popupWindowCursor
anchors.left: parent.left
anchors.leftMargin: root.getCursorPosition().x - clientArea.x - 6
anchors.top: parent.top
anchors.topMargin: root.getCursorPosition().y - clientArea.y - 6
width: 12
height: 12
border.color: colors.tileBorderColor
border.width: 2
color: colors.tileBackgroundColorActive
radius: 6
visible: !root.useMouseCursor
Rectangle {
anchors.centerIn: parent
width: 2
height: 2
color: colors.textColor
radius: 1
opacity: 0.8
}
}
Timer {
interval: 1
repeat: false
running: popupTiler.visible && !sizeEstablished
onTriggered: {
sizeEstablished = true;
updateScreen(true);
}
}
Timer {
interval: root.config.popupGridPollingRate
repeat: true
running: popupTiler.visible
onTriggered: {
let forceUpdate = lastShowAll != showAll;
if (forceUpdate) {
if (showAll) {
lastShowAll = true;
} else {
lastShowAll = false;
}
}
updateScreen(forceUpdate);
updateRevealed();
let x = root.getCursorPosition().x;
let y = root.getCursorPosition().y;
let layoutIndex = -1;
let tileIndex = -1;
let virtualDesktopIndex = -1;
if (root.config.windowVisibility == 2) {
var updatedHovered;
let layoutsPosition = layouts.mapToGlobal(Qt.point(0, 0));
let visibleHeight = (layouts.visible ? layouts.height : 0) + (virtualDesktop.visible ? virtualDesktop.height : 0) + (layouts.visible && virtualDesktop.visible ? 2 : 0)
if (layoutsPosition.x <= x && layoutsPosition.x + layouts.width >= x && layoutsPosition.y <= y && layoutsPosition.y + visibleHeight >= y) {
updatedHovered = true;
} else {
updatedHovered = false;
}
if (updatedHovered != currentlyHovered) {
currentlyHovered = updatedHovered;
root.updateWindowVisibility();
}
}
if (layouts.visible) {
for (let i = 0; i < layoutRepeater.count; i++) {
let currentLayout = layoutRepeater.itemAt(i);
let currentLayoutPosition = currentLayout.mapToGlobal(Qt.point(0, 0));
if (currentLayoutPosition.x <= x && currentLayoutPosition.x + currentLayout.width >= x && currentLayoutPosition.y <= y && currentLayoutPosition.y + currentLayout.height >= y) {
layoutIndex = i;
// if (layoutRepeater.model[layoutIndex].special) {
// tileIndex = 0;
// } else {
//for (let j = 0; j < currentLayout.children.length; j++) {
for (let j = currentLayout.children.length - 1; j >= 0; j--) {
let currentTile = currentLayout.children[j];
// if (currentTile.tileDisabled) {
// continue;
// }
let currentTilePosition = currentTile.mapToGlobal(Qt.point(0, 0));
if (currentTilePosition.x <= x && currentTilePosition.x + currentTile.width >= x && currentTilePosition.y <= y && currentTilePosition.y + currentTile.height >= y) {
tileIndex = j;
break;
}
}
// }
break;
}
}
}
if (root.virtualDesktopVisibile && layoutIndex == -1) {
for (let i = 0; i < virtualDesktopRepeater.count; i++) {
let currentVirtualDesktop = virtualDesktopRepeater.itemAt(i);
let currentVirtualDesktopPosition = currentVirtualDesktop.mapToGlobal(Qt.point(0, 0));
if (currentVirtualDesktopPosition.x <= x && currentVirtualDesktopPosition.x + currentVirtualDesktop.width >= x && currentVirtualDesktopPosition.y <= y && currentVirtualDesktopPosition.y + currentVirtualDesktop.height >= y) {
virtualDesktopIndex = i;
}
}
}
let switchVirtualDesktop = virtualDesktopIndex != -1 && !root.virtualDesktops[virtualDesktopIndex].isAdd && virtualDesktopIndex != root.currentVirtualDesktopIndex;
if (activeVirtualDesktopIndex != virtualDesktopIndex) {
activeVirtualDesktopIndex = virtualDesktopIndex;
if (switchVirtualDesktop) {
if (config.virtualDesktopHoverTime == 0) {
autoTiler.virtualDesktopAboutToChange(); // Notify to remove window from current virtual desktop auto-tiler
Workspace.currentDesktop = root.virtualDesktops[activeVirtualDesktopIndex].desktop;
} else {
activeVirtualDesktopHoverTime = Date.now();
}
}
updateHintContent();
} else if (switchVirtualDesktop && config.virtualDesktopHoverTime > 0 && Date.now() - activeVirtualDesktopHoverTime > config.virtualDesktopHoverTime) {
autoTiler.virtualDesktopAboutToChange(); // Notify to remove window from current virtual desktop auto-tiler
Workspace.currentDesktop = root.virtualDesktops[activeVirtualDesktopIndex].desktop;
updateHintContent();
}
// if (layoutIndex == -1) {
// let leftScroll = autoTilerScrollLeft.mapToGlobal(Qt.point(0, 0));
// let rightScroll = autoTilerScrollRight.mapToGlobal(Qt.point(0, 0));
// if (leftScroll.x <= x && leftScroll.x + autoTilerScrollLeft.width >= x && leftScroll.y <= y && leftScroll.y + autoTilerScrollLeft.height >= y) {
// logDev('HOVERING LEFT!!!!');
// let timeNow = Date.now();
// if (scrollLeftTime == 0) {
// scrollLeftTime = timeNow + 1000;
// } else if (timeNow >= scrollLeftTime) {
// autoTiler.modifyPrimaryIndex(-1);
// scrollLeftTime = timeNow + 1000;
// }
// } else if (rightScroll.x <= x && rightScroll.x + autoTilerScrollRight.width >= x && rightScroll.y <= y && rightScroll.y + autoTilerScrollRight.height >= y) {
// logDev('HOVERING RIGHT!!!!');
// let timeNow = Date.now();
// if (scrollLeftTime == 0) {
// scrollLeftTime = timeNow + 1000;
// } else if (timeNow >= scrollLeftTime) {
// autoTiler.modifyPrimaryIndex(-1);
// scrollLeftTime = timeNow + 1000;
// }
// } else {
// scrollLeftTime = 0;
// scrollRightTime = 0;
// }
// } else {
// scrollLeftTime = 0;
// scrollRightTime = 0;
// }
// TODO: Add support for negative values (-)
// TODO: Span more than 1 layout if x < 0 || y < 0 || w > 100 || h > 100 to support SPECIAL_EMPTY
if (layoutIndex != activeLayoutIndex || tileIndex != activeTileIndex) {
activeLayoutIndex = layoutIndex;
activeTileIndex = tileIndex;
updateHintContent();
} else if (popupDropHintIsCenterInTile != root.centerInTile && activeLayoutIndex >= 0 && activeTileIndex >= 0) {
updateHintContent();
popupDropHintIsCenterInTile = root.centerInTile;
}
}
}
}
}
@@ -0,0 +1,517 @@
import QtQuick
import org.kde.kwin
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
// Window {
PlasmaCore.Dialog {
id: windowSuggestions
property var activeScreen: null
property var currentDesktop: null
property var currentActivity: null
property bool isDefault: true
property int layoutIndex: 0
property int tileIndex: 0
property var clientArea: ({width: 1, height: 1, x: 0, y: 0})
property var tilePadding: 2
property list<var> convertedOverlay: ([])
property int skipIndex: -1
property int activeIndex: -1
property int suggestionsVisibility: 0
property bool suggestionsInsideTile: true
property bool excludeOtherScreens: true
property bool excludeOtherDesktops: true
property bool excludeOtherActivities: true
property bool excludeAutoTiled: true
property bool excludeMinimized: true
property int sortMode: 2
property int colCount: 1
property int rowCount: 1
property int cellWidth: 0
property int previewHeight: 0
property real cellRatio: 0
property int cellHeight: 0
property int cellBottomMargin: 0
property int textSize: 14
property int totalWidth: 0
property int totalHeight: 0
property int offsetX: 0
property int offsetY: 0
property int gridSpacing: 20
property list<var> validWindows: ([])
width: clientArea.width
height: clientArea.height
x: clientArea.x
y: clientArea.y
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowDoesNotAcceptFocus
// flags: Qt.Tool | Qt.BypassWindowManagerHint | Qt.FramelessWindowHint
// color: "transparent" // PlasmaCore.Dialog
visible: false
// outputOnly: true
backgroundHints: PlasmaCore.Types.NoBackground // PlasmaCore.Dialog
// type: PlasmaCore.Dialog.OnScreenDisplay
location: PlasmaCore.Types.Desktop // PlasmaCore.Dialog
function init() {
suggestionsVisibility = KWin.readConfig("suggestionsVisibility", 0);
suggestionsInsideTile = KWin.readConfig("suggestionsMode", 0) == 0;
excludeOtherScreens = !KWin.readConfig("suggestOtherScreens", false);
excludeOtherDesktops = !KWin.readConfig("suggestOtherDesktops", false);
excludeOtherActivities = !KWin.readConfig("suggestOtherActivities", false);
excludeAutoTiled = !KWin.readConfig("suggestAutoTiled", false);
excludeMinimized = !KWin.readConfig("suggestMinimized", false);
}
function updateValid(addedWindow) {
let valid = [];
for (let i = 0; i < Workspace.stackingOrder.length; i++) {
let window = Workspace.stackingOrder[i];
if (window == addedWindow) continue;
if (!root.isValidWindow(window)) continue;
if (window.fullScreen) continue;
// if (window.maximizeMode > 0) continue;
if (excludeAutoTiled && window.mt_auto) continue;
if (excludeMinimized && window.minimized) continue;
if (excludeOtherScreens && window.output != activeScreen) continue;
if (excludeOtherDesktops && window.desktops.length > 0 && !window.desktops.includes(currentDesktop)) continue;
if (excludeOtherActivities && window.activities.length > 0 && !window.activities.includes(currentActivity)) continue;
valid.push(window);
}
switch (sortMode) {
case 0: // newest focused first
valid.reverse();
break;
case 1: // oldest focused first
break;
case 2: // a-z
valid.sort((a, b) => a.caption.toLowerCase().localeCompare(b.caption.toLowerCase()));
break;
}
validWindows = valid;
}
function updateSizes() {
let count = validWindows.length;
log('Valid count: ' + count);
let usableHeight = suggestionsInsideTile ? convertedOverlay[activeIndex].height : clientArea.height - 180;
let usableWidth = suggestionsInsideTile ? convertedOverlay[activeIndex].width : clientArea.width / 2;
let wantedRatio = 16 / 9;
let ratio = usableWidth / usableHeight;
if (!suggestionsInsideTile) {
if (ratio < wantedRatio) {
usableWidth = parseInt(usableWidth);
usableHeight = parseInt(usableWidth / wantedRatio);
} else {
usableHeight = parseInt(usableHeight);
usableWidth = parseInt(usableHeight * wantedRatio);
}
}
colCount = Math.ceil(Math.sqrt(count));
rowCount = Math.ceil(count / colCount);
cellWidth = (usableWidth - gridSpacing * (colCount + 1)) / Math.max(colCount, 2);
log('CellWidth before: ' + cellWidth);
if (suggestionsInsideTile) {
if (cellWidth < 320) {
colCount = Math.min(count, Math.floor(convertedOverlay[activeIndex].width / 320));
} else {
colCount = Math.min(count, Math.floor(convertedOverlay[activeIndex].width / cellWidth));
}
cellWidth = (convertedOverlay[activeIndex].width - gridSpacing * (colCount + 1)) / Math.max(colCount, 2);
}
log('ColCount: ' + colCount + ' width: ' + cellWidth + ' gridSpacing: ' + gridSpacing + ' width: ' + convertedOverlay[activeIndex].width + ' usable: ' + usableWidth);
cellBottomMargin = Kirigami.Units.iconSizes.large / 4;
previewHeight = (usableHeight - gridSpacing * (rowCount + 1)) / Math.max(colCount, 2);
if (suggestionsInsideTile && previewHeight < 200) {
rowCount = Math.ceil(count / colCount);
previewHeight = 200;
}
cellHeight = previewHeight - cellBottomMargin - textSize;
totalWidth = suggestionsInsideTile ? convertedOverlay[activeIndex].width : cellWidth * Math.max(colCount, 2) + gridSpacing * (colCount + 1);
totalHeight = suggestionsInsideTile ? convertedOverlay[activeIndex].height : previewHeight * rowCount + gridSpacing * (rowCount + 1);
cellRatio = cellWidth / previewHeight;
log('Count: ' + count + ' rowCount: ' + rowCount + ' colCount: ' + colCount + ' width: ' + usableWidth + ' height: ' + usableHeight + ' ratio: ' + ratio + ' wanted ratio: ' + wantedRatio + ' cell width: ' + cellWidth + ' cell height: ' + cellHeight + ' totalHeight: ' + totalHeight);
}
function showSuggestions(window, screen, virtualDesktop, activity, isDefault, layoutIndex, tileIndex) {
log('screen: ' + screen.name + ' virtualDesktop: ' + virtualDesktop.id + ' activity: ' + activity + ' isDefault: ' + isDefault + ' layoutIndex: ' + layoutIndex + ' tileIndex: ' + tileIndex);
activeScreen = screen;
currentDesktop = virtualDesktop;
currentActivity = activity;
windowSuggestions.isDefault = isDefault;
windowSuggestions.layoutIndex = layoutIndex;
windowSuggestions.tileIndex = tileIndex;
clientArea = Workspace.clientArea(KWin.FullScreenArea, activeScreen, currentDesktop);
activeIndex = 0;
skipIndex = tileIndex;
convertLayoutToScreen();
updateValid(window);
if (validWindows.length > 0 && convertedOverlay.length > 0) {
updateSizes();
updateOffsets();
windowSuggestions.visible = true;
}
}
function convertLayoutToScreen() {
let layout = isDefault ? popupGridLayouts[layoutIndex].tiles : popupGridAllLayouts[layoutIndex].tiles;
log('Window suggestions layout to convert: ' + JSON.stringify(layout));
let converted = [];
for (let i = 0; i < layout.length; i++) {
if (i == skipIndex) continue;
let tile = layout[i];
let width = (tile.pxW == undefined ? tile.w / 100 * windowSuggestions.width : tile.pxW);
let height = (tile.pxH == undefined ? tile.h / 100 * windowSuggestions.height : tile.pxH);
// Temporarily add clientArea x/y since it is needed for calculating margins
let geometry = {
x: clientArea.x + ((tile.pxX == undefined ? tile.x / 100 * windowSuggestions.width : tile.pxX) - (tile.aX == undefined ? 0 : tile.aX * width / 100)),
y: clientArea.y + ((tile.pxY == undefined ? tile.y / 100 * windowSuggestions.height : tile.pxY) - (tile.aY == undefined ? 0 : tile.aY * height / 100)),
width: width,
height: height,
tileIndex: i
};
root.addMargins(geometry, true, true, true, true);
geometry.x -= clientArea.x;
geometry.y -= clientArea.y;
converted.push(geometry);
}
windowSuggestions.convertedOverlay = converted;
}
function updateOffsets() {
if (activeIndex < convertedOverlay.length) {
if (suggestionsInsideTile) {
offsetX = convertedOverlay[activeIndex].x;
offsetY = convertedOverlay[activeIndex].y;
} else {
let overlay = convertedOverlay[activeIndex];
let rightSpace = clientArea.width - overlay.x - overlay.width;
if (overlay.x < rightSpace) {
offsetX = Math.min(clientArea.width - rightSpace + 2, clientArea.width - totalWidth - 2);
} else {
offsetX = Math.max(overlay.x - totalWidth - 2, 2);
}
offsetY = overlay.y - ((totalHeight + 80 - overlay.height) / 2);
if (offsetY < 0) {
offsetY = 0;
} else if (offsetY + totalHeight + 80 > clientArea.height) {
offsetY = clientArea.height - totalHeight - 80;
}
}
}
}
function selectSuggestion(index, tileIndex) {
log('Select suggestion: ' + index + ' ' + tileIndex);
activeIndex = index;
if (suggestionsInsideTile) {
updateSizes();
}
updateOffsets();
}
function addWindowToSelected(window) {
log('Selected window caption: ' + window.caption);
if (activeIndex != -1 && validWindows.length > 0) {
let localWindows = [...validWindows];
let overlays = JSON.parse(JSON.stringify(windowSuggestions.convertedOverlay)); // Workaround for a strange bug where wrong item is fetched even if activeIndex is correct
let geometry = overlays.splice(activeIndex, 1)[0];
windowSuggestions.convertedOverlay = [...overlays];
geometry.x += clientArea.x;
geometry.y += clientArea.y;
let index = localWindows.indexOf(window);
if (index != -1) {
localWindows.splice(index, 1);
if (!window.desktops.includes(currentDesktop)) {
window.desktops = [currentDesktop];
}
if (!window.activities.includes(currentActivity)) {
window.activities = [currentActivity];
}
if (window.mt_auto) {
autoTiler.disableAutoTiling(window);
}
if (window.minimized) {
window.minimized = false;
}
if (window.maximizeMode > 0) {
window.setMaximize(false, false);
}
if (!window.mt_originalSize) {
window.mt_originalSize = {x: window.x, y: window.y, width: window.width, height: window.height};
}
root.moveAndResizeWindow(window, geometry);
Workspace.raiseWindow(window);
activeIndex = 0;
if (localWindows.length == 0 || convertedOverlay.length == 0) {
windowSuggestions.visible = false;
validWindows = [];
} else {
validWindows = localWindows;
if (suggestionsInsideTile) {
updateSizes();
}
updateOffsets();
}
}
}
}
function windowClosed(window) {
log('Closed window caption: ' + window.caption);
if (activeIndex != -1 && validWindows.length > 0) {
let localWindows = [...validWindows];
let index = localWindows.indexOf(window);
if (index != -1) {
localWindows.splice(index, 1);
if (localWindows.length == 0) {
validWindows = [];
} else {
validWindows = localWindows;
if (suggestionsInsideTile) {
updateSizes();
}
}
}
}
}
Item {
id: mainItem
width: windowSuggestions.width
height: windowSuggestions.height
TapHandler {
onTapped: windowSuggestions.visible = false;
}
Colors {
id: colors
}
Repeater {
id: tileRepeater
model: windowSuggestions.convertedOverlay
Item {
id: tile
property bool active: activeIndex == index
property int tileIndex: modelData.tileIndex
x: modelData.x
y: modelData.y
width: modelData.width
height: modelData.height
Rectangle {
anchors.fill: parent
anchors.margins: tilePadding
border.color: colors.tileBorderColor
border.width: 2
color: active ? colors.tileBackgroundColorActive : colors.tileBackgroundColorIntense
radius: 12
Text {
anchors.centerIn: parent
color: colors.overlayTextColor
textFormat: Text.StyledText
text: "<b>Select a window to tile here</b>"
font.pixelSize: 16
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
visible: active && !suggestionsInsideTile
}
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds
onTapped: selectSuggestion(index, tileIndex);
}
}
}
}
Item {
height: suggestionsInsideTile ? totalHeight : totalHeight + 80
width: totalWidth
anchors.top: parent.top
// anchors.topMargin: (clientArea.height - height) / 2
anchors.topMargin: offsetY
anchors.left: parent.left
anchors.leftMargin: offsetX
Rectangle {
id: cellWrapper
width: totalWidth
height: suggestionsInsideTile ? totalHeight : totalHeight + 80
color: suggestionsInsideTile ? "transparent" : "#BB000000"
border.width: 1
border.color: suggestionsInsideTile ? "transparent" : "#80FFFFFF"
radius: 6
GridView {
id: listView
model: validWindows
width: colCount * (windowSuggestions.cellWidth + gridSpacing)
// height: rowCount * (previewHeight + gridSpacing)
height: suggestionsInsideTile ? Math.min((previewHeight + gridSpacing) * rowCount, totalHeight - 80 - gridSpacing * 2) : totalHeight - 80 - gridSpacing * 2
cellWidth: windowSuggestions.cellWidth + gridSpacing
cellHeight: previewHeight + gridSpacing
interactive: suggestionsInsideTile ? true : false
clip: suggestionsInsideTile
anchors.top: parent.top
anchors.topMargin: suggestionsInsideTile ? (cellWrapper.height - height) / 2 : 40 + gridSpacing
anchors.left: parent.left
anchors.leftMargin: suggestionsInsideTile ? (cellWrapper.width + gridSpacing - width) / 2 : gridSpacing
delegate: Rectangle {
width: windowSuggestions.cellWidth
height: previewHeight
color: "transparent"
property real previewRatio: modelData.width / modelData.height
property int previewActualWidth: previewRatio > cellRatio ? windowSuggestions.cellWidth : windowSuggestions.cellHeight * previewRatio
property int previewActualHeight: previewRatio > cellRatio ? windowSuggestions.cellWidth / previewRatio : windowSuggestions.cellHeight
WindowThumbnail {
id: preview
client: modelData
width: previewActualWidth
height: previewActualHeight
anchors.centerIn: parent
anchors.verticalCenterOffset: -((textSize + cellBottomMargin) / 2)
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds
onTapped: addWindowToSelected(modelData);
}
Kirigami.Icon {
id: icon
width: Kirigami.Units.iconSizes.large
height: Kirigami.Units.iconSizes.large
source: modelData.icon
anchors.horizontalCenter: preview.horizontalCenter
anchors.verticalCenter: preview.bottom
anchors.verticalCenterOffset: -Math.round(height / 4)
PlasmaComponents.Label {
id: text
width: windowSuggestions.cellWidth
height: textSize
text: modelData.caption
anchors.top: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
color: "white"
background: Rectangle {
anchors.centerIn: parent
anchors.verticalCenterOffset: 3
height: parent.height + 4
width: parent.contentWidth + 6
color: "#66000000"
radius: 3
}
}
}
}
}
}
}
Rectangle {
anchors.top: parent.top
anchors.topMargin: suggestionsInsideTile ? 4 : 1
anchors.left: parent.left
anchors.leftMargin: suggestionsInsideTile ? 4 : 1
width: suggestionsInsideTile ? totalWidth - 8 : totalWidth - 2
height: 40;
color: "#EE333333"
radius: suggestionsInsideTile ? 12 : 6
Text {
anchors.centerIn: parent
color: "white"
textFormat: Text.StyledText
text: suggestionsInsideTile ? "Select a window to place here" : "Select a window to place in the highlighted tile"
font.pixelSize: 16
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
}
Text {
anchors.right: parent.right
anchors.rightMargin: 12
anchors.verticalCenter: parent.verticalCenter
color: "white"
textFormat: Text.StyledText
text: "✖"
font.pixelSize: 16
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
}
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds
onTapped: windowSuggestions.visible = false;
}
}
Rectangle {
anchors.bottom: parent.bottom
anchors.bottomMargin: suggestionsInsideTile ? 4 : 1
anchors.left: parent.left
anchors.leftMargin: suggestionsInsideTile ? 4 : 1
width: suggestionsInsideTile ? totalWidth - 8 : totalWidth - 2
height: 40;
color: "#EE333333"
radius: suggestionsInsideTile ? 12 : 6
Text {
anchors.centerIn: parent
color: "white"
textFormat: Text.StyledText
text: "Click a tile to switch to it. Click anywhere else to close suggestions. Disable suggestions (<b>" + config.shortcutToggleTilingSuggestions + "</b>)"
font.pixelSize: 16
font.family: "Noto Sans"
horizontalAlignment: Text.AlignHCenter
}
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds
onTapped: windowSuggestions.visible = false;
}
}
}
}
}
@@ -0,0 +1,20 @@
{
"KPackageStructure": "KWin/Script",
"KPlugin": {
"Authors": [
{
"Name": "rxappdev"
}
],
"Name": "Mouse Tiler",
"Description": "Tile your windows with minimal effort",
"Icon": "preferences-desktop-virtual",
"Id": "mousetiler",
"Version": "6.4.0",
"License": "GPLv3",
"Website": "https://github.com/rxappdev/MouseTiler"
},
"X-Plasma-API": "declarativescript",
"X-Plasma-MainScript": "ui/main.qml",
"X-KDE-ConfigModule": "kwin/effects/configs/kcm_kwin4_genericscripted"
}