From b9f3e86a5195b446dddb4acc1d73926b5bd4be0d Mon Sep 17 00:00:00 2001 From: tfuxu <73042332+tfuxu@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:41:15 +0200 Subject: [PATCH 1/5] feat: add new loading overlay for dithering process --- data/ui/dither_page.blp | 118 +++++++++++++++++++--------------- halftone/views/dither_page.py | 12 ++-- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/data/ui/dither_page.blp b/data/ui/dither_page.blp index ced48ae..0c332d6 100644 --- a/data/ui/dither_page.blp +++ b/data/ui/dither_page.blp @@ -82,69 +82,81 @@ template $HalftoneDitherPage: Adw.BreakpointBin { vexpand: true; hexpand: true; - Gtk.Stack preview_group_stack { - height-request: 150; - transition-type: crossfade; - - Gtk.StackPage { - name: "preview_stack_main_page"; - - child: Gtk.Overlay { - child: Gtk.ScrolledWindow preview_scroll_window { - vexpand: true; - hexpand: true; - - Gtk.Picture image_dithered { - content-fit: cover; - can-shrink: false; - halign: center; - valign: center; - } - }; - - [overlay] - Gtk.Button toggle_sheet_button { - halign: start; - valign: end; - icon-name: "sidebar-show-left-symbolic"; - action-name: "app.toggle-sheet"; - tooltip-text: _("Toggle Sidebar"); - - styles [ - "osd", - "circular", - "custom-on-image" - ] - } - - [overlay] - Gtk.Button { - halign: end; - valign: end; - icon-name: "adw-external-link-symbolic"; - tooltip-text: _("Open in External Image Viewer"); - action-name: "app.show-preview-image"; - - styles [ - "osd", - "circular", - "custom-on-image" - ] + Gtk.Overlay { + child: Gtk.Overlay { + child: Gtk.ScrolledWindow preview_scroll_window { + vexpand: true; + hexpand: true; + + Gtk.Picture image_dithered { + content-fit: cover; + can-shrink: false; + halign: center; + valign: center; } }; - } - Gtk.StackPage { - name: "preview_stack_loading_page"; + [overlay] + Gtk.Button toggle_sheet_button { + halign: start; + valign: end; + icon-name: "sidebar-show-left-symbolic"; + action-name: "app.toggle-sheet"; + tooltip-text: _("Toggle Sidebar"); + + styles [ + "osd", + "circular", + "custom-on-image" + ] + } + + [overlay] + Gtk.Button { + halign: end; + valign: end; + icon-name: "adw-external-link-symbolic"; + tooltip-text: _("Open in External Image Viewer"); + action-name: "app.show-preview-image"; + + styles [ + "osd", + "circular", + "custom-on-image" + ] + } + }; + + [overlay] + Gtk.Box preview_loading_overlay { + vexpand: true; + hexpand: true; + orientation: vertical; + visible: false; - child: Gtk.Box { + Gtk.Box { + vexpand: true; + hexpand: true; valign: center; halign: center; + spacing: 10; + orientation: vertical; Gtk.Spinner { + height-request: 64; + width-request: 64; + spinning: true; } - }; + + Gtk.Label { + label: _("Dithering your imageā€¦"); + } + } + + styles [ + "osd" + ] } } diff --git a/halftone/views/dither_page.py b/halftone/views/dither_page.py index 48f7b13..d816b67 100644 --- a/halftone/views/dither_page.py +++ b/halftone/views/dither_page.py @@ -57,7 +57,7 @@ class HalftoneDitherPage(Adw.BreakpointBin): save_image_chooser = Gtk.Template.Child() all_filter = Gtk.Template.Child() - preview_group_stack = Gtk.Template.Child() + preview_loading_overlay = Gtk.Template.Child() mobile_breakpoint = Gtk.Template.Child() @@ -117,9 +117,6 @@ def setup_signals(self): self.update_preview_content_fit) def setup(self): - # Set default preview stack child - self.preview_group_stack.set_visible_child_name("preview_stack_loading_page") - # Set utility page in sidebar by default self.sidebar_view.set_content(self.image_prefs_bin) @@ -192,7 +189,6 @@ def update_preview_image(self, path: str, output_options: OutputOptions, raise self.image_dithered.set_paintable(self.updated_paintable) - self.on_successful_image_load() if callback: callback() @@ -384,11 +380,13 @@ def on_save_format_selected(self, widget, *args): self.output_options.output_format = format_string def on_successful_image_load(self, *args): - self.preview_group_stack.set_visible_child_name("preview_stack_main_page") + self.preview_loading_overlay.set_visible(False) + self.image_dithered.remove_css_class("preview-loading-blur") self.save_image_button.set_sensitive(True) def on_awaiting_image_load(self, *args): - self.preview_group_stack.set_visible_child_name("preview_stack_loading_page") + self.preview_loading_overlay.set_visible(True) + self.image_dithered.add_css_class("preview-loading-blur") self.save_image_button.set_sensitive(False) def on_breakpoint_apply(self, *args): From ac0a3a34bcff54bce03c0cb0dbb4345a489a3940 Mon Sep 17 00:00:00 2001 From: tfuxu <73042332+tfuxu@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:20:37 +0200 Subject: [PATCH 2/5] fix: set paintables to previewer directly in `set_*_paintable` methods --- halftone/views/dither_page.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/halftone/views/dither_page.py b/halftone/views/dither_page.py index d816b67..7e5e336 100644 --- a/halftone/views/dither_page.py +++ b/halftone/views/dither_page.py @@ -188,8 +188,6 @@ def update_preview_image(self, path: str, output_options: OutputOptions, self.win.show_error_page() raise - self.image_dithered.set_paintable(self.updated_paintable) - if callback: callback() @@ -413,6 +411,8 @@ def set_original_paintable(self, path: str): self.win.latest_traceback = logging.get_traceback(e) raise + self.image_dithered.set_paintable(self.original_paintable) + def set_updated_paintable(self, path: str): try: self.updated_paintable = Gdk.Texture.new_from_filename(path) @@ -423,6 +423,8 @@ def set_updated_paintable(self, path: str): self.win.latest_traceback = logging.get_traceback(e) raise + self.image_dithered.set_paintable(self.updated_paintable) + def clean_preview_paintable(self): try: HalftoneTempFile().delete_temp_file(self.preview_image_path) From fbbac44ca053ad03d27d29511640a966c226780f Mon Sep 17 00:00:00 2001 From: tfuxu <73042332+tfuxu@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:25:04 +0200 Subject: [PATCH 3/5] feat: add blur to preview loading overlay --- data/style.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/data/style.css b/data/style.css index f067a38..c607120 100644 --- a/data/style.css +++ b/data/style.css @@ -25,3 +25,7 @@ headerbar.desktop windowcontrols button:active image { .sheet-toolbar { padding: 12px; } + +.preview-loading-blur { + filter: blur(6px); +} From 75d817b253ed7b3430e32770d024d6a32f9119c8 Mon Sep 17 00:00:00 2001 From: tfuxu <73042332+tfuxu@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:31:55 +0200 Subject: [PATCH 4/5] feat: add visibility delay to loading overlay Currently set to 2 seconds --- halftone/views/dither_page.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/halftone/views/dither_page.py b/halftone/views/dither_page.py index 7e5e336..04c8b7a 100644 --- a/halftone/views/dither_page.py +++ b/halftone/views/dither_page.py @@ -72,6 +72,7 @@ def __init__(self, parent, **kwargs): self.toast_overlay = self.parent.toast_overlay + self.is_image_ready: bool = False self.is_mobile: bool = False self.origin_x: float = None @@ -89,6 +90,7 @@ def __init__(self, parent, **kwargs): self.output_options: OutputOptions = OutputOptions() self.keep_aspect_ratio = True + self.loading_overlay_delay = 2000 # In miliseconds self.setup_signals() self.setup() @@ -174,7 +176,8 @@ def preview_drag_update(self, widget, offset_x: float, offset_y: float, *args): def update_preview_image(self, path: str, output_options: OutputOptions, callback: callable = None): - self.on_awaiting_image_load() + self.is_image_ready = False + GLib.timeout_add(self.loading_overlay_delay, self.on_awaiting_image_load) if self.preview_image_path: self.clean_preview_paintable() @@ -188,6 +191,9 @@ def update_preview_image(self, path: str, output_options: OutputOptions, self.win.show_error_page() raise + self.on_successful_image_load() + self.is_image_ready = True + if callback: callback() @@ -383,9 +389,10 @@ def on_successful_image_load(self, *args): self.save_image_button.set_sensitive(True) def on_awaiting_image_load(self, *args): - self.preview_loading_overlay.set_visible(True) - self.image_dithered.add_css_class("preview-loading-blur") - self.save_image_button.set_sensitive(False) + if not self.is_image_ready: + self.preview_loading_overlay.set_visible(True) + self.image_dithered.add_css_class("preview-loading-blur") + self.save_image_button.set_sensitive(False) def on_breakpoint_apply(self, *args): self.sidebar_view.set_content(None) From efdf7063c455eae3d45bb0290605fb3c880adb08 Mon Sep 17 00:00:00 2001 From: tfuxu <73042332+tfuxu@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:34:35 +0200 Subject: [PATCH 5/5] fix: disable delay when loading a new image --- halftone/views/dither_page.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/halftone/views/dither_page.py b/halftone/views/dither_page.py index 04c8b7a..88fcb5e 100644 --- a/halftone/views/dither_page.py +++ b/halftone/views/dither_page.py @@ -175,9 +175,13 @@ def preview_drag_update(self, widget, offset_x: float, offset_y: float, *args): """ Main functions """ def update_preview_image(self, path: str, output_options: OutputOptions, - callback: callable = None): + run_delay: bool = True, callback: callable = None): self.is_image_ready = False - GLib.timeout_add(self.loading_overlay_delay, self.on_awaiting_image_load) + + if run_delay: + GLib.timeout_add(self.loading_overlay_delay, self.on_awaiting_image_load) + else: + self.on_awaiting_image_load() if self.preview_image_path: self.clean_preview_paintable() @@ -200,6 +204,7 @@ def update_preview_image(self, path: str, output_options: OutputOptions, # NOTE: Use this only if you initially load the picture (eg. from file chooser) def load_preview_image(self, file: Gio.File): self.input_image_path = file.get_path() + try: self.set_original_paintable(self.input_image_path) except GLib.GError: @@ -208,13 +213,15 @@ def load_preview_image(self, file: Gio.File): self.set_size_spins(self.original_paintable.get_width(), self.original_paintable.get_height()) + self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + False, self.on_successful_image_load) def save_image(self, paintable: Gdk.Paintable, output_path: str, - output_options: OutputOptions, callback: callable): + output_options: OutputOptions, callback: callable): self.win.show_loading_page() image_bytes = paintable.save_to_tiff_bytes() @@ -248,6 +255,7 @@ def on_color_amount_changed(self, widget): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) @Gtk.Template.Callback() @@ -262,6 +270,7 @@ def on_brightness_changed(self, widget): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) @Gtk.Template.Callback() @@ -276,6 +285,7 @@ def on_contrast_changed(self, widget): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) @Gtk.Template.Callback() @@ -299,6 +309,7 @@ def on_image_width_changed(self, widget): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) @Gtk.Template.Callback() @@ -315,6 +326,7 @@ def on_image_height_changed(self, widget): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) def on_save_image(self, *args): @@ -375,6 +387,7 @@ def on_dither_algorithm_selected(self, widget, *args): self.start_task(self.update_preview_image, self.input_image_path, self.output_options, + True, self.on_successful_image_load) def on_save_format_selected(self, widget, *args):