Log name of expander function.
[geda-gaf/berndj.git] / gschem / src / x_dialog.c
blobb5d5866bb3bf6340c3b3060db2415e0f61791b54
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;
2168 char *action_name_chars;
2170 path = gtk_tree_model_get_path(model, &row);
2172 n = gtk_tree_path_get_depth(path);
2173 g_assert(n > 0);
2175 indices = gtk_tree_path_get_indices(path);
2177 for (i = 1; i < n; i++) {
2178 int j;
2180 /* Skip parent and pick out the right child. */
2181 subtree = SCM_CDR(subtree);
2182 for (j = 0; j < indices[i]; j++) {
2183 subtree = SCM_CDR(subtree);
2185 subtree = SCM_CAR(subtree);
2188 if (scm_is_true(scm_list_p(SCM_CAR(subtree)))) {
2189 /* Look into the list for the group header. */
2190 action_name = SCM_CAAR(subtree);
2191 thunk = SCM_CADAR(subtree);
2192 } else {
2193 action_name = SCM_CAR(subtree);
2194 thunk = SCM_CADR(subtree);
2197 if (scm_is_true(scm_procedure_p(thunk))) {
2198 retval = g_scm_apply_protected(thunk, SCM_EOL, NULL, NULL);
2199 } else {
2200 retval = thunk;
2203 if (scm_is_string(action_name)) {
2204 action_name_chars = scm_to_locale_string(action_name);
2205 s_log_message(_("Called slot chooser expander \"%s\"\n"), action_name_chars);
2206 free(action_name_chars);
2207 } else {
2208 s_log_message(_("Called unnamed slot chooser expander\n"));
2211 /* If the thunk returned a list, it's a tree-expander. */
2212 if (scm_is_true(scm_list_p(retval)) && !scm_is_null(retval)) {
2213 SCM list, group_header;
2214 GtkTreeStore *treestore;
2215 int thunk_returned_tree;
2216 char *group_header_chars;
2218 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2220 thunk_returned_tree = scm_is_true(scm_list_p(SCM_CAR(retval)));
2222 if (thunk_returned_tree) {
2223 group_header = SCM_CAR(retval);
2224 } else {
2225 group_header = retval;
2228 /* Replace the text in the treeview. */
2229 group_header_chars = scm_to_locale_string(SCM_CAR(group_header));
2230 gtk_tree_store_set(treestore, &row,
2231 SLOT_CHOOSER_FRIENDLY_NAME, group_header_chars,
2232 -1);
2233 free(group_header_chars);
2235 /* Replace the node with the return value. */
2236 if (thunk_returned_tree) {
2237 /* The thunk returned a tree. */
2238 scm_set_car_x(subtree, group_header);
2239 scm_set_cdr_x(subtree, SCM_CDR(retval));
2241 /* Add the children to the treeview. */
2242 for (list = SCM_CDR(retval); !scm_is_null(list); list = SCM_CDR(list)) {
2243 if (scm_is_true(scm_list_p(SCM_CAAR(list)))) {
2244 slot_chooser_add_rows(sc, SCM_CAR(list), &row);
2245 } else {
2246 SCM synthetic_tree = scm_cons(SCM_CAR(list), SCM_EOL);
2247 slot_chooser_add_rows(sc, synthetic_tree, &row);
2250 } else {
2251 /* The thunk returned just a single row. */
2252 scm_set_car_x(subtree, SCM_CAR(group_header));
2253 scm_set_cdr_x(subtree, SCM_CDR(group_header));
2257 gtk_tree_path_free(path);
2259 return retval;
2261 } else {
2262 fprintf(stderr, "nothing selected\n");
2265 return SCM_BOOL_T;
2268 /*! \brief Apply some action depending on which button emitted the signal.
2270 void slot_chooser_finish(GtkButton *button, gpointer user_data)
2272 struct slot_chooser *sc;
2273 char *widget_name;
2275 g_object_get(button, "name", &widget_name, "user-data", &sc, NULL);
2277 if (widget_name == NULL) {
2278 /* Ignore unknown buttons. */
2279 return;
2282 if (strcmp(widget_name, "ok_button") == 0) {
2283 slot_chooser_apply(sc);
2284 } else if (strcmp(widget_name, "apply_button") == 0) {
2285 /* Change the slotting, keep the slot chooser open. */
2286 slot_chooser_apply(sc);
2287 return;
2290 fprintf(stderr, "slot_chooser_finish(%s)\n", widget_name);
2291 g_free(widget_name);
2292 fprintf(stderr, "o_selected = %s\n", sc->o_selected->name);
2293 gtk_widget_destroy(GTK_WIDGET(sc->scwindow));
2294 scm_gc_unprotect_object(sc->scheme_tree);
2295 g_free(sc);
2298 /*! \brief Free the "user-data" property of the slot chooser window.
2300 gboolean slot_chooser_delete(GtkWidget *widget, GdkEvent *event,
2301 gpointer user_data)
2303 struct slot_chooser *sc;
2305 g_object_get(widget, "user-data", &sc, NULL);
2306 fprintf(stderr, "slot_chooser_delete()\n");
2307 scm_gc_unprotect_object(sc->scheme_tree);
2308 g_free(sc);
2310 /* Let the default handler destroy the window (?). */
2311 return FALSE;
2314 /*! \brief Recompute which rows should be sensitive.
2316 void slot_chooser_toggle(GtkToggleButton *button, gpointer user_data)
2318 struct slot_chooser *sc;
2319 GtkTreeStore *treestore;
2321 g_object_get(button, "user-data", &sc, NULL);
2322 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2324 /* TODO: Don't make slot_chooser_mark_available() search for widgets. */
2325 slot_chooser_mark_available(treestore, sc);
2328 /*! \brief Choose a slot and destroy the dialog.
2330 void slot_chooser_row_activated(GtkTreeView *tree_view,
2331 GtkTreePath *path,
2332 GtkTreeViewColumn *column,
2333 gpointer user_data)
2335 struct slot_chooser *sc;
2336 SCM apply_result;
2338 g_object_get(tree_view, "user-data", &sc, NULL);
2339 apply_result = slot_chooser_apply(sc);
2340 if (scm_is_bool(apply_result) && scm_is_true(apply_result)) {
2341 /* TODO: Rather just delegate to the "OK" button. */
2342 gtk_widget_destroy(GTK_WIDGET(sc->scwindow));
2343 scm_gc_unprotect_object(sc->scheme_tree);
2344 g_free(sc);
2345 return;
2349 /*! \brief Reset the Remove button if an available slot is selected.
2351 void slot_chooser_row_changed(GtkTreeView *tree_view,
2352 gpointer user_data)
2354 struct slot_chooser *sc;
2355 GtkTreeSelection *sel;
2356 GtkTreeModel *model;
2357 GtkTreeIter row;
2359 g_object_get(tree_view, "user-data", &sc, NULL);
2361 sel = gtk_tree_view_get_selection(sc->treeview);
2362 if (gtk_tree_selection_get_selected(sel, &model, &row)) {
2363 gboolean is_allowed;
2365 gtk_tree_model_get(model, &row,
2366 SLOT_CHOOSER_IS_ALLOWED, &is_allowed,
2367 -1);
2368 if (is_allowed) {
2369 /* Deactivate the Remove button. */
2370 g_object_set(sc->remove_button, "active", FALSE, NULL);
2375 struct slot_chooser_tree_parent {
2376 GtkTreeView *treeview;
2377 GtkTreeIter *row;
2378 OBJECT *o_selected;
2381 /*! \brief Visit each slot in a component to add it to the GtkTreeView.
2382 * \par Function Description
2383 * Add a new row to the slot chooser's GtkTreeView and populate its
2384 * columns with the slot's details.
2385 * \param [in] key The name of the slot.
2386 * \param [in] value The slot to add to the GtkTreeView.
2387 * \param [in] context The struct slot_chooser_tree_parent context.
2389 void slot_chooser_slots_visitor(gpointer key, gpointer value, gpointer context)
2391 struct slot_chooser_tree_parent *tree_parent = context;
2392 OBJECT *slot_object = value;
2393 GtkTreeStore *treestore;
2394 GtkTreeIter newrow;
2395 GtkTreeView *treeview;
2396 static gboolean is_current, is_available, is_compatible, is_occupied;
2398 is_compatible = s_slot_compatible(tree_parent->o_selected, slot_object);
2399 is_available = s_slot_available(tree_parent->o_selected, slot_object);
2400 is_occupied = slot_object->slot->symbol ? TRUE : FALSE;
2401 is_current = (slot_object->slot->symbol == tree_parent->o_selected ? TRUE : FALSE);
2403 /* 'key' is the slotname attribute. */
2404 treeview = GTK_TREE_VIEW(tree_parent->treeview);
2405 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2406 gtk_tree_store_append(treestore, &newrow, tree_parent->row);
2407 gtk_tree_store_set(treestore, &newrow,
2408 SLOT_CHOOSER_FRIENDLY_NAME, key,
2409 SLOT_CHOOSER_IS_CURRENT, is_current,
2410 SLOT_CHOOSER_IS_AVAILABLE, is_available,
2411 SLOT_CHOOSER_IS_OCCUPIED, is_occupied,
2412 SLOT_CHOOSER_IS_COMPATIBLE, is_compatible,
2413 SLOT_CHOOSER_TARGET, (gpointer) slot_object,
2414 SLOT_CHOOSER_IS_SPECIFIC, TRUE,
2415 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2416 -1);
2418 /* Is this the currently assigned slot? */
2419 if (tree_parent->o_selected->owning_slot == slot_object) {
2420 GtkTreeSelection *sel;
2421 GtkTreePath *path;
2423 path = gtk_tree_model_get_path(GTK_TREE_MODEL(treestore), &newrow);
2425 /* Expand the tree to the currently assigned slot. */
2426 gtk_tree_view_expand_to_path(treeview, path);
2427 sel = gtk_tree_view_get_selection(treeview);
2429 /* Select the currently assigned slot. */
2430 gtk_tree_selection_select_path(sel, path);
2432 gtk_tree_path_free(path);
2435 fprintf(stderr, "Found slot %s (%s)\n",
2436 (char *) key, is_compatible ? "compatible" : "incompatible");
2439 void slot_chooser_visitor(OBJECT *o_current, void *context)
2441 struct slot_chooser_tree_parent *tree_parent = context;
2442 GtkTreeView *treeview;
2443 GtkTreeStore *treestore;
2444 GtkTreeIter part_header;
2445 GtkTreeIter *parent_row;
2446 char *refdes;
2448 if (o_current->type != OBJ_COMPLEX) {
2449 return;
2452 /* Don't offer a symbol as a slot for itself. */
2453 if (o_current == tree_parent->o_selected) {
2454 return;
2457 /* Don't offer slots that are themselves inside another slot. */
2458 if (o_current->owning_slot) {
2459 return;
2462 /* Also don't offer components that have no slots. */
2463 if (o_current->complex->slots == NULL ||
2464 g_hash_table_size(o_current->complex->slots) == 0) {
2465 return;
2468 /* Save the treestore iterator. */
2469 parent_row = tree_parent->row;
2471 refdes = o_complex_get_refdes(o_current, _("(unknown part)"));
2473 /* Add a row for the part as a whole. */
2474 treeview = tree_parent->treeview;
2475 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
2476 gtk_tree_store_append(treestore, &part_header, parent_row);
2477 gtk_tree_store_set(treestore, &part_header,
2478 SLOT_CHOOSER_FRIENDLY_NAME, refdes,
2479 SLOT_CHOOSER_IS_CURRENT, FALSE,
2480 SLOT_CHOOSER_IS_AVAILABLE, TRUE,
2481 SLOT_CHOOSER_IS_OCCUPIED, FALSE,
2482 SLOT_CHOOSER_IS_COMPATIBLE, TRUE,
2483 SLOT_CHOOSER_TARGET, (gpointer) o_current,
2484 SLOT_CHOOSER_IS_SPECIFIC, FALSE,
2485 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2486 -1);
2488 /* Become the parent for slots we find. */
2489 tree_parent->row = &part_header;
2491 g_hash_table_foreach(o_current->complex->slots,
2492 &slot_chooser_slots_visitor, tree_parent);
2494 /* Restore the treestore iterator. */
2495 tree_parent->row = parent_row;
2498 static void slot_chooser_add_one_row(struct slot_chooser *sc,
2499 SCM name, SCM callback,
2500 GtkTreeIter *parent_row,
2501 GtkTreeIter *new_row)
2503 GtkTreeStore *treestore;
2504 char *name_chars;
2506 treestore = GTK_TREE_STORE(gtk_tree_view_get_model(sc->treeview));
2507 gtk_tree_store_append(treestore, new_row, parent_row);
2509 if (!scm_is_string(name)) {
2510 g_warning("Expecting a slotname string from (find-slots object)\n");
2511 return;
2513 if (!scm_is_bool(callback) && scm_is_false(scm_procedure_p(callback))) {
2514 g_warning("Expecting a callback from (find-slots object)\n");
2517 name_chars = scm_to_locale_string(name);
2518 fprintf(stderr, "**** Scheme says: %s ****\n", name_chars);
2519 gtk_tree_store_set(treestore, new_row,
2520 SLOT_CHOOSER_FRIENDLY_NAME, name_chars,
2521 SLOT_CHOOSER_TARGET, NULL,
2522 SLOT_CHOOSER_IS_SPECIFIC, TRUE,
2523 SLOT_CHOOSER_IS_ALLOWED, TRUE,
2524 -1);
2525 free(name_chars);
2528 static void slot_chooser_add_rows(struct slot_chooser *sc,
2529 SCM list,
2530 GtkTreeIter *parent_row)
2532 GtkTreeIter group_row;
2533 SCM group = SCM_CAR(list);
2534 SCM groupname = SCM_CAR(group);
2535 SCM callback = SCM_CADR(group);
2537 slot_chooser_add_one_row(sc, groupname, callback,
2538 parent_row, &group_row);
2540 for (list = SCM_CDR(list); !scm_is_null(list); list = SCM_CDR(list)) {
2541 SCM row = SCM_CAR(list);
2542 SCM car = SCM_CAR(row);
2544 if (scm_is_true(scm_list_p(car))) {
2545 slot_chooser_add_rows(sc, row, &group_row);
2546 } else {
2547 GtkTreeIter child_row;
2548 SCM slotname = car;
2549 SCM slot_callback = SCM_CADR(row);
2551 slot_chooser_add_one_row(sc, slotname, slot_callback,
2552 &group_row, &child_row);
2557 static void slot_chooser_populate(TOPLEVEL *toplevel,
2558 struct slot_chooser *sc)
2560 SCM o_smob = g_make_object_smob(toplevel, sc->o_selected);
2561 SCM slots;
2563 slots = g_scm_apply_protected(g_scm_safe_ref_lookup("find-slots"),
2564 scm_list_1(o_smob),
2565 NULL, NULL);
2567 if (scm_is_false(scm_list_p(slots))) {
2568 s_log_message(_("find-slots #<object %s> didn't return a list\n"),
2569 sc->o_selected->name);
2570 return;
2573 sc->scheme_tree = slots;
2575 if (!scm_is_null(slots)) {
2576 slot_chooser_add_rows(sc, slots, NULL);
2579 scm_gc_protect_object(sc->scheme_tree);
2582 /*! \brief Create the slot chooser dialog
2583 * \par Function Description
2584 * This function creates the slot chooser dialog.
2586 void slot_chooser_dialog(GSCHEM_TOPLEVEL *w_current, OBJECT *o_current,
2587 char const *slotname_attrib)
2589 struct slot_chooser_tree_parent tree_parent;
2590 struct slot_chooser *sc;
2591 GladeXML *xml;
2592 GtkWindow *scwindow;
2593 GtkTreeStore *treestore;
2594 GtkCellRenderer *renderer;
2595 GtkTreeViewColumn *column;
2596 GtkWidget *widget;
2597 char *refdes;
2599 widget = x_glade_get_widget(&xml, "slot_chooser",
2600 "slot_chooser_finish",
2601 G_CALLBACK(&slot_chooser_finish),
2602 "slot_chooser_delete",
2603 G_CALLBACK(&slot_chooser_delete),
2604 "slot_chooser_toggle",
2605 G_CALLBACK(&slot_chooser_toggle),
2606 "slot_chooser_row_activated",
2607 G_CALLBACK(&slot_chooser_row_activated),
2608 "slot_chooser_row_changed",
2609 G_CALLBACK(&slot_chooser_row_changed),
2610 NULL);
2612 if (widget == NULL) {
2613 s_log_message("Can't find dialog component \"slot_chooser_dialog\"\n");
2614 return;
2616 scwindow = GTK_WINDOW(widget);
2617 refdes = o_complex_get_refdes(o_current, _("(unknown part)"));
2618 if (refdes) {
2619 char *title, *slotname;
2621 slotname = o_attrib_search_name_single(o_current, "slotname", NULL);
2623 if (slotname) {
2624 title = g_strconcat("Slot Chooser - ", refdes, ":", slotname, NULL);
2625 } else {
2626 title = g_strconcat("Slot Chooser - ", refdes, NULL);
2628 gtk_window_set_title(scwindow, title);
2630 g_free(title);
2631 g_free(slotname);
2632 g_free(refdes);
2635 /* FIXME: Where do we release this memory? */
2636 sc = g_new(struct slot_chooser, 1);
2638 sc->scwindow = scwindow;
2639 widget = x_lookup_widget_set(xml, "hijack_button",
2640 "user-data", sc, NULL);
2641 sc->hijack_button = GTK_TOGGLE_BUTTON(widget);
2642 widget = x_lookup_widget_set(xml, "compatible_button",
2643 "user-data", sc, NULL);
2644 sc->compatible_button = GTK_TOGGLE_BUTTON(widget);
2645 widget = x_lookup_widget_set(xml, "remove_button",
2646 "user-data", sc, NULL);
2647 sc->remove_button = GTK_TOGGLE_BUTTON(widget);
2648 sc->w_current = w_current->toplevel;
2649 sc->o_selected = o_current;
2650 widget = x_lookup_widget_set(xml, "slot_treeview",
2651 "user-data", sc, NULL);
2652 sc->treeview = GTK_TREE_VIEW(widget);
2654 fprintf(stderr, "scwindow = %p\n", scwindow);
2656 /* Remember what we're doing, when we get the callback. */
2657 g_object_set(scwindow, "user-data", sc, NULL);
2658 x_lookup_widget_set(xml, "cancel_button", "user-data", sc, NULL);
2659 x_lookup_widget_set(xml, "apply_button", "user-data", sc, NULL);
2660 x_lookup_widget_set(xml, "remove_button", "user-data", sc, NULL);
2661 x_lookup_widget_set(xml, "ok_button", "user-data", sc, NULL);
2663 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(sc->treeview),
2664 GTK_SELECTION_SINGLE);
2666 /* Use the tree model. */
2667 treestore = gtk_tree_store_new(SLOT_CHOOSER_N_COLUMNS,
2668 G_TYPE_STRING,
2669 G_TYPE_POINTER,
2670 G_TYPE_BOOLEAN,
2671 G_TYPE_BOOLEAN,
2672 G_TYPE_BOOLEAN,
2673 G_TYPE_BOOLEAN,
2674 G_TYPE_BOOLEAN,
2675 G_TYPE_BOOLEAN);
2676 gtk_tree_view_set_model(sc->treeview, GTK_TREE_MODEL(treestore));
2677 gtk_tree_view_set_search_column(sc->treeview, SLOT_CHOOSER_FRIENDLY_NAME);
2679 /* Now set the view component for each column. */
2681 renderer = gtk_cell_renderer_text_new();
2682 column = gtk_tree_view_column_new_with_attributes("name", renderer,
2683 "text",
2684 SLOT_CHOOSER_FRIENDLY_NAME,
2685 "sensitive",
2686 SLOT_CHOOSER_IS_ALLOWED,
2687 NULL);
2688 gtk_tree_view_append_column(sc->treeview, column);
2690 if (GEDA_DEBUG) {
2691 renderer = gtk_cell_renderer_toggle_new();
2692 g_object_set(renderer, "activatable", FALSE, NULL);
2693 column = gtk_tree_view_column_new_with_attributes("occupied", renderer,
2694 "active",
2695 SLOT_CHOOSER_IS_OCCUPIED,
2696 "sensitive",
2697 SLOT_CHOOSER_IS_ALLOWED,
2698 NULL);
2699 gtk_tree_view_append_column(sc->treeview, column);
2701 renderer = gtk_cell_renderer_toggle_new();
2702 g_object_set(renderer, "activatable", FALSE, NULL);
2703 column = gtk_tree_view_column_new_with_attributes("compatible", renderer,
2704 "active",
2705 SLOT_CHOOSER_IS_COMPATIBLE,
2706 "sensitive",
2707 SLOT_CHOOSER_IS_ALLOWED,
2708 NULL);
2709 gtk_tree_view_append_column(sc->treeview, column);
2712 gtk_tree_view_expand_all(sc->treeview);
2714 /* Find some compatible slots. */
2715 tree_parent.treeview = sc->treeview;
2716 tree_parent.row = NULL;
2717 tree_parent.o_selected = o_current;
2719 /* TODO: perhaps use an infinite-depth search. */
2720 s_visit_toplevel(w_current->toplevel, &slot_chooser_visitor, &tree_parent,
2721 VISIT_UNORDERED, 1);
2723 /* Let gschemrc add some rows too. */
2724 slot_chooser_populate(w_current->toplevel, sc);
2726 slot_chooser_mark_available(treestore, sc);
2728 g_object_unref(xml);
2730 gtk_window_present(scwindow);
2733 /***************** End of Slot chooser dialog box ********************/
2735 /***************** Start of component list dialog box ****************/
2737 enum component_list_columns {
2738 COMPONENT_LIST_REFDES,
2739 COMPONENT_LIST_N_COLUMNS
2742 struct component_list {
2743 PAGE *page;
2744 GtkWindow *clwindow;
2745 GtkTreeView *treeview;
2746 GtkListStore *liststore;
2749 /*! \brief Clean up resources that GTK+ doesn't know about.
2750 * \par Function Description
2751 * Cleans up resources that the component list dialog uses.
2753 * \param [in] widget A widget with a "user-data" property.
2755 * \returns A pointer to the GtkWindow of the dialog.
2757 static GtkWindow *component_list_cleanup(GtkWidget *widget)
2759 struct component_list *cl;
2760 GtkWindow *clwindow;
2762 g_object_get(widget, "user-data", &cl, NULL);
2764 clwindow = cl->clwindow;
2766 g_free(cl);
2768 return clwindow;
2771 gboolean component_list_window_delete(GtkWidget *widget,
2772 GdkEvent *event,
2773 gpointer user_data)
2775 component_list_cleanup(widget);
2777 return FALSE;
2780 void component_list_finish(GtkButton *button, gpointer user_data)
2782 GtkWindow *clwindow;
2784 clwindow = component_list_cleanup(GTK_WIDGET(button));
2786 gtk_widget_destroy(GTK_WIDGET(clwindow));
2789 void component_list_edit(GtkButton *button, gpointer user_data)
2791 /* TODO: Start the multi attrib editor. */
2794 void component_list_row_activated(GtkTreeView *treeview,
2795 GtkTreePath *path,
2796 GtkTreeViewColumn *column,
2797 gpointer user_data)
2799 /* TODO: Start the multi attrib editor. */
2802 /*! \brief Show the component list dialog.
2803 * \par Function Description
2804 * Show the component list dialog with a given list of objects.
2806 * \param [in] components A list of OBJECTs to show in the dialog.
2808 void component_list_dialog(GList const *components)
2810 struct component_list *cl;
2811 GladeXML *xml;
2812 GtkWidget *widget;
2813 GtkCellRenderer *renderer;
2814 GtkTreeViewColumn *column;
2815 OBJECT *o;
2817 cl = g_new(struct component_list, 1);
2819 widget = x_glade_get_widget(&xml, "component_list",
2820 "on_component_list_dialog_delete_event",
2821 G_CALLBACK(&component_list_window_delete),
2822 "on_ok_button_clicked",
2823 G_CALLBACK(&component_list_finish),
2824 "on_edit_button_clicked",
2825 G_CALLBACK(&component_list_edit),
2826 "component_list_row_activated",
2827 G_CALLBACK(&component_list_row_activated),
2828 NULL);
2830 if (widget == NULL) {
2831 s_log_message("Can't find dialog component \"component_list\"\n");
2832 return;
2834 cl->clwindow = GTK_WINDOW(widget);
2836 /* Set "user-data" properties on all interesting widgets. */
2837 x_lookup_widget_set(xml, "ok_button", "user-data", cl, NULL);
2838 x_lookup_widget_set(xml, "edit_button", "user-data", cl, NULL);
2839 widget = x_lookup_widget_set(xml, "components_treeview",
2840 "user-data", cl, NULL);
2841 cl->treeview = GTK_TREE_VIEW(widget);
2842 g_object_set(cl->clwindow, "user-data", cl, NULL);
2844 /* Set up the tree view. */
2845 cl->liststore = gtk_list_store_new(COMPONENT_LIST_N_COLUMNS,
2846 G_TYPE_STRING);
2847 gtk_tree_view_set_model(cl->treeview, GTK_TREE_MODEL(cl->liststore));
2848 gtk_tree_view_set_search_column(cl->treeview, COMPONENT_LIST_REFDES);
2850 /* Tell the tree view how to display its cells. */
2851 renderer = gtk_cell_renderer_text_new();
2852 column = gtk_tree_view_column_new_with_attributes("refdes", renderer,
2853 "text", COMPONENT_LIST_REFDES,
2854 NULL);
2855 gtk_tree_view_append_column(cl->treeview, column);
2857 /* Populate the tree view with the objects given as a parameter. */
2858 for (; components != NULL; components = components->next) {
2859 GtkTreeIter row;
2860 char *refdes;
2862 o = components->data;
2864 refdes = o_attrib_search_name_single_exact(o, "refdes", NULL);
2866 gtk_list_store_append(cl->liststore, &row);
2867 gtk_list_store_set(cl->liststore, &row,
2868 COMPONENT_LIST_REFDES, refdes,
2869 -1);
2871 g_free(refdes);
2875 /***************** End of component list dialog box ******************/
2877 /***************** Start of REPL dialog box ********************/
2879 enum repl_columns {
2880 REPL_SCM,
2881 REPL_REPRESENTATION,
2882 REPL_N_COLUMNS
2885 struct repl {
2886 GladeXML *xml;
2887 GSCHEM_TOPLEVEL *w_current;
2888 GtkWidget *window;
2889 GtkTreeStore *treestore;
2890 GtkTreeView *treeview;
2891 GtkTreeSelection *selection;
2892 GtkNotebook *notebook;
2893 SCM result;
2896 void repl_destroy(struct repl *r)
2898 if (r->window) {
2899 gtk_widget_destroy(r->window);
2901 g_object_unref(r->xml);
2902 g_free(r);
2905 void repl_populate_treeview(GtkTreeStore *treestore, SCM expr,
2906 GtkTreeIter *parent)
2908 GtkTreeIter newrow;
2909 SCM representation;
2911 representation = scm_simple_format(SCM_BOOL_F,
2912 scm_from_locale_string("~S"),
2913 scm_list_1(expr));
2915 gtk_tree_store_append(treestore, &newrow, parent);
2916 if (scm_is_string(representation)) {
2917 char *representation_c = scm_to_locale_string(representation);
2918 SCM *rowexpr = g_new(SCM, 1);
2920 *rowexpr = expr;
2921 gtk_tree_store_set(treestore, &newrow,
2922 REPL_SCM, rowexpr,
2923 REPL_REPRESENTATION, representation_c,
2924 -1);
2925 free(representation_c);
2926 } else {
2927 gtk_tree_store_set(treestore, &newrow,
2928 REPL_SCM, NULL,
2929 REPL_REPRESENTATION, "<libguile error>",
2930 -1);
2933 if (scm_is_true(scm_list_p(expr))) {
2934 SCM i;
2936 for (i = expr; !scm_is_null(i); i = SCM_CDR(i)) {
2937 repl_populate_treeview(treestore, SCM_CAR(i), &newrow);
2942 gboolean repl_clear_row(GtkTreeModel *model, GtkTreePath *path,
2943 GtkTreeIter *iter, gpointer user_data)
2945 SCM *rowexpr;
2947 gtk_tree_model_get(model, iter, REPL_SCM, &rowexpr, -1);
2948 g_free(rowexpr);
2950 return FALSE;
2953 void repl_execute(GtkButton *button, gpointer user_data)
2955 struct repl *r;
2956 gint current_page_index;
2957 GtkWidget *current_page;
2958 GtkTextBuffer *textbuffer;
2959 gchar *text;
2961 g_object_get(G_OBJECT(button), "user-data", &r, NULL);
2963 current_page_index = gtk_notebook_get_current_page(r->notebook);
2964 if (current_page_index == -1) {
2965 printf("No open pages\n");
2966 return;
2969 current_page = gtk_notebook_get_nth_page(r->notebook, current_page_index);
2970 if (current_page == NULL) {
2971 printf("Can't get current page\n");
2972 return;
2975 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(current_page));
2976 /* TODO - g_type_is_a() */
2977 g_object_get(G_OBJECT(textbuffer), "text", &text, NULL);
2979 if (r->result != SCM_UNDEFINED) {
2980 scm_gc_unprotect_object(r->result);
2983 /* Pass the string to the interpreter. */
2984 r->result = g_scm_apply_protected(g_scm_safe_ref_lookup("invoke-macro"),
2985 scm_list_1(scm_from_locale_string(text)),
2986 NULL, NULL);
2987 g_free(text);
2988 scm_gc_protect_object(r->result);
2990 /* TODO: Give feedback if an exception occurred. */
2991 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_clear_row, NULL);
2992 gtk_tree_store_clear(r->treestore);
2993 repl_populate_treeview(r->treestore, r->result, NULL);
2995 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_selection_one, r);
2998 void repl_cancel(GtkButton *button, gpointer user_data)
3000 struct repl *r;
3002 g_object_get(G_OBJECT(button), "user-data", &r, NULL);
3004 gtk_widget_hide(r->window);
3007 void repl_row_activated(GtkTreeView *tree_view,
3008 GtkTreePath *path,
3009 GtkTreeViewColumn *column,
3010 gpointer user_data)
3012 GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
3013 GtkTreeIter iter;
3014 TOPLEVEL *toplevel;
3015 OBJECT *o_current;
3016 SCM *rowexpr;
3018 gtk_tree_model_get_iter(model, &iter, path);
3019 gtk_tree_model_get(model, &iter, REPL_SCM, &rowexpr, -1);
3021 if (g_get_data_from_object_smob(*rowexpr, &toplevel, &o_current)) {
3022 struct repl *r;
3024 g_object_get(G_OBJECT(tree_view), "user-data", &r, NULL);
3026 x_multiattrib_open(r->w_current, toplevel->page_current->selection_list);
3027 } else if (scm_is_true(scm_thunk_p(*rowexpr))) {
3028 /* TODO: Execute thunk with g_scm_apply_protected. */
3032 /* XXX getting both w_current and toplevel is odd. */
3033 void repl_selection_one_object(GtkTreeSelection *selection, GtkTreePath *path,
3034 GSCHEM_TOPLEVEL *w_current, TOPLEVEL *toplevel,
3035 OBJECT *o_current)
3037 PAGE *page = toplevel->page_current;
3039 o_select_object_simple(w_current, toplevel, page, o_current,
3040 gtk_tree_selection_path_is_selected(selection, path));
3043 static gboolean repl_selection_one(GtkTreeModel *model, GtkTreePath *path,
3044 GtkTreeIter *iter, gpointer user_data)
3046 struct repl *r = user_data;
3047 TOPLEVEL *toplevel;
3048 OBJECT *o_current;
3049 SCM *rowexpr;
3051 gtk_tree_model_get(model, iter, REPL_SCM, &rowexpr, -1);
3052 if (g_get_data_from_object_smob(*rowexpr, &toplevel, &o_current)) {
3053 repl_selection_one_object(r->selection, path, r->w_current, toplevel, o_current);
3056 return FALSE;
3059 void repl_selection_changed(GtkTreeSelection *selection, gpointer user_data)
3061 struct repl *r = user_data;
3063 gtk_tree_model_foreach(GTK_TREE_MODEL(r->treestore), &repl_selection_one, r);
3066 void repl_new_page(GtkNotebook *notebook)
3068 GtkWidget *textview = gtk_text_view_new();
3069 GtkTextBuffer *textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
3070 GtkWidget *label = gtk_label_new("New");
3072 gtk_text_buffer_set_text(textbuffer, ";; Write some Scheme here", -1);
3073 select_all_text_in_textview(GTK_TEXT_VIEW(textview));
3074 gtk_widget_show(GTK_WIDGET(textview));
3075 gtk_notebook_prepend_page(notebook, textview, label);
3076 gtk_notebook_set_current_page(notebook, 0);
3077 gtk_widget_grab_focus(textview);
3078 if (gtk_notebook_get_n_pages(notebook) > 1) {
3079 g_object_set(G_OBJECT(notebook), "show-tabs", TRUE, NULL);
3083 void repl_dialog(GSCHEM_TOPLEVEL *w_current)
3085 static struct repl *r = NULL;
3087 if (r != NULL) {
3088 repl_new_page(r->notebook);
3089 gtk_widget_show(r->window);
3090 return;
3093 r = g_new0(struct repl, 1);
3094 r->w_current = w_current;
3095 r->result = SCM_UNDEFINED;
3097 r->window = x_glade_get_widget(&r->xml, "repl",
3098 "on_repl_window_delete_event",
3099 G_CALLBACK(gtk_widget_hide_on_delete),
3100 "on_execute_button_clicked",
3101 G_CALLBACK(repl_execute),
3102 "on_cancel_button_clicked",
3103 G_CALLBACK(repl_cancel),
3104 "on_result_treeview_row_activated",
3105 G_CALLBACK(repl_row_activated),
3106 NULL);
3107 if (r->window == NULL) {
3108 s_log_message("Can't find dialog component \"repl\"\n");
3109 repl_destroy(r);
3110 r = NULL;
3111 return;
3114 r->notebook = GTK_NOTEBOOK(x_lookup_widget(r->xml, "sexpr-notebook"));
3115 if (r->notebook == NULL) {
3116 s_log_message("Can't find sexpr notebook in dialog component \"repl\"\n");
3117 repl_destroy(r);
3118 r = NULL;
3119 return;
3122 r->treeview = GTK_TREE_VIEW(x_lookup_widget(r->xml, "result-treeview"));
3123 if (r->treeview != NULL) {
3124 GtkCellRenderer *renderer;
3125 GtkTreeViewColumn *column;
3127 r->treestore = gtk_tree_store_new(REPL_N_COLUMNS,
3128 G_TYPE_POINTER,
3129 G_TYPE_STRING);
3130 gtk_tree_view_set_model(r->treeview, GTK_TREE_MODEL(r->treestore));
3132 renderer = gtk_cell_renderer_text_new();
3133 column = gtk_tree_view_column_new_with_attributes("value", renderer,
3134 "text", REPL_REPRESENTATION,
3135 NULL);
3136 gtk_tree_view_append_column(r->treeview, column);
3138 r->selection = gtk_tree_view_get_selection(r->treeview);
3139 gtk_tree_selection_set_mode(r->selection, GTK_SELECTION_MULTIPLE);
3141 g_signal_connect(r->selection, "changed", G_CALLBACK(repl_selection_changed), r);
3144 x_lookup_widget_set(r->xml, "execute_button", "user-data", r, NULL);
3145 x_lookup_widget_set(r->xml, "cancel_button", "user-data", r, NULL);
3146 x_lookup_widget_set(r->xml, "result-treeview", "user-data", r, NULL);
3148 gtk_notebook_remove_page(r->notebook, 0);
3149 repl_new_page(r->notebook);
3152 /***************** End of REPL dialog box ******************/
3154 /***************** Start of help/about dialog box ********************/
3156 /*! \brief Response function for the about dialog
3157 * \par Function Description
3158 * This function destroys the about dialog.
3160 void about_dialog_response(GtkWidget *w, gint response,
3161 GSCHEM_TOPLEVEL *w_current)
3163 switch (response) {
3164 case GTK_RESPONSE_REJECT:
3165 case GTK_RESPONSE_DELETE_EVENT:
3166 /* void */
3167 break;
3168 default:
3169 printf("about_dialog_response(): strange signal %d\n",response);
3172 gtk_widget_destroy(w_current->abwindow);
3173 w_current->abwindow = NULL;
3176 /*! \brief Create the about dialog and show it
3177 * \par Function Description
3178 * This function creates the about dialog.
3180 void about_dialog (GSCHEM_TOPLEVEL *w_current)
3182 GtkWidget *label = NULL;
3183 GtkWidget *vbox;
3184 char *string;
3186 if (!w_current->abwindow) {
3187 w_current->abwindow = gschem_dialog_new_with_buttons(_("About..."),
3188 GTK_WINDOW(w_current->main_window),
3189 GTK_DIALOG_MODAL,
3190 "about", w_current,
3191 GTK_STOCK_CLOSE,
3192 GTK_RESPONSE_REJECT,
3193 NULL);
3195 gtk_window_position (GTK_WINDOW (w_current->abwindow),
3196 GTK_WIN_POS_MOUSE);
3198 gtk_signal_connect (GTK_OBJECT (w_current->abwindow), "response",
3199 GTK_SIGNAL_FUNC(about_dialog_response),
3200 w_current);
3202 gtk_container_border_width (GTK_CONTAINER(w_current->abwindow),
3203 DIALOG_BORDER_SPACING);
3204 vbox = GTK_DIALOG(w_current->abwindow)->vbox;
3205 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3207 label = gtk_label_new ( _("<b>gEDA: GPL Electronic Design Automation</b>"));
3208 gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
3209 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3211 string = g_strdup_printf(_("<b>gschem version %s%s.%s</b>"),
3212 PREPEND_VERSION_STRING, DOTTED_VERSION,
3213 DATE_VERSION);
3214 label = gtk_label_new (string);
3215 gtk_label_set_use_markup (GTK_LABEL(label), TRUE);
3216 g_free(string);
3217 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3219 label = gtk_label_new ( _("Written by:\n"
3220 "Ales Hvezda\n"
3221 "ahvezda@geda.seul.org\n"
3222 "And many others (See AUTHORS file)"));
3223 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
3224 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
3226 gtk_widget_show_all(w_current->abwindow);
3229 else { /* dialog already created */
3230 gtk_window_present(GTK_WINDOW(w_current->abwindow));
3234 /***************** End of help/about dialog box *********************/
3236 /***************** Start of coord dialog box ************************/
3237 /*! \brief Response function for the coord dialog
3238 * \par Function Description
3239 * This function destroys the coord dialog box and does some cleanup.
3241 void coord_dialog_response(GtkWidget *w, gint response, GSCHEM_TOPLEVEL *w_current)
3243 gtk_widget_destroy(w_current->cowindow);
3244 w_current->cowindow = NULL;
3245 w_current->coord_world = NULL;
3246 w_current->coord_screen = NULL;
3249 /*! \brief Update the coordinates in the coord dialog box.
3250 * \par Function Description
3251 * This function takes the screen coordinates and prints the
3252 * screen and the world coordinates in the coord dialog.
3254 void coord_display_update(GSCHEM_TOPLEVEL *w_current, int x, int y)
3256 TOPLEVEL *toplevel = w_current->toplevel;
3257 PAGE *page = toplevel->page_current;
3258 char *string;
3259 int world_x, world_y;
3261 string = g_strdup_printf("(%d, %d)", x, y);
3262 gtk_label_set_text(GTK_LABEL(w_current->coord_screen), string );
3263 g_free(string);
3265 SCREENtoWORLD(page, x, y, &world_x, &world_y);
3266 /* TODO: Do we want to snap the coordinate display? */
3267 world_x = snap_grid(toplevel, world_x);
3268 world_y = snap_grid(toplevel, world_y);
3270 string = g_strdup_printf("(%d, %d)", world_x, world_y);
3271 gtk_label_set_text(GTK_LABEL(w_current->coord_world), string );
3272 g_free(string);
3275 /*! \brief Create the coord dialog
3276 * \par Function Description
3277 * This function creates the coord dialog box.
3279 void coord_dialog (GSCHEM_TOPLEVEL *w_current, int x, int y)
3281 GtkWidget *frame;
3282 GtkWidget *vbox;
3284 if (!w_current->cowindow) {
3285 w_current->cowindow = gschem_dialog_new_with_buttons(_("Coords"),
3286 GTK_WINDOW(w_current->main_window),
3287 0, /* Not modal GTK_DIALOG_MODAL */
3288 "coord", w_current,
3289 GTK_STOCK_CLOSE,
3290 GTK_RESPONSE_REJECT,
3291 NULL);
3293 gtk_window_position (GTK_WINDOW (w_current->cowindow),
3294 GTK_WIN_POS_NONE);
3296 gtk_signal_connect (GTK_OBJECT (w_current->cowindow), "response",
3297 GTK_SIGNAL_FUNC(coord_dialog_response),
3298 w_current);
3300 gtk_container_border_width (GTK_CONTAINER(w_current->cowindow),
3301 DIALOG_BORDER_SPACING);
3302 vbox = GTK_DIALOG(w_current->cowindow)->vbox;
3303 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3306 frame = gtk_frame_new (_("Screen"));
3307 w_current->coord_screen = gtk_label_new("(########, ########)");
3308 gtk_label_set_justify( GTK_LABEL(w_current->coord_screen), GTK_JUSTIFY_LEFT);
3309 gtk_misc_set_padding(GTK_MISC(w_current->coord_screen),
3310 DIALOG_H_SPACING, DIALOG_V_SPACING);
3311 gtk_container_add(GTK_CONTAINER (frame),
3312 w_current->coord_screen);
3313 gtk_box_pack_start(GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3315 frame = gtk_frame_new (_("World"));
3316 w_current->coord_world = gtk_label_new ("(########, ########)");
3317 gtk_misc_set_padding(GTK_MISC(w_current->coord_world),
3318 DIALOG_H_SPACING, DIALOG_V_SPACING);
3319 gtk_label_set_justify(GTK_LABEL(w_current->coord_world),
3320 GTK_JUSTIFY_LEFT);
3321 gtk_container_add(GTK_CONTAINER (frame),
3322 w_current->coord_world);
3323 gtk_box_pack_start(GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3325 gtk_widget_show_all(w_current->cowindow);
3328 else { /* window already creatad */
3329 gtk_window_present(GTK_WINDOW(w_current->cowindow));
3332 /* always update the coords when the dialog is requested */
3333 coord_display_update(w_current, x, y);
3336 /***************** End of coord dialog box **************************/
3338 /***************** Start of color edit dialog box *******************/
3340 /*! \todo Finish function documentation!!!
3341 * \brief
3342 * \par Function Description
3344 * \warning
3345 * Caller must g_free returned character string.
3348 char *index2functionstring(int index)
3350 char *string;
3352 switch(index) {
3353 case(BACKGROUND_COLOR):
3354 string = g_strdup (_("Background"));
3355 break;
3356 case(PIN_COLOR):
3357 string = g_strdup (_("Pin"));
3358 break;
3359 case(NET_ENDPOINT_COLOR):
3360 string = g_strdup (_("Net endpoint"));
3361 break;
3362 case(GRAPHIC_COLOR):
3363 string = g_strdup (_("Graphic"));
3364 break;
3365 case(NET_COLOR):
3366 string = g_strdup (_("Net"));
3367 break;
3368 case(ATTRIBUTE_COLOR):
3369 string = g_strdup (_("Attribute"));
3370 break;
3371 case(LOGIC_BUBBLE_COLOR):
3372 string = g_strdup (_("Logic bubble"));
3373 break;
3374 case(GRID_COLOR):
3375 string = g_strdup (_("Grid point"));
3376 break;
3377 case(DETACHED_ATTRIBUTE_COLOR):
3378 string = g_strdup (_("Detached attribute"));
3379 break;
3380 case(TEXT_COLOR):
3381 string = g_strdup (_("Text"));
3382 break;
3383 case(BUS_COLOR):
3384 string = g_strdup (_("Bus"));
3385 break;
3386 case(SELECT_COLOR):
3387 string = g_strdup (_("Selection"));
3388 break;
3389 case(BOUNDINGBOX_COLOR):
3390 string = g_strdup (_("Bounding box"));
3391 break;
3392 case(ZOOM_BOX_COLOR):
3393 string = g_strdup (_("Zoom box"));
3394 break;
3395 case(STROKE_COLOR):
3396 string = g_strdup (_("Stroke"));
3397 break;
3398 case(LOCK_COLOR):
3399 string = g_strdup (_("Lock"));
3400 break;
3401 case(OUTPUT_BACKGROUND_COLOR):
3402 string = g_strdup (_("Output background"));
3403 break;
3404 case(JUNCTION_COLOR):
3405 string = g_strdup (_("Net junction"));
3406 break;
3407 default:
3408 string = g_strdup (_("Unknown"));
3409 break;
3411 return(string);
3414 /*! \brief Cell layout data function for color combobox.
3415 * \par Function Description
3416 * Cell layout data function to support color swatches in the color
3417 * combobox.
3419 * \param data the current #GSCHEM_TOPLEVEL pointer.
3421 static void
3422 color_menu_swatch_layout_data (GtkCellLayout *layout,
3423 GtkCellRenderer *cell,
3424 GtkTreeModel *model,
3425 GtkTreeIter *iter,
3426 gpointer data)
3428 /* GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data; */
3429 GValue v = {0, };
3430 gint idx;
3432 /* Get the index of the color on this row */
3433 gtk_tree_model_get_value (model, iter, 1, &v);
3434 idx = g_value_get_int (&v);
3436 /* Set the cell's background color */
3437 g_object_set (cell, "background-gdk", x_get_color (idx), NULL);
3440 /*! \brief Handle color combobox selection change event.
3441 * \par Function Description
3442 * Update application state to reflect color combobox selection
3443 * changes.
3445 * \param data the current #GSCHEM_TOPLEVEL pointer.
3447 static void
3448 color_menu_change_selection (GtkWidget *widget,
3449 gpointer data)
3451 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data;
3452 GtkComboBox *cbox = GTK_COMBO_BOX (widget);
3453 gint idx;
3454 GtkTreeIter iter;
3455 GValue v = {0, };
3457 if (!gtk_combo_box_get_active_iter (cbox, &iter)) {
3458 return; /* No color selected */
3460 gtk_tree_model_get_value (gtk_combo_box_get_model (cbox),
3461 &iter, 1, &v);
3462 idx = g_value_get_int (&v);
3464 /* Stash the selected color in the GSCHEM_TOPLEVEL.
3465 * FIXME this is ugly. */
3466 w_current->edit_color = idx;
3469 /*! \brief Create a ComboBox with the gschem colors.
3470 * \par Function Description
3471 * Creates a #GtkComboBox with the color list and swatches showing
3472 * each of the available colors.
3474 * The backing #GtkTreeModel is a #GtkListStore with two columns, the
3475 * first holding the user-friendly name of the color, and the other
3476 * the color map index.
3478 * \param [in] w_current The current gschem context.
3480 static GtkWidget *
3481 create_color_menu (GSCHEM_TOPLEVEL *w_current)
3483 GtkListStore *store;
3484 GtkComboBox *cbox;
3485 GtkCellLayout *layout;
3486 GtkCellRenderer *text_cell;
3487 GtkCellRenderer *color_cell;
3489 gint i;
3490 gchar *str;
3491 OBJECT *obj;
3492 GtkTreeIter iter;
3494 obj = o_select_return_first_object (w_current);
3495 if (obj != NULL)
3496 w_current->edit_color = obj->saved_color;
3498 /* The columns are: name of color, index of color. */
3499 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3500 cbox = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)));
3501 layout = GTK_CELL_LAYOUT (cbox); /* For convenience */
3503 /* Renders the color swatch. Since this won't contain text, set a
3504 * minimum width. */
3505 color_cell = GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3506 g_object_set (color_cell, "width", 25, NULL);
3507 gtk_cell_layout_pack_start (layout, color_cell, FALSE);
3508 gtk_cell_layout_set_cell_data_func (layout, color_cell,
3509 color_menu_swatch_layout_data,
3510 (gpointer) w_current,
3511 NULL);
3513 /* Renders the name of the color */
3514 text_cell = GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3515 g_object_set (text_cell, "xpad", 5, NULL);
3516 gtk_cell_layout_pack_start (layout, text_cell, TRUE);
3517 gtk_cell_layout_add_attribute (layout, text_cell, "text", 0);
3519 /* Populate the list */
3520 for (i = 0; i < MAX_COLORS; i++) {
3521 /* Skip 'invalid' colors. FIXME this is ugly. */
3522 gchar *buf = x_color_get_name(i);
3523 if (buf == NULL) continue;
3524 g_free (buf);
3526 str = index2functionstring (i);
3527 gtk_list_store_append (store, &iter);
3528 gtk_list_store_set (store, &iter, 0, str, 1, i, -1);
3529 if (i == w_current->edit_color)
3530 gtk_combo_box_set_active_iter (cbox, &iter);
3533 g_signal_connect (cbox,
3534 "changed",
3535 GTK_SIGNAL_FUNC (color_menu_change_selection),
3536 w_current);
3538 return GTK_WIDGET (cbox);
3541 /*! \brief Apply a color change to selected objects
3542 * \par Function Description
3543 * This function applies a color change to the currently selected objects.
3545 void color_edit_dialog_apply(GtkWidget *w, GSCHEM_TOPLEVEL *w_current)
3547 TOPLEVEL *toplevel = safe_toplevel(w_current);
3548 PAGE *page = safe_page_current(toplevel);;
3549 GList *s_current = NULL;
3550 OBJECT *object = NULL;
3552 s_current = geda_list_get_glist(page->selection_list);
3554 while(s_current != NULL) {
3555 object = s_current->data;
3556 if (object == NULL) {
3557 fprintf(stderr, _("ERROR: NULL object in color_edit_dialog_apply!\n"));
3558 exit(-1);
3561 switch(object->type) {
3562 case(OBJ_LINE):
3563 case(OBJ_BOX):
3564 case(OBJ_CIRCLE):
3565 case(OBJ_NET):
3566 case(OBJ_BUS):
3567 case(OBJ_PIN):
3568 case(OBJ_ARC):
3569 object->saved_color = w_current->edit_color;
3570 page->CHANGED = 1;
3571 break;
3573 case(OBJ_TEXT):
3574 object->saved_color = w_current->edit_color;
3575 o_complex_set_saved_color_only(
3576 object->text->prim_objs,
3577 w_current->edit_color);
3578 page->CHANGED = 1;
3579 break;
3582 s_current = g_list_next(s_current);
3584 o_undo_savestate(w_current, UNDO_ALL);
3587 /*! \brief response function for the color edit dialog
3588 * \par Function Description
3589 * This function takes the user response from the color edit dialog
3591 void color_edit_dialog_response(GtkWidget *widget, gint response, GSCHEM_TOPLEVEL *w_current)
3593 switch (response) {
3594 case GTK_RESPONSE_REJECT:
3595 case GTK_RESPONSE_DELETE_EVENT:
3596 gtk_widget_destroy(w_current->clwindow);
3597 w_current->clwindow = NULL;
3598 break;
3599 case GTK_RESPONSE_ACCEPT:
3600 color_edit_dialog_apply(widget, w_current);
3601 break;
3602 default:
3603 printf("ERROR: color_edit_dialog_response(): strange signal %d\n",response);
3608 /*! \brief Create the color edit dialog
3609 * \par Function Description
3610 * This function creates the color edit dialog
3612 void color_edit_dialog (GSCHEM_TOPLEVEL *w_current)
3614 GtkWidget *optionmenu;
3615 GtkWidget *label;
3616 GtkWidget *vbox;
3618 if (!w_current->clwindow) {
3619 w_current->clwindow = gschem_dialog_new_with_buttons(_("Color Edit"),
3620 GTK_WINDOW(w_current->main_window),
3621 0, /* nonmodal dialog */
3622 "color-edit", w_current,
3623 GTK_STOCK_CLOSE,
3624 GTK_RESPONSE_REJECT,
3625 GTK_STOCK_APPLY,
3626 GTK_RESPONSE_ACCEPT,
3627 NULL);
3629 /* Set the alternative button order (ok, cancel, help) for other systems */
3630 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->clwindow),
3631 GTK_RESPONSE_ACCEPT,
3632 GTK_RESPONSE_REJECT,
3633 -1);
3635 gtk_window_position (GTK_WINDOW (w_current->clwindow),
3636 GTK_WIN_POS_MOUSE);
3638 gtk_dialog_set_default_response (GTK_DIALOG (w_current->clwindow),
3639 GTK_RESPONSE_ACCEPT);
3641 gtk_signal_connect(GTK_OBJECT(w_current->clwindow), "response",
3642 GTK_SIGNAL_FUNC(color_edit_dialog_response),
3643 w_current);
3645 gtk_container_border_width(GTK_CONTAINER(w_current->clwindow),
3646 DIALOG_BORDER_SPACING);
3647 vbox = GTK_DIALOG(w_current->clwindow)->vbox;
3648 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3650 label = gtk_label_new(_("Object color:"));
3651 gtk_misc_set_alignment(GTK_MISC(label),0,0);
3652 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
3654 optionmenu = create_color_menu (w_current);
3655 gtk_box_pack_start(GTK_BOX(vbox),
3656 optionmenu, FALSE, FALSE, 0);
3657 gtk_widget_show_all(w_current->clwindow);
3660 else { /* dialog already created */
3661 gtk_window_present(GTK_WINDOW(w_current->clwindow));
3665 /***************** End of color edit dialog box *********************/
3667 /***************** Start of help/keymapping dialog box **************/
3669 /*! \brief Response function for the hotkey dialog
3670 * \par Function Description
3671 * This function destroys the hotkey dialog and does some cleanup.
3673 void x_dialog_hotkeys_response(GtkWidget *w, gint response,
3674 GSCHEM_TOPLEVEL *w_current)
3676 switch(response) {
3677 case GTK_RESPONSE_REJECT:
3678 case GTK_RESPONSE_DELETE_EVENT:
3679 /* void */
3680 break;
3681 default:
3682 printf("x_dialog_hotkeys_response(): strange signal %d\n", response);
3684 /* clean up */
3685 gtk_widget_destroy(w_current->hkwindow);
3686 w_current->hkwindow = NULL;
3689 /*! \brief Creates the hotkeys dialog
3690 * \par Function Description
3691 * This function creates the hotkey dialog and puts the list of hotkeys
3692 * into it.
3694 void x_dialog_hotkeys (GSCHEM_TOPLEVEL *w_current)
3696 GtkWidget *vbox, *scrolled_win;
3697 GtkListStore *store;
3698 GtkWidget *treeview;
3699 GtkCellRenderer *renderer;
3700 GtkTreeViewColumn *column;
3701 GArray *keymap;
3702 gint i;
3703 struct keyseq_action_t {
3704 gchar *keyseq, *action;
3707 if (!w_current->hkwindow) {
3708 w_current->hkwindow = gschem_dialog_new_with_buttons(_("Hotkeys"),
3709 GTK_WINDOW(w_current->main_window),
3710 0, /* not modal */
3711 "hotkeys", w_current,
3712 GTK_STOCK_CLOSE,
3713 GTK_RESPONSE_REJECT,
3714 NULL);
3716 gtk_window_position (GTK_WINDOW (w_current->hkwindow),
3717 GTK_WIN_POS_NONE);
3719 gtk_signal_connect (GTK_OBJECT (w_current->hkwindow), "response",
3720 GTK_SIGNAL_FUNC(x_dialog_hotkeys_response),
3721 w_current);
3723 gtk_dialog_set_default_response(GTK_DIALOG(w_current->hkwindow),
3724 GTK_RESPONSE_ACCEPT);
3726 gtk_container_border_width (GTK_CONTAINER (w_current->hkwindow),
3727 DIALOG_BORDER_SPACING);
3728 gtk_widget_set_usize(w_current->hkwindow, 300,300);
3730 vbox = GTK_DIALOG(w_current->hkwindow)->vbox;
3731 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
3733 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
3734 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
3735 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
3736 GTK_POLICY_AUTOMATIC,
3737 GTK_POLICY_AUTOMATIC);
3739 /* the model */
3740 store = gtk_list_store_new (2,G_TYPE_STRING, G_TYPE_STRING);
3742 /* retrieve current keymap */
3743 keymap = g_keys_dump_keymap ();
3744 /* add each keymap entry to the list store of the dialog */
3745 for (i = 0; keymap && i < keymap->len; i++) {
3746 GtkTreeIter iter;
3747 struct keyseq_action_t *keymap_entry;
3749 keymap_entry = &g_array_index (keymap, struct keyseq_action_t, i);
3750 gtk_list_store_append (store, &iter);
3751 gtk_list_store_set (store, &iter,
3752 0, keymap_entry->action,
3753 1, keymap_entry->keyseq,
3754 -1);
3757 /* finally free the array for keymap */
3758 for (i = 0; keymap && i < keymap->len; i++) {
3759 struct keyseq_action_t *keymap_entry;
3760 keymap_entry = &g_array_index (keymap, struct keyseq_action_t, i);
3761 g_free (keymap_entry->keyseq);
3762 g_free (keymap_entry->action);
3764 g_array_free (keymap, TRUE);
3766 /* the tree view */
3767 treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
3768 gtk_container_add(GTK_CONTAINER(scrolled_win), treeview);
3770 /* the columns */
3771 renderer = gtk_cell_renderer_text_new ();
3772 column = gtk_tree_view_column_new_with_attributes (_("Function"),
3773 renderer,
3774 "text",
3776 NULL);
3777 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
3778 renderer = gtk_cell_renderer_text_new ();
3779 column = gtk_tree_view_column_new_with_attributes (_("Keystroke(s)"),
3780 renderer,
3781 "text",
3783 NULL);
3784 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview), column);
3786 /* show all recursively */
3787 gtk_widget_show_all(w_current->hkwindow);
3790 else { /* dialog already created */
3791 gtk_window_present(GTK_WINDOW(w_current->hkwindow));
3795 /***************** End of help/keymapping dialog box ****************/
3797 /*********** Start of misc support functions for dialog boxes *******/
3798 extern GtkWidget *stwindow;
3800 /*! \todo Finish function documentation!!!
3801 * \brief
3802 * \par Function Description
3805 void x_dialog_raise_all(GSCHEM_TOPLEVEL *w_current)
3807 if(w_current->sowindow) {
3808 gdk_window_raise(w_current->sowindow->window);
3810 if(w_current->cswindow) {
3811 gdk_window_raise(w_current->cswindow->window);
3813 if(w_current->iwindow) {
3814 gdk_window_raise(w_current->iwindow->window);
3816 if(w_current->tiwindow) {
3817 gdk_window_raise(w_current->tiwindow->window);
3819 if(w_current->tewindow) {
3820 gdk_window_raise(w_current->tewindow->window);
3822 if(w_current->sewindow) {
3823 gdk_window_raise(w_current->sewindow->window);
3825 if(w_current->aawindow) {
3826 gdk_window_raise(w_current->aawindow->window);
3828 if(w_current->mawindow) {
3829 gdk_window_raise(w_current->mawindow->window);
3831 if(w_current->aewindow) {
3832 gdk_window_raise(w_current->aewindow->window);
3834 if(w_current->trwindow) {
3835 gdk_window_raise(w_current->trwindow->window);
3837 if(w_current->tswindow) {
3838 gdk_window_raise(w_current->tswindow->window);
3840 if(w_current->abwindow) {
3841 gdk_window_raise(w_current->abwindow->window);
3843 if(w_current->hkwindow) {
3844 gdk_window_raise(w_current->hkwindow->window);
3846 if(w_current->cowindow) {
3847 gdk_window_raise(w_current->cowindow->window);
3849 if(w_current->clwindow) {
3850 gdk_window_raise(w_current->clwindow->window);
3855 /*********** End of misc support functions for dialog boxes *******/
3857 /***************** Start of generic message dialog box *******************/
3859 /*! \todo Finish function documentation!!!
3860 * \brief
3861 * \par Function Description
3864 void generic_msg_dialog (const char *msg)
3866 GtkWidget *dialog;
3868 dialog = gtk_message_dialog_new (NULL,
3869 GTK_DIALOG_MODAL |
3870 GTK_DIALOG_DESTROY_WITH_PARENT,
3871 GTK_MESSAGE_INFO,
3872 GTK_BUTTONS_OK,
3873 "%s", msg);
3875 gtk_dialog_run (GTK_DIALOG (dialog));
3876 gtk_widget_destroy (dialog);
3880 /***************** End of generic message dialog box *********************/
3882 /***************** Start of generic confirm dialog box *******************/
3884 /*! \todo Finish function documentation!!!
3885 * \brief
3886 * \par Function Description
3889 int generic_confirm_dialog (const char *msg)
3891 GtkWidget *dialog;
3892 gint r;
3894 dialog = gtk_message_dialog_new (NULL,
3895 GTK_DIALOG_MODAL |
3896 GTK_DIALOG_DESTROY_WITH_PARENT,
3897 GTK_MESSAGE_INFO,
3898 GTK_BUTTONS_OK_CANCEL,
3899 "%s", msg);
3901 r = gtk_dialog_run (GTK_DIALOG (dialog));
3902 gtk_widget_destroy (dialog);
3904 if (r == GTK_RESPONSE_OK)
3905 return 1;
3906 else
3907 return 0;
3910 /***************** End of generic confirm dialog box *********************/
3912 /***************** Start of generic file select dialog box ***************/
3913 /*! \todo Finish function documentation!!!
3914 * \brief
3915 * \par Function Description
3917 * \warning
3918 * Caller must g_free returned character string.
3920 char *generic_filesel_dialog (const char *msg, const char *templ, gint flags)
3922 GtkWidget *dialog;
3923 gchar *result = NULL, *folder, *seed;
3924 char *title;
3925 static gchar *path = NULL;
3926 static gchar *shortcuts = NULL;
3928 /* Default to load if not specified. Maybe this should cause an error. */
3929 if (! (flags & (FSB_LOAD | FSB_SAVE))) {
3930 flags = flags | FSB_LOAD;
3933 if (flags & FSB_LOAD) {
3934 title = g_strdup_printf("%s: Open", msg);
3935 dialog = gtk_file_chooser_dialog_new (title,
3936 NULL,
3937 GTK_FILE_CHOOSER_ACTION_OPEN,
3938 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3939 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
3940 NULL);
3941 /* Since this is a load dialog box, the file must exist! */
3942 flags = flags | FSB_MUST_EXIST;
3944 } else {
3945 title = g_strdup_printf("%s: Save", msg);
3946 dialog = gtk_file_chooser_dialog_new (title,
3947 NULL,
3948 GTK_FILE_CHOOSER_ACTION_SAVE,
3949 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3950 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
3951 NULL);
3954 /* Set the alternative button order (ok, cancel, help) for other systems */
3955 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
3956 GTK_RESPONSE_OK,
3957 GTK_RESPONSE_CANCEL,
3958 -1);
3960 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
3962 /* Pick the current default folder to look for files in */
3963 if (path && *path) {
3964 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), path);
3968 /* Pick the current template (*.rc) or default file name */
3969 if (templ && *templ) {
3970 if (flags & FSB_SAVE) {
3971 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), templ);
3972 } else {
3973 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (dialog), templ);
3978 if (shortcuts && *shortcuts) {
3979 printf ("shortcuts = \"%s\"\n", shortcuts);
3980 folder = g_strdup (shortcuts);
3981 seed = folder;
3982 while ((folder = strtok (seed, ":")) != NULL) {
3983 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog),
3984 folder, NULL);
3985 seed = NULL;
3988 g_free (folder);
3991 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
3992 result = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
3993 folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
3994 /*! \bug FIXME
3995 if (folder && path) {
3996 dup_string (path, folder);
3997 g_free (folder);
4001 gtk_widget_destroy (dialog);
4003 g_free (title);
4005 return result;
4008 /***************** End of generic file select dialog box *****************/
4010 /*********** Start of find text dialog box *******/
4012 int start_find;
4013 PAGE *remember_page;
4015 /*! \brief response function for the find text dialog
4016 * \par Function Description
4017 * This function takes the string the user likes to find and searches it
4018 * in the schematic.
4020 void find_text_dialog_response(GtkWidget *w, gint response,
4021 GSCHEM_TOPLEVEL *w_current)
4023 TOPLEVEL *toplevel = w_current->toplevel;
4024 GtkWidget *textentry;
4025 GtkWidget *checkdescend;
4026 gchar *string;
4027 gint done=0, close=0;
4029 switch (response) {
4030 case GTK_RESPONSE_ACCEPT:
4031 textentry = g_object_get_data(G_OBJECT(w_current->tfindwindow),"textentry");
4032 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4033 checkdescend = g_object_get_data(G_OBJECT(w_current->tfindwindow),"checkdescend");
4035 strncpy(generic_textstring, string, 256);
4037 if (remember_page != toplevel->page_current) {
4038 s_toplevel_goto_page(toplevel, remember_page);
4040 done =
4041 o_edit_find_text(w_current, remember_page->object_head, string,
4042 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
4043 (checkdescend)),
4044 !start_find);
4045 if (done) {
4046 o_redraw_all(w_current);
4047 close = 1;
4049 start_find = 0;
4050 break;
4051 case GTK_RESPONSE_REJECT:
4052 case GTK_RESPONSE_DELETE_EVENT:
4053 close = 1;
4054 break;
4055 default:
4056 printf("find_text_dialog_response(): strange signal %d\n", response);
4058 if (close) {
4059 gtk_widget_destroy(w_current->tfindwindow);
4060 w_current->tfindwindow = NULL;
4064 /*! \brief Create the text find dialog
4065 * \par Function Description
4066 * This function creates the text find dialog.
4068 void find_text_dialog(GSCHEM_TOPLEVEL *w_current)
4070 GtkWidget *label = NULL;
4071 GtkWidget *vbox;
4072 GtkWidget *checkdescend;
4073 GtkWidget *textentry;
4074 OBJECT *object = NULL;
4076 start_find = 1;
4077 remember_page = w_current->toplevel->page_current;
4078 if ((object = o_select_return_first_object(w_current)) != NULL) {
4079 if (object->type == OBJ_TEXT) {
4080 strncpy(generic_textstring, o_text_get_string(object), 256);
4084 if (!w_current->tfindwindow) {
4085 w_current->tfindwindow = gschem_dialog_new_with_buttons(_("Find Text"),
4086 GTK_WINDOW(w_current->main_window),
4087 0, /* not modal GTK_DIALOG_MODAL */
4088 "find-text", w_current,
4089 GTK_STOCK_CLOSE,
4090 GTK_RESPONSE_REJECT,
4091 GTK_STOCK_FIND,
4092 GTK_RESPONSE_ACCEPT,
4093 NULL);
4095 /* Set the alternative button order (ok, cancel, help) for other systems */
4096 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tfindwindow),
4097 GTK_RESPONSE_ACCEPT,
4098 GTK_RESPONSE_REJECT,
4099 -1);
4101 gtk_window_position(GTK_WINDOW(w_current->tfindwindow),
4102 GTK_WIN_POS_MOUSE);
4104 gtk_signal_connect(GTK_OBJECT(w_current->tfindwindow), "response",
4105 GTK_SIGNAL_FUNC(find_text_dialog_response),
4106 w_current);
4108 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tfindwindow),
4109 GTK_RESPONSE_ACCEPT);
4111 gtk_container_border_width(GTK_CONTAINER(w_current->tfindwindow),
4112 DIALOG_BORDER_SPACING);
4113 vbox = GTK_DIALOG(w_current->tfindwindow)->vbox;
4114 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4116 label = gtk_label_new(_("Text to find:"));
4117 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4118 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4120 textentry = gtk_entry_new_with_max_length(20);
4121 gtk_editable_select_region(GTK_EDITABLE(textentry), 0, -1);
4122 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4123 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4124 gtk_widget_grab_focus(textentry);
4126 checkdescend = gtk_check_button_new_with_label(_("descend into hierarchy"));
4127 gtk_box_pack_start(GTK_BOX(vbox), checkdescend, TRUE, TRUE, 0);
4129 GLADE_HOOKUP_OBJECT(w_current->tfindwindow, textentry, "textentry");
4130 GLADE_HOOKUP_OBJECT(w_current->tfindwindow, checkdescend, "checkdescend");
4132 gtk_widget_show_all(w_current->tfindwindow);
4135 else { /* dialog already created */
4136 gtk_window_present(GTK_WINDOW(w_current->tfindwindow));
4139 /* always select the text string in the entry */
4140 textentry = g_object_get_data (G_OBJECT (w_current->tfindwindow), "textentry");
4141 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4142 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4145 /*********** End of find text dialog box *******/
4147 /*********** Start of hide text dialog box *******/
4149 /*! \brief Response function for the hide text dialog
4150 * \par Function Description
4151 * This is the response function of the hide text dialog. It takes the user input
4152 * and hides all text elements that starts with the searchtext.
4154 void hide_text_dialog_response(GtkWidget *w, gint response,
4155 GSCHEM_TOPLEVEL *w_current)
4157 GtkWidget *textentry;
4158 gchar *string;
4160 switch (response) {
4161 case GTK_RESPONSE_ACCEPT:
4162 textentry = g_object_get_data(G_OBJECT(w_current->thidewindow),"textentry");
4163 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4165 strncpy(generic_textstring, string, 256);
4166 o_edit_hide_specific_text(w_current,
4167 w_current->toplevel->page_current->object_head, string);
4168 break;
4169 case GTK_RESPONSE_REJECT:
4170 case GTK_RESPONSE_DELETE_EVENT:
4171 gtk_widget_destroy(w_current->thidewindow);
4172 w_current->thidewindow = NULL;
4173 break;
4174 default:
4175 printf("show_text_dialog_response(): strange signal %d\n",response);
4179 /*! \brief Creates the hide text dialog
4180 * \par Function Description
4181 * This function creates the hide text dialog.
4183 void hide_text_dialog(GSCHEM_TOPLEVEL * w_current)
4185 GtkWidget *label = NULL;
4186 GtkWidget *textentry;
4187 GtkWidget *vbox;
4189 if (!w_current->thidewindow) {
4190 w_current->thidewindow = gschem_dialog_new_with_buttons(_("Hide Text"),
4191 GTK_WINDOW(w_current->main_window),
4192 0, /* not modal GTK_DIALOG_MODAL, */
4193 "hide-text", w_current,
4194 GTK_STOCK_CLOSE,
4195 GTK_RESPONSE_REJECT,
4196 GTK_STOCK_APPLY,
4197 GTK_RESPONSE_ACCEPT,
4198 NULL);
4200 /* Set the alternative button order (ok, cancel, help) for other systems */
4201 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->thidewindow),
4202 GTK_RESPONSE_ACCEPT,
4203 GTK_RESPONSE_REJECT,
4204 -1);
4206 gtk_window_position(GTK_WINDOW(w_current->thidewindow),
4207 GTK_WIN_POS_MOUSE);
4209 gtk_signal_connect(GTK_OBJECT(w_current->thidewindow), "response",
4210 GTK_SIGNAL_FUNC(hide_text_dialog_response),
4211 w_current);
4213 gtk_dialog_set_default_response(GTK_DIALOG(w_current->thidewindow),
4214 GTK_RESPONSE_ACCEPT);
4216 gtk_container_border_width(GTK_CONTAINER(w_current->thidewindow),
4217 DIALOG_BORDER_SPACING);
4218 vbox = GTK_DIALOG(w_current->thidewindow)->vbox;
4219 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4221 label = gtk_label_new(_("Hide text starting with:"));
4222 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4223 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4225 textentry = gtk_entry_new_with_max_length(20);
4226 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4227 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4228 gtk_widget_grab_focus(textentry);
4230 GLADE_HOOKUP_OBJECT(w_current->thidewindow, textentry, "textentry");
4231 gtk_widget_show_all(w_current->thidewindow);
4234 else { /* dialog already created, just select it */
4235 gtk_window_present(GTK_WINDOW(w_current->thidewindow));
4238 /* always select the text in the search entry */
4239 textentry = g_object_get_data (G_OBJECT (w_current->thidewindow), "textentry");
4240 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4241 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4244 /*********** End of hide text dialog box *******/
4246 /*********** Start of show text dialog box *******/
4248 /*! \brief Response function for the show text dialog
4249 * \par Function Description
4250 * This function takes the users input and searches all strings starting with
4251 * the given search text and hides those text objects.
4253 void show_text_dialog_response(GtkWidget *widget, gint response,
4254 GSCHEM_TOPLEVEL *w_current)
4256 GtkWidget *textentry;
4257 gchar *string;
4259 switch (response) {
4260 case GTK_RESPONSE_ACCEPT:
4261 textentry = g_object_get_data(G_OBJECT(w_current->tshowwindow),"textentry");
4262 string = (gchar*) gtk_entry_get_text(GTK_ENTRY(textentry));
4264 strncpy(generic_textstring, string, 256);
4265 o_edit_show_specific_text(w_current,
4266 w_current->toplevel->page_current->object_head, string);
4267 break;
4268 case GTK_RESPONSE_REJECT:
4269 case GTK_RESPONSE_DELETE_EVENT:
4270 gtk_widget_destroy(w_current->tshowwindow);
4271 w_current->tshowwindow = NULL;
4272 break;
4273 default:
4274 printf("show_text_dialog_response(): strange signal %d\n",response);
4278 /*! \brief Create the show text dialog.
4279 * \par Function Description
4280 * This function creates the show text dialog.
4282 void show_text_dialog(GSCHEM_TOPLEVEL * w_current)
4284 GtkWidget *label = NULL;
4285 GtkWidget *textentry;
4286 GtkWidget *vbox;
4288 if (!w_current->tshowwindow) {
4289 w_current->tshowwindow = gschem_dialog_new_with_buttons(_("Show Text"),
4290 GTK_WINDOW(w_current->main_window),
4291 0, /* not modal GTK_DIALOG_MODAL, */
4292 "show-text", w_current,
4293 GTK_STOCK_CLOSE,
4294 GTK_RESPONSE_REJECT,
4295 GTK_STOCK_APPLY,
4296 GTK_RESPONSE_ACCEPT,
4297 NULL);
4299 /* Set the alternative button order (ok, cancel, help) for other systems */
4300 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current->tshowwindow),
4301 GTK_RESPONSE_ACCEPT,
4302 GTK_RESPONSE_REJECT,
4303 -1);
4305 gtk_window_position(GTK_WINDOW(w_current->tshowwindow),
4306 GTK_WIN_POS_MOUSE);
4308 gtk_signal_connect(GTK_OBJECT(w_current->tshowwindow), "response",
4309 GTK_SIGNAL_FUNC(show_text_dialog_response),
4310 w_current);
4312 gtk_dialog_set_default_response(GTK_DIALOG(w_current->tshowwindow),
4313 GTK_RESPONSE_ACCEPT);
4315 gtk_container_border_width(GTK_CONTAINER(w_current->tshowwindow),
4316 DIALOG_BORDER_SPACING);
4317 vbox = GTK_DIALOG(w_current->tshowwindow)->vbox;
4318 gtk_box_set_spacing(GTK_BOX(vbox), DIALOG_V_SPACING);
4320 label = gtk_label_new(_("Show text starting with:"));
4321 gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
4322 gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
4324 textentry = gtk_entry_new_with_max_length(20);
4325 gtk_box_pack_start(GTK_BOX(vbox), textentry, FALSE, FALSE, 0);
4326 gtk_entry_set_activates_default(GTK_ENTRY(textentry), TRUE);
4327 gtk_widget_grab_focus(textentry);
4329 GLADE_HOOKUP_OBJECT(w_current->tshowwindow, textentry, "textentry");
4330 gtk_widget_show_all(w_current->tshowwindow);
4333 else { /* dialog already created. Show it */
4334 gtk_window_present(GTK_WINDOW(w_current->tshowwindow));
4337 /* always select the text in the entry */
4338 textentry = g_object_get_data (G_OBJECT (w_current->tshowwindow), "textentry");
4339 gtk_entry_set_text(GTK_ENTRY(textentry), generic_textstring);
4340 gtk_entry_select_region(GTK_ENTRY(textentry), 0, -1);
4343 /*********** End of show text dialog box *******/
4345 /*********** Start of some Gtk utils *******/
4347 /*! \brief Selects all text in a TextView widget
4348 * \par Function Description
4349 * The function selects all the text in a TextView widget.
4351 void select_all_text_in_textview(GtkTextView *textview)
4353 GtkTextBuffer *textbuffer;
4354 GtkTextIter start, end;
4356 textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
4357 gtk_text_buffer_get_bounds (textbuffer, &start, &end);
4358 gtk_text_buffer_select_range(textbuffer, &start, &end);
4361 /*! \todo Finish function documentation!!!
4362 * \brief
4363 * \par Function Description
4366 int text_view_calculate_real_tab_width(GtkTextView *textview, int tab_size)
4368 PangoLayout *layout;
4369 gchar *tab_string;
4370 gint tab_width = 0;
4372 if (tab_size == 0)
4373 return -1;
4375 tab_string = g_strnfill (tab_size, ' ');
4377 layout = gtk_widget_create_pango_layout (
4378 GTK_WIDGET (textview),
4379 tab_string);
4380 g_free (tab_string);
4382 if (layout != NULL) {
4383 pango_layout_get_pixel_size (layout, &tab_width, NULL);
4384 g_object_unref (G_OBJECT (layout));
4385 } else
4386 tab_width = -1;
4388 return tab_width;
4392 /*********** End of some Gtk utils *******/
4394 /*********** Start of major symbol changed dialog box *******/
4396 /*! \todo Finish function documentation!!!
4397 * \brief
4398 * \par Function Description
4401 void major_changed_dialog(GSCHEM_TOPLEVEL* w_current)
4403 GtkWidget* dialog;
4404 char* refdes_string = NULL;
4405 char* tmp;
4407 if (w_current->toplevel->major_changed_refdes) {
4409 GList* current = w_current->toplevel->major_changed_refdes;
4410 while (current)
4412 char *value = (char*) current->data;
4414 if (!refdes_string)
4416 refdes_string = g_strdup (value);
4417 } else {
4418 tmp = g_strconcat (refdes_string, "\n", value, NULL);
4419 g_free(refdes_string);
4420 refdes_string = tmp;
4423 current = g_list_next(current);
4426 tmp = g_strconcat (refdes_string,
4427 "\n\nBe sure to verify each of these symbols!",
4428 NULL);
4429 g_free(refdes_string);
4430 refdes_string = tmp;
4432 dialog = gtk_message_dialog_new ((GtkWindow*) w_current->main_window,
4433 GTK_DIALOG_DESTROY_WITH_PARENT,
4434 GTK_MESSAGE_ERROR,
4435 GTK_BUTTONS_CLOSE,
4436 "Major symbol changes detected in refdes:\n\n%s\n",
4437 refdes_string);
4439 gtk_widget_show(dialog);
4441 g_signal_connect_swapped (dialog, "response",
4442 G_CALLBACK (gtk_widget_destroy),
4443 dialog);
4445 g_free(refdes_string);
4449 /*********** End of major symbol changed dialog box *******/
4451 /***************** Start of Close Confirmation dialog box ************/
4453 #define TYPE_CLOSE_CONFIRMATION_DIALOG (close_confirmation_dialog_get_type ())
4454 #define CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialog))
4455 #define CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4456 #define IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG))
4457 #define IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG))
4458 #define CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4461 typedef struct _CloseConfirmationDialog CloseConfirmationDialog;
4462 typedef struct _CloseConfirmationDialogClass CloseConfirmationDialogClass;
4464 struct _CloseConfirmationDialog
4466 GtkDialog parent;
4468 GtkListStore *store_unsaved_pages;
4471 struct _CloseConfirmationDialogClass
4473 GtkDialogClass parent_class;
4477 enum {
4478 PROP_UNSAVED_PAGE=1,
4479 PROP_UNSAVED_PAGES,
4480 PROP_SELECTED_PAGES
4483 enum {
4484 COLUMN_SAVE,
4485 COLUMN_PAGE,
4486 NUM_COLUMNS
4490 static gpointer close_confirmation_dialog_parent_class = NULL;
4493 static void close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass);
4494 static void close_confirmation_dialog_init (CloseConfirmationDialog *self);
4495 static void close_confirmation_dialog_set_property (GObject *object,
4496 guint property_id,
4497 const GValue *value,
4498 GParamSpec *pspec);
4499 static void close_confirmation_dialog_get_property (GObject *object,
4500 guint property_id,
4501 GValue *value,
4502 GParamSpec *pspec);
4503 static GObject* close_confirmation_dialog_constructor (GType type,
4504 guint n_construct_properties,
4505 GObjectConstructParam *construct_params);
4507 GList *close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog);
4511 GType
4512 close_confirmation_dialog_get_type ()
4514 static GType close_confirmation_dialog_type = 0;
4516 if (!close_confirmation_dialog_type) {
4517 static const GTypeInfo close_confirmation_dialog_info = {
4518 sizeof(CloseConfirmationDialogClass),
4519 NULL, /* base_init */
4520 NULL, /* base_finalize */
4521 (GClassInitFunc) close_confirmation_dialog_class_init,
4522 NULL, /* class_finalize */
4523 NULL, /* class_data */
4524 sizeof(CloseConfirmationDialog),
4525 0, /* n_preallocs */
4526 (GInstanceInitFunc) close_confirmation_dialog_init,
4529 close_confirmation_dialog_type =
4530 g_type_register_static (GTK_TYPE_DIALOG,
4531 "CloseConfirmationDialog",
4532 &close_confirmation_dialog_info, 0);
4535 return close_confirmation_dialog_type;
4538 static void
4539 close_confirmation_dialog_class_init (CloseConfirmationDialogClass *klass)
4541 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
4543 close_confirmation_dialog_parent_class = g_type_class_peek_parent (klass);
4545 gobject_class->constructor = close_confirmation_dialog_constructor;
4546 gobject_class->set_property = close_confirmation_dialog_set_property;
4547 gobject_class->get_property = close_confirmation_dialog_get_property;
4549 g_object_class_install_property (
4550 gobject_class, PROP_UNSAVED_PAGE,
4551 g_param_spec_pointer ("unsaved-page",
4554 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
4555 g_object_class_install_property (
4556 gobject_class, PROP_UNSAVED_PAGES,
4557 g_param_spec_pointer ("unsaved-pages",
4560 G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
4561 g_object_class_install_property (
4562 gobject_class, PROP_SELECTED_PAGES,
4563 g_param_spec_pointer ("selected-pages",
4566 G_PARAM_READABLE));
4570 static void
4571 close_confirmation_dialog_init (CloseConfirmationDialog *self)
4573 /* create model for treeview and populate */
4574 self->store_unsaved_pages = gtk_list_store_new (NUM_COLUMNS,
4575 G_TYPE_BOOLEAN, /* save? */
4576 G_TYPE_POINTER); /* page */
4580 /*! \brief Returns the number of pages in the model.
4581 * \par Function Description
4582 * This function determines the number of pages with unsaved changes
4583 * from the model.
4585 * \param in model The tree model.
4586 * \returns The number of pages with unsaved changes.
4588 static gint
4589 count_pages (GtkTreeModel *model)
4591 GtkTreeIter iter;
4592 gint n_pages;
4594 gtk_tree_model_get_iter_first (model, &iter);
4595 for (n_pages = 1;
4596 gtk_tree_model_iter_next (model, &iter);
4597 n_pages++);
4599 return n_pages;
4602 /*! \brief Returns the name to use for the given page in the model.
4603 * \par Function Description
4604 * This function determines the text to be used to identify a
4605 * specific page from the model of pages with unsaved changes.
4607 * If <B>piter</B> is NULL, the name for the first page of the model
4608 * is returned. Otherwise, it returns the name for the page defined
4609 * by the pointed iterator.
4611 * The returned value must be freed by caller.
4613 * \param in model The tree model.
4614 * \param in piter A pointer on a GtkTreeIter of model or NULL.
4615 * \returns The name for the page.
4617 static gchar*
4618 get_page_name (GtkTreeModel *model, GtkTreeIter *piter)
4620 GtkTreeIter iter;
4621 PAGE *page;
4623 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
4625 if (piter == NULL) {
4626 gtk_tree_model_get_iter_first (model, &iter);
4627 } else {
4628 iter = *piter;
4631 gtk_tree_model_get (model, &iter,
4632 COLUMN_PAGE, &page,
4633 -1);
4634 g_assert (page != NULL && page->page_filename != NULL);
4635 return g_path_get_basename (page->page_filename);
4638 /*! \brief Sets the contents of the name cell in the treeview of dialog.
4639 * \par Function Description
4640 * This functions sets the cell of the treeview with the short name
4641 * of the page obtained with <B>get_page_name()</B>.
4643 * \param in tree_column A GtkTreeColumn.
4644 * \param in cell The GtkCellRenderer that is being rendered by
4645 * tree_column.
4646 * \param in tree_model The GtkTreeModel being rendered.
4647 * \param in iter A GtkTreeIter of the current row rendered.
4648 * \param in data .
4650 static void
4651 close_confirmation_dialog_set_page_name (GtkTreeViewColumn *tree_column,
4652 GtkCellRenderer *cell,
4653 GtkTreeModel *tree_model,
4654 GtkTreeIter *iter,
4655 gpointer data)
4657 gchar *page_name;
4659 page_name = get_page_name (tree_model, iter);
4660 g_object_set (cell,
4661 "text", page_name,
4662 NULL);
4663 g_free (page_name);
4667 /*! \brief Callback function for the toggled signal of check box in treeview.
4668 * \par Function Description
4669 * This functions changes the value of the save column in the model
4670 * for the affected row when user toggles the check box in the
4671 * treeview.
4673 * \param in cell_renderer The GtkCellRendererToggle.
4674 * \param in path The GtkTreePath to the concerned row in model.
4675 * \param in user The dialog as user data.
4677 static void
4678 close_confirmation_dialog_callback_renderer_toggled (GtkCellRendererToggle *cell_renderer,
4679 gchar *path,
4680 gpointer user_data)
4682 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (user_data);
4683 GtkTreeModel *model;
4684 GtkTreeIter iter;
4685 gboolean save;
4687 model = GTK_TREE_MODEL (dialog->store_unsaved_pages);
4689 gtk_tree_model_get_iter_from_string (model, &iter, path);
4690 gtk_tree_model_get (model, &iter,
4691 COLUMN_SAVE, &save,
4692 -1);
4693 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
4694 COLUMN_SAVE, (save != TRUE),
4695 -1);
4699 /*! \brief Adds a treeview to confirmation dialog for selecting of pages.
4700 * \par Function Description
4701 * This function adds a treeview and caption to display the content
4702 * of the dialog model of pages with unsaved changes.
4704 * The treeview displays the page names with check boxes.
4706 * \param in dialog The dialog.
4707 * \returns A pointer on the GtkVBox to add to dialog.
4709 static GtkWidget*
4710 close_confirmation_dialog_build_page_list (CloseConfirmationDialog *dialog)
4712 GtkWidget *vbox, *scrolled_window, *treeview, *label;
4713 GtkCellRenderer *renderer;
4714 GtkTreeViewColumn *column;
4715 const gchar *text;
4717 /* place the treeview and its caption into their own box */
4718 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
4719 /* GtkBox */
4720 "homogeneous", FALSE,
4721 "spacing", 8,
4722 NULL));
4724 /* the list of pages with changes */
4725 /* - scrolled window as container for the treeview first */
4726 scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
4727 /* GtkScrolledWindow */
4728 "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
4729 "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
4730 "shadow-type", GTK_SHADOW_IN,
4731 NULL));
4732 /* - then the treeview */
4733 /* create model for treeview and populate */
4734 treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
4735 /* GtkTreeView */
4736 "enable-search", FALSE,
4737 "headers-visible", FALSE,
4738 "model", dialog->store_unsaved_pages,
4739 NULL));
4740 renderer = gtk_cell_renderer_toggle_new ();
4741 g_signal_connect (renderer, "toggled",
4742 G_CALLBACK (
4743 close_confirmation_dialog_callback_renderer_toggled),
4744 dialog);
4745 column = gtk_tree_view_column_new_with_attributes ("Save?",
4746 renderer,
4747 "active", COLUMN_SAVE,
4748 NULL);
4749 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4751 renderer = gtk_cell_renderer_text_new ();
4752 column = GTK_TREE_VIEW_COLUMN (
4753 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
4754 /* GtkTreeViewColumn */
4755 "title", _("Name"),
4756 NULL));
4757 gtk_tree_view_column_pack_start (column, renderer, TRUE);
4758 gtk_tree_view_column_set_cell_data_func (column, renderer,
4759 close_confirmation_dialog_set_page_name,
4760 NULL, NULL);
4761 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
4763 gtk_container_add (GTK_CONTAINER (scrolled_window), treeview);
4765 gtk_box_pack_end (GTK_BOX (vbox), scrolled_window,
4766 TRUE, TRUE, 0);
4768 /* the caption label above the list of pages */
4769 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4770 /* GtkMisc */
4771 "xalign", 0.0,
4772 "yalign", 0.0,
4773 /* GtkLabel */
4774 "wrap", TRUE,
4775 "mnemonic-widget", treeview,
4776 NULL));
4777 text = _("S_elect the schematics you want to save:");
4778 gtk_label_set_text_with_mnemonic (GTK_LABEL (label), text);
4779 gtk_label_set_mnemonic_widget (GTK_LABEL (label), treeview);
4780 gtk_box_pack_start (GTK_BOX (vbox), label,
4781 FALSE, FALSE, 0);
4783 return vbox;
4786 static GObject*
4787 close_confirmation_dialog_constructor (GType type,
4788 guint n_construct_properties,
4789 GObjectConstructParam *construct_params)
4791 GObject *object;
4792 CloseConfirmationDialog *dialog;
4793 GtkWidget *hbox, *image, *vbox, *label;
4794 GtkTreeIter iter;
4795 gboolean ret, single_page;
4796 gchar *tmp, *str;
4798 /* chain up to constructor of parent class */
4799 object =
4800 G_OBJECT_CLASS (close_confirmation_dialog_parent_class)->constructor (
4801 type,
4802 n_construct_properties,
4803 construct_params);
4804 dialog = CLOSE_CONFIRMATION_DIALOG (object);
4806 g_object_set (dialog,
4807 /* GtkDialog */
4808 "has-separator", FALSE,
4809 /* GtkWindow */
4810 "resizable", FALSE,
4811 "skip-taskbar-hint", TRUE,
4812 /* GtkContainer */
4813 "border-width", 5,
4814 NULL);
4815 g_object_set (GTK_DIALOG (dialog)->vbox,
4816 /* GtkBox */
4817 "spacing", 14,
4818 NULL);
4819 g_object_set (GTK_DIALOG (dialog)->action_area,
4820 /* GtkBox */
4821 "spacing", 6,
4822 /* GtkContainer */
4823 "border-width", 5,
4824 NULL);
4826 /* check if there is one or more than one page with changes */
4827 ret = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (
4828 dialog->store_unsaved_pages),
4829 &iter);
4830 g_assert (ret);
4831 single_page = !gtk_tree_model_iter_next (GTK_TREE_MODEL (
4832 dialog->store_unsaved_pages),
4833 &iter);
4835 /* here starts the layout of the dialog */
4836 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
4837 /* GtkContainer */
4838 "border-width", 5,
4839 /* GtkBox */
4840 "homogeneous", FALSE,
4841 "spacing", 12,
4842 NULL));
4844 /* warning image */
4845 image = g_object_new (GTK_TYPE_IMAGE,
4846 /* GtkMisc */
4847 "xalign", 0.5,
4848 "yalign", 0.0,
4849 /* GtkImage */
4850 "stock", GTK_STOCK_DIALOG_WARNING,
4851 "icon-size", GTK_ICON_SIZE_DIALOG,
4852 NULL);
4853 gtk_box_pack_start (GTK_BOX (hbox), image,
4854 FALSE, FALSE, 0);
4856 /* vertical box on the right hand side of the dialog */
4857 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
4858 /* GtkBox */
4859 "homogeneous", FALSE,
4860 "spacing", 12,
4861 NULL));
4863 /* primary label */
4864 if (single_page) {
4865 /* single page */
4866 gchar *page_name;
4868 page_name = get_page_name (GTK_TREE_MODEL (dialog->store_unsaved_pages),
4869 NULL);
4870 tmp = g_strdup_printf (
4871 _("Save the changes to schematic \"%s\" before closing?"),
4872 page_name);
4873 g_free (page_name);
4874 } else {
4875 /* multi page */
4876 tmp = g_strdup_printf (
4877 _("There are %d schematics with unsaved changes. "
4878 "Save changes before closing?"),
4879 count_pages (GTK_TREE_MODEL (dialog->store_unsaved_pages)));
4881 str = g_strconcat ("<big><b>", tmp, "</b></big>", NULL);
4882 g_free (tmp);
4883 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4884 /* GtkMisc */
4885 "xalign", 0.0,
4886 "yalign", 0.0,
4887 "selectable", TRUE,
4888 /* GtkLabel */
4889 "wrap", TRUE,
4890 "use-markup", TRUE,
4891 "label", str,
4892 NULL));
4893 g_free (str);
4894 gtk_box_pack_start (GTK_BOX (vbox), label,
4895 FALSE, FALSE, 0);
4897 if (!single_page) {
4898 /* more than one page with changes, display each page and offer */
4899 /* the opportunity to save them before exiting */
4900 gtk_box_pack_start (GTK_BOX (vbox),
4901 close_confirmation_dialog_build_page_list (dialog),
4902 FALSE, FALSE, 0);
4905 /* secondary label */
4906 str = _("If you don't save, all your changes will be permanently lost.");
4907 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
4908 /* GtkMisc */
4909 "xalign", 0.0,
4910 "yalign", 0.0,
4911 "selectable", TRUE,
4912 /* GtkLabel */
4913 "wrap", TRUE,
4914 "label", str,
4915 NULL));
4916 gtk_box_pack_start (GTK_BOX (vbox), label,
4917 FALSE, FALSE, 0);
4920 gtk_box_pack_start (GTK_BOX (hbox), vbox,
4921 FALSE, FALSE, 0);
4924 /* add buttons to dialog action area */
4925 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
4926 _("_Close without saving"), GTK_RESPONSE_NO,
4927 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
4928 GTK_STOCK_SAVE, GTK_RESPONSE_YES,
4929 NULL);
4931 /* Set the alternative button order (ok, cancel, help) for other systems */
4932 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog),
4933 GTK_RESPONSE_YES,
4934 GTK_RESPONSE_NO,
4935 GTK_RESPONSE_CANCEL,
4936 -1);
4938 /* all done, let's show the contents of the dialog */
4939 gtk_widget_show_all (hbox);
4941 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
4942 FALSE, FALSE, 0);
4944 return object;
4947 static void
4948 close_confirmation_dialog_set_property (GObject *object,
4949 guint property_id,
4950 const GValue *value,
4951 GParamSpec *pspec)
4953 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
4954 GtkTreeIter iter;
4955 gpointer data;
4956 GList *p_current;
4958 switch(property_id) {
4959 case PROP_UNSAVED_PAGE:
4960 data = g_value_get_pointer (value);
4961 if (data != NULL) {
4962 /* add single page to model */
4963 gtk_list_store_append (dialog->store_unsaved_pages,
4964 &iter);
4965 gtk_list_store_set (dialog->store_unsaved_pages,
4966 &iter,
4967 COLUMN_SAVE, TRUE,
4968 COLUMN_PAGE, data,
4969 -1);
4971 break;
4973 case PROP_UNSAVED_PAGES:
4974 data = g_value_get_pointer (value);
4975 /* add set of pages to model */
4976 for (p_current = (GList*)data;
4977 p_current != NULL;
4978 p_current = g_list_next (p_current)) {
4979 gtk_list_store_append (dialog->store_unsaved_pages,
4980 &iter);
4981 gtk_list_store_set (dialog->store_unsaved_pages,
4982 &iter,
4983 COLUMN_SAVE, TRUE,
4984 COLUMN_PAGE, p_current->data,
4985 -1);
4987 break;
4989 default:
4990 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
4995 static void
4996 close_confirmation_dialog_get_property (GObject *object,
4997 guint property_id,
4998 GValue *value,
4999 GParamSpec *pspec)
5001 CloseConfirmationDialog *dialog = CLOSE_CONFIRMATION_DIALOG (object);
5003 switch(property_id) {
5004 case PROP_SELECTED_PAGES:
5005 g_value_set_pointer (
5006 value,
5007 close_confirmation_dialog_get_selected_pages (dialog));
5008 break;
5010 default:
5011 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
5016 /*! \brief Helps building a list of selected page to save.
5017 * \par Function Description
5018 * This is the <B>GtkTreeModelForeachFunc</B> for function
5019 * <B>close_confirmation_dialog_get_selected_pages()</B>.
5021 * It builds from the tree model a list of PAGEs for which a save
5022 * action has been requested. Each selected page is appended to the
5023 * GList pointed by <B>data</B>
5025 * \param in model The tree model.
5026 * \param in path .
5027 * \param in iter .
5028 * \param in data A pointer on a GList* to fill.
5029 * \returns FALSE to continue walking the tree.
5031 static gboolean
5032 get_selected_pages (GtkTreeModel *model,
5033 GtkTreePath *path,
5034 GtkTreeIter *iter,
5035 gpointer data)
5037 PAGE *page;
5038 gboolean save;
5040 gtk_tree_model_get (model, iter,
5041 COLUMN_SAVE, &save,
5042 COLUMN_PAGE, &page,
5043 -1);
5044 if (save) {
5045 g_assert (page != NULL);
5046 *(GList**)data = g_list_append (*(GList**)data, page);
5049 return FALSE;
5052 /*! \brief Returns a list of the selected pages with changes to save.
5053 * \par Function Description
5054 * This function returns the pages that the user has selected in the
5055 * confirmation dialog.
5057 * The returned list must be freed.
5059 * \param in dialog The dialog.
5060 * \returns A GList of selected PAGE* in dialog.
5062 GList*
5063 close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog *dialog)
5065 GList *selected = NULL;
5067 gtk_tree_model_foreach (GTK_TREE_MODEL (dialog->store_unsaved_pages),
5068 (GtkTreeModelForeachFunc)get_selected_pages,
5069 &selected);
5071 return selected;
5075 /*! \brief Asks for confirmation before closing a changed page.
5076 * \par Function Description
5077 * This function asks the user to confirm its closing order for
5078 * page <B>page</B> while it still has unsaved changes.
5080 * It displays a message dialog inviting the user to cancel the
5081 * closing, or to discard the changes or to save the changes to a
5082 * file.
5084 * \param in toplevel The toplevel environment.
5085 * \param in page The page to close.
5087 void
5088 x_dialog_close_changed_page (GSCHEM_TOPLEVEL *w_current, PAGE *page)
5090 GtkWidget *dialog;
5091 PAGE *keep_page;
5093 g_return_if_fail (page != NULL && page->CHANGED);
5095 keep_page = w_current->toplevel->page_current;
5097 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
5098 "unsaved-page", page,
5099 NULL));
5100 /* set default response signal. This is usually triggered by the
5101 "Return" key */
5102 gtk_dialog_set_default_response(GTK_DIALOG(dialog),
5103 GTK_RESPONSE_YES);
5105 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
5106 case GTK_RESPONSE_NO:
5107 /* action selected: close without saving */
5108 /* close the page, discard changes */
5109 x_window_close_page (w_current, page);
5110 break;
5113 case GTK_RESPONSE_YES:
5114 /* action selected: save */
5115 s_toplevel_goto_page(w_current->toplevel, page);
5116 i_callback_file_save(w_current, 0, NULL);
5117 /* has the page been really saved? */
5118 if (!page->CHANGED) {
5119 x_window_close_page (w_current, page);
5121 /* no, user has cancelled the save and page has changes */
5122 /* do not close page */
5123 break;
5125 case GTK_RESPONSE_CANCEL:
5126 /* action selected: cancel */
5127 /* fall through */
5128 default:
5129 /* Hit when the user breaks out of the dialog with the escape key
5130 * or otherwise destroys the dialog window without a proper response */
5131 /* nothing to do */
5132 break;
5134 gtk_widget_destroy (dialog);
5136 /* Switch back to the page we were on if it wasn't the one being closed */
5137 g_return_if_fail (keep_page != NULL);
5138 if (keep_page != page)
5139 s_toplevel_goto_page(w_current->toplevel, keep_page);
5142 /*! \brief Asks for confirmation before closing a window.
5143 * \par Function Description
5144 * This function asks the user to confirm its closing order for
5145 * the given window.
5147 * The user is given the possibility to save the pages that currently
5148 * have unsaved changes, if any.
5150 * It returns TRUE if the user really accepts the close of the
5151 * window. Otherwise the user has somehow cancelled and the window
5152 * must not be closed.
5154 * \param in toplevel The toplevel environment.
5155 * \returns TRUE if the window can be closed, FALSE otherwise.
5157 gboolean
5158 x_dialog_close_window (GSCHEM_TOPLEVEL *w_current)
5160 TOPLEVEL *toplevel = w_current->toplevel;
5161 GList *iter;
5162 GtkWidget *dialog;
5163 PAGE *p_current;
5164 PAGE *keep_page;
5165 GList *unsaved_pages, *p_unsaved;
5166 gboolean ret = FALSE;
5168 keep_page = toplevel->page_current;
5170 for ( iter = geda_list_get_glist( toplevel->pages ), unsaved_pages = NULL;
5171 iter != NULL;
5172 iter = g_list_next( iter ) ) {
5174 p_current = (PAGE*)iter->data;
5176 if (p_current->CHANGED) {
5177 unsaved_pages = g_list_append (unsaved_pages, (gpointer)p_current);
5181 if (unsaved_pages == NULL) {
5182 /* no page with unsaved changes, close window */
5183 return TRUE;
5186 dialog = GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG,
5187 "unsaved-pages", unsaved_pages,
5188 NULL));
5190 gtk_window_set_transient_for (GTK_WINDOW (dialog),
5191 GTK_WINDOW (w_current->main_window));
5193 g_list_free (unsaved_pages);
5194 switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
5195 case GTK_RESPONSE_NO:
5196 /* action selected: close without saving */
5197 /* discard changes, ok to close window */
5198 ret = TRUE;
5199 break;
5201 case GTK_RESPONSE_YES:
5202 /* action selected: save */
5203 g_object_get (dialog,
5204 "selected-pages", &unsaved_pages,
5205 NULL);
5206 for (p_unsaved = unsaved_pages, ret = TRUE;
5207 p_unsaved != NULL;
5208 p_unsaved = g_list_next (p_unsaved)) {
5209 p_current = (PAGE*)p_unsaved->data;
5211 s_toplevel_goto_page(toplevel, p_current);
5212 i_callback_file_save(w_current, 0, NULL);
5213 /* if user cancelled previous, do not close window */
5214 ret &= !p_current->CHANGED;
5216 g_list_free (unsaved_pages);
5217 break;
5219 case GTK_RESPONSE_CANCEL:
5220 /* action selected: cancel */
5221 /* fall through */
5222 default:
5223 /* Hit when the user breaks out of the dialog with the escape key
5224 * or otherwise destroys the dialog window without a proper response */
5225 ret = FALSE;
5226 break;
5228 gtk_widget_destroy (dialog);
5230 /* Switch back to the page we were on */
5231 g_return_val_if_fail (keep_page != NULL, ret);
5232 s_toplevel_goto_page(toplevel, keep_page);
5234 return ret;
5237 /***************** End of Close Confirmation dialog box **************/
5240 /***************** Start of misc helper dialog boxes **************/
5241 /*! \brief Validate the input attribute
5242 * \par Function Description
5243 * This function validates the attribute and if it isn't valid
5244 * pops up an error message box.
5246 * \param parent The parent window which spawned this dialog box.
5247 * \param attribute The attribute to be validated.
5248 * \returns TRUE if the attribute is valid, FALSE otherwise.
5250 int x_dialog_validate_attribute(GtkWindow* parent, char *attribute)
5252 GtkWidget* message_box;
5254 /* validate the new attribute */
5255 if (!o_attrib_get_name_value(attribute, NULL, NULL)) {
5256 message_box = gtk_message_dialog_new_with_markup (parent,
5257 GTK_DIALOG_DESTROY_WITH_PARENT,
5258 GTK_MESSAGE_ERROR,
5259 GTK_BUTTONS_CLOSE,
5260 _("<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."),
5261 attribute);
5262 gtk_window_set_title(GTK_WINDOW(message_box), _("Invalid Attribute"));
5263 gtk_dialog_run (GTK_DIALOG (message_box));
5264 gtk_widget_destroy (message_box);
5265 return FALSE;
5267 return TRUE;
5269 /***************** End of misc helper dialog boxes **************/