pragma ComponentBehavior: Bound import ZShell.Components import QtQuick import QtQuick.Layouts import qs.Components import ZShell.Config import qs.Services CustomRect { id: root readonly property var colorPalette: ["#ff3b30", "#ff9500", "#ffcc00", "#34c759", "#0a84ff", "#af52de", "#ffffff", "#000000"] property color inkColor: "#ff3b30" property string tool: "move" readonly property var toolList: [ { id: "move", glyph: "arrows_output" }, { id: "pen", glyph: "draw" }, { id: "line", glyph: "diagonal_line" }, { id: "arrow", glyph: "arrow_outward" }, { id: "rect", glyph: "rectangle" }, { id: "ellipse", glyph: "circle" } ] signal cancelRequested signal clearRequested signal colorSelected(color c) signal copyRequested signal saveRequested signal toolSelected(string tool) signal undoRequested color: Colors.palette.m3surface height: row.implicitHeight + Tokens.padding.small * 2 radius: Tokens.rounding.full width: row.implicitWidth + Tokens.padding.small * 2 RowLayout { id: row anchors.centerIn: parent spacing: 6 ButtonRow { id: toolRow spacing: Tokens.spacing.extraSmall Repeater { model: root.toolList delegate: IconButton { id: tool required property var modelData color: root.tool === modelData.id ? "#3584e4" : "transparent" font.pointSize: Tokens.font.size.large icon: tool.modelData.glyph inactiveColor: root.tool === modelData.id ? Colors.palette.m3primary : "transparent" inactiveOnColor: root.tool === modelData.id ? Colors.palette.m3onPrimary : Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: shapeMorph && pressed ? 12 : 0 onClicked: root.toolSelected(tool.modelData.id) } } } CustomRect { Layout.fillHeight: true Layout.preferredWidth: 1 color: Colors.palette.m3outlineVariant } ButtonRow { spacing: Tokens.spacing.extraSmall Repeater { model: root.colorPalette delegate: IconButton { readonly property real buttonSize: toolRow.implicitHeight - Tokens.padding.small required property color modelData fillWidth: false font.pointSize: Tokens.font.size.large icon: "" implicitHeight: buttonSize implicitWidth: buttonSize inactiveColor: modelData inactiveOnColor: Colors.on(modelData) isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.colorSelected(modelData) } } } CustomRect { Layout.fillHeight: true Layout.preferredWidth: 1 color: Colors.palette.m3outlineVariant } ButtonRow { spacing: Tokens.spacing.extraSmall IconButton { font.pointSize: Tokens.font.size.large icon: "undo" inactiveColor: "transparent" inactiveOnColor: Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.undoRequested() } IconButton { font.pointSize: Tokens.font.size.large icon: "delete_history" inactiveColor: "transparent" inactiveOnColor: Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.clearRequested() } IconButton { font.pointSize: Tokens.font.size.large icon: "content_copy" inactiveColor: "transparent" inactiveOnColor: Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.copyRequested() } IconButton { font.pointSize: Tokens.font.size.large icon: "delete_forever" inactiveColor: "transparent" inactiveOnColor: Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.cancelRequested() } IconButton { font.pointSize: Tokens.font.size.large icon: "check" inactiveColor: "transparent" inactiveOnColor: Colors.palette.m3onSurface isRound: true shapeMorph: true shapeMorphExpansion: pressed ? 12 : 0 onClicked: root.saveRequested() } } } }