Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe1cea9e2b | |||
| 0bf78c54d0 | |||
| 8a58e66c20 | |||
| f9a84b18e8 | |||
| c53c149d31 | |||
| 17348f7acf | |||
| e1b464e36c | |||
| d97ec091c5 | |||
| af63b5ad43 | |||
| 3636e3ffac | |||
| c04ec20704 | |||
| 506bb45dda | |||
| 4a4cc9f778 | |||
| 20223b21de | |||
| 66e4023b7a | |||
| 22920ad712 | |||
| 513cb38154 | |||
| 14f6548ce7 | |||
| 12cd81bf65 | |||
| 1833399aaa | |||
| 4e1da62b90 | |||
| a0fe24bbd1 | |||
| ccaf08e238 | |||
| 1a8a986674 | |||
| 7c5e86e8dc | |||
| 132b33bdf8 | |||
| 0cfe14feed | |||
| f843e01847 | |||
| d21557b0f1 | |||
| 6a997e4945 | |||
| d88a21c6f0 | |||
| edc1e62ff3 | |||
| f087c18ab1 | |||
| a5b9da3f34 | |||
| d433ab579d | |||
| 78a925ff8a | |||
| 5ca5b76d7c |
6
.gitignore
vendored
@@ -1,7 +1,9 @@
|
|||||||
*.glade~
|
*.glade~
|
||||||
*.glade#
|
*.glade#
|
||||||
extracted/
|
|
||||||
custom_images/
|
|
||||||
*.txt
|
*.txt
|
||||||
|
*.json
|
||||||
|
extracted_images/
|
||||||
selected/
|
selected/
|
||||||
__pycache__
|
__pycache__
|
||||||
|
time_bar.svg
|
||||||
|
time_bar_polylines.svg
|
||||||
21
CHANGELOG
@@ -1,3 +1,24 @@
|
|||||||
|
# Version 2.1
|
||||||
|
- Bugfixes
|
||||||
|
- Smaller UI for displays with reduced resolution (< 1000px height)
|
||||||
|
|
||||||
|
# Version 2.0
|
||||||
|
- New App icon
|
||||||
|
- Preferences window redesign - All settings are now in one window accessable!
|
||||||
|
- Graphic visualizing of the time periods of a day with a bar chart
|
||||||
|
- Adding custom time periods by user choice
|
||||||
|
- Adding folder as image source
|
||||||
|
- Option to display image on lock screens
|
||||||
|
- Bugfixes
|
||||||
|
- Remove support for Cinnamon 5.2 and older
|
||||||
|
- Apply and OK button to test settings without closing the window
|
||||||
|
|
||||||
|
# Version 1.4
|
||||||
|
- Log System
|
||||||
|
- Bugfixes
|
||||||
|
- Display times in Image Configurator
|
||||||
|
- Display time of last location update in Preferences
|
||||||
|
|
||||||
# Version 1.3
|
# Version 1.3
|
||||||
- Adding option to stretch the image over multiple displays
|
- Adding option to stretch the image over multiple displays
|
||||||
|
|
||||||
|
|||||||
60
README.md
@@ -1,35 +1,39 @@
|
|||||||
# Cinnamon Dynamic Wallpaper
|
# Cinnamon Dynamic Wallpaper
|
||||||
|
<img src="cinnamon-dynamic-wallpaper@TobiZog/5.4/icons/icon.svg" alt="drawing" width="200" style="margin-left:auto; margin-right:auto; width:50%; display:block"/>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## About the project
|
## About the project
|
||||||
Based on a location, this extension calculates the periods of a day and switches the background image of your Cinnamon desktop. The extension offers the choice between a set of included wallpapers or to select a HEIC-file.
|
This extension switches the background image of your Cinnamon desktop multiple times in a day, based on a location or custom time periods. You can choose between included image-sets, your own HEIC-file or a source folder with single images. Configuration through a user-friendly configuration window.
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
- 8 included image sets
|
- 9 included image sets
|
||||||
- 9 day periods
|
- 10 day periods
|
||||||
- HEIF converter
|
- HEIF converter
|
||||||
- Image configuration assistent with simple one-click setup for image choose
|
- Image configuration assistent with simple one-click setup for image choices
|
||||||
- Online location estimation or offline with manual latitude and longitude input
|
- Online location estimation or offline with manual latitude and longitude input
|
||||||
|
- Time periods individual configured by user
|
||||||
- Offline sun angles estimation
|
- Offline sun angles estimation
|
||||||
- Image stretching over multiple displays or repeat image for every display
|
- Image stretching over multiple displays or repeat image for every display
|
||||||
|
- Show image on lock screen
|
||||||
|
|
||||||
### Tested Cinnamon versions
|
### Tested Cinnamon versions
|
||||||
- 4.8 (Mint 20.1)
|
|
||||||
- 5.0 (Mint 20.2)
|
|
||||||
- 5.2 (Mint 20.3)
|
|
||||||
- 5.4 (Mint 21)
|
- 5.4 (Mint 21)
|
||||||
- 5.6 (Mint 21.1)
|
- 5.6 (Mint 21.1)
|
||||||
- 5.8 (Mint 21.2)
|
- 5.8 (Mint 21.2)
|
||||||
|
- 6.0 (Mint 21.3)
|
||||||
|
|
||||||
### Technology
|
### Technology
|
||||||
- Using `JavaScript` for
|
- `JavaScript`
|
||||||
- Sun angle estimation
|
- Display desktop notifications
|
||||||
- Location estimation
|
- Calling the Python loop script every 60 seconds to refresh the background image
|
||||||
- Change of the desktop wallpapers
|
- `Python`
|
||||||
- `Python` displays the Image Configurator
|
- Handles the preference window
|
||||||
- Image Configurator UI was written with `Glade`
|
- Esimates the location
|
||||||
|
- Changes of the desktop wallpapers
|
||||||
|
- `Glade`
|
||||||
|
- Preference window UI design
|
||||||
|
---
|
||||||
## Installation
|
## Installation
|
||||||
### From Built-in Extension Manager
|
### From Built-in Extension Manager
|
||||||

|

