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