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
;
2169 path
= gtk_tree_model_get_path(model
, &row
);
2171 n
= gtk_tree_path_get_depth(path
);
2174 indices
= gtk_tree_path_get_indices(path
);
2176 for (i
= 1; i
< n
; i
++) {
2179 /* Skip parent and pick out the right child. */
2180 subtree
= SCM_CDR(subtree
);
2181 for (j
= 0; j
< indices
[i
]; j
++) {
2182 subtree
= SCM_CDR(subtree
);
2184 subtree
= SCM_CAR(subtree
);
2187 if (scm_is_true(scm_list_p(SCM_CAR(subtree
)))) {
2188 /* Look into the list for the group header. */
2189 action_name
= SCM_CAAR(subtree
);
2190 thunk
= SCM_CADAR(subtree
);
2192 action_name
= SCM_CAR(subtree
);
2193 thunk
= SCM_CADR(subtree
);
2196 if (scm_is_true(scm_procedure_p(thunk
))) {
2197 retval
= g_scm_apply_protected(thunk
, SCM_EOL
, NULL
, NULL
);
2202 /* If the thunk returned a list, it's a tree-expander. */
2203 if (scm_is_true(scm_list_p(retval
)) && !scm_is_null(retval
)) {
2204 SCM list
, group_header
;
2205 GtkTreeStore
*treestore
;
2206 int thunk_returned_tree
;
2207 char *group_header_chars
;
2209 treestore
= GTK_TREE_STORE(gtk_tree_view_get_model(sc
->treeview
));
2211 thunk_returned_tree
= scm_is_true(scm_list_p(SCM_CAR(retval
)));
2213 if (thunk_returned_tree
) {
2214 group_header
= SCM_CAR(retval
);
2216 group_header
= retval
;
2219 /* Replace the text in the treeview. */
2220 group_header_chars
= scm_to_locale_string(SCM_CAR(group_header
));
2221 gtk_tree_store_set(treestore
, &row
,
2222 SLOT_CHOOSER_FRIENDLY_NAME
, group_header_chars
,
2224 free(group_header_chars
);
2226 /* Replace the node with the return value. */
2227 if (thunk_returned_tree
) {
2228 /* The thunk returned a tree. */
2229 scm_set_car_x(subtree
, group_header
);
2230 scm_set_cdr_x(subtree
, SCM_CDR(retval
));
2232 /* Add the children to the treeview. */
2233 for (list
= SCM_CDR(retval
); !scm_is_null(list
); list
= SCM_CDR(list
)) {
2234 if (scm_is_true(scm_list_p(SCM_CAAR(list
)))) {
2235 slot_chooser_add_rows(sc
, SCM_CAR(list
), &row
);
2237 SCM synthetic_tree
= scm_cons(SCM_CAR(list
), SCM_EOL
);
2238 slot_chooser_add_rows(sc
, synthetic_tree
, &row
);
2242 /* The thunk returned just a single row. */
2243 scm_set_car_x(subtree
, SCM_CAR(group_header
));
2244 scm_set_cdr_x(subtree
, SCM_CDR(group_header
));
2248 gtk_tree_path_free(path
);
2253 fprintf(stderr
, "nothing selected\n");
2259 /*! \brief Apply some action depending on which button emitted the signal.
2261 void slot_chooser_finish(GtkButton
*button
, gpointer user_data
)
2263 struct slot_chooser
*sc
;
2266 g_object_get(button
, "name", &widget_name
, "user-data", &sc
, NULL
);
2268 if (widget_name
== NULL
) {
2269 /* Ignore unknown buttons. */
2273 if (strcmp(widget_name
, "ok_button") == 0) {
2274 slot_chooser_apply(sc
);
2275 } else if (strcmp(widget_name
, "apply_button") == 0) {
2276 /* Change the slotting, keep the slot chooser open. */
2277 slot_chooser_apply(sc
);
2281 fprintf(stderr
, "slot_chooser_finish(%s)\n", widget_name
);
2282 g_free(widget_name
);
2283 fprintf(stderr
, "o_selected = %s\n", sc
->o_selected
->name
);
2284 gtk_widget_destroy(GTK_WIDGET(sc
->scwindow
));
2285 scm_gc_unprotect_object(sc
->scheme_tree
);
2289 /*! \brief Free the "user-data" property of the slot chooser window.
2291 gboolean
slot_chooser_delete(GtkWidget
*widget
, GdkEvent
*event
,
2294 struct slot_chooser
*sc
;
2296 g_object_get(widget
, "user-data", &sc
, NULL
);
2297 fprintf(stderr
, "slot_chooser_delete()\n");
2298 scm_gc_unprotect_object(sc
->scheme_tree
);
2301 /* Let the default handler destroy the window (?). */
2305 /*! \brief Recompute which rows should be sensitive.
2307 void slot_chooser_toggle(GtkToggleButton
*button
, gpointer user_data
)
2309 struct slot_chooser
*sc
;
2310 GtkTreeStore
*treestore
;
2312 g_object_get(button
, "user-data", &sc
, NULL
);
2313 treestore
= GTK_TREE_STORE(gtk_tree_view_get_model(sc
->treeview
));
2315 /* TODO: Don't make slot_chooser_mark_available() search for widgets. */
2316 slot_chooser_mark_available(treestore
, sc
);
2319 /*! \brief Choose a slot and destroy the dialog.
2321 void slot_chooser_row_activated(GtkTreeView
*tree_view
,
2323 GtkTreeViewColumn
*column
,
2326 struct slot_chooser
*sc
;
2329 g_object_get(tree_view
, "user-data", &sc
, NULL
);
2330 apply_result
= slot_chooser_apply(sc
);
2331 if (scm_is_bool(apply_result
) && scm_is_true(apply_result
)) {
2332 /* TODO: Rather just delegate to the "OK" button. */
2333 gtk_widget_destroy(GTK_WIDGET(sc
->scwindow
));
2334 scm_gc_unprotect_object(sc
->scheme_tree
);
2340 /*! \brief Reset the Remove button if an available slot is selected.
2342 void slot_chooser_row_changed(GtkTreeView
*tree_view
,
2345 struct slot_chooser
*sc
;
2346 GtkTreeSelection
*sel
;
2347 GtkTreeModel
*model
;
2350 g_object_get(tree_view
, "user-data", &sc
, NULL
);
2352 sel
= gtk_tree_view_get_selection(sc
->treeview
);
2353 if (gtk_tree_selection_get_selected(sel
, &model
, &row
)) {
2354 gboolean is_allowed
;
2356 gtk_tree_model_get(model
, &row
,
2357 SLOT_CHOOSER_IS_ALLOWED
, &is_allowed
,
2360 /* Deactivate the Remove button. */
2361 g_object_set(sc
->remove_button
, "active", FALSE
, NULL
);
2366 struct slot_chooser_tree_parent
{
2367 GtkTreeView
*treeview
;
2372 /*! \brief Visit each slot in a component to add it to the GtkTreeView.
2373 * \par Function Description
2374 * Add a new row to the slot chooser's GtkTreeView and populate its
2375 * columns with the slot's details.
2376 * \param [in] key The name of the slot.
2377 * \param [in] value The slot to add to the GtkTreeView.
2378 * \param [in] context The struct slot_chooser_tree_parent context.
2380 void slot_chooser_slots_visitor(gpointer key
, gpointer value
, gpointer context
)
2382 struct slot_chooser_tree_parent
*tree_parent
= context
;
2383 OBJECT
*slot_object
= value
;
2384 GtkTreeStore
*treestore
;
2386 GtkTreeView
*treeview
;
2387 static gboolean is_current
, is_available
, is_compatible
, is_occupied
;
2389 is_compatible
= s_slot_compatible(tree_parent
->o_selected
, slot_object
);
2390 is_available
= s_slot_available(tree_parent
->o_selected
, slot_object
);
2391 is_occupied
= slot_object
->slot
->symbol
? TRUE
: FALSE
;
2392 is_current
= (slot_object
->slot
->symbol
== tree_parent
->o_selected
? TRUE
: FALSE
);
2394 /* 'key' is the slotname attribute. */
2395 treeview
= GTK_TREE_VIEW(tree_parent
->treeview
);
2396 treestore
= GTK_TREE_STORE(gtk_tree_view_get_model(treeview
));
2397 gtk_tree_store_append(treestore
, &newrow
, tree_parent
->row
);
2398 gtk_tree_store_set(treestore
, &newrow
,
2399 SLOT_CHOOSER_FRIENDLY_NAME
, key
,
2400 SLOT_CHOOSER_IS_CURRENT
, is_current
,
2401 SLOT_CHOOSER_IS_AVAILABLE
, is_available
,
2402 SLOT_CHOOSER_IS_OCCUPIED
, is_occupied
,
2403 SLOT_CHOOSER_IS_COMPATIBLE
, is_compatible
,
2404 SLOT_CHOOSER_TARGET
, (gpointer
) slot_object
,
2405 SLOT_CHOOSER_IS_SPECIFIC
, TRUE
,
2406 SLOT_CHOOSER_IS_ALLOWED
, TRUE
,
2409 /* Is this the currently assigned slot? */
2410 if (tree_parent
->o_selected
->owning_slot
== slot_object
) {
2411 GtkTreeSelection
*sel
;
2414 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(treestore
), &newrow
);
2416 /* Expand the tree to the currently assigned slot. */
2417 gtk_tree_view_expand_to_path(treeview
, path
);
2418 sel
= gtk_tree_view_get_selection(treeview
);
2420 /* Select the currently assigned slot. */
2421 gtk_tree_selection_select_path(sel
, path
);
2423 gtk_tree_path_free(path
);
2426 fprintf(stderr
, "Found slot %s (%s)\n",
2427 (char *) key
, is_compatible
? "compatible" : "incompatible");
2430 void slot_chooser_visitor(OBJECT
*o_current
, void *context
)
2432 struct slot_chooser_tree_parent
*tree_parent
= context
;
2433 GtkTreeView
*treeview
;
2434 GtkTreeStore
*treestore
;
2435 GtkTreeIter part_header
;
2436 GtkTreeIter
*parent_row
;
2439 if (o_current
->type
!= OBJ_COMPLEX
) {
2443 /* Don't offer a symbol as a slot for itself. */
2444 if (o_current
== tree_parent
->o_selected
) {
2448 /* Don't offer slots that are themselves inside another slot. */
2449 if (o_current
->owning_slot
) {
2453 /* Also don't offer components that have no slots. */
2454 if (o_current
->complex->slots
== NULL
||
2455 g_hash_table_size(o_current
->complex->slots
) == 0) {
2459 /* Save the treestore iterator. */
2460 parent_row
= tree_parent
->row
;
2462 refdes
= o_complex_get_refdes(o_current
, _("(unknown part)"));
2464 /* Add a row for the part as a whole. */
2465 treeview
= tree_parent
->treeview
;
2466 treestore
= GTK_TREE_STORE(gtk_tree_view_get_model(treeview
));
2467 gtk_tree_store_append(treestore
, &part_header
, parent_row
);
2468 gtk_tree_store_set(treestore
, &part_header
,
2469 SLOT_CHOOSER_FRIENDLY_NAME
, refdes
,
2470 SLOT_CHOOSER_IS_CURRENT
, FALSE
,
2471 SLOT_CHOOSER_IS_AVAILABLE
, TRUE
,
2472 SLOT_CHOOSER_IS_OCCUPIED
, FALSE
,
2473 SLOT_CHOOSER_IS_COMPATIBLE
, TRUE
,
2474 SLOT_CHOOSER_TARGET
, (gpointer
) o_current
,
2475 SLOT_CHOOSER_IS_SPECIFIC
, FALSE
,
2476 SLOT_CHOOSER_IS_ALLOWED
, TRUE
,
2479 /* Become the parent for slots we find. */
2480 tree_parent
->row
= &part_header
;
2482 g_hash_table_foreach(o_current
->complex->slots
,
2483 &slot_chooser_slots_visitor
, tree_parent
);
2485 /* Restore the treestore iterator. */
2486 tree_parent
->row
= parent_row
;
2489 static void slot_chooser_add_one_row(struct slot_chooser
*sc
,
2490 SCM name
, SCM callback
,
2491 GtkTreeIter
*parent_row
,
2492 GtkTreeIter
*new_row
)
2494 GtkTreeStore
*treestore
;
2497 treestore
= GTK_TREE_STORE(gtk_tree_view_get_model(sc
->treeview
));
2498 gtk_tree_store_append(treestore
, new_row
, parent_row
);
2500 if (!scm_is_string(name
)) {
2501 g_warning("Expecting a slotname string from (find-slots object)\n");
2504 if (!scm_is_bool(callback
) && scm_is_false(scm_procedure_p(callback
))) {
2505 g_warning("Expecting a callback from (find-slots object)\n");
2508 name_chars
= scm_to_locale_string(name
);
2509 fprintf(stderr
, "**** Scheme says: %s ****\n", name_chars
);
2510 gtk_tree_store_set(treestore
, new_row
,
2511 SLOT_CHOOSER_FRIENDLY_NAME
, name_chars
,
2512 SLOT_CHOOSER_TARGET
, NULL
,
2513 SLOT_CHOOSER_IS_SPECIFIC
, TRUE
,
2514 SLOT_CHOOSER_IS_ALLOWED
, TRUE
,
2519 static void slot_chooser_add_rows(struct slot_chooser
*sc
,
2521 GtkTreeIter
*parent_row
)
2523 GtkTreeIter group_row
;
2524 SCM group
= SCM_CAR(list
);
2525 SCM groupname
= SCM_CAR(group
);
2526 SCM callback
= SCM_CADR(group
);
2528 slot_chooser_add_one_row(sc
, groupname
, callback
,
2529 parent_row
, &group_row
);
2531 for (list
= SCM_CDR(list
); !scm_is_null(list
); list
= SCM_CDR(list
)) {
2532 SCM row
= SCM_CAR(list
);
2533 SCM car
= SCM_CAR(row
);
2535 if (scm_is_true(scm_list_p(car
))) {
2536 slot_chooser_add_rows(sc
, row
, &group_row
);
2538 GtkTreeIter child_row
;
2540 SCM slot_callback
= SCM_CADR(row
);
2542 slot_chooser_add_one_row(sc
, slotname
, slot_callback
,
2543 &group_row
, &child_row
);
2548 static void slot_chooser_populate(TOPLEVEL
*toplevel
,
2549 struct slot_chooser
*sc
)
2551 SCM o_smob
= g_make_object_smob(toplevel
, sc
->o_selected
);
2554 slots
= g_scm_apply_protected(g_scm_safe_ref_lookup("find-slots"),
2558 if (scm_is_false(scm_list_p(slots
))) {
2559 s_log_message(_("find-slots #<object %s> didn't return a list\n"),
2560 sc
->o_selected
->name
);
2564 sc
->scheme_tree
= slots
;
2566 if (!scm_is_null(slots
)) {
2567 slot_chooser_add_rows(sc
, slots
, NULL
);
2570 scm_gc_protect_object(sc
->scheme_tree
);
2573 /*! \brief Create the slot chooser dialog
2574 * \par Function Description
2575 * This function creates the slot chooser dialog.
2577 void slot_chooser_dialog(GSCHEM_TOPLEVEL
*w_current
, OBJECT
*o_current
,
2578 char const *slotname_attrib
)
2580 struct slot_chooser_tree_parent tree_parent
;
2581 struct slot_chooser
*sc
;
2583 GtkWindow
*scwindow
;
2584 GtkTreeStore
*treestore
;
2585 GtkCellRenderer
*renderer
;
2586 GtkTreeViewColumn
*column
;
2590 widget
= x_glade_get_widget(&xml
, "slot_chooser",
2591 "slot_chooser_finish",
2592 G_CALLBACK(&slot_chooser_finish
),
2593 "slot_chooser_delete",
2594 G_CALLBACK(&slot_chooser_delete
),
2595 "slot_chooser_toggle",
2596 G_CALLBACK(&slot_chooser_toggle
),
2597 "slot_chooser_row_activated",
2598 G_CALLBACK(&slot_chooser_row_activated
),
2599 "slot_chooser_row_changed",
2600 G_CALLBACK(&slot_chooser_row_changed
),
2603 if (widget
== NULL
) {
2604 s_log_message("Can't find dialog component \"slot_chooser_dialog\"\n");
2607 scwindow
= GTK_WINDOW(widget
);
2608 refdes
= o_complex_get_refdes(o_current
, _("(unknown part)"));
2610 char *title
, *slotname
;
2612 slotname
= o_attrib_search_name_single(o_current
, "slotname", NULL
);
2615 title
= g_strconcat("Slot Chooser - ", refdes
, ":", slotname
, NULL
);
2617 title
= g_strconcat("Slot Chooser - ", refdes
, NULL
);
2619 gtk_window_set_title(scwindow
, title
);
2626 /* FIXME: Where do we release this memory? */
2627 sc
= g_new(struct slot_chooser
, 1);
2629 sc
->scwindow
= scwindow
;
2630 widget
= x_lookup_widget_set(xml
, "hijack_button",
2631 "user-data", sc
, NULL
);
2632 sc
->hijack_button
= GTK_TOGGLE_BUTTON(widget
);
2633 widget
= x_lookup_widget_set(xml
, "compatible_button",
2634 "user-data", sc
, NULL
);
2635 sc
->compatible_button
= GTK_TOGGLE_BUTTON(widget
);
2636 widget
= x_lookup_widget_set(xml
, "remove_button",
2637 "user-data", sc
, NULL
);
2638 sc
->remove_button
= GTK_TOGGLE_BUTTON(widget
);
2639 sc
->w_current
= w_current
->toplevel
;
2640 sc
->o_selected
= o_current
;
2641 widget
= x_lookup_widget_set(xml
, "slot_treeview",
2642 "user-data", sc
, NULL
);
2643 sc
->treeview
= GTK_TREE_VIEW(widget
);
2645 fprintf(stderr
, "scwindow = %p\n", scwindow
);
2647 /* Remember what we're doing, when we get the callback. */
2648 g_object_set(scwindow
, "user-data", sc
, NULL
);
2649 x_lookup_widget_set(xml
, "cancel_button", "user-data", sc
, NULL
);
2650 x_lookup_widget_set(xml
, "apply_button", "user-data", sc
, NULL
);
2651 x_lookup_widget_set(xml
, "remove_button", "user-data", sc
, NULL
);
2652 x_lookup_widget_set(xml
, "ok_button", "user-data", sc
, NULL
);
2654 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(sc
->treeview
),
2655 GTK_SELECTION_SINGLE
);
2657 /* Use the tree model. */
2658 treestore
= gtk_tree_store_new(SLOT_CHOOSER_N_COLUMNS
,
2667 gtk_tree_view_set_model(sc
->treeview
, GTK_TREE_MODEL(treestore
));
2668 gtk_tree_view_set_search_column(sc
->treeview
, SLOT_CHOOSER_FRIENDLY_NAME
);
2670 /* Now set the view component for each column. */
2672 renderer
= gtk_cell_renderer_text_new();
2673 column
= gtk_tree_view_column_new_with_attributes("name", renderer
,
2675 SLOT_CHOOSER_FRIENDLY_NAME
,
2677 SLOT_CHOOSER_IS_ALLOWED
,
2679 gtk_tree_view_append_column(sc
->treeview
, column
);
2682 renderer
= gtk_cell_renderer_toggle_new();
2683 g_object_set(renderer
, "activatable", FALSE
, NULL
);
2684 column
= gtk_tree_view_column_new_with_attributes("occupied", renderer
,
2686 SLOT_CHOOSER_IS_OCCUPIED
,
2688 SLOT_CHOOSER_IS_ALLOWED
,
2690 gtk_tree_view_append_column(sc
->treeview
, column
);
2692 renderer
= gtk_cell_renderer_toggle_new();
2693 g_object_set(renderer
, "activatable", FALSE
, NULL
);
2694 column
= gtk_tree_view_column_new_with_attributes("compatible", renderer
,
2696 SLOT_CHOOSER_IS_COMPATIBLE
,
2698 SLOT_CHOOSER_IS_ALLOWED
,
2700 gtk_tree_view_append_column(sc
->treeview
, column
);
2703 gtk_tree_view_expand_all(sc
->treeview
);
2705 /* Find some compatible slots. */
2706 tree_parent
.treeview
= sc
->treeview
;
2707 tree_parent
.row
= NULL
;
2708 tree_parent
.o_selected
= o_current
;
2710 /* TODO: perhaps use an infinite-depth search. */
2711 s_visit_toplevel(w_current
->toplevel
, &slot_chooser_visitor
, &tree_parent
,
2712 VISIT_UNORDERED
, 1);
2714 /* Let gschemrc add some rows too. */
2715 slot_chooser_populate(w_current
->toplevel
, sc
);
2717 slot_chooser_mark_available(treestore
, sc
);
2719 g_object_unref(xml
);
2721 gtk_window_present(scwindow
);
2724 /***************** End of Slot chooser dialog box ********************/
2726 /***************** Start of component list dialog box ****************/
2728 enum component_list_columns
{
2729 COMPONENT_LIST_REFDES
,
2730 COMPONENT_LIST_N_COLUMNS
2733 struct component_list
{
2735 GtkWindow
*clwindow
;
2736 GtkTreeView
*treeview
;
2737 GtkListStore
*liststore
;
2740 /*! \brief Clean up resources that GTK+ doesn't know about.
2741 * \par Function Description
2742 * Cleans up resources that the component list dialog uses.
2744 * \param [in] widget A widget with a "user-data" property.
2746 * \returns A pointer to the GtkWindow of the dialog.
2748 static GtkWindow
*component_list_cleanup(GtkWidget
*widget
)
2750 struct component_list
*cl
;
2751 GtkWindow
*clwindow
;
2753 g_object_get(widget
, "user-data", &cl
, NULL
);
2755 clwindow
= cl
->clwindow
;
2762 gboolean
component_list_window_delete(GtkWidget
*widget
,
2766 component_list_cleanup(widget
);
2771 void component_list_finish(GtkButton
*button
, gpointer user_data
)
2773 GtkWindow
*clwindow
;
2775 clwindow
= component_list_cleanup(GTK_WIDGET(button
));
2777 gtk_widget_destroy(GTK_WIDGET(clwindow
));
2780 void component_list_edit(GtkButton
*button
, gpointer user_data
)
2782 /* TODO: Start the multi attrib editor. */
2785 void component_list_row_activated(GtkTreeView
*treeview
,
2787 GtkTreeViewColumn
*column
,
2790 /* TODO: Start the multi attrib editor. */
2793 /*! \brief Show the component list dialog.
2794 * \par Function Description
2795 * Show the component list dialog with a given list of objects.
2797 * \param [in] components A list of OBJECTs to show in the dialog.
2799 void component_list_dialog(GList
const *components
)
2801 struct component_list
*cl
;
2804 GtkCellRenderer
*renderer
;
2805 GtkTreeViewColumn
*column
;
2808 cl
= g_new(struct component_list
, 1);
2810 widget
= x_glade_get_widget(&xml
, "component_list",
2811 "on_component_list_dialog_delete_event",
2812 G_CALLBACK(&component_list_window_delete
),
2813 "on_ok_button_clicked",
2814 G_CALLBACK(&component_list_finish
),
2815 "on_edit_button_clicked",
2816 G_CALLBACK(&component_list_edit
),
2817 "component_list_row_activated",
2818 G_CALLBACK(&component_list_row_activated
),
2821 if (widget
== NULL
) {
2822 s_log_message("Can't find dialog component \"component_list\"\n");
2825 cl
->clwindow
= GTK_WINDOW(widget
);
2827 /* Set "user-data" properties on all interesting widgets. */
2828 x_lookup_widget_set(xml
, "ok_button", "user-data", cl
, NULL
);
2829 x_lookup_widget_set(xml
, "edit_button", "user-data", cl
, NULL
);
2830 widget
= x_lookup_widget_set(xml
, "components_treeview",
2831 "user-data", cl
, NULL
);
2832 cl
->treeview
= GTK_TREE_VIEW(widget
);
2833 g_object_set(cl
->clwindow
, "user-data", cl
, NULL
);
2835 /* Set up the tree view. */
2836 cl
->liststore
= gtk_list_store_new(COMPONENT_LIST_N_COLUMNS
,
2838 gtk_tree_view_set_model(cl
->treeview
, GTK_TREE_MODEL(cl
->liststore
));
2839 gtk_tree_view_set_search_column(cl
->treeview
, COMPONENT_LIST_REFDES
);
2841 /* Tell the tree view how to display its cells. */
2842 renderer
= gtk_cell_renderer_text_new();
2843 column
= gtk_tree_view_column_new_with_attributes("refdes", renderer
,
2844 "text", COMPONENT_LIST_REFDES
,
2846 gtk_tree_view_append_column(cl
->treeview
, column
);
2848 /* Populate the tree view with the objects given as a parameter. */
2849 for (; components
!= NULL
; components
= components
->next
) {
2853 o
= components
->data
;
2855 refdes
= o_attrib_search_name_single_exact(o
, "refdes", NULL
);
2857 gtk_list_store_append(cl
->liststore
, &row
);
2858 gtk_list_store_set(cl
->liststore
, &row
,
2859 COMPONENT_LIST_REFDES
, refdes
,
2866 /***************** End of component list dialog box ******************/
2868 /***************** Start of REPL dialog box ********************/
2872 REPL_REPRESENTATION
,
2878 GSCHEM_TOPLEVEL
*w_current
;
2880 GtkTreeStore
*treestore
;
2881 GtkTreeView
*treeview
;
2882 GtkTreeSelection
*selection
;
2883 GtkNotebook
*notebook
;
2887 void repl_destroy(struct repl
*r
)
2890 gtk_widget_destroy(r
->window
);
2892 g_object_unref(r
->xml
);
2896 void repl_populate_treeview(GtkTreeStore
*treestore
, SCM expr
,
2897 GtkTreeIter
*parent
)
2902 representation
= scm_simple_format(SCM_BOOL_F
,
2903 scm_from_locale_string("~S"),
2906 gtk_tree_store_append(treestore
, &newrow
, parent
);
2907 if (scm_is_string(representation
)) {
2908 char *representation_c
= scm_to_locale_string(representation
);
2909 SCM
*rowexpr
= g_new(SCM
, 1);
2912 gtk_tree_store_set(treestore
, &newrow
,
2914 REPL_REPRESENTATION
, representation_c
,
2916 free(representation_c
);
2918 gtk_tree_store_set(treestore
, &newrow
,
2920 REPL_REPRESENTATION
, "<libguile error>",
2924 if (scm_is_true(scm_list_p(expr
))) {
2927 for (i
= expr
; !scm_is_null(i
); i
= SCM_CDR(i
)) {
2928 repl_populate_treeview(treestore
, SCM_CAR(i
), &newrow
);
2933 gboolean
repl_clear_row(GtkTreeModel
*model
, GtkTreePath
*path
,
2934 GtkTreeIter
*iter
, gpointer user_data
)
2938 gtk_tree_model_get(model
, iter
, REPL_SCM
, &rowexpr
, -1);
2944 void repl_execute(GtkButton
*button
, gpointer user_data
)
2947 gint current_page_index
;
2948 GtkWidget
*current_page
;
2949 GtkTextBuffer
*textbuffer
;
2952 g_object_get(G_OBJECT(button
), "user-data", &r
, NULL
);
2954 current_page_index
= gtk_notebook_get_current_page(r
->notebook
);
2955 if (current_page_index
== -1) {
2956 printf("No open pages\n");
2960 current_page
= gtk_notebook_get_nth_page(r
->notebook
, current_page_index
);
2961 if (current_page
== NULL
) {
2962 printf("Can't get current page\n");
2966 textbuffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(current_page
));
2967 /* TODO - g_type_is_a() */
2968 g_object_get(G_OBJECT(textbuffer
), "text", &text
, NULL
);
2970 if (r
->result
!= SCM_UNDEFINED
) {
2971 scm_gc_unprotect_object(r
->result
);
2974 /* Pass the string to the interpreter. */
2975 r
->result
= g_scm_apply_protected(g_scm_safe_ref_lookup("invoke-macro"),
2976 scm_list_1(scm_from_locale_string(text
)),
2979 scm_gc_protect_object(r
->result
);
2981 /* TODO: Give feedback if an exception occurred. */
2982 gtk_tree_model_foreach(GTK_TREE_MODEL(r
->treestore
), &repl_clear_row
, NULL
);
2983 gtk_tree_store_clear(r
->treestore
);
2984 repl_populate_treeview(r
->treestore
, r
->result
, NULL
);
2986 gtk_tree_model_foreach(GTK_TREE_MODEL(r
->treestore
), &repl_selection_one
, r
);
2989 void repl_cancel(GtkButton
*button
, gpointer user_data
)
2993 g_object_get(G_OBJECT(button
), "user-data", &r
, NULL
);
2995 gtk_widget_hide(r
->window
);
2998 void repl_row_activated(GtkTreeView
*tree_view
,
3000 GtkTreeViewColumn
*column
,
3003 GtkTreeModel
*model
= gtk_tree_view_get_model(tree_view
);
3009 gtk_tree_model_get_iter(model
, &iter
, path
);
3010 gtk_tree_model_get(model
, &iter
, REPL_SCM
, &rowexpr
, -1);
3012 if (g_get_data_from_object_smob(*rowexpr
, &toplevel
, &o_current
)) {
3015 g_object_get(G_OBJECT(tree_view
), "user-data", &r
, NULL
);
3017 x_multiattrib_open(r
->w_current
, toplevel
->page_current
->selection_list
);
3018 } else if (scm_is_true(scm_thunk_p(*rowexpr
))) {
3019 /* TODO: Execute thunk with g_scm_apply_protected. */
3023 /* XXX getting both w_current and toplevel is odd. */
3024 void repl_selection_one_object(GtkTreeSelection
*selection
, GtkTreePath
*path
,
3025 GSCHEM_TOPLEVEL
*w_current
, TOPLEVEL
*toplevel
,
3028 PAGE
*page
= toplevel
->page_current
;
3030 o_select_object_simple(w_current
, toplevel
, page
, o_current
,
3031 gtk_tree_selection_path_is_selected(selection
, path
));
3034 static gboolean
repl_selection_one(GtkTreeModel
*model
, GtkTreePath
*path
,
3035 GtkTreeIter
*iter
, gpointer user_data
)
3037 struct repl
*r
= user_data
;
3042 gtk_tree_model_get(model
, iter
, REPL_SCM
, &rowexpr
, -1);
3043 if (g_get_data_from_object_smob(*rowexpr
, &toplevel
, &o_current
)) {
3044 repl_selection_one_object(r
->selection
, path
, r
->w_current
, toplevel
, o_current
);
3050 void repl_selection_changed(GtkTreeSelection
*selection
, gpointer user_data
)
3052 struct repl
*r
= user_data
;
3054 gtk_tree_model_foreach(GTK_TREE_MODEL(r
->treestore
), &repl_selection_one
, r
);
3057 void repl_new_page(GtkNotebook
*notebook
)
3059 GtkWidget
*textview
= gtk_text_view_new();
3060 GtkTextBuffer
*textbuffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview
));
3061 GtkWidget
*label
= gtk_label_new("New");
3063 gtk_text_buffer_set_text(textbuffer
, ";; Write some Scheme here", -1);
3064 select_all_text_in_textview(GTK_TEXT_VIEW(textview
));
3065 gtk_widget_show(GTK_WIDGET(textview
));
3066 gtk_notebook_prepend_page(notebook
, textview
, label
);
3067 gtk_notebook_set_current_page(notebook
, 0);
3068 gtk_widget_grab_focus(textview
);
3069 if (gtk_notebook_get_n_pages(notebook
) > 1) {
3070 g_object_set(G_OBJECT(notebook
), "show-tabs", TRUE
, NULL
);
3074 void repl_dialog(GSCHEM_TOPLEVEL
*w_current
)
3076 static struct repl
*r
= NULL
;
3079 repl_new_page(r
->notebook
);
3080 gtk_widget_show(r
->window
);
3084 r
= g_new0(struct repl
, 1);
3085 r
->w_current
= w_current
;
3086 r
->result
= SCM_UNDEFINED
;
3088 r
->window
= x_glade_get_widget(&r
->xml
, "repl",
3089 "on_repl_window_delete_event",
3090 G_CALLBACK(gtk_widget_hide_on_delete
),
3091 "on_execute_button_clicked",
3092 G_CALLBACK(repl_execute
),
3093 "on_cancel_button_clicked",
3094 G_CALLBACK(repl_cancel
),
3095 "on_result_treeview_row_activated",
3096 G_CALLBACK(repl_row_activated
),
3098 if (r
->window
== NULL
) {
3099 s_log_message("Can't find dialog component \"repl\"\n");
3105 r
->notebook
= GTK_NOTEBOOK(x_lookup_widget(r
->xml
, "sexpr-notebook"));
3106 if (r
->notebook
== NULL
) {
3107 s_log_message("Can't find sexpr notebook in dialog component \"repl\"\n");
3113 r
->treeview
= GTK_TREE_VIEW(x_lookup_widget(r
->xml
, "result-treeview"));
3114 if (r
->treeview
!= NULL
) {
3115 GtkCellRenderer
*renderer
;
3116 GtkTreeViewColumn
*column
;
3118 r
->treestore
= gtk_tree_store_new(REPL_N_COLUMNS
,
3121 gtk_tree_view_set_model(r
->treeview
, GTK_TREE_MODEL(r
->treestore
));
3123 renderer
= gtk_cell_renderer_text_new();
3124 column
= gtk_tree_view_column_new_with_attributes("value", renderer
,
3125 "text", REPL_REPRESENTATION
,
3127 gtk_tree_view_append_column(r
->treeview
, column
);
3129 r
->selection
= gtk_tree_view_get_selection(r
->treeview
);
3130 gtk_tree_selection_set_mode(r
->selection
, GTK_SELECTION_MULTIPLE
);
3132 g_signal_connect(r
->selection
, "changed", G_CALLBACK(repl_selection_changed
), r
);
3135 x_lookup_widget_set(r
->xml
, "execute_button", "user-data", r
, NULL
);
3136 x_lookup_widget_set(r
->xml
, "cancel_button", "user-data", r
, NULL
);
3137 x_lookup_widget_set(r
->xml
, "result-treeview", "user-data", r
, NULL
);
3139 gtk_notebook_remove_page(r
->notebook
, 0);
3140 repl_new_page(r
->notebook
);
3143 /***************** End of REPL dialog box ******************/
3145 /***************** Start of help/about dialog box ********************/
3147 /*! \brief Response function for the about dialog
3148 * \par Function Description
3149 * This function destroys the about dialog.
3151 void about_dialog_response(GtkWidget
*w
, gint response
,
3152 GSCHEM_TOPLEVEL
*w_current
)
3155 case GTK_RESPONSE_REJECT
:
3156 case GTK_RESPONSE_DELETE_EVENT
:
3160 printf("about_dialog_response(): strange signal %d\n",response
);
3163 gtk_widget_destroy(w_current
->abwindow
);
3164 w_current
->abwindow
= NULL
;
3167 /*! \brief Create the about dialog and show it
3168 * \par Function Description
3169 * This function creates the about dialog.
3171 void about_dialog (GSCHEM_TOPLEVEL
*w_current
)
3173 GtkWidget
*label
= NULL
;
3177 if (!w_current
->abwindow
) {
3178 w_current
->abwindow
= gschem_dialog_new_with_buttons(_("About..."),
3179 GTK_WINDOW(w_current
->main_window
),
3183 GTK_RESPONSE_REJECT
,
3186 gtk_window_position (GTK_WINDOW (w_current
->abwindow
),
3189 gtk_signal_connect (GTK_OBJECT (w_current
->abwindow
), "response",
3190 GTK_SIGNAL_FUNC(about_dialog_response
),
3193 gtk_container_border_width (GTK_CONTAINER(w_current
->abwindow
),
3194 DIALOG_BORDER_SPACING
);
3195 vbox
= GTK_DIALOG(w_current
->abwindow
)->vbox
;
3196 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
3198 label
= gtk_label_new ( _("<b>gEDA: GPL Electronic Design Automation</b>"));
3199 gtk_label_set_use_markup (GTK_LABEL(label
), TRUE
);
3200 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
3202 string
= g_strdup_printf(_("<b>gschem version %s%s.%s</b>"),
3203 PREPEND_VERSION_STRING
, DOTTED_VERSION
,
3205 label
= gtk_label_new (string
);
3206 gtk_label_set_use_markup (GTK_LABEL(label
), TRUE
);
3208 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
3210 label
= gtk_label_new ( _("Written by:\n"
3212 "ahvezda@geda.seul.org\n"
3213 "And many others (See AUTHORS file)"));
3214 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
3215 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
3217 gtk_widget_show_all(w_current
->abwindow
);
3220 else { /* dialog already created */
3221 gtk_window_present(GTK_WINDOW(w_current
->abwindow
));
3225 /***************** End of help/about dialog box *********************/
3227 /***************** Start of coord dialog box ************************/
3228 /*! \brief Response function for the coord dialog
3229 * \par Function Description
3230 * This function destroys the coord dialog box and does some cleanup.
3232 void coord_dialog_response(GtkWidget
*w
, gint response
, GSCHEM_TOPLEVEL
*w_current
)
3234 gtk_widget_destroy(w_current
->cowindow
);
3235 w_current
->cowindow
= NULL
;
3236 w_current
->coord_world
= NULL
;
3237 w_current
->coord_screen
= NULL
;
3240 /*! \brief Update the coordinates in the coord dialog box.
3241 * \par Function Description
3242 * This function takes the screen coordinates and prints the
3243 * screen and the world coordinates in the coord dialog.
3245 void coord_display_update(GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
3247 TOPLEVEL
*toplevel
= w_current
->toplevel
;
3248 PAGE
*page
= toplevel
->page_current
;
3250 int world_x
, world_y
;
3252 string
= g_strdup_printf("(%d, %d)", x
, y
);
3253 gtk_label_set_text(GTK_LABEL(w_current
->coord_screen
), string
);
3256 SCREENtoWORLD(page
, x
, y
, &world_x
, &world_y
);
3257 /* TODO: Do we want to snap the coordinate display? */
3258 world_x
= snap_grid(toplevel
, world_x
);
3259 world_y
= snap_grid(toplevel
, world_y
);
3261 string
= g_strdup_printf("(%d, %d)", world_x
, world_y
);
3262 gtk_label_set_text(GTK_LABEL(w_current
->coord_world
), string
);
3266 /*! \brief Create the coord dialog
3267 * \par Function Description
3268 * This function creates the coord dialog box.
3270 void coord_dialog (GSCHEM_TOPLEVEL
*w_current
, int x
, int y
)
3275 if (!w_current
->cowindow
) {
3276 w_current
->cowindow
= gschem_dialog_new_with_buttons(_("Coords"),
3277 GTK_WINDOW(w_current
->main_window
),
3278 0, /* Not modal GTK_DIALOG_MODAL */
3281 GTK_RESPONSE_REJECT
,
3284 gtk_window_position (GTK_WINDOW (w_current
->cowindow
),
3287 gtk_signal_connect (GTK_OBJECT (w_current
->cowindow
), "response",
3288 GTK_SIGNAL_FUNC(coord_dialog_response
),
3291 gtk_container_border_width (GTK_CONTAINER(w_current
->cowindow
),
3292 DIALOG_BORDER_SPACING
);
3293 vbox
= GTK_DIALOG(w_current
->cowindow
)->vbox
;
3294 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
3297 frame
= gtk_frame_new (_("Screen"));
3298 w_current
->coord_screen
= gtk_label_new("(########, ########)");
3299 gtk_label_set_justify( GTK_LABEL(w_current
->coord_screen
), GTK_JUSTIFY_LEFT
);
3300 gtk_misc_set_padding(GTK_MISC(w_current
->coord_screen
),
3301 DIALOG_H_SPACING
, DIALOG_V_SPACING
);
3302 gtk_container_add(GTK_CONTAINER (frame
),
3303 w_current
->coord_screen
);
3304 gtk_box_pack_start(GTK_BOX (vbox
), frame
, FALSE
, FALSE
, 0);
3306 frame
= gtk_frame_new (_("World"));
3307 w_current
->coord_world
= gtk_label_new ("(########, ########)");
3308 gtk_misc_set_padding(GTK_MISC(w_current
->coord_world
),
3309 DIALOG_H_SPACING
, DIALOG_V_SPACING
);
3310 gtk_label_set_justify(GTK_LABEL(w_current
->coord_world
),
3312 gtk_container_add(GTK_CONTAINER (frame
),
3313 w_current
->coord_world
);
3314 gtk_box_pack_start(GTK_BOX (vbox
), frame
, FALSE
, FALSE
, 0);
3316 gtk_widget_show_all(w_current
->cowindow
);
3319 else { /* window already creatad */
3320 gtk_window_present(GTK_WINDOW(w_current
->cowindow
));
3323 /* always update the coords when the dialog is requested */
3324 coord_display_update(w_current
, x
, y
);
3327 /***************** End of coord dialog box **************************/
3329 /***************** Start of color edit dialog box *******************/
3331 /*! \todo Finish function documentation!!!
3333 * \par Function Description
3336 * Caller must g_free returned character string.
3339 char *index2functionstring(int index
)
3344 case(BACKGROUND_COLOR
):
3345 string
= g_strdup (_("Background"));
3348 string
= g_strdup (_("Pin"));
3350 case(NET_ENDPOINT_COLOR
):
3351 string
= g_strdup (_("Net endpoint"));
3353 case(GRAPHIC_COLOR
):
3354 string
= g_strdup (_("Graphic"));
3357 string
= g_strdup (_("Net"));
3359 case(ATTRIBUTE_COLOR
):
3360 string
= g_strdup (_("Attribute"));
3362 case(LOGIC_BUBBLE_COLOR
):
3363 string
= g_strdup (_("Logic bubble"));
3366 string
= g_strdup (_("Grid point"));
3368 case(DETACHED_ATTRIBUTE_COLOR
):
3369 string
= g_strdup (_("Detached attribute"));
3372 string
= g_strdup (_("Text"));
3375 string
= g_strdup (_("Bus"));
3378 string
= g_strdup (_("Selection"));
3380 case(BOUNDINGBOX_COLOR
):
3381 string
= g_strdup (_("Bounding box"));
3383 case(ZOOM_BOX_COLOR
):
3384 string
= g_strdup (_("Zoom box"));
3387 string
= g_strdup (_("Stroke"));
3390 string
= g_strdup (_("Lock"));
3392 case(OUTPUT_BACKGROUND_COLOR
):
3393 string
= g_strdup (_("Output background"));
3395 case(JUNCTION_COLOR
):
3396 string
= g_strdup (_("Net junction"));
3399 string
= g_strdup (_("Unknown"));
3405 /*! \brief Cell layout data function for color combobox.
3406 * \par Function Description
3407 * Cell layout data function to support color swatches in the color
3410 * \param data the current #GSCHEM_TOPLEVEL pointer.
3413 color_menu_swatch_layout_data (GtkCellLayout
*layout
,
3414 GtkCellRenderer
*cell
,
3415 GtkTreeModel
*model
,
3419 /* GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) data; */
3423 /* Get the index of the color on this row */
3424 gtk_tree_model_get_value (model
, iter
, 1, &v
);
3425 idx
= g_value_get_int (&v
);
3427 /* Set the cell's background color */
3428 g_object_set (cell
, "background-gdk", x_get_color (idx
), NULL
);
3431 /*! \brief Handle color combobox selection change event.
3432 * \par Function Description
3433 * Update application state to reflect color combobox selection
3436 * \param data the current #GSCHEM_TOPLEVEL pointer.
3439 color_menu_change_selection (GtkWidget
*widget
,
3442 GSCHEM_TOPLEVEL
*w_current
= (GSCHEM_TOPLEVEL
*) data
;
3443 GtkComboBox
*cbox
= GTK_COMBO_BOX (widget
);
3448 if (!gtk_combo_box_get_active_iter (cbox
, &iter
)) {
3449 return; /* No color selected */
3451 gtk_tree_model_get_value (gtk_combo_box_get_model (cbox
),
3453 idx
= g_value_get_int (&v
);
3455 /* Stash the selected color in the GSCHEM_TOPLEVEL.
3456 * FIXME this is ugly. */
3457 w_current
->edit_color
= idx
;
3460 /*! \brief Create a ComboBox with the gschem colors.
3461 * \par Function Description
3462 * Creates a #GtkComboBox with the color list and swatches showing
3463 * each of the available colors.
3465 * The backing #GtkTreeModel is a #GtkListStore with two columns, the
3466 * first holding the user-friendly name of the color, and the other
3467 * the color map index.
3469 * \param [in] w_current The current gschem context.
3472 create_color_menu (GSCHEM_TOPLEVEL
*w_current
)
3474 GtkListStore
*store
;
3476 GtkCellLayout
*layout
;
3477 GtkCellRenderer
*text_cell
;
3478 GtkCellRenderer
*color_cell
;
3485 obj
= o_select_return_first_object (w_current
);
3487 w_current
->edit_color
= obj
->saved_color
;
3489 /* The columns are: name of color, index of color. */
3490 store
= gtk_list_store_new (2, G_TYPE_STRING
, G_TYPE_INT
);
3491 cbox
= GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (store
)));
3492 layout
= GTK_CELL_LAYOUT (cbox
); /* For convenience */
3494 /* Renders the color swatch. Since this won't contain text, set a
3496 color_cell
= GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3497 g_object_set (color_cell
, "width", 25, NULL
);
3498 gtk_cell_layout_pack_start (layout
, color_cell
, FALSE
);
3499 gtk_cell_layout_set_cell_data_func (layout
, color_cell
,
3500 color_menu_swatch_layout_data
,
3501 (gpointer
) w_current
,
3504 /* Renders the name of the color */
3505 text_cell
= GTK_CELL_RENDERER (gtk_cell_renderer_text_new());
3506 g_object_set (text_cell
, "xpad", 5, NULL
);
3507 gtk_cell_layout_pack_start (layout
, text_cell
, TRUE
);
3508 gtk_cell_layout_add_attribute (layout
, text_cell
, "text", 0);
3510 /* Populate the list */
3511 for (i
= 0; i
< MAX_COLORS
; i
++) {
3512 /* Skip 'invalid' colors. FIXME this is ugly. */
3513 gchar
*buf
= x_color_get_name(i
);
3514 if (buf
== NULL
) continue;
3517 str
= index2functionstring (i
);
3518 gtk_list_store_append (store
, &iter
);
3519 gtk_list_store_set (store
, &iter
, 0, str
, 1, i
, -1);
3520 if (i
== w_current
->edit_color
)
3521 gtk_combo_box_set_active_iter (cbox
, &iter
);
3524 g_signal_connect (cbox
,
3526 GTK_SIGNAL_FUNC (color_menu_change_selection
),
3529 return GTK_WIDGET (cbox
);
3532 /*! \brief Apply a color change to selected objects
3533 * \par Function Description
3534 * This function applies a color change to the currently selected objects.
3536 void color_edit_dialog_apply(GtkWidget
*w
, GSCHEM_TOPLEVEL
*w_current
)
3538 TOPLEVEL
*toplevel
= safe_toplevel(w_current
);
3539 PAGE
*page
= safe_page_current(toplevel
);;
3540 GList
*s_current
= NULL
;
3541 OBJECT
*object
= NULL
;
3543 s_current
= geda_list_get_glist(page
->selection_list
);
3545 while(s_current
!= NULL
) {
3546 object
= s_current
->data
;
3547 if (object
== NULL
) {
3548 fprintf(stderr
, _("ERROR: NULL object in color_edit_dialog_apply!\n"));
3552 switch(object
->type
) {
3560 object
->saved_color
= w_current
->edit_color
;
3565 object
->saved_color
= w_current
->edit_color
;
3566 o_complex_set_saved_color_only(
3567 object
->text
->prim_objs
,
3568 w_current
->edit_color
);
3573 s_current
= g_list_next(s_current
);
3575 o_undo_savestate(w_current
, UNDO_ALL
);
3578 /*! \brief response function for the color edit dialog
3579 * \par Function Description
3580 * This function takes the user response from the color edit dialog
3582 void color_edit_dialog_response(GtkWidget
*widget
, gint response
, GSCHEM_TOPLEVEL
*w_current
)
3585 case GTK_RESPONSE_REJECT
:
3586 case GTK_RESPONSE_DELETE_EVENT
:
3587 gtk_widget_destroy(w_current
->clwindow
);
3588 w_current
->clwindow
= NULL
;
3590 case GTK_RESPONSE_ACCEPT
:
3591 color_edit_dialog_apply(widget
, w_current
);
3594 printf("ERROR: color_edit_dialog_response(): strange signal %d\n",response
);
3599 /*! \brief Create the color edit dialog
3600 * \par Function Description
3601 * This function creates the color edit dialog
3603 void color_edit_dialog (GSCHEM_TOPLEVEL
*w_current
)
3605 GtkWidget
*optionmenu
;
3609 if (!w_current
->clwindow
) {
3610 w_current
->clwindow
= gschem_dialog_new_with_buttons(_("Color Edit"),
3611 GTK_WINDOW(w_current
->main_window
),
3612 0, /* nonmodal dialog */
3613 "color-edit", w_current
,
3615 GTK_RESPONSE_REJECT
,
3617 GTK_RESPONSE_ACCEPT
,
3620 /* Set the alternative button order (ok, cancel, help) for other systems */
3621 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->clwindow
),
3622 GTK_RESPONSE_ACCEPT
,
3623 GTK_RESPONSE_REJECT
,
3626 gtk_window_position (GTK_WINDOW (w_current
->clwindow
),
3629 gtk_dialog_set_default_response (GTK_DIALOG (w_current
->clwindow
),
3630 GTK_RESPONSE_ACCEPT
);
3632 gtk_signal_connect(GTK_OBJECT(w_current
->clwindow
), "response",
3633 GTK_SIGNAL_FUNC(color_edit_dialog_response
),
3636 gtk_container_border_width(GTK_CONTAINER(w_current
->clwindow
),
3637 DIALOG_BORDER_SPACING
);
3638 vbox
= GTK_DIALOG(w_current
->clwindow
)->vbox
;
3639 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
3641 label
= gtk_label_new(_("Object color:"));
3642 gtk_misc_set_alignment(GTK_MISC(label
),0,0);
3643 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
3645 optionmenu
= create_color_menu (w_current
);
3646 gtk_box_pack_start(GTK_BOX(vbox
),
3647 optionmenu
, FALSE
, FALSE
, 0);
3648 gtk_widget_show_all(w_current
->clwindow
);
3651 else { /* dialog already created */
3652 gtk_window_present(GTK_WINDOW(w_current
->clwindow
));
3656 /***************** End of color edit dialog box *********************/
3658 /***************** Start of help/keymapping dialog box **************/
3660 /*! \brief Response function for the hotkey dialog
3661 * \par Function Description
3662 * This function destroys the hotkey dialog and does some cleanup.
3664 void x_dialog_hotkeys_response(GtkWidget
*w
, gint response
,
3665 GSCHEM_TOPLEVEL
*w_current
)
3668 case GTK_RESPONSE_REJECT
:
3669 case GTK_RESPONSE_DELETE_EVENT
:
3673 printf("x_dialog_hotkeys_response(): strange signal %d\n", response
);
3676 gtk_widget_destroy(w_current
->hkwindow
);
3677 w_current
->hkwindow
= NULL
;
3680 /*! \brief Creates the hotkeys dialog
3681 * \par Function Description
3682 * This function creates the hotkey dialog and puts the list of hotkeys
3685 void x_dialog_hotkeys (GSCHEM_TOPLEVEL
*w_current
)
3687 GtkWidget
*vbox
, *scrolled_win
;
3688 GtkListStore
*store
;
3689 GtkWidget
*treeview
;
3690 GtkCellRenderer
*renderer
;
3691 GtkTreeViewColumn
*column
;
3694 struct keyseq_action_t
{
3695 gchar
*keyseq
, *action
;
3698 if (!w_current
->hkwindow
) {
3699 w_current
->hkwindow
= gschem_dialog_new_with_buttons(_("Hotkeys"),
3700 GTK_WINDOW(w_current
->main_window
),
3702 "hotkeys", w_current
,
3704 GTK_RESPONSE_REJECT
,
3707 gtk_window_position (GTK_WINDOW (w_current
->hkwindow
),
3710 gtk_signal_connect (GTK_OBJECT (w_current
->hkwindow
), "response",
3711 GTK_SIGNAL_FUNC(x_dialog_hotkeys_response
),
3714 gtk_dialog_set_default_response(GTK_DIALOG(w_current
->hkwindow
),
3715 GTK_RESPONSE_ACCEPT
);
3717 gtk_container_border_width (GTK_CONTAINER (w_current
->hkwindow
),
3718 DIALOG_BORDER_SPACING
);
3719 gtk_widget_set_usize(w_current
->hkwindow
, 300,300);
3721 vbox
= GTK_DIALOG(w_current
->hkwindow
)->vbox
;
3722 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
3724 scrolled_win
= gtk_scrolled_window_new (NULL
, NULL
);
3725 gtk_box_pack_start (GTK_BOX (vbox
), scrolled_win
, TRUE
, TRUE
, 0);
3726 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win
),
3727 GTK_POLICY_AUTOMATIC
,
3728 GTK_POLICY_AUTOMATIC
);
3731 store
= gtk_list_store_new (2,G_TYPE_STRING
, G_TYPE_STRING
);
3733 /* retrieve current keymap */
3734 keymap
= g_keys_dump_keymap ();
3735 /* add each keymap entry to the list store of the dialog */
3736 for (i
= 0; keymap
&& i
< keymap
->len
; i
++) {
3738 struct keyseq_action_t
*keymap_entry
;
3740 keymap_entry
= &g_array_index (keymap
, struct keyseq_action_t
, i
);
3741 gtk_list_store_append (store
, &iter
);
3742 gtk_list_store_set (store
, &iter
,
3743 0, keymap_entry
->action
,
3744 1, keymap_entry
->keyseq
,
3748 /* finally free the array for keymap */
3749 for (i
= 0; keymap
&& i
< keymap
->len
; i
++) {
3750 struct keyseq_action_t
*keymap_entry
;
3751 keymap_entry
= &g_array_index (keymap
, struct keyseq_action_t
, i
);
3752 g_free (keymap_entry
->keyseq
);
3753 g_free (keymap_entry
->action
);
3755 g_array_free (keymap
, TRUE
);
3758 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
3759 gtk_container_add(GTK_CONTAINER(scrolled_win
), treeview
);
3762 renderer
= gtk_cell_renderer_text_new ();
3763 column
= gtk_tree_view_column_new_with_attributes (_("Function"),
3768 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
3769 renderer
= gtk_cell_renderer_text_new ();
3770 column
= gtk_tree_view_column_new_with_attributes (_("Keystroke(s)"),
3775 gtk_tree_view_append_column (GTK_TREE_VIEW(treeview
), column
);
3777 /* show all recursively */
3778 gtk_widget_show_all(w_current
->hkwindow
);
3781 else { /* dialog already created */
3782 gtk_window_present(GTK_WINDOW(w_current
->hkwindow
));
3786 /***************** End of help/keymapping dialog box ****************/
3788 /*********** Start of misc support functions for dialog boxes *******/
3789 extern GtkWidget
*stwindow
;
3791 /*! \todo Finish function documentation!!!
3793 * \par Function Description
3796 void x_dialog_raise_all(GSCHEM_TOPLEVEL
*w_current
)
3798 if(w_current
->sowindow
) {
3799 gdk_window_raise(w_current
->sowindow
->window
);
3801 if(w_current
->cswindow
) {
3802 gdk_window_raise(w_current
->cswindow
->window
);
3804 if(w_current
->iwindow
) {
3805 gdk_window_raise(w_current
->iwindow
->window
);
3807 if(w_current
->tiwindow
) {
3808 gdk_window_raise(w_current
->tiwindow
->window
);
3810 if(w_current
->tewindow
) {
3811 gdk_window_raise(w_current
->tewindow
->window
);
3813 if(w_current
->sewindow
) {
3814 gdk_window_raise(w_current
->sewindow
->window
);
3816 if(w_current
->aawindow
) {
3817 gdk_window_raise(w_current
->aawindow
->window
);
3819 if(w_current
->mawindow
) {
3820 gdk_window_raise(w_current
->mawindow
->window
);
3822 if(w_current
->aewindow
) {
3823 gdk_window_raise(w_current
->aewindow
->window
);
3825 if(w_current
->trwindow
) {
3826 gdk_window_raise(w_current
->trwindow
->window
);
3828 if(w_current
->tswindow
) {
3829 gdk_window_raise(w_current
->tswindow
->window
);
3831 if(w_current
->abwindow
) {
3832 gdk_window_raise(w_current
->abwindow
->window
);
3834 if(w_current
->hkwindow
) {
3835 gdk_window_raise(w_current
->hkwindow
->window
);
3837 if(w_current
->cowindow
) {
3838 gdk_window_raise(w_current
->cowindow
->window
);
3840 if(w_current
->clwindow
) {
3841 gdk_window_raise(w_current
->clwindow
->window
);
3846 /*********** End of misc support functions for dialog boxes *******/
3848 /***************** Start of generic message dialog box *******************/
3850 /*! \todo Finish function documentation!!!
3852 * \par Function Description
3855 void generic_msg_dialog (const char *msg
)
3859 dialog
= gtk_message_dialog_new (NULL
,
3861 GTK_DIALOG_DESTROY_WITH_PARENT
,
3866 gtk_dialog_run (GTK_DIALOG (dialog
));
3867 gtk_widget_destroy (dialog
);
3871 /***************** End of generic message dialog box *********************/
3873 /***************** Start of generic confirm dialog box *******************/
3875 /*! \todo Finish function documentation!!!
3877 * \par Function Description
3880 int generic_confirm_dialog (const char *msg
)
3885 dialog
= gtk_message_dialog_new (NULL
,
3887 GTK_DIALOG_DESTROY_WITH_PARENT
,
3889 GTK_BUTTONS_OK_CANCEL
,
3892 r
= gtk_dialog_run (GTK_DIALOG (dialog
));
3893 gtk_widget_destroy (dialog
);
3895 if (r
== GTK_RESPONSE_OK
)
3901 /***************** End of generic confirm dialog box *********************/
3903 /***************** Start of generic file select dialog box ***************/
3904 /*! \todo Finish function documentation!!!
3906 * \par Function Description
3909 * Caller must g_free returned character string.
3911 char *generic_filesel_dialog (const char *msg
, const char *templ
, gint flags
)
3914 gchar
*result
= NULL
, *folder
, *seed
;
3916 static gchar
*path
= NULL
;
3917 static gchar
*shortcuts
= NULL
;
3919 /* Default to load if not specified. Maybe this should cause an error. */
3920 if (! (flags
& (FSB_LOAD
| FSB_SAVE
))) {
3921 flags
= flags
| FSB_LOAD
;
3924 if (flags
& FSB_LOAD
) {
3925 title
= g_strdup_printf("%s: Open", msg
);
3926 dialog
= gtk_file_chooser_dialog_new (title
,
3928 GTK_FILE_CHOOSER_ACTION_OPEN
,
3929 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
3930 GTK_STOCK_OPEN
, GTK_RESPONSE_OK
,
3932 /* Since this is a load dialog box, the file must exist! */
3933 flags
= flags
| FSB_MUST_EXIST
;
3936 title
= g_strdup_printf("%s: Save", msg
);
3937 dialog
= gtk_file_chooser_dialog_new (title
,
3939 GTK_FILE_CHOOSER_ACTION_SAVE
,
3940 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
3941 GTK_STOCK_OPEN
, GTK_RESPONSE_OK
,
3945 /* Set the alternative button order (ok, cancel, help) for other systems */
3946 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
3948 GTK_RESPONSE_CANCEL
,
3951 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
3953 /* Pick the current default folder to look for files in */
3954 if (path
&& *path
) {
3955 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), path
);
3959 /* Pick the current template (*.rc) or default file name */
3960 if (templ
&& *templ
) {
3961 if (flags
& FSB_SAVE
) {
3962 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), templ
);
3964 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (dialog
), templ
);
3969 if (shortcuts
&& *shortcuts
) {
3970 printf ("shortcuts = \"%s\"\n", shortcuts
);
3971 folder
= g_strdup (shortcuts
);
3973 while ((folder
= strtok (seed
, ":")) != NULL
) {
3974 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
3982 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
) {
3983 result
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
3984 folder
= gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog
));
3986 if (folder && path) {
3987 dup_string (path, folder);
3992 gtk_widget_destroy (dialog
);
3999 /***************** End of generic file select dialog box *****************/
4001 /*********** Start of find text dialog box *******/
4004 PAGE
*remember_page
;
4006 /*! \brief response function for the find text dialog
4007 * \par Function Description
4008 * This function takes the string the user likes to find and searches it
4011 void find_text_dialog_response(GtkWidget
*w
, gint response
,
4012 GSCHEM_TOPLEVEL
*w_current
)
4014 TOPLEVEL
*toplevel
= w_current
->toplevel
;
4015 GtkWidget
*textentry
;
4016 GtkWidget
*checkdescend
;
4018 gint done
=0, close
=0;
4021 case GTK_RESPONSE_ACCEPT
:
4022 textentry
= g_object_get_data(G_OBJECT(w_current
->tfindwindow
),"textentry");
4023 string
= (gchar
*) gtk_entry_get_text(GTK_ENTRY(textentry
));
4024 checkdescend
= g_object_get_data(G_OBJECT(w_current
->tfindwindow
),"checkdescend");
4026 strncpy(generic_textstring
, string
, 256);
4028 if (remember_page
!= toplevel
->page_current
) {
4029 s_toplevel_goto_page(toplevel
, remember_page
);
4032 o_edit_find_text(w_current
, remember_page
->object_head
, string
,
4033 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
4037 o_redraw_all(w_current
);
4042 case GTK_RESPONSE_REJECT
:
4043 case GTK_RESPONSE_DELETE_EVENT
:
4047 printf("find_text_dialog_response(): strange signal %d\n", response
);
4050 gtk_widget_destroy(w_current
->tfindwindow
);
4051 w_current
->tfindwindow
= NULL
;
4055 /*! \brief Create the text find dialog
4056 * \par Function Description
4057 * This function creates the text find dialog.
4059 void find_text_dialog(GSCHEM_TOPLEVEL
*w_current
)
4061 GtkWidget
*label
= NULL
;
4063 GtkWidget
*checkdescend
;
4064 GtkWidget
*textentry
;
4065 OBJECT
*object
= NULL
;
4068 remember_page
= w_current
->toplevel
->page_current
;
4069 if ((object
= o_select_return_first_object(w_current
)) != NULL
) {
4070 if (object
->type
== OBJ_TEXT
) {
4071 strncpy(generic_textstring
, o_text_get_string(object
), 256);
4075 if (!w_current
->tfindwindow
) {
4076 w_current
->tfindwindow
= gschem_dialog_new_with_buttons(_("Find Text"),
4077 GTK_WINDOW(w_current
->main_window
),
4078 0, /* not modal GTK_DIALOG_MODAL */
4079 "find-text", w_current
,
4081 GTK_RESPONSE_REJECT
,
4083 GTK_RESPONSE_ACCEPT
,
4086 /* Set the alternative button order (ok, cancel, help) for other systems */
4087 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->tfindwindow
),
4088 GTK_RESPONSE_ACCEPT
,
4089 GTK_RESPONSE_REJECT
,
4092 gtk_window_position(GTK_WINDOW(w_current
->tfindwindow
),
4095 gtk_signal_connect(GTK_OBJECT(w_current
->tfindwindow
), "response",
4096 GTK_SIGNAL_FUNC(find_text_dialog_response
),
4099 gtk_dialog_set_default_response(GTK_DIALOG(w_current
->tfindwindow
),
4100 GTK_RESPONSE_ACCEPT
);
4102 gtk_container_border_width(GTK_CONTAINER(w_current
->tfindwindow
),
4103 DIALOG_BORDER_SPACING
);
4104 vbox
= GTK_DIALOG(w_current
->tfindwindow
)->vbox
;
4105 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
4107 label
= gtk_label_new(_("Text to find:"));
4108 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
4109 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
4111 textentry
= gtk_entry_new_with_max_length(20);
4112 gtk_editable_select_region(GTK_EDITABLE(textentry
), 0, -1);
4113 gtk_box_pack_start(GTK_BOX(vbox
), textentry
, FALSE
, FALSE
, 0);
4114 gtk_entry_set_activates_default(GTK_ENTRY(textentry
), TRUE
);
4115 gtk_widget_grab_focus(textentry
);
4117 checkdescend
= gtk_check_button_new_with_label(_("descend into hierarchy"));
4118 gtk_box_pack_start(GTK_BOX(vbox
), checkdescend
, TRUE
, TRUE
, 0);
4120 GLADE_HOOKUP_OBJECT(w_current
->tfindwindow
, textentry
, "textentry");
4121 GLADE_HOOKUP_OBJECT(w_current
->tfindwindow
, checkdescend
, "checkdescend");
4123 gtk_widget_show_all(w_current
->tfindwindow
);
4126 else { /* dialog already created */
4127 gtk_window_present(GTK_WINDOW(w_current
->tfindwindow
));
4130 /* always select the text string in the entry */
4131 textentry
= g_object_get_data (G_OBJECT (w_current
->tfindwindow
), "textentry");
4132 gtk_entry_set_text(GTK_ENTRY(textentry
), generic_textstring
);
4133 gtk_entry_select_region(GTK_ENTRY(textentry
), 0, -1);
4136 /*********** End of find text dialog box *******/
4138 /*********** Start of hide text dialog box *******/
4140 /*! \brief Response function for the hide text dialog
4141 * \par Function Description
4142 * This is the response function of the hide text dialog. It takes the user input
4143 * and hides all text elements that starts with the searchtext.
4145 void hide_text_dialog_response(GtkWidget
*w
, gint response
,
4146 GSCHEM_TOPLEVEL
*w_current
)
4148 GtkWidget
*textentry
;
4152 case GTK_RESPONSE_ACCEPT
:
4153 textentry
= g_object_get_data(G_OBJECT(w_current
->thidewindow
),"textentry");
4154 string
= (gchar
*) gtk_entry_get_text(GTK_ENTRY(textentry
));
4156 strncpy(generic_textstring
, string
, 256);
4157 o_edit_hide_specific_text(w_current
,
4158 w_current
->toplevel
->page_current
->object_head
, string
);
4160 case GTK_RESPONSE_REJECT
:
4161 case GTK_RESPONSE_DELETE_EVENT
:
4162 gtk_widget_destroy(w_current
->thidewindow
);
4163 w_current
->thidewindow
= NULL
;
4166 printf("show_text_dialog_response(): strange signal %d\n",response
);
4170 /*! \brief Creates the hide text dialog
4171 * \par Function Description
4172 * This function creates the hide text dialog.
4174 void hide_text_dialog(GSCHEM_TOPLEVEL
* w_current
)
4176 GtkWidget
*label
= NULL
;
4177 GtkWidget
*textentry
;
4180 if (!w_current
->thidewindow
) {
4181 w_current
->thidewindow
= gschem_dialog_new_with_buttons(_("Hide Text"),
4182 GTK_WINDOW(w_current
->main_window
),
4183 0, /* not modal GTK_DIALOG_MODAL, */
4184 "hide-text", w_current
,
4186 GTK_RESPONSE_REJECT
,
4188 GTK_RESPONSE_ACCEPT
,
4191 /* Set the alternative button order (ok, cancel, help) for other systems */
4192 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->thidewindow
),
4193 GTK_RESPONSE_ACCEPT
,
4194 GTK_RESPONSE_REJECT
,
4197 gtk_window_position(GTK_WINDOW(w_current
->thidewindow
),
4200 gtk_signal_connect(GTK_OBJECT(w_current
->thidewindow
), "response",
4201 GTK_SIGNAL_FUNC(hide_text_dialog_response
),
4204 gtk_dialog_set_default_response(GTK_DIALOG(w_current
->thidewindow
),
4205 GTK_RESPONSE_ACCEPT
);
4207 gtk_container_border_width(GTK_CONTAINER(w_current
->thidewindow
),
4208 DIALOG_BORDER_SPACING
);
4209 vbox
= GTK_DIALOG(w_current
->thidewindow
)->vbox
;
4210 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
4212 label
= gtk_label_new(_("Hide text starting with:"));
4213 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
4214 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
4216 textentry
= gtk_entry_new_with_max_length(20);
4217 gtk_box_pack_start(GTK_BOX(vbox
), textentry
, FALSE
, FALSE
, 0);
4218 gtk_entry_set_activates_default(GTK_ENTRY(textentry
), TRUE
);
4219 gtk_widget_grab_focus(textentry
);
4221 GLADE_HOOKUP_OBJECT(w_current
->thidewindow
, textentry
, "textentry");
4222 gtk_widget_show_all(w_current
->thidewindow
);
4225 else { /* dialog already created, just select it */
4226 gtk_window_present(GTK_WINDOW(w_current
->thidewindow
));
4229 /* always select the text in the search entry */
4230 textentry
= g_object_get_data (G_OBJECT (w_current
->thidewindow
), "textentry");
4231 gtk_entry_set_text(GTK_ENTRY(textentry
), generic_textstring
);
4232 gtk_entry_select_region(GTK_ENTRY(textentry
), 0, -1);
4235 /*********** End of hide text dialog box *******/
4237 /*********** Start of show text dialog box *******/
4239 /*! \brief Response function for the show text dialog
4240 * \par Function Description
4241 * This function takes the users input and searches all strings starting with
4242 * the given search text and hides those text objects.
4244 void show_text_dialog_response(GtkWidget
*widget
, gint response
,
4245 GSCHEM_TOPLEVEL
*w_current
)
4247 GtkWidget
*textentry
;
4251 case GTK_RESPONSE_ACCEPT
:
4252 textentry
= g_object_get_data(G_OBJECT(w_current
->tshowwindow
),"textentry");
4253 string
= (gchar
*) gtk_entry_get_text(GTK_ENTRY(textentry
));
4255 strncpy(generic_textstring
, string
, 256);
4256 o_edit_show_specific_text(w_current
,
4257 w_current
->toplevel
->page_current
->object_head
, string
);
4259 case GTK_RESPONSE_REJECT
:
4260 case GTK_RESPONSE_DELETE_EVENT
:
4261 gtk_widget_destroy(w_current
->tshowwindow
);
4262 w_current
->tshowwindow
= NULL
;
4265 printf("show_text_dialog_response(): strange signal %d\n",response
);
4269 /*! \brief Create the show text dialog.
4270 * \par Function Description
4271 * This function creates the show text dialog.
4273 void show_text_dialog(GSCHEM_TOPLEVEL
* w_current
)
4275 GtkWidget
*label
= NULL
;
4276 GtkWidget
*textentry
;
4279 if (!w_current
->tshowwindow
) {
4280 w_current
->tshowwindow
= gschem_dialog_new_with_buttons(_("Show Text"),
4281 GTK_WINDOW(w_current
->main_window
),
4282 0, /* not modal GTK_DIALOG_MODAL, */
4283 "show-text", w_current
,
4285 GTK_RESPONSE_REJECT
,
4287 GTK_RESPONSE_ACCEPT
,
4290 /* Set the alternative button order (ok, cancel, help) for other systems */
4291 gtk_dialog_set_alternative_button_order(GTK_DIALOG(w_current
->tshowwindow
),
4292 GTK_RESPONSE_ACCEPT
,
4293 GTK_RESPONSE_REJECT
,
4296 gtk_window_position(GTK_WINDOW(w_current
->tshowwindow
),
4299 gtk_signal_connect(GTK_OBJECT(w_current
->tshowwindow
), "response",
4300 GTK_SIGNAL_FUNC(show_text_dialog_response
),
4303 gtk_dialog_set_default_response(GTK_DIALOG(w_current
->tshowwindow
),
4304 GTK_RESPONSE_ACCEPT
);
4306 gtk_container_border_width(GTK_CONTAINER(w_current
->tshowwindow
),
4307 DIALOG_BORDER_SPACING
);
4308 vbox
= GTK_DIALOG(w_current
->tshowwindow
)->vbox
;
4309 gtk_box_set_spacing(GTK_BOX(vbox
), DIALOG_V_SPACING
);
4311 label
= gtk_label_new(_("Show text starting with:"));
4312 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
4313 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
4315 textentry
= gtk_entry_new_with_max_length(20);
4316 gtk_box_pack_start(GTK_BOX(vbox
), textentry
, FALSE
, FALSE
, 0);
4317 gtk_entry_set_activates_default(GTK_ENTRY(textentry
), TRUE
);
4318 gtk_widget_grab_focus(textentry
);
4320 GLADE_HOOKUP_OBJECT(w_current
->tshowwindow
, textentry
, "textentry");
4321 gtk_widget_show_all(w_current
->tshowwindow
);
4324 else { /* dialog already created. Show it */
4325 gtk_window_present(GTK_WINDOW(w_current
->tshowwindow
));
4328 /* always select the text in the entry */
4329 textentry
= g_object_get_data (G_OBJECT (w_current
->tshowwindow
), "textentry");
4330 gtk_entry_set_text(GTK_ENTRY(textentry
), generic_textstring
);
4331 gtk_entry_select_region(GTK_ENTRY(textentry
), 0, -1);
4334 /*********** End of show text dialog box *******/
4336 /*********** Start of some Gtk utils *******/
4338 /*! \brief Selects all text in a TextView widget
4339 * \par Function Description
4340 * The function selects all the text in a TextView widget.
4342 void select_all_text_in_textview(GtkTextView
*textview
)
4344 GtkTextBuffer
*textbuffer
;
4345 GtkTextIter start
, end
;
4347 textbuffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview
));
4348 gtk_text_buffer_get_bounds (textbuffer
, &start
, &end
);
4349 gtk_text_buffer_select_range(textbuffer
, &start
, &end
);
4352 /*! \todo Finish function documentation!!!
4354 * \par Function Description
4357 int text_view_calculate_real_tab_width(GtkTextView
*textview
, int tab_size
)
4359 PangoLayout
*layout
;
4366 tab_string
= g_strnfill (tab_size
, ' ');
4368 layout
= gtk_widget_create_pango_layout (
4369 GTK_WIDGET (textview
),
4371 g_free (tab_string
);
4373 if (layout
!= NULL
) {
4374 pango_layout_get_pixel_size (layout
, &tab_width
, NULL
);
4375 g_object_unref (G_OBJECT (layout
));
4383 /*********** End of some Gtk utils *******/
4385 /*********** Start of major symbol changed dialog box *******/
4387 /*! \todo Finish function documentation!!!
4389 * \par Function Description
4392 void major_changed_dialog(GSCHEM_TOPLEVEL
* w_current
)
4395 char* refdes_string
= NULL
;
4398 if (w_current
->toplevel
->major_changed_refdes
) {
4400 GList
* current
= w_current
->toplevel
->major_changed_refdes
;
4403 char *value
= (char*) current
->data
;
4407 refdes_string
= g_strdup (value
);
4409 tmp
= g_strconcat (refdes_string
, "\n", value
, NULL
);
4410 g_free(refdes_string
);
4411 refdes_string
= tmp
;
4414 current
= g_list_next(current
);
4417 tmp
= g_strconcat (refdes_string
,
4418 "\n\nBe sure to verify each of these symbols!",
4420 g_free(refdes_string
);
4421 refdes_string
= tmp
;
4423 dialog
= gtk_message_dialog_new ((GtkWindow
*) w_current
->main_window
,
4424 GTK_DIALOG_DESTROY_WITH_PARENT
,
4427 "Major symbol changes detected in refdes:\n\n%s\n",
4430 gtk_widget_show(dialog
);
4432 g_signal_connect_swapped (dialog
, "response",
4433 G_CALLBACK (gtk_widget_destroy
),
4436 g_free(refdes_string
);
4440 /*********** End of major symbol changed dialog box *******/
4442 /***************** Start of Close Confirmation dialog box ************/
4444 #define TYPE_CLOSE_CONFIRMATION_DIALOG (close_confirmation_dialog_get_type ())
4445 #define CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialog))
4446 #define CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4447 #define IS_CLOSE_CONFIRMATION_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLOSE_CONFIRMATION_DIALOG))
4448 #define IS_CLOSE_CONFIRMATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLOSE_CONFIRMATION_DIALOG))
4449 #define CLOSE_CONFIRMATION_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),TYPE_CLOSE_CONFIRMATION_DIALOG, CloseConfirmationDialogClass))
4452 typedef struct _CloseConfirmationDialog CloseConfirmationDialog
;
4453 typedef struct _CloseConfirmationDialogClass CloseConfirmationDialogClass
;
4455 struct _CloseConfirmationDialog
4459 GtkListStore
*store_unsaved_pages
;
4462 struct _CloseConfirmationDialogClass
4464 GtkDialogClass parent_class
;
4469 PROP_UNSAVED_PAGE
=1,
4481 static gpointer close_confirmation_dialog_parent_class
= NULL
;
4484 static void close_confirmation_dialog_class_init (CloseConfirmationDialogClass
*klass
);
4485 static void close_confirmation_dialog_init (CloseConfirmationDialog
*self
);
4486 static void close_confirmation_dialog_set_property (GObject
*object
,
4488 const GValue
*value
,
4490 static void close_confirmation_dialog_get_property (GObject
*object
,
4494 static GObject
* close_confirmation_dialog_constructor (GType type
,
4495 guint n_construct_properties
,
4496 GObjectConstructParam
*construct_params
);
4498 GList
*close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog
*dialog
);
4503 close_confirmation_dialog_get_type ()
4505 static GType close_confirmation_dialog_type
= 0;
4507 if (!close_confirmation_dialog_type
) {
4508 static const GTypeInfo close_confirmation_dialog_info
= {
4509 sizeof(CloseConfirmationDialogClass
),
4510 NULL
, /* base_init */
4511 NULL
, /* base_finalize */
4512 (GClassInitFunc
) close_confirmation_dialog_class_init
,
4513 NULL
, /* class_finalize */
4514 NULL
, /* class_data */
4515 sizeof(CloseConfirmationDialog
),
4516 0, /* n_preallocs */
4517 (GInstanceInitFunc
) close_confirmation_dialog_init
,
4520 close_confirmation_dialog_type
=
4521 g_type_register_static (GTK_TYPE_DIALOG
,
4522 "CloseConfirmationDialog",
4523 &close_confirmation_dialog_info
, 0);
4526 return close_confirmation_dialog_type
;
4530 close_confirmation_dialog_class_init (CloseConfirmationDialogClass
*klass
)
4532 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
4534 close_confirmation_dialog_parent_class
= g_type_class_peek_parent (klass
);
4536 gobject_class
->constructor
= close_confirmation_dialog_constructor
;
4537 gobject_class
->set_property
= close_confirmation_dialog_set_property
;
4538 gobject_class
->get_property
= close_confirmation_dialog_get_property
;
4540 g_object_class_install_property (
4541 gobject_class
, PROP_UNSAVED_PAGE
,
4542 g_param_spec_pointer ("unsaved-page",
4545 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
4546 g_object_class_install_property (
4547 gobject_class
, PROP_UNSAVED_PAGES
,
4548 g_param_spec_pointer ("unsaved-pages",
4551 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
4552 g_object_class_install_property (
4553 gobject_class
, PROP_SELECTED_PAGES
,
4554 g_param_spec_pointer ("selected-pages",
4562 close_confirmation_dialog_init (CloseConfirmationDialog
*self
)
4564 /* create model for treeview and populate */
4565 self
->store_unsaved_pages
= gtk_list_store_new (NUM_COLUMNS
,
4566 G_TYPE_BOOLEAN
, /* save? */
4567 G_TYPE_POINTER
); /* page */
4571 /*! \brief Returns the number of pages in the model.
4572 * \par Function Description
4573 * This function determines the number of pages with unsaved changes
4576 * \param in model The tree model.
4577 * \returns The number of pages with unsaved changes.
4580 count_pages (GtkTreeModel
*model
)
4585 gtk_tree_model_get_iter_first (model
, &iter
);
4587 gtk_tree_model_iter_next (model
, &iter
);
4593 /*! \brief Returns the name to use for the given page in the model.
4594 * \par Function Description
4595 * This function determines the text to be used to identify a
4596 * specific page from the model of pages with unsaved changes.
4598 * If <B>piter</B> is NULL, the name for the first page of the model
4599 * is returned. Otherwise, it returns the name for the page defined
4600 * by the pointed iterator.
4602 * The returned value must be freed by caller.
4604 * \param in model The tree model.
4605 * \param in piter A pointer on a GtkTreeIter of model or NULL.
4606 * \returns The name for the page.
4609 get_page_name (GtkTreeModel
*model
, GtkTreeIter
*piter
)
4614 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), NULL
);
4616 if (piter
== NULL
) {
4617 gtk_tree_model_get_iter_first (model
, &iter
);
4622 gtk_tree_model_get (model
, &iter
,
4625 g_assert (page
!= NULL
&& page
->page_filename
!= NULL
);
4626 return g_path_get_basename (page
->page_filename
);
4629 /*! \brief Sets the contents of the name cell in the treeview of dialog.
4630 * \par Function Description
4631 * This functions sets the cell of the treeview with the short name
4632 * of the page obtained with <B>get_page_name()</B>.
4634 * \param in tree_column A GtkTreeColumn.
4635 * \param in cell The GtkCellRenderer that is being rendered by
4637 * \param in tree_model The GtkTreeModel being rendered.
4638 * \param in iter A GtkTreeIter of the current row rendered.
4642 close_confirmation_dialog_set_page_name (GtkTreeViewColumn
*tree_column
,
4643 GtkCellRenderer
*cell
,
4644 GtkTreeModel
*tree_model
,
4650 page_name
= get_page_name (tree_model
, iter
);
4658 /*! \brief Callback function for the toggled signal of check box in treeview.
4659 * \par Function Description
4660 * This functions changes the value of the save column in the model
4661 * for the affected row when user toggles the check box in the
4664 * \param in cell_renderer The GtkCellRendererToggle.
4665 * \param in path The GtkTreePath to the concerned row in model.
4666 * \param in user The dialog as user data.
4669 close_confirmation_dialog_callback_renderer_toggled (GtkCellRendererToggle
*cell_renderer
,
4673 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (user_data
);
4674 GtkTreeModel
*model
;
4678 model
= GTK_TREE_MODEL (dialog
->store_unsaved_pages
);
4680 gtk_tree_model_get_iter_from_string (model
, &iter
, path
);
4681 gtk_tree_model_get (model
, &iter
,
4684 gtk_list_store_set (GTK_LIST_STORE (model
), &iter
,
4685 COLUMN_SAVE
, (save
!= TRUE
),
4690 /*! \brief Adds a treeview to confirmation dialog for selecting of pages.
4691 * \par Function Description
4692 * This function adds a treeview and caption to display the content
4693 * of the dialog model of pages with unsaved changes.
4695 * The treeview displays the page names with check boxes.
4697 * \param in dialog The dialog.
4698 * \returns A pointer on the GtkVBox to add to dialog.
4701 close_confirmation_dialog_build_page_list (CloseConfirmationDialog
*dialog
)
4703 GtkWidget
*vbox
, *scrolled_window
, *treeview
, *label
;
4704 GtkCellRenderer
*renderer
;
4705 GtkTreeViewColumn
*column
;
4708 /* place the treeview and its caption into their own box */
4709 vbox
= GTK_WIDGET (g_object_new (GTK_TYPE_VBOX
,
4711 "homogeneous", FALSE
,
4715 /* the list of pages with changes */
4716 /* - scrolled window as container for the treeview first */
4717 scrolled_window
= GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
4718 /* GtkScrolledWindow */
4719 "hscrollbar-policy", GTK_POLICY_AUTOMATIC
,
4720 "vscrollbar-policy", GTK_POLICY_AUTOMATIC
,
4721 "shadow-type", GTK_SHADOW_IN
,
4723 /* - then the treeview */
4724 /* create model for treeview and populate */
4725 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
4727 "enable-search", FALSE
,
4728 "headers-visible", FALSE
,
4729 "model", dialog
->store_unsaved_pages
,
4731 renderer
= gtk_cell_renderer_toggle_new ();
4732 g_signal_connect (renderer
, "toggled",
4734 close_confirmation_dialog_callback_renderer_toggled
),
4736 column
= gtk_tree_view_column_new_with_attributes ("Save?",
4738 "active", COLUMN_SAVE
,
4740 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
4742 renderer
= gtk_cell_renderer_text_new ();
4743 column
= GTK_TREE_VIEW_COLUMN (
4744 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
4745 /* GtkTreeViewColumn */
4748 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
4749 gtk_tree_view_column_set_cell_data_func (column
, renderer
,
4750 close_confirmation_dialog_set_page_name
,
4752 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
4754 gtk_container_add (GTK_CONTAINER (scrolled_window
), treeview
);
4756 gtk_box_pack_end (GTK_BOX (vbox
), scrolled_window
,
4759 /* the caption label above the list of pages */
4760 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
4766 "mnemonic-widget", treeview
,
4768 text
= _("S_elect the schematics you want to save:");
4769 gtk_label_set_text_with_mnemonic (GTK_LABEL (label
), text
);
4770 gtk_label_set_mnemonic_widget (GTK_LABEL (label
), treeview
);
4771 gtk_box_pack_start (GTK_BOX (vbox
), label
,
4778 close_confirmation_dialog_constructor (GType type
,
4779 guint n_construct_properties
,
4780 GObjectConstructParam
*construct_params
)
4783 CloseConfirmationDialog
*dialog
;
4784 GtkWidget
*hbox
, *image
, *vbox
, *label
;
4786 gboolean ret
, single_page
;
4789 /* chain up to constructor of parent class */
4791 G_OBJECT_CLASS (close_confirmation_dialog_parent_class
)->constructor (
4793 n_construct_properties
,
4795 dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
4797 g_object_set (dialog
,
4799 "has-separator", FALSE
,
4802 "skip-taskbar-hint", TRUE
,
4806 g_object_set (GTK_DIALOG (dialog
)->vbox
,
4810 g_object_set (GTK_DIALOG (dialog
)->action_area
,
4817 /* check if there is one or more than one page with changes */
4818 ret
= gtk_tree_model_get_iter_first (GTK_TREE_MODEL (
4819 dialog
->store_unsaved_pages
),
4822 single_page
= !gtk_tree_model_iter_next (GTK_TREE_MODEL (
4823 dialog
->store_unsaved_pages
),
4826 /* here starts the layout of the dialog */
4827 hbox
= GTK_WIDGET (g_object_new (GTK_TYPE_HBOX
,
4831 "homogeneous", FALSE
,
4836 image
= g_object_new (GTK_TYPE_IMAGE
,
4841 "stock", GTK_STOCK_DIALOG_WARNING
,
4842 "icon-size", GTK_ICON_SIZE_DIALOG
,
4844 gtk_box_pack_start (GTK_BOX (hbox
), image
,
4847 /* vertical box on the right hand side of the dialog */
4848 vbox
= GTK_WIDGET (g_object_new (GTK_TYPE_VBOX
,
4850 "homogeneous", FALSE
,
4859 page_name
= get_page_name (GTK_TREE_MODEL (dialog
->store_unsaved_pages
),
4861 tmp
= g_strdup_printf (
4862 _("Save the changes to schematic \"%s\" before closing?"),
4867 tmp
= g_strdup_printf (
4868 _("There are %d schematics with unsaved changes. "
4869 "Save changes before closing?"),
4870 count_pages (GTK_TREE_MODEL (dialog
->store_unsaved_pages
)));
4872 str
= g_strconcat ("<big><b>", tmp
, "</b></big>", NULL
);
4874 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
4885 gtk_box_pack_start (GTK_BOX (vbox
), label
,
4889 /* more than one page with changes, display each page and offer */
4890 /* the opportunity to save them before exiting */
4891 gtk_box_pack_start (GTK_BOX (vbox
),
4892 close_confirmation_dialog_build_page_list (dialog
),
4896 /* secondary label */
4897 str
= _("If you don't save, all your changes will be permanently lost.");
4898 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
4907 gtk_box_pack_start (GTK_BOX (vbox
), label
,
4911 gtk_box_pack_start (GTK_BOX (hbox
), vbox
,
4915 /* add buttons to dialog action area */
4916 gtk_dialog_add_buttons (GTK_DIALOG (dialog
),
4917 _("_Close without saving"), GTK_RESPONSE_NO
,
4918 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
4919 GTK_STOCK_SAVE
, GTK_RESPONSE_YES
,
4922 /* Set the alternative button order (ok, cancel, help) for other systems */
4923 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
4926 GTK_RESPONSE_CANCEL
,
4929 /* all done, let's show the contents of the dialog */
4930 gtk_widget_show_all (hbox
);
4932 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog
)->vbox
), hbox
,
4939 close_confirmation_dialog_set_property (GObject
*object
,
4941 const GValue
*value
,
4944 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
4949 switch(property_id
) {
4950 case PROP_UNSAVED_PAGE
:
4951 data
= g_value_get_pointer (value
);
4953 /* add single page to model */
4954 gtk_list_store_append (dialog
->store_unsaved_pages
,
4956 gtk_list_store_set (dialog
->store_unsaved_pages
,
4964 case PROP_UNSAVED_PAGES
:
4965 data
= g_value_get_pointer (value
);
4966 /* add set of pages to model */
4967 for (p_current
= (GList
*)data
;
4969 p_current
= g_list_next (p_current
)) {
4970 gtk_list_store_append (dialog
->store_unsaved_pages
,
4972 gtk_list_store_set (dialog
->store_unsaved_pages
,
4975 COLUMN_PAGE
, p_current
->data
,
4981 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
4987 close_confirmation_dialog_get_property (GObject
*object
,
4992 CloseConfirmationDialog
*dialog
= CLOSE_CONFIRMATION_DIALOG (object
);
4994 switch(property_id
) {
4995 case PROP_SELECTED_PAGES
:
4996 g_value_set_pointer (
4998 close_confirmation_dialog_get_selected_pages (dialog
));
5002 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
5007 /*! \brief Helps building a list of selected page to save.
5008 * \par Function Description
5009 * This is the <B>GtkTreeModelForeachFunc</B> for function
5010 * <B>close_confirmation_dialog_get_selected_pages()</B>.
5012 * It builds from the tree model a list of PAGEs for which a save
5013 * action has been requested. Each selected page is appended to the
5014 * GList pointed by <B>data</B>
5016 * \param in model The tree model.
5019 * \param in data A pointer on a GList* to fill.
5020 * \returns FALSE to continue walking the tree.
5023 get_selected_pages (GtkTreeModel
*model
,
5031 gtk_tree_model_get (model
, iter
,
5036 g_assert (page
!= NULL
);
5037 *(GList
**)data
= g_list_append (*(GList
**)data
, page
);
5043 /*! \brief Returns a list of the selected pages with changes to save.
5044 * \par Function Description
5045 * This function returns the pages that the user has selected in the
5046 * confirmation dialog.
5048 * The returned list must be freed.
5050 * \param in dialog The dialog.
5051 * \returns A GList of selected PAGE* in dialog.
5054 close_confirmation_dialog_get_selected_pages (CloseConfirmationDialog
*dialog
)
5056 GList
*selected
= NULL
;
5058 gtk_tree_model_foreach (GTK_TREE_MODEL (dialog
->store_unsaved_pages
),
5059 (GtkTreeModelForeachFunc
)get_selected_pages
,
5066 /*! \brief Asks for confirmation before closing a changed page.
5067 * \par Function Description
5068 * This function asks the user to confirm its closing order for
5069 * page <B>page</B> while it still has unsaved changes.
5071 * It displays a message dialog inviting the user to cancel the
5072 * closing, or to discard the changes or to save the changes to a
5075 * \param in toplevel The toplevel environment.
5076 * \param in page The page to close.
5079 x_dialog_close_changed_page (GSCHEM_TOPLEVEL
*w_current
, PAGE
*page
)
5084 g_return_if_fail (page
!= NULL
&& page
->CHANGED
);
5086 keep_page
= w_current
->toplevel
->page_current
;
5088 dialog
= GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG
,
5089 "unsaved-page", page
,
5091 /* set default response signal. This is usually triggered by the
5093 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
5096 switch (gtk_dialog_run (GTK_DIALOG (dialog
))) {
5097 case GTK_RESPONSE_NO
:
5098 /* action selected: close without saving */
5099 /* close the page, discard changes */
5100 x_window_close_page (w_current
, page
);
5104 case GTK_RESPONSE_YES
:
5105 /* action selected: save */
5106 s_toplevel_goto_page(w_current
->toplevel
, page
);
5107 i_callback_file_save(w_current
, 0, NULL
);
5108 /* has the page been really saved? */
5109 if (!page
->CHANGED
) {
5110 x_window_close_page (w_current
, page
);
5112 /* no, user has cancelled the save and page has changes */
5113 /* do not close page */
5116 case GTK_RESPONSE_CANCEL
:
5117 /* action selected: cancel */
5120 /* Hit when the user breaks out of the dialog with the escape key
5121 * or otherwise destroys the dialog window without a proper response */
5125 gtk_widget_destroy (dialog
);
5127 /* Switch back to the page we were on if it wasn't the one being closed */
5128 g_return_if_fail (keep_page
!= NULL
);
5129 if (keep_page
!= page
)
5130 s_toplevel_goto_page(w_current
->toplevel
, keep_page
);
5133 /*! \brief Asks for confirmation before closing a window.
5134 * \par Function Description
5135 * This function asks the user to confirm its closing order for
5138 * The user is given the possibility to save the pages that currently
5139 * have unsaved changes, if any.
5141 * It returns TRUE if the user really accepts the close of the
5142 * window. Otherwise the user has somehow cancelled and the window
5143 * must not be closed.
5145 * \param in toplevel The toplevel environment.
5146 * \returns TRUE if the window can be closed, FALSE otherwise.
5149 x_dialog_close_window (GSCHEM_TOPLEVEL
*w_current
)
5151 TOPLEVEL
*toplevel
= w_current
->toplevel
;
5156 GList
*unsaved_pages
, *p_unsaved
;
5157 gboolean ret
= FALSE
;
5159 keep_page
= toplevel
->page_current
;
5161 for ( iter
= geda_list_get_glist( toplevel
->pages
), unsaved_pages
= NULL
;
5163 iter
= g_list_next( iter
) ) {
5165 p_current
= (PAGE
*)iter
->data
;
5167 if (p_current
->CHANGED
) {
5168 unsaved_pages
= g_list_append (unsaved_pages
, (gpointer
)p_current
);
5172 if (unsaved_pages
== NULL
) {
5173 /* no page with unsaved changes, close window */
5177 dialog
= GTK_WIDGET (g_object_new (TYPE_CLOSE_CONFIRMATION_DIALOG
,
5178 "unsaved-pages", unsaved_pages
,
5181 gtk_window_set_transient_for (GTK_WINDOW (dialog
),
5182 GTK_WINDOW (w_current
->main_window
));
5184 g_list_free (unsaved_pages
);
5185 switch (gtk_dialog_run (GTK_DIALOG (dialog
))) {
5186 case GTK_RESPONSE_NO
:
5187 /* action selected: close without saving */
5188 /* discard changes, ok to close window */
5192 case GTK_RESPONSE_YES
:
5193 /* action selected: save */
5194 g_object_get (dialog
,
5195 "selected-pages", &unsaved_pages
,
5197 for (p_unsaved
= unsaved_pages
, ret
= TRUE
;
5199 p_unsaved
= g_list_next (p_unsaved
)) {
5200 p_current
= (PAGE
*)p_unsaved
->data
;
5202 s_toplevel_goto_page(toplevel
, p_current
);
5203 i_callback_file_save(w_current
, 0, NULL
);
5204 /* if user cancelled previous, do not close window */
5205 ret
&= !p_current
->CHANGED
;
5207 g_list_free (unsaved_pages
);
5210 case GTK_RESPONSE_CANCEL
:
5211 /* action selected: cancel */
5214 /* Hit when the user breaks out of the dialog with the escape key
5215 * or otherwise destroys the dialog window without a proper response */
5219 gtk_widget_destroy (dialog
);
5221 /* Switch back to the page we were on */
5222 g_return_val_if_fail (keep_page
!= NULL
, ret
);
5223 s_toplevel_goto_page(toplevel
, keep_page
);
5228 /***************** End of Close Confirmation dialog box **************/
5231 /***************** Start of misc helper dialog boxes **************/
5232 /*! \brief Validate the input attribute
5233 * \par Function Description
5234 * This function validates the attribute and if it isn't valid
5235 * pops up an error message box.
5237 * \param parent The parent window which spawned this dialog box.
5238 * \param attribute The attribute to be validated.
5239 * \returns TRUE if the attribute is valid, FALSE otherwise.
5241 int x_dialog_validate_attribute(GtkWindow
* parent
, char *attribute
)
5243 GtkWidget
* message_box
;
5245 /* validate the new attribute */
5246 if (!o_attrib_get_name_value(attribute
, NULL
, NULL
)) {
5247 message_box
= gtk_message_dialog_new_with_markup (parent
,
5248 GTK_DIALOG_DESTROY_WITH_PARENT
,
5251 _("<span weight=\"bold\" size=\"larger\">The input attribute \"%s\" is invalid\nPlease correct in order to continue</span>\n\nThe name and value must be non-empty.\nThe name cannot end with a space.\nThe value cannot start with a space."),
5253 gtk_window_set_title(GTK_WINDOW(message_box
), _("Invalid Attribute"));
5254 gtk_dialog_run (GTK_DIALOG (message_box
));
5255 gtk_widget_destroy (message_box
);
5260 /***************** End of misc helper dialog boxes **************/