Custom buttons: improved UI, still wip
This commit is contained in:
parent
7f34ca4122
commit
598bc48957
3 changed files with 279 additions and 48 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
|
@ -16,6 +17,7 @@ NBox {
|
|||
signal addWidget(string widgetId, string section)
|
||||
signal removeWidget(string section, int index)
|
||||
signal reorderWidget(string section, int fromIndex, int toIndex)
|
||||
signal updateWidgetSettings(string section, int index, var settings)
|
||||
|
||||
color: Color.mSurface
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -33,21 +35,209 @@ NBox {
|
|||
}
|
||||
|
||||
// Generate widget color from name checksum
|
||||
function getWidgetColor(widgetId) {
|
||||
const totalSum = widgetId.split('').reduce((acc, character) => {
|
||||
function getWidgetColor(widget) {
|
||||
const totalSum = JSON.stringify(widget).split('').reduce((acc, character) => {
|
||||
return acc + character.charCodeAt(0)
|
||||
}, 0)
|
||||
switch (totalSum % 5) {
|
||||
case 0:
|
||||
return Color.mPrimary
|
||||
case 1:
|
||||
return Color.mSecondary
|
||||
case 2:
|
||||
return Color.mTertiary
|
||||
case 3:
|
||||
return Color.mError
|
||||
case 4:
|
||||
return Color.mOnSurface
|
||||
switch (totalSum % 10) {
|
||||
case 0:
|
||||
return Color.mPrimary
|
||||
case 1:
|
||||
return Color.mSecondary
|
||||
case 2:
|
||||
return Color.mTertiary
|
||||
case 3:
|
||||
return Color.mError
|
||||
case 4:
|
||||
return Color.mOnSurface
|
||||
case 5:
|
||||
return Qt.darker(Color.mPrimary, 1.3)
|
||||
case 6:
|
||||
return Qt.darker(Color.mSecondary, 1.3)
|
||||
case 7:
|
||||
return Qt.darker(Color.mTertiary, 1.3)
|
||||
case 8:
|
||||
return Qt.darker(Color.mError, 1.3)
|
||||
case 9:
|
||||
return Qt.darker(Color.mOnSurface, 1.3)
|
||||
}
|
||||
}
|
||||
|
||||
// Widget Settings Dialog Component
|
||||
Component {
|
||||
id: widgetSettingsDialog
|
||||
|
||||
Popup {
|
||||
id: settingsPopup
|
||||
|
||||
property int widgetIndex: -1
|
||||
property var widgetData: null
|
||||
property string widgetId: ""
|
||||
|
||||
// Center popup in parent
|
||||
x: (parent.width - width) * 0.5
|
||||
y: (parent.height - height) * 0.5
|
||||
|
||||
width: 400 * scaling
|
||||
height: content.implicitHeight + padding * 2
|
||||
padding: Style.marginL * scaling
|
||||
modal: true
|
||||
|
||||
background: Rectangle {
|
||||
id: bgRect
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusL * scaling
|
||||
border.color: Color.mPrimary
|
||||
border.width: Style.borderM * scaling
|
||||
}
|
||||
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
width: parent.width
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Title
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Widget Settings: " + settingsPopup.widgetId
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mPrimary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
colorBg: Color.transparent
|
||||
colorFg: Color.mOnSurface
|
||||
colorBgHover: Color.applyOpacity(Color.mError, "20")
|
||||
colorFgHover: Color.mError
|
||||
onClicked: settingsPopup.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Separator
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1
|
||||
color: Color.mOutline
|
||||
}
|
||||
|
||||
// Settings based on widget type
|
||||
Loader {
|
||||
id: settingsLoader
|
||||
Layout.fillWidth: true
|
||||
sourceComponent: {
|
||||
if (settingsPopup.widgetId === "CustomButton") {
|
||||
return customButtonSettings
|
||||
}
|
||||
// Add more widget settings components here as needed
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Action buttons
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginM * scaling
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: "Cancel"
|
||||
outlined: true
|
||||
onClicked: settingsPopup.close()
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: "Save"
|
||||
onClicked: {
|
||||
if (settingsLoader.item && settingsLoader.item.saveSettings) {
|
||||
var newSettings = settingsLoader.item.saveSettings()
|
||||
root.updateWidgetSettings(sectionId, settingsPopup.widgetIndex, newSettings)
|
||||
settingsPopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CustomButton settings component
|
||||
Component {
|
||||
id: customButtonSettings
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
property alias iconField: iconInput
|
||||
property alias executeField: executeInput
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, settingsPopup.widgetData)
|
||||
settings.icon = iconInput.text
|
||||
settings.execute = executeInput.text
|
||||
return settings
|
||||
}
|
||||
|
||||
// Icon setting
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS * scaling
|
||||
|
||||
NText {
|
||||
text: "Icon Name"
|
||||
font.pointSize: Style.fontSizeS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
|
||||
NTextInput{
|
||||
id: iconInput
|
||||
Layout.fillWidth: true
|
||||
//placeholder: "Enter icon name (e.g., favorite, home, settings)"
|
||||
text: settingsPopup.widgetData.icon || ""
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Use Material Icon names from the icon set"
|
||||
font.pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.applyOpacity(Color.mOnSurfaceVariant, "80")
|
||||
}
|
||||
}
|
||||
|
||||
// Execute command setting
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginXS * scaling
|
||||
|
||||
NText {
|
||||
text: "Execute Command"
|
||||
font.pointSize: Style.fontSizeS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: executeInput
|
||||
Layout.fillWidth: true
|
||||
//placeholder: "Enter command to execute (e.g., firefox, code, terminal)"
|
||||
text: settingsPopup.widgetData.execute || ""
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Command or application to run when clicked"
|
||||
font.pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.applyOpacity(Color.mOnSurfaceVariant, "80")
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +312,7 @@ NBox {
|
|||
width: widgetContent.implicitWidth + Style.marginL * scaling
|
||||
height: 40 * scaling
|
||||
radius: Style.radiusL * scaling
|
||||
color: root.getWidgetColor(modelData.id)
|
||||
color: root.getWidgetColor(modelData)
|
||||
border.color: Color.mOutline
|
||||
border.width: Math.max(1, Style.borderS * scaling)
|
||||
|
||||
|
|
@ -172,7 +362,14 @@ NBox {
|
|||
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
|
||||
colorFgHover: Color.mOnPrimary
|
||||
onClicked: {
|
||||
// TODO open settings
|
||||
// Open widget settings dialog
|
||||
var dialog = widgetSettingsDialog.createObject(root, {
|
||||
widgetIndex: index,
|
||||
widgetData: modelData,
|
||||
widgetId: modelData.id,
|
||||
parent: Overlay.overlay
|
||||
})
|
||||
dialog.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -199,15 +396,15 @@ NBox {
|
|||
drag.target: parent
|
||||
|
||||
onPressed: mouse => {
|
||||
// Check if the click is on the close button area
|
||||
const closeButtonX = widgetContent.x + widgetContent.width - 20 * scaling
|
||||
const closeButtonY = widgetContent.y
|
||||
const closeButtonWidth = 20 * scaling
|
||||
const closeButtonHeight = 20 * scaling
|
||||
// Check if the click is on the settings or close button area
|
||||
const buttonsX = widgetContent.x + widgetContent.width - 45 * scaling
|
||||
const buttonsY = widgetContent.y
|
||||
const buttonsWidth = 45 * scaling
|
||||
const buttonsHeight = 20 * scaling
|
||||
|
||||
if (mouseX >= closeButtonX && mouseX <= closeButtonX + closeButtonWidth
|
||||
&& mouseY >= closeButtonY && mouseY <= closeButtonY + closeButtonHeight) {
|
||||
// Click is on the close button, don't start drag
|
||||
if (mouseX >= buttonsX && mouseX <= buttonsX + buttonsWidth
|
||||
&& mouseY >= buttonsY && mouseY <= buttonsY + buttonsHeight) {
|
||||
// Click is on the buttons, don't start drag
|
||||
mouse.accepted = false
|
||||
return
|
||||
}
|
||||
|
|
@ -255,13 +452,7 @@ NBox {
|
|||
if (targetIndex !== -1 && targetIndex !== index) {
|
||||
const fromIndex = index
|
||||
const toIndex = targetIndex
|
||||
// Logger.log(
|
||||
// "NSectionEditor",
|
||||
// `Dropped widget from index ${fromIndex} to position ${toIndex} (distance: ${minDistance.toFixed(
|
||||
// 2)})`)
|
||||
reorderWidget(sectionId, fromIndex, toIndex)
|
||||
} else {
|
||||
Logger.warn("NSectionEditor", `No valid drop target found for widget at index ${index}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue