Skip to content

Commit

Permalink
Add new loading overlay for dithering process (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
tfuxu authored Aug 24, 2024
2 parents 93fff08 + efdf706 commit 1a4b996
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 64 deletions.
4 changes: 4 additions & 0 deletions data/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ headerbar.desktop windowcontrols button:active image {
.sheet-toolbar {
padding: 12px;
}

.preview-loading-blur {
filter: blur(6px);
}
118 changes: 65 additions & 53 deletions data/ui/dither_page.blp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
}

Expand Down
42 changes: 31 additions & 11 deletions halftone/views/dither_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -117,9 +119,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)

Expand Down Expand Up @@ -176,8 +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):
self.on_awaiting_image_load()
run_delay: bool = True, callback: callable = None):
self.is_image_ready = False

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()
Expand All @@ -191,15 +195,16 @@ def update_preview_image(self, path: str, output_options: OutputOptions,
self.win.show_error_page()
raise

self.image_dithered.set_paintable(self.updated_paintable)
self.on_successful_image_load()
self.is_image_ready = True

if callback:
callback()

# 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:
Expand All @@ -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()
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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()
Expand All @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -384,12 +397,15 @@ 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.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)
Expand All @@ -415,6 +431,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)
Expand All @@ -425,6 +443,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)
Expand Down

0 comments on commit 1a4b996

Please sign in to comment.