Revert "Redesign calendar component"

This reverts commit b6f9e51b65cd4fad354f7604e75960d3ab88647a. The MR
was not approved by anyone and still had outstanding criticisms raised
in the VDG room that were not addressed.

CCMAIL: carl@carlschwan.eu
This commit is contained in:
Jan Blackquill 2021-03-25 19:28:02 -04:00
parent b6f9e51b65
commit d526a2c29a
2 changed files with 313 additions and 234 deletions

View File

@ -20,27 +20,37 @@ Item {
signal headerClicked signal headerClicked
signal previous
signal next
signal activated(int index, var date, var item) signal activated(int index, var date, var item)
// so it forwards it to the delegate which then emits activated with all the necessary data // so it forwards it to the delegate which then emits activated with all the necessary data
signal activateHighlightedItem signal activateHighlightedItem
readonly property int gridColumns: showWeekNumbers ? calendarGrid.columns + 1 : calendarGrid.columns readonly property int gridColumns: showWeekNumbers ? calendarGrid.columns + 1 : calendarGrid.columns
property alias previousLabel: previousButton.tooltip
property alias nextLabel: nextButton.tooltip
property int rows property int rows
property int columns property int columns
property bool showWeekNumbers property bool showWeekNumbers
onShowWeekNumbersChanged: canvas.requestPaint()
// how precise date matching should be, 3 = day+month+year, 2 = month+year, 1 = just year // how precise date matching should be, 3 = day+month+year, 2 = month+year, 1 = just year
property int dateMatchingPrecision property int dateMatchingPrecision
property alias headerModel: days.model property alias headerModel: days.model
property alias gridModel: repeater.model property alias gridModel: repeater.model
property alias title: heading.text
// Take the calendar width, subtract the inner and outer spacings and divide by number of columns (==days in week) // Take the calendar width, subtract the inner and outer spacings and divide by number of columns (==days in week)
readonly property int cellWidth: Math.floor((swipeView.width - (daysCalendar.columns + 1) * root.borderWidth) / (daysCalendar.columns + (showWeekNumbers ? 1 : 0))) readonly property int cellWidth: Math.floor((stack.width - (daysCalendar.columns + 1) * root.borderWidth) / (daysCalendar.columns + (showWeekNumbers ? 1 : 0)))
// Take the calendar height, subtract the inner spacings and divide by number of rows (root.weeks + one row for day names) // Take the calendar height, subtract the inner spacings and divide by number of rows (root.weeks + one row for day names)
readonly property int cellHeight: Math.floor((swipeView.height - heading.height - calendarGrid.rows * root.borderWidth) / calendarGrid.rows) readonly property int cellHeight: Math.floor((stack.height - heading.height - calendarGrid.rows * root.borderWidth) / calendarGrid.rows)
property real transformScale: 1 property real transformScale: 1
property point transformOrigin: Qt.point(width / 2, height / 2) property point transformOrigin: Qt.point(width / 2, height / 2)
@ -66,6 +76,166 @@ Item {
} }
} }
RowLayout {
anchors {
top: parent.top
left: canvas.left
right: canvas.right
}
spacing: PlasmaCore.Units.smallSpacing
PlasmaExtras.Heading {
id: heading
Layout.fillWidth: true
level: 2
elide: Text.ElideRight
font.capitalization: Font.Capitalize
//SEE QTBUG-58307
//try to make all heights an even number, otherwise the layout engine gets confused
Layout.preferredHeight: implicitHeight + implicitHeight%2
MouseArea {
id: monthMouse
property int previousPixelDelta
anchors.fill: parent
onClicked: {
if (!stack.busy) {
daysCalendar.headerClicked()
}
}
onExited: previousPixelDelta = 0
onWheel: {
var delta = wheel.angleDelta.y || wheel.angleDelta.x
var pixelDelta = wheel.pixelDelta.y || wheel.pixelDelta.x
// For high-precision touchpad scrolling, we get a wheel event for basically every slightest
// finger movement. To prevent the view from suddenly ending up in the next century, we
// cumulate all the pixel deltas until they're larger than the label and then only change
// the month. Standard mouse wheel scrolling is unaffected since it's fine.
if (pixelDelta) {
if (Math.abs(previousPixelDelta) < monthMouse.height) {
previousPixelDelta += pixelDelta
return
}
}
if (delta >= 15) {
daysCalendar.previous()
} else if (delta <= -15) {
daysCalendar.next()
}
previousPixelDelta = 0
}
}
}
Components.ToolButton {
id: previousButton
property string tooltip
icon.name: Qt.application.layoutDirection === Qt.RightToLeft ? "go-next" : "go-previous"
onClicked: daysCalendar.previous()
Accessible.name: tooltip
Components.ToolTip { text: parent.tooltip }
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight%2
}
Components.ToolButton {
icon.name: "go-jump-today"
property string tooltip
onClicked: root.resetToToday()
tooltip: i18ndc("libplasma5", "Reset calendar to today", "Today")
Accessible.name: tooltip
Accessible.description: i18nd("libplasma5", "Reset calendar to today")
Components.ToolTip { text: parent.tooltip }
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight%2
}
Components.ToolButton {
id: nextButton
property string tooltip
icon.name: Qt.application.layoutDirection === Qt.RightToLeft ? "go-previous" : "go-next"
onClicked: daysCalendar.next()
Accessible.name: tooltip
Components.ToolTip { text: parent.tooltip }
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight%2
}
}
// Paints the inner grid and the outer frame
Canvas {
id: canvas
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
}
width: (daysCalendar.cellWidth + root.borderWidth) * gridColumns + root.borderWidth
height: (daysCalendar.cellHeight + root.borderWidth) * calendarGrid.rows + root.borderWidth
opacity: root.borderOpacity
antialiasing: false
clip: false
onPaint: {
var ctx = getContext("2d");
// this is needed as otherwise the canvas seems to have some sort of
// inner clip region which does not update on size changes
ctx.reset();
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = PlasmaCore.Theme.textColor;
ctx.lineWidth = root.borderWidth
ctx.globalAlpha = 1.0;
ctx.beginPath();
// When line is more wide than 1px, it is painted with 1px line at the actual coords
// and then 1px lines are added first to the left of the middle then right (then left again)
// So all the lines need to be offset a bit to have their middle point in the center
// of the grid spacing rather than on the left most pixel, otherwise they will be painted
// over the days grid which will be visible on eg. mouse hover
var lineBasePoint = Math.floor(root.borderWidth / 2)
// horizontal lines
for (var i = 0; i < calendarGrid.rows + 1; i++) {
var lineY = lineBasePoint + (daysCalendar.cellHeight + root.borderWidth) * (i);
if (i == 0 || i == calendarGrid.rows) {
ctx.moveTo(0, lineY);
} else {
ctx.moveTo(showWeekNumbers ? daysCalendar.cellWidth + root.borderWidth : root.borderWidth, lineY);
}
ctx.lineTo(width, lineY);
}
// vertical lines
for (var i = 0; i < gridColumns + 1; i++) {
var lineX = lineBasePoint + (daysCalendar.cellWidth + root.borderWidth) * (i);
// Draw the outer vertical lines in full height so that it closes
// the outer rectangle
if (i == 0 || i == gridColumns || !daysCalendar.headerModel) {
ctx.moveTo(lineX, 0);
} else {
ctx.moveTo(lineX, root.borderWidth + daysCalendar.cellHeight);
}
ctx.lineTo(lineX, height);
}
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
PlasmaCore.Svg { PlasmaCore.Svg {
id: calendarSvg id: calendarSvg
imagePath: "widgets/calendar" imagePath: "widgets/calendar"
@ -81,13 +251,20 @@ Item {
} }
} }
Connections {
target: theme
function onTextColorChanged() {
canvas.requestPaint();
}
}
Column { Column {
id: weeksColumn id: weeksColumn
visible: showWeekNumbers visible: showWeekNumbers
anchors { anchors {
top: parent.top top: canvas.top
left: parent.left left: parent.left
bottom: parent.bottom bottom: canvas.bottom
// The borderWidth needs to be counted twice here because it goes // The borderWidth needs to be counted twice here because it goes
// in fact through two lines - the topmost one (the outer edge) // in fact through two lines - the topmost one (the outer edge)
// and then the one below weekday strings // and then the one below weekday strings
@ -114,8 +291,7 @@ Item {
id: calendarGrid id: calendarGrid
anchors { anchors {
top: parent.top right: canvas.right
right: parent.right
rightMargin: root.borderWidth rightMargin: root.borderWidth
bottom: parent.bottom bottom: parent.bottom
bottomMargin: root.borderWidth bottomMargin: root.borderWidth

View File

@ -6,15 +6,15 @@
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
import QtQuick 2.0 import QtQuick 2.0
import QtQuick.Controls 2.15 as QQC2 import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import org.kde.plasma.calendar 2.0 import org.kde.plasma.calendar 2.0
import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 3.0 as Components import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.extras 2.0 as PlasmaExtras
Item { PinchArea {
id: root id: root
anchors.fill: parent anchors.fill: parent
@ -39,130 +39,76 @@ Item {
property int firstDay: new Date(showDate.getFullYear(), showDate.getMonth(), 1).getDay() property int firstDay: new Date(showDate.getFullYear(), showDate.getMonth(), 1).getDay()
property alias today: calendarBackend.today property alias today: calendarBackend.today
property bool showWeekNumbers: false property bool showWeekNumbers: false
property bool showCustomHeader: false
/**
* Current index of the internal swipeView. Usefull for binding
* a TabBar to it.
*/
property alias currentIndex: swipeView.currentIndex
property alias cellHeight: mainDaysCalendar.cellHeight property alias cellHeight: mainDaysCalendar.cellHeight
property QtObject daysModel: calendarBackend.daysModel property QtObject daysModel: calendarBackend.daysModel
onPinchStarted: stack.currentItem.transformOrigin = pinch.center
onPinchUpdated: {
var item = stack.currentItem
if (stack.depth < 3 && pinch.scale < 1) {
item.transformScale = pinch.scale
item.opacity = pinch.scale
} else if (stack.depth > 1 && pinch.scale > 1) {
item.transformScale = pinch.scale
item.opacity = (2 - pinch.scale / 2)
}
}
onPinchFinished: {
var item = stack.currentItem
if (item.transformScale < 0.7) {
item.headerClicked()
} else if (item.transformScale > 1.4) {
item.activateHighlightedItem()
} else {
item.transformScale = 1
item.opacity = 1
}
}
function isToday(date) { function isToday(date) {
return date.toDateString() === new Date().toDateString(); if (date.toDateString() == new Date().toDateString()) {
return true;
}
return false;
} }
function eventDate(yearNumber,monthNumber,dayNumber) { function eventDate(yearNumber,monthNumber,dayNumber) {
const d = new Date(yearNumber, monthNumber-1, dayNumber); var d = new Date(yearNumber, monthNumber-1, dayNumber);
return Qt.formatDate(d, "dddd dd MMM yyyy"); return Qt.formatDate(d, "dddd dd MMM yyyy");
} }
/**
* Move calendar to month view showing today's date.
*/
function resetToToday() { function resetToToday() {
calendarBackend.resetToToday(); calendarBackend.resetToToday();
root.currentDate = root.today; root.currentDate = root.today;
swipeView.currentIndex = 0; stack.pop(null);
} }
function updateYearOverview() { function updateYearOverview() {
const date = calendarBackend.displayedDate; var date = calendarBackend.displayedDate;
const day = date.getDate(); var day = date.getDate();
const year = date.getFullYear(); var year = date.getFullYear();
for (let i = 0, j = monthModel.count; i < j; ++i) { for (var i = 0, j = monthModel.count; i < j; ++i) {
monthModel.setProperty(i, "yearNumber", year); monthModel.setProperty(i, "yearNumber", year);
} }
} }
function updateDecadeOverview() { function updateDecadeOverview() {
const date = calendarBackend.displayedDate; var date = calendarBackend.displayedDate;
const day = date.getDate(); var day = date.getDate();
const month = date.getMonth() + 1; var month = date.getMonth() + 1;
const year = date.getFullYear(); var year = date.getFullYear();
const decade = year - year % 10; var decade = year - year % 10;
for (let i = 0, j = yearModel.count; i < j; ++i) { for (var i = 0, j = yearModel.count; i < j; ++i) {
const label = decade - 1 + i; var label = decade - 1 + i;
yearModel.setProperty(i, "yearNumber", label); yearModel.setProperty(i, "yearNumber", label);
yearModel.setProperty(i, "label", label); yearModel.setProperty(i, "label", label);
} }
} }
/**
* Possible calendar views
*/
enum CalendarView {
DayView,
MonthView,
YearView
}
/**
* Go to the next month/year/decade depending on the current
* calendar view displayed.
*/
function nextFrame() {
if (swipeView.currentIndex === 0) {
calendarBackend.nextMonth();
} else if (swipeView.currentIndex === 1) {
calendarBackend.nextYear();
} else if (swipeView.currentIndex === 2) {
calendarBackend.nextDecade();
}
}
/**
* Go to the previous month/year/decade depending on the current
* calendar view displayed.
*/
function previousFrame() {
if (swipeView.currentIndex === 0) {
calendarBackend.previousMonth();
} else if (swipeView.currentIndex === 1) {
calendarBackend.previousYear();
} else if (swipeView.currentIndex === 2) {
calendarBackend.previousDecade();
}
}
/**
* \return CalendarView
*/
readonly property var calendarViewDisplayed: {
if (swipeView.currentIndex === 0) {
return MonthView.CalendarView.DayView;
} else if (swipeView.currentIndex === 1) {
return MonthView.CalendarView.MonthView;
} else if (swipeView.currentIndex === 2) {
return MonthView.CalendarView.YearView;
}
}
/**
* Show month view.
*/
function showMonthView() {
swipeView.currentIndex = 0;
}
/**
* Show year view.
*/
function showYearView() {
swipeView.currentIndex = 1;
}
/**
* Show month view.
*/
function showDecadeView() {
swipeView.currentIndex = 2;
}
Calendar { Calendar {
id: calendarBackend id: calendarBackend
@ -202,8 +148,6 @@ Item {
Component.onCompleted: { Component.onCompleted: {
for (var i = 0; i < 12; ++i) { for (var i = 0; i < 12; ++i) {
append({ append({
label: 2050, // this value will be overwritten, but it set the type of the property to int
yearNumber: 2050,
isCurrent: (i > 0 && i < 11) // first and last year are outside the decade isCurrent: (i > 0 && i < 11) // first and last year are outside the decade
}) })
} }
@ -221,136 +165,63 @@ Item {
onPressed: mouse.accepted = false onPressed: mouse.accepted = false
} }
ColumnLayout { StackView {
id: viewHeader id: stack
visible: !showCustomHeader
height: !visible ? 0 : implicitHeight
width: parent.width
anchors {
top: parent.top
}
RowLayout { anchors.fill: parent
PlasmaExtras.Heading {
id: heading
text: i18ndc("libplasma5", "Format: **month** year", "<strong>%1</strong> %2", root.selectedMonth, root.selectedYear.toString())
level: 2 delegate: StackViewDelegate {
elide: Text.ElideRight pushTransition: StackViewTransition {
font.capitalization: Font.Capitalize NumberAnimation {
//SEE QTBUG-58307 target: exitItem
//try to make all heights an even number, otherwise the layout engine gets confused duration: PlasmaCore.Units.longDuration
Layout.preferredHeight: implicitHeight + implicitHeight%2 property: "opacity"
Layout.fillWidth: true from: 1
to: 0
}
NumberAnimation {
target: enterItem
duration: PlasmaCore.Units.longDuration
property: "opacity"
from: 0
to: 1
}
NumberAnimation {
target: enterItem
duration: PlasmaCore.Units.longDuration
property: "transformScale"
from: 1.5
to: 1
}
} }
Row { popTransition: StackViewTransition {
spacing: 0 NumberAnimation {
Components.ToolButton { target: exitItem
id: previousButton duration: PlasmaCore.Units.longDuration
property string tooltip: { property: "opacity"
switch(root.calendarViewDisplayed) { from: 1
case MonthView.CalendarView.DayView: to: 0
return i18nd("libplasma5", "Previous Month")
case MonthView.CalendarView.MonthView:
return i18nd("libplasma5", "Previous Year")
case MonthView.CalendarView.YearView:
return i18nd("libplasma5", "Previous Decade")
default:
return "";
}
}
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight % 2
icon.name: Qt.application.layoutDirection === Qt.RightToLeft ? "go-next" : "go-previous"
onClicked: root.previousFrame()
Accessible.name: tooltip
Components.ToolTip { text: parent.tooltip }
} }
NumberAnimation {
Components.ToolButton { target: exitItem
icon.name: "go-jump-today" duration: PlasmaCore.Units.longDuration
property string tooltip property: "transformScale"
// so no matter how much you scaled, it would still fly towards you
//SEE QTBUG-58307 to: exitItem.transformScale * 1.5
Layout.preferredHeight: implicitHeight + implicitHeight % 2
onClicked: root.resetToToday()
Components.ToolTip {
text: i18ndc("libplasma5", "Reset calendar to today", "Today")
}
Accessible.name: tooltip
Accessible.description: i18nd("libplasma5", "Reset calendar to today")
} }
NumberAnimation {
Components.ToolButton { target: enterItem
id: nextButton duration: PlasmaCore.Units.longDuration
property string tooltip: { property: "opacity"
switch(root.calendarViewDisplayed) { from: 0
case MonthView.CalendarView.DayView: to: 1
return i18nd("libplasma5", "Next Month")
case MonthView.CalendarView.MonthView:
return i18nd("libplasma5", "Next Year")
case MonthView.CalendarView.YearView:
return i18nd("libplasma5", "Next Decade")
default:
return "";
}
}
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight % 2
icon.name: Qt.application.layoutDirection === Qt.RightToLeft ? "go-previous" : "go-next"
Components.ToolTip { text: parent.tooltip }
onClicked: root.nextFrame();
Accessible.name: tooltip
} }
} }
} }
Components.TabBar { initialItem: DaysCalendar {
id: tabBar
currentIndex: swipeView.currentIndex
Layout.preferredWidth: contentWidth
Layout.alignment: Qt.AlignRight
Components.TabButton {
text: i18nc("libplasma5", "Days");
onClicked: root.showMonthView();
opacity: root.calendarViewDisplayed === MonthView.CalendarView.MonthView ? 1 : 0.8
width: implicitWidth
}
Components.TabButton {
text: i18nd("libplasma5", "Months");
onClicked: root.showYearView();
opacity: root.calendarViewDisplayed === MonthView.CalendarView.YearView ? 1 : 0.7
width: implicitWidth
}
Components.TabButton {
text: i18nd("libplasma5", "Years");
onClicked: root.showDecadeView();
opacity: root.calendarViewDisplayed === MonthView.CalendarView.DecadeView ? 1 : 0.7
width: implicitWidth
}
}
}
QQC2.SwipeView {
id: swipeView
orientation: Qt.Vertical
anchors {
top: viewHeader.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
clip: true
onCurrentIndexChanged: if (currentIndex > 1) {
updateDecadeOverview();
}
// MonthView
DaysCalendar {
id: mainDaysCalendar id: mainDaysCalendar
title: calendarBackend.displayedDate.getFullYear() == new Date().getFullYear() ? root.selectedMonth : root.selectedMonth + ", " + root.selectedYear
columns: calendarBackend.days columns: calendarBackend.days
rows: calendarBackend.weeks rows: calendarBackend.weeks
@ -362,43 +233,75 @@ Item {
dateMatchingPrecision: Calendar.MatchYearMonthAndDay dateMatchingPrecision: Calendar.MatchYearMonthAndDay
previousLabel: i18nd("libplasma5", "Previous Month")
nextLabel: i18nd("libplasma5", "Next Month")
onPrevious: calendarBackend.previousMonth()
onNext: calendarBackend.nextMonth()
onHeaderClicked: {
stack.push(yearOverview)
}
onActivated: { onActivated: {
const rowNumber = Math.floor(index / columns); var rowNumber = Math.floor(index / columns);
week = 1 + calendarBackend.weeksModel[rowNumber]; week = 1 + calendarBackend.weeksModel[rowNumber];
root.currentDate = new Date(date.yearNumber, date.monthNumber - 1, date.dayNumber) root.currentDate = new Date(date.yearNumber, date.monthNumber - 1, date.dayNumber)
} }
} }
}
Component {
id: yearOverview
// YearView
DaysCalendar { DaysCalendar {
title: calendarBackend.displayedDate.getFullYear()
columns: 3 columns: 3
rows: 4 rows: 4
dateMatchingPrecision: Calendar.MatchYearAndMonth dateMatchingPrecision: Calendar.MatchYearAndMonth
gridModel: monthModel gridModel: monthModel
previousLabel: i18nd("libplasma5", "Previous Year")
nextLabel: i18nd("libplasma5", "Next Year")
onPrevious: calendarBackend.previousYear()
onNext: calendarBackend.nextYear()
onHeaderClicked: {
updateDecadeOverview();
stack.push(decadeOverview)
}
onActivated: { onActivated: {
calendarBackend.goToMonth(date.monthNumber); calendarBackend.goToMonth(date.monthNumber)
swipeView.currentIndex = 0; stack.pop()
} }
} }
}
Component {
id: decadeOverview
// DecadeView
DaysCalendar { DaysCalendar {
readonly property int decade: { readonly property int decade: {
const year = calendarBackend.displayedDate.getFullYear() var year = calendarBackend.displayedDate.getFullYear()
return year - year % 10 return year - year % 10
} }
title: decade + " " + (decade + 9)
columns: 3 columns: 3
rows: 4 rows: 4
dateMatchingPrecision: Calendar.MatchYear dateMatchingPrecision: Calendar.MatchYear
gridModel: yearModel gridModel: yearModel
previousLabel: i18nd("libplasma5", "Previous Decade")
nextLabel: i18nd("libplasma5", "Next Decade")
onPrevious: calendarBackend.previousDecade()
onNext: calendarBackend.nextDecade()
onActivated: { onActivated: {
calendarBackend.goToYear(date.yearNumber); calendarBackend.goToYear(date.yearNumber)
swipeView.currentIndex = 1; stack.pop()
} }
} }
} }