Revert "Redesign calendar component"

This reverts commit b6f9e51b65. 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 previous
signal next
signal activated(int index, var date, var item)
// so it forwards it to the delegate which then emits activated with all the necessary data
signal activateHighlightedItem
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 columns
property bool showWeekNumbers
onShowWeekNumbersChanged: canvas.requestPaint()
// how precise date matching should be, 3 = day+month+year, 2 = month+year, 1 = just year
property int dateMatchingPrecision
property alias headerModel: days.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)
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)
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 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 {
id: calendarSvg
imagePath: "widgets/calendar"
@ -81,13 +251,20 @@ Item {
}
}
Connections {
target: theme
function onTextColorChanged() {
canvas.requestPaint();
}
}
Column {
id: weeksColumn
visible: showWeekNumbers
anchors {
top: parent.top
top: canvas.top
left: parent.left
bottom: parent.bottom
bottom: canvas.bottom
// The borderWidth needs to be counted twice here because it goes
// in fact through two lines - the topmost one (the outer edge)
// and then the one below weekday strings
@ -114,8 +291,7 @@ Item {
id: calendarGrid
anchors {
top: parent.top
right: parent.right
right: canvas.right
rightMargin: root.borderWidth
bottom: parent.bottom
bottomMargin: root.borderWidth

View File

@ -6,15 +6,15 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Controls 2.15 as QQC2
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import org.kde.plasma.calendar 2.0
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
Item {
PinchArea {
id: root
anchors.fill: parent
@ -39,130 +39,76 @@ Item {
property int firstDay: new Date(showDate.getFullYear(), showDate.getMonth(), 1).getDay()
property alias today: calendarBackend.today
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 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) {
return date.toDateString() === new Date().toDateString();
if (date.toDateString() == new Date().toDateString()) {
return true;
}
return false;
}
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");
}
/**
* Move calendar to month view showing today's date.
*/
function resetToToday() {
calendarBackend.resetToToday();
root.currentDate = root.today;
swipeView.currentIndex = 0;
stack.pop(null);
}
function updateYearOverview() {
const date = calendarBackend.displayedDate;
const day = date.getDate();
const year = date.getFullYear();
var date = calendarBackend.displayedDate;
var day = date.getDate();
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);
}
}
function updateDecadeOverview() {
const date = calendarBackend.displayedDate;
const day = date.getDate();
const month = date.getMonth() + 1;
const year = date.getFullYear();
const decade = year - year % 10;
var date = calendarBackend.displayedDate;
var day = date.getDate();
var month = date.getMonth() + 1;
var year = date.getFullYear();
var decade = year - year % 10;
for (let i = 0, j = yearModel.count; i < j; ++i) {
const label = decade - 1 + i;
for (var i = 0, j = yearModel.count; i < j; ++i) {
var label = decade - 1 + i;
yearModel.setProperty(i, "yearNumber", 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 {
id: calendarBackend
@ -202,8 +148,6 @@ Item {
Component.onCompleted: {
for (var i = 0; i < 12; ++i) {
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
})
}
@ -221,136 +165,63 @@ Item {
onPressed: mouse.accepted = false
}
ColumnLayout {
id: viewHeader
visible: !showCustomHeader
height: !visible ? 0 : implicitHeight
width: parent.width
anchors {
top: parent.top
}
StackView {
id: stack
RowLayout {
PlasmaExtras.Heading {
id: heading
text: i18ndc("libplasma5", "Format: **month** year", "<strong>%1</strong> %2", root.selectedMonth, root.selectedYear.toString())
anchors.fill: parent
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
Layout.fillWidth: true
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
NumberAnimation {
target: exitItem
duration: PlasmaCore.Units.longDuration
property: "opacity"
from: 1
to: 0
}
Row {
spacing: 0
Components.ToolButton {
id: previousButton
property string tooltip: {
switch(root.calendarViewDisplayed) {
case MonthView.CalendarView.DayView:
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 "";
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
}
}
//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 }
popTransition: StackViewTransition {
NumberAnimation {
target: exitItem
duration: PlasmaCore.Units.longDuration
property: "opacity"
from: 1
to: 0
}
Components.ToolButton {
icon.name: "go-jump-today"
property string tooltip
//SEE QTBUG-58307
Layout.preferredHeight: implicitHeight + implicitHeight % 2
onClicked: root.resetToToday()
Components.ToolTip {
text: i18ndc("libplasma5", "Reset calendar to today", "Today")
NumberAnimation {
target: exitItem
duration: PlasmaCore.Units.longDuration
property: "transformScale"
// so no matter how much you scaled, it would still fly towards you
to: exitItem.transformScale * 1.5
}
Accessible.name: tooltip
Accessible.description: i18nd("libplasma5", "Reset calendar to today")
}
Components.ToolButton {
id: nextButton
property string tooltip: {
switch(root.calendarViewDisplayed) {
case MonthView.CalendarView.DayView:
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
NumberAnimation {
target: enterItem
duration: PlasmaCore.Units.longDuration
property: "opacity"
from: 0
to: 1
}
}
}
Components.TabBar {
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 {
initialItem: DaysCalendar {
id: mainDaysCalendar
title: calendarBackend.displayedDate.getFullYear() == new Date().getFullYear() ? root.selectedMonth : root.selectedMonth + ", " + root.selectedYear
columns: calendarBackend.days
rows: calendarBackend.weeks
@ -362,43 +233,75 @@ Item {
dateMatchingPrecision: Calendar.MatchYearMonthAndDay
previousLabel: i18nd("libplasma5", "Previous Month")
nextLabel: i18nd("libplasma5", "Next Month")
onPrevious: calendarBackend.previousMonth()
onNext: calendarBackend.nextMonth()
onHeaderClicked: {
stack.push(yearOverview)
}
onActivated: {
const rowNumber = Math.floor(index / columns);
var rowNumber = Math.floor(index / columns);
week = 1 + calendarBackend.weeksModel[rowNumber];
root.currentDate = new Date(date.yearNumber, date.monthNumber - 1, date.dayNumber)
}
}
}
Component {
id: yearOverview
// YearView
DaysCalendar {
title: calendarBackend.displayedDate.getFullYear()
columns: 3
rows: 4
dateMatchingPrecision: Calendar.MatchYearAndMonth
gridModel: monthModel
previousLabel: i18nd("libplasma5", "Previous Year")
nextLabel: i18nd("libplasma5", "Next Year")
onPrevious: calendarBackend.previousYear()
onNext: calendarBackend.nextYear()
onHeaderClicked: {
updateDecadeOverview();
stack.push(decadeOverview)
}
onActivated: {
calendarBackend.goToMonth(date.monthNumber);
swipeView.currentIndex = 0;
calendarBackend.goToMonth(date.monthNumber)
stack.pop()
}
}
}
// DecadeView
Component {
id: decadeOverview
DaysCalendar {
readonly property int decade: {
const year = calendarBackend.displayedDate.getFullYear()
var year = calendarBackend.displayedDate.getFullYear()
return year - year % 10
}
title: decade + " " + (decade + 9)
columns: 3
rows: 4
dateMatchingPrecision: Calendar.MatchYear
gridModel: yearModel
previousLabel: i18nd("libplasma5", "Previous Decade")
nextLabel: i18nd("libplasma5", "Next Decade")
onPrevious: calendarBackend.previousDecade()
onNext: calendarBackend.nextDecade()
onActivated: {
calendarBackend.goToYear(date.yearNumber);
swipeView.currentIndex = 1;
calendarBackend.goToYear(date.yearNumber)
stack.pop()
}
}
}