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 */
33 #include "glade_compat.h"
36 #ifdef HAVE_LIBDMALLOC
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
);
53 static void slot_chooser_add_rows(struct slot_chooser
*sc
,
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
{
62 GtkWidget
*width_entry
;
64 GtkWidget
*length_entry
;
65 GtkWidget
*space_entry
;
67 GSCHEM_TOPLEVEL
*w_current
;
71 struct fill_type_data
{
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
;
84 /*! \todo Finish function documentation!!!
86 * \par Function Description
89 void destroy_window(GtkWidget
*widget
, GtkWidget
**window
)
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
;
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' )
122 switch(w_current
->text_caps
) {
124 tmp
= g_utf8_strdown (string
, -1);
128 tmp
= g_utf8_strup (string
, -1);
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
);
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
)
155 case GTK_RESPONSE_ACCEPT
:
156 text_input_dialog_apply(widget
, w_current
);
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
;
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
;
180 GtkWidget
*viewport1
= NULL
;
181 GtkWidget
*scrolled_window
= NULL
;
182 PangoTabArray
*tab_array
;
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
),
189 "text-entry", w_current
,
196 /* Set the alternative button order (ok, cancel, help) for other systems */
197 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->tiwindow
),
202 gtk_window_position(GTK_WINDOW (w_current
->tiwindow
),
205 gtk_signal_connect(GTK_OBJECT (w_current
->tiwindow
), "response",
206 GTK_SIGNAL_FUNC(text_input_dialog_response
),
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
),
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
),
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
),
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
)
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 */
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
296 static GtkWidget
*create_menu_alignment (GSCHEM_TOPLEVEL
*w_current
)
303 menu
= gtk_menu_new ();
306 buf
= g_strdup_printf( _("Lower Left"));
307 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
315 gtk_widget_show (menuitem
);
317 buf
= g_strdup_printf( _("Middle Left"));
318 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
326 gtk_widget_show (menuitem
);
328 buf
= g_strdup_printf( _("Upper Left"));
329 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
337 gtk_widget_show (menuitem
);
339 buf
= g_strdup_printf( _("Lower Middle"));
340 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
348 gtk_widget_show (menuitem
);
350 buf
= g_strdup_printf( _("Middle Middle"));
351 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
359 gtk_widget_show (menuitem
);
361 buf
= g_strdup_printf( _("Upper Middle"));
362 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
370 gtk_widget_show (menuitem
);
372 buf
= g_strdup_printf( _("Lower Right"));
373 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
381 gtk_widget_show (menuitem
);
383 buf
= g_strdup_printf( _("Middle Right"));
384 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
392 gtk_widget_show (menuitem
);
394 buf
= g_strdup_printf( _("Upper Right"));
395 menuitem
= gtk_radio_menu_item_new_with_label (group
, 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
,
403 gtk_widget_show (menuitem
);
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
)
420 char *text_string
= NULL
;
421 char *text_size_string
= NULL
;
422 int new_text_alignment
;
424 GtkTextBuffer
*textbuffer
;
425 GtkTextIter start
, end
;
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
));
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
)
467 case GTK_RESPONSE_ACCEPT
:
468 text_edit_dialog_ok(widget
, w_current
);
470 case GTK_RESPONSE_REJECT
:
471 case GTK_RESPONSE_DELETE_EVENT
:
475 printf("text_edit_dialog_response(): strange signal %d\n", response
);
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
,
493 GtkWidget
*label
= NULL
;
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
;
507 if (!w_current
->tewindow
) {
508 w_current
->tewindow
= gschem_dialog_new_with_buttons(_("Edit Text Properties"),
509 GTK_WINDOW(w_current
->main_window
),
511 "text-edit", w_current
,
518 /* Set the alternative button order (ok, cancel, help) for other systems */
519 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->tewindow
),
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
),
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
),
613 gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu
),
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
))),
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
),
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
)
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
} };
666 menu
= gtk_menu_new ();
669 for (i
= 0; i
< sizeof (types
) / sizeof (struct line_type
); i
++) {
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
);
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
;
692 gboolean activate_length_entry
, activate_space_entry
;
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"));
703 activate_length_entry
= FALSE
;
704 activate_space_entry
= FALSE
;
707 activate_length_entry
= FALSE
;
708 activate_space_entry
= TRUE
;
713 activate_length_entry
= TRUE
;
714 activate_space_entry
= TRUE
;
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
);
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
;
741 const gchar
*width_str
, *length_str
, *space_str
;
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 (
757 gtk_menu_get_active (
758 GTK_MENU (gtk_option_menu_get_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
,
780 o_redraw_single (w_current
, o_current
);
783 /* more than one object in the list */
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 */
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
,
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
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
)
826 case GTK_RESPONSE_REJECT
:
827 case GTK_RESPONSE_DELETE_EVENT
:
830 case GTK_RESPONSE_ACCEPT
:
831 line_type_dialog_ok(widget
, line_type_data
);
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
)
855 GtkWidget
*optionmenu
= NULL
;
856 GtkWidget
*length_entry
= NULL
;
857 GtkWidget
*space_entry
= NULL
;
858 GtkWidget
*width_entry
= NULL
;
861 struct line_type_data
*line_type_data
;
862 gchar
*width_str
, *space_str
, *length_str
;
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
),
871 "line-type", w_current
,
878 /* Set the alternative button order (ok, cancel, help) for other systems */
879 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
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
),
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
,
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
,
935 gtk_signal_connect(GTK_OBJECT (optionmenu
), "changed",
936 (GtkSignalFunc
) line_type_dialog_linetype_change
,
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
,
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
,
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
;
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
)))),
985 gtk_menu_append (menu
, menuitem
);
986 gtk_object_set_data (GTK_OBJECT (menuitem
),
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
);
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
)
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
} };
1030 menu
= gtk_menu_new ();
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
);
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
;
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"));
1068 case(FILLING_HOLLOW
):
1070 activate_width_entry
= FALSE
;
1071 activate_anglepitch1_entries
= FALSE
;
1072 activate_anglepitch2_entries
= FALSE
;
1074 case(FILLING_HATCH
):
1075 activate_width_entry
= TRUE
;
1076 activate_anglepitch1_entries
= TRUE
;
1077 activate_anglepitch2_entries
= FALSE
;
1080 activate_width_entry
= TRUE
;
1081 activate_anglepitch1_entries
= TRUE
;
1082 activate_anglepitch2_entries
= TRUE
;
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
);
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
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
;
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 (
1135 gtk_menu_get_active (
1136 GTK_MENU (gtk_option_menu_get_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
,
1158 o_redraw_single (w_current
, o_current
);
1161 /* more than one object in the list */
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 */
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
)
1207 case GTK_RESPONSE_REJECT
:
1208 case GTK_RESPONSE_DELETE_EVENT
:
1211 case GTK_RESPONSE_ACCEPT
:
1212 fill_type_dialog_ok(widget
, fill_type_data
);
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
1234 void fill_type_dialog(GSCHEM_TOPLEVEL
*w_current
, GList
*objects
)
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
;
1246 struct fill_type_data
*fill_type_data
;
1247 gchar
*width_str
, *angle1_str
, *pitch1_str
, *angle2_str
, *pitch2_str
;
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
),
1256 "fill-type", w_current
,
1258 GTK_RESPONSE_REJECT
,
1260 GTK_RESPONSE_ACCEPT
,
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
,
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
,
1322 gtk_signal_connect(GTK_OBJECT (optionmenu
), "changed",
1323 (GtkSignalFunc
) fill_type_dialog_filltype_change
,
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
,
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
,
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
,
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
,
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
,
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
);
1375 GtkWidget
*menuitem
;
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
)))),
1391 gtk_menu_append (menu
, menuitem
);
1392 gtk_object_set_data (GTK_OBJECT (menuitem
),
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
);
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
;
1441 case GTK_RESPONSE_REJECT
:
1442 case GTK_RESPONSE_DELETE_EVENT
:
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
);
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
;
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
),
1489 "arc-angle", w_current
,
1491 GTK_RESPONSE_REJECT
,
1493 GTK_RESPONSE_ACCEPT
,
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
,
1502 gtk_window_position(GTK_WINDOW(w_current
->aawindow
),
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);
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
;
1596 case GTK_RESPONSE_REJECT
:
1597 case GTK_RESPONSE_DELETE_EVENT
:
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
));
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
)
1625 GtkWidget
*textentry
;
1628 if (!w_current
->trwindow
) {
1629 w_current
->trwindow
= gschem_dialog_new_with_buttons(_("Translate"),
1630 GTK_WINDOW(w_current
->main_window
),
1632 "translate", w_current
,
1634 GTK_RESPONSE_REJECT
,
1636 GTK_RESPONSE_ACCEPT
,
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
,
1645 gtk_window_position(GTK_WINDOW (w_current
->trwindow
),
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
;
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
);
1701 case GTK_RESPONSE_REJECT
:
1702 case GTK_RESPONSE_DELETE_EVENT
:
1706 printf("text_size_dialog_response(): strange signal %d\n",response
);
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
;
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
),
1730 "text-size", w_current
,
1732 GTK_RESPONSE_REJECT
,
1734 GTK_RESPONSE_ACCEPT
,
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
,
1743 gtk_window_position(GTK_WINDOW(w_current
->tswindow
),
1746 gtk_signal_connect(GTK_OBJECT(w_current
->tswindow
), "response",
1747 GTK_SIGNAL_FUNC(text_size_dialog_response
),
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
;
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
);
1806 case GTK_RESPONSE_REJECT
:
1807 case GTK_RESPONSE_DELETE_EVENT
:
1811 printf("snap_size_dialog_response(): strange signal %d\n",response
);
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
;
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
),
1835 "snap-size", w_current
,
1837 GTK_RESPONSE_REJECT
,
1839 GTK_RESPONSE_ACCEPT
,
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
,
1848 gtk_window_position(GTK_WINDOW(w_current
->tswindow
),
1851 gtk_signal_connect(GTK_OBJECT(w_current
->tswindow
), "response",
1852 GTK_SIGNAL_FUNC(snap_size_dialog_response
),
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
1895 void slot_edit_dialog_response(GtkWidget
*widget
, gint response
, GSCHEM_TOPLEVEL
*w_current
)
1897 GtkWidget
*textentry
;
1899 gchar
*string
= NULL
;
1902 case GTK_RESPONSE_REJECT
:
1903 case GTK_RESPONSE_DELETE_EVENT
:
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
);
1911 o_slot_end(w_current
, string
, len
);
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
;
1934 if (!w_current
->sewindow
) {
1935 w_current
->sewindow
= gschem_dialog_new_with_buttons(_("Edit slot number"),
1936 GTK_WINDOW(w_current
->main_window
),
1938 "slot-edit", w_current
,
1940 GTK_RESPONSE_REJECT
,
1942 GTK_RESPONSE_ACCEPT
,
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
,
1951 gtk_window_position(GTK_WINDOW(w_current
->sewindow
),
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
),
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. */
2014 GtkWindow
*scwindow
;
2015 GtkToggleButton
*hijack_button
;
2016 GtkToggleButton
*compatible_button
;
2017 GtkToggleButton
*remove_button
;
2018 GtkTreeView
*treeview
;
2021 struct slot_chooser_available_filter
{
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
,
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
;
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
,
2054 if (target
== NULL
) {
2055 /* A Scheme row: just believe its SLOT_CHOOSER_IS_ALLOWED column. */
2060 if ((is_occupied
|| !is_available
) && !is_current
&& !filter
->hijack
) {
2063 if (!is_compatible
&& filter
->compatible
) {
2068 OBJECT
*slot_object
= target
;
2069 if (filter
->o_selected
->owning_slot
== slot_object
) {
2074 gtk_tree_store_set(GTK_TREE_STORE(model
), row
,
2075 SLOT_CHOOSER_IS_ALLOWED
, is_allowed
,
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
= {
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
;
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
);
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
);
2130 sel
= gtk_tree_view_get_selection(sc
->treeview
);
2131 if (gtk_tree_selection_get_selected(sel
, &model
, &row
)) {
2133 gboolean is_specific
, is_allowed
;
2134 gchar
*friendly_name
;
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
,
2144 s_log_message("You can't choose %s for #<object %s>!",
2145 friendly_name
, sc
->o_selected
->name
);
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
);
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
);
2162 /* Call the Scheme thunk. */
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
);
2175 indices
= gtk_tree_path_get_indices(path
);
2177 for (i
= 1; i
< n
; i
++) {
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
);
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
);
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
);
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
);
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
,
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
);
2246 SCM synthetic_tree
= scm_cons(SCM_CAR(list
), SCM_EOL
);
2247 slot_chooser_add_rows(sc
, synthetic_tree
, &row
);
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
);
2262 fprintf(stderr
, "nothing selected\n");
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
;
2275 g_object_get(button
, "name", &widget_name
, "user-data", &sc
, NULL
);
2277 if (widget_name
== NULL
) {
2278 /* Ignore unknown buttons. */
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
);
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
);
2298 /*! \brief Free the "user-data" property of the slot chooser window.
2300 gboolean
slot_chooser_delete(GtkWidget
*widget
, GdkEvent
*event
,
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
);
2310 /* Let the default handler destroy the window (?). */
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
,
2332 GtkTreeViewColumn
*column
,
2335 struct slot_chooser
*sc
;
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
);
2349 /*! \brief Reset the Remove button if an available slot is selected.
2351 void slot_chooser_row_changed(GtkTreeView
*tree_view
,
2354 struct slot_chooser
*sc
;
2355 GtkTreeSelection
*sel
;
2356 GtkTreeModel
*model
;
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
,
2369 /* Deactivate the Remove button. */
2370 g_object_set(sc
->remove_button
, "active", FALSE
, NULL
);
2375 struct slot_chooser_tree_parent
{
2376 GtkTreeView
*treeview
;
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
;
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
,
2418 /* Is this the currently assigned slot? */
2419 if (tree_parent
->o_selected
->owning_slot
== slot_object
) {
2420 GtkTreeSelection
*sel
;
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
;
2448 if (o_current
->type
!= OBJ_COMPLEX
) {
2452 /* Don't offer a symbol as a slot for itself. */
2453 if (o_current
== tree_parent
->o_selected
) {
2457 /* Don't offer slots that are themselves inside another slot. */
2458 if (o_current
->owning_slot
) {
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) {
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
,
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
;
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");
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
,
2528 static void slot_chooser_add_rows(struct slot_chooser
*sc
,
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
);
2547 GtkTreeIter child_row
;
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
);
2563 slots
= g_scm_apply_protected(g_scm_safe_ref_lookup("find-slots"),
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
);
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
;
2592 GtkWindow
*scwindow
;
2593 GtkTreeStore
*treestore
;
2594 GtkCellRenderer
*renderer
;
2595 GtkTreeViewColumn
*column
;
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
),
2612 if (widget
== NULL
) {
2613 s_log_message("Can't find dialog component \"slot_chooser_dialog\"\n");
2616 scwindow
= GTK_WINDOW(widget
);
2617 refdes
= o_complex_get_refdes(o_current
, _("(unknown part)"));
2619 char *title
, *slotname
;
2621 slotname
= o_attrib_search_name_single(o_current
, "slotname", NULL
);
2624 title
= g_strconcat("Slot Chooser - ", refdes
, ":", slotname
, NULL
);
2626 title
= g_strconcat("Slot Chooser - ", refdes
, NULL
);
2628 gtk_window_set_title(scwindow
, title
);
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
,
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
,
2684 SLOT_CHOOSER_FRIENDLY_NAME
,
2686 SLOT_CHOOSER_IS_ALLOWED
,
2688 gtk_tree_view_append_column(sc
->treeview
, column
);
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
,
2695 SLOT_CHOOSER_IS_OCCUPIED
,
2697 SLOT_CHOOSER_IS_ALLOWED
,
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
,
2705 SLOT_CHOOSER_IS_COMPATIBLE
,
2707 SLOT_CHOOSER_IS_ALLOWED
,
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
{
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
;
2771 gboolean
component_list_window_delete(GtkWidget
*widget
,
2775 component_list_cleanup(widget
);
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
,
2796 GtkTreeViewColumn
*column
,
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
;
2813 GtkCellRenderer
*renderer
;
2814 GtkTreeViewColumn
*column
;
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
),
2830 if (widget
== NULL
) {
2831 s_log_message("Can't find dialog component \"component_list\"\n");
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
,
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
,
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
) {
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
,
2875 /***************** End of component list dialog box ******************/
2877 /***************** Start of REPL dialog box ********************/
2881 REPL_REPRESENTATION
,
2887 GSCHEM_TOPLEVEL
*w_current
;
2889 GtkTreeStore
*treestore
;
2890 GtkTreeView
*treeview
;
2891 GtkTreeSelection
*selection
;
2892 GtkNotebook
*notebook
;
2896 void repl_destroy(struct repl
*r
)
2899 gtk_widget_destroy(r
->window
);
2901 g_object_unref(r
->xml
);
2905 void repl_populate_treeview(GtkTreeStore
*treestore
, SCM expr
,
2906 GtkTreeIter
*parent
)
2911 representation
= scm_simple_format(SCM_BOOL_F
,
2912 scm_from_locale_string("~S"),
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);
2921 gtk_tree_store_set(treestore
, &newrow
,
2923 REPL_REPRESENTATION
, representation_c
,
2925 free(representation_c
);
2927 gtk_tree_store_set(treestore
, &newrow
,
2929 REPL_REPRESENTATION
, "<libguile error>",
2933 if (scm_is_true(scm_list_p(expr
))) {
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
)
2947 gtk_tree_model_get(model
, iter
, REPL_SCM
, &rowexpr
, -1);
2953 void repl_execute(GtkButton
*button
, gpointer user_data
)
2956 gint current_page_index
;
2957 GtkWidget
*current_page
;
2958 GtkTextBuffer
*textbuffer
;
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");
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");
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
)),
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
)
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
,
3009 GtkTreeViewColumn
*column
,
3012 GtkTreeModel
*model
= gtk_tree_view_get_model(tree_view
);
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
)) {
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
,
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
;
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
);
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
;
3088 repl_new_page(r
->notebook
);
3089 gtk_widget_show(r
->window
);
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
),
3107 if (r
->window
== NULL
) {
3108 s_log_message("Can't find dialog component \"repl\"\n");
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");
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
,
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
,
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
)
3164 case GTK_RESPONSE_REJECT
:
3165 case GTK_RESPONSE_DELETE_EVENT
:
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
;
3186 if (!w_current
->abwindow
) {
3187 w_current
->abwindow
= gschem_dialog_new_with_buttons(_("About..."),
3188 GTK_WINDOW(w_current
->main_window
),
3192 GTK_RESPONSE_REJECT
,
3195 gtk_window_position (GTK_WINDOW (w_current
->abwindow
),
3198 gtk_signal_connect (GTK_OBJECT (w_current
->abwindow
), "response",
3199 GTK_SIGNAL_FUNC(about_dialog_response
),
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
,
3214 label
= gtk_label_new (string
);
3215 gtk_label_set_use_markup (GTK_LABEL(label
), TRUE
);
3217 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
3219 label
= gtk_label_new ( _("Written by:\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
;
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
);
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
);
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
)
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 */
3290 GTK_RESPONSE_REJECT
,
3293 gtk_window_position (GTK_WINDOW (w_current
->cowindow
),
3296 gtk_signal_connect (GTK_OBJECT (w_current
->cowindow
), "response",
3297 GTK_SIGNAL_FUNC(coord_dialog_response
),
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
),
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!!!
3342 * \par Function Description
3345 * Caller must g_free returned character string.
3348 char *index2functionstring(int index
)
3353 case(BACKGROUND_COLOR
):
3354 string
= g_strdup (_("Background"));
3357 string
= g_strdup (_("Pin"));
3359 case(NET_ENDPOINT_COLOR
):
3360 string
= g_strdup (_("Net endpoint"));
3362 case(GRAPHIC_COLOR
):
3363 string
= g_strdup (_("Graphic"));
3366 string
= g_strdup (_("Net"));
3368 case(ATTRIBUTE_COLOR
):
3369 string
= g_strdup (_("Attribute"));
3371 case(LOGIC_BUBBLE_COLOR
):
3372 string
= g_strdup (_("Logic bubble"));
3375 string
= g_strdup (_("Grid point"));
3377 case(DETACHED_ATTRIBUTE_COLOR
):
3378 string
= g_strdup (_("Detached attribute"));
3381 string
= g_strdup (_("Text"));
3384 string
= g_strdup (_("Bus"));
3387 string
= g_strdup (_("Selection"));
3389 case(BOUNDINGBOX_COLOR
):
3390 string
= g_strdup (_("Bounding box"));
3392 case(ZOOM_BOX_COLOR
):
3393 string
= g_strdup (_("Zoom box"));
3396 string
= g_strdup (_("Stroke"));
3399 string
= g_strdup (_("Lock"));
3401 case(OUTPUT_BACKGROUND_COLOR
):
3402 string
= g_strdup (_("Output background"));
3404 case(JUNCTION_COLOR
):
3405 string
= g_strdup (_("Net junction"));
3408 string
= g_strdup (_("Unknown"));
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
3419 * \param data the current #GSCHEM_TOPLEVEL pointer.
3422 color_menu_swatch_layout_data (GtkCellLayout
*layout
,
3423 GtkCellRenderer
*cell
,
3424 GtkTreeModel
*model
,
3428 /* GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data; */
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
3445 * \param data the current #GSCHEM_TOPLEVEL pointer.
3448 color_menu_change_selection (GtkWidget
*widget
,
3451 GSCHEM_TOPLEVEL
*w_current
= (GSCHEM_TOPLEVEL
*) data
;
3452 GtkComboBox
*cbox
= GTK_COMBO_BOX (widget
);
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
),
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.
3481 create_color_menu (GSCHEM_TOPLEVEL
*w_current
)
3483 GtkListStore
*store
;
3485 GtkCellLayout
*layout
;
3486 GtkCellRenderer
*text_cell
;
3487 GtkCellRenderer
*color_cell
;
3494 obj
= o_select_return_first_object (w_current
);
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
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
,
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;
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
,
3535 GTK_SIGNAL_FUNC (color_menu_change_selection
),
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"));
3561 switch(object
->type
) {
3569 object
->saved_color
= w_current
->edit_color
;
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
);
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
)
3594 case GTK_RESPONSE_REJECT
:
3595 case GTK_RESPONSE_DELETE_EVENT
:
3596 gtk_widget_destroy(w_current
->clwindow
);
3597 w_current
->clwindow
= NULL
;
3599 case GTK_RESPONSE_ACCEPT
:
3600 color_edit_dialog_apply(widget
, w_current
);
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
;
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
,
3624 GTK_RESPONSE_REJECT
,
3626 GTK_RESPONSE_ACCEPT
,
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
,
3635 gtk_window_position (GTK_WINDOW (w_current
->clwindow
),
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
),
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
)
3677 case GTK_RESPONSE_REJECT
:
3678 case GTK_RESPONSE_DELETE_EVENT
:
3682 printf("x_dialog_hotkeys_response(): strange signal %d\n", response
);
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
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
;
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
),
3711 "hotkeys", w_current
,
3713 GTK_RESPONSE_REJECT
,
3716 gtk_window_position (GTK_WINDOW (w_current
->hkwindow
),
3719 gtk_signal_connect (GTK_OBJECT (w_current
->hkwindow
), "response",
3720 GTK_SIGNAL_FUNC(x_dialog_hotkeys_response
),
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
);
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
++) {
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
,
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
);
3767 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
3768 gtk_container_add(GTK_CONTAINER(scrolled_win
), treeview
);
3771 renderer
= gtk_cell_renderer_text_new ();
3772 column
= gtk_tree_view_column_new_with_attributes (_("Function"),
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)"),
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!!!
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!!!
3861 * \par Function Description
3864 void generic_msg_dialog (const char *msg
)
3868 dialog
= gtk_message_dialog_new (NULL
,
3870 GTK_DIALOG_DESTROY_WITH_PARENT
,
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!!!
3886 * \par Function Description
3889 int generic_confirm_dialog (const char *msg
)
3894 dialog
= gtk_message_dialog_new (NULL
,
3896 GTK_DIALOG_DESTROY_WITH_PARENT
,
3898 GTK_BUTTONS_OK_CANCEL
,
3901 r
= gtk_dialog_run (GTK_DIALOG (dialog
));
3902 gtk_widget_destroy (dialog
);
3904 if (r
== GTK_RESPONSE_OK
)
3910 /***************** End of generic confirm dialog box *********************/
3912 /***************** Start of generic file select dialog box ***************/
3913 /*! \todo Finish function documentation!!!
3915 * \par Function Description
3918 * Caller must g_free returned character string.
3920 char *generic_filesel_dialog (const char *msg
, const char *templ
, gint flags
)
3923 gchar
*result
= NULL
, *folder
, *seed
;
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
,
3937 GTK_FILE_CHOOSER_ACTION_OPEN
,
3938 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
3939 GTK_STOCK_OPEN
, GTK_RESPONSE_OK
,
3941 /* Since this is a load dialog box, the file must exist! */
3942 flags
= flags
| FSB_MUST_EXIST
;
3945 title
= g_strdup_printf("%s: Save", msg
);
3946 dialog
= gtk_file_chooser_dialog_new (title
,
3948 GTK_FILE_CHOOSER_ACTION_SAVE
,
3949 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
3950 GTK_STOCK_OPEN
, GTK_RESPONSE_OK
,
3954 /* Set the alternative button order (ok, cancel, help) for other systems */
3955 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
3957 GTK_RESPONSE_CANCEL
,
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
);
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
);
3982 while ((folder
= strtok (seed
, ":")) != NULL
) {
3983 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
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
));
3995 if (folder && path) {
3996 dup_string (path, folder);
4001 gtk_widget_destroy (dialog
);
4008 /***************** End of generic file select dialog box *****************/
4010 /*********** Start of find text dialog box *******/
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
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
;
4027 gint done
=0, close
=0;
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
);
4041 o_edit_find_text(w_current
, remember_page
->object_head
, string
,
4042 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
4046 o_redraw_all(w_current
);
4051 case GTK_RESPONSE_REJECT
:
4052 case GTK_RESPONSE_DELETE_EVENT
:
4056 printf("find_text_dialog_response(): strange signal %d\n", response
);
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
;
4072 GtkWidget
*checkdescend
;
4073 GtkWidget
*textentry
;
4074 OBJECT
*object
= NULL
;
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
,
4090 GTK_RESPONSE_REJECT
,
4092 GTK_RESPONSE_ACCEPT
,
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
,
4101 gtk_window_position(GTK_WINDOW(w_current
->tfindwindow
),
4104 gtk_signal_connect(GTK_OBJECT(w_current
->tfindwindow
), "response",
4105 GTK_SIGNAL_FUNC(find_text_dialog_response
),
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
;
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
);
4169 case GTK_RESPONSE_REJECT
:
4170 case GTK_RESPONSE_DELETE_EVENT
:
4171 gtk_widget_destroy(w_current
->thidewindow
);
4172 w_current
->thidewindow
= NULL
;
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
;
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
,
4195 GTK_RESPONSE_REJECT
,
4197 GTK_RESPONSE_ACCEPT
,
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
,
4206 gtk_window_position(GTK_WINDOW(w_current
->thidewindow
),
4209 gtk_signal_connect(GTK_OBJECT(w_current
->thidewindow
), "response",
4210 GTK_SIGNAL_FUNC(hide_text_dialog_response
),
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
;
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
);
4268 case GTK_RESPONSE_REJECT
:
4269 case GTK_RESPONSE_DELETE_EVENT
:
4270 gtk_widget_destroy(w_current
->tshowwindow
);
4271 w_current
->tshowwindow
= NULL
;
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
;
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
,
4294 GTK_RESPONSE_REJECT
,
4296 GTK_RESPONSE_ACCEPT
,
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
,
4305 gtk_window_position(GTK_WINDOW(w_current
->tshowwindow
),
4308 gtk_signal_connect(GTK_OBJECT(w_current
->tshowwindow
), "response",
4309 GTK_SIGNAL_FUNC(show_text_dialog_response
),
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!!!
4363 * \par Function Description
4366 int text_view_calculate_real_tab_width(GtkTextView
*textview
, int tab_size
)
4368 PangoLayout
*layout
;
4375 tab_string
= g_strnfill (tab_size
, ' ');
4377 layout
= gtk_widget_create_pango_layout (
4378 GTK_WIDGET (textview
),
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
));
4392 /*********** End of some Gtk utils *******/
4394 /*********** Start of major symbol changed dialog box *******/
4396 /*! \todo Finish function documentation!!!
4398 * \par Function Description
4401 void major_changed_dialog(GSCHEM_TOPLEVEL
* w_current
)
4404 char* refdes_string
= NULL
;
4407 if (w_current
->toplevel
->major_changed_refdes
) {
4409 GList
* current
= w_current
->toplevel
->major_changed_refdes
;
4412 char *value
= (char*) current
->data
;
4416 refdes_string
= g_strdup (value
);
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!",
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
,
4436 "Major symbol changes detected in refdes:\n\n%s\n",
4439 gtk_widget_show(dialog
);
4441 g_signal_connect_swapped (dialog
, "response",
4442 G_CALLBACK (gtk_widget_destroy
),
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
4468 GtkListStore
*store_unsaved_pages
;
4471 struct _CloseConfirmationDialogClass
4473 GtkDialogClass parent_class
;
4478 PROP_UNSAVED_PAGE
=1,
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
,
4497 const GValue
*value
,
4499 static void close_confirmation_dialog_get_property (GObject
*object
,
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
);
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
;
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",
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
4585 * \param in model The tree model.
4586 * \returns The number of pages with unsaved changes.
4589 count_pages (GtkTreeModel
*model
)
4594 gtk_tree_model_get_iter_first (model
, &iter
);
4596 gtk_tree_model_iter_next (model
, &iter
);
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.
4618 get_page_name (GtkTreeModel
*model
, GtkTreeIter
*piter
)
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
);
4631 gtk_tree_model_get (model
, &iter
,
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
4646 * \param in tree_model The GtkTreeModel being rendered.
4647 * \param in iter A GtkTreeIter of the current row rendered.
4651 close_confirmation_dialog_set_page_name (GtkTreeViewColumn
*tree_column
,
4652 GtkCellRenderer
*cell
,
4653 GtkTreeModel
*tree_model
,
4659 page_name
= get_page_name (tree_model
, iter
);
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
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.
4678 close_confirmation_dialog_callback_renderer_toggled (GtkCellRendererToggle
*cell_renderer
,
4682 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (user_data
);
4683 GtkTreeModel
*model
;
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
,
4693 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
4694 COLUMN_SAVE
, (save
!= TRUE
),
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.
4710 close_confirmation_dialog_build_page_list (CloseConfirmationDialog
*dialog
)
4712 GtkWidget
*vbox
, *scrolled_window
, *treeview
, *label
;
4713 GtkCellRenderer
*renderer
;
4714 GtkTreeViewColumn
*column
;
4717 /* place the treeview and its caption into their own box */
4718 vbox
= GTK_WIDGET (g_object_new (GTK_TYPE_VBOX
,
4720 "homogeneous", FALSE
,
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
,
4732 /* - then the treeview */
4733 /* create model for treeview and populate */
4734 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
4736 "enable-search", FALSE
,
4737 "headers-visible", FALSE
,
4738 "model", dialog
->store_unsaved_pages
,
4740 renderer
= gtk_cell_renderer_toggle_new ();
4741 g_signal_connect (renderer
, "toggled",
4743 close_confirmation_dialog_callback_renderer_toggled
),
4745 column
= gtk_tree_view_column_new_with_attributes ("Save?",
4747 "active", COLUMN_SAVE
,
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 */
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
,
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
,
4768 /* the caption label above the list of pages */
4769 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
4775 "mnemonic-widget", treeview
,
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
,
4787 close_confirmation_dialog_constructor (GType type
,
4788 guint n_construct_properties
,
4789 GObjectConstructParam
*construct_params
)
4792 CloseConfirmationDialog
*dialog
;
4793 GtkWidget
*hbox
, *image
, *vbox
, *label
;
4795 gboolean ret
, single_page
;
4798 /* chain up to constructor of parent class */
4800 G_OBJECT_CLASS (close_confirmation_dialog_parent_class
)->constructor (
4802 n_construct_properties
,
4804 dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
4806 g_object_set (dialog
,
4808 "has-separator", FALSE
,
4811 "skip-taskbar-hint", TRUE
,
4815 g_object_set (GTK_DIALOG (dialog
)->vbox
,
4819 g_object_set (GTK_DIALOG (dialog
)->action_area
,
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
),
4831 single_page
= !gtk_tree_model_iter_next (GTK_TREE_MODEL (
4832 dialog
->store_unsaved_pages
),
4835 /* here starts the layout of the dialog */
4836 hbox
= GTK_WIDGET (g_object_new (GTK_TYPE_HBOX
,
4840 "homogeneous", FALSE
,
4845 image
= g_object_new (GTK_TYPE_IMAGE
,
4850 "stock", GTK_STOCK_DIALOG_WARNING
,
4851 "icon-size", GTK_ICON_SIZE_DIALOG
,
4853 gtk_box_pack_start (GTK_BOX (hbox
), image
,
4856 /* vertical box on the right hand side of the dialog */
4857 vbox
= GTK_WIDGET (g_object_new (GTK_TYPE_VBOX
,
4859 "homogeneous", FALSE
,
4868 page_name
= get_page_name (GTK_TREE_MODEL (dialog
->store_unsaved_pages
),
4870 tmp
= g_strdup_printf (
4871 _("Save the changes to schematic \"%s\" before closing?"),
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
);
4883 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
4894 gtk_box_pack_start (GTK_BOX (vbox
), label
,
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
),
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
,
4916 gtk_box_pack_start (GTK_BOX (vbox
), label
,
4920 gtk_box_pack_start (GTK_BOX (hbox
), vbox
,
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
,
4931 /* Set the alternative button order (ok, cancel, help) for other systems */
4932 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
4935 GTK_RESPONSE_CANCEL
,
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
,
4948 close_confirmation_dialog_set_property (GObject
*object
,
4950 const GValue
*value
,
4953 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
4958 switch(property_id
) {
4959 case PROP_UNSAVED_PAGE
:
4960 data
= g_value_get_pointer (value
);
4962 /* add single page to model */
4963 gtk_list_store_append (dialog
->store_unsaved_pages
,
4965 gtk_list_store_set (dialog
->store_unsaved_pages
,
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
;
4978 p_current
= g_list_next (p_current
)) {
4979 gtk_list_store_append (dialog
->store_unsaved_pages
,
4981 gtk_list_store_set (dialog
->store_unsaved_pages
,
4984 COLUMN_PAGE
, p_current
->data
,
4990 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
4996 close_confirmation_dialog_get_property (GObject
*object
,
5001 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
5003 switch(property_id
) {
5004 case PROP_SELECTED_PAGES
:
5005 g_value_set_pointer (
5007 close_confirmation_dialog_get_selected_pages (dialog
));
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.
5028 * \param in data A pointer on a GList* to fill.
5029 * \returns FALSE to continue walking the tree.
5032 get_selected_pages (GtkTreeModel
*model
,
5040 gtk_tree_model_get (model
, iter
,
5045 g_assert (page
!= NULL
);
5046 *(GList
**)data
= g_list_append (*(GList
**)data
, page
);
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.
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
,
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
5084 * \param in toplevel The toplevel environment.
5085 * \param in page The page to close.
5088 x_dialog_close_changed_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*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
,
5100 /* set default response signal. This is usually triggered by the
5102 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
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
);
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 */
5125 case GTK_RESPONSE_CANCEL
:
5126 /* action selected: cancel */
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 */
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
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.
5158 x_dialog_close_window (GSCHEM_TOPLEVEL
*w_current
)
5160 TOPLEVEL
*toplevel
= w_current
->toplevel
;
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
;
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 */
5186 dialog
= GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG
,
5187 "unsaved-pages", unsaved_pages
,
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 */
5201 case GTK_RESPONSE_YES
:
5202 /* action selected: save */
5203 g_object_get (dialog
,
5204 "selected-pages", &unsaved_pages
,
5206 for (p_unsaved
= unsaved_pages
, ret
= TRUE
;
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
);
5219 case GTK_RESPONSE_CANCEL
:
5220 /* action selected: cancel */
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 */
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
);
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
,
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."),
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
);
5269 /***************** End of misc helper dialog boxes **************/