1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

widgets: add spacer, divider, tweak interface

This commit is contained in:
bbedward
2025-08-02 13:10:39 -04:00
parent 2e85494236
commit 21c40b58bc
47 changed files with 2660 additions and 2205 deletions

View File

@@ -31,7 +31,6 @@ StyledRect {
stateColor: Theme.primary
cornerRadius: root.radius
onClicked: {
console.log("StateLayer clicked for button:", root.iconName);
root.clicked();
}
}

View File

@@ -5,6 +5,8 @@ import qs.Common
import qs.Widgets
Rectangle {
// Force recreate popup when component becomes visible
id: root
property string text: ""
@@ -38,7 +40,6 @@ Rectangle {
if (!visible && popup && popup.visible)
popup.close();
else if (visible)
// Force recreate popup when component becomes visible
forceRecreateTimer.start();
}

View File

@@ -15,7 +15,8 @@ Column {
signal itemEnabledChanged(string sectionId, string itemId, bool enabled)
signal itemOrderChanged(var newOrder)
signal addWidget(string sectionId)
signal removeLastWidget(string sectionId)
signal removeWidget(string sectionId, string itemId)
signal spacerSizeChanged(string sectionId, string itemId, int newSize)
width: parent.width
spacing: Theme.spacingM
@@ -44,30 +45,32 @@ Column {
width: parent.width - 60
height: 1
}
}
// Widget Items
Column {
id: itemsList
width: parent.width
spacing: Theme.spacingS
Repeater {
model: root.items
delegate: Item {
id: delegateItem
property bool held: dragArea.pressed
property real originalY: y
width: itemsList.width
height: 70
property int visualIndex: index
property bool held: dragArea.pressed
property string itemId: modelData.id
z: held ? 2 : 1
Rectangle {
id: itemBackground
anchors.fill: parent
anchors.margins: 2
radius: Theme.cornerRadius
@@ -75,39 +78,29 @@ Column {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
// Drag handle
Rectangle {
width: 40
height: parent.height
color: "transparent"
DankIcon {
name: "drag_indicator"
size: Theme.iconSize - 4
color: Theme.outline
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.leftMargin: Theme.spacingM + 8
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "drag_indicator"
size: Theme.iconSize - 4
color: Theme.outline
anchors.centerIn: parent
opacity: 0.8
}
opacity: 0.8
}
// Widget icon
DankIcon {
name: modelData.icon
size: Theme.iconSize
color: modelData.enabled ? Theme.primary : Theme.outline
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM + 40 + Theme.spacingM
anchors.leftMargin: Theme.spacingM * 2 + 40
anchors.verticalCenter: parent.verticalCenter
}
// Widget info
Column {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM + 40 + Theme.spacingM + Theme.iconSize + Theme.spacingM
anchors.right: toggle.left
anchors.leftMargin: Theme.spacingM * 3 + 40 + Theme.iconSize
anchors.right: actionButtons.left
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: 2
@@ -129,135 +122,174 @@ Column {
width: parent.width
wrapMode: Text.WordWrap
}
}
// Toggle - positioned at right edge
DankToggle {
id: toggle
Row {
id: actionButtons
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
width: 48
height: 24
hideText: true
checked: modelData.enabled
onToggled: (checked) => {
root.itemEnabledChanged(root.sectionId, modelData.id, checked)
spacing: Theme.spacingXS
DankActionButton {
visible: modelData.id !== "spacer"
buttonSize: 32
iconName: modelData.enabled ? "visibility" : "visibility_off"
iconSize: 18
iconColor: modelData.enabled ? Theme.primary : Theme.outline
onClicked: {
root.itemEnabledChanged(root.sectionId, modelData.id, !modelData.enabled);
}
}
Row {
visible: modelData.id === "spacer"
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
DankActionButton {
buttonSize: 24
iconName: "remove"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var currentSize = modelData.size || 20;
var newSize = Math.max(5, currentSize - 5);
root.spacerSizeChanged(root.sectionId, modelData.id, newSize);
}
}
StyledText {
text: (modelData.size || 20).toString()
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
DankActionButton {
buttonSize: 24
iconName: "add"
iconSize: 14
iconColor: Theme.outline
onClicked: {
var currentSize = modelData.size || 20;
var newSize = Math.min(5000, currentSize + 5);
root.spacerSizeChanged(root.sectionId, modelData.id, newSize);
}
}
}
DankActionButton {
buttonSize: 32
iconName: "close"
iconSize: 18
iconColor: Theme.error
onClicked: {
root.removeWidget(root.sectionId, modelData.id);
}
}
}
// Drag functionality
MouseArea {
id: dragArea
anchors.fill: parent
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 60
hoverEnabled: true
property bool validDragStart: false
drag.target: held && validDragStart ? delegateItem : undefined
cursorShape: Qt.SizeVerCursor
drag.target: held ? delegateItem : undefined
drag.axis: Drag.YAxis
drag.minimumY: -delegateItem.height
drag.maximumY: itemsList.height
onPressed: (mouse) => {
// Only allow dragging from the drag handle area (first 60px)
if (mouse.x <= 60) {
validDragStart = true
delegateItem.z = 2
} else {
validDragStart = false
mouse.accepted = false
}
onPressed: {
delegateItem.z = 2;
delegateItem.originalY = delegateItem.y;
}
onReleased: {
delegateItem.z = 1
if (drag.active && validDragStart) {
// Calculate new index based on position
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing))
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1))
delegateItem.z = 1;
if (drag.active) {
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing));
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1));
if (newIndex !== index) {
var newItems = root.items.slice()
var draggedItem = newItems.splice(index, 1)[0]
newItems.splice(newIndex, 0, draggedItem)
root.itemOrderChanged(newItems.map(item => ({id: item.id, enabled: item.enabled})))
var newItems = root.items.slice();
var draggedItem = newItems.splice(index, 1)[0];
newItems.splice(newIndex, 0, draggedItem);
root.itemOrderChanged(newItems.map((item) => {
return ({
"id": item.id,
"enabled": item.enabled,
"size": item.size
});
}));
}
}
// Reset position
delegateItem.x = 0
delegateItem.y = 0
validDragStart = false
delegateItem.x = 0;
delegateItem.y = delegateItem.originalY;
}
}
// Animations for drag
Behavior on y {
enabled: !dragArea.held && !dragArea.drag.active
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
// Add/Remove Controls
// Add Widget Control
Rectangle {
width: parent.width * 0.5
width: 200
height: 40
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
color: addButtonArea.containsMouse ? Theme.primaryContainer : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
Row {
StyledText {
text: "Add Widget"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
anchors.centerIn: parent
spacing: Theme.spacingL
}
StyledText {
text: "Add or remove widgets"
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
anchors.verticalCenter: parent.verticalCenter
}
MouseArea {
id: addButtonArea
Row {
spacing: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
// Add button
DankActionButton {
iconName: "add"
iconSize: Theme.iconSize - 4
iconColor: Theme.primary
hoverColor: Theme.primaryContainer
onClicked: {
root.addWidget(root.sectionId);
}
}
// Remove button
DankActionButton {
iconName: "remove"
iconSize: Theme.iconSize - 4
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1)
enabled: root.items.length > 0
opacity: root.items.length > 0 ? 1.0 : 0.5
onClicked: {
if (root.items.length > 0) {
root.removeLastWidget(root.sectionId);
}
}
}
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.addWidget(root.sectionId);
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -44,30 +44,33 @@ Column {
width: parent.width - 60
height: 1
}
}
// Widget Items
Column {
id: itemsList
width: parent.width
spacing: Theme.spacingS
Repeater {
model: root.items
delegate: Item {
id: delegateItem
width: itemsList.width
height: 70
property int visualIndex: index
property bool held: dragArea.pressed
property string itemId: modelData.id
width: itemsList.width
height: 70
z: held ? 2 : 1
Rectangle {
id: itemBackground
anchors.fill: parent
anchors.margins: 2
radius: Theme.cornerRadius
@@ -86,7 +89,7 @@ Column {
height: parent.height
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "drag_indicator"
size: Theme.iconSize - 4
@@ -94,6 +97,7 @@ Column {
anchors.centerIn: parent
opacity: 0.8
}
}
// Widget icon
@@ -127,6 +131,7 @@ Column {
width: parent.width
wrapMode: Text.WordWrap
}
}
// Spacer to push toggle to right
@@ -143,70 +148,73 @@ Column {
hideText: true
checked: modelData.enabled
onToggled: (checked) => {
root.itemEnabledChanged(modelData.id, checked)
root.itemEnabledChanged(modelData.id, checked);
}
}
}
// Drag functionality
MouseArea {
id: dragArea
property bool validDragStart: false
anchors.fill: parent
hoverEnabled: true
property bool validDragStart: false
drag.target: held && validDragStart ? delegateItem : undefined
drag.axis: Drag.YAxis
drag.minimumY: -delegateItem.height
drag.maximumY: itemsList.height
onPressed: (mouse) => {
// Only allow dragging from the drag handle area (first 60px)
if (mouse.x <= 60) {
validDragStart = true
delegateItem.z = 2
validDragStart = true;
delegateItem.z = 2;
} else {
validDragStart = false
mouse.accepted = false
validDragStart = false;
mouse.accepted = false;
}
}
onReleased: {
delegateItem.z = 1
delegateItem.z = 1;
if (drag.active && validDragStart) {
// Calculate new index based on position
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing))
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1))
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing));
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1));
if (newIndex !== index) {
var newItems = root.items.slice()
var draggedItem = newItems.splice(index, 1)[0]
newItems.splice(newIndex, 0, draggedItem)
root.itemOrderChanged(newItems.map(item => item.id))
var newItems = root.items.slice();
var draggedItem = newItems.splice(index, 1)[0];
newItems.splice(newIndex, 0, draggedItem);
root.itemOrderChanged(newItems.map((item) => {
return item.id;
}));
}
}
// Reset position
delegateItem.x = 0
delegateItem.y = 0
validDragStart = false
delegateItem.x = 0;
delegateItem.y = 0;
validDragStart = false;
}
}
// Animations for drag
Behavior on y {
enabled: !dragArea.held && !dragArea.drag.active
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
// Add/Remove Controls
@@ -252,14 +260,18 @@ Column {
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1)
enabled: root.items.length > 0
opacity: root.items.length > 0 ? 1.0 : 0.5
opacity: root.items.length > 0 ? 1 : 0.5
onClicked: {
if (root.items.length > 0) {
if (root.items.length > 0)
root.removeLastWidget(root.sectionId);
}
}
}
}
}
}
}

