[analog-clock] Allow themes to define hand shadow offset & hand rot center

Summary:
Currently the shadow offset of the hands as well as the rotation center of
the hands is hard-coded to match the light model and the hands shape of the
Breeze theme. As well did some older change to move the rotation center to
width/2 in y direction break older themes which relied on the y=0 offset.

This patch adds the option for themes to control the shadow offset as well
as define the rotation offset for each hand (to avoid the need to create
large pixmaps as workaround with empty space to match the assumption of
the center to be at (width/2, width/2), by these new hints:

One shadow offset for all hands, as the simulated physical model can be
assumed to have all hands almost on same layer (also matching that we have
only one shadow for stacked objects, like windows, elsewhere):
* hint-hands-shadow-offset-to-west/hint-hands-shadows-offset-to-east
* hint-hands-shadow-offset-to-north/hint-hands-shadow-offset-to-south
(west vs. east & north vs. south as negative rect size is not possible).
If no hint is set, defaults to 0.
The default of 0 is a small breakage, but almost all themes from
store.kde.org do not use a shadow, also was the hour shadow broken/not shown
until recently and only fixed for upcoming Plasma 5.16, where the offset of
the shadows was tuned as well,  so any themes with hand shadows will need
some tuning for Plasma 5.16 in any case.

Separate rotation offsets for all hands & their shadows, so pixmaps can be
as small as needed, with no transparent area padding needed:
* hint-hourhand-rotation-center-offset
* hint-hourhandshadow-rotation-center-offset
* hint-minutehand-rotation-center-offset
* hint-minutehandshadow-rotation-center-offset
* hint-secondhand-rotation-center-offset
* hint-secondhandshadow-rotation-center-offset
The offset is taken from the center of the hint element, relative
to the position of the hand element, so visually in the SVG file
the hint element directly marks the rotation center for the hand.
If no hint is set, defaults to (width/2, width/2).

Test Plan:
Clocks of unmodified themes from store.kde.org still look as before.
Themes with hints added have shadows at proper place as well as rotation
center of hands at the expected offset.

Reviewers: #plasma, #vdg, mart, davidedmundson, ngraham

Reviewed By: #plasma, #vdg, mart, ngraham

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D20112
parent d86d3a92
......@@ -24,17 +24,39 @@ import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
PlasmaCore.SvgItem {
id: secondHand
id: handRoot
property alias rotation: rotation.angle
property double svgScale
property double horizontalRotationOffset: 0
property double verticalRotationOffset: 0
property string rotationCenterHintId
readonly property double horizontalRotationCenter: {
if (svg.hasElement(rotationCenterHintId)) {
var hintedCenterRect = svg.elementRect(rotationCenterHintId),
handRect = svg.elementRect(elementId),
hintedX = hintedCenterRect.x - handRect.x + hintedCenterRect.width/2;
return Math.round(hintedX * svgScale) + Math.round(hintedX * svgScale) % 2;
}
return width/2;
}
readonly property double verticalRotationCenter: {
if (svg.hasElement(rotationCenterHintId)) {
var hintedCenterRect = svg.elementRect(rotationCenterHintId),
handRect = svg.elementRect(elementId),
hintedY = hintedCenterRect.y - handRect.y + hintedCenterRect.height/2;
return Math.round(hintedY * svgScale) + width % 2;
}
return width/2;
}
width: Math.round(naturalSize.width * svgScale) + Math.round(naturalSize.width * svgScale) % 2
height: Math.round(naturalSize.height * svgScale) + width % 2
anchors {
top: clock.verticalCenter
topMargin: -width/2
horizontalCenter: clock.horizontalCenter
topMargin: -verticalRotationCenter + verticalRotationOffset
left: clock.horizontalCenter
leftMargin: -horizontalRotationCenter + horizontalRotationOffset
}
svg: clockSvg
......@@ -43,8 +65,8 @@ PlasmaCore.SvgItem {
id: rotation
angle: 0
origin {
x: secondHand.width/2
y: secondHand.width/2
x: handRoot.horizontalRotationCenter
y: handRoot.verticalRotationCenter
}
Behavior on angle {
RotationAnimation {
......
......@@ -93,6 +93,34 @@ Item {
PlasmaCore.Svg {
id: clockSvg
imagePath: "widgets/clock"
function estimateHorizontalHandShadowOffset() {
var id = "hint-hands-shadow-offset-to-west";
if (hasElement(id)) {
return -elementSize(id).width;
}
id = "hint-hands-shadows-offset-to-east";
if (hasElement(id)) {
return elementSize(id).width;
}
return 0;
}
function estimateVerticalHandShadowOffset() {
var id = "hint-hands-shadow-offset-to-north";
if (hasElement(id)) {
return -elementSize(id).height;
}
id = "hint-hands-shadow-offset-to-south";
if (hasElement(id)) {
return elementSize(id).height;
}
return 0;
}
property double naturalHorizontalHandShadowOffset: estimateHorizontalHandShadowOffset()
property double naturalVerticalHandShadowOffset: estimateVerticalHandShadowOffset()
onRepaintNeeded: {
naturalHorizontalHandShadowOffset = estimateHorizontalHandShadowOffset();
naturalVerticalHandShadowOffset = estimateVerticalHandShadowOffset();
}
}
Item {
......@@ -102,6 +130,11 @@ Item {
top: parent.top
bottom: showTimezone ? timezoneBg.top : parent.bottom
}
readonly property double svgScale: face.width / face.naturalSize.width
readonly property double horizontalShadowOffset:
Math.round(clockSvg.naturalHorizontalHandShadowOffset * svgScale) + Math.round(clockSvg.naturalHorizontalHandShadowOffset * svgScale) % 2
readonly property double verticalShadowOffset:
Math.round(clockSvg.naturalVerticalHandShadowOffset * svgScale) + Math.round(clockSvg.naturalVerticalHandShadowOffset * svgScale) % 2
PlasmaCore.SvgItem {
id: face
......@@ -113,48 +146,57 @@ Item {
}
Hand {
anchors.topMargin: -6
elementId: "HourHandShadow"
rotationCenterHintId: "hint-hourhandshadow-rotation-center-offset"
horizontalRotationOffset: clock.horizontalShadowOffset
verticalRotationOffset: clock.verticalShadowOffset
rotation: 180 + hours * 30 + (minutes/2)
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
Hand {
elementId: "HourHand"
rotationCenterHintId: "hint-hourhand-rotation-center-offset"
rotation: 180 + hours * 30 + (minutes/2)
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
Hand {
anchors.topMargin: 3
elementId: "MinuteHandShadow"
rotationCenterHintId: "hint-minutehandshadow-rotation-center-offset"
horizontalRotationOffset: clock.horizontalShadowOffset
verticalRotationOffset: clock.verticalShadowOffset
rotation: 180 + minutes * 6
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
Hand {
elementId: "MinuteHand"
rotationCenterHintId: "hint-minutehand-rotation-center-offset"
rotation: 180 + minutes * 6
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
Hand {
anchors.topMargin: 2
elementId: "SecondHandShadow"
rotationCenterHintId: "hint-secondhandshadow-rotation-center-offset"
horizontalRotationOffset: clock.horizontalShadowOffset
verticalRotationOffset: clock.verticalShadowOffset
rotation: 180 + seconds * 6
visible: showSecondsHand
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
Hand {
elementId: "SecondHand"
rotationCenterHintId: "hint-secondhand-rotation-center-offset"
rotation: 180 + seconds * 6
visible: showSecondsHand
svgScale: face.width / face.naturalSize.width
svgScale: clock.svgScale
}
PlasmaCore.SvgItem {
id: center
width: naturalSize.width * face.width / face.naturalSize.width
height: naturalSize.height * face.width / face.naturalSize.width
width: naturalSize.width * clock.svgScale
height: naturalSize.height * clock.svgScale
anchors.centerIn: clock
svg: clockSvg
elementId: "HandCenterScrew"
......@@ -165,8 +207,8 @@ Item {
anchors.fill: face
svg: clockSvg
elementId: "Glass"
width: naturalSize.width * face.width / face.naturalSize.width
height: naturalSize.height * face.width / face.naturalSize.width
width: naturalSize.width * clock.svgScale
height: naturalSize.height * clock.svgScale
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment