drawing
This commit is contained in:
@@ -11,7 +11,7 @@ import qs.Modules.Dashboard as Dashboard
|
||||
import qs.Modules.Osd as Osd
|
||||
import qs.Modules.Launcher as Launcher
|
||||
import qs.Modules.Resources as Resources
|
||||
|
||||
import qs.Modules.Drawing as Drawing
|
||||
import qs.Modules.Settings as Settings
|
||||
|
||||
Shape {
|
||||
@@ -31,6 +31,12 @@ Shape {
|
||||
}
|
||||
}
|
||||
|
||||
Drawing.Background {
|
||||
startX: 0
|
||||
startY: wrapper.y - rounding
|
||||
wrapper: root.panels.drawing
|
||||
}
|
||||
|
||||
Resources.Background {
|
||||
startX: 0 - rounding
|
||||
startY: 0
|
||||
|
||||
+35
-11
@@ -32,19 +32,9 @@ Variants {
|
||||
WlrLayershell.namespace: "ZShell-Bar"
|
||||
color: "transparent"
|
||||
contentItem.focus: true
|
||||
mask: visibilities.isDrawing ? null : region
|
||||
screen: scope.modelData
|
||||
|
||||
mask: Region {
|
||||
id: region
|
||||
|
||||
height: bar.screen.height - backgroundRect.implicitHeight
|
||||
intersection: Intersection.Xor
|
||||
regions: popoutRegions.instances
|
||||
width: bar.width
|
||||
x: 0
|
||||
y: Config.barConfig.autoHide && !visibilities.bar ? 4 : backgroundRect.height
|
||||
}
|
||||
|
||||
contentItem.Keys.onEscapePressed: {
|
||||
if (Config.barConfig.autoHide)
|
||||
visibilities.bar = false;
|
||||
@@ -55,6 +45,17 @@ Variants {
|
||||
visibilities.resources = false;
|
||||
}
|
||||
|
||||
Region {
|
||||
id: region
|
||||
|
||||
height: bar.screen.height - backgroundRect.implicitHeight
|
||||
intersection: Intersection.Xor
|
||||
regions: popoutRegions.instances
|
||||
width: bar.width
|
||||
x: 0
|
||||
y: Config.barConfig.autoHide && !visibilities.bar ? 4 : backgroundRect.height
|
||||
}
|
||||
|
||||
PanelWindow {
|
||||
id: exclusionZone
|
||||
|
||||
@@ -117,6 +118,7 @@ Variants {
|
||||
|
||||
property bool bar
|
||||
property bool dashboard
|
||||
property bool isDrawing
|
||||
property bool launcher
|
||||
property bool notif: NotifServer.popups.length > 0
|
||||
property bool osd
|
||||
@@ -157,20 +159,42 @@ Variants {
|
||||
}
|
||||
}
|
||||
|
||||
Drawing {
|
||||
id: drawing
|
||||
|
||||
anchors.fill: parent
|
||||
z: 2
|
||||
}
|
||||
|
||||
DrawingInput {
|
||||
id: input
|
||||
|
||||
bar: backgroundRect
|
||||
drawing: drawing
|
||||
panels: panels
|
||||
popout: panels.drawing
|
||||
visibilities: visibilities
|
||||
z: 2
|
||||
}
|
||||
|
||||
Interactions {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
bar: barLoader
|
||||
drawing: drawing
|
||||
input: input
|
||||
panels: panels
|
||||
popouts: panels.popouts
|
||||
screen: scope.modelData
|
||||
visibilities: visibilities
|
||||
z: 1
|
||||
|
||||
Panels {
|
||||
id: panels
|
||||
|
||||
bar: backgroundRect
|
||||
drawingItem: drawing
|
||||
screen: scope.modelData
|
||||
visibilities: visibilities
|
||||
}
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
import QtQuick
|
||||
|
||||
Canvas {
|
||||
id: root
|
||||
|
||||
property rect dirtyRect: Qt.rect(0, 0, 0, 0)
|
||||
property bool frameQueued: false
|
||||
property bool fullRepaintPending: true
|
||||
property point lastPoint: Qt.point(0, 0)
|
||||
property real minPointDistance: 2.0
|
||||
property color penColor: "white"
|
||||
property real penWidth: 4
|
||||
property var pendingSegments: []
|
||||
property bool strokeActive: false
|
||||
property var strokes: []
|
||||
|
||||
function appendPoint(x, y) {
|
||||
if (!strokeActive || strokes.length === 0)
|
||||
return;
|
||||
const dx = x - lastPoint.x;
|
||||
const dy = y - lastPoint.y;
|
||||
|
||||
if ((dx * dx + dy * dy) < (minPointDistance * minPointDistance))
|
||||
return;
|
||||
const x1 = lastPoint.x;
|
||||
const y1 = lastPoint.y;
|
||||
const x2 = x;
|
||||
const y2 = y;
|
||||
|
||||
strokes[strokes.length - 1].push(Qt.point(x2, y2));
|
||||
|
||||
pendingSegments.push({
|
||||
dot: false,
|
||||
x1: x1,
|
||||
y1: y1,
|
||||
x2: x2,
|
||||
y2: y2
|
||||
});
|
||||
|
||||
lastPoint = Qt.point(x2, y2);
|
||||
queueDirty(segmentDirtyRect(x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
function beginStroke(x, y) {
|
||||
const p = Qt.point(x, y);
|
||||
strokes.push([p]);
|
||||
lastPoint = p;
|
||||
strokeActive = true;
|
||||
|
||||
pendingSegments.push({
|
||||
dot: true,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
|
||||
queueDirty(pointDirtyRect(x, y));
|
||||
}
|
||||
|
||||
function clear() {
|
||||
strokes = [];
|
||||
pendingSegments = [];
|
||||
dirtyRect = Qt.rect(0, 0, 0, 0);
|
||||
fullRepaintPending = true;
|
||||
markDirty(Qt.rect(0, 0, width, height));
|
||||
}
|
||||
|
||||
function drawDot(ctx, x, y) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, penWidth / 2, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
function drawSegment(ctx, x1, y1, x2, y2) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function endStroke() {
|
||||
strokeActive = false;
|
||||
}
|
||||
|
||||
function pointDirtyRect(x, y) {
|
||||
const pad = penWidth + 2;
|
||||
return Qt.rect(x - pad, y - pad, pad * 2, pad * 2);
|
||||
}
|
||||
|
||||
function queueDirty(r) {
|
||||
dirtyRect = unionRects(dirtyRect, r);
|
||||
|
||||
if (frameQueued)
|
||||
return;
|
||||
frameQueued = true;
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
frameQueued = false;
|
||||
|
||||
if (dirtyRect.width > 0 && dirtyRect.height > 0) {
|
||||
markDirty(dirtyRect);
|
||||
dirtyRect = Qt.rect(0, 0, 0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function replayAll(ctx) {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
for (const stroke of strokes) {
|
||||
if (!stroke || stroke.length === 0)
|
||||
continue;
|
||||
if (stroke.length === 1) {
|
||||
const p = stroke[0];
|
||||
drawDot(ctx, p.x, p.y);
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(stroke[0].x, stroke[0].y);
|
||||
for (let i = 1; i < stroke.length; ++i)
|
||||
ctx.lineTo(stroke[i].x, stroke[i].y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
function requestFullRepaint() {
|
||||
fullRepaintPending = true;
|
||||
markDirty(Qt.rect(0, 0, width, height));
|
||||
}
|
||||
|
||||
function segmentDirtyRect(x1, y1, x2, y2) {
|
||||
const pad = penWidth + 2;
|
||||
const left = Math.min(x1, x2) - pad;
|
||||
const top = Math.min(y1, y2) - pad;
|
||||
const right = Math.max(x1, x2) + pad;
|
||||
const bottom = Math.max(y1, y2) + pad;
|
||||
return Qt.rect(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
function unionRects(a, b) {
|
||||
if (a.width <= 0 || a.height <= 0)
|
||||
return b;
|
||||
if (b.width <= 0 || b.height <= 0)
|
||||
return a;
|
||||
|
||||
const left = Math.min(a.x, b.x);
|
||||
const top = Math.min(a.y, b.y);
|
||||
const right = Math.max(a.x + a.width, b.x + b.width);
|
||||
const bottom = Math.max(a.y + a.height, b.y + b.height);
|
||||
|
||||
return Qt.rect(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
contextType: "2d"
|
||||
renderStrategy: Canvas.Threaded
|
||||
renderTarget: Canvas.Image
|
||||
|
||||
onHeightChanged: requestFullRepaint()
|
||||
onPaint: region => {
|
||||
const ctx = getContext("2d");
|
||||
|
||||
ctx.lineCap = "round";
|
||||
ctx.lineJoin = "round";
|
||||
ctx.lineWidth = penWidth;
|
||||
ctx.strokeStyle = penColor;
|
||||
ctx.fillStyle = penColor;
|
||||
|
||||
if (fullRepaintPending) {
|
||||
fullRepaintPending = false;
|
||||
replayAll(ctx);
|
||||
pendingSegments = [];
|
||||
return;
|
||||
}
|
||||
|
||||
for (const seg of pendingSegments) {
|
||||
if (seg.dot)
|
||||
drawDot(ctx, seg.x, seg.y);
|
||||
else
|
||||
drawSegment(ctx, seg.x1, seg.y1, seg.x2, seg.y2);
|
||||
}
|
||||
|
||||
pendingSegments = [];
|
||||
}
|
||||
onWidthChanged: requestFullRepaint()
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.Components
|
||||
|
||||
CustomMouseArea {
|
||||
id: root
|
||||
|
||||
required property var bar
|
||||
required property Drawing drawing
|
||||
required property Panels panels
|
||||
required property var popout
|
||||
required property PersistentProperties visibilities
|
||||
|
||||
function inLeftPanel(panel: Item, x: real, y: real): bool {
|
||||
return x < panel.x + panel.width && withinPanelHeight(panel, x, y);
|
||||
}
|
||||
|
||||
function withinPanelHeight(panel: Item, x: real, y: real): bool {
|
||||
const panelY = panel.y + bar.implicitHeight;
|
||||
return y >= panelY && y <= panelY + panel.height;
|
||||
}
|
||||
|
||||
anchors.fill: root.visibilities.isDrawing ? parent : undefined
|
||||
hoverEnabled: true
|
||||
visible: root.visibilities.isDrawing
|
||||
|
||||
onPositionChanged: event => {
|
||||
const x = event.x;
|
||||
const y = event.y;
|
||||
|
||||
if (event.buttons & Qt.LeftButton)
|
||||
root.drawing.appendPoint(x, y);
|
||||
|
||||
if (root.inLeftPanel(root.popout, x, y)) {
|
||||
root.z = -2;
|
||||
root.panels.drawing.expanded = true;
|
||||
}
|
||||
}
|
||||
onPressed: event => {
|
||||
const x = event.x;
|
||||
const y = event.y;
|
||||
|
||||
if (root.visibilities.isDrawing && (event.buttons & Qt.LeftButton)) {
|
||||
root.panels.drawing.expanded = false;
|
||||
root.drawing.beginStroke(x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
onReleased: {
|
||||
if (root.visibilities.isDrawing)
|
||||
root.drawing.endStroke();
|
||||
}
|
||||
}
|
||||
+14
-103
@@ -10,6 +10,8 @@ CustomMouseArea {
|
||||
required property Item bar
|
||||
property bool dashboardShortcutActive
|
||||
property point dragStart
|
||||
required property Drawing drawing
|
||||
required property DrawingInput input
|
||||
property bool osdShortcutActive
|
||||
required property Panels panels
|
||||
required property BarPopouts.Wrapper popouts
|
||||
@@ -51,20 +53,10 @@ CustomMouseArea {
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
// onPressed: event => {
|
||||
// if ( root.popouts.hasCurrent && !inTopPanel( root.popouts, event.x, event.y )) {
|
||||
// root.popouts.hasCurrent = false;
|
||||
// } else if (root.visibilities.sidebar && !inRightPanel( panels.sidebar, event.x, event.y )) {
|
||||
// root.visibilities.sidebar = false;
|
||||
// } else if (root.visibilities.dashboard && !inTopPanel( panels.dashboard, event.x, event.y )) {
|
||||
// root.visibilities.dashboard = false;
|
||||
// }
|
||||
// }
|
||||
propagateComposedEvents: true
|
||||
|
||||
onContainsMouseChanged: {
|
||||
if (!containsMouse) {
|
||||
// Only hide if not activated by shortcut
|
||||
if (!osdShortcutActive) {
|
||||
visibilities.osd = false;
|
||||
root.panels.osd.hovered = false;
|
||||
@@ -87,120 +79,42 @@ CustomMouseArea {
|
||||
const dragX = x - dragStart.x;
|
||||
const dragY = y - dragStart.y;
|
||||
|
||||
// Show bar in non-exclusive mode on hover
|
||||
if (root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, x, y)) {
|
||||
root.input.z = 2;
|
||||
root.panels.drawing.expanded = false;
|
||||
}
|
||||
|
||||
if (!visibilities.bar && Config.barConfig.autoHide && y < bar.implicitHeight + bar.anchors.topMargin)
|
||||
visibilities.bar = true;
|
||||
|
||||
if (panels.sidebar.width === 0) {
|
||||
// Show osd on hover
|
||||
const showOsd = inRightPanel(panels.osd, x, y);
|
||||
|
||||
// // Always update visibility based on hover if not in shortcut mode
|
||||
if (!osdShortcutActive) {
|
||||
visibilities.osd = showOsd;
|
||||
root.panels.osd.hovered = showOsd;
|
||||
} else if (showOsd) {
|
||||
// If hovering over OSD area while in shortcut mode, transition to hover control
|
||||
if (showOsd) {
|
||||
osdShortcutActive = false;
|
||||
root.panels.osd.hovered = true;
|
||||
}
|
||||
|
||||
// const showSidebar = pressed && dragStart.x > bar.implicitWidth + panels.sidebar.x;
|
||||
//
|
||||
// // Show/hide session on drag
|
||||
// if (pressed && inRightPanel(panels.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) {
|
||||
// if (dragX < -Config.session.dragThreshold)
|
||||
// visibilities.session = true;
|
||||
// else if (dragX > Config.session.dragThreshold)
|
||||
// visibilities.session = false;
|
||||
//
|
||||
// // Show sidebar on drag if in session area and session is nearly fully visible
|
||||
// if (showSidebar && panels.session.width >= panels.session.nonAnimWidth && dragX < -Config.sidebar.dragThreshold)
|
||||
// visibilities.sidebar = true;
|
||||
// } else if (showSidebar && dragX < -Config.sidebar.dragThreshold) {
|
||||
// // Show sidebar on drag if not in session area
|
||||
// visibilities.sidebar = true;
|
||||
// }
|
||||
} else {
|
||||
const outOfSidebar = x < width - panels.sidebar.width;
|
||||
// Show osd on hover
|
||||
const showOsd = outOfSidebar && inRightPanel(panels.osd, x, y);
|
||||
|
||||
// Always update visibility based on hover if not in shortcut mode
|
||||
if (!osdShortcutActive) {
|
||||
visibilities.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.session, dragStart.x, dragStart.y) && withinPanelHeight(panels.session, x, y)) {
|
||||
// if (dragX < -Config.session.dragThreshold)
|
||||
// visibilities.session = true;
|
||||
// else if (dragX > Config.session.dragThreshold)
|
||||
// visibilities.session = false;
|
||||
// }
|
||||
//
|
||||
// // Hide sidebar on drag
|
||||
// if (pressed && inRightPanel(panels.sidebar, dragStart.x, 0) && dragX > Config.sidebar.dragThreshold)
|
||||
// visibilities.sidebar = false;
|
||||
}
|
||||
|
||||
// Show launcher on hover, or show/hide on drag if hover is disabled
|
||||
// if (Config.launcher.showOnHover) {
|
||||
// if (!visibilities.launcher && inBottomPanel(panels.launcher, x, y))
|
||||
// visibilities.launcher = true;
|
||||
// } else if (pressed && inBottomPanel(panels.launcher, dragStart.x, dragStart.y) && withinPanelWidth(panels.launcher, x, y)) {
|
||||
// if (dragY < -Config.launcher.dragThreshold)
|
||||
// visibilities.launcher = true;
|
||||
// else if (dragY > Config.launcher.dragThreshold)
|
||||
// visibilities.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) {
|
||||
// visibilities.dashboard = showDashboard;
|
||||
// } else if (showDashboard) {
|
||||
// // If hovering over dashboard area while in shortcut mode, transition to hover control
|
||||
// dashboardShortcutActive = false;
|
||||
// }
|
||||
//
|
||||
// // Show/hide dashboard on drag (for touchscreen devices)
|
||||
// if (pressed && inTopPanel(panels.dashboard, dragStart.x, dragStart.y) && withinPanelWidth(panels.dashboard, x, y)) {
|
||||
// if (dragY > Config.dashboard.dragThreshold)
|
||||
// visibilities.dashboard = true;
|
||||
// else if (dragY < -Config.dashboard.dragThreshold)
|
||||
// visibilities.dashboard = false;
|
||||
// }
|
||||
//
|
||||
// // Show utilities on hover
|
||||
// const showUtilities = inBottomPanel(panels.utilities, x, y);
|
||||
//
|
||||
// // Always update visibility based on hover if not in shortcut mode
|
||||
// if (!utilitiesShortcutActive) {
|
||||
// visibilities.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 (y < bar.implicitHeight) {
|
||||
bar.checkPopout(x);
|
||||
}
|
||||
}
|
||||
|
||||
// Monitor individual visibility changes
|
||||
Connections {
|
||||
function onDashboardChanged() {
|
||||
if (root.visibilities.dashboard) {
|
||||
// Dashboard became visible, immediately check if this should be shortcut mode
|
||||
const inDashboardArea = root.inTopPanel(root.panels.dashboard, root.mouseX, root.mouseY);
|
||||
if (!inDashboardArea) {
|
||||
root.dashboardShortcutActive = true;
|
||||
@@ -209,20 +123,21 @@ CustomMouseArea {
|
||||
root.visibilities.sidebar = false;
|
||||
root.popouts.hasCurrent = false;
|
||||
} else {
|
||||
// Dashboard hidden, clear shortcut flag
|
||||
root.dashboardShortcutActive = false;
|
||||
// root.visibilities.bar = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onIsDrawingChanged() {
|
||||
if (!root.visibilities.isDrawing)
|
||||
root.drawing.clear();
|
||||
}
|
||||
|
||||
function onLauncherChanged() {
|
||||
// If launcher is hidden, clear shortcut flags for dashboard and OSD
|
||||
if (!root.visibilities.launcher) {
|
||||
root.dashboardShortcutActive = false;
|
||||
root.osdShortcutActive = 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);
|
||||
|
||||
if (!inOsdArea) {
|
||||
@@ -234,13 +149,11 @@ CustomMouseArea {
|
||||
|
||||
function onOsdChanged() {
|
||||
if (root.visibilities.osd) {
|
||||
// OSD became visible, immediately check if this should be shortcut mode
|
||||
const inOsdArea = root.inRightPanel(root.panels.osd, root.mouseX, root.mouseY);
|
||||
if (!inOsdArea) {
|
||||
root.osdShortcutActive = true;
|
||||
}
|
||||
} else {
|
||||
// OSD hidden, clear shortcut flag
|
||||
root.osdShortcutActive = false;
|
||||
}
|
||||
}
|
||||
@@ -260,13 +173,11 @@ CustomMouseArea {
|
||||
|
||||
function onUtilitiesChanged() {
|
||||
if (root.visibilities.utilities) {
|
||||
// Utilities became visible, immediately check if this should be shortcut mode
|
||||
const inUtilitiesArea = root.inBottomPanel(root.panels.utilities, root.mouseX, root.mouseY);
|
||||
if (!inUtilitiesArea) {
|
||||
root.utilitiesShortcutActive = true;
|
||||
}
|
||||
} else {
|
||||
// Utilities hidden, clear shortcut flag
|
||||
root.utilitiesShortcutActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import qs.Components.Toast as Toasts
|
||||
import qs.Modules.Launcher as Launcher
|
||||
import qs.Modules.Resources as Resources
|
||||
import qs.Modules.Settings as Settings
|
||||
import qs.Modules.Drawing as Drawing
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
@@ -18,6 +19,8 @@ Item {
|
||||
|
||||
required property Item bar
|
||||
readonly property alias dashboard: dashboard
|
||||
readonly property alias drawing: drawing
|
||||
required property Canvas drawingItem
|
||||
readonly property alias launcher: launcher
|
||||
readonly property alias notifications: notifications
|
||||
readonly property alias osd: osd
|
||||
@@ -47,6 +50,16 @@ Item {
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
Drawing.Wrapper {
|
||||
id: drawing
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
drawing: root.drawingItem
|
||||
screen: root.screen
|
||||
visibilities: root.visibilities
|
||||
}
|
||||
|
||||
Osd.Wrapper {
|
||||
id: osd
|
||||
|
||||
|
||||
Reference in New Issue
Block a user