1 /*
2  *                            COPYRIGHT
3  *
4  *  PCB, interactive printed circuit board design
5  *  Copyright (C) 1994,1995,1996 Thomas Nau
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License along
18  *  with this program; if not, write to the Free Software Foundation, Inc.,
19  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22 
23 /* This module, gui-utils.c, was written by Bill Wilson and the functions
24  * here are Copyright (C) 2004 by Bill Wilson.  These functions are utility
25  * functions which are taken from my other GPL'd projects gkrellm and
26  * gstocks and are copied here for the Gtk PCB port.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "gui.h"
34 #include <gdk/gdkkeysyms.h>
35 
36 #ifdef HAVE_LIBDMALLOC
37 #include <dmalloc.h>
38 #endif
39 
40 /* Not a gui function, but no better place to put it...
41  */
42 gboolean
dup_string(gchar ** dst,const gchar * src)43 dup_string (gchar ** dst, const gchar * src)
44 {
45   if ((dst == NULL) || ((*dst == NULL) && (src == NULL)))
46     return FALSE;
47   if (*dst)
48     {
49       if (src && !strcmp (*dst, src))
50 	return FALSE;
51       g_free (*dst);
52     }
53   *dst = g_strdup (src);
54   return TRUE;
55 }
56 
57 void
free_glist_and_data(GList ** list_head)58 free_glist_and_data (GList ** list_head)
59 {
60   GList *list;
61 
62   if (*list_head == NULL)
63     return;
64   for (list = *list_head; list; list = list->next)
65     if (list->data)
66       g_free (list->data);
67   g_list_free (*list_head);
68   *list_head = NULL;
69 }
70 
71 
72 gboolean
ghid_is_modifier_key_sym(gint ksym)73 ghid_is_modifier_key_sym (gint ksym)
74 {
75   if (ksym == GDK_Shift_R || ksym == GDK_Shift_L
76       || ksym == GDK_Control_R || ksym == GDK_Control_L)
77     return TRUE;
78   return FALSE;
79 }
80 
81 
82 ModifierKeysState
ghid_modifier_keys_state(GdkModifierType * state)83 ghid_modifier_keys_state (GdkModifierType * state)
84 {
85   GdkModifierType mask;
86   ModifierKeysState mk;
87   gboolean shift, control, mod1;
88   GHidPort *out = &ghid_port;
89 
90   if (!state)
91     gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
92                             NULL, NULL, &mask);
93   else
94     mask = *state;
95 
96   shift = (mask & GDK_SHIFT_MASK);
97   control = (mask & GDK_CONTROL_MASK);
98   mod1 = (mask & GDK_MOD1_MASK);
99 
100   if (shift && !control && !mod1)
101     mk = SHIFT_PRESSED;
102   else if (!shift && control && !mod1)
103     mk = CONTROL_PRESSED;
104   else if (!shift && !control && mod1)
105     mk = MOD1_PRESSED;
106   else if (shift && control && !mod1)
107     mk = SHIFT_CONTROL_PRESSED;
108   else if (shift && !control && mod1)
109     mk = SHIFT_MOD1_PRESSED;
110   else if (!shift && control && mod1)
111     mk = CONTROL_MOD1_PRESSED;
112   else if (shift && control && mod1)
113     mk = SHIFT_CONTROL_MOD1_PRESSED;
114   else
115     mk = NONE_PRESSED;
116 
117   return mk;
118 }
119 
120 ButtonState
ghid_button_state(GdkModifierType * state)121 ghid_button_state (GdkModifierType * state)
122 {
123   GdkModifierType mask;
124   ButtonState bs;
125   gboolean button1, button2, button3;
126   GHidPort *out = &ghid_port;
127 
128   if (!state)
129     gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
130                             NULL, NULL, &mask);
131   else
132     mask = *state;
133 
134   button1 = (mask & GDK_BUTTON1_MASK);
135   button2 = (mask & GDK_BUTTON2_MASK);
136   button3 = (mask & GDK_BUTTON3_MASK);
137 
138   if (button1)
139     bs = BUTTON1_PRESSED;
140   else if (button2)
141     bs = BUTTON2_PRESSED;
142   else if (button3)
143     bs = BUTTON3_PRESSED;
144   else
145     bs = NO_BUTTON_PRESSED;
146 
147   return bs;
148 }
149 
150 void
ghid_draw_area_update(GHidPort * port,GdkRectangle * rect)151 ghid_draw_area_update (GHidPort * port, GdkRectangle * rect)
152 {
153   gdk_window_invalidate_rect (gtk_widget_get_window (port->drawing_area),
154                               rect, FALSE);
155 }
156 
157 
158 gchar *
ghid_get_color_name(GdkColor * color)159 ghid_get_color_name (GdkColor * color)
160 {
161   gchar *name;
162 
163   if (!color)
164     name = g_strdup ("#000000");
165   else
166     name = g_strdup_printf ("#%2.2x%2.2x%2.2x",
167 			    (color->red >> 8) & 0xff,
168 			    (color->green >> 8) & 0xff,
169 			    (color->blue >> 8) & 0xff);
170   return name;
171 }
172 
173 void
ghid_map_color_string(char * color_string,GdkColor * color)174 ghid_map_color_string (char *color_string, GdkColor * color)
175 {
176   static GdkColormap *colormap = NULL;
177   GHidPort *out = &ghid_port;
178 
179   if (!color || !out->top_window)
180     return;
181   if (colormap == NULL)
182     colormap = gtk_widget_get_colormap (out->top_window);
183   if (color->red || color->green || color->blue)
184     gdk_colormap_free_colors (colormap, color, 1);
185   gdk_color_parse (color_string, color);
186   gdk_color_alloc (colormap, color);
187 }
188 
189 
190 gchar *
ghid_entry_get_text(GtkWidget * entry)191 ghid_entry_get_text (GtkWidget * entry)
192 {
193   gchar *s = "";
194 
195   if (entry)
196     s = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));
197   while (*s == ' ' || *s == '\t')
198     ++s;
199   return s;
200 }
201 
202 
203 
204 void
ghid_check_button_connected(GtkWidget * box,GtkWidget ** button,gboolean active,gboolean pack_start,gboolean expand,gboolean fill,gint pad,void (* cb_func)(GtkToggleButton *,gpointer),gpointer data,gchar * string)205 ghid_check_button_connected (GtkWidget * box,
206 			     GtkWidget ** button,
207 			     gboolean active,
208 			     gboolean pack_start,
209 			     gboolean expand,
210 			     gboolean fill,
211 			     gint pad,
212 			     void (*cb_func) (GtkToggleButton *, gpointer),
213 			     gpointer data, gchar * string)
214 {
215   GtkWidget *b;
216 
217   if (!string)
218     return;
219   b = gtk_check_button_new_with_mnemonic (string);
220   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), active);
221   if (box && pack_start)
222     gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad);
223   else if (box && !pack_start)
224     gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad);
225 
226   if (cb_func)
227     g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data);
228   if (button)
229     *button = b;
230 }
231 
232 void
ghid_button_connected(GtkWidget * box,GtkWidget ** button,gboolean pack_start,gboolean expand,gboolean fill,gint pad,void (* cb_func)(gpointer),gpointer data,gchar * string)233 ghid_button_connected (GtkWidget * box, GtkWidget ** button,
234 		       gboolean pack_start, gboolean expand, gboolean fill,
235 		       gint pad, void (*cb_func) (gpointer), gpointer data,
236 		       gchar * string)
237 {
238   GtkWidget *b;
239 
240   if (!string)
241     return;
242   b = gtk_button_new_with_mnemonic (string);
243   if (box && pack_start)
244     gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad);
245   else if (box && !pack_start)
246     gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad);
247 
248   if (cb_func)
249     g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data);
250   if (button)
251     *button = b;
252 }
253 
254 void
ghid_coord_entry(GtkWidget * box,GtkWidget ** coord_entry,Coord value,Coord low,Coord high,enum ce_step_size step_size,gint width,void (* cb_func)(GHidCoordEntry *,gpointer),gpointer data,gboolean right_align,gchar * string)255 ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value,
256 		  Coord low, Coord high,  enum ce_step_size step_size,
257 		  gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
258 		  gpointer data, gboolean right_align, gchar * string)
259 {
260   GtkWidget *hbox = NULL, *label, *entry_widget;
261   GHidCoordEntry *entry;
262 
263   if (string && box)
264     {
265       hbox = gtk_hbox_new (FALSE, 0);
266       gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2);
267       box = hbox;
268     }
269 
270   entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
271   if (coord_entry)
272     *coord_entry = entry_widget;
273   if (width > 0)
274     gtk_widget_set_size_request (entry_widget, width, -1);
275   entry = GHID_COORD_ENTRY (entry_widget);
276   if (data == NULL)
277     data = (gpointer) entry;
278   if (cb_func)
279     g_signal_connect (G_OBJECT (entry_widget), "value_changed",
280 		      G_CALLBACK (cb_func), data);
281   if (box)
282     {
283       if (right_align && string)
284 	{
285 	  label = gtk_label_new (string);
286 	  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
287 	  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
288 	}
289       gtk_box_pack_start (GTK_BOX (box), entry_widget, FALSE, FALSE, 2);
290       if (!right_align && string)
291 	{
292 	  label = gtk_label_new (string);
293 	  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
294 	  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
295 	}
296     }
297 }
298 
299 void
ghid_spin_button(GtkWidget * box,GtkWidget ** spin_button,gfloat value,gfloat low,gfloat high,gfloat step0,gfloat step1,gint digits,gint width,void (* cb_func)(GtkSpinButton *,gpointer),gpointer data,gboolean right_align,gchar * string)300 ghid_spin_button (GtkWidget * box, GtkWidget ** spin_button, gfloat value,
301 		  gfloat low, gfloat high, gfloat step0, gfloat step1,
302 		  gint digits, gint width,
303 		  void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align,
304 		  gchar * string)
305 {
306   GtkWidget *hbox = NULL, *label, *spin_but;
307   GtkSpinButton *spin;
308   GtkAdjustment *adj;
309 
310   if (string && box)
311     {
312       hbox = gtk_hbox_new (FALSE, 0);
313       gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2);
314       box = hbox;
315     }
316   adj = (GtkAdjustment *) gtk_adjustment_new (value,
317 					      low, high, step0, step1, 0.0);
318   spin_but = gtk_spin_button_new (adj, 0.5, digits);
319   if (spin_button)
320     *spin_button = spin_but;
321   if (width > 0)
322     gtk_widget_set_size_request (spin_but, width, -1);
323   spin = GTK_SPIN_BUTTON (spin_but);
324   gtk_spin_button_set_numeric (spin, TRUE);
325   if (data == NULL)
326     data = (gpointer) spin;
327   if (cb_func)
328     g_signal_connect (G_OBJECT (spin_but), "value_changed",
329 		      G_CALLBACK (cb_func), data);
330   if (box)
331     {
332       if (right_align && string)
333 	{
334 	  label = gtk_label_new (string);
335 	  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
336 	  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
337 	}
338       gtk_box_pack_start (GTK_BOX (box), spin_but, FALSE, FALSE, 2);
339       if (!right_align && string)
340 	{
341 	  label = gtk_label_new (string);
342 	  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
343 	  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
344 	}
345     }
346 }
347 
348 void
ghid_table_coord_entry(GtkWidget * table,gint row,gint column,GtkWidget ** coord_entry,Coord value,Coord low,Coord high,enum ce_step_size step_size,gint width,void (* cb_func)(GHidCoordEntry *,gpointer),gpointer data,gboolean right_align,gchar * string)349 ghid_table_coord_entry (GtkWidget * table, gint row, gint column,
350 			GtkWidget ** coord_entry, Coord value,
351 			Coord low, Coord high, enum ce_step_size step_size,
352 			gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
353 			gpointer data, gboolean right_align, gchar * string)
354 {
355   GtkWidget *label, *entry_widget;
356   GHidCoordEntry *entry;
357 
358   if (!table)
359     return;
360 
361   entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
362   if (coord_entry)
363     *coord_entry = entry_widget;
364   if (width > 0)
365     gtk_widget_set_size_request (entry_widget, width, -1);
366   entry = GHID_COORD_ENTRY (entry_widget);
367   if (data == NULL)
368     data = (gpointer) entry;
369   if (cb_func)
370     g_signal_connect (G_OBJECT (entry), "value_changed",
371 		      G_CALLBACK (cb_func), data);
372 
373   if (right_align)
374     {
375       gtk_table_attach_defaults (GTK_TABLE (table), entry_widget,
376 				 column + 1, column + 2, row, row + 1);
377       if (string)
378 	{
379 	  label = gtk_label_new (string);
380 	  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
381 	  gtk_table_attach_defaults (GTK_TABLE (table), label,
382 				     column, column + 1, row, row + 1);
383 	}
384     }
385   else
386     {
387       gtk_table_attach_defaults (GTK_TABLE (table), entry_widget,
388 				 column, column + 1, row, row + 1);
389       if (string)
390 	{
391 	  label = gtk_label_new (string);
392 	  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
393 	  gtk_table_attach_defaults (GTK_TABLE (table), label,
394 				     column + 1, column + 2, row, row + 1);
395 	}
396     }
397 }
398 
399 
400 void
ghid_table_spin_button(GtkWidget * table,gint row,gint column,GtkWidget ** spin_button,gfloat value,gfloat low,gfloat high,gfloat step0,gfloat step1,gint digits,gint width,void (* cb_func)(GtkSpinButton *,gpointer),gpointer data,gboolean right_align,gchar * string)401 ghid_table_spin_button (GtkWidget * table, gint row, gint column,
402 			GtkWidget ** spin_button, gfloat value,
403 			gfloat low, gfloat high, gfloat step0, gfloat step1,
404 			gint digits, gint width,
405 			void (*cb_func) (GtkSpinButton *, gpointer), gpointer data,
406 			gboolean right_align, gchar * string)
407 {
408   GtkWidget *label, *spin_but;
409   GtkSpinButton *spin;
410   GtkAdjustment *adj;
411 
412   if (!table)
413     return;
414 
415   adj = (GtkAdjustment *) gtk_adjustment_new (value,
416                                              low, high, step0, step1, 0.0);
417   spin_but = gtk_spin_button_new (adj, 0.5, digits);
418 
419   if (spin_button)
420     *spin_button = spin_but;
421   if (width > 0)
422     gtk_widget_set_size_request (spin_but, width, -1);
423   spin = GTK_SPIN_BUTTON (spin_but);
424   gtk_spin_button_set_numeric (spin, TRUE);
425   if (data == NULL)
426     data = (gpointer) spin;
427   if (cb_func)
428     g_signal_connect (G_OBJECT (spin_but), "value_changed",
429 		      G_CALLBACK (cb_func), data);
430 
431   if (right_align)
432     {
433       gtk_table_attach_defaults (GTK_TABLE (table), spin_but,
434 				 column + 1, column + 2, row, row + 1);
435       if (string)
436 	{
437 	  label = gtk_label_new (string);
438 	  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
439 	  gtk_table_attach_defaults (GTK_TABLE (table), label,
440 				     column, column + 1, row, row + 1);
441 	}
442     }
443   else
444     {
445       gtk_table_attach_defaults (GTK_TABLE (table), spin_but,
446 				 column, column + 1, row, row + 1);
447       if (string)
448 	{
449 	  label = gtk_label_new (string);
450 	  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
451 	  gtk_table_attach_defaults (GTK_TABLE (table), label,
452 				     column + 1, column + 2, row, row + 1);
453 	}
454     }
455 }
456 
457 void
ghid_range_control(GtkWidget * box,GtkWidget ** scale_res,gboolean horizontal,GtkPositionType pos,gboolean set_draw_value,gint digits,gboolean pack_start,gboolean expand,gboolean fill,guint pad,gfloat value,gfloat low,gfloat high,gfloat step0,gfloat step1,void (* cb_func)(),gpointer data)458 ghid_range_control (GtkWidget * box, GtkWidget ** scale_res,
459 		    gboolean horizontal, GtkPositionType pos,
460 		    gboolean set_draw_value, gint digits, gboolean pack_start,
461 		    gboolean expand, gboolean fill, guint pad, gfloat value,
462 		    gfloat low, gfloat high, gfloat step0, gfloat step1,
463 		    void (*cb_func) (), gpointer data)
464 {
465   GtkWidget *scale;
466   GtkAdjustment *adj;
467 
468   adj = (GtkAdjustment *) gtk_adjustment_new (value,
469 					      low, high, step0, step1, 0.0);
470 
471   if (horizontal)
472     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj));
473   else
474     scale = gtk_vscale_new (GTK_ADJUSTMENT (adj));
475   gtk_scale_set_value_pos (GTK_SCALE (scale), pos);
476   gtk_scale_set_draw_value (GTK_SCALE (scale), set_draw_value);
477   gtk_scale_set_digits (GTK_SCALE (scale), digits);
478 
479   /* Increments don't make sense, use -1,1 because that does closest to
480      |  what I want: scroll down decrements slider value.
481    */
482   gtk_range_set_increments (GTK_RANGE (scale), -1, 1);
483 
484   if (pack_start)
485     gtk_box_pack_start (GTK_BOX (box), scale, expand, fill, pad);
486   else
487     gtk_box_pack_end (GTK_BOX (box), scale, expand, fill, pad);
488 
489   if (data == NULL)
490     data = (gpointer) adj;
491   if (cb_func)
492     g_signal_connect (G_OBJECT (adj), "value_changed",
493 		      G_CALLBACK (cb_func), data);
494   if (scale_res)
495     *scale_res = scale;
496 }
497 
498 GtkWidget *
ghid_scrolled_vbox(GtkWidget * box,GtkWidget ** scr,GtkPolicyType h_policy,GtkPolicyType v_policy)499 ghid_scrolled_vbox (GtkWidget * box, GtkWidget ** scr,
500 		    GtkPolicyType h_policy, GtkPolicyType v_policy)
501 {
502   GtkWidget *scrolled, *vbox;
503 
504   scrolled = gtk_scrolled_window_new (NULL, NULL);
505   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
506 				  h_policy, v_policy);
507   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
508   vbox = gtk_vbox_new (FALSE, 0);
509   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
510 					 vbox);
511   if (scr)
512     *scr = scrolled;
513   return vbox;
514 }
515 
516 /* frame_border_width - border around outside of frame.
517    |  vbox_pad - pad between widgets to be packed in returned vbox.
518    |  vbox_border_width - border between returned vbox and frame.
519 */
520 GtkWidget *
ghid_framed_vbox(GtkWidget * box,gchar * label,gint frame_border_width,gboolean frame_expand,gint vbox_pad,gint vbox_border_width)521 ghid_framed_vbox (GtkWidget * box, gchar * label, gint frame_border_width,
522 		  gboolean frame_expand, gint vbox_pad,
523 		  gint vbox_border_width)
524 {
525   GtkWidget *frame;
526   GtkWidget *vbox;
527 
528   frame = gtk_frame_new (label);
529   gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width);
530   gtk_box_pack_start (GTK_BOX (box), frame, frame_expand, frame_expand, 0);
531   vbox = gtk_vbox_new (FALSE, vbox_pad);
532   gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width);
533   gtk_container_add (GTK_CONTAINER (frame), vbox);
534   return vbox;
535 }
536 
537 GtkWidget *
ghid_framed_vbox_end(GtkWidget * box,gchar * label,gint frame_border_width,gboolean frame_expand,gint vbox_pad,gint vbox_border_width)538 ghid_framed_vbox_end (GtkWidget * box, gchar * label, gint frame_border_width,
539 		      gboolean frame_expand, gint vbox_pad,
540 		      gint vbox_border_width)
541 {
542   GtkWidget *frame;
543   GtkWidget *vbox;
544 
545   frame = gtk_frame_new (label);
546   gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width);
547   gtk_box_pack_end (GTK_BOX (box), frame, frame_expand, frame_expand, 0);
548   vbox = gtk_vbox_new (FALSE, vbox_pad);
549   gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width);
550   gtk_container_add (GTK_CONTAINER (frame), vbox);
551   return vbox;
552 }
553 
554 GtkWidget *
ghid_category_vbox(GtkWidget * box,const gchar * category_header,gint header_pad,gint box_pad,gboolean pack_start,gboolean bottom_pad)555 ghid_category_vbox (GtkWidget * box, const gchar * category_header,
556 		    gint header_pad,
557 		    gint box_pad, gboolean pack_start, gboolean bottom_pad)
558 {
559   GtkWidget *vbox, *vbox1, *hbox, *label;
560   gchar *s;
561 
562   vbox = gtk_vbox_new (FALSE, 0);
563   if (pack_start)
564     gtk_box_pack_start (GTK_BOX (box), vbox, FALSE, FALSE, 0);
565   else
566     gtk_box_pack_end (GTK_BOX (box), vbox, FALSE, FALSE, 0);
567 
568   if (category_header)
569     {
570       label = gtk_label_new (NULL);
571       s = g_strconcat ("<span weight=\"bold\">", category_header,
572 		       "</span>", NULL);
573       gtk_label_set_markup (GTK_LABEL (label), s);
574       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
575       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, header_pad);
576       g_free (s);
577     }
578 
579   hbox = gtk_hbox_new (FALSE, 0);
580   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
581   label = gtk_label_new ("     ");
582   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
583   vbox1 = gtk_vbox_new (FALSE, box_pad);
584   gtk_box_pack_start (GTK_BOX (hbox), vbox1, TRUE, TRUE, 0);
585 
586   if (bottom_pad)
587     {
588       label = gtk_label_new ("");
589       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
590     }
591   return vbox1;
592 }
593 
594 GtkTreeSelection *
ghid_scrolled_selection(GtkTreeView * treeview,GtkWidget * box,GtkSelectionMode s_mode,GtkPolicyType h_policy,GtkPolicyType v_policy,void (* func_cb)(GtkTreeSelection *,gpointer),gpointer data)595 ghid_scrolled_selection (GtkTreeView * treeview, GtkWidget * box,
596 			 GtkSelectionMode s_mode,
597 			 GtkPolicyType h_policy, GtkPolicyType v_policy,
598 			 void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data)
599 {
600   GtkTreeSelection *selection;
601   GtkWidget *scrolled;
602 
603   if (!box || !treeview)
604     return NULL;
605 
606   scrolled = gtk_scrolled_window_new (NULL, NULL);
607   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
608   gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview));
609   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
610 				  h_policy, v_policy);
611   selection = gtk_tree_view_get_selection (treeview);
612   gtk_tree_selection_set_mode (selection, s_mode);
613   if (func_cb)
614     g_signal_connect (G_OBJECT (selection), "changed",
615 		      G_CALLBACK (func_cb), data);
616   return selection;
617 }
618 
619 GtkWidget *
ghid_notebook_page(GtkWidget * tabs,const char * name,gint pad,gint border)620 ghid_notebook_page (GtkWidget * tabs, const char *name, gint pad, gint border)
621 {
622   GtkWidget *label;
623   GtkWidget *vbox;
624 
625   vbox = gtk_vbox_new (FALSE, pad);
626   gtk_container_set_border_width (GTK_CONTAINER (vbox), border);
627 
628   label = gtk_label_new (name);
629   gtk_notebook_append_page (GTK_NOTEBOOK (tabs), vbox, label);
630 
631   return vbox;
632 }
633 
634 GtkWidget *
ghid_framed_notebook_page(GtkWidget * tabs,char * name,gint border,gint frame_border,gint vbox_pad,gint vbox_border)635 ghid_framed_notebook_page (GtkWidget * tabs, char *name, gint border,
636 			   gint frame_border, gint vbox_pad, gint vbox_border)
637 {
638   GtkWidget *vbox;
639 
640   vbox = ghid_notebook_page (tabs, name, 0, border);
641   vbox = ghid_framed_vbox (vbox, NULL, frame_border, TRUE,
642 			   vbox_pad, vbox_border);
643   return vbox;
644 }
645 
646 void
ghid_dialog_report(gchar * title,gchar * message)647 ghid_dialog_report (gchar * title, gchar * message)
648 {
649   GtkWidget *top_win;
650   GtkWidget *dialog;
651   GtkWidget *content_area;
652   GtkWidget *scrolled;
653   GtkWidget *vbox, *vbox1;
654   GtkWidget *label;
655   gchar *s;
656   gint nlines;
657   GHidPort *out = &ghid_port;
658 
659   if (!message)
660     return;
661   top_win = out->top_window;
662   dialog = gtk_dialog_new_with_buttons (title ? title : "PCB",
663 					GTK_WINDOW (top_win),
664 					GTK_DIALOG_DESTROY_WITH_PARENT,
665 					GTK_STOCK_OK, GTK_RESPONSE_NONE,
666 					NULL);
667   g_signal_connect_swapped (GTK_OBJECT (dialog), "response",
668 			    G_CALLBACK (gtk_widget_destroy),
669 			    GTK_OBJECT (dialog));
670   gtk_window_set_wmclass (GTK_WINDOW (dialog), "PCB_Dialog", "PCB");
671 
672   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
673 
674   vbox = gtk_vbox_new (FALSE, 0);
675   gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
676   gtk_box_pack_start (GTK_BOX (content_area), vbox, FALSE, FALSE, 0);
677 
678   label = gtk_label_new (message);
679   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
680 
681   for (nlines = 0, s = message; *s; ++s)
682     if (*s == '\n')
683       ++nlines;
684   if (nlines > 20)
685     {
686       vbox1 = ghid_scrolled_vbox (vbox, &scrolled,
687 				  GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
688       gtk_widget_set_size_request (scrolled, -1, 300);
689       gtk_box_pack_start (GTK_BOX (vbox1), label, FALSE, FALSE, 0);
690     }
691   else
692     gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
693 
694   gtk_widget_show_all (dialog);
695 }
696 
697 
698 void
ghid_label_set_markup(GtkWidget * label,const gchar * text)699 ghid_label_set_markup (GtkWidget * label, const gchar * text)
700 {
701   if (label)
702     gtk_label_set_markup (GTK_LABEL (label), text ? text : "");
703 }
704 
705 
706 static void
text_view_append(GtkWidget * view,gchar * s)707 text_view_append (GtkWidget * view, gchar * s)
708 {
709   GtkTextIter iter;
710   GtkTextBuffer *buffer;
711   GtkTextMark *mark;
712 
713   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
714   gtk_text_buffer_get_end_iter (buffer, &iter);
715   /* gtk_text_iter_forward_to_end(&iter); */
716 
717   if (strncmp (s, "<b>", 3) == 0)
718     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
719 					      s + 3, -1, "bold", NULL);
720   else if (strncmp (s, "<i>", 3) == 0)
721     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
722 					      s + 3, -1, "italic", NULL);
723   else if (strncmp (s, "<h>", 3) == 0)
724     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
725 					      s + 3, -1, "heading", NULL);
726   else if (strncmp (s, "<c>", 3) == 0)
727     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
728 					      s + 3, -1, "center", NULL);
729   else if (strncmp (s, "<ul>", 4) == 0)
730     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
731 					      s + 4, -1, "underline", NULL);
732   else
733     gtk_text_buffer_insert (buffer, &iter, s, -1);
734 
735   mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE);
736   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), mark,
737 				0, TRUE, 0.0, 1.0);
738   gtk_text_buffer_delete_mark (buffer, mark);
739 }
740 
741 void
ghid_text_view_append(GtkWidget * view,gchar * string)742 ghid_text_view_append (GtkWidget * view, gchar * string)
743 {
744   static gchar *tag;
745   gchar *s;
746 
747   s = string;
748   if (*s == '<'
749       && ((*(s + 2) == '>' && !*(s + 3)) || (*(s + 3) == '>' && !*(s + 4))))
750     {
751       tag = g_strdup (s);
752       return;
753     }
754 
755   if (tag)
756     {
757       s = g_strconcat (tag, string, NULL);
758       text_view_append (view, s);
759       g_free (s);
760       g_free (tag);
761       tag = NULL;
762     }
763   else
764     text_view_append (view, string);
765 }
766 
767 void
ghid_text_view_append_strings(GtkWidget * view,gchar ** string,gint n_strings)768 ghid_text_view_append_strings (GtkWidget * view, gchar ** string,
769 			       gint n_strings)
770 {
771   gchar *tag = NULL;
772   gchar *s, *t;
773   gint i;
774 
775   for (i = 0; i < n_strings; ++i)
776     {
777       s = string[i];
778       if (*s == '<'
779 	  && ((*(s + 2) == '>' && !*(s + 3))
780 	      || (*(s + 3) == '>' && !*(s + 4))))
781 	{
782 	  tag = g_strdup (s);
783 	  continue;
784 	}
785       s = _(string[i]);
786       if (tag)
787 	{
788 	  t = g_strconcat (tag, s, NULL);
789 	  text_view_append (view, t);
790 	  g_free (t);
791 	  g_free (tag);
792 	  tag = NULL;
793 	}
794       else
795 	text_view_append (view, s);
796     }
797 }
798 
799 
800 GtkWidget *
ghid_scrolled_text_view(GtkWidget * box,GtkWidget ** scr,GtkPolicyType h_policy,GtkPolicyType v_policy)801 ghid_scrolled_text_view (GtkWidget * box,
802 			 GtkWidget ** scr,
803 			 GtkPolicyType h_policy, GtkPolicyType v_policy)
804 {
805   GtkWidget *scrolled, *view;
806   GtkTextBuffer *buffer;
807 
808   scrolled = gtk_scrolled_window_new (NULL, NULL);
809   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
810 				  h_policy, v_policy);
811   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
812 
813   view = gtk_text_view_new ();
814   gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
815   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
816   gtk_text_buffer_create_tag (buffer, "heading",
817 			      "weight", PANGO_WEIGHT_BOLD,
818 			      "size", 14 * PANGO_SCALE, NULL);
819   gtk_text_buffer_create_tag (buffer, "italic",
820 			      "style", PANGO_STYLE_ITALIC, NULL);
821   gtk_text_buffer_create_tag (buffer, "bold",
822 			      "weight", PANGO_WEIGHT_BOLD, NULL);
823   gtk_text_buffer_create_tag (buffer, "center",
824 			      "justification", GTK_JUSTIFY_CENTER, NULL);
825   gtk_text_buffer_create_tag (buffer, "underline",
826 			      "underline", PANGO_UNDERLINE_SINGLE, NULL);
827 
828   gtk_container_add (GTK_CONTAINER (scrolled), view);
829   if (scr)
830     *scr = scrolled;
831   return view;
832 }
833