Compare commits
10
Commits
10d763cfe5
...
7cc673430c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cc673430c | ||
|
|
08bb221699 | ||
|
|
60293abe61 | ||
|
|
a22022e969 | ||
|
|
62e19b5261 | ||
|
|
d76aaf093b | ||
|
|
4ebb4ce859 | ||
|
|
be3c938c39 | ||
|
|
f6fa2f0230 | ||
|
|
4a021d81ac |
@@ -17,12 +17,9 @@ ScrollBar {
|
|||||||
property bool shouldBeActive
|
property bool shouldBeActive
|
||||||
readonly property real travelScale: root.rawTravel > 0 ? root.effectiveTravel / root.rawTravel : 0
|
readonly property real travelScale: root.rawTravel > 0 ? root.effectiveTravel / root.rawTravel : 0
|
||||||
|
|
||||||
property bool shouldBeActive
|
|
||||||
property bool inverted
|
|
||||||
|
|
||||||
enabled: !ShellState.forActive().isDrawing
|
enabled: !ShellState.forActive().isDrawing
|
||||||
implicitWidth: size === 1 ? 0 : isHorizontal ? 0 : Tokens.padding.extraSmall * 2
|
implicitHeight: Tokens.padding.extraSmall * 2
|
||||||
implicitHeight: size === 1 ? 0 : isHorizontal ? Tokens.padding.extraSmall * 2 : 0
|
implicitWidth: Tokens.padding.extraSmall * 2
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Components
|
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import qs.Components
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
import qs.Modules.Bar.Popouts
|
import qs.Modules.Bar.Popouts
|
||||||
|
|
||||||
|
|||||||
+213
-207
@@ -1,309 +1,315 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
|
import ZShell.Internal
|
||||||
import qs.Components
|
import qs.Components
|
||||||
import qs.Modules.Bar as Bar
|
import qs.Helpers
|
||||||
import qs.Modules.Bar.Popouts as BarPopouts
|
import qs.Modules.Bar.Popouts
|
||||||
|
|
||||||
CustomMouseArea {
|
CustomMouseArea {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property ShellScreen screen
|
required property Item bar
|
||||||
required property BarPopouts.Wrapper popouts
|
|
||||||
required property ScreenState screenState
|
|
||||||
required property Panels panels
|
|
||||||
required property Bar.BarLoader bar
|
|
||||||
required property real borderThickness
|
required property real borderThickness
|
||||||
required property bool fullscreen
|
required property ScreenState screenState
|
||||||
|
required property Drawing drawing
|
||||||
|
required property EdgeGeometry geometry
|
||||||
|
required property Panels panels
|
||||||
|
required property Wrapper popouts
|
||||||
|
required property ShellScreen screen
|
||||||
|
|
||||||
property point dragStart
|
|
||||||
property bool dashboardShortcutActive
|
property bool dashboardShortcutActive
|
||||||
property bool osdShortcutActive
|
property bool osdShortcutActive
|
||||||
|
property bool singleGestureTriggered: false
|
||||||
property bool utilitiesShortcutActive
|
property bool utilitiesShortcutActive
|
||||||
|
property bool setInitialPoint: false
|
||||||
|
property point dragStart
|
||||||
|
|
||||||
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
function inBottomPanel(panel: Item, x: real, y: real): bool {
|
||||||
const panelY = root.borderThickness + panel.y;
|
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
|
||||||
return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding;
|
return y > root.height - (panelHeight + geometry.insetBottom(borderThickness)) && withinPanelWidth(panel, x, y);
|
||||||
}
|
|
||||||
|
|
||||||
function withinPanelWidth(panel: Item, x: real, y: real): bool {
|
|
||||||
const panelX = bar.implicitWidth + panel.x;
|
|
||||||
return x >= panelX - Config.border.rounding && x <= panelX + panel.width + Config.border.rounding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inLeftPanel(panel: Item, x: real, y: real): bool {
|
function inLeftPanel(panel: Item, x: real, y: real): bool {
|
||||||
return x < bar.implicitWidth + panel.x + panel.width && withinPanelHeight(panel, x, y);
|
return x < panel.x + panel.width + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inPopoutArea(x: real, y: real): bool {
|
||||||
|
const panel = panels.popoutsWrapper;
|
||||||
|
if (!geometry.horizontal)
|
||||||
|
return inLeftPanel(panel, x, y);
|
||||||
|
return withinPanelWidth(panel, x, y) && withinPanelHeight(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inRightPanel(panel: Item, x: real, y: real): bool {
|
function inRightPanel(panel: Item, x: real, y: real): bool {
|
||||||
return x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panel.x) && withinPanelHeight(panel, x, y);
|
return x > panel.x + geometry.insetLeft(borderThickness) && withinPanelHeight(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inTopPanel(panel: Item, x: real, y: real): bool {
|
function inTopPanel(panel: Item, x: real, y: real): bool {
|
||||||
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); // qmllint disable missing-property
|
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0));
|
||||||
return y < Math.max(Config.border.minThickness, Config.border.thickness + panelHeight) && withinPanelWidth(panel, x, y);
|
return y < geometry.insetTop(borderThickness) + panelHeight && withinPanelWidth(panel, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inBottomPanel(panel: Item, x: real, y: real, isCorner = false): bool {
|
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
||||||
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); // qmllint disable missing-property
|
const panelY = panel.y + geometry.insetTop(borderThickness);
|
||||||
return y > height - Math.max(Config.border.minThickness, Config.border.thickness + panelHeight) - (isCorner ? Config.border.rounding : 0) && withinPanelWidth(panel, x, y);
|
return y >= panelY && y <= panelY + panel.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWheel(event: WheelEvent): void {
|
function withinPanelWidth(panel: Item, x: real, y: real): bool {
|
||||||
if (fullscreen)
|
const panelX = panel.x + geometry.insetLeft(borderThickness);
|
||||||
return;
|
return x >= panelX && x <= panelX + panel.width;
|
||||||
if (event.x < bar.implicitWidth) {
|
|
||||||
bar.handleWheel(event.y, event.angleDelta);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: fullscreen ? Qt.NoButton : Qt.AllButtons
|
acceptedButtons: bar.fullscreen ? Qt.NoButton : Qt.AllButtons
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onPressed: event => dragStart = Qt.point(event.x, event.y)
|
onPressed: event => {
|
||||||
|
dragStart = Qt.point(event.x, event.y);
|
||||||
|
|
||||||
|
if (screenState.isDrawing) {
|
||||||
|
if (event.button & Qt.RightButton) {
|
||||||
|
drawing.content.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inLeftPanel(panels.drawing, mouseX, mouseY))
|
||||||
|
drawing.content.beginStroke(event.x, event.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressedChanged: {
|
||||||
|
if (!pressed) {
|
||||||
|
if (screenState.isDrawing) {
|
||||||
|
setInitialPoint = false;
|
||||||
|
drawing.content.endStroke();
|
||||||
|
if (!inLeftPanel(panels.drawing, mouseX, mouseY))
|
||||||
|
drawing.content.showHover(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (screenState.isDrawing) {
|
||||||
|
panels.drawing.collapse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
if (!containsMouse) {
|
if (!containsMouse) {
|
||||||
// Only hide if not activated by shortcut
|
|
||||||
if (!osdShortcutActive) {
|
if (!osdShortcutActive) {
|
||||||
screenState.osd = false;
|
screenState.osd = false;
|
||||||
root.panels.osd.hovered = false;
|
panels.osd.hovered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dashboardShortcutActive)
|
if (!popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover) {
|
||||||
screenState.dashboard = false;
|
|
||||||
|
|
||||||
if (!utilitiesShortcutActive)
|
|
||||||
screenState.utilities = false;
|
|
||||||
|
|
||||||
if (!popouts.currentName.startsWith("traymenu") || ((popouts.current as StackView)?.depth ?? 0) <= 1) {
|
|
||||||
popouts.hasCurrent = false;
|
popouts.hasCurrent = false;
|
||||||
bar.closeTray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.bar.showOnHover)
|
if (Config.bar.autoHide || bar.fullscreen)
|
||||||
bar.isHovered = false;
|
bar.isHovered = false;
|
||||||
|
|
||||||
if (Config.sidebar.showOnHover)
|
if (screenState.dashboard && Config.dashboard.showOnHover)
|
||||||
screenState.sidebar = false;
|
screenState.dashboard = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPositionChanged: event => {
|
onPositionChanged: event => {
|
||||||
if (popouts.isDetached)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const x = event.x;
|
const x = event.x;
|
||||||
const y = event.y;
|
const y = event.y;
|
||||||
const dragX = x - dragStart.x;
|
const dragX = x - dragStart.x;
|
||||||
const dragY = y - dragStart.y;
|
const dragY = y - dragStart.y;
|
||||||
|
|
||||||
if (fullscreen) {
|
if (screenState.isDrawing) {
|
||||||
root.panels.osd.hovered = inRightPanel(panels.osdWrapper, x, y);
|
if (pressed) {
|
||||||
|
drawing.content.appendPoint(x, y);
|
||||||
|
} else {
|
||||||
|
if (inLeftPanel(panels.drawing, x, y)) {
|
||||||
|
if (!(pressedButtons & Qt.LeftButton)) {
|
||||||
|
panels.drawing.expand();
|
||||||
|
drawing.content.hideHover();
|
||||||
|
Cursor.clearOverride();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Cursor.setOverride(Qt.BlankCursor);
|
||||||
|
drawing.content.showHover(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (drawing.content.hoverVisible)
|
||||||
|
drawing.content.showHover(x, y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show bar in non-exclusive mode on hover
|
if (root.bar.fullscreen && !root.bar.isHovered)
|
||||||
if (!screenState.bar && Config.bar.showOnHover && x < bar.clampedWidth)
|
unhideTimer.start();
|
||||||
bar.isHovered = true;
|
|
||||||
|
|
||||||
// Show/hide bar on drag
|
if (pressed && dragStart.y >= screen.height - Config.bar.border && dragStart.x > screen.width / 5 && dragY < -Config.launcher.dragThreshold)
|
||||||
if (pressed && dragStart.x < bar.clampedWidth) {
|
screenState.launcher = true;
|
||||||
if (dragX > Config.bar.dragThreshold)
|
|
||||||
screenState.bar = true;
|
|
||||||
else if (dragX < -Config.bar.dragThreshold)
|
|
||||||
screenState.bar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panels.sidebar.offsetScale === 1) {
|
const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboardWrapper, x, y);
|
||||||
// Show osd on hover
|
|
||||||
const showOsd = inRightPanel(panels.osdWrapper, x, y);
|
|
||||||
|
|
||||||
// Always update visibility based on hover if not in shortcut mode
|
|
||||||
if (!osdShortcutActive) {
|
|
||||||
screenState.osd = showOsd;
|
|
||||||
root.panels.osd.hovered = showOsd;
|
|
||||||
} else if (showOsd) {
|
|
||||||
// If hovering over OSD area while in shortcut mode, transition to hover control
|
|
||||||
osdShortcutActive = false;
|
|
||||||
root.panels.osd.hovered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const showSidebar = pressed && dragStart.x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panels.sidebar.x);
|
|
||||||
|
|
||||||
// Show sidebar on hover (top-right corner, bounded by notification panel height)
|
|
||||||
if (Config.sidebar.showOnHover) {
|
|
||||||
const sidebarTriggerY = Math.max(Config.sidebar.minHoverThreshold, panels.notifications.y + panels.notifications.height + borderThickness);
|
|
||||||
const showSidebarHover = x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panels.sidebar.x) && y <= sidebarTriggerY;
|
|
||||||
if (showSidebarHover && !screenState.sidebar)
|
|
||||||
screenState.sidebar = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show/hide session on drag
|
|
||||||
if (pressed && inRightPanel(panels.sessionWrapper, dragStart.x, dragStart.y) && withinPanelHeight(panels.sessionWrapper, x, y)) {
|
|
||||||
if (dragX < -Config.session.dragThreshold)
|
|
||||||
screenState.session = true;
|
|
||||||
else if (dragX > Config.session.dragThreshold)
|
|
||||||
screenState.session = false;
|
|
||||||
|
|
||||||
// Show sidebar on drag if in session area and session is nearly fully visible
|
|
||||||
if (showSidebar && panels.session.offsetScale <= 0 && dragX < -Config.sidebar.dragThreshold)
|
|
||||||
screenState.sidebar = true;
|
|
||||||
} else if (showSidebar && dragX < -Config.sidebar.dragThreshold) {
|
|
||||||
// Show sidebar on drag if not in session area
|
|
||||||
screenState.sidebar = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const outOfSidebar = x < width - panels.sidebar.width * (1 - panels.sidebar.offsetScale);
|
|
||||||
// Show osd on hover
|
|
||||||
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
|
|
||||||
|
|
||||||
// Always update visibility based on hover if not in shortcut mode
|
|
||||||
if (!osdShortcutActive) {
|
|
||||||
screenState.osd = showOsd;
|
|
||||||
root.panels.osd.hovered = showOsd;
|
|
||||||
} else if (showOsd) {
|
|
||||||
// If hovering over OSD area while in shortcut mode, transition to hover control
|
|
||||||
osdShortcutActive = false;
|
|
||||||
root.panels.osd.hovered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show/hide session on drag
|
|
||||||
if (pressed && outOfSidebar && inRightPanel(panels.sessionWrapper, dragStart.x, dragStart.y) && withinPanelHeight(panels.sessionWrapper, x, y)) {
|
|
||||||
if (dragX < -Config.session.dragThreshold)
|
|
||||||
screenState.session = true;
|
|
||||||
else if (dragX > Config.session.dragThreshold)
|
|
||||||
screenState.session = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show/hide sidebar on hover
|
|
||||||
if (Config.sidebar.showOnHover && !pressed) {
|
|
||||||
const sidebarTriggerY = Math.max(Config.sidebar.minHoverThreshold, panels.notifications.y + panels.notifications.height + borderThickness);
|
|
||||||
const showSidebarHover = x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panels.sidebar.x) && y <= sidebarTriggerY;
|
|
||||||
if (showSidebarHover && !screenState.sidebar) {
|
|
||||||
screenState.sidebar = true;
|
|
||||||
} else {
|
|
||||||
const inSidebarArea = inRightPanel(panels.sidebar, x, y) || inRightPanel(panels.sessionWrapper, x, y);
|
|
||||||
if (!inSidebarArea)
|
|
||||||
screenState.sidebar = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide sidebar on drag
|
|
||||||
if (pressed && inRightPanel(panels.sidebar, dragStart.x, 0) && dragX > Config.sidebar.dragThreshold)
|
|
||||||
screenState.sidebar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show launcher on hover, or show/hide on drag if hover is disabled
|
|
||||||
if (Config.launcher.showOnHover) {
|
|
||||||
if (!screenState.launcher && inBottomPanel(panels.launcher, x, y))
|
|
||||||
screenState.launcher = true;
|
|
||||||
} else if (pressed && inBottomPanel(panels.launcher, dragStart.x, dragStart.y) && withinPanelWidth(panels.launcher, x, y)) {
|
|
||||||
if (dragY < -Config.launcher.dragThreshold)
|
|
||||||
screenState.launcher = true;
|
|
||||||
else if (dragY > Config.launcher.dragThreshold)
|
|
||||||
screenState.launcher = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show dashboard on hover
|
|
||||||
const showDashboard = Config.dashboard.showOnHover && inTopPanel(panels.dashboard, x, y);
|
|
||||||
|
|
||||||
// Always update visibility based on hover if not in shortcut mode
|
|
||||||
if (!dashboardShortcutActive) {
|
if (!dashboardShortcutActive) {
|
||||||
screenState.dashboard = showDashboard;
|
screenState.dashboard = showDashboard;
|
||||||
} else if (showDashboard) {
|
} else if (showDashboard) {
|
||||||
// If hovering over dashboard area while in shortcut mode, transition to hover control
|
|
||||||
dashboardShortcutActive = false;
|
dashboardShortcutActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show/hide dashboard on drag (for touchscreen devices)
|
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && withinPanelWidth(panels.dashboardWrapper, x, y)) {
|
||||||
if (pressed && inTopPanel(panels.dashboard, dragStart.x, dragStart.y) && withinPanelWidth(panels.dashboard, x, y)) {
|
|
||||||
if (dragY > Config.dashboard.dragThreshold)
|
if (dragY > Config.dashboard.dragThreshold)
|
||||||
screenState.dashboard = true;
|
screenState.dashboard = true;
|
||||||
else if (dragY < -Config.dashboard.dragThreshold)
|
else if (dragY < -Config.dashboard.dragThreshold)
|
||||||
screenState.dashboard = false;
|
screenState.dashboard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show utilities on hover
|
if (pressed && geometry.insetTop(borderThickness) > dragStart.y && (Config.dashboard.showOnHover || !inTopPanel(panels.dashboardWrapper, dragStart.x, dragStart.y))) {
|
||||||
const showUtilities = inBottomPanel(panels.utilities, x, y, true);
|
if (dragY > 20) {
|
||||||
|
screenState.settings = true;
|
||||||
// Always update visibility based on hover if not in shortcut mode
|
} else if (dragY < -20) {
|
||||||
if (!utilitiesShortcutActive) {
|
screenState.settings = false;
|
||||||
screenState.utilities = showUtilities;
|
}
|
||||||
} else if (showUtilities) {
|
|
||||||
// If hovering over utilities area while in shortcut mode, transition to hover control
|
|
||||||
utilitiesShortcutActive = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show popouts on hover
|
if (pressed && dragStart.y > screen.height - geometry.insetBottom(borderThickness) && dragStart.x < screen.width / 5 && dragY < -50)
|
||||||
if (x < bar.implicitWidth) {
|
screenState.clipboard = true;
|
||||||
bar.checkPopout(y);
|
|
||||||
} else if ((!popouts.currentName.startsWith("traymenu") || ((popouts.current as StackView)?.depth ?? 0) <= 1) && !inLeftPanel(panels.popoutsWrapper, x, y)) {
|
if (pressed && !Config.dock.hoverToReveal && dragStart.y > screen.height - geometry.insetTop(borderThickness) && dragStart.x > screen.width / 5 && !screenState.launcher)
|
||||||
popouts.hasCurrent = false;
|
if (dragY < -10)
|
||||||
bar.closeTray();
|
screenState.dock = true;
|
||||||
|
|
||||||
|
if (pressed && dragStart.x > screen.width - Config.bar.border && dragStart.y < (screen.height / 2) && dragX < -Config.sidebar.dragThreshold)
|
||||||
|
screenState.sidebar = true;
|
||||||
|
|
||||||
|
if (pressed && dragStart.x >= screen.width - Config.bar.border && dragStart.y > (screen.height / 2) && dragX < -20)
|
||||||
|
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r+1', on_current_monitor = true })`);
|
||||||
|
|
||||||
|
if (pressed && dragStart.x <= Config.bar.border && dragX > 20)
|
||||||
|
Hypr.dispatch(`hl.dsp.focus({ workspace = 'r-1', on_current_monitor = true })`);
|
||||||
|
|
||||||
|
if (!screenState.bar && Config.bar.autoHide && geometry.barContains(x, y, true))
|
||||||
|
bar.isHovered = true;
|
||||||
|
|
||||||
|
if (panels.sidebar.offsetScale === 1) {
|
||||||
|
const showOsd = inRightPanel(panels.osdWrapper, x, y);
|
||||||
|
|
||||||
|
if (showOsd) {
|
||||||
|
osdShortcutActive = false;
|
||||||
|
panels.osd.hovered = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const outOfSidebar = x < width - panels.sidebar.width * (1 - panels.sidebar.offsetScale);
|
||||||
|
const showOsd = outOfSidebar && inRightPanel(panels.osdWrapper, x, y);
|
||||||
|
|
||||||
|
if (!osdShortcutActive) {
|
||||||
|
screenState.osd = showOsd;
|
||||||
|
panels.osd.hovered = showOsd;
|
||||||
|
} else if (showOsd) {
|
||||||
|
osdShortcutActive = false;
|
||||||
|
panels.osd.hovered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.dock.enable && Config.dock.hoverToReveal && !screenState.dock && !screenState.launcher && inBottomPanel(panels.dock, x, y))
|
||||||
|
screenState.dock = true;
|
||||||
|
|
||||||
|
if (geometry.barContains(x, y))
|
||||||
|
bar.checkPopout(geometry.axisPos(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: unhideTimer
|
||||||
|
|
||||||
|
interval: Config.bar.revealDelay
|
||||||
|
repeat: false
|
||||||
|
running: false
|
||||||
|
|
||||||
|
onTriggered: {
|
||||||
|
if (root.containsMouse)
|
||||||
|
root.bar.isHovered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Monitor individual visibility changes
|
|
||||||
Connections {
|
Connections {
|
||||||
function onLauncherChanged() {
|
function onDashboardChanged(): void {
|
||||||
// If launcher is hidden, clear shortcut flags for dashboard and OSD
|
if (root.screenState.dashboard) {
|
||||||
|
const inDashboardArea = root.inTopPanel(root.panels.dashboardWrapper, root.mouseX, root.mouseY);
|
||||||
|
if (!inDashboardArea) {
|
||||||
|
root.dashboardShortcutActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.screenState.launcher = false;
|
||||||
|
root.screenState.settings = false;
|
||||||
|
root.screenState.sidebar = false;
|
||||||
|
root.screenState.resources = false;
|
||||||
|
root.popouts.hasCurrent = false;
|
||||||
|
} else {
|
||||||
|
root.dashboardShortcutActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onIsDrawingChanged(): void {
|
||||||
|
if (root.screenState.isDrawing) {
|
||||||
|
Cursor.setOverride(Qt.BlankCursor);
|
||||||
|
} else {
|
||||||
|
Cursor.clearOverride();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLauncherChanged(): void {
|
||||||
if (!root.screenState.launcher) {
|
if (!root.screenState.launcher) {
|
||||||
root.dashboardShortcutActive = false;
|
root.dashboardShortcutActive = false;
|
||||||
root.osdShortcutActive = false;
|
root.osdShortcutActive = false;
|
||||||
root.utilitiesShortcutActive = false;
|
root.utilitiesShortcutActive = false;
|
||||||
|
|
||||||
// Also hide dashboard and OSD if they're not being hovered
|
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
|
||||||
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
|
|
||||||
const inOsdArea = root.inRightPanel(root.panels.osdWrapper, root.mouseX, root.mouseY);
|
|
||||||
|
|
||||||
if (!inDashboardArea) {
|
|
||||||
root.screenState.dashboard = false;
|
|
||||||
}
|
|
||||||
if (!inOsdArea) {
|
if (!inOsdArea) {
|
||||||
root.screenState.osd = false;
|
root.screenState.osd = false;
|
||||||
root.panels.osd.hovered = false;
|
root.panels.osd.hovered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function onDashboardChanged() {
|
if (root.screenState.launcher) {
|
||||||
if (root.screenState.dashboard) {
|
root.screenState.dashboard = false;
|
||||||
// Dashboard became visible, immediately check if this should be shortcut mode
|
root.screenState.dock = false;
|
||||||
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
|
root.screenState.settings = false;
|
||||||
if (!inDashboardArea) {
|
|
||||||
root.dashboardShortcutActive = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Dashboard hidden, clear shortcut flag
|
|
||||||
root.dashboardShortcutActive = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onOsdChanged() {
|
function onOsdChanged(): void {
|
||||||
if (root.screenState.osd) {
|
if (root.screenState.osd) {
|
||||||
// OSD became visible, immediately check if this should be shortcut mode
|
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
|
||||||
const inOsdArea = root.inRightPanel(root.panels.osdWrapper, root.mouseX, root.mouseY);
|
|
||||||
if (!inOsdArea) {
|
if (!inOsdArea) {
|
||||||
root.osdShortcutActive = true;
|
root.osdShortcutActive = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// OSD hidden, clear shortcut flag
|
|
||||||
root.osdShortcutActive = false;
|
root.osdShortcutActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUtilitiesChanged() {
|
function onResourcesChanged(): void {
|
||||||
if (root.screenState.utilities) {
|
if (root.screenState.resources) {
|
||||||
// Utilities became visible, immediately check if this should be shortcut mode
|
if (root.popouts.currentName.startsWith("audio") || root.popouts.currentName.startsWith("updates"))
|
||||||
const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY);
|
root.popouts.hasCurrent = false;
|
||||||
if (!inUtilitiesArea) {
|
|
||||||
root.utilitiesShortcutActive = true;
|
root.screenState.settings = false;
|
||||||
}
|
root.screenState.dashboard = false;
|
||||||
} else {
|
}
|
||||||
// Utilities hidden, clear shortcut flag
|
}
|
||||||
root.utilitiesShortcutActive = false;
|
|
||||||
|
function onSettingsChanged(): void {
|
||||||
|
if (root.screenState.settings) {
|
||||||
|
root.screenState.resources = false;
|
||||||
|
root.screenState.dashboard = false;
|
||||||
|
root.screenState.sidebar = false;
|
||||||
|
root.panels.popouts.hasCurrent = false;
|
||||||
|
root.screenState.launcher = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSidebarChanged(): void {
|
||||||
|
if (root.screenState.sidebar) {
|
||||||
|
if (root.panels.dashboardWrapper.x + root.panels.dashboardWrapper.width > root.panels.sidebar.x)
|
||||||
|
root.screenState.dashboard = false;
|
||||||
|
root.screenState.settings = false;
|
||||||
|
root.popouts.hasCurrent = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -37,12 +37,12 @@ Item {
|
|||||||
readonly property alias resources: resources
|
readonly property alias resources: resources
|
||||||
readonly property alias resourcesWrapper: resourcesWrapper
|
readonly property alias resourcesWrapper: resourcesWrapper
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
|
required property ScreenState screenState
|
||||||
readonly property alias settings: settings
|
readonly property alias settings: settings
|
||||||
readonly property alias settingsWrapper: settingsWrapper
|
readonly property alias settingsWrapper: settingsWrapper
|
||||||
readonly property alias sidebar: sidebar
|
readonly property alias sidebar: sidebar
|
||||||
readonly property alias toasts: toasts
|
readonly property alias toasts: toasts
|
||||||
readonly property alias utilities: utilities
|
readonly property alias utilities: utilities
|
||||||
required property ScreenState screenState
|
|
||||||
|
|
||||||
anchors.bottomMargin: geometry.insetBottom(borderThickness)
|
anchors.bottomMargin: geometry.insetBottom(borderThickness)
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -84,8 +84,8 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
screen: root.screen
|
screen: root.screen
|
||||||
sidebarOrSessionVisible: sidebar.visible
|
|
||||||
screenState: root.screenState
|
screenState: root.screenState
|
||||||
|
sidebarOrSessionVisible: sidebar.visible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +121,8 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
panels: root
|
panels: root
|
||||||
sidebarPanel: sidebar
|
|
||||||
screenState: root.screenState
|
screenState: root.screenState
|
||||||
|
sidebarPanel: sidebar
|
||||||
}
|
}
|
||||||
|
|
||||||
Launcher.Wrapper {
|
Launcher.Wrapper {
|
||||||
@@ -140,9 +140,8 @@ Item {
|
|||||||
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
popouts: popouts
|
|
||||||
sidebar: sidebar
|
|
||||||
screenState: root.screenState
|
screenState: root.screenState
|
||||||
|
sidebar: sidebar
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -150,8 +149,8 @@ Item {
|
|||||||
|
|
||||||
property real offsetScale: dashboard.shouldBeActive ? 0 : 1
|
property real offsetScale: dashboard.shouldBeActive ? 0 : 1
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
clip: true
|
clip: true
|
||||||
implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
|
implicitHeight: dashboard.implicitHeight * (1 - offsetScale)
|
||||||
implicitWidth: dashboard.implicitWidth
|
implicitWidth: dashboard.implicitWidth
|
||||||
|
|||||||
+1
-1
@@ -375,7 +375,7 @@ CustomWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Interactions {
|
Interactions2 {
|
||||||
id: interactions
|
id: interactions
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -13,21 +13,17 @@ import qs.Paths
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property M3Palette current: M3Palette {
|
readonly property M3Palette current: M3Palette {}
|
||||||
}
|
|
||||||
property bool currentLight
|
property bool currentLight
|
||||||
property string flavour
|
property string flavour
|
||||||
readonly property bool light: showPreview ? previewLight : currentLight
|
readonly property bool light: showPreview ? previewLight : currentLight
|
||||||
readonly property M3Palette palette: showPreview ? preview : current
|
readonly property M3Palette palette: showPreview ? preview : current
|
||||||
readonly property M3Palette preview: M3Palette {
|
readonly property M3Palette preview: M3Palette {}
|
||||||
}
|
|
||||||
property bool previewLight
|
property bool previewLight
|
||||||
property string scheme
|
property string scheme
|
||||||
property bool showPreview
|
property bool showPreview
|
||||||
readonly property M3TPalette tPalette: M3TPalette {
|
readonly property M3TPalette tPalette: M3TPalette {}
|
||||||
}
|
readonly property Transparency transparency: Transparency {}
|
||||||
readonly property Transparency transparency: Transparency {
|
|
||||||
}
|
|
||||||
readonly property alias wallLuminance: analyser.luminance
|
readonly property alias wallLuminance: analyser.luminance
|
||||||
|
|
||||||
function alterColor(c: color, a: real, layer: int): color {
|
function alterColor(c: color, a: real, layer: int): color {
|
||||||
@@ -112,8 +108,7 @@ Singleton {
|
|||||||
|
|
||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
||||||
Config.general.color.mode = mode;
|
Config.colors.mode = mode;
|
||||||
Config.save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function swapRG(c: color): color {
|
function swapRG(c: color): color {
|
||||||
|
|||||||
@@ -11,14 +11,14 @@ import qs.Services
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
|
readonly property int darkEnd: Config.colors.scheduleDarkEnd
|
||||||
readonly property int darkStart: Config.general.color.scheduleDarkStart
|
readonly property int darkStart: Config.colors.scheduleDarkStart
|
||||||
readonly property bool enabled: Config.general.color.scheduleDark && Config.general.color.schemeGeneration
|
readonly property bool enabled: Config.colors.scheduleDark && Config.colors.schemeGen
|
||||||
|
|
||||||
function applyDarkMode() {
|
function applyDarkMode() {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
|
||||||
|
|
||||||
Config.general.color.mode = "dark";
|
Config.colors.mode = "dark";
|
||||||
|
|
||||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]);
|
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]);
|
||||||
|
|
||||||
@@ -30,13 +30,13 @@ Singleton {
|
|||||||
function applyLightMode() {
|
function applyLightMode() {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "light"]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "light"]);
|
||||||
|
|
||||||
Config.general.color.mode = "light";
|
Config.colors.mode = "light";
|
||||||
|
|
||||||
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]);
|
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]);
|
||||||
|
|
||||||
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
|
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
|
||||||
|
|
||||||
if (Config.general.color.neovimColors)
|
if (Config.colors.neovimColors)
|
||||||
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
|
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool enabled: service.enabled
|
readonly property bool enabled: service.enabled
|
||||||
readonly property int end: Config.general.color.scheduleHyprsunsetEnd
|
readonly property int end: Config.display.nightlight.scheduleEnd
|
||||||
property bool manualToggle: false
|
property bool manualToggle: false
|
||||||
readonly property int start: Config.general.color.scheduleHyprsunsetStart
|
readonly property int start: Config.display.nightlight.scheduleStart
|
||||||
readonly property int temp: Config.general.color.hyprsunsetTemp
|
readonly property int temp: Config.display.nightlight.temp
|
||||||
|
|
||||||
function checkStartup(): void {
|
function checkStartup(): void {
|
||||||
if (!Config.general.color.scheduleHyprsunset)
|
if (!Config.display.nightlight.schedule)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
service.apply();
|
service.apply();
|
||||||
@@ -29,11 +29,11 @@ Singleton {
|
|||||||
NightlightManager {
|
NightlightManager {
|
||||||
id: service
|
id: service
|
||||||
|
|
||||||
activeAuto: Config.general.color.scheduleHyprsunset
|
activeAuto: Config.display.nightlight.schedule
|
||||||
endTime: root.end
|
endTime: root.end
|
||||||
startTime: root.start
|
startTime: root.start
|
||||||
temp: root.temp
|
temp: root.temp
|
||||||
fadeDuration: Config.general.color.nativeFadeDuration / 1000
|
fadeDuration: Config.display.nightlight.fadeDuration / 1000
|
||||||
useNativeNightlight: Config.general.color.useNativeNightlight
|
useNativeNightlight: Config.display.nightlight.useNative
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ Searcher {
|
|||||||
previewPath = path;
|
previewPath = path;
|
||||||
showPreview = true;
|
showPreview = true;
|
||||||
|
|
||||||
if (Config.general.color.schemeGeneration)
|
if (Config.colors.schemeGen)
|
||||||
previewColorsProc.running = true;
|
previewColorsProc.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ Searcher {
|
|||||||
WallpaperPath.currentWallpaperPath = path;
|
WallpaperPath.currentWallpaperPath = path;
|
||||||
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
|
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
|
||||||
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
|
||||||
if (Config.general.color.schemeGeneration)
|
if (Config.colors.schemeGen)
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.colors.mode}`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopPreview(): void {
|
function stopPreview(): void {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ WidgetBase {
|
|||||||
Repeater {
|
Repeater {
|
||||||
id: repeater
|
id: repeater
|
||||||
|
|
||||||
model: SystemTray.items
|
model: SystemTray.items.values.filter(i => i.status !== Status.Passive && i.hasMenu)
|
||||||
|
|
||||||
TrayItem {
|
TrayItem {
|
||||||
id: trayItem
|
id: trayItem
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import qs.Components
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property real nonAnimWidth: view.implicitWidth + clipWrapper.anchors.margins * 2
|
readonly property real nonAnimWidth: view.implicitWidth + viewWrapper.anchors.margins * 2
|
||||||
readonly property real nonAnimHeight: tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + clipWrapper.anchors.margins + clipWrapper.anchors.topMargin
|
readonly property real nonAnimHeight: tabs.implicitHeight + tabs.anchors.topMargin + view.implicitHeight + viewWrapper.anchors.margins + viewWrapper.anchors.topMargin
|
||||||
|
|
||||||
required property ScreenState screenState
|
required property ScreenState screenState
|
||||||
|
|
||||||
@@ -74,115 +74,118 @@ Item {
|
|||||||
anchors.margins: Tokens.padding.small
|
anchors.margins: Tokens.padding.small
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomClippingRect {
|
Item {
|
||||||
id: clipWrapper
|
id: viewWrapper
|
||||||
|
|
||||||
|
property int radius: Tokens.rounding.extraLarge - anchors.margins
|
||||||
|
|
||||||
anchors.top: tabs.bottom
|
anchors.top: tabs.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.topMargin: Tokens.spacing.small
|
anchors.topMargin: Tokens.spacing.small
|
||||||
anchors.margins: Tokens.padding.small
|
anchors.margins: Tokens.padding.small
|
||||||
radius: Tokens.rounding.extraLarge - anchors.margins
|
clip: true
|
||||||
|
|
||||||
Item {
|
Flickable {
|
||||||
id: viewWrapper
|
id: view
|
||||||
|
|
||||||
|
readonly property int currentIndex: root.screenState.dashboardTab
|
||||||
|
readonly property Item currentItem: {
|
||||||
|
repeater.count;
|
||||||
|
return repeater.itemAt(currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Flickable {
|
implicitWidth: currentItem?.implicitWidth ?? 0
|
||||||
id: view
|
implicitHeight: currentItem?.implicitHeight ?? 0
|
||||||
|
|
||||||
readonly property int currentIndex: root.screenState.dashboardTab
|
contentX: currentItem?.x ?? 0
|
||||||
readonly property Item currentItem: {
|
contentWidth: row.implicitWidth
|
||||||
repeater.count;
|
contentHeight: row.implicitHeight
|
||||||
return repeater.itemAt(currentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
interactive: false
|
||||||
|
|
||||||
implicitWidth: currentItem?.implicitWidth ?? 0
|
onContentXChanged: {
|
||||||
implicitHeight: currentItem?.implicitHeight ?? 0
|
if (!moving || !currentItem)
|
||||||
|
return;
|
||||||
|
|
||||||
contentX: currentItem?.x ?? 0
|
const x = contentX - currentItem.x;
|
||||||
contentWidth: row.implicitWidth
|
if (x > currentItem.implicitWidth / 2)
|
||||||
contentHeight: row.implicitHeight
|
root.screenState.dashboardTab = Math.min(root.screenState.dashboardTab + 1, tabs.count - 1);
|
||||||
|
else if (x < -currentItem.implicitWidth / 2)
|
||||||
|
root.screenState.dashboardTab = Math.max(root.screenState.dashboardTab - 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
interactive: false
|
RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
onContentXChanged: {
|
Repeater {
|
||||||
if (!moving || !currentItem)
|
id: repeater
|
||||||
return;
|
|
||||||
|
|
||||||
const x = contentX - currentItem.x;
|
model: ScriptModel {
|
||||||
if (x > currentItem.implicitWidth / 2)
|
values: root.dashboardTabs
|
||||||
root.screenState.dashboardTab = Math.min(root.screenState.dashboardTab + 1, tabs.count - 1);
|
}
|
||||||
else if (x < -currentItem.implicitWidth / 2)
|
|
||||||
root.screenState.dashboardTab = Math.max(root.screenState.dashboardTab - 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
delegate: Loader {
|
||||||
id: row
|
id: paneLoader
|
||||||
|
|
||||||
Repeater {
|
required property int index
|
||||||
id: repeater
|
required property var modelData
|
||||||
|
|
||||||
model: ScriptModel {
|
Layout.alignment: Qt.AlignTop
|
||||||
values: root.dashboardTabs
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Loader {
|
sourceComponent: modelData.component
|
||||||
id: paneLoader
|
|
||||||
|
|
||||||
required property int index
|
Component.onCompleted: active = Qt.binding(() => {
|
||||||
required property var modelData
|
if (index === view.currentIndex)
|
||||||
|
return true;
|
||||||
Layout.alignment: Qt.AlignTop
|
const vx = Math.floor(view.visibleArea.xPosition * view.contentWidth);
|
||||||
|
const vex = Math.floor(vx + view.visibleArea.widthRatio * view.contentWidth);
|
||||||
sourceComponent: modelData.component
|
return (vx >= x && vx <= x + implicitWidth) || (vex >= x && vex <= x + implicitWidth);
|
||||||
|
})
|
||||||
Component.onCompleted: active = Qt.binding(() => {
|
|
||||||
if (index === view.currentIndex)
|
|
||||||
return true;
|
|
||||||
const vx = Math.floor(view.visibleArea.xPosition * view.contentWidth);
|
|
||||||
const vex = Math.floor(vx + view.visibleArea.widthRatio * view.contentWidth);
|
|
||||||
return (vx >= x && vx <= x + implicitWidth) || (vex >= x && vex <= x + implicitWidth);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: dashComponent
|
id: dashComponent
|
||||||
|
|
||||||
Dash {
|
Dash {
|
||||||
screenState: root.screenState
|
screenState: root.screenState
|
||||||
}
|
radius: viewWrapper.radius
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: weatherComponent
|
id: weatherComponent
|
||||||
|
|
||||||
WeatherTab {}
|
WeatherTab {
|
||||||
|
radius: viewWrapper.radius
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: mediaComponent
|
id: mediaComponent
|
||||||
|
|
||||||
Media {
|
Media {
|
||||||
screenState: root.screenState
|
screenState: root.screenState
|
||||||
}
|
radius: viewWrapper.radius
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: procsComponent
|
id: procsComponent
|
||||||
|
|
||||||
ProcessesTab {}
|
ProcessesTab {
|
||||||
|
radius: viewWrapper.radius
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Behavior on contentX {
|
Behavior on contentX {
|
||||||
Anim {
|
Anim {
|
||||||
type: Anim.DefaultEffects
|
type: Anim.DefaultEffects
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ GridLayout {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool dashboardVisible: screenState.dashboard
|
readonly property bool dashboardVisible: screenState.dashboard
|
||||||
property int radius: Tokens.rounding.medium
|
required property int radius
|
||||||
required property ScreenState screenState
|
required property ScreenState screenState
|
||||||
|
|
||||||
columnSpacing: Tokens.spacing.small
|
columnSpacing: Tokens.spacing.small
|
||||||
|
|||||||
@@ -11,12 +11,18 @@ Item {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
property ScreenState screenState
|
property ScreenState screenState
|
||||||
|
required property int radius
|
||||||
|
|
||||||
implicitWidth: 1000
|
implicitWidth: 1000
|
||||||
implicitHeight: 320
|
implicitHeight: 320
|
||||||
|
|
||||||
BackgroundShapes {
|
CustomClippingRect {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
radius: root.radius
|
||||||
|
|
||||||
|
BackgroundShapes {
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import qs.Services
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property int radius
|
||||||
|
|
||||||
implicitHeight: layout.implicitHeight
|
implicitHeight: layout.implicitHeight
|
||||||
|
|
||||||
ServiceRef {
|
ServiceRef {
|
||||||
@@ -53,7 +55,7 @@ Item {
|
|||||||
property list<var> values
|
property list<var> values
|
||||||
|
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
radius: Tokens.rounding.largeIncreased
|
radius: root.radius
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
implicitHeight: mainLayout.implicitHeight + mainLayout.anchors.margins * 2
|
implicitHeight: mainLayout.implicitHeight + mainLayout.anchors.margins * 2
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import qs.Services
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property int radius
|
||||||
|
|
||||||
implicitWidth: Tokens.sizes.dashboard.processesWidth
|
implicitWidth: Tokens.sizes.dashboard.processesWidth
|
||||||
implicitHeight: Tokens.sizes.dashboard.processesHeight
|
implicitHeight: Tokens.sizes.dashboard.processesHeight
|
||||||
|
|
||||||
@@ -47,5 +49,6 @@ Item {
|
|||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
radius: root.radius
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import ZShell.Config
|
import ZShell.Config
|
||||||
@@ -9,6 +11,7 @@ import qs.Helpers
|
|||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property int radius
|
||||||
readonly property var today: Weather.forecast && Weather.forecast.length > 0 ? Weather.forecast[0] : null
|
readonly property var today: Weather.forecast && Weather.forecast.length > 0 ? Weather.forecast[0] : null
|
||||||
|
|
||||||
implicitWidth: layout.implicitWidth > 800 ? layout.implicitWidth : 840
|
implicitWidth: layout.implicitWidth > 800 ? layout.implicitWidth : 840
|
||||||
@@ -136,7 +139,7 @@ Item {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2
|
implicitHeight: forecastItemColumn.implicitHeight + Tokens.padding.medium * 2
|
||||||
|
|
||||||
radius: Tokens.rounding.large
|
radius: root.radius
|
||||||
color: Colors.tPalette.m3surfaceContainer
|
color: Colors.tPalette.m3surfaceContainer
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Item {
|
|||||||
for (let i = 0; i < count; i++)
|
for (let i = 0; i < count; i++)
|
||||||
height += (list.itemAtIndex(i) as NotifWrapper)?.nonAnimHeight ?? 0;
|
height += (list.itemAtIndex(i) as NotifWrapper)?.nonAnimHeight ?? 0;
|
||||||
|
|
||||||
if (panels.popouts.hasCurrent && (panels.popouts.currentCenter + (panels.popouts.current?.width / 2)) > panels.notifications.x || screenState.dashboard)
|
if (panels.popouts.hasCurrent && (panels.popouts.currentCenter + (panels.popouts.current?.width / 2)) > panels.notifications.x)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (screenState.osd) {
|
if (screenState.osd) {
|
||||||
@@ -47,8 +47,7 @@ Item {
|
|||||||
implicitWidth: Config.notifs.sizes.width + padding * 2
|
implicitWidth: Config.notifs.sizes.width + padding * 2
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
Anim {
|
Anim {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClippingWrapperRectangle {
|
ClippingWrapperRectangle {
|
||||||
@@ -65,8 +64,7 @@ Item {
|
|||||||
orientation: Qt.Vertical
|
orientation: Qt.Vertical
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
delegate: NotifWrapper {
|
delegate: NotifWrapper {}
|
||||||
}
|
|
||||||
displaced: Transition {
|
displaced: Transition {
|
||||||
Anim {
|
Anim {
|
||||||
property: "y"
|
property: "y"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import qs.Services
|
|||||||
DialogRowButton {
|
DialogRowButton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
property var initialSelect
|
||||||
required property var model
|
required property var model
|
||||||
property var selectedItem
|
property var selectedItem
|
||||||
|
|
||||||
|
|||||||
@@ -13,25 +13,48 @@ import qs.Services
|
|||||||
Item {
|
Item {
|
||||||
id: wrapper
|
id: wrapper
|
||||||
|
|
||||||
property int buttonRowHeight: Tokens.padding.large * 3
|
|
||||||
property bool changesMade: false
|
|
||||||
readonly property var currentScreen: screens.length > selectedScreenIndex ? screens[selectedScreenIndex] : null
|
readonly property var currentScreen: screens.length > selectedScreenIndex ? screens[selectedScreenIndex] : null
|
||||||
|
readonly property real maxZoom: 5.0
|
||||||
|
|
||||||
|
readonly property bool changesMade: {
|
||||||
|
cropRevision;
|
||||||
|
|
||||||
|
const r = cropRectLoader.item;
|
||||||
|
if (!r || !currentScreen || scaledImg.status !== Image.Ready)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const t = r.savedTarget();
|
||||||
|
|
||||||
|
return Math.abs(r.x - t.x) > 0.5 || Math.abs(r.y - t.y) > 0.5 || Math.abs(r.zoom - t.zoom) > 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
property int cropRevision: 0
|
||||||
|
property int buttonRowHeight: Tokens.padding.large * 3
|
||||||
property var screens: []
|
property var screens: []
|
||||||
property int selectedScreenIndex: 0
|
property int selectedScreenIndex: 0
|
||||||
property bool shouldBeActive: true
|
property bool shouldBeActive: true
|
||||||
|
|
||||||
|
function zoomFromSlider(t: real): real {
|
||||||
|
return 1 / (1 - t * (1 - 1 / maxZoom));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sliderFromZoom(zoom: real): real {
|
||||||
|
return (1 - 1 / zoom) / (1 - 1 / maxZoom);
|
||||||
|
}
|
||||||
|
|
||||||
function applyCrop(): void {
|
function applyCrop(): void {
|
||||||
if (!cropRectLoader.item || !currentScreen)
|
if (!cropRectLoader.item || !currentScreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const cropRect = cropRectLoader.item;
|
const cropRect = cropRectLoader.item;
|
||||||
|
|
||||||
const cropXPercent = (cropRect.x - cropRect.imageX) / scaledImg.paintedWidth;
|
const cropXPercent = (cropRect.x - cropRect.imageX) / cropRect.imageW;
|
||||||
const cropYPercent = (cropRect.y - cropRect.imageY) / scaledImg.paintedHeight;
|
const cropYPercent = (cropRect.y - cropRect.imageY) / cropRect.imageH;
|
||||||
const cropWidthPercent = cropRect.width / scaledImg.paintedWidth;
|
const cropWidthPercent = cropRect.width / cropRect.imageW;
|
||||||
const cropHeightPercent = cropRect.height / scaledImg.paintedHeight;
|
const cropHeightPercent = cropRect.height / cropRect.imageH;
|
||||||
|
|
||||||
Wallpapers.setCrop(currentScreen.name, Qt.rect(cropXPercent, cropYPercent, cropWidthPercent, cropHeightPercent), cropRect.zoom);
|
Wallpapers.setCrop(currentScreen.name, Qt.rect(cropXPercent, cropYPercent, cropWidthPercent, cropHeightPercent), cropRect.zoom);
|
||||||
|
cropRevision++;
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshScreens(): void {
|
function refreshScreens(): void {
|
||||||
@@ -79,16 +102,13 @@ Item {
|
|||||||
visible: opacity > 0
|
visible: opacity > 0
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
Anim {
|
Anim {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Behavior on scale {
|
Behavior on scale {
|
||||||
Anim {
|
Anim {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Behavior on y {
|
Behavior on y {
|
||||||
Anim {
|
Anim {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -99,34 +119,10 @@ Item {
|
|||||||
Qt.callLater(syncCropToScreen);
|
Qt.callLater(syncCropToScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton {
|
|
||||||
anchors.margins: Tokens.padding.small
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
icon: "check"
|
|
||||||
opacity: wrapper.changesMade ? 1 : 0
|
|
||||||
scale: wrapper.changesMade ? 1 : 0
|
|
||||||
z: 2
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Behavior on scale {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
wrapper.applyCrop();
|
|
||||||
wrapper.changesMade = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ButtonRow {
|
ButtonRow {
|
||||||
id: screenSelector
|
id: screenSelector
|
||||||
|
|
||||||
anchors.bottom: scaledImg.top
|
anchors.bottom: imageSlot.top
|
||||||
anchors.bottomMargin: Tokens.spacing.medium
|
anchors.bottomMargin: Tokens.spacing.medium
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Tokens.padding.extraLarge * 2
|
anchors.leftMargin: Tokens.padding.extraLarge * 2
|
||||||
@@ -149,6 +145,7 @@ Item {
|
|||||||
isRound: true
|
isRound: true
|
||||||
shapeMorph: true
|
shapeMorph: true
|
||||||
text: modelData.name
|
text: modelData.name
|
||||||
|
font: Tokens.font.body.builders.large.weight(Font.DemiBold).build()
|
||||||
|
|
||||||
onClicked: wrapper.selectScreen(index)
|
onClicked: wrapper.selectScreen(index)
|
||||||
}
|
}
|
||||||
@@ -170,24 +167,54 @@ Item {
|
|||||||
Layout.leftMargin: Tokens.padding.small
|
Layout.leftMargin: Tokens.padding.small
|
||||||
Layout.preferredHeight: Tokens.padding.medium * 3
|
Layout.preferredHeight: Tokens.padding.medium * 3
|
||||||
Layout.rightMargin: Tokens.padding.small
|
Layout.rightMargin: Tokens.padding.small
|
||||||
from: 1.0
|
|
||||||
implicitHeight: Tokens.padding.small * 3
|
implicitHeight: Tokens.padding.small * 3
|
||||||
insetIcon: "crop"
|
insetIcon: "crop"
|
||||||
to: 5.0
|
value: cropRectLoader.item ? wrapper.sliderFromZoom(cropRectLoader.item.zoom) : 0
|
||||||
value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0
|
|
||||||
|
|
||||||
onInteraction: value => {
|
onInteraction: value => {
|
||||||
wrapper.zoomClipRect(1 + (value * 4));
|
wrapper.zoomClipRect(wrapper.zoomFromSlider(value));
|
||||||
wrapper.changesMade = true;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonRow {
|
||||||
|
spacing: Tokens.spacing.medium
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
isRound: true
|
||||||
|
icon: "close"
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
shapeMorph: true
|
||||||
|
horizontalPadding: Tokens.padding.large
|
||||||
|
inactiveColor: Colors.layer(Colors.palette.m3surfaceContainerHighest, 2)
|
||||||
|
inactiveOnColor: Colors.palette.m3onSurfaceVariant
|
||||||
|
enabled: wrapper.changesMade
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
wrapper.syncCropToScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
isRound: true
|
||||||
|
icon: "check"
|
||||||
|
text: qsTr("Apply")
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
shapeMorph: true
|
||||||
|
horizontalPadding: Tokens.padding.large
|
||||||
|
inactiveColor: Colors.palette.m3secondary
|
||||||
|
inactiveOnColor: Colors.palette.m3onSecondary
|
||||||
|
enabled: wrapper.changesMade
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
wrapper.applyCrop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
Item {
|
||||||
id: scaledImg
|
id: imageSlot
|
||||||
|
|
||||||
property var displayData
|
|
||||||
property real monitorScale: 1.0
|
|
||||||
|
|
||||||
anchors.bottom: sliderLayout.top
|
anchors.bottom: sliderLayout.top
|
||||||
anchors.bottomMargin: Tokens.spacing.medium
|
anchors.bottomMargin: Tokens.spacing.medium
|
||||||
@@ -195,147 +222,238 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: wrapper.buttonRowHeight + Tokens.spacing.medium
|
anchors.topMargin: wrapper.buttonRowHeight + Tokens.spacing.medium
|
||||||
// anchors.top: screenSelector.bottom
|
|
||||||
asynchronous: true
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
retainWhileLoading: true
|
|
||||||
source: Wallpapers.current
|
|
||||||
sourceSize.height: parent.height
|
|
||||||
sourceSize.width: parent.width
|
|
||||||
|
|
||||||
onPaintedWidthChanged: {
|
CustomClippingRect {
|
||||||
if (paintedWidth > 0 && cropRectLoader.item) {
|
id: fitBox
|
||||||
if (!wrapper.screens.length)
|
|
||||||
wrapper.refreshScreens();
|
|
||||||
|
|
||||||
wrapper.syncCropToScreen();
|
readonly property real aspect: scaledImg.implicitHeight > 0 ? scaledImg.implicitWidth / scaledImg.implicitHeight : 1
|
||||||
}
|
readonly property real fitW: Math.min(imageSlot.width, imageSlot.height * aspect)
|
||||||
}
|
|
||||||
onSourceChanged: {
|
|
||||||
if (cropRectLoader.item) {
|
|
||||||
if (!wrapper.screens.length)
|
|
||||||
wrapper.refreshScreens();
|
|
||||||
|
|
||||||
wrapper.syncCropToScreen();
|
implicitHeight: Math.round(fitW / aspect)
|
||||||
}
|
implicitWidth: Math.round(fitW)
|
||||||
}
|
x: Math.round((imageSlot.width - width) / 2)
|
||||||
onStatusChanged: {
|
y: Math.round((imageSlot.height - height) / 2)
|
||||||
if (scaledImg.status == Image.Ready && cropRectLoader.item) {
|
radius: Tokens.rounding.largeIncreased
|
||||||
if (!wrapper.screens.length)
|
|
||||||
wrapper.refreshScreens();
|
|
||||||
|
|
||||||
wrapper.syncCropToScreen();
|
Loader {
|
||||||
}
|
anchors.centerIn: parent
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
opacity: scaledImg.status === Image.Ready ? 0 : 1
|
||||||
id: cropRectLoader
|
active: opacity > 0
|
||||||
|
|
||||||
active: scaledImg.status === Image.Ready
|
sourceComponent: CustomRect {
|
||||||
|
implicitWidth: loadingIndicator.implicitSize + Tokens.padding.large * 2
|
||||||
|
implicitHeight: loadingIndicator.implicitSize + Tokens.padding.large * 2
|
||||||
|
|
||||||
sourceComponent: Component {
|
color: Colors.palette.m3primaryContainer
|
||||||
CustomRect {
|
radius: Tokens.rounding.full
|
||||||
id: cropRect
|
|
||||||
|
|
||||||
property real aspectRatio: wrapper.currentScreen ? wrapper.currentScreen.width / wrapper.currentScreen.height : 1
|
LoadingIndicator {
|
||||||
readonly property real baseHeight: baseWidth / aspectRatio
|
id: loadingIndicator
|
||||||
readonly property real baseWidth: {
|
|
||||||
let fittedHeight = scaledImg.paintedHeight;
|
|
||||||
let fittedWidth = fittedHeight * aspectRatio;
|
|
||||||
|
|
||||||
if (fittedWidth > scaledImg.paintedWidth) {
|
anchors.centerIn: parent
|
||||||
fittedWidth = scaledImg.paintedWidth;
|
|
||||||
fittedHeight = fittedWidth / aspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fittedWidth;
|
containsIcon: true
|
||||||
|
implicitSize: Math.min(fitBox.width, fitBox.height) * 0.3
|
||||||
}
|
}
|
||||||
readonly property real imageX: (scaledImg.width - scaledImg.paintedWidth) / 2
|
}
|
||||||
readonly property real imageY: (scaledImg.height - scaledImg.paintedHeight) / 2
|
|
||||||
property real imgAspectRatio: scaledImg.paintedWidth / scaledImg.paintedHeight
|
|
||||||
property real zoom: 1.0
|
|
||||||
|
|
||||||
function centerInImage() {
|
Behavior on opacity {
|
||||||
x = imageX + (scaledImg.paintedWidth - width) / 2;
|
Anim {
|
||||||
y = imageY + (scaledImg.paintedHeight - height) / 2;
|
type: Anim.DefaultEffects
|
||||||
}
|
}
|
||||||
|
|
||||||
function clampToBounds() {
|
|
||||||
x = Math.max(imageX, Math.min(x, imageX + scaledImg.paintedWidth - width));
|
|
||||||
y = Math.max(imageY, Math.min(y, imageY + scaledImg.paintedHeight - height));
|
|
||||||
}
|
|
||||||
|
|
||||||
function restoreFromData() {
|
|
||||||
let data = Wallpapers.getCrop(wrapper.currentScreen.name);
|
|
||||||
|
|
||||||
if (data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001)) {
|
|
||||||
zoom = data.zoom > 0 ? data.zoom : 1.0;
|
|
||||||
x = imageX + (data.x * scaledImg.paintedWidth);
|
|
||||||
y = imageY + (data.y * scaledImg.paintedHeight);
|
|
||||||
|
|
||||||
clampToBounds();
|
|
||||||
} else {
|
|
||||||
zoom = 1.0;
|
|
||||||
centerInImage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
border.color: Colors.palette.m3primary
|
|
||||||
border.width: 2
|
|
||||||
height: baseHeight / zoom
|
|
||||||
opacity: 1
|
|
||||||
width: baseWidth / zoom
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
Anim {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
restoreFromData();
|
|
||||||
}
|
|
||||||
onHeightChanged: clampToBounds()
|
|
||||||
onWidthChanged: clampToBounds()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
Image {
|
||||||
id: mouse
|
id: scaledImg
|
||||||
|
|
||||||
function updateCrop(mouseX, mouseY) {
|
anchors.fill: parent
|
||||||
if (!cropRectLoader.item)
|
asynchronous: true
|
||||||
return;
|
fillMode: Image.Stretch
|
||||||
|
source: Wallpapers.current
|
||||||
|
sourceSize: {
|
||||||
|
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||||
|
return Qt.size(width * dpr, height * dpr);
|
||||||
|
}
|
||||||
|
retainWhileLoading: true
|
||||||
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
|
||||||
const cropRect = cropRectLoader.item;
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
let nx = mouseX - cropRect.width * 0.5;
|
type: Anim.SlowEffects
|
||||||
let ny = mouseY - cropRect.height * 0.5;
|
}
|
||||||
|
}
|
||||||
nx = Math.max(cropRect.imageX, Math.min(nx, cropRect.imageX + scaledImg.paintedWidth - cropRect.width));
|
|
||||||
ny = Math.max(cropRect.imageY, Math.min(ny, cropRect.imageY + scaledImg.paintedHeight - cropRect.height));
|
|
||||||
|
|
||||||
cropRect.x = nx;
|
|
||||||
cropRect.y = ny;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.fill: parent
|
Loader {
|
||||||
hoverEnabled: true
|
id: cropRectLoader
|
||||||
preventStealing: true
|
|
||||||
|
|
||||||
onPositionChanged: mouse => {
|
active: scaledImg.status === Image.Ready
|
||||||
if (pressed) {
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
CustomRect {
|
||||||
|
id: cropRect
|
||||||
|
|
||||||
|
property real aspectRatio: wrapper.currentScreen ? wrapper.currentScreen.width / wrapper.currentScreen.height : 1
|
||||||
|
readonly property real baseHeight: baseWidth / aspectRatio
|
||||||
|
|
||||||
|
readonly property real baseWidth: {
|
||||||
|
let fittedHeight = imageH;
|
||||||
|
let fittedWidth = fittedHeight * aspectRatio;
|
||||||
|
|
||||||
|
if (fittedWidth > imageW) {
|
||||||
|
fittedWidth = imageW;
|
||||||
|
fittedHeight = fittedWidth / aspectRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fittedWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property real imageH: Math.round(fitBox.height)
|
||||||
|
readonly property real imageW: Math.round(fitBox.width)
|
||||||
|
readonly property real imageX: 0
|
||||||
|
readonly property real imageY: 0
|
||||||
|
property real imgAspectRatio: imageH > 0 ? imageW / imageH : 1
|
||||||
|
property real zoom: 1.0
|
||||||
|
|
||||||
|
function centerInImage() {
|
||||||
|
x = Math.round(imageX + (imageW - width) / 2);
|
||||||
|
y = Math.round(imageY + (imageH - height) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampToBounds() {
|
||||||
|
x = Math.max(imageX, Math.min(x, imageX + imageW - width));
|
||||||
|
y = Math.max(imageY, Math.min(y, imageY + imageH - height));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Where the rect should be according to saved data (same rules as a restore).
|
||||||
|
function savedTarget() {
|
||||||
|
const data = Wallpapers.getCrop(wrapper.currentScreen.name);
|
||||||
|
const hasCrop = data && (Math.abs(data.x) > 0.001 || Math.abs(data.y) > 0.001 || Math.abs(data.width - 1.0) > 0.001 || Math.abs(data.height - 1.0) > 0.001);
|
||||||
|
|
||||||
|
const z = hasCrop && data.zoom > 0 ? data.zoom : 1.0;
|
||||||
|
const w = Math.round(baseWidth / z);
|
||||||
|
const h = Math.round(baseHeight / z);
|
||||||
|
|
||||||
|
let tx = hasCrop ? Math.round(imageX + data.x * imageW) : Math.round(imageX + (imageW - w) / 2);
|
||||||
|
let ty = hasCrop ? Math.round(imageY + data.y * imageH) : Math.round(imageY + (imageH - h) / 2);
|
||||||
|
|
||||||
|
tx = Math.max(imageX, Math.min(tx, imageX + imageW - w));
|
||||||
|
ty = Math.max(imageY, Math.min(ty, imageY + imageH - h));
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: tx,
|
||||||
|
y: ty,
|
||||||
|
zoom: z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreFromData() {
|
||||||
|
const t = savedTarget();
|
||||||
|
zoom = t.zoom;
|
||||||
|
x = t.x;
|
||||||
|
y = t.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
height: Math.round(baseHeight / zoom)
|
||||||
|
width: Math.round(baseWidth / zoom)
|
||||||
|
color: zoomSlider.dragging || mouse.pressed ? Qt.alpha(Colors.palette.m3tertiary, 0.3) : "transparent"
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
CAnim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
restoreFromData();
|
||||||
|
}
|
||||||
|
onHeightChanged: clampToBounds()
|
||||||
|
onWidthChanged: clampToBounds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderEffect {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
readonly property real dpr: (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1
|
||||||
|
|
||||||
|
function snap(v: real): real {
|
||||||
|
return Math.round(v * dpr) / dpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
property color borderColor: Colors.palette.m3tertiary
|
||||||
|
property vector4d cropBox: cropRectLoader.item ? Qt.vector4d(snap(cropRectLoader.item.x), snap(cropRectLoader.item.y), snap(cropRectLoader.item.width), snap(cropRectLoader.item.height)) : Qt.vector4d(0, 0, 0, 0)
|
||||||
|
property real borderWidth: 2
|
||||||
|
property real cornerRadius: fitBox.radius
|
||||||
|
property vector2d itemSize: Qt.vector2d(width, height)
|
||||||
|
property real pixelScale: dpr
|
||||||
|
|
||||||
|
fragmentShader: Qt.resolvedUrl(`${Quickshell.shellDir}/assets/shaders/crop_sdf.frag.qsb`)
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouse
|
||||||
|
|
||||||
|
property real grabX: 0
|
||||||
|
property real grabY: 0
|
||||||
|
|
||||||
|
function insideCropRect(mx, my): bool {
|
||||||
|
const r = cropRectLoader.item;
|
||||||
|
if (!r)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return mx >= r.x && mx <= r.x + r.width && my >= r.y && my <= r.y + r.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
function beginGrab(mx, my): void {
|
||||||
|
const r = cropRectLoader.item;
|
||||||
|
if (!r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const inside = insideCropRect(mx, my);
|
||||||
|
|
||||||
|
if (inside) {
|
||||||
|
grabX = mx - r.x;
|
||||||
|
grabY = my - r.y;
|
||||||
|
} else {
|
||||||
|
grabX = r.width * 0.5;
|
||||||
|
grabY = r.height * 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCrop(mx, my): void {
|
||||||
|
if (!cropRectLoader.item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const cropRect = cropRectLoader.item;
|
||||||
|
|
||||||
|
let nx = mx - grabX;
|
||||||
|
let ny = my - grabY;
|
||||||
|
|
||||||
|
nx = Math.max(cropRect.imageX, Math.min(nx, cropRect.imageX + cropRect.imageW - cropRect.width));
|
||||||
|
ny = Math.max(cropRect.imageY, Math.min(ny, cropRect.imageY + cropRect.imageH - cropRect.height));
|
||||||
|
|
||||||
|
cropRect.x = nx;
|
||||||
|
cropRect.y = ny;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: true
|
||||||
|
|
||||||
|
cursorShape: pressed ? Qt.ClosedHandCursor : insideCropRect(mouseX, mouseY) ? Qt.OpenHandCursor : Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (pressed) {
|
||||||
|
updateCrop(mouse.x, mouse.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onPressed: mouse => {
|
||||||
|
beginGrab(mouse.x, mouse.y);
|
||||||
updateCrop(mouse.x, mouse.y);
|
updateCrop(mouse.x, mouse.y);
|
||||||
wrapper.changesMade = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPressed: mouse => {
|
|
||||||
updateCrop(mouse.x, mouse.y);
|
|
||||||
wrapper.changesMade = true;
|
|
||||||
}
|
|
||||||
onReleased: {
|
|
||||||
wrapper.changesMade = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -43,17 +43,17 @@ Item {
|
|||||||
|
|
||||||
Component.onCompleted: root.loadPage(root.sState.currentPageIdx)
|
Component.onCompleted: root.loadPage(root.sState.currentPageIdx)
|
||||||
|
|
||||||
CustomRect {
|
// CustomRect {
|
||||||
anchors.fill: parent
|
// anchors.fill: parent
|
||||||
color: Qt.alpha(Colors.palette.m3shadow, 0.3)
|
// color: Qt.alpha(Colors.palette.m3shadow, 0.3)
|
||||||
opacity: root.sState.dimmed ? 1 : 0
|
// opacity: root.sState.dimmed ? 1 : 0
|
||||||
visible: opacity > 0
|
// visible: opacity > 0
|
||||||
z: 0
|
// z: 0
|
||||||
|
//
|
||||||
Behavior on opacity {
|
// Behavior on opacity {
|
||||||
Anim {}
|
// Anim {}
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|||||||
@@ -202,12 +202,12 @@ PageBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ToggleRow {
|
ToggleRow {
|
||||||
checked: Config.general.color.smart
|
checked: Config.colors.smart
|
||||||
settingAnchor: "services-smart-color-scheme"
|
settingAnchor: "services-smart-color-scheme"
|
||||||
subtext: qsTr("Derive theme mode from the wallpaper")
|
subtext: qsTr("Derive theme mode from the wallpaper")
|
||||||
text: qsTr("Smart color scheme")
|
text: qsTr("Smart color scheme")
|
||||||
|
|
||||||
onToggled: Config.general.color.smart = checked
|
onToggled: Config.colors.smart = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectRow {
|
SelectRow {
|
||||||
|
|||||||
@@ -73,15 +73,15 @@ PageBase {
|
|||||||
ToggleRow {
|
ToggleRow {
|
||||||
text: qsTr("Dynamic colors")
|
text: qsTr("Dynamic colors")
|
||||||
first: true
|
first: true
|
||||||
subtext: qsTr("Automatic color scheme based on wallpaper is %1").arg(Config.general.color.schemeGeneration ? "enabled" : "disabled")
|
subtext: qsTr("Automatic color scheme based on wallpaper is %1").arg(Config.colors.schemeGen ? "enabled" : "disabled")
|
||||||
checked: Config.general.color.schemeGeneration
|
checked: Config.colors.schemeGen
|
||||||
settingAnchor: "colors-fonts-dynamic-colors"
|
settingAnchor: "colors-fonts-dynamic-colors"
|
||||||
|
|
||||||
onToggled: {
|
onToggled: {
|
||||||
Config.general.color.schemeGeneration = checked;
|
Config.colors.schemeGen = checked;
|
||||||
|
|
||||||
if (checked)
|
if (checked)
|
||||||
Colors.setMode(Config.general.color.mode);
|
Colors.setMode(Config.colors.mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ PageBase {
|
|||||||
settingAnchor: "colors-fonts-preset-scheme"
|
settingAnchor: "colors-fonts-preset-scheme"
|
||||||
model: root.schemes
|
model: root.schemes
|
||||||
acceptLabel: qsTr("Confirm")
|
acceptLabel: qsTr("Confirm")
|
||||||
enabled: !Config.general.color.schemeGeneration
|
enabled: !Config.colors.schemeGen
|
||||||
header: qsTr("Select scheme")
|
header: qsTr("Select scheme")
|
||||||
rowButton.activeItem: root.schemes.find(s => {
|
rowButton.activeItem: root.schemes.find(s => {
|
||||||
var regex = new RegExp(Config.colors.presets.name, "i");
|
var regex = new RegExp(Config.colors.presets.name, "i");
|
||||||
@@ -157,7 +157,7 @@ PageBase {
|
|||||||
}
|
}
|
||||||
// qmlformat on
|
// qmlformat on
|
||||||
acceptLabel: qsTr("Confirm")
|
acceptLabel: qsTr("Confirm")
|
||||||
enabled: !Config.general.color.schemeGeneration && model.length > 1
|
enabled: !Config.colors.schemeGen && model.length > 1
|
||||||
header: qsTr("Select variant")
|
header: qsTr("Select variant")
|
||||||
rowButton.activeItem: {
|
rowButton.activeItem: {
|
||||||
const v = Config.colors.presets.variant ?? "";
|
const v = Config.colors.presets.variant ?? "";
|
||||||
@@ -210,7 +210,7 @@ PageBase {
|
|||||||
}
|
}
|
||||||
// qmlformat on
|
// qmlformat on
|
||||||
acceptLabel: qsTr("Confirm")
|
acceptLabel: qsTr("Confirm")
|
||||||
enabled: !Config.general.color.schemeGeneration && model.length > 1
|
enabled: !Config.colors.schemeGen && model.length > 1
|
||||||
header: qsTr("Select accent")
|
header: qsTr("Select accent")
|
||||||
rowButton.activeItem: {
|
rowButton.activeItem: {
|
||||||
const a = Config.colors.presets.accent ?? "";
|
const a = Config.colors.presets.accent ?? "";
|
||||||
|
|||||||
@@ -96,20 +96,21 @@ PageBase {
|
|||||||
TimeDialogSelect {
|
TimeDialogSelect {
|
||||||
readonly property string endTime: {
|
readonly property string endTime: {
|
||||||
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
d.setMinutes(Config.general.color.scheduleDarkEnd);
|
d.setMinutes(Config.colors.scheduleDarkEnd);
|
||||||
return Qt.formatTime(d, "hh:mm AP");
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
}
|
}
|
||||||
readonly property string startTime: {
|
readonly property string startTime: {
|
||||||
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
d.setMinutes(Config.general.color.scheduleDarkStart);
|
d.setMinutes(Config.colors.scheduleDarkStart);
|
||||||
return Qt.formatTime(d, "hh:mm AP");
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
}
|
}
|
||||||
|
|
||||||
rowButton.checked: Config.general.color.scheduleDark
|
rowButton.checked: Config.colors.scheduleDark
|
||||||
rowButton.onToggled: Config.general.color.scheduleDark = rowButton.checked
|
rowButton.onToggled: Config.colors.scheduleDark = rowButton.checked
|
||||||
start: Config.general.color.scheduleDarkStart
|
start: Config.colors.scheduleDarkStart
|
||||||
end: Config.general.color.scheduleDarkEnd
|
end: Config.colors.scheduleDarkEnd
|
||||||
first: true
|
first: true
|
||||||
|
last: true
|
||||||
settingAnchor: "style-schedule-dark-mode"
|
settingAnchor: "style-schedule-dark-mode"
|
||||||
acceptLabel: qsTr("Apply")
|
acceptLabel: qsTr("Apply")
|
||||||
rootParent: root.flickable
|
rootParent: root.flickable
|
||||||
@@ -122,8 +123,8 @@ PageBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
Config.general.color.scheduleDarkStart = startCurrent;
|
Config.colors.scheduleDarkStart = startCurrent;
|
||||||
Config.general.color.scheduleDarkEnd = endCurrent;
|
Config.colors.scheduleDarkEnd = endCurrent;
|
||||||
ModeScheduler.checkStartup();
|
ModeScheduler.checkStartup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,27 +132,26 @@ PageBase {
|
|||||||
TimeDialogSelect {
|
TimeDialogSelect {
|
||||||
readonly property string endTime: {
|
readonly property string endTime: {
|
||||||
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
d.setMinutes(Config.general.color.scheduleHyprsunsetEnd);
|
d.setMinutes(Config.display.nightlight.scheduleEnd);
|
||||||
return Qt.formatTime(d, "hh:mm AP");
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
}
|
}
|
||||||
readonly property string startTime: {
|
readonly property string startTime: {
|
||||||
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
var d = new Date(0, 0, 0, 0, 0, 0, 0);
|
||||||
d.setMinutes(Config.general.color.scheduleHyprsunsetStart);
|
d.setMinutes(Config.display.nightlight.scheduleStart);
|
||||||
return Qt.formatTime(d, "hh:mm AP");
|
return Qt.formatTime(d, "hh:mm AP");
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
rowButton.checked: Config.display.nightlight.schedule
|
||||||
rowButton.checked: Config.general.color.scheduleHyprsunset
|
rowButton.onToggled: Config.display.nightlight.schedule = rowButton.checked
|
||||||
rowButton.onToggled: Config.general.color.scheduleHyprsunset = rowButton.checked
|
start: Config.display.nightlight.scheduleStart
|
||||||
start: Config.general.color.scheduleHyprsunsetStart
|
end: Config.display.nightlight.scheduleEnd
|
||||||
end: Config.general.color.scheduleHyprsunsetEnd
|
first: true
|
||||||
last: true
|
settingAnchor: "style-schedule-nightlight"
|
||||||
settingAnchor: "style-schedule-hyprsunset"
|
|
||||||
acceptLabel: qsTr("Apply")
|
acceptLabel: qsTr("Apply")
|
||||||
rootParent: root.flickable
|
rootParent: root.flickable
|
||||||
header: qsTr("Select time")
|
header: qsTr("Select time")
|
||||||
subtext: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
|
subtext: qsTr("Nightlight will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
|
||||||
label: qsTr("Schedule hyprsunset")
|
label: qsTr("Schedule nightlight")
|
||||||
|
|
||||||
onOpenChanged: {
|
onOpenChanged: {
|
||||||
root.sState.dimmed = open;
|
root.sState.dimmed = open;
|
||||||
@@ -163,5 +163,46 @@ PageBase {
|
|||||||
Nightlight.checkStartup();
|
Nightlight.checkStartup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
|
||||||
|
checked: Config.display.nightlight.useNative
|
||||||
|
settingAnchor: "display-nightlight-useNative"
|
||||||
|
text: qsTr("Use native")
|
||||||
|
subtext: qsTr("Use native shader nightlight for more features")
|
||||||
|
|
||||||
|
onToggled: Config.display.nightlight.useNative = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
|
||||||
|
from: 2000
|
||||||
|
settingAnchor: "display-nightlight-temp"
|
||||||
|
stepSize: 100
|
||||||
|
subtext: qsTr("How warm/orange the screen will be. Lower is warmer (Kelvin)")
|
||||||
|
text: qsTr("Temperature")
|
||||||
|
to: 6500
|
||||||
|
value: Config.display.nightlight.temp
|
||||||
|
|
||||||
|
onMoved: v => Config.display.nightlight.temp = v
|
||||||
|
}
|
||||||
|
|
||||||
|
SpinRow {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
settingAnchor: "display-nightlight-fade-duration"
|
||||||
|
enabled: Config.display.nightlight.useNative
|
||||||
|
last: true
|
||||||
|
stepSize: 1
|
||||||
|
subtext: qsTr("How long it takes for the gradual nightlight to finish (s)")
|
||||||
|
text: qsTr("Fade duration")
|
||||||
|
to: 60 * 5
|
||||||
|
value: Config.display.nightlight.fadeDuration / 1000
|
||||||
|
|
||||||
|
onMoved: v => Config.display.nightlight.fadeDuration = v * 1000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ qml_module(ZShell-config
|
|||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
ZShell.Settings
|
ZShell.Settings
|
||||||
SOURCES
|
SOURCES
|
||||||
common.hpp common.cpp
|
confignode.hpp confignode.cpp
|
||||||
rootnodes.hpp rootnodes.cpp
|
configobject.hpp configobject.cpp
|
||||||
|
configlist.hpp configlist.cpp
|
||||||
|
config.hpp config.cpp
|
||||||
migration.hpp migration.cpp
|
migration.hpp migration.cpp
|
||||||
anim.hpp anim.cpp
|
anim.hpp anim.cpp
|
||||||
fontbuilder.hpp fontbuilder.cpp
|
fontbuilder.hpp fontbuilder.cpp
|
||||||
@@ -17,6 +19,7 @@ qml_module(ZShell-config
|
|||||||
clipboard.hpp
|
clipboard.hpp
|
||||||
colors.hpp
|
colors.hpp
|
||||||
dashboard.hpp
|
dashboard.hpp
|
||||||
|
display.hpp
|
||||||
dock.hpp
|
dock.hpp
|
||||||
enums.hpp
|
enums.hpp
|
||||||
general.hpp
|
general.hpp
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#include "migration.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
namespace ZShell::config {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// A stored value is "missing" if the path does not resolve to an entry.
|
||||||
|
// Note: default-constructed QJsonValue is Null, not Undefined.
|
||||||
|
bool isMissing(const QJsonValue& v) {
|
||||||
|
return v.isUndefined() || v.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonValue valueAt(const QJsonObject& obj, const QStringList& path) {
|
||||||
|
QJsonObject cur = obj;
|
||||||
|
|
||||||
|
for (int i = 0; i < path.size() - 1; ++i) {
|
||||||
|
if (!cur.value(path.at(i)).isObject()) return QJsonValue::Undefined;
|
||||||
|
cur = cur.value(path.at(i)).toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString key = path.last();
|
||||||
|
if (!cur.contains(key)) return QJsonValue::Undefined;
|
||||||
|
return cur.value(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject placeAt(QJsonObject obj, QStringList path, const QJsonValue& value) {
|
||||||
|
const QString head = path.takeFirst();
|
||||||
|
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
obj[head] = value;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject child = obj.value(head).isObject() ? obj.value(head).toObject()
|
||||||
|
: QJsonObject();
|
||||||
|
obj[head] = placeAt(child, path, value);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes `path` from `obj`. Returns true if a value was removed.
|
||||||
|
// Parent objects left empty are removed as well.
|
||||||
|
bool removeAt(QJsonObject& obj, const QStringList& path) {
|
||||||
|
const QString head = path.first();
|
||||||
|
|
||||||
|
if (path.size() == 1) {
|
||||||
|
if (!obj.contains(head)) return false;
|
||||||
|
obj.remove(head);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj.value(head).isObject()) return false;
|
||||||
|
|
||||||
|
QJsonObject child = obj.value(head).toObject();
|
||||||
|
const bool removed = removeAt(child, path.mid(1));
|
||||||
|
|
||||||
|
if (child.isEmpty())
|
||||||
|
obj.remove(head);
|
||||||
|
else
|
||||||
|
obj[head] = child;
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const QList<ConfigMigrationRule>& ConfigMigrations::rules() {
|
||||||
|
static const QList<ConfigMigrationRule> s_rules = {
|
||||||
|
migrate(
|
||||||
|
"general.color.scheduleHyprsunset", "display.nightlight.schedule"),
|
||||||
|
migrate(
|
||||||
|
"general.color.scheduleHyprsunsetStart",
|
||||||
|
"display.nightlight.scheduleStart"),
|
||||||
|
migrate(
|
||||||
|
"general.color.scheduleHyprsunsetEnd",
|
||||||
|
"display.nightlight.scheduleEnd"),
|
||||||
|
migrate("general.color.scheduleDark", "colors.scheduleDark"),
|
||||||
|
migrate("general.color.scheduleDarkStart", "colors.scheduleDarkStart"),
|
||||||
|
migrate("general.color.scheduleDarkEnd", "colors.scheduleDarkEnd"),
|
||||||
|
migrate("general.color.schemeGeneration", "colors.schemeGen"),
|
||||||
|
migrate(
|
||||||
|
"general.color.useNativeNightlight",
|
||||||
|
"display.nightlight.useNative"),
|
||||||
|
migrate(
|
||||||
|
"general.color.nativeFadeDuration",
|
||||||
|
"display.nightlight.fadeDuration"),
|
||||||
|
migrate("general.color.hyprsunsetTemp", "display.nightlight.temp"),
|
||||||
|
migrate("general.color.neovimColors", "colors.neovimColors"),
|
||||||
|
migrate("general.color.mode", "colors.mode"),
|
||||||
|
migrate("general.color.smart", "colors.smart"),
|
||||||
|
};
|
||||||
|
return s_rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject ConfigMigrations::apply(const QJsonObject& json) {
|
||||||
|
QJsonObject obj = json;
|
||||||
|
|
||||||
|
for (const auto& rule : rules()) {
|
||||||
|
const QStringList from =
|
||||||
|
rule.from.split(QLatin1Char('.'), Qt::SkipEmptyParts);
|
||||||
|
const QStringList to =
|
||||||
|
rule.to.split(QLatin1Char('.'), Qt::SkipEmptyParts);
|
||||||
|
|
||||||
|
if (from.isEmpty() || to.isEmpty()) continue;
|
||||||
|
|
||||||
|
const QJsonValue oldValue = valueAt(obj, from);
|
||||||
|
if (isMissing(oldValue)) continue;
|
||||||
|
|
||||||
|
const bool targetExists = !isMissing(valueAt(obj, to));
|
||||||
|
if (!targetExists) obj = placeAt(obj, to, oldValue);
|
||||||
|
|
||||||
|
if (removeAt(obj, from)) {
|
||||||
|
qInfo() << "Config migration:" << rule.from << "->" << rule.to
|
||||||
|
<< (targetExists ? "(target already set, old value dropped)"
|
||||||
|
: "(value moved)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ZShell::config
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace ZShell::config {
|
||||||
|
|
||||||
|
// A single migration rule: move the value stored at the dotted `from` path
|
||||||
|
// to the dotted `to` path, then delete the old key (and any parent objects
|
||||||
|
// left empty).
|
||||||
|
//
|
||||||
|
// Rules are applied to the raw JSON file on every load, before the schema
|
||||||
|
// loads it. They are idempotent: once the old key is gone the rule never
|
||||||
|
// fires again, so no version stamping is needed. Old rules can stay in the
|
||||||
|
// table forever.
|
||||||
|
//
|
||||||
|
// WARNING: the target path must exist in the schema (i.e. a ConfigObject
|
||||||
|
// property somewhere in the tree). If it does not, the migrated value is
|
||||||
|
// loaded as an unknown key and silently dropped on the next save.
|
||||||
|
struct ConfigMigrationRule {
|
||||||
|
QString from;
|
||||||
|
QString to;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper for writing rules: migrate("general.color.foo", "display.bar.foo")
|
||||||
|
inline ConfigMigrationRule migrate(const QString& from, const QString& to) {
|
||||||
|
return {from, to};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigMigrations {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static const QList<ConfigMigrationRule>& rules();
|
||||||
|
|
||||||
|
// Applies all rules to `json`, returning the migrated object.
|
||||||
|
[[nodiscard]] static QJsonObject apply(const QJsonObject& json);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZShell::config
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <qcursor.h>
|
#include <qcursor.h>
|
||||||
#include <qguiapplication.h>
|
#include <qguiapplication.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
#include <qobject.h>
|
#include <qobject.h>
|
||||||
#include <qqmlintegration.h>
|
#include <qqmlintegration.h>
|
||||||
|
|
||||||
@@ -14,23 +16,25 @@ class Cursor : public QObject {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Q_INVOKABLE void setOverride(Qt::CursorShape shape) {
|
Q_INVOKABLE void setOverride(Qt::CursorShape shape) {
|
||||||
if (m_override)
|
if (m_shape == shape) return;
|
||||||
|
|
||||||
|
if (m_shape)
|
||||||
QGuiApplication::changeOverrideCursor(QCursor(shape));
|
QGuiApplication::changeOverrideCursor(QCursor(shape));
|
||||||
else {
|
else {
|
||||||
QGuiApplication::setOverrideCursor(QCursor(shape));
|
QGuiApplication::setOverrideCursor(QCursor(shape));
|
||||||
m_override = true;
|
|
||||||
}
|
}
|
||||||
|
m_shape = shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE void clearOverride() {
|
Q_INVOKABLE void clearOverride() {
|
||||||
if (!m_override) return;
|
if (!m_shape) return;
|
||||||
|
|
||||||
QGuiApplication::restoreOverrideCursor();
|
QGuiApplication::restoreOverrideCursor();
|
||||||
m_override = false;
|
m_shape.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_override = false;
|
std::optional<Qt::CursorShape> m_shape;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZShell::internal
|
} // namespace ZShell::internal
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ void Memory::tick() {
|
|||||||
QStringLiteral("MemTotal: *(\\d+)"));
|
QStringLiteral("MemTotal: *(\\d+)"));
|
||||||
static const QRegularExpression reAvail(
|
static const QRegularExpression reAvail(
|
||||||
QStringLiteral("MemAvailable: *(\\d+)"));
|
QStringLiteral("MemAvailable: *(\\d+)"));
|
||||||
static const QRegularExpression reCached(QStringLiteral(
|
static const QRegularExpression reCached(QStringLiteral("Cached: *(\\d+)"));
|
||||||
"Cached: *(\\d+)"));
|
|
||||||
const QString text = QString::fromLatin1(data);
|
const QString text = QString::fromLatin1(data);
|
||||||
|
|
||||||
const auto totalMatch = reTotal.match(text);
|
const auto totalMatch = reTotal.match(text);
|
||||||
@@ -78,14 +77,14 @@ void Memory::tick() {
|
|||||||
const auto pgin = rePgin.match(vtext);
|
const auto pgin = rePgin.match(vtext);
|
||||||
const auto pgout = rePgout.match(vtext);
|
const auto pgout = rePgout.match(vtext);
|
||||||
if (pgin.hasMatch()) {
|
if (pgin.hasMatch()) {
|
||||||
readKib = static_cast<quint64>(static_cast<double>(
|
readKib = static_cast<quint64>(
|
||||||
pgin.captured(1).toULongLong()) *
|
static_cast<double>(pgin.captured(1).toULongLong()) *
|
||||||
pageKib);
|
pageKib);
|
||||||
}
|
}
|
||||||
if (pgout.hasMatch()) {
|
if (pgout.hasMatch()) {
|
||||||
writeKib = static_cast<quint64>(static_cast<double>(
|
writeKib = static_cast<quint64>(
|
||||||
pgout.captured(1).toULongLong()) *
|
static_cast<double>(pgout.captured(1).toULongLong()) *
|
||||||
pageKib);
|
pageKib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ namespace ZShell::services {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr const char* NL_EVENT = "zshell-nightlight";
|
constexpr const char* NL_EVENT = "zshell-nightlight";
|
||||||
constexpr int NEUTRAL_KELVIN = 6500;
|
|
||||||
constexpr int RECONNECT_MS = 2000;
|
constexpr int RECONNECT_MS = 2000;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -404,7 +403,6 @@ void NightlightManager::handleEventLine(const QByteArray& line) {
|
|||||||
|
|
||||||
if (line.left(sep) != NL_EVENT) return;
|
if (line.left(sep) != NL_EVENT) return;
|
||||||
|
|
||||||
// data = enabled,animating,last,current
|
|
||||||
const auto fields = line.mid(sep + 2).split(',');
|
const auto fields = line.mid(sep + 2).split(',');
|
||||||
if (fields.size() < 4) return;
|
if (fields.size() < 4) return;
|
||||||
|
|
||||||
|
|||||||
@@ -793,8 +793,7 @@ void ProcessModel::scanChunk(
|
|||||||
nowTicks > prevTicks ? nowTicks - prevTicks : 0;
|
nowTicks > prevTicks ? nowTicks - prevTicks : 0;
|
||||||
entry.cpuPercent =
|
entry.cpuPercent =
|
||||||
(static_cast<double>(deltaTicks) /
|
(static_cast<double>(deltaTicks) /
|
||||||
(ctx.deltaSecs *
|
(ctx.deltaSecs * static_cast<double>(ctx.clockTicksPerSec))) *
|
||||||
static_cast<double>(ctx.clockTicksPerSec))) *
|
|
||||||
100.0;
|
100.0;
|
||||||
} else {
|
} else {
|
||||||
entry.cpuPercent = 0.0;
|
entry.cpuPercent = 0.0;
|
||||||
@@ -839,7 +838,8 @@ ProcessModel::ScanResult ProcessModel::scanProcesses(
|
|||||||
// syscall-bound (open/read/close per file per process) and serializes
|
// syscall-bound (open/read/close per file per process) and serializes
|
||||||
// badly on large systems. Keep one pool thread free for this function,
|
// badly on large systems. Keep one pool thread free for this function,
|
||||||
// which itself runs inside the global pool.
|
// which itself runs inside the global pool.
|
||||||
int nThreads = qMin(16, QThreadPool::globalInstance()->maxThreadCount() - 1);
|
int nThreads =
|
||||||
|
qMin(16, QThreadPool::globalInstance()->maxThreadCount() - 1);
|
||||||
if (pids.size() < 128 || nThreads < 2) {
|
if (pids.size() < 128 || nThreads < 2) {
|
||||||
nThreads = 1;
|
nThreads = 1;
|
||||||
}
|
}
|
||||||
@@ -860,8 +860,8 @@ ProcessModel::ScanResult ProcessModel::scanProcesses(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
chunks[t] = pids.mid(a, b - a);
|
chunks[t] = pids.mid(a, b - a);
|
||||||
futures.append(QtConcurrent::run(
|
futures.append(
|
||||||
[&ctx, &chunks, &outs, &uidParts, t]() {
|
QtConcurrent::run([&ctx, &chunks, &outs, &uidParts, t]() {
|
||||||
scanChunk(ctx, chunks[t], outs[t], uidParts[t]);
|
scanChunk(ctx, chunks[t], outs[t], uidParts[t]);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -880,8 +880,9 @@ ProcessModel::ScanResult ProcessModel::scanProcesses(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(
|
std::sort(
|
||||||
fresh.begin(), fresh.end(), [](const ProcessEntry& a,
|
fresh.begin(),
|
||||||
const ProcessEntry& b) {
|
fresh.end(),
|
||||||
|
[](const ProcessEntry& a, const ProcessEntry& b) {
|
||||||
return a.pid < b.pid;
|
return a.pid < b.pid;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1012,8 +1013,8 @@ void ProcessModel::applyView() {
|
|||||||
const FuzzyText prep = fuzzyPrepare(src.command);
|
const FuzzyText prep = fuzzyPrepare(src.command);
|
||||||
fe.commandChars = std::move(prep.chars);
|
fe.commandChars = std::move(prep.chars);
|
||||||
fe.commandClasses = std::move(prep.classes);
|
fe.commandClasses = std::move(prep.classes);
|
||||||
fe.hasCommandLine =
|
fe.hasCommandLine = !src.commandLine.isEmpty() &&
|
||||||
!src.commandLine.isEmpty() && src.commandLine != src.command;
|
src.commandLine != src.command;
|
||||||
if (fe.hasCommandLine) {
|
if (fe.hasCommandLine) {
|
||||||
const FuzzyText prepCl = fuzzyPrepare(src.commandLine);
|
const FuzzyText prepCl = fuzzyPrepare(src.commandLine);
|
||||||
fe.commandLineChars = std::move(prepCl.chars);
|
fe.commandLineChars = std::move(prepCl.chars);
|
||||||
|
|||||||
+5
-9
@@ -13,21 +13,17 @@ import qs.Paths
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property M3Palette current: M3Palette {
|
readonly property M3Palette current: M3Palette {}
|
||||||
}
|
|
||||||
property bool currentLight
|
property bool currentLight
|
||||||
property string flavour
|
property string flavour
|
||||||
readonly property bool light: showPreview ? previewLight : currentLight
|
readonly property bool light: showPreview ? previewLight : currentLight
|
||||||
readonly property M3Palette palette: showPreview ? preview : current
|
readonly property M3Palette palette: showPreview ? preview : current
|
||||||
readonly property M3Palette preview: M3Palette {
|
readonly property M3Palette preview: M3Palette {}
|
||||||
}
|
|
||||||
property bool previewLight
|
property bool previewLight
|
||||||
property string scheme
|
property string scheme
|
||||||
property bool showPreview
|
property bool showPreview
|
||||||
readonly property M3TPalette tPalette: M3TPalette {
|
readonly property M3TPalette tPalette: M3TPalette {}
|
||||||
}
|
readonly property Transparency transparency: Transparency {}
|
||||||
readonly property Transparency transparency: Transparency {
|
|
||||||
}
|
|
||||||
readonly property alias wallLuminance: analyser.luminance
|
readonly property alias wallLuminance: analyser.luminance
|
||||||
|
|
||||||
function alterColor(c: color, a: real, layer: int): color {
|
function alterColor(c: color, a: real, layer: int): color {
|
||||||
@@ -112,7 +108,7 @@ Singleton {
|
|||||||
|
|
||||||
function setMode(mode: string): void {
|
function setMode(mode: string): void {
|
||||||
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
|
||||||
Config.general.color.mode = mode;
|
Config.colors.mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function swapRG(c: color): color {
|
function swapRG(c: color): color {
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#version 440
|
||||||
|
layout(location = 0) in vec2 qt_TexCoord0;
|
||||||
|
layout(location = 0) out vec4 fragColor;
|
||||||
|
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform buf {
|
||||||
|
mat4 qt_Matrix;
|
||||||
|
float qt_Opacity;
|
||||||
|
vec2 itemSize;
|
||||||
|
vec4 cropBox;
|
||||||
|
vec4 borderColor;
|
||||||
|
float cornerRadius;
|
||||||
|
float borderWidth;
|
||||||
|
float pixelScale;
|
||||||
|
};
|
||||||
|
|
||||||
|
float sdRoundBox(vec2 p, vec2 halfSize, float r) {
|
||||||
|
vec2 q = abs(p) - halfSize + r;
|
||||||
|
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 sz = itemSize * pixelScale;
|
||||||
|
vec2 p = qt_TexCoord0 * sz;
|
||||||
|
vec4 box = cropBox * pixelScale;
|
||||||
|
float r = cornerRadius * pixelScale;
|
||||||
|
float bw = borderWidth * pixelScale;
|
||||||
|
|
||||||
|
float dImage = sdRoundBox(p - sz * 0.5, sz * 0.5, r);
|
||||||
|
float dCrop = sdRoundBox(p - (box.xy + box.zw * 0.5), box.zw * 0.5, 0.0);
|
||||||
|
|
||||||
|
float d = max(dImage, dCrop);
|
||||||
|
|
||||||
|
// ramp is exactly 1 physical pixel wide
|
||||||
|
float outer = clamp(0.5 - d, 0.0, 1.0);
|
||||||
|
float inner = clamp(0.5 - (d + bw), 0.0, 1.0);
|
||||||
|
float a = outer - inner;
|
||||||
|
|
||||||
|
fragColor = vec4(borderColor.rgb, 1.0) * (borderColor.a * a * qt_Opacity);
|
||||||
|
}
|
||||||
Binary file not shown.
@@ -625,8 +625,8 @@ def generate(
|
|||||||
scheme_type = config["colors"].get("schemeType", "fruit-salad")
|
scheme_type = config["colors"].get("schemeType", "fruit-salad")
|
||||||
scheme = scheme or scheme_type
|
scheme = scheme or scheme_type
|
||||||
assert isinstance(scheme, str)
|
assert isinstance(scheme, str)
|
||||||
config_mode = config["general"]["color"]["mode"]
|
config_mode = config["colors"]["mode"]
|
||||||
smart = bool(config["general"]["color"].get("smart", False))
|
smart = bool(config["colors"].get("smart", False))
|
||||||
scheme_class = get_scheme_class(scheme)
|
scheme_class = get_scheme_class(scheme)
|
||||||
|
|
||||||
p_variant = "default"
|
p_variant = "default"
|
||||||
|
|||||||
@@ -23,33 +23,27 @@ ShellRoot {
|
|||||||
|
|
||||||
settings.watchFiles: true
|
settings.watchFiles: true
|
||||||
|
|
||||||
Drawers {
|
Drawers {}
|
||||||
}
|
|
||||||
|
|
||||||
Wallpaper {
|
Wallpaper {}
|
||||||
}
|
|
||||||
|
|
||||||
AreaPicker {
|
AreaPicker {}
|
||||||
}
|
|
||||||
|
|
||||||
Lock {
|
Lock {
|
||||||
id: lock
|
id: lock
|
||||||
}
|
}
|
||||||
|
|
||||||
Shortcuts {
|
Shortcuts {}
|
||||||
}
|
|
||||||
|
|
||||||
IdleMonitors {
|
IdleMonitors {
|
||||||
lock: lock
|
lock: lock
|
||||||
}
|
}
|
||||||
|
|
||||||
Polkit {
|
Polkit {}
|
||||||
}
|
|
||||||
|
|
||||||
LazyLoader {
|
LazyLoader {
|
||||||
activeAsync: root.laptop
|
activeAsync: root.laptop
|
||||||
|
|
||||||
component: BatteryService {
|
component: BatteryService {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user