252 lines
7.4 KiB
QML
252 lines
7.4 KiB
QML
import QtQuick
|
|
import qs.Commons
|
|
import "CalendarModel.js" as CalendarModel
|
|
|
|
Column {
|
|
id: root
|
|
|
|
property date today: new Date()
|
|
property int weekStart: CalendarModel.normalizedWeekStart(null, Qt.locale().firstDayOfWeek)
|
|
property color foreground: Color.foreground
|
|
property string fontFamily: Style.font.family
|
|
property bool showWeekNumbers: false
|
|
property bool navigationAtBottom: false
|
|
property string weekHeaderTooltip: ""
|
|
|
|
property real cellWidth: Style.space(36)
|
|
property real cellHeight: Style.space(28)
|
|
property real cellSpacing: Style.space(2)
|
|
property real weekColumnWidth: Style.space(32)
|
|
property real gutterWidth: Style.space(14)
|
|
|
|
property int viewYear: today.getFullYear()
|
|
property int viewMonth: today.getMonth()
|
|
property int selectedYear: today.getFullYear()
|
|
property int selectedMonth: today.getMonth()
|
|
property int selectedDay: today.getDate()
|
|
|
|
property bool pickingMonth: false
|
|
property int pickerYear: viewYear
|
|
property int pickerMonth: viewMonth
|
|
|
|
readonly property string todayKey: CalendarModel.keyForDate(today)
|
|
readonly property string selectedKey: CalendarModel.dateKey(selectedYear, selectedMonth, selectedDay)
|
|
readonly property bool selectionIsToday: selectedKey === todayKey
|
|
readonly property bool viewingCurrentMonth: viewYear === today.getFullYear() && viewMonth === today.getMonth()
|
|
readonly property date viewDate: new Date(viewYear, viewMonth, 1)
|
|
readonly property date selectedDate: new Date(selectedYear, selectedMonth, selectedDay)
|
|
readonly property int selectedOffset: CalendarModel.daysBetween(
|
|
today.getFullYear(), today.getMonth(), today.getDate(), selectedYear, selectedMonth, selectedDay)
|
|
readonly property var labelLocale: Qt.locale("en_US")
|
|
readonly property real gridWidth: body.width
|
|
readonly property color mutedForeground: Qt.darker(foreground, 1.5)
|
|
|
|
signal weekHeaderClicked()
|
|
|
|
spacing: Style.space(8)
|
|
|
|
function weekdayLabel(weekday) {
|
|
return String(labelLocale.dayName(weekday, Locale.ShortFormat)).toUpperCase()
|
|
}
|
|
|
|
function monthLabel(month) {
|
|
return String(labelLocale.monthName(month, Locale.ShortFormat)).toUpperCase()
|
|
}
|
|
|
|
function selectDay(year, month, day) {
|
|
selectedYear = year
|
|
selectedMonth = month
|
|
selectedDay = day
|
|
viewYear = year
|
|
viewMonth = month
|
|
pickingMonth = false
|
|
}
|
|
|
|
function goToToday() {
|
|
selectDay(today.getFullYear(), today.getMonth(), today.getDate())
|
|
}
|
|
|
|
function moveMonth(delta) {
|
|
var next = CalendarModel.stepMonth(viewYear, viewMonth, delta)
|
|
selectDay(next.year, next.month, CalendarModel.clampDay(next.year, next.month, selectedDay))
|
|
}
|
|
|
|
function moveYear(delta) {
|
|
if (pickingMonth) pickerYear += delta
|
|
else moveMonth(delta * 12)
|
|
}
|
|
|
|
function moveSelection(days) {
|
|
var next = CalendarModel.stepDay(selectedYear, selectedMonth, selectedDay, days)
|
|
selectDay(next.year, next.month, next.day)
|
|
}
|
|
|
|
function movePickerCursor(months) {
|
|
var next = CalendarModel.stepMonth(pickerYear, pickerMonth, months)
|
|
pickerYear = next.year
|
|
pickerMonth = next.month
|
|
}
|
|
|
|
function handleMove(dx, dy) {
|
|
if (pickingMonth) movePickerCursor(dx + dy * 4)
|
|
else moveSelection(dx + dy * 7)
|
|
}
|
|
|
|
function openPicker() {
|
|
pickerYear = viewYear
|
|
pickerMonth = viewMonth
|
|
pickingMonth = true
|
|
}
|
|
|
|
function togglePicker() {
|
|
if (pickingMonth) pickingMonth = false
|
|
else openPicker()
|
|
}
|
|
|
|
function choosePickerMonth(year, month) {
|
|
selectDay(year, month, CalendarModel.clampDay(year, month, selectedDay))
|
|
}
|
|
|
|
function activate() {
|
|
if (pickingMonth) choosePickerMonth(pickerYear, pickerMonth)
|
|
else goToToday()
|
|
}
|
|
|
|
function dismissPicker() {
|
|
if (!pickingMonth) return false
|
|
pickingMonth = false
|
|
return true
|
|
}
|
|
|
|
function selectedSummary() {
|
|
var format = selectedYear === today.getFullYear() ? "dddd, MMMM d" : "dddd, MMMM d, yyyy"
|
|
return Qt.formatDate(selectedDate, format)
|
|
+ " · Day " + CalendarModel.dayOfYear(selectedYear, selectedMonth, selectedDay)
|
|
+ " · " + CalendarModel.relativeDayLabel(selectedOffset)
|
|
}
|
|
|
|
MonthNavigation {
|
|
visible: !root.navigationAtBottom
|
|
}
|
|
|
|
Item {
|
|
width: root.width
|
|
height: body.height
|
|
|
|
Item {
|
|
id: body
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: days.width
|
|
height: days.height
|
|
|
|
CalendarDays {
|
|
id: days
|
|
calendar: root
|
|
visible: !root.pickingMonth
|
|
}
|
|
|
|
CalendarMonthPicker {
|
|
anchors.fill: parent
|
|
calendar: root
|
|
visible: root.pickingMonth
|
|
}
|
|
|
|
WheelHandler {
|
|
onWheel: function(event) {
|
|
if (event.angleDelta.y === 0) return
|
|
var step = event.angleDelta.y > 0 ? -1 : 1
|
|
if (root.pickingMonth) root.pickerYear += step
|
|
else root.moveMonth(step)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
width: root.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
textFormat: Text.PlainText
|
|
elide: Text.ElideRight
|
|
text: root.selectedSummary()
|
|
color: root.mutedForeground
|
|
font.family: root.fontFamily
|
|
font.pixelSize: Style.font.bodySmall
|
|
}
|
|
|
|
MonthNavigation {
|
|
visible: root.navigationAtBottom
|
|
}
|
|
|
|
component MonthNavigation: Item {
|
|
width: root.width
|
|
height: visible ? navigationLabel.implicitHeight + Style.space(10) : 0
|
|
|
|
Item {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
width: body.width
|
|
height: parent.height
|
|
|
|
Rectangle {
|
|
anchors.centerIn: navigationLabel
|
|
width: navigationLabel.width
|
|
height: navigationLabel.implicitHeight + Style.space(6)
|
|
radius: Style.cornerRadius
|
|
color: navigationMouse.containsMouse ? Style.hoverFillFor(root.foreground, Color.accent) : "transparent"
|
|
}
|
|
|
|
Text {
|
|
id: navigationLabel
|
|
anchors.centerIn: parent
|
|
width: Style.space(150)
|
|
horizontalAlignment: Text.AlignHCenter
|
|
textFormat: Text.PlainText
|
|
text: root.pickingMonth
|
|
? String(root.pickerYear)
|
|
: Qt.formatDate(root.viewDate, "MMMM yyyy").toUpperCase()
|
|
color: navigationMouse.containsMouse
|
|
? Style.hoverStateColor(root.foreground, Color.accent)
|
|
: Qt.darker(root.foreground, 1.4)
|
|
font.family: root.fontFamily
|
|
font.pixelSize: Style.font.body
|
|
font.letterSpacing: 1
|
|
}
|
|
|
|
MouseArea {
|
|
id: navigationMouse
|
|
anchors.fill: navigationLabel
|
|
hoverEnabled: true
|
|
cursorShape: Qt.PointingHandCursor
|
|
onClicked: root.togglePicker()
|
|
|
|
PanelToolTip {
|
|
visible: navigationMouse.containsMouse
|
|
text: root.pickingMonth ? "Back to the days" : "Pick a month"
|
|
fontFamily: root.fontFamily
|
|
}
|
|
}
|
|
|
|
PanelActionButton {
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: -Style.space(8)
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
iconText: ""
|
|
tooltipText: root.pickingMonth ? "Previous year" : "Previous month"
|
|
foreground: root.foreground
|
|
fontFamily: root.fontFamily
|
|
onClicked: root.pickingMonth ? root.moveYear(-1) : root.moveMonth(-1)
|
|
}
|
|
|
|
PanelActionButton {
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: -Style.space(8)
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
iconText: ""
|
|
tooltipText: root.pickingMonth ? "Next year" : "Next month"
|
|
foreground: root.foreground
|
|
fontFamily: root.fontFamily
|
|
onClicked: root.pickingMonth ? root.moveYear(1) : root.moveMonth(1)
|
|
}
|
|
}
|
|
}
|
|
}
|