do freeze/thaw in packet_list_set_selected_row only, if the list must be moved. This...
[obnox/wireshark/wip.git] / gtk / layout_prefs.c
1 /* layout_prefs.c
2  * Dialog box for layout preferences
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <gtk/gtk.h>
30
31 #include "globals.h"
32 #include "layout_prefs.h"
33 #include "gtkglobals.h"
34 #include <epan/prefs.h>
35 #include "gui_utils.h"
36 #include "main.h"
37 #include "compat_macros.h"
38 #include "dlg_utils.h"
39
40 #include "../image/icon_layout_1.xpm"
41 #include "../image/icon_layout_2.xpm"
42 #include "../image/icon_layout_3.xpm"
43 #include "../image/icon_layout_4.xpm"
44 #include "../image/icon_layout_5.xpm"
45 #include "../image/icon_layout_6.xpm"
46
47 #define LAYOUT_QTY (layout_type_max - 1)
48
49
50 static void layout_validate_cb(GtkWidget *w _U_, gpointer data);
51
52
53
54 typedef struct {
55     layout_type_e           type;
56     layout_pane_content_e   content[3];
57 } layout_t;
58
59
60 #define LAYOUT_TYPE_BUTTONS_KEY     "layout_type_buttons"
61
62 #define LAYOUT_NONE_RB_KEY          "layout_none_radio_button"
63 #define LAYOUT_PLIST_RB_KEY         "layout_plist_radio_button"
64 #define LAYOUT_PDETAILS_RB_KEY      "layout_pdetails_radio_button"
65 #define LAYOUT_PBYTES_RB_KEY        "layout_pbytes_radio_button"
66
67 #define LAYOUT_CONTENT1_VB_KEY      "layout_content1_vbox"
68 #define LAYOUT_CONTENT2_VB_KEY      "layout_content2_vbox"
69 #define LAYOUT_CONTENT3_VB_KEY      "layout_content3_vbox"
70
71
72 static GtkWidget *layout_content_radio_vbox(GtkWidget *main_vb, GtkTooltips *tooltips, int i, layout_pane_content_e content) {
73     GtkWidget   *radio_vb, *radio_lb;
74     GtkWidget   *radio_none_rb, *radio_plist_rb, *radio_pdetails_rb, *radio_pbytes_rb;
75     char buf[64];
76
77
78     /* radio vbox */
79     radio_vb = gtk_vbox_new(FALSE, 0);
80     gtk_container_set_border_width(GTK_CONTAINER(radio_vb), 6);
81
82     g_snprintf (buf, sizeof(buf), "Pane %d:", i);
83     radio_lb = gtk_label_new(buf);
84     gtk_misc_set_alignment(GTK_MISC(radio_lb), 0.0, 0.5);
85     gtk_container_add(GTK_CONTAINER(radio_vb), radio_lb);
86
87     radio_none_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(NULL, "None", NULL);
88     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(radio_none_rb), content == layout_pane_content_none);
89     gtk_tooltips_set_tip (tooltips, radio_none_rb, "Put nothing in this pane.", NULL);
90     gtk_container_add(GTK_CONTAINER(radio_vb), radio_none_rb);
91
92     radio_plist_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(radio_none_rb, "Packet List", NULL);
93     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(radio_plist_rb), content == layout_pane_content_plist);
94     gtk_tooltips_set_tip (tooltips, radio_plist_rb, "Put the packet list in this pane.", NULL);
95     gtk_container_add(GTK_CONTAINER(radio_vb), radio_plist_rb);
96
97     radio_pdetails_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(radio_none_rb, "Packet Details", NULL);
98     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(radio_pdetails_rb), content == layout_pane_content_pdetails);
99     gtk_tooltips_set_tip (tooltips, radio_pdetails_rb, "Put the packet details tree in this pane.", NULL);
100     gtk_container_add(GTK_CONTAINER(radio_vb), radio_pdetails_rb);
101
102     radio_pbytes_rb = RADIO_BUTTON_NEW_WITH_MNEMONIC(radio_none_rb, "Packet Bytes", NULL);
103     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(radio_pbytes_rb), content == layout_pane_content_pbytes);
104     gtk_tooltips_set_tip (tooltips, radio_pbytes_rb, "Put the packet bytes hexdump in this pane.", NULL);
105     gtk_container_add(GTK_CONTAINER(radio_vb), radio_pbytes_rb);
106
107     OBJECT_SET_DATA(radio_vb, LAYOUT_NONE_RB_KEY,       radio_none_rb);
108     OBJECT_SET_DATA(radio_vb, LAYOUT_PLIST_RB_KEY,      radio_plist_rb);
109     OBJECT_SET_DATA(radio_vb, LAYOUT_PDETAILS_RB_KEY,   radio_pdetails_rb);
110     OBJECT_SET_DATA(radio_vb, LAYOUT_PBYTES_RB_KEY,     radio_pbytes_rb);
111
112     SIGNAL_CONNECT(radio_none_rb,       "toggled", layout_validate_cb, main_vb);
113     SIGNAL_CONNECT(radio_plist_rb,      "toggled", layout_validate_cb, main_vb);
114     SIGNAL_CONNECT(radio_pdetails_rb,   "toggled", layout_validate_cb, main_vb);
115     SIGNAL_CONNECT(radio_pbytes_rb,     "toggled", layout_validate_cb, main_vb);
116
117     return radio_vb;
118 }
119
120 static void
121 layout_type_changed_cb (GtkToggleButton * togglebutton, gpointer user_data)
122 {
123         GtkWidget ** layout_type_buttons = (GtkWidget**) user_data;
124         static gboolean dampen_feedback_loop = FALSE;
125
126         if (!dampen_feedback_loop) {
127                 int i;
128                 dampen_feedback_loop = TRUE;
129                 for (i=0; i<LAYOUT_QTY; ++i) {
130                         GtkToggleButton * tb = GTK_TOGGLE_BUTTON(layout_type_buttons[i]);
131                         gboolean active = togglebutton==tb;
132                         if (gtk_toggle_button_get_active(tb) != active)
133                                 gtk_toggle_button_set_active (tb, active);
134                 }
135                 dampen_feedback_loop = FALSE;
136         }
137 }
138
139
140 static layout_pane_content_e  layout_pane_get_content(GtkWidget * radio_vb) {
141
142     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_NONE_RB_KEY))))
143         return layout_pane_content_none;
144     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PLIST_RB_KEY))))
145         return layout_pane_content_plist;
146     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PDETAILS_RB_KEY))))
147         return layout_pane_content_pdetails;
148     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PBYTES_RB_KEY))))
149         return layout_pane_content_pbytes;
150
151     g_assert_not_reached();
152     return -1;
153 }
154
155 static void layout_pane_set_content(GtkWidget * radio_vb, layout_pane_content_e pane_content) {
156
157
158     switch(pane_content) {
159     case(layout_pane_content_none):
160         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_NONE_RB_KEY)), TRUE);
161         break;
162     case(layout_pane_content_plist):
163         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PLIST_RB_KEY)), TRUE);
164         break;
165     case(layout_pane_content_pdetails):
166         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PDETAILS_RB_KEY)), TRUE);
167         break;
168     case(layout_pane_content_pbytes):
169         gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(OBJECT_GET_DATA(radio_vb, LAYOUT_PBYTES_RB_KEY)), TRUE);
170         break;
171     default:
172         g_assert_not_reached();
173     }
174 }
175
176
177
178 static void layout_set(GtkWidget * main_vb, layout_t *layout) {
179     GtkWidget   *radio_vb;
180     GtkWidget ** layout_type_buttons = OBJECT_GET_DATA(main_vb, LAYOUT_TYPE_BUTTONS_KEY);
181
182     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(layout_type_buttons[layout->type - 1]), TRUE);
183
184     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT1_VB_KEY);
185     layout_pane_set_content(radio_vb, layout->content[0]);
186     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT2_VB_KEY);
187     layout_pane_set_content(radio_vb, layout->content[1]);
188     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT3_VB_KEY);
189     layout_pane_set_content(radio_vb, layout->content[2]);
190 }
191
192 static void layout_get(GtkWidget * main_vb, layout_t *layout_out) {
193     GtkWidget   *radio_vb;
194     GtkWidget ** layout_type_buttons = OBJECT_GET_DATA(main_vb, LAYOUT_TYPE_BUTTONS_KEY);
195     int i;
196
197     for (i=0; i<LAYOUT_QTY; ++i) {
198         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(layout_type_buttons[i]))) {
199             layout_out->type = i + 1;
200             break;
201         }
202     }
203
204     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT1_VB_KEY);
205     layout_out->content[0] = layout_pane_get_content(radio_vb);
206     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT2_VB_KEY);
207     layout_out->content[1] = layout_pane_get_content(radio_vb);
208     radio_vb = OBJECT_GET_DATA(main_vb, LAYOUT_CONTENT3_VB_KEY);
209     layout_out->content[2] = layout_pane_get_content(radio_vb);
210 }
211
212 static void layout_validate(layout_t *layout) {
213
214     if(layout->content[1] == layout->content[0]) {
215         layout->content[1] = layout_pane_content_none;
216     }
217     if(layout->content[2] == layout->content[0] || layout->content[2] == layout->content[1]) {
218         layout->content[2] = layout_pane_content_none;
219     }
220 }
221
222
223 static void layout_validate_cb(GtkWidget *w _U_, gpointer data) {
224     layout_t    layout;
225
226     layout_get(data, &layout);
227     layout_validate(&layout);
228     layout_set(data, &layout);
229 }
230
231 static void
232 layout_defaults_cb (GtkWidget * w _U_, gpointer data _U_)
233 {
234     layout_t default_layout = { 
235         layout_type_5,
236         {
237             layout_pane_content_plist,
238             layout_pane_content_pdetails,
239             layout_pane_content_pbytes
240         }
241     };
242
243     layout_set(data, &default_layout);
244 }
245
246
247 GtkWidget*
248 layout_prefs_show(void)
249 {
250 #if GTK_MAJOR_VERSION < 2
251     GtkAccelGroup *accel_group;
252 #endif
253     GtkTooltips   *tooltips;
254
255     GtkWidget   *main_vb, *button_hb, *type_tb;
256     GtkWidget   *radio_hb, *radio_vb;
257     GtkWidget   *default_vb, *default_bt;
258
259     const char ** inline_txt [LAYOUT_QTY] = {
260                 icon_layout_5_xpm, icon_layout_2_xpm, icon_layout_1_xpm,
261                 icon_layout_4_xpm, icon_layout_3_xpm, icon_layout_6_xpm };
262     GtkWidget ** layout_type_buttons = g_malloc (sizeof(GtkWidget*) * LAYOUT_QTY);
263
264     int i;
265
266
267     /* main vertical box */
268     main_vb = gtk_vbox_new(FALSE, 7);
269     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
270
271 #if GTK_MAJOR_VERSION < 2
272     /* Accelerator group for the accelerators (or, as they're called in
273      Windows and, I think, in Motif, "mnemonics"; Alt+<key> is a mnemonic,
274      Ctrl+<key> is an accelerator). */
275     accel_group = gtk_accel_group_new();
276     /*gtk_window_add_accel_group(GTK_WINDOW(main_win), accel_group);*/
277 #endif
278
279     /* Enable tooltips */
280     tooltips = gtk_tooltips_new();
281
282
283     /* button hbox */
284     button_hb = gtk_hbox_new(FALSE, 0);
285     gtk_container_set_border_width(GTK_CONTAINER(button_hb), 6);
286     gtk_box_pack_start (GTK_BOX(main_vb), button_hb, FALSE, FALSE, 0);
287
288     /* pane layout */
289     for (i=0; i<LAYOUT_QTY; ++i)
290     {
291         type_tb = gtk_toggle_button_new ();
292         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(type_tb),
293             (layout_type_e)(i + 1) == prefs.gui_layout_type);
294
295         gtk_container_add (GTK_CONTAINER(type_tb), xpm_to_widget(inline_txt[i]));
296
297         SIGNAL_CONNECT(type_tb, "toggled", layout_type_changed_cb, layout_type_buttons);
298         layout_type_buttons[i] = type_tb;
299         gtk_box_pack_start (GTK_BOX(button_hb), type_tb, TRUE, FALSE, 0);
300     }
301
302     OBJECT_SET_DATA(main_vb, LAYOUT_TYPE_BUTTONS_KEY, layout_type_buttons);
303
304     /* radio hbox */
305     radio_hb = gtk_hbox_new(FALSE, 0);
306     gtk_container_set_border_width(GTK_CONTAINER(radio_hb), 6);
307     gtk_box_pack_start (GTK_BOX(main_vb), radio_hb, FALSE, FALSE, 0);
308
309     radio_vb = layout_content_radio_vbox(main_vb, tooltips, 1, prefs.gui_layout_content_1);
310     gtk_container_set_border_width(GTK_CONTAINER(radio_vb), 6);
311     gtk_box_pack_start (GTK_BOX(radio_hb), radio_vb, FALSE, FALSE, 0);
312     OBJECT_SET_DATA(main_vb, LAYOUT_CONTENT1_VB_KEY, radio_vb);
313
314     radio_vb = layout_content_radio_vbox(main_vb, tooltips, 2, prefs.gui_layout_content_2);
315     gtk_container_set_border_width(GTK_CONTAINER(radio_vb), 6);
316     gtk_box_pack_start (GTK_BOX(radio_hb), radio_vb, FALSE, FALSE, 0);
317     OBJECT_SET_DATA(main_vb, LAYOUT_CONTENT2_VB_KEY, radio_vb);
318
319     radio_vb = layout_content_radio_vbox(main_vb, tooltips, 3, prefs.gui_layout_content_3);
320     gtk_container_set_border_width(GTK_CONTAINER(radio_vb), 6);
321     gtk_box_pack_start (GTK_BOX(radio_hb), radio_vb, FALSE, FALSE, 0);
322     OBJECT_SET_DATA(main_vb, LAYOUT_CONTENT3_VB_KEY, radio_vb);
323
324     default_vb = gtk_vbox_new(FALSE, 0);
325     default_bt = gtk_button_new_with_label("Defaults");
326     gtk_tooltips_set_tip (tooltips, default_bt, "Reset the pane layout settings to default values.", NULL);
327     SIGNAL_CONNECT(default_bt, "clicked", layout_defaults_cb, main_vb);
328     gtk_box_pack_end(GTK_BOX(default_vb), default_bt, FALSE, FALSE, 0);
329     gtk_box_pack_end(GTK_BOX(radio_hb), default_vb, FALSE, FALSE, 0);
330
331     /* Show 'em what we got */
332     gtk_widget_show_all(main_vb);
333
334     return(main_vb);
335 }
336
337 void
338 layout_prefs_fetch(GtkWidget *w)
339 {
340     layout_t layout_fetched;
341
342     layout_get(w, &layout_fetched);
343
344     prefs.gui_layout_type = layout_fetched.type;
345     prefs.gui_layout_content_1 = layout_fetched.content[0];
346     prefs.gui_layout_content_2 = layout_fetched.content[1];
347     prefs.gui_layout_content_3 = layout_fetched.content[2];
348 }
349
350 void
351 layout_prefs_apply(GtkWidget *w _U_)
352 {
353     main_widgets_rearrange();
354 }
355
356 void
357 layout_prefs_destroy(GtkWidget *main_vb)
358 {
359     GtkWidget ** layout_type_buttons = OBJECT_GET_DATA(main_vb, LAYOUT_TYPE_BUTTONS_KEY);
360
361     g_free(layout_type_buttons);
362 }
363