DPS_Manage/DelegateUI/Controls/DelTimePicker.qml

470 lines
17 KiB
QML

import QtQuick 2.15
import QtGraphicalEffects 1.15
import QtQuick.Controls 2.15 as T
import QtQuick.Window 2.15
import DelegateUI 1.0
T.TextField {
id: control
enum IconPosition {
Position_Left = 0,
Position_Right = 1
}
enum TimeFormat {
Format_HHMMSS = 0,
Format_HHMM = 1,
Format_MMSS = 2
}
popupFont {
family: DelTheme.DelTimePicker.fontFamily
pixelSize: DelTheme.DelTimePicker.fontSize
}
signal acceptedTime(time: string)
property bool animationEnabled: DelTheme.animationEnabled
readonly property bool active: hovered || activeFocus
property int format: DelTimePicker.Format_HHMMSS
property int iconSize: DelTheme.DelTimePicker.fontIconSize
property int iconPosition: DelTimePicker.Position_Right
property color colorText: enabled ? DelTheme.DelTimePicker.colorText : DelTheme.DelTimePicker.colorTextDisabled
property color colorBorder: enabled ?
active ? DelTheme.DelTimePicker.colorBorderHover :
DelTheme.DelTimePicker.colorBorder : DelTheme.DelTimePicker.colorBorderDisabled
property color colorBg: enabled ? DelTheme.DelTimePicker.colorBg : DelTheme.DelTimePicker.colorBgDisabled
property color colorPopupText: DelTheme.DelTimePicker.colorPopupText
property font popupFont
property int radiusBg: 6
property int radiusPopupBg: 6
property string contentDescription: ''
function clearTime() {
if (__private.cleared) {
control.text = '';
} else {
control.text = __private.getTime();
}
}
Behavior on colorText { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
Behavior on colorBorder { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
Behavior on colorBg { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
Behavior on placeholderTextColor { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
objectName: '__DelTimePicker__'
focus: __picker.opened
padding: 5
leftPadding: 10 + (iconPosition == DelTimePicker.Position_Left ? iconSize : 0)
rightPadding: 10 + (iconPosition == DelTimePicker.Position_Right ? iconSize : 0)
width: 130
implicitWidth: contentWidth + leftPadding + rightPadding
implicitHeight: contentHeight + topPadding + bottomPadding
placeholderText: qsTr('请选择时间')
color: colorText
placeholderTextColor: enabled ? DelTheme.DelTimePicker.colorPlaceholderText : DelTheme.DelTimePicker.colorPlaceholderTextDisabled
selectedTextColor: DelTheme.DelTimePicker.colorSelectedText
selectionColor: DelTheme.DelTimePicker.colorSelection
font {
family: DelTheme.DelTimePicker.fontFamily
pixelSize: DelTheme.DelTimePicker.fontSize
}
background: Rectangle {
color: control.colorBg
border.color: control.colorBorder
radius: control.radiusBg
}
onActiveFocusChanged: {
if (activeFocus)
__picker.open();
}
onTextEdited: {
__private.commit();
}
onEditingFinished: {
clearTime();
}
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
__confirmButton.clicked();
}
}
component TimeListView: MouseArea {
id: __rootItem
property string value: '00'
property string checkValue: '00'
property string tempValue: '00'
property alias model: __listView.model
function clearCheck() {
value = checkValue = tempValue = '00';
if (__buttonGroup.checkedButton != null)
__buttonGroup.checkedButton.checked = false;
var item = __listView.itemAtIndex(0);
if (item)
item.checked = true;
__listView.positionViewAtBeginning();
}
function initValue(v) {
value = checkValue = tempValue = v;
}
function checkIndex(index) {
checkValue = tempValue = (String(index).padStart(2, '0'));
var item = __listView.itemAtIndex(index);
if (item) {
item.checked = true;
item.clicked();
}
__listView.positionViewAtIndex(index, ListView.Beginning);
}
function positionViewAtIndex(index, mode) {
__listView.positionViewAtIndex(index, mode);
}
width: 50
height: parent.height
hoverEnabled: true
onExited: {
tempValue = checkValue;
control.text = __private.getCheckTime();
}
ListView {
id: __listView
height: parent.height
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 2
clip: true
boundsBehavior: Flickable.StopAtBounds
delegate: T.AbstractButton {
width: __listView.width
height: 28
checkable: true
contentItem: Text {
id: __viewText
font: control.popupFont
text: String(index).padStart(2, '0')
color: control.colorPopupText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
radius: 4
color: hovered ? DelTheme.DelTimePicker.colorButtonBgHover :
checked ? DelTheme.DelTimePicker.colorButtonBgActive : 'transparent'
}
T.ButtonGroup.group: __buttonGroup
onClicked: {
__rootItem.checkValue = __viewText.text;
}
onHoveredChanged: {
if (hovered) {
__rootItem.tempValue = __viewText.text;
control.text = __private.getTempTime();
}
}
Component.onCompleted: checked = (index == 0);
}
onContentHeightChanged: cacheBuffer = contentHeight;
T.ScrollBar.vertical: DelScrollBar { policy: T.ScrollBar.AsNeeded }
T.ButtonGroup {
id: __buttonGroup
}
}
}
Item {
id: __private
property var window: Window.window
property bool cleared: true
function getTime() {
switch (control.format) {
case DelTimePicker.Format_HHMMSS:
return`${__hourListView.value}:${__minuteListView.value}:${__secondListView.value}`;
case DelTimePicker.Format_HHMM:
return`${__hourListView.value}:${__minuteListView.value}`;
case DelTimePicker.Format_MMSS:
return`${__minuteListView.value}:${__secondListView.value}`;
}
}
function getCheckTime() {
switch (control.format) {
case DelTimePicker.Format_HHMMSS:
return`${__hourListView.checkValue}:${__minuteListView.checkValue}:${__secondListView.checkValue}`;
case DelTimePicker.Format_HHMM:
return`${__hourListView.checkValue}:${__minuteListView.checkValue}`;
case DelTimePicker.Format_MMSS:
return`${__minuteListView.checkValue}:${__secondListView.checkValue}`;
}
}
function getTempTime() {
switch (control.format) {
case DelTimePicker.Format_HHMMSS:
return`${__hourListView.tempValue}:${__minuteListView.tempValue}:${__secondListView.tempValue}`;
case DelTimePicker.Format_HHMM:
return`${__hourListView.tempValue}:${__minuteListView.tempValue}`;
case DelTimePicker.Format_MMSS:
return`${__minuteListView.tempValue}:${__secondListView.tempValue}`;
}
}
function testValid() {
let reg;
switch (control.format) {
case DelTimePicker.Format_HHMMSS:
reg = /^([0-1]\d|2[0-3]):([0-5]\d):([0-5]\d)$/;
break;
case DelTimePicker.Format_HHMM:
reg = /^([0-1]\d|2[0-3]):([0-5]\d)$/;
break;
case DelTimePicker.Format_MMSS:
reg = /^([0-5]\d):([0-5]\d)$/;
break;
}
return reg.test(control.text);
}
function commit() {
let hour = '';
let minute = '';
let second = '';
if (testValid()) {
switch (control.format) {
case DelTimePicker.Format_HHMMSS:
hour = control.getText(0, 2);
minute = control.getText(3, 5);
second = control.getText(6, 8);
break;
case DelTimePicker.Format_HHMM:
hour = control.getText(0, 2);
minute = control.getText(3, 5);
break;
case DelTimePicker.Format_MMSS:
minute = control.getText(0, 2);
second = control.getText(3, 5);
break;
}
if (hour.length === 2) {
const index = parseInt(hour);
__hourListView.value = hour;
__hourListView.checkIndex(index);
}
if (minute.length === 2) {
const index = parseInt(minute);
__minuteListView.value = minute;
__minuteListView.checkIndex(index);
}
if (second.length === 2) {
const index = parseInt(second);
__secondListView.value = second;
__secondListView.checkIndex(index);
}
}
}
}
TapHandler {
onTapped: {
__picker.open();
}
}
DelIconText {
anchors.left: control.iconPosition == DelTimePicker.Position_Left ? parent.left : undefined
anchors.right: control.iconPosition == DelTimePicker.Position_Right ? parent.right : undefined
anchors.margins: 5
anchors.verticalCenter: parent.verticalCenter
iconSource: (control.hovered && control.text.length !== 0) ? DelIcon.CloseCircleFilled : DelIcon.ClockCircleOutlined
iconSize: control.iconSize
colorIcon: control.enabled ?
__iconMouse.hovered ? DelTheme.DelTimePicker.colorIconHover :
DelTheme.DelTimePicker.colorIcon : DelTheme.DelTimePicker.colorIconDisabled
Behavior on colorIcon { enabled: control.animationEnabled; ColorAnimation { duration: DelTheme.Primary.durationFast } }
MouseArea {
id: __iconMouse
anchors.fill: parent
hoverEnabled: true
cursorShape: parent.iconSource == DelIcon.CloseCircleFilled ? Qt.PointingHandCursor : Qt.ArrowCursor
onEntered: hovered = true;
onExited: hovered = false;
property bool hovered: false
onClicked: {
__hourListView.clearCheck();
__minuteListView.clearCheck();
__secondListView.clearCheck();
__private.cleared = true;
control.text = '';
}
}
}
DelPopup {
id: __picker
implicitWidth: implicitContentWidth + leftPadding + rightPadding
implicitHeight: implicitContentHeight + topPadding + bottomPadding
leftPadding: 2
rightPadding: 2
topPadding: 6
bottomPadding: 6
closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent
enter: Transition {
NumberAnimation {
property: 'opacity'
from: 0.0
to: 1.0
easing.type: Easing.InOutQuad
duration: control.animationEnabled ? DelTheme.Primary.durationMid : 0
}
}
exit: Transition {
NumberAnimation {
property: 'opacity'
from: 1.0
to: 0.0
easing.type: Easing.InOutQuad
duration: control.animationEnabled ? DelTheme.Primary.durationMid : 0
}
}
onAboutToShow: {
const pos = control.mapToItem(null, 0, 0);
x = (control.width - width) * 0.5;
if (__private.window.height > (pos.y + control.height + height + 6)){
y = control.height + 6;
} else if (pos.y > height) {
y = -height - 6;
} else {
y = __private.window.height - (pos.y + height + 6);
}
__private.commit();
}
onAboutToHide: {
control.editingFinished();
}
contentItem: Item {
implicitWidth: __row.width
implicitHeight: 250
Row {
id: __row
height: parent.height - 30
TimeListView {
id: __hourListView
model: 24
visible: control.format == DelTimePicker.Format_HHMMSS ||
control.format == DelTimePicker.Format_HHMM
DelDivider {
width: 1
height: parent.height
anchors.right: parent.right
orientation: Qt.Vertical
}
}
TimeListView {
id: __minuteListView
model: 60
visible: control.format == DelTimePicker.Format_HHMMSS ||
control.format == DelTimePicker.Format_HHMM ||
control.format == DelTimePicker.Format_MMSS
DelDivider {
width: 1
height: parent.height
anchors.right: parent.right
orientation: Qt.Vertical
visible: control.format == DelTimePicker.Format_HHMMSS ||
control.format == DelTimePicker.Format_MMSS
}
}
TimeListView {
id: __secondListView
model: 60
visible: control.format == DelTimePicker.Format_HHMMSS ||
control.format == DelTimePicker.Format_MMSS
}
}
Item {
width: parent.width
anchors.top: __row.bottom
anchors.bottom: parent.bottom
DelDivider {
width: parent.width
height: 1
}
DelButton {
padding: 2
topPadding: 2
bottomPadding: 2
anchors.left: parent.left
anchors.leftMargin: 5
anchors.bottom: parent.bottom
type: DelButton.Type_Text
text: qsTr('此刻')
colorBg: 'transparent'
onClicked: {
const now = new Date();
__hourListView.initValue(String(now.getHours()).padStart(2, '0'));
__hourListView.checkIndex(now.getHours());
__minuteListView.initValue(String(now.getMinutes()).padStart(2, '0'));
__minuteListView.checkIndex(now.getMinutes());
__secondListView.initValue(String(now.getSeconds()).padStart(2, '0'));
__secondListView.checkIndex(now.getSeconds());
__private.cleared = false;
__picker.close();
control.acceptedTime(__private.getTime());
control.text = __private.getTime();
}
}
DelButton {
id: __confirmButton
topPadding: 2
bottomPadding: 2
leftPadding: 10
rightPadding: 10
anchors.right: parent.right
anchors.rightMargin: 5
anchors.bottom: parent.bottom
type: DelButton.Type_Primary
text: qsTr('确定')
onClicked: {
__hourListView.initValue(__hourListView.tempValue);
__minuteListView.initValue(__minuteListView.tempValue);
__secondListView.initValue(__secondListView.tempValue);
__private.cleared = false;
__picker.close();
control.acceptedTime(__private.getTime());
control.text = __private.getTime();
}
}
}
}
}
Accessible.role: Accessible.EditableText
Accessible.editable: true
Accessible.description: control.contentDescription
}