[calendar] Refactor the Calendar grid computation a bit
Makes the code a bit simpler & lighter and fixes the sometimes missing bottom line in calendar. The grid is now equally padded from both sides (including the month name), so basically it's now always aligned to the center and this also fixes the cases where there was a bigger padding on one side than on the other. The grid is now also anchored to the bottom so that the bottom margin can stay moreless consistent with the side margins in different sizes. Change-Id: I2f2173d11e473d6e93db2bdca002269e4239f516 REVIEW: 124072 CHANGELOG: Improve hidpi support in the Calendar grid component
This commit is contained in:
parent
f9d4f3d836
commit
23add5d6e4
@ -25,21 +25,14 @@ Item {
|
||||
|
||||
readonly property int gridColumns: root.showWeekNumbers ? calendarGrid.columns + 1 : calendarGrid.columns
|
||||
|
||||
// This is to ensure that the inner grid.width is always aligned to be divisible by 7,
|
||||
// fixes wrong side margins because of the rounding of cell size
|
||||
// (consider the parent.width to be 404, the cell width would be 56,
|
||||
// but 56*7 + 6 (the inner spacing) is 398, so we split the remaining 6 to avoid
|
||||
// wrong alignment)
|
||||
anchors {
|
||||
leftMargin: Math.floor(((parent.width - (gridColumns + 1) * borderWidth) % gridColumns) / 2)
|
||||
rightMargin: anchors.leftMargin
|
||||
bottomMargin: anchors.leftMargin
|
||||
}
|
||||
|
||||
// Paints the inner grid and the outer frame
|
||||
Canvas {
|
||||
id: canvas
|
||||
anchors.fill: parent
|
||||
|
||||
width: (root.cellWidth + root.borderWidth) * gridColumns + root.borderWidth
|
||||
height: (root.cellHeight + root.borderWidth) * calendarGrid.rows + root.borderWidth
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
opacity: root.borderOpacity
|
||||
antialiasing: false
|
||||
clip: false
|
||||
@ -56,28 +49,37 @@ Item {
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
// This isn't the real width/height, but rather the X coord where the line will stop
|
||||
// and as the coord system starts from (0,0), we need to do "-1" to not get off-by-1 errors
|
||||
var rectWidth = (root.cellWidth + root.borderWidth) * gridColumns + root.borderWidth - 1
|
||||
var rectHeight = (root.cellHeight + root.borderWidth) * calendarGrid.rows + root.borderWidth - 1
|
||||
|
||||
// the outer frame
|
||||
ctx.strokeRect(0, 0, rectWidth, rectHeight);
|
||||
// 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 = (rectHeight / calendarGrid.rows) * (i + 1);
|
||||
for (var i = 0; i < calendarGrid.rows + 1; i++) {
|
||||
var lineY = lineBasePoint + (root.cellHeight + root.borderWidth) * (i);
|
||||
|
||||
ctx.moveTo(root.showWeekNumbers ? root.cellWidth + root.borderWidth : root.borderWidth, lineY);
|
||||
ctx.lineTo(rectWidth, lineY);
|
||||
if (i == 0 || i == calendarGrid.rows) {
|
||||
ctx.moveTo(0, lineY);
|
||||
} else {
|
||||
ctx.moveTo(root.showWeekNumbers ? root.cellWidth + root.borderWidth : root.borderWidth, lineY);
|
||||
}
|
||||
ctx.lineTo(width, lineY);
|
||||
}
|
||||
|
||||
// vertical lines
|
||||
for (var i = 0; i < gridColumns - 1; i++) {
|
||||
var lineX = (rectWidth / gridColumns) * (i + 1);
|
||||
for (var i = 0; i < gridColumns + 1; i++) {
|
||||
var lineX = lineBasePoint + (root.cellWidth + root.borderWidth) * (i);
|
||||
|
||||
ctx.moveTo(lineX, root.borderWidth + root.cellHeight);
|
||||
ctx.lineTo(lineX, rectHeight);
|
||||
// Draw the outer vertical lines in full height so that it closes
|
||||
// the outer rectangle
|
||||
if (i == 0 || i == gridColumns) {
|
||||
ctx.moveTo(lineX, 0);
|
||||
} else {
|
||||
ctx.moveTo(lineX, root.borderWidth + root.cellHeight);
|
||||
}
|
||||
ctx.lineTo(lineX, height);
|
||||
}
|
||||
|
||||
ctx.closePath();
|
||||
@ -129,10 +131,15 @@ Item {
|
||||
// because there's one more cell to count with and therefore also
|
||||
// another border to add
|
||||
x: root.showWeekNumbers ? 2 * root.borderWidth + root.cellWidth: root.borderWidth
|
||||
y: root.borderWidth
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: root.borderWidth
|
||||
}
|
||||
|
||||
columns: calendarBackend.days
|
||||
rows: calendarBackend.weeks + 1
|
||||
spacing: 1
|
||||
spacing: root.borderWidth
|
||||
property Item selectedItem
|
||||
property bool containsEventItems: false // FIXME
|
||||
property bool containsTodoItems: false // FIXME
|
||||
@ -145,6 +152,8 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Repeater {
|
||||
id: days
|
||||
model: calendarBackend.days
|
||||
@ -158,7 +167,7 @@ Item {
|
||||
verticalAlignment: Text.AlignBottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: borderWidth * 2
|
||||
anchors.bottomMargin: units.smallSpacing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import QtQuick 2.0
|
||||
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 2.0 as PlasmaComponents
|
||||
@ -23,8 +24,8 @@ import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
property QtObject date
|
||||
property date showDate: new Date()
|
||||
@ -32,44 +33,24 @@ Item {
|
||||
property alias selectedMonth: calendarBackend.monthName
|
||||
property alias selectedYear: calendarBackend.year
|
||||
|
||||
property int mWidth: theme.mSize(theme.defaultFont).width
|
||||
property int mHeight: theme.mSize(theme.defaultFont).height
|
||||
property int borderWidth: 1
|
||||
property real borderOpacity: 0.4
|
||||
|
||||
property int columns: calendarBackend.days
|
||||
property int rows: calendarBackend.weeks
|
||||
|
||||
property int cellWidth: prefCellWidth()
|
||||
property int cellHeight: prefCellHeight()
|
||||
// Take the calendar width, subtract the inner and outer spacings and divide by number of columns (==days in week)
|
||||
property int cellWidth: Math.floor((calendar.width - (root.columns + 1) * borderWidth) / (root.columns + (root.showWeekNumbers ? 1 : 0))) //prefCellWidth()
|
||||
|
||||
// Take the calendar height, subtract the inner spacings and divide by number of rows (root.weeks + one row for day names)
|
||||
property int cellHeight: Math.floor((calendar.height - (root.rows + 1) * borderWidth) / (root.rows + 1)) //prefCellHeight()
|
||||
|
||||
property Item selectedItem
|
||||
property int week;
|
||||
property int firstDay: new Date(showDate.getFullYear(), showDate.getMonth(), 1).getDay()
|
||||
property date today
|
||||
property bool showWeekNumbers: true
|
||||
property bool showWeekNumbers: false
|
||||
|
||||
function prefCellWidth() {
|
||||
return Math.min(
|
||||
Math.max(
|
||||
mWidth * 3,
|
||||
// Take the calendar width, subtract the inner and outer spacings and divide by number of columns (==days in week)
|
||||
Math.floor((calendar.width - (root.columns + 1) * borderWidth) / (root.columns + (root.showWeekNumbers ? 1 : 0)))
|
||||
),
|
||||
mWidth * 100
|
||||
)
|
||||
}
|
||||
|
||||
function prefCellHeight() {
|
||||
return Math.min(
|
||||
Math.max(
|
||||
mHeight * 1.5,
|
||||
// Take the calendar height, subtract the inner spacings and divide by number of rows (root.weeks + one row for day names)
|
||||
Math.floor((calendar.height - (root.rows + 1) * borderWidth) / (root.rows + 1))
|
||||
),
|
||||
mHeight * 40
|
||||
)
|
||||
}
|
||||
|
||||
function isToday(date) {
|
||||
if (date.toDateString() == new Date().toDateString()) {
|
||||
@ -88,67 +69,6 @@ Item {
|
||||
calendarBackend.resetToToday();
|
||||
}
|
||||
|
||||
PlasmaExtras.Heading {
|
||||
id: monthHeading
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
level: 1
|
||||
text: calendarBackend.displayedDate.getFullYear() == new Date().getFullYear() ? root.selectedMonth : root.selectedMonth + ", " + root.selectedYear
|
||||
elide: Text.ElideRight
|
||||
font.capitalization: Font.Capitalize
|
||||
|
||||
Loader {
|
||||
id: menuLoader
|
||||
property QtObject calendarBackend: calendarBackend
|
||||
}
|
||||
MouseArea {
|
||||
id: monthMouse
|
||||
property int previousPixelDelta
|
||||
|
||||
width: monthHeading.paintedWidth
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
onClicked: {
|
||||
if (menuLoader.source == "") {
|
||||
menuLoader.source = "MonthMenu.qml"
|
||||
}
|
||||
menuLoader.item.year = selectedYear
|
||||
menuLoader.item.open(0, height);
|
||||
}
|
||||
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) {
|
||||
calendarBackend.previousMonth()
|
||||
} else if (delta <= -15) {
|
||||
calendarBackend.nextMonth()
|
||||
}
|
||||
previousPixelDelta = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Calendar {
|
||||
id: calendarBackend
|
||||
|
||||
@ -158,56 +78,126 @@ Item {
|
||||
today: root.today
|
||||
}
|
||||
|
||||
DaysCalendar {
|
||||
id: calendar
|
||||
|
||||
ColumnLayout {
|
||||
// This is to ensure that the inner grid.width is always aligned to be divisible by 7,
|
||||
// fixes wrong side margins because of the rounding of cell size
|
||||
// (consider the parent.width to be 404, the cell width would be 56,
|
||||
// but 56*7 + 6 (the inner spacing) is 398, so we split the remaining 6 to avoid
|
||||
// wrong alignment)
|
||||
anchors {
|
||||
top: monthHeading.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
fill: parent
|
||||
leftMargin: Math.floor(((parent.width - (calendar.gridColumns + 1) * borderWidth) % calendar.gridColumns) / 2)
|
||||
rightMargin: anchors.leftMargin
|
||||
bottomMargin: anchors.leftMargin
|
||||
}
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: "◀"
|
||||
opacity: leftmouse.containsMouse ? 1 : 0.4
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
leftMargin: Math.floor(units.largeSpacing / 2)
|
||||
PlasmaExtras.Heading {
|
||||
id: monthHeading
|
||||
|
||||
level: 1
|
||||
text: calendarBackend.displayedDate.getFullYear() == new Date().getFullYear() ? root.selectedMonth : root.selectedMonth + ", " + root.selectedYear
|
||||
elide: Text.ElideRight
|
||||
font.capitalization: Font.Capitalize
|
||||
|
||||
Loader {
|
||||
id: menuLoader
|
||||
property QtObject calendarBackend: calendarBackend
|
||||
}
|
||||
MouseArea {
|
||||
id: leftmouse
|
||||
anchors.fill: parent
|
||||
anchors.margins: -units.largeSpacing / 3
|
||||
hoverEnabled: true
|
||||
id: monthMouse
|
||||
property int previousPixelDelta
|
||||
|
||||
width: monthHeading.paintedWidth
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
onClicked: {
|
||||
calendarBackend.previousMonth()
|
||||
if (menuLoader.source == "") {
|
||||
menuLoader.source = "MonthMenu.qml"
|
||||
}
|
||||
menuLoader.item.year = selectedYear
|
||||
menuLoader.item.open(0, height);
|
||||
}
|
||||
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) {
|
||||
calendarBackend.previousMonth()
|
||||
} else if (delta <= -15) {
|
||||
calendarBackend.nextMonth()
|
||||
}
|
||||
previousPixelDelta = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
PlasmaComponents.Label {
|
||||
text: "▶"
|
||||
opacity: rightmouse.containsMouse ? 1 : 0.4
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
rightMargin: Math.floor(units.largeSpacing / 2)
|
||||
|
||||
DaysCalendar {
|
||||
id: calendar
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
PlasmaComponents.Label {
|
||||
text: "◀"
|
||||
opacity: leftmouse.containsMouse ? 1 : 0.4
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
font.pixelSize: Math.max(theme.smallestFont.pixelSize, Math.floor(root.cellHeight / 3))
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
leftMargin: Math.floor(units.largeSpacing / 2) + root.borderWidth
|
||||
topMargin: anchors.leftMargin
|
||||
}
|
||||
MouseArea {
|
||||
id: leftmouse
|
||||
anchors.fill: parent
|
||||
anchors.margins: -units.largeSpacing / 3
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
calendarBackend.previousMonth()
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: rightmouse
|
||||
anchors.fill: parent
|
||||
anchors.margins: -units.largeSpacing / 3
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
calendarBackend.nextMonth()
|
||||
PlasmaComponents.Label {
|
||||
text: "▶"
|
||||
opacity: rightmouse.containsMouse ? 1 : 0.4
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
font.pixelSize: Math.max(theme.smallestFont.pixelSize, Math.floor(root.cellHeight / 3))
|
||||
anchors {
|
||||
top: parent.top
|
||||
right: parent.right
|
||||
rightMargin: Math.floor(units.largeSpacing / 2) + root.borderWidth
|
||||
topMargin: anchors.rightMargin
|
||||
}
|
||||
MouseArea {
|
||||
id: rightmouse
|
||||
anchors.fill: parent
|
||||
anchors.margins: -units.largeSpacing / 3
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
calendarBackend.nextMonth()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Item {
|
||||
id: calendarToolbar
|
||||
|
Loading…
Reference in New Issue
Block a user