kcms/nightcolor: Add map to "manual location" mode

Most people don't have their latitude and longitude memorized. It is
*far* easier for people to point out their approximate location on a
map, than to look up their latitude and longitude online.

This also removes the need for a "Detect Location" button there.
wilder-5.26
Bharadwaj Raju 4 years ago committed by Nate Graham
parent 0baa8a97fa
commit 648648f118
  1. 2
      kcms/nightcolor/CMakeLists.txt
  2. 11
      kcms/nightcolor/kcm.cpp
  3. 3
      kcms/nightcolor/kcm.h
  4. 314
      kcms/nightcolor/package/contents/ui/LocationsFixedView.qml
  5. 5
      kcms/nightcolor/package/contents/ui/main.qml
  6. BIN
      kcms/nightcolor/worldmap.png

@ -27,4 +27,6 @@ target_link_libraries(kcm_nightcolor
PW::LibColorCorrect PW::LibColorCorrect
) )
install(FILES worldmap.png DESTINATION ${KDE_INSTALL_DATADIR}/plasma/nightcolor)
kpackage_install_package(package kcm_nightcolor kcms) kpackage_install_package(package kcm_nightcolor kcms)

@ -6,6 +6,9 @@
#include "kcm.h" #include "kcm.h"
#include <QIcon>
#include <QStandardPaths>
#include <KLocalizedString> #include <KLocalizedString>
#include <KPluginFactory> #include <KPluginFactory>
@ -22,6 +25,8 @@ KCMNightColor::KCMNightColor(QObject *parent, const KPluginMetaData &data, const
qmlRegisterAnonymousType<NightColorSettings>("org.kde.private.kcms.nightcolor", 1); qmlRegisterAnonymousType<NightColorSettings>("org.kde.private.kcms.nightcolor", 1);
qmlRegisterUncreatableMetaObject(ColorCorrect::staticMetaObject, "org.kde.private.kcms.nightcolor", 1, 0, "NightColorMode", "Error: only enums"); qmlRegisterUncreatableMetaObject(ColorCorrect::staticMetaObject, "org.kde.private.kcms.nightcolor", 1, 0, "NightColorMode", "Error: only enums");
worldMapFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/nightcolor/worldmap.png"), QStandardPaths::LocateFile);
setButtons(Apply | Default); setButtons(Apply | Default);
} }
@ -30,6 +35,12 @@ NightColorSettings *KCMNightColor::nightColorSettings() const
return m_data->settings(); return m_data->settings();
} }
// FIXME: This was added to work around the nonstandardness of the Breeze zoom icons
// remove once https://bugs.kde.org/show_bug.cgi?id=435671 is fixed
bool KCMNightColor::isIconThemeBreeze()
{
return QIcon::themeName().contains(QStringLiteral("breeze"));
}
} }
#include "kcm.moc" #include "kcm.moc"

@ -18,14 +18,17 @@ class KCMNightColor : public KQuickAddons::ManagedConfigModule
Q_OBJECT Q_OBJECT
Q_PROPERTY(NightColorSettings *nightColorSettings READ nightColorSettings CONSTANT) Q_PROPERTY(NightColorSettings *nightColorSettings READ nightColorSettings CONSTANT)
Q_PROPERTY(QString worldMapFile MEMBER worldMapFile CONSTANT)
public: public:
KCMNightColor(QObject *parent, const KPluginMetaData &data, const QVariantList &args); KCMNightColor(QObject *parent, const KPluginMetaData &data, const QVariantList &args);
~KCMNightColor() override = default; ~KCMNightColor() override = default;
NightColorSettings *nightColorSettings() const; NightColorSettings *nightColorSettings() const;
Q_INVOKABLE bool isIconThemeBreeze();
private: private:
NightColorData *const m_data; NightColorData *const m_data;
QString worldMapFile;
}; };
} }

