blob: aee993a778f41a438bed99b6296bd5077e9f3c87 [file] [log] [blame]
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001/* 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
29enum {
30 SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
31};
32
33enum {
34 OPT_NORMAL, OPT_ALL, OPT_PROMPT
35};
36
37static gint view_mode = FULL_VIEW;
38static gboolean show_name = TRUE;
39static gboolean show_range = TRUE;
40static gboolean show_value = TRUE;
41static gboolean resizeable = FALSE;
42static int opt_mode = OPT_NORMAL;
43
44GtkWidget *main_wnd = NULL;
45GtkWidget *tree1_w = NULL; // left frame
46GtkWidget *tree2_w = NULL; // right frame
47GtkWidget *text_w = NULL;
48GtkWidget *hpaned = NULL;
49GtkWidget *vpaned = NULL;
50GtkWidget *back_btn = NULL;
51GtkWidget *save_btn = NULL;
52GtkWidget *save_menu_item = NULL;
53
54GtkTextTag *tag1, *tag2;
55GdkColor color;
56
57GtkTreeStore *tree1, *tree2, *tree;
58GtkTreeModel *model1, *model2;
59static GtkTreeIter *parents[256];
60static gint indent;
61
62static struct menu *current; // current node for SINGLE view
63static struct menu *browsed; // browsed node for SPLIT view
64
65enum {
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
72static void display_list(void);
73static void display_tree(struct menu *menu);
74static void display_tree_part(void);
75static void update_tree(struct menu *src, GtkTreeIter * dst);
76static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
77static gchar **fill_row(struct menu *menu);
78static void conf_changed(void);
79
80/* Helping/Debugging Functions */
81
82const 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/");
Tom Rini5d4ecf22020-03-27 11:46:27 -0400104 if (val & SYMBOL_NO_WRITE)
105 strcat(buf, "no_write/");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900106
107 buf[strlen(buf) - 1] = '\0';
108
109 return buf;
110}
111
112void 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 */
131void 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)
Tom Rini40f11702020-03-11 18:11:17 -0400140 g_error("GUI loading failed !\n");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900141 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
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900172 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
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900179 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
193void 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
223void 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);
Tom Rini40f11702020-03-11 18:11:17 -0400236 gtk_tree_view_column_set_title(column, "Options");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900237
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
261static void renderer_edited(GtkCellRendererText * cell,
262 const gchar * path_string,
263 const gchar * new_text, gpointer user_data);
264
265void 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);
Tom Rini40f11702020-03-11 18:11:17 -0400279 gtk_tree_view_column_set_title(column, "Options");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900280
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,
Tom Rini40f11702020-03-11 18:11:17 -0400308 "Name", renderer,
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900309 "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,
Tom Rini40f11702020-03-11 18:11:17 -0400332 "Value", renderer,
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900333 "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
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900363/* Utility Functions */
364
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900365static void text_insert_help(struct menu *menu)
366{
367 GtkTextBuffer *buffer;
368 GtkTextIter start, end;
Tom Rini40f11702020-03-11 18:11:17 -0400369 const char *prompt = menu_get_prompt(menu);
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900370 struct gstr help = str_new();
371
372 menu_get_ext_help(menu, &help);
373
374 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
375 gtk_text_buffer_get_bounds(buffer, &start, &end);
376 gtk_text_buffer_delete(buffer, &start, &end);
377 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
378
379 gtk_text_buffer_get_end_iter(buffer, &end);
380 gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
381 NULL);
382 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
383 gtk_text_buffer_get_end_iter(buffer, &end);
384 gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
385 NULL);
386 str_free(&help);
387}
388
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900389static void text_insert_msg(const char *title, const char *message)
390{
391 GtkTextBuffer *buffer;
392 GtkTextIter start, end;
393 const char *msg = message;
394
395 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
396 gtk_text_buffer_get_bounds(buffer, &start, &end);
397 gtk_text_buffer_delete(buffer, &start, &end);
398 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
399
400 gtk_text_buffer_get_end_iter(buffer, &end);
401 gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
402 NULL);
403 gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
404 gtk_text_buffer_get_end_iter(buffer, &end);
405 gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
406 NULL);
407}
408
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900409/* Main Windows Callbacks */
410
411void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
412gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
413 gpointer user_data)
414{
415 GtkWidget *dialog, *label;
416 gint result;
417
418 if (!conf_get_changed())
419 return FALSE;
420
Tom Rini40f11702020-03-11 18:11:17 -0400421 dialog = gtk_dialog_new_with_buttons("Warning !",
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900422 GTK_WINDOW(main_wnd),
423 (GtkDialogFlags)
424 (GTK_DIALOG_MODAL |
425 GTK_DIALOG_DESTROY_WITH_PARENT),
426 GTK_STOCK_OK,
427 GTK_RESPONSE_YES,
428 GTK_STOCK_NO,
429 GTK_RESPONSE_NO,
430 GTK_STOCK_CANCEL,
431 GTK_RESPONSE_CANCEL, NULL);
432 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
433 GTK_RESPONSE_CANCEL);
434
Tom Rini40f11702020-03-11 18:11:17 -0400435 label = gtk_label_new("\nSave configuration ?\n");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900436 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
437 gtk_widget_show(label);
438
439 result = gtk_dialog_run(GTK_DIALOG(dialog));
440 switch (result) {
441 case GTK_RESPONSE_YES:
442 on_save_activate(NULL, NULL);
443 return FALSE;
444 case GTK_RESPONSE_NO:
445 return FALSE;
446 case GTK_RESPONSE_CANCEL:
447 case GTK_RESPONSE_DELETE_EVENT:
448 default:
449 gtk_widget_destroy(dialog);
450 return TRUE;
451 }
452
453 return FALSE;
454}
455
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900456void on_window1_destroy(GtkObject * object, gpointer user_data)
457{
458 gtk_main_quit();
459}
460
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900461void
462on_window1_size_request(GtkWidget * widget,
463 GtkRequisition * requisition, gpointer user_data)
464{
465 static gint old_h;
466 gint w, h;
467
468 if (widget->window == NULL)
469 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
470 else
471 gdk_window_get_size(widget->window, &w, &h);
472
473 if (h == old_h)
474 return;
475 old_h = h;
476
477 gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
478}
479
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900480/* Menu & Toolbar Callbacks */
481
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900482static void
483load_filename(GtkFileSelection * file_selector, gpointer user_data)
484{
485 const gchar *fn;
486
487 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
488 (user_data));
489
490 if (conf_read(fn))
Tom Rini40f11702020-03-11 18:11:17 -0400491 text_insert_msg("Error", "Unable to load configuration !");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900492 else
493 display_tree(&rootmenu);
494}
495
496void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
497{
498 GtkWidget *fs;
499
Tom Rini40f11702020-03-11 18:11:17 -0400500 fs = gtk_file_selection_new("Load file...");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900501 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
502 "clicked",
503 G_CALLBACK(load_filename), (gpointer) fs);
504 g_signal_connect_swapped(GTK_OBJECT
505 (GTK_FILE_SELECTION(fs)->ok_button),
506 "clicked", G_CALLBACK(gtk_widget_destroy),
507 (gpointer) fs);
508 g_signal_connect_swapped(GTK_OBJECT
509 (GTK_FILE_SELECTION(fs)->cancel_button),
510 "clicked", G_CALLBACK(gtk_widget_destroy),
511 (gpointer) fs);
512 gtk_widget_show(fs);
513}
514
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900515void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
516{
517 if (conf_write(NULL))
Tom Rini40f11702020-03-11 18:11:17 -0400518 text_insert_msg("Error", "Unable to save configuration !");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900519}
520
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900521static void
522store_filename(GtkFileSelection * file_selector, gpointer user_data)
523{
524 const gchar *fn;
525
526 fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
527 (user_data));
528
529 if (conf_write(fn))
Tom Rini40f11702020-03-11 18:11:17 -0400530 text_insert_msg("Error", "Unable to save configuration !");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900531
532 gtk_widget_destroy(GTK_WIDGET(user_data));
533}
534
535void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
536{
537 GtkWidget *fs;
538
Tom Rini40f11702020-03-11 18:11:17 -0400539 fs = gtk_file_selection_new("Save file as...");
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900540 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
541 "clicked",
542 G_CALLBACK(store_filename), (gpointer) fs);
543 g_signal_connect_swapped(GTK_OBJECT
544 (GTK_FILE_SELECTION(fs)->ok_button),
545 "clicked", G_CALLBACK(gtk_widget_destroy),
546 (gpointer) fs);
547 g_signal_connect_swapped(GTK_OBJECT
548 (GTK_FILE_SELECTION(fs)->cancel_button),
549 "clicked", G_CALLBACK(gtk_widget_destroy),
550 (gpointer) fs);
551 gtk_widget_show(fs);
552}
553
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900554void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
555{
556 if (!on_window1_delete_event(NULL, NULL, NULL))
557 gtk_widget_destroy(GTK_WIDGET(main_wnd));
558}
559
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900560void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
561{
562 GtkTreeViewColumn *col;
563
564 show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
565 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
566 if (col)
567 gtk_tree_view_column_set_visible(col, show_name);
568}
569
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900570void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
571{
572 GtkTreeViewColumn *col;
573
574 show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
575 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
576 if (col)
577 gtk_tree_view_column_set_visible(col, show_range);
578 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
579 if (col)
580 gtk_tree_view_column_set_visible(col, show_range);
581 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
582 if (col)
583 gtk_tree_view_column_set_visible(col, show_range);
584
585}
586
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900587void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
588{
589 GtkTreeViewColumn *col;
590
591 show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
592 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
593 if (col)
594 gtk_tree_view_column_set_visible(col, show_value);
595}
596
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900597void
598on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
599{
600 opt_mode = OPT_NORMAL;
601 gtk_tree_store_clear(tree2);
602 display_tree(&rootmenu); /* instead of update_tree to speed-up */
603}
604
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900605void
606on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
607{
608 opt_mode = OPT_ALL;
609 gtk_tree_store_clear(tree2);
610 display_tree(&rootmenu); /* instead of update_tree to speed-up */
611}
612
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900613void
614on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
615{
616 opt_mode = OPT_PROMPT;
617 gtk_tree_store_clear(tree2);
618 display_tree(&rootmenu); /* instead of update_tree to speed-up */
619}
620
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900621void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
622{
623 GtkWidget *dialog;
Wolfgang Denk9d328a62021-09-27 17:42:38 +0200624 const gchar *intro_text =
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900625 "Welcome to gkc, the GTK+ graphical configuration tool\n"
626 "For each option, a blank box indicates the feature is disabled, a\n"
627 "check indicates it is enabled, and a dot indicates that it is to\n"
628 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
629 "\n"
630 "If you do not see an option (e.g., a device driver) that you\n"
631 "believe should be present, try turning on Show All Options\n"
632 "under the Options menu.\n"
633 "Although there is no cross reference yet to help you figure out\n"
634 "what other options must be enabled to support the option you\n"
635 "are interested in, you can still view the help of a grayed-out\n"
636 "option.\n"
637 "\n"
638 "Toggling Show Debug Info under the Options menu will show \n"
Tom Rini40f11702020-03-11 18:11:17 -0400639 "the dependencies, which you can then match by examining other options.";
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900640
641 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
642 GTK_DIALOG_DESTROY_WITH_PARENT,
643 GTK_MESSAGE_INFO,
644 GTK_BUTTONS_CLOSE, "%s", intro_text);
645 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
646 G_CALLBACK(gtk_widget_destroy),
647 GTK_OBJECT(dialog));
648 gtk_widget_show_all(dialog);
649}
650
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900651void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
652{
653 GtkWidget *dialog;
654 const gchar *about_text =
Tom Rini40f11702020-03-11 18:11:17 -0400655 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
656 "Based on the source code from Roman Zippel.\n";
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900657
658 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
659 GTK_DIALOG_DESTROY_WITH_PARENT,
660 GTK_MESSAGE_INFO,
661 GTK_BUTTONS_CLOSE, "%s", about_text);
662 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
663 G_CALLBACK(gtk_widget_destroy),
664 GTK_OBJECT(dialog));
665 gtk_widget_show_all(dialog);
666}
667
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900668void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
669{
670 GtkWidget *dialog;
671 const gchar *license_text =
Tom Rini40f11702020-03-11 18:11:17 -0400672 "gkc is released under the terms of the GNU GPL v2.\n"
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900673 "For more information, please see the source code or\n"
Tom Rini40f11702020-03-11 18:11:17 -0400674 "visit http://www.fsf.org/licenses/licenses.html\n";
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900675
676 dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
677 GTK_DIALOG_DESTROY_WITH_PARENT,
678 GTK_MESSAGE_INFO,
679 GTK_BUTTONS_CLOSE, "%s", license_text);
680 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
681 G_CALLBACK(gtk_widget_destroy),
682 GTK_OBJECT(dialog));
683 gtk_widget_show_all(dialog);
684}
685
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900686void on_back_clicked(GtkButton * button, gpointer user_data)
687{
688 enum prop_type ptype;
689
690 current = current->parent;
691 ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
692 if (ptype != P_MENU)
693 current = current->parent;
694 display_tree_part();
695
696 if (current == &rootmenu)
697 gtk_widget_set_sensitive(back_btn, FALSE);
698}
699
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900700void on_load_clicked(GtkButton * button, gpointer user_data)
701{
702 on_load1_activate(NULL, user_data);
703}
704
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900705void on_single_clicked(GtkButton * button, gpointer user_data)
706{
707 view_mode = SINGLE_VIEW;
708 gtk_widget_hide(tree1_w);
709 current = &rootmenu;
710 display_tree_part();
711}
712
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900713void on_split_clicked(GtkButton * button, gpointer user_data)
714{
715 gint w, h;
716 view_mode = SPLIT_VIEW;
717 gtk_widget_show(tree1_w);
718 gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
719 gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
720 if (tree2)
721 gtk_tree_store_clear(tree2);
722 display_list();
723
724 /* Disable back btn, like in full mode. */
725 gtk_widget_set_sensitive(back_btn, FALSE);
726}
727
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900728void on_full_clicked(GtkButton * button, gpointer user_data)
729{
730 view_mode = FULL_VIEW;
731 gtk_widget_hide(tree1_w);
732 if (tree2)
733 gtk_tree_store_clear(tree2);
734 display_tree(&rootmenu);
735 gtk_widget_set_sensitive(back_btn, FALSE);
736}
737
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900738void on_collapse_clicked(GtkButton * button, gpointer user_data)
739{
740 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
741}
742
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900743void on_expand_clicked(GtkButton * button, gpointer user_data)
744{
745 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
746}
747
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900748/* CTree Callbacks */
749
750/* Change hex/int/string value in the cell */
751static void renderer_edited(GtkCellRendererText * cell,
752 const gchar * path_string,
753 const gchar * new_text, gpointer user_data)
754{
755 GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
756 GtkTreeIter iter;
757 const char *old_def, *new_def;
758 struct menu *menu;
759 struct symbol *sym;
760
761 if (!gtk_tree_model_get_iter(model2, &iter, path))
762 return;
763
764 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
765 sym = menu->sym;
766
767 gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
768 new_def = new_text;
769
770 sym_set_string_value(sym, new_def);
771
772 update_tree(&rootmenu, NULL);
773
774 gtk_tree_path_free(path);
775}
776
777/* Change the value of a symbol and update the tree */
778static void change_sym_value(struct menu *menu, gint col)
779{
780 struct symbol *sym = menu->sym;
781 tristate newval;
782
783 if (!sym)
784 return;
785
786 if (col == COL_NO)
787 newval = no;
788 else if (col == COL_MOD)
789 newval = mod;
790 else if (col == COL_YES)
791 newval = yes;
792 else
793 return;
794
795 switch (sym_get_type(sym)) {
796 case S_BOOLEAN:
797 case S_TRISTATE:
798 if (!sym_tristate_within_range(sym, newval))
799 newval = yes;
800 sym_set_tristate_value(sym, newval);
801 if (view_mode == FULL_VIEW)
802 update_tree(&rootmenu, NULL);
803 else if (view_mode == SPLIT_VIEW) {
804 update_tree(browsed, NULL);
805 display_list();
806 }
807 else if (view_mode == SINGLE_VIEW)
808 display_tree_part(); //fixme: keep exp/coll
809 break;
810 case S_INT:
811 case S_HEX:
812 case S_STRING:
813 default:
814 break;
815 }
816}
817
818static void toggle_sym_value(struct menu *menu)
819{
820 if (!menu->sym)
821 return;
822
823 sym_toggle_tristate_value(menu->sym);
824 if (view_mode == FULL_VIEW)
825 update_tree(&rootmenu, NULL);
826 else if (view_mode == SPLIT_VIEW) {
827 update_tree(browsed, NULL);
828 display_list();
829 }
830 else if (view_mode == SINGLE_VIEW)
831 display_tree_part(); //fixme: keep exp/coll
832}
833
834static gint column2index(GtkTreeViewColumn * column)
835{
836 gint i;
837
838 for (i = 0; i < COL_NUMBER; i++) {
839 GtkTreeViewColumn *col;
840
841 col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
842 if (col == column)
843 return i;
844 }
845
846 return -1;
847}
848
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900849/* User click: update choice (full) or goes down (single) */
850gboolean
851on_treeview2_button_press_event(GtkWidget * widget,
852 GdkEventButton * event, gpointer user_data)
853{
854 GtkTreeView *view = GTK_TREE_VIEW(widget);
855 GtkTreePath *path;
856 GtkTreeViewColumn *column;
857 GtkTreeIter iter;
858 struct menu *menu;
859 gint col;
860
861#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
862 gint tx = (gint) event->x;
863 gint ty = (gint) event->y;
864 gint cx, cy;
865
866 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
867 &cy);
868#else
869 gtk_tree_view_get_cursor(view, &path, &column);
870#endif
871 if (path == NULL)
872 return FALSE;
873
874 if (!gtk_tree_model_get_iter(model2, &iter, path))
875 return FALSE;
876 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
877
878 col = column2index(column);
879 if (event->type == GDK_2BUTTON_PRESS) {
880 enum prop_type ptype;
881 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
882
883 if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
884 // goes down into menu
885 current = menu;
886 display_tree_part();
887 gtk_widget_set_sensitive(back_btn, TRUE);
Eugeniu Roscad57dd942018-05-19 14:13:50 +0200888 } else if (col == COL_OPTION) {
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900889 toggle_sym_value(menu);
890 gtk_tree_view_expand_row(view, path, TRUE);
891 }
892 } else {
893 if (col == COL_VALUE) {
894 toggle_sym_value(menu);
895 gtk_tree_view_expand_row(view, path, TRUE);
896 } else if (col == COL_NO || col == COL_MOD
897 || col == COL_YES) {
898 change_sym_value(menu, col);
899 gtk_tree_view_expand_row(view, path, TRUE);
900 }
901 }
902
903 return FALSE;
904}
905
906/* Key pressed: update choice */
907gboolean
908on_treeview2_key_press_event(GtkWidget * widget,
909 GdkEventKey * event, gpointer user_data)
910{
911 GtkTreeView *view = GTK_TREE_VIEW(widget);
912 GtkTreePath *path;
913 GtkTreeViewColumn *column;
914 GtkTreeIter iter;
915 struct menu *menu;
916 gint col;
917
918 gtk_tree_view_get_cursor(view, &path, &column);
919 if (path == NULL)
920 return FALSE;
921
922 if (event->keyval == GDK_space) {
923 if (gtk_tree_view_row_expanded(view, path))
924 gtk_tree_view_collapse_row(view, path);
925 else
926 gtk_tree_view_expand_row(view, path, FALSE);
927 return TRUE;
928 }
929 if (event->keyval == GDK_KP_Enter) {
930 }
931 if (widget == tree1_w)
932 return FALSE;
933
934 gtk_tree_model_get_iter(model2, &iter, path);
935 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
936
937 if (!strcasecmp(event->string, "n"))
938 col = COL_NO;
939 else if (!strcasecmp(event->string, "m"))
940 col = COL_MOD;
941 else if (!strcasecmp(event->string, "y"))
942 col = COL_YES;
943 else
944 col = -1;
945 change_sym_value(menu, col);
946
947 return FALSE;
948}
949
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900950/* Row selection changed: update help */
951void
952on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
953{
954 GtkTreeSelection *selection;
955 GtkTreeIter iter;
956 struct menu *menu;
957
958 selection = gtk_tree_view_get_selection(treeview);
959 if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
960 gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
961 text_insert_help(menu);
962 }
963}
964
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +0900965/* User click: display sub-tree in the right frame. */
966gboolean
967on_treeview1_button_press_event(GtkWidget * widget,
968 GdkEventButton * event, gpointer user_data)
969{
970 GtkTreeView *view = GTK_TREE_VIEW(widget);
971 GtkTreePath *path;
972 GtkTreeViewColumn *column;
973 GtkTreeIter iter;
974 struct menu *menu;
975
976 gint tx = (gint) event->x;
977 gint ty = (gint) event->y;
978 gint cx, cy;
979
980 gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
981 &cy);
982 if (path == NULL)
983 return FALSE;
984
985 gtk_tree_model_get_iter(model1, &iter, path);
986 gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
987
988 if (event->type == GDK_2BUTTON_PRESS) {
989 toggle_sym_value(menu);
990 current = menu;
991 display_tree_part();
992 } else {
993 browsed = menu;
994 display_tree_part();
995 }
996
997 gtk_widget_realize(tree2_w);
998 gtk_tree_view_set_cursor(view, path, NULL, FALSE);
999 gtk_widget_grab_focus(tree2_w);
1000
1001 return FALSE;
1002}
1003
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001004/* Fill a row of strings */
1005static gchar **fill_row(struct menu *menu)
1006{
1007 static gchar *row[COL_NUMBER];
1008 struct symbol *sym = menu->sym;
1009 const char *def;
1010 int stype;
1011 tristate val;
1012 enum prop_type ptype;
1013 int i;
1014
1015 for (i = COL_OPTION; i <= COL_COLOR; i++)
1016 g_free(row[i]);
1017 bzero(row, sizeof(row));
1018
1019 row[COL_OPTION] =
Tom Rini40f11702020-03-11 18:11:17 -04001020 g_strdup_printf("%s %s", menu_get_prompt(menu),
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001021 sym && !sym_has_value(sym) ? "(NEW)" : "");
1022
1023 if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1024 row[COL_COLOR] = g_strdup("DarkGray");
1025 else if (opt_mode == OPT_PROMPT &&
1026 menu_has_prompt(menu) && !menu_is_visible(menu))
1027 row[COL_COLOR] = g_strdup("DarkGray");
1028 else
1029 row[COL_COLOR] = g_strdup("Black");
1030
1031 ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1032 switch (ptype) {
1033 case P_MENU:
1034 row[COL_PIXBUF] = (gchar *) xpm_menu;
1035 if (view_mode == SINGLE_VIEW)
1036 row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1037 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1038 break;
1039 case P_COMMENT:
1040 row[COL_PIXBUF] = (gchar *) xpm_void;
1041 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1042 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1043 break;
1044 default:
1045 row[COL_PIXBUF] = (gchar *) xpm_void;
1046 row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1047 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1048 break;
1049 }
1050
1051 if (!sym)
1052 return row;
1053 row[COL_NAME] = g_strdup(sym->name);
1054
1055 sym_calc_value(sym);
1056 sym->flags &= ~SYMBOL_CHANGED;
1057
1058 if (sym_is_choice(sym)) { // parse childs for getting final value
1059 struct menu *child;
1060 struct symbol *def_sym = sym_get_choice_value(sym);
1061 struct menu *def_menu = NULL;
1062
1063 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1064
1065 for (child = menu->list; child; child = child->next) {
1066 if (menu_is_visible(child)
1067 && child->sym == def_sym)
1068 def_menu = child;
1069 }
1070
1071 if (def_menu)
1072 row[COL_VALUE] =
Tom Rini40f11702020-03-11 18:11:17 -04001073 g_strdup(menu_get_prompt(def_menu));
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001074 }
1075 if (sym->flags & SYMBOL_CHOICEVAL)
1076 row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1077
1078 stype = sym_get_type(sym);
1079 switch (stype) {
1080 case S_BOOLEAN:
1081 if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1082 row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1083 if (sym_is_choice(sym))
1084 break;
1085 /* fall through */
1086 case S_TRISTATE:
1087 val = sym_get_tristate_value(sym);
1088 switch (val) {
1089 case no:
1090 row[COL_NO] = g_strdup("N");
1091 row[COL_VALUE] = g_strdup("N");
1092 row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1093 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1094 break;
1095 case mod:
1096 row[COL_MOD] = g_strdup("M");
1097 row[COL_VALUE] = g_strdup("M");
1098 row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1099 break;
1100 case yes:
1101 row[COL_YES] = g_strdup("Y");
1102 row[COL_VALUE] = g_strdup("Y");
1103 row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1104 row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1105 break;
1106 }
1107
1108 if (val != no && sym_tristate_within_range(sym, no))
1109 row[COL_NO] = g_strdup("_");
1110 if (val != mod && sym_tristate_within_range(sym, mod))
1111 row[COL_MOD] = g_strdup("_");
1112 if (val != yes && sym_tristate_within_range(sym, yes))
1113 row[COL_YES] = g_strdup("_");
1114 break;
1115 case S_INT:
1116 case S_HEX:
1117 case S_STRING:
1118 def = sym_get_string_value(sym);
1119 row[COL_VALUE] = g_strdup(def);
1120 row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1121 row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1122 break;
1123 }
1124
1125 return row;
1126}
1127
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001128/* Set the node content with a row of strings */
1129static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1130{
1131 GdkColor color;
1132 gboolean success;
1133 GdkPixbuf *pix;
1134
1135 pix = gdk_pixbuf_new_from_xpm_data((const char **)
1136 row[COL_PIXBUF]);
1137
1138 gdk_color_parse(row[COL_COLOR], &color);
1139 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1140 FALSE, FALSE, &success);
1141
1142 gtk_tree_store_set(tree, node,
1143 COL_OPTION, row[COL_OPTION],
1144 COL_NAME, row[COL_NAME],
1145 COL_NO, row[COL_NO],
1146 COL_MOD, row[COL_MOD],
1147 COL_YES, row[COL_YES],
1148 COL_VALUE, row[COL_VALUE],
1149 COL_MENU, (gpointer) menu,
1150 COL_COLOR, &color,
1151 COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1152 COL_PIXBUF, pix,
1153 COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1154 COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1155 COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1156 COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1157 COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1158 -1);
1159
1160 g_object_unref(pix);
1161}
1162
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001163/* Add a node to the tree */
1164static void place_node(struct menu *menu, char **row)
1165{
1166 GtkTreeIter *parent = parents[indent - 1];
1167 GtkTreeIter *node = parents[indent];
1168
1169 gtk_tree_store_append(tree, node, parent);
1170 set_node(node, menu, row);
1171}
1172
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001173/* Find a node in the GTK+ tree */
1174static GtkTreeIter found;
1175
1176/*
1177 * Find a menu in the GtkTree starting at parent.
1178 */
1179GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1180 struct menu *tofind)
1181{
1182 GtkTreeIter iter;
1183 GtkTreeIter *child = &iter;
1184 gboolean valid;
1185 GtkTreeIter *ret;
1186
1187 valid = gtk_tree_model_iter_children(model2, child, parent);
1188 while (valid) {
1189 struct menu *menu;
1190
1191 gtk_tree_model_get(model2, child, 6, &menu, -1);
1192
1193 if (menu == tofind) {
1194 memcpy(&found, child, sizeof(GtkTreeIter));
1195 return &found;
1196 }
1197
1198 ret = gtktree_iter_find_node(child, tofind);
1199 if (ret)
1200 return ret;
1201
1202 valid = gtk_tree_model_iter_next(model2, child);
1203 }
1204
1205 return NULL;
1206}
1207
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001208/*
1209 * Update the tree by adding/removing entries
1210 * Does not change other nodes
1211 */
1212static void update_tree(struct menu *src, GtkTreeIter * dst)
1213{
1214 struct menu *child1;
1215 GtkTreeIter iter, tmp;
1216 GtkTreeIter *child2 = &iter;
1217 gboolean valid;
1218 GtkTreeIter *sibling;
1219 struct symbol *sym;
1220 struct menu *menu1, *menu2;
1221
1222 if (src == &rootmenu)
1223 indent = 1;
1224
1225 valid = gtk_tree_model_iter_children(model2, child2, dst);
1226 for (child1 = src->list; child1; child1 = child1->next) {
1227
1228 sym = child1->sym;
1229
1230 reparse:
1231 menu1 = child1;
1232 if (valid)
1233 gtk_tree_model_get(model2, child2, COL_MENU,
1234 &menu2, -1);
1235 else
1236 menu2 = NULL; // force adding of a first child
1237
1238#ifdef DEBUG
1239 printf("%*c%s | %s\n", indent, ' ',
1240 menu1 ? menu_get_prompt(menu1) : "nil",
1241 menu2 ? menu_get_prompt(menu2) : "nil");
1242#endif
1243
1244 if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
1245 (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
1246 (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
1247
1248 /* remove node */
1249 if (gtktree_iter_find_node(dst, menu1) != NULL) {
1250 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1251 valid = gtk_tree_model_iter_next(model2,
1252 child2);
1253 gtk_tree_store_remove(tree2, &tmp);
1254 if (!valid)
1255 return; /* next parent */
1256 else
1257 goto reparse; /* next child */
1258 } else
1259 continue;
1260 }
1261
1262 if (menu1 != menu2) {
1263 if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1264 if (!valid && !menu2)
1265 sibling = NULL;
1266 else
1267 sibling = child2;
1268 gtk_tree_store_insert_before(tree2,
1269 child2,
1270 dst, sibling);
1271 set_node(child2, menu1, fill_row(menu1));
1272 if (menu2 == NULL)
1273 valid = TRUE;
1274 } else { // remove node
1275 memcpy(&tmp, child2, sizeof(GtkTreeIter));
1276 valid = gtk_tree_model_iter_next(model2,
1277 child2);
1278 gtk_tree_store_remove(tree2, &tmp);
1279 if (!valid)
1280 return; // next parent
1281 else
1282 goto reparse; // next child
1283 }
1284 } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1285 set_node(child2, menu1, fill_row(menu1));
1286 }
1287
1288 indent++;
1289 update_tree(child1, child2);
1290 indent--;
1291
1292 valid = gtk_tree_model_iter_next(model2, child2);
1293 }
1294}
1295
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001296/* Display the whole tree (single/split/full view) */
1297static void display_tree(struct menu *menu)
1298{
1299 struct symbol *sym;
1300 struct property *prop;
1301 struct menu *child;
1302 enum prop_type ptype;
1303
1304 if (menu == &rootmenu) {
1305 indent = 1;
1306 current = &rootmenu;
1307 }
1308
1309 for (child = menu->list; child; child = child->next) {
1310 prop = child->prompt;
1311 sym = child->sym;
1312 ptype = prop ? prop->type : P_UNKNOWN;
1313
1314 if (sym)
1315 sym->flags &= ~SYMBOL_CHANGED;
1316
1317 if ((view_mode == SPLIT_VIEW)
1318 && !(child->flags & MENU_ROOT) && (tree == tree1))
1319 continue;
1320
1321 if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1322 && (tree == tree2))
1323 continue;
1324
1325 if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
1326 (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
1327 (opt_mode == OPT_ALL && menu_get_prompt(child)))
1328 place_node(child, fill_row(child));
1329#ifdef DEBUG
1330 printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1331 printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1332 printf("%s", prop_get_type_name(ptype));
1333 printf(" | ");
1334 if (sym) {
1335 printf("%s", sym_type_name(sym->type));
1336 printf(" | ");
1337 printf("%s", dbg_sym_flags(sym->flags));
1338 printf("\n");
1339 } else
1340 printf("\n");
1341#endif
1342 if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1343 && (tree == tree2))
1344 continue;
1345/*
1346 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1347 || (view_mode == FULL_VIEW)
1348 || (view_mode == SPLIT_VIEW))*/
1349
1350 /* Change paned position if the view is not in 'split mode' */
1351 if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
1352 gtk_paned_set_position(GTK_PANED(hpaned), 0);
1353 }
1354
1355 if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1356 || (view_mode == FULL_VIEW)
1357 || (view_mode == SPLIT_VIEW)) {
1358 indent++;
1359 display_tree(child);
1360 indent--;
1361 }
1362 }
1363}
1364
1365/* Display a part of the tree starting at current node (single/split view) */
1366static void display_tree_part(void)
1367{
1368 if (tree2)
1369 gtk_tree_store_clear(tree2);
1370 if (view_mode == SINGLE_VIEW)
1371 display_tree(current);
1372 else if (view_mode == SPLIT_VIEW)
1373 display_tree(browsed);
1374 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1375}
1376
1377/* Display the list in the left frame (split view) */
1378static void display_list(void)
1379{
1380 if (tree1)
1381 gtk_tree_store_clear(tree1);
1382
1383 tree = tree1;
1384 display_tree(&rootmenu);
1385 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1386 tree = tree2;
1387}
1388
1389void fixup_rootmenu(struct menu *menu)
1390{
1391 struct menu *child;
1392 static int menu_cnt = 0;
1393
1394 menu->flags |= MENU_ROOT;
1395 for (child = menu->list; child; child = child->next) {
1396 if (child->prompt && child->prompt->type == P_MENU) {
1397 menu_cnt++;
1398 fixup_rootmenu(child);
1399 menu_cnt--;
1400 } else if (!menu_cnt)
1401 fixup_rootmenu(child);
1402 }
1403}
1404
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001405/* Main */
1406int main(int ac, char *av[])
1407{
1408 const char *name;
1409 char *env;
1410 gchar *glade_file;
1411
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001412 /* GTK stuffs */
1413 gtk_set_locale();
1414 gtk_init(&ac, &av);
1415 glade_init();
1416
1417 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1418 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1419
1420 /* Determine GUI path */
1421 env = getenv(SRCTREE);
1422 if (env)
1423 glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
1424 else if (av[0][0] == '/')
1425 glade_file = g_strconcat(av[0], ".glade", NULL);
1426 else
1427 glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1428
1429 /* Conf stuffs */
1430 if (ac > 1 && av[1][0] == '-') {
1431 switch (av[1][1]) {
1432 case 'a':
1433 //showAll = 1;
1434 break;
Masahiro Yamada331cec32015-07-05 01:56:54 +09001435 case 's':
1436 conf_set_message_callback(NULL);
1437 break;
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001438 case 'h':
1439 case '?':
Masahiro Yamada331cec32015-07-05 01:56:54 +09001440 printf("%s [-s] <config>\n", av[0]);
Masahiro Yamadaed16f5a2014-07-30 14:08:13 +09001441 exit(0);
1442 }
1443 name = av[2];
1444 } else
1445 name = av[1];
1446
1447 conf_parse(name);
1448 fixup_rootmenu(&rootmenu);
1449 conf_read(NULL);
1450
1451 /* Load the interface and connect signals */
1452 init_main_window(glade_file);
1453 init_tree_model();
1454 init_left_tree();
1455 init_right_tree();
1456
1457 switch (view_mode) {
1458 case SINGLE_VIEW:
1459 display_tree_part();
1460 break;
1461 case SPLIT_VIEW:
1462 display_list();
1463 break;
1464 case FULL_VIEW:
1465 display_tree(&rootmenu);
1466 break;
1467 }
1468
1469 gtk_main();
1470
1471 return 0;
1472}
1473
1474static void conf_changed(void)
1475{
1476 bool changed = conf_get_changed();
1477 gtk_widget_set_sensitive(save_btn, changed);
1478 gtk_widget_set_sensitive(save_menu_item, changed);
1479}