medit/moo/mooutils/mooprefsdialog-settings.c

660 lines
20 KiB
C

/*
* mooutils/mooprefsdialog-settings.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#define MOOPREFS_COMPILATION
#define INSIDE_MOOPREFSDIALOG_SETTINGS_C
#include "mooutils/mooprefsdialog-settings.h"
#include "mooutils/mooprefs.h"
#include <string.h>
void _moo_prefs_dialog_page_init_sig (MooPrefsDialogPage *page)
{
settings_init_sig (get_settings (page));
}
void _moo_prefs_dialog_page_apply (MooPrefsDialogPage *page)
{
settings_apply_sig (get_settings (page));
}
void moo_prefs_dialog_page_bind_setting (MooPrefsDialogPage *page,
GtkWidget *widget,
const char *setting_name,
GtkToggleButton *set_or_not)
{
g_return_if_fail (MOO_IS_PREFS_DIALOG_PAGE (page));
g_return_if_fail (widget != NULL && setting_name != NULL);
settings_bind (get_settings (page), widget, setting_name, set_or_not);
}
void moo_prefs_dialog_page_bind_radio_setting
(MooPrefsDialogPage *page,
const char *setting_name,
GtkToggleButton **btns,
const char **cvals)
{
g_return_if_fail (MOO_IS_PREFS_DIALOG_PAGE (page));
g_return_if_fail (setting_name != NULL);
settings_bind_radio (get_settings (page), setting_name, btns, cvals);
}
void moo_prefs_dialog_page_bind_radio (MooPrefsDialogPage *page,
const char *setting_name,
GtkToggleButton *btn,
const char *cval)
{
g_return_if_fail (MOO_IS_PREFS_DIALOG_PAGE (page));
g_return_if_fail (setting_name != NULL && btn != NULL && cval != NULL);
settings_add_radio (get_settings (page), setting_name, btn, cval);
}
/**************************************************************************/
/* Aux stuff
*/
static void string_list_free (GSList *list)
{
g_slist_foreach (list, (GFunc) g_free, NULL);
g_slist_free (list);
}
/**************************************************************************/
/* Settings
*/
static GQuark settings_quark (void)
{
static GQuark q = 0;
if (!q) q = g_quark_from_static_string ("moo_prefs_dialog_settings");
return q;
}
static Settings *get_settings (MooPrefsDialogPage *page)
{
Settings *s = g_object_get_qdata (G_OBJECT (page), MOO_PREFS_DIALOG_SETTINGS_QUARK);
if (!s) {
s = settings_new ();
g_object_set_qdata_full (G_OBJECT (page),
MOO_PREFS_DIALOG_SETTINGS_QUARK,
s,
(GDestroyNotify) settings_free);
g_signal_connect_swapped (page, "init",
G_CALLBACK (settings_init_sig), s);
g_signal_connect_swapped (page, "apply",
G_CALLBACK (settings_apply_sig), s);
}
return s;
}
static Settings *settings_new (void)
{
return g_new0 (Settings, 1);
}
static void settings_free (Settings *settings)
{
g_return_if_fail (settings != NULL);
g_slist_foreach (settings->settings, (GFunc) setting_free, NULL);
g_slist_free (settings->settings);
g_slist_free (settings->radio_settings);
}
static void settings_bind (Settings *settings,
GtkWidget *widget,
const char *setting_name,
GtkToggleButton *set_or_not)
{
Setting *s = NULL;
if (GTK_IS_SPIN_BUTTON (widget))
s = double_setting_new (GTK_SPIN_BUTTON (widget), setting_name, set_or_not);
else if (GTK_IS_ENTRY (widget))
s = string_setting_new (GTK_ENTRY (widget), setting_name, set_or_not);
else if (GTK_IS_FONT_BUTTON (widget))
s = font_setting_new (GTK_FONT_BUTTON (widget), setting_name, set_or_not);
else if (GTK_IS_COLOR_BUTTON (widget))
s = color_setting_new (GTK_COLOR_BUTTON (widget), setting_name, set_or_not);
else if (GTK_IS_TOGGLE_BUTTON (widget))
s = bool_setting_new (GTK_TOGGLE_BUTTON (widget), setting_name, set_or_not);
else {
g_critical ("%s: unsupported widget type %s", G_STRLOC,
g_type_name (G_TYPE_FROM_INSTANCE(widget)));
return;
}
settings->settings = g_slist_prepend (settings->settings, s);
s->set_or_not = set_or_not;
}
static void settings_init_sig (Settings *settings)
{
g_slist_foreach (settings->settings, (GFunc) setting_init_sig, NULL);
}
static void settings_apply_sig (Settings *settings)
{
g_slist_foreach (settings->settings, (GFunc) setting_apply_sig, NULL);
}
static int check_setting_name (Setting *s, const char *setting_name)
{
return strcmp (s->setting_name, setting_name);
}
static void settings_bind_radio (Settings *settings,
const char *setting_name,
GtkToggleButton **btns,
const char **cvals)
{
GSList *l;
RadioSetting *s;
GtkToggleButton **btn;
const char **val;
l = g_slist_find_custom (settings->radio_settings,
setting_name,
(GCompareFunc) check_setting_name);
if (!l) {
s = RADIO_SETTING (radio_setting_new (setting_name, NULL));
settings->settings = g_slist_prepend (settings->settings, s);
settings->radio_settings = g_slist_prepend (settings->radio_settings, s);
}
else
s = l->data;
/* TODO: check arguments */
for (btn = btns; *btn != NULL; ++btn)
s->buttons = g_slist_append (s->buttons, *btn);
for (val = cvals; *val != NULL; ++val)
s->values = g_slist_append (s->values, g_strdup (*val));
}
static void settings_add_radio (Settings *settings,
const char *setting_name,
GtkToggleButton *btn,
const char *sval)
{
GSList *l;
RadioSetting *s;
l = g_slist_find_custom (settings->radio_settings,
setting_name,
(GCompareFunc) check_setting_name);
if (!l) {
s = RADIO_SETTING (radio_setting_new (setting_name, NULL));
settings->settings = g_slist_prepend (settings->settings, s);
settings->radio_settings = g_slist_prepend (settings->radio_settings, s);
}
else
s = l->data;
/* TODO: check arguments */
s->buttons = g_slist_append (s->buttons, btn);
s->values = g_slist_append (s->values, g_strdup (sval));
}
/**************************************************************************/
/* Setting
*/
static Setting *setting_new (SettingType typ,
GtkWidget *widget,
const char *setting_name,
GtkToggleButton *set_or_not)
{
gsize size = sizeof (Setting);
Setting *s;
g_return_val_if_fail (setting_name != NULL, NULL);
switch (typ) {
case SETTING_STRING:
size = sizeof (StringSetting);
break;
case SETTING_FONT:
size = sizeof (FontSetting);
break;
case SETTING_COLOR:
size = sizeof (ColorSetting);
break;
case SETTING_BOOL:
size = sizeof (BoolSetting);
break;
case SETTING_DOUBLE:
size = sizeof (DoubleSetting);
break;
case SETTING_RADIO:
size = sizeof (RadioSetting);
break;
default:
g_assert_not_reached ();
}
s = (Setting*) g_malloc0 (size);
s->type = typ;
s->setting_name = g_strdup (setting_name);
s->widget = widget;
s->set_or_not = set_or_not;
if (widget && set_or_not)
moo_bind_sensitive (set_or_not, &widget, 1, FALSE);
return s;
}
static void setting_free (Setting *s)
{
g_return_if_fail (s != NULL);
switch (s->type) {
case SETTING_STRING:
string_setting_free (STRING_SETTING (s));
break;
case SETTING_FONT:
font_setting_free (FONT_SETTING (s));
break;
case SETTING_COLOR:
color_setting_free (COLOR_SETTING (s));
break;
case SETTING_BOOL:
bool_setting_free (BOOL_SETTING (s));
break;
case SETTING_DOUBLE:
double_setting_free (DOUBLE_SETTING (s));
break;
case SETTING_RADIO:
radio_setting_free (RADIO_SETTING (s));
break;
default:
g_assert_not_reached ();
}
g_free (s->setting_name);
g_free (s);
}
static void setting_init_sig (Setting *s)
{
g_return_if_fail (s != NULL);
if (s->set_or_not) {
gboolean set = moo_prefs_get (SETTING_NAME (s)) ? TRUE : FALSE;
gtk_toggle_button_set_active (s->set_or_not, set);
if (!set) return;
}
switch (s->type) {
case SETTING_STRING:
string_setting_init_sig (STRING_SETTING (s));
break;
case SETTING_FONT:
font_setting_init_sig (FONT_SETTING (s));
break;
case SETTING_COLOR:
color_setting_init_sig (COLOR_SETTING (s));
break;
case SETTING_BOOL:
bool_setting_init_sig (BOOL_SETTING (s));
break;
case SETTING_DOUBLE:
double_setting_init_sig (DOUBLE_SETTING (s));
break;
case SETTING_RADIO:
radio_setting_init_sig (RADIO_SETTING (s));
break;
default:
g_assert_not_reached ();
}
}
static void setting_apply_sig (Setting *s)
{
g_return_if_fail (s != NULL);
if (s->set_or_not &&
GTK_WIDGET_SENSITIVE (s->set_or_not) &&
!gtk_toggle_button_get_active (s->set_or_not))
{
moo_prefs_set (SETTING_NAME (s), NULL);
return;
}
if (s->widget && !GTK_WIDGET_SENSITIVE (s->widget))
return;
switch (s->type) {
case SETTING_STRING:
string_setting_apply_sig (STRING_SETTING (s));
break;
case SETTING_FONT:
font_setting_apply_sig (FONT_SETTING (s));
break;
case SETTING_COLOR:
color_setting_apply_sig (COLOR_SETTING (s));
break;
case SETTING_BOOL:
bool_setting_apply_sig (BOOL_SETTING (s));
break;
case SETTING_DOUBLE:
double_setting_apply_sig (DOUBLE_SETTING (s));
break;
case SETTING_RADIO:
radio_setting_apply_sig (RADIO_SETTING (s));
break;
default:
g_assert_not_reached ();
}
}
/**************************************************************************/
/* StringSetting
*/
static Setting *string_setting_new (GtkEntry *entry,
const char *setting_name,
GtkToggleButton *set_or_not)
{
StringSetting *s = STRING_SETTING (setting_new (SETTING_STRING,
GTK_WIDGET (entry),
setting_name,
set_or_not));
s->empty_is_null = FALSE;
return SETTING (s);
}
static void string_setting_free (G_GNUC_UNUSED StringSetting *s)
{
}
static void string_setting_init_sig (StringSetting *s)
{
const char *val = moo_prefs_get_string (SETTING_NAME (s));
if (!val) {
val = "";
if (!s->empty_is_null)
g_critical ("%s: '%s' not set", G_STRLOC, SETTING_NAME (s));
}
gtk_entry_set_text (GTK_ENTRY (SETTING (s)->widget), val);
}
static void string_setting_apply_sig (StringSetting *s)
{
const char *old_val = moo_prefs_get_string (SETTING_NAME (s));
const char *new_val = gtk_entry_get_text (GTK_ENTRY (SETTING (s)->widget));
if ((old_val && strcmp (old_val, new_val)) ||
(!old_val && (!s->empty_is_null || new_val[0])))
moo_prefs_set_string (SETTING_NAME (s), new_val);
}
/**************************************************************************/
/* FontSetting
*/
static Setting *font_setting_new (GtkFontButton *btn,
const char *setting_name,
GtkToggleButton *set_or_not)
{
return setting_new (SETTING_FONT,
GTK_WIDGET (btn),
setting_name,
set_or_not);
}
static void font_setting_free (G_GNUC_UNUSED FontSetting *s)
{
}
static void font_setting_init_sig (FontSetting *s)
{
const char *val = moo_prefs_get_string (SETTING_NAME (s));
if (!val)
g_critical ("%s: '%s' not set", G_STRLOC, SETTING_NAME (s));
else
gtk_font_button_set_font_name (GTK_FONT_BUTTON (SETTING (s)->widget), val);
}
static void font_setting_apply_sig (FontSetting *s)
{
const char *old_val = moo_prefs_get_string (SETTING_NAME (s));
const char *new_val = gtk_font_button_get_font_name (GTK_FONT_BUTTON (SETTING (s)->widget));
if ((old_val && new_val && strcmp (old_val, new_val)) ||
((!old_val || !new_val) && old_val != new_val))
moo_prefs_set_string (SETTING_NAME (s), new_val);
}
/**************************************************************************/
/* ColorSetting
*/
static Setting *color_setting_new (GtkColorButton *btn,
const char *setting_name,
GtkToggleButton *set_or_not)
{
return setting_new (SETTING_COLOR,
GTK_WIDGET (btn),
setting_name,
set_or_not);
}
static void color_setting_free (G_GNUC_UNUSED ColorSetting *s)
{
}
static void color_setting_init_sig (ColorSetting *s)
{
const GdkColor *color = moo_prefs_get_color (SETTING_NAME (s));
if (!color) {
s->color.red = s->color.green = s->color.blue = 0;
g_critical ("%s: '%s' not set", G_STRLOC, SETTING_NAME (s));
}
else {
s->color = *color;
gtk_color_button_set_color (GTK_COLOR_BUTTON (SETTING (s)->widget), color);
}
}
static void color_setting_apply_sig (ColorSetting *s)
{
GdkColor color;
gtk_color_button_get_color (GTK_COLOR_BUTTON (SETTING (s)->widget), &color);
if (color.red != s->color.red ||
color.green != s->color.green ||
color.blue != s->color.blue)
{
s->color = color;
moo_prefs_set_color (SETTING_NAME (s), &color);
}
}
/**************************************************************************/
/* BoolSetting
*/
static Setting *bool_setting_new (GtkToggleButton *btn,
const char *setting_name,
GtkToggleButton *set_or_not)
{
return setting_new (SETTING_BOOL,
GTK_WIDGET (btn),
setting_name,
set_or_not);
}
static void bool_setting_free (G_GNUC_UNUSED BoolSetting *s)
{
}
static void bool_setting_init_sig (BoolSetting *s)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (SETTING (s)->widget),
moo_prefs_get_bool (SETTING_NAME (s)));
}
static void bool_setting_apply_sig (BoolSetting *s)
{
gboolean val = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (SETTING (s)->widget));
if (val != moo_prefs_get_bool (SETTING_NAME (s)))
moo_prefs_set_bool (SETTING_NAME (s), val);
}
/**************************************************************************/
/* DoubleSetting
*/
static Setting *double_setting_new (GtkSpinButton *spin,
const char *setting_name,
GtkToggleButton *set_or_not)
{
return setting_new (SETTING_DOUBLE,
GTK_WIDGET (spin),
setting_name,
set_or_not);
}
static void double_setting_free (G_GNUC_UNUSED DoubleSetting *s)
{
}
static void double_setting_init_sig (DoubleSetting *s)
{
gtk_spin_button_set_value (GTK_SPIN_BUTTON (SETTING (s)->widget),
moo_prefs_get_double (SETTING_NAME (s)));
}
static void double_setting_apply_sig (DoubleSetting *s)
{
double val = gtk_spin_button_get_value (GTK_SPIN_BUTTON (SETTING (s)->widget));
if (val != moo_prefs_get_double (SETTING_NAME (s)))
moo_prefs_set_double (SETTING_NAME (s), val);
}
/**************************************************************************/
/* RadioSetting
*/
static Setting *radio_setting_new (const char *setting_name,
GtkToggleButton *set_or_not)
{
RadioSetting *s = RADIO_SETTING (setting_new (SETTING_RADIO,
NULL,
setting_name,
set_or_not));
s->value = -1;
s->buttons = NULL;
s->values = NULL;
return SETTING (s);
}
static void radio_setting_free (RadioSetting *s)
{
string_list_free (s->values);
}
static void radio_setting_init_sig (RadioSetting *s)
{
int pos = -1;
const char *val = moo_prefs_get_string (SETTING_NAME(s));
GtkToggleButton *btn = NULL;
if (!val) {
g_critical ("%s: '%s' not set", G_STRLOC, SETTING_NAME (s));
}
else {
GSList *l = g_slist_find_custom (s->values, val, (GCompareFunc) strcmp);
if (!l) {
g_critical ("%s: can't find '%s' in the list of values", G_STRLOC, val);
}
else
pos = g_slist_position (s->values, l);
}
if (pos >= 0) {
btn = g_slist_nth_data (s->buttons, (guint) pos);
g_assert (btn != NULL);
gtk_toggle_button_set_active (btn, TRUE);
}
}
static void radio_setting_apply_sig (RadioSetting *s)
{
int pos = -1;
GSList *l = NULL;
const char *old_val;
const char *new_val;
for (l = s->buttons; l != NULL; l = l->next)
if (gtk_toggle_button_get_active (l->data))
break;
g_return_if_fail (l != NULL);
pos = g_slist_position (s->buttons, l);
g_return_if_fail (pos > 0);
new_val = g_slist_nth_data (s->values, (guint) pos);
g_return_if_fail (new_val != NULL);
old_val = moo_prefs_get_string (SETTING_NAME (s));
if (!old_val || strcmp (old_val, new_val))
moo_prefs_set_string (SETTING_NAME (s), new_val);
}