@ -4,71 +4,275 @@
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
*/ */
import QtQuick 2.1 import QtQuick 2.15
import QtQuick.Layouts 1.1 import QtQuick.Layouts 1.1
import QtQuick.Controls 2.5 as QQC2 import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.5 as Kirigami import org.kde.kirigami 2.15 as Kirigami
import org.kde.kcm 1.5 as KCM import org.kde.kcm 1.5 as KCM
import QtGraphicalEffects 1.12
Kirigami.FormLayout { Kirigami.FormLayout {
twinFormLayouts: parentLayout
/* Equirectangular projection maps (x, y) to (lat, long) cleanly */
function longitudeToX(lon) {
NumberField { return (lon + 180) * (mapImage.width / 360);
id: latitudeFixedField }
// Match combobox width function latitudeToY(lat) {
Layout.minimumWidth: modeSwitcher.width return (90 - lat) * (mapImage.height / 180);
Layout.maximumWidth: modeSwitcher.width }
Kirigami.FormData.label: i18n("Latitude:")
validator: DoubleValidator {bottom: -90; top: 90; decimals: 10} function xToLongitude(x) {
backend: kcm.nightColorSettings.latitudeFixed return (x / (mapImage.width / 360)) - 180;
onBackendChanged: { }
kcm.nightColorSettings.latitudeFixed = backend; function yToLatitude(y) {
} return 90 - (y / (mapImage.height / 180));
KCM.SettingStateBinding {
configObject: kcm.nightColorSettings
settingName: "LatitudeFixed"
extraEnabledConditions: kcm.nightColorSettings.active
}
} }
NumberField { ColumnLayout {
id: longitudeFixedField QQC2.Label {
// Match combobox width id: mapLabel
Layout.minimumWidth: modeSwitcher.width wrapMode: Text.Wrap
Layout.maximumWidth: modeSwitcher.width Layout.maximumWidth: mapRect.width
Kirigami.FormData.label: i18n("Longitude:") Layout.bottomMargin: Kirigami.Units.smallSpacing
validator: DoubleValidator {bottom: -180; top: 180; decimals: 10} Layout.alignment: Qt.AlignHCenter
backend: kcm.nightColorSettings.longitudeFixed text: Kirigami.Settings.tabletMode
onBackendChanged: { ? i18nc("@label:chooser Tap should be translated to mean touching using a touchscreen", "Tap to choose your location on the map.")
kcm.nightColorSettings.longitudeFixed = backend; : i18nc("@label:chooser Click should be translated to mean clicking using a mouse", "Click to choose your location on the map.")
font: Kirigami.Theme.smallFont
} }
KCM.SettingStateBinding {
configObject: kcm.nightColorSettings Kirigami.ShadowedRectangle {
settingName: "LongitudeFixed" id: mapRect
extraEnabledConditions: kcm.nightColorSettings.active Layout.alignment: Qt.AlignHCenter
implicitWidth: Kirigami.Units.gridUnit * 30
Layout.maximumWidth: Kirigami.Units.gridUnit * 30
implicitHeight: Kirigami.Units.gridUnit * 15
Layout.maximumHeight: Kirigami.Units.gridUnit * 15
radius: Kirigami.Units.smallSpacing
Kirigami.Theme.inherit: false
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
shadow.xOffset: 0
shadow.yOffset: 2
shadow.size: 10
shadow.color: Qt.rgba(0, 0, 0, 0.3)
property double zoomFactor: 1.2;
property double currentScale: 1.0;
/* Zoom in/out buttons */
RowLayout {
anchors {
right: parent.right
rightMargin: Kirigami.Units.smallSpacing*2
bottom: parent.bottom
bottomMargin: Kirigami.Units.smallSpacing*2
}
// Always show above thumbnail content
z: 9999
QQC2.Button {
// HACK: using list-add and list-remove for more obvious/standard zoom icons till we change the Breeze ones
// https://bugs.kde.org/show_bug.cgi?id=435671
text: i18n("Zoom in")
display: QQC2.AbstractButton.IconOnly
icon.name: kcm.isIconThemeBreeze() ? "list-add" : "zoom-in"
activeFocusOnTab: false
onClicked: {
if (mapRect.currentScale < 5) {
let centrePos = { x: mapImage.width / 2, y: mapImage.height / 2 };
var realX = centrePos.x * mapZoom.xScale
var realY = centrePos.y * mapZoom.yScale
mapFlick.contentX -= (1-mapRect.zoomFactor)*realX
mapFlick.contentY -= (1-mapRect.zoomFactor)*realY
mapRect.currentScale *= mapRect.zoomFactor;
}
}
onDoubleClicked: {
onClicked();
}
QQC2.ToolTip {
text: parent.text
}
}
QQC2.Button {
// HACK: using list-add and list-remove for more obvious/standard zoom icons till we change the Breeze ones
// https://bugs.kde.org/show_bug.cgi?id=435671
text: i18n("Zoom in")
display: QQC2.AbstractButton.IconOnly
icon.name: kcm.isIconThemeBreeze() ? "list-remove" : "zoom-out"
activeFocusOnTab: false
onClicked: {
if (mapRect.currentScale > 1) {
let centrePos = { x: mapImage.width / 2, y: mapImage.height / 2 };
var realX = centrePos.x * mapZoom.xScale
var realY = centrePos.y * mapZoom.yScale
mapFlick.contentX -= (1-(1/mapRect.zoomFactor))*realX
mapFlick.contentY -= (1-(1/mapRect.zoomFactor))*realY
mapRect.currentScale *= (1/mapRect.zoomFactor)
}
}
onDoubleClicked: {
onClicked();
}
QQC2.ToolTip {
text: parent.text
}
}
}
Flickable {
id: mapFlick
anchors {
fill: parent
margins: Kirigami.Units.smallSpacing
}
contentWidth: mapImage.width * mapRect.currentScale
contentHeight: mapImage.height * mapRect.currentScale
clip: true
Image {
id: mapImage
source: kcm.worldMapFile
transform: Scale {
id: mapZoom
xScale: mapRect.currentScale
yScale: mapRect.currentScale
}
Kirigami.Icon {
z: 9999
id: mapPin
property double rawX: longitudeToX(kcm.nightColorSettings.longitudeFixed)
property double rawY: latitudeToY(kcm.nightColorSettings.latitudeFixed)
x: rawX - (width/2)/mapRect.currentScale
y: rawY - (height - 4)/mapRect.currentScale
width: Kirigami.Units.iconSizes.medium
height: Kirigami.Units.iconSizes.medium
source: "mark-location"
color: "#232629"
transform: Scale {
xScale: 1/mapRect.currentScale
yScale: 1/mapRect.currentScale
}
}
Connections {
target: kcm.nightColorSettings
function onLatitudeFixedChanged() {
mapPin.rawY = latitudeToY(kcm.nightColorSettings.latitudeFixed);
}
function onLongitudeFixedChanged() {
mapPin.rawX = longitudeToX(kcm.nightColorSettings.longitudeFixed);
}
}
TapHandler {
onTapped: {
let clickPos = mapImage.mapFromItem(root, eventPoint.scenePosition);
mapPin.rawX = clickPos.x;
mapPin.rawY = clickPos.y;
kcm.nightColorSettings.latitudeFixed = yToLatitude(mapPin.rawY);
kcm.nightColorSettings.longitudeFixed = xToLongitude(mapPin.rawX);
}
}
WheelHandler {
acceptedModifiers: Qt.ControlModifier
onWheel: {
let wheelPos = mapImage.mapFromItem(root, point.scenePosition);
var realX = wheelPos.x * mapZoom.xScale
var realY = wheelPos.y * mapZoom.yScale
let clicks = event.angleDelta.y / 120;
if (clicks > 0 && mapRect.currentScale < 5) {
mapFlick.contentX -= (1-mapRect.zoomFactor)*realX
mapFlick.contentY -= (1-mapRect.zoomFactor)*realY
mapRect.currentScale *= mapRect.zoomFactor;
} else if (clicks < 0 && mapRect.currentScale > 1) {
mapFlick.contentX -= (1-(1/mapRect.zoomFactor))*realX
mapFlick.contentY -= (1-(1/mapRect.zoomFactor))*realY
mapRect.currentScale *= (1/(mapRect.zoomFactor));
}
}
}
Component.onCompleted: {
width = mapFlick.width;
height = mapFlick.height;
}
}
}
} }
}
QQC2.Button { TextEdit {
text: i18n("Detect Location") id: mapAttributionLabel
// Match combobox width textFormat: TextEdit.RichText
Layout.minimumWidth: modeSwitcher.width wrapMode: Text.Wrap
icon.name: "find-location" readOnly: true
onClicked: { color: Kirigami.Theme.textColor
startLocator(); selectedTextColor: Kirigami.Theme.highlightedTextColor
latitudeFixedField.backend = locator.latitude; selectionColor: Kirigami.Theme.highlightColor
longitudeFixedField.backend = locator.longitude; font: Kirigami.Theme.smallFont
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.maximumWidth: mapRect.width
Layout.alignment: Qt.AlignHCenter
text: xi18nc("@info", "Modified from <link url='https://commons.wikimedia.org/wiki/File:World_location_map_(equirectangular_180).svg'>World location map</link> by TUBS / Wikimedia Commons / <link url='https://creativecommons.org/licenses/by-sa/3.0'>CC BY-SA 3.0</link>")
onLinkActivated: (url) => Qt.openUrlExternally(url)
HoverHandler {
acceptedButtons: Qt.NoButton
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
}
} }
}
// Inform about geolocation access on clicking detect RowLayout {
QQC2.Label { Layout.topMargin: Kirigami.Units.smallSpacing
enabled: activator.checked Layout.alignment: Qt.AlignHCenter
wrapMode: Text.Wrap
Layout.maximumWidth: modeSwitcher.width QQC2.Label {
text: i18n("The device's location will be detected using GPS (if available), or by sending network information to <a href=\"https://location.services.mozilla.com\">Mozilla Location Service</a>.") text: i18nc("@label: textbox", "Latitude:")
onLinkActivated: { Qt.openUrlExternally("https://location.services.mozilla.com"); } }
font: Kirigami.Theme.smallFont Connections {
target: kcm.nightColorSettings
function onLatitudeFixedChanged() {
latitudeFixedField.backend = kcm.nightColorSettings.latitudeFixed;
}
function onLongitudeFixedChanged() {
longitudeFixedField.backend = kcm.nightColorSettings.longitudeFixed;
}
}
NumberField {
id: latitudeFixedField
validator: DoubleValidator {bottom: -90; top: 90; decimals: 10}
backend: kcm.nightColorSettings.latitudeFixed
onBackendChanged: {
kcm.nightColorSettings.latitudeFixed = backend;
}
KCM.SettingStateBinding {
configObject: kcm.nightColorSettings
settingName: "LatitudeFixed"
extraEnabledConditions: kcm.nightColorSettings.active
}
}
QQC2.Label {
text: i18nc("@label: textbox", "Longitude:")
}
NumberField {
id: longitudeFixedField
validator: DoubleValidator {bottom: -180; top: 180; decimals: 10}
backend: kcm.nightColorSettings.longitudeFixed
onBackendChanged: {
kcm.nightColorSettings.longitudeFixed = backend;
}
KCM.SettingStateBinding {
configObject: kcm.nightColorSettings
settingName: "LongitudeFixed"
extraEnabledConditions: kcm.nightColorSettings.active
}
}
}
} }
} }

@ -187,10 +187,6 @@ KCM.SimpleKCM {
] ]
} }
Item {
Kirigami.FormData.isSection: true
}
QQC2.ComboBox { QQC2.ComboBox {
id: modeSwitcher id: modeSwitcher
// Work around https://bugs.kde.org/show_bug.cgi?id=403153 // Work around https://bugs.kde.org/show_bug.cgi?id=403153
@ -370,6 +366,7 @@ KCM.SimpleKCM {
// Show location chooser in manual location mode // Show location chooser in manual location mode
LocationsFixedView { LocationsFixedView {
visible: kcm.nightColorSettings.mode === NightColorMode.Location visible: kcm.nightColorSettings.mode === NightColorMode.Location
Layout.alignment: Qt.AlignHCenter
enabled: activator.checked enabled: activator.checked
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Loading…
Cancel
Save