Changeset View
Changeset View
Standalone View
Standalone View
kcms/nightcolor/package/contents/ui/main.qml
1 | /******************************************************************** | 1 | /******************************************************************** | ||
---|---|---|---|---|---|
2 | Copyright 2017 Roman Gilg <subdiff@gmail.com> | 2 | Copyright 2017 Roman Gilg <subdiff@gmail.com> | ||
3 | 3 | | |||
4 | This program is free software; you can redistribute it and/or modify | 4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | 6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | 7 | (at your option) any later version. | ||
8 | 8 | | |||
9 | This program is distributed in the hope that it will be useful, | 9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | 12 | GNU General Public License for more details. | ||
13 | 13 | | |||
14 | You should have received a copy of the GNU General Public License | 14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | *********************************************************************/ | 16 | *********************************************************************/ | ||
17 | import QtQuick 2.1 | 17 | import QtQuick 2.12 | ||
18 | import QtQuick.Layouts 1.1 | 18 | import QtQuick.Layouts 1.1 | ||
19 | import QtQuick.Controls 1.4 as Controls | 19 | import QtQuick.Controls 2.5 as QQC2 | ||
20 | 20 | | |||
21 | import org.kde.kquickcontrolsaddons 2.0 | 21 | import org.kde.kirigami 2.5 as Kirigami | ||
22 | import org.kde.plasma.core 2.0 as PlasmaCore | 22 | import org.kde.kcm 1.2 as KCM | ||
filipf: Are these 3 imports needed? I couldn't figure out what they were doing. | |||||
23 | import org.kde.plasma.extras 2.0 as PlasmaExtras | | |||
24 | 23 | | |||
25 | import org.kde.colorcorrect 0.1 as CC | 24 | import org.kde.colorcorrect 0.1 as CC | ||
26 | 25 | | |||
27 | Item { | 26 | KCM.SimpleKCM { | ||
28 | id: root | 27 | id: root | ||
29 | | ||||
30 | implicitHeight: units.gridUnit * 20 | | |||
31 | | ||||
32 | property int error: cA.error | 28 | property int error: cA.error | ||
33 | | ||||
34 | property bool defaultRequested: false | 29 | property bool defaultRequested: false | ||
35 | 30 | | |||
36 | CC.CompositorAdaptor { | 31 | CC.CompositorAdaptor { | ||
37 | id: cA | 32 | id: cA | ||
38 | } | 33 | } | ||
39 | 34 | | |||
40 | CC.Geolocator { | 35 | CC.Geolocator { | ||
41 | id: locator | 36 | id: locator | ||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Line(s) | 79 | onStagedDataReset: { | |||
86 | tempSlider.value = cA.nightTemperature; | 81 | tempSlider.value = cA.nightTemperature; | ||
87 | modeSwitcher.currentIndex = cA.mode; | 82 | modeSwitcher.currentIndex = cA.mode; | ||
88 | reset(); | 83 | reset(); | ||
89 | calcNeedsSave(); | 84 | calcNeedsSave(); | ||
90 | } | 85 | } | ||
91 | } | 86 | } | ||
92 | signal reset() | 87 | signal reset() | ||
93 | 88 | | |||
94 | Item { | 89 | header: ColumnLayout{ | ||
95 | id: main | 90 | Kirigami.InlineMessage { | ||
96 | width: childrenRect.width | 91 | id: errorMessage | ||
97 | height: childrenRect.height | 92 | Layout.fillWidth: true | ||
93 | visible: error != CC.CompositorAdaptor.ErrorCodeSuccess | ||||
94 | type: Kirigami.MessageType.Error | ||||
95 | text: cA.errorText | ||||
96 | } | ||||
97 | } | ||||
98 | | ||||
99 | ColumnLayout { | ||||
98 | 100 | | |||
99 | enabled: cA.nightColorAvailable | 101 | Kirigami.FormLayout { | ||
102 | id: parentLayout | ||||
100 | 103 | | |||
101 | Controls.CheckBox { | 104 | QQC2.CheckBox { | ||
102 | id: activator | 105 | id: activator | ||
103 | text: i18n("Activate Night Color") | 106 | text: i18n("Activate Night Color") | ||
107 | enabled: cA.nightColorAvailable | ||||
104 | checked: cA.active | 108 | checked: cA.active | ||
105 | 109 | | |||
106 | onCheckedChanged: { | 110 | onCheckedChanged: { | ||
107 | cA.activeStaged = checked; | 111 | cA.activeStaged = checked; | ||
108 | calcNeedsSave(); | 112 | calcNeedsSave(); | ||
109 | } | 113 | } | ||
110 | } | 114 | } | ||
111 | 115 | | |||
112 | ColumnLayout { | 116 | QQC2.Slider { | ||
113 | id: mainControls | | |||
114 | anchors.top: activator.bottom | | |||
115 | anchors.topMargin: units.largeSpacing | | |||
116 | | ||||
117 | enabled: activator.checked | | |||
118 | | ||||
119 | Controls.Label { | | |||
120 | text: i18n("Night Color Temperature: ") + tempSlider.value + i18n(" K") | | |||
121 | } | | |||
122 | | ||||
123 | Controls.Slider { | | |||
124 | id: tempSlider | 117 | id: tempSlider | ||
125 | implicitWidth: units.gridUnit * 15 | 118 | Kirigami.FormData.label: i18n("Night Color temperature:") | ||
126 | 119 | enabled: activator.checked | |||
127 | minimumValue: cA.minimalTemperature | 120 | from: cA.minimalTemperature | ||
128 | maximumValue: cA.neutralTemperature | 121 | to: cA.neutralTemperature | ||
129 | value: cA.nightTemperature | 122 | value: cA.nightTemperature | ||
130 | stepSize: 100 | 123 | stepSize: 100 | ||
131 | 124 | | |||
132 | onValueChanged: { | 125 | onValueChanged: { | ||
133 | cA.nightTemperatureStaged = value; | 126 | cA.nightTemperatureStaged = value; | ||
134 | calcNeedsSave(); | 127 | calcNeedsSave(); | ||
135 | } | 128 | } | ||
136 | } | 129 | } | ||
137 | 130 | | |||
138 | RowLayout { | 131 | RowLayout { | ||
139 | spacing: units.largeSpacing | 132 | enabled: activator.checked | ||
140 | Controls.Label { | 133 | Layout.fillWidth: true | ||
141 | text: i18n("Operation mode:") | 134 | | ||
135 | QQC2.Label { | ||||
136 | Layout.fillWidth: true | ||||
137 | horizontalAlignment: Text.AlignHCenter | ||||
138 | text: tempSlider.value + i18n(" K") | ||||
139 | } | ||||
142 | } | 140 | } | ||
143 | Controls.ComboBox { | 141 | | ||
142 | QQC2.ComboBox { | ||||
144 | id: modeSwitcher | 143 | id: modeSwitcher | ||
145 | width: theme.mSize(theme.defaultFont).width * 9 | 144 | Kirigami.FormData.label: i18n("Operation mode:") | ||
145 | enabled: activator.checked | ||||
146 | model: [i18n("Automatic"), | 146 | model: [i18n("Automatic"), | ||
147 | i18n("Location"), | 147 | i18n("Location"), | ||
148 | i18n("Times")] | 148 | i18n("Times")] | ||
149 | currentIndex: cA.mode | 149 | currentIndex: cA.mode | ||
150 | onCurrentIndexChanged: { | 150 | onCurrentIndexChanged: { | ||
151 | cA.modeStaged = currentIndex; | 151 | cA.modeStaged = currentIndex; | ||
152 | advancedControlLoader.updatePage(currentIndex); | 152 | advancedControlLoader.updatePage(currentIndex); | ||
153 | calcNeedsSave(); | 153 | calcNeedsSave(); | ||
154 | } | 154 | } | ||
155 | } | 155 | } | ||
156 | } | 156 | } | ||
157 | } | 157 | | ||
158 | Kirigami.FormLayout { | ||||
158 | 159 | | |||
159 | Loader { | 160 | Loader { | ||
160 | id: advancedControlLoader | 161 | id: advancedControlLoader | ||
161 | 162 | | |||
162 | anchors.top: mainControls.bottom | | |||
163 | anchors.topMargin: units.largeSpacing | | |||
164 | 163 | | |||
165 | function updatePage(index) { | 164 | function updatePage(index) { | ||
166 | sourceComponent = undefined; | 165 | sourceComponent = undefined; | ||
167 | var page; | 166 | var page; | ||
168 | if (index === CC.CompositorAdaptor.ModeLocation) { | 167 | if (index === CC.CompositorAdaptor.ModeLocation) { | ||
169 | page = manualLocationsView; | 168 | page = manualLocationsView; | ||
170 | } else if (index === CC.CompositorAdaptor.ModeTimings) { | 169 | } else if (index === CC.CompositorAdaptor.ModeTimings) { | ||
171 | page = manualTimingsView; | 170 | page = manualTimingsView; | ||
172 | } else { | 171 | } else { | ||
173 | page = automaticView; | 172 | page = automaticView; | ||
174 | } | 173 | } | ||
175 | 174 | | |||
176 | sourceComponent = page; | 175 | sourceComponent = page; | ||
177 | } | 176 | } | ||
178 | } | 177 | } | ||
179 | 178 | | |||
180 | Component { | 179 | Component { | ||
181 | id: automaticView | 180 | id: automaticView | ||
182 | Row { | 181 | | ||
183 | spacing: units.largeSpacing | 182 | ColumnLayout { | ||
184 | 183 | | |||
185 | Loader { | 184 | Loader { | ||
186 | sourceComponent: TimingsView { | 185 | sourceComponent: TimingsView { | ||
187 | latitude: locator.latitude | 186 | latitude: locator.latitude | ||
188 | longitude: locator.longitude | 187 | longitude: locator.longitude | ||
189 | } | 188 | } | ||
190 | } | 189 | } | ||
190 | | ||||
191 | Kirigami.Separator { | ||||
192 | Layout.fillWidth: true | ||||
193 | Kirigami.FormData.isSection: true | ||||
194 | } | ||||
195 | | ||||
191 | Loader { | 196 | Loader { | ||
192 | sourceComponent: LocationsAutoView { | 197 | sourceComponent: LocationsAutoView { | ||
193 | latitude: locator.latitude | 198 | latitude: locator.latitude | ||
194 | longitude: locator.longitude | 199 | longitude: locator.longitude | ||
195 | } | 200 | } | ||
196 | } | 201 | } | ||
197 | } | 202 | } | ||
198 | } | 203 | } | ||
199 | 204 | | |||
200 | Component { | 205 | Component { | ||
201 | id: manualLocationsView | 206 | id: manualLocationsView | ||
202 | 207 | | |||
203 | Row { | 208 | ColumnLayout { | ||
204 | id: manualLocationsViewRow | 209 | id: manualLocationsViewRow | ||
205 | spacing: units.largeSpacing | | |||
206 | | ||||
207 | signal change() | 210 | signal change() | ||
208 | 211 | | |||
209 | Loader { | 212 | Loader { | ||
210 | sourceComponent: TimingsView { | 213 | sourceComponent: TimingsView { | ||
211 | latitude: cA.latitudeFixedStaged | 214 | latitude: cA.latitudeFixedStaged | ||
212 | longitude: cA.longitudeFixedStaged | 215 | longitude: cA.longitudeFixedStaged | ||
213 | 216 | | |||
214 | Connections { | 217 | Connections { | ||
215 | target: manualLocationsViewRow | 218 | target: manualLocationsViewRow | ||
216 | onChange: { | 219 | onChange: { | ||
217 | reset(); | 220 | reset(); | ||
218 | } | 221 | } | ||
219 | } | 222 | } | ||
220 | } | 223 | } | ||
221 | } | 224 | } | ||
225 | | ||||
226 | Kirigami.Separator { | ||||
227 | Layout.fillWidth: true | ||||
228 | Kirigami.FormData.isSection: true | ||||
229 | } | ||||
230 | | ||||
222 | Loader { | 231 | Loader { | ||
223 | sourceComponent: LocationsFixedView {} | 232 | sourceComponent: LocationsFixedView {} | ||
224 | } | 233 | } | ||
225 | } | 234 | } | ||
226 | } | 235 | } | ||
227 | 236 | | |||
228 | Component { | 237 | Component { | ||
229 | id: manualTimingsView | 238 | id: manualTimingsView | ||
230 | Column { | | |||
231 | spacing: units.smallSpacing | | |||
232 | 239 | | |||
233 | GridLayout { | 240 | Kirigami.FormLayout { | ||
234 | id: manualTimingsViewGrid | 241 | twinFormLayouts: parentLayout | ||
235 | | ||||
236 | columns: 3 | | |||
237 | rowSpacing: units.smallSpacing | | |||
238 | columnSpacing: units.smallSpacing | | |||
239 | enabled: activator.checked && cA.timingsEnabled | 242 | enabled: activator.checked && cA.timingsEnabled | ||
240 | 243 | | |||
241 | Connections { | 244 | Connections { | ||
242 | target: root | 245 | target: root | ||
243 | onReset: { | 246 | onReset: { | ||
244 | mornBeginManField.backend = cA.morningBeginFixed; | 247 | mornBeginManField.backend = cA.morningBeginFixed; | ||
245 | evenBeginManField.backend = cA.eveningBeginFixed; | 248 | evenBeginManField.backend = cA.eveningBeginFixed; | ||
246 | transTimeField.backend = cA.transitionTime; | 249 | transTimeField.backend = cA.transitionTime; | ||
247 | } | 250 | } | ||
248 | } | 251 | } | ||
249 | 252 | | |||
250 | Controls.Label { | | |||
251 | text: i18n("Sunrise begins") | | |||
252 | Layout.alignment: Qt.AlignRight | | |||
253 | } | | |||
254 | TimeField { | 253 | TimeField { | ||
255 | id: mornBeginManField | 254 | id: mornBeginManField | ||
255 | Kirigami.FormData.label: i18n("Sunrise begins:") | ||||
256 | backend: cA.morningBeginFixedStaged | 256 | backend: cA.morningBeginFixedStaged | ||
257 | onBackendChanged: {cA.morningBeginFixedStaged = backend; | 257 | onBackendChanged: {cA.morningBeginFixedStaged = backend; | ||
258 | calcNeedsSave(); | 258 | calcNeedsSave(); | ||
259 | } | 259 | } | ||
260 | | ||||
261 | QQC2.ToolTip { | ||||
262 | text: i18n("(Input format: HH:MM)") | ||||
260 | } | 263 | } | ||
261 | Controls.Label { | | |||
262 | enabled: false | | |||
263 | text: i18n("(HH:MM)") | | |||
264 | } | | |||
265 | Controls.Label { | | |||
266 | text: i18n("Sunset begins") | | |||
267 | Layout.alignment: Qt.AlignRight | | |||
268 | } | 264 | } | ||
265 | | ||||
269 | TimeField { | 266 | TimeField { | ||
270 | id: evenBeginManField | 267 | id: evenBeginManField | ||
268 | Kirigami.FormData.label: i18n("Sunset begins:") | ||||
271 | backend: cA.eveningBeginFixedStaged | 269 | backend: cA.eveningBeginFixedStaged | ||
272 | onBackendChanged: {cA.eveningBeginFixedStaged = backend; | 270 | onBackendChanged: {cA.eveningBeginFixedStaged = backend; | ||
273 | calcNeedsSave(); | 271 | calcNeedsSave(); | ||
274 | } | 272 | } | ||
273 | | ||||
274 | QQC2.ToolTip { | ||||
275 | text: i18n("Input format: HH:MM") | ||||
275 | } | 276 | } | ||
276 | Controls.Label { | | |||
277 | enabled: false | | |||
278 | text: i18n("(HH:MM)") | | |||
279 | } | | |||
280 | Controls.Label { | | |||
281 | text: i18n("Transition duration") | | |||
282 | Layout.alignment: Qt.AlignRight | | |||
283 | } | 277 | } | ||
278 | | ||||
284 | NumberField { | 279 | NumberField { | ||
285 | id: transTimeField | 280 | id: transTimeField | ||
281 | Kirigami.FormData.label: i18n("Transition duration:") | ||||
286 | backend: cA.transitionTimeStaged | 282 | backend: cA.transitionTimeStaged | ||
287 | onBackendChanged: {cA.transitionTimeStaged = backend; | 283 | onBackendChanged: {cA.transitionTimeStaged = backend; | ||
288 | calcNeedsSave(); | 284 | calcNeedsSave(); | ||
289 | } | 285 | } | ||
290 | 286 | | |||
291 | inputMethodHints: Qt.ImhDigitsOnly | 287 | inputMethodHints: Qt.ImhDigitsOnly | ||
292 | validator: IntValidator {bottom: 1; top: 600;} // less than 12 hours (in minutes: 720) | 288 | validator: IntValidator {bottom: 1; top: 600;} // less than 12 hours (in minutes: 720) | ||
293 | } | 289 | | ||
294 | Controls.Label { | 290 | QQC2.ToolTip { | ||
295 | enabled: false | 291 | text: i18n("Input minutes - min. 1, max. 600") | ||
296 | text: i18n("(In minutes - min. 1, max. 600)") | | |||
297 | } | 292 | } | ||
298 | } | 293 | } | ||
299 | Controls.Label { | 294 | | ||
295 | QQC2.Label { | ||||
300 | id: manualTimingsError1 | 296 | id: manualTimingsError1 | ||
301 | anchors.horizontalCenter: manualTimingsViewGrid.horizontalCenter | | |||
302 | visible: evenBeginManField.getNormedDate() - mornBeginManField.getNormedDate() <= 0 | 297 | visible: evenBeginManField.getNormedDate() - mornBeginManField.getNormedDate() <= 0 | ||
303 | | ||||
304 | font.italic: true | 298 | font.italic: true | ||
305 | text: i18n("Error: Morning not before evening.") | 299 | text: i18n("Error: Morning is before evening.") | ||
306 | } | 300 | } | ||
307 | Controls.Label { | 301 | | ||
302 | QQC2.Label { | ||||
308 | id: manualTimingsError2 | 303 | id: manualTimingsError2 | ||
309 | anchors.horizontalCenter: manualTimingsViewGrid.horizontalCenter | | |||
310 | visible: { | 304 | visible: { | ||
311 | if (manualTimingsError1.visible) { | 305 | if (manualTimingsError1.visible) { | ||
312 | return false; | 306 | return false; | ||
313 | } | 307 | } | ||
314 | var trTime = transTimeField.backend * 60 * 1000; | 308 | var trTime = transTimeField.backend * 60 * 1000; | ||
315 | var mor = mornBeginManField.getNormedDate(); | 309 | var mor = mornBeginManField.getNormedDate(); | ||
316 | var eve = evenBeginManField.getNormedDate(); | 310 | var eve = evenBeginManField.getNormedDate(); | ||
317 | 311 | | |||
318 | return eve - mor <= trTime || eve - mor >= 86400000 - trTime; | 312 | return eve - mor <= trTime || eve - mor >= 86400000 - trTime; | ||
319 | } | 313 | } | ||
320 | font.italic: true | 314 | font.italic: true | ||
321 | text: i18n("Error: Transition time overlaps.") | 315 | text: i18n("Error: Transition time overlaps.") | ||
322 | } | 316 | } | ||
323 | } | 317 | } | ||
324 | } | 318 | } | ||
325 | } | 319 | } | ||
326 | | ||||
327 | // error message as overlay | | |||
328 | Item { | | |||
329 | width: 0.8 * main.width | | |||
330 | height: 0.8 * main.height | | |||
331 | anchors.centerIn: main | | |||
332 | | ||||
333 | visible: error != CC.CompositorAdaptor.ErrorCodeSuccess | | |||
334 | | ||||
335 | Rectangle { | | |||
336 | anchors.centerIn: parent | | |||
337 | width: errorMessage.contentWidth * 1.1 | | |||
338 | height: errorMessage.contentHeight * 1.1 | | |||
339 | color: theme.backgroundColor | | |||
340 | opacity: 0.8 | | |||
341 | | ||||
342 | border { | | |||
343 | width: units.devicePixelRatio | | |||
344 | color: theme.textColor | | |||
345 | } | | |||
346 | } | | |||
347 | | ||||
348 | PlasmaExtras.Heading { | | |||
349 | id: errorMessage | | |||
350 | anchors.fill: parent | | |||
351 | | ||||
352 | level: 4 | | |||
353 | text: cA.errorText | | |||
354 | | ||||
355 | horizontalAlignment: Text.AlignHCenter | | |||
356 | verticalAlignment: Text.AlignVCenter | | |||
357 | | ||||
358 | wrapMode: Text.Wrap | | |||
359 | textFormat: Text.PlainText | | |||
360 | } | | |||
361 | } | 320 | } | ||
362 | } | 321 | } |
Are these 3 imports needed? I couldn't figure out what they were doing.