summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-07-21 18:54:08 +0300
committerPaul Buetow <paul@buetow.org>2026-07-21 18:54:08 +0300
commit11f8bc04255c9889ac7380dd3675ba6c10c5f2e3 (patch)
tree50cad8456d8be1c466b5e24e23ddd668b209c711 /src
parentcfda8297cc4432a77e3f7e8679753a908e9f5759 (diff)
enhance: 'a' opens a preset menu with number hotkeys (1-9, 0) instead of cycling
Replace the a=cycle behavior with a GtkPopover listing the presets as rows (1 Auto-fix, 2 Brightness, ... 8 Denoise, 0 Original). Click a row or press its digit to apply that preset as the live preview; Escape or 'a' again closes. Refactored the apply logic into _apply_enhance(idx) shared by the menu and (unchanged) win.enhance-save. The popover is parented to the overlay and torn down on the 'closed' signal. The ? overlay Enhance group now documents the menu.
Diffstat (limited to 'src')
-rw-r--r--src/window.c163
1 files changed, 135 insertions, 28 deletions
diff --git a/src/window.c b/src/window.c
index 4e4e253..4ac7fae 100644
--- a/src/window.c
+++ b/src/window.c
@@ -52,8 +52,9 @@ struct _GgazeWindow {
gboolean b_fullscreen;
guint u_hdr_hide; /* fullscreen header auto-hide timeout */
#if GGAZE_HAVE_GEGL
- int i_enhance_idx; /* active preset index (-1 = original) */
- Enhancer *p_enhancer; /* GEGL preset engine (NULL w/o GEGL) */
+ int i_enhance_idx; /* active preset index (-1 = original) */
+ Enhancer *p_enhancer; /* GEGL preset engine (NULL w/o GEGL) */
+ GtkWidget *p_enhance_pop; /* the enhance popup (NULL when closed) */
#endif
};
@@ -455,8 +456,8 @@ static const char *SHORTCUTS_UI =
" <child>\n"
" <object class=\"GtkShortcutsShortcut\">\n"
" <property name=\"accelerator\">a</property>\n"
- " <property name=\"title\">Cycle enhance preset "
- "(preview)</property>\n"
+ " <property name=\"title\">Enhance menu (then 1-9 pick a "
+ "preset, 0 = Original)</property>\n"
" </object>\n"
" </child>\n"
" <child>\n"
@@ -610,52 +611,46 @@ _action_back(GSimpleAction *p_a, GVariant *p_v, gpointer p_data) {
}
#if GGAZE_HAVE_GEGL
-/* win.enhance (key 'a'): cycle the active enhance preset and preview it on
- * the current image. Synchronous - may briefly block the UI on large images
- * (acceptable for v1; async apply is a later milestone). On any failure reset
- * to the original. */
+/* Apply preset i_idx to the current image as a live preview (i_idx = -1 =>
+ * restore the original). Switches to large view so the result shows. On any
+ * failure resets to the original. Synchronous - may briefly block the UI on
+ * large images (async apply is a later milestone). */
static void
-_action_enhance(GSimpleAction *p_a, GVariant *p_v, gpointer p_data) {
- (void)p_a;
- (void)p_v;
- GgazeWindow *p_win = GGAZE_WINDOW(p_data);
+_apply_enhance(GgazeWindow *p_win, gint i_idx) {
if (p_win->p_nav == NULL || p_win->p_enhancer == NULL) {
return;
}
- /* Only meaningful in large view; switch there first so the result shows. */
const char *c_cur =
gtk_stack_get_visible_child_name(GTK_STACK(p_win->p_stack));
if (g_strcmp0(c_cur, "large") != 0) {
gtk_stack_set_visible_child_name(GTK_STACK(p_win->p_stack), "large");
}
-
- const GPtrArray *p_presets = enhancer_get_presets(p_win->p_enhancer);
- gint i_n = (gint)(p_presets != NULL ? p_presets->len : 0);
- gint i_next = p_win->i_enhance_idx + 1;
- if (i_next >= i_n) {
- i_next = -1; /* wrap back to original */
- }
- p_win->i_enhance_idx = i_next;
-
- if (i_next < 0) {
- _load_current(p_win); /* restore original (texturecache makes it fast) */
+ p_win->i_enhance_idx = i_idx;
+ if (i_idx < 0) {
+ _load_current(p_win); /* restore original (texturecache is fast) */
_update_header(p_win);
return;
}
-
GFile *p_file = navigator_get_current(p_win->p_nav);
if (p_file == NULL) {
p_win->i_enhance_idx = -1;
_update_header(p_win);
return;
}
-
+ const GPtrArray *p_presets = enhancer_get_presets(p_win->p_enhancer);
+ const EnhancerPreset *p_preset =
+ (p_presets != NULL && (guint)i_idx < p_presets->len)
+ ? g_ptr_array_index((GPtrArray *)p_presets, (guint)i_idx)
+ : NULL;
+ if (p_preset == NULL) {
+ p_win->i_enhance_idx = -1;
+ _update_header(p_win);
+ return;
+ }
GError *p_err = NULL;
GeglBuffer *p_buf = enhancer_load(p_file, &p_err);
GdkTexture *p_tex = NULL;
if (p_buf != NULL) {
- const EnhancerPreset *p_preset =
- g_ptr_array_index((GPtrArray *)p_presets, (guint)i_next);
GeglBuffer *p_enh =
enhancer_apply(p_win->p_enhancer, p_buf, p_preset, &p_err);
if (p_enh != NULL) {
@@ -677,6 +672,118 @@ _action_enhance(GSimpleAction *p_a, GVariant *p_v, gpointer p_data) {
_update_header(p_win);
}
+/* Hide the enhance popup (the "closed" signal does the real teardown). */
+static void
+_enhance_pop_popdown(GgazeWindow *p_win) {
+ if (p_win->p_enhance_pop != NULL) {
+ gtk_popover_popdown(GTK_POPOVER(p_win->p_enhance_pop));
+ }
+}
+
+/* "closed" handler: unparent + destroy the popup. */
+static void
+_enhance_pop_closed(GgazeWindow *p_win) {
+ GtkWidget *p_pop = p_win->p_enhance_pop;
+ if (p_pop == NULL) {
+ return;
+ }
+ p_win->p_enhance_pop = NULL;
+ gtk_widget_unparent(p_pop); /* drops our set_parent ref -> destroys */
+}
+
+/* Apply the preset attached to the clicked button (qdata "idx") and close. */
+static void
+_enhance_row_apply(GgazeWindow *p_win, GtkWidget *p_btn) {
+ gint i_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(p_btn), "idx"));
+ _apply_enhance(p_win, i_idx);
+ _enhance_pop_popdown(p_win);
+}
+
+/* Digit / Escape handling inside the enhance popup. */
+static gboolean
+_enhance_pop_key(GtkEventControllerKey *p_key, guint u_kv, guint u_kc,
+ GdkModifierType e_st, gpointer p_data) {
+ (void)p_key;
+ (void)u_kc;
+ (void)e_st;
+ GgazeWindow *p_win = GGAZE_WINDOW(p_data);
+ if (u_kv >= GDK_KEY_1 && u_kv <= GDK_KEY_9) {
+ gint i_idx = (gint)(u_kv - GDK_KEY_1);
+ const GPtrArray *p_presets = enhancer_get_presets(p_win->p_enhancer);
+ if (p_presets != NULL && (guint)i_idx < p_presets->len) {
+ _apply_enhance(p_win, i_idx);
+ _enhance_pop_popdown(p_win);
+ return (TRUE);
+ }
+ return (FALSE);
+ }
+ if (u_kv == GDK_KEY_0) {
+ _apply_enhance(p_win, -1);
+ _enhance_pop_popdown(p_win);
+ return (TRUE);
+ }
+ if (u_kv == GDK_KEY_Escape) {
+ _enhance_pop_popdown(p_win);
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/* win.enhance (key 'a'): open a popup listing the presets with number
+ * hotkeys (1..N = presets, 0 = Original). Click a row or press its digit to
+ * apply; Escape closes. */
+static void
+_action_enhance(GSimpleAction *p_a, GVariant *p_v, gpointer p_data) {
+ (void)p_a;
+ (void)p_v;
+ GgazeWindow *p_win = GGAZE_WINDOW(p_data);
+ if (p_win->p_nav == NULL || p_win->p_enhancer == NULL) {
+ return;
+ }
+ if (p_win->p_enhance_pop != NULL) {
+ _enhance_pop_popdown(p_win); /* toggle: 'a' again closes */
+ return;
+ }
+ const GPtrArray *p_presets = enhancer_get_presets(p_win->p_enhancer);
+ if (p_presets == NULL || p_presets->len == 0) {
+ return;
+ }
+ GtkWidget *p_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
+ gtk_widget_set_margin_start(p_box, 8);
+ gtk_widget_set_margin_end(p_box, 8);
+ gtk_widget_set_margin_top(p_box, 8);
+ gtk_widget_set_margin_bottom(p_box, 8);
+ for (guint i = 0; i < p_presets->len && i < 9; i++) {
+ const EnhancerPreset *p_pr = g_ptr_array_index((GPtrArray *)p_presets, i);
+ char *c_lbl = g_strdup_printf("%u %s", i + 1, p_pr->c_name);
+ GtkWidget *p_btn = gtk_button_new_with_label(c_lbl);
+ gtk_widget_set_halign(p_btn, GTK_ALIGN_START);
+ g_object_set_data(G_OBJECT(p_btn), "idx", GINT_TO_POINTER((gint)i));
+ g_signal_connect_swapped(p_btn, "clicked", G_CALLBACK(_enhance_row_apply),
+ p_win);
+ gtk_box_append(GTK_BOX(p_box), p_btn);
+ g_free(c_lbl);
+ }
+ GtkWidget *p_btn0 = gtk_button_new_with_label("0 Original");
+ gtk_widget_set_halign(p_btn0, GTK_ALIGN_START);
+ g_object_set_data(G_OBJECT(p_btn0), "idx", GINT_TO_POINTER(-1));
+ g_signal_connect_swapped(p_btn0, "clicked", G_CALLBACK(_enhance_row_apply),
+ p_win);
+ gtk_box_append(GTK_BOX(p_box), p_btn0);
+
+ GtkWidget *p_pop = gtk_popover_new();
+ gtk_popover_set_child(GTK_POPOVER(p_pop), p_box);
+ gtk_popover_set_position(GTK_POPOVER(p_pop), GTK_POS_BOTTOM);
+ gtk_widget_set_parent(p_pop, p_win->p_overlay);
+ GtkEventController *p_key = gtk_event_controller_key_new();
+ g_signal_connect(p_key, "key-pressed", G_CALLBACK(_enhance_pop_key), p_win);
+ gtk_widget_add_controller(p_pop, p_key);
+ p_win->p_enhance_pop = p_pop;
+ g_signal_connect_swapped(p_pop, "closed", G_CALLBACK(_enhance_pop_closed),
+ p_win);
+ gtk_popover_popup(GTK_POPOVER(p_pop));
+}
+
/* win.enhance-save (key 's'): export the current image with the active preset
* to <stem>-enhanced.<ext>. Never overwrites the original. No-op (with a
* warning) when no preview is active. */