1 /* Hey EMACS -*- linux-c -*- */ 2 /* 3 * 4 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info> 5 * Released under the terms of the GNU GPL v2.0. 6 * 7 */ 8 9 #ifdef HAVE_CONFIG_H 10 # include <config.h> 11 #endif 12 13 #include <stdlib.h> 14 #include "lkc.h" 15 #include "images.c" 16 17 #include <glade/glade.h> 18 #include <gtk/gtk.h> 19 #include <glib.h> 20 #include <gdk/gdkkeysyms.h> 21 22 #include <stdio.h> 23 #include <string.h> 24 #include <unistd.h> 25 #include <time.h> 26 27 //#define DEBUG 28 29 enum { 30 SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW 31 }; 32 33 enum { 34 OPT_NORMAL, OPT_ALL, OPT_PROMPT 35 }; 36 37 static gint view_mode = FULL_VIEW; 38 static gboolean show_name = TRUE; 39 static gboolean show_range = TRUE; 40 static gboolean show_value = TRUE; 41 static gboolean resizeable = FALSE; 42 static int opt_mode = OPT_NORMAL; 43 44 GtkWidget *main_wnd = NULL; 45 GtkWidget *tree1_w = NULL; // left frame 46 GtkWidget *tree2_w = NULL; // right frame 47 GtkWidget *text_w = NULL; 48 GtkWidget *hpaned = NULL; 49 GtkWidget *vpaned = NULL; 50 GtkWidget *back_btn = NULL; 51 GtkWidget *save_btn = NULL; 52 GtkWidget *save_menu_item = NULL; 53 54 GtkTextTag *tag1, *tag2; 55 GdkColor color; 56 57 GtkTreeStore *tree1, *tree2, *tree; 58 GtkTreeModel *model1, *model2; 59 static GtkTreeIter *parents[256]; 60 static gint indent; 61 62 static struct menu *current; // current node for SINGLE view 63 static struct menu *browsed; // browsed node for SPLIT view 64 65 enum { 66 COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE, 67 COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF, 68 COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD, 69 COL_NUMBER 70 }; 71 72 static void display_list(void); 73 static void display_tree(struct menu *menu); 74 static void display_tree_part(void); 75 static void update_tree(struct menu *src, GtkTreeIter * dst); 76 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row); 77 static gchar **fill_row(struct menu *menu); 78 static void conf_changed(void); 79 80 /* Helping/Debugging Functions */ 81 82 const char *dbg_sym_flags(int val) 83 { 84 static char buf[256]; 85 86 bzero(buf, 256); 87 88 if (val & SYMBOL_CONST) 89 strcat(buf, "const/"); 90 if (val & SYMBOL_CHECK) 91 strcat(buf, "check/"); 92 if (val & SYMBOL_CHOICE) 93 strcat(buf, "choice/"); 94 if (val & SYMBOL_CHOICEVAL) 95 strcat(buf, "choiceval/"); 96 if (val & SYMBOL_VALID) 97 strcat(buf, "valid/"); 98 if (val & SYMBOL_OPTIONAL) 99 strcat(buf, "optional/"); 100 if (val & SYMBOL_WRITE) 101 strcat(buf, "write/"); 102 if (val & SYMBOL_CHANGED) 103 strcat(buf, "changed/"); 104 if (val & SYMBOL_NO_WRITE) 105 strcat(buf, "no_write/"); 106 107 buf[strlen(buf) - 1] = '\0'; 108 109 return buf; 110 } 111 112 void replace_button_icon(GladeXML * xml, GdkDrawable * window, 113 GtkStyle * style, gchar * btn_name, gchar ** xpm) 114 { 115 GdkPixmap *pixmap; 116 GdkBitmap *mask; 117 GtkToolButton *button; 118 GtkWidget *image; 119 120 pixmap = gdk_pixmap_create_from_xpm_d(window, &mask, 121 &style->bg[GTK_STATE_NORMAL], 122 xpm); 123 124 button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name)); 125 image = gtk_image_new_from_pixmap(pixmap, mask); 126 gtk_widget_show(image); 127 gtk_tool_button_set_icon_widget(button, image); 128 } 129 130 /* Main Window Initialization */ 131 void init_main_window(const gchar * glade_file) 132 { 133 GladeXML *xml; 134 GtkWidget *widget; 135 GtkTextBuffer *txtbuf; 136 GtkStyle *style; 137 138 xml = glade_xml_new(glade_file, "window1", NULL); 139 if (!xml) 140 g_error("GUI loading failed !\n"); 141 glade_xml_signal_autoconnect(xml); 142 143 main_wnd = glade_xml_get_widget(xml, "window1"); 144 hpaned = glade_xml_get_widget(xml, "hpaned1"); 145 vpaned = glade_xml_get_widget(xml, "vpaned1"); 146 tree1_w = glade_xml_get_widget(xml, "treeview1"); 147 tree2_w = glade_xml_get_widget(xml, "treeview2"); 148 text_w = glade_xml_get_widget(xml, "textview3"); 149 150 back_btn = glade_xml_get_widget(xml, "button1"); 151 gtk_widget_set_sensitive(back_btn, FALSE); 152 153 widget = glade_xml_get_widget(xml, "show_name1"); 154 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 155 show_name); 156 157 widget = glade_xml_get_widget(xml, "show_range1"); 158 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 159 show_range); 160 161 widget = glade_xml_get_widget(xml, "show_data1"); 162 gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget, 163 show_value); 164 165 save_btn = glade_xml_get_widget(xml, "button3"); 166 save_menu_item = glade_xml_get_widget(xml, "save1"); 167 conf_set_changed_callback(conf_changed); 168 169 style = gtk_widget_get_style(main_wnd); 170 widget = glade_xml_get_widget(xml, "toolbar1"); 171 172 replace_button_icon(xml, main_wnd->window, style, 173 "button4", (gchar **) xpm_single_view); 174 replace_button_icon(xml, main_wnd->window, style, 175 "button5", (gchar **) xpm_split_view); 176 replace_button_icon(xml, main_wnd->window, style, 177 "button6", (gchar **) xpm_tree_view); 178 179 txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 180 tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1", 181 "foreground", "red", 182 "weight", PANGO_WEIGHT_BOLD, 183 NULL); 184 tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2", 185 /*"style", PANGO_STYLE_OBLIQUE, */ 186 NULL); 187 188 gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text); 189 190 gtk_widget_show(main_wnd); 191 } 192 193 void init_tree_model(void) 194 { 195 gint i; 196 197 tree = tree2 = gtk_tree_store_new(COL_NUMBER, 198 G_TYPE_STRING, G_TYPE_STRING, 199 G_TYPE_STRING, G_TYPE_STRING, 200 G_TYPE_STRING, G_TYPE_STRING, 201 G_TYPE_POINTER, GDK_TYPE_COLOR, 202 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 203 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 204 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 205 G_TYPE_BOOLEAN); 206 model2 = GTK_TREE_MODEL(tree2); 207 208 for (parents[0] = NULL, i = 1; i < 256; i++) 209 parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter)); 210 211 tree1 = gtk_tree_store_new(COL_NUMBER, 212 G_TYPE_STRING, G_TYPE_STRING, 213 G_TYPE_STRING, G_TYPE_STRING, 214 G_TYPE_STRING, G_TYPE_STRING, 215 G_TYPE_POINTER, GDK_TYPE_COLOR, 216 G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF, 217 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 218 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, 219 G_TYPE_BOOLEAN); 220 model1 = GTK_TREE_MODEL(tree1); 221 } 222 223 void init_left_tree(void) 224 { 225 GtkTreeView *view = GTK_TREE_VIEW(tree1_w); 226 GtkCellRenderer *renderer; 227 GtkTreeSelection *sel; 228 GtkTreeViewColumn *column; 229 230 gtk_tree_view_set_model(view, model1); 231 gtk_tree_view_set_headers_visible(view, TRUE); 232 gtk_tree_view_set_rules_hint(view, TRUE); 233 234 column = gtk_tree_view_column_new(); 235 gtk_tree_view_append_column(view, column); 236 gtk_tree_view_column_set_title(column, "Options"); 237 238 renderer = gtk_cell_renderer_toggle_new(); 239 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 240 renderer, FALSE); 241 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 242 renderer, 243 "active", COL_BTNACT, 244 "inconsistent", COL_BTNINC, 245 "visible", COL_BTNVIS, 246 "radio", COL_BTNRAD, NULL); 247 renderer = gtk_cell_renderer_text_new(); 248 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 249 renderer, FALSE); 250 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 251 renderer, 252 "text", COL_OPTION, 253 "foreground-gdk", 254 COL_COLOR, NULL); 255 256 sel = gtk_tree_view_get_selection(view); 257 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 258 gtk_widget_realize(tree1_w); 259 } 260 261 static void renderer_edited(GtkCellRendererText * cell, 262 const gchar * path_string, 263 const gchar * new_text, gpointer user_data); 264 265 void init_right_tree(void) 266 { 267 GtkTreeView *view = GTK_TREE_VIEW(tree2_w); 268 GtkCellRenderer *renderer; 269 GtkTreeSelection *sel; 270 GtkTreeViewColumn *column; 271 gint i; 272 273 gtk_tree_view_set_model(view, model2); 274 gtk_tree_view_set_headers_visible(view, TRUE); 275 gtk_tree_view_set_rules_hint(view, TRUE); 276 277 column = gtk_tree_view_column_new(); 278 gtk_tree_view_append_column(view, column); 279 gtk_tree_view_column_set_title(column, "Options"); 280 281 renderer = gtk_cell_renderer_pixbuf_new(); 282 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 283 renderer, FALSE); 284 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 285 renderer, 286 "pixbuf", COL_PIXBUF, 287 "visible", COL_PIXVIS, NULL); 288 renderer = gtk_cell_renderer_toggle_new(); 289 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 290 renderer, FALSE); 291 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 292 renderer, 293 "active", COL_BTNACT, 294 "inconsistent", COL_BTNINC, 295 "visible", COL_BTNVIS, 296 "radio", COL_BTNRAD, NULL); 297 renderer = gtk_cell_renderer_text_new(); 298 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), 299 renderer, FALSE); 300 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), 301 renderer, 302 "text", COL_OPTION, 303 "foreground-gdk", 304 COL_COLOR, NULL); 305 306 renderer = gtk_cell_renderer_text_new(); 307 gtk_tree_view_insert_column_with_attributes(view, -1, 308 "Name", renderer, 309 "text", COL_NAME, 310 "foreground-gdk", 311 COL_COLOR, NULL); 312 renderer = gtk_cell_renderer_text_new(); 313 gtk_tree_view_insert_column_with_attributes(view, -1, 314 "N", renderer, 315 "text", COL_NO, 316 "foreground-gdk", 317 COL_COLOR, NULL); 318 renderer = gtk_cell_renderer_text_new(); 319 gtk_tree_view_insert_column_with_attributes(view, -1, 320 "M", renderer, 321 "text", COL_MOD, 322 "foreground-gdk", 323 COL_COLOR, NULL); 324 renderer = gtk_cell_renderer_text_new(); 325 gtk_tree_view_insert_column_with_attributes(view, -1, 326 "Y", renderer, 327 "text", COL_YES, 328 "foreground-gdk", 329 COL_COLOR, NULL); 330 renderer = gtk_cell_renderer_text_new(); 331 gtk_tree_view_insert_column_with_attributes(view, -1, 332 "Value", renderer, 333 "text", COL_VALUE, 334 "editable", 335 COL_EDIT, 336 "foreground-gdk", 337 COL_COLOR, NULL); 338 g_signal_connect(G_OBJECT(renderer), "edited", 339 G_CALLBACK(renderer_edited), NULL); 340 341 column = gtk_tree_view_get_column(view, COL_NAME); 342 gtk_tree_view_column_set_visible(column, show_name); 343 column = gtk_tree_view_get_column(view, COL_NO); 344 gtk_tree_view_column_set_visible(column, show_range); 345 column = gtk_tree_view_get_column(view, COL_MOD); 346 gtk_tree_view_column_set_visible(column, show_range); 347 column = gtk_tree_view_get_column(view, COL_YES); 348 gtk_tree_view_column_set_visible(column, show_range); 349 column = gtk_tree_view_get_column(view, COL_VALUE); 350 gtk_tree_view_column_set_visible(column, show_value); 351 352 if (resizeable) { 353 for (i = 0; i < COL_VALUE; i++) { 354 column = gtk_tree_view_get_column(view, i); 355 gtk_tree_view_column_set_resizable(column, TRUE); 356 } 357 } 358 359 sel = gtk_tree_view_get_selection(view); 360 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); 361 } 362 363 364 /* Utility Functions */ 365 366 367 static void text_insert_help(struct menu *menu) 368 { 369 GtkTextBuffer *buffer; 370 GtkTextIter start, end; 371 const char *prompt = menu_get_prompt(menu); 372 struct gstr help = str_new(); 373 374 menu_get_ext_help(menu, &help); 375 376 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 377 gtk_text_buffer_get_bounds(buffer, &start, &end); 378 gtk_text_buffer_delete(buffer, &start, &end); 379 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); 380 381 gtk_text_buffer_get_end_iter(buffer, &end); 382 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1, 383 NULL); 384 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); 385 gtk_text_buffer_get_end_iter(buffer, &end); 386 gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2, 387 NULL); 388 str_free(&help); 389 } 390 391 392 static void text_insert_msg(const char *title, const char *message) 393 { 394 GtkTextBuffer *buffer; 395 GtkTextIter start, end; 396 const char *msg = message; 397 398 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w)); 399 gtk_text_buffer_get_bounds(buffer, &start, &end); 400 gtk_text_buffer_delete(buffer, &start, &end); 401 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15); 402 403 gtk_text_buffer_get_end_iter(buffer, &end); 404 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1, 405 NULL); 406 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2); 407 gtk_text_buffer_get_end_iter(buffer, &end); 408 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2, 409 NULL); 410 } 411 412 413 /* Main Windows Callbacks */ 414 415 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data); 416 gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event, 417 gpointer user_data) 418 { 419 GtkWidget *dialog, *label; 420 gint result; 421 422 if (!conf_get_changed()) 423 return FALSE; 424 425 dialog = gtk_dialog_new_with_buttons("Warning !", 426 GTK_WINDOW(main_wnd), 427 (GtkDialogFlags) 428 (GTK_DIALOG_MODAL | 429 GTK_DIALOG_DESTROY_WITH_PARENT), 430 GTK_STOCK_OK, 431 GTK_RESPONSE_YES, 432 GTK_STOCK_NO, 433 GTK_RESPONSE_NO, 434 GTK_STOCK_CANCEL, 435 GTK_RESPONSE_CANCEL, NULL); 436 gtk_dialog_set_default_response(GTK_DIALOG(dialog), 437 GTK_RESPONSE_CANCEL); 438 439 label = gtk_label_new("\nSave configuration ?\n"); 440 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label); 441 gtk_widget_show(label); 442 443 result = gtk_dialog_run(GTK_DIALOG(dialog)); 444 switch (result) { 445 case GTK_RESPONSE_YES: 446 on_save_activate(NULL, NULL); 447 return FALSE; 448 case GTK_RESPONSE_NO: 449 return FALSE; 450 case GTK_RESPONSE_CANCEL: 451 case GTK_RESPONSE_DELETE_EVENT: 452 default: 453 gtk_widget_destroy(dialog); 454 return TRUE; 455 } 456 457 return FALSE; 458 } 459 460 461 void on_window1_destroy(GtkObject * object, gpointer user_data) 462 { 463 gtk_main_quit(); 464 } 465 466 467 void 468 on_window1_size_request(GtkWidget * widget, 469 GtkRequisition * requisition, gpointer user_data) 470 { 471 static gint old_h; 472 gint w, h; 473 474 if (widget->window == NULL) 475 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); 476 else 477 gdk_window_get_size(widget->window, &w, &h); 478 479 if (h == old_h) 480 return; 481 old_h = h; 482 483 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3); 484 } 485 486 487 /* Menu & Toolbar Callbacks */ 488 489 490 static void 491 load_filename(GtkFileSelection * file_selector, gpointer user_data) 492 { 493 const gchar *fn; 494 495 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION 496 (user_data)); 497 498 if (conf_read(fn)) 499 text_insert_msg("Error", "Unable to load configuration !"); 500 else 501 display_tree(&rootmenu); 502 } 503 504 void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data) 505 { 506 GtkWidget *fs; 507 508 fs = gtk_file_selection_new("Load file..."); 509 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), 510 "clicked", 511 G_CALLBACK(load_filename), (gpointer) fs); 512 g_signal_connect_swapped(GTK_OBJECT 513 (GTK_FILE_SELECTION(fs)->ok_button), 514 "clicked", G_CALLBACK(gtk_widget_destroy), 515 (gpointer) fs); 516 g_signal_connect_swapped(GTK_OBJECT 517 (GTK_FILE_SELECTION(fs)->cancel_button), 518 "clicked", G_CALLBACK(gtk_widget_destroy), 519 (gpointer) fs); 520 gtk_widget_show(fs); 521 } 522 523 524 void on_save_activate(GtkMenuItem * menuitem, gpointer user_data) 525 { 526 if (conf_write(NULL)) 527 text_insert_msg("Error", "Unable to save configuration !"); 528 conf_write_autoconf(0); 529 } 530 531 532 static void 533 store_filename(GtkFileSelection * file_selector, gpointer user_data) 534 { 535 const gchar *fn; 536 537 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION 538 (user_data)); 539 540 if (conf_write(fn)) 541 text_insert_msg("Error", "Unable to save configuration !"); 542 543 gtk_widget_destroy(GTK_WIDGET(user_data)); 544 } 545 546 void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data) 547 { 548 GtkWidget *fs; 549 550 fs = gtk_file_selection_new("Save file as..."); 551 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button), 552 "clicked", 553 G_CALLBACK(store_filename), (gpointer) fs); 554 g_signal_connect_swapped(GTK_OBJECT 555 (GTK_FILE_SELECTION(fs)->ok_button), 556 "clicked", G_CALLBACK(gtk_widget_destroy), 557 (gpointer) fs); 558 g_signal_connect_swapped(GTK_OBJECT 559 (GTK_FILE_SELECTION(fs)->cancel_button), 560 "clicked", G_CALLBACK(gtk_widget_destroy), 561 (gpointer) fs); 562 gtk_widget_show(fs); 563 } 564 565 566 void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data) 567 { 568 if (!on_window1_delete_event(NULL, NULL, NULL)) 569 gtk_widget_destroy(GTK_WIDGET(main_wnd)); 570 } 571 572 573 void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data) 574 { 575 GtkTreeViewColumn *col; 576 577 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active; 578 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME); 579 if (col) 580 gtk_tree_view_column_set_visible(col, show_name); 581 } 582 583 584 void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data) 585 { 586 GtkTreeViewColumn *col; 587 588 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active; 589 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO); 590 if (col) 591 gtk_tree_view_column_set_visible(col, show_range); 592 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD); 593 if (col) 594 gtk_tree_view_column_set_visible(col, show_range); 595 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES); 596 if (col) 597 gtk_tree_view_column_set_visible(col, show_range); 598 599 } 600 601 602 void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data) 603 { 604 GtkTreeViewColumn *col; 605 606 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active; 607 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE); 608 if (col) 609 gtk_tree_view_column_set_visible(col, show_value); 610 } 611 612 613 void 614 on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data) 615 { 616 opt_mode = OPT_NORMAL; 617 gtk_tree_store_clear(tree2); 618 display_tree(&rootmenu); /* instead of update_tree to speed-up */ 619 } 620 621 622 void 623 on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data) 624 { 625 opt_mode = OPT_ALL; 626 gtk_tree_store_clear(tree2); 627 display_tree(&rootmenu); /* instead of update_tree to speed-up */ 628 } 629 630 631 void 632 on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data) 633 { 634 opt_mode = OPT_PROMPT; 635 gtk_tree_store_clear(tree2); 636 display_tree(&rootmenu); /* instead of update_tree to speed-up */ 637 } 638 639 640 void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data) 641 { 642 GtkWidget *dialog; 643 const gchar *intro_text = 644 "Welcome to gkc, the GTK+ graphical configuration tool\n" 645 "For each option, a blank box indicates the feature is disabled, a\n" 646 "check indicates it is enabled, and a dot indicates that it is to\n" 647 "be compiled as a module. Clicking on the box will cycle through the three states.\n" 648 "\n" 649 "If you do not see an option (e.g., a device driver) that you\n" 650 "believe should be present, try turning on Show All Options\n" 651 "under the Options menu.\n" 652 "Although there is no cross reference yet to help you figure out\n" 653 "what other options must be enabled to support the option you\n" 654 "are interested in, you can still view the help of a grayed-out\n" 655 "option.\n" 656 "\n" 657 "Toggling Show Debug Info under the Options menu will show \n" 658 "the dependencies, which you can then match by examining other options."; 659 660 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), 661 GTK_DIALOG_DESTROY_WITH_PARENT, 662 GTK_MESSAGE_INFO, 663 GTK_BUTTONS_CLOSE, "%s", intro_text); 664 g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 665 G_CALLBACK(gtk_widget_destroy), 666 GTK_OBJECT(dialog)); 667 gtk_widget_show_all(dialog); 668 } 669 670 671 void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data) 672 { 673 GtkWidget *dialog; 674 const gchar *about_text = 675 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n" 676 "Based on the source code from Roman Zippel.\n"; 677 678 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), 679 GTK_DIALOG_DESTROY_WITH_PARENT, 680 GTK_MESSAGE_INFO, 681 GTK_BUTTONS_CLOSE, "%s", about_text); 682 g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 683 G_CALLBACK(gtk_widget_destroy), 684 GTK_OBJECT(dialog)); 685 gtk_widget_show_all(dialog); 686 } 687 688 689 void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data) 690 { 691 GtkWidget *dialog; 692 const gchar *license_text = 693 "gkc is released under the terms of the GNU GPL v2.\n" 694 "For more information, please see the source code or\n" 695 "visit http://www.fsf.org/licenses/licenses.html\n"; 696 697 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd), 698 GTK_DIALOG_DESTROY_WITH_PARENT, 699 GTK_MESSAGE_INFO, 700 GTK_BUTTONS_CLOSE, "%s", license_text); 701 g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 702 G_CALLBACK(gtk_widget_destroy), 703 GTK_OBJECT(dialog)); 704 gtk_widget_show_all(dialog); 705 } 706 707 708 void on_back_clicked(GtkButton * button, gpointer user_data) 709 { 710 enum prop_type ptype; 711 712 current = current->parent; 713 ptype = current->prompt ? current->prompt->type : P_UNKNOWN; 714 if (ptype != P_MENU) 715 current = current->parent; 716 display_tree_part(); 717 718 if (current == &rootmenu) 719 gtk_widget_set_sensitive(back_btn, FALSE); 720 } 721 722 723 void on_load_clicked(GtkButton * button, gpointer user_data) 724 { 725 on_load1_activate(NULL, user_data); 726 } 727 728 729 void on_single_clicked(GtkButton * button, gpointer user_data) 730 { 731 view_mode = SINGLE_VIEW; 732 gtk_widget_hide(tree1_w); 733 current = &rootmenu; 734 display_tree_part(); 735 } 736 737 738 void on_split_clicked(GtkButton * button, gpointer user_data) 739 { 740 gint w, h; 741 view_mode = SPLIT_VIEW; 742 gtk_widget_show(tree1_w); 743 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); 744 gtk_paned_set_position(GTK_PANED(hpaned), w / 2); 745 if (tree2) 746 gtk_tree_store_clear(tree2); 747 display_list(); 748 749 /* Disable back btn, like in full mode. */ 750 gtk_widget_set_sensitive(back_btn, FALSE); 751 } 752 753 754 void on_full_clicked(GtkButton * button, gpointer user_data) 755 { 756 view_mode = FULL_VIEW; 757 gtk_widget_hide(tree1_w); 758 if (tree2) 759 gtk_tree_store_clear(tree2); 760 display_tree(&rootmenu); 761 gtk_widget_set_sensitive(back_btn, FALSE); 762 } 763 764 765 void on_collapse_clicked(GtkButton * button, gpointer user_data) 766 { 767 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w)); 768 } 769 770 771 void on_expand_clicked(GtkButton * button, gpointer user_data) 772 { 773 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); 774 } 775 776 777 /* CTree Callbacks */ 778 779 /* Change hex/int/string value in the cell */ 780 static void renderer_edited(GtkCellRendererText * cell, 781 const gchar * path_string, 782 const gchar * new_text, gpointer user_data) 783 { 784 GtkTreePath *path = gtk_tree_path_new_from_string(path_string); 785 GtkTreeIter iter; 786 const char *old_def, *new_def; 787 struct menu *menu; 788 struct symbol *sym; 789 790 if (!gtk_tree_model_get_iter(model2, &iter, path)) 791 return; 792 793 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 794 sym = menu->sym; 795 796 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1); 797 new_def = new_text; 798 799 sym_set_string_value(sym, new_def); 800 801 update_tree(&rootmenu, NULL); 802 803 gtk_tree_path_free(path); 804 } 805 806 /* Change the value of a symbol and update the tree */ 807 static void change_sym_value(struct menu *menu, gint col) 808 { 809 struct symbol *sym = menu->sym; 810 tristate newval; 811 812 if (!sym) 813 return; 814 815 if (col == COL_NO) 816 newval = no; 817 else if (col == COL_MOD) 818 newval = mod; 819 else if (col == COL_YES) 820 newval = yes; 821 else 822 return; 823 824 switch (sym_get_type(sym)) { 825 case S_BOOLEAN: 826 case S_TRISTATE: 827 if (!sym_tristate_within_range(sym, newval)) 828 newval = yes; 829 sym_set_tristate_value(sym, newval); 830 if (view_mode == FULL_VIEW) 831 update_tree(&rootmenu, NULL); 832 else if (view_mode == SPLIT_VIEW) { 833 update_tree(browsed, NULL); 834 display_list(); 835 } 836 else if (view_mode == SINGLE_VIEW) 837 display_tree_part(); //fixme: keep exp/coll 838 break; 839 case S_INT: 840 case S_HEX: 841 case S_STRING: 842 default: 843 break; 844 } 845 } 846 847 static void toggle_sym_value(struct menu *menu) 848 { 849 if (!menu->sym) 850 return; 851 852 sym_toggle_tristate_value(menu->sym); 853 if (view_mode == FULL_VIEW) 854 update_tree(&rootmenu, NULL); 855 else if (view_mode == SPLIT_VIEW) { 856 update_tree(browsed, NULL); 857 display_list(); 858 } 859 else if (view_mode == SINGLE_VIEW) 860 display_tree_part(); //fixme: keep exp/coll 861 } 862 863 static gint column2index(GtkTreeViewColumn * column) 864 { 865 gint i; 866 867 for (i = 0; i < COL_NUMBER; i++) { 868 GtkTreeViewColumn *col; 869 870 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i); 871 if (col == column) 872 return i; 873 } 874 875 return -1; 876 } 877 878 879 /* User click: update choice (full) or goes down (single) */ 880 gboolean 881 on_treeview2_button_press_event(GtkWidget * widget, 882 GdkEventButton * event, gpointer user_data) 883 { 884 GtkTreeView *view = GTK_TREE_VIEW(widget); 885 GtkTreePath *path; 886 GtkTreeViewColumn *column; 887 GtkTreeIter iter; 888 struct menu *menu; 889 gint col; 890 891 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK 892 gint tx = (gint) event->x; 893 gint ty = (gint) event->y; 894 gint cx, cy; 895 896 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, 897 &cy); 898 #else 899 gtk_tree_view_get_cursor(view, &path, &column); 900 #endif 901 if (path == NULL) 902 return FALSE; 903 904 if (!gtk_tree_model_get_iter(model2, &iter, path)) 905 return FALSE; 906 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 907 908 col = column2index(column); 909 if (event->type == GDK_2BUTTON_PRESS) { 910 enum prop_type ptype; 911 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 912 913 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { 914 // goes down into menu 915 current = menu; 916 display_tree_part(); 917 gtk_widget_set_sensitive(back_btn, TRUE); 918 } else if (col == COL_OPTION) { 919 toggle_sym_value(menu); 920 gtk_tree_view_expand_row(view, path, TRUE); 921 } 922 } else { 923 if (col == COL_VALUE) { 924 toggle_sym_value(menu); 925 gtk_tree_view_expand_row(view, path, TRUE); 926 } else if (col == COL_NO || col == COL_MOD 927 || col == COL_YES) { 928 change_sym_value(menu, col); 929 gtk_tree_view_expand_row(view, path, TRUE); 930 } 931 } 932 933 return FALSE; 934 } 935 936 /* Key pressed: update choice */ 937 gboolean 938 on_treeview2_key_press_event(GtkWidget * widget, 939 GdkEventKey * event, gpointer user_data) 940 { 941 GtkTreeView *view = GTK_TREE_VIEW(widget); 942 GtkTreePath *path; 943 GtkTreeViewColumn *column; 944 GtkTreeIter iter; 945 struct menu *menu; 946 gint col; 947 948 gtk_tree_view_get_cursor(view, &path, &column); 949 if (path == NULL) 950 return FALSE; 951 952 if (event->keyval == GDK_space) { 953 if (gtk_tree_view_row_expanded(view, path)) 954 gtk_tree_view_collapse_row(view, path); 955 else 956 gtk_tree_view_expand_row(view, path, FALSE); 957 return TRUE; 958 } 959 if (event->keyval == GDK_KP_Enter) { 960 } 961 if (widget == tree1_w) 962 return FALSE; 963 964 gtk_tree_model_get_iter(model2, &iter, path); 965 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 966 967 if (!strcasecmp(event->string, "n")) 968 col = COL_NO; 969 else if (!strcasecmp(event->string, "m")) 970 col = COL_MOD; 971 else if (!strcasecmp(event->string, "y")) 972 col = COL_YES; 973 else 974 col = -1; 975 change_sym_value(menu, col); 976 977 return FALSE; 978 } 979 980 981 /* Row selection changed: update help */ 982 void 983 on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data) 984 { 985 GtkTreeSelection *selection; 986 GtkTreeIter iter; 987 struct menu *menu; 988 989 selection = gtk_tree_view_get_selection(treeview); 990 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) { 991 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1); 992 text_insert_help(menu); 993 } 994 } 995 996 997 /* User click: display sub-tree in the right frame. */ 998 gboolean 999 on_treeview1_button_press_event(GtkWidget * widget, 1000 GdkEventButton * event, gpointer user_data) 1001 { 1002 GtkTreeView *view = GTK_TREE_VIEW(widget); 1003 GtkTreePath *path; 1004 GtkTreeViewColumn *column; 1005 GtkTreeIter iter; 1006 struct menu *menu; 1007 1008 gint tx = (gint) event->x; 1009 gint ty = (gint) event->y; 1010 gint cx, cy; 1011 1012 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx, 1013 &cy); 1014 if (path == NULL) 1015 return FALSE; 1016 1017 gtk_tree_model_get_iter(model1, &iter, path); 1018 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1); 1019 1020 if (event->type == GDK_2BUTTON_PRESS) { 1021 toggle_sym_value(menu); 1022 current = menu; 1023 display_tree_part(); 1024 } else { 1025 browsed = menu; 1026 display_tree_part(); 1027 } 1028 1029 gtk_widget_realize(tree2_w); 1030 gtk_tree_view_set_cursor(view, path, NULL, FALSE); 1031 gtk_widget_grab_focus(tree2_w); 1032 1033 return FALSE; 1034 } 1035 1036 1037 /* Fill a row of strings */ 1038 static gchar **fill_row(struct menu *menu) 1039 { 1040 static gchar *row[COL_NUMBER]; 1041 struct symbol *sym = menu->sym; 1042 const char *def; 1043 int stype; 1044 tristate val; 1045 enum prop_type ptype; 1046 int i; 1047 1048 for (i = COL_OPTION; i <= COL_COLOR; i++) 1049 g_free(row[i]); 1050 bzero(row, sizeof(row)); 1051 1052 row[COL_OPTION] = 1053 g_strdup_printf("%s %s", menu_get_prompt(menu), 1054 sym && !sym_has_value(sym) ? "(NEW)" : ""); 1055 1056 if (opt_mode == OPT_ALL && !menu_is_visible(menu)) 1057 row[COL_COLOR] = g_strdup("DarkGray"); 1058 else if (opt_mode == OPT_PROMPT && 1059 menu_has_prompt(menu) && !menu_is_visible(menu)) 1060 row[COL_COLOR] = g_strdup("DarkGray"); 1061 else 1062 row[COL_COLOR] = g_strdup("Black"); 1063 1064 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; 1065 switch (ptype) { 1066 case P_MENU: 1067 row[COL_PIXBUF] = (gchar *) xpm_menu; 1068 if (view_mode == SINGLE_VIEW) 1069 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); 1070 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 1071 break; 1072 case P_COMMENT: 1073 row[COL_PIXBUF] = (gchar *) xpm_void; 1074 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); 1075 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 1076 break; 1077 default: 1078 row[COL_PIXBUF] = (gchar *) xpm_void; 1079 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE); 1080 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); 1081 break; 1082 } 1083 1084 if (!sym) 1085 return row; 1086 row[COL_NAME] = g_strdup(sym->name); 1087 1088 sym_calc_value(sym); 1089 sym->flags &= ~SYMBOL_CHANGED; 1090 1091 if (sym_is_choice(sym)) { // parse childs for getting final value 1092 struct menu *child; 1093 struct symbol *def_sym = sym_get_choice_value(sym); 1094 struct menu *def_menu = NULL; 1095 1096 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 1097 1098 for (child = menu->list; child; child = child->next) { 1099 if (menu_is_visible(child) 1100 && child->sym == def_sym) 1101 def_menu = child; 1102 } 1103 1104 if (def_menu) 1105 row[COL_VALUE] = 1106 g_strdup(menu_get_prompt(def_menu)); 1107 } 1108 if (sym->flags & SYMBOL_CHOICEVAL) 1109 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE); 1110 1111 stype = sym_get_type(sym); 1112 switch (stype) { 1113 case S_BOOLEAN: 1114 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE) 1115 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE); 1116 if (sym_is_choice(sym)) 1117 break; 1118 /* fall through */ 1119 case S_TRISTATE: 1120 val = sym_get_tristate_value(sym); 1121 switch (val) { 1122 case no: 1123 row[COL_NO] = g_strdup("N"); 1124 row[COL_VALUE] = g_strdup("N"); 1125 row[COL_BTNACT] = GINT_TO_POINTER(FALSE); 1126 row[COL_BTNINC] = GINT_TO_POINTER(FALSE); 1127 break; 1128 case mod: 1129 row[COL_MOD] = g_strdup("M"); 1130 row[COL_VALUE] = g_strdup("M"); 1131 row[COL_BTNINC] = GINT_TO_POINTER(TRUE); 1132 break; 1133 case yes: 1134 row[COL_YES] = g_strdup("Y"); 1135 row[COL_VALUE] = g_strdup("Y"); 1136 row[COL_BTNACT] = GINT_TO_POINTER(TRUE); 1137 row[COL_BTNINC] = GINT_TO_POINTER(FALSE); 1138 break; 1139 } 1140 1141 if (val != no && sym_tristate_within_range(sym, no)) 1142 row[COL_NO] = g_strdup("_"); 1143 if (val != mod && sym_tristate_within_range(sym, mod)) 1144 row[COL_MOD] = g_strdup("_"); 1145 if (val != yes && sym_tristate_within_range(sym, yes)) 1146 row[COL_YES] = g_strdup("_"); 1147 break; 1148 case S_INT: 1149 case S_HEX: 1150 case S_STRING: 1151 def = sym_get_string_value(sym); 1152 row[COL_VALUE] = g_strdup(def); 1153 row[COL_EDIT] = GINT_TO_POINTER(TRUE); 1154 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE); 1155 break; 1156 } 1157 1158 return row; 1159 } 1160 1161 1162 /* Set the node content with a row of strings */ 1163 static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row) 1164 { 1165 GdkColor color; 1166 gboolean success; 1167 GdkPixbuf *pix; 1168 1169 pix = gdk_pixbuf_new_from_xpm_data((const char **) 1170 row[COL_PIXBUF]); 1171 1172 gdk_color_parse(row[COL_COLOR], &color); 1173 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1, 1174 FALSE, FALSE, &success); 1175 1176 gtk_tree_store_set(tree, node, 1177 COL_OPTION, row[COL_OPTION], 1178 COL_NAME, row[COL_NAME], 1179 COL_NO, row[COL_NO], 1180 COL_MOD, row[COL_MOD], 1181 COL_YES, row[COL_YES], 1182 COL_VALUE, row[COL_VALUE], 1183 COL_MENU, (gpointer) menu, 1184 COL_COLOR, &color, 1185 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]), 1186 COL_PIXBUF, pix, 1187 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]), 1188 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]), 1189 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]), 1190 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]), 1191 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]), 1192 -1); 1193 1194 g_object_unref(pix); 1195 } 1196 1197 1198 /* Add a node to the tree */ 1199 static void place_node(struct menu *menu, char **row) 1200 { 1201 GtkTreeIter *parent = parents[indent - 1]; 1202 GtkTreeIter *node = parents[indent]; 1203 1204 gtk_tree_store_append(tree, node, parent); 1205 set_node(node, menu, row); 1206 } 1207 1208 1209 /* Find a node in the GTK+ tree */ 1210 static GtkTreeIter found; 1211 1212 /* 1213 * Find a menu in the GtkTree starting at parent. 1214 */ 1215 GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent, 1216 struct menu *tofind) 1217 { 1218 GtkTreeIter iter; 1219 GtkTreeIter *child = &iter; 1220 gboolean valid; 1221 GtkTreeIter *ret; 1222 1223 valid = gtk_tree_model_iter_children(model2, child, parent); 1224 while (valid) { 1225 struct menu *menu; 1226 1227 gtk_tree_model_get(model2, child, 6, &menu, -1); 1228 1229 if (menu == tofind) { 1230 memcpy(&found, child, sizeof(GtkTreeIter)); 1231 return &found; 1232 } 1233 1234 ret = gtktree_iter_find_node(child, tofind); 1235 if (ret) 1236 return ret; 1237 1238 valid = gtk_tree_model_iter_next(model2, child); 1239 } 1240 1241 return NULL; 1242 } 1243 1244 1245 /* 1246 * Update the tree by adding/removing entries 1247 * Does not change other nodes 1248 */ 1249 static void update_tree(struct menu *src, GtkTreeIter * dst) 1250 { 1251 struct menu *child1; 1252 GtkTreeIter iter, tmp; 1253 GtkTreeIter *child2 = &iter; 1254 gboolean valid; 1255 GtkTreeIter *sibling; 1256 struct symbol *sym; 1257 struct menu *menu1, *menu2; 1258 1259 if (src == &rootmenu) 1260 indent = 1; 1261 1262 valid = gtk_tree_model_iter_children(model2, child2, dst); 1263 for (child1 = src->list; child1; child1 = child1->next) { 1264 1265 sym = child1->sym; 1266 1267 reparse: 1268 menu1 = child1; 1269 if (valid) 1270 gtk_tree_model_get(model2, child2, COL_MENU, 1271 &menu2, -1); 1272 else 1273 menu2 = NULL; // force adding of a first child 1274 1275 #ifdef DEBUG 1276 printf("%*c%s | %s\n", indent, ' ', 1277 menu1 ? menu_get_prompt(menu1) : "nil", 1278 menu2 ? menu_get_prompt(menu2) : "nil"); 1279 #endif 1280 1281 if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) || 1282 (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) || 1283 (opt_mode == OPT_ALL && !menu_get_prompt(child1))) { 1284 1285 /* remove node */ 1286 if (gtktree_iter_find_node(dst, menu1) != NULL) { 1287 memcpy(&tmp, child2, sizeof(GtkTreeIter)); 1288 valid = gtk_tree_model_iter_next(model2, 1289 child2); 1290 gtk_tree_store_remove(tree2, &tmp); 1291 if (!valid) 1292 return; /* next parent */ 1293 else 1294 goto reparse; /* next child */ 1295 } else 1296 continue; 1297 } 1298 1299 if (menu1 != menu2) { 1300 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node 1301 if (!valid && !menu2) 1302 sibling = NULL; 1303 else 1304 sibling = child2; 1305 gtk_tree_store_insert_before(tree2, 1306 child2, 1307 dst, sibling); 1308 set_node(child2, menu1, fill_row(menu1)); 1309 if (menu2 == NULL) 1310 valid = TRUE; 1311 } else { // remove node 1312 memcpy(&tmp, child2, sizeof(GtkTreeIter)); 1313 valid = gtk_tree_model_iter_next(model2, 1314 child2); 1315 gtk_tree_store_remove(tree2, &tmp); 1316 if (!valid) 1317 return; // next parent 1318 else 1319 goto reparse; // next child 1320 } 1321 } else if (sym && (sym->flags & SYMBOL_CHANGED)) { 1322 set_node(child2, menu1, fill_row(menu1)); 1323 } 1324 1325 indent++; 1326 update_tree(child1, child2); 1327 indent--; 1328 1329 valid = gtk_tree_model_iter_next(model2, child2); 1330 } 1331 } 1332 1333 1334 /* Display the whole tree (single/split/full view) */ 1335 static void display_tree(struct menu *menu) 1336 { 1337 struct symbol *sym; 1338 struct property *prop; 1339 struct menu *child; 1340 enum prop_type ptype; 1341 1342 if (menu == &rootmenu) { 1343 indent = 1; 1344 current = &rootmenu; 1345 } 1346 1347 for (child = menu->list; child; child = child->next) { 1348 prop = child->prompt; 1349 sym = child->sym; 1350 ptype = prop ? prop->type : P_UNKNOWN; 1351 1352 if (sym) 1353 sym->flags &= ~SYMBOL_CHANGED; 1354 1355 if ((view_mode == SPLIT_VIEW) 1356 && !(child->flags & MENU_ROOT) && (tree == tree1)) 1357 continue; 1358 1359 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) 1360 && (tree == tree2)) 1361 continue; 1362 1363 if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) || 1364 (opt_mode == OPT_PROMPT && menu_has_prompt(child)) || 1365 (opt_mode == OPT_ALL && menu_get_prompt(child))) 1366 place_node(child, fill_row(child)); 1367 #ifdef DEBUG 1368 printf("%*c%s: ", indent, ' ', menu_get_prompt(child)); 1369 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : ""); 1370 printf("%s", prop_get_type_name(ptype)); 1371 printf(" | "); 1372 if (sym) { 1373 printf("%s", sym_type_name(sym->type)); 1374 printf(" | "); 1375 printf("%s", dbg_sym_flags(sym->flags)); 1376 printf("\n"); 1377 } else 1378 printf("\n"); 1379 #endif 1380 if ((view_mode != FULL_VIEW) && (ptype == P_MENU) 1381 && (tree == tree2)) 1382 continue; 1383 /* 1384 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) 1385 || (view_mode == FULL_VIEW) 1386 || (view_mode == SPLIT_VIEW))*/ 1387 1388 /* Change paned position if the view is not in 'split mode' */ 1389 if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) { 1390 gtk_paned_set_position(GTK_PANED(hpaned), 0); 1391 } 1392 1393 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT)) 1394 || (view_mode == FULL_VIEW) 1395 || (view_mode == SPLIT_VIEW)) { 1396 indent++; 1397 display_tree(child); 1398 indent--; 1399 } 1400 } 1401 } 1402 1403 /* Display a part of the tree starting at current node (single/split view) */ 1404 static void display_tree_part(void) 1405 { 1406 if (tree2) 1407 gtk_tree_store_clear(tree2); 1408 if (view_mode == SINGLE_VIEW) 1409 display_tree(current); 1410 else if (view_mode == SPLIT_VIEW) 1411 display_tree(browsed); 1412 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w)); 1413 } 1414 1415 /* Display the list in the left frame (split view) */ 1416 static void display_list(void) 1417 { 1418 if (tree1) 1419 gtk_tree_store_clear(tree1); 1420 1421 tree = tree1; 1422 display_tree(&rootmenu); 1423 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w)); 1424 tree = tree2; 1425 } 1426 1427 void fixup_rootmenu(struct menu *menu) 1428 { 1429 struct menu *child; 1430 static int menu_cnt = 0; 1431 1432 menu->flags |= MENU_ROOT; 1433 for (child = menu->list; child; child = child->next) { 1434 if (child->prompt && child->prompt->type == P_MENU) { 1435 menu_cnt++; 1436 fixup_rootmenu(child); 1437 menu_cnt--; 1438 } else if (!menu_cnt) 1439 fixup_rootmenu(child); 1440 } 1441 } 1442 1443 1444 /* Main */ 1445 int main(int ac, char *av[]) 1446 { 1447 const char *name; 1448 char *env; 1449 gchar *glade_file; 1450 1451 /* GTK stuffs */ 1452 gtk_set_locale(); 1453 gtk_init(&ac, &av); 1454 glade_init(); 1455 1456 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); 1457 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); 1458 1459 /* Determine GUI path */ 1460 env = getenv(SRCTREE); 1461 if (env) 1462 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL); 1463 else if (av[0][0] == '/') 1464 glade_file = g_strconcat(av[0], ".glade", NULL); 1465 else 1466 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL); 1467 1468 /* Conf stuffs */ 1469 if (ac > 1 && av[1][0] == '-') { 1470 switch (av[1][1]) { 1471 case 'a': 1472 //showAll = 1; 1473 break; 1474 case 's': 1475 conf_set_message_callback(NULL); 1476 break; 1477 case 'h': 1478 case '?': 1479 printf("%s [-s] <config>\n", av[0]); 1480 exit(0); 1481 } 1482 name = av[2]; 1483 } else 1484 name = av[1]; 1485 1486 conf_parse(name); 1487 fixup_rootmenu(&rootmenu); 1488 conf_read(NULL); 1489 1490 /* Load the interface and connect signals */ 1491 init_main_window(glade_file); 1492 init_tree_model(); 1493 init_left_tree(); 1494 init_right_tree(); 1495 1496 switch (view_mode) { 1497 case SINGLE_VIEW: 1498 display_tree_part(); 1499 break; 1500 case SPLIT_VIEW: 1501 display_list(); 1502 break; 1503 case FULL_VIEW: 1504 display_tree(&rootmenu); 1505 break; 1506 } 1507 1508 gtk_main(); 1509 1510 return 0; 1511 } 1512 1513 static void conf_changed(void) 1514 { 1515 bool changed = conf_get_changed(); 1516 gtk_widget_set_sensitive(save_btn, changed); 1517 gtk_widget_set_sensitive(save_menu_item, changed); 1518 } 1519