|
||||||
@@ -42,19 +46,21 @@ Based on a location, this extension calculates the periods of a day and switches
|
|||||||
1. Download the Repository
|
1. Download the Repository
|
||||||
2. Extract the files
|
2. Extract the files
|
||||||
3. Copy the folder `cinnamon-dynamic-wallpaper@TobiZog` to `~/.local/share/cinnamon/extensions/`
|
3. Copy the folder `cinnamon-dynamic-wallpaper@TobiZog` to `~/.local/share/cinnamon/extensions/`
|
||||||
|
---
|
||||||
## How to use it
|
## Usage
|
||||||
1. Active the Extension via Cinnamon Extension Manager
|
1. Active the Extension via Cinnamon Extension Manager
|
||||||
2. Open the settings
|
2. Open the settings
|
||||||
3. Keep `Estimate coordinates via network` active or disable it and insert latitude and longitude in the fields
|
3. Configure it to your
|
||||||
4. Choose a set of images or disable it and select for every daytime an image manually
|
- You can apply the setted settings without closing the window if you click on "Apply"
|
||||||
|
4. If your config is complete, click on "OK"
|
||||||
## Image Configurator
|
---
|
||||||
The Cinnamon Dynamic Wallpaper extension offers an integrated image configuration assistant. Here, you can choose an included image set or import a HEIC-file from your system. You have to choose the images for the time periods after the import.
|
## Preferences Window
|
||||||
|
Because of the lack of configuration options in the standard Cinnamon configuration system for extensions offers this extension a custom preference window.
|
||||||
|
All configuration will be handled there. You can choose between included image sets, a HEIC file or a folder source and set the image to ten different daytime periods. Time periods will be estimated via network, custom coordinations or custom time periods. Some behaviour preferences (strech image, fill empty background with gradient color) are also here.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
---
|
||||||
## Included image sets
|
## Included image sets
|
||||||
The image sets are from https://github.com/adi1090x/dynamic-wallpaper
|
The image sets are from https://github.com/adi1090x/dynamic-wallpaper
|
||||||
|
|
||||||
@@ -62,10 +68,10 @@ The image sets are from https://github.com/adi1090x/dynamic-wallpaper
|
|||||||
| ------ | ----- | ------ |
|
| ------ | ----- | ------ |
|
||||||
|  |  |  |
|
|  |  |  |
|
||||||
|
|
||||||
| Cliffs | Gradient | Lakeside |
|
| Cliffs | Earth | Gradient |
|
||||||
| -------- | --------- | ------ |
|
| -------- | --------- | ------ |
|
||||||
|  |  |  |
|
|  |  |  |
|
||||||
|
|
||||||
| Mountains | Sahara |
|
| Lakeside | Mountains | Sahara |
|
||||||
| --------- | ------ |
|
| --------- | ------ | ------ |
|
||||||
|  |  |
|
|  |  |  |
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/extension.js
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/icon/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/icons/icon.png
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/icons/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../5.4/image-configurator/data/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../5.4/image-configurator/image-configurator.glade
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import os
|
|
||||||
import windowHandler
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
wh = windowHandler.WindowHandler(os.path.expanduser("~") + "/.cinnamon/configs/cinnamon-dynamic-wallpaper@TobiZog/cinnamon-dynamic-wallpaper@TobiZog.json")
|
|
||||||
wh.showMainWindow()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../5.4/image-configurator/windowHandler.py
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/images/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/scripts/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../5.4/settings-schema.json
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class ImageSourceEnum(enumerate):
|
||||||
|
IMAGESET = "image_set"
|
||||||
|
HEICFILE = "heic_file"
|
||||||
|
SOURCEFOLDER = "source_folder"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class PeriodSourceEnum(enumerate):
|
||||||
|
NETWORKLOCATION = "network_location"
|
||||||
|
CUSTOMLOCATION = "custom_location"
|
||||||
|
CUSTOMTIMEPERIODS = "custom_time_periods"
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
/**
|
/**
|
||||||
* @name Cinnamon-Dynamic-Wallpaper
|
* @name Cinnamon-Dynamic-Wallpaper
|
||||||
* @alias TobiZog
|
* @alias TobiZog
|
||||||
* @since 2023
|
* @since 2023-05-17
|
||||||
|
*
|
||||||
|
* @description Main application file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************** Imports ********************/
|
/******************** Imports ********************/
|
||||||
|
|
||||||
const MessageTray = imports.ui.messageTray;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
const Settings = imports.ui.settings;
|
const Settings = imports.ui.settings;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const { find_program_in_path } = imports.gi.GLib;
|
const { find_program_in_path } = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
let suntimes = require('./scripts/suntimes')
|
|
||||||
let location = require('./scripts/location')
|
|
||||||
|
|
||||||
|
|
||||||
/******************** Constants ********************/
|
/******************** Constants ********************/
|
||||||
@@ -33,12 +33,7 @@ const PATH = DIRECTORY.path;
|
|||||||
// The extension object
|
// The extension object
|
||||||
let extension;
|
let extension;
|
||||||
|
|
||||||
// Time and date of the last location update
|
// Loop state
|
||||||
let lastLocationUpdate = new Date()
|
|
||||||
|
|
||||||
// The last calculated suntime of the day
|
|
||||||
let lastDayTime = suntimes.DAYPERIOD.NONE
|
|
||||||
|
|
||||||
let looping = true
|
let looping = true
|
||||||
|
|
||||||
|
|
||||||
@@ -50,6 +45,9 @@ function CinnamonDynamicWallpaperExtension(uuid) {
|
|||||||
|
|
||||||
|
|
||||||
CinnamonDynamicWallpaperExtension.prototype = {
|
CinnamonDynamicWallpaperExtension.prototype = {
|
||||||
|
|
||||||
|
/******************** Lifecycle ********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialization
|
* Initialization
|
||||||
*
|
*
|
||||||
@@ -58,53 +56,17 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
_init: function(uuid) {
|
_init: function(uuid) {
|
||||||
this.settings = new Settings.ExtensionSettings(this, uuid);
|
this.settings = new Settings.ExtensionSettings(this, uuid);
|
||||||
|
|
||||||
// Image set
|
|
||||||
this.bindSettings("sw_image_stretch", "imageStretch", this.settingsUpdated)
|
|
||||||
|
|
||||||
// Location estimation
|
|
||||||
this.bindSettings("sw_auto_location", "autolocation", this.settingsUpdated)
|
|
||||||
this.bindSettings("sc_location_refresh_time", "locationRefreshTime", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_latitude", "latitude", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_longitude", "longitude", this.settingsUpdated)
|
|
||||||
|
|
||||||
// Time periods
|
|
||||||
this.bindSettings("tv_times", "tvTimes")
|
|
||||||
|
|
||||||
// Image Configurator
|
|
||||||
this.bindSettings("etr_img_morning_twilight", "img_morning_twilight", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_sunrise", "img_sunrise", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_morning", "img_morning", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_noon", "img_noon", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_afternoon", "img_afternoon", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_evening", "img_evening", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_sunset", "img_sunset", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_night_twilight", "img_night_twilight", this.settingsUpdated)
|
|
||||||
this.bindSettings("etr_img_night", "img_night", this.settingsUpdated)
|
|
||||||
|
|
||||||
|
|
||||||
// Check for the first startup
|
// Check for the first startup
|
||||||
if (this.settings.getValue("first_start")) {
|
if (this.settings.getValue("first_start")) {
|
||||||
|
|
||||||
// Welcome notification
|
// Welcome notification
|
||||||
this.showNotification("Welcome to Cinnamon Dynamic Wallpaper",
|
this.showNotification("Welcome to Cinnamon Dynamic Wallpaper",
|
||||||
"Check the preferences to choose a dynamic wallpaper", true)
|
"Check the preferences to choose a dynamic wallpaper", true)
|
||||||
|
|
||||||
// Hide the notification on system restart
|
// Hide the notification on system restart
|
||||||
this.settings.setValue("first_start", false)
|
this.settings.setValue("first_start", false)
|
||||||
|
this.settings.setValue("source_folder", DIRECTORY["path"] + "/images/included_image_sets/lakeside/")
|
||||||
// Create the folder for the selected images
|
|
||||||
Util.spawnCommandLine("mkdir " + DIRECTORY.path + "/images/selected/")
|
|
||||||
|
|
||||||
// Link the default wallpaper to the folder
|
|
||||||
for (let i = 1; i <= 9; i++) {
|
|
||||||
Util.spawnCommandLine("ln -s " +
|
|
||||||
DIRECTORY.path + "/images/included_image_sets/lakeside/" + i + ".jpg " +
|
|
||||||
DIRECTORY.path + "/images/selected/" + i + ".jpg");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Set image initial at desktop wallpaper
|
|
||||||
this.setImageToTime()
|
|
||||||
|
|
||||||
// Start the main loop, checks in fixed time periods the
|
// Start the main loop, checks in fixed time periods the
|
||||||
this._loop()
|
this._loop()
|
||||||
@@ -114,9 +76,9 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Binding the settings objects
|
* Binding the settings objects
|
||||||
*
|
*
|
||||||
* @param {*} ui_name Name of preference in settings-schema.json
|
* @param {string} ui_name Name of preference in settings-schema.json
|
||||||
* @param {*} js_name Name of preference in JavaScript
|
* @param {string} js_name Name of preference in JavaScript
|
||||||
* @param {*} func Function to call on change
|
* @param {Function} func Function to call on change
|
||||||
*/
|
*/
|
||||||
bindSettings: function (ui_name, js_name, func = this.on_settings_changed) {
|
bindSettings: function (ui_name, js_name, func = this.on_settings_changed) {
|
||||||
this.settings.bindProperty(
|
this.settings.bindProperty(
|
||||||
@@ -129,25 +91,24 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles changes in settings
|
* Main loop
|
||||||
*/
|
*/
|
||||||
settingsUpdated: function() {
|
_loop: function () {
|
||||||
lastDayTime = suntimes.DAYPERIOD.NONE
|
if (looping) {
|
||||||
|
try {
|
||||||
|
Util.spawnCommandLine("/usr/bin/env python3 " + DIRECTORY.path + "/loop.py")
|
||||||
|
} catch(e) {
|
||||||
|
this.showNotification("Error!",
|
||||||
|
"Cinnamon Dynamic Wallpaper got an error while running the loop script. Please create an issue on GitHub.")
|
||||||
|
}
|
||||||
|
|
||||||
this.updateLocation()
|
// Refresh every 60 seconds
|
||||||
this.setImageToTime()
|
Mainloop.timeout_add_seconds(60, Lang.bind(this, this._loop));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
showNotification(title, text, showOpenSettings = false) {
|
||||||
* Displaying a desktop notification
|
|
||||||
*
|
|
||||||
* @param {string} title The Title in the notification
|
|
||||||
* @param {string} text The text in the notification
|
|
||||||
* @param {boolean} showOpenSettings Display the "Open settings" button in the notification,
|
|
||||||
* defaults to false
|
|
||||||
*/
|
|
||||||
showNotification: function (title, text, showOpenSettings = false) {
|
|
||||||
let source = new MessageTray.Source(this.uuid);
|
let source = new MessageTray.Source(this.uuid);
|
||||||
|
|
||||||
// Parameter
|
// Parameter
|
||||||
@@ -158,7 +119,6 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
icon_size: source.ICON_SIZE
|
icon_size: source.ICON_SIZE
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// The notification itself
|
// The notification itself
|
||||||
let notification = new MessageTray.Notification(source, title, text, params);
|
let notification = new MessageTray.Notification(source, title, text, params);
|
||||||
|
|
||||||
@@ -167,7 +127,8 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
notification.addButton("open-settings", _("Open settings"));
|
notification.addButton("open-settings", _("Open settings"));
|
||||||
|
|
||||||
notification.connect("action-invoked", () =>
|
notification.connect("action-invoked", () =>
|
||||||
Util.spawnCommandLine("xlet-settings extension " + UUID));
|
Util.spawnCommandLine("/usr/bin/env python3 " +
|
||||||
|
DIRECTORY.path + "/preferences.py"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put all together
|
// Put all together
|
||||||
@@ -175,149 +136,6 @@ CinnamonDynamicWallpaperExtension.prototype = {
|
|||||||
|
|
||||||
// Display it
|
// Display it
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the desktop background image
|
|
||||||
*
|
|
||||||
* @param {jpg} imageURI The new desktop image
|
|
||||||
*/
|
|
||||||
changeWallpaper: function(imageURI) {
|
|
||||||
let gSetting = new Gio.Settings({schema: 'org.cinnamon.desktop.background'});
|
|
||||||
gSetting.set_string('picture-uri', imageURI);
|
|
||||||
|
|
||||||
if (this.imageStretch) {
|
|
||||||
gSetting.set_string('picture-options', 'spanned')
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gSetting.set_string('picture-options', 'zoom')
|
|
||||||
}
|
|
||||||
|
|
||||||
Gio.Settings.sync();
|
|
||||||
gSetting.apply();
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Estimate the right image based on time period of the day
|
|
||||||
*/
|
|
||||||
setImageToTime: function() {
|
|
||||||
let times = suntimes.calcTimePeriod(this.latitude, this.longitude)
|
|
||||||
let now = new Date()
|
|
||||||
|
|
||||||
let timesArray = [
|
|
||||||
times["morning_twilight"], times["sunrise"], times["morning"],
|
|
||||||
times["noon"], times["afternoon"], times["evening"],
|
|
||||||
times["sunset"], times["night_twilight"], times["night"]
|
|
||||||
]
|
|
||||||
|
|
||||||
let imageSet = [
|
|
||||||
this.img_morning_twilight, this.img_sunrise, this.img_morning,
|
|
||||||
this.img_noon, this.img_afternoon, this.img_evening,
|
|
||||||
this.img_sunset, this.img_night_twilight, this.img_night
|
|
||||||
]
|
|
||||||
|
|
||||||
for(let i = 0; i < timesArray.length; i++) {
|
|
||||||
if(timesArray[i][0] <= now && now <= timesArray[i][1] && i != lastDayTime) {
|
|
||||||
this.changeWallpaper("file://" + PATH + "/images/selected/" + imageSet[i])
|
|
||||||
|
|
||||||
lastDayTime = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function convertToTimeString(time) {
|
|
||||||
return time.getHours().toString().padStart(2, "0") + ":" + time.getMinutes().toString().padStart(2, "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tvTimes =
|
|
||||||
"Morning Twilight:\t\t" + convertToTimeString(timesArray[0][0]) + " - " + convertToTimeString(timesArray[0][1]) +
|
|
||||||
"\nSunrise:\t\t\t\t" + convertToTimeString(timesArray[1][0]) + " - " + convertToTimeString(timesArray[1][1]) +
|
|
||||||
"\nMorning:\t\t\t" + convertToTimeString(timesArray[2][0]) + " - " + convertToTimeString(timesArray[2][1]) +
|
|
||||||
"\nNoon:\t\t\t\t" + convertToTimeString(timesArray[3][0]) + " - " + convertToTimeString(timesArray[3][1]) +
|
|
||||||
"\nAfternoon:\t\t\t" + convertToTimeString(timesArray[4][0]) + " - " + convertToTimeString(timesArray[4][1]) +
|
|
||||||
"\nEvening:\t\t\t" + convertToTimeString(timesArray[5][0]) + " - " + convertToTimeString(timesArray[5][1]) +
|
|
||||||
"\nSunset:\t\t\t\t" + convertToTimeString(timesArray[6][0]) + " - " + convertToTimeString(timesArray[6][1]) +
|
|
||||||
"\nNight Twilight:\t\t" + convertToTimeString(timesArray[7][0]) + " - " + convertToTimeString(timesArray[7][1]) +
|
|
||||||
"\nNight:\t\t\t\t" + convertToTimeString(timesArray[8][0]) + " - " + convertToTimeString(timesArray[8][1])
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the location of the user
|
|
||||||
* Callback for changes in preferences
|
|
||||||
*/
|
|
||||||
updateLocation: function () {
|
|
||||||
if (this.autolocation) {
|
|
||||||
let loc = location.estimateLocation()
|
|
||||||
this.latitude = loc["latitude"]
|
|
||||||
this.longitude = loc["longitude"]
|
|
||||||
} else {
|
|
||||||
this.latitude = this.latitude
|
|
||||||
this.longitude = this.longitude
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the update information
|
|
||||||
lastLocationUpdate = new Date()
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main loop
|
|
||||||
*/
|
|
||||||
_loop: function () {
|
|
||||||
if (looping) {
|
|
||||||
this.setImageToTime()
|
|
||||||
|
|
||||||
if (lastLocationUpdate < new Date().getTime() - this.locationRefreshTime * 1000) {
|
|
||||||
this.updateLocation()
|
|
||||||
lastLocationUpdate = new Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh every 60 seconds
|
|
||||||
Mainloop.timeout_add_seconds(60, Lang.bind(this, this._loop));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/******************** UI Callbacks ********************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for settings-schema
|
|
||||||
* Opens the external image configurator window
|
|
||||||
*/
|
|
||||||
openImageConfigurator: function() {
|
|
||||||
Util.spawnCommandLine("/usr/bin/env python3 " +
|
|
||||||
DIRECTORY.path + "/image-configurator/image-configurator.py");
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for settings-schema
|
|
||||||
* Opens the browser and navigates to the URL of the respository
|
|
||||||
*/
|
|
||||||
openRepoWebsite: function() {
|
|
||||||
Util.spawnCommandLine("xdg-open https://github.com/TobiZog/cinnamon-dynamic-wallpaper");
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for settings-schema
|
|
||||||
* Opens the browser and navigates to the URL of the Cinnamon Spices extension
|
|
||||||
*/
|
|
||||||
openSpicesWebsite: function() {
|
|
||||||
Util.spawnCommandLine("xdg-open https://cinnamon-spices.linuxmint.com/extensions/view/97")
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for settings-schema
|
|
||||||
* Opens the browser and navigates to the GitHub issue page
|
|
||||||
*/
|
|
||||||
openIssueWebsite: function() {
|
|
||||||
Util.spawnCommandLine("xdg-open https://github.com/TobiZog/cinnamon-dynamic-wallpaper/issues/new")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
icons/icon.png
|
|
||||||
1
cinnamon-dynamic-wallpaper@TobiZog/5.4/icon.svg
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
icons/icon.svg
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 9.1 KiB |
31
cinnamon-dynamic-wallpaper@TobiZog/5.4/icons/icon.svg
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<linearGradient id="a" gradientTransform="matrix(0.232143 0 0 0.328947 -9.109985 263.79837)" gradientUnits="userSpaceOnUse" x1="88.595886" x2="536.595886" y1="-449.394012" y2="-449.394012">
|
||||||
|
<stop offset="0" stop-color="#77767b"/>
|
||||||
|
<stop offset="0.0384615" stop-color="#c0bfbc"/>
|
||||||
|
<stop offset="0.0768555" stop-color="#9a9996"/>
|
||||||
|
<stop offset="0.923077" stop-color="#9a9996"/>
|
||||||
|
<stop offset="0.961538" stop-color="#c0bfbc"/>
|
||||||
|
<stop offset="1" stop-color="#77767b"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="b" gradientTransform="matrix(0.978582 0 0 0.937323 -9.031522 -9.577706)" gradientUnits="userSpaceOnUse" x1="20.937046" x2="127.213333" y1="76.334984" y2="76.334984">
|
||||||
|
<stop offset="0" stop-color="#066996"/>
|
||||||
|
<stop offset="1" stop-color="#001533"/>
|
||||||
|
</linearGradient>
|
||||||
|
<path d="m 19.457031 15.972656 h 88 c 4.417969 0 8 3.582032 8 8 v 84 c 0 4.417969 -3.582031 8 -8 8 h -88 c -4.417969 0 -8 -3.582031 -8 -8 v -84 c 0 -4.417968 3.582031 -8 8 -8 z m 0 0" fill="url(#a)"/>
|
||||||
|
<path d="m 17.328125 11.972656 h 92.257813 c 3.242187 0 5.871093 2.519532 5.871093 5.625 v 88.75 c 0 3.105469 -2.628906 5.625 -5.871093 5.625 h -92.257813 c -3.242187 0 -5.871094 -2.519531 -5.871094 -5.625 v -88.75 c 0 -3.105468 2.628907 -5.625 5.871094 -5.625 z m 0 0" fill="url(#b)"/>
|
||||||
|
<path d="m 63.945312 74.6875 c 0 10.257812 -8.671874 18.574219 -19.367187 18.574219 s -19.367187 -8.316407 -19.367187 -18.574219 s 8.671874 -18.574219 19.367187 -18.574219 s 19.367187 8.316407 19.367187 18.574219 z m 0 0" fill="#f7c22c"/>
|
||||||
|
<path d="m 61.160156 74.136719 c 0 10.03125 -8.128906 18.164062 -18.160156 18.164062 c -10.027344 0 -18.160156 -8.132812 -18.160156 -18.164062 c 0 -10.027344 8.132812 -18.160157 18.160156 -18.160157 c 10.03125 0 18.160156 8.132813 18.160156 18.160157 z m 0 0" fill="#f7d97e"/>
|
||||||
|
<path d="m 85.46875 19.277344 c 7.65625 3.941406 12.472656 11.832031 12.472656 20.445312 c 0 12.695313 -10.292968 22.992188 -22.992187 22.992188 c -0.074219 -0.007813 -0.148438 -0.011719 -0.222657 -0.019532 c 3.253907 1.679688 6.863282 2.558594 10.527344 2.5625 c 12.695313 0 22.992188 -10.296874 22.992188 -22.992187 c -0.003906 -12.613281 -10.167969 -22.871094 -22.777344 -22.988281 z m 0 0" fill="#eaa22f"/>
|
||||||
|
<path d="m 82.804688 18.175781 c 7.660156 3.9375 12.472656 11.828125 12.476562 20.441407 c 0 12.699218 -10.296875 22.992187 -22.992188 22.992187 c -0.078124 -0.003906 -0.152343 -0.011719 -0.226562 -0.015625 c 3.253906 1.679688 6.863281 2.554688 10.527344 2.558594 c 12.699218 0 22.992187 -10.292969 22.992187 -22.992188 c -0.003906 -12.613281 -10.164062 -22.867187 -22.777343 -22.984375 z m 0 0" fill="#ffc61b"/>
|
||||||
|
<g fill="#f7d97e">
|
||||||
|
<path d="m 44.394531 45.09375 c 0.527344 0 0.953125 0.445312 0.953125 1 v 7.558594 c 0 0.554687 -0.425781 1 -0.953125 1 c -0.527343 0 -0.957031 -0.445313 -0.957031 -1 v -7.558594 c 0 -0.554688 0.429688 -1 0.957031 -1 z m 0 0"/>
|
||||||
|
<path d="m 44.222656 94.574219 c 0.527344 0 0.953125 0.449219 0.953125 1 v 7.5625 c 0 0.554687 -0.425781 1 -0.953125 1 s -0.957031 -0.445313 -0.957031 -1 v -7.5625 c 0 -0.550781 0.429687 -1 0.957031 -1 z m 0 0"/>
|
||||||
|
<path d="m 65.402344 74.839844 c 0 -0.527344 0.449218 -0.953125 1 -0.953125 h 7.5625 c 0.550781 0 1 0.425781 1 0.953125 s -0.449219 0.957031 -1 0.957031 h -7.5625 c -0.550782 0 -1 -0.429687 -1 -0.957031 z m 0 0"/>
|
||||||
|
<path d="m 13.84375 74.300781 c 0 -0.527343 0.445312 -0.957031 1 -0.957031 h 7.558594 c 0.554687 0 1 0.429688 1 0.957031 c 0 0.527344 -0.445313 0.953125 -1 0.953125 h -7.558594 c -0.554688 0 -1 -0.425781 -1 -0.953125 z m 0 0"/>
|
||||||
|
<path d="m 22.230469 53.699219 c 0.371093 -0.375 0.988281 -0.359375 1.378906 0.03125 l 5.347656 5.347656 c 0.390625 0.390625 0.40625 1.007813 0.03125 1.382813 c -0.371093 0.371093 -0.992187 0.355468 -1.382812 -0.035157 l -5.34375 -5.34375 c -0.390625 -0.390625 -0.40625 -1.011719 -0.03125 -1.382812 z m 0 0"/>
|
||||||
|
<path d="m 59.175781 88.910156 c 0.371094 -0.375 0.992188 -0.359375 1.382813 0.03125 l 5.347656 5.347656 c 0.390625 0.390626 0.402344 1.007813 0.03125 1.382813 c -0.375 0.371094 -0.992188 0.355469 -1.382812 -0.035156 l -5.347657 -5.34375 c -0.390625 -0.390625 -0.40625 -1.011719 -0.03125 -1.382813 z m 0 0"/>
|
||||||
|
<path d="m 59.378906 60.664062 c -0.371094 -0.371093 -0.359375 -0.992187 0.03125 -1.382812 l 5.347656 -5.34375 c 0.390626 -0.390625 1.007813 -0.40625 1.382813 -0.035156 c 0.371094 0.375 0.359375 0.992187 -0.03125 1.382812 l -5.347656 5.347656 c -0.390625 0.390626 -1.007813 0.40625 -1.382813 0.03125 z m 0 0"/>
|
||||||
|
<path d="m 22.867188 95.21875 c -0.375 -0.375 -0.359376 -0.992188 0.03125 -1.382812 l 5.34375 -5.347657 c 0.390624 -0.390625 1.011718 -0.40625 1.382812 -0.03125 c 0.375 0.371094 0.359375 0.992188 -0.03125 1.382813 l -5.347656 5.347656 c -0.390625 0.390625 -1.007813 0.402344 -1.378906 0.03125 z m 0 0"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -1,6 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
|
|
||||||
class Source(Enum):
|
|
||||||
SELECTED = 0 # Load previous selected images
|
|
||||||
EXTRACT = 1 # Use a custom image set from a heic file
|
|
||||||
SET = 2 # Use an included image set
|
|
||||||
@@ -1,925 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Generated with glade 3.40.0 -->
|
|
||||||
<interface>
|
|
||||||
<requires lib="gtk+" version="3.24"/>
|
|
||||||
<object class="GtkFileFilter" id="filefilter1">
|
|
||||||
<patterns>
|
|
||||||
<pattern>*.heic</pattern>
|
|
||||||
</patterns>
|
|
||||||
</object>
|
|
||||||
<object class="GtkScrolledWindow" id="page_config">
|
|
||||||
<property name="width-request">100</property>
|
|
||||||
<property name="height-request">80</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkViewport">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vscroll-policy">natural</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">8</property>
|
|
||||||
<property name="margin-end">8</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">4</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.009999999776482582</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<!-- n-columns=2 n-rows=2 -->
|
|
||||||
<object class="GtkGrid">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">8</property>
|
|
||||||
<property name="margin-end">8</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="row-spacing">8</property>
|
|
||||||
<property name="column-spacing">8</property>
|
|
||||||
<property name="column-homogeneous">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Use an included or a custom image set?</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
<property name="height">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="rb_included_image_set">
|
|
||||||
<property name="label" translatable="yes">Use an included image set</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">False</property>
|
|
||||||
<property name="active">True</property>
|
|
||||||
<property name="draw-indicator">True</property>
|
|
||||||
<signal name="toggled" handler="onRadioImageSet" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="rb_external_image_set">
|
|
||||||
<property name="label" translatable="yes">Import a heic-file</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">False</property>
|
|
||||||
<property name="active">True</property>
|
|
||||||
<property name="draw-indicator">True</property>
|
|
||||||
<property name="group">rb_included_image_set</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Image Source</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.009999999776482582</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<!-- n-columns=2 n-rows=2 -->
|
|
||||||
<object class="GtkGrid">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">8</property>
|
|
||||||
<property name="margin-end">8</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="row-spacing">8</property>
|
|
||||||
<property name="column-spacing">8</property>
|
|
||||||
<property name="column-homogeneous">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="lb_image_set">
|
|
||||||
<property name="height-request">36</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Select an image-set</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFileChooserButton" id="fc_heic_file">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="no-show-all">True</property>
|
|
||||||
<property name="filter">filefilter1</property>
|
|
||||||
<property name="title" translatable="yes"/>
|
|
||||||
<signal name="file-set" handler="onHeifSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel" id="lb_heic_file">
|
|
||||||
<property name="height-request">36</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="no-show-all">True</property>
|
|
||||||
<property name="label" translatable="yes">Choose the file, which you want to use</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_image_set">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onImageSetSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Image Set</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="label-xalign">0.009999999776482582</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<!-- n-columns=3 n-rows=3 -->
|
|
||||||
<object class="GtkGrid">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="row-spacing">8</property>
|
|
||||||
<property name="column-spacing">8</property>
|
|
||||||
<property name="row-homogeneous">True</property>
|
|
||||||
<property name="column-homogeneous">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_1">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
<property name="pixel-size">30</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_1">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Morning Twilight</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_2">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_2">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Sunrise</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_3">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_3">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Morning</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">2</property>
|
|
||||||
<property name="top-attach">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_4">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_4">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Noon</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_5">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_5">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Afternoon</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_6">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_6">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Evening</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">2</property>
|
|
||||||
<property name="top-attach">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_7">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_7">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Sunset</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">0</property>
|
|
||||||
<property name="top-attach">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_8">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_8">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Night Twilight</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">1</property>
|
|
||||||
<property name="top-attach">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkFrame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label-xalign">0.5</property>
|
|
||||||
<property name="shadow-type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkAlignment">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="top-padding">8</property>
|
|
||||||
<property name="bottom-padding">8</property>
|
|
||||||
<property name="left-padding">8</property>
|
|
||||||
<property name="right-padding">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage" id="img_preview_9">
|
|
||||||
<property name="width-request">300</property>
|
|
||||||
<property name="height-request">200</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="stock">gtk-missing-image</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkComboBoxText" id="cb_preview_9">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<signal name="changed" handler="onPreviewComboboxSelected" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">1</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Night</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="left-attach">2</property>
|
|
||||||
<property name="top-attach">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">4</property>
|
|
||||||
<property name="margin-end">4</property>
|
|
||||||
<property name="label" translatable="yes">Preview</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<object class="GtkWindow" id="main_window">
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="window-position">center</property>
|
|
||||||
<property name="default-width">1024</property>
|
|
||||||
<property name="default-height">768</property>
|
|
||||||
<property name="icon">../../icon.png</property>
|
|
||||||
<signal name="destroy" handler="onDestroy" swapped="no"/>
|
|
||||||
<child>
|
|
||||||
<object class="GtkStack" id="stack_main">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="transition-type">crossfade</property>
|
|
||||||
<child>
|
|
||||||
<placeholder/>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="titlebar">
|
|
||||||
<object class="GtkHeaderBar">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="title" translatable="yes">Cinnamon Dynamic Wallpaper</property>
|
|
||||||
<property name="subtitle" translatable="yes">Image Configuration</property>
|
|
||||||
<property name="show-close-button">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkButton">
|
|
||||||
<property name="label">gtk-apply</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">True</property>
|
|
||||||
<property name="receives-default">True</property>
|
|
||||||
<property name="use-stock">True</property>
|
|
||||||
<property name="always-show-image">True</property>
|
|
||||||
<signal name="clicked" handler="onApply" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<object class="GtkBox" id="page_load">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="margin-start">8</property>
|
|
||||||
<property name="margin-end">8</property>
|
|
||||||
<property name="margin-top">8</property>
|
|
||||||
<property name="margin-bottom">8</property>
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">8</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkSpinner">
|
|
||||||
<property name="height-request">64</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="active">True</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">True</property>
|
|
||||||
<property name="fill">False</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkLabel">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can-focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Proceeding...</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">2</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
import os
|
|
||||||
import windowHandler
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
wh = windowHandler.WindowHandler(os.path.expanduser("~") + "/.config/cinnamon/spices/cinnamon-dynamic-wallpaper@TobiZog/cinnamon-dynamic-wallpaper@TobiZog.json")
|
|
||||||
wh.showMainWindow()
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
import gi, os, glob, json, shutil, threading, subprocess
|
|
||||||
from data.enum import Source
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
|
||||||
from gi.repository import Gtk, GdkPixbuf
|
|
||||||
|
|
||||||
CONFIGURATOR_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
PROJECT_DIR = os.path.dirname(CONFIGURATOR_DIR) + "/"
|
|
||||||
UI_PATH = CONFIGURATOR_DIR + "/" + "image-configurator.glade"
|
|
||||||
|
|
||||||
IMAGE_DIR = PROJECT_DIR + "images/"
|
|
||||||
IMAGE_EXTRACT_DIR = IMAGE_DIR + "extracted/"
|
|
||||||
IMAGE_SETS_DIR = IMAGE_DIR + "included_image_sets/"
|
|
||||||
IMAGE_SELECTED_DIR = IMAGE_DIR + "selected/"
|
|
||||||
|
|
||||||
|
|
||||||
class WindowHandler:
|
|
||||||
def __init__(self, pref_path: str) -> None:
|
|
||||||
|
|
||||||
########### Class variables ###########
|
|
||||||
self.pref_path = pref_path
|
|
||||||
|
|
||||||
self.pref_vars = [
|
|
||||||
"etr_img_morning_twilight",
|
|
||||||
"etr_img_sunrise",
|
|
||||||
"etr_img_morning",
|
|
||||||
"etr_img_noon",
|
|
||||||
"etr_img_afternoon",
|
|
||||||
"etr_img_evening",
|
|
||||||
"etr_img_sunset",
|
|
||||||
"etr_img_night_twilight",
|
|
||||||
"etr_img_night"
|
|
||||||
]
|
|
||||||
|
|
||||||
self.img_sets = [
|
|
||||||
"aurora",
|
|
||||||
"beach",
|
|
||||||
"bitday",
|
|
||||||
"cliffs",
|
|
||||||
"gradient",
|
|
||||||
"lakeside",
|
|
||||||
"mountains",
|
|
||||||
"sahara"
|
|
||||||
]
|
|
||||||
|
|
||||||
########### Create the folder ###########
|
|
||||||
try:
|
|
||||||
os.mkdir(IMAGE_EXTRACT_DIR)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.mkdir(IMAGE_SELECTED_DIR)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
########### GTK stuff ###########
|
|
||||||
self.builder = Gtk.Builder()
|
|
||||||
self.builder.add_from_file(UI_PATH)
|
|
||||||
self.builder.connect_signals(self)
|
|
||||||
|
|
||||||
########### Glade Ressources ###########
|
|
||||||
self.rb_included_image_set = self.builder.get_object("rb_included_image_set")
|
|
||||||
self.rb_external_image_set = self.builder.get_object("rb_external_image_set")
|
|
||||||
|
|
||||||
self.lb_image_set = self.builder.get_object("lb_image_set")
|
|
||||||
self.cb_image_set = self.builder.get_object("cb_image_set")
|
|
||||||
|
|
||||||
self.lb_heic_file = self.builder.get_object("lb_heic_file")
|
|
||||||
self.fc_heic_file = self.builder.get_object("fc_heic_file")
|
|
||||||
|
|
||||||
self.img_previews = [
|
|
||||||
self.builder.get_object("img_preview_1"),
|
|
||||||
self.builder.get_object("img_preview_2"),
|
|
||||||
self.builder.get_object("img_preview_3"),
|
|
||||||
self.builder.get_object("img_preview_4"),
|
|
||||||
self.builder.get_object("img_preview_5"),
|
|
||||||
self.builder.get_object("img_preview_6"),
|
|
||||||
self.builder.get_object("img_preview_7"),
|
|
||||||
self.builder.get_object("img_preview_8"),
|
|
||||||
self.builder.get_object("img_preview_9")
|
|
||||||
]
|
|
||||||
|
|
||||||
self.cb_previews = [
|
|
||||||
self.builder.get_object("cb_preview_1"),
|
|
||||||
self.builder.get_object("cb_preview_2"),
|
|
||||||
self.builder.get_object("cb_preview_3"),
|
|
||||||
self.builder.get_object("cb_preview_4"),
|
|
||||||
self.builder.get_object("cb_preview_5"),
|
|
||||||
self.builder.get_object("cb_preview_6"),
|
|
||||||
self.builder.get_object("cb_preview_7"),
|
|
||||||
self.builder.get_object("cb_preview_8"),
|
|
||||||
self.builder.get_object("cb_preview_9")
|
|
||||||
]
|
|
||||||
|
|
||||||
# The GtkStack
|
|
||||||
self.stack_main = self.builder.get_object("stack_main")
|
|
||||||
self.stack_main.add_named(self.builder.get_object("page_config"), "config")
|
|
||||||
self.stack_main.add_named(self.builder.get_object("page_load"), "load")
|
|
||||||
self.stack_main.set_visible_child_name("config")
|
|
||||||
|
|
||||||
|
|
||||||
########### Load predefinitions and settings ###########
|
|
||||||
for set in self.img_sets:
|
|
||||||
self.cb_image_set.append_text(set)
|
|
||||||
|
|
||||||
self.image_source = Source.SELECTED
|
|
||||||
|
|
||||||
# Load preferences
|
|
||||||
self.loadFromSettings()
|
|
||||||
|
|
||||||
|
|
||||||
def showMainWindow(self):
|
|
||||||
""" Opens the main window, starts the Gtk main routine
|
|
||||||
"""
|
|
||||||
window = self.builder.get_object("main_window")
|
|
||||||
window.show_all()
|
|
||||||
|
|
||||||
self.imageSetVisibility(self.image_source)
|
|
||||||
self.rb_external_image_set.set_active(self.image_source == Source.EXTRACT)
|
|
||||||
|
|
||||||
Gtk.main()
|
|
||||||
|
|
||||||
|
|
||||||
def loadFromSettings(self):
|
|
||||||
""" Load preferences from the Cinnamon preference file
|
|
||||||
"""
|
|
||||||
#try:
|
|
||||||
# Load the settings
|
|
||||||
with open(self.pref_path, "r") as pref_file:
|
|
||||||
pref_data = json.load(pref_file)
|
|
||||||
|
|
||||||
|
|
||||||
# Get all images in the "selected" folder
|
|
||||||
choosable_images = os.listdir(IMAGE_SELECTED_DIR)
|
|
||||||
choosable_images.sort()
|
|
||||||
|
|
||||||
|
|
||||||
# Add the founded image names to the ComboBoxes
|
|
||||||
if pref_data["etr_choosen_image_set"]["value"] == "custom":
|
|
||||||
for combobox in self.cb_previews:
|
|
||||||
for option in choosable_images:
|
|
||||||
combobox.append_text(option)
|
|
||||||
else:
|
|
||||||
for i, set in enumerate(self.img_sets):
|
|
||||||
if set == pref_data["etr_choosen_image_set"]["value"]:
|
|
||||||
self.cb_image_set.set_active(i)
|
|
||||||
|
|
||||||
|
|
||||||
for i, val in enumerate(self.pref_vars):
|
|
||||||
# Set the preview image
|
|
||||||
self.changePreviewImage(i, IMAGE_SELECTED_DIR + pref_data[val]['value'])
|
|
||||||
|
|
||||||
# Set the ComboBox selection
|
|
||||||
if pref_data["etr_choosen_image_set"]["value"] == "custom":
|
|
||||||
self.image_source = Source.EXTRACT
|
|
||||||
|
|
||||||
for j, set in enumerate(choosable_images):
|
|
||||||
if set == pref_data[val]["value"]:
|
|
||||||
self.cb_previews[i].set_active(j)
|
|
||||||
else:
|
|
||||||
self.image_source = Source.SET
|
|
||||||
#except:
|
|
||||||
# pass
|
|
||||||
|
|
||||||
|
|
||||||
def writeToSettings(self):
|
|
||||||
""" Save preferences to the Cinnamon preference file
|
|
||||||
"""
|
|
||||||
# Load the settings
|
|
||||||
with open(self.pref_path, "r") as pref_file:
|
|
||||||
pref_data = json.load(pref_file)
|
|
||||||
|
|
||||||
|
|
||||||
# Update the settings
|
|
||||||
if self.image_source == Source.SET:
|
|
||||||
pref_data["etr_choosen_image_set"]["value"] = self.cb_image_set.get_active_text()
|
|
||||||
|
|
||||||
for i, val in enumerate(self.pref_vars):
|
|
||||||
pref_data[val]['value'] = str(i + 1) + ".jpg"
|
|
||||||
else:
|
|
||||||
pref_data["etr_choosen_image_set"]["value"] = "custom"
|
|
||||||
|
|
||||||
for i, val in enumerate(self.pref_vars):
|
|
||||||
pref_data[val]['value'] = self.cb_previews[i].get_active_text()
|
|
||||||
|
|
||||||
|
|
||||||
# Write the settings
|
|
||||||
with open(self.pref_path, "w") as pref_file:
|
|
||||||
json.dump(pref_data, pref_file, separators=(',', ':'), indent=4)
|
|
||||||
|
|
||||||
|
|
||||||
def changePreviewImage(self, imageId: int, imageURI: str):
|
|
||||||
""" Exchanges the image in the preview
|
|
||||||
|
|
||||||
Args:
|
|
||||||
imageId (int): The number of the preview (0-8)
|
|
||||||
imageURI (str): URI to the new image
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
pixbuf = GdkPixbuf.Pixbuf.new_from_file(imageURI)
|
|
||||||
pixbuf = pixbuf.scale_simple(300, 200, GdkPixbuf.InterpType.BILINEAR)
|
|
||||||
|
|
||||||
self.img_previews[imageId].set_from_pixbuf(pixbuf)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def extractHeifImages(self, imageURI: str):
|
|
||||||
""" Extract all images in a heif file
|
|
||||||
|
|
||||||
Args:
|
|
||||||
imageURI (str): URI to the heif file
|
|
||||||
"""
|
|
||||||
imageURI = imageURI.replace("%20", "\ ")
|
|
||||||
|
|
||||||
filename = imageURI[imageURI.rfind("/") + 1:imageURI.rfind(".")]
|
|
||||||
|
|
||||||
self.image_source = Source.EXTRACT
|
|
||||||
|
|
||||||
self.wipeImages(Source.EXTRACT)
|
|
||||||
os.system("heif-convert " + imageURI + " " + IMAGE_EXTRACT_DIR + "/" + filename + ".jpg")
|
|
||||||
|
|
||||||
self.createExtracted()
|
|
||||||
|
|
||||||
|
|
||||||
def wipeImages(self, source: Source):
|
|
||||||
""" Removes all image of a folder
|
|
||||||
|
|
||||||
Args:
|
|
||||||
source (Source): Choose the folder by selecting the Source
|
|
||||||
"""
|
|
||||||
if source == Source.EXTRACT:
|
|
||||||
dir = IMAGE_EXTRACT_DIR + "*"
|
|
||||||
elif source == Source.SELECTED:
|
|
||||||
dir = IMAGE_SELECTED_DIR + "*"
|
|
||||||
|
|
||||||
for file in glob.glob(dir):
|
|
||||||
os.remove(file)
|
|
||||||
|
|
||||||
|
|
||||||
def createExtracted(self):
|
|
||||||
""" Create the extracted images array
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if self.image_source == Source.SELECTED:
|
|
||||||
self.extracted = os.listdir(IMAGE_SELECTED_DIR)
|
|
||||||
elif self.image_source == Source.EXTRACT:
|
|
||||||
self.extracted = os.listdir(IMAGE_EXTRACT_DIR)
|
|
||||||
|
|
||||||
self.extracted.sort()
|
|
||||||
|
|
||||||
for combobox in self.cb_previews:
|
|
||||||
for option in self.extracted:
|
|
||||||
combobox.append_text(option)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.stack_main.set_visible_child_name("config")
|
|
||||||
|
|
||||||
|
|
||||||
def copyToSelected(self, source: Source):
|
|
||||||
""" Copies the extracted images to "res/"
|
|
||||||
"""
|
|
||||||
# Clean the "selected folder up"
|
|
||||||
self.wipeImages(Source.SELECTED)
|
|
||||||
|
|
||||||
# Estimate the source folder
|
|
||||||
if source == Source.EXTRACT:
|
|
||||||
source_folder = IMAGE_EXTRACT_DIR
|
|
||||||
else:
|
|
||||||
source_folder = IMAGE_SETS_DIR + self.cb_image_set.get_active_text() + "/"
|
|
||||||
|
|
||||||
# Copy it to "selected/"
|
|
||||||
for image in os.listdir(source_folder):
|
|
||||||
shutil.copy(source_folder + image, IMAGE_SELECTED_DIR + image)
|
|
||||||
|
|
||||||
|
|
||||||
def imageSetVisibility(self, source: Source):
|
|
||||||
""" Toggle the visibility of the option in the "Image set" box
|
|
||||||
|
|
||||||
Args:
|
|
||||||
source (Source): Toggle by type of Source
|
|
||||||
"""
|
|
||||||
self.image_source = source
|
|
||||||
|
|
||||||
self.lb_image_set.set_visible(source == Source.SET)
|
|
||||||
self.cb_image_set.set_visible(source == Source.SET)
|
|
||||||
|
|
||||||
self.lb_heic_file.set_visible(source != Source.SET)
|
|
||||||
self.fc_heic_file.set_visible(source != Source.SET)
|
|
||||||
|
|
||||||
for i in range(0, 9):
|
|
||||||
self.cb_previews[i].set_visible(source != Source.SET)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
########## UI Signals ##########
|
|
||||||
|
|
||||||
def onImageSetSelected(self, cb):
|
|
||||||
""" UI signal if the image set combo box value changed
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cb (GtkComboBox): The active ComboBox
|
|
||||||
"""
|
|
||||||
if self.image_source != Source.SELECTED:
|
|
||||||
set_name = cb.get_active_text()
|
|
||||||
|
|
||||||
for i, _ in enumerate(self.img_previews):
|
|
||||||
self.changePreviewImage(i, IMAGE_SETS_DIR + set_name + "/" + str(i + 1) + ".jpg")
|
|
||||||
|
|
||||||
|
|
||||||
def onRadioImageSet(self, rb):
|
|
||||||
""" UI signal if the radio buttons are toggled
|
|
||||||
|
|
||||||
Args:
|
|
||||||
rb (GtkRadioButton): The toggled RadioButton
|
|
||||||
"""
|
|
||||||
if rb.get_active():
|
|
||||||
self.imageSetVisibility(Source.SET)
|
|
||||||
else:
|
|
||||||
self.imageSetVisibility(Source.EXTRACT)
|
|
||||||
|
|
||||||
|
|
||||||
def onHeifSelected(self, fc):
|
|
||||||
""" UI signal if the filechooser has a file selected
|
|
||||||
|
|
||||||
Args:
|
|
||||||
fc (filechooser): The selected filechooser
|
|
||||||
"""
|
|
||||||
# Get the URI to the file
|
|
||||||
uri = fc.get_file().get_uri()
|
|
||||||
uri = uri[7:]
|
|
||||||
|
|
||||||
self.stack_main.set_visible_child_name("load")
|
|
||||||
|
|
||||||
thread = threading.Thread(target=self.extractHeifImages, args=(uri, ))
|
|
||||||
thread.daemon = True
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
def onPreviewComboboxSelected(self, cb):
|
|
||||||
""" UI signal if one of the preview combobox is selected
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cb (ComboBox): The selected combobox
|
|
||||||
"""
|
|
||||||
number = Gtk.Buildable.get_name(cb)
|
|
||||||
number = number[number.rfind("_") + 1:]
|
|
||||||
|
|
||||||
if self.image_source == Source.EXTRACT:
|
|
||||||
self.changePreviewImage(int(number) - 1, IMAGE_EXTRACT_DIR + cb.get_active_text())
|
|
||||||
|
|
||||||
|
|
||||||
def onApply(self, *args):
|
|
||||||
""" UI signal if the user presses the "Apply" button
|
|
||||||
"""
|
|
||||||
self.writeToSettings()
|
|
||||||
self.copyToSelected(self.image_source)
|
|
||||||
|
|
||||||
Gtk.main_quit()
|
|
||||||
|
|
||||||
|
|
||||||
def onDestroy(self, *args):
|
|
||||||
""" UI signal if the window is closed by the user
|
|
||||||
"""
|
|
||||||
Gtk.main_quit()
|
|
||||||
|
After Width: | Height: | Size: 233 KiB |
|
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 488 KiB After Width: | Height: | Size: 246 KiB |
|
Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 230 KiB |
|
Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 236 KiB |
|
Before Width: | Height: | Size: 470 KiB After Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 229 KiB |
|
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 216 KiB |
|
Before Width: | Height: | Size: 420 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 485 KiB After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 371 KiB |
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 491 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 513 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 527 KiB |
|
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 526 KiB |
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 495 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 455 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 450 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 5 B |
@@ -0,0 +1 @@
|
|||||||
|
0.jpg
|
||||||
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 5 B |
|
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 352 KiB |
|
After Width: | Height: | Size: 856 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 5 B |
@@ -0,0 +1 @@
|
|||||||
|
0.jpg
|
||||||
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 5 B |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 634 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 759 KiB |
|
After Width: | Height: | Size: 528 KiB |
|
After Width: | Height: | Size: 335 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 449 KiB After Width: | Height: | Size: 358 KiB |
|
Before Width: | Height: | Size: 558 KiB After Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 681 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 654 KiB After Width: | Height: | Size: 388 KiB |
|
Before Width: | Height: | Size: 631 KiB After Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 548 KiB After Width: | Height: | Size: 366 KiB |
|
Before Width: | Height: | Size: 540 KiB After Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 465 KiB After Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 392 KiB After Width: | Height: | Size: 358 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 134 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 200 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 135 KiB |
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 5 B |
@@ -0,0 +1 @@
|
|||||||
|
0.jpg
|
||||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 5 B |
|
After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 118 KiB |
110
cinnamon-dynamic-wallpaper@TobiZog/5.4/loop.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
from scripts.cinnamon_pref_handler import *
|
||||||
|
from scripts.suntimes import *
|
||||||
|
from datetime import datetime, time
|
||||||
|
from enums.PeriodSourceEnum import *
|
||||||
|
from scripts.location import *
|
||||||
|
from gi.repository import Gio
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
class Loop():
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.prefs = Cinnamon_Pref_Handler()
|
||||||
|
|
||||||
|
self.suntimes = Suntimes()
|
||||||
|
self.location = Location()
|
||||||
|
self.background_settings = Gio.Settings.new("org.cinnamon.desktop.background")
|
||||||
|
|
||||||
|
# Position should estimate by network
|
||||||
|
if self.prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
|
||||||
|
current_location = self.location.get_location()
|
||||||
|
|
||||||
|
self.suntimes.calc_suntimes(float(current_location["latitude"]), float(current_location["longitude"]))
|
||||||
|
self.start_times = self.suntimes.day_periods
|
||||||
|
|
||||||
|
# Position is given by user
|
||||||
|
elif self.prefs.period_source == PeriodSourceEnum.CUSTOMLOCATION:
|
||||||
|
self.suntimes.calc_suntimes(float(self.prefs.latitude_custom), float(self.prefs.longitude_custom))
|
||||||
|
self.start_times = self.suntimes.day_periods
|
||||||
|
|
||||||
|
# No position, concrete times
|
||||||
|
else:
|
||||||
|
def string_to_time_converter(raw_str: str) -> time:
|
||||||
|
hour = raw_str[0:raw_str.find(":")]
|
||||||
|
minute = raw_str[raw_str.find(":") + 1:]
|
||||||
|
|
||||||
|
return time(hour=int(hour), minute=int(minute))
|
||||||
|
|
||||||
|
self.start_times = [
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[0]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[1]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[2]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[3]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[4]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[5]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[6]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[7]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[8]),
|
||||||
|
string_to_time_converter(self.prefs.period_custom_start_time[9])
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def exchange_image(self):
|
||||||
|
""" Replace the desktop image
|
||||||
|
"""
|
||||||
|
# Get the time of day
|
||||||
|
time_now = time(datetime.now().hour, datetime.now().minute)
|
||||||
|
|
||||||
|
# Assign the last image as fallback
|
||||||
|
self.current_image_uri = self.prefs.source_folder + self.prefs.period_images[9]
|
||||||
|
|
||||||
|
for i in range(0, 9):
|
||||||
|
# Replace the image URI, if it's not the last time period of the day
|
||||||
|
if self.start_times[i] <= time_now and time_now < self.start_times[i + 1]:
|
||||||
|
self.current_image_uri = self.prefs.source_folder + self.prefs.period_images[i]
|
||||||
|
break
|
||||||
|
|
||||||
|
# Set the background
|
||||||
|
self.background_settings['picture-uri'] = "file://" + self.current_image_uri
|
||||||
|
|
||||||
|
# Set background stretching
|
||||||
|
self.background_settings['picture-options'] = self.prefs.picture_aspect
|
||||||
|
|
||||||
|
self.set_background_gradient()
|
||||||
|
|
||||||
|
|
||||||
|
def set_background_gradient(self):
|
||||||
|
""" Setting a gradient background to hide images, which are not high enough
|
||||||
|
"""
|
||||||
|
# Load the image
|
||||||
|
try:
|
||||||
|
im = Image.open(self.current_image_uri)
|
||||||
|
pix = im.load()
|
||||||
|
|
||||||
|
# Width and height of the current setted image
|
||||||
|
width, height = im.size
|
||||||
|
|
||||||
|
# Color of the top and bottom pixel in the middle of the image
|
||||||
|
top_color = pix[width / 2,0]
|
||||||
|
bottom_color = pix[width / 2, height - 1]
|
||||||
|
|
||||||
|
# Create the gradient
|
||||||
|
self.background_settings['color-shading-type'] = "vertical"
|
||||||
|
|
||||||
|
if self.prefs.dynamic_background_color:
|
||||||
|
self.background_settings['primary-color'] = f"#{top_color[0]:x}{top_color[1]:x}{top_color[2]:x}"
|
||||||
|
self.background_settings['secondary-color'] = f"#{bottom_color[0]:x}{bottom_color[1]:x}{bottom_color[2]:x}"
|
||||||
|
else:
|
||||||
|
self.background_settings['primary-color'] = "#000000"
|
||||||
|
self.background_settings['secondary-color'] = "#000000"
|
||||||
|
except:
|
||||||
|
self.background_settings['primary-color'] = "#000000"
|
||||||
|
self.background_settings['secondary-color'] = "#000000"
|
||||||
|
|
||||||
|
|
||||||
|
# Needed for JavaScript
|
||||||
|
if __name__ == "__main__":
|
||||||
|
l = Loop()
|
||||||
|
l.exchange_image()
|
||||||
2865
cinnamon-dynamic-wallpaper@TobiZog/5.4/preferences.glade
Normal file
642
cinnamon-dynamic-wallpaper@TobiZog/5.4/preferences.py
Executable file
@@ -0,0 +1,642 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Imports #
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
# Packages
|
||||||
|
import gi, os, subprocess, time
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
# Local scripts
|
||||||
|
from scripts import cinnamon_pref_handler, dialogs, display, images, location, suntimes, time_bar_chart, ui
|
||||||
|
from loop import *
|
||||||
|
from enums.ImageSourceEnum import ImageSourceEnum
|
||||||
|
from enums.PeriodSourceEnum import PeriodSourceEnum
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gtk, GdkPixbuf
|
||||||
|
|
||||||
|
|
||||||
|
# Global definitions
|
||||||
|
PREFERENCES_URI = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
GLADE_URI = PREFERENCES_URI + "/preferences.glade"
|
||||||
|
|
||||||
|
|
||||||
|
class Preferences:
|
||||||
|
""" Preference window class
|
||||||
|
"""
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Lifecycle #
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# Objects from external scripts
|
||||||
|
self.prefs = cinnamon_pref_handler.Cinnamon_Pref_Handler()
|
||||||
|
self.dialogs = dialogs.Dialogs()
|
||||||
|
self.display = display.Display()
|
||||||
|
self.images = images.Images()
|
||||||
|
self.location = location.Location()
|
||||||
|
self.suntimes = suntimes.Suntimes()
|
||||||
|
self.time_bar_chart = time_bar_chart.Time_Bar_Chart()
|
||||||
|
|
||||||
|
# Glade
|
||||||
|
self.builder = Gtk.Builder()
|
||||||
|
self.builder.add_from_file(GLADE_URI)
|
||||||
|
self.builder.connect_signals(self)
|
||||||
|
|
||||||
|
self.ui = ui.UI(self.builder)
|
||||||
|
|
||||||
|
|
||||||
|
# Local Config
|
||||||
|
self.smaller_ui_height = 1000
|
||||||
|
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
""" Display the window to the screen
|
||||||
|
"""
|
||||||
|
window = self.builder.get_object("window_main")
|
||||||
|
window.show_all()
|
||||||
|
|
||||||
|
# Load from preferences
|
||||||
|
if self.prefs.image_source == ImageSourceEnum.IMAGESET:
|
||||||
|
self.ui.tb_image_set.set_active(True)
|
||||||
|
elif self.prefs.image_source == ImageSourceEnum.HEICFILE:
|
||||||
|
self.ui.tb_heic_file.set_active(True)
|
||||||
|
elif self.prefs.image_source == ImageSourceEnum.SOURCEFOLDER:
|
||||||
|
self.ui.tb_source_folder.set_active(True)
|
||||||
|
|
||||||
|
|
||||||
|
# Remove icons in the ToggleButtons if the screen height resolution < 1000 px
|
||||||
|
if self.display.get_screen_height() < self.smaller_ui_height:
|
||||||
|
self.ui.img_tb_image_set.clear()
|
||||||
|
self.ui.img_tb_heic_file.clear()
|
||||||
|
self.ui.img_tb_source_folder.clear()
|
||||||
|
self.ui.img_tb_network_location.clear()
|
||||||
|
self.ui.img_tb_custom_location.clear()
|
||||||
|
self.ui.img_tb_time_periods.clear()
|
||||||
|
|
||||||
|
|
||||||
|
picture_aspects = ["centered", "scaled", "stretched", "zoom", "spanned"]
|
||||||
|
self.ui.add_items_to_combo_box(self.ui.cb_picture_aspect, picture_aspects)
|
||||||
|
self.ui.set_active_combobox_item(self.ui.cb_picture_aspect, self.prefs.picture_aspect)
|
||||||
|
|
||||||
|
self.ui.sw_dynamic_background_color.set_active(self.prefs.dynamic_background_color)
|
||||||
|
|
||||||
|
|
||||||
|
if self.prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
|
||||||
|
self.ui.tb_network_location.set_active(True)
|
||||||
|
elif self.prefs.period_source == PeriodSourceEnum.CUSTOMLOCATION:
|
||||||
|
self.ui.tb_custom_location.set_active(True)
|
||||||
|
elif self.prefs.period_source == PeriodSourceEnum.CUSTOMTIMEPERIODS:
|
||||||
|
self.ui.tb_time_periods.set_active(True)
|
||||||
|
|
||||||
|
|
||||||
|
# Time diagram
|
||||||
|
try:
|
||||||
|
self.refresh_chart()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Show the main window
|
||||||
|
Gtk.main()
|
||||||
|
|
||||||
|
|
||||||
|
def on_destroy(self, *args):
|
||||||
|
""" Lifecycle handler when window will be destroyed
|
||||||
|
"""
|
||||||
|
Gtk.main_quit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Local methods #
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
def refresh_chart(self):
|
||||||
|
""" Recomputes both time bar charts and load them to the UI
|
||||||
|
"""
|
||||||
|
# Stores the start times of the periods in minutes since midnight
|
||||||
|
time_periods_min = []
|
||||||
|
|
||||||
|
if self.prefs.period_source == PeriodSourceEnum.CUSTOMTIMEPERIODS:
|
||||||
|
for i in range(0, 10):
|
||||||
|
time_str = self.prefs.period_custom_start_time[i]
|
||||||
|
|
||||||
|
time_periods_min.append(int(time_str[0:2]) * 60 + int(time_str[3:5]))
|
||||||
|
else:
|
||||||
|
if self.prefs.period_source == PeriodSourceEnum.NETWORKLOCATION:
|
||||||
|
self.suntimes.calc_suntimes(float(self.prefs.latitude_auto), float(self.prefs.longitude_auto))
|
||||||
|
else:
|
||||||
|
self.suntimes.calc_suntimes(float(self.ui.etr_latitude.get_text()), float(self.ui.etr_longitude.get_text()))
|
||||||
|
|
||||||
|
|
||||||
|
# Get all time periods. Store the minutes to the list and print the values to the text views
|
||||||
|
for i in range(0, 10):
|
||||||
|
time_range_now = self.suntimes.day_periods[i]
|
||||||
|
|
||||||
|
if i != 9:
|
||||||
|
time_range_next = self.suntimes.day_periods[i + 1]
|
||||||
|
else:
|
||||||
|
time_range_next = time(hour=23, minute=59)
|
||||||
|
|
||||||
|
self.ui.etr_periods[i].set_text(
|
||||||
|
str(time_range_now.hour).rjust(2, '0') + ":" + str(time_range_now.minute).rjust(2, '0') + \
|
||||||
|
" - " + str(time_range_next.hour).rjust(2, '0') + ":" + str(time_range_next.minute).rjust(2, '0'))
|
||||||
|
|
||||||
|
time_periods_min.append(time_range_now.hour * 60 + time_range_now.minute)
|
||||||
|
|
||||||
|
# Create time bar
|
||||||
|
# Reduce size for small displays
|
||||||
|
if self.display.get_screen_height() < self.smaller_ui_height:
|
||||||
|
bar_width = 1150
|
||||||
|
bar_height = 110
|
||||||
|
else:
|
||||||
|
bar_width = 1300
|
||||||
|
bar_height = 150
|
||||||
|
|
||||||
|
self.time_bar_chart.create_bar_chart_with_polylines(PREFERENCES_URI, bar_width, bar_height, time_periods_min)
|
||||||
|
self.time_bar_chart.create_bar_chart(PREFERENCES_URI, bar_width, bar_height, time_periods_min)
|
||||||
|
|
||||||
|
# Load to the views
|
||||||
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(PREFERENCES_URI + "/time_bar_polylines.svg")
|
||||||
|
self.ui.img_bar_images.set_from_pixbuf(pixbuf)
|
||||||
|
|
||||||
|
pixbuf2 = GdkPixbuf.Pixbuf.new_from_file(PREFERENCES_URI + "/time_bar.svg")
|
||||||
|
self.ui.img_bar_times.set_from_pixbuf(pixbuf2)
|
||||||
|
|
||||||
|
|
||||||
|
def load_image_options_to_combo_boxes(self, options: list):
|
||||||
|
""" Add a list of Strings to all image option comboboxes
|
||||||
|
|
||||||
|
Args:
|
||||||
|
options (list): All possible options
|
||||||
|
"""
|
||||||
|
options.insert(0, "")
|
||||||
|
|
||||||
|
for combobox in self.ui.cb_periods:
|
||||||
|
self.ui.add_items_to_combo_box(combobox, options)
|
||||||
|
|
||||||
|
|
||||||
|
def load_image_to_preview(self, image_preview: Gtk.Image, image_src: str):
|
||||||
|
""" Scales the image to a lower resoultion and put them into the time bar chart
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_preview (Gtk.Image): Gtk Image where it will be displayed
|
||||||
|
image_src (str): Absolute path to the image
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
pixbuf = GdkPixbuf.Pixbuf.new_from_file(image_src)
|
||||||
|
|
||||||
|
screen_height = self.display.get_screen_height()
|
||||||
|
|
||||||
|
# Scaling the images smaller for screens
|
||||||
|
if screen_height < self.smaller_ui_height:
|
||||||
|
pixbuf = pixbuf.scale_simple(221, 128, GdkPixbuf.InterpType.BILINEAR)
|
||||||
|
else:
|
||||||
|
pixbuf = pixbuf.scale_simple(260, 150, GdkPixbuf.InterpType.BILINEAR)
|
||||||
|
|
||||||
|
image_preview.set_from_pixbuf(pixbuf)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
# Callbacks #
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
## Image Configuration
|
||||||
|
|
||||||
|
# +-----------+-----------+---------------+
|
||||||
|
# | Image Set | HEIC file | Source Folder |
|
||||||
|
# +-----------+-----------+---------------+
|
||||||
|
|
||||||
|
def on_toggle_button_image_set_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
""" Clicked on ToggleButton "Image Set"
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.ToggleButton): Clicked ToggleButton
|
||||||
|
"""
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.image_source = ImageSourceEnum.IMAGESET
|
||||||
|
self.ui.tb_heic_file.set_active(False)
|
||||||
|
self.ui.tb_source_folder.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_image_set.set_visible(True)
|
||||||
|
self.ui.lbr_heic_file.set_visible(False)
|
||||||
|
self.ui.lbr_source_folder.set_visible(False)
|
||||||
|
|
||||||
|
image_set_choices = [
|
||||||
|
"aurora", "beach",
|
||||||
|
"bitday", "cliffs",
|
||||||
|
"earth", "gradient",
|
||||||
|
"lakeside", "mountains",
|
||||||
|
"sahara"
|
||||||
|
]
|
||||||
|
self.ui.add_items_to_combo_box(self.ui.cb_image_set, image_set_choices)
|
||||||
|
|
||||||
|
self.ui.set_active_combobox_item(self.ui.cb_image_set, self.prefs.selected_image_set)
|
||||||
|
|
||||||
|
for i, combobox in enumerate(self.ui.cb_periods):
|
||||||
|
selected_image_name = self.prefs.period_images[i]
|
||||||
|
self.ui.set_active_combobox_item(combobox, selected_image_name)
|
||||||
|
|
||||||
|
# Make the comboboxes invisible
|
||||||
|
for combobox in self.ui.cb_periods:
|
||||||
|
combobox.set_visible(False)
|
||||||
|
|
||||||
|
|
||||||
|
def on_toggle_button_heic_file_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
""" Clicked on ToggleButton "Heic file"
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.ToggleButton): Clicked ToggleButton
|
||||||
|
"""
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.image_source = ImageSourceEnum.HEICFILE
|
||||||
|
self.ui.tb_image_set.set_active(False)
|
||||||
|
self.ui.tb_source_folder.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_image_set.set_visible(False)
|
||||||
|
self.ui.lbr_heic_file.set_visible(True)
|
||||||
|
self.ui.lbr_source_folder.set_visible(False)
|
||||||
|
|
||||||
|
# Make the comboboxes visible
|
||||||
|
for combobox in self.ui.cb_periods:
|
||||||
|
combobox.set_visible(True)
|
||||||
|
|
||||||
|
# Load images from source folder
|
||||||
|
files = self.images.get_images_from_folder(self.prefs.source_folder)
|
||||||
|
|
||||||
|
if len(files) != 0:
|
||||||
|
self.load_image_options_to_combo_boxes(files)
|
||||||
|
|
||||||
|
# Load the values for the images from the preferences
|
||||||
|
for i in range(0, 10):
|
||||||
|
self.ui.set_active_combobox_item(self.ui.cb_periods[i], self.prefs.period_images[i])
|
||||||
|
else:
|
||||||
|
print("No image files!")
|
||||||
|
|
||||||
|
|
||||||
|
def on_toggle_button_source_folder_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
""" Clicked on ToggleButton "Source Folder"
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.ToggleButton): Clicked ToggleButton
|
||||||
|
"""
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.image_source = ImageSourceEnum.SOURCEFOLDER
|
||||||
|
self.ui.tb_image_set.set_active(False)
|
||||||
|
self.ui.tb_heic_file.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_image_set.set_visible(False)
|
||||||
|
self.ui.lbr_heic_file.set_visible(False)
|
||||||
|
self.ui.lbr_source_folder.set_visible(True)
|
||||||
|
|
||||||
|
# Make the comboboxes visible
|
||||||
|
for combobox in self.ui.cb_periods:
|
||||||
|
combobox.set_visible(True)
|
||||||
|
|
||||||
|
# Load the source folder to the view
|
||||||
|
# This will update the comboboxes in the preview to contain the right items
|
||||||
|
self.ui.lbl_source_folder.set_label(self.prefs.source_folder)
|
||||||
|
|
||||||
|
# Load files from saved source folder
|
||||||
|
files = self.images.get_images_from_folder(self.prefs.source_folder)
|
||||||
|
|
||||||
|
if len(files) != 0:
|
||||||
|
self.load_image_options_to_combo_boxes(files)
|
||||||
|
|
||||||
|
# Load the values for the images from the preferences
|
||||||
|
for i in range(0, 10):
|
||||||
|
self.ui.set_active_combobox_item(self.ui.cb_periods[i], self.prefs.period_images[i])
|
||||||
|
else:
|
||||||
|
print("No image files!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# +------------------------------------+
|
||||||
|
# | Select an image set | aurora ▼ |
|
||||||
|
# +------------------------------------+
|
||||||
|
|
||||||
|
def on_cb_image_set_changed(self, combobox: Gtk.ComboBox):
|
||||||
|
""" User select on of the included image sets
|
||||||
|
|
||||||
|
Args:
|
||||||
|
combobox (Gtk.ComboBox): The used ComboBox
|
||||||
|
"""
|
||||||
|
tree_iter = combobox.get_active_iter()
|
||||||
|
|
||||||
|
if tree_iter is not None and self.prefs.image_source == ImageSourceEnum.IMAGESET:
|
||||||
|
# Get the selected value
|
||||||
|
model = combobox.get_model()
|
||||||
|
selected_image_set = model[tree_iter][0]
|
||||||
|
|
||||||
|
# Store to the preferences
|
||||||
|
self.prefs.selected_image_set = selected_image_set
|
||||||
|
self.prefs.source_folder = os.path.abspath(os.path.join(PREFERENCES_URI, os.pardir)) + \
|
||||||
|
"/5.4/images/included_image_sets/" + selected_image_set + "/"
|
||||||
|
|
||||||
|
# Load all possible options to the comboboxes
|
||||||
|
image_names = self.images.get_images_from_folder(self.prefs.source_folder)
|
||||||
|
self.load_image_options_to_combo_boxes(image_names)
|
||||||
|
|
||||||
|
# Image sets have the same names for the images:
|
||||||
|
# 9.jpg = Period 0
|
||||||
|
# 1.jpg = Period 1
|
||||||
|
# 2.jpg = Period 2
|
||||||
|
# and so on....
|
||||||
|
for i in range(0, 10):
|
||||||
|
self.ui.cb_periods[i].set_active(i + 1)
|
||||||
|
|
||||||
|
|
||||||
|
# +----------------------------------------------+
|
||||||
|
# | Select a heic file to import | (None) 📄 |
|
||||||
|
# +----------------------------------------------+
|
||||||
|
|
||||||
|
def on_fc_heic_file_file_set(self, fc_button: Gtk.FileChooser):
|
||||||
|
""" User has a heic file selected with the FileChooserDialog
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fc_button (Gtk.FileChooser): Parameter about the selected file
|
||||||
|
"""
|
||||||
|
# The the absolute path to the heic file
|
||||||
|
file_path: str = fc_button.get_filename()
|
||||||
|
|
||||||
|
# Extract the heic file
|
||||||
|
result = self.images.extract_heic_file(file_path)
|
||||||
|
|
||||||
|
# Update the preferences
|
||||||
|
self.prefs.selected_image_set = ""
|
||||||
|
self.prefs.source_folder = PREFERENCES_URI + "/images/extracted_images/"
|
||||||
|
|
||||||
|
# Load images only if the extraction was successfully
|
||||||
|
if result:
|
||||||
|
# Collect all extracted images and push them to the comboboxes
|
||||||
|
image_names = self.images.get_images_from_folder(self.prefs.source_folder)
|
||||||
|
self.load_image_options_to_combo_boxes(image_names)
|
||||||
|
else:
|
||||||
|
self.dialogs.message_dialog("Error during extraction")
|
||||||
|
|
||||||
|
|
||||||
|
# +------------------------------------------------------------+
|
||||||
|
# | Select a source folder | 📂 Open file selection dialog |
|
||||||
|
# | /home/developer/Downloads/
|
||||||
|
# +------------------------------------------------------------+
|
||||||
|
|
||||||
|
def on_btn_source_folder_clicked(self, button: Gtk.Button):
|
||||||
|
""" Button to choose an image source folder was clicked
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.Button): The clicked button
|
||||||
|
"""
|
||||||
|
folder = self.dialogs.source_folder_dialog()
|
||||||
|
files = self.images.get_images_from_folder(folder)
|
||||||
|
|
||||||
|
# Update the preferences
|
||||||
|
self.prefs.selected_image_set = ""
|
||||||
|
self.prefs.source_folder = folder + "/"
|
||||||
|
|
||||||
|
# Update the label
|
||||||
|
self.ui.lbl_source_folder.set_label(folder)
|
||||||
|
|
||||||
|
# Update the image comboboxes
|
||||||
|
self.load_image_options_to_combo_boxes(files)
|
||||||
|
|
||||||
|
# Load the values for the images from the preferences
|
||||||
|
for i in range(0, 10):
|
||||||
|
self.ui.cb_periods[i].set_active(0)
|
||||||
|
|
||||||
|
if len(files) == 1:
|
||||||
|
self.dialogs.message_dialog("No image files found!")
|
||||||
|
|
||||||
|
|
||||||
|
def on_cb_period_preview_changed(self, combobox: Gtk.ComboBox):
|
||||||
|
""" User select an image from the ComboBox for the time period
|
||||||
|
|
||||||
|
Args:
|
||||||
|
combobox (Gtk.ComboBox): The used ComboBox
|
||||||
|
"""
|
||||||
|
tree_iter = combobox.get_active_iter()
|
||||||
|
|
||||||
|
combobox_name = Gtk.Buildable.get_name(combobox)
|
||||||
|
period_index = int(combobox_name[10:11])
|
||||||
|
|
||||||
|
if tree_iter is not None:
|
||||||
|
# Get the selected value
|
||||||
|
model = combobox.get_model()
|
||||||
|
image_file_name = model[tree_iter][0]
|
||||||
|
|
||||||
|
# Store selection to preferences
|
||||||
|
self.prefs.period_images[period_index] = image_file_name
|
||||||
|
|
||||||
|
# Build up image path
|
||||||
|
image_path = self.prefs.source_folder + image_file_name
|
||||||
|
|
||||||
|
self.load_image_to_preview(self.ui.img_periods[period_index], image_path)
|
||||||
|
|
||||||
|
|
||||||
|
## Location & Times
|
||||||
|
|
||||||
|
def on_toggle_button_network_location_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
""" User clicks on the ToggleButton for the network location
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.ToggleButton): Clicked ToggleButton
|
||||||
|
"""
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.period_source = PeriodSourceEnum.NETWORKLOCATION
|
||||||
|
self.ui.tb_custom_location.set_active(False)
|
||||||
|
self.ui.tb_time_periods.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_network_location.set_visible(True)
|
||||||
|
self.ui.lbr_current_location.set_visible(True)
|
||||||
|
self.ui.lbr_custom_location_longitude.set_visible(False)
|
||||||
|
self.ui.lbr_custom_location_latitude.set_visible(False)
|
||||||
|
self.ui.lbr_time_periods.set_visible(False)
|
||||||
|
|
||||||
|
self.ui.spb_network_location_refresh_time.set_value(self.prefs.location_refresh_intervals)
|
||||||
|
|
||||||
|
|
||||||
|
# Display the location in the UI
|
||||||
|
current_location = self.location.get_location()
|
||||||
|
self.ui.lb_current_location.set_text("Latitude: " + current_location["latitude"] + \
|
||||||
|
", Longitude: " + current_location["longitude"])
|
||||||
|
|
||||||
|
# Store the location to the preferences
|
||||||
|
self.prefs.latitude_auto = float(current_location["latitude"])
|
||||||
|
self.prefs.longitude_auto = float(current_location["longitude"])
|
||||||
|
|
||||||
|
self.refresh_chart()
|
||||||
|
|
||||||
|
|
||||||
|
def on_toggle_button_custom_location_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.period_source = PeriodSourceEnum.CUSTOMLOCATION
|
||||||
|
self.ui.tb_network_location.set_active(False)
|
||||||
|
self.ui.tb_time_periods.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_network_location.set_visible(False)
|
||||||
|
self.ui.lbr_current_location.set_visible(False)
|
||||||
|
self.ui.lbr_custom_location_longitude.set_visible(True)
|
||||||
|
self.ui.lbr_custom_location_latitude.set_visible(True)
|
||||||
|
self.ui.lbr_time_periods.set_visible(False)
|
||||||
|
|
||||||
|
self.ui.etr_latitude.set_text(str(self.prefs.latitude_custom))
|
||||||
|
self.ui.etr_longitude.set_text(str(self.prefs.longitude_custom))
|
||||||
|
|
||||||
|
|
||||||
|
def on_toggle_button_time_periods_clicked(self, button: Gtk.ToggleButton):
|
||||||
|
if button.get_active():
|
||||||
|
self.prefs.period_source = PeriodSourceEnum.CUSTOMTIMEPERIODS
|
||||||
|
self.ui.tb_network_location.set_active(False)
|
||||||
|
self.ui.tb_custom_location.set_active(False)
|
||||||
|
|
||||||
|
self.ui.lbr_network_location.set_visible(False)
|
||||||
|
self.ui.lbr_current_location.set_visible(False)
|
||||||
|
self.ui.lbr_custom_location_longitude.set_visible(False)
|
||||||
|
self.ui.lbr_custom_location_latitude.set_visible(False)
|
||||||
|
self.ui.lbr_time_periods.set_visible(True)
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(0, 9):
|
||||||
|
pref_value = self.prefs.period_custom_start_time[i + 1]
|
||||||
|
time_parts = [int(pref_value[0:pref_value.find(":")]), int(pref_value[pref_value.find(":") + 1:])]
|
||||||
|
|
||||||
|
self.ui.spb_periods_hour[i].set_value(time_parts[0])
|
||||||
|
self.ui.spb_periods_minute[i].set_value(time_parts[1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_spb_period_value_changed(self, spin_button: Gtk.SpinButton):
|
||||||
|
""" Callback if one of the time spinners (minute or hour) will be clicked
|
||||||
|
|
||||||
|
(1) (2) (3)
|
||||||
|
Previous period Current period Next period
|
||||||
|
12:34 - 14:40 14:41 - 16:20 16:21 - 17:30
|
||||||
|
^
|
||||||
|
Variable to change
|
||||||
|
|
||||||
|
Args:
|
||||||
|
spin_button (Gtk.SpinButton): SpinButton which was changed
|
||||||
|
"""
|
||||||
|
spin_button_name = Gtk.Buildable.get_name(spin_button)
|
||||||
|
index = int(spin_button_name[11:12]) - 1
|
||||||
|
|
||||||
|
# Determe time string and store to prefs
|
||||||
|
time_current_start = datetime(2024,1,1, int(self.ui.spb_periods_hour[index].get_value()), int(self.ui.spb_periods_minute[index].get_value()))
|
||||||
|
time_current_start_str = str(time_current_start.hour).rjust(2, '0') + ":" + str(time_current_start.minute).rjust(2, '0')
|
||||||
|
|
||||||
|
self.prefs.period_custom_start_time[index + 1] = time_current_start_str
|
||||||
|
|
||||||
|
|
||||||
|
time_previous_end = time_current_start - timedelta(minutes=1)
|
||||||
|
self.ui.lb_period_end[index].set_text(str(time_previous_end.hour).rjust(2, '0') + ":" + str(time_previous_end.minute).rjust(2, '0'))
|
||||||
|
|
||||||
|
|
||||||
|
self.refresh_chart()
|
||||||
|
|
||||||
|
|
||||||
|
def on_spb_network_location_refresh_time_changed(self, spin_button: Gtk.SpinButton):
|
||||||
|
""" User changed the refresh time of network location estimation
|
||||||
|
|
||||||
|
Args:
|
||||||
|
spin_button (Gtk.SpinButton): The used SpinButton
|
||||||
|
"""
|
||||||
|
self.prefs.location_refresh_intervals = spin_button.get_value()
|
||||||
|
|
||||||
|
|
||||||
|
def on_etr_longitude_changed(self, entry: Gtk.Entry):
|
||||||
|
""" User changes the value of the longitude Entry
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry (Gtk.Entry): The manipulated Entry object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.prefs.longitude_custom = float(entry.get_text())
|
||||||
|
self.refresh_chart()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def on_etr_latitude_changed(self, entry: Gtk.Entry):
|
||||||
|
""" User changes the value of the latitude Entry
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry (Gtk.Entry): The manipulated Entry object
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.prefs.latitude_custom = float(entry.get_text())
|
||||||
|
self.refresh_chart()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Behaviour
|
||||||
|
|
||||||
|
def on_cb_picture_aspect_changed(self, combobox: Gtk.ComboBox):
|
||||||
|
tree_iter = combobox.get_active_iter()
|
||||||
|
|
||||||
|
if tree_iter is not None:
|
||||||
|
model = combobox.get_model()
|
||||||
|
self.prefs.picture_aspect = model[tree_iter][0]
|
||||||
|
|
||||||
|
def on_sw_dynamic_background_color_state_set(self, switch: Gtk.Switch, state):
|
||||||
|
self.prefs.dynamic_background_color = state
|
||||||
|
|
||||||
|
|
||||||
|
# About
|
||||||
|
|
||||||
|
def on_cinnamon_spices_website_button_clicked(self, button: Gtk.Button):
|
||||||
|
""" Callback for the button to navigate to the Cinnamon Spices web page of this project
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.Button): Button which was clicked
|
||||||
|
"""
|
||||||
|
subprocess.Popen(["xdg-open", "https://cinnamon-spices.linuxmint.com/extensions/view/97"])
|
||||||
|
|
||||||
|
|
||||||
|
def on_github_website_button_clicked(self, button: Gtk.Button):
|
||||||
|
""" Callback for the button to navigate to the GitHub web page of this project
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.Button): Button which was clicked
|
||||||
|
"""
|
||||||
|
subprocess.Popen(["xdg-open", "https://github.com/TobiZog/cinnamon-dynamic-wallpaper"])
|
||||||
|
|
||||||
|
|
||||||
|
def on_create_issue_button_clicked(self, button):
|
||||||
|
""" Callback for the button to navigate to the Issues page on GitHub of this project
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (Gtk.Button): Button which was clicked
|
||||||
|
"""
|
||||||
|
subprocess.Popen(["xdg-open", "https://github.com/TobiZog/cinnamon-dynamic-wallpaper/issues/new"])
|
||||||
|
|
||||||
|
|
||||||
|
def on_ok(self, *args):
|
||||||
|
""" Callback for the OK button in the top bar
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.on_apply()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Close the window
|
||||||
|
self.on_destroy()
|
||||||
|
|
||||||
|
|
||||||
|
def on_apply(self, *args):
|
||||||
|
""" Callback for the Apply button in the top bar
|
||||||
|
"""
|
||||||
|
# Store all values to the JSON file
|
||||||
|
self.prefs.store_preferences()
|
||||||
|
|
||||||
|
# Use the new settings
|
||||||
|
loop = Loop()
|
||||||
|
loop.exchange_image()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
Preferences().show()
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import os, json
|
||||||
|
|
||||||
|
class Cinnamon_Pref_Handler:
|
||||||
|
""" Class to work with the Cinnamon Extension preference format
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# Location of the Cinnamon preference file since Cinnamon 5.4
|
||||||
|
self.pref_location = os.path.expanduser("~") + \
|
||||||
|
"/.config/cinnamon/spices/cinnamon-dynamic-wallpaper@TobiZog/cinnamon-dynamic-wallpaper@TobiZog.json"
|
||||||
|
|
||||||
|
self.load_preferences()
|
||||||
|
|
||||||
|
|
||||||
|
def load_preferences(self):
|
||||||
|
""" Load the JSON preferences to the Preference object
|
||||||
|
"""
|
||||||
|
with open(self.pref_location, "r") as pref_file:
|
||||||
|
pref_data = json.load(pref_file)
|
||||||
|
|
||||||
|
self.picture_aspect = pref_data['picture_aspect']['value']
|
||||||
|
self.dynamic_background_color = pref_data['dynamic_background_color']['value']
|
||||||
|
self.image_source = pref_data['image_source']['value']
|
||||||
|
self.selected_image_set = pref_data['selected_image_set']['value']
|
||||||
|
self.source_folder = pref_data['source_folder']['value']
|
||||||
|
|
||||||
|
self.period_images = [
|
||||||
|
pref_data['period_0_image']['value'],
|
||||||
|
pref_data['period_1_image']['value'],
|
||||||
|
pref_data['period_2_image']['value'],
|
||||||
|
pref_data['period_3_image']['value'],
|
||||||
|
pref_data['period_4_image']['value'],
|
||||||
|
pref_data['period_5_image']['value'],
|
||||||
|
pref_data['period_6_image']['value'],
|
||||||
|
pref_data['period_7_image']['value'],
|
||||||
|
pref_data['period_8_image']['value'],
|
||||||
|
pref_data['period_9_image']['value']
|
||||||
|
]
|
||||||
|
|
||||||
|
self.period_source = pref_data['period_source']['value']
|
||||||
|
self.location_refresh_intervals = pref_data['location_refresh_intervals']['value']
|
||||||
|
self.latitude_auto = pref_data['latitude_auto']['value']
|
||||||
|
self.longitude_auto = pref_data['longitude_auto']['value']
|
||||||
|
self.latitude_custom = pref_data['latitude_custom']['value']
|
||||||
|
self.longitude_custom = pref_data['longitude_custom']['value']
|
||||||
|
|
||||||
|
self.period_custom_start_time = [
|
||||||
|
pref_data['period_0_custom_start_time']['value'],
|
||||||
|
pref_data['period_1_custom_start_time']['value'],
|
||||||
|
pref_data['period_2_custom_start_time']['value'],
|
||||||
|
pref_data['period_3_custom_start_time']['value'],
|
||||||
|
pref_data['period_4_custom_start_time']['value'],
|
||||||
|
pref_data['period_5_custom_start_time']['value'],
|
||||||
|
pref_data['period_6_custom_start_time']['value'],
|
||||||
|
pref_data['period_7_custom_start_time']['value'],
|
||||||
|
pref_data['period_8_custom_start_time']['value'],
|
||||||
|
pref_data['period_9_custom_start_time']['value']
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def store_preferences(self):
|
||||||
|
""" Store the values of the Preference object to the JSON file
|
||||||
|
"""
|
||||||
|
with open(self.pref_location, "r") as pref_file:
|
||||||
|
pref_data = json.load(pref_file)
|
||||||
|
|
||||||
|
pref_data['picture_aspect']['value'] = self.picture_aspect
|
||||||
|
pref_data['dynamic_background_color']['value'] = self.dynamic_background_color
|
||||||
|
pref_data['image_source']['value'] = self.image_source
|
||||||
|
pref_data['selected_image_set']['value'] = self.selected_image_set
|
||||||
|
pref_data['source_folder']['value'] = self.source_folder
|
||||||
|
pref_data['period_0_image']['value'] = self.period_images[0]
|
||||||
|
pref_data['period_1_image']['value'] = self.period_images[1]
|
||||||
|
pref_data['period_2_image']['value'] = self.period_images[2]
|
||||||
|
pref_data['period_3_image']['value'] = self.period_images[3]
|
||||||
|
pref_data['period_4_image']['value'] = self.period_images[4]
|
||||||
|
pref_data['period_5_image']['value'] = self.period_images[5]
|
||||||
|
pref_data['period_6_image']['value'] = self.period_images[6]
|
||||||
|
pref_data['period_7_image']['value'] = self.period_images[7]
|
||||||
|
pref_data['period_8_image']['value'] = self.period_images[8]
|
||||||
|
pref_data['period_9_image']['value'] = self.period_images[9]
|
||||||
|
pref_data['period_source']['value'] = self.period_source
|
||||||
|
pref_data['location_refresh_intervals']['value'] = self.location_refresh_intervals
|
||||||
|
pref_data['latitude_auto']['value'] = self.latitude_auto
|
||||||
|
pref_data['longitude_auto']['value'] = self.longitude_auto
|
||||||
|
pref_data['latitude_custom']['value'] = self.latitude_custom
|
||||||
|
pref_data['longitude_custom']['value'] = self.longitude_custom
|
||||||
|
pref_data['period_0_custom_start_time']['value'] = self.period_custom_start_time[0]
|
||||||
|
pref_data['period_1_custom_start_time']['value'] = self.period_custom_start_time[1]
|
||||||
|
pref_data['period_2_custom_start_time']['value'] = self.period_custom_start_time[2]
|
||||||
|
pref_data['period_3_custom_start_time']['value'] = self.period_custom_start_time[3]
|
||||||
|
pref_data['period_4_custom_start_time']['value'] = self.period_custom_start_time[4]
|
||||||
|
pref_data['period_5_custom_start_time']['value'] = self.period_custom_start_time[5]
|
||||||
|
pref_data['period_6_custom_start_time']['value'] = self.period_custom_start_time[6]
|
||||||
|
pref_data['period_7_custom_start_time']['value'] = self.period_custom_start_time[7]
|
||||||
|
pref_data['period_8_custom_start_time']['value'] = self.period_custom_start_time[8]
|
||||||
|
pref_data['period_9_custom_start_time']['value'] = self.period_custom_start_time[9]
|
||||||
|
|
||||||
|
# Write to file
|
||||||
|
with open(self.pref_location, "w") as pref_file:
|
||||||
|
json.dump(pref_data, pref_file, separators=(',', ':'), indent=4)
|
||||||
61
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/dialogs.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
class Dialogs(Gtk.Window):
|
||||||
|
""" All used Gtk dialogs
|
||||||
|
|
||||||
|
Args:
|
||||||
|
Gtk (Gtk.Window): Window of Gtk application
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def source_folder_dialog(self) -> str:
|
||||||
|
""" Display a FileChooser dialog where the user choose a folder
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Absolute path to the selected folder
|
||||||
|
"""
|
||||||
|
dialog = Gtk.FileChooserDialog(
|
||||||
|
title= "Please choose a folder with images",
|
||||||
|
parent=self,
|
||||||
|
action=Gtk.FileChooserAction.SELECT_FOLDER
|
||||||
|
)
|
||||||
|
|
||||||
|
dialog.add_buttons(
|
||||||
|
Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, "Select", Gtk.ResponseType.OK
|
||||||
|
)
|
||||||
|
|
||||||
|
dialog.set_default_size(800, 400)
|
||||||
|
|
||||||
|
response = dialog.run()
|
||||||
|
|
||||||
|
if response == Gtk.ResponseType.OK:
|
||||||
|
location = dialog.get_filename()
|
||||||
|
elif response == Gtk.ResponseType.CANCEL:
|
||||||
|
location = ""
|
||||||
|
|
||||||
|
dialog.destroy()
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
||||||
|
|
||||||
|
def message_dialog(self, message: str):
|
||||||
|
""" Displaying a Gtk Message dialog to the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message (str): Message which appear in the dialog
|
||||||
|
"""
|
||||||
|
dialog = Gtk.MessageDialog(
|
||||||
|
transient_for=self,
|
||||||
|
flags=0,
|
||||||
|
message_type=Gtk.MessageType.INFO,
|
||||||
|
buttons=Gtk.ButtonsType.OK,
|
||||||
|
text=message
|
||||||
|
)
|
||||||
|
|
||||||
|
dialog.run()
|
||||||
|
dialog.destroy()
|
||||||
20
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/display.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import gi
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gdk
|
||||||
|
|
||||||
|
class Display:
|
||||||
|
""" Handling display informations and actions
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.display = Gdk.Display.get_default()
|
||||||
|
|
||||||
|
|
||||||
|
def get_screen_height(self) -> int:
|
||||||
|
""" Estimate the height resolution of the primary display
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: Height in pixel
|
||||||
|
"""
|
||||||
|
geometry = self.display.get_monitor(0).get_geometry()
|
||||||
|
|
||||||
|
return geometry.height
|
||||||
60
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/images.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
class Images:
|
||||||
|
""" Class for image operations
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_images_from_folder(self, URI: str) -> list:
|
||||||
|
""" List all images in a folder
|
||||||
|
|
||||||
|
Args:
|
||||||
|
URI (str): Absolute path of the folder
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: List of file names which are images
|
||||||
|
"""
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for file in os.listdir(URI):
|
||||||
|
if file.endswith(("jpg", "jpeg", "png", "bmp", "svg")):
|
||||||
|
items.append(file)
|
||||||
|
|
||||||
|
items.sort()
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def extract_heic_file(self, file_uri: str) -> bool:
|
||||||
|
""" Extract a heic file to an internal folder
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_uri (str): Absolute path to the heic file
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: Extraction was successful
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
extract_folder = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) + \
|
||||||
|
"/images/extracted_images/"
|
||||||
|
|
||||||
|
file_name: str = file_uri[file_uri.rfind("/") + 1:]
|
||||||
|
file_name = file_name[:file_name.rfind(".")]
|
||||||
|
|
||||||
|
# Create the buffer folder if its not existing
|
||||||
|
try:
|
||||||
|
os.mkdir(extract_folder)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Cleanup the folder
|
||||||
|
for file in self.get_images_from_folder(extract_folder):
|
||||||
|
os.remove(extract_folder + file)
|
||||||
|
|
||||||
|
# Extract the HEIC file
|
||||||
|
os.system("heif-convert '" + file_uri + "' '" + extract_folder + file_name + ".jpg'")
|
||||||
|
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
const Soup = imports.gi.Soup;
|
|
||||||
|
|
||||||
|
|
||||||
function estimateLocation() {
|
|
||||||
let sessionSync = new Soup.SessionSync();
|
|
||||||
let msg = Soup.Message.new('GET', "https://get.geojs.io/v1/ip/geo.json");
|
|
||||||
sessionSync.send_message(msg);
|
|
||||||
|
|
||||||
if (msg.status_code == 200) {
|
|
||||||
return JSON.parse(msg.response_body.data);
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
22
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/location.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import urllib.request, json
|
||||||
|
|
||||||
|
class Location():
|
||||||
|
""" Class to handle location requests
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
self.GEO_URL = "https://get.geojs.io/v1/ip/geo.json"
|
||||||
|
|
||||||
|
def get_location(self) -> dict:
|
||||||
|
""" Request the location via network
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: latitude and longitude
|
||||||
|
"""
|
||||||
|
request = urllib.request.urlopen(self.GEO_URL)
|
||||||
|
|
||||||
|
data = json.load(request)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"latitude": data["latitude"],
|
||||||
|
"longitude": data["longitude"]
|
||||||
|
}
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
/**
|
|
||||||
* @name Cinnamon-Dynamic-Wallpaper
|
|
||||||
* @alias TobiZog
|
|
||||||
* @since 2023
|
|
||||||
*/
|
|
||||||
|
|
||||||
const DAYPERIOD = {
|
|
||||||
MTWILIGHT: 0,
|
|
||||||
SUNRISE: 1,
|
|
||||||
MORNING: 2,
|
|
||||||
NOON: 3,
|
|
||||||
AFTERNOON: 4,
|
|
||||||
EVENING: 5,
|
|
||||||
SUNSET: 6,
|
|
||||||
NTWILIGHT: 7,
|
|
||||||
NIGHT: 8,
|
|
||||||
NONE: 10
|
|
||||||
}
|
|
||||||
|
|
||||||
const DAYMS = 1000 * 60 * 60 * 24
|
|
||||||
const J1970 = 2440588
|
|
||||||
const J2000 = 2451545
|
|
||||||
|
|
||||||
|
|
||||||
function fromJulian(j) {
|
|
||||||
let ms_date = (j + 0.5 - J1970) * DAYMS
|
|
||||||
return new Date(ms_date)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculating specific events of the sun during a day
|
|
||||||
*
|
|
||||||
* @param {float} latitude Location latitude
|
|
||||||
* @param {float} longitude Location longitude
|
|
||||||
*
|
|
||||||
* @returns List of sun events in a day: dawn, sunrise, noon, sunset, dusk
|
|
||||||
*/
|
|
||||||
function sunEventsOfDay(latitude, longitude, date) {
|
|
||||||
let rad = Math.PI / 180
|
|
||||||
let lw = rad * (-longitude)
|
|
||||||
|
|
||||||
let d = (date / DAYMS) - 0.5 + J1970 - J2000
|
|
||||||
let n = Math.round(d - 0.0009 - lw / (2 * Math.PI))
|
|
||||||
let ds = 0.0009 + lw / (2 * Math.PI) + n
|
|
||||||
|
|
||||||
let M = rad * (357.5291 + 0.98560028 * ds)
|
|
||||||
let C = rad * (1.9148 * Math.sin(M) + 0.02 * Math.sin(2 * M) + 0.0003 * Math.sin(3 * M))
|
|
||||||
let P = rad * 102.9372
|
|
||||||
let L = M + C + P + Math.PI
|
|
||||||
|
|
||||||
let dec = Math.asin(Math.sin(rad * 23.4397) * Math.sin(L))
|
|
||||||
|
|
||||||
|
|
||||||
// Angles for the sun
|
|
||||||
let angles = [-0.833, -6]
|
|
||||||
|
|
||||||
for(var i = 0; i < angles.length; i++) {
|
|
||||||
angles[i] = angles[i] * rad
|
|
||||||
angles[i] = Math.acos((Math.sin(angles[i]) - Math.sin(rad * latitude) * Math.sin(dec)) / (Math.cos(rad * latitude) * Math.cos(dec)))
|
|
||||||
angles[i] = 0.0009 + (angles[i] + lw) / (2 * Math.PI) + n
|
|
||||||
}
|
|
||||||
|
|
||||||
let jnoon = J2000 + ds + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L)
|
|
||||||
|
|
||||||
return {
|
|
||||||
dawn: fromJulian(jnoon - (J2000 + angles[1] + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L) - jnoon)),
|
|
||||||
sunrise: fromJulian(jnoon - (J2000 + angles[0] + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L) - jnoon)),
|
|
||||||
noon: fromJulian(jnoon),
|
|
||||||
sunset: fromJulian(J2000 + angles[0] + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L)),
|
|
||||||
dusk: fromJulian(J2000 + angles[1] + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2 * L))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addMinutesToTime(date, minutes = 0) {
|
|
||||||
let newDate = new Date(date)
|
|
||||||
newDate.setMinutes(date.getMinutes() + minutes)
|
|
||||||
return newDate
|
|
||||||
}
|
|
||||||
|
|
||||||
function subTimesToMinutes(date1, date2) {
|
|
||||||
let diff = new Date(date1 - date2)
|
|
||||||
return diff.getUTCHours() * 60 + diff.getMinutes()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function calcTimePeriod(latitude, longitude) {
|
|
||||||
let todaySunEventsDay = sunEventsOfDay(latitude, longitude, Date.now())
|
|
||||||
let tomorrowSunEventsDay = sunEventsOfDay(latitude, longitude, addMinutesToTime(new Date(), 1440))
|
|
||||||
|
|
||||||
return {
|
|
||||||
morning_twilight: [
|
|
||||||
todaySunEventsDay.dawn,
|
|
||||||
addMinutesToTime(todaySunEventsDay.sunrise, -1)
|
|
||||||
],
|
|
||||||
sunrise: [
|
|
||||||
todaySunEventsDay.sunrise,
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.sunrise,
|
|
||||||
subTimesToMinutes(todaySunEventsDay.noon, todaySunEventsDay.sunrise) / 8 - 1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
morning: [
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.sunrise,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.noon, todaySunEventsDay.sunrise) / 8) * 1
|
|
||||||
),
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.sunrise,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.noon, todaySunEventsDay.sunrise) / 8)*6 - 1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
noon: [
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.sunrise,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.noon, todaySunEventsDay.sunrise) / 8) * 6
|
|
||||||
),
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 2 - 1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
afternoon: [
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 2
|
|
||||||
),
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 5 - 1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
evening: [
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 5
|
|
||||||
),
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 7 - 1
|
|
||||||
)
|
|
||||||
],
|
|
||||||
sunset: [
|
|
||||||
addMinutesToTime(
|
|
||||||
todaySunEventsDay.noon,
|
|
||||||
(subTimesToMinutes(todaySunEventsDay.sunset, todaySunEventsDay.noon) / 8) * 7 - 1
|
|
||||||
),
|
|
||||||
todaySunEventsDay.sunset
|
|
||||||
],
|
|
||||||
night_twilight: [
|
|
||||||
addMinutesToTime(todaySunEventsDay.sunset, 1),
|
|
||||||
todaySunEventsDay.dusk
|
|
||||||
],
|
|
||||||
night: [
|
|
||||||
addMinutesToTime(todaySunEventsDay.dusk, 1),
|
|
||||||
addMinutesToTime(tomorrowSunEventsDay.dawn, -1)
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
146
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/suntimes.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
from math import pi, sin, asin, acos, cos, floor, atan, tan
|
||||||
|
from datetime import datetime, timezone, time
|
||||||
|
|
||||||
|
|
||||||
|
class Suntimes:
|
||||||
|
""" Calculates all time periods based on latitude and longitude
|
||||||
|
Inspired by https://github.com/SatAgro/suntime
|
||||||
|
|
||||||
|
author: TobiZog
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
""" Initialization
|
||||||
|
|
||||||
|
Args:
|
||||||
|
latitude (float): Latitude of the position
|
||||||
|
longitude (float): Longitude of the position
|
||||||
|
"""
|
||||||
|
self.today = datetime.now()
|
||||||
|
|
||||||
|
|
||||||
|
def calc_suntimes(self, latitude: float, longitude: float) -> None:
|
||||||
|
""" Start the calculation process
|
||||||
|
|
||||||
|
Args:
|
||||||
|
latitude (float): Current latitude
|
||||||
|
longitude (float): Current longitude
|
||||||
|
"""
|
||||||
|
self.latitude = latitude
|
||||||
|
self.longitude = longitude
|
||||||
|
self.calc_sun_events()
|
||||||
|
|
||||||
|
|
||||||
|
def to_range(self, value: float, range_max: float) -> float:
|
||||||
|
""" Converting a variable to a given range
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (float): The given value
|
||||||
|
range_max (float): Upper boundary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: Corrected value inside range 0 to range_max
|
||||||
|
"""
|
||||||
|
if value < 0:
|
||||||
|
return value + range_max
|
||||||
|
elif value >= range_max:
|
||||||
|
return value - range_max
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def calc_sun_events(self):
|
||||||
|
""" Parent sun event calculater. Calls calc_sunrise_sunset_time() for every time period
|
||||||
|
"""
|
||||||
|
civial_dawn_start = self.calc_sunrise_sunset_time(True, 96)
|
||||||
|
sunrise_start = self.calc_sunrise_sunset_time(True)
|
||||||
|
morning_start = self.calc_sunrise_sunset_time(True, 89.167)
|
||||||
|
|
||||||
|
sunset_start = self.calc_sunrise_sunset_time(False, 89.167)
|
||||||
|
civial_dusk_start = self.calc_sunrise_sunset_time(False)
|
||||||
|
night_start = self.calc_sunrise_sunset_time(False, 96)
|
||||||
|
|
||||||
|
light_period_duration = (sunset_start - morning_start) / 8
|
||||||
|
|
||||||
|
noon_start = morning_start + 3 * light_period_duration
|
||||||
|
afternoon_start = morning_start + 5 * light_period_duration
|
||||||
|
evening_start = morning_start + 7 * light_period_duration
|
||||||
|
|
||||||
|
self.day_periods = [
|
||||||
|
time(hour=0, minute=0),
|
||||||
|
time(civial_dawn_start.hour, civial_dawn_start.minute),
|
||||||
|
time(sunrise_start.hour, sunrise_start.minute),
|
||||||
|
time(morning_start.hour, morning_start.minute),
|
||||||
|
time(noon_start.hour, noon_start.minute),
|
||||||
|
time(afternoon_start.hour, afternoon_start.minute),
|
||||||
|
time(evening_start.hour, evening_start.minute),
|
||||||
|
time(sunset_start.hour, sunset_start.minute),
|
||||||
|
time(civial_dusk_start.hour, civial_dusk_start.minute),
|
||||||
|
time(night_start.hour, night_start.minute),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def calc_sunrise_sunset_time(self, is_sunrise: bool, zenith=90.833) -> datetime:
|
||||||
|
""" Calculate all values to estimate the day periods
|
||||||
|
"""
|
||||||
|
RAD = pi / 180
|
||||||
|
|
||||||
|
# Day of the year
|
||||||
|
day_of_year = self.today.timetuple().tm_yday
|
||||||
|
|
||||||
|
# 2
|
||||||
|
lng_hour = self.longitude / 15
|
||||||
|
|
||||||
|
if is_sunrise:
|
||||||
|
t = day_of_year + ((6 - lng_hour) / 24)
|
||||||
|
else:
|
||||||
|
t = day_of_year + ((18 - lng_hour) / 24)
|
||||||
|
|
||||||
|
# 3
|
||||||
|
M = (0.9856 * t) - 3.289
|
||||||
|
|
||||||
|
# 4
|
||||||
|
L = self.to_range(M + (1.916 * sin(RAD * M)) + (0.020 * sin(RAD * 2 * M)) + 282.634, 360)
|
||||||
|
|
||||||
|
# 5
|
||||||
|
RA = self.to_range((1 / RAD) * atan(0.91764 * tan(RAD * L)), 360)
|
||||||
|
RA += ((floor(L / 90)) * 90 - (floor(RA / 90)) * 90)
|
||||||
|
RA /= 15
|
||||||
|
|
||||||
|
# 6
|
||||||
|
sin_dec = 0.39782 * sin(RAD * L)
|
||||||
|
cos_dec = cos(asin(sin_dec))
|
||||||
|
|
||||||
|
|
||||||
|
# 7a
|
||||||
|
cos_h = (cos(RAD * zenith) - (sin_dec * sin(RAD * self.latitude))) / (cos_dec * cos(RAD * self.latitude))
|
||||||
|
|
||||||
|
# The sun rises or sets never
|
||||||
|
if cos_h > 1 or cos_h < -1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 7b
|
||||||
|
if is_sunrise:
|
||||||
|
H = 360 - (1 / RAD) * acos(cos_h)
|
||||||
|
else: #setting
|
||||||
|
H = (1 / RAD) * acos(cos_h)
|
||||||
|
|
||||||
|
H = H / 15
|
||||||
|
|
||||||
|
# 8
|
||||||
|
T = H + RA - (0.06571 * t) - 6.622
|
||||||
|
|
||||||
|
# 9
|
||||||
|
UT = T - lng_hour
|
||||||
|
UT = self.to_range(UT, 24) # UTC time in decimal format (e.g. 23.23)
|
||||||
|
|
||||||
|
|
||||||
|
# 10
|
||||||
|
hr = self.to_range(int(UT), 24)
|
||||||
|
min = round((UT - int(UT))*60, 0)
|
||||||
|
if min == 60:
|
||||||
|
hr += 1
|
||||||
|
min = 0
|
||||||
|
|
||||||
|
|
||||||
|
res = datetime(self.today.year, self.today.month, self.today.day, hr, int(min))
|
||||||
|
return res.replace(tzinfo=timezone.utc).astimezone(tz=None)
|
||||||
173
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/time_bar_chart.py
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
class Time_Bar_Chart:
|
||||||
|
""" Class to handle the creation of the day time period bar
|
||||||
|
"""
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.image_code = []
|
||||||
|
|
||||||
|
self.colors = [
|
||||||
|
"00193d",
|
||||||
|
"05597f",
|
||||||
|
"54babf",
|
||||||
|
"9ec3a1",
|
||||||
|
"ffb95e",
|
||||||
|
"fcae4e",
|
||||||
|
"f37f73",
|
||||||
|
"b45bbc",
|
||||||
|
"7e38ce",
|
||||||
|
"00285f"
|
||||||
|
]
|
||||||
|
|
||||||
|
self.bar_pos_x = []
|
||||||
|
|
||||||
|
|
||||||
|
def create_bar_chart_with_polylines(self, save_location: str, image_width: int, image_height: int, times: list):
|
||||||
|
""" Create a time bar chart WITH polylines
|
||||||
|
|
||||||
|
Args:
|
||||||
|
save_location (str): Absolute path to store
|
||||||
|
image_width (int): Width of the image in pixel
|
||||||
|
image_height (int): Height of the image in pixel
|
||||||
|
times (list): List of start times of the periods in minutes since midnight
|
||||||
|
"""
|
||||||
|
self.create_bar(image_width, image_height, times)
|
||||||
|
self.create_polylines(image_width, image_height)
|
||||||
|
self.create_time_markers(image_width, image_height)
|
||||||
|
|
||||||
|
# Write to file
|
||||||
|
self.image_code.insert(0, '<svg xmlns="http://www.w3.org/2000/svg" width="%s" height="%s">' % (image_width, image_height))
|
||||||
|
self.image_code.append('</svg>')
|
||||||
|
|
||||||
|
file = open(save_location + "/time_bar_polylines.svg", "w")
|
||||||
|
for i in self.image_code:
|
||||||
|
file.write(i + '\n')
|
||||||
|
|
||||||
|
self.image_code.clear()
|
||||||
|
self.bar_pos_x.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def create_bar_chart(self, save_location: str, image_width: int, image_height: int, times: list):
|
||||||
|
""" Create a time bar chart WITHOUT polylines
|
||||||
|
|
||||||
|
Args:
|
||||||
|
save_location (str): Absolute path to store
|
||||||
|
image_width (int): Width of the image in pixel
|
||||||
|
image_height (int): Height of the image in pixel
|
||||||
|
times (list): List of start times of the periods in minutes since midnight
|
||||||
|
"""
|
||||||
|
self.create_bar(image_width, image_height, times)
|
||||||
|
self.create_time_markers(image_width, image_height)
|
||||||
|
|
||||||
|
# Write to file
|
||||||
|
self.image_code.insert(0, '<svg xmlns="http://www.w3.org/2000/svg" width="%s" height="%s">' % (image_width, image_height))
|
||||||
|
self.image_code.append('</svg>')
|
||||||
|
|
||||||
|
file = open(save_location + "/time_bar.svg", "w")
|
||||||
|
for i in self.image_code:
|
||||||
|
file.write(i + '\n')
|
||||||
|
|
||||||
|
self.image_code.clear()
|
||||||
|
self.bar_pos_x.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def create_bar(self, image_width: int, image_height: int, times: list):
|
||||||
|
""" Generates the code for the horizontal multi-color bar chart
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_width (int): Total width of the image
|
||||||
|
image_height (int): Total height of the image
|
||||||
|
times (list): List of start times of the periods, in minutes
|
||||||
|
"""
|
||||||
|
x = 0
|
||||||
|
y = 40
|
||||||
|
width = 0
|
||||||
|
height = image_height - 80
|
||||||
|
|
||||||
|
if times[len(times) - 1] != 1440:
|
||||||
|
times.append(1440)
|
||||||
|
|
||||||
|
# Adding the bar parts
|
||||||
|
for i in range(1, len(times)):
|
||||||
|
width = math.ceil((((100 / 1440) * (times[i] - times[i - 1]) / 100) * image_width))
|
||||||
|
|
||||||
|
self.image_code.append(
|
||||||
|
'<rect fill="#%s" x="%s" y="%s" width="%s" height="%s"/>' % (self.colors[i - 1], x, y, width, height)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.bar_pos_x.append(x)
|
||||||
|
x += width
|
||||||
|
|
||||||
|
|
||||||
|
def create_time_markers(self, image_width: int, image_height: int):
|
||||||
|
""" Generates the code for the vertical hour markers
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_width (int): Total width of the image
|
||||||
|
image_height (int): Total height of the image
|
||||||
|
"""
|
||||||
|
for i in range(0, 8):
|
||||||
|
# 3 hour vertical line
|
||||||
|
self.image_code.append(
|
||||||
|
'<line x1="%s" y1="40" x2="%s" y2="%s" stroke="white" stroke-width="2" />' %
|
||||||
|
(i * (image_width // 8), i * (image_width // 8), image_height - 40)
|
||||||
|
)
|
||||||
|
|
||||||
|
# The two hours between the 3 hour lines
|
||||||
|
for j in range(1, 3):
|
||||||
|
self.image_code.append(
|
||||||
|
'<line x1="%s" y1="40" x2="%s" y2="%s" stroke="white" stroke-width="0.5" />' %
|
||||||
|
(i * (image_width // 8) + image_width // 24 * j, i * (image_width // 8) + image_width // 24 * j, image_height - 40)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Time labels
|
||||||
|
self.image_code.append(
|
||||||
|
'<text x="%s" y="%s" fill="white" font-size="20" font-family="Liberation Sans">%s</text>' %
|
||||||
|
(i * (image_width // 8) + 5, image_height - 45, i * 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def create_polylines(self, image_width: int, image_height: int):
|
||||||
|
""" Generates the code for the polylines which connect the images with the bar sections
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_width (int): Total width of the image
|
||||||
|
image_height (int): Total height of the image
|
||||||
|
"""
|
||||||
|
bar_x_start = 0
|
||||||
|
|
||||||
|
self.bar_pos_x.append(image_width)
|
||||||
|
|
||||||
|
for i in range(0, len(self.bar_pos_x) - 1):
|
||||||
|
# X-Middle of a bar
|
||||||
|
bar_mid = bar_x_start + (self.bar_pos_x[i + 1] - bar_x_start) / 2
|
||||||
|
|
||||||
|
# Position of the image in the window
|
||||||
|
image_x = (image_width - 32) / 10 + ((i // 2) % 5) * image_width / 5
|
||||||
|
|
||||||
|
# i == 0, 2, 4, ... => Upper Polylines
|
||||||
|
if (i % 2 == 0):
|
||||||
|
polyline_y = 0
|
||||||
|
else:
|
||||||
|
polyline_y = image_height
|
||||||
|
|
||||||
|
if i == 0 or i == 8:
|
||||||
|
polyline_x = 30
|
||||||
|
elif i == 2 or i == 6:
|
||||||
|
polyline_x = 20
|
||||||
|
elif i == 1 or i == 9:
|
||||||
|
polyline_x = image_height - 30
|
||||||
|
elif i == 3 or i == 7:
|
||||||
|
polyline_x = image_height - 20
|
||||||
|
elif i == 5:
|
||||||
|
polyline_x = image_height - 10
|
||||||
|
else:
|
||||||
|
polyline_x = 10
|
||||||
|
|
||||||
|
self.image_code.append(
|
||||||
|
'<polyline points="%s,%s %s,%s %s,%s %s,%s" stroke="#%s" fill="none" stroke-width="5" />' %
|
||||||
|
(image_x, polyline_y, image_x, polyline_x, bar_mid, polyline_x, bar_mid, image_height / 2, self.colors[i])
|
||||||
|
)
|
||||||
|
|
||||||
|
# Store the end point of the bar as start point of the next
|
||||||
|
bar_x_start = self.bar_pos_x[i + 1]
|
||||||
147
cinnamon-dynamic-wallpaper@TobiZog/5.4/scripts/ui.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import gi
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
class UI:
|
||||||
|
""" Class to handle UI components and actions
|
||||||
|
"""
|
||||||
|
def __init__(self, builder: Gtk.Builder) -> None:
|
||||||
|
# Page 1
|
||||||
|
self.tb_image_set: Gtk.ToggleButton = builder.get_object("tb_image_set")
|
||||||
|
self.tb_heic_file: Gtk.ToggleButton = builder.get_object("tb_heic_file")
|
||||||
|
self.tb_source_folder: Gtk.ToggleButton = builder.get_object("tb_source_folder")
|
||||||
|
self.img_tb_image_set: Gtk.Image = builder.get_object("img_tb_image_set")
|
||||||
|
self.img_tb_heic_file: Gtk.Image = builder.get_object("img_tb_heic_file")
|
||||||
|
self.img_tb_source_folder: Gtk.Image = builder.get_object("img_tb_source_folder")
|
||||||
|
|
||||||
|
# Image set
|
||||||
|
self.lbr_image_set: Gtk.ListBoxRow = builder.get_object("lbr_image_set")
|
||||||
|
self.cb_image_set: Gtk.ComboBox = builder.get_object("cb_image_set")
|
||||||
|
|
||||||
|
# HEIC file
|
||||||
|
self.lbr_heic_file: Gtk.ListBoxRow = builder.get_object("lbr_heic_file")
|
||||||
|
|
||||||
|
# Source folder
|
||||||
|
self.lbr_source_folder: Gtk.ListBoxRow = builder.get_object("lbr_source_folder")
|
||||||
|
self.btn_source_folder: Gtk.Button = builder.get_object("btn_source_folder")
|
||||||
|
self.lbl_source_folder: Gtk.Label = builder.get_object("lbl_source_folder")
|
||||||
|
|
||||||
|
# Time bar chart
|
||||||
|
self.img_bar_images: Gtk.Image = builder.get_object("img_bar_images")
|
||||||
|
self.etr_periods: list[Gtk.Entry] = [
|
||||||
|
builder.get_object("etr_period_1"), builder.get_object("etr_period_2"),
|
||||||
|
builder.get_object("etr_period_3"), builder.get_object("etr_period_4"),
|
||||||
|
builder.get_object("etr_period_5"), builder.get_object("etr_period_6"),
|
||||||
|
builder.get_object("etr_period_7"), builder.get_object("etr_period_8"),
|
||||||
|
builder.get_object("etr_period_9"), builder.get_object("etr_period_10"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.img_periods: list[Gtk.Image] = [
|
||||||
|
builder.get_object("img_period_0"), builder.get_object("img_period_1"),
|
||||||
|
builder.get_object("img_period_2"), builder.get_object("img_period_3"),
|
||||||
|
builder.get_object("img_period_4"), builder.get_object("img_period_5"),
|
||||||
|
builder.get_object("img_period_6"), builder.get_object("img_period_7"),
|
||||||
|
builder.get_object("img_period_8"), builder.get_object("img_period_9"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.cb_periods: list[Gtk.ComboBox] = [
|
||||||
|
builder.get_object("cb_period_0"), builder.get_object("cb_period_1"),
|
||||||
|
builder.get_object("cb_period_2"), builder.get_object("cb_period_3"),
|
||||||
|
builder.get_object("cb_period_4"), builder.get_object("cb_period_5"),
|
||||||
|
builder.get_object("cb_period_6"), builder.get_object("cb_period_7"),
|
||||||
|
builder.get_object("cb_period_8"), builder.get_object("cb_period_9"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### Page 2: Location & Times
|
||||||
|
self.tb_network_location: Gtk.ToggleButton = builder.get_object("tb_network_location")
|
||||||
|
self.tb_custom_location: Gtk.ToggleButton = builder.get_object("tb_custom_location")
|
||||||
|
self.tb_time_periods: Gtk.ToggleButton = builder.get_object("tb_time_periods")
|
||||||
|
self.img_tb_network_location: Gtk.Image = builder.get_object("img_tb_network_location")
|
||||||
|
self.img_tb_custom_location: Gtk.Image = builder.get_object("img_tb_custom_location")
|
||||||
|
self.img_tb_time_periods: Gtk.Image = builder.get_object("img_tb_time_periods")
|
||||||
|
|
||||||
|
# Network Location
|
||||||
|
self.lb_current_location: Gtk.Label = builder.get_object("lb_current_location")
|
||||||
|
self.lbr_current_location: Gtk.ListBoxRow = builder.get_object("lbr_current_location")
|
||||||
|
self.lbr_network_location: Gtk.ListBoxRow = builder.get_object("lbr_network_location")
|
||||||
|
self.spb_network_location_refresh_time: Gtk.SpinButton = builder.get_object("spb_network_location_refresh_time")
|
||||||
|
|
||||||
|
# Custom location
|
||||||
|
self.lbr_custom_location_longitude: Gtk.ListBoxRow = builder.get_object("lbr_custom_location_longitude")
|
||||||
|
self.lbr_custom_location_latitude: Gtk.ListBoxRow = builder.get_object("lbr_custom_location_latitude")
|
||||||
|
self.lbr_time_periods: Gtk.ListBoxRow = builder.get_object("lbr_time_periods")
|
||||||
|
self.etr_longitude: Gtk.Entry = builder.get_object("etr_longitude")
|
||||||
|
self.etr_latitude: Gtk.Entry = builder.get_object("etr_latitude")
|
||||||
|
self.img_bar_times: Gtk.Image = builder.get_object("img_bar_times")
|
||||||
|
self.spb_periods_hour: list[Gtk.SpinButton] = [
|
||||||
|
builder.get_object("spb_period_1_hour"),
|
||||||
|
builder.get_object("spb_period_2_hour"),
|
||||||
|
builder.get_object("spb_period_3_hour"),
|
||||||
|
builder.get_object("spb_period_4_hour"),
|
||||||
|
builder.get_object("spb_period_5_hour"),
|
||||||
|
builder.get_object("spb_period_6_hour"),
|
||||||
|
builder.get_object("spb_period_7_hour"),
|
||||||
|
builder.get_object("spb_period_8_hour"),
|
||||||
|
builder.get_object("spb_period_9_hour"),
|
||||||
|
]
|
||||||
|
self.spb_periods_minute: list[Gtk.SpinButton] = [
|
||||||
|
builder.get_object("spb_period_1_minute"),
|
||||||
|
builder.get_object("spb_period_2_minute"),
|
||||||
|
builder.get_object("spb_period_3_minute"),
|
||||||
|
builder.get_object("spb_period_4_minute"),
|
||||||
|
builder.get_object("spb_period_5_minute"),
|
||||||
|
builder.get_object("spb_period_6_minute"),
|
||||||
|
builder.get_object("spb_period_7_minute"),
|
||||||
|
builder.get_object("spb_period_8_minute"),
|
||||||
|
builder.get_object("spb_period_9_minute")
|
||||||
|
]
|
||||||
|
self.lb_period_end: list[Gtk.Label] = [
|
||||||
|
builder.get_object("lb_period_0_end"), builder.get_object("lb_period_1_end"),
|
||||||
|
builder.get_object("lb_period_2_end"), builder.get_object("lb_period_3_end"),
|
||||||
|
builder.get_object("lb_period_4_end"), builder.get_object("lb_period_5_end"),
|
||||||
|
builder.get_object("lb_period_6_end"), builder.get_object("lb_period_7_end"),
|
||||||
|
builder.get_object("lb_period_8_end"), builder.get_object("lb_period_9_end"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Page 3: Behaviour
|
||||||
|
self.cb_picture_aspect: Gtk.ComboBox = builder.get_object("cb_picture_aspect")
|
||||||
|
self.sw_dynamic_background_color: Gtk.Switch = builder.get_object("sw_dynamic_background_color")
|
||||||
|
|
||||||
|
|
||||||
|
def set_active_combobox_item(self, combobox: Gtk.ComboBoxText, active_item: str):
|
||||||
|
""" Change active item in combobox by String value
|
||||||
|
|
||||||
|
Args:
|
||||||
|
combobox (Gtk.ComboBoxText): ComboBox to set active
|
||||||
|
active_item (str): String item to set active
|
||||||
|
"""
|
||||||
|
list_store = combobox.get_model()
|
||||||
|
|
||||||
|
for i in range(0, len(list_store)):
|
||||||
|
row = list_store[i]
|
||||||
|
if row[0] == active_item:
|
||||||
|
combobox.set_active(i)
|
||||||
|
|
||||||
|
|
||||||
|
def add_items_to_combo_box(self, combobox: Gtk.ComboBox, items: list):
|
||||||
|
""" Add items to a combo box
|
||||||
|
|
||||||
|
Args:
|
||||||
|
combobox (Gtk.ComboBox): ComboBox where to add the options
|
||||||
|
items (list): Possible options
|
||||||
|
"""
|
||||||
|
model = combobox.get_model()
|
||||||
|
store = Gtk.ListStore(str)
|
||||||
|
|
||||||
|
for image_set in items:
|
||||||
|
store.append([image_set])
|
||||||
|
|
||||||
|
combobox.set_model(store)
|
||||||
|
|
||||||
|
if model == None:
|
||||||
|
renderer_text = Gtk.CellRendererText()
|
||||||
|
combobox.pack_start(renderer_text, True)
|
||||||
|
combobox.add_attribute(renderer_text, "text", 0)
|
||||||
@@ -1,224 +1,130 @@
|
|||||||
{
|
{
|
||||||
"layout": {
|
|
||||||
"type": "layout",
|
|
||||||
"pages": [
|
|
||||||
"pg_config",
|
|
||||||
"pg_about"
|
|
||||||
],
|
|
||||||
"pg_config": {
|
|
||||||
"type": "page",
|
|
||||||
"title": "Configuration",
|
|
||||||
"sections": [
|
|
||||||
"sec_image_configuration",
|
|
||||||
"sec_location",
|
|
||||||
"sec_times"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"pg_about": {
|
|
||||||
"type": "page",
|
|
||||||
"title": "About",
|
|
||||||
"sections": [
|
|
||||||
"sec_project",
|
|
||||||
"sec_github",
|
|
||||||
"sec_report_issue"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
"sec_image_configuration": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "Image set",
|
|
||||||
"keys": [
|
|
||||||
"lb_image_configuration",
|
|
||||||
"btn_config_images",
|
|
||||||
"sw_image_stretch"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sec_location": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "Location estimation",
|
|
||||||
"keys": [
|
|
||||||
"sw_auto_location",
|
|
||||||
"sc_location_refresh_time",
|
|
||||||
"etr_latitude",
|
|
||||||
"etr_longitude"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sec_times": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "Time periods",
|
|
||||||
"keys": [
|
|
||||||
"tv_times"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sec_project": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "About the project",
|
|
||||||
"keys": [
|
|
||||||
"lb_about",
|
|
||||||
"lb_author",
|
|
||||||
"lb_spices",
|
|
||||||
"btn_spices"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sec_github": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "Source Code on GitHub",
|
|
||||||
"keys": [
|
|
||||||
"lb_repository",
|
|
||||||
"btn_open_repository"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sec_report_issue": {
|
|
||||||
"type": "section",
|
|
||||||
"title": "Report an issue",
|
|
||||||
"keys": [
|
|
||||||
"lb_report_issue",
|
|
||||||
"btn_report_issue"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
"lb_image_configuration": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "Choose an included image set or import a heic-file with the Image Configurator"
|
|
||||||
},
|
|
||||||
"btn_config_images": {
|
|
||||||
"type": "button",
|
|
||||||
"description": "Image Configurator",
|
|
||||||
"callback": "openImageConfigurator"
|
|
||||||
},
|
|
||||||
"sw_image_stretch": {
|
|
||||||
"type": "switch",
|
|
||||||
"description": "Expand image over all displays",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"sw_auto_location": {
|
|
||||||
"type": "switch",
|
|
||||||
"default": true,
|
|
||||||
"description": "Estimate coordinates via network"
|
|
||||||
},
|
|
||||||
"sc_location_refresh_time": {
|
|
||||||
"type": "scale",
|
|
||||||
"default": 15,
|
|
||||||
"min": 5,
|
|
||||||
"max": 60,
|
|
||||||
"step": 5,
|
|
||||||
"description": "Interval time to refresh the location via network (min)",
|
|
||||||
"dependency": "sw_auto_location"
|
|
||||||
},
|
|
||||||
"etr_latitude": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "",
|
|
||||||
"description": "Latitude",
|
|
||||||
"dependency": "!sw_auto_location"
|
|
||||||
},
|
|
||||||
"etr_longitude": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "",
|
|
||||||
"description": "Longitude",
|
|
||||||
"dependency": "!sw_auto_location"
|
|
||||||
},
|
|
||||||
"tv_times": {
|
|
||||||
"type": "textview",
|
|
||||||
"description": "Time sections today",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
"lb_about": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "Based on a location, this extension calculates the periods of a day and switch the background image of your Cinnamon desktop. The extension offers the choice between a set of predownloaded wallpapers or to select a custom set of images."
|
|
||||||
},
|
|
||||||
"lb_author": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "Developed by TobiZog"
|
|
||||||
},
|
|
||||||
"lb_spices": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "If you want more information or rate the extension, you can visit the site Cinnamon Spices Website."
|
|
||||||
},
|
|
||||||
"btn_spices": {
|
|
||||||
"type": "button",
|
|
||||||
"description": "Cinnamon Dynamic Wallpaper at Cinnamon Spices Website",
|
|
||||||
"callback": "openSpicesWebsite"
|
|
||||||
},
|
|
||||||
|
|
||||||
"lb_repository": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "This project is Open Source. You can visit the whole source code of this extension on GitHub"
|
|
||||||
},
|
|
||||||
"btn_open_repository": {
|
|
||||||
"type": "button",
|
|
||||||
"description": "Open the Repository",
|
|
||||||
"callback": "openRepoWebsite"
|
|
||||||
},
|
|
||||||
|
|
||||||
"lb_report_issue": {
|
|
||||||
"type": "label",
|
|
||||||
"description": "Do you find an issue? Or want a new feature? Go to the GitHub repository and create a new issue."
|
|
||||||
},
|
|
||||||
|
|
||||||
"btn_report_issue": {
|
|
||||||
"type": "button",
|
|
||||||
"description": "Submit an Issue",
|
|
||||||
"callback": "openIssueWebsite"
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
"etr_choosen_image_set": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "lakeside",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_morning_twilight": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "1.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_sunrise": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "2.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_morning": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "3.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_noon": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "4.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_afternoon": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "5.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_evening": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "6.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_sunset": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "7.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_night_twilight": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "8.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"etr_img_night": {
|
|
||||||
"type": "entry",
|
|
||||||
"default": "9.jpg",
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"first_start": {
|
"first_start": {
|
||||||
"type": "generic",
|
"type": "generic",
|
||||||
"default": true
|
"default": true
|
||||||
|
},
|
||||||
|
"picture_aspect": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "scaled"
|
||||||
|
},
|
||||||
|
"dynamic_background_color": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"image_source": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "image_set"
|
||||||
|
},
|
||||||
|
"selected_image_set": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "lakeside"
|
||||||
|
},
|
||||||
|
"source_folder": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"period_0_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "9.jpg"
|
||||||
|
},
|
||||||
|
"period_1_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "1.jpg"
|
||||||
|
},
|
||||||
|
"period_2_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "2.jpg"
|
||||||
|
},
|
||||||
|
"period_3_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "3.jpg"
|
||||||
|
},
|
||||||
|
"period_4_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "4.jpg"
|
||||||
|
},
|
||||||
|
"period_5_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "5.jpg"
|
||||||
|
},
|
||||||
|
"period_6_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "6.jpg"
|
||||||
|
},
|
||||||
|
"period_7_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "7.jpg"
|
||||||
|
},
|
||||||
|
"period_8_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "8.jpg"
|
||||||
|
},
|
||||||
|
"period_9_image": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "9.jpg"
|
||||||
|
},
|
||||||
|
"period_source": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "network_location"
|
||||||
|
},
|
||||||
|
"location_refresh_intervals": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": 15
|
||||||
|
},
|
||||||
|
"latitude_auto": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"longitude_auto": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"latitude_custom": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"longitude_custom": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"period_0_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "00:00"
|
||||||
|
},
|
||||||
|
"period_1_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "05:00"
|
||||||
|
},
|
||||||
|
"period_2_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "07:00"
|
||||||
|
},
|
||||||
|
"period_3_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "09:00"
|
||||||
|
},
|
||||||
|
"period_4_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "11:00"
|
||||||
|
},
|
||||||
|
"period_5_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "13:00"
|
||||||
|
},
|
||||||
|
"period_6_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "15:00"
|
||||||
|
},
|
||||||
|
"period_7_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "17:00"
|
||||||
|
},
|
||||||
|
"period_8_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "19:00"
|
||||||
|
},
|
||||||
|
"period_9_custom_start_time": {
|
||||||
|
"type": "generic",
|
||||||
|
"default": "21:00"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1
cinnamon-dynamic-wallpaper@TobiZog/icon.svg
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
5.4/icons/icon.svg
|
||||||