pcb 4.1.1
An interactive printed circuit board layout editor.

gui-utils.c

Go to the documentation of this file.
00001 /*
00002  *                            COPYRIGHT
00003  *
00004  *  PCB, interactive printed circuit board design
00005  *  Copyright (C) 1994,1995,1996 Thomas Nau
00006  *
00007  *  This program is free software; you can redistribute it and/or modify
00008  *  it under the terms of the GNU General Public License as published by
00009  *  the Free Software Foundation; either version 2 of the License, or
00010  *  (at your option) any later version.
00011  *
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License along
00018  *  with this program; if not, write to the Free Software Foundation, Inc.,
00019  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00020  *
00021  */
00022 
00023 /* This module, gui-utils.c, was written by Bill Wilson and the functions
00024  * here are Copyright (C) 2004 by Bill Wilson.  These functions are utility
00025  * functions which are taken from my other GPL'd projects gkrellm and
00026  * gstocks and are copied here for the Gtk PCB port.
00027  */
00028 
00029 #ifdef HAVE_CONFIG_H
00030 #include "config.h"
00031 #endif
00032 
00033 #include "gui.h"
00034 #include <gdk/gdkkeysyms.h>
00035 
00036 #ifdef HAVE_LIBDMALLOC
00037 #include <dmalloc.h>
00038 #endif
00039 
00040 /* Not a gui function, but no better place to put it...
00041  */
00042 gboolean
00043 dup_string (gchar ** dst, const gchar * src)
00044 {
00045   if ((dst == NULL) || ((*dst == NULL) && (src == NULL)))
00046     return FALSE;
00047   if (*dst)
00048     {
00049       if (src && !strcmp (*dst, src))
00050         return FALSE;
00051       g_free (*dst);
00052     }
00053   *dst = g_strdup (src);
00054   return TRUE;
00055 }
00056 
00057 void
00058 free_glist_and_data (GList ** list_head)
00059 {
00060   GList *list;
00061 
00062   if (*list_head == NULL)
00063     return;
00064   for (list = *list_head; list; list = list->next)
00065     if (list->data)
00066       g_free (list->data);
00067   g_list_free (*list_head);
00068   *list_head = NULL;
00069 }
00070 
00071 
00072 gboolean
00073 ghid_is_modifier_key_sym (gint ksym)
00074 {
00075   if (ksym == GDK_Shift_R || ksym == GDK_Shift_L
00076       || ksym == GDK_Control_R || ksym == GDK_Control_L)
00077     return TRUE;
00078   return FALSE;
00079 }
00080 
00081 
00082 ModifierKeysState
00083 ghid_modifier_keys_state (GdkModifierType * state)
00084 {
00085   GdkModifierType mask;
00086   ModifierKeysState mk;
00087   gboolean shift, control, mod1;
00088   GHidPort *out = &ghid_port;
00089 
00090   if (!state)
00091     gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
00092                             NULL, NULL, &mask);
00093   else
00094     mask = *state;
00095 
00096   shift = (mask & GDK_SHIFT_MASK);
00097   control = (mask & GDK_CONTROL_MASK);
00098   mod1 = (mask & GDK_MOD1_MASK);
00099 
00100   if (shift && !control && !mod1)
00101     mk = SHIFT_PRESSED;
00102   else if (!shift && control && !mod1)
00103     mk = CONTROL_PRESSED;
00104   else if (!shift && !control && mod1)
00105     mk = MOD1_PRESSED;
00106   else if (shift && control && !mod1)
00107     mk = SHIFT_CONTROL_PRESSED;
00108   else if (shift && !control && mod1)
00109     mk = SHIFT_MOD1_PRESSED;
00110   else if (!shift && control && mod1)
00111     mk = CONTROL_MOD1_PRESSED;
00112   else if (shift && control && mod1)
00113     mk = SHIFT_CONTROL_MOD1_PRESSED;
00114   else
00115     mk = NONE_PRESSED;
00116 
00117   return mk;
00118 }
00119 
00120 ButtonState
00121 ghid_button_state (GdkModifierType * state)
00122 {
00123   GdkModifierType mask;
00124   ButtonState bs;
00125   gboolean button1, button2, button3;
00126   GHidPort *out = &ghid_port;
00127 
00128   if (!state)
00129     gdk_window_get_pointer (gtk_widget_get_window (out->drawing_area),
00130                             NULL, NULL, &mask);
00131   else
00132     mask = *state;
00133 
00134   button1 = (mask & GDK_BUTTON1_MASK);
00135   button2 = (mask & GDK_BUTTON2_MASK);
00136   button3 = (mask & GDK_BUTTON3_MASK);
00137 
00138   if (button1)
00139     bs = BUTTON1_PRESSED;
00140   else if (button2)
00141     bs = BUTTON2_PRESSED;
00142   else if (button3)
00143     bs = BUTTON3_PRESSED;
00144   else
00145     bs = NO_BUTTON_PRESSED;
00146 
00147   return bs;
00148 }
00149 
00150 void
00151 ghid_draw_area_update (GHidPort * port, GdkRectangle * rect)
00152 {
00153   gdk_window_invalidate_rect (gtk_widget_get_window (port->drawing_area),
00154                               rect, FALSE);
00155 }
00156 
00157 
00158 gchar *
00159 ghid_get_color_name (GdkColor * color)
00160 {
00161   gchar *name;
00162 
00163   if (!color)
00164     name = g_strdup ("#000000");
00165   else
00166     name = g_strdup_printf ("#%2.2x%2.2x%2.2x",
00167                             (color->red >> 8) & 0xff,
00168                             (color->green >> 8) & 0xff,
00169                             (color->blue >> 8) & 0xff);
00170   return name;
00171 }
00172 
00173 void
00174 ghid_map_color_string (char *color_string, GdkColor * color)
00175 {
00176   static GdkColormap *colormap = NULL;
00177   GHidPort *out = &ghid_port;
00178 
00179   if (!color || !out->top_window)
00180     return;
00181   if (colormap == NULL)
00182     colormap = gtk_widget_get_colormap (out->top_window);
00183   if (color->red || color->green || color->blue)
00184     gdk_colormap_free_colors (colormap, color, 1);
00185   gdk_color_parse (color_string, color);
00186   gdk_color_alloc (colormap, color);
00187 }
00188 
00189 
00190 gchar *
00191 ghid_entry_get_text (GtkWidget * entry)
00192 {
00193   gchar *s = "";
00194 
00195   if (entry)
00196     s = (gchar *) gtk_entry_get_text (GTK_ENTRY (entry));
00197   while (*s == ' ' || *s == '\t')
00198     ++s;
00199   return s;
00200 }
00201 
00202 
00203 
00204 void
00205 ghid_check_button_connected (GtkWidget * box,
00206                              GtkWidget ** button,
00207                              gboolean active,
00208                              gboolean pack_start,
00209                              gboolean expand,
00210                              gboolean fill,
00211                              gint pad,
00212                              void (*cb_func) (GtkToggleButton *, gpointer),
00213                              gpointer data, gchar * string)
00214 {
00215   GtkWidget *b;
00216 
00217   if (!string)
00218     return;
00219   b = gtk_check_button_new_with_mnemonic (string);
00220   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (b), active);
00221   if (box && pack_start)
00222     gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad);
00223   else if (box && !pack_start)
00224     gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad);
00225 
00226   if (cb_func)
00227     g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data);
00228   if (button)
00229     *button = b;
00230 }
00231 
00232 void
00233 ghid_button_connected (GtkWidget * box, GtkWidget ** button,
00234                        gboolean pack_start, gboolean expand, gboolean fill,
00235                        gint pad, void (*cb_func) (gpointer), gpointer data,
00236                        gchar * string)
00237 {
00238   GtkWidget *b;
00239 
00240   if (!string)
00241     return;
00242   b = gtk_button_new_with_mnemonic (string);
00243   if (box && pack_start)
00244     gtk_box_pack_start (GTK_BOX (box), b, expand, fill, pad);
00245   else if (box && !pack_start)
00246     gtk_box_pack_end (GTK_BOX (box), b, expand, fill, pad);
00247 
00248   if (cb_func)
00249     g_signal_connect (b, "clicked", G_CALLBACK (cb_func), data);
00250   if (button)
00251     *button = b;
00252 }
00253 
00254 void
00255 ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value,
00256                   Coord low, Coord high,  enum ce_step_size step_size,
00257                   gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
00258                   gpointer data, gboolean right_align, gchar * string)
00259 {
00260   GtkWidget *hbox = NULL, *label, *entry_widget;
00261   GHidCoordEntry *entry;
00262 
00263   if (string && box)
00264     {
00265       hbox = gtk_hbox_new (FALSE, 0);
00266       gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2);
00267       box = hbox;
00268     }
00269 
00270   entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
00271   if (coord_entry)
00272     *coord_entry = entry_widget;
00273   if (width > 0)
00274     gtk_widget_set_size_request (entry_widget, width, -1);
00275   entry = GHID_COORD_ENTRY (entry_widget);
00276   if (data == NULL)
00277     data = (gpointer) entry;
00278   if (cb_func)
00279     g_signal_connect (G_OBJECT (entry_widget), "value_changed",
00280                       G_CALLBACK (cb_func), data);
00281   if (box)
00282     {
00283       if (right_align && string)
00284         {
00285           label = gtk_label_new (string);
00286           gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
00287           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
00288         }
00289       gtk_box_pack_start (GTK_BOX (box), entry_widget, FALSE, FALSE, 2);
00290       if (!right_align && string)
00291         {
00292           label = gtk_label_new (string);
00293           gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
00294           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
00295         }
00296     }
00297 }
00298 
00299 void
00300 ghid_spin_button (GtkWidget * box, GtkWidget ** spin_button, gfloat value,
00301                   gfloat low, gfloat high, gfloat step0, gfloat step1,
00302                   gint digits, gint width,
00303                   void (*cb_func) (GtkSpinButton *, gpointer), gpointer data, gboolean right_align,
00304                   gchar * string)
00305 {
00306   GtkWidget *hbox = NULL, *label, *spin_but;
00307   GtkSpinButton *spin;
00308   GtkAdjustment *adj;
00309 
00310   if (string && box)
00311     {
00312       hbox = gtk_hbox_new (FALSE, 0);
00313       gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 2);
00314       box = hbox;
00315     }
00316   adj = (GtkAdjustment *) gtk_adjustment_new (value,
00317                                               low, high, step0, step1, 0.0);
00318   spin_but = gtk_spin_button_new (adj, 0.5, digits);
00319   if (spin_button)
00320     *spin_button = spin_but;
00321   if (width > 0)
00322     gtk_widget_set_size_request (spin_but, width, -1);
00323   spin = GTK_SPIN_BUTTON (spin_but);
00324   gtk_spin_button_set_numeric (spin, TRUE);
00325   if (data == NULL)
00326     data = (gpointer) spin;
00327   if (cb_func)
00328     g_signal_connect (G_OBJECT (spin_but), "value_changed",
00329                       G_CALLBACK (cb_func), data);
00330   if (box)
00331     {
00332       if (right_align && string)
00333         {
00334           label = gtk_label_new (string);
00335           gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
00336           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
00337         }
00338       gtk_box_pack_start (GTK_BOX (box), spin_but, FALSE, FALSE, 2);
00339       if (!right_align && string)
00340         {
00341           label = gtk_label_new (string);
00342           gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
00343           gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 2);
00344         }
00345     }
00346 }
00347 
00348 void
00349 ghid_table_coord_entry (GtkWidget * table, gint row, gint column,
00350                         GtkWidget ** coord_entry, Coord value,
00351                         Coord low, Coord high, enum ce_step_size step_size,
00352                         gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
00353                         gpointer data, gboolean right_align, gchar * string)
00354 {
00355   GtkWidget *label, *entry_widget;
00356   GHidCoordEntry *entry;
00357 
00358   if (!table)
00359     return;
00360 
00361   entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
00362   if (coord_entry)
00363     *coord_entry = entry_widget;
00364   if (width > 0)
00365     gtk_widget_set_size_request (entry_widget, width, -1);
00366   entry = GHID_COORD_ENTRY (entry_widget);
00367   if (data == NULL)
00368     data = (gpointer) entry;
00369   if (cb_func)
00370     g_signal_connect (G_OBJECT (entry), "value_changed",
00371                       G_CALLBACK (cb_func), data);
00372 
00373   if (right_align)
00374     {
00375       gtk_table_attach_defaults (GTK_TABLE (table), entry_widget,
00376                                  column + 1, column + 2, row, row + 1);
00377       if (string)
00378         {
00379           label = gtk_label_new (string);
00380           gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
00381           gtk_table_attach_defaults (GTK_TABLE (table), label,
00382                                      column, column + 1, row, row + 1);
00383         }
00384     }
00385   else
00386     {
00387       gtk_table_attach_defaults (GTK_TABLE (table), entry_widget,
00388                                  column, column + 1, row, row + 1);
00389       if (string)
00390         {
00391           label = gtk_label_new (string);
00392           gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
00393           gtk_table_attach_defaults (GTK_TABLE (table), label,
00394                                      column + 1, column + 2, row, row + 1);
00395         }
00396     }
00397 }
00398 
00399 
00400 void
00401 ghid_table_spin_button (GtkWidget * table, gint row, gint column,
00402                         GtkWidget ** spin_button, gfloat value,
00403                         gfloat low, gfloat high, gfloat step0, gfloat step1,
00404                         gint digits, gint width,
00405                         void (*cb_func) (GtkSpinButton *, gpointer), gpointer data,
00406                         gboolean right_align, gchar * string)
00407 {
00408   GtkWidget *label, *spin_but;
00409   GtkSpinButton *spin;
00410   GtkAdjustment *adj;
00411 
00412   if (!table)
00413     return;
00414 
00415   adj = (GtkAdjustment *) gtk_adjustment_new (value,
00416                                              low, high, step0, step1, 0.0);
00417   spin_but = gtk_spin_button_new (adj, 0.5, digits);
00418 
00419   if (spin_button)
00420     *spin_button = spin_but;
00421   if (width > 0)
00422     gtk_widget_set_size_request (spin_but, width, -1);
00423   spin = GTK_SPIN_BUTTON (spin_but);
00424   gtk_spin_button_set_numeric (spin, TRUE);
00425   if (data == NULL)
00426     data = (gpointer) spin;
00427   if (cb_func)
00428     g_signal_connect (G_OBJECT (spin_but), "value_changed",
00429                       G_CALLBACK (cb_func), data);
00430 
00431   if (right_align)
00432     {
00433       gtk_table_attach_defaults (GTK_TABLE (table), spin_but,
00434                                  column + 1, column + 2, row, row + 1);
00435       if (string)
00436         {
00437           label = gtk_label_new (string);
00438           gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
00439           gtk_table_attach_defaults (GTK_TABLE (table), label,
00440                                      column, column + 1, row, row + 1);
00441         }
00442     }
00443   else
00444     {
00445       gtk_table_attach_defaults (GTK_TABLE (table), spin_but,
00446                                  column, column + 1, row, row + 1);
00447       if (string)
00448         {
00449           label = gtk_label_new (string);
00450           gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
00451           gtk_table_attach_defaults (GTK_TABLE (table), label,
00452                                      column + 1, column + 2, row, row + 1);
00453         }
00454     }
00455 }
00456 
00457 void
00458 ghid_range_control (GtkWidget * box, GtkWidget ** scale_res,
00459                     gboolean horizontal, GtkPositionType pos,
00460                     gboolean set_draw_value, gint digits, gboolean pack_start,
00461                     gboolean expand, gboolean fill, guint pad, gfloat value,
00462                     gfloat low, gfloat high, gfloat step0, gfloat step1,
00463                     void (*cb_func) (), gpointer data)
00464 {
00465   GtkWidget *scale;
00466   GtkAdjustment *adj;
00467 
00468   adj = (GtkAdjustment *) gtk_adjustment_new (value,
00469                                               low, high, step0, step1, 0.0);
00470 
00471   if (horizontal)
00472     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj));
00473   else
00474     scale = gtk_vscale_new (GTK_ADJUSTMENT (adj));
00475   gtk_scale_set_value_pos (GTK_SCALE (scale), pos);
00476   gtk_scale_set_draw_value (GTK_SCALE (scale), set_draw_value);
00477   gtk_scale_set_digits (GTK_SCALE (scale), digits);
00478 
00479   /* Increments don't make sense, use -1,1 because that does closest to
00480      |  what I want: scroll down decrements slider value.
00481    */
00482   gtk_range_set_increments (GTK_RANGE (scale), -1, 1);
00483 
00484   if (pack_start)
00485     gtk_box_pack_start (GTK_BOX (box), scale, expand, fill, pad);
00486   else
00487     gtk_box_pack_end (GTK_BOX (box), scale, expand, fill, pad);
00488 
00489   if (data == NULL)
00490     data = (gpointer) adj;
00491   if (cb_func)
00492     g_signal_connect (G_OBJECT (adj), "value_changed",
00493                       G_CALLBACK (cb_func), data);
00494   if (scale_res)
00495     *scale_res = scale;
00496 }
00497 
00498 GtkWidget *
00499 ghid_scrolled_vbox (GtkWidget * box, GtkWidget ** scr,
00500                     GtkPolicyType h_policy, GtkPolicyType v_policy)
00501 {
00502   GtkWidget *scrolled, *vbox;
00503 
00504   scrolled = gtk_scrolled_window_new (NULL, NULL);
00505   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
00506                                   h_policy, v_policy);
00507   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
00508   vbox = gtk_vbox_new (FALSE, 0);
00509   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
00510                                          vbox);
00511   if (scr)
00512     *scr = scrolled;
00513   return vbox;
00514 }
00515 
00516 /* frame_border_width - border around outside of frame.
00517    |  vbox_pad - pad between widgets to be packed in returned vbox.
00518    |  vbox_border_width - border between returned vbox and frame.
00519 */
00520 GtkWidget *
00521 ghid_framed_vbox (GtkWidget * box, gchar * label, gint frame_border_width,
00522                   gboolean frame_expand, gint vbox_pad,
00523                   gint vbox_border_width)
00524 {
00525   GtkWidget *frame;
00526   GtkWidget *vbox;
00527 
00528   frame = gtk_frame_new (label);
00529   gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width);
00530   gtk_box_pack_start (GTK_BOX (box), frame, frame_expand, frame_expand, 0);
00531   vbox = gtk_vbox_new (FALSE, vbox_pad);
00532   gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width);
00533   gtk_container_add (GTK_CONTAINER (frame), vbox);
00534   return vbox;
00535 }
00536 
00537 GtkWidget *
00538 ghid_framed_vbox_end (GtkWidget * box, gchar * label, gint frame_border_width,
00539                       gboolean frame_expand, gint vbox_pad,
00540                       gint vbox_border_width)
00541 {
00542   GtkWidget *frame;
00543   GtkWidget *vbox;
00544 
00545   frame = gtk_frame_new (label);
00546   gtk_container_set_border_width (GTK_CONTAINER (frame), frame_border_width);
00547   gtk_box_pack_end (GTK_BOX (box), frame, frame_expand, frame_expand, 0);
00548   vbox = gtk_vbox_new (FALSE, vbox_pad);
00549   gtk_container_set_border_width (GTK_CONTAINER (vbox), vbox_border_width);
00550   gtk_container_add (GTK_CONTAINER (frame), vbox);
00551   return vbox;
00552 }
00553 
00554 GtkWidget *
00555 ghid_category_vbox (GtkWidget * box, const gchar * category_header,
00556                     gint header_pad,
00557                     gint box_pad, gboolean pack_start, gboolean bottom_pad)
00558 {
00559   GtkWidget *vbox, *vbox1, *hbox, *label;
00560   gchar *s;
00561 
00562   vbox = gtk_vbox_new (FALSE, 0);
00563   if (pack_start)
00564     gtk_box_pack_start (GTK_BOX (box), vbox, FALSE, FALSE, 0);
00565   else
00566     gtk_box_pack_end (GTK_BOX (box), vbox, FALSE, FALSE, 0);
00567 
00568   if (category_header)
00569     {
00570       label = gtk_label_new (NULL);
00571       s = g_strconcat ("<span weight=\"bold\">", category_header,
00572                        "</span>", NULL);
00573       gtk_label_set_markup (GTK_LABEL (label), s);
00574       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
00575       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, header_pad);
00576       g_free (s);
00577     }
00578 
00579   hbox = gtk_hbox_new (FALSE, 0);
00580   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
00581   label = gtk_label_new ("     ");
00582   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
00583   vbox1 = gtk_vbox_new (FALSE, box_pad);
00584   gtk_box_pack_start (GTK_BOX (hbox), vbox1, TRUE, TRUE, 0);
00585 
00586   if (bottom_pad)
00587     {
00588       label = gtk_label_new ("");
00589       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
00590     }
00591   return vbox1;
00592 }
00593 
00594 GtkTreeSelection *
00595 ghid_scrolled_selection (GtkTreeView * treeview, GtkWidget * box,
00596                          GtkSelectionMode s_mode,
00597                          GtkPolicyType h_policy, GtkPolicyType v_policy,
00598                          void (*func_cb) (GtkTreeSelection *, gpointer), gpointer data)
00599 {
00600   GtkTreeSelection *selection;
00601   GtkWidget *scrolled;
00602 
00603   if (!box || !treeview)
00604     return NULL;
00605 
00606   scrolled = gtk_scrolled_window_new (NULL, NULL);
00607   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
00608   gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (treeview));
00609   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
00610                                   h_policy, v_policy);
00611   selection = gtk_tree_view_get_selection (treeview);
00612   gtk_tree_selection_set_mode (selection, s_mode);
00613   if (func_cb)
00614     g_signal_connect (G_OBJECT (selection), "changed",
00615                       G_CALLBACK (func_cb), data);
00616   return selection;
00617 }
00618 
00619 GtkWidget *
00620 ghid_notebook_page (GtkWidget * tabs, const char *name, gint pad, gint border)
00621 {
00622   GtkWidget *label;
00623   GtkWidget *vbox;
00624 
00625   vbox = gtk_vbox_new (FALSE, pad);
00626   gtk_container_set_border_width (GTK_CONTAINER (vbox), border);
00627 
00628   label = gtk_label_new (name);
00629   gtk_notebook_append_page (GTK_NOTEBOOK (tabs), vbox, label);
00630 
00631   return vbox;
00632 }
00633 
00634 GtkWidget *
00635 ghid_framed_notebook_page (GtkWidget * tabs, char *name, gint border,
00636                            gint frame_border, gint vbox_pad, gint vbox_border)
00637 {
00638   GtkWidget *vbox;
00639 
00640   vbox = ghid_notebook_page (tabs, name, 0, border);
00641   vbox = ghid_framed_vbox (vbox, NULL, frame_border, TRUE,
00642                            vbox_pad, vbox_border);
00643   return vbox;
00644 }
00645 
00646 void
00647 ghid_dialog_report (gchar * title, gchar * message)
00648 {
00649   GtkWidget *top_win;
00650   GtkWidget *dialog;
00651   GtkWidget *content_area;
00652   GtkWidget *scrolled;
00653   GtkWidget *vbox, *vbox1;
00654   GtkWidget *label;
00655   gchar *s;
00656   gint nlines;
00657   GHidPort *out = &ghid_port;
00658 
00659   if (!message)
00660     return;
00661   top_win = out->top_window;
00662   dialog = gtk_dialog_new_with_buttons (title ? title : "PCB",
00663                                         GTK_WINDOW (top_win),
00664                                         GTK_DIALOG_DESTROY_WITH_PARENT,
00665                                         GTK_STOCK_OK, GTK_RESPONSE_NONE,
00666                                         NULL);
00667   g_signal_connect_swapped (GTK_OBJECT (dialog), "response",
00668                             G_CALLBACK (gtk_widget_destroy),
00669                             GTK_OBJECT (dialog));
00670   gtk_window_set_wmclass (GTK_WINDOW (dialog), "PCB_Dialog", "PCB");
00671 
00672   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
00673 
00674   vbox = gtk_vbox_new (FALSE, 0);
00675   gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
00676   gtk_box_pack_start (GTK_BOX (content_area), vbox, FALSE, FALSE, 0);
00677 
00678   label = gtk_label_new (message);
00679   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
00680 
00681   for (nlines = 0, s = message; *s; ++s)
00682     if (*s == '\n')
00683       ++nlines;
00684   if (nlines > 20)
00685     {
00686       vbox1 = ghid_scrolled_vbox (vbox, &scrolled,
00687                                   GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
00688       gtk_widget_set_size_request (scrolled, -1, 300);
00689       gtk_box_pack_start (GTK_BOX (vbox1), label, FALSE, FALSE, 0);
00690     }
00691   else
00692     gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
00693 
00694   gtk_widget_show_all (dialog);
00695 }
00696 
00697 
00698 void
00699 ghid_label_set_markup (GtkWidget * label, const gchar * text)
00700 {
00701   if (label)
00702     gtk_label_set_markup (GTK_LABEL (label), text ? text : "");
00703 }
00704 
00705 
00706 static void
00707 text_view_append (GtkWidget * view, gchar * s)
00708 {
00709   GtkTextIter iter;
00710   GtkTextBuffer *buffer;
00711   GtkTextMark *mark;
00712 
00713   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
00714   gtk_text_buffer_get_end_iter (buffer, &iter);
00715   /* gtk_text_iter_forward_to_end(&iter); */
00716 
00717   if (strncmp (s, "<b>", 3) == 0)
00718     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
00719                                               s + 3, -1, "bold", NULL);
00720   else if (strncmp (s, "<i>", 3) == 0)
00721     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
00722                                               s + 3, -1, "italic", NULL);
00723   else if (strncmp (s, "<h>", 3) == 0)
00724     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
00725                                               s + 3, -1, "heading", NULL);
00726   else if (strncmp (s, "<c>", 3) == 0)
00727     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
00728                                               s + 3, -1, "center", NULL);
00729   else if (strncmp (s, "<ul>", 4) == 0)
00730     gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
00731                                               s + 4, -1, "underline", NULL);
00732   else
00733     gtk_text_buffer_insert (buffer, &iter, s, -1);
00734 
00735   mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE);
00736   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (view), mark,
00737                                 0, TRUE, 0.0, 1.0);
00738   gtk_text_buffer_delete_mark (buffer, mark);
00739 }
00740 
00741 void
00742 ghid_text_view_append (GtkWidget * view, gchar * string)
00743 {
00744   static gchar *tag;
00745   gchar *s;
00746 
00747   s = string;
00748   if (*s == '<'
00749       && ((*(s + 2) == '>' && !*(s + 3)) || (*(s + 3) == '>' && !*(s + 4))))
00750     {
00751       tag = g_strdup (s);
00752       return;
00753     }
00754 
00755   if (tag)
00756     {
00757       s = g_strconcat (tag, string, NULL);
00758       text_view_append (view, s);
00759       g_free (s);
00760       g_free (tag);
00761       tag = NULL;
00762     }
00763   else
00764     text_view_append (view, string);
00765 }
00766 
00767 void
00768 ghid_text_view_append_strings (GtkWidget * view, gchar ** string,
00769                                gint n_strings)
00770 {
00771   gchar *tag = NULL;
00772   gchar *s, *t;
00773   gint i;
00774 
00775   for (i = 0; i < n_strings; ++i)
00776     {
00777       s = string[i];
00778       if (*s == '<'
00779           && ((*(s + 2) == '>' && !*(s + 3))
00780               || (*(s + 3) == '>' && !*(s + 4))))
00781         {
00782           tag = g_strdup (s);
00783           continue;
00784         }
00785       s = _(string[i]);
00786       if (tag)
00787         {
00788           t = g_strconcat (tag, s, NULL);
00789           text_view_append (view, t);
00790           g_free (t);
00791           g_free (tag);
00792           tag = NULL;
00793         }
00794       else
00795         text_view_append (view, s);
00796     }
00797 }
00798 
00799 
00800 GtkWidget *
00801 ghid_scrolled_text_view (GtkWidget * box,
00802                          GtkWidget ** scr,
00803                          GtkPolicyType h_policy, GtkPolicyType v_policy)
00804 {
00805   GtkWidget *scrolled, *view;
00806   GtkTextBuffer *buffer;
00807 
00808   scrolled = gtk_scrolled_window_new (NULL, NULL);
00809   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
00810                                   h_policy, v_policy);
00811   gtk_box_pack_start (GTK_BOX (box), scrolled, TRUE, TRUE, 0);
00812 
00813   view = gtk_text_view_new ();
00814   gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE);
00815   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
00816   gtk_text_buffer_create_tag (buffer, "heading",
00817                               "weight", PANGO_WEIGHT_BOLD,
00818                               "size", 14 * PANGO_SCALE, NULL);
00819   gtk_text_buffer_create_tag (buffer, "italic",
00820                               "style", PANGO_STYLE_ITALIC, NULL);
00821   gtk_text_buffer_create_tag (buffer, "bold",
00822                               "weight", PANGO_WEIGHT_BOLD, NULL);
00823   gtk_text_buffer_create_tag (buffer, "center",
00824                               "justification", GTK_JUSTIFY_CENTER, NULL);
00825   gtk_text_buffer_create_tag (buffer, "underline",
00826                               "underline", PANGO_UNDERLINE_SINGLE, NULL);
00827 
00828   gtk_container_add (GTK_CONTAINER (scrolled), view);
00829   if (scr)
00830     *scr = scrolled;
00831   return view;
00832 }