Improving the architechture

This commit is contained in:
Roman 2023-08-09 12:17:28 +09:00
parent 69317daf18
commit a193295f6a
4 changed files with 168 additions and 119 deletions

View File

@ -2,22 +2,29 @@ import sys
from waypaper.app import App
from waypaper.changer import change_wallpaper
from waypaper.config import cf
__version__ = "1.1"
__version__ = "1.2"
def run():
"""Read user arguments and either run GUI app or just reset the wallpaper"""
app = App()
app.load_data()
# Set the wallpaper and quit:
if "--restore" in sys.argv:
if app.current_wallpaper is not None:
change_wallpaper(app.current_wallpaper, app.fill_option)
change_wallpaper(cf.current_wallpaper, cf.fill_option)
exit()
# Print the version and quit:
elif "--version" in sys.argv:
print(f"waypaper v.{__version__}")
exit()
# Start GUI:
else:
app = App()
app.run()

View File

@ -5,33 +5,36 @@ import os
import subprocess
import configparser
from waypaper.changer import change_wallpaper
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf, Gdk
from waypaper.changer import change_wallpaper
from waypaper.config import cf
def get_image_paths(root_folder, include_subfolders=False, depth=None):
"""Get a list of file paths depending of weather we include subfolders and how deep we scan"""
file_paths = []
for root, directories, files in os.walk(root_folder):
if not include_subfolders and root != root_folder:
continue
if depth is not None and root != root_folder:
current_depth = root.count(os.path.sep) - root_folder.count(os.path.sep)
if current_depth > depth:
continue
for filename in files:
if filename.endswith(".jpg") or filename.endswith(".png") or filename.endswith(".gif"):
file_paths.append(os.path.join(root, filename))
return file_paths
class App(Gtk.Window):
"""Main application class that controls GUI"""
selected_image_path = None
thumb_width = 240
default_fill_option = "fill"
config_dir = os.path.expanduser("~/.config/waypaper")
config_file_path = os.path.join(config_dir, "config.ini")
number_of_columns = 3
padding = 0
def __init__(self):
super().__init__(title="Waypaper")
self.set_default_size(780, 600)
# Create the configuration directory if it doesn't exist:
os.makedirs(self.config_dir, exist_ok=True)
# Create a vertical box for layout:
self.main_box = Gtk.VBox(spacing=10)
self.add(self.main_box)
@ -52,25 +55,32 @@ class App(Gtk.Window):
# Create a grid layout for images:
self.grid = Gtk.Grid()
self.grid.set_row_spacing(self.padding)
self.grid.set_column_spacing(self.padding)
self.grid.set_row_spacing(0)
self.grid.set_column_spacing(0)
self.scrolled_window.add(self.grid)
# Set default image folder:
self.default_image_folder = os.path.expanduser("~/Pictures")
# Create subfolder toggle:
self.include_subfolders_checkbox = Gtk.ToggleButton(label="Subfolders")
self.include_subfolders_checkbox.set_active(cf.include_subfolders)
self.include_subfolders_checkbox.connect("toggled", self.on_include_subfolders_toggled)
# Create a display option dropdown menu:
self.fill_option_label = Gtk.Label(label="Fill option:")
# Create a fill option dropdown menu:
# self.fill_option_label = Gtk.Label(label="")
self.fill_option_combo = Gtk.ComboBoxText()
self.fill_option_combo.append_text("stretch")
self.fill_option_combo.append_text("fit")
self.fill_option_combo.append_text("fill")
self.fill_option_combo.append_text("center")
self.fill_option_combo.append_text("tile")
self.fill_option_combo.set_active(2) # Default to "fill"
self.fill_option_combo.append_text("Fill")
self.fill_option_combo.append_text("Stretch")
self.fill_option_combo.append_text("Fit")
self.fill_option_combo.append_text("Center")
self.fill_option_combo.append_text("Tile")
self.fill_option_combo.set_active(0)
self.fill_option_combo.connect("changed", self.on_fill_option_changed)
# Create exit button:
self.exit_button = Gtk.Button(label=" Exit ")
self.exit_button.connect("clicked", self.on_exit_clicked)
# Create a box to contain the bottom row of buttons with margin
self.bottom_button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
self.bottom_button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
self.bottom_button_box.set_margin_bottom(10)
self.main_box.pack_end(self.bottom_button_box, False, False, 0)
@ -79,68 +89,20 @@ class App(Gtk.Window):
self.bottom_button_box.pack_start(self.button_row_alignment, True, False, 0)
# Create a horizontal box for display option and exit button
self.option_exit_box = Gtk.HBox(spacing=10)
self.option_exit_box.pack_start(self.fill_option_label, False, False, 0)
self.option_exit_box.pack_start(self.fill_option_combo, False, False, 0)
self.option_exit_box.pack_end(self.create_exit_button(), False, False, 0)
self.button_row_alignment.add(self.option_exit_box)
self.options_box = Gtk.HBox(spacing=10)
self.options_box.pack_start(self.include_subfolders_checkbox, False, False, 0)
# self.options_box.pack_start(self.fill_option_label, False, False, 0)
self.options_box.pack_start(self.fill_option_combo, False, False, 0)
self.options_box.pack_end(self.exit_button, False, False, 0)
self.button_row_alignment.add(self.options_box)
# Connect the "q" key press event to exit the application
self.connect("key-press-event", self.on_key_pressed)
def create_exit_button(self):
exit_button = Gtk.Button(label="Exit")
exit_button.connect("clicked", self.on_exit_clicked)
return exit_button
def load_data(self):
"""Load data from the config or use default if it does not exists"""
config = configparser.ConfigParser()
if os.path.exists(self.config_file_path):
config.read(self.config_file_path)
self.image_folder = config.get("Settings", "folder", fallback=self.default_image_folder)
self.fill_option = config.get("Settings", "fill", fallback=self.default_fill_option)
self.current_wallpaper = config.get("Settings", "wallpaper", fallback=None)
else:
self.image_folder = self.default_image_folder
def save_data(self):
"""Save the parameters to the configuration file"""
config = configparser.ConfigParser()
if os.path.exists(self.config_file_path):
config.read(self.config_file_path)
if not config.has_section("Settings"):
config.add_section("Settings")
# Save folder:
config.set("Settings", "folder", self.image_folder)
# Save selected wallpaper:
if self.selected_image_path is not None:
config.set("Settings", "wallpaper", self.selected_image_path)
# Save fill option:
fill_option = self.fill_option_combo.get_active_text() or self.default_fill_option
config.set("Settings", "fill", fill_option)
with open(self.config_file_path, "w") as configfile:
config.write(configfile)
def load_images(self):
"""Load images from the selected folder, resize them, and arrange int grid"""
if not os.path.exists(self.default_image_folder):
self.default_image_folder = "/"
if not os.path.exists(self.image_folder):
self.image_folder = self.default_image_folder
# Clear existing images:
for child in self.grid.get_children():
self.grid.remove(child)
@ -149,14 +111,13 @@ class App(Gtk.Window):
col = 0
# Load images from the folder:
for filename in os.listdir(self.image_folder):
if filename.endswith(".jpg") or filename.endswith(".png") or filename.endswith(".gif"):
image_path = os.path.join(self.image_folder, filename)
image_paths = get_image_paths(cf.image_folder, cf.include_subfolders, depth=1)
for image_path in image_paths:
# Load and scale the image:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(image_path)
aspect_ratio = pixbuf.get_width() / pixbuf.get_height()
scaled_width = self.thumb_width
scaled_width = 240
scaled_height = int(scaled_width / aspect_ratio)
scaled_pixbuf = pixbuf.scale_simple(scaled_width, scaled_height, GdkPixbuf.InterpType.BILINEAR)
@ -171,7 +132,7 @@ class App(Gtk.Window):
button.connect("clicked", self.on_image_clicked, image_path)
col += 1
if col >= self.number_of_columns:
if col >= 3:
col = 0
row += 1
@ -188,31 +149,41 @@ class App(Gtk.Window):
)
response = dialog.run()
if response == Gtk.ResponseType.OK:
self.image_folder = dialog.get_filename()
self.save_data()
cf.image_folder = dialog.get_filename()
cf.save()
self.load_images()
dialog.destroy()
def on_include_subfolders_toggled(self, toggle):
"""On chosing to include subfolders"""
cf.include_subfolders = toggle.get_active()
self.load_images()
def on_fill_option_changed(self, combo):
cf.fill_option = combo.get_active_text()
def on_image_clicked(self, widget, user_data):
"""On clicking an image, set it as a wallpaper and save"""
self.selected_image_path = user_data
print("Selected image path:", self.selected_image_path)
fill_option = self.fill_option_combo.get_active_text() or self.default_fill_option
change_wallpaper(self.selected_image_path, fill_option)
self.save_data()
cf.wallpaper = user_data
print("Selected image path:", cf.wallpaper)
cf.fill_option = self.fill_option_combo.get_active_text() or cf.fill_option
change_wallpaper(cf.wallpaper, cf.fill_option)
cf.save()
def on_exit_clicked(self, widget):
"""On clicking exit button, save the data and quit"""
self.save_data()
cf.save()
Gtk.main_quit()
def on_key_pressed(self, widget, event):
"""On clicking q, save the data and quit"""
if event.keyval == Gdk.KEY_q:
self.save_data()
cf.save()
Gtk.main_quit()

View File

@ -5,7 +5,7 @@ import subprocess
def change_wallpaper(image_path, fill_option):
"""Run a system command swaybg -i image_path -m fill_option &"""
try:
subprocess.Popen(["swaybg", "-i", image_path, "-m", fill_option])
subprocess.Popen(["swaybg", "-i", image_path, "-m", fill_option.lower()])
print("Wallpaper changed successfully.")
except Exception as e:
print("Error changing wallpaper:", e)

71
waypaper/config.py Normal file
View File

@ -0,0 +1,71 @@
"""Module responsible for taking care of configuration file"""
import configparser
import pathlib
import os
class Config:
"""User configuration loaded from the config.ini file"""
def __init__(self):
self.image_folder = str(pathlib.Path.home())
if os.path.exists(str(pathlib.Path.home()) + "/Pictures"):
self.image_folder = str(pathlib.Path.home()) + "/Pictures"
self.wallpaper = None
self.fill_option = "fill"
self.include_subfolders = False
self.config_folder = str(pathlib.Path.home()) + "/.config/waypaper"
self.config_file = self.config_folder + "/config.ini"
def create(self):
"""Create a default config.ini file if it does not exist"""
config = configparser.ConfigParser()
config["Settings"] = {
"folder": str(self.image_folder),
"fill": str(self.fill_option),
"subfolders": str(self.include_subfolders),
"wallpaper": str(self.wallpaper),
}
with open(cf.config_file, "w") as configfile:
config.write(configfile)
def read(self):
"""Load data from the config.ini or use default if it does not exists"""
try:
config = configparser.ConfigParser()
config.read(self.config_file, 'utf-8')
self.image_folder = config.get("Settings", "folder", fallback=self.image_folder)
self.wallpaper = config.get("Settings", "wallpaper", fallback=self.wallpaper)
self.fill_option = config.get("Settings", "fill", fallback=self.fill_option)
self.include_subfolders = config.getboolean("Settings", "subfolders", fallback=self.include_subfolders)
except Exception as e:
print(e)
exit()
def save(self):
"""Save the parameters to the configuration file"""
config = configparser.ConfigParser()
config.read(self.config_file)
config.set("Settings", "folder", cf.image_folder)
config.set("Settings", "wallpaper", cf.wallpaper)
config.set("Settings", "fill", cf.fill_option)
config.set("Settings", "subfolders", str(cf.include_subfolders))
with open(cf.config_file, "w") as configfile:
config.write(configfile)
cf = Config()
# Create config folder:
if not os.path.exists(cf.config_folder):
os.makedirs(cf.config_folder)
# Create config file:
if not os.path.exists(cf.config_file):
cf.create()
# Read config file:
cf.read()