1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2000 Ales V. Hvezda
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
29 #include <libgeda/libgeda.h>
31 #include "../include/globals.h"
32 #include "../include/prototype.h"
34 #ifdef HAVE_LIBDMALLOC
38 #include "../include/x_pagesel.h"
41 static void x_pagesel_callback_response (GtkDialog
*dialog
,
47 /*! \brief Open the page manager dialog.
48 * \par Function Description
49 * Opens the page manager dialog for <B>toplevel</B> if it is not already.
50 * In this last case, it raises the dialog.
52 * \param [in] toplevel The TOPLEVEL object to open page manager for.
54 void x_pagesel_open (TOPLEVEL
*toplevel
)
56 if (toplevel
->pswindow
== NULL
) {
57 toplevel
->pswindow
= GTK_WIDGET (g_object_new (TYPE_PAGESEL
,
61 g_signal_connect (toplevel
->pswindow
,
63 G_CALLBACK (x_pagesel_callback_response
),
66 gtk_widget_show (toplevel
->pswindow
);
68 gdk_window_raise (toplevel
->pswindow
->window
);
73 /*! \brief Close the page manager dialog.
74 * \par Function Description
75 * Closes the page manager dialog associated with <B>toplevel</B>.
77 * \param [in] toplevel The TOPLEVEL object to close page manager for.
79 void x_pagesel_close (TOPLEVEL
*toplevel
)
81 if (toplevel
->pswindow
) {
82 g_assert (IS_PAGESEL (toplevel
->pswindow
));
83 gtk_widget_destroy (toplevel
->pswindow
);
84 toplevel
->pswindow
= NULL
;
89 /*! \brief Update the list and status of <B>toplevel</B>'s pages.
90 * \par Function Description
91 * Updates the list and status of <B>toplevel</B>\'s pages if the page
92 * manager dialog is opened.
94 * \param [in] toplevel The TOPLEVEL object to update.
96 void x_pagesel_update (TOPLEVEL
*toplevel
)
98 if (toplevel
->pswindow
) {
99 g_assert (IS_PAGESEL (toplevel
->pswindow
));
100 pagesel_update (PAGESEL (toplevel
->pswindow
));
105 /*! \brief Callback for page manager response.
106 * \par Function Description
107 * Handles response <B>arg1</B> of the page manager dialog <B>dialog</B>.
109 * \param [in] dialog GtkDialog that issues callback.
110 * \param [in] arg1 Response argument of page manager dialog.
111 * \param [in] user_data Pointer to relevant TOPLEVEL structure.
113 static void x_pagesel_callback_response (GtkDialog
*dialog
,
117 TOPLEVEL
*toplevel
= (TOPLEVEL
*)user_data
;
120 case PAGESEL_RESPONSE_UPDATE
:
121 pagesel_update (PAGESEL (dialog
));
123 case GTK_RESPONSE_DELETE_EVENT
:
124 case PAGESEL_RESPONSE_CLOSE
:
125 g_assert (GTK_WIDGET (dialog
) == toplevel
->pswindow
);
126 gtk_widget_destroy (GTK_WIDGET (dialog
));
127 toplevel
->pswindow
= NULL
;
130 g_assert_not_reached ();
147 static void pagesel_class_init (PageselClass
*class);
148 static void pagesel_init (Pagesel
*pagesel
);
149 static void pagesel_set_property (GObject
*object
,
153 static void pagesel_get_property (GObject
*object
,
158 static void pagesel_popup_menu (Pagesel
*pagesel
,
159 GdkEventButton
*event
);
161 /*! \todo Finish function documentation!!!
163 * \par Function Description
166 static void pagesel_callback_selection_changed (GtkTreeSelection
*selection
,
171 Pagesel
*pagesel
= (Pagesel
*)user_data
;
175 if (!gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
179 toplevel
= pagesel
->toplevel
;
180 gtk_tree_model_get (model
, &iter
,
185 s_page_goto (toplevel
, page
);
186 i_set_filename (toplevel
, toplevel
->page_current
->page_filename
);
187 x_scrollbars_update (toplevel
);
188 o_redraw_all (toplevel
);
190 /* We would like to use the following call, but since it calls
191 * x_pagesel_update() it would cause an infinite loop.
193 /* x_window_set_current_page (toplevel, page); */
197 /*! \todo Finish function documentation!!!
199 * \par Function Description
202 static gboolean
pagesel_callback_button_pressed (GtkWidget
*widget
,
203 GdkEventButton
*event
,
206 Pagesel
*pagesel
= (Pagesel
*)user_data
;
207 gboolean ret
= FALSE
;
209 if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
210 pagesel_popup_menu (pagesel
, event
);
217 /*! \todo Finish function documentation!!!
219 * \par Function Description
222 static gboolean
pagesel_callback_popup_menu (GtkWidget
*widget
,
225 Pagesel
*pagesel
= (Pagesel
*)user_data
;
227 pagesel_popup_menu (pagesel
, NULL
);
232 #define DEFINE_POPUP_CALLBACK(name, action) \
234 pagesel_callback_popup_ ## name (GtkMenuItem *menuitem, \
235 gpointer user_data) \
237 i_callback_ ## action (PAGESEL (user_data)->toplevel, 0, NULL); \
240 DEFINE_POPUP_CALLBACK (new_page
, file_new
)
241 DEFINE_POPUP_CALLBACK (open_page
, file_open
)
242 DEFINE_POPUP_CALLBACK (save_page
, file_save
)
243 DEFINE_POPUP_CALLBACK (close_page
, page_close
)
244 DEFINE_POPUP_CALLBACK (discard_page
, page_discard
)
247 /*! \brief Popup context-sensitive menu.
248 * \par Function Description
249 * Pops up a context-sensitive menu.
251 * <B>event</B> can be NULL if the popup is triggered by a key binding
252 * instead of a mouse click.
254 * \param [in] pagesel The Pagesel object.
255 * \param [in] event Mouse click event info.
257 static void pagesel_popup_menu (Pagesel
*pagesel
,
258 GdkEventButton
*event
)
266 struct menuitem_t menuitems
[] = {
267 { N_("New Page"), G_CALLBACK (pagesel_callback_popup_new_page
) },
268 { N_("Open Page..."), G_CALLBACK (pagesel_callback_popup_open_page
) },
270 { N_("Save Page"), G_CALLBACK (pagesel_callback_popup_save_page
) },
271 { N_("Close Page"), G_CALLBACK (pagesel_callback_popup_close_page
) },
272 { N_("Discard Page"), G_CALLBACK (pagesel_callback_popup_discard_page
) },
274 struct menuitem_t
*tmp
;
277 gtk_tree_view_get_path_at_pos (pagesel
->treeview
,
280 &path
, NULL
, NULL
, NULL
)) {
281 GtkTreeSelection
*selection
;
282 selection
= gtk_tree_view_get_selection (pagesel
->treeview
);
283 gtk_tree_selection_unselect_all (selection
);
284 gtk_tree_selection_select_path (selection
, path
);
285 gtk_tree_path_free (path
);
288 /* create the context menu */
289 menu
= gtk_menu_new();
290 for (tmp
= menuitems
; tmp
->label
!= NULL
; tmp
++) {
292 if (g_strcasecmp (tmp
->label
, "-") == 0) {
293 menuitem
= gtk_separator_menu_item_new ();
295 menuitem
= gtk_menu_item_new_with_label (_(tmp
->label
));
296 g_signal_connect (menuitem
,
301 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), menuitem
);
303 gtk_widget_show_all (menu
);
304 /* make menu a popup menu */
305 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
,
306 (event
!= NULL
) ? event
->button
: 0,
307 gdk_event_get_time ((GdkEvent
*)event
));
311 /*! \todo Finish function documentation!!!
313 * \par Function Description
316 GType
pagesel_get_type()
318 static GType pagesel_type
= 0;
321 static const GTypeInfo pagesel_info
= {
322 sizeof(PageselClass
),
323 NULL
, /* base_init */
324 NULL
, /* base_finalize */
325 (GClassInitFunc
) pagesel_class_init
,
326 NULL
, /* class_finalize */
327 NULL
, /* class_data */
330 (GInstanceInitFunc
) pagesel_init
,
333 pagesel_type
= g_type_register_static (GTK_TYPE_DIALOG
,
341 /*! \todo Finish function documentation!!!
343 * \par Function Description
346 static void pagesel_class_init (PageselClass
*klass
)
348 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
350 gobject_class
->set_property
= pagesel_set_property
;
351 gobject_class
->get_property
= pagesel_get_property
;
353 g_object_class_install_property (
354 gobject_class
, PROP_TOPLEVEL
,
355 g_param_spec_pointer ("toplevel",
358 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
362 /*! \todo Finish function documentation!!!
364 * \par Function Description
367 static void pagesel_init (Pagesel
*pagesel
)
369 GtkWidget
*scrolled_win
, *treeview
, *label
;
371 GtkCellRenderer
*renderer
;
372 GtkTreeViewColumn
*column
;
373 GtkTreeSelection
*selection
;
375 /* dialog initialization */
376 g_object_set (G_OBJECT (pagesel
),
380 "type", GTK_WINDOW_TOPLEVEL
,
381 "title", _("Page Manager"),
382 "default-height", 180,
383 "default-width", 515,
385 "window-position", GTK_WIN_POS_NONE
,
386 "type-hint", GDK_WINDOW_TYPE_HINT_NORMAL
,
388 "has-separator", TRUE
,
391 /* create the model for the treeview */
392 store
= (GtkTreeModel
*)gtk_tree_store_new (NUM_COLUMNS
,
393 G_TYPE_POINTER
, /* page */
394 G_TYPE_STRING
, /* name */
395 G_TYPE_BOOLEAN
); /* changed */
397 /* create a scrolled window for the treeview */
398 scrolled_win
= GTK_WIDGET (
399 g_object_new (GTK_TYPE_SCROLLED_WINDOW
,
402 /* GtkScrolledWindow */
403 "hscrollbar-policy", GTK_POLICY_AUTOMATIC
,
404 "vscrollbar-policy", GTK_POLICY_ALWAYS
,
405 "shadow-type", GTK_SHADOW_ETCHED_IN
,
407 /* create the treeview */
408 treeview
= GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW
,
413 g_signal_connect (treeview
,
414 "button-press-event",
415 G_CALLBACK (pagesel_callback_button_pressed
),
417 g_signal_connect (treeview
,
419 G_CALLBACK (pagesel_callback_popup_menu
),
421 selection
= gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview
));
422 gtk_tree_selection_set_mode (selection
,
423 GTK_SELECTION_SINGLE
);
424 g_signal_connect (selection
,
426 G_CALLBACK (pagesel_callback_selection_changed
),
428 /* - first column: page name */
429 renderer
= GTK_CELL_RENDERER (
430 g_object_new (GTK_TYPE_CELL_RENDERER_TEXT
,
431 /* GtkCellRendererText */
434 column
= GTK_TREE_VIEW_COLUMN (
435 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
436 /* GtkTreeViewColumn */
437 "title", _("Filename"),
441 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
442 gtk_tree_view_column_add_attribute (column
, renderer
, "text", COLUMN_NAME
);
443 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
444 /* - second column: changed */
445 renderer
= GTK_CELL_RENDERER (
446 g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE
,
447 /* GtkCellRendererToggle */
448 "activatable", FALSE
,
450 column
= GTK_TREE_VIEW_COLUMN (
451 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN
,
452 /* GtkTreeViewColumn */
453 "title", _("Changed"),
454 "sizing", GTK_TREE_VIEW_COLUMN_FIXED
,
456 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
457 gtk_tree_view_column_add_attribute (column
, renderer
, "active", COLUMN_CHANGED
);
458 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview
), column
);
460 /* add the treeview to the scrolled window */
461 gtk_container_add (GTK_CONTAINER (scrolled_win
), treeview
);
462 /* set treeview of pagesel */
463 pagesel
->treeview
= GTK_TREE_VIEW (treeview
);
465 /* add the scrolled window to the dialog vbox */
466 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (pagesel
)->vbox
), scrolled_win
,
468 gtk_widget_show_all (scrolled_win
);
470 /* add a label below the scrolled window */
471 label
= GTK_WIDGET (g_object_new (GTK_TYPE_LABEL
,
473 "label", _("Right click on the filename for more options..."),
475 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (pagesel
)->vbox
), label
,
477 gtk_widget_show (label
);
479 /* now add buttons in the action area */
480 gtk_dialog_add_buttons (GTK_DIALOG (pagesel
),
481 /* - update button */
482 GTK_STOCK_REFRESH
, PAGESEL_RESPONSE_UPDATE
,
484 GTK_STOCK_CLOSE
, PAGESEL_RESPONSE_CLOSE
,
487 #if GTK_CHECK_VERSION (2,6,0)
488 /* Set the alternative button order (ok, cancel, help) for other systems */
489 gtk_dialog_set_alternative_button_order(GTK_DIALOG(pagesel
),
490 PAGESEL_RESPONSE_UPDATE
,
491 PAGESEL_RESPONSE_CLOSE
,
498 /*! \todo Finish function documentation!!!
500 * \par Function Description
503 static void pagesel_set_property (GObject
*object
,
508 Pagesel
*pagesel
= PAGESEL (object
);
510 switch(property_id
) {
512 pagesel
->toplevel
= (TOPLEVEL
*)g_value_get_pointer (value
);
513 pagesel_update (pagesel
);
516 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
521 /*! \todo Finish function documentation!!!
523 * \par Function Description
526 static void pagesel_get_property (GObject
*object
,
531 Pagesel
*pagesel
= PAGESEL (object
);
533 switch(property_id
) {
535 g_value_set_pointer (value
, (gpointer
)pagesel
->toplevel
);
538 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
543 /*! \brief Update tree model of <B>pagesel</B>'s treeview.
544 * \par Function Description
545 * Updates the tree model of <B>pagesel</B>\'s treeview.
547 * Right now, each time it is called, it rebuilds all the model from the
548 * list of page in the toplevel.
549 * It is a recursive function to populate the tree store
551 * \param [in] model GtkTreeModel to update.
552 * \param [in] parent GtkTreeIter pointer to tree root.
553 * \param [in] page The PAGE object to update tree model from.
555 static void add_page (GtkTreeModel
*model
, GtkTreeIter
*parent
,
561 /* add the page to the store */
562 gtk_tree_store_append (GTK_TREE_STORE (model
),
565 gtk_tree_store_set (GTK_TREE_STORE (model
),
568 COLUMN_NAME
, page
->page_filename
,
569 COLUMN_CHANGED
, page
->CHANGED
,
572 /* search a page that has a up field == p_current->pid */
573 for (p_current
= page
->next
;
575 p_current
= p_current
->next
) {
576 if (p_current
->up
== page
->pid
) {
577 add_page (model
, &iter
, p_current
);
583 /*! \todo Finish function documentation!!!
585 * \par Function Description
586 * Recursive function to select the current page in the treeview
589 static void select_page(GtkTreeView
*treeview
,
590 GtkTreeIter
*parent
, PAGE
*page
)
592 GtkTreeModel
*treemodel
= gtk_tree_view_get_model (treeview
);
596 if (!gtk_tree_model_iter_children (treemodel
, &iter
, parent
)) {
601 gtk_tree_model_get (treemodel
, &iter
,
602 COLUMN_PAGE
, &p_current
,
604 if (p_current
== page
) {
605 gtk_tree_view_expand_all (treeview
);
606 gtk_tree_selection_select_iter (
607 gtk_tree_view_get_selection (treeview
),
612 select_page (treeview
, &iter
, page
);
614 } while (gtk_tree_model_iter_next (treemodel
, &iter
));
618 /*! \todo Finish function documentation!!!
620 * \par Function Description
623 void pagesel_update (Pagesel
*pagesel
)
629 g_assert (IS_PAGESEL (pagesel
));
631 g_return_if_fail (pagesel
->toplevel
);
633 toplevel
= pagesel
->toplevel
;
634 model
= gtk_tree_view_get_model (pagesel
->treeview
);
636 /* wipe out every thing in the store */
637 gtk_tree_store_clear (GTK_TREE_STORE (model
));
639 for (p_current
= toplevel
->page_head
->next
;
641 p_current
= p_current
->next
) {
642 /* find every page that is not a hierarchy-down of another page */
643 if (p_current
->up
< 0 ||
644 s_hierarchy_find_page (toplevel
->page_head
->next
,
645 p_current
->up
) == NULL
) {
646 add_page (model
, NULL
, p_current
);
650 /* select the current page in the treeview */
651 select_page (pagesel
->treeview
, NULL
, toplevel
->page_current
);
655 * This function was in the noweb file, but was not referenced.
656 * Create a gtk button with a custom label <B>text</B> and a stock
658 * <B>text</B>: The mnemonic text for the label.
659 * <B>stock</B>: The name of the stock item to get the icon from.
661 * Return value: The widget.
662 * Taken from evolution code:
663 * http://lists.ximian.com/archives/public/evolution-patches/2003-April/000088.html
665 /*! \todo Finish function documentation!!!
667 * \par Function Description
671 GtkWidget *e_gtk_button_new_with_icon(const char *text, const char *stock)
673 GtkWidget *button, *label;
676 button = gtk_button_new();
677 label = gtk_label_new_with_mnemonic(text);
678 gtk_label_set_mnemonic_widget((GtkLabel *)label, button);
680 if (gtk_stock_lookup(stock, &item)) {
681 GtkWidget *image, *hbox, *align;
683 image = gtk_image_new_from_stock(stock, GTK_ICON_SIZE_BUTTON);
684 hbox = gtk_hbox_new(FALSE, 2);
685 align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
686 gtk_box_pack_start((GtkBox *)hbox, image, FALSE, FALSE, 0);
687 gtk_box_pack_end((GtkBox *)hbox, label, FALSE, FALSE, 0);
688 gtk_container_add((GtkContainer *)align, hbox);
689 gtk_container_add((GtkContainer *)button, align);
690 gtk_widget_show_all(align);
692 gtk_misc_set_alignment((GtkMisc *)label, 0.5, 0.5);
693 gtk_container_add((GtkContainer *)button, label);
694 gtk_widget_show(label);