View File

@@ -12,30 +12,28 @@ Popup {
signal widgetSelected(string widgetId, string targetSection)
// Prevent multiple openings
function safeOpen() {
if (!isOpening && !visible) {
isOpening = true;
open();
}
}
width: 400
height: 450
modal: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
// Prevent multiple openings
function safeOpen() {
if (!isOpening && !visible) {
isOpening = true
open()
}
}
onOpened: {
isOpening = false
isOpening = false;
}
onClosed: {
isOpening = false
isOpening = false;
// Clear references to prevent memory leaks
allWidgets = []
targetSection = ""
allWidgets = [];
targetSection = "";
}
background: Rectangle {
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
border.color: Theme.primarySelected
@@ -61,6 +59,7 @@ Popup {
Column {
id: contentColumn
spacing: Theme.spacingM
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -85,15 +84,16 @@ Popup {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: "Select a widget to add to the " + root.targetSection.toLowerCase() + " section of the top bar. You can add multiple instances of the same widget if needed."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width
wrapMode: Text.WordWrap
}
StyledText {
text: "Select a widget to add to the " + root.targetSection.toLowerCase() + " section of the top bar. You can add multiple instances of the same widget if needed."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width
wrapMode: Text.WordWrap
}
// Widget List
ScrollView {
@@ -103,6 +103,7 @@ Popup {
ListView {
id: widgetList
spacing: Theme.spacingS
model: root.allWidgets
@@ -150,6 +151,7 @@ Popup {
width: parent.width
wrapMode: Text.WordWrap
}
}
// Add icon
@@ -159,17 +161,18 @@ Popup {
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: widgetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.widgetSelected(modelData.id, root.targetSection)
root.close()
root.widgetSelected(modelData.id, root.targetSection);
root.close();
}
}
@@ -178,10 +181,17 @@ Popup {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}
}

View File

@@ -10,13 +10,14 @@ Text {
color: Theme.surfaceText
font.pixelSize: Appearance.fontSize.normal
font.family: {
// Use system default
var requestedFont = isMonospace ? Prefs.monoFontFamily : Prefs.fontFamily;
var defaultFont = isMonospace ? Prefs.defaultMonoFontFamily : Prefs.defaultFontFamily;
// If user hasn't overridden the font and we're using the default
if (requestedFont === defaultFont) {
var availableFonts = Qt.fontFamilies();
if (!availableFonts.includes(requestedFont))
// Use system default
return isMonospace ? "Monospace" : "DejaVu Sans";
}