00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <string.h>
00021 #include <stdio.h>
00022
00023 #include <gdk/gdkkeysyms.h>
00024 #include <gtk/gtk.h>
00025
00026 #include <libaudcore/hook.h>
00027
00028 #include "audconfig.h"
00029 #include "config.h"
00030 #include "configdb.h"
00031 #include "debug.h"
00032 #include "gtk-compat.h"
00033 #include "i18n.h"
00034 #include "misc.h"
00035 #include "output.h"
00036 #include "playback.h"
00037 #include "playlist.h"
00038 #include "playlist-utils.h"
00039 #include "plugin.h"
00040 #include "plugins.h"
00041 #include "preferences.h"
00042 #include "ui_preferences.h"
00043
00044 #ifdef USE_CHARDET
00045 #include <libguess.h>
00046 #endif
00047
00048 #define TITLESTRING_UPDATE_TIMEOUT 3
00049
00050 static void sw_volume_toggled (void);
00051
00052 enum CategoryViewCols {
00053 CATEGORY_VIEW_COL_ICON,
00054 CATEGORY_VIEW_COL_NAME,
00055 CATEGORY_VIEW_COL_ID,
00056 CATEGORY_VIEW_N_COLS
00057 };
00058
00059 typedef struct {
00060 const gchar *icon_path;
00061 const gchar *name;
00062 } Category;
00063
00064 typedef struct {
00065 const gchar *name;
00066 const gchar *tag;
00067 } TitleFieldTag;
00068
00069 static void * prefswin = NULL;
00070 static GtkWidget *filepopup_settings = NULL;
00071 static GtkWidget *category_treeview = NULL;
00072 static GtkWidget *category_notebook = NULL;
00073 GtkWidget *filepopupbutton = NULL;
00074
00075
00076 GtkWidget *filepopup_settings_cover_name_include;
00077 GtkWidget *filepopup_settings_cover_name_exclude;
00078 GtkWidget *filepopup_settings_recurse_for_cover;
00079 GtkWidget *filepopup_settings_recurse_for_cover_depth;
00080 GtkWidget *filepopup_settings_recurse_for_cover_depth_box;
00081 GtkWidget *filepopup_settings_use_file_cover;
00082 GtkWidget *filepopup_settings_showprogressbar;
00083 GtkWidget *filepopup_settings_delay;
00084
00085
00086 GtkWidget *titlestring_entry;
00087 GtkWidget *filepopup_for_tuple_settings_button;
00088 static gint titlestring_timeout_counter = 0;
00089
00090 static Category categories[] = {
00091 {"audio.png", N_("Audio")},
00092 {"connectivity.png", N_("Network")},
00093 {"playlist.png", N_("Playlist")},
00094 {"plugins.png", N_("Plugins")},
00095 };
00096
00097 static gint n_categories = G_N_ELEMENTS(categories);
00098
00099 static TitleFieldTag title_field_tags[] = {
00100 { N_("Artist") , "${artist}" },
00101 { N_("Album") , "${album}" },
00102 { N_("Title") , "${title}" },
00103 { N_("Tracknumber"), "${track-number}" },
00104 { N_("Genre") , "${genre}" },
00105 { N_("Filename") , "${file-name}" },
00106 { N_("Filepath") , "${file-path}" },
00107 { N_("Date") , "${date}" },
00108 { N_("Year") , "${year}" },
00109 { N_("Comment") , "${comment}" },
00110 { N_("Codec") , "${codec}" },
00111 { N_("Quality") , "${quality}" },
00112 };
00113 static const guint n_title_field_tags = G_N_ELEMENTS(title_field_tags);
00114
00115 #ifdef USE_CHARDET
00116 static ComboBoxElements chardet_detector_presets[] = {
00117 {"", N_("None")},
00118 {GUESS_REGION_AR, N_("Arabic")},
00119 {GUESS_REGION_BL, N_("Baltic")},
00120 {GUESS_REGION_CN, N_("Chinese")},
00121 {GUESS_REGION_GR, N_("Greek")},
00122 {GUESS_REGION_HW, N_("Hebrew")},
00123 {GUESS_REGION_JP, N_("Japanese")},
00124 {GUESS_REGION_KR, N_("Korean")},
00125 {GUESS_REGION_PL, N_("Polish")},
00126 {GUESS_REGION_RU, N_("Russian")},
00127 {GUESS_REGION_TW, N_("Taiwanese")},
00128 {GUESS_REGION_TR, N_("Turkish")}};
00129 #endif
00130
00131 static ComboBoxElements bitdepth_elements[] = {
00132 { GINT_TO_POINTER(16), "16" },
00133 { GINT_TO_POINTER(24), "24" },
00134 { GINT_TO_POINTER(32), "32" },
00135 {GINT_TO_POINTER (0), "Floating point"},
00136 };
00137
00138 typedef struct {
00139 void *next;
00140 GtkWidget *container;
00141 const gchar * pg_name;
00142 const gchar * img_url;
00143 } CategoryQueueEntry;
00144
00145 CategoryQueueEntry *category_queue = NULL;
00146
00147 static void * create_output_plugin_box (void);
00148
00149 static PreferencesWidget rg_mode_widgets[] = {
00150 {WIDGET_RADIO_BTN, N_("Single track mode"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.replay_gain_track},
00151 {WIDGET_RADIO_BTN, N_("Album mode"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.replay_gain_album}};
00152
00153 static PreferencesWidget audio_page_widgets[] = {
00154 {WIDGET_LABEL, N_("<b>Output Settings</b>")},
00155 {WIDGET_CUSTOM, .data = {.populate = create_output_plugin_box}},
00156 {WIDGET_COMBO_BOX, N_("Bit depth:"),
00157 .cfg_type = VALUE_INT, .cfg = & cfg.output_bit_depth,
00158 .data = {.combo = {bitdepth_elements, G_N_ELEMENTS (bitdepth_elements), TRUE}}},
00159 {WIDGET_SPIN_BTN, N_("Buffer size:"),
00160 .cfg_type = VALUE_INT, .cfg = & cfg.output_buffer_size,
00161 .data = {.spin_btn = {100, 10000, 1000, N_("ms")}}},
00162 {WIDGET_CHK_BTN, N_("Use software volume control (not recommended)"),
00163 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.software_volume_control, .callback = sw_volume_toggled},
00164 {WIDGET_LABEL, N_("<b>Replay Gain</b>")},
00165 {WIDGET_CHK_BTN, N_("Enable Replay Gain"),
00166 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.enable_replay_gain},
00167 {WIDGET_BOX, .child = TRUE, .data = {.box = {rg_mode_widgets, G_N_ELEMENTS (rg_mode_widgets), TRUE}}},
00168 {WIDGET_CHK_BTN, N_("Prevent clipping (recommended)"), .child = TRUE,
00169 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.enable_clipping_prevention},
00170 {WIDGET_LABEL, N_("<b>Adjust Levels</b>"), .child = TRUE},
00171 {WIDGET_SPIN_BTN, N_("Amplify all files:"), .child = TRUE,
00172 .cfg_type = VALUE_FLOAT, .cfg = & cfg.replay_gain_preamp,
00173 .data = {.spin_btn = {-15, 15, 0.1, N_("dB")}}},
00174 {WIDGET_SPIN_BTN, N_("Amplify untagged files:"), .child = TRUE,
00175 .cfg_type = VALUE_FLOAT, .cfg = & cfg.default_gain,
00176 .data = {.spin_btn = {-15, 15, 0.1, N_("dB")}}}};
00177
00178 static PreferencesWidget proxy_host_port_elements[] = {
00179 {WIDGET_ENTRY, N_("Proxy hostname:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_host},
00180 {WIDGET_ENTRY, N_("Proxy port:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_port}};
00181
00182 static PreferencesWidget proxy_auth_elements[] = {
00183 {WIDGET_ENTRY, N_("Proxy username:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_user},
00184 {WIDGET_ENTRY, N_("Proxy password:"), .cfg_type = VALUE_STRING, .cfg = & cfg.proxy_user,
00185 .data = {.entry = {.password = TRUE}}}};
00186
00187 static PreferencesWidget connectivity_page_widgets[] = {
00188 {WIDGET_LABEL, N_("<b>Proxy Configuration</b>"), NULL, NULL, NULL, FALSE},
00189 {WIDGET_CHK_BTN, N_("Enable proxy usage"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.use_proxy},
00190 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_host_port_elements, G_N_ELEMENTS(proxy_host_port_elements)}}},
00191 {WIDGET_CHK_BTN, N_("Use authentication with proxy"), .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.use_proxy_auth},
00192 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {proxy_auth_elements, G_N_ELEMENTS(proxy_auth_elements)}}},
00193 {WIDGET_LABEL, N_("<span size=\"small\">Changing these settings will require a restart of Audacious.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-dialog-warning"}}},
00194 };
00195
00196 static PreferencesWidget chardet_elements[] = {
00197 #ifdef USE_CHARDET
00198 {WIDGET_COMBO_BOX, N_("Auto character encoding detector for:"),
00199 .cfg_type = VALUE_STRING, .cfg = & cfg.chardet_detector, .child = TRUE,
00200 .data = {.combo = {chardet_detector_presets,
00201 G_N_ELEMENTS (chardet_detector_presets), TRUE}}},
00202 #endif
00203 {WIDGET_ENTRY, N_("Fallback character encodings:"), .cfg_type = VALUE_STRING,
00204 .cfg = & cfg.chardet_fallback, .callback = aud_config_chardet_update,
00205 .child = TRUE}};
00206
00207 static PreferencesWidget playlist_page_widgets[] = {
00208 {WIDGET_LABEL, N_("<b>Behavior</b>"), NULL, NULL, NULL, FALSE},
00209 {WIDGET_CHK_BTN, N_("Continue playback on startup"),
00210 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.resume_playback_on_startup},
00211 {WIDGET_CHK_BTN, N_("Advance when the current song is deleted"),
00212 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.advance_on_delete},
00213 {WIDGET_CHK_BTN, N_("Clear the playlist when opening files"),
00214 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.clear_playlist},
00215 {WIDGET_CHK_BTN, N_("Open files in a temporary playlist"),
00216 .cfg_type = VALUE_BOOLEAN, .cfg = & cfg.open_to_temporary},
00217 {WIDGET_LABEL, N_("<b>Metadata</b>"), NULL, NULL, NULL, FALSE},
00218 {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {chardet_elements, G_N_ELEMENTS(chardet_elements)}}},
00219 };
00220
00221 static void prefswin_page_queue_destroy(CategoryQueueEntry *ent);
00222
00223 static void
00224 change_category(GtkNotebook * notebook,
00225 GtkTreeSelection * selection)
00226 {
00227 GtkTreeModel *model;
00228 GtkTreeIter iter;
00229 gint index;
00230
00231 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
00232 return;
00233
00234 gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1);
00235 gtk_notebook_set_current_page(notebook, index);
00236 }
00237
00238 static void
00239 editable_insert_text(GtkEditable * editable,
00240 const gchar * text,
00241 gint * pos)
00242 {
00243 gtk_editable_insert_text(editable, text, strlen(text), pos);
00244 }
00245
00246 static void
00247 titlestring_tag_menu_callback(GtkMenuItem * menuitem,
00248 gpointer data)
00249 {
00250 const gchar *separator = " - ";
00251 gint item = GPOINTER_TO_INT(data);
00252 gint pos;
00253
00254 pos = gtk_editable_get_position(GTK_EDITABLE(titlestring_entry));
00255
00256
00257 if (g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(titlestring_entry)), -1) > 0)
00258 editable_insert_text(GTK_EDITABLE(titlestring_entry), separator, &pos);
00259
00260 editable_insert_text(GTK_EDITABLE(titlestring_entry), _(title_field_tags[item].tag),
00261 &pos);
00262
00263 gtk_editable_set_position(GTK_EDITABLE(titlestring_entry), pos);
00264 }
00265
00266 static void
00267 on_titlestring_help_button_clicked(GtkButton * button,
00268 gpointer data)
00269 {
00270 GtkMenu * menu = data;
00271 gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
00272 }
00273
00274 static gboolean
00275 titlestring_timeout_proc (gpointer data)
00276 {
00277 titlestring_timeout_counter--;
00278
00279 if(titlestring_timeout_counter <= 0) {
00280 titlestring_timeout_counter = 0;
00281 playlist_reformat_titles ();
00282 return FALSE;
00283 } else {
00284 return TRUE;
00285 }
00286 }
00287
00288 static void
00289 on_titlestring_entry_changed(GtkWidget * entry,
00290 gpointer data)
00291 {
00292 g_free(cfg.gentitle_format);
00293 cfg.gentitle_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
00294
00295 if(titlestring_timeout_counter == 0) {
00296 g_timeout_add_seconds (1, (GSourceFunc) titlestring_timeout_proc, NULL);
00297 }
00298
00299 titlestring_timeout_counter = TITLESTRING_UPDATE_TIMEOUT;
00300 }
00301
00302 static void
00303 on_titlestring_cbox_changed(GtkWidget * cbox,
00304 gpointer data)
00305 {
00306 gint position = gtk_combo_box_get_active(GTK_COMBO_BOX(cbox));
00307
00308 cfg.titlestring_preset = position;
00309 gtk_widget_set_sensitive(GTK_WIDGET(data), (position == 6));
00310
00311 playlist_reformat_titles ();
00312 }
00313
00314 static void
00315 on_font_btn_font_set(GtkFontButton * button, gchar **config)
00316 {
00317 g_free(*config);
00318 *config = g_strdup(gtk_font_button_get_font_name(button));
00319 AUDDBG("Returned font name: \"%s\"\n", *config);
00320 void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback");
00321 if (callback != NULL) callback();
00322 }
00323
00324 static void
00325 plugin_preferences_ok(GtkWidget *widget, PluginPreferences *settings)
00326 {
00327 if (settings->apply)
00328 settings->apply();
00329
00330 gtk_widget_destroy(GTK_WIDGET(settings->data));
00331 }
00332
00333 static void
00334 plugin_preferences_apply(GtkWidget *widget, PluginPreferences *settings)
00335 {
00336 if (settings->apply)
00337 settings->apply();
00338 }
00339
00340 static void
00341 plugin_preferences_cancel(GtkWidget *widget, PluginPreferences *settings)
00342 {
00343 if (settings->cancel)
00344 settings->cancel();
00345
00346 gtk_widget_destroy(GTK_WIDGET(settings->data));
00347 }
00348
00349 static void plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings)
00350 {
00351 gtk_widget_destroy(widget);
00352
00353 if (settings->cleanup)
00354 settings->cleanup();
00355
00356 settings->data = NULL;
00357 }
00358
00359 void plugin_preferences_show (PluginPreferences * settings)
00360 {
00361 GtkWidget *window;
00362 GtkWidget *vbox, *bbox, *ok, *apply, *cancel;
00363
00364 if (settings->data != NULL) {
00365 gtk_widget_show(GTK_WIDGET(settings->data));
00366 return;
00367 }
00368
00369 if (settings->init)
00370 settings->init();
00371
00372 const gchar * d = settings->domain;
00373 if (! d)
00374 {
00375 printf ("WARNING: PluginPreferences window with title \"%s\" did not "
00376 "declare its gettext domain. Text may not be translated correctly.\n",
00377 settings->title);
00378 d = "audacious-plugins";
00379 }
00380
00381 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00382 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
00383
00384 if (settings->title)
00385 gtk_window_set_title ((GtkWindow *) window, dgettext (d, settings->title));
00386
00387 gtk_container_set_border_width(GTK_CONTAINER(window), 10);
00388 g_signal_connect(G_OBJECT(window), "destroy",
00389 G_CALLBACK(plugin_preferences_destroy), settings);
00390
00391 vbox = gtk_vbox_new(FALSE, 10);
00392 create_widgets_with_domain ((GtkBox *) vbox, settings->prefs,
00393 settings->n_prefs, d);
00394 gtk_container_add(GTK_CONTAINER(window), vbox);
00395
00396 bbox = gtk_hbutton_box_new();
00397 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
00398 gtk_box_set_spacing(GTK_BOX(bbox), 5);
00399 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
00400
00401 ok = gtk_button_new_from_stock(GTK_STOCK_OK);
00402 g_signal_connect(G_OBJECT(ok), "clicked",
00403 G_CALLBACK(plugin_preferences_ok), settings);
00404 gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
00405 gtk_widget_set_can_default (ok, TRUE);
00406 gtk_widget_grab_default(ok);
00407
00408 apply = gtk_button_new_from_stock(GTK_STOCK_APPLY);
00409 g_signal_connect(G_OBJECT(apply), "clicked",
00410 G_CALLBACK(plugin_preferences_apply), settings);
00411 gtk_box_pack_start(GTK_BOX(bbox), apply, TRUE, TRUE, 0);
00412
00413 cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
00414 g_signal_connect(G_OBJECT(cancel), "clicked",
00415 G_CALLBACK(plugin_preferences_cancel), settings);
00416 gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
00417
00418 gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(prefswin));
00419 gtk_widget_show_all(window);
00420 settings->data = (gpointer)window;
00421 }
00422
00423 void plugin_preferences_cleanup (PluginPreferences * p)
00424 {
00425 if (p->data != NULL)
00426 {
00427 gtk_widget_destroy (p->data);
00428 p->data = NULL;
00429 }
00430 }
00431
00432 static void
00433 on_spin_btn_changed_gint(GtkSpinButton *button, gint *cfg)
00434 {
00435 *cfg = gtk_spin_button_get_value_as_int(button);
00436 }
00437
00438 static void
00439 on_spin_btn_changed_gfloat(GtkSpinButton *button, gfloat *cfg)
00440 {
00441 *cfg = (gfloat) gtk_spin_button_get_value(button);
00442 }
00443
00444
00445 static void fill_category_list (GtkTreeView * treeview, GtkNotebook * notebook)
00446 {
00447 GtkListStore *store;
00448 GtkCellRenderer *renderer;
00449 GtkTreeViewColumn *column;
00450 GtkTreeSelection *selection;
00451 GtkTreeIter iter;
00452 GdkPixbuf *img;
00453 CategoryQueueEntry *qlist;
00454 gint i;
00455
00456 column = gtk_tree_view_column_new();
00457 gtk_tree_view_column_set_title(column, _("Category"));
00458 gtk_tree_view_append_column(treeview, column);
00459 gtk_tree_view_column_set_spacing(column, 2);
00460
00461 renderer = gtk_cell_renderer_pixbuf_new();
00462 gtk_tree_view_column_pack_start(column, renderer, FALSE);
00463 gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", 0, NULL);
00464
00465 renderer = gtk_cell_renderer_text_new();
00466 gtk_tree_view_column_pack_start(column, renderer, FALSE);
00467 gtk_tree_view_column_set_attributes(column, renderer, "text", 1, NULL);
00468
00469 g_object_set ((GObject *) renderer, "wrap-width", 96, "wrap-mode",
00470 PANGO_WRAP_WORD_CHAR, NULL);
00471
00472 store = gtk_list_store_new(CATEGORY_VIEW_N_COLS,
00473 GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT);
00474 gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
00475
00476 for (i = 0; i < n_categories; i ++)
00477 {
00478 gchar * path = g_strdup_printf ("%s/images/%s",
00479 get_path (AUD_PATH_DATA_DIR), categories[i].icon_path);
00480 img = gdk_pixbuf_new_from_file (path, NULL);
00481 g_free (path);
00482
00483 gtk_list_store_append(store, &iter);
00484 gtk_list_store_set(store, &iter,
00485 CATEGORY_VIEW_COL_ICON, img,
00486 CATEGORY_VIEW_COL_NAME,
00487 gettext(categories[i].name), CATEGORY_VIEW_COL_ID,
00488 i, -1);
00489 g_object_unref(img);
00490 }
00491
00492 selection = gtk_tree_view_get_selection(treeview);
00493
00494 g_signal_connect_swapped(selection, "changed",
00495 G_CALLBACK(change_category), notebook);
00496
00497
00498 category_treeview = GTK_WIDGET(treeview);
00499
00500
00501 for (qlist = category_queue; qlist != NULL; qlist = category_queue)
00502 {
00503 CategoryQueueEntry *ent = (CategoryQueueEntry *) qlist;
00504
00505 prefswin_page_new(ent->container, ent->pg_name, ent->img_url);
00506 prefswin_page_queue_destroy(ent);
00507 }
00508 }
00509
00510 static void
00511 on_show_filepopup_for_tuple_toggled(GtkToggleButton * button, gpointer data)
00512 {
00513 cfg.show_filepopup_for_tuple = gtk_toggle_button_get_active(button);
00514
00515 gtk_widget_set_sensitive(filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple);
00516 }
00517
00518 static void
00519 on_recurse_for_cover_toggled(GtkToggleButton *button, gpointer data)
00520 {
00521 gtk_widget_set_sensitive(GTK_WIDGET(data),
00522 gtk_toggle_button_get_active(button));
00523 }
00524
00525 static void
00526 on_filepopup_for_tuple_settings_clicked(GtkButton *button, gpointer data)
00527 {
00528 gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_include), cfg.cover_name_include);
00529 gtk_entry_set_text(GTK_ENTRY(filepopup_settings_cover_name_exclude), cfg.cover_name_exclude);
00530 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), cfg.recurse_for_cover);
00531 gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), cfg.recurse_for_cover_depth);
00532 on_recurse_for_cover_toggled(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover), filepopup_settings_recurse_for_cover_depth_box);
00533 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover), cfg.use_file_cover);
00534 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar), cfg.filepopup_showprogressbar);
00535 gtk_spin_button_set_value(GTK_SPIN_BUTTON(filepopup_settings_delay), cfg.filepopup_delay);
00536
00537 gtk_widget_show(filepopup_settings);
00538 }
00539
00540 static void
00541 on_filepopup_settings_ok_clicked(GtkButton *button, gpointer data)
00542 {
00543 g_free(cfg.cover_name_include);
00544 cfg.cover_name_include = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_include)));
00545
00546 g_free(cfg.cover_name_exclude);
00547 cfg.cover_name_exclude = g_strdup(gtk_entry_get_text(GTK_ENTRY(filepopup_settings_cover_name_exclude)));
00548
00549 cfg.recurse_for_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_recurse_for_cover));
00550 cfg.recurse_for_cover_depth = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth));
00551 cfg.use_file_cover = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_use_file_cover));
00552 cfg.filepopup_showprogressbar = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(filepopup_settings_showprogressbar));
00553 cfg.filepopup_delay = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(filepopup_settings_delay));
00554
00555 gtk_widget_hide(filepopup_settings);
00556 }
00557
00558 static void
00559 on_filepopup_settings_cancel_clicked(GtkButton *button, gpointer data)
00560 {
00561 gtk_widget_hide(filepopup_settings);
00562 }
00563
00564 static void
00565 on_toggle_button_toggled(GtkToggleButton * button, gboolean *cfg)
00566 {
00567 *cfg = gtk_toggle_button_get_active(button);
00568 void (*callback) (void) = g_object_get_data(G_OBJECT(button), "callback");
00569 if (callback != NULL) callback();
00570 GtkWidget *child = g_object_get_data(G_OBJECT(button), "child");
00571 if (child) gtk_widget_set_sensitive(GTK_WIDGET(child), *cfg);
00572 }
00573
00574 static void
00575 on_entry_changed(GtkEntry *entry, gchar **cfg)
00576 {
00577 void (*callback) (void) = g_object_get_data(G_OBJECT(entry), "callback");
00578 const gchar *ret;
00579
00580 g_return_if_fail(cfg != NULL);
00581
00582 g_free(*cfg);
00583
00584 ret = gtk_entry_get_text(entry);
00585
00586 if (ret == NULL)
00587 *cfg = g_strdup("");
00588 else
00589 *cfg = g_strdup(ret);
00590
00591 if (callback != NULL) callback();
00592 }
00593
00594 static void
00595 on_cbox_changed_int(GtkComboBox * combobox, PreferencesWidget *widget)
00596 {
00597 gint position = 0;
00598
00599 position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
00600 *((gint *)widget->cfg) = GPOINTER_TO_INT(widget->data.combo.elements[position].value);
00601 }
00602
00603 static void
00604 on_cbox_changed_string(GtkComboBox * combobox, PreferencesWidget *widget)
00605 {
00606 gint position = 0;
00607
00608 position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
00609
00610 g_free(*((gchar **)widget->cfg));
00611
00612 *((gchar **)widget->cfg) = g_strdup(widget->data.combo.elements[position].value);
00613 }
00614
00615 static void fill_cbox (GtkWidget * combobox, PreferencesWidget * widget)
00616 {
00617 guint i=0,index=0;
00618
00619 for (i = 0; i < widget->data.combo.n_elements; i ++)
00620 gtk_combo_box_text_append_text ((GtkComboBoxText *) combobox,
00621 _(widget->data.combo.elements[i].label));
00622
00623 if (widget->data.combo.enabled) {
00624 switch (widget->cfg_type) {
00625 case VALUE_INT:
00626 g_signal_connect(combobox, "changed",
00627 G_CALLBACK(on_cbox_changed_int), widget);
00628 for(i=0; i<widget->data.combo.n_elements; i++) {
00629 if (GPOINTER_TO_INT(widget->data.combo.elements[i].value) == *((gint *) widget->cfg)) {
00630 index = i;
00631 break;
00632 }
00633 }
00634 break;
00635 case VALUE_STRING:
00636 g_signal_connect(combobox, "changed",
00637 G_CALLBACK(on_cbox_changed_string), widget);
00638 for(i=0; i<widget->data.combo.n_elements; i++) {
00639 if(!strcmp((gchar *)widget->data.combo.elements[i].value, *((gchar **)widget->cfg))) {
00640 index = i;
00641 break;
00642 }
00643 }
00644 break;
00645 case VALUE_NULL:
00646 break;
00647 default:
00648 g_warning("Unhandled cbox value type");
00649 break;
00650 }
00651 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index);
00652 } else {
00653 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), -1);
00654 gtk_widget_set_sensitive(GTK_WIDGET(combobox), 0);
00655 }
00656 }
00657
00658 void
00659 create_filepopup_settings(void)
00660 {
00661 GtkWidget *vbox;
00662 GtkWidget *table;
00663
00664 GtkWidget *label_cover_retrieve;
00665 GtkWidget *label_cover_search;
00666 GtkWidget *label_exclude;
00667 GtkWidget *label_include;
00668 GtkWidget *label_search_depth;
00669 GtkWidget *label_misc;
00670 GtkWidget *label_delay;
00671
00672 GtkAdjustment *recurse_for_cover_depth_adj;
00673 GtkAdjustment *delay_adj;
00674 GtkWidget *alignment;
00675
00676 GtkWidget *hbox;
00677 GtkWidget *hbuttonbox;
00678 GtkWidget *btn_cancel;
00679 GtkWidget *btn_ok;
00680
00681 filepopup_settings = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00682 gtk_container_set_border_width(GTK_CONTAINER(filepopup_settings), 12);
00683 gtk_window_set_title(GTK_WINDOW(filepopup_settings), _("Popup Information Settings"));
00684 gtk_window_set_position(GTK_WINDOW(filepopup_settings), GTK_WIN_POS_CENTER_ON_PARENT);
00685 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(filepopup_settings), TRUE);
00686 gtk_window_set_type_hint(GTK_WINDOW(filepopup_settings), GDK_WINDOW_TYPE_HINT_DIALOG);
00687 gtk_window_set_transient_for(GTK_WINDOW(filepopup_settings), GTK_WINDOW(prefswin));
00688
00689 vbox = gtk_vbox_new(FALSE, 12);
00690 gtk_container_add(GTK_CONTAINER(filepopup_settings), vbox);
00691
00692 label_cover_retrieve = gtk_label_new(_("<b>Cover image retrieve</b>"));
00693 gtk_box_pack_start(GTK_BOX(vbox), label_cover_retrieve, FALSE, FALSE, 0);
00694 gtk_label_set_use_markup(GTK_LABEL(label_cover_retrieve), TRUE);
00695 gtk_misc_set_alignment(GTK_MISC(label_cover_retrieve), 0, 0.5);
00696
00697 label_cover_search = gtk_label_new(_("While searching for the album's cover, Audacious looks for certain words in the filename. You can specify those words in the lists below, separated using commas."));
00698 gtk_box_pack_start(GTK_BOX(vbox), label_cover_search, FALSE, FALSE, 0);
00699 gtk_label_set_line_wrap(GTK_LABEL(label_cover_search), TRUE);
00700 gtk_misc_set_alignment(GTK_MISC(label_cover_search), 0, 0);
00701 gtk_misc_set_padding(GTK_MISC(label_cover_search), 12, 0);
00702
00703 table = gtk_table_new(2, 2, FALSE);
00704 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
00705 gtk_table_set_row_spacings(GTK_TABLE(table), 4);
00706 gtk_table_set_col_spacings(GTK_TABLE(table), 4);
00707
00708 filepopup_settings_cover_name_include = gtk_entry_new();
00709 gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_include, 1, 2, 0, 1,
00710 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
00711 (GtkAttachOptions) (0), 0, 0);
00712 gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_include), TRUE);
00713
00714 label_exclude = gtk_label_new(_("Exclude:"));
00715 gtk_table_attach(GTK_TABLE(table), label_exclude, 0, 1, 1, 2,
00716 (GtkAttachOptions) (0),
00717 (GtkAttachOptions) (0), 0, 0);
00718 gtk_misc_set_alignment(GTK_MISC(label_exclude), 0, 0.5);
00719 gtk_misc_set_padding(GTK_MISC(label_exclude), 12, 0);
00720
00721 label_include = gtk_label_new(_("Include:"));
00722 gtk_table_attach(GTK_TABLE(table), label_include, 0, 1, 0, 1,
00723 (GtkAttachOptions) (0),
00724 (GtkAttachOptions) (0), 0, 0);
00725 gtk_misc_set_alignment(GTK_MISC(label_include), 0, 0.5);
00726 gtk_misc_set_padding(GTK_MISC(label_include), 12, 0);
00727
00728 filepopup_settings_cover_name_exclude = gtk_entry_new();
00729 gtk_table_attach(GTK_TABLE(table), filepopup_settings_cover_name_exclude, 1, 2, 1, 2,
00730 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
00731 (GtkAttachOptions) (0), 0, 0);
00732 gtk_entry_set_activates_default(GTK_ENTRY(filepopup_settings_cover_name_exclude), TRUE);
00733
00734 alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
00735 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
00736 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
00737
00738 filepopup_settings_recurse_for_cover = gtk_check_button_new_with_mnemonic(_("Recursively search for cover"));
00739 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover);
00740
00741 alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
00742 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
00743 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 45, 0);
00744
00745 filepopup_settings_recurse_for_cover_depth_box = gtk_hbox_new(FALSE, 0);
00746 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_recurse_for_cover_depth_box);
00747
00748 label_search_depth = gtk_label_new(_("Search depth: "));
00749 gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), label_search_depth, TRUE, TRUE, 0);
00750 gtk_misc_set_padding(GTK_MISC(label_search_depth), 4, 0);
00751
00752 recurse_for_cover_depth_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0,
00753 100, 1, 10, 0);
00754 filepopup_settings_recurse_for_cover_depth = gtk_spin_button_new(GTK_ADJUSTMENT(recurse_for_cover_depth_adj), 1, 0);
00755 gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), filepopup_settings_recurse_for_cover_depth, TRUE, TRUE, 0);
00756 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), TRUE);
00757
00758 alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
00759 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
00760 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
00761
00762 filepopup_settings_use_file_cover = gtk_check_button_new_with_mnemonic(_("Use per-file cover"));
00763 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_use_file_cover);
00764
00765 label_misc = gtk_label_new(_("<b>Miscellaneous</b>"));
00766 gtk_box_pack_start(GTK_BOX(vbox), label_misc, FALSE, FALSE, 0);
00767 gtk_label_set_use_markup(GTK_LABEL(label_misc), TRUE);
00768 gtk_misc_set_alignment(GTK_MISC(label_misc), 0, 0.5);
00769
00770 alignment = gtk_alignment_new(0.5, 0.5, 1, 1);
00771 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
00772 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
00773
00774 filepopup_settings_showprogressbar = gtk_check_button_new_with_mnemonic(_("Show Progress bar for the current track"));
00775 gtk_container_add(GTK_CONTAINER(alignment), filepopup_settings_showprogressbar);
00776
00777 alignment = gtk_alignment_new(0, 0.5, 1, 1);
00778 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
00779 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 12, 0);
00780
00781 hbox = gtk_hbox_new(FALSE, 0);
00782 gtk_container_add(GTK_CONTAINER(alignment), hbox);
00783
00784 label_delay = gtk_label_new(_("Delay until filepopup comes up: "));
00785 gtk_box_pack_start(GTK_BOX(hbox), label_delay, TRUE, TRUE, 0);
00786 gtk_misc_set_alignment(GTK_MISC(label_delay), 0, 0.5);
00787 gtk_misc_set_padding(GTK_MISC(label_delay), 12, 0);
00788
00789 delay_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 100, 1, 10, 0);
00790 filepopup_settings_delay = gtk_spin_button_new(GTK_ADJUSTMENT(delay_adj), 1, 0);
00791 gtk_box_pack_start(GTK_BOX(hbox), filepopup_settings_delay, TRUE, TRUE, 0);
00792 gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_delay), TRUE);
00793
00794 hbuttonbox = gtk_hbutton_box_new();
00795 gtk_box_pack_start(GTK_BOX(vbox), hbuttonbox, FALSE, FALSE, 0);
00796 gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_END);
00797 gtk_box_set_spacing(GTK_BOX(hbuttonbox), 6);
00798
00799 btn_cancel = gtk_button_new_from_stock("gtk-cancel");
00800 gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_cancel);
00801
00802 btn_ok = gtk_button_new_from_stock("gtk-ok");
00803 gtk_container_add(GTK_CONTAINER(hbuttonbox), btn_ok);
00804 gtk_widget_set_can_default(btn_ok, TRUE);
00805
00806 g_signal_connect(G_OBJECT(filepopup_settings), "delete_event",
00807 G_CALLBACK(gtk_widget_hide_on_delete),
00808 NULL);
00809 g_signal_connect(G_OBJECT(btn_cancel), "clicked",
00810 G_CALLBACK(on_filepopup_settings_cancel_clicked),
00811 NULL);
00812 g_signal_connect(G_OBJECT(btn_ok), "clicked",
00813 G_CALLBACK(on_filepopup_settings_ok_clicked),
00814 NULL);
00815 g_signal_connect(G_OBJECT(filepopup_settings_recurse_for_cover), "toggled",
00816 G_CALLBACK(on_recurse_for_cover_toggled),
00817 filepopup_settings_recurse_for_cover_depth_box);
00818
00819 gtk_widget_grab_default(btn_ok);
00820 gtk_widget_show_all(vbox);
00821 }
00822
00823 static void create_spin_button (PreferencesWidget * widget, GtkWidget * *
00824 label_pre, GtkWidget * * spin_btn, GtkWidget * * label_past, const gchar *
00825 domain)
00826 {
00827 g_return_if_fail(widget->type == WIDGET_SPIN_BTN);
00828
00829 * label_pre = gtk_label_new (dgettext (domain, widget->label));
00830
00831 *spin_btn = gtk_spin_button_new_with_range(widget->data.spin_btn.min,
00832 widget->data.spin_btn.max,
00833 widget->data.spin_btn.step);
00834
00835
00836 if (widget->tooltip)
00837 gtk_widget_set_tooltip_text (* spin_btn, dgettext (domain,
00838 widget->tooltip));
00839
00840 if (widget->data.spin_btn.right_label) {
00841 * label_past = gtk_label_new (dgettext (domain,
00842 widget->data.spin_btn.right_label));
00843 }
00844
00845 switch (widget->cfg_type) {
00846 case VALUE_INT:
00847 gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, * (gint *) widget->cfg);
00848 g_signal_connect(G_OBJECT(*spin_btn), "value_changed",
00849 G_CALLBACK(on_spin_btn_changed_gint),
00850 widget->cfg);
00851 break;
00852 case VALUE_FLOAT:
00853 gtk_spin_button_set_value ((GtkSpinButton *) * spin_btn, * (gfloat *) widget->cfg);
00854 g_signal_connect(G_OBJECT(*spin_btn), "value_changed",
00855 G_CALLBACK(on_spin_btn_changed_gfloat),
00856 widget->cfg);
00857 break;
00858 case VALUE_NULL:
00859 break;
00860 default:
00861 g_warning("Unsupported value type for spin button");
00862 }
00863 }
00864
00865 void create_font_btn (PreferencesWidget * widget, GtkWidget * * label,
00866 GtkWidget * * font_btn, const gchar * domain)
00867 {
00868 *font_btn = gtk_font_button_new();
00869 gtk_font_button_set_use_font(GTK_FONT_BUTTON(*font_btn), TRUE);
00870 gtk_font_button_set_use_size(GTK_FONT_BUTTON(*font_btn), TRUE);
00871 if (widget->label) {
00872 * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label));
00873 gtk_label_set_use_markup(GTK_LABEL(*label), TRUE);
00874 gtk_misc_set_alignment(GTK_MISC(*label), 1, 0.5);
00875 gtk_label_set_justify(GTK_LABEL(*label), GTK_JUSTIFY_RIGHT);
00876 gtk_label_set_mnemonic_widget(GTK_LABEL(*label), *font_btn);
00877 }
00878
00879 if (widget->data.font_btn.title)
00880 gtk_font_button_set_title (GTK_FONT_BUTTON (* font_btn),
00881 dgettext (domain, widget->data.font_btn.title));
00882
00883 gtk_font_button_set_font_name ((GtkFontButton *) * font_btn, * (gchar * *) widget->cfg);
00884
00885 g_object_set_data ((GObject *) (* font_btn), "callback", (void *)
00886 widget->callback);
00887
00888 g_signal_connect(G_OBJECT(*font_btn), "font_set",
00889 G_CALLBACK(on_font_btn_font_set),
00890 (gchar**)widget->cfg);
00891 }
00892
00893 static void create_entry (PreferencesWidget * widget, GtkWidget * * label,
00894 GtkWidget * * entry, const gchar * domain)
00895 {
00896 *entry = gtk_entry_new();
00897 gtk_entry_set_visibility(GTK_ENTRY(*entry), !widget->data.entry.password);
00898
00899 if (widget->label)
00900 * label = gtk_label_new (dgettext (domain, widget->label));
00901
00902 if (widget->tooltip)
00903 gtk_widget_set_tooltip_text (* entry, dgettext (domain, widget->tooltip));
00904
00905 g_object_set_data ((GObject *) (* entry), "callback", (void *)
00906 widget->callback);
00907
00908 if (widget->cfg)
00909 {
00910 if (widget->cfg_type == VALUE_STRING)
00911 {
00912 if (* (gchar * *) widget->cfg)
00913 gtk_entry_set_text ((GtkEntry *) * entry, * (gchar * *) widget->cfg);
00914
00915 g_signal_connect (* entry, "changed", (GCallback) on_entry_changed, widget->cfg);
00916 }
00917 else
00918 printf ("WARNING: Invalid PreferencesWidget config type.\n");
00919 }
00920 }
00921
00922 static void create_label (PreferencesWidget * widget, GtkWidget * * label,
00923 GtkWidget * * icon, const gchar * domain)
00924 {
00925 if (widget->data.label.stock_id)
00926 *icon = gtk_image_new_from_stock(widget->data.label.stock_id, GTK_ICON_SIZE_BUTTON);
00927
00928 * label = gtk_label_new_with_mnemonic (dgettext (domain, widget->label));
00929 gtk_label_set_use_markup(GTK_LABEL(*label), TRUE);
00930
00931 if (widget->data.label.single_line == FALSE)
00932 gtk_label_set_line_wrap(GTK_LABEL(*label), TRUE);
00933
00934 gtk_misc_set_alignment(GTK_MISC(*label), 0, 0.5);
00935 }
00936
00937 static void create_cbox (PreferencesWidget * widget, GtkWidget * * label,
00938 GtkWidget * * combobox, const gchar * domain)
00939 {
00940 * combobox = gtk_combo_box_text_new ();
00941
00942 if (widget->label) {
00943 * label = gtk_label_new (dgettext (domain, widget->label));
00944 }
00945
00946 fill_cbox (* combobox, widget);
00947 }
00948
00949 static void fill_table (GtkWidget * table, PreferencesWidget * elements, gint
00950 amt, const gchar * domain)
00951 {
00952 gint x;
00953 GtkWidget *widget_left, *widget_middle, *widget_right;
00954 GtkAttachOptions middle_policy = (GtkAttachOptions) (0);
00955
00956 for (x = 0; x < amt; ++x) {
00957 widget_left = widget_middle = widget_right = NULL;
00958 switch (elements[x].type) {
00959 case WIDGET_SPIN_BTN:
00960 create_spin_button (& elements[x], & widget_left,
00961 & widget_middle, & widget_right, domain);
00962 middle_policy = (GtkAttachOptions) (GTK_FILL);
00963 break;
00964 case WIDGET_LABEL:
00965 create_label (& elements[x], & widget_middle, & widget_left,
00966 domain);
00967 middle_policy = (GtkAttachOptions) (GTK_FILL);
00968 break;
00969 case WIDGET_FONT_BTN:
00970 create_font_btn (& elements[x], & widget_left, & widget_middle,
00971 domain);
00972 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
00973 break;
00974 case WIDGET_ENTRY:
00975 create_entry (& elements[x], & widget_left, & widget_middle,
00976 domain);
00977 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
00978 break;
00979 case WIDGET_COMBO_BOX:
00980 create_cbox (& elements[x], & widget_left, & widget_middle,
00981 domain);
00982 middle_policy = (GtkAttachOptions) (GTK_EXPAND | GTK_FILL);
00983 break;
00984 default:
00985 g_warning("Unsupported widget type %d in table", elements[x].type);
00986 }
00987
00988 if (widget_left)
00989 gtk_table_attach(GTK_TABLE (table), widget_left, 0, 1, x, x+1,
00990 (GtkAttachOptions) (0),
00991 (GtkAttachOptions) (0), 0, 0);
00992
00993 if (widget_middle)
00994 gtk_table_attach(GTK_TABLE(table), widget_middle, 1, widget_right ? 2 : 3, x, x+1,
00995 middle_policy,
00996 (GtkAttachOptions) (0), 4, 0);
00997
00998 if (widget_right)
00999 gtk_table_attach(GTK_TABLE(table), widget_right, 2, 3, x, x+1,
01000 (GtkAttachOptions) (0),
01001 (GtkAttachOptions) (0), 0, 0);
01002 }
01003 }
01004
01005
01006
01007 void create_widgets_with_domain (void * box, PreferencesWidget * widgets, gint
01008 amt, const gchar * domain)
01009 {
01010 gint x;
01011 GtkWidget *alignment = NULL, *widget = NULL;
01012 GtkWidget *child_box = NULL;
01013 GSList *radio_btn_group = NULL;
01014
01015 for (x = 0; x < amt; ++x) {
01016 if (widget && widgets[x].child)
01017 {
01018 if (!child_box) {
01019 child_box = gtk_vbox_new(FALSE, 0);
01020 g_object_set_data(G_OBJECT(widget), "child", child_box);
01021 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
01022 gtk_box_pack_start(box, alignment, FALSE, FALSE, 0);
01023 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
01024 gtk_container_add (GTK_CONTAINER (alignment), child_box);
01025
01026 if (GTK_IS_TOGGLE_BUTTON (widget))
01027 gtk_widget_set_sensitive (child_box, gtk_toggle_button_get_active ((GtkToggleButton *) widget));
01028 }
01029 } else
01030 child_box = NULL;
01031
01032 alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
01033 gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 0, 12, 0);
01034 gtk_box_pack_start(child_box ? GTK_BOX(child_box) : box, alignment, FALSE, FALSE, 0);
01035
01036 if (radio_btn_group && widgets[x].type != WIDGET_RADIO_BTN)
01037 radio_btn_group = NULL;
01038
01039 switch(widgets[x].type) {
01040 case WIDGET_CHK_BTN:
01041 widget = gtk_check_button_new_with_mnemonic (dgettext (domain,
01042 widgets[x].label));
01043 g_object_set_data ((GObject *) widget, "callback",
01044 (void *) widgets[x].callback);
01045
01046 if (widgets[x].cfg)
01047 {
01048 if (widgets[x].cfg_type == VALUE_BOOLEAN)
01049 {
01050 gtk_toggle_button_set_active ((GtkToggleButton *) widget, * (gboolean *) widgets[x].cfg);
01051 g_signal_connect (widget, "toggled", (GCallback) on_toggle_button_toggled, widgets[x].cfg);
01052 }
01053 else
01054 printf ("WARNING: Invalid PreferencesWidget config type.\n");
01055 }
01056
01057 break;
01058 case WIDGET_LABEL:
01059 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 12, 0, 0, 0);
01060
01061 GtkWidget *label = NULL, *icon = NULL;
01062 create_label (& widgets[x], & label, & icon, domain);
01063
01064 if (icon == NULL)
01065 widget = label;
01066 else {
01067 widget = gtk_hbox_new(FALSE, 6);
01068 gtk_box_pack_start(GTK_BOX(widget), icon, FALSE, FALSE, 0);
01069 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01070 }
01071 break;
01072 case WIDGET_RADIO_BTN:
01073 widget = gtk_radio_button_new_with_mnemonic (radio_btn_group,
01074 dgettext (domain, widgets[x].label));
01075 radio_btn_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
01076
01077 if (widgets[x].cfg)
01078 {
01079 if (widgets[x].cfg_type == VALUE_BOOLEAN)
01080 {
01081 gtk_toggle_button_set_active ((GtkToggleButton *) widget, * (gboolean *) widgets[x].cfg);
01082 g_signal_connect (widget, "toggled", (GCallback) on_toggle_button_toggled, widgets[x].cfg);
01083 }
01084 else
01085 printf ("WARNING: Invalid PreferencesWidget config type.\n");
01086 }
01087
01088 break;
01089 case WIDGET_SPIN_BTN:
01090 widget = gtk_hbox_new(FALSE, 6);
01091
01092 GtkWidget *label_pre = NULL, *spin_btn = NULL, *label_past = NULL;
01093 create_spin_button (& widgets[x], & label_pre, & spin_btn,
01094 & label_past, domain);
01095
01096 if (label_pre)
01097 gtk_box_pack_start(GTK_BOX(widget), label_pre, FALSE, FALSE, 0);
01098 if (spin_btn)
01099 gtk_box_pack_start(GTK_BOX(widget), spin_btn, FALSE, FALSE, 0);
01100 if (label_past)
01101 gtk_box_pack_start(GTK_BOX(widget), label_past, FALSE, FALSE, 0);
01102
01103 break;
01104 case WIDGET_CUSTOM:
01105 if (widgets[x].data.populate)
01106 widget = widgets[x].data.populate();
01107 else
01108 widget = NULL;
01109
01110 break;
01111 case WIDGET_FONT_BTN:
01112 widget = gtk_hbox_new(FALSE, 6);
01113
01114 GtkWidget *font_btn = NULL;
01115 create_font_btn (& widgets[x], & label, & font_btn, domain);
01116
01117 if (label)
01118 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01119 if (font_btn)
01120 gtk_box_pack_start(GTK_BOX(widget), font_btn, FALSE, FALSE, 0);
01121 break;
01122 case WIDGET_TABLE:
01123 widget = gtk_table_new(widgets[x].data.table.rows, 3, FALSE);
01124 fill_table (widget, widgets[x].data.table.elem,
01125 widgets[x].data.table.rows, domain);
01126 gtk_table_set_row_spacings(GTK_TABLE(widget), 6);
01127 break;
01128 case WIDGET_ENTRY:
01129 widget = gtk_hbox_new(FALSE, 6);
01130
01131 GtkWidget *entry = NULL;
01132 create_entry (& widgets[x], & label, & entry, domain);
01133
01134 if (label)
01135 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01136 if (entry)
01137 gtk_box_pack_start(GTK_BOX(widget), entry, TRUE, TRUE, 0);
01138 break;
01139 case WIDGET_COMBO_BOX:
01140 widget = gtk_hbox_new(FALSE, 6);
01141
01142 GtkWidget *combo = NULL;
01143 create_cbox (& widgets[x], & label, & combo, domain);
01144
01145 if (label)
01146 gtk_box_pack_start(GTK_BOX(widget), label, FALSE, FALSE, 0);
01147 if (combo)
01148 gtk_box_pack_start(GTK_BOX(widget), combo, FALSE, FALSE, 0);
01149 break;
01150 case WIDGET_BOX:
01151 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 0, 0);
01152
01153 if (widgets[x].data.box.horizontal) {
01154 widget = gtk_hbox_new(FALSE, 0);
01155 } else {
01156 widget = gtk_vbox_new(FALSE, 0);
01157 }
01158
01159 create_widgets_with_domain ((GtkBox *) widget,
01160 widgets[x].data.box.elem, widgets[x].data.box.n_elem, domain);
01161
01162 if (widgets[x].data.box.frame) {
01163 GtkWidget *tmp;
01164 tmp = widget;
01165
01166 widget = gtk_frame_new (dgettext (domain, widgets[x].label));
01167 gtk_container_add(GTK_CONTAINER(widget), tmp);
01168 }
01169 break;
01170 case WIDGET_NOTEBOOK:
01171 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 0, 0, 0);
01172
01173 widget = gtk_notebook_new();
01174
01175 gint i;
01176 for (i = 0; i<widgets[x].data.notebook.n_tabs; i++) {
01177 GtkWidget *vbox;
01178 vbox = gtk_vbox_new(FALSE, 5);
01179 create_widgets_with_domain ((GtkBox *) vbox,
01180 widgets[x].data.notebook.tabs[i].settings,
01181 widgets[x].data.notebook.tabs[i].n_settings, domain);
01182
01183 gtk_notebook_append_page (GTK_NOTEBOOK (widget), vbox,
01184 gtk_label_new (dgettext (domain,
01185 widgets[x].data.notebook.tabs[i].name)));
01186 }
01187 break;
01188 case WIDGET_SEPARATOR:
01189 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 6, 0, 0);
01190
01191 if (widgets[x].data.separator.horizontal == TRUE) {
01192 widget = gtk_hseparator_new();
01193 } else {
01194 widget = gtk_vseparator_new();
01195 }
01196 break;
01197 default:
01198 break;
01199 }
01200
01201 if (widget && !gtk_widget_get_parent(widget))
01202 gtk_container_add(GTK_CONTAINER(alignment), widget);
01203 if (widget && widgets[x].tooltip && widgets[x].type != WIDGET_SPIN_BTN)
01204 gtk_widget_set_tooltip_text (widget, dgettext (domain,
01205 widgets[x].tooltip));
01206 }
01207
01208 }
01209
01210 static GtkWidget *
01211 create_titlestring_tag_menu(void)
01212 {
01213 GtkWidget *titlestring_tag_menu, *menu_item;
01214 guint i;
01215
01216 titlestring_tag_menu = gtk_menu_new();
01217 for(i = 0; i < n_title_field_tags; i++) {
01218 menu_item = gtk_menu_item_new_with_label(_(title_field_tags[i].name));
01219 gtk_menu_shell_append(GTK_MENU_SHELL(titlestring_tag_menu), menu_item);
01220 g_signal_connect(menu_item, "activate",
01221 G_CALLBACK(titlestring_tag_menu_callback),
01222 GINT_TO_POINTER(i));
01223 };
01224 gtk_widget_show_all(titlestring_tag_menu);
01225
01226 return titlestring_tag_menu;
01227 }
01228
01229 static void show_numbers_cb (GtkToggleButton * numbers, void * unused)
01230 {
01231 cfg.show_numbers_in_pl = gtk_toggle_button_get_active (numbers);
01232
01233 hook_call ("title change", NULL);
01234
01235
01236 gchar * t = playlist_get_title (playlist_get_active ());
01237 playlist_set_title (playlist_get_active (), t);
01238 g_free (t);
01239 }
01240
01241 static void leading_zero_cb (GtkToggleButton * leading)
01242 {
01243 cfg.leading_zero = gtk_toggle_button_get_active (leading);
01244
01245 hook_call ("title change", NULL);
01246
01247
01248 gchar * t = playlist_get_title (playlist_get_active ());
01249 playlist_set_title (playlist_get_active (), t);
01250 g_free (t);
01251 }
01252
01253 static void
01254 create_playlist_category(void)
01255 {
01256 GtkWidget *vbox5;
01257 GtkWidget *alignment55;
01258 GtkWidget *label60;
01259 GtkWidget *alignment56;
01260 GtkWidget *table6;
01261 GtkWidget *titlestring_help_button;
01262 GtkWidget *image1;
01263 GtkWidget *titlestring_cbox;
01264 GtkWidget *label62;
01265 GtkWidget *label61;
01266 GtkWidget *alignment85;
01267 GtkWidget *label84;
01268 GtkWidget *alignment86;
01269 GtkWidget *hbox9;
01270 GtkWidget *vbox34;
01271 GtkWidget *image8;
01272 GtkWidget *titlestring_tag_menu = create_titlestring_tag_menu();
01273 GtkWidget * numbers_alignment, * numbers;
01274
01275 vbox5 = gtk_vbox_new (FALSE, 0);
01276 gtk_container_add ((GtkContainer *) category_notebook, vbox5);
01277
01278 create_widgets(GTK_BOX(vbox5), playlist_page_widgets, G_N_ELEMENTS(playlist_page_widgets));
01279
01280 alignment55 = gtk_alignment_new (0.5, 0.5, 1, 1);
01281 gtk_box_pack_start (GTK_BOX (vbox5), alignment55, FALSE, FALSE, 0);
01282 gtk_alignment_set_padding ((GtkAlignment *) alignment55, 12, 3, 0, 0);
01283
01284 label60 = gtk_label_new (_("<b>Song Display</b>"));
01285 gtk_container_add (GTK_CONTAINER (alignment55), label60);
01286 gtk_label_set_use_markup (GTK_LABEL (label60), TRUE);
01287 gtk_misc_set_alignment (GTK_MISC (label60), 0, 0.5);
01288
01289 numbers_alignment = gtk_alignment_new (0, 0, 0, 0);
01290 gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0);
01291 gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3);
01292
01293 numbers = gtk_check_button_new_with_label (_("Show song numbers"));
01294 gtk_toggle_button_set_active ((GtkToggleButton *) numbers,
01295 cfg.show_numbers_in_pl);
01296 g_signal_connect ((GObject *) numbers, "toggled", (GCallback)
01297 show_numbers_cb, 0);
01298 gtk_container_add ((GtkContainer *) numbers_alignment, numbers);
01299
01300 numbers_alignment = gtk_alignment_new (0, 0, 0, 0);
01301 gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0);
01302 gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3);
01303
01304 numbers = gtk_check_button_new_with_label (_("Show leading zeroes (02:00 "
01305 "instead of 2:00)"));
01306 gtk_toggle_button_set_active ((GtkToggleButton *) numbers, cfg.leading_zero);
01307 g_signal_connect ((GObject *) numbers, "toggled", (GCallback)
01308 leading_zero_cb, 0);
01309 gtk_container_add ((GtkContainer *) numbers_alignment, numbers);
01310
01311 alignment56 = gtk_alignment_new (0.5, 0.5, 1, 1);
01312 gtk_box_pack_start (GTK_BOX (vbox5), alignment56, FALSE, FALSE, 0);
01313 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment56), 0, 0, 12, 0);
01314
01315 table6 = gtk_table_new (2, 3, FALSE);
01316 gtk_container_add (GTK_CONTAINER (alignment56), table6);
01317 gtk_table_set_row_spacings (GTK_TABLE (table6), 4);
01318 gtk_table_set_col_spacings (GTK_TABLE (table6), 12);
01319
01320 titlestring_help_button = gtk_button_new ();
01321 gtk_table_attach (GTK_TABLE (table6), titlestring_help_button, 2, 3, 1, 2,
01322 (GtkAttachOptions) (0),
01323 (GtkAttachOptions) (0), 0, 0);
01324
01325 gtk_widget_set_can_focus (titlestring_help_button, FALSE);
01326 gtk_widget_set_tooltip_text (titlestring_help_button, _("Show information about titlestring format"));
01327 gtk_button_set_relief (GTK_BUTTON (titlestring_help_button), GTK_RELIEF_HALF);
01328 gtk_button_set_focus_on_click (GTK_BUTTON (titlestring_help_button), FALSE);
01329
01330 image1 = gtk_image_new_from_stock ("gtk-index", GTK_ICON_SIZE_BUTTON);
01331 gtk_container_add (GTK_CONTAINER (titlestring_help_button), image1);
01332
01333 titlestring_cbox = gtk_combo_box_text_new ();
01334 gtk_combo_box_set_active ((GtkComboBox *) titlestring_cbox, cfg.titlestring_preset);
01335
01336 gtk_table_attach (GTK_TABLE (table6), titlestring_cbox, 1, 3, 0, 1,
01337 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01338 (GtkAttachOptions) (0), 0, 0);
01339
01340 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("TITLE"));
01341 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - TITLE"));
01342 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TITLE"));
01343 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TRACK. TITLE"));
01344 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST [ ALBUM ] - TRACK. TITLE"));
01345 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ALBUM - TITLE"));
01346 gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("Custom"));
01347
01348 titlestring_entry = gtk_entry_new ();
01349 gtk_entry_set_text ((GtkEntry *) titlestring_entry, cfg.gentitle_format);
01350 gtk_widget_set_sensitive (titlestring_entry, cfg.titlestring_preset == n_titlestring_presets);
01351 gtk_table_attach (GTK_TABLE (table6), titlestring_entry, 1, 2, 1, 2,
01352 (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
01353 (GtkAttachOptions) (0), 0, 0);
01354
01355 label62 = gtk_label_new (_("Custom string:"));
01356 gtk_table_attach (GTK_TABLE (table6), label62, 0, 1, 1, 2,
01357 (GtkAttachOptions) (0),
01358 (GtkAttachOptions) (0), 0, 0);
01359 gtk_label_set_justify (GTK_LABEL (label62), GTK_JUSTIFY_RIGHT);
01360 gtk_misc_set_alignment (GTK_MISC (label62), 1, 0.5);
01361
01362 label61 = gtk_label_new (_("Title format:"));
01363 gtk_table_attach (GTK_TABLE (table6), label61, 0, 1, 0, 1,
01364 (GtkAttachOptions) (0),
01365 (GtkAttachOptions) (0), 0, 0);
01366 gtk_label_set_justify (GTK_LABEL (label61), GTK_JUSTIFY_RIGHT);
01367 gtk_misc_set_alignment (GTK_MISC (label61), 1, 0.5);
01368
01369 alignment85 = gtk_alignment_new (0.5, 0.5, 1, 1);
01370 gtk_box_pack_start (GTK_BOX (vbox5), alignment85, FALSE, FALSE, 0);
01371 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment85), 12, 12, 0, 0);
01372
01373 label84 = gtk_label_new (_("<b>Popup Information</b>"));
01374 gtk_container_add (GTK_CONTAINER (alignment85), label84);
01375 gtk_label_set_use_markup (GTK_LABEL (label84), TRUE);
01376 gtk_misc_set_alignment (GTK_MISC (label84), 0, 0.5);
01377
01378 alignment86 = gtk_alignment_new (0.5, 0.5, 1, 1);
01379 gtk_box_pack_start (GTK_BOX (vbox5), alignment86, FALSE, FALSE, 0);
01380 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment86), 0, 0, 12, 0);
01381
01382 hbox9 = gtk_hbox_new (FALSE, 12);
01383 gtk_container_add (GTK_CONTAINER (alignment86), hbox9);
01384
01385 vbox34 = gtk_vbox_new (FALSE, 0);
01386 gtk_box_pack_start (GTK_BOX (hbox9), vbox34, TRUE, TRUE, 0);
01387
01388 filepopupbutton = gtk_check_button_new_with_mnemonic (_("Show popup information for playlist entries"));
01389 gtk_widget_set_tooltip_text (filepopupbutton, _("Toggles popup information window for the pointed entry in the playlist. The window shows title of song, name of album, genre, year of publish, track number, track length, and artwork."));
01390 gtk_toggle_button_set_active ((GtkToggleButton *) filepopupbutton, cfg.show_filepopup_for_tuple);
01391 gtk_box_pack_start ((GtkBox *) vbox34, filepopupbutton, TRUE, FALSE, 0);
01392
01393 filepopup_for_tuple_settings_button = gtk_button_new ();
01394 gtk_widget_set_sensitive (filepopup_for_tuple_settings_button, cfg.show_filepopup_for_tuple);
01395 gtk_box_pack_start (GTK_BOX (hbox9), filepopup_for_tuple_settings_button, FALSE, FALSE, 0);
01396
01397 gtk_widget_set_can_focus (filepopup_for_tuple_settings_button, FALSE);
01398 gtk_widget_set_tooltip_text (filepopup_for_tuple_settings_button, _("Edit settings for popup information"));
01399 gtk_button_set_relief (GTK_BUTTON (filepopup_for_tuple_settings_button), GTK_RELIEF_HALF);
01400
01401 image8 = gtk_image_new_from_stock ("gtk-properties", GTK_ICON_SIZE_BUTTON);
01402 gtk_container_add (GTK_CONTAINER (filepopup_for_tuple_settings_button), image8);
01403
01404
01405
01406 g_signal_connect (filepopupbutton, "toggled",
01407 G_CALLBACK(on_show_filepopup_for_tuple_toggled),
01408 NULL);
01409 g_signal_connect(G_OBJECT(filepopup_for_tuple_settings_button), "clicked",
01410 G_CALLBACK(on_filepopup_for_tuple_settings_clicked),
01411 NULL);
01412
01413 g_signal_connect(titlestring_cbox, "changed",
01414 G_CALLBACK(on_titlestring_cbox_changed),
01415 titlestring_entry);
01416
01417 g_signal_connect(titlestring_cbox, "changed",
01418 G_CALLBACK(on_titlestring_cbox_changed),
01419 titlestring_help_button);
01420 g_signal_connect(titlestring_help_button, "clicked",
01421 G_CALLBACK(on_titlestring_help_button_clicked),
01422 titlestring_tag_menu);
01423
01424 g_signal_connect(G_OBJECT(titlestring_entry), "changed",
01425 G_CALLBACK(on_titlestring_entry_changed),
01426 NULL);
01427
01428
01429 create_filepopup_settings();
01430 }
01431
01432 static GtkWidget * output_config_button, * output_about_button;
01433
01434 static gboolean output_enum_cb (PluginHandle * plugin, GList * * list)
01435 {
01436 * list = g_list_prepend (* list, plugin);
01437 return TRUE;
01438 }
01439
01440 static GList * output_get_list (void)
01441 {
01442 static GList * list = NULL;
01443
01444 if (list == NULL)
01445 {
01446 plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_enum_cb,
01447 & list);
01448 list = g_list_reverse (list);
01449 }
01450
01451 return list;
01452 }
01453
01454 static void output_combo_update (GtkComboBox * combo)
01455 {
01456 PluginHandle * plugin = plugin_get_current (PLUGIN_TYPE_OUTPUT);
01457 gtk_combo_box_set_active (combo, g_list_index (output_get_list (), plugin));
01458 gtk_widget_set_sensitive (output_config_button, plugin_has_configure (plugin));
01459 gtk_widget_set_sensitive (output_about_button, plugin_has_about (plugin));
01460 }
01461
01462 static void output_combo_changed (GtkComboBox * combo)
01463 {
01464 PluginHandle * plugin = g_list_nth_data (output_get_list (),
01465 gtk_combo_box_get_active (combo));
01466 g_return_if_fail (plugin != NULL);
01467
01468 plugin_enable (plugin, TRUE);
01469 output_combo_update (combo);
01470 }
01471
01472 static void output_combo_fill (GtkComboBox * combo)
01473 {
01474 for (GList * node = output_get_list (); node != NULL; node = node->next)
01475 gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
01476 plugin_get_name (node->data));
01477 }
01478
01479 static void output_do_config (void)
01480 {
01481 OutputPlugin * op = plugin_get_header (output_plugin_get_current ());
01482 g_return_if_fail (op != NULL);
01483 if (op->configure != NULL)
01484 op->configure ();
01485 }
01486
01487 static void output_do_about (void)
01488 {
01489 OutputPlugin * op = plugin_get_header (output_plugin_get_current ());
01490 g_return_if_fail (op != NULL);
01491 if (op->about != NULL)
01492 op->about ();
01493 }
01494
01495 static void * create_output_plugin_box (void)
01496 {
01497 GtkWidget * hbox1 = gtk_hbox_new (FALSE, 6);
01498 gtk_box_pack_start ((GtkBox *) hbox1, gtk_label_new (_("Output plugin:")), FALSE, FALSE, 0);
01499
01500 GtkWidget * vbox = gtk_vbox_new (FALSE, 6);
01501 gtk_box_pack_start ((GtkBox *) hbox1, vbox, FALSE, FALSE, 0);
01502
01503 GtkWidget * hbox2 = gtk_hbox_new (FALSE, 6);
01504 gtk_box_pack_start ((GtkBox *) vbox, hbox2, FALSE, FALSE, 0);
01505
01506 GtkWidget * output_plugin_cbox = gtk_combo_box_text_new ();
01507 gtk_box_pack_start ((GtkBox *) hbox2, output_plugin_cbox, FALSE, FALSE, 0);
01508
01509 GtkWidget * hbox3 = gtk_hbox_new (FALSE, 6);
01510 gtk_box_pack_start ((GtkBox *) vbox, hbox3, FALSE, FALSE, 0);
01511
01512 output_config_button = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
01513 gtk_box_pack_start ((GtkBox *) hbox3, output_config_button, FALSE, FALSE, 0);
01514
01515 output_about_button = gtk_button_new_from_stock (GTK_STOCK_ABOUT);
01516 gtk_box_pack_start ((GtkBox *) hbox3, output_about_button, FALSE, FALSE, 0);
01517
01518 output_combo_fill ((GtkComboBox *) output_plugin_cbox);
01519 output_combo_update ((GtkComboBox *) output_plugin_cbox);
01520
01521 g_signal_connect (output_plugin_cbox, "changed", (GCallback) output_combo_changed, NULL);
01522 g_signal_connect (output_config_button, "clicked", (GCallback) output_do_config, NULL);
01523 g_signal_connect (output_about_button, "clicked", (GCallback) output_do_about, NULL);
01524
01525 return hbox1;
01526 }
01527
01528 static void create_audio_category (void)
01529 {
01530 GtkWidget * audio_page_vbox = gtk_vbox_new (FALSE, 0);
01531 create_widgets ((GtkBox *) audio_page_vbox, audio_page_widgets, G_N_ELEMENTS (audio_page_widgets));
01532 gtk_container_add ((GtkContainer *) category_notebook, audio_page_vbox);
01533 }
01534
01535 static void
01536 create_connectivity_category(void)
01537 {
01538 GtkWidget *connectivity_page_vbox;
01539 GtkWidget *vbox29;
01540
01541 connectivity_page_vbox = gtk_vbox_new (FALSE, 0);
01542 gtk_container_add (GTK_CONTAINER (category_notebook), connectivity_page_vbox);
01543
01544 vbox29 = gtk_vbox_new (FALSE, 0);
01545 gtk_box_pack_start (GTK_BOX (connectivity_page_vbox), vbox29, TRUE, TRUE, 0);
01546
01547 create_widgets(GTK_BOX(vbox29), connectivity_page_widgets, G_N_ELEMENTS(connectivity_page_widgets));
01548 }
01549
01550 static void create_plugin_category (void)
01551 {
01552 GtkWidget * notebook = gtk_notebook_new ();
01553 gtk_container_add ((GtkContainer *) category_notebook, notebook);
01554
01555 gint types[] = {PLUGIN_TYPE_TRANSPORT, PLUGIN_TYPE_PLAYLIST,
01556 PLUGIN_TYPE_INPUT, PLUGIN_TYPE_EFFECT, PLUGIN_TYPE_VIS, PLUGIN_TYPE_GENERAL};
01557 const gchar * names[] = {N_("Transport"), N_("Playlist"), N_("Input"),
01558 N_("Effect"), N_("Visualization"), N_("General")};
01559
01560 for (gint i = 0; i < G_N_ELEMENTS (types); i ++)
01561 gtk_notebook_append_page ((GtkNotebook *) notebook, plugin_view_new
01562 (types[i]), gtk_label_new (_(names[i])));
01563 }
01564
01565 static gboolean
01566 prefswin_destroy(GtkWidget *window, GdkEvent *event, gpointer data)
01567 {
01568 prefswin = NULL;
01569 category_notebook = NULL;
01570 gtk_widget_destroy(filepopup_settings);
01571 filepopup_settings = NULL;
01572 gtk_widget_destroy(window);
01573 return TRUE;
01574 }
01575
01576
01577 void * * create_prefs_window (void)
01578 {
01579 gchar *aud_version_string;
01580
01581 GtkWidget *vbox;
01582 GtkWidget *hbox1;
01583 GtkWidget *scrolledwindow6;
01584 GtkWidget *hseparator1;
01585 GtkWidget *hbox4;
01586 GtkWidget *audversionlabel;
01587 GtkWidget *prefswin_button_box;
01588 GtkWidget *hbox11;
01589 GtkWidget *image10;
01590 GtkWidget *close;
01591 GtkAccelGroup *accel_group;
01592
01593 accel_group = gtk_accel_group_new ();
01594
01595 prefswin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
01596 gtk_window_set_type_hint (GTK_WINDOW (prefswin), GDK_WINDOW_TYPE_HINT_DIALOG);
01597 gtk_container_set_border_width (GTK_CONTAINER (prefswin), 12);
01598 gtk_window_set_title (GTK_WINDOW (prefswin), _("Audacious Preferences"));
01599 gtk_window_set_position (GTK_WINDOW (prefswin), GTK_WIN_POS_CENTER);
01600 gtk_window_set_default_size (GTK_WINDOW (prefswin), 680, 400);
01601
01602 vbox = gtk_vbox_new (FALSE, 0);
01603 gtk_container_add (GTK_CONTAINER (prefswin), vbox);
01604
01605 hbox1 = gtk_hbox_new (FALSE, 8);
01606 gtk_box_pack_start (GTK_BOX (vbox), hbox1, TRUE, TRUE, 0);
01607
01608 scrolledwindow6 = gtk_scrolled_window_new (NULL, NULL);
01609 gtk_box_pack_start (GTK_BOX (hbox1), scrolledwindow6, FALSE, FALSE, 0);
01610 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
01611 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow6), GTK_SHADOW_IN);
01612
01613 category_treeview = gtk_tree_view_new ();
01614 gtk_container_add (GTK_CONTAINER (scrolledwindow6), category_treeview);
01615 gtk_widget_set_size_request (scrolledwindow6, 168, -1);
01616 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (category_treeview), FALSE);
01617
01618 category_notebook = gtk_notebook_new ();
01619 gtk_box_pack_start (GTK_BOX (hbox1), category_notebook, TRUE, TRUE, 0);
01620
01621 gtk_widget_set_can_focus (category_notebook, FALSE);
01622 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (category_notebook), FALSE);
01623 gtk_notebook_set_show_border (GTK_NOTEBOOK (category_notebook), FALSE);
01624 gtk_notebook_set_scrollable (GTK_NOTEBOOK (category_notebook), TRUE);
01625
01626 create_audio_category();
01627 create_connectivity_category();
01628 create_playlist_category();
01629 create_plugin_category();
01630
01631 hseparator1 = gtk_hseparator_new ();
01632 gtk_box_pack_start (GTK_BOX (vbox), hseparator1, FALSE, FALSE, 6);
01633
01634 hbox4 = gtk_hbox_new (FALSE, 0);
01635 gtk_box_pack_start (GTK_BOX (vbox), hbox4, FALSE, FALSE, 0);
01636
01637 audversionlabel = gtk_label_new ("");
01638 gtk_box_pack_start (GTK_BOX (hbox4), audversionlabel, FALSE, FALSE, 0);
01639 gtk_label_set_use_markup (GTK_LABEL (audversionlabel), TRUE);
01640
01641 prefswin_button_box = gtk_hbutton_box_new ();
01642 gtk_box_pack_start (GTK_BOX (hbox4), prefswin_button_box, TRUE, TRUE, 0);
01643 gtk_button_box_set_layout (GTK_BUTTON_BOX (prefswin_button_box), GTK_BUTTONBOX_END);
01644 gtk_box_set_spacing (GTK_BOX (prefswin_button_box), 6);
01645
01646 hbox11 = gtk_hbox_new (FALSE, 2);
01647
01648 image10 = gtk_image_new_from_stock ("gtk-refresh", GTK_ICON_SIZE_BUTTON);
01649 gtk_box_pack_start (GTK_BOX (hbox11), image10, FALSE, FALSE, 0);
01650
01651 close = gtk_button_new_from_stock ("gtk-close");
01652 gtk_container_add (GTK_CONTAINER (prefswin_button_box), close);
01653 gtk_widget_set_can_default(close, TRUE);
01654 gtk_widget_add_accelerator (close, "clicked", accel_group,
01655 GDK_Escape, (GdkModifierType) 0,
01656 GTK_ACCEL_VISIBLE);
01657
01658
01659 gtk_window_add_accel_group (GTK_WINDOW (prefswin), accel_group);
01660
01661
01662 g_signal_connect(G_OBJECT(prefswin), "delete_event",
01663 G_CALLBACK(prefswin_destroy),
01664 NULL);
01665 g_signal_connect_swapped(G_OBJECT(close), "clicked",
01666 G_CALLBACK(prefswin_destroy),
01667 prefswin);
01668
01669
01670 fill_category_list ((GtkTreeView *) category_treeview, (GtkNotebook *) category_notebook);
01671
01672
01673
01674 aud_version_string = g_strdup_printf
01675 ("<span size='small'>%s (%s)</span>", "Audacious " PACKAGE_VERSION,
01676 BUILDSTAMP);
01677
01678 gtk_label_set_markup( GTK_LABEL(audversionlabel) , aud_version_string );
01679 g_free(aud_version_string);
01680 gtk_widget_show_all(vbox);
01681
01682 return & prefswin;
01683 }
01684
01685 void
01686 destroy_prefs_window(void)
01687 {
01688 prefswin_destroy(prefswin, NULL, NULL);
01689 }
01690
01691 void show_prefs_window (void)
01692 {
01693 if (! prefswin)
01694 create_prefs_window ();
01695
01696 gtk_window_present ((GtkWindow *) prefswin);
01697 }
01698
01699 void
01700 hide_prefs_window(void)
01701 {
01702 g_return_if_fail(prefswin);
01703 gtk_widget_hide(GTK_WIDGET(prefswin));
01704 }
01705
01706 static void prefswin_page_queue_new (GtkWidget * container, const gchar * name,
01707 const gchar * imgurl)
01708 {
01709 CategoryQueueEntry *ent = g_new0(CategoryQueueEntry, 1);
01710
01711 ent->container = container;
01712 ent->pg_name = name;
01713 ent->img_url = imgurl;
01714
01715 if (category_queue)
01716 ent->next = category_queue;
01717
01718 category_queue = ent;
01719 }
01720
01721 static void
01722 prefswin_page_queue_destroy(CategoryQueueEntry *ent)
01723 {
01724 category_queue = ent->next;
01725 g_free(ent);
01726 }
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741 gint prefswin_page_new (void * container, const gchar * name, const gchar *
01742 imgurl)
01743 {
01744 GtkTreeModel *model;
01745 GtkTreeIter iter;
01746 GdkPixbuf *img = NULL;
01747 GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview);
01748 gint id;
01749
01750 if (treeview == NULL || category_notebook == NULL)
01751 {
01752 prefswin_page_queue_new(container, name, imgurl);
01753 return -1;
01754 }
01755
01756 model = gtk_tree_view_get_model(treeview);
01757
01758 if (model == NULL)
01759 {
01760 prefswin_page_queue_new(container, name, imgurl);
01761 return -1;
01762 }
01763
01764
01765 gtk_widget_show(container);
01766 id = gtk_notebook_append_page(GTK_NOTEBOOK(category_notebook), container, NULL);
01767
01768 if (id == -1)
01769 return -1;
01770
01771 if (imgurl != NULL)
01772 img = gdk_pixbuf_new_from_file(imgurl, NULL);
01773
01774 gtk_list_store_append(GTK_LIST_STORE(model), &iter);
01775 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
01776 CATEGORY_VIEW_COL_ICON, img,
01777 CATEGORY_VIEW_COL_NAME,
01778 name, CATEGORY_VIEW_COL_ID, id, -1);
01779
01780 if (img != NULL)
01781 g_object_unref(img);
01782
01783 return id;
01784 }
01785
01786 void
01787 prefswin_page_destroy(GtkWidget *container)
01788 {
01789 GtkTreeModel *model;
01790 GtkTreeIter iter;
01791 GtkTreeView *treeview = GTK_TREE_VIEW(category_treeview);
01792 gboolean ret;
01793 gint id;
01794 gint index = -1;
01795
01796 if (category_notebook == NULL || treeview == NULL || container == NULL)
01797 return;
01798
01799 id = gtk_notebook_page_num(GTK_NOTEBOOK(category_notebook), container);
01800
01801 if (id == -1)
01802 return;
01803
01804 gtk_notebook_remove_page(GTK_NOTEBOOK(category_notebook), id);
01805
01806 model = gtk_tree_view_get_model(treeview);
01807
01808 if (model == NULL)
01809 return;
01810
01811 ret = gtk_tree_model_get_iter_first(model, &iter);
01812
01813 while (ret == TRUE)
01814 {
01815 gtk_tree_model_get(model, &iter, CATEGORY_VIEW_COL_ID, &index, -1);
01816
01817 if (index == id)
01818 {
01819 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
01820 ret = gtk_tree_model_get_iter_first(model, &iter);
01821 continue;
01822 }
01823
01824 if (index > id)
01825 {
01826 index--;
01827 gtk_list_store_set(GTK_LIST_STORE(model), &iter, CATEGORY_VIEW_COL_ID, index, -1);
01828 }
01829
01830 ret = gtk_tree_model_iter_next(model, &iter);
01831 }
01832 }
01833
01834 static void sw_volume_toggled (void)
01835 {
01836 gint vol[2];
01837
01838 if (cfg.software_volume_control)
01839 {
01840 vol[0] = cfg.sw_volume_left;
01841 vol[1] = cfg.sw_volume_right;
01842 }
01843 else
01844 playback_get_volume (& vol[0], & vol[1]);
01845
01846 hook_call ("volume set", vol);
01847 }