settings
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import qs.Config
|
||||
import qs.Helpers
|
||||
|
||||
Row {
|
||||
id: root
|
||||
@@ -29,8 +30,29 @@ Row {
|
||||
property int type: CustomSplitButton.Filled
|
||||
property real verticalPadding: Appearance.padding.smaller
|
||||
|
||||
function closeDropdown(): void {
|
||||
SettingsDropdowns.close(menu);
|
||||
}
|
||||
|
||||
function openDropdown(): void {
|
||||
if (root.disabled)
|
||||
return;
|
||||
SettingsDropdowns.open(menu, root);
|
||||
}
|
||||
|
||||
function toggleDropdown(): void {
|
||||
if (root.disabled)
|
||||
return;
|
||||
SettingsDropdowns.toggle(menu, root);
|
||||
}
|
||||
|
||||
spacing: Math.floor(Appearance.spacing.small / 2)
|
||||
|
||||
onExpandedChanged: {
|
||||
if (!expanded)
|
||||
SettingsDropdowns.forget(menu);
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
bottomRightRadius: Appearance.rounding.small / 2
|
||||
color: root.disabled ? root.disabledColor : root.color
|
||||
@@ -109,7 +131,7 @@ Row {
|
||||
id: expandStateLayer
|
||||
|
||||
function onClicked(): void {
|
||||
root.expanded = !root.expanded;
|
||||
root.toggleDropdown();
|
||||
}
|
||||
|
||||
color: root.textColor
|
||||
|
||||
@@ -47,9 +47,10 @@ Item {
|
||||
|
||||
menu.onItemSelected: item => {
|
||||
root.selected(item);
|
||||
splitButton.closeDropdown();
|
||||
}
|
||||
stateLayer.onClicked: {
|
||||
splitButton.expanded = !splitButton.expanded;
|
||||
splitButton.toggleDropdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import QtQuick
|
||||
|
||||
Path {
|
||||
id: root
|
||||
|
||||
required property real viewHeight
|
||||
required property real viewWidth
|
||||
|
||||
startX: root.viewWidth / 2
|
||||
startY: 0
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.25
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight * (1 / 6)
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.45
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight * (2 / 6)
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.70
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight * (3 / 6)
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 1.00
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight * (4 / 6)
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.70
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight * (5 / 6)
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.45
|
||||
}
|
||||
|
||||
PathLine {
|
||||
x: root.viewWidth / 2
|
||||
y: root.viewHeight
|
||||
}
|
||||
|
||||
PathAttribute {
|
||||
name: "itemOpacity"
|
||||
value: 0.25
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Config
|
||||
|
||||
Elevation {
|
||||
id: root
|
||||
|
||||
required property int currentIndex
|
||||
property bool expanded
|
||||
required property int from
|
||||
property color insideTextColor: DynamicColors.palette.m3onPrimary
|
||||
property int itemHeight
|
||||
property int listHeight: 200
|
||||
property color outsideTextColor: DynamicColors.palette.m3onSurfaceVariant
|
||||
readonly property var spinnerModel: root.range(root.from, root.to)
|
||||
required property int to
|
||||
property Item triggerItem
|
||||
|
||||
signal itemSelected(item: int)
|
||||
|
||||
function range(first, last) {
|
||||
let out = [];
|
||||
for (let i = first; i <= last; ++i)
|
||||
out.push(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
implicitHeight: root.expanded ? view.implicitHeight : 0
|
||||
level: root.expanded ? 2 : 0
|
||||
radius: itemHeight / 2
|
||||
visible: implicitHeight > 0
|
||||
|
||||
Behavior on implicitHeight {
|
||||
Anim {
|
||||
}
|
||||
}
|
||||
|
||||
onExpandedChanged: {
|
||||
if (!root.expanded)
|
||||
root.itemSelected(view.currentIndex + 1);
|
||||
}
|
||||
|
||||
Component {
|
||||
id: spinnerDelegate
|
||||
|
||||
Item {
|
||||
id: wrapper
|
||||
|
||||
readonly property color delegateTextColor: wrapper.PathView.view ? wrapper.PathView.view.delegateTextColor : "white"
|
||||
required property var modelData
|
||||
|
||||
height: root.itemHeight
|
||||
opacity: wrapper.PathView.itemOpacity
|
||||
visible: wrapper.PathView.onPath
|
||||
width: wrapper.PathView.view ? wrapper.PathView.view.width : 0
|
||||
z: wrapper.PathView.isCurrentItem ? 100 : Math.round(wrapper.PathView.itemScale * 100)
|
||||
|
||||
CustomText {
|
||||
anchors.centerIn: parent
|
||||
color: wrapper.delegateTextColor
|
||||
font.pointSize: Appearance.font.size.large
|
||||
text: wrapper.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomClippingRect {
|
||||
anchors.fill: parent
|
||||
color: DynamicColors.palette.m3surfaceContainer
|
||||
radius: parent.radius
|
||||
|
||||
// Main visible spinner: normal/outside text color
|
||||
PathView {
|
||||
id: view
|
||||
|
||||
property color delegateTextColor: root.outsideTextColor
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
clip: true
|
||||
currentIndex: root.currentIndex - 1
|
||||
delegate: spinnerDelegate
|
||||
dragMargin: width
|
||||
highlightRangeMode: PathView.StrictlyEnforceRange
|
||||
implicitHeight: root.listHeight
|
||||
model: root.spinnerModel
|
||||
pathItemCount: 7
|
||||
preferredHighlightBegin: 0.5
|
||||
preferredHighlightEnd: 0.5
|
||||
snapMode: PathView.SnapToItem
|
||||
|
||||
path: PathMenu {
|
||||
viewHeight: view.height
|
||||
viewWidth: view.width
|
||||
}
|
||||
}
|
||||
|
||||
// The selection rectangle itself
|
||||
CustomRect {
|
||||
id: selectionRect
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: DynamicColors.palette.m3primary
|
||||
height: root.itemHeight
|
||||
radius: root.itemHeight / 2
|
||||
width: parent.width
|
||||
z: 2
|
||||
}
|
||||
|
||||
// Hidden source: same PathView, but with the "inside selection" text color
|
||||
Item {
|
||||
id: selectedTextSource
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
|
||||
PathView {
|
||||
id: selectedTextView
|
||||
|
||||
property color delegateTextColor: root.insideTextColor
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
clip: true
|
||||
currentIndex: view.currentIndex
|
||||
delegate: spinnerDelegate
|
||||
dragMargin: view.dragMargin
|
||||
highlightRangeMode: view.highlightRangeMode
|
||||
implicitHeight: root.listHeight
|
||||
interactive: false
|
||||
model: view.model
|
||||
|
||||
// Keep this PathView visually locked to the real one
|
||||
offset: view.offset
|
||||
pathItemCount: view.pathItemCount
|
||||
preferredHighlightBegin: view.preferredHighlightBegin
|
||||
preferredHighlightEnd: view.preferredHighlightEnd
|
||||
snapMode: view.snapMode
|
||||
|
||||
path: PathMenu {
|
||||
viewHeight: selectedTextView.height
|
||||
viewWidth: selectedTextView.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mask matching the selection rectangle
|
||||
Item {
|
||||
id: selectionMask
|
||||
|
||||
anchors.fill: parent
|
||||
layer.enabled: true
|
||||
visible: false
|
||||
|
||||
CustomRect {
|
||||
color: "white"
|
||||
height: selectionRect.height
|
||||
radius: selectionRect.radius
|
||||
width: selectionRect.width
|
||||
x: selectionRect.x
|
||||
y: selectionRect.y
|
||||
}
|
||||
}
|
||||
|
||||
// Only show the "inside selection" text where the mask exists
|
||||
MultiEffect {
|
||||
anchors.fill: selectedTextSource
|
||||
maskEnabled: true
|
||||
maskInverted: false
|
||||
maskSource: selectionMask
|
||||
source: selectedTextSource
|
||||
z: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user