Adding options menu

This creates a more compact menu, and also addresse partly issue #41
This commit is contained in:
Anufriev Roman 2024-05-19 11:48:11 +09:00
parent 8b197a7141
commit e20290e683
5 changed files with 105 additions and 42 deletions

View File

@ -18,7 +18,7 @@ setuptools.setup(
]
},
install_requires=["PyGObject", "importlib_metadata", "platformdirs", "Pillow"],
version='2.1.3',
version='2.2',
python_requires='>3.9',
classifiers=[
"Development Status :: 4 - Beta",

View File

@ -94,12 +94,6 @@ class App(Gtk.Window):
self.grid.set_column_spacing(0)
self.scrolled_window.add(self.grid)
# Create subfolder toggle:
self.include_subfolders_checkbox = Gtk.ToggleButton(label=self.txt.msg_subfolders)
self.include_subfolders_checkbox.set_active(self.cf.include_subfolders)
self.include_subfolders_checkbox.connect("toggled", self.on_include_subfolders_toggled)
self.include_subfolders_checkbox.set_tooltip_text(self.txt.tip_subfolder)
# Create a backend dropdown menu:
self.backend_option_combo = Gtk.ComboBoxText()
for backend in self.cf.installed_backends:
@ -140,7 +134,6 @@ class App(Gtk.Window):
self.sort_option_combo.connect("changed", self.on_sort_option_changed)
self.sort_option_combo.set_tooltip_text(self.txt.tip_sorting)
# Create exit button:
self.exit_button = Gtk.Button(label=self.txt.msg_exit)
self.exit_button.connect("clicked", self.on_exit_clicked)
@ -173,12 +166,16 @@ class App(Gtk.Window):
# Create a monitor option dropdown menu:
self.monitor_option_combo = Gtk.ComboBoxText()
# Create the options menu button:
self.options_button = Gtk.Button(label="Options")
self.options_button.connect("clicked", self.on_options_button_clicked)
# Create a horizontal box for display option and exit button:
self.options_box = Gtk.HBox(spacing=10)
self.options_box.pack_end(self.exit_button, False, False, 0)
self.options_box.pack_end(self.options_button, False, False, 0)
self.options_box.pack_end(self.refresh_button, False, False, 0)
self.options_box.pack_end(self.random_button, False, False, 0)
self.options_box.pack_end(self.include_subfolders_checkbox, False, False, 0)
self.options_box.pack_end(self.sort_option_combo, False, False, 0)
self.options_box.pack_end(self.color_picker_button, False, False, 0)
self.options_box.pack_end(self.fill_option_combo, False, False, 0)
@ -192,6 +189,37 @@ class App(Gtk.Window):
self.show_all()
def create_menu(self):
"""Create a GTK menu and items inside it"""
self.menu = Gtk.Menu()
# Create gifs toggle:
self.filter_gifs_checkbox = Gtk.CheckMenuItem(label=self.txt.msg_gifs)
self.filter_gifs_checkbox.set_active(self.cf.show_gifs_only)
self.filter_gifs_checkbox.connect("toggled", self.on_filter_gifs_toggled)
# Create subfolder toggle:
self.include_subfolders_checkbox = Gtk.CheckMenuItem(label=self.txt.msg_subfolders)
self.include_subfolders_checkbox.set_active(self.cf.include_subfolders)
self.include_subfolders_checkbox.connect("toggled", self.on_include_subfolders_toggled)
# Create hidden toggle:
self.include_hidden_checkbox = Gtk.CheckMenuItem(label=self.txt.msg_hidden)
self.include_hidden_checkbox.set_active(self.cf.show_hidden)
self.include_hidden_checkbox.connect("toggled", self.on_hidden_files_toggled)
self.menu.append(self.filter_gifs_checkbox)
self.menu.append(self.include_subfolders_checkbox)
self.menu.append(self.include_hidden_checkbox)
self.menu.show_all()
def on_options_button_clicked(self, widget):
'''Position the menu at the button and show it'''
self.create_menu()
self.menu.popup_at_widget(widget, Gdk.Gravity.NORTH, Gdk.Gravity.SOUTH, None)
def monitor_option_display(self):
"""Display monitor option if backend is swww"""
self.options_box.remove(self.monitor_option_combo)
@ -257,7 +285,8 @@ class App(Gtk.Window):
def process_images(self):
"""Load images from the selected folder, resize them, and arrange into a grid"""
self.image_paths = get_image_paths(self.cf.backend, self.cf.image_folder, self.cf.include_subfolders, self.cf.show_hidden, depth=1)
self.image_paths = get_image_paths(self.cf.backend, self.cf.image_folder, self.cf.include_subfolders,
self.cf.show_hidden, self.cf.show_gifs_only, depth=1)
self.sort_images()
# Show caching label:
@ -338,7 +367,6 @@ class App(Gtk.Window):
def choose_folder(self):
"""Choosing the folder of images, saving the path, and reloading images"""
dialog = Gtk.FileChooserDialog(
self.txt.msg_choosefolder, self, Gtk.FileChooserAction.SELECT_FOLDER,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, self.txt.msg_select, Gtk.ResponseType.OK)
@ -356,12 +384,36 @@ class App(Gtk.Window):
self.cf.save()
def on_filter_gifs_toggled(self, toggle):
"""Toggle only gifs checkbox via menu"""
self.cf.show_gifs_only = toggle.get_active()
threading.Thread(target=self.process_images).start()
def on_include_subfolders_toggled(self, toggle):
"""On chosing to include subfolders"""
"""Toggle subfolders visibility via menu"""
self.cf.include_subfolders = toggle.get_active()
threading.Thread(target=self.process_images).start()
def toggle_include_subfolders(self):
"""Toggle subfolders visibility via key"""
self.cf.include_subfolders = not self.cf.include_subfolders
threading.Thread(target=self.process_images).start()
def on_hidden_files_toggled(self, toggle):
"""Toggle visibility of hidden files via menu"""
self.cf.show_hidden = toggle.get_active()
threading.Thread(target=self.process_images).start()
def toggle_hidden_files(self):
"""Toggle visibility of hidden files via keys"""
self.cf.show_hidden = not self.cf.show_hidden
threading.Thread(target=self.process_images).start()
def on_fill_option_changed(self, combo):
"""Save fill parameter when it was changed"""
self.cf.fill_option = combo.get_active_text()
@ -436,13 +488,6 @@ class App(Gtk.Window):
self.cf.save()
def toggle_hidden_files(self):
"""Toggle visibility of hidden files"""
self.cf.show_hidden = not self.cf.show_hidden
threading.Thread(target=self.process_images).start()
self.cf.save()
def clear_cache(self):
"""Delete cache folder and reprocess the images"""
try:
@ -467,6 +512,9 @@ class App(Gtk.Window):
elif event.keyval in [Gdk.KEY_period]:
self.toggle_hidden_files()
elif event.keyval in [Gdk.KEY_s]:
self.toggle_include_subfolders()
elif event.keyval in [Gdk.KEY_h, Gdk.KEY_Left]:
self.selected_index = max(self.selected_index - 1, 0)
self.load_image_grid()
@ -514,7 +562,7 @@ class App(Gtk.Window):
self.cf.save()
# Prevent other default key handling:
if event.keyval in [Gdk.KEY_Up, Gdk.KEY_Down, Gdk.KEY_Left, Gdk.KEY_Right, Gdk.KEY_Return, Gdk.KEY_KP_Enter]:
if event.keyval in [Gdk.KEY_Up, Gdk.KEY_Down, Gdk.KEY_Left, Gdk.KEY_Right, Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_period]:
return True

View File

@ -13,18 +13,14 @@ def has_image_extension(file_path, backend):
return ext in image_extensions
def get_image_paths(backend, root_folder, include_subfolders=False, include_hidden=False, depth=None):
"""Get a list of file paths depending of weather we include subfolders and how deep we scan"""
def get_image_paths(backend, root_folder, include_subfolders=False, include_hidden=False, only_gifs=False, depth=None):
"""Get a list of file paths depending on the filters that were requested"""
image_paths = []
for root, directories, files in os.walk(root_folder):
# Remove hidden files from consideration:
for directory in directories:
if directory.startswith('.') and not include_hidden:
directories.remove(directory)
for file in files:
if file.startswith('.') and not include_hidden:
files.remove(file)
# Remove subfolders from consideration:
if not include_subfolders and str(root) != str(root_folder):
@ -38,16 +34,21 @@ def get_image_paths(backend, root_folder, include_subfolders=False, include_hidd
# Remove files that are not images from consideration:
for filename in files:
if filename.startswith('.') and not include_hidden:
continue
if not has_image_extension(filename, backend):
continue
if not filename.endswith('.gif') and only_gifs:
continue
image_paths.append(os.path.join(root, filename))
# print(root, directories, files)
return image_paths
def get_random_file(backend, folder, include_subfolders, include_hidden=False):
"""Pick a random file from the folder"""
try:
image_paths = get_image_paths(backend, folder, include_subfolders, include_hidden, depth=1)
image_paths = get_image_paths(backend, folder, include_subfolders, include_hidden, only_gifs=False, depth=1)
return random.choice(image_paths)
except:
return None

View File

@ -34,6 +34,7 @@ class Config:
self.post_command = ""
self.include_subfolders = False
self.show_hidden = False
self.show_gifs_only = False
self.about = AboutData()
self.cache_dir = user_cache_path(self.about.applicationName())
self.config_dir = user_config_path(self.about.applicationName())
@ -73,6 +74,7 @@ class Config:
self.lang = config.get("Settings", "language", fallback=self.lang)
self.include_subfolders = config.getboolean("Settings", "subfolders", fallback=self.include_subfolders)
self.show_hidden = config.getboolean("Settings", "show_hidden", fallback=self.show_hidden)
self.show_gifs_only = config.getboolean("Settings", "show_gifs_only", fallback=self.show_gifs_only)
self.monitors_str = config.get("Settings", "monitors", fallback=self.selected_monitor, raw=True)
self.wallpapers_str = config.get("Settings", "wallpaper", fallback="", raw=True)
self.number_of_columns = config.get("Settings", "number_of_columns", fallback=self.number_of_columns)
@ -107,10 +109,10 @@ class Config:
if 0 > int(self.swww_transition_duration):
self.swww_transition_duration = 2
def save(self):
"""Update the parameters and save them to the configuration file"""
# If only certain monitor was affected, change only its wallpaper:
def attribute_selected_wallpaper(self):
"""If only certain monitor was affected, change only its wallpaper"""
if self.selected_wallpaper == "":
return
if self.selected_monitor == "All":
self.monitors = [self.selected_monitor]
self.wallpapers = [self.shorten_path(self.selected_wallpaper)]
@ -121,6 +123,11 @@ class Config:
self.monitors.append(self.selected_monitor)
self.wallpapers.append(self.shorten_path(self.selected_wallpaper))
def save(self):
"""Update the parameters and save them to the configuration file"""
self.attribute_selected_wallpaper()
# Write configuration to the file:
config = configparser.ConfigParser()
config.read(self.config_file)
@ -136,6 +143,7 @@ class Config:
config.set("Settings", "color", self.color)
config.set("Settings", "subfolders", str(self.include_subfolders))
config.set("Settings", "show_hidden", str(self.show_hidden))
config.set("Settings", "show_gifs_only", str(self.show_gifs_only))
config.set("Settings", "post_command", self.post_command)
config.set("Settings", "number_of_columns", str(self.number_of_columns))
config.set("Settings", "swww_transition_type", str(self.swww_transition_type))

View File

@ -17,7 +17,9 @@ class English:
self.msg_refresh = "Refresh"
self.msg_random = "Random"
self.msg_exit = "Exit"
self.msg_subfolders = "Subfolders"
self.msg_subfolders = "Show subfolders"
self.msg_hidden = "Show hidden"
self.msg_gifs = "Show gifs only"
self.msg_changefolder = "Change wallpaper folder"
self.msg_choosefolder = "Please choose a folder"
self.msg_caching = "Caching wallpapers..."
@ -25,7 +27,7 @@ class English:
self.msg_help = "Waypaper's hotkeys:\n\nhjkl - Navigation (←↓↑→)\nEnter - Set selected wallpaper\nf - Change wallpaper folder\n"
self.msg_help += "g - Scroll to top\nG - Scroll to bottom\nR - Set random wallpaper\nr - Recache wallpapers\n"
self.msg_help += ". - Include/exclude hidden images\ns - Include/exclude images in subfolders\n? - Help\nq - Exit\n\n"
self.msg_help += ". - Toggle hidden images\ns - Toggle images in subfolders\n? - Help\nq - Exit\n\n"
self.msg_help += self.msg_info
self.err_cache = "Error deleting cache"
@ -39,7 +41,6 @@ class English:
self.err_disp = "Error determining monitor names:"
self.err_kill = "Warning related to killall:"
self.tip_subfolder = "Include/exclude images in subfolders"
self.tip_refresh = "Recache the folder of images"
self.tip_fill = "Choose fill type"
self.tip_backend = "Choose backend"
@ -67,6 +68,8 @@ class German:
self.msg_random = "Zufällig"
self.msg_exit = "Beenden"
self.msg_subfolders = "Unterordner"
self.msg_hidden = "Hidden"
self.msg_gifs = "Show only gifs"
self.msg_changefolder = "Hintergrundbild-Ordner ändern"
self.msg_choosefolder = "Bitte wählen Sie einen Ordner aus"
self.msg_caching = "Hintergrundbilder werden zwischengespeichert..."
@ -88,7 +91,6 @@ class German:
self.err_disp = "Fehler beim Ermitteln der Monitor-Namen:"
self.err_kill = "Warnung im Zusammenhang mit dem Befehl killall:"
self.tip_subfolder = "Wählen, ob Unterordner mit einbezogen werden sollen"
self.tip_refresh = "Erneutes einlesen des Hintergrundbild-Ordners"
self.tip_fill = "Skalierungsart auswählen"
self.tip_backend = "Backend auswählen"
@ -116,6 +118,8 @@ class French:
self.msg_random = "Aléatoire"
self.msg_exit = "Quitter"
self.msg_subfolders = "Sous-dossiers"
self.msg_hidden = "Hidden"
self.msg_gifs = "Show only gifs"
self.msg_changefolder = "Changer de dossier de papier peint"
self.msg_choosefolder = "Veuillez choisir un dossier"
self.msg_caching = "Mise en cache des papiers peints..."
@ -137,7 +141,6 @@ class French:
self.err_disp = "Erreur lors de la détermination des noms des moniteurs :"
self.err_kill = "Avertissement lié à killall :"
self.tip_subfolder = "Inclure/exclure les images des sous-dossiers"
self.tip_refresh = "Recréer le dossier d'images"
self.tip_fill = "Choisir le type de remplissage"
self.tip_backend = "Choisir le backend"
@ -165,6 +168,8 @@ class Polish:
self.msg_random = "Losowo"
self.msg_exit = "Wyjście"
self.msg_subfolders = "Podkatalogi"
self.msg_hidden = "Hidden"
self.msg_gifs = "Show only gifs"
self.msg_changefolder = "Zmień folder z tapetami"
self.msg_choosefolder = "Proszę wybrać folder"
self.msg_caching = "Kasowanie tapet..."
@ -186,7 +191,6 @@ class Polish:
self.err_disp = "Błąd podczas określania nazw monitorów:"
self.err_kill = "Ostrzeżenie związane z poleceniem killall:"
self.tip_subfolder = "Dołącz/wyłącz obrazy z podkatalogów"
self.tip_refresh = "Odśwież folder z obrazami"
self.tip_fill = "Wybierz typ wypełnienia"
self.tip_backend = "Wybierz backend"
@ -213,7 +217,9 @@ class Russian:
self.msg_refresh = "Обновить"
self.msg_random = "Случайно"
self.msg_exit = "Выход"
self.msg_subfolders = "Подпапки"
self.msg_subfolders = "Показать подпапки"
self.msg_hidden = "Показать скрытые"
self.msg_gifs = "Показать только gif"
self.msg_changefolder = "Изменить папку с обоями"
self.msg_choosefolder = "Пожалуйста, выберите папку"
self.msg_caching = "Кэширование обоев..."
@ -221,12 +227,12 @@ class Russian:
self.msg_help = "Горячие клавиши Waypaper:\n\nhjkl - Навигация (←↓↑→)\nf - Изменить папку с обоями\n"
self.msg_help += "g - Прокрутка в начало\nG - Прокрутка в конец\nR - Установить случайные обои\nr - Обновить кэш обоев\n"
self.msg_help += ". - Включить/исключить скрытые файлы \ns - Включить/исключить подпапки\n? - Справка\nq - Выход\n\n"
self.msg_help += ". - Показать/скрыть скрытые файлы \ns - Показать/скрыть вложенные папки\n? - Справка\nq - Выход\n\n"
self.msg_help += self.msg_info
self.err_cache = "Ошибка при удалении кэша"
self.err_backend = "Похоже, что ни один из бэкендов для установки обоев не установлен в системе.\n"
self.err_backend += "Используйте менеджер пакетов для установки хотя бы одного из этих бэкендов:\n\n"
self.err_backend += "Используйте менеджер пакетов для установки хотя бы одного из следующих бэкендов:\n\n"
self.err_backend += "- swaybg (для Wayland)\n- swww (для Wayland)\n"
self.err_backend += "- feh (для Xorg)\n- wallutils (для Xorg и Wayland)\n\n"
self.err_backend += self.msg_info
@ -235,7 +241,6 @@ class Russian:
self.err_disp = "Ошибка определения названий мониторов:"
self.err_kill = "Предупреждение связанное с killall:"
self.tip_subfolder = "Включить/отключить изображения в подпапках"
self.tip_refresh = "Обновить папку с изображениями"
self.tip_fill = "Выбрать тип заполнения"
self.tip_backend = "Выбрать бэкенд"
@ -263,6 +268,8 @@ class Chinese:
self.msg_random = "随机"
self.msg_exit = "退出"
self.msg_subfolders = "子文件夹"
self.msg_hidden = "Show hidden"
self.msg_gifs = "Show only gifs"
self.msg_changefolder = "更改壁纸文件夹"
self.msg_choosefolder = "请选择一个文件夹"
self.msg_caching = "缓存壁纸..."
@ -284,7 +291,6 @@ class Chinese:
self.err_disp = "确定监视器名称时出错:"
self.err_kill = "与killall相关的警告"
self.tip_subfolder = "在子文件夹中包含/排除图像"
self.tip_refresh = "重新缓存图像文件夹"
self.tip_fill = "选择填充类型"
self.tip_backend = "选择后端"