2018-12-18 20:13:35 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
|
|
|
|
*/
|
|
|
|
|
2012-10-20 07:06:25 +08:00
|
|
|
#include <stdlib.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include "lkc.h"
|
2018-12-21 16:33:07 +08:00
|
|
|
#include "images.h"
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#include <glade/glade.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <glib.h>
|
|
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2020-01-10 00:16:36 +08:00
|
|
|
#include <strings.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
//#define DEBUG
|
|
|
|
|
|
|
|
enum {
|
|
|
|
SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
|
|
|
|
};
|
|
|
|
|
2010-04-14 11:46:24 +08:00
|
|
|
enum {
|
|
|
|
OPT_NORMAL, OPT_ALL, OPT_PROMPT
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static gint view_mode = FULL_VIEW;
|
|
|
|
static gboolean show_name = TRUE;
|
|
|
|
static gboolean show_range = TRUE;
|
|
|
|
static gboolean show_value = TRUE;
|
|
|
|
static gboolean resizeable = FALSE;
|
2010-04-14 11:46:24 +08:00
|
|
|
static int opt_mode = OPT_NORMAL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
GtkWidget *main_wnd = NULL;
|
|
|
|
GtkWidget *tree1_w = NULL; // left frame
|
|
|
|
GtkWidget *tree2_w = NULL; // right frame
|
|
|
|
GtkWidget *text_w = NULL;
|
|
|
|
GtkWidget *hpaned = NULL;
|
|
|
|
GtkWidget *vpaned = NULL;
|
|
|
|
GtkWidget *back_btn = NULL;
|
2006-12-13 16:34:09 +08:00
|
|
|
GtkWidget *save_btn = NULL;
|
|
|
|
GtkWidget *save_menu_item = NULL;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
GtkTextTag *tag1, *tag2;
|
|
|
|
GdkColor color;
|
|
|
|
|
|
|
|
GtkTreeStore *tree1, *tree2, *tree;
|
|
|
|
GtkTreeModel *model1, *model2;
|
|
|
|
static GtkTreeIter *parents[256];
|
|
|
|
static gint indent;
|
|
|
|
|
|
|
|
static struct menu *current; // current node for SINGLE view
|
|
|
|
static struct menu *browsed; // browsed node for SPLIT view
|
|
|
|
|
|
|
|
enum {
|
|
|
|
COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
|
|
|
|
COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
|
|
|
|
COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
|
|
|
|
COL_NUMBER
|
|
|
|
};
|
|
|
|
|
|
|
|
static void display_list(void);
|
|
|
|
static void display_tree(struct menu *menu);
|
|
|
|
static void display_tree_part(void);
|
|
|
|
static void update_tree(struct menu *src, GtkTreeIter * dst);
|
|
|
|
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
|
|
|
|
static gchar **fill_row(struct menu *menu);
|
2006-12-13 16:34:09 +08:00
|
|
|
static void conf_changed(void);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Helping/Debugging Functions */
|
2018-12-21 16:33:08 +08:00
|
|
|
#ifdef DEBUG
|
2018-12-21 16:33:06 +08:00
|
|
|
static const char *dbg_sym_flags(int val)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
static char buf[256];
|
|
|
|
|
|
|
|
bzero(buf, 256);
|
|
|
|
|
|
|
|
if (val & SYMBOL_CONST)
|
|
|
|
strcat(buf, "const/");
|
|
|
|
if (val & SYMBOL_CHECK)
|
|
|
|
strcat(buf, "check/");
|
|
|
|
if (val & SYMBOL_CHOICE)
|
|
|
|
strcat(buf, "choice/");
|
|
|
|
if (val & SYMBOL_CHOICEVAL)
|
|
|
|
strcat(buf, "choiceval/");
|
|
|
|
if (val & SYMBOL_VALID)
|
|
|
|
strcat(buf, "valid/");
|
|
|
|
if (val & SYMBOL_OPTIONAL)
|
|
|
|
strcat(buf, "optional/");
|
|
|
|
if (val & SYMBOL_WRITE)
|
|
|
|
strcat(buf, "write/");
|
|
|
|
if (val & SYMBOL_CHANGED)
|
|
|
|
strcat(buf, "changed/");
|
2018-07-03 20:43:31 +08:00
|
|
|
if (val & SYMBOL_NO_WRITE)
|
|
|
|
strcat(buf, "no_write/");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
buf[strlen(buf) - 1] = '\0';
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2018-12-21 16:33:08 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2018-12-21 16:33:06 +08:00
|
|
|
static void replace_button_icon(GladeXML *xml, GdkDrawable *window,
|
|
|
|
GtkStyle *style, gchar *btn_name, gchar **xpm)
|
2005-07-29 06:18:03 +08:00
|
|
|
{
|
|
|
|
GdkPixmap *pixmap;
|
|
|
|
GdkBitmap *mask;
|
|
|
|
GtkToolButton *button;
|
|
|
|
GtkWidget *image;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
|
|
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
|
|
xpm);
|
|
|
|
|
|
|
|
button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
|
|
|
|
image = gtk_image_new_from_pixmap(pixmap, mask);
|
|
|
|
gtk_widget_show(image);
|
|
|
|
gtk_tool_button_set_icon_widget(button, image);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
/* Main Window Initialization */
|
2018-12-21 16:33:06 +08:00
|
|
|
static void init_main_window(const gchar *glade_file)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
GladeXML *xml;
|
|
|
|
GtkWidget *widget;
|
|
|
|
GtkTextBuffer *txtbuf;
|
|
|
|
GtkStyle *style;
|
|
|
|
|
|
|
|
xml = glade_xml_new(glade_file, "window1", NULL);
|
|
|
|
if (!xml)
|
2018-05-23 03:36:12 +08:00
|
|
|
g_error("GUI loading failed !\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
glade_xml_signal_autoconnect(xml);
|
|
|
|
|
|
|
|
main_wnd = glade_xml_get_widget(xml, "window1");
|
|
|
|
hpaned = glade_xml_get_widget(xml, "hpaned1");
|
|
|
|
vpaned = glade_xml_get_widget(xml, "vpaned1");
|
|
|
|
tree1_w = glade_xml_get_widget(xml, "treeview1");
|
|
|
|
tree2_w = glade_xml_get_widget(xml, "treeview2");
|
|
|
|
text_w = glade_xml_get_widget(xml, "textview3");
|
|
|
|
|
|
|
|
back_btn = glade_xml_get_widget(xml, "button1");
|
|
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
|
|
|
|
|
|
widget = glade_xml_get_widget(xml, "show_name1");
|
|
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
|
|
show_name);
|
|
|
|
|
|
|
|
widget = glade_xml_get_widget(xml, "show_range1");
|
|
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
|
|
show_range);
|
|
|
|
|
|
|
|
widget = glade_xml_get_widget(xml, "show_data1");
|
|
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
|
|
show_value);
|
|
|
|
|
2006-12-13 16:34:09 +08:00
|
|
|
save_btn = glade_xml_get_widget(xml, "button3");
|
|
|
|
save_menu_item = glade_xml_get_widget(xml, "save1");
|
|
|
|
conf_set_changed_callback(conf_changed);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
style = gtk_widget_get_style(main_wnd);
|
|
|
|
widget = glade_xml_get_widget(xml, "toolbar1");
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
|
|
"button4", (gchar **) xpm_single_view);
|
|
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
|
|
"button5", (gchar **) xpm_split_view);
|
|
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
|
|
"button6", (gchar **) xpm_tree_view);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
|
|
tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
|
|
|
|
"foreground", "red",
|
|
|
|
"weight", PANGO_WEIGHT_BOLD,
|
|
|
|
NULL);
|
|
|
|
tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
|
|
|
|
/*"style", PANGO_STYLE_OBLIQUE, */
|
|
|
|
NULL);
|
|
|
|
|
2010-08-18 13:57:13 +08:00
|
|
|
gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
gtk_widget_show(main_wnd);
|
|
|
|
}
|
|
|
|
|
2018-12-21 16:33:06 +08:00
|
|
|
static void init_tree_model(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
tree = tree2 = gtk_tree_store_new(COL_NUMBER,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_POINTER, GDK_TYPE_COLOR,
|
|
|
|
G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
|
|
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
|
|
G_TYPE_BOOLEAN);
|
|
|
|
model2 = GTK_TREE_MODEL(tree2);
|
|
|
|
|
|
|
|
for (parents[0] = NULL, i = 1; i < 256; i++)
|
|
|
|
parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
|
|
|
|
|
|
|
|
tree1 = gtk_tree_store_new(COL_NUMBER,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
|
|
G_TYPE_POINTER, GDK_TYPE_COLOR,
|
|
|
|
G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
|
|
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
|
|
G_TYPE_BOOLEAN);
|
|
|
|
model1 = GTK_TREE_MODEL(tree1);
|
|
|
|
}
|
|
|
|
|
2018-12-21 16:33:06 +08:00
|
|
|
static void init_left_tree(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
|
|
|
|
GtkCellRenderer *renderer;
|
|
|
|
GtkTreeSelection *sel;
|
|
|
|
GtkTreeViewColumn *column;
|
|
|
|
|
|
|
|
gtk_tree_view_set_model(view, model1);
|
|
|
|
gtk_tree_view_set_headers_visible(view, TRUE);
|
2011-05-19 20:37:01 +08:00
|
|
|
gtk_tree_view_set_rules_hint(view, TRUE);
|
2005-07-29 06:18:03 +08:00
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
column = gtk_tree_view_column_new();
|
|
|
|
gtk_tree_view_append_column(view, column);
|
2018-05-23 03:36:12 +08:00
|
|
|
gtk_tree_view_column_set_title(column, "Options");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
renderer = gtk_cell_renderer_toggle_new();
|
|
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer, FALSE);
|
|
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer,
|
|
|
|
"active", COL_BTNACT,
|
|
|
|
"inconsistent", COL_BTNINC,
|
2005-07-29 06:18:03 +08:00
|
|
|
"visible", COL_BTNVIS,
|
2005-04-17 06:20:36 +08:00
|
|
|
"radio", COL_BTNRAD, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
2005-07-29 06:18:03 +08:00
|
|
|
renderer, FALSE);
|
2005-04-17 06:20:36 +08:00
|
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer,
|
|
|
|
"text", COL_OPTION,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
|
|
|
|
sel = gtk_tree_view_get_selection(view);
|
|
|
|
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
|
|
|
|
gtk_widget_realize(tree1_w);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void renderer_edited(GtkCellRendererText * cell,
|
|
|
|
const gchar * path_string,
|
|
|
|
const gchar * new_text, gpointer user_data);
|
|
|
|
|
2018-12-21 16:33:06 +08:00
|
|
|
static void init_right_tree(void)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
|
|
|
|
GtkCellRenderer *renderer;
|
|
|
|
GtkTreeSelection *sel;
|
|
|
|
GtkTreeViewColumn *column;
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
gtk_tree_view_set_model(view, model2);
|
|
|
|
gtk_tree_view_set_headers_visible(view, TRUE);
|
2011-05-19 20:37:01 +08:00
|
|
|
gtk_tree_view_set_rules_hint(view, TRUE);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
column = gtk_tree_view_column_new();
|
|
|
|
gtk_tree_view_append_column(view, column);
|
2018-05-23 03:36:12 +08:00
|
|
|
gtk_tree_view_column_set_title(column, "Options");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
renderer = gtk_cell_renderer_pixbuf_new();
|
|
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer, FALSE);
|
|
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer,
|
|
|
|
"pixbuf", COL_PIXBUF,
|
|
|
|
"visible", COL_PIXVIS, NULL);
|
|
|
|
renderer = gtk_cell_renderer_toggle_new();
|
|
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer, FALSE);
|
|
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer,
|
|
|
|
"active", COL_BTNACT,
|
|
|
|
"inconsistent", COL_BTNINC,
|
2005-07-29 06:18:03 +08:00
|
|
|
"visible", COL_BTNVIS,
|
2005-04-17 06:20:36 +08:00
|
|
|
"radio", COL_BTNRAD, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer, FALSE);
|
|
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
|
|
renderer,
|
|
|
|
"text", COL_OPTION,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
2018-05-23 03:36:12 +08:00
|
|
|
"Name", renderer,
|
2005-04-17 06:20:36 +08:00
|
|
|
"text", COL_NAME,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
|
|
"N", renderer,
|
|
|
|
"text", COL_NO,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
|
|
"M", renderer,
|
|
|
|
"text", COL_MOD,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
|
|
"Y", renderer,
|
|
|
|
"text", COL_YES,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
2018-05-23 03:36:12 +08:00
|
|
|
"Value", renderer,
|
2005-04-17 06:20:36 +08:00
|
|
|
"text", COL_VALUE,
|
|
|
|
"editable",
|
|
|
|
COL_EDIT,
|
|
|
|
"foreground-gdk",
|
|
|
|
COL_COLOR, NULL);
|
|
|
|
g_signal_connect(G_OBJECT(renderer), "edited",
|
|
|
|
G_CALLBACK(renderer_edited), NULL);
|
|
|
|
|
|
|
|
column = gtk_tree_view_get_column(view, COL_NAME);
|
|
|
|
gtk_tree_view_column_set_visible(column, show_name);
|
|
|
|
column = gtk_tree_view_get_column(view, COL_NO);
|
|
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
|
|
column = gtk_tree_view_get_column(view, COL_MOD);
|
|
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
|
|
column = gtk_tree_view_get_column(view, COL_YES);
|
|
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
|
|
column = gtk_tree_view_get_column(view, COL_VALUE);
|
|
|
|
gtk_tree_view_column_set_visible(column, show_value);
|
|
|
|
|
|
|
|
if (resizeable) {
|
|
|
|
for (i = 0; i < COL_VALUE; i++) {
|
|
|
|
column = gtk_tree_view_get_column(view, i);
|
|
|
|
gtk_tree_view_column_set_resizable(column, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sel = gtk_tree_view_get_selection(view);
|
|
|
|
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Utility Functions */
|
|
|
|
|
|
|
|
|
|
|
|
static void text_insert_help(struct menu *menu)
|
|
|
|
{
|
|
|
|
GtkTextBuffer *buffer;
|
|
|
|
GtkTextIter start, end;
|
2018-05-23 03:36:12 +08:00
|
|
|
const char *prompt = menu_get_prompt(menu);
|
2009-07-12 16:11:46 +08:00
|
|
|
struct gstr help = str_new();
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2009-07-12 16:11:46 +08:00
|
|
|
menu_get_ext_help(menu, &help);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
|
|
gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
|
|
gtk_text_buffer_delete(buffer, &start, &end);
|
|
|
|
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
|
|
|
|
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
|
|
|
|
NULL);
|
|
|
|
gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
2009-07-12 16:11:46 +08:00
|
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
|
2005-04-17 06:20:36 +08:00
|
|
|
NULL);
|
2009-07-12 16:11:46 +08:00
|
|
|
str_free(&help);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void text_insert_msg(const char *title, const char *message)
|
|
|
|
{
|
|
|
|
GtkTextBuffer *buffer;
|
|
|
|
GtkTextIter start, end;
|
|
|
|
const char *msg = message;
|
|
|
|
|
|
|
|
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
|
|
gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
|
|
gtk_text_buffer_delete(buffer, &start, &end);
|
|
|
|
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
|
|
|
|
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
|
|
|
|
NULL);
|
|
|
|
gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Main Windows Callbacks */
|
|
|
|
|
2006-12-13 16:34:09 +08:00
|
|
|
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
|
2005-04-17 06:20:36 +08:00
|
|
|
gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog, *label;
|
|
|
|
gint result;
|
|
|
|
|
2006-12-13 16:34:09 +08:00
|
|
|
if (!conf_get_changed())
|
2005-04-17 06:20:36 +08:00
|
|
|
return FALSE;
|
|
|
|
|
2018-05-23 03:36:12 +08:00
|
|
|
dialog = gtk_dialog_new_with_buttons("Warning !",
|
2005-04-17 06:20:36 +08:00
|
|
|
GTK_WINDOW(main_wnd),
|
|
|
|
(GtkDialogFlags)
|
|
|
|
(GTK_DIALOG_MODAL |
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
|
|
GTK_STOCK_OK,
|
|
|
|
GTK_RESPONSE_YES,
|
|
|
|
GTK_STOCK_NO,
|
|
|
|
GTK_RESPONSE_NO,
|
|
|
|
GTK_STOCK_CANCEL,
|
|
|
|
GTK_RESPONSE_CANCEL, NULL);
|
|
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog),
|
|
|
|
GTK_RESPONSE_CANCEL);
|
|
|
|
|
2018-05-23 03:36:12 +08:00
|
|
|
label = gtk_label_new("\nSave configuration ?\n");
|
2005-04-17 06:20:36 +08:00
|
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
|
|
|
|
gtk_widget_show(label);
|
|
|
|
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
|
|
switch (result) {
|
|
|
|
case GTK_RESPONSE_YES:
|
2006-12-13 16:34:09 +08:00
|
|
|
on_save_activate(NULL, NULL);
|
2005-04-17 06:20:36 +08:00
|
|
|
return FALSE;
|
|
|
|
case GTK_RESPONSE_NO:
|
|
|
|
return FALSE;
|
|
|
|
case GTK_RESPONSE_CANCEL:
|
|
|
|
case GTK_RESPONSE_DELETE_EVENT:
|
|
|
|
default:
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_window1_destroy(GtkObject * object, gpointer user_data)
|
|
|
|
{
|
|
|
|
gtk_main_quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
on_window1_size_request(GtkWidget * widget,
|
|
|
|
GtkRequisition * requisition, gpointer user_data)
|
|
|
|
{
|
|
|
|
static gint old_h;
|
|
|
|
gint w, h;
|
|
|
|
|
|
|
|
if (widget->window == NULL)
|
|
|
|
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
|
|
|
|
else
|
|
|
|
gdk_window_get_size(widget->window, &w, &h);
|
|
|
|
|
|
|
|
if (h == old_h)
|
|
|
|
return;
|
|
|
|
old_h = h;
|
|
|
|
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Menu & Toolbar Callbacks */
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
load_filename(GtkFileSelection * file_selector, gpointer user_data)
|
|
|
|
{
|
|
|
|
const gchar *fn;
|
|
|
|
|
|
|
|
fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
|
|
|
|
(user_data));
|
|
|
|
|
|
|
|
if (conf_read(fn))
|
2018-05-23 03:36:12 +08:00
|
|
|
text_insert_msg("Error", "Unable to load configuration !");
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
|
|
|
display_tree(&rootmenu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *fs;
|
|
|
|
|
2018-05-23 03:36:12 +08:00
|
|
|
fs = gtk_file_selection_new("Load file...");
|
2005-04-17 06:20:36 +08:00
|
|
|
g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
|
|
|
|
"clicked",
|
|
|
|
G_CALLBACK(load_filename), (gpointer) fs);
|
|
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
|
|
(GTK_FILE_SELECTION(fs)->ok_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer) fs);
|
|
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
|
|
(GTK_FILE_SELECTION(fs)->cancel_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer) fs);
|
|
|
|
gtk_widget_show(fs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-12-13 16:34:09 +08:00
|
|
|
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
if (conf_write(NULL))
|
2018-05-23 03:36:12 +08:00
|
|
|
text_insert_msg("Error", "Unable to save configuration !");
|
kconfig: allow all config targets to write auto.conf if missing
Currently, only syncconfig creates or updates include/config/auto.conf
and some other files. Other config targets create or update only the
.config file.
When you configure and build the kernel from a pristine source tree,
any config target is followed by syncconfig in the build stage since
include/config/auto.conf is missing.
We are moving compiler tests from Makefile to Kconfig. It means that
parsing Kconfig files will be more costly since Kconfig invokes the
compiler commands internally. Thus, we want to avoid invoking Kconfig
twice (one for *config to create the .config, and one for syncconfig
to synchronize the auto.conf). If auto.conf does not exist, we can
generate all configuration files in the first configuration stage,
which will save the syncconfig in the build stage.
Please note this should be done only when auto.conf is missing. If
*config blindly did this, time stamp files under include/config/ would
be unnecessarily touched, triggering unneeded rebuild of objects.
I assume a scenario like this:
1. You have a source tree that has already been built
with CONFIG_FOO disabled
2. Run "make menuconfig" to enable CONFIG_FOO
3. CONFIG_FOO turns out to be unnecessary.
Run "make menuconfig" again to disable CONFIG_FOO
4. Run "make"
In this case, include/config/foo.h should not be touched since there
is no change in CONFIG_FOO. The sync process should be delayed until
the user really attempts to build the kernel.
This commit has another motivation; I want to suppress the 'No such
file or directory' warning from the 'include' directive.
The top-level Makefile includes auto.conf with '-include' directive,
like this:
ifeq ($(dot-config),1)
-include include/config/auto.conf
endif
This looks strange because auto.conf is mandatory when dot-config is 1.
I guess only the reason of using '-include' is to suppress the warning
'include/config/auto.conf: No such file or directory' when building
from a clean tree. However, this has a side-effect; Make considers
the files included by '-include' are optional. Hence, Make continues
to build even if it fails to generate include/config/auto.conf. I will
change this in the next commit, but the warning message is annoying.
(At least, kbuild test robot reports it as a regression.)
With this commit, Kconfig will generate all configuration files together
with the .config and I guess it is a solution good enough to suppress
the warning.
Note:
GNU Make 4.2 or later does not display the warning from the 'include'
directive if include files are successfully generated. See GNU Make
commit 87a5f98d248f ("[SV 102] Don't show unnecessary include file
errors.") However, older GNU Make versions are still widely used.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
2018-07-20 15:46:31 +08:00
|
|
|
conf_write_autoconf(0);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
store_filename(GtkFileSelection * file_selector, gpointer user_data)
|
|
|
|
{
|
|
|
|
const gchar *fn;
|
|
|
|
|
|
|
|
fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
|
|
|
|
(user_data));
|
|
|
|
|
|
|
|
if (conf_write(fn))
|
2018-05-23 03:36:12 +08:00
|
|
|
text_insert_msg("Error", "Unable to save configuration !");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(user_data));
|
|
|
|
}
|
|
|
|
|
|
|
|
void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *fs;
|
|
|
|
|
2018-05-23 03:36:12 +08:00
|
|
|
fs = gtk_file_selection_new("Save file as...");
|
2005-04-17 06:20:36 +08:00
|
|
|
g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
|
|
|
|
"clicked",
|
|
|
|
G_CALLBACK(store_filename), (gpointer) fs);
|
|
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
|
|
(GTK_FILE_SELECTION(fs)->ok_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer) fs);
|
|
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
|
|
(GTK_FILE_SELECTION(fs)->cancel_button),
|
|
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
|
|
(gpointer) fs);
|
|
|
|
gtk_widget_show(fs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
if (!on_window1_delete_event(NULL, NULL, NULL))
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(main_wnd));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeViewColumn *col;
|
|
|
|
|
|
|
|
show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
|
|
|
|
if (col)
|
|
|
|
gtk_tree_view_column_set_visible(col, show_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeViewColumn *col;
|
|
|
|
|
|
|
|
show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
|
|
|
|
if (col)
|
|
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
|
|
|
|
if (col)
|
|
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
|
|
|
|
if (col)
|
|
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeViewColumn *col;
|
|
|
|
|
|
|
|
show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
|
|
|
|
if (col)
|
|
|
|
gtk_tree_view_column_set_visible(col, show_value);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-04-14 11:46:24 +08:00
|
|
|
on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
opt_mode = OPT_NORMAL;
|
|
|
|
gtk_tree_store_clear(tree2);
|
|
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2010-04-14 11:46:24 +08:00
|
|
|
opt_mode = OPT_ALL;
|
|
|
|
gtk_tree_store_clear(tree2);
|
|
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-04-14 11:46:24 +08:00
|
|
|
void
|
|
|
|
on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
opt_mode = OPT_PROMPT;
|
2005-04-17 06:20:36 +08:00
|
|
|
gtk_tree_store_clear(tree2);
|
2010-04-14 11:46:24 +08:00
|
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
2019-05-09 10:46:31 +08:00
|
|
|
const gchar *intro_text =
|
2010-08-15 11:51:40 +08:00
|
|
|
"Welcome to gkc, the GTK+ graphical configuration tool\n"
|
2005-04-17 06:20:36 +08:00
|
|
|
"For each option, a blank box indicates the feature is disabled, a\n"
|
|
|
|
"check indicates it is enabled, and a dot indicates that it is to\n"
|
|
|
|
"be compiled as a module. Clicking on the box will cycle through the three states.\n"
|
|
|
|
"\n"
|
|
|
|
"If you do not see an option (e.g., a device driver) that you\n"
|
|
|
|
"believe should be present, try turning on Show All Options\n"
|
|
|
|
"under the Options menu.\n"
|
|
|
|
"Although there is no cross reference yet to help you figure out\n"
|
|
|
|
"what other options must be enabled to support the option you\n"
|
|
|
|
"are interested in, you can still view the help of a grayed-out\n"
|
|
|
|
"option.\n"
|
|
|
|
"\n"
|
|
|
|
"Toggling Show Debug Info under the Options menu will show \n"
|
2018-05-23 03:36:12 +08:00
|
|
|
"the dependencies, which you can then match by examining other options.";
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_MESSAGE_INFO,
|
2011-10-23 01:19:02 +08:00
|
|
|
GTK_BUTTONS_CLOSE, "%s", intro_text);
|
2005-04-17 06:20:36 +08:00
|
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
|
|
GTK_OBJECT(dialog));
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
const gchar *about_text =
|
2018-05-23 03:36:12 +08:00
|
|
|
"gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
|
|
|
|
"Based on the source code from Roman Zippel.\n";
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_MESSAGE_INFO,
|
2011-10-23 01:19:02 +08:00
|
|
|
GTK_BUTTONS_CLOSE, "%s", about_text);
|
2005-04-17 06:20:36 +08:00
|
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
|
|
GTK_OBJECT(dialog));
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
const gchar *license_text =
|
2018-05-23 03:36:12 +08:00
|
|
|
"gkc is released under the terms of the GNU GPL v2.\n"
|
[PATCH] Kconfig i18n support
This patch adds i18n support for make *config, allowing users to have the
config process in their own language.
No printk was harmed in the process, don't worry, so all the bug reports,
kernel messages, etc, remain in english, just the user tools to configure
the kernel are internationalized.
Users not interested in translations can just unset the related LANG,
LC_ALL, etc env variables and have the config process in plain english,
something like:
LANG= make menuconfig
is enough for having the whole config process in english. Or just don't
install any translation file.
Translations for brazilian portuguese are being done by a team of
volunteers at:
http://www.visionflex.inf.br/kernel_ptbr/pmwiki.php/Principal/Traducoes
To start the translation process:
make update-po-config
This will generate the pot template named scripts/kconfig/linux.pot,
copy it to, say, ~/es.po, to start the translation for spanish.
To test your translation, as root issue this command:
msgfmt -o /usr/share/locale/es/LC_MESSAGES/linux.mo ~/es.po
Replace "es" with your language code.
Then execute, for instance:
make menuconfig
The current patch doesn't use any optimization to reduce the size of the
generated .mo file, it is possible to use the config option as a key, but
this doesn't prevent the current patch from being used or the translations
done under the current scheme to be in any way lost if we chose to do any
kind of keying.
Thanks to Fabricio Vaccari for starting the pt_BR (brazilian portuguese)
translation effort, Thiago Maciera for helping me with the gconf.cc (QT
frontent) i18n coding and to all the volunteers that are already working on
the first translation, to pt_BR.
I left the question on whether to ship the translations with the stock kernel
sources to be discussed here, please share your suggestions.
Signed-off-by: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org
Signed-off-by: Andrew Morton <akpm@osdl.org>
2005-05-06 06:09:46 +08:00
|
|
|
"For more information, please see the source code or\n"
|
2018-05-23 03:36:12 +08:00
|
|
|
"visit http://www.fsf.org/licenses/licenses.html\n";
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
|
|
GTK_MESSAGE_INFO,
|
2011-10-23 01:19:02 +08:00
|
|
|
GTK_BUTTONS_CLOSE, "%s", license_text);
|
2005-04-17 06:20:36 +08:00
|
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
|
|
GTK_OBJECT(dialog));
|
|
|
|
gtk_widget_show_all(dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
void on_back_clicked(GtkButton * button, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
enum prop_type ptype;
|
|
|
|
|
|
|
|
current = current->parent;
|
|
|
|
ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
|
|
|
|
if (ptype != P_MENU)
|
|
|
|
current = current->parent;
|
|
|
|
display_tree_part();
|
|
|
|
|
|
|
|
if (current == &rootmenu)
|
|
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
void on_load_clicked(GtkButton * button, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
on_load1_activate(NULL, user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_single_clicked(GtkButton * button, gpointer user_data)
|
|
|
|
{
|
|
|
|
view_mode = SINGLE_VIEW;
|
|
|
|
gtk_widget_hide(tree1_w);
|
|
|
|
current = &rootmenu;
|
|
|
|
display_tree_part();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_split_clicked(GtkButton * button, gpointer user_data)
|
|
|
|
{
|
|
|
|
gint w, h;
|
|
|
|
view_mode = SPLIT_VIEW;
|
|
|
|
gtk_widget_show(tree1_w);
|
|
|
|
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
|
|
|
|
gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
|
2005-07-29 06:18:03 +08:00
|
|
|
if (tree2)
|
2005-04-17 06:20:36 +08:00
|
|
|
gtk_tree_store_clear(tree2);
|
|
|
|
display_list();
|
2005-07-29 06:18:03 +08:00
|
|
|
|
|
|
|
/* Disable back btn, like in full mode. */
|
|
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void on_full_clicked(GtkButton * button, gpointer user_data)
|
|
|
|
{
|
|
|
|
view_mode = FULL_VIEW;
|
|
|
|
gtk_widget_hide(tree1_w);
|
|
|
|
if (tree2)
|
|
|
|
gtk_tree_store_clear(tree2);
|
|
|
|
display_tree(&rootmenu);
|
|
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
void on_collapse_clicked(GtkButton * button, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
void on_expand_clicked(GtkButton * button, gpointer user_data)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* CTree Callbacks */
|
|
|
|
|
|
|
|
/* Change hex/int/string value in the cell */
|
|
|
|
static void renderer_edited(GtkCellRendererText * cell,
|
|
|
|
const gchar * path_string,
|
|
|
|
const gchar * new_text, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
|
|
|
|
GtkTreeIter iter;
|
|
|
|
const char *old_def, *new_def;
|
|
|
|
struct menu *menu;
|
|
|
|
struct symbol *sym;
|
|
|
|
|
|
|
|
if (!gtk_tree_model_get_iter(model2, &iter, path))
|
|
|
|
return;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
sym = menu->sym;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
|
|
|
|
new_def = new_text;
|
|
|
|
|
|
|
|
sym_set_string_value(sym, new_def);
|
|
|
|
|
|
|
|
update_tree(&rootmenu, NULL);
|
|
|
|
|
|
|
|
gtk_tree_path_free(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Change the value of a symbol and update the tree */
|
|
|
|
static void change_sym_value(struct menu *menu, gint col)
|
|
|
|
{
|
|
|
|
struct symbol *sym = menu->sym;
|
2011-10-23 02:01:24 +08:00
|
|
|
tristate newval;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (!sym)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (col == COL_NO)
|
|
|
|
newval = no;
|
|
|
|
else if (col == COL_MOD)
|
|
|
|
newval = mod;
|
|
|
|
else if (col == COL_YES)
|
|
|
|
newval = yes;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (sym_get_type(sym)) {
|
|
|
|
case S_BOOLEAN:
|
|
|
|
case S_TRISTATE:
|
|
|
|
if (!sym_tristate_within_range(sym, newval))
|
|
|
|
newval = yes;
|
|
|
|
sym_set_tristate_value(sym, newval);
|
|
|
|
if (view_mode == FULL_VIEW)
|
|
|
|
update_tree(&rootmenu, NULL);
|
|
|
|
else if (view_mode == SPLIT_VIEW) {
|
|
|
|
update_tree(browsed, NULL);
|
|
|
|
display_list();
|
|
|
|
}
|
|
|
|
else if (view_mode == SINGLE_VIEW)
|
|
|
|
display_tree_part(); //fixme: keep exp/coll
|
|
|
|
break;
|
|
|
|
case S_INT:
|
|
|
|
case S_HEX:
|
|
|
|
case S_STRING:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void toggle_sym_value(struct menu *menu)
|
|
|
|
{
|
|
|
|
if (!menu->sym)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sym_toggle_tristate_value(menu->sym);
|
|
|
|
if (view_mode == FULL_VIEW)
|
|
|
|
update_tree(&rootmenu, NULL);
|
|
|
|
else if (view_mode == SPLIT_VIEW) {
|
|
|
|
update_tree(browsed, NULL);
|
|
|
|
display_list();
|
|
|
|
}
|
|
|
|
else if (view_mode == SINGLE_VIEW)
|
|
|
|
display_tree_part(); //fixme: keep exp/coll
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint column2index(GtkTreeViewColumn * column)
|
|
|
|
{
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
for (i = 0; i < COL_NUMBER; i++) {
|
|
|
|
GtkTreeViewColumn *col;
|
|
|
|
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
|
|
|
|
if (col == column)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* User click: update choice (full) or goes down (single) */
|
|
|
|
gboolean
|
|
|
|
on_treeview2_button_press_event(GtkWidget * widget,
|
|
|
|
GdkEventButton * event, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeViewColumn *column;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct menu *menu;
|
|
|
|
gint col;
|
|
|
|
|
|
|
|
#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
|
|
|
|
gint tx = (gint) event->x;
|
|
|
|
gint ty = (gint) event->y;
|
|
|
|
gint cx, cy;
|
|
|
|
|
|
|
|
gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
|
|
|
|
&cy);
|
|
|
|
#else
|
|
|
|
gtk_tree_view_get_cursor(view, &path, &column);
|
|
|
|
#endif
|
|
|
|
if (path == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!gtk_tree_model_get_iter(model2, &iter, path))
|
|
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
|
|
|
|
col = column2index(column);
|
|
|
|
if (event->type == GDK_2BUTTON_PRESS) {
|
|
|
|
enum prop_type ptype;
|
|
|
|
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
|
|
|
|
|
|
|
|
if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
|
|
|
|
// goes down into menu
|
|
|
|
current = menu;
|
|
|
|
display_tree_part();
|
|
|
|
gtk_widget_set_sensitive(back_btn, TRUE);
|
2017-03-14 03:33:41 +08:00
|
|
|
} else if (col == COL_OPTION) {
|
2005-04-17 06:20:36 +08:00
|
|
|
toggle_sym_value(menu);
|
|
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (col == COL_VALUE) {
|
|
|
|
toggle_sym_value(menu);
|
|
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
|
|
} else if (col == COL_NO || col == COL_MOD
|
|
|
|
|| col == COL_YES) {
|
|
|
|
change_sym_value(menu, col);
|
|
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Key pressed: update choice */
|
|
|
|
gboolean
|
|
|
|
on_treeview2_key_press_event(GtkWidget * widget,
|
|
|
|
GdkEventKey * event, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeViewColumn *column;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct menu *menu;
|
|
|
|
gint col;
|
|
|
|
|
|
|
|
gtk_tree_view_get_cursor(view, &path, &column);
|
|
|
|
if (path == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (event->keyval == GDK_space) {
|
|
|
|
if (gtk_tree_view_row_expanded(view, path))
|
|
|
|
gtk_tree_view_collapse_row(view, path);
|
|
|
|
else
|
|
|
|
gtk_tree_view_expand_row(view, path, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if (event->keyval == GDK_KP_Enter) {
|
|
|
|
}
|
|
|
|
if (widget == tree1_w)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gtk_tree_model_get_iter(model2, &iter, path);
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
|
|
|
|
if (!strcasecmp(event->string, "n"))
|
|
|
|
col = COL_NO;
|
|
|
|
else if (!strcasecmp(event->string, "m"))
|
|
|
|
col = COL_MOD;
|
|
|
|
else if (!strcasecmp(event->string, "y"))
|
|
|
|
col = COL_YES;
|
|
|
|
else
|
|
|
|
col = -1;
|
|
|
|
change_sym_value(menu, col);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Row selection changed: update help */
|
|
|
|
void
|
|
|
|
on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeSelection *selection;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct menu *menu;
|
|
|
|
|
|
|
|
selection = gtk_tree_view_get_selection(treeview);
|
|
|
|
if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
text_insert_help(menu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* User click: display sub-tree in the right frame. */
|
|
|
|
gboolean
|
|
|
|
on_treeview1_button_press_event(GtkWidget * widget,
|
|
|
|
GdkEventButton * event, gpointer user_data)
|
|
|
|
{
|
|
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
|
|
GtkTreePath *path;
|
|
|
|
GtkTreeViewColumn *column;
|
|
|
|
GtkTreeIter iter;
|
|
|
|
struct menu *menu;
|
|
|
|
|
|
|
|
gint tx = (gint) event->x;
|
|
|
|
gint ty = (gint) event->y;
|
|
|
|
gint cx, cy;
|
|
|
|
|
|
|
|
gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
|
|
|
|
&cy);
|
|
|
|
if (path == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gtk_tree_model_get_iter(model1, &iter, path);
|
|
|
|
gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
|
|
|
|
|
|
|
|
if (event->type == GDK_2BUTTON_PRESS) {
|
|
|
|
toggle_sym_value(menu);
|
|
|
|
current = menu;
|
|
|
|
display_tree_part();
|
|
|
|
} else {
|
|
|
|
browsed = menu;
|
|
|
|
display_tree_part();
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_widget_realize(tree2_w);
|
|
|
|
gtk_tree_view_set_cursor(view, path, NULL, FALSE);
|
|
|
|
gtk_widget_grab_focus(tree2_w);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Fill a row of strings */
|
|
|
|
static gchar **fill_row(struct menu *menu)
|
|
|
|
{
|
|
|
|
static gchar *row[COL_NUMBER];
|
|
|
|
struct symbol *sym = menu->sym;
|
|
|
|
const char *def;
|
|
|
|
int stype;
|
|
|
|
tristate val;
|
|
|
|
enum prop_type ptype;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = COL_OPTION; i <= COL_COLOR; i++)
|
|
|
|
g_free(row[i]);
|
|
|
|
bzero(row, sizeof(row));
|
|
|
|
|
2021-04-18 13:51:22 +08:00
|
|
|
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
row[COL_OPTION] =
|
2021-04-18 13:51:22 +08:00
|
|
|
g_strdup_printf("%s %s %s %s",
|
|
|
|
ptype == P_COMMENT ? "***" : "",
|
|
|
|
menu_get_prompt(menu),
|
|
|
|
ptype == P_COMMENT ? "***" : "",
|
2010-05-07 13:57:35 +08:00
|
|
|
sym && !sym_has_value(sym) ? "(NEW)" : "");
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2010-04-14 11:46:24 +08:00
|
|
|
if (opt_mode == OPT_ALL && !menu_is_visible(menu))
|
|
|
|
row[COL_COLOR] = g_strdup("DarkGray");
|
|
|
|
else if (opt_mode == OPT_PROMPT &&
|
|
|
|
menu_has_prompt(menu) && !menu_is_visible(menu))
|
2005-04-17 06:20:36 +08:00
|
|
|
row[COL_COLOR] = g_strdup("DarkGray");
|
|
|
|
else
|
|
|
|
row[COL_COLOR] = g_strdup("Black");
|
|
|
|
|
|
|
|
switch (ptype) {
|
|
|
|
case P_MENU:
|
|
|
|
row[COL_PIXBUF] = (gchar *) xpm_menu;
|
|
|
|
if (view_mode == SINGLE_VIEW)
|
|
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
break;
|
|
|
|
case P_COMMENT:
|
|
|
|
row[COL_PIXBUF] = (gchar *) xpm_void;
|
|
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
row[COL_PIXBUF] = (gchar *) xpm_void;
|
|
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sym)
|
|
|
|
return row;
|
|
|
|
row[COL_NAME] = g_strdup(sym->name);
|
|
|
|
|
|
|
|
sym_calc_value(sym);
|
|
|
|
sym->flags &= ~SYMBOL_CHANGED;
|
|
|
|
|
|
|
|
if (sym_is_choice(sym)) { // parse childs for getting final value
|
|
|
|
struct menu *child;
|
|
|
|
struct symbol *def_sym = sym_get_choice_value(sym);
|
|
|
|
struct menu *def_menu = NULL;
|
|
|
|
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
|
|
if (menu_is_visible(child)
|
|
|
|
&& child->sym == def_sym)
|
|
|
|
def_menu = child;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (def_menu)
|
|
|
|
row[COL_VALUE] =
|
2018-05-23 03:36:12 +08:00
|
|
|
g_strdup(menu_get_prompt(def_menu));
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2005-07-29 06:18:03 +08:00
|
|
|
if (sym->flags & SYMBOL_CHOICEVAL)
|
2005-04-17 06:20:36 +08:00
|
|
|
row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
|
|
|
|
|
|
|
|
stype = sym_get_type(sym);
|
|
|
|
switch (stype) {
|
|
|
|
case S_BOOLEAN:
|
2005-07-29 06:18:03 +08:00
|
|
|
if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
|
2005-04-17 06:20:36 +08:00
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
|
|
|
|
if (sym_is_choice(sym))
|
|
|
|
break;
|
2011-06-01 00:30:26 +08:00
|
|
|
/* fall through */
|
2005-04-17 06:20:36 +08:00
|
|
|
case S_TRISTATE:
|
|
|
|
val = sym_get_tristate_value(sym);
|
|
|
|
switch (val) {
|
|
|
|
case no:
|
|
|
|
row[COL_NO] = g_strdup("N");
|
|
|
|
row[COL_VALUE] = g_strdup("N");
|
|
|
|
row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
|
|
|
|
row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
|
|
|
|
break;
|
|
|
|
case mod:
|
|
|
|
row[COL_MOD] = g_strdup("M");
|
|
|
|
row[COL_VALUE] = g_strdup("M");
|
|
|
|
row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
|
|
|
|
break;
|
|
|
|
case yes:
|
|
|
|
row[COL_YES] = g_strdup("Y");
|
|
|
|
row[COL_VALUE] = g_strdup("Y");
|
|
|
|
row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
|
|
|
|
row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (val != no && sym_tristate_within_range(sym, no))
|
|
|
|
row[COL_NO] = g_strdup("_");
|
|
|
|
if (val != mod && sym_tristate_within_range(sym, mod))
|
|
|
|
row[COL_MOD] = g_strdup("_");
|
|
|
|
if (val != yes && sym_tristate_within_range(sym, yes))
|
|
|
|
row[COL_YES] = g_strdup("_");
|
|
|
|
break;
|
|
|
|
case S_INT:
|
|
|
|
case S_HEX:
|
|
|
|
case S_STRING:
|
|
|
|
def = sym_get_string_value(sym);
|
|
|
|
row[COL_VALUE] = g_strdup(def);
|
|
|
|
row[COL_EDIT] = GINT_TO_POINTER(TRUE);
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return row;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Set the node content with a row of strings */
|
|
|
|
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
|
|
|
|
{
|
|
|
|
GdkColor color;
|
|
|
|
gboolean success;
|
|
|
|
GdkPixbuf *pix;
|
|
|
|
|
|
|
|
pix = gdk_pixbuf_new_from_xpm_data((const char **)
|
|
|
|
row[COL_PIXBUF]);
|
|
|
|
|
|
|
|
gdk_color_parse(row[COL_COLOR], &color);
|
|
|
|
gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
|
|
|
|
FALSE, FALSE, &success);
|
|
|
|
|
|
|
|
gtk_tree_store_set(tree, node,
|
|
|
|
COL_OPTION, row[COL_OPTION],
|
|
|
|
COL_NAME, row[COL_NAME],
|
|
|
|
COL_NO, row[COL_NO],
|
|
|
|
COL_MOD, row[COL_MOD],
|
|
|
|
COL_YES, row[COL_YES],
|
|
|
|
COL_VALUE, row[COL_VALUE],
|
|
|
|
COL_MENU, (gpointer) menu,
|
|
|
|
COL_COLOR, &color,
|
|
|
|
COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
|
|
|
|
COL_PIXBUF, pix,
|
|
|
|
COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
|
|
|
|
COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
|
|
|
|
COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
|
|
|
|
COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
|
|
|
|
COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
|
|
|
|
-1);
|
|
|
|
|
|
|
|
g_object_unref(pix);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Add a node to the tree */
|
|
|
|
static void place_node(struct menu *menu, char **row)
|
|
|
|
{
|
|
|
|
GtkTreeIter *parent = parents[indent - 1];
|
|
|
|
GtkTreeIter *node = parents[indent];
|
|
|
|
|
|
|
|
gtk_tree_store_append(tree, node, parent);
|
|
|
|
set_node(node, menu, row);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Find a node in the GTK+ tree */
|
|
|
|
static GtkTreeIter found;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find a menu in the GtkTree starting at parent.
|
|
|
|
*/
|
2018-12-21 16:33:06 +08:00
|
|
|
static GtkTreeIter *gtktree_iter_find_node(GtkTreeIter *parent,
|
|
|
|
struct menu *tofind)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeIter *child = &iter;
|
|
|
|
gboolean valid;
|
|
|
|
GtkTreeIter *ret;
|
|
|
|
|
|
|
|
valid = gtk_tree_model_iter_children(model2, child, parent);
|
|
|
|
while (valid) {
|
|
|
|
struct menu *menu;
|
|
|
|
|
|
|
|
gtk_tree_model_get(model2, child, 6, &menu, -1);
|
|
|
|
|
|
|
|
if (menu == tofind) {
|
|
|
|
memcpy(&found, child, sizeof(GtkTreeIter));
|
|
|
|
return &found;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = gtktree_iter_find_node(child, tofind);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
valid = gtk_tree_model_iter_next(model2, child);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Update the tree by adding/removing entries
|
|
|
|
* Does not change other nodes
|
|
|
|
*/
|
|
|
|
static void update_tree(struct menu *src, GtkTreeIter * dst)
|
|
|
|
{
|
|
|
|
struct menu *child1;
|
|
|
|
GtkTreeIter iter, tmp;
|
|
|
|
GtkTreeIter *child2 = &iter;
|
|
|
|
gboolean valid;
|
|
|
|
GtkTreeIter *sibling;
|
|
|
|
struct symbol *sym;
|
|
|
|
struct menu *menu1, *menu2;
|
|
|
|
|
|
|
|
if (src == &rootmenu)
|
|
|
|
indent = 1;
|
|
|
|
|
|
|
|
valid = gtk_tree_model_iter_children(model2, child2, dst);
|
|
|
|
for (child1 = src->list; child1; child1 = child1->next) {
|
|
|
|
|
|
|
|
sym = child1->sym;
|
|
|
|
|
|
|
|
reparse:
|
|
|
|
menu1 = child1;
|
|
|
|
if (valid)
|
|
|
|
gtk_tree_model_get(model2, child2, COL_MENU,
|
|
|
|
&menu2, -1);
|
|
|
|
else
|
|
|
|
menu2 = NULL; // force adding of a first child
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("%*c%s | %s\n", indent, ' ',
|
|
|
|
menu1 ? menu_get_prompt(menu1) : "nil",
|
|
|
|
menu2 ? menu_get_prompt(menu2) : "nil");
|
|
|
|
#endif
|
|
|
|
|
2010-04-14 11:46:24 +08:00
|
|
|
if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
|
2010-05-07 13:57:49 +08:00
|
|
|
(opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
|
|
|
|
(opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
|
2010-04-14 11:46:24 +08:00
|
|
|
|
|
|
|
/* remove node */
|
2005-04-17 06:20:36 +08:00
|
|
|
if (gtktree_iter_find_node(dst, menu1) != NULL) {
|
|
|
|
memcpy(&tmp, child2, sizeof(GtkTreeIter));
|
|
|
|
valid = gtk_tree_model_iter_next(model2,
|
|
|
|
child2);
|
|
|
|
gtk_tree_store_remove(tree2, &tmp);
|
|
|
|
if (!valid)
|
2010-04-14 11:46:24 +08:00
|
|
|
return; /* next parent */
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
2010-04-14 11:46:24 +08:00
|
|
|
goto reparse; /* next child */
|
2005-04-17 06:20:36 +08:00
|
|
|
} else
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (menu1 != menu2) {
|
|
|
|
if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
|
|
|
|
if (!valid && !menu2)
|
|
|
|
sibling = NULL;
|
|
|
|
else
|
|
|
|
sibling = child2;
|
|
|
|
gtk_tree_store_insert_before(tree2,
|
|
|
|
child2,
|
|
|
|
dst, sibling);
|
|
|
|
set_node(child2, menu1, fill_row(menu1));
|
|
|
|
if (menu2 == NULL)
|
|
|
|
valid = TRUE;
|
|
|
|
} else { // remove node
|
|
|
|
memcpy(&tmp, child2, sizeof(GtkTreeIter));
|
|
|
|
valid = gtk_tree_model_iter_next(model2,
|
|
|
|
child2);
|
|
|
|
gtk_tree_store_remove(tree2, &tmp);
|
|
|
|
if (!valid)
|
2005-07-29 06:18:03 +08:00
|
|
|
return; // next parent
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
|
|
|
goto reparse; // next child
|
|
|
|
}
|
|
|
|
} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
|
|
|
|
set_node(child2, menu1, fill_row(menu1));
|
|
|
|
}
|
|
|
|
|
|
|
|
indent++;
|
|
|
|
update_tree(child1, child2);
|
|
|
|
indent--;
|
|
|
|
|
|
|
|
valid = gtk_tree_model_iter_next(model2, child2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Display the whole tree (single/split/full view) */
|
|
|
|
static void display_tree(struct menu *menu)
|
|
|
|
{
|
|
|
|
struct symbol *sym;
|
|
|
|
struct property *prop;
|
|
|
|
struct menu *child;
|
|
|
|
enum prop_type ptype;
|
|
|
|
|
|
|
|
if (menu == &rootmenu) {
|
|
|
|
indent = 1;
|
|
|
|
current = &rootmenu;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
|
|
prop = child->prompt;
|
|
|
|
sym = child->sym;
|
|
|
|
ptype = prop ? prop->type : P_UNKNOWN;
|
|
|
|
|
|
|
|
if (sym)
|
|
|
|
sym->flags &= ~SYMBOL_CHANGED;
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
if ((view_mode == SPLIT_VIEW)
|
|
|
|
&& !(child->flags & MENU_ROOT) && (tree == tree1))
|
2005-04-17 06:20:36 +08:00
|
|
|
continue;
|
|
|
|
|
2005-07-29 06:18:03 +08:00
|
|
|
if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
|
|
|
|
&& (tree == tree2))
|
2005-04-17 06:20:36 +08:00
|
|
|
continue;
|
|
|
|
|
2010-04-14 11:46:24 +08:00
|
|
|
if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
|
|
|
|
(opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
|
2010-05-07 13:57:49 +08:00
|
|
|
(opt_mode == OPT_ALL && menu_get_prompt(child)))
|
2005-04-17 06:20:36 +08:00
|
|
|
place_node(child, fill_row(child));
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
|
|
|
|
printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
|
2010-04-14 11:44:34 +08:00
|
|
|
printf("%s", prop_get_type_name(ptype));
|
2005-04-17 06:20:36 +08:00
|
|
|
printf(" | ");
|
|
|
|
if (sym) {
|
2010-04-14 11:44:34 +08:00
|
|
|
printf("%s", sym_type_name(sym->type));
|
2005-04-17 06:20:36 +08:00
|
|
|
printf(" | ");
|
2010-04-14 11:44:34 +08:00
|
|
|
printf("%s", dbg_sym_flags(sym->flags));
|
2005-04-17 06:20:36 +08:00
|
|
|
printf("\n");
|
|
|
|
} else
|
|
|
|
printf("\n");
|
|
|
|
#endif
|
|
|
|
if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
|
|
|
|
&& (tree == tree2))
|
|
|
|
continue;
|
|
|
|
/*
|
2014-06-10 18:08:13 +08:00
|
|
|
if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
|
2005-07-29 06:18:03 +08:00
|
|
|
|| (view_mode == FULL_VIEW)
|
2005-04-17 06:20:36 +08:00
|
|
|
|| (view_mode == SPLIT_VIEW))*/
|
2011-05-19 20:38:25 +08:00
|
|
|
|
|
|
|
/* Change paned position if the view is not in 'split mode' */
|
|
|
|
if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
|
|
|
|
gtk_paned_set_position(GTK_PANED(hpaned), 0);
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
|
2005-07-29 06:18:03 +08:00
|
|
|
|| (view_mode == FULL_VIEW)
|
|
|
|
|| (view_mode == SPLIT_VIEW)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
indent++;
|
|
|
|
display_tree(child);
|
|
|
|
indent--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Display a part of the tree starting at current node (single/split view) */
|
|
|
|
static void display_tree_part(void)
|
|
|
|
{
|
|
|
|
if (tree2)
|
|
|
|
gtk_tree_store_clear(tree2);
|
2005-07-29 06:18:03 +08:00
|
|
|
if (view_mode == SINGLE_VIEW)
|
2005-04-17 06:20:36 +08:00
|
|
|
display_tree(current);
|
2005-07-29 06:18:03 +08:00
|
|
|
else if (view_mode == SPLIT_VIEW)
|
2005-04-17 06:20:36 +08:00
|
|
|
display_tree(browsed);
|
|
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Display the list in the left frame (split view) */
|
|
|
|
static void display_list(void)
|
|
|
|
{
|
|
|
|
if (tree1)
|
|
|
|
gtk_tree_store_clear(tree1);
|
|
|
|
|
|
|
|
tree = tree1;
|
|
|
|
display_tree(&rootmenu);
|
|
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
|
|
|
|
tree = tree2;
|
|
|
|
}
|
|
|
|
|
2018-12-21 16:33:06 +08:00
|
|
|
static void fixup_rootmenu(struct menu *menu)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-07-29 06:18:03 +08:00
|
|
|
struct menu *child;
|
|
|
|
static int menu_cnt = 0;
|
|
|
|
|
|
|
|
menu->flags |= MENU_ROOT;
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
|
|
if (child->prompt && child->prompt->type == P_MENU) {
|
|
|
|
menu_cnt++;
|
|
|
|
fixup_rootmenu(child);
|
|
|
|
menu_cnt--;
|
|
|
|
} else if (!menu_cnt)
|
|
|
|
fixup_rootmenu(child);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Main */
|
|
|
|
int main(int ac, char *av[])
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
char *env;
|
|
|
|
gchar *glade_file;
|
|
|
|
|
|
|
|
/* GTK stuffs */
|
|
|
|
gtk_set_locale();
|
|
|
|
gtk_init(&ac, &av);
|
|
|
|
glade_init();
|
|
|
|
|
|
|
|
/* Determine GUI path */
|
|
|
|
env = getenv(SRCTREE);
|
|
|
|
if (env)
|
|
|
|
glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
|
|
|
|
else if (av[0][0] == '/')
|
|
|
|
glade_file = g_strconcat(av[0], ".glade", NULL);
|
|
|
|
else
|
|
|
|
glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
|
|
|
|
|
|
|
|
/* Conf stuffs */
|
|
|
|
if (ac > 1 && av[1][0] == '-') {
|
|
|
|
switch (av[1][1]) {
|
|
|
|
case 'a':
|
|
|
|
//showAll = 1;
|
|
|
|
break;
|
2015-04-08 19:30:42 +08:00
|
|
|
case 's':
|
|
|
|
conf_set_message_callback(NULL);
|
|
|
|
break;
|
2005-04-17 06:20:36 +08:00
|
|
|
case 'h':
|
|
|
|
case '?':
|
2015-04-08 19:30:42 +08:00
|
|
|
printf("%s [-s] <config>\n", av[0]);
|
2005-04-17 06:20:36 +08:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
name = av[2];
|
|
|
|
} else
|
|
|
|
name = av[1];
|
|
|
|
|
|
|
|
conf_parse(name);
|
|
|
|
fixup_rootmenu(&rootmenu);
|
|
|
|
conf_read(NULL);
|
|
|
|
|
2010-09-20 10:47:17 +08:00
|
|
|
/* Load the interface and connect signals */
|
|
|
|
init_main_window(glade_file);
|
|
|
|
init_tree_model();
|
|
|
|
init_left_tree();
|
|
|
|
init_right_tree();
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
switch (view_mode) {
|
|
|
|
case SINGLE_VIEW:
|
|
|
|
display_tree_part();
|
|
|
|
break;
|
|
|
|
case SPLIT_VIEW:
|
|
|
|
display_list();
|
|
|
|
break;
|
|
|
|
case FULL_VIEW:
|
|
|
|
display_tree(&rootmenu);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_main();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2006-12-13 16:34:09 +08:00
|
|
|
|
|
|
|
static void conf_changed(void)
|
|
|
|
{
|
|
|
|
bool changed = conf_get_changed();
|
|
|
|
gtk_widget_set_sensitive(save_btn, changed);
|
|
|
|
gtk_widget_set_sensitive(save_menu_item, changed);
|
|
|
|
}
|