mirror of
https://github.com/stemoretti/BaseUI.git
synced 2025-05-28 00:30:27 -04:00
Make time picker animations better
This commit is contained in:
parent
11606b8f39
commit
051e97c636
@ -10,7 +10,7 @@ Item {
|
|||||||
readonly property string timeString: _zeroPad(hours) + ":" + _zeroPad(minutes)
|
readonly property string timeString: _zeroPad(hours) + ":" + _zeroPad(minutes)
|
||||||
readonly property bool isPM: hours >= 12
|
readonly property bool isPM: hours >= 12
|
||||||
|
|
||||||
property bool pickMinutes: false
|
readonly property alias pickMinutes: clock.pickMinutes
|
||||||
property bool time24h: false
|
property bool time24h: false
|
||||||
|
|
||||||
property color clockColor: "gray"
|
property color clockColor: "gray"
|
||||||
@ -25,6 +25,11 @@ Item {
|
|||||||
property int labelsSize: 20
|
property int labelsSize: 20
|
||||||
property int clockHandCircleSize: 2 * labelsSize
|
property int clockHandCircleSize: 2 * labelsSize
|
||||||
|
|
||||||
|
function setPickMinutes(pick) {
|
||||||
|
if (!animation.running)
|
||||||
|
clock.pickMinutes = pick
|
||||||
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
circle.pos = circle.mapToItem(root.screen, 0, circle.height)
|
circle.pos = circle.mapToItem(root.screen, 0, circle.height)
|
||||||
circle.pos.y = Window.height - circle.pos.y
|
circle.pos.y = Window.height - circle.pos.y
|
||||||
@ -45,20 +50,45 @@ Item {
|
|||||||
implicitHeight: implicitWidth
|
implicitHeight: implicitWidth
|
||||||
|
|
||||||
onPickMinutesChanged: {
|
onPickMinutesChanged: {
|
||||||
handAnimation.enabled = circleAnimation.enabled = true
|
var minAngle = 360 / 60 * root.minutes
|
||||||
disableAnimationTimer.start()
|
var hourAngle = 360 / 12 * (root.hours - (root.hours >= 12 ? 12 : 0))
|
||||||
|
|
||||||
|
var diff = minAngle - hourAngle
|
||||||
|
if (Math.abs(diff) <= 180) {
|
||||||
|
handToAnimation.to = handFromAnimation.from = (minAngle + hourAngle) / 2
|
||||||
|
} else {
|
||||||
|
handToAnimation.to = root.pickMinutes ? (diff >= 0 ? 0 : 360) : (diff >= 0 ? 360 : 0)
|
||||||
|
handFromAnimation.from = root.pickMinutes ? (diff >= 0 ? 360 : 0) : (diff >= 0 ? 0 : 360)
|
||||||
|
}
|
||||||
|
circleToAnimation.to = handToAnimation.to / 180 * Math.PI
|
||||||
|
circleFromAnimation.from = handFromAnimation.from / 180 * Math.PI
|
||||||
|
|
||||||
|
var toMiddleTime
|
||||||
|
var fromMiddleTime
|
||||||
|
if (root.pickMinutes) {
|
||||||
|
toMiddleTime = Math.abs(hourAngle - handToAnimation.to) / 180 * 400
|
||||||
|
fromMiddleTime = Math.abs(minAngle - handFromAnimation.from) / 180 * 400
|
||||||
|
} else {
|
||||||
|
toMiddleTime = Math.abs(minAngle - handToAnimation.to) / 180 * 400
|
||||||
|
fromMiddleTime = Math.abs(hourAngle - handFromAnimation.from) / 180 * 400
|
||||||
|
}
|
||||||
|
handToAnimation.duration = circleToAnimation.duration = toMiddleTime
|
||||||
|
handFromAnimation.duration = circleFromAnimation.duration = fromMiddleTime
|
||||||
|
|
||||||
|
animation.interval = Math.max(toMiddleTime + fromMiddleTime, 200)
|
||||||
|
|
||||||
|
animation.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: disableAnimationTimer
|
id: animation
|
||||||
interval: 400
|
|
||||||
repeat: false
|
|
||||||
onTriggered: handAnimation.enabled = circleAnimation.enabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: clock
|
id: clock
|
||||||
|
|
||||||
|
property bool pickMinutes: false
|
||||||
|
|
||||||
width: Math.min(root.width, root.height)
|
width: Math.min(root.width, root.height)
|
||||||
height: width
|
height: width
|
||||||
radius: width / 2
|
radius: width / 2
|
||||||
@ -98,13 +128,14 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enabled: !animation.running
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
pressAndHoldInterval: 100
|
pressAndHoldInterval: 100
|
||||||
|
|
||||||
onClicked: (mouse) => { selectTime(mouse, true); root.pickMinutes = true }
|
onClicked: (mouse) => { selectTime(mouse, true); clock.pickMinutes = true }
|
||||||
onPositionChanged: (mouse) => { if (isHold) selectTime(mouse) }
|
onPositionChanged: (mouse) => { if (isHold) selectTime(mouse) }
|
||||||
onPressAndHold: (mouse) => { isHold = true; selectTime(mouse) }
|
onPressAndHold: (mouse) => { isHold = true; selectTime(mouse) }
|
||||||
onReleased: { if (isHold) { isHold = false; root.pickMinutes = true } }
|
onReleased: { if (isHold) { isHold = false; clock.pickMinutes = true } }
|
||||||
}
|
}
|
||||||
|
|
||||||
// clock hand
|
// clock hand
|
||||||
@ -125,9 +156,15 @@ Item {
|
|||||||
color: root.clockHandColor
|
color: root.clockHandColor
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
Behavior on rotation {
|
Behavior on rotation {
|
||||||
id: handAnimation
|
enabled: animation.running
|
||||||
enabled: false
|
SequentialAnimation {
|
||||||
NumberAnimation { duration: 400 }
|
NumberAnimation { id: handToAnimation }
|
||||||
|
NumberAnimation { id: handFromAnimation }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Behavior on height {
|
||||||
|
enabled: animation.running
|
||||||
|
NumberAnimation { duration: animation.interval }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,9 +196,11 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Behavior on angle {
|
Behavior on angle {
|
||||||
id: circleAnimation
|
enabled: animation.running
|
||||||
enabled: false
|
SequentialAnimation {
|
||||||
NumberAnimation { duration: 400 }
|
NumberAnimation { id: circleToAnimation }
|
||||||
|
NumberAnimation { id: circleFromAnimation }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,9 +227,9 @@ Item {
|
|||||||
font.pixelSize: root.labelsSize
|
font.pixelSize: root.labelsSize
|
||||||
visible: root.time24h
|
visible: root.time24h
|
||||||
opacity: root.pickMinutes ? 0 : 1
|
opacity: root.pickMinutes ? 0 : 1
|
||||||
color: root.labelsColor
|
color: layer.enabled || modelData != root.hours ? root.labelsColor : root.labelsSelectedColor
|
||||||
text: modelData
|
text: modelData
|
||||||
layer.enabled: true
|
layer.enabled: root.labelsSelectedColor != root.labelsColor && animation.running
|
||||||
layer.samplerName: "maskSource"
|
layer.samplerName: "maskSource"
|
||||||
layer.effect: shaderEffect
|
layer.effect: shaderEffect
|
||||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||||
@ -210,9 +249,24 @@ Item {
|
|||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
font.pixelSize: root.labelsSize
|
font.pixelSize: root.labelsSize
|
||||||
opacity: root.pickMinutes ? 0 : 1
|
opacity: root.pickMinutes ? 0 : 1
|
||||||
color: root.labelsColor
|
color: {
|
||||||
|
if (!layer.enabled) {
|
||||||
|
if (root.time24h) {
|
||||||
|
if (modelData == root.hours)
|
||||||
|
return root.labelsSelectedColor
|
||||||
|
} else if (root.isPM) {
|
||||||
|
if (modelData == root.hours - 12
|
||||||
|
|| (modelData == 12 && root.hours == 12))
|
||||||
|
return root.labelsSelectedColor
|
||||||
|
} else if (modelData == root.hours
|
||||||
|
|| (modelData == 12 && root.hours == 0)) {
|
||||||
|
return root.labelsSelectedColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root.labelsColor
|
||||||
|
}
|
||||||
text: modelData
|
text: modelData
|
||||||
layer.enabled: true
|
layer.enabled: root.labelsSelectedColor != root.labelsColor && animation.running
|
||||||
layer.samplerName: "maskSource"
|
layer.samplerName: "maskSource"
|
||||||
layer.effect: shaderEffect
|
layer.effect: shaderEffect
|
||||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||||
@ -233,9 +287,14 @@ Item {
|
|||||||
font.pixelSize: root.labelsSize
|
font.pixelSize: root.labelsSize
|
||||||
visible: modelData % 5 == 0
|
visible: modelData % 5 == 0
|
||||||
opacity: root.pickMinutes ? 1 : 0
|
opacity: root.pickMinutes ? 1 : 0
|
||||||
color: root.labelsColor
|
color: animation.running || modelData != root.minutes
|
||||||
|
? root.labelsColor : root.labelsSelectedColor
|
||||||
text: _zeroPad(modelData)
|
text: _zeroPad(modelData)
|
||||||
layer.enabled: true
|
layer.enabled: animation.running
|
||||||
|
|| (root.labelsSelectedColor != root.labelsColor
|
||||||
|
&& root.minutes != modelData
|
||||||
|
&& (Math.abs(root.minutes - modelData) < 5
|
||||||
|
|| (modelData == 0 && root.minutes > 55)))
|
||||||
layer.samplerName: "maskSource"
|
layer.samplerName: "maskSource"
|
||||||
layer.effect: shaderEffect
|
layer.effect: shaderEffect
|
||||||
Behavior on opacity { NumberAnimation { duration: 200 } }
|
Behavior on opacity { NumberAnimation { duration: 200 } }
|
||||||
|
@ -32,7 +32,7 @@ Dialog {
|
|||||||
focus: true
|
focus: true
|
||||||
|
|
||||||
onOpened: timePicker.update()
|
onOpened: timePicker.update()
|
||||||
onClosed: timePicker.pickMinutes = false
|
onClosed: timePicker.setPickMinutes(false)
|
||||||
|
|
||||||
on_IsLandscapeChanged: updateTimer.restart()
|
on_IsLandscapeChanged: updateTimer.restart()
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ Dialog {
|
|||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: timePicker.pickMinutes = false
|
onClicked: timePicker.setPickMinutes(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ Dialog {
|
|||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: timePicker.pickMinutes = true
|
onClicked: timePicker.setPickMinutes(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user