refactor: stage theme prefs edits; preview live, commit on OK, discard on cancel

This commit is contained in:
2026-03-17 09:43:50 -06:00
parent 48b551b188
commit 854a913911
3 changed files with 184 additions and 48 deletions

View File

@@ -2195,9 +2195,10 @@ setup_ok_cb (GtkWidget *but, GtkWidget *win)
PreferencesPersistenceResult save_result; PreferencesPersistenceResult save_result;
char buffer[192]; char buffer[192];
gtk_widget_destroy (win); theme_preferences_stage_commit ();
setup_apply (&setup_prefs); setup_apply (&setup_prefs);
save_result = preferences_persistence_save_all (); save_result = preferences_persistence_save_all ();
gtk_widget_destroy (win);
if (save_result.success) if (save_result.success)
return; return;
@@ -2256,6 +2257,7 @@ setup_close_cb (GtkWidget *win, GtkWidget **swin)
{ {
*swin = NULL; *swin = NULL;
theme_preferences_stage_discard ();
if (font_dialog) if (font_dialog)
{ {
@@ -2276,6 +2278,7 @@ setup_open (void)
memcpy (&setup_prefs, &prefs, sizeof (prefs)); memcpy (&setup_prefs, &prefs, sizeof (prefs));
color_change = FALSE; color_change = FALSE;
theme_preferences_stage_begin ();
setup_window = setup_window_open (); setup_window = setup_window_open ();
g_signal_connect (G_OBJECT (setup_window), "destroy", g_signal_connect (G_OBJECT (setup_window), "destroy",

View File

@@ -70,6 +70,139 @@ typedef struct
#define COLOR_MANAGER_RESPONSE_RESET 1 #define COLOR_MANAGER_RESPONSE_RESET 1
typedef struct
{
gboolean active;
gboolean changed;
gboolean snapshot_valid[THEME_TOKEN_COUNT];
gboolean staged_valid[THEME_TOKEN_COUNT];
GdkRGBA snapshot[THEME_TOKEN_COUNT];
GdkRGBA staged[THEME_TOKEN_COUNT];
} theme_preferences_stage_state;
static theme_preferences_stage_state theme_preferences_stage;
static gboolean
theme_preferences_staged_get_color (ThemeSemanticToken token, GdkRGBA *rgba)
{
if (token < 0 || token >= THEME_TOKEN_COUNT || !rgba)
return FALSE;
if (theme_preferences_stage.active && theme_preferences_stage.staged_valid[token])
{
*rgba = theme_preferences_stage.staged[token];
return TRUE;
}
return theme_get_color (token, rgba);
}
static void
theme_preferences_stage_recompute_changed (void)
{
ThemeSemanticToken token;
theme_preferences_stage.changed = FALSE;
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{
if (!theme_preferences_stage.snapshot_valid[token] || !theme_preferences_stage.staged_valid[token])
continue;
if (!gdk_rgba_equal (&theme_preferences_stage.snapshot[token], &theme_preferences_stage.staged[token]))
{
theme_preferences_stage.changed = TRUE;
return;
}
}
}
static void
theme_preferences_stage_sync_runtime_to_snapshot (void)
{
ThemeSemanticToken token;
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{
if (theme_preferences_stage.snapshot_valid[token])
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, token,
&theme_preferences_stage.snapshot[token], NULL);
}
}
static void
theme_preferences_stage_sync_runtime_to_staged (void)
{
ThemeSemanticToken token;
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{
if (theme_preferences_stage.staged_valid[token])
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, token,
&theme_preferences_stage.staged[token], NULL);
}
}
static void
theme_preferences_staged_set_color (ThemeSemanticToken token, const GdkRGBA *rgba,
gboolean *color_change_flag, gboolean live_preview)
{
if (token < 0 || token >= THEME_TOKEN_COUNT || !rgba)
return;
if (theme_preferences_stage.active)
{
theme_preferences_stage.staged[token] = *rgba;
theme_preferences_stage.staged_valid[token] = TRUE;
theme_preferences_stage_recompute_changed ();
if (color_change_flag)
*color_change_flag = theme_preferences_stage.changed;
}
if (live_preview)
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, token, rgba, NULL);
}
void
theme_preferences_stage_begin (void)
{
ThemeSemanticToken token;
memset (&theme_preferences_stage, 0, sizeof (theme_preferences_stage));
theme_preferences_stage.active = TRUE;
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{
GdkRGBA rgba;
if (!theme_preferences_staged_get_color (token, &rgba))
continue;
theme_preferences_stage.snapshot[token] = rgba;
theme_preferences_stage.staged[token] = rgba;
theme_preferences_stage.snapshot_valid[token] = TRUE;
theme_preferences_stage.staged_valid[token] = TRUE;
}
}
void
theme_preferences_stage_commit (void)
{
if (!theme_preferences_stage.active)
return;
theme_preferences_stage_sync_runtime_to_staged ();
memset (&theme_preferences_stage, 0, sizeof (theme_preferences_stage));
}
void
theme_preferences_stage_discard (void)
{
if (!theme_preferences_stage.active)
return;
theme_preferences_stage_sync_runtime_to_snapshot ();
memset (&theme_preferences_stage, 0, sizeof (theme_preferences_stage));
}
static void static void
theme_preferences_show_import_error (GtkWidget *button, const char *message); theme_preferences_show_import_error (GtkWidget *button, const char *message);
@@ -116,16 +249,16 @@ theme_preferences_manager_update_preview (theme_color_manager_ui *ui)
if (!ui) if (!ui)
return; return;
if (!theme_get_color (THEME_TOKEN_TEXT_FOREGROUND, &text_fg) if (!theme_preferences_staged_get_color (THEME_TOKEN_TEXT_FOREGROUND, &text_fg)
|| !theme_get_color (THEME_TOKEN_TEXT_BACKGROUND, &text_bg) || !theme_preferences_staged_get_color (THEME_TOKEN_TEXT_BACKGROUND, &text_bg)
|| !theme_get_color (THEME_TOKEN_SELECTION_FOREGROUND, &sel_fg) || !theme_preferences_staged_get_color (THEME_TOKEN_SELECTION_FOREGROUND, &sel_fg)
|| !theme_get_color (THEME_TOKEN_SELECTION_BACKGROUND, &sel_bg) || !theme_preferences_staged_get_color (THEME_TOKEN_SELECTION_BACKGROUND, &sel_bg)
|| !theme_get_color (THEME_TOKEN_MARKER, &marker) || !theme_preferences_staged_get_color (THEME_TOKEN_MARKER, &marker)
|| !theme_get_color (THEME_TOKEN_TAB_NEW_DATA, &tab_new_data) || !theme_preferences_staged_get_color (THEME_TOKEN_TAB_NEW_DATA, &tab_new_data)
|| !theme_get_color (THEME_TOKEN_TAB_NEW_MESSAGE, &tab_new_message) || !theme_preferences_staged_get_color (THEME_TOKEN_TAB_NEW_MESSAGE, &tab_new_message)
|| !theme_get_color (THEME_TOKEN_TAB_HIGHLIGHT, &tab_highlight) || !theme_preferences_staged_get_color (THEME_TOKEN_TAB_HIGHLIGHT, &tab_highlight)
|| !theme_get_color (THEME_TOKEN_TAB_AWAY, &tab_away) || !theme_preferences_staged_get_color (THEME_TOKEN_TAB_AWAY, &tab_away)
|| !theme_get_color (THEME_TOKEN_SPELL, &spell)) || !theme_preferences_staged_get_color (THEME_TOKEN_SPELL, &spell))
return; return;
gtkutil_apply_palette (ui->preview_window, &text_bg, &text_fg, NULL); gtkutil_apply_palette (ui->preview_window, &text_bg, &text_fg, NULL);
@@ -305,15 +438,12 @@ theme_preferences_color_response_cb (GtkDialog *dialog, gint response_id, gpoint
if (response_id == GTK_RESPONSE_OK) if (response_id == GTK_RESPONSE_OK)
{ {
GdkRGBA rgba; GdkRGBA rgba;
gboolean changed = FALSE;
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &rgba); gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &rgba);
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, theme_preferences_staged_set_color (data->token,
data->token, &rgba,
&rgba, data->color_change_flag,
&changed); TRUE);
if (data->color_change_flag)
*data->color_change_flag = *data->color_change_flag || changed;
theme_preferences_color_button_apply (data->button, &rgba); theme_preferences_color_button_apply (data->button, &rgba);
theme_preferences_manager_update_preview ((theme_color_manager_ui *) data->manager_ui); theme_preferences_manager_update_preview ((theme_color_manager_ui *) data->manager_ui);
} }
@@ -332,7 +462,7 @@ theme_preferences_color_cb (GtkWidget *button, gpointer userdata)
token = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "zoitechat-theme-token")); token = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "zoitechat-theme-token"));
if (!theme_get_color (token, &rgba)) if (!theme_preferences_staged_get_color (token, &rgba))
return; return;
dialog = gtk_color_chooser_dialog_new (_("Select color"), GTK_WINDOW (userdata)); dialog = gtk_color_chooser_dialog_new (_("Select color"), GTK_WINDOW (userdata));
theme_manager_attach_window (dialog); theme_manager_attach_window (dialog);
@@ -408,14 +538,7 @@ theme_preferences_manager_row_apply (theme_color_manager_row *row, const GdkRGBA
static void static void
theme_preferences_manager_row_commit (theme_color_manager_row *row, const GdkRGBA *rgba) theme_preferences_manager_row_commit (theme_color_manager_row *row, const GdkRGBA *rgba)
{ {
gboolean changed = FALSE; theme_preferences_staged_set_color (row->token, rgba, row->color_change_flag, TRUE);
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT,
row->token,
rgba,
&changed);
if (row->color_change_flag)
*row->color_change_flag = *row->color_change_flag || changed;
theme_preferences_manager_row_apply (row, rgba); theme_preferences_manager_row_apply (row, rgba);
theme_preferences_manager_update_preview ((theme_color_manager_ui *) row->manager_ui); theme_preferences_manager_update_preview ((theme_color_manager_ui *) row->manager_ui);
} }
@@ -428,7 +551,7 @@ theme_preferences_manager_entry_commit (theme_color_manager_row *row)
if (!gdk_rgba_parse (&rgba, text)) if (!gdk_rgba_parse (&rgba, text))
{ {
if (theme_get_color (row->token, &rgba)) if (theme_preferences_staged_get_color (row->token, &rgba))
theme_preferences_manager_row_apply (row, &rgba); theme_preferences_manager_row_apply (row, &rgba);
return; return;
} }
@@ -486,7 +609,7 @@ theme_preferences_manager_pick_cb (GtkWidget *button, gpointer user_data)
GdkRGBA rgba; GdkRGBA rgba;
theme_manager_live_picker_data *data; theme_manager_live_picker_data *data;
if (!theme_get_color (row->token, &rgba)) if (!theme_preferences_staged_get_color (row->token, &rgba))
return; return;
dialog = gtk_color_chooser_dialog_new (_("Select color"), row->parent); dialog = gtk_color_chooser_dialog_new (_("Select color"), row->parent);
@@ -545,7 +668,7 @@ theme_preferences_manager_refresh_rows (theme_color_manager_ui *ui)
theme_color_manager_row *row = g_ptr_array_index (ui->rows, i); theme_color_manager_row *row = g_ptr_array_index (ui->rows, i);
GdkRGBA rgba; GdkRGBA rgba;
if (theme_get_color (row->token, &rgba)) if (theme_preferences_staged_get_color (row->token, &rgba))
theme_preferences_manager_row_apply (row, &rgba); theme_preferences_manager_row_apply (row, &rgba);
} }
@@ -564,7 +687,24 @@ theme_preferences_manager_dialog_response_cb (GtkDialog *dialog, gint response_i
gboolean changed = FALSE; gboolean changed = FALSE;
theme_manager_reset_mode_colors (ZOITECHAT_DARK_MODE_LIGHT, &changed); theme_manager_reset_mode_colors (ZOITECHAT_DARK_MODE_LIGHT, &changed);
if (ui->color_change_flag) if (theme_preferences_stage.active)
{
ThemeSemanticToken token;
for (token = THEME_TOKEN_MIRC_0; token < THEME_TOKEN_COUNT; token++)
{
GdkRGBA rgba;
if (!theme_get_color (token, &rgba))
continue;
theme_preferences_stage.staged[token] = rgba;
theme_preferences_stage.staged_valid[token] = TRUE;
}
theme_preferences_stage_recompute_changed ();
if (ui->color_change_flag)
*ui->color_change_flag = theme_preferences_stage.changed;
}
else if (ui->color_change_flag)
*ui->color_change_flag = *ui->color_change_flag || changed; *ui->color_change_flag = *ui->color_change_flag || changed;
} }
@@ -698,7 +838,7 @@ theme_preferences_create_color_manager_dialog (GtkWindow *parent, gboolean *colo
g_free (token_code); g_free (token_code);
g_free (search_text); g_free (search_text);
if (theme_get_color (token, &rgba)) if (theme_preferences_staged_get_color (token, &rgba))
theme_preferences_manager_row_apply (row, &rgba); theme_preferences_manager_row_apply (row, &rgba);
g_signal_connect (G_OBJECT (button), "clicked", g_signal_connect (G_OBJECT (button), "clicked",
@@ -727,20 +867,15 @@ static void
theme_preferences_manage_colors_cb (GtkWidget *button, gpointer user_data) theme_preferences_manage_colors_cb (GtkWidget *button, gpointer user_data)
{ {
gboolean *color_change_flag = user_data; gboolean *color_change_flag = user_data;
gboolean old_changed = FALSE;
GtkWidget *dialog; GtkWidget *dialog;
if (color_change_flag)
old_changed = *color_change_flag;
dialog = theme_preferences_create_color_manager_dialog (GTK_WINDOW (gtk_widget_get_toplevel (button)), dialog = theme_preferences_create_color_manager_dialog (GTK_WINDOW (gtk_widget_get_toplevel (button)),
color_change_flag); color_change_flag);
gtk_dialog_run (GTK_DIALOG (dialog)); gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog); gtk_widget_destroy (dialog);
if (color_change_flag && *color_change_flag != old_changed && if (color_change_flag)
!theme_manager_save_preferences ()) *color_change_flag = theme_preferences_stage.active ? theme_preferences_stage.changed : *color_change_flag;
theme_preferences_show_import_error (button, _("Could not save colors.conf."));
} }
static void static void
@@ -869,12 +1004,8 @@ theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data)
char *cfg; char *cfg;
GError *error = NULL; GError *error = NULL;
gboolean any_imported = FALSE; gboolean any_imported = FALSE;
gboolean old_changed = FALSE;
ThemeSemanticToken token; ThemeSemanticToken token;
if (color_change_flag)
old_changed = *color_change_flag;
dialog = gtk_file_chooser_dialog_new (_("Import colors.conf colors"), dialog = gtk_file_chooser_dialog_new (_("Import colors.conf colors"),
GTK_WINDOW (gtk_widget_get_toplevel (button)), GTK_WINDOW (gtk_widget_get_toplevel (button)),
GTK_FILE_CHOOSER_ACTION_OPEN, GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -910,15 +1041,14 @@ theme_preferences_import_colors_conf_cb (GtkWidget *button, gpointer user_data)
if (!theme_preferences_read_import_color (cfg, token, &rgba)) if (!theme_preferences_read_import_color (cfg, token, &rgba))
continue; continue;
theme_manager_set_token_color (ZOITECHAT_DARK_MODE_LIGHT, token, &rgba, color_change_flag); theme_preferences_staged_set_color (token, &rgba, color_change_flag, TRUE);
any_imported = TRUE; any_imported = TRUE;
} }
if (!any_imported) if (!any_imported)
theme_preferences_show_import_error (button, _("No importable colors were found in that colors.conf file.")); theme_preferences_show_import_error (button, _("No importable colors were found in that colors.conf file."));
else if (color_change_flag && *color_change_flag != old_changed && else if (color_change_flag)
!theme_manager_save_preferences ()) *color_change_flag = theme_preferences_stage.active ? theme_preferences_stage.changed : *color_change_flag;
theme_preferences_show_import_error (button, _("Could not save colors.conf."));
g_free (cfg); g_free (cfg);
g_free (path); g_free (path);
@@ -962,7 +1092,7 @@ theme_preferences_create_color_button (GtkWidget *table,
g_object_set_data (G_OBJECT (but), "zoitechat-theme-color-change", color_change_flag); g_object_set_data (G_OBJECT (but), "zoitechat-theme-color-change", color_change_flag);
gtk_grid_attach (GTK_GRID (table), but, col, row, 1, 1); gtk_grid_attach (GTK_GRID (table), but, col, row, 1, 1);
g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (theme_preferences_color_cb), parent); g_signal_connect (G_OBJECT (but), "clicked", G_CALLBACK (theme_preferences_color_cb), parent);
if (theme_get_color (token, &color)) if (theme_preferences_staged_get_color (token, &color))
theme_preferences_color_button_apply (but, &color); theme_preferences_color_button_apply (but, &color);
} }

View File

@@ -13,5 +13,8 @@ GtkWidget *theme_preferences_create_color_page (GtkWindow *parent,
struct zoitechatprefs *setup_prefs, struct zoitechatprefs *setup_prefs,
gboolean *color_change_flag); gboolean *color_change_flag);
void theme_preferences_apply_to_session (session_gui *gui, InputStyle *input_style); void theme_preferences_apply_to_session (session_gui *gui, InputStyle *input_style);
void theme_preferences_stage_begin (void);
void theme_preferences_stage_commit (void);
void theme_preferences_stage_discard (void);
#endif #endif