Support default return value in o_complex_get_refdes.
[geda-gaf/berndj.git] / gschem / src / x_dialog.c
blob60de72801fdeeafebc6d3cccc0233b79455ada80
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 /*! \todo STILL NEED to clean up line lengths in aa and tr */
21 #include <config.h>
23 #include <stdio.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
31 #include "gschem.h"
33 #include "glade_compat.h"
34 #include "support.h"
36 #ifdef HAVE_LIBDMALLOC
37 #include <dmalloc.h>
38 #endif
40 #define GLADE_HOOKUP_OBJECT(component,widget,name) \
41 g_object_set_data_full (G_OBJECT (component), name, \
42 gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
44 static GtkWidget* create_menu_linetype (GSCHEM_TOPLEVEL *w_current);
45 static gint line_type_dialog_linetype_change (GtkWidget *w, gpointer data);
46 static void line_type_dialog_ok (GtkWidget *w, gpointer data);
48 static GtkWidget* create_menu_filltype (GSCHEM_TOPLEVEL *w_current);
49 static gint fill_type_dialog_filltype_change(GtkWidget *w, gpointer data);
50 static void fill_type_dialog_ok(GtkWidget *w, gpointer data);
52 struct slot_chooser;
53 static void slot_chooser_add_rows(struct slot_chooser *sc,
54 SCM list,
55 GtkTreeIter *parent_row);
57 static gboolean repl_selection_one(GtkTreeModel *model, GtkTreePath *path,
58 GtkTreeIter *iter, gpointer user_data);
60 struct line_type_data {
61 GtkWidget *dialog;
62 GtkWidget *width_entry;
63 GtkWidget *line_type;
64 GtkWidget *length_entry;
65 GtkWidget *space_entry;
67 GSCHEM_TOPLEVEL *w_current;
68 GList *objects;
71 struct fill_type_data {
72 GtkWidget *dialog;
73 GtkWidget *fill_type;
74 GtkWidget *width_entry;
75 GtkWidget *angle1_entry;
76 GtkWidget *pitch1_entry;
77 GtkWidget *angle2_entry;
78 GtkWidget *pitch2_entry;
80 GSCHEM_TOPLEVEL *w_current;
81 GList *objects;
84 /*! \todo Finish function documentation!!!
85 * \brief
86 * \par Function Description
89 void destroy_window(GtkWidget *widget, GtkWidget **window)
91 *window = NULL;
94 /* TODO: This string is used by the dialogs: show_text, find_text and hide_text
95 * I think it should be removed. (Werner Hoch)
97 char generic_textstring[256] = "refdes=R";
99 /***************** Start of Text Input dialog box *********************/
101 /*! \brief worker function for the text entry dialog
102 * \par Function Description
103 * This function applies the text from the text entry dialog.
105 void text_input_dialog_apply(GtkWidget *w, GSCHEM_TOPLEVEL *w_current)
107 gchar *string = NULL;
108 gchar *tmp = NULL;
109 GtkWidget *tientry;
110 GtkTextBuffer *textbuffer;
111 GtkTextIter start, end;
113 tientry = gtk_object_get_data(GTK_OBJECT(w_current->tiwindow),"tientry");
115 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tientry));
116 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
117 string = gtk_text_iter_get_text (&start, &end);
119 if (string[0] == '\0' )
120 return;
122 switch(w_current->text_caps) {
123 case(LOWER):
124 tmp = g_utf8_strdown (string, -1);
125 break;
127 case(UPPER):
128 tmp = g_utf8_strup (string, -1);
129 break;
131 case(BOTH):
132 default:
133 /* do nothing */
134 break;
137 /* select the text, so you can continue immediately writing the next text */
138 select_all_text_in_textview(GTK_TEXT_VIEW(tientry));
139 gtk_widget_grab_focus(tientry);
141 w_current->toplevel->page_current->CHANGED=1;
143 o_text_prepare_place (w_current, tmp == NULL ? string : tmp);
144 g_free (string);
145 g_free (tmp);
148 /*! \brief response function for the text entry dialog
149 * \par Function Description
150 * Callback function for the text entry dialog.
152 void text_input_dialog_response(GtkWidget * widget, gint response, GSCHEM_TOPLEVEL *w_current)
154 switch(response) {
155 case GTK_RESPONSE_ACCEPT:
156 text_input_dialog_apply(widget, w_current);
157 break;
158 case GTK_RESPONSE_REJECT:
159 case GTK_RESPONSE_DELETE_EVENT:
160 i_set_state(w_current, SELECT);
161 i_update_toolbar(w_current);
162 gtk_widget_destroy(w_current->tiwindow);
163 w_current->tiwindow=NULL;
164 break;
165 default:
166 printf("text_edit_dialog_response(): strange signal %d\n", response);
171 /*! \brief create or present the text entry dialog
172 * \par Function Description
173 * This function creates or raises the modal text entry dialog
175 void text_input_dialog (GSCHEM_TOPLEVEL *w_current)
177 GtkWidget *label = NULL;
178 GtkWidget *tientry = NULL;
179 GtkWidget *vbox;
180 GtkWidget *viewport1 = NULL;
181 GtkWidget *scrolled_window = NULL;
182 PangoTabArray *tab_array;
183 int real_tab_width;
185 if (!w_current->tiwindow) { /* dialog not created yet */
186 w_current->tiwindow = gschem_dialog_new_with_buttons(_("Text Entry..."),
187 GTK_WINDOW(w_current->main_window),
188 0, /* NON_MODAL */
189 "text-entry", w_current,
190 GTK_STOCK_CLOSE,
191 GTK_RESPONSE_REJECT,
192 GTK_STOCK_APPLY,
193 GTK_RESPONSE_ACCEPT,
194 NULL);
196 /* Set the alternative button order (ok, cancel, help) for other systems */
197 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tiwindow),
198 GTK_RESPONSE_ACCEPT,
199 GTK_RESPONSE_REJECT,
200 -1);
202 gtk_window_position(GTK_WINDOW (w_current->tiwindow),
203 GTK_WIN_POS_NONE);
205 gtk_signal_connect(GTK_OBJECT (w_current->tiwindow), "response",
206 GTK_SIGNAL_FUNC(text_input_dialog_response),
207 w_current);
209 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tiwindow),
210 GTK_RESPONSE_ACCEPT);
212 gtk_container_border_width(GTK_CONTAINER (w_current->tiwindow),
213 DIALOG_BORDER_SPACING);
214 vbox = GTK_DIALOG(w_current->tiwindow)->vbox;
215 gtk_box_set_spacing(GTK_BOX(vbox),DIALOG_V_SPACING);
217 label = gtk_label_new (_("Enter text, click apply,\n"
218 "move cursor into window, click to place text.\n"
219 "Middle button to rotate while placing."));
220 gtk_misc_set_alignment(GTK_MISC(label),0,0);
221 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
223 viewport1 = gtk_viewport_new (NULL, NULL);
224 gtk_widget_show (viewport1);
226 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
227 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
228 GTK_POLICY_AUTOMATIC,
229 GTK_POLICY_AUTOMATIC);
230 gtk_container_add (GTK_CONTAINER (viewport1), scrolled_window);
231 gtk_box_pack_start( GTK_BOX(vbox), viewport1, TRUE, TRUE, 0);
233 tientry = gtk_text_view_new();
234 gtk_text_view_set_editable(GTK_TEXT_VIEW(tientry), TRUE);
235 select_all_text_in_textview(GTK_TEXT_VIEW(tientry));
237 /* Set the tab width, using pango tab array */
238 /*! \bug FIXME: This doesn't work. Why? */
239 tab_array = pango_tab_array_new (1, TRUE);
240 real_tab_width = text_view_calculate_real_tab_width(GTK_TEXT_VIEW(tientry),
241 tab_in_chars);
242 if (real_tab_width >= 0) {
243 pango_tab_array_set_tab (tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
244 /* printf("Real tab width: %i\n", real_tab_width);*/
245 gtk_text_view_set_tabs (GTK_TEXT_VIEW (tientry),
246 tab_array);
248 else {
249 g_warning ("text_input_dialog: Impossible to set tab width.\n");
251 pango_tab_array_free (tab_array);
252 gtk_container_add(GTK_CONTAINER(scrolled_window), tientry);
254 gtk_object_set_data(GTK_OBJECT(w_current->tiwindow),
255 "tientry",tientry);
257 gtk_widget_show_all (w_current->tiwindow);
259 else { /* dialog already created */
260 gtk_window_present (GTK_WINDOW(w_current->tiwindow));
263 /* always select the text in the entry */
264 tientry = gtk_object_get_data(GTK_OBJECT(w_current->tiwindow),"tientry");
265 select_all_text_in_textview(GTK_TEXT_VIEW(tientry));
266 gtk_widget_grab_focus(tientry);
269 /***************** End of Text Input dialog box ***********************/
271 /***************** Start of Text Edit dialog box **********************/
272 /*! \brief CAllback for a text aligment change
273 * \par Function Description
274 * This function stores a change of the text alignment in the
275 * <b>GSCHEM_TOPLEVEL</b> struct.
276 * \todo Remove that function. Only the OK-Button should set any
277 * properties in the GSCHEM_TOPLEVEL struct.
279 gint change_alignment(GtkWidget *w, GSCHEM_TOPLEVEL *w_current)
281 char *alignment;
282 alignment = gtk_object_get_data(GTK_OBJECT(w),"alignment");
283 w_current->text_alignment = atoi(alignment);
285 /*w_current->page_current->CHANGED=1; I don't think this belongs */
286 /* o_undo_savestate(w_current, UNDO_ALL); I don't think this belongs */
288 return 0;
291 /*! \brief Create the alignment menu for the text property dialog
292 * \par Function Description
293 * This function creates a GtkMenu with nine different alignment
294 * entries.
296 static GtkWidget *create_menu_alignment (GSCHEM_TOPLEVEL *w_current)
298 GtkWidget *menu;
299 GtkWidget *menuitem;
300 GSList *group;
301 char *buf;
303 menu = gtk_menu_new ();
304 group = NULL;
306 buf = g_strdup_printf( _("Lower Left"));
307 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
308 g_free(buf);
309 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
310 gtk_menu_append (GTK_MENU (menu), menuitem);
311 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "0");
312 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
313 (GtkSignalFunc) change_alignment,
314 w_current);
315 gtk_widget_show (menuitem);
317 buf = g_strdup_printf( _("Middle Left"));
318 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
319 g_free(buf);
320 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
321 gtk_menu_append (GTK_MENU (menu), menuitem);
322 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "1");
323 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
324 (GtkSignalFunc) change_alignment,
325 w_current);
326 gtk_widget_show (menuitem);
328 buf = g_strdup_printf( _("Upper Left"));
329 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
330 g_free(buf);
331 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
332 gtk_menu_append (GTK_MENU (menu), menuitem);
333 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "2");
334 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
335 (GtkSignalFunc) change_alignment,
336 w_current);
337 gtk_widget_show (menuitem);
339 buf = g_strdup_printf( _("Lower Middle"));
340 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
341 g_free(buf);
342 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
343 gtk_menu_append (GTK_MENU (menu), menuitem);
344 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "3");
345 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
346 (GtkSignalFunc) change_alignment,
347 w_current);
348 gtk_widget_show (menuitem);
350 buf = g_strdup_printf( _("Middle Middle"));
351 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
352 g_free(buf);
353 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
354 gtk_menu_append (GTK_MENU (menu), menuitem);
355 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "4");
356 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
357 (GtkSignalFunc) change_alignment,
358 w_current);
359 gtk_widget_show (menuitem);
361 buf = g_strdup_printf( _("Upper Middle"));
362 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
363 g_free(buf);
364 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
365 gtk_menu_append (GTK_MENU (menu), menuitem);
366 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "5");
367 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
368 (GtkSignalFunc) change_alignment,
369 w_current);
370 gtk_widget_show (menuitem);
372 buf = g_strdup_printf( _("Lower Right"));
373 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
374 g_free(buf);
375 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
376 gtk_menu_append (GTK_MENU (menu), menuitem);
377 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "6");
378 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
379 (GtkSignalFunc) change_alignment,
380 w_current);
381 gtk_widget_show (menuitem);
383 buf = g_strdup_printf( _("Middle Right"));
384 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
385 g_free(buf);
386 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
387 gtk_menu_append (GTK_MENU (menu), menuitem);
388 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "7");
389 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
390 (GtkSignalFunc) change_alignment,
391 w_current);
392 gtk_widget_show (menuitem);
394 buf = g_strdup_printf( _("Upper Right"));
395 menuitem = gtk_radio_menu_item_new_with_label (group, buf);
396 g_free(buf);
397 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
398 gtk_menu_append (GTK_MENU (menu), menuitem);
399 gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "8");
400 gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
401 (GtkSignalFunc) change_alignment,
402 w_current);
403 gtk_widget_show (menuitem);
405 return menu;
408 /* we reuse the color menu so we need to declare it */
409 static GtkWidget *create_color_menu(GSCHEM_TOPLEVEL * w_current);
411 /*! \brief Apply the settings from the text property dialog
412 * \par Function Description
413 * This function applies the user settings to the selected text objects
414 * and closes the dialog
416 void text_edit_dialog_ok(GtkWidget *w, GSCHEM_TOPLEVEL *w_current)
418 int len=0;
419 int text_size=8;
420 char *text_string = NULL;
421 char *text_size_string = NULL;
422 int new_text_alignment;
423 int num_selected;
424 GtkTextBuffer *textbuffer;
425 GtkTextIter start, end;
426 GtkWidget *widget;
428 num_selected = g_list_length( geda_list_get_glist( w_current->toplevel->page_current->selection_list ));
430 /* text string entry will only show up if one object is selected */
431 if (num_selected == 1) {
432 widget = g_object_get_data (G_OBJECT (w_current->tewindow), "textentry");
433 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
434 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
435 text_string = gtk_text_iter_get_text (&start, &end);
436 } /* else the string will be null which is okay */
438 widget = g_object_get_data (G_OBJECT (w_current->tewindow), "sizeentry");
439 text_size_string = (char *) gtk_entry_get_text(GTK_ENTRY(widget));
441 if (text_string) {
442 len = strlen(text_string);
445 if (text_size_string) {
446 text_size = atoi(text_size_string);
449 if (text_size == 0) {
450 text_size = default_text_size;
453 new_text_alignment = w_current->text_alignment;
455 o_text_edit_end(w_current, text_string, len, text_size, new_text_alignment);
458 /*! \brief Response function for the text property dialog
459 * \par Function Description
460 * This function receives the user response of the text property dialog.
461 * The response is either <b>OK</b>, <b>Cancel</b> or delete.
464 void text_edit_dialog_response(GtkWidget * widget, gint response, GSCHEM_TOPLEVEL *w_current)
466 switch(response) {
467 case GTK_RESPONSE_ACCEPT:
468 text_edit_dialog_ok(widget, w_current);
469 break;
470 case GTK_RESPONSE_REJECT:
471 case GTK_RESPONSE_DELETE_EVENT:
472 /* void */
473 break;
474 default:
475 printf("text_edit_dialog_response(): strange signal %d\n", response);
477 /* clean up */
478 i_set_state(w_current, SELECT);
479 i_update_toolbar(w_current);
480 gtk_widget_destroy(w_current->tewindow);
481 w_current->tewindow = NULL;
484 /*! \brief Create the edit text properties dialog
485 * \par Function Description
486 * This Function creates the dialog to edit text properties.
487 * \todo Check why there's no color in the calling parameters
488 * \todo If more than one text element is selected, add an unchanged option
490 void text_edit_dialog (GSCHEM_TOPLEVEL *w_current, const char *string, int text_size,
491 int text_alignment)
493 GtkWidget *label = NULL;
494 GtkWidget *table;
495 GtkWidget *vbox;
496 GtkWidget *optionmenu = NULL;
497 GtkWidget *align_menu = NULL;
498 GtkWidget *viewport1 = NULL;
499 GtkWidget *textentry = NULL;
500 GtkWidget *sizeentry = NULL;
501 GtkWidget *alignment;
502 GtkWidget *scrolled_window = NULL;
503 GtkTextBuffer *textbuffer;
504 char *text_size_string;
505 int num_selected=0;
507 if (!w_current->tewindow) {
508 w_current->tewindow = gschem_dialog_new_with_buttons(_("Edit Text Properties"),
509 GTK_WINDOW(w_current->main_window),
510 GTK_DIALOG_MODAL,
511 "text-edit", w_current,
512 GTK_STOCK_CANCEL,
513 GTK_RESPONSE_REJECT,
514 GTK_STOCK_OK,
515 GTK_RESPONSE_ACCEPT,
516 NULL);
518 /* Set the alternative button order (ok, cancel, help) for other systems */
519 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tewindow),
520 GTK_RESPONSE_ACCEPT,
521 GTK_RESPONSE_REJECT,
522 -1);
524 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tewindow),
525 GTK_RESPONSE_ACCEPT);
527 gtk_signal_connect(GTK_OBJECT(w_current->tewindow), "response",
528 GTK_SIGNAL_FUNC(text_edit_dialog_response), w_current);
530 gtk_window_position(GTK_WINDOW (w_current->tewindow),
531 GTK_WIN_POS_MOUSE);
534 vbox = GTK_DIALOG(w_current->tewindow)->vbox;
535 gtk_container_set_border_width(GTK_CONTAINER(w_current->tewindow),DIALOG_BORDER_SPACING);
536 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
538 /* add a text box if only one object is selected */
539 num_selected = g_list_length( geda_list_get_glist( w_current->toplevel->page_current->selection_list ));
541 if (num_selected == 1) {
542 label = gtk_label_new (_("<b>Text Content</b>"));
543 gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
544 gtk_misc_set_alignment(GTK_MISC(label),0,0);
545 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
547 alignment = gtk_alignment_new(0,0,1,1);
548 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
549 DIALOG_INDENTATION, 0);
550 gtk_box_pack_start(GTK_BOX(vbox), alignment, TRUE, TRUE, 0);
552 viewport1 = gtk_viewport_new (NULL, NULL);
553 gtk_widget_set_size_request(GTK_WIDGET(viewport1),-1,75);
555 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
556 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
557 GTK_POLICY_AUTOMATIC,
558 GTK_POLICY_AUTOMATIC);
559 gtk_container_add (GTK_CONTAINER (viewport1), scrolled_window);
560 gtk_container_add( GTK_CONTAINER(alignment), viewport1);
562 textentry = gtk_text_view_new();
563 gtk_text_view_set_editable(GTK_TEXT_VIEW(textentry), TRUE);
564 select_all_text_in_textview(GTK_TEXT_VIEW(textentry));
566 /*! \bug FIXME: Set tab's width in the textview widget. */
567 /* See first the code in text_input_dialog and get it working before adding it here. */
569 gtk_container_add(GTK_CONTAINER(scrolled_window), textentry);
570 gtk_widget_grab_focus(textentry);
571 GLADE_HOOKUP_OBJECT(w_current->tewindow, textentry,"textentry");
574 label = gtk_label_new(_("<b>Text Properties</b>"));
575 gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
576 gtk_misc_set_alignment(GTK_MISC(label),0,0);
577 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
579 alignment = gtk_alignment_new(0,0,1,1);
580 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
581 DIALOG_INDENTATION, 0);
582 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
584 table = gtk_table_new (3, 2, FALSE);
585 gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING);
586 gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING);
587 gtk_container_add(GTK_CONTAINER(alignment), table);
589 label = gtk_label_new(_("Color:"));
590 gtk_misc_set_alignment(GTK_MISC(label),0,0);
591 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0);
593 optionmenu = create_color_menu (w_current);
594 gtk_table_attach_defaults(GTK_TABLE(table), optionmenu, 1,2,0,1);
596 label = gtk_label_new(_("Size:"));
597 gtk_misc_set_alignment(GTK_MISC(label),0,0);
598 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2, GTK_FILL,0,0,0);
600 sizeentry = gtk_entry_new_with_max_length (10);
601 gtk_editable_select_region(GTK_EDITABLE (sizeentry), 0, -1);
602 gtk_table_attach_defaults(GTK_TABLE(table), sizeentry, 1,2,1,2);
603 gtk_entry_set_activates_default(GTK_ENTRY(sizeentry), TRUE);
605 label = gtk_label_new(_("Alignment:"));
606 gtk_misc_set_alignment(GTK_MISC(label),0,0);
607 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3, GTK_FILL,0,0,0);
609 optionmenu = gtk_option_menu_new ();
610 align_menu = create_menu_alignment (w_current);
611 gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
612 align_menu);
613 gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu),
614 text_alignment);
615 w_current->text_alignment = text_alignment;
616 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_menu_get_active(GTK_MENU(align_menu))),
617 TRUE);
618 gtk_table_attach_defaults(GTK_TABLE(table), optionmenu, 1,2,2,3);
620 GLADE_HOOKUP_OBJECT(w_current->tewindow, sizeentry,"sizeentry");
621 gtk_widget_show_all(w_current->tewindow);
624 else { /* dialog already there */
625 gtk_window_present(GTK_WINDOW(w_current->tewindow));
628 if (string != NULL) {
629 if (num_selected == 1) { /* only if one thing is selected */
630 textentry = g_object_get_data (G_OBJECT (w_current->tewindow), "textentry");
631 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textentry));
632 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(textbuffer), string, -1);
633 select_all_text_in_textview(GTK_TEXT_VIEW(textentry));
637 text_size_string = g_strdup_printf("%d", text_size);
638 sizeentry = g_object_get_data (G_OBJECT (w_current->tewindow), "sizeentry");
639 gtk_entry_set_text(GTK_ENTRY(sizeentry),
640 text_size_string);
641 g_free(text_size_string);
644 /***************** End of Text Edit dialog box ************************/
646 /***************** Start of Line Type/width dialog box ****************/
648 /*! \brief Create a line type menu for the line type dialog
649 * \par Function Description
650 * This function creates a GtkMenu with the different linetypes.
652 static GtkWidget *create_menu_linetype (GSCHEM_TOPLEVEL *w_current)
654 GtkWidget *menu;
655 GSList *group;
656 struct line_type {
657 gchar *str;
658 OBJECT_TYPE type;
659 } types[] = { { N_("Solid"), TYPE_SOLID },
660 { N_("Dotted"), TYPE_DOTTED },
661 { N_("Dashed"), TYPE_DASHED },
662 { N_("Center"), TYPE_CENTER },
663 { N_("Phantom"), TYPE_PHANTOM } };
664 gint i;
666 menu = gtk_menu_new ();
667 group = NULL;
669 for (i = 0; i < sizeof (types) / sizeof (struct line_type); i++) {
670 GtkWidget *menuitem;
672 menuitem = gtk_radio_menu_item_new_with_label (group, _(types[i].str));
673 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
674 gtk_menu_append (GTK_MENU (menu), menuitem);
675 gtk_object_set_data (GTK_OBJECT(menuitem), "linetype",
676 GINT_TO_POINTER (types[i].type));
677 gtk_widget_show (menuitem);
680 return(menu);
683 /*! \brief Callback function for the linetype menu item in the line type dialog
684 * \par Function Description
685 * This Function is called when the user changes the line type selection.
686 * It sets the dash space/length entries either active or inactive.
688 static gint line_type_dialog_linetype_change(GtkWidget *w, gpointer data)
690 struct line_type_data *line_type_data = (struct line_type_data*) data;
691 GtkWidget *menuitem;
692 gboolean activate_length_entry, activate_space_entry;
693 gint type;
695 menuitem = gtk_menu_get_active (
696 GTK_MENU (gtk_option_menu_get_menu (
697 GTK_OPTION_MENU (line_type_data->line_type))));
699 type = GPOINTER_TO_INT(
700 gtk_object_get_data (GTK_OBJECT (menuitem), "linetype"));
701 switch(type) {
702 case(TYPE_SOLID):
703 activate_length_entry = FALSE;
704 activate_space_entry = FALSE;
705 break;
706 case(TYPE_DOTTED):
707 activate_length_entry = FALSE;
708 activate_space_entry = TRUE;
709 break;
710 case(TYPE_DASHED):
711 case(TYPE_CENTER):
712 case(TYPE_PHANTOM):
713 activate_length_entry = TRUE;
714 activate_space_entry = TRUE;
715 break;
716 default:
717 activate_length_entry = TRUE;
718 activate_space_entry = TRUE;
721 gtk_widget_set_sensitive (line_type_data->space_entry,
722 activate_space_entry);
723 gtk_widget_set_sensitive (line_type_data->length_entry,
724 activate_length_entry);
726 return(0);
730 /*! \brief Worker function for the line type and width dialog
731 * \par Function Description
732 * The function takes the properties of the dialog and applies
733 * them to the selected objects.
735 static void line_type_dialog_ok(GtkWidget *w, gpointer data)
737 struct line_type_data *line_type_data = (struct line_type_data*)data;
738 GSCHEM_TOPLEVEL *w_current = line_type_data->w_current;
739 TOPLEVEL *toplevel = w_current->toplevel;
740 GList *objects;
741 const gchar *width_str, *length_str, *space_str;
742 OBJECT_TYPE type;
744 /* retrieve the list of objects */
745 objects = line_type_data->objects;
747 /* get the new values from the text entries of the dialog */
748 width_str = gtk_entry_get_text (GTK_ENTRY (
749 line_type_data->width_entry));
750 length_str = gtk_entry_get_text (GTK_ENTRY (
751 line_type_data->length_entry));
752 space_str = gtk_entry_get_text (GTK_ENTRY (
753 line_type_data->space_entry));
754 type = GPOINTER_TO_INT(
755 gtk_object_get_data (
756 GTK_OBJECT (
757 gtk_menu_get_active (
758 GTK_MENU (gtk_option_menu_get_menu (
759 GTK_OPTION_MENU (
760 line_type_data->line_type))))), "linetype"));
762 /* are there several objects concerned? */
763 if (g_list_next (objects) == NULL) {
764 /* no, there is only one object */
765 OBJECT *o_current = (OBJECT*) objects->data;
766 gint width, length, space;
768 width = atoi (width_str);
769 length = atoi (length_str);
770 space = atoi (space_str);
772 /* apply the new line options to object */
773 o_erase_single (w_current, o_current);
774 o_set_line_options (o_current,
775 o_current->line_end,
776 type,
777 width,
778 length,
779 space);
780 o_redraw_single (w_current, o_current);
782 } else {
783 /* more than one object in the list */
784 GList *object;
785 gint width, length, space;
787 /* get the new line options */
788 width = g_strcasecmp (width_str,
789 _("*unchanged*")) ? atoi (width_str) : -1;
790 length = g_strcasecmp (length_str,
791 _("*unchanged*")) ? atoi (length_str) : -1;
792 space = g_strcasecmp (space_str,
793 _("*unchanged*")) ? atoi (space_str) : -1;
795 /* apply changes to each object */
796 object = objects;
797 while (object != NULL) {
798 OBJECT *o_current = (OBJECT*)object->data;
800 o_erase_single (w_current, o_current);
801 o_set_line_options (o_current,
802 o_current->line_end,
803 type == -1 ? o_current->line_type : type,
804 width == -1 ? o_current->line_width : width,
805 length == -1 ? o_current->line_length : length,
806 space == -1 ? o_current->line_space : space);
807 o_redraw_single (w_current, o_current);
809 object = g_list_next(object);
813 toplevel->page_current->CHANGED = 1;
816 /*! \brief response function for the line type and width dialog
817 * \par Function Description
818 * This function takes the user input and applies it to selected
819 * objects.
820 * After that it kills the dialog.
822 void line_type_dialog_response(GtkWidget *widget, gint response,
823 struct line_type_data *line_type_data)
825 switch (response) {
826 case GTK_RESPONSE_REJECT:
827 case GTK_RESPONSE_DELETE_EVENT:
828 /* void */
829 break;
830 case GTK_RESPONSE_ACCEPT:
831 line_type_dialog_ok(widget, line_type_data);
832 break;
833 default:
834 printf("line_type_dialog_response(): strange signal %d\n",response);
837 i_set_state (line_type_data->w_current, SELECT);
838 i_update_toolbar (line_type_data->w_current);
839 gtk_widget_destroy (line_type_data->dialog);
841 /* get ride of the list of objects but not the objects */
842 g_list_free (line_type_data->objects);
843 g_free (line_type_data);
846 /*! \brief Creates the line type and width dialog
847 * \par Function Description
848 * This function creates and sets up a dialog for manipulating the
849 * line width and the line type setting of objects.
851 void line_type_dialog (GSCHEM_TOPLEVEL *w_current, GList *objects)
853 GtkWidget *dialog;
854 GtkWidget *vbox;
855 GtkWidget *optionmenu = NULL;
856 GtkWidget *length_entry = NULL;
857 GtkWidget *space_entry = NULL;
858 GtkWidget *width_entry = NULL;
859 GtkWidget *table;
860 GtkWidget *label;
861 struct line_type_data *line_type_data;
862 gchar *width_str, *space_str, *length_str;
863 gint type;
865 line_type_data = (struct line_type_data*) g_malloc (
866 sizeof (struct line_type_data));
868 dialog = gschem_dialog_new_with_buttons(_("Edit Line Width & Type"),
869 GTK_WINDOW(w_current->main_window),
870 GTK_DIALOG_MODAL,
871 "line-type", w_current,
872 GTK_STOCK_CANCEL,
873 GTK_RESPONSE_REJECT,
874 GTK_STOCK_OK,
875 GTK_RESPONSE_ACCEPT,
876 NULL);
878 /* Set the alternative button order (ok, cancel, help) for other systems */
879 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
880 GTK_RESPONSE_ACCEPT,
881 GTK_RESPONSE_REJECT,
882 -1);
884 gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
886 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
888 gtk_signal_connect(GTK_OBJECT(dialog), "response",
889 GTK_SIGNAL_FUNC(line_type_dialog_response),
890 line_type_data);
892 gtk_container_border_width(GTK_CONTAINER(dialog),
893 DIALOG_BORDER_SPACING);
894 vbox = GTK_DIALOG(dialog)->vbox;
895 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
897 /* Don't know whether to set the headline or not (Werner) */
898 /* label = gtk_label_new(_("Line Properties:"));
899 gtk_misc_set_alignment(GTK_MISC(label),0,0);
900 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); */
902 table = gtk_table_new (4, 2, FALSE);
903 gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING);
904 gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING);
905 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
907 label = gtk_label_new (_("Width:"));
908 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
909 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0);
911 label = gtk_label_new (_("Type:"));
912 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
913 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2, GTK_FILL,0,0,0);
915 label = gtk_label_new (_("Dash Length:"));
916 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
917 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3, GTK_FILL,0,0,0);
919 label = gtk_label_new (_("Dash Space:"));
920 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
921 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4, GTK_FILL,0,0,0);
923 width_entry = gtk_entry_new();
924 gtk_entry_set_activates_default (GTK_ENTRY(width_entry), TRUE);
925 gtk_editable_select_region(GTK_EDITABLE(width_entry), 0, -1);
926 gtk_table_attach_defaults(GTK_TABLE(table), width_entry,
927 1,2,0,1);
929 optionmenu = gtk_option_menu_new ();
930 gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
931 create_menu_linetype (w_current));
932 gtk_table_attach_defaults(GTK_TABLE(table), optionmenu,
933 1,2,1,2);
935 gtk_signal_connect(GTK_OBJECT (optionmenu), "changed",
936 (GtkSignalFunc) line_type_dialog_linetype_change,
937 line_type_data);
939 length_entry = gtk_entry_new();
940 gtk_entry_set_activates_default (GTK_ENTRY(length_entry), TRUE);
941 gtk_editable_select_region(GTK_EDITABLE(length_entry), 0, -1);
942 gtk_table_attach_defaults(GTK_TABLE(table), length_entry,
943 1,2,2,3);
945 space_entry = gtk_entry_new();
946 gtk_entry_set_activates_default (GTK_ENTRY(space_entry), TRUE);
947 gtk_editable_select_region(GTK_EDITABLE(space_entry), 0, -1);
948 gtk_table_attach_defaults(GTK_TABLE(table), space_entry,
949 1,2,3,4);
951 /* populate the data structure */
952 line_type_data->dialog = dialog;
953 line_type_data->width_entry = width_entry;
954 line_type_data->line_type = optionmenu;
955 line_type_data->length_entry = length_entry;
956 line_type_data->space_entry = space_entry;
958 line_type_data->w_current = w_current;
959 line_type_data->objects = objects;
961 /* fill in the fields of the dialog */
962 if (g_list_next (objects) == NULL) {
963 /* only one object in object list */
964 OBJECT *o_current = (OBJECT*) objects->data;
966 width_str = g_strdup_printf ("%d", o_current->line_width);
967 space_str = g_strdup_printf ("%d", o_current->line_space);
968 length_str = g_strdup_printf ("%d", o_current->line_length);
969 type = o_current->line_type;
970 } else {
971 GtkWidget *menuitem;
972 GtkWidget *menu;
974 width_str = g_strdup_printf (_("*unchanged*"));
975 space_str = g_strdup_printf (_("*unchanged*"));
976 length_str = g_strdup_printf (_("*unchanged*"));
977 type = TYPE_PHANTOM + 1;
979 /* add a new menuitem to option menu for line type */
980 menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (optionmenu));
981 menuitem = gtk_radio_menu_item_new_with_label (
982 gtk_radio_menu_item_get_group (
983 GTK_RADIO_MENU_ITEM (gtk_menu_get_active (GTK_MENU (menu)))),
984 _("*unchanged*"));
985 gtk_menu_append (menu, menuitem);
986 gtk_object_set_data (GTK_OBJECT (menuitem),
987 "linetype",
988 GINT_TO_POINTER (-1));
989 gtk_widget_show (menuitem);
992 gtk_entry_set_text (GTK_ENTRY (width_entry), width_str);
993 gtk_entry_select_region (GTK_ENTRY (width_entry), 0, strlen (width_str));
994 gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), type);
995 gtk_entry_set_text (GTK_ENTRY (space_entry), space_str);
996 gtk_entry_set_text (GTK_ENTRY (length_entry), length_str);
998 /* calling it once will set the dash space/length activity */
999 line_type_dialog_linetype_change(optionmenu, line_type_data);
1001 gtk_widget_grab_focus(width_entry);
1002 gtk_widget_show_all (dialog);
1004 g_free (width_str);
1005 g_free (space_str);
1006 g_free (length_str);
1009 /***************** End of Line Type / Width dialog box ****************/
1011 /***************** Start of Fill Type dialog box **********************/
1013 /*! \brief Create a menu with fill types for the line type dialog
1014 * \par Function Description
1015 * This function creates a GtkMenu with the different fill types.
1017 static GtkWidget *create_menu_filltype (GSCHEM_TOPLEVEL *w_current)
1019 GtkWidget *menu;
1020 GSList *group;
1021 struct fill_type {
1022 gchar *str;
1023 OBJECT_FILLING type;
1024 } types[] = { { N_("Hollow"), FILLING_HOLLOW },
1025 { N_("Filled"), FILLING_FILL },
1026 { N_("Mesh"), FILLING_MESH },
1027 { N_("Hatch"), FILLING_HATCH } };
1028 gint i;
1030 menu = gtk_menu_new ();
1031 group = NULL;
1033 for (i = 0; i < sizeof (types) / sizeof (struct fill_type); i++) {
1034 GtkWidget *menuitem;
1036 menuitem = gtk_radio_menu_item_new_with_label (group, _(types[i].str));
1037 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
1038 gtk_menu_append (GTK_MENU (menu), menuitem);
1039 gtk_object_set_data (GTK_OBJECT(menuitem), "filltype",
1040 GINT_TO_POINTER (types[i].type));
1041 gtk_widget_show (menuitem);
1044 return menu;
1047 /*! \brief Callback function for the filltype menu in the filltype dialog
1048 * \par Function Description
1049 * This function sets the entry activity according to the selected
1050 * filltype of the filltype dialog.
1052 static gint fill_type_dialog_filltype_change(GtkWidget *w, gpointer data)
1054 struct fill_type_data *fill_type_data = (struct fill_type_data*) data;
1055 GtkWidget *menuitem;
1056 gboolean activate_width_entry;
1057 gboolean activate_anglepitch1_entries;
1058 gboolean activate_anglepitch2_entries;
1059 gint type;
1061 menuitem = gtk_menu_get_active (
1062 GTK_MENU (gtk_option_menu_get_menu (
1063 GTK_OPTION_MENU (fill_type_data->fill_type))));
1065 type = GPOINTER_TO_INT(
1066 gtk_object_get_data (GTK_OBJECT (menuitem), "filltype"));
1067 switch(type) {
1068 case(FILLING_HOLLOW):
1069 case(FILLING_FILL):
1070 activate_width_entry = FALSE;
1071 activate_anglepitch1_entries = FALSE;
1072 activate_anglepitch2_entries = FALSE;
1073 break;
1074 case(FILLING_HATCH):
1075 activate_width_entry = TRUE;
1076 activate_anglepitch1_entries = TRUE;
1077 activate_anglepitch2_entries = FALSE;
1078 break;
1079 case(FILLING_MESH):
1080 activate_width_entry = TRUE;
1081 activate_anglepitch1_entries = TRUE;
1082 activate_anglepitch2_entries = TRUE;
1083 break;
1084 default:
1085 activate_width_entry = TRUE;
1086 activate_anglepitch1_entries = TRUE;
1087 activate_anglepitch2_entries = TRUE;
1090 gtk_widget_set_sensitive (fill_type_data->width_entry,
1091 activate_width_entry);
1092 gtk_widget_set_sensitive (fill_type_data->angle1_entry,
1093 activate_anglepitch1_entries);
1094 gtk_widget_set_sensitive (fill_type_data->pitch1_entry,
1095 activate_anglepitch1_entries);
1096 gtk_widget_set_sensitive (fill_type_data->angle2_entry,
1097 activate_anglepitch2_entries);
1098 gtk_widget_set_sensitive (fill_type_data->pitch2_entry,
1099 activate_anglepitch2_entries);
1101 return(0);
1104 /*! \brief Apply the settings of the filltype dialog to the selection
1105 * \par Function Description
1106 * This function applies the settings of the filltype dialog to the
1107 * selected objects
1109 static void fill_type_dialog_ok(GtkWidget *w, gpointer data)
1111 struct fill_type_data *fill_type_data = (struct fill_type_data*)data;
1112 GSCHEM_TOPLEVEL *w_current = fill_type_data->w_current;
1113 TOPLEVEL *toplevel = w_current->toplevel;
1114 GList *objects;
1115 const gchar *width_str, *angle1_str, *pitch1_str, *angle2_str, *pitch2_str;
1116 OBJECT_FILLING type;
1118 /* retrieve the list of objects */
1119 objects = fill_type_data->objects;
1121 /* get the new values from the text entries of the dialog */
1122 width_str = gtk_entry_get_text (GTK_ENTRY (
1123 fill_type_data->width_entry));
1124 angle1_str = gtk_entry_get_text (GTK_ENTRY (
1125 fill_type_data->angle1_entry));
1126 pitch1_str = gtk_entry_get_text (GTK_ENTRY (
1127 fill_type_data->pitch1_entry));
1128 angle2_str = gtk_entry_get_text (GTK_ENTRY (
1129 fill_type_data->angle2_entry));
1130 pitch2_str = gtk_entry_get_text (GTK_ENTRY (
1131 fill_type_data->pitch2_entry));
1132 type = GPOINTER_TO_INT(
1133 gtk_object_get_data (
1134 GTK_OBJECT (
1135 gtk_menu_get_active (
1136 GTK_MENU (gtk_option_menu_get_menu (
1137 GTK_OPTION_MENU (
1138 fill_type_data->fill_type))))), "filltype"));
1140 /* are there several objects concerned? */
1141 if (g_list_next (objects) == NULL) {
1142 /* no, there is only one object */
1143 OBJECT *o_current = (OBJECT*) objects->data;
1144 gint width, angle1, pitch1, angle2, pitch2;
1146 width = atoi (width_str);
1147 angle1 = atoi (angle1_str);
1148 pitch1 = atoi (pitch1_str);
1149 angle2 = atoi (angle2_str);
1150 pitch2 = atoi (pitch2_str);
1152 /* apply the new line options to object */
1153 o_erase_single (w_current, o_current);
1154 o_set_fill_options(o_current,
1155 type, width,
1156 pitch1, angle1,
1157 pitch2, angle2);
1158 o_redraw_single (w_current, o_current);
1160 } else {
1161 /* more than one object in the list */
1162 GList *object;
1163 gint width, angle1, pitch1, angle2, pitch2;
1165 /* get the new line options */
1166 width = g_strcasecmp (width_str,
1167 _("*unchanged*")) ? atoi (width_str) : -1;
1168 angle1 = g_strcasecmp (angle1_str,
1169 _("*unchanged*")) ? atoi (angle1_str) : -1;
1170 pitch1 = g_strcasecmp (pitch1_str,
1171 _("*unchanged*")) ? atoi (pitch1_str) : -1;
1172 angle2 = g_strcasecmp (angle2_str,
1173 _("*unchanged*")) ? atoi (angle2_str) : -1;
1174 pitch2 = g_strcasecmp (pitch2_str,
1175 _("*unchanged*")) ? atoi (pitch2_str) : -1;
1177 /* apply changes to each object */
1178 object = objects;
1179 while (object != NULL) {
1180 OBJECT *o_current = (OBJECT*)object->data;
1182 o_erase_single (w_current, o_current);
1183 o_set_fill_options (o_current,
1184 type == -1 ? o_current->fill_type : type,
1185 width == -1 ? o_current->fill_width : width,
1186 pitch1 == -1 ? o_current->fill_pitch1 : pitch1,
1187 angle1 == -1 ? o_current->fill_angle1 : angle1,
1188 pitch2 == -1 ? o_current->fill_pitch2 : pitch2,
1189 angle2 == -1 ? o_current->fill_angle2 : angle2);
1190 o_redraw_single (w_current, o_current);
1192 object = g_list_next(object);
1195 toplevel->page_current->CHANGED = 1;
1198 /*! \brief response function for the filltype dialog
1199 * \par Function Description
1200 * This function handles the user response to the filltype dialog.
1201 * It destroys the dialog after that.
1203 void fill_type_dialog_response(GtkWidget *widget, gint response,
1204 struct fill_type_data *fill_type_data)
1206 switch (response) {
1207 case GTK_RESPONSE_REJECT:
1208 case GTK_RESPONSE_DELETE_EVENT:
1209 /* void */
1210 break;
1211 case GTK_RESPONSE_ACCEPT:
1212 fill_type_dialog_ok(widget, fill_type_data);
1213 break;
1214 default:
1215 printf("line_type_dialog_response(): strange signal %d\n",response);
1218 i_set_state (fill_type_data->w_current, SELECT);
1219 i_update_toolbar (fill_type_data->w_current);
1221 gtk_grab_remove (fill_type_data->dialog);
1222 gtk_widget_destroy (fill_type_data->dialog);
1224 /* get ride of the list of objects but not the objects */
1225 g_list_free (fill_type_data->objects);
1226 g_free (fill_type_data);
1229 /*! \brief Creates the fill type dialog
1230 * \par Function Description
1231 * This function creates the fill type dialog. It operates on a list
1232 * of objects.
1234 void fill_type_dialog(GSCHEM_TOPLEVEL *w_current, GList *objects)
1236 GtkWidget *dialog;
1237 GtkWidget *vbox;
1238 GtkWidget *optionmenu = NULL;
1239 GtkWidget *width_entry = NULL;
1240 GtkWidget *angle1_entry = NULL;
1241 GtkWidget *pitch1_entry = NULL;
1242 GtkWidget *angle2_entry = NULL;
1243 GtkWidget *pitch2_entry = NULL;
1244 GtkWidget *label;
1245 GtkWidget *table;
1246 struct fill_type_data *fill_type_data;
1247 gchar *width_str, *angle1_str, *pitch1_str, *angle2_str, *pitch2_str;
1248 gint type;
1250 fill_type_data = (struct fill_type_data*) g_malloc (
1251 sizeof (struct fill_type_data));
1253 dialog = gschem_dialog_new_with_buttons(_("Edit Fill Type"),
1254 GTK_WINDOW(w_current->main_window),
1255 GTK_DIALOG_MODAL,
1256 "fill-type", w_current,
1257 GTK_STOCK_CANCEL,
1258 GTK_RESPONSE_REJECT,
1259 GTK_STOCK_OK,
1260 GTK_RESPONSE_ACCEPT,
1261 NULL);
1263 /* Set the alternative button order (ok, cancel, help) for other systems */
1264 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
1265 GTK_RESPONSE_ACCEPT,
1266 GTK_RESPONSE_REJECT,
1267 -1);
1269 gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
1271 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
1272 GTK_RESPONSE_ACCEPT);
1274 gtk_signal_connect(GTK_OBJECT(dialog), "response",
1275 GTK_SIGNAL_FUNC(fill_type_dialog_response), fill_type_data);
1277 gtk_container_border_width(GTK_CONTAINER(dialog), DIALOG_BORDER_SPACING);
1278 vbox = GTK_DIALOG(dialog)->vbox;
1279 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1281 /* Don't know whether to use the headline or not (Werner) */
1282 /* label = gtk_label_new(_("Fill Properties:"));
1283 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1284 gtk_box_pack_start(GTK_BOX(vbox),label, FALSE, FALSE, 0); */
1286 table = gtk_table_new (6, 2, FALSE);
1287 gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING);
1288 gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING);
1289 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
1291 label = gtk_label_new (_("Fill Type:"));
1292 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1293 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0);
1295 label = gtk_label_new (_("Line Width:"));
1296 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1297 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2, GTK_FILL,0,0,0);
1299 label = gtk_label_new (_("Angle 1:"));
1300 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1301 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3, GTK_FILL,0,0,0);
1303 label = gtk_label_new (_("Pitch 1:"));
1304 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1305 gtk_table_attach(GTK_TABLE(table), label, 0,1,3,4, GTK_FILL,0,0,0);
1307 label = gtk_label_new (_("Angle 2:"));
1308 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1309 gtk_table_attach(GTK_TABLE(table), label, 0,1,4,5, GTK_FILL,0,0,0);
1311 label = gtk_label_new (_("Pitch 2:"));
1312 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1313 gtk_table_attach(GTK_TABLE(table), label, 0,1,5,6, GTK_FILL,0,0,0);
1316 optionmenu = gtk_option_menu_new ();
1317 gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
1318 create_menu_filltype (w_current));
1319 gtk_table_attach_defaults(GTK_TABLE(table), optionmenu,
1320 1,2,0,1);
1322 gtk_signal_connect(GTK_OBJECT (optionmenu), "changed",
1323 (GtkSignalFunc) fill_type_dialog_filltype_change,
1324 fill_type_data);
1326 width_entry = gtk_entry_new();
1327 gtk_entry_set_activates_default (GTK_ENTRY(width_entry), TRUE);
1328 gtk_table_attach_defaults(GTK_TABLE(table), width_entry,
1329 1,2,1,2);
1331 angle1_entry = gtk_entry_new ();
1332 gtk_entry_set_activates_default (GTK_ENTRY(angle1_entry), TRUE);
1333 gtk_table_attach_defaults(GTK_TABLE(table), angle1_entry,
1334 1,2,2,3);
1336 pitch1_entry = gtk_entry_new ();
1337 gtk_entry_set_activates_default (GTK_ENTRY(pitch1_entry), TRUE);
1338 gtk_table_attach_defaults(GTK_TABLE(table), pitch1_entry,
1339 1,2,3,4);
1341 angle2_entry = gtk_entry_new ();
1342 gtk_entry_set_activates_default (GTK_ENTRY(angle2_entry), TRUE);
1343 gtk_table_attach_defaults(GTK_TABLE(table), angle2_entry,
1344 1,2,4,5);
1346 pitch2_entry = gtk_entry_new ();
1347 gtk_entry_set_activates_default (GTK_ENTRY(pitch2_entry), TRUE);
1348 gtk_table_attach_defaults(GTK_TABLE(table), pitch2_entry,
1349 1,2,5,6);
1351 /* populate the data structure */
1352 fill_type_data->dialog = dialog;
1353 fill_type_data->fill_type = optionmenu;
1354 fill_type_data->width_entry = width_entry;
1355 fill_type_data->angle1_entry = angle1_entry;
1356 fill_type_data->pitch1_entry = pitch1_entry;
1357 fill_type_data->angle2_entry = angle2_entry;
1358 fill_type_data->pitch2_entry = pitch2_entry;
1360 fill_type_data->w_current = w_current;
1361 fill_type_data->objects = objects;
1363 /* fill in the fields of the dialog */
1364 if (g_list_next (objects) == NULL) {
1365 /* only one object in object list */
1366 OBJECT *o_current = (OBJECT*) objects->data;
1368 type = o_current->fill_type;
1369 width_str = g_strdup_printf ("%d", o_current->fill_width);
1370 angle1_str = g_strdup_printf ("%d", o_current->fill_angle1);
1371 pitch1_str = g_strdup_printf ("%d", o_current->fill_pitch1);
1372 angle2_str = g_strdup_printf ("%d", o_current->fill_angle2);
1373 pitch2_str = g_strdup_printf ("%d", o_current->fill_pitch2);
1374 } else {
1375 GtkWidget *menuitem;
1376 GtkWidget *menu;
1378 width_str = g_strdup_printf (_("*unchanged*"));
1379 angle1_str = g_strdup_printf (_("*unchanged*"));
1380 pitch1_str = g_strdup_printf (_("*unchanged*"));
1381 angle2_str = g_strdup_printf (_("*unchanged*"));
1382 pitch2_str = g_strdup_printf (_("*unchanged*"));
1383 type = FILLING_HATCH + 1;
1385 /* add a new menuitem to option menu for line type */
1386 menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (optionmenu));
1387 menuitem = gtk_radio_menu_item_new_with_label (
1388 gtk_radio_menu_item_get_group (
1389 GTK_RADIO_MENU_ITEM (gtk_menu_get_active (GTK_MENU (menu)))),
1390 _("*unchanged*"));
1391 gtk_menu_append (menu, menuitem);
1392 gtk_object_set_data (GTK_OBJECT (menuitem),
1393 "filltype",
1394 GINT_TO_POINTER (-1));
1395 gtk_widget_show (menuitem);
1398 gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), type);
1399 gtk_entry_set_text (GTK_ENTRY (width_entry), width_str);
1400 gtk_entry_select_region (GTK_ENTRY (width_entry), 0, strlen (width_str));
1401 gtk_entry_set_text (GTK_ENTRY (angle1_entry), angle1_str);
1402 gtk_entry_select_region (GTK_ENTRY (angle1_entry), 0, strlen (angle1_str));
1403 gtk_entry_set_text (GTK_ENTRY (pitch1_entry), pitch1_str);
1404 gtk_entry_select_region (GTK_ENTRY (pitch1_entry), 0, strlen (pitch1_str));
1405 gtk_entry_set_text (GTK_ENTRY (angle2_entry), angle2_str);
1406 gtk_entry_select_region (GTK_ENTRY (angle2_entry), 0, strlen (angle2_str));
1407 gtk_entry_set_text (GTK_ENTRY (pitch2_entry), pitch2_str);
1408 gtk_entry_select_region (GTK_ENTRY (pitch2_entry), 0, strlen (pitch2_str));
1410 /* Set the widget activity according to the current filltype */
1411 fill_type_dialog_filltype_change(optionmenu, fill_type_data);
1413 gtk_widget_grab_focus(width_entry);
1414 gtk_widget_show_all (dialog);
1416 g_free (width_str);
1417 g_free (angle1_str);
1418 g_free (pitch1_str);
1419 g_free (angle2_str);
1420 g_free (pitch2_str);
1423 /***************** End of Fill Type dialog box ***********************/
1425 /***************** Start of Arc dialog box ***************************/
1427 /*! \brief response function for the arc angle dialog
1428 * \par Function Description
1429 * The response function of th arc angle dialog takes the content of
1430 * the dialog and applies it on the current arc.
1431 * If the dialog is closed or canceled the function destroys the dialog.
1433 void arc_angle_dialog_response(GtkWidget *w, gint response,
1434 GSCHEM_TOPLEVEL *w_current)
1436 GtkWidget *spinentry;
1437 gint radius, start_angle, sweep_angle;
1438 OBJECT *arc_object = NULL;
1440 switch (response) {
1441 case GTK_RESPONSE_REJECT:
1442 case GTK_RESPONSE_DELETE_EVENT:
1443 /* void */
1444 break;
1445 case GTK_RESPONSE_ACCEPT:
1446 spinentry = g_object_get_data(G_OBJECT(w_current->aawindow),"radius");
1447 radius = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spinentry));
1448 spinentry = g_object_get_data(G_OBJECT(w_current->aawindow),"spin_start");
1449 start_angle = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spinentry));
1450 spinentry = g_object_get_data(G_OBJECT(w_current->aawindow),"spin_sweep");
1451 sweep_angle = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spinentry));
1452 arc_object = (OBJECT*) g_object_get_data(G_OBJECT(w_current->aawindow),"arc_object");
1454 o_erase_selected(w_current);
1455 o_arc_set_radius(arc_object, radius);
1456 o_arc_set_start_angle(arc_object, start_angle);
1457 o_arc_set_end_angle(arc_object, sweep_angle);
1458 o_draw_selected(w_current);
1459 break;
1460 default:
1461 printf("arc_angle_dialog_response(): strange signal %d\n",response);
1464 gtk_widget_destroy(w_current->aawindow);
1465 w_current->aawindow = NULL;
1468 /*! \brief Creates the arc angle dialog
1469 * \par Function Description
1470 * This function creates the arc angle dialog. Depending on the
1471 * \a arc_object the entries are filled with the arc OBJECT properties
1472 * or with some standard values.
1474 * \param [in] w_current The GSCHEM_TOPLEVEL object
1475 * \param [in] arc_object an arc OBJECT if used to modify an arc
1476 * or NULL to create a new arc.
1478 void arc_angle_dialog (GSCHEM_TOPLEVEL *w_current, OBJECT *arc_object)
1480 GtkWidget *label = NULL;
1481 GtkWidget *vbox;
1482 GtkWidget *alignment, *table;
1483 GtkWidget *radius, *spin_start, *spin_sweep;
1485 if (!w_current->aawindow) {
1486 w_current->aawindow = gschem_dialog_new_with_buttons(_("Arc Params"),
1487 GTK_WINDOW(w_current->main_window),
1488 GTK_DIALOG_MODAL,
1489 "arc-angle", w_current,
1490 GTK_STOCK_CANCEL,
1491 GTK_RESPONSE_REJECT,
1492 GTK_STOCK_OK,
1493 GTK_RESPONSE_ACCEPT,
1494 NULL);
1496 /* Set the alternative button order (ok, cancel, help) for other systems */
1497 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->aawindow),
1498 GTK_RESPONSE_ACCEPT,
1499 GTK_RESPONSE_REJECT,
1500 -1);
1502 gtk_window_position(GTK_WINDOW(w_current->aawindow),
1503 GTK_WIN_POS_MOUSE);
1505 gtk_signal_connect(GTK_OBJECT(w_current->aawindow), "response",
1506 GTK_SIGNAL_FUNC(arc_angle_dialog_response), w_current);
1508 gtk_dialog_set_default_response(GTK_DIALOG(w_current->aawindow),
1509 GTK_RESPONSE_ACCEPT);
1511 gtk_container_border_width(GTK_CONTAINER(w_current->aawindow), DIALOG_BORDER_SPACING);
1512 vbox = GTK_DIALOG(w_current->aawindow)->vbox;
1513 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1516 alignment = gtk_alignment_new(0,0,1,1);
1517 gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0,
1518 0 /*DIALOG_INDENTATION */, 0);
1519 gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
1521 table = gtk_table_new (2, 3, FALSE);
1522 gtk_table_set_row_spacings(GTK_TABLE(table), DIALOG_V_SPACING);
1523 gtk_table_set_col_spacings(GTK_TABLE(table), DIALOG_H_SPACING);
1524 gtk_container_add(GTK_CONTAINER(alignment), table);
1526 label = gtk_label_new (_("Arc Radius:"));
1527 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1528 gtk_table_attach(GTK_TABLE(table), label, 0,1,0,1, GTK_FILL,0,0,0);
1530 radius = gtk_spin_button_new_with_range(1, 100000, 100);
1531 gtk_entry_set_activates_default(GTK_ENTRY(radius), TRUE);
1532 gtk_table_attach_defaults(GTK_TABLE(table), radius, 1,2,0,1);
1534 label = gtk_label_new (_("Start Angle:"));
1535 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1536 gtk_table_attach(GTK_TABLE(table), label, 0,1,1,2, GTK_FILL,0,0,0);
1538 spin_start = gtk_spin_button_new_with_range(-360,360,1);
1539 gtk_entry_set_activates_default(GTK_ENTRY(spin_start), TRUE);
1540 gtk_table_attach_defaults(GTK_TABLE(table), spin_start, 1,2,1,2);
1542 label = gtk_label_new(_("Degrees of Sweep:"));
1543 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
1544 gtk_table_attach(GTK_TABLE(table), label, 0,1,2,3, GTK_FILL,0,0,0);
1546 spin_sweep = gtk_spin_button_new_with_range(-360,360,1);
1547 gtk_entry_set_activates_default(GTK_ENTRY(spin_sweep), TRUE);
1548 gtk_table_attach_defaults(GTK_TABLE(table), spin_sweep, 1,2,2,3);
1550 GLADE_HOOKUP_OBJECT(w_current->aawindow, radius, "radius");
1551 GLADE_HOOKUP_OBJECT(w_current->aawindow, spin_start,"spin_start");
1552 GLADE_HOOKUP_OBJECT(w_current->aawindow, spin_sweep,"spin_sweep");
1553 g_object_set_data(G_OBJECT(w_current->aawindow), "arc_object", arc_object);
1554 gtk_widget_show_all (w_current->aawindow);
1557 else { /* dialog already created */
1558 gtk_window_present (GTK_WINDOW(w_current->aawindow));
1559 radius = g_object_get_data(G_OBJECT(w_current->aawindow),"radius");
1560 spin_start = g_object_get_data(G_OBJECT(w_current->aawindow),"spin_start");
1561 spin_sweep = g_object_get_data(G_OBJECT(w_current->aawindow),"spin_sweep");
1564 if (arc_object == NULL) {
1565 gtk_spin_button_set_value(GTK_SPIN_BUTTON(radius), w_current->distance);
1566 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_start),0);
1567 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_sweep), 90);
1568 } else {
1569 gtk_spin_button_set_value(GTK_SPIN_BUTTON(radius),
1570 o_arc_get_radius(arc_object));
1571 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_start),
1572 o_arc_get_start_angle(arc_object));
1573 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_sweep),
1574 o_arc_get_end_angle(arc_object));
1577 gtk_widget_grab_focus(radius);
1580 /***************** End of Arc dialog box *****************************/
1582 /***************** Start of Translate dialog box *********************/
1584 /*! \brief response function for the translate dialog
1585 * \par Function Description
1586 * This function takes the user action and applies it.
1587 * \todo improve error detection / use a spin button?
1589 void translate_dialog_response(GtkWidget *widget, gint response,
1590 GSCHEM_TOPLEVEL *w_current)
1592 GtkWidget *textentry;
1593 gchar *string;
1595 switch (response) {
1596 case GTK_RESPONSE_REJECT:
1597 case GTK_RESPONSE_DELETE_EVENT:
1598 /* void */
1599 break;
1600 case GTK_RESPONSE_ACCEPT:
1601 textentry = g_object_get_data(G_OBJECT(w_current->trwindow),"textentry");
1602 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
1603 if (strlen(string) != 0) {
1604 o_complex_translate_all(w_current, atoi(string));
1606 break;
1607 default:
1608 printf("translate_edit_dialog_response(): strange signal %d\n",response);
1611 i_set_state(w_current, SELECT);
1612 i_update_toolbar(w_current);
1613 gtk_widget_destroy(w_current->trwindow);
1614 w_current->trwindow=NULL;
1618 /*! \brief Create the translate dialog
1619 * \par Function Description
1620 * Create the dialog to translate symbols.
1622 void translate_dialog (GSCHEM_TOPLEVEL *w_current)
1624 GtkWidget *label;
1625 GtkWidget *textentry;
1626 GtkWidget *vbox;
1628 if (!w_current->trwindow) {
1629 w_current->trwindow = gschem_dialog_new_with_buttons(_("Translate"),
1630 GTK_WINDOW(w_current->main_window),
1631 GTK_DIALOG_MODAL,
1632 "translate", w_current,
1633 GTK_STOCK_CANCEL,
1634 GTK_RESPONSE_REJECT,
1635 GTK_STOCK_OK,
1636 GTK_RESPONSE_ACCEPT,
1637 NULL);
1639 /* Set the alternative button order (ok, cancel, help) for other systems */
1640 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->trwindow),
1641 GTK_RESPONSE_ACCEPT,
1642 GTK_RESPONSE_REJECT,
1643 -1);
1645 gtk_window_position(GTK_WINDOW (w_current->trwindow),
1646 GTK_WIN_POS_MOUSE);
1648 gtk_signal_connect(GTK_OBJECT (w_current->trwindow), "response",
1649 GTK_SIGNAL_FUNC(translate_dialog_response), w_current);
1651 gtk_dialog_set_default_response(GTK_DIALOG(w_current->trwindow),
1652 GTK_RESPONSE_ACCEPT);
1654 gtk_container_border_width(GTK_CONTAINER(w_current->trwindow),
1655 DIALOG_BORDER_SPACING);
1656 vbox = GTK_DIALOG(w_current->trwindow)->vbox;
1657 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1659 label = gtk_label_new(_("Offset to translate?\n(0 for origin)"));
1660 gtk_misc_set_alignment(GTK_MISC (label), 0, 0);
1661 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1663 textentry = gtk_entry_new_with_max_length (10);
1664 gtk_entry_set_text(GTK_ENTRY(textentry), "0");
1665 gtk_editable_select_region(GTK_EDITABLE(textentry), 0, -1);
1666 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
1667 gtk_box_pack_start(GTK_BOX(vbox),textentry, FALSE, FALSE, 0);
1669 GLADE_HOOKUP_OBJECT(w_current->trwindow, textentry, "textentry");
1670 gtk_widget_show_all (w_current->trwindow);
1673 else { /* dialog already created */
1674 gtk_window_present(GTK_WINDOW(w_current->trwindow));
1678 /***************** End of Translate dialog box ***********************/
1680 /***************** Start of Text size dialog box *********************/
1682 /*! \brief response function for the text size dialog
1683 * \par Function Description
1684 * This function takes the user input and applies it to gschem
1686 void text_size_dialog_response(GtkWidget *w, gint response,
1687 GSCHEM_TOPLEVEL *w_current)
1689 GtkWidget *spin_size;
1690 gint size;
1692 switch (response) {
1693 case GTK_RESPONSE_ACCEPT:
1694 spin_size = g_object_get_data(G_OBJECT(w_current->tswindow),"spin_size");
1695 size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_size));
1697 w_current->text_size = size;
1698 w_current->toplevel->page_current->CHANGED=1;
1699 o_undo_savestate(w_current, UNDO_ALL);
1700 break;
1701 case GTK_RESPONSE_REJECT:
1702 case GTK_RESPONSE_DELETE_EVENT:
1703 /* void */
1704 break;
1705 default:
1706 printf("text_size_dialog_response(): strange signal %d\n",response);
1709 /* clean up */
1710 i_set_state(w_current, SELECT);
1711 i_update_toolbar(w_current);
1712 gtk_widget_destroy(w_current->tswindow);
1713 w_current->tswindow = NULL;
1716 /*! \brief Create the text size dialog
1717 * \par Function Description
1718 * This function creates the text size dialog.
1720 void text_size_dialog (GSCHEM_TOPLEVEL *w_current)
1722 GtkWidget *label = NULL;
1723 GtkWidget *vbox;
1724 GtkWidget *spin_size;
1726 if (!w_current->tswindow) {
1727 w_current->tswindow = gschem_dialog_new_with_buttons(_("Text Size"),
1728 GTK_WINDOW(w_current->main_window),
1729 GTK_DIALOG_MODAL,
1730 "text-size", w_current,
1731 GTK_STOCK_CANCEL,
1732 GTK_RESPONSE_REJECT,
1733 GTK_STOCK_OK,
1734 GTK_RESPONSE_ACCEPT,
1735 NULL);
1737 /* Set the alternative button order (ok, cancel, help) for other systems */
1738 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tswindow),
1739 GTK_RESPONSE_ACCEPT,
1740 GTK_RESPONSE_REJECT,
1741 -1);
1743 gtk_window_position(GTK_WINDOW(w_current->tswindow),
1744 GTK_WIN_POS_MOUSE);
1746 gtk_signal_connect(GTK_OBJECT(w_current->tswindow), "response",
1747 GTK_SIGNAL_FUNC(text_size_dialog_response),
1748 w_current);
1749 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tswindow),
1750 GTK_RESPONSE_ACCEPT);
1752 gtk_container_border_width(GTK_CONTAINER(w_current->tswindow),
1753 DIALOG_BORDER_SPACING);
1754 vbox = GTK_DIALOG(w_current->tswindow)->vbox;
1755 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1757 label = gtk_label_new (_("Enter new text size:"));
1758 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1759 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1761 spin_size = gtk_spin_button_new_with_range(2,10000,2);
1762 gtk_editable_select_region( GTK_EDITABLE(spin_size), 0, -1);
1763 gtk_box_pack_start(GTK_BOX(vbox), spin_size, FALSE, FALSE, 0);
1764 gtk_entry_set_activates_default(GTK_ENTRY(spin_size), TRUE);
1765 gtk_widget_grab_focus(spin_size);
1767 GLADE_HOOKUP_OBJECT(w_current->tswindow, spin_size, "spin_size");
1768 gtk_widget_show_all(w_current->tswindow);
1771 else { /* dialog already created */
1772 gtk_window_present(GTK_WINDOW(w_current->tswindow));
1775 /* always set the current text size to the dialog */
1776 spin_size = g_object_get_data(G_OBJECT(w_current->tswindow),"spin_size");
1777 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_size), w_current->text_size);
1778 gtk_editable_select_region(GTK_EDITABLE(spin_size), 0, -1);
1781 /***************** End of Text size dialog box ***********************/
1783 /***************** Start of Snap size dialog box *********************/
1785 /*! \brief response function for the snap size dialog
1786 * \par Function Description
1787 * This is the response function for the snap size dialog.
1788 * It sets the given snap size to gschem.
1790 void snap_size_dialog_response(GtkWidget *w, gint response,
1791 GSCHEM_TOPLEVEL *w_current)
1793 GtkWidget *spin_size;
1794 gint size;
1796 switch (response) {
1797 case GTK_RESPONSE_ACCEPT:
1798 spin_size = g_object_get_data(G_OBJECT(w_current->tswindow),"spin_size");
1799 size = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_size));
1801 w_current->toplevel->snap_size = size;
1802 o_redraw_all(w_current);
1803 w_current->toplevel->page_current->CHANGED=1; /* maybe remove those two lines */
1804 o_undo_savestate(w_current, UNDO_ALL);
1805 break;
1806 case GTK_RESPONSE_REJECT:
1807 case GTK_RESPONSE_DELETE_EVENT:
1808 /* void */
1809 break;
1810 default:
1811 printf("snap_size_dialog_response(): strange signal %d\n",response);
1814 /* clean up */
1815 i_set_state(w_current, SELECT);
1816 i_update_toolbar(w_current);
1817 gtk_widget_destroy(w_current->tswindow);
1818 w_current->tswindow = NULL;
1821 /*! \brief Create the snap size dialog
1822 * \par Function Description
1823 * This function creates the snap size dialog.
1825 void snap_size_dialog (GSCHEM_TOPLEVEL *w_current)
1827 GtkWidget *label = NULL;
1828 GtkWidget *vbox;
1829 GtkWidget *spin_size;
1831 if (!w_current->tswindow) {
1832 w_current->tswindow = gschem_dialog_new_with_buttons(_("Snap Size"),
1833 GTK_WINDOW(w_current->main_window),
1834 GTK_DIALOG_MODAL,
1835 "snap-size", w_current,
1836 GTK_STOCK_CANCEL,
1837 GTK_RESPONSE_REJECT,
1838 GTK_STOCK_OK,
1839 GTK_RESPONSE_ACCEPT,
1840 NULL);
1842 /* Set the alternative button order (ok, cancel, help) for other systems */
1843 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tswindow),
1844 GTK_RESPONSE_ACCEPT,
1845 GTK_RESPONSE_REJECT,
1846 -1);
1848 gtk_window_position(GTK_WINDOW(w_current->tswindow),
1849 GTK_WIN_POS_MOUSE);
1851 gtk_signal_connect(GTK_OBJECT(w_current->tswindow), "response",
1852 GTK_SIGNAL_FUNC(snap_size_dialog_response),
1853 w_current);
1854 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tswindow),
1855 GTK_RESPONSE_ACCEPT);
1857 gtk_container_border_width(GTK_CONTAINER(w_current->tswindow),
1858 DIALOG_BORDER_SPACING);
1859 vbox = GTK_DIALOG(w_current->tswindow)->vbox;
1860 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1862 label = gtk_label_new (_("Enter new snap grid spacing:"));
1863 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1864 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
1866 spin_size = gtk_spin_button_new_with_range(0,100000,5);
1867 gtk_editable_select_region( GTK_EDITABLE(spin_size), 0, -1);
1868 gtk_box_pack_start(GTK_BOX(vbox), spin_size, FALSE, FALSE, 0);
1869 gtk_entry_set_activates_default(GTK_ENTRY(spin_size), TRUE);
1870 gtk_widget_grab_focus(spin_size);
1872 GLADE_HOOKUP_OBJECT(w_current->tswindow, spin_size, "spin_size");
1873 gtk_widget_show_all(w_current->tswindow);
1876 else { /* dialog already there */
1877 gtk_window_present(GTK_WINDOW(w_current->tswindow));
1880 /* always set the current gschem value to the dialog entry */
1881 spin_size = g_object_get_data(G_OBJECT(w_current->tswindow),"spin_size");
1882 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_size), w_current->toplevel->snap_size);
1883 gtk_editable_select_region(GTK_EDITABLE(spin_size), 0, -1);
1886 /***************** End of Snap size dialog box ***********************/
1888 /***************** Start of slot edit dialog box *********************/
1890 /*! \brief response function for the slot edit dialog
1891 * \par Function Description
1892 * The function takes the dialog entry and applies the new slot to the
1893 * symbol.
1895 void slot_edit_dialog_response(GtkWidget *widget, gint response, GSCHEM_TOPLEVEL *w_current)
1897 GtkWidget *textentry;
1898 int len;
1899 gchar *string = NULL;
1901 switch (response) {
1902 case GTK_RESPONSE_REJECT:
1903 case GTK_RESPONSE_DELETE_EVENT:
1904 /* void */
1905 break;
1906 case GTK_RESPONSE_ACCEPT:
1907 textentry = g_object_get_data(G_OBJECT(w_current->sewindow),"textentry");
1908 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
1909 len = strlen(string);
1910 if (len != 0) {
1911 o_slot_end(w_current, string, len);
1913 break;
1914 default:
1915 printf("slot_edit_dialog_response(): strange signal %d\n",response);
1917 i_set_state(w_current, SELECT);
1918 i_update_toolbar(w_current);
1919 gtk_widget_destroy(w_current->sewindow);
1920 w_current->sewindow = NULL;
1924 /*! \brief Create the slot entry dialog
1925 * \par Function Description
1926 * This function creates the slot edit dialog.
1928 void slot_edit_dialog (GSCHEM_TOPLEVEL *w_current, const char *string)
1930 GtkWidget *label = NULL;
1931 GtkWidget *textentry;
1932 GtkWidget *vbox;
1934 if (!w_current->sewindow) {
1935 w_current->sewindow = gschem_dialog_new_with_buttons(_("Edit slot number"),
1936 GTK_WINDOW(w_current->main_window),
1937 GTK_DIALOG_MODAL,
1938 "slot-edit", w_current,
1939 GTK_STOCK_CANCEL,
1940 GTK_RESPONSE_REJECT,
1941 GTK_STOCK_OK,
1942 GTK_RESPONSE_ACCEPT,
1943 NULL);
1945 /* Set the alternative button order (ok, cancel, help) for other systems */
1946 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->sewindow),
1947 GTK_RESPONSE_ACCEPT,
1948 GTK_RESPONSE_REJECT,
1949 -1);
1951 gtk_window_position(GTK_WINDOW(w_current->sewindow),
1952 GTK_WIN_POS_MOUSE);
1954 gtk_dialog_set_default_response (GTK_DIALOG (w_current->sewindow),
1955 GTK_RESPONSE_ACCEPT);
1957 gtk_signal_connect(GTK_OBJECT(w_current->sewindow), "response",
1958 GTK_SIGNAL_FUNC(slot_edit_dialog_response),
1959 w_current);
1961 gtk_container_border_width(GTK_CONTAINER(w_current->sewindow),
1962 DIALOG_BORDER_SPACING);
1963 vbox = GTK_DIALOG(w_current->sewindow)->vbox;
1964 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
1966 label = gtk_label_new (_("Edit slot number:"));
1967 gtk_misc_set_alignment(GTK_MISC(label),0,0);
1968 gtk_box_pack_start(GTK_BOX (vbox), label, FALSE, FALSE, 0);
1970 textentry = gtk_entry_new();
1971 gtk_box_pack_start( GTK_BOX(vbox),
1972 textentry, FALSE, FALSE, 0);
1973 gtk_entry_set_max_length(GTK_ENTRY(textentry), 80);
1974 gtk_entry_set_activates_default (GTK_ENTRY(textentry),TRUE);
1976 GLADE_HOOKUP_OBJECT(w_current->sewindow, textentry, "textentry");
1977 gtk_widget_show_all (w_current->sewindow);
1980 else { /* dialog already created */
1981 gtk_window_present (GTK_WINDOW(w_current->sewindow));
1984 /* always set the current text and select the number of the slot */
1985 if (string != NULL) {
1986 textentry = g_object_get_data(G_OBJECT(w_current->sewindow),"textentry");
1987 gtk_entry_set_text(GTK_ENTRY(textentry), string);
1988 gtk_entry_select_region(GTK_ENTRY(textentry),
1989 strlen("slot="), strlen(string));
1993 /***************** End of Slot Edit dialog box ***********************/
1995 /***************** Start of slot chooser dialog box ******************/
1997 /* Remember to add column types to gtk_tree_store_new() when adding columns. */
1998 enum slot_chooser_columns {
1999 SLOT_CHOOSER_FRIENDLY_NAME,
2000 SLOT_CHOOSER_TARGET,
2001 SLOT_CHOOSER_IS_SPECIFIC,
2002 SLOT_CHOOSER_IS_CURRENT,
2003 SLOT_CHOOSER_IS_AVAILABLE,
2004 SLOT_CHOOSER_IS_OCCUPIED,
2005 SLOT_CHOOSER_IS_COMPATIBLE,
2006 SLOT_CHOOSER_IS_ALLOWED,
2007 SLOT_CHOOSER_N_COLUMNS
2010 struct slot_chooser {
2011 TOPLEVEL *w_current;
2012 OBJECT *o_selected; /* The object we're editing. */
2013 SCM scheme_tree;
2014 GtkWindow *scwindow;
2015 GtkToggleButton *hijack_button;
2016 GtkToggleButton *compatible_button;
2017 GtkToggleButton *remove_button;
2018 GtkTreeView *treeview;
2021 struct slot_chooser_available_filter {
2022 OBJECT *o_selected;
2023 gboolean hijack;
2024 gboolean compatible;
2027 /*! \brief Mark each slot as available or not according to a policy.
2028 * \par Function Description
2029 * \param [in] model A GtkTreeModel containing the slot.
2030 * \param [in] path The path to the slot's entry (unused).
2031 * \param [in] row An iterator pointing to the slot's entry.
2032 * \param [in] user_data The policy describing what slot properties matter.
2033 * \return FALSE to continue iterating over the model.
2035 static gboolean mark_available_visitor(GtkTreeModel *model,
2036 GtkTreePath *path,
2037 GtkTreeIter *row,
2038 gpointer user_data)
2040 struct slot_chooser_available_filter *filter = user_data;
2041 gboolean is_current, is_available, is_occupied, is_compatible;
2042 gboolean is_allowed, is_specific;
2043 gpointer target;
2045 gtk_tree_model_get(model, row,
2046 SLOT_CHOOSER_IS_CURRENT, &is_current,
2047 SLOT_CHOOSER_IS_AVAILABLE, &is_available,
2048 SLOT_CHOOSER_IS_OCCUPIED, &is_occupied,
2049 SLOT_CHOOSER_IS_COMPATIBLE, &is_compatible,
2050 SLOT_CHOOSER_IS_SPECIFIC, &is_specific,
2051 SLOT_CHOOSER_TARGET, &target,
2052 -1);
2054 if (target == NULL) {
2055 /* A Scheme row: just believe its SLOT_CHOOSER_IS_ALLOWED column. */
2056 return FALSE;
2059 is_allowed = TRUE;
2060 if ((is_occupied || !is_available) && !is_current && !filter->hijack) {
2061 is_allowed = FALSE;
2063 if (!is_compatible && filter->compatible) {
2064 is_allowed = FALSE;
2067 if (is_specific) {
2068 OBJECT *slot_object = target;
2069 if (filter->o_selected->owning_slot == slot_object) {
2070 is_allowed = TRUE;
2074 gtk_tree_store_set(GTK_TREE_STORE(model), row,
2075 SLOT_CHOOSER_IS_ALLOWED, is_allowed,
2076 -1);
2077 return FALSE;
2080 /*! \brief Recompute which rows should be sensitive.
2081 * \par Function Description
2082 * Add a new row to the slot chooser's GtkTreeView and populate its
2083 * columns with the slot's details.
2084 * \param [in] treestore The GtkTreeModel containing the slot data.
2085 * \param [in] sc A collection of context related to the slot chooser instance.
2087 void slot_chooser_mark_available(GtkTreeStore *treestore,
2088 struct slot_chooser *sc)
2090 struct slot_chooser_available_filter filter = {
2091 .hijack = FALSE,
2092 .compatible = TRUE,
2093 .o_selected = sc->o_selected
2096 if (sc->hijack_button) {
2097 filter.hijack = gtk_toggle_button_get_active(sc->hijack_button);
2099 if (sc->compatible_button) {
2100 filter.compatible = gtk_toggle_button_get_active(sc->compatible_button);
2103 gtk_tree_model_foreach(GTK_TREE_MODEL(treestore),
2104 &mark_available_visitor, &filter);
2107 /*! \brief Assign the selected symbol to the chosen slot.
2108 * \par Function Description
2109 * \param [in] sc A collection of context related to the slot chooser instance.
2111 static SCM slot_chooser_apply(struct slot_chooser *sc)
2113 GtkTreeSelection *sel;
2114 GtkTreeModel *model;
2115 GtkTreeIter row;
2116 gboolean just_unlink;
2118 g_object_get(sc->remove_button, "active", &just_unlink, NULL);
2119 /* Deactivate the Remove button once we have applied the dialog action. */
2120 g_object_set(sc->remove_button, "active", FALSE, NULL);
2122 if (just_unlink) {
2123 s_log_message("Unlinking #<object %s> from any slot",
2124 sc->o_selected->name);
2125 s_slot_unlink(sc->o_selected);
2126 s_slot_reset_attribs(sc->o_selected);
2127 return SCM_BOOL_T;
2130 sel = gtk_tree_view_get_selection(sc->treeview);
2131 if (gtk_tree_selection_get_selected(sel, &model, &row)) {
2132 gpointer target;
2133 gboolean is_specific, is_allowed;
2134 gchar *friendly_name;
2135 OBJECT *component;
2137 gtk_tree_model_get(model, &row,
2138 SLOT_CHOOSER_FRIENDLY_NAME, &friendly_name,
2139 SLOT_CHOOSER_TARGET, &target,
2140 SLOT_CHOOSER_IS_SPECIFIC, &is_specific,
2141 SLOT_CHOOSER_IS_ALLOWED, &is_allowed,
2142 -1);
2143 if (!is_allowed) {
2144 s_log_message("You can't choose %s for #<object %s>!",
2145 friendly_name, sc->o_selected->name);
2148 if (target) {
2149 if (is_allowed && is_specific) {
2150 OBJECT *slot_object = target;
2151 s_slot_reparent_specific_slot(sc->w_current, sc->o_selected, slot_object);
2152 fprintf(stderr, "Reparented %s to %s:%s\n",
2153 sc->o_selected->name, slot_object->slot->owner->name, friendly_name);
2154 } else {
2155 component = target;
2156 /* TODO: Find any suitable slot. */
2157 fprintf(stderr, "Looking for suitable slot for %s in %s (%s)\n",
2158 sc->o_selected->name, component->name, friendly_name);
2160 return SCM_BOOL_T;
2161 } else {
2162 /* Call the Scheme thunk. */
2163 GtkTreePath *path;
2164 int *indices;
2165 int i, n;
2166 SCM subtree = sc->scheme_tree;
2167 SCM action_name, thunk, retval;
2169 path = gtk_tree_model_get_path(model, &row);
2171 n = gtk_tree_path_get_depth(path);
2172 g_assert(n > 0);
2174 indices = gtk_tree_path_get_indices(path);
2176 for (i = 1; i < n; i++) {
2177 int j;
2179 /* Skip parent and pick out the right child. */
2180 subtree = SCM_CDR(subtree);
2181 for (j = 0; j < indices[i]; j++) {
2182 subtree = SCM_CDR(subtree);
2184 subtree = SCM_CAR(subtree);
2187 if (scm_is_true(scm_list_p(SCM_CAR(subtree)))) {
2188 /* Look into the list for the group header. */
2189 action_name = SCM_CAAR(subtree);
2190 thunk = SCM_CADAR(subtree);
2191 } else {
2192 action_name = SCM_CAR(subtree);
2193 thunk = SCM_CADR(subtree);
2196 if (scm_is_true(scm_procedure_p(thunk))) {
2197 retval = g_scm_apply_protected(thunk, SCM_EOL, NULL, NULL);
2198 } else {
2199 retval = thunk;
2202 /* If the thunk returned a list, it's a tree-expander. */
2203 if (scm_is_true(scm_list_p(retval)) && !scm_is_null(retval)) {
2204 SCM list, group_header;
2205 GtkTreeStore *treestore;
2206 int thunk_returned_tree;
2207 char *group_header_chars;
2209 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2211 thunk_returned_tree = scm_is_true(scm_list_p(SCM_CAR(retval)));
2213 if (thunk_returned_tree) {
2214 group_header = SCM_CAR(retval);
2215 } else {
2216 group_header = retval;
2219 /* Replace the text in the treeview. */
2220 group_header_chars = scm_to_locale_string(SCM_CAR(group_header));
2221 gtk_tree_store_set(treestore, &row,
2222 SLOT_CHOOSER_FRIENDLY_NAME, group_header_chars,
2223 -1);
2224 free(group_header_chars);
2226 /* Replace the node with the return value. */
2227 if (thunk_returned_tree) {
2228 /* The thunk returned a tree. */
2229 scm_set_car_x(subtree, group_header);
2230 scm_set_cdr_x(subtree, SCM_CDR(retval));
2232 /* Add the children to the treeview. */
2233 for (list = SCM_CDR(retval); !scm_is_null(list); list = SCM_CDR(list)) {
2234 if (scm_is_true(scm_list_p(SCM_CAAR(list)))) {
2235 slot_chooser_add_rows(sc, SCM_CAR(list), &row);
2236 } else {
2237 SCM synthetic_tree = scm_cons(SCM_CAR(list), SCM_EOL);
2238 slot_chooser_add_rows(sc, synthetic_tree, &row);
2241 } else {
2242 /* The thunk returned just a single row. */
2243 scm_set_car_x(subtree, SCM_CAR(group_header));
2244 scm_set_cdr_x(subtree, SCM_CDR(group_header));
2248 gtk_tree_path_free(path);
2250 return retval;
2252 } else {
2253 fprintf(stderr, "nothing selected\n");
2256 return SCM_BOOL_T;
2259 /*! \brief Apply some action depending on which button emitted the signal.
2261 void slot_chooser_finish(GtkButton *button, gpointer user_data)
2263 struct slot_chooser *sc;
2264 char *widget_name;
2266 g_object_get(button, "name", &widget_name, "user-data", &sc, NULL);
2268 if (widget_name == NULL) {
2269 /* Ignore unknown buttons. */
2270 return;
2273 if (strcmp(widget_name, "ok_button") == 0) {
2274 slot_chooser_apply(sc);
2275 } else if (strcmp(widget_name, "apply_button") == 0) {
2276 /* Change the slotting, keep the slot chooser open. */
2277 slot_chooser_apply(sc);
2278 return;
2281 fprintf(stderr, "slot_chooser_finish(%s)\n", widget_name);
2282 g_free(widget_name);
2283 fprintf(stderr, "o_selected = %s\n", sc->o_selected->name);
2284 gtk_widget_destroy(GTK_WIDGET(sc->scwindow));
2285 scm_gc_unprotect_object(sc->scheme_tree);
2286 g_free(sc);
2289 /*! \brief Free the "user-data" property of the slot chooser window.
2291 gboolean slot_chooser_delete(GtkWidget *widget, GdkEvent *event,
2292 gpointer user_data)
2294 struct slot_chooser *sc;
2296 g_object_get(widget, "user-data", &sc, NULL);
2297 fprintf(stderr, "slot_chooser_delete()\n");
2298 scm_gc_unprotect_object(sc->scheme_tree);
2299 g_free(sc);
2301 /* Let the default handler destroy the window (?). */
2302 return FALSE;
2305 /*! \brief Recompute which rows should be sensitive.
2307 void slot_chooser_toggle(GtkToggleButton *button, gpointer user_data)
2309 struct slot_chooser *sc;
2310 GtkTreeStore *treestore;
2312 g_object_get(button, "user-data", &sc, NULL);
2313 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2315 /* TODO: Don't make slot_chooser_mark_available() search for widgets. */
2316 slot_chooser_mark_available(treestore, sc);
2319 /*! \brief Choose a slot and destroy the dialog.
2321 void slot_chooser_row_activated(GtkTreeView *tree_view,
2322 GtkTreePath *path,
2323 GtkTreeViewColumn *column,
2324 gpointer user_data)
2326 struct slot_chooser *sc;
2327 SCM apply_result;
2329 g_object_get(tree_view, "user-data", &sc, NULL);
2330 apply_result = slot_chooser_apply(sc);
2331 if (scm_is_bool(apply_result) && scm_is_true(apply_result)) {
2332 /* TODO: Rather just delegate to the "OK" button. */
2333 gtk_widget_destroy(GTK_WIDGET(sc->scwindow));
2334 scm_gc_unprotect_object(sc->scheme_tree);
2335 g_free(sc);
2336 return;
2340 /*! \brief Reset the Remove button if an available slot is selected.
2342 void slot_chooser_row_changed(GtkTreeView *tree_view,
2343 gpointer user_data)
2345 struct slot_chooser *sc;
2346 GtkTreeSelection *sel;
2347 GtkTreeModel *model;
2348 GtkTreeIter row;
2350 g_object_get(tree_view, "user-data", &sc, NULL);
2352 sel = gtk_tree_view_get_selection(sc->treeview);
2353 if (gtk_tree_selection_get_selected(sel, &model, &row)) {
2354 gboolean is_allowed;
2356 gtk_tree_model_get(model, &row,
2357 SLOT_CHOOSER_IS_ALLOWED, &is_allowed,
2358 -1);
2359 if (is_allowed) {
2360 /* Deactivate the Remove button. */
2361 g_object_set(sc->remove_button, "active", FALSE, NULL);
2366 struct slot_chooser_tree_parent {
2367 GtkTreeView *treeview;
2368 GtkTreeIter *row;
2369 OBJECT *o_selected;
2372 /*! \brief Visit each slot in a component to add it to the GtkTreeView.
2373 * \par Function Description
2374 * Add a new row to the slot chooser's GtkTreeView and populate its
2375 * columns with the slot's details.
2376 * \param [in] key The name of the slot.
2377 * \param [in] value The slot to add to the GtkTreeView.
2378 * \param [in] context The struct slot_chooser_tree_parent context.
2380 void slot_chooser_slots_visitor(gpointer key, gpointer value, gpointer context)
2382 struct slot_chooser_tree_parent *tree_parent = context;
2383 OBJECT *slot_object = value;
2384 GtkTreeStore *treestore;
2385 GtkTreeIter newrow;
2386 GtkTreeView *treeview;
2387 static gboolean is_current, is_available, is_compatible, is_occupied;
2389 is_compatible = s_slot_compatible(tree_parent->o_selected, slot_object);
2390 is_available = s_slot_available(tree_parent->o_selected, slot_object);
2391 is_occupied = slot_object->slot->symbol ? TRUE : FALSE;
2392 is_current = (slot_object->slot->symbol == tree_parent->o_selected ? TRUE : FALSE);
2394 /* 'key' is the slotname attribute. */
2395 treeview = GTK_TREE_VIEW(tree_parent->treeview);
2396 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2397 gtk_tree_store_append(treestore, &newrow, tree_parent->row);
2398 gtk_tree_store_set(treestore, &newrow,
2399 SLOT_CHOOSER_FRIENDLY_NAME, key,
2400 SLOT_CHOOSER_IS_CURRENT, is_current,
2401 SLOT_CHOOSER_IS_AVAILABLE, is_available,
2402 SLOT_CHOOSER_IS_OCCUPIED, is_occupied,
2403 SLOT_CHOOSER_IS_COMPATIBLE, is_compatible,
2404 SLOT_CHOOSER_TARGET, (gpointer) slot_object,
2405 SLOT_CHOOSER_IS_SPECIFIC, TRUE,
2406 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2407 -1);
2409 /* Is this the currently assigned slot? */
2410 if (tree_parent->o_selected->owning_slot == slot_object) {
2411 GtkTreeSelection *sel;
2412 GtkTreePath *path;
2414 path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), &newrow);
2416 /* Expand the tree to the currently assigned slot. */
2417 gtk_tree_view_expand_to_path(treeview, path);
2418 sel = gtk_tree_view_get_selection(treeview);
2420 /* Select the currently assigned slot. */
2421 gtk_tree_selection_select_path(sel, path);
2423 gtk_tree_path_free(path);
2426 fprintf(stderr, "Found slot %s (%s)\n",
2427 (char *) key, is_compatible ? "compatible" : "incompatible");
2430 void slot_chooser_visitor(OBJECT *o_current, void *context)
2432 struct slot_chooser_tree_parent *tree_parent = context;
2433 GtkTreeView *treeview;
2434 GtkTreeStore *treestore;
2435 GtkTreeIter part_header;
2436 GtkTreeIter *parent_row;
2437 char *refdes;
2439 if (o_current->type != OBJ_COMPLEX) {
2440 return;
2443 /* Don't offer a symbol as a slot for itself. */
2444 if (o_current == tree_parent->o_selected) {
2445 return;
2448 /* Don't offer slots that are themselves inside another slot. */
2449 if (o_current->owning_slot) {
2450 return;
2453 /* Also don't offer components that have no slots. */
2454 if (o_current->complex->slots == NULL ||
2455 g_hash_table_size(o_current->complex->slots) == 0) {
2456 return;
2459 /* Save the treestore iterator. */
2460 parent_row = tree_parent->row;
2462 refdes = o_complex_get_refdes(o_current, _("(unknown part)"));
2464 /* Add a row for the part as a whole. */
2465 treeview = tree_parent->treeview;
2466 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2467 gtk_tree_store_append(treestore, &part_header, parent_row);
2468 gtk_tree_store_set(treestore, &part_header,
2469 SLOT_CHOOSER_FRIENDLY_NAME, refdes,
2470 SLOT_CHOOSER_IS_CURRENT, FALSE,
2471 SLOT_CHOOSER_IS_AVAILABLE, TRUE,
2472 SLOT_CHOOSER_IS_OCCUPIED, FALSE,
2473 SLOT_CHOOSER_IS_COMPATIBLE, TRUE,
2474 SLOT_CHOOSER_TARGET, (gpointer) o_current,
2475 SLOT_CHOOSER_IS_SPECIFIC, FALSE,
2476 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2477 -1);
2479 /* Become the parent for slots we find. */
2480 tree_parent->row = &part_header;
2482 g_hash_table_foreach(o_current->complex->slots,
2483 &slot_chooser_slots_visitor, tree_parent);
2485 /* Restore the treestore iterator. */
2486 tree_parent->row = parent_row;
2489 static void slot_chooser_add_one_row(struct slot_chooser *sc,
2490 SCM name, SCM callback,
2491 GtkTreeIter *parent_row,
2492 GtkTreeIter *new_row)
2494 GtkTreeStore *treestore;
2495 char *name_chars;
2497 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2498 gtk_tree_store_append(treestore, new_row, parent_row);
2500 if (!scm_is_string(name)) {
2501 g_warning("Expecting a slotname string from (find-slots object)\n");
2502 return;
2504 if (!scm_is_bool(callback) && scm_is_false(scm_procedure_p(callback))) {
2505 g_warning("Expecting a callback from (find-slots object)\n");
2508 name_chars = scm_to_locale_string(name);
2509 fprintf(stderr, "**** Scheme says: %s ****\n", name_chars);
2510 gtk_tree_store_set(treestore, new_row,
2511 SLOT_CHOOSER_FRIENDLY_NAME, name_chars,
2512 SLOT_CHOOSER_TARGET, NULL,
2513 SLOT_CHOOSER_IS_SPECIFIC, TRUE,
2514 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2515 -1);
2516 free(name_chars);
2519 static void slot_chooser_add_rows(struct slot_chooser *sc,
2520 SCM list,
2521 GtkTreeIter *parent_row)
2523 GtkTreeIter group_row;
2524 SCM group = SCM_CAR(list);
2525 SCM groupname = SCM_CAR(group);
2526 SCM callback = SCM_CADR(group);
2528 slot_chooser_add_one_row(sc, groupname, callback,
2529 parent_row, &group_row);
2531 for (list = SCM_CDR(list); !scm_is_null(list); list = SCM_CDR(list)) {
2532 SCM row = SCM_CAR(list);
2533 SCM car = SCM_CAR(row);
2535 if (scm_is_true(scm_list_p(car))) {
2536 slot_chooser_add_rows(sc, row, &group_row);
2537 } else {
2538 GtkTreeIter child_row;
2539 SCM slotname = car;
2540 SCM slot_callback = SCM_CADR(row);
2542 slot_chooser_add_one_row(sc, slotname, slot_callback,
2543 &group_row, &child_row);
2548 static void slot_chooser_populate(TOPLEVEL *toplevel,
2549 struct slot_chooser *sc)
2551 SCM o_smob = g_make_object_smob(toplevel, sc->o_selected);
2552 SCM slots;
2554 slots = g_scm_apply_protected(g_scm_safe_ref_lookup("find-slots"),
2555 scm_list_1(o_smob),
2556 NULL, NULL);
2558 if (scm_is_false(scm_list_p(slots))) {
2559 s_log_message(_("find-slots #<object %s> didn't return a list\n"),
2560 sc->o_selected->name);
2561 return;
2564 sc->scheme_tree = slots;
2566 if (!scm_is_null(slots)) {
2567 slot_chooser_add_rows(sc, slots, NULL);
2570 scm_gc_protect_object(sc->scheme_tree);
2573 /*! \brief Create the slot chooser dialog
2574 * \par Function Description
2575 * This function creates the slot chooser dialog.
2577 void slot_chooser_dialog(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
2578 char const *slotname_attrib)
2580 struct slot_chooser_tree_parent tree_parent;
2581 struct slot_chooser *sc;
2582 GladeXML *xml;
2583 GtkWindow *scwindow;
2584 GtkTreeStore *treestore;
2585 GtkCellRenderer *renderer;
2586 GtkTreeViewColumn *column;
2587 GtkWidget *widget;
2588 char *refdes;
2590 widget = x_glade_get_widget(&xml, "slot_chooser",
2591 "slot_chooser_finish",
2592 G_CALLBACK(&slot_chooser_finish),
2593 "slot_chooser_delete",
2594 G_CALLBACK(&slot_chooser_delete),
2595 "slot_chooser_toggle",
2596 G_CALLBACK(&slot_chooser_toggle),
2597 "slot_chooser_row_activated",
2598 G_CALLBACK(&slot_chooser_row_activated),
2599 "slot_chooser_row_changed",
2600 G_CALLBACK(&slot_chooser_row_changed),
2601 NULL);
2603 if (widget == NULL) {
2604 s_log_message("Can't find dialog component \"slot_chooser_dialog\"\n");
2605 return;
2607 scwindow = GTK_WINDOW(widget);
2608 refdes = o_complex_get_refdes(o_current, _("(unknown part)"));
2609 if (refdes) {
2610 char *title, *slotname;
2612 slotname = o_attrib_search_name_single(o_current, "slotname", NULL);
2614 if (slotname) {
2615 title = g_strconcat("Slot Chooser - ", refdes, ":", slotname, NULL);
2616 } else {
2617 title = g_strconcat("Slot Chooser - ", refdes, NULL);
2619 gtk_window_set_title(scwindow, title);
2621 g_free(title);
2622 g_free(slotname);
2623 g_free(refdes);
2626 /* FIXME: Where do we release this memory? */
2627 sc = g_new(struct slot_chooser, 1);
2629 sc->scwindow = scwindow;
2630 widget = x_lookup_widget_set(xml, "hijack_button",
2631 "user-data", sc, NULL);
2632 sc->hijack_button = GTK_TOGGLE_BUTTON(widget);
2633 widget = x_lookup_widget_set(xml, "compatible_button",
2634 "user-data", sc, NULL);
2635 sc->compatible_button = GTK_TOGGLE_BUTTON(widget);
2636 widget = x_lookup_widget_set(xml, "remove_button",
2637 "user-data", sc, NULL);
2638 sc->remove_button = GTK_TOGGLE_BUTTON(widget);
2639 sc->w_current = w_current->toplevel;
2640 sc->o_selected = o_current;
2641 widget = x_lookup_widget_set(xml, "slot_treeview",
2642 "user-data", sc, NULL);
2643 sc->treeview = GTK_TREE_VIEW(widget);
2645 fprintf(stderr, "scwindow = %p\n", scwindow);
2647 /* Remember what we're doing, when we get the callback. */
2648 g_object_set(scwindow, "user-data", sc, NULL);
2649 x_lookup_widget_set(xml, "cancel_button", "user-data", sc, NULL);
2650 x_lookup_widget_set(xml, "apply_button", "user-data", sc, NULL);
2651 x_lookup_widget_set(xml, "remove_button", "user-data", sc, NULL);
2652 x_lookup_widget_set(xml, "ok_button", "user-data", sc, NULL);
2654 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(sc->treeview),
2655 GTK_SELECTION_SINGLE);
2657 /* Use the tree model. */
2658 treestore = gtk_tree_store_new(SLOT_CHOOSER_N_COLUMNS,
2659 G_TYPE_STRING,
2660 G_TYPE_POINTER,
2661 G_TYPE_BOOLEAN,
2662 G_TYPE_BOOLEAN,
2663 G_TYPE_BOOLEAN,
2664 G_TYPE_BOOLEAN,
2665 G_TYPE_BOOLEAN,
2666 G_TYPE_BOOLEAN);
2667 gtk_tree_view_set_model(sc->treeview, GTK_TREE_MODEL(treestore));
2668 gtk_tree_view_set_search_column(sc->treeview, SLOT_CHOOSER_FRIENDLY_NAME);
2670 /* Now set the view component for each column. */
2672 renderer = gtk_cell_renderer_text_new();
2673 column = gtk_tree_view_column_new_with_attributes("name", renderer,
2674 "text",
2675 SLOT_CHOOSER_FRIENDLY_NAME,
2676 "sensitive",
2677 SLOT_CHOOSER_IS_ALLOWED,
2678 NULL);
2679 gtk_tree_view_append_column(sc->treeview, column);
2681 #if DEBUG
2682 renderer = gtk_cell_renderer_toggle_new();
2683 g_object_set(renderer, "activatable", FALSE, NULL);
2684 column = gtk_tree_view_column_new_with_attributes("occupied", renderer,
2685 "active",
2686 SLOT_CHOOSER_IS_OCCUPIED,
2687 "sensitive",
2688 SLOT_CHOOSER_IS_ALLOWED,
2689 NULL);
2690 gtk_tree_view_append_column(sc->treeview, column);
2692 renderer = gtk_cell_renderer_toggle_new();
2693 g_object_set(renderer, "activatable", FALSE, NULL);
2694 column = gtk_tree_view_column_new_with_attributes("compatible", renderer,
2695 "active",
2696 SLOT_CHOOSER_IS_COMPATIBLE,
2697 "sensitive",
2698 SLOT_CHOOSER_IS_ALLOWED,
2699 NULL);
2700 gtk_tree_view_append_column(sc->treeview, column);
2701 #endif
2703 gtk_tree_view_expand_all(sc->treeview);
2705 /* Find some compatible slots. */
2706 tree_parent.treeview = sc->treeview;
2707 tree_parent.row = NULL;
2708 tree_parent.o_selected = o_current;
2710 /* TODO: perhaps use an infinite-depth search. */
2711 s_visit_toplevel(w_current->toplevel, &slot_chooser_visitor, &tree_parent,
2712 VISIT_UNORDERED, 1);
2714 /* Let gschemrc add some rows too. */
2715 slot_chooser_populate(w_current->toplevel, sc);
2717 slot_chooser_mark_available(treestore, sc);
2719 g_object_unref(xml);
2721 gtk_window_present(scwindow);
2724 /***************** End of Slot chooser dialog box ********************/
2726 /***************** Start of component list dialog box ****************/
2728 enum component_list_columns {
2729 COMPONENT_LIST_REFDES,
2730 COMPONENT_LIST_N_COLUMNS
2733 struct component_list {
2734 PAGE *page;
2735 GtkWindow *clwindow;
2736 GtkTreeView *treeview;
2737 GtkListStore *liststore;
2740 /*! \brief Clean up resources that GTK+ doesn't know about.
2741 * \par Function Description
2742 * Cleans up resources that the component list dialog uses.
2744 * \param [in] widget A widget with a "user-data" property.
2746 * \returns A pointer to the GtkWindow of the dialog.
2748 static GtkWindow *component_list_cleanup(GtkWidget *widget)
2750 struct component_list *cl;
2751 GtkWindow *clwindow;
2753 g_object_get(widget, "user-data", &cl, NULL);
2755 clwindow = cl->clwindow;
2757 g_free(cl);
2759 return clwindow;
2762 gboolean component_list_window_delete(GtkWidget *widget,
2763 GdkEvent *event,
2764 gpointer user_data)
2766 component_list_cleanup(widget);
2768 return FALSE;
2771 void component_list_finish(GtkButton *button, gpointer user_data)
2773 GtkWindow *clwindow;
2775 clwindow = component_list_cleanup(GTK_WIDGET(button));
2777 gtk_widget_destroy(GTK_WIDGET(clwindow));
2780 void component_list_edit(GtkButton *button, gpointer user_data)
2782 /* TODO: Start the multi attrib editor. */
2785 void component_list_row_activated(GtkTreeView *treeview,
2786 GtkTreePath *path,
2787 GtkTreeViewColumn *column,
2788 gpointer user_data)
2790 /* TODO: Start the multi attrib editor. */
2793 /*! \brief Show the component list dialog.
2794 * \par Function Description
2795 * Show the component list dialog with a given list of objects.
2797 * \param [in] components A list of OBJECTs to show in the dialog.
2799 void component_list_dialog(GList const *components)
2801 struct component_list *cl;
2802 GladeXML *xml;
2803 GtkWidget *widget;
2804 GtkCellRenderer *renderer;
2805 GtkTreeViewColumn *column;
2806 OBJECT *o;
2808 cl = g_new(struct component_list, 1);
2810 widget = x_glade_get_widget(&xml, "component_list",
2811 "on_component_list_dialog_delete_event",
2812 G_CALLBACK(&component_list_window_delete),
2813 "on_ok_button_clicked",
2814 G_CALLBACK(&component_list_finish),
2815 "on_edit_button_clicked",
2816 G_CALLBACK(&component_list_edit),
2817 "component_list_row_activated",
2818 G_CALLBACK(&component_list_row_activated),
2819 NULL);
2821 if (widget == NULL) {
2822 s_log_message("Can't find dialog component \"component_list\"\n");
2823 return;
2825 cl->clwindow = GTK_WINDOW(widget);
2827 /* Set "user-data" properties on all interesting widgets. */
2828 x_lookup_widget_set(xml, "ok_button", "user-data", cl, NULL);
2829 x_lookup_widget_set(xml, "edit_button", "user-data", cl, NULL);
2830 widget = x_lookup_widget_set(xml, "components_treeview",
2831 "user-data", cl, NULL);
2832 cl->treeview = GTK_TREE_VIEW(widget);
2833 g_object_set(cl->clwindow, "user-data", cl, NULL);
2835 /* Set up the tree view. */
2836 cl->liststore = gtk_list_store_new(COMPONENT_LIST_N_COLUMNS,
2837 G_TYPE_STRING);
2838 gtk_tree_view_set_model(cl->treeview, GTK_TREE_MODEL(cl->liststore));
2839 gtk_tree_view_set_search_column(cl->treeview, COMPONENT_LIST_REFDES);
2841 /* Tell the tree view how to display its cells. */
2842 renderer = gtk_cell_renderer_text_new();
2843 column = gtk_tree_view_column_new_with_attributes("refdes", renderer,
2844 "text", COMPONENT_LIST_REFDES,
2845 NULL);
2846 gtk_tree_view_append_column(cl->treeview, column);
2848 /* Populate the tree view with the objects given as a parameter. */
2849 for (; components != NULL; components = components->next) {
2850 GtkTreeIter row;
2851 char *refdes;
2853 o = components->data;
2855 refdes = o_attrib_search_name_single_exact(o, "refdes", NULL);
2857 gtk_list_store_append(cl->liststore, &row);
2858 gtk_list_store_set(cl->liststore, &row,
2859 COMPONENT_LIST_REFDES, refdes,
2860 -1);
2862 g_free(refdes);
2866 /***************** End of component list dialog box ******************/
2868 /***************** Start of REPL dialog box ********************/
2870 enum repl_columns {
2871 REPL_SCM,
2872 REPL_REPRESENTATION,
2873 REPL_N_COLUMNS
2876 struct repl {
2877 GladeXML *xml;
2878 GSCHEM_TOPLEVEL *w_current;
2879 GtkWidget *window;
2880 GtkTreeStore *treestore;
2881 GtkTreeView *treeview;
2882 GtkTreeSelection *selection;
2883 GtkNotebook *notebook;
2884 SCM result;
2887 void repl_destroy(struct repl *r)
2889 if (r->window) {
2890 gtk_widget_destroy(r->window);
2892 g_object_unref(r->xml);
2893 g_free(r);
2896 void repl_populate_treeview(GtkTreeStore *treestore, SCM expr,
2897 GtkTreeIter *parent)
2899 GtkTreeIter newrow;
2900 SCM representation;
2902 representation = scm_simple_format(SCM_BOOL_F,
2903 scm_from_locale_string("~S"),
2904 scm_list_1(expr));
2906 gtk_tree_store_append(treestore, &newrow, parent);
2907 if (scm_is_string(representation)) {
2908 char *representation_c = scm_to_locale_string(representation);
2909 SCM *rowexpr = g_new(SCM, 1);
2911 *rowexpr = expr;
2912 gtk_tree_store_set(treestore, &newrow,
2913 REPL_SCM, rowexpr,
2914 REPL_REPRESENTATION, representation_c,
2915 -1);
2916 free(representation_c);
2917 } else {
2918 gtk_tree_store_set(treestore, &newrow,
2919 REPL_SCM, NULL,
2920 REPL_REPRESENTATION, "<libguile error>",
2921 -1);
2924 if (scm_is_true(scm_list_p(expr))) {
2925 SCM i;
2927 for (i = expr; !scm_is_null(i); i = SCM_CDR(i)) {
2928 repl_populate_treeview(treestore, SCM_CAR(i), &newrow);
2933 gboolean repl_clear_row(GtkTreeModel *model, GtkTreePath *path,
2934 GtkTreeIter *iter, gpointer user_data)
2936 SCM *rowexpr;
2938 gtk_tree_model_get(model, iter, REPL_SCM, &rowexpr, -1);
2939 g_free(rowexpr);
2941 return FALSE;
2944 void repl_execute(GtkButton *button, gpointer user_data)
2946 struct repl *r;
2947 gint current_page_index;
2948 GtkWidget *current_page;
2949 GtkTextBuffer *textbuffer;
2950 gchar *text;
2952 g_object_get(G_OBJECT(button), "user-data", &r, NULL);
2954 current_page_index = gtk_notebook_get_current_page(r->notebook);
2955 if (current_page_index == -1) {
2956 printf("No open pages\n");
2957 return;
2960 current_page = gtk_notebook_get_nth_page(r->notebook, current_page_index);
2961 if (current_page == NULL) {
2962 printf("Can't get current page\n");
2963 return;
2966 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(current_page));
2967 /* TODO - g_type_is_a() */
2968 g_object_get(G_OBJECT(textbuffer), "text", &text, NULL);
2970 if (r->result != SCM_UNDEFINED) {
2971 scm_gc_unprotect_object(r->result);
2974 /* Pass the string to the interpreter. */
2975 r->result = g_scm_apply_protected(g_scm_safe_ref_lookup("invoke-macro"),
2976 scm_list_1(scm_from_locale_string(text)),
2977 NULL, NULL);
2978 g_free(text);
2979 scm_gc_protect_object(r->result);
2981 /* TODO: Give feedback if an exception occurred. */
2982 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_clear_row, NULL);
2983 gtk_tree_store_clear(r->treestore);
2984 repl_populate_treeview(r->treestore, r->result, NULL);
2986 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_selection_one, r);
2989 void repl_cancel(GtkButton *button, gpointer user_data)
2991 struct repl *r;
2993 g_object_get(G_OBJECT(button), "user-data", &r, NULL);
2995 gtk_widget_hide(r->window);
2998 void repl_row_activated(GtkTreeView *tree_view,
2999 GtkTreePath *path,
3000 GtkTreeViewColumn *column,
3001 gpointer user_data)
3003 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
3004 GtkTreeIter iter;
3005 TOPLEVEL *toplevel;
3006 OBJECT *o_current;
3007 SCM *rowexpr;
3009 gtk_tree_model_get_iter(model, &iter, path);
3010 gtk_tree_model_get(model, &iter, REPL_SCM, &rowexpr, -1);
3012 if (g_get_data_from_object_smob(*rowexpr, &toplevel, &o_current)) {
3013 struct repl *r;
3015 g_object_get(G_OBJECT(tree_view), "user-data", &r, NULL);
3017 x_multiattrib_open(r->w_current, toplevel->page_current->selection_list);
3018 } else if (scm_is_true(scm_thunk_p(*rowexpr))) {
3019 /* TODO: Execute thunk with g_scm_apply_protected. */
3023 /* XXX getting both w_current and toplevel is odd. */
3024 void repl_selection_one_object(GtkTreeSelection *selection, GtkTreePath *path,
3025 GSCHEM_TOPLEVEL *w_current, TOPLEVEL *toplevel,
3026 OBJECT *o_current)
3028 PAGE *page = toplevel->page_current;
3030 o_select_object_simple(w_current, toplevel, page, o_current,
3031 gtk_tree_selection_path_is_selected(selection, path));
3034 static gboolean repl_selection_one(GtkTreeModel *model, GtkTreePath *path,
3035 GtkTreeIter *iter, gpointer user_data)
3037 struct repl *r = user_data;
3038 TOPLEVEL *toplevel;
3039 OBJECT *o_current;
3040 SCM *rowexpr;
3042 gtk_tree_model_get(model, iter, REPL_SCM, &rowexpr, -1);
3043 if (g_get_data_from_object_smob(*rowexpr, &toplevel, &o_current)) {
3044 repl_selection_one_object(r->selection, path, r->w_current, toplevel, o_current);
3047 return FALSE;
3050 void repl_selection_changed(GtkTreeSelection *selection, gpointer user_data)
3052 struct repl *r = user_data;
3054 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_selection_one, r);
3057 void repl_new_page(GtkNotebook *notebook)
3059 GtkWidget *textview = gtk_text_view_new();
3060 GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
3061 GtkWidget *label = gtk_label_new("New");
3063 gtk_text_buffer_set_text(textbuffer, ";; Write some Scheme here", -1);
3064 select_all_text_in_textview(GTK_TEXT_VIEW(textview));
3065 gtk_widget_show(GTK_WIDGET(textview));
3066 gtk_notebook_prepend_page(notebook, textview, label);
3067 gtk_notebook_set_current_page(notebook, 0);
3068 gtk_widget_grab_focus(textview);
3069 if (gtk_notebook_get_n_pages(notebook) > 1) {
3070 g_object_set(G_OBJECT(notebook), "show-tabs", TRUE, NULL);
3074 void repl_dialog(GSCHEM_TOPLEVEL *w_current)
3076 static struct repl *r = NULL;
3078 if (r != NULL) {
3079 repl_new_page(r->notebook);
3080 gtk_widget_show(r->window);
3081 return;
3084 r = g_new0(struct repl, 1);
3085 r->w_current = w_current;
3086 r->result = SCM_UNDEFINED;
3088 r->window = x_glade_get_widget(&r->xml, "repl",
3089 "on_repl_window_delete_event",
3090 G_CALLBACK(gtk_widget_hide_on_delete),
3091 "on_execute_button_clicked",
3092 G_CALLBACK(repl_execute),
3093 "on_cancel_button_clicked",
3094 G_CALLBACK(repl_cancel),
3095 "on_result_treeview_row_activated",
3096 G_CALLBACK(repl_row_activated),
3097 NULL);
3098 if (r->window == NULL) {
3099 s_log_message("Can't find dialog component \"repl\"\n");
3100 repl_destroy(r);
3101 r = NULL;
3102 return;
3105 r->notebook = GTK_NOTEBOOK(x_lookup_widget(r->xml, "sexpr-notebook"));
3106 if (r->notebook == NULL) {
3107 s_log_message("Can't find sexpr notebook in dialog component \"repl\"\n");
3108 repl_destroy(r);
3109 r = NULL;
3110 return;
3113 r->treeview = GTK_TREE_VIEW(x_lookup_widget(r->xml, "result-treeview"));
3114 if (r->treeview != NULL) {
3115 GtkCellRenderer *renderer;
3116 GtkTreeViewColumn *column;
3118 r->treestore = gtk_tree_store_new(REPL_N_COLUMNS,
3119 G_TYPE_POINTER,
3120 G_TYPE_STRING);
3121 gtk_tree_view_set_model(r->treeview, GTK_TREE_MODEL(r->treestore));
3123 renderer = gtk_cell_renderer_text_new();
3124 column = gtk_tree_view_column_new_with_attributes("value", renderer,
3125 "text", REPL_REPRESENTATION,
3126 NULL);
3127 gtk_tree_view_append_column(r->treeview, column);
3129 r->selection = gtk_tree_view_get_selection(r->treeview);
3130 gtk_tree_selection_set_mode(r->selection, GTK_SELECTION_MULTIPLE);
3132 g_signal_connect(r->selection, "changed", G_CALLBACK(repl_selection_changed), r);
3135 x_lookup_widget_set(r->xml, "execute_button", "user-data", r, NULL);
3136 x_lookup_widget_set(r->xml, "cancel_button", "user-data", r, NULL);
3137 x_lookup_widget_set(r->xml, "result-treeview", "user-data", r, NULL);
3139 gtk_notebook_remove_page(r->notebook, 0);
3140 repl_new_page(r->notebook);
3143 /***************** End of REPL dialog box ******************/
3145 /***************** Start of help/about dialog box ********************/
3147 /*! \brief Response function for the about dialog
3148 * \par Function Description
3149 * This function destroys the about dialog.
3151 void about_dialog_response(GtkWidget *w, gint response,
3152 GSCHEM_TOPLEVEL *w_current)
3154 switch (response) {
3155 case GTK_RESPONSE_REJECT:
3156 case GTK_RESPONSE_DELETE_EVENT:
3157 /* void */
3158 break;
3159 default:
3160 printf("about_dialog_response(): strange signal %d\n",response);
3163 gtk_widget_destroy(w_current->abwindow);
3164 w_current->abwindow = NULL;
3167 /*! \brief Create the about dialog and show it
3168 * \par Function Description
3169 * This function creates the about dialog.
3171 void about_dialog (GSCHEM_TOPLEVEL *w_current)
3173 GtkWidget *label = NULL;
3174 GtkWidget *vbox;
3175 char *string;
3177 if (!w_current->abwindow) {
3178 w_current->abwindow = gschem_dialog_new_with_buttons(_("About..."),
3179 GTK_WINDOW(w_current->main_window),
3180 GTK_DIALOG_MODAL,
3181 "about", w_current,
3182 GTK_STOCK_CLOSE,
3183 GTK_RESPONSE_REJECT,
3184 NULL);
3186 gtk_window_position (GTK_WINDOW (w_current->abwindow),
3187 GTK_WIN_POS_MOUSE);
3189 gtk_signal_connect (GTK_OBJECT (w_current->abwindow), "response",
3190 GTK_SIGNAL_FUNC(about_dialog_response),
3191 w_current);
3193 gtk_container_border_width (GTK_CONTAINER(w_current->abwindow),
3194 DIALOG_BORDER_SPACING);
3195 vbox = GTK_DIALOG(w_current->abwindow)->vbox;
3196 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3198 label = gtk_label_new ( _("<b>gEDA: GPL Electronic Design Automation</b>"));
3199 gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
3200 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3202 string = g_strdup_printf(_("<b>gschem version %s%s.%s</b>"),
3203 PREPEND_VERSION_STRING, DOTTED_VERSION,
3204 DATE_VERSION);
3205 label = gtk_label_new (string);
3206 gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
3207 g_free(string);
3208 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3210 label = gtk_label_new ( _("Written by:\n"
3211 "Ales Hvezda\n"
3212 "ahvezda@geda.seul.org\n"
3213 "And many others (See AUTHORS file)"));
3214 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
3215 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3217 gtk_widget_show_all(w_current->abwindow);
3220 else { /* dialog already created */
3221 gtk_window_present(GTK_WINDOW(w_current->abwindow));
3225 /***************** End of help/about dialog box *********************/
3227 /***************** Start of coord dialog box ************************/
3228 /*! \brief Response function for the coord dialog
3229 * \par Function Description
3230 * This function destroys the coord dialog box and does some cleanup.
3232 void coord_dialog_response(GtkWidget *w, gint response, GSCHEM_TOPLEVEL *w_current)
3234 gtk_widget_destroy(w_current->cowindow);
3235 w_current->cowindow = NULL;
3236 w_current->coord_world = NULL;
3237 w_current->coord_screen = NULL;
3240 /*! \brief Update the coordinates in the coord dialog box.
3241 * \par Function Description
3242 * This function takes the screen coordinates and prints the
3243 * screen and the world coordinates in the coord dialog.
3245 void coord_display_update(GSCHEM_TOPLEVEL *w_current, int x, int y)
3247 TOPLEVEL *toplevel = w_current->toplevel;
3248 PAGE *page = toplevel->page_current;
3249 char *string;
3250 int world_x, world_y;
3252 string = g_strdup_printf("(%d, %d)", x, y);
3253 gtk_label_set_text(GTK_LABEL(w_current->coord_screen), string );
3254 g_free(string);
3256 SCREENtoWORLD(page, x, y, &world_x, &world_y);
3257 /* TODO: Do we want to snap the coordinate display? */
3258 world_x = snap_grid(toplevel, world_x);
3259 world_y = snap_grid(toplevel, world_y);
3261 string = g_strdup_printf("(%d, %d)", world_x, world_y);
3262 gtk_label_set_text(GTK_LABEL(w_current->coord_world), string );
3263 g_free(string);
3266 /*! \brief Create the coord dialog
3267 * \par Function Description
3268 * This function creates the coord dialog box.
3270 void coord_dialog (GSCHEM_TOPLEVEL *w_current, int x, int y)
3272 GtkWidget *frame;
3273 GtkWidget *vbox;
3275 if (!w_current->cowindow) {
3276 w_current->cowindow = gschem_dialog_new_with_buttons(_("Coords"),
3277 GTK_WINDOW(w_current->main_window),
3278 0, /* Not modal GTK_DIALOG_MODAL */
3279 "coord", w_current,
3280 GTK_STOCK_CLOSE,
3281 GTK_RESPONSE_REJECT,
3282 NULL);
3284 gtk_window_position (GTK_WINDOW (w_current->cowindow),
3285 GTK_WIN_POS_NONE);
3287 gtk_signal_connect (GTK_OBJECT (w_current->cowindow), "response",
3288 GTK_SIGNAL_FUNC(coord_dialog_response),
3289 w_current);
3291 gtk_container_border_width (GTK_CONTAINER(w_current->cowindow),
3292 DIALOG_BORDER_SPACING);
3293 vbox = GTK_DIALOG(w_current->cowindow)->vbox;
3294 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3297 frame = gtk_frame_new (_("Screen"));
3298 w_current->coord_screen = gtk_label_new("(########, ########)");
3299 gtk_label_set_justify( GTK_LABEL(w_current->coord_screen), GTK_JUSTIFY_LEFT);
3300 gtk_misc_set_padding(GTK_MISC(w_current->coord_screen),
3301 DIALOG_H_SPACING, DIALOG_V_SPACING);
3302 gtk_container_add(GTK_CONTAINER (frame),
3303 w_current->coord_screen);
3304 gtk_box_pack_start(GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3306 frame = gtk_frame_new (_("World"));
3307 w_current->coord_world = gtk_label_new ("(########, ########)");
3308 gtk_misc_set_padding(GTK_MISC(w_current->coord_world),
3309 DIALOG_H_SPACING, DIALOG_V_SPACING);
3310 gtk_label_set_justify(GTK_LABEL(w_current->coord_world),
3311 GTK_JUSTIFY_LEFT);
3312 gtk_container_add(GTK_CONTAINER (frame),
3313 w_current->coord_world);
3314 gtk_box_pack_start(GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3316 gtk_widget_show_all(w_current->cowindow);
3319 else { /* window already creatad */
3320 gtk_window_present(GTK_WINDOW(w_current->cowindow));
3323 /* always update the coords when the dialog is requested */
3324 coord_display_update(w_current, x, y);
3327 /***************** End of coord dialog box **************************/
3329 /***************** Start of color edit dialog box *******************/
3331 /*! \todo Finish function documentation!!!
3332 * \brief
3333 * \par Function Description
3335 * \warning
3336 * Caller must g_free returned character string.
3339 char *index2functionstring(int index)
3341 char *string;
3343 switch(index) {
3344 case(BACKGROUND_COLOR):
3345 string = g_strdup (_("Background"));
3346 break;
3347 case(PIN_COLOR):
3348 string = g_strdup (_("Pin"));
3349 break;
3350 case(NET_ENDPOINT_COLOR):
3351 string = g_strdup (_("Net endpoint"));
3352 break;
3353 case(GRAPHIC_COLOR):
3354 string = g_strdup (_("Graphic"));
3355 break;
3356 case(NET_COLOR):
3357 string = g_strdup (_("Net"));
3358 break;
3359 case(ATTRIBUTE_COLOR):
3360 string = g_strdup (_("Attribute"));
3361 break;
3362 case(LOGIC_BUBBLE_COLOR):
3363 string = g_strdup (_("Logic bubble"));
3364 break;
3365 case(GRID_COLOR):
3366 string = g_strdup (_("Grid point"));
3367 break;
3368 case(DETACHED_ATTRIBUTE_COLOR):
3369 string = g_strdup (_("Detached attribute"));
3370 break;
3371 case(TEXT_COLOR):
3372 string = g_strdup (_("Text"));
3373 break;
3374 case(BUS_COLOR):
3375 string = g_strdup (_("Bus"));
3376 break;
3377 case(SELECT_COLOR):
3378 string = g_strdup (_("Selection"));
3379 break;
3380 case(BOUNDINGBOX_COLOR):
3381 string = g_strdup (_("Bounding box"));
3382 break;
3383 case(ZOOM_BOX_COLOR):
3384 string = g_strdup (_("Zoom box"));
3385 break;
3386 case(STROKE_COLOR):
3387 string = g_strdup (_("Stroke"));
3388 break;
3389 case(LOCK_COLOR):
3390 string = g_strdup (_("Lock"));
3391 break;
3392 case(OUTPUT_BACKGROUND_COLOR):
3393 string = g_strdup (_("Output background"));
3394 break;
3395 case(JUNCTION_COLOR):
3396 string = g_strdup (_("Net junction"));
3397 break;
3398 default:
3399 string = g_strdup (_("Unknown"));
3400 break;
3402 return(string);
3405 /*! \brief Cell layout data function for color combobox.
3406 * \par Function Description
3407 * Cell layout data function to support color swatches in the color
3408 * combobox.
3410 * \param data the current #GSCHEM_TOPLEVEL pointer.
3412 static void
3413 color_menu_swatch_layout_data (GtkCellLayout *layout,
3414 GtkCellRenderer *cell,
3415 GtkTreeModel *model,
3416 GtkTreeIter *iter,
3417 gpointer data)
3419 /* GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data; */
3420 GValue v = {0, };
3421 gint idx;
3423 /* Get the index of the color on this row */
3424 gtk_tree_model_get_value (model, iter, 1, &v);
3425 idx = g_value_get_int (&v);
3427 /* Set the cell's background color */
3428 g_object_set (cell, "background-gdk", x_get_color (idx), NULL);
3431 /*! \brief Handle color combobox selection change event.
3432 * \par Function Description
3433 * Update application state to reflect color combobox selection
3434 * changes.
3436 * \param data the current #GSCHEM_TOPLEVEL pointer.
3438 static void
3439 color_menu_change_selection (GtkWidget *widget,
3440 gpointer data)
3442 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data;
3443 GtkComboBox *cbox = GTK_COMBO_BOX (widget);
3444 gint idx;
3445 GtkTreeIter iter;
3446 GValue v = {0, };
3448 if (!gtk_combo_box_get_active_iter (cbox, &iter)) {
3449 return; /* No color selected */
3451 gtk_tree_model_get_value (gtk_combo_box_get_model (cbox),
3452 &iter, 1, &v);
3453 idx = g_value_get_int (&v);
3455 /* Stash the selected color in the GSCHEM_TOPLEVEL.
3456 * FIXME this is ugly. */
3457 w_current->edit_color = idx;
3460 /*! \brief Create a ComboBox with the gschem colors.
3461 * \par Function Description
3462 * Creates a #GtkComboBox with the color list and swatches showing
3463 * each of the available colors.
3465 * The backing #GtkTreeModel is a #GtkListStore with two columns, the
3466 * first holding the user-friendly name of the color, and the other
3467 * the color map index.
3469 * \param [in] w_current The current gschem context.
3471 static GtkWidget *
3472 create_color_menu (GSCHEM_TOPLEVEL *w_current)
3474 GtkListStore *store;
3475 GtkComboBox *cbox;
3476 GtkCellLayout *layout;
3477 GtkCellRenderer *text_cell;
3478 GtkCellRenderer *color_cell;
3480 gint i;
3481 gchar *str;
3482 OBJECT *obj;
3483 GtkTreeIter iter;
3485 obj = o_select_return_first_object (w_current);
3486 if (obj != NULL)
3487 w_current->edit_color = obj->saved_color;
3489 /* The columns are: name of color, index of color. */
3490 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3491 cbox = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)));
3492 layout = GTK_CELL_LAYOUT (cbox); /* For convenience */
3494 /* Renders the color swatch. Since this won't contain text, set a
3495 * minimum width. */
3496 color_cell = GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3497 g_object_set (color_cell, "width", 25, NULL);
3498 gtk_cell_layout_pack_start (layout, color_cell, FALSE);
3499 gtk_cell_layout_set_cell_data_func (layout, color_cell,
3500 color_menu_swatch_layout_data,
3501 (gpointer) w_current,
3502 NULL);
3504 /* Renders the name of the color */
3505 text_cell = GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3506 g_object_set (text_cell, "xpad", 5, NULL);
3507 gtk_cell_layout_pack_start (layout, text_cell, TRUE);
3508 gtk_cell_layout_add_attribute (layout, text_cell, "text", 0);
3510 /* Populate the list */
3511 for (i = 0; i < MAX_COLORS; i++) {
3512 /* Skip 'invalid' colors. FIXME this is ugly. */
3513 gchar *buf = x_color_get_name(i);
3514 if (buf == NULL) continue;
3515 g_free (buf);
3517 str = index2functionstring (i);
3518 gtk_list_store_append (store, &iter);
3519 gtk_list_store_set (store, &iter, 0, str, 1, i, -1);
3520 if (i == w_current->edit_color)
3521 gtk_combo_box_set_active_iter (cbox, &iter);
3524 g_signal_connect (cbox,
3525 "changed",
3526 GTK_SIGNAL_FUNC (color_menu_change_selection),
3527 w_current);
3529 return GTK_WIDGET (cbox);
3532 /*! \brief Apply a color change to selected objects
3533 * \par Function Description
3534 * This function applies a color change to the currently selected objects.
3536 void color_edit_dialog_apply(GtkWidget *w, GSCHEM_TOPLEVEL *w_current)
3538 TOPLEVEL *toplevel = safe_toplevel(w_current);
3539 PAGE *page = safe_page_current(toplevel);;
3540 GList *s_current = NULL;
3541 OBJECT *object = NULL;
3543 s_current = geda_list_get_glist(page->selection_list);
3545 while(s_current != NULL) {
3546 object = s_current->data;
3547 if (object == NULL) {
3548 fprintf(stderr, _("ERROR: NULL object in color_edit_dialog_apply!\n"));
3549 exit(-1);
3552 switch(object->type) {
3553 case(OBJ_LINE):
3554 case(OBJ_BOX):
3555 case(OBJ_CIRCLE):
3556 case(OBJ_NET):
3557 case(OBJ_BUS):
3558 case(OBJ_PIN):
3559 case(OBJ_ARC):
3560 object->saved_color = w_current->edit_color;
3561 page->CHANGED = 1;
3562 break;
3564 case(OBJ_TEXT):
3565 object->saved_color = w_current->edit_color;
3566 o_complex_set_saved_color_only(
3567 object->text->prim_objs,
3568 w_current->edit_color);
3569 page->CHANGED = 1;
3570 break;
3573 s_current = g_list_next(s_current);
3575 o_undo_savestate(w_current, UNDO_ALL);
3578 /*! \brief response function for the color edit dialog
3579 * \par Function Description
3580 * This function takes the user response from the color edit dialog
3582 void color_edit_dialog_response(GtkWidget *widget, gint response, GSCHEM_TOPLEVEL *w_current)
3584 switch (response) {
3585 case GTK_RESPONSE_REJECT:
3586 case GTK_RESPONSE_DELETE_EVENT:
3587 gtk_widget_destroy(w_current->clwindow);
3588 w_current->clwindow = NULL;
3589 break;
3590 case GTK_RESPONSE_ACCEPT:
3591 color_edit_dialog_apply(widget, w_current);
3592 break;
3593 default:
3594 printf("ERROR: color_edit_dialog_response(): strange signal %d\n",response);
3599 /*! \brief Create the color edit dialog
3600 * \par Function Description
3601 * This function creates the color edit dialog
3603 void color_edit_dialog (GSCHEM_TOPLEVEL *w_current)
3605 GtkWidget *optionmenu;
3606 GtkWidget *label;
3607 GtkWidget *vbox;
3609 if (!w_current->clwindow) {
3610 w_current->clwindow = gschem_dialog_new_with_buttons(_("Color Edit"),
3611 GTK_WINDOW(w_current->main_window),
3612 0, /* nonmodal dialog */
3613 "color-edit", w_current,
3614 GTK_STOCK_CLOSE,
3615 GTK_RESPONSE_REJECT,
3616 GTK_STOCK_APPLY,
3617 GTK_RESPONSE_ACCEPT,
3618 NULL);
3620 /* Set the alternative button order (ok, cancel, help) for other systems */
3621 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->clwindow),
3622 GTK_RESPONSE_ACCEPT,
3623 GTK_RESPONSE_REJECT,
3624 -1);
3626 gtk_window_position (GTK_WINDOW (w_current->clwindow),
3627 GTK_WIN_POS_MOUSE);
3629 gtk_dialog_set_default_response (GTK_DIALOG (w_current->clwindow),
3630 GTK_RESPONSE_ACCEPT);
3632 gtk_signal_connect(GTK_OBJECT(w_current->clwindow), "response",
3633 GTK_SIGNAL_FUNC(color_edit_dialog_response),
3634 w_current);
3636 gtk_container_border_width(GTK_CONTAINER(w_current->clwindow),
3637 DIALOG_BORDER_SPACING);
3638 vbox = GTK_DIALOG(w_current->clwindow)->vbox;
3639 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3641 label = gtk_label_new(_("Object color:"));
3642 gtk_misc_set_alignment(GTK_MISC(label),0,0);
3643 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
3645 optionmenu = create_color_menu (w_current);
3646 gtk_box_pack_start(GTK_BOX(vbox),
3647 optionmenu, FALSE, FALSE, 0);
3648 gtk_widget_show_all(w_current->clwindow);
3651 else { /* dialog already created */
3652 gtk_window_present(GTK_WINDOW(w_current->clwindow));
3656 /***************** End of color edit dialog box *********************/
3658 /***************** Start of help/keymapping dialog box **************/
3660 /*! \brief Response function for the hotkey dialog
3661 * \par Function Description
3662 * This function destroys the hotkey dialog and does some cleanup.
3664 void x_dialog_hotkeys_response(GtkWidget *w, gint response,
3665 GSCHEM_TOPLEVEL *w_current)
3667 switch(response) {
3668 case GTK_RESPONSE_REJECT:
3669 case GTK_RESPONSE_DELETE_EVENT:
3670 /* void */
3671 break;
3672 default:
3673 printf("x_dialog_hotkeys_response(): strange signal %d\n", response);
3675 /* clean up */
3676 gtk_widget_destroy(w_current->hkwindow);
3677 w_current->hkwindow = NULL;
3680 /*! \brief Creates the hotkeys dialog
3681 * \par Function Description
3682 * This function creates the hotkey dialog and puts the list of hotkeys
3683 * into it.
3685 void x_dialog_hotkeys (GSCHEM_TOPLEVEL *w_current)
3687 GtkWidget *vbox, *scrolled_win;
3688 GtkListStore *store;
3689 GtkWidget *treeview;
3690 GtkCellRenderer *renderer;
3691 GtkTreeViewColumn *column;
3692 GArray *keymap;
3693 gint i;
3694 struct keyseq_action_t {
3695 gchar *keyseq, *action;
3698 if (!w_current->hkwindow) {
3699 w_current->hkwindow = gschem_dialog_new_with_buttons(_("Hotkeys"),
3700 GTK_WINDOW(w_current->main_window),
3701 0, /* not modal */
3702 "hotkeys", w_current,
3703 GTK_STOCK_CLOSE,
3704 GTK_RESPONSE_REJECT,
3705 NULL);
3707 gtk_window_position (GTK_WINDOW (w_current->hkwindow),
3708 GTK_WIN_POS_NONE);
3710 gtk_signal_connect (GTK_OBJECT (w_current->hkwindow), "response",
3711 GTK_SIGNAL_FUNC(x_dialog_hotkeys_response),
3712 w_current);
3714 gtk_dialog_set_default_response(GTK_DIALOG(w_current->hkwindow),
3715 GTK_RESPONSE_ACCEPT);
3717 gtk_container_border_width (GTK_CONTAINER (w_current->hkwindow),
3718 DIALOG_BORDER_SPACING);
3719 gtk_widget_set_usize(w_current->hkwindow, 300,300);
3721 vbox = GTK_DIALOG(w_current->hkwindow)->vbox;
3722 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3724 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
3725 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
3726 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
3727 GTK_POLICY_AUTOMATIC,
3728 GTK_POLICY_AUTOMATIC);
3730 /* the model */
3731 store = gtk_list_store_new (2,G_TYPE_STRING, G_TYPE_STRING);
3733 /* retrieve current keymap */
3734 keymap = g_keys_dump_keymap ();
3735 /* add each keymap entry to the list store of the dialog */
3736 for (i = 0; keymap && i < keymap->len; i++) {
3737 GtkTreeIter iter;
3738 struct keyseq_action_t *keymap_entry;
3740 keymap_entry = &g_array_index (keymap, struct keyseq_action_t, i);
3741 gtk_list_store_append (store, &iter);
3742 gtk_list_store_set (store, &iter,
3743 0, keymap_entry->action,
3744 1, keymap_entry->keyseq,
3745 -1);
3748 /* finally free the array for keymap */
3749 for (i = 0; keymap && i < keymap->len; i++) {
3750 struct keyseq_action_t *keymap_entry;
3751 keymap_entry = &g_array_index (keymap, struct keyseq_action_t, i);
3752 g_free (keymap_entry->keyseq);
3753 g_free (keymap_entry->action);
3755 g_array_free (keymap, TRUE);
3757 /* the tree view */
3758 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
3759 gtk_container_add(GTK_CONTAINER(scrolled_win), treeview);
3761 /* the columns */
3762 renderer = gtk_cell_renderer_text_new ();
3763 column = gtk_tree_view_column_new_with_attributes (_("Function"),
3764 renderer,
3765 "text",
3767 NULL);
3768 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
3769 renderer = gtk_cell_renderer_text_new ();
3770 column = gtk_tree_view_column_new_with_attributes (_("Keystroke(s)"),
3771 renderer,
3772 "text",
3774 NULL);
3775 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
3777 /* show all recursively */
3778 gtk_widget_show_all(w_current->hkwindow);
3781 else { /* dialog already created */
3782 gtk_window_present(GTK_WINDOW(w_current->hkwindow));
3786 /***************** End of help/keymapping dialog box ****************/
3788 /*********** Start of misc support functions for dialog boxes *******/
3789 extern GtkWidget *stwindow;
3791 /*! \todo Finish function documentation!!!
3792 * \brief
3793 * \par Function Description
3796 void x_dialog_raise_all(GSCHEM_TOPLEVEL *w_current)
3798 if(w_current->sowindow) {
3799 gdk_window_raise(w_current->sowindow->window);
3801 if(w_current->cswindow) {
3802 gdk_window_raise(w_current->cswindow->window);
3804 if(w_current->iwindow) {
3805 gdk_window_raise(w_current->iwindow->window);
3807 if(w_current->tiwindow) {
3808 gdk_window_raise(w_current->tiwindow->window);
3810 if(w_current->tewindow) {
3811 gdk_window_raise(w_current->tewindow->window);
3813 if(w_current->sewindow) {
3814 gdk_window_raise(w_current->sewindow->window);
3816 if(w_current->aawindow) {
3817 gdk_window_raise(w_current->aawindow->window);
3819 if(w_current->mawindow) {
3820 gdk_window_raise(w_current->mawindow->window);
3822 if(w_current->aewindow) {
3823 gdk_window_raise(w_current->aewindow->window);
3825 if(w_current->trwindow) {
3826 gdk_window_raise(w_current->trwindow->window);
3828 if(w_current->tswindow) {
3829 gdk_window_raise(w_current->tswindow->window);
3831 if(w_current->abwindow) {
3832 gdk_window_raise(w_current->abwindow->window);
3834 if(w_current->hkwindow) {
3835 gdk_window_raise(w_current->hkwindow->window);
3837 if(w_current->cowindow) {
3838 gdk_window_raise(w_current->cowindow->window);
3840 if(w_current->clwindow) {
3841 gdk_window_raise(w_current->clwindow->window);
3846 /*********** End of misc support functions for dialog boxes *******/
3848 /***************** Start of generic message dialog box *******************/
3850 /*! \todo Finish function documentation!!!
3851 * \brief
3852 * \par Function Description
3855 void generic_msg_dialog (const char *msg)
3857 GtkWidget *dialog;
3859 dialog = gtk_message_dialog_new (NULL,
3860 GTK_DIALOG_MODAL |
3861 GTK_DIALOG_DESTROY_WITH_PARENT,
3862 GTK_MESSAGE_INFO,
3863 GTK_BUTTONS_OK,
3864 "%s", msg);
3866 gtk_dialog_run (GTK_DIALOG (dialog));
3867 gtk_widget_destroy (dialog);
3871 /***************** End of generic message dialog box *********************/
3873 /***************** Start of generic confirm dialog box *******************/
3875 /*! \todo Finish function documentation!!!
3876 * \brief
3877 * \par Function Description
3880 int generic_confirm_dialog (const char *msg)
3882 GtkWidget *dialog;
3883 gint r;
3885 dialog = gtk_message_dialog_new (NULL,
3886 GTK_DIALOG_MODAL |
3887 GTK_DIALOG_DESTROY_WITH_PARENT,
3888 GTK_MESSAGE_INFO,
3889 GTK_BUTTONS_OK_CANCEL,
3890 "%s", msg);
3892 r = gtk_dialog_run (GTK_DIALOG (dialog));
3893 gtk_widget_destroy (dialog);
3895 if (r == GTK_RESPONSE_OK)
3896 return 1;
3897 else
3898 return 0;
3901 /***************** End of generic confirm dialog box *********************/
3903 /***************** Start of generic file select dialog box ***************/
3904 /*! \todo Finish function documentation!!!
3905 * \brief
3906 * \par Function Description
3908 * \warning
3909 * Caller must g_free returned character string.
3911 char *generic_filesel_dialog (const char *msg, const char *templ, gint flags)
3913 GtkWidget *dialog;
3914 gchar *result = NULL, *folder, *seed;
3915 char *title;
3916 static gchar *path = NULL;
3917 static gchar *shortcuts = NULL;
3919 /* Default to load if not specified. Maybe this should cause an error. */
3920 if (! (flags & (FSB_LOAD | FSB_SAVE))) {
3921 flags = flags | FSB_LOAD;
3924 if (flags & FSB_LOAD) {
3925 title = g_strdup_printf("%s: Open", msg);
3926 dialog = gtk_file_chooser_dialog_new (title,
3927 NULL,
3928 GTK_FILE_CHOOSER_ACTION_OPEN,
3929 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3930 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
3931 NULL);
3932 /* Since this is a load dialog box, the file must exist! */
3933 flags = flags | FSB_MUST_EXIST;
3935 } else {
3936 title = g_strdup_printf("%s: Save", msg);
3937 dialog = gtk_file_chooser_dialog_new (title,
3938 NULL,
3939 GTK_FILE_CHOOSER_ACTION_SAVE,
3940 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3941 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
3942 NULL);
3945 /* Set the alternative button order (ok, cancel, help) for other systems */
3946 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
3947 GTK_RESPONSE_OK,
3948 GTK_RESPONSE_CANCEL,
3949 -1);
3951 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
3953 /* Pick the current default folder to look for files in */
3954 if (path && *path) {
3955 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), path);
3959 /* Pick the current template (*.rc) or default file name */
3960 if (templ && *templ) {
3961 if (flags & FSB_SAVE) {
3962 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), templ);
3963 } else {
3964 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (dialog), templ);
3969 if (shortcuts && *shortcuts) {
3970 printf ("shortcuts = \"%s\"\n", shortcuts);
3971 folder = g_strdup (shortcuts);
3972 seed = folder;
3973 while ((folder = strtok (seed, ":")) != NULL) {
3974 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog),
3975 folder, NULL);
3976 seed = NULL;
3979 g_free (folder);
3982 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
3983 result = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
3984 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
3985 /*! \bug FIXME
3986 if (folder && path) {
3987 dup_string (path, folder);
3988 g_free (folder);
3992 gtk_widget_destroy (dialog);
3994 g_free (title);
3996 return result;
3999 /***************** End of generic file select dialog box *****************/
4001 /*********** Start of find text dialog box *******/
4003 int start_find;
4004 PAGE *remember_page;
4006 /*! \brief response function for the find text dialog
4007 * \par Function Description
4008 * This function takes the string the user likes to find and searches it
4009 * in the schematic.
4011 void find_text_dialog_response(GtkWidget *w, gint response,
4012 GSCHEM_TOPLEVEL *w_current)
4014 TOPLEVEL *toplevel = w_current->toplevel;
4015 GtkWidget *textentry;
4016 GtkWidget *checkdescend;
4017 gchar *string;
4018 gint done=0, close=0;
4020 switch (response) {
4021 case GTK_RESPONSE_ACCEPT:
4022 textentry = g_object_get_data(G_OBJECT(w_current->tfindwindow),"textentry");
4023 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4024 checkdescend = g_object_get_data(G_OBJECT(w_current->tfindwindow),"checkdescend");
4026 strncpy(generic_textstring, string, 256);
4028 if (remember_page != toplevel->page_current) {
4029 s_toplevel_goto_page(toplevel, remember_page);
4031 done =
4032 o_edit_find_text(w_current, remember_page->object_head, string,
4033 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
4034 (checkdescend)),
4035 !start_find);
4036 if (done) {
4037 o_redraw_all(w_current);
4038 close = 1;
4040 start_find = 0;
4041 break;
4042 case GTK_RESPONSE_REJECT:
4043 case GTK_RESPONSE_DELETE_EVENT:
4044 close = 1;
4045 break;
4046 default:
4047 printf("find_text_dialog_response(): strange signal %d\n", response);
4049 if (close) {
4050 gtk_widget_destroy(w_current->tfindwindow);
4051 w_current->tfindwindow = NULL;
4055 /*! \brief Create the text find dialog
4056 * \par Function Description
4057 * This function creates the text find dialog.
4059 void find_text_dialog(GSCHEM_TOPLEVEL *w_current)
4061 GtkWidget *label = NULL;
4062 GtkWidget *vbox;
4063 GtkWidget *checkdescend;
4064 GtkWidget *textentry;
4065 OBJECT *object = NULL;
4067 start_find = 1;
4068 remember_page = w_current->toplevel->page_current;
4069 if ((object = o_select_return_first_object(w_current)) != NULL) {
4070 if (object->type == OBJ_TEXT) {
4071 strncpy(generic_textstring, o_text_get_string(object), 256);
4075 if (!w_current->tfindwindow) {
4076 w_current->tfindwindow = gschem_dialog_new_with_buttons(_("Find Text"),
4077 GTK_WINDOW(w_current->main_window),
4078 0, /* not modal GTK_DIALOG_MODAL */
4079 "find-text", w_current,
4080 GTK_STOCK_CLOSE,
4081 GTK_RESPONSE_REJECT,
4082 GTK_STOCK_FIND,
4083 GTK_RESPONSE_ACCEPT,
4084 NULL);
4086 /* Set the alternative button order (ok, cancel, help) for other systems */
4087 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tfindwindow),
4088 GTK_RESPONSE_ACCEPT,
4089 GTK_RESPONSE_REJECT,
4090 -1);
4092 gtk_window_position(GTK_WINDOW(w_current->tfindwindow),
4093 GTK_WIN_POS_MOUSE);
4095 gtk_signal_connect(GTK_OBJECT(w_current->tfindwindow), "response",
4096 GTK_SIGNAL_FUNC(find_text_dialog_response),
4097 w_current);
4099 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tfindwindow),
4100 GTK_RESPONSE_ACCEPT);
4102 gtk_container_border_width(GTK_CONTAINER(w_current->tfindwindow),
4103 DIALOG_BORDER_SPACING);
4104 vbox = GTK_DIALOG(w_current->tfindwindow)->vbox;
4105 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4107 label = gtk_label_new(_("Text to find:"));
4108 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4109 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4111 textentry = gtk_entry_new_with_max_length(20);
4112 gtk_editable_select_region(GTK_EDITABLE(textentry), 0, -1);
4113 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4114 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4115 gtk_widget_grab_focus(textentry);
4117 checkdescend = gtk_check_button_new_with_label(_("descend into hierarchy"));
4118 gtk_box_pack_start(GTK_BOX(vbox), checkdescend, TRUE, TRUE, 0);
4120 GLADE_HOOKUP_OBJECT(w_current->tfindwindow, textentry, "textentry");
4121 GLADE_HOOKUP_OBJECT(w_current->tfindwindow, checkdescend, "checkdescend");
4123 gtk_widget_show_all(w_current->tfindwindow);
4126 else { /* dialog already created */
4127 gtk_window_present(GTK_WINDOW(w_current->tfindwindow));
4130 /* always select the text string in the entry */
4131 textentry = g_object_get_data (G_OBJECT (w_current->tfindwindow), "textentry");
4132 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4133 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4136 /*********** End of find text dialog box *******/
4138 /*********** Start of hide text dialog box *******/
4140 /*! \brief Response function for the hide text dialog
4141 * \par Function Description
4142 * This is the response function of the hide text dialog. It takes the user input
4143 * and hides all text elements that starts with the searchtext.
4145 void hide_text_dialog_response(GtkWidget *w, gint response,
4146 GSCHEM_TOPLEVEL *w_current)
4148 GtkWidget *textentry;
4149 gchar *string;
4151 switch (response) {
4152 case GTK_RESPONSE_ACCEPT:
4153 textentry = g_object_get_data(G_OBJECT(w_current->thidewindow),"textentry");
4154 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4156 strncpy(generic_textstring, string, 256);
4157 o_edit_hide_specific_text(w_current,
4158 w_current->toplevel->page_current->object_head, string);
4159 break;
4160 case GTK_RESPONSE_REJECT:
4161 case GTK_RESPONSE_DELETE_EVENT:
4162 gtk_widget_destroy(w_current->thidewindow);
4163 w_current->thidewindow = NULL;
4164 break;
4165 default:
4166 printf("show_text_dialog_response(): strange signal %d\n",response);
4170 /*! \brief Creates the hide text dialog
4171 * \par Function Description
4172 * This function creates the hide text dialog.
4174 void hide_text_dialog(GSCHEM_TOPLEVEL * w_current)
4176 GtkWidget *label = NULL;
4177 GtkWidget *textentry;
4178 GtkWidget *vbox;
4180 if (!w_current->thidewindow) {
4181 w_current->thidewindow = gschem_dialog_new_with_buttons(_("Hide Text"),
4182 GTK_WINDOW(w_current->main_window),
4183 0, /* not modal GTK_DIALOG_MODAL, */
4184 "hide-text", w_current,
4185 GTK_STOCK_CLOSE,
4186 GTK_RESPONSE_REJECT,
4187 GTK_STOCK_APPLY,
4188 GTK_RESPONSE_ACCEPT,
4189 NULL);
4191 /* Set the alternative button order (ok, cancel, help) for other systems */
4192 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->thidewindow),
4193 GTK_RESPONSE_ACCEPT,
4194 GTK_RESPONSE_REJECT,
4195 -1);
4197 gtk_window_position(GTK_WINDOW(w_current->thidewindow),
4198 GTK_WIN_POS_MOUSE);
4200 gtk_signal_connect(GTK_OBJECT(w_current->thidewindow), "response",
4201 GTK_SIGNAL_FUNC(hide_text_dialog_response),
4202 w_current);
4204 gtk_dialog_set_default_response(GTK_DIALOG(w_current->thidewindow),
4205 GTK_RESPONSE_ACCEPT);
4207 gtk_container_border_width(GTK_CONTAINER(w_current->thidewindow),
4208 DIALOG_BORDER_SPACING);
4209 vbox = GTK_DIALOG(w_current->thidewindow)->vbox;
4210 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4212 label = gtk_label_new(_("Hide text starting with:"));
4213 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4214 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4216 textentry = gtk_entry_new_with_max_length(20);
4217 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4218 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4219 gtk_widget_grab_focus(textentry);
4221 GLADE_HOOKUP_OBJECT(w_current->thidewindow, textentry, "textentry");
4222 gtk_widget_show_all(w_current->thidewindow);
4225 else { /* dialog already created, just select it */
4226 gtk_window_present(GTK_WINDOW(w_current->thidewindow));
4229 /* always select the text in the search entry */
4230 textentry = g_object_get_data (G_OBJECT (w_current->thidewindow), "textentry");
4231 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4232 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4235 /*********** End of hide text dialog box *******/
4237 /*********** Start of show text dialog box *******/
4239 /*! \brief Response function for the show text dialog
4240 * \par Function Description
4241 * This function takes the users input and searches all strings starting with
4242 * the given search text and hides those text objects.
4244 void show_text_dialog_response(GtkWidget *widget, gint response,
4245 GSCHEM_TOPLEVEL *w_current)
4247 GtkWidget *textentry;
4248 gchar *string;
4250 switch (response) {
4251 case GTK_RESPONSE_ACCEPT:
4252 textentry = g_object_get_data(G_OBJECT(w_current->tshowwindow),"textentry");
4253 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4255 strncpy(generic_textstring, string, 256);
4256 o_edit_show_specific_text(w_current,
4257 w_current->toplevel->page_current->object_head, string);
4258 break;
4259 case GTK_RESPONSE_REJECT:
4260 case GTK_RESPONSE_DELETE_EVENT:
4261 gtk_widget_destroy(w_current->tshowwindow);
4262 w_current->tshowwindow = NULL;
4263 break;
4264 default:
4265 printf("show_text_dialog_response(): strange signal %d\n",response);
4269 /*! \brief Create the show text dialog.
4270 * \par Function Description
4271 * This function creates the show text dialog.
4273 void show_text_dialog(GSCHEM_TOPLEVEL * w_current)
4275 GtkWidget *label = NULL;
4276 GtkWidget *textentry;
4277 GtkWidget *vbox;
4279 if (!w_current->tshowwindow) {
4280 w_current->tshowwindow = gschem_dialog_new_with_buttons(_("Show Text"),
4281 GTK_WINDOW(w_current->main_window),
4282 0, /* not modal GTK_DIALOG_MODAL, */
4283 "show-text", w_current,
4284 GTK_STOCK_CLOSE,
4285 GTK_RESPONSE_REJECT,
4286 GTK_STOCK_APPLY,
4287 GTK_RESPONSE_ACCEPT,
4288 NULL);
4290 /* Set the alternative button order (ok, cancel, help) for other systems */
4291 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tshowwindow),
4292 GTK_RESPONSE_ACCEPT,
4293 GTK_RESPONSE_REJECT,
4294 -1);
4296 gtk_window_position(GTK_WINDOW(w_current->tshowwindow),
4297 GTK_WIN_POS_MOUSE);
4299 gtk_signal_connect(GTK_OBJECT(w_current->tshowwindow), "response",
4300 GTK_SIGNAL_FUNC(show_text_dialog_response),
4301 w_current);
4303 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tshowwindow),
4304 GTK_RESPONSE_ACCEPT);
4306 gtk_container_border_width(GTK_CONTAINER(w_current->tshowwindow),
4307 DIALOG_BORDER_SPACING);
4308 vbox = GTK_DIALOG(w_current->tshowwindow)->vbox;
4309 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4311 label = gtk_label_new(_("Show text starting with:"));
4312 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4313 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4315 textentry = gtk_entry_new_with_max_length(20);
4316 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4317 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4318 gtk_widget_grab_focus(textentry);
4320 GLADE_HOOKUP_OBJECT(w_current->tshowwindow, textentry, "textentry");
4321 gtk_widget_show_all(w_current->tshowwindow);
4324 else { /* dialog already created. Show it */
4325 gtk_window_present(GTK_WINDOW(w_current->tshowwindow));
4328 /* always select the text in the entry */
4329 textentry = g_object_get_data (G_OBJECT (w_current->tshowwindow), "textentry");
4330 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4331 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4334 /*********** End of show text dialog box *******/
4336 /*********** Start of some Gtk utils *******/
4338 /*! \brief Selects all text in a TextView widget
4339 * \par Function Description
4340 * The function selects all the text in a TextView widget.
4342 void select_all_text_in_textview(GtkTextView *textview)
4344 GtkTextBuffer *textbuffer;
4345 GtkTextIter start, end;
4347 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
4348 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
4349 gtk_text_buffer_select_range(textbuffer, &start, &end);
4352 /*! \todo Finish function documentation!!!
4353 * \brief
4354 * \par Function Description
4357 int text_view_calculate_real_tab_width(GtkTextView *textview, int tab_size)
4359 PangoLayout *layout;
4360 gchar *tab_string;
4361 gint tab_width = 0;
4363 if (tab_size == 0)
4364 return -1;
4366 tab_string = g_strnfill (tab_size, ' ');
4368 layout = gtk_widget_create_pango_layout (
4369 GTK_WIDGET (textview),
4370 tab_string);
4371 g_free (tab_string);
4373 if (layout != NULL) {
4374 pango_layout_get_pixel_size (layout, &tab_width, NULL);
4375 g_object_unref (G_OBJECT (layout));
4376 } else
4377 tab_width = -1;
4379 return tab_width;
4383 /*********** End of some Gtk utils *******/
4385 /*********** Start of major symbol changed dialog box *******/
4387 /*! \todo Finish function documentation!!!
4388 * \brief
4389 * \par Function Description
4392 void major_changed_dialog(GSCHEM_TOPLEVEL* w_current)
4394 GtkWidget* dialog;
4395 char* refdes_string = NULL;
4396 char* tmp;
4398 if (w_current->toplevel->major_changed_refdes) {
4400 GList* current = w_current->toplevel->major_changed_refdes;
4401 while (current)
4403 char *value = (char*) current->data;
4405 if (!refdes_string)
4407 refdes_string = g_strdup (value);
4408 } else {
4409 tmp = g_strconcat (refdes_string, "\n", value, NULL);
4410 g_free(refdes_string);
4411 refdes_string = tmp;
4414 current = g_list_next(current);
4417 tmp = g_strconcat (refdes_string,
4418 "\n\nBe sure to verify each of these symbols!",
4419 NULL);
4420 g_free(refdes_string);
4421 refdes_string = tmp;
4423 dialog = gtk_message_dialog_new ((GtkWindow*) w_current->main_window,
4424 GTK_DIALOG_DESTROY_WITH_PARENT,
4425 GTK_MESSAGE_ERROR,
4426 GTK_BUTTONS_CLOSE,
4427 "Major symbol changes detected in refdes:\n\n%s\n",
4428 refdes_string);
4430 gtk_widget_show(dialog);
4432 g_signal_connect_swapped (dialog, "response",
4433 G_CALLBACK (gtk_widget_destroy),
4434 dialog);
4436 g_free(refdes_string);
4440 /*********** End of major symbol changed dialog box *******/
4442 /***************** Start of Close Confirmation dialog box ************/
4444 #define TYPE_CLOSE_CONFIRMATION_DIALOG (close_confirmation_dialog_get_type ())
4445 #define CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialog))
4446 #define CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4447 #define IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG))
4448 #define IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG))
4449 #define CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4452 typedef struct _CloseConfirmationDialog CloseConfirmationDialog;
4453 typedef struct _CloseConfirmationDialogClass CloseConfirmationDialogClass;
4455 struct _CloseConfirmationDialog
4457 GtkDialog parent;
4459 GtkListStore *store_unsaved_pages;
4462 struct _CloseConfirmationDialogClass
4464 GtkDialogClass parent_class;
4468 enum {
4469 PROP_UNSAVED_PAGE=1,
4470 PROP_UNSAVED_PAGES,
4471 PROP_SELECTED_PAGES
4474 enum {
4475 COLUMN_SAVE,
4476 COLUMN_PAGE,
4477 NUM_COLUMNS
4481 static gpointer close_confirmation_dialog_parent_class = NULL;
4484 static void close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass);
4485 static void close_confirmation_dialog_init (CloseConfirmationDialog *self);
4486 static void close_confirmation_dialog_set_property (GObject *object,
4487 guint property_id,
4488 const GValue *value,
4489 GParamSpec *pspec);
4490 static void close_confirmation_dialog_get_property (GObject *object,
4491 guint property_id,
4492 GValue *value,
4493 GParamSpec *pspec);
4494 static GObject* close_confirmation_dialog_constructor (GType type,
4495 guint n_construct_properties,
4496 GObjectConstructParam *construct_params);
4498 GList *close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog);
4502 GType
4503 close_confirmation_dialog_get_type ()
4505 static GType close_confirmation_dialog_type = 0;
4507 if (!close_confirmation_dialog_type) {
4508 static const GTypeInfo close_confirmation_dialog_info = {
4509 sizeof(CloseConfirmationDialogClass),
4510 NULL, /* base_init */
4511 NULL, /* base_finalize */
4512 (GClassInitFunc) close_confirmation_dialog_class_init,
4513 NULL, /* class_finalize */
4514 NULL, /* class_data */
4515 sizeof(CloseConfirmationDialog),
4516 0, /* n_preallocs */
4517 (GInstanceInitFunc) close_confirmation_dialog_init,
4520 close_confirmation_dialog_type =
4521 g_type_register_static (GTK_TYPE_DIALOG,
4522 "CloseConfirmationDialog",
4523 &close_confirmation_dialog_info, 0);
4526 return close_confirmation_dialog_type;
4529 static void
4530 close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass)
4532 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
4534 close_confirmation_dialog_parent_class = g_type_class_peek_parent (klass);
4536 gobject_class->constructor = close_confirmation_dialog_constructor;
4537 gobject_class->set_property = close_confirmation_dialog_set_property;
4538 gobject_class->get_property = close_confirmation_dialog_get_property;
4540 g_object_class_install_property (
4541 gobject_class, PROP_UNSAVED_PAGE,
4542 g_param_spec_pointer ("unsaved-page",
4545 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
4546 g_object_class_install_property (
4547 gobject_class, PROP_UNSAVED_PAGES,
4548 g_param_spec_pointer ("unsaved-pages",
4551 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
4552 g_object_class_install_property (
4553 gobject_class, PROP_SELECTED_PAGES,
4554 g_param_spec_pointer ("selected-pages",
4557 G_PARAM_READABLE));
4561 static void
4562 close_confirmation_dialog_init (CloseConfirmationDialog *self)
4564 /* create model for treeview and populate */
4565 self->store_unsaved_pages = gtk_list_store_new (NUM_COLUMNS,
4566 G_TYPE_BOOLEAN, /* save? */
4567 G_TYPE_POINTER); /* page */
4571 /*! \brief Returns the number of pages in the model.
4572 * \par Function Description
4573 * This function determines the number of pages with unsaved changes
4574 * from the model.
4576 * \param in model The tree model.
4577 * \returns The number of pages with unsaved changes.
4579 static gint
4580 count_pages (GtkTreeModel *model)
4582 GtkTreeIter iter;
4583 gint n_pages;
4585 gtk_tree_model_get_iter_first (model, &iter);
4586 for (n_pages = 1;
4587 gtk_tree_model_iter_next (model, &iter);
4588 n_pages++);
4590 return n_pages;
4593 /*! \brief Returns the name to use for the given page in the model.
4594 * \par Function Description
4595 * This function determines the text to be used to identify a
4596 * specific page from the model of pages with unsaved changes.
4598 * If <B>piter</B> is NULL, the name for the first page of the model
4599 * is returned. Otherwise, it returns the name for the page defined
4600 * by the pointed iterator.
4602 * The returned value must be freed by caller.
4604 * \param in model The tree model.
4605 * \param in piter A pointer on a GtkTreeIter of model or NULL.
4606 * \returns The name for the page.
4608 static gchar*
4609 get_page_name (GtkTreeModel *model, GtkTreeIter *piter)
4611 GtkTreeIter iter;
4612 PAGE *page;
4614 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
4616 if (piter == NULL) {
4617 gtk_tree_model_get_iter_first (model, &iter);
4618 } else {
4619 iter = *piter;
4622 gtk_tree_model_get (model, &iter,
4623 COLUMN_PAGE, &page,
4624 -1);
4625 g_assert (page != NULL && page->page_filename != NULL);
4626 return g_path_get_basename (page->page_filename);
4629 /*! \brief Sets the contents of the name cell in the treeview of dialog.
4630 * \par Function Description
4631 * This functions sets the cell of the treeview with the short name
4632 * of the page obtained with <B>get_page_name()</B>.
4634 * \param in tree_column A GtkTreeColumn.
4635 * \param in cell The GtkCellRenderer that is being rendered by
4636 * tree_column.
4637 * \param in tree_model The GtkTreeModel being rendered.
4638 * \param in iter A GtkTreeIter of the current row rendered.
4639 * \param in data .
4641 static void
4642 close_confirmation_dialog_set_page_name (GtkTreeViewColumn *tree_column,
4643 GtkCellRenderer *cell,
4644 GtkTreeModel *tree_model,
4645 GtkTreeIter *iter,
4646 gpointer data)
4648 gchar *page_name;
4650 page_name = get_page_name (tree_model, iter);
4651 g_object_set (cell,
4652 "text", page_name,
4653 NULL);
4654 g_free (page_name);
4658 /*! \brief Callback function for the toggled signal of check box in treeview.
4659 * \par Function Description
4660 * This functions changes the value of the save column in the model
4661 * for the affected row when user toggles the check box in the
4662 * treeview.
4664 * \param in cell_renderer The GtkCellRendererToggle.
4665 * \param in path The GtkTreePath to the concerned row in model.
4666 * \param in user The dialog as user data.
4668 static void
4669 close_confirmation_dialog_callback_renderer_toggled (GtkCellRendererToggle *cell_renderer,
4670 gchar *path,
4671 gpointer user_data)
4673 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (user_data);
4674 GtkTreeModel *model;
4675 GtkTreeIter iter;
4676 gboolean save;
4678 model = GTK_TREE_MODEL (dialog->store_unsaved_pages);
4680 gtk_tree_model_get_iter_from_string (model, &iter, path);
4681 gtk_tree_model_get (model, &iter,
4682 COLUMN_SAVE, &save,
4683 -1);
4684 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
4685 COLUMN_SAVE, (save != TRUE),
4686 -1);
4690 /*! \brief Adds a treeview to confirmation dialog for selecting of pages.
4691 * \par Function Description
4692 * This function adds a treeview and caption to display the content
4693 * of the dialog model of pages with unsaved changes.
4695 * The treeview displays the page names with check boxes.
4697 * \param in dialog The dialog.
4698 * \returns A pointer on the GtkVBox to add to dialog.
4700 static GtkWidget*
4701 close_confirmation_dialog_build_page_list (CloseConfirmationDialog *dialog)
4703 GtkWidget *vbox, *scrolled_window, *treeview, *label;
4704 GtkCellRenderer *renderer;
4705 GtkTreeViewColumn *column;
4706 const gchar *text;
4708 /* place the treeview and its caption into their own box */
4709 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
4710 /* GtkBox */
4711 "homogeneous", FALSE,
4712 "spacing", 8,
4713 NULL));
4715 /* the list of pages with changes */
4716 /* - scrolled window as container for the treeview first */
4717 scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
4718 /* GtkScrolledWindow */
4719 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
4720 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
4721 "shadow-type", GTK_SHADOW_IN,
4722 NULL));
4723 /* - then the treeview */
4724 /* create model for treeview and populate */
4725 treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
4726 /* GtkTreeView */
4727 "enable-search", FALSE,
4728 "headers-visible", FALSE,
4729 "model", dialog->store_unsaved_pages,
4730 NULL));
4731 renderer = gtk_cell_renderer_toggle_new ();
4732 g_signal_connect (renderer, "toggled",
4733 G_CALLBACK (
4734 close_confirmation_dialog_callback_renderer_toggled),
4735 dialog);
4736 column = gtk_tree_view_column_new_with_attributes ("Save?",
4737 renderer,
4738 "active", COLUMN_SAVE,
4739 NULL);
4740 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4742 renderer = gtk_cell_renderer_text_new ();
4743 column = GTK_TREE_VIEW_COLUMN (
4744 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
4745 /* GtkTreeViewColumn */
4746 "title", _("Name"),
4747 NULL));
4748 gtk_tree_view_column_pack_start (column, renderer, TRUE);
4749 gtk_tree_view_column_set_cell_data_func (column, renderer,
4750 close_confirmation_dialog_set_page_name,
4751 NULL, NULL);
4752 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4754 gtk_container_add (GTK_CONTAINER (scrolled_window), treeview);
4756 gtk_box_pack_end (GTK_BOX (vbox), scrolled_window,
4757 TRUE, TRUE, 0);
4759 /* the caption label above the list of pages */
4760 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4761 /* GtkMisc */
4762 "xalign", 0.0,
4763 "yalign", 0.0,
4764 /* GtkLabel */
4765 "wrap", TRUE,
4766 "mnemonic-widget", treeview,
4767 NULL));
4768 text = _("S_elect the schematics you want to save:");
4769 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), text);
4770 gtk_label_set_mnemonic_widget (GTK_LABEL (label), treeview);
4771 gtk_box_pack_start (GTK_BOX (vbox), label,
4772 FALSE, FALSE, 0);
4774 return vbox;
4777 static GObject*
4778 close_confirmation_dialog_constructor (GType type,
4779 guint n_construct_properties,
4780 GObjectConstructParam *construct_params)
4782 GObject *object;
4783 CloseConfirmationDialog *dialog;
4784 GtkWidget *hbox, *image, *vbox, *label;
4785 GtkTreeIter iter;
4786 gboolean ret, single_page;
4787 gchar *tmp, *str;
4789 /* chain up to constructor of parent class */
4790 object =
4791 G_OBJECT_CLASS (close_confirmation_dialog_parent_class)->constructor (
4792 type,
4793 n_construct_properties,
4794 construct_params);
4795 dialog = CLOSE_CONFIRMATION_DIALOG (object);
4797 g_object_set (dialog,
4798 /* GtkDialog */
4799 "has-separator", FALSE,
4800 /* GtkWindow */
4801 "resizable", FALSE,
4802 "skip-taskbar-hint", TRUE,
4803 /* GtkContainer */
4804 "border-width", 5,
4805 NULL);
4806 g_object_set (GTK_DIALOG (dialog)->vbox,
4807 /* GtkBox */
4808 "spacing", 14,
4809 NULL);
4810 g_object_set (GTK_DIALOG (dialog)->action_area,
4811 /* GtkBox */
4812 "spacing", 6,
4813 /* GtkContainer */
4814 "border-width", 5,
4815 NULL);
4817 /* check if there is one or more than one page with changes */
4818 ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (
4819 dialog->store_unsaved_pages),
4820 &iter);
4821 g_assert (ret);
4822 single_page = !gtk_tree_model_iter_next (GTK_TREE_MODEL (
4823 dialog->store_unsaved_pages),
4824 &iter);
4826 /* here starts the layout of the dialog */
4827 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
4828 /* GtkContainer */
4829 "border-width", 5,
4830 /* GtkBox */
4831 "homogeneous", FALSE,
4832 "spacing", 12,
4833 NULL));
4835 /* warning image */
4836 image = g_object_new (GTK_TYPE_IMAGE,
4837 /* GtkMisc */
4838 "xalign", 0.5,
4839 "yalign", 0.0,
4840 /* GtkImage */
4841 "stock", GTK_STOCK_DIALOG_WARNING,
4842 "icon-size", GTK_ICON_SIZE_DIALOG,
4843 NULL);
4844 gtk_box_pack_start (GTK_BOX (hbox), image,
4845 FALSE, FALSE, 0);
4847 /* vertical box on the right hand side of the dialog */
4848 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
4849 /* GtkBox */
4850 "homogeneous", FALSE,
4851 "spacing", 12,
4852 NULL));
4854 /* primary label */
4855 if (single_page) {
4856 /* single page */
4857 gchar *page_name;
4859 page_name = get_page_name (GTK_TREE_MODEL (dialog->store_unsaved_pages),
4860 NULL);
4861 tmp = g_strdup_printf (
4862 _("Save the changes to schematic \"%s\" before closing?"),
4863 page_name);
4864 g_free (page_name);
4865 } else {
4866 /* multi page */
4867 tmp = g_strdup_printf (
4868 _("There are %d schematics with unsaved changes. "
4869 "Save changes before closing?"),
4870 count_pages (GTK_TREE_MODEL (dialog->store_unsaved_pages)));
4872 str = g_strconcat ("<big><b>", tmp, "</b></big>", NULL);
4873 g_free (tmp);
4874 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4875 /* GtkMisc */
4876 "xalign", 0.0,
4877 "yalign", 0.0,
4878 "selectable", TRUE,
4879 /* GtkLabel */
4880 "wrap", TRUE,
4881 "use-markup", TRUE,
4882 "label", str,
4883 NULL));
4884 g_free (str);
4885 gtk_box_pack_start (GTK_BOX (vbox), label,
4886 FALSE, FALSE, 0);
4888 if (!single_page) {
4889 /* more than one page with changes, display each page and offer */
4890 /* the opportunity to save them before exiting */
4891 gtk_box_pack_start (GTK_BOX (vbox),
4892 close_confirmation_dialog_build_page_list (dialog),
4893 FALSE, FALSE, 0);
4896 /* secondary label */
4897 str = _("If you don't save, all your changes will be permanently lost.");
4898 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4899 /* GtkMisc */
4900 "xalign", 0.0,
4901 "yalign", 0.0,
4902 "selectable", TRUE,
4903 /* GtkLabel */
4904 "wrap", TRUE,
4905 "label", str,
4906 NULL));
4907 gtk_box_pack_start (GTK_BOX (vbox), label,
4908 FALSE, FALSE, 0);
4911 gtk_box_pack_start (GTK_BOX (hbox), vbox,
4912 FALSE, FALSE, 0);
4915 /* add buttons to dialog action area */
4916 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
4917 _("_Close without saving"), GTK_RESPONSE_NO,
4918 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4919 GTK_STOCK_SAVE, GTK_RESPONSE_YES,
4920 NULL);
4922 /* Set the alternative button order (ok, cancel, help) for other systems */
4923 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
4924 GTK_RESPONSE_YES,
4925 GTK_RESPONSE_NO,
4926 GTK_RESPONSE_CANCEL,
4927 -1);
4929 /* all done, let's show the contents of the dialog */
4930 gtk_widget_show_all (hbox);
4932 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
4933 FALSE, FALSE, 0);
4935 return object;
4938 static void
4939 close_confirmation_dialog_set_property (GObject *object,
4940 guint property_id,
4941 const GValue *value,
4942 GParamSpec *pspec)
4944 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
4945 GtkTreeIter iter;
4946 gpointer data;
4947 GList *p_current;
4949 switch(property_id) {
4950 case PROP_UNSAVED_PAGE:
4951 data = g_value_get_pointer (value);
4952 if (data != NULL) {
4953 /* add single page to model */
4954 gtk_list_store_append (dialog->store_unsaved_pages,
4955 &iter);
4956 gtk_list_store_set (dialog->store_unsaved_pages,
4957 &iter,
4958 COLUMN_SAVE, TRUE,
4959 COLUMN_PAGE, data,
4960 -1);
4962 break;
4964 case PROP_UNSAVED_PAGES:
4965 data = g_value_get_pointer (value);
4966 /* add set of pages to model */
4967 for (p_current = (GList*)data;
4968 p_current != NULL;
4969 p_current = g_list_next (p_current)) {
4970 gtk_list_store_append (dialog->store_unsaved_pages,
4971 &iter);
4972 gtk_list_store_set (dialog->store_unsaved_pages,
4973 &iter,
4974 COLUMN_SAVE, TRUE,
4975 COLUMN_PAGE, p_current->data,
4976 -1);
4978 break;
4980 default:
4981 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4986 static void
4987 close_confirmation_dialog_get_property (GObject *object,
4988 guint property_id,
4989 GValue *value,
4990 GParamSpec *pspec)
4992 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
4994 switch(property_id) {
4995 case PROP_SELECTED_PAGES:
4996 g_value_set_pointer (
4997 value,
4998 close_confirmation_dialog_get_selected_pages (dialog));
4999 break;
5001 default:
5002 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
5007 /*! \brief Helps building a list of selected page to save.
5008 * \par Function Description
5009 * This is the <B>GtkTreeModelForeachFunc</B> for function
5010 * <B>close_confirmation_dialog_get_selected_pages()</B>.
5012 * It builds from the tree model a list of PAGEs for which a save
5013 * action has been requested. Each selected page is appended to the
5014 * GList pointed by <B>data</B>
5016 * \param in model The tree model.
5017 * \param in path .
5018 * \param in iter .
5019 * \param in data A pointer on a GList* to fill.
5020 * \returns FALSE to continue walking the tree.
5022 static gboolean
5023 get_selected_pages (GtkTreeModel *model,
5024 GtkTreePath *path,
5025 GtkTreeIter *iter,
5026 gpointer data)
5028 PAGE *page;
5029 gboolean save;
5031 gtk_tree_model_get (model, iter,
5032 COLUMN_SAVE, &save,
5033 COLUMN_PAGE, &page,
5034 -1);
5035 if (save) {
5036 g_assert (page != NULL);
5037 *(GList**)data = g_list_append (*(GList**)data, page);
5040 return FALSE;
5043 /*! \brief Returns a list of the selected pages with changes to save.
5044 * \par Function Description
5045 * This function returns the pages that the user has selected in the
5046 * confirmation dialog.
5048 * The returned list must be freed.
5050 * \param in dialog The dialog.
5051 * \returns A GList of selected PAGE* in dialog.
5053 GList*
5054 close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog)
5056 GList *selected = NULL;
5058 gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->store_unsaved_pages),
5059 (GtkTreeModelForeachFunc)get_selected_pages,
5060 &selected);
5062 return selected;
5066 /*! \brief Asks for confirmation before closing a changed page.
5067 * \par Function Description
5068 * This function asks the user to confirm its closing order for
5069 * page <B>page</B> while it still has unsaved changes.
5071 * It displays a message dialog inviting the user to cancel the
5072 * closing, or to discard the changes or to save the changes to a
5073 * file.
5075 * \param in toplevel The toplevel environment.
5076 * \param in page The page to close.
5078 void
5079 x_dialog_close_changed_page (GSCHEM_TOPLEVEL *w_current, PAGE *page)
5081 GtkWidget *dialog;
5082 PAGE *keep_page;
5084 g_return_if_fail (page != NULL && page->CHANGED);
5086 keep_page = w_current->toplevel->page_current;
5088 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
5089 "unsaved-page", page,
5090 NULL));
5091 /* set default response signal. This is usually triggered by the
5092 "Return" key */
5093 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
5094 GTK_RESPONSE_YES);
5096 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
5097 case GTK_RESPONSE_NO:
5098 /* action selected: close without saving */
5099 /* close the page, discard changes */
5100 x_window_close_page (w_current, page);
5101 break;
5104 case GTK_RESPONSE_YES:
5105 /* action selected: save */
5106 s_toplevel_goto_page(w_current->toplevel, page);
5107 i_callback_file_save(w_current, 0, NULL);
5108 /* has the page been really saved? */
5109 if (!page->CHANGED) {
5110 x_window_close_page (w_current, page);
5112 /* no, user has cancelled the save and page has changes */
5113 /* do not close page */
5114 break;
5116 case GTK_RESPONSE_CANCEL:
5117 /* action selected: cancel */
5118 /* fall through */
5119 default:
5120 /* Hit when the user breaks out of the dialog with the escape key
5121 * or otherwise destroys the dialog window without a proper response */
5122 /* nothing to do */
5123 break;
5125 gtk_widget_destroy (dialog);
5127 /* Switch back to the page we were on if it wasn't the one being closed */
5128 g_return_if_fail (keep_page != NULL);
5129 if (keep_page != page)
5130 s_toplevel_goto_page(w_current->toplevel, keep_page);
5133 /*! \brief Asks for confirmation before closing a window.
5134 * \par Function Description
5135 * This function asks the user to confirm its closing order for
5136 * the given window.
5138 * The user is given the possibility to save the pages that currently
5139 * have unsaved changes, if any.
5141 * It returns TRUE if the user really accepts the close of the
5142 * window. Otherwise the user has somehow cancelled and the window
5143 * must not be closed.
5145 * \param in toplevel The toplevel environment.
5146 * \returns TRUE if the window can be closed, FALSE otherwise.
5148 gboolean
5149 x_dialog_close_window (GSCHEM_TOPLEVEL *w_current)
5151 TOPLEVEL *toplevel = w_current->toplevel;
5152 GList *iter;
5153 GtkWidget *dialog;
5154 PAGE *p_current;
5155 PAGE *keep_page;
5156 GList *unsaved_pages, *p_unsaved;
5157 gboolean ret = FALSE;
5159 keep_page = toplevel->page_current;
5161 for ( iter = geda_list_get_glist( toplevel->pages ), unsaved_pages = NULL;
5162 iter != NULL;
5163 iter = g_list_next( iter ) ) {
5165 p_current = (PAGE*)iter->data;
5167 if (p_current->CHANGED) {
5168 unsaved_pages = g_list_append (unsaved_pages, (gpointer)p_current);
5172 if (unsaved_pages == NULL) {
5173 /* no page with unsaved changes, close window */
5174 return TRUE;
5177 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
5178 "unsaved-pages", unsaved_pages,
5179 NULL));
5181 gtk_window_set_transient_for (GTK_WINDOW (dialog),
5182 GTK_WINDOW (w_current->main_window));
5184 g_list_free (unsaved_pages);
5185 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
5186 case GTK_RESPONSE_NO:
5187 /* action selected: close without saving */
5188 /* discard changes, ok to close window */
5189 ret = TRUE;
5190 break;
5192 case GTK_RESPONSE_YES:
5193 /* action selected: save */
5194 g_object_get (dialog,
5195 "selected-pages", &unsaved_pages,
5196 NULL);
5197 for (p_unsaved = unsaved_pages, ret = TRUE;
5198 p_unsaved != NULL;
5199 p_unsaved = g_list_next (p_unsaved)) {
5200 p_current = (PAGE*)p_unsaved->data;
5202 s_toplevel_goto_page(toplevel, p_current);
5203 i_callback_file_save(w_current, 0, NULL);
5204 /* if user cancelled previous, do not close window */
5205 ret &= !p_current->CHANGED;
5207 g_list_free (unsaved_pages);
5208 break;
5210 case GTK_RESPONSE_CANCEL:
5211 /* action selected: cancel */
5212 /* fall through */
5213 default:
5214 /* Hit when the user breaks out of the dialog with the escape key
5215 * or otherwise destroys the dialog window without a proper response */
5216 ret = FALSE;
5217 break;
5219 gtk_widget_destroy (dialog);
5221 /* Switch back to the page we were on */
5222 g_return_val_if_fail (keep_page != NULL, ret);
5223 s_toplevel_goto_page(toplevel, keep_page);
5225 return ret;
5228 /***************** End of Close Confirmation dialog box **************/
5231 /***************** Start of misc helper dialog boxes **************/
5232 /*! \brief Validate the input attribute
5233 * \par Function Description
5234 * This function validates the attribute and if it isn't valid
5235 * pops up an error message box.
5237 * \param parent The parent window which spawned this dialog box.
5238 * \param attribute The attribute to be validated.
5239 * \returns TRUE if the attribute is valid, FALSE otherwise.
5241 int x_dialog_validate_attribute(GtkWindow* parent, char *attribute)
5243 GtkWidget* message_box;
5245 /* validate the new attribute */
5246 if (!o_attrib_get_name_value(attribute, NULL, NULL)) {
5247 message_box = gtk_message_dialog_new_with_markup (parent,
5248 GTK_DIALOG_DESTROY_WITH_PARENT,
5249 GTK_MESSAGE_ERROR,
5250 GTK_BUTTONS_CLOSE,
5251 _("<span weight=\"bold\" size=\"larger\">The input attribute \"%s\" is invalid\nPlease correct in order to continue</span>\n\nThe name and value must be non-empty.\nThe name cannot end with a space.\nThe value cannot start with a space."),
5252 attribute);
5253 gtk_window_set_title(GTK_WINDOW(message_box), _("Invalid Attribute"));
5254 gtk_dialog_run (GTK_DIALOG (message_box));
5255 gtk_widget_destroy (message_box);
5256 return FALSE;
5258 return TRUE;
5260 /***************** End of misc helper dialog boxes **************/