Fix lockup when a scroll event is received outside the drawing area
[geda-pcb/pcjc2.git] / src / hid / gtk / gui-library-window.c
blob1d22dd428d987508891f22a9b0cccbdbb6864833
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* This file originally from the PCB Gtk port by Bill Wilson. It has
28 * since been combined with modified code from the gEDA project:
30 * gschem/src/ghid_library_window.c, checked out by Peter Clifton
31 * from gEDA/gaf commit 72581a91da08c9d69593c24756144fc18940992e
32 * on 3rd Jan, 2008.
34 * gEDA - GPL Electronic Design Automation
35 * gschem - gEDA Schematic Capture
36 * Copyright (C) 1998-2007 Ales Hvezda
37 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
39 * This program is free software; you can redistribute it and/or modify
40 * it under the terms of the GNU General Public License as published by
41 * the Free Software Foundation; either version 2 of the License, or
42 * (at your option) any later version.
44 * This program is distributed in the hope that it will be useful,
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 * GNU General Public License for more details.
49 * You should have received a copy of the GNU General Public License
50 * along with this program; if not, write to the Free Software
51 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
58 #include "gui.h"
59 #include "global.h"
60 #include "buffer.h"
61 #include "data.h"
62 #include "set.h"
64 #include <gdk/gdkkeysyms.h>
66 #ifdef HAVE_LIBDMALLOC
67 #include <dmalloc.h>
68 #endif
70 static GtkWidget *library_window;
72 #include "gui-pinout-preview.h"
73 #include "gui-library-window.h"
75 /*! \def LIBRARY_FILTER_INTERVAL
76 * \brief The time interval between request and actual filtering
78 * This constant is the time-lag between user modifications in the
79 * filter entry and the actual evaluation of the filter which
80 * ultimately update the display. It helps reduce the frequency of
81 * evaluation of the filter as user types.
83 * Unit is milliseconds.
85 #define LIBRARY_FILTER_INTERVAL 200
88 static gint
89 library_window_configure_event_cb (GtkWidget * widget, GdkEventConfigure * ev,
90 gpointer data)
92 GtkAllocation allocation;
94 gtk_widget_get_allocation (widget, &allocation);
95 ghidgui->library_window_width = allocation.width;
96 ghidgui->library_window_height = allocation.height;
97 ghidgui->config_modified = TRUE;
98 return FALSE;
102 enum
104 MENU_NAME_COLUMN, /* Text to display in the tree */
105 MENU_LIBRARY_COLUMN, /* Pointer to the LibraryMenuType */
106 MENU_ENTRY_COLUMN, /* Pointer to the LibraryEntryType */
107 N_MENU_COLUMNS
111 /*! \brief Process the response returned by the library dialog.
112 * \par Function Description
113 * This function handles the response <B>arg1</B> of the library
114 * dialog <B>dialog</B>.
116 * Parameter <B>user_data</B> is a pointer on the relevant toplevel
117 * structure.
119 * \param [in] dialog The library dialog.
120 * \param [in] arg1 The response ID.
121 * \param [in] user_data
123 static void
124 library_window_callback_response (GtkDialog * dialog,
125 gint arg1, gpointer user_data)
127 switch (arg1)
129 case GTK_RESPONSE_CLOSE:
130 case GTK_RESPONSE_DELETE_EVENT:
131 gtk_widget_destroy (GTK_WIDGET (library_window));
132 library_window = NULL;
133 break;
135 default:
136 /* Do nothing, in case there's another handler function which
137 can handle the response ID received. */
138 break;
143 /*! \brief Creates a library dialog.
144 * \par Function Description
145 * This function create the library dialog if it is not already created.
146 * It does not show the dialog, use ghid_library_window_show for that.
149 void
150 ghid_library_window_create (GHidPort * out)
152 GtkWidget *current_tab, *entry_filter;
153 GtkNotebook *notebook;
155 if (library_window)
156 return;
158 library_window = (GtkWidget *)g_object_new (GHID_TYPE_LIBRARY_WINDOW, NULL);
160 g_signal_connect (library_window,
161 "response",
162 G_CALLBACK (library_window_callback_response), NULL);
163 g_signal_connect (G_OBJECT (library_window), "configure_event",
164 G_CALLBACK (library_window_configure_event_cb), NULL);
165 gtk_window_set_default_size (GTK_WINDOW (library_window),
166 ghidgui->library_window_width,
167 ghidgui->library_window_height);
169 gtk_window_set_title (GTK_WINDOW (library_window), _("PCB Library"));
170 gtk_window_set_wmclass (GTK_WINDOW (library_window), "PCB_Library",
171 "PCB");
173 gtk_widget_realize (library_window);
174 if (Settings.AutoPlace)
175 gtk_window_move (GTK_WINDOW (library_window), 10, 10);
177 gtk_editable_select_region (GTK_EDITABLE
178 (GHID_LIBRARY_WINDOW (library_window)->
179 entry_filter), 0, -1);
181 /* Set the focus to the filter entry only if it is in the current
182 displayed tab */
183 notebook = GTK_NOTEBOOK (GHID_LIBRARY_WINDOW (library_window)->viewtabs);
184 current_tab = gtk_notebook_get_nth_page (notebook,
185 gtk_notebook_get_current_page
186 (notebook));
187 entry_filter =
188 GTK_WIDGET (GHID_LIBRARY_WINDOW (library_window)->entry_filter);
189 if (gtk_widget_is_ancestor (entry_filter, current_tab))
191 gtk_widget_grab_focus (entry_filter);
195 /*! \brief Show the library dialog.
196 * \par Function Description
197 * This function show the library dialog, creating it if it is not
198 * already created, and presents it to the user (brings it to the
199 * front with focus).
201 void
202 ghid_library_window_show (GHidPort * out, gboolean raise)
204 ghid_library_window_create (out);
205 gtk_widget_show_all (library_window);
206 if (raise)
207 gtk_window_present (GTK_WINDOW(library_window));
210 static GObjectClass *library_window_parent_class = NULL;
213 /*! \brief Determines visibility of items of the library treeview.
214 * \par Function Description
215 * This is the function used to filter entries of the footprint
216 * selection tree.
218 * \param [in] model The current selection in the treeview.
219 * \param [in] iter An iterator on a footprint or folder in the tree.
220 * \param [in] data The library dialog.
221 * \returns TRUE if item should be visible, FALSE otherwise.
223 static gboolean
224 lib_model_filter_visible_func (GtkTreeModel * model,
225 GtkTreeIter * iter, gpointer data)
227 GhidLibraryWindow *library_window = (GhidLibraryWindow *) data;
228 const gchar *compname;
229 gchar *compname_upper, *text_upper, *pattern;
230 const gchar *text;
231 gboolean ret;
233 g_assert (GHID_IS_LIBRARY_WINDOW (data));
235 text = gtk_entry_get_text (library_window->entry_filter);
236 if (g_ascii_strcasecmp (text, "") == 0)
238 return TRUE;
241 /* If this is a source, only display it if it has children that
242 * match */
243 if (gtk_tree_model_iter_has_child (model, iter))
245 GtkTreeIter iter2;
247 gtk_tree_model_iter_children (model, &iter2, iter);
248 ret = FALSE;
251 if (lib_model_filter_visible_func (model, &iter2, data))
253 ret = TRUE;
254 break;
257 while (gtk_tree_model_iter_next (model, &iter2));
259 else
261 gtk_tree_model_get (model, iter, MENU_NAME_COLUMN, &compname, -1);
262 /* Do a case insensitive comparison, converting the strings
263 to uppercase */
264 compname_upper = g_ascii_strup (compname, -1);
265 text_upper = g_ascii_strup (text, -1);
266 pattern = g_strconcat ("*", text_upper, "*", NULL);
267 ret = g_pattern_match_simple (pattern, compname_upper);
268 g_free (compname_upper);
269 g_free (text_upper);
270 g_free (pattern);
273 return ret;
277 /*! \brief Handles activation (e.g. double-clicking) of a component row
278 * \par Function Description
279 * Component row activated handler:
280 * As a convenince to the user, expand / contract any node with children.
282 * \param [in] tree_view The component treeview.
283 * \param [in] path The GtkTreePath to the activated row.
284 * \param [in] column The GtkTreeViewColumn in which the activation occurre
285 * \param [in] user_data The component selection dialog.
287 static void
288 tree_row_activated (GtkTreeView *tree_view,
289 GtkTreePath *path,
290 GtkTreeViewColumn *column,
291 gpointer user_data)
293 GtkTreeModel *model;
294 GtkTreeIter iter;
296 model = gtk_tree_view_get_model (tree_view);
297 gtk_tree_model_get_iter (model, &iter, path);
299 if (!gtk_tree_model_iter_has_child (model, &iter))
300 return;
302 if (gtk_tree_view_row_expanded (tree_view, path))
303 gtk_tree_view_collapse_row (tree_view, path);
304 else
305 gtk_tree_view_expand_row (tree_view, path, FALSE);
308 /*! \brief Handles CTRL-C keypress in the TreeView
309 * \par Function Description
310 * Keypress activation handler:
311 * If CTRL-C is pressed, copy footprint name into the clipboard.
313 * \param [in] tree_view The component treeview.
314 * \param [in] event The GdkEventKey with keypress info.
315 * \param [in] user_data Not used.
316 * \return TRUE if CTRL-C event was handled, FALSE otherwise.
318 static gboolean
319 tree_row_key_pressed (GtkTreeView *tree_view,
320 GdkEventKey *event,
321 gpointer user_data)
323 GtkTreeSelection *selection;
324 GtkTreeModel *model;
325 GtkTreeIter iter;
326 GtkClipboard *clipboard;
327 const gchar *compname;
328 guint default_mod_mask = gtk_accelerator_get_default_mod_mask();
330 /* Handle both lower- and uppercase `c' */
331 if (((event->state & default_mod_mask) != GDK_CONTROL_MASK)
332 || ((event->keyval != GDK_c) && (event->keyval != GDK_C)))
333 return FALSE;
335 selection = gtk_tree_view_get_selection (tree_view);
336 g_return_val_if_fail (selection != NULL, TRUE);
338 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
339 return TRUE;
341 gtk_tree_model_get (model, &iter, MENU_NAME_COLUMN, &compname, -1);
343 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
344 g_return_val_if_fail (clipboard != NULL, TRUE);
346 gtk_clipboard_set_text (clipboard, compname, -1);
348 return TRUE;
351 /*! \brief Handles changes in the treeview selection.
352 * \par Function Description
353 * This is the callback function that is called every time the user
354 * select a row the library treeview of the dialog.
356 * If the selection is not a selection of a footprint, it does
357 * nothing. Otherwise it updates the preview and Element data.
359 * \param [in] selection The current selection in the treeview.
360 * \param [in] user_data The library dialog.
362 static void
363 library_window_callback_tree_selection_changed (GtkTreeSelection * selection,
364 gpointer user_data)
366 GtkTreeModel *model;
367 GtkTreeIter iter;
368 GhidLibraryWindow *library_window = (GhidLibraryWindow *) user_data;
369 LibraryEntryType *entry = NULL;
370 gchar *m4_args;
372 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
373 return;
375 gtk_tree_model_get (model, &iter, MENU_ENTRY_COLUMN, &entry, -1);
377 if (entry == NULL)
378 return;
380 /* -1 flags this is an element file part and the file path is in
381 | entry->AllocateMemory.
383 if (entry->Template == (char *) -1)
385 if (LoadElementToBuffer (PASTEBUFFER, entry->AllocatedMemory, true))
387 SetMode (PASTEBUFFER_MODE);
388 goto out;
390 return;
393 /* Otherwise, it's a m4 element and we need to create a string of
394 | macro arguments to be passed to the library command in
395 | LoadElementToBuffer()
397 m4_args = g_strdup_printf ("'%s' '%s' '%s'", EMPTY (entry->Template),
398 EMPTY (entry->Value), EMPTY (entry->Package));
400 if (LoadElementToBuffer (PASTEBUFFER, m4_args, false))
402 SetMode (PASTEBUFFER_MODE);
403 g_free (m4_args);
404 goto out;
407 g_free (m4_args);
408 return;
410 out:
412 /* update the preview with new symbol data */
413 g_object_set (library_window->preview,
414 "element-data", PASTEBUFFER->Data->Element->data, NULL);
417 /*! \brief Requests re-evaluation of the filter.
418 * \par Function Description
419 * This is the timeout function for the filtering of footprint
420 * in the tree of the dialog.
422 * The timeout this callback is attached to is removed after the
423 * function.
425 * \param [in] data The library dialog.
426 * \returns FALSE to remove the timeout.
428 static gboolean
429 library_window_filter_timeout (gpointer data)
431 GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (data);
432 GtkTreeModel *model;
434 /* resets the source id in library_window */
435 library_window->filter_timeout = 0;
437 model = gtk_tree_view_get_model (library_window->libtreeview);
439 if (model != NULL)
441 const gchar *text = gtk_entry_get_text (library_window->entry_filter);
442 gtk_tree_model_filter_refilter ((GtkTreeModelFilter *) model);
443 if (strcmp (text, "") != 0)
445 /* filter text not-empty */
446 gtk_tree_view_expand_all (library_window->libtreeview);
447 } else {
448 /* filter text is empty, collapse expanded tree */
449 gtk_tree_view_collapse_all (library_window->libtreeview);
453 /* return FALSE to remove the source */
454 return FALSE;
457 /*! \brief Callback function for the changed signal of the filter entry.
458 * \par Function Description
459 * This function monitors changes in the entry filter of the dialog.
461 * It specifically manages the sensitivity of the clear button of the
462 * entry depending on its contents. It also requests an update of the
463 * footprint list by re-evaluating filter at every changes.
465 * \param [in] editable The filter text entry.
466 * \param [in] user_data The library dialog.
468 static void
469 library_window_callback_filter_entry_changed (GtkEditable * editable,
470 gpointer user_data)
472 GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
473 GtkWidget *button;
474 gboolean sensitive;
476 /* turns button off if filter entry is empty */
477 /* turns it on otherwise */
478 button = GTK_WIDGET (library_window->button_clear);
479 sensitive =
480 (g_ascii_strcasecmp (gtk_entry_get_text (library_window->entry_filter),
481 "") != 0);
482 gtk_widget_set_sensitive (button, sensitive);
484 /* Cancel any pending update of the footprint list filter */
485 if (library_window->filter_timeout != 0)
486 g_source_remove (library_window->filter_timeout);
488 /* Schedule an update of the footprint list filter in
489 * LIBRARY_FILTER_INTERVAL milliseconds */
490 library_window->filter_timeout = g_timeout_add (LIBRARY_FILTER_INTERVAL,
491 library_window_filter_timeout,
492 library_window);
496 /*! \brief Handles a click on the clear button.
497 * \par Function Description
498 * This is the callback function called every time the user press the
499 * clear button associated with the filter.
501 * It resets the filter entry, indirectly causing re-evaluation
502 * of the filter on the list of symbols to update the display.
504 * \param [in] editable The filter text entry.
505 * \param [in] user_data The library dialog.
507 static void
508 library_window_callback_filter_button_clicked (GtkButton * button,
509 gpointer user_data)
511 GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
513 /* clears text in text entry for filter */
514 gtk_entry_set_text (library_window->entry_filter, "");
518 /* \brief Create the tree model for the "Library" view.
519 * \par Function Description
520 * Creates a tree where the branches are the available library
521 * sources and the leaves are the footprints.
523 static GtkTreeModel *
524 create_lib_tree_model (GhidLibraryWindow * library_window)
526 GtkTreeStore *tree;
527 GtkTreeIter iter, p_iter, e_iter, c_iter;
528 gchar *name;
529 gboolean exists;
531 tree = gtk_tree_store_new (N_MENU_COLUMNS,
532 G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
534 MENU_LOOP (&Library);
536 /* Watch for directory changes of library parts and create new
537 | parent iter at each change.
539 if (!menu->directory) /* Shouldn't happen */
540 menu->directory = g_strdup ("???");
542 exists = FALSE;
543 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &e_iter))
546 gtk_tree_model_get (GTK_TREE_MODEL (tree), &e_iter,
547 MENU_NAME_COLUMN, &name, -1);
548 if (!strcmp (name, menu->directory))
550 exists = TRUE;
551 break;
554 while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tree), &e_iter));
556 if (exists)
557 p_iter = e_iter;
558 else
560 gtk_tree_store_append (tree, &p_iter, NULL);
561 gtk_tree_store_set (tree, &p_iter,
562 MENU_NAME_COLUMN, menu->directory,
563 MENU_LIBRARY_COLUMN, NULL,
564 MENU_ENTRY_COLUMN, NULL, -1);
566 gtk_tree_store_append (tree, &iter, &p_iter);
567 gtk_tree_store_set (tree, &iter,
568 MENU_NAME_COLUMN, menu->Name,
569 MENU_LIBRARY_COLUMN, menu,
570 MENU_ENTRY_COLUMN, NULL, -1);
571 ENTRY_LOOP (menu);
573 gtk_tree_store_append (tree, &c_iter, &iter);
574 gtk_tree_store_set (tree, &c_iter,
575 MENU_NAME_COLUMN, entry->ListEntry,
576 MENU_LIBRARY_COLUMN, menu,
577 MENU_ENTRY_COLUMN, entry, -1);
579 END_LOOP;
582 END_LOOP;
584 return (GtkTreeModel *) tree;
588 #if 0
589 /* \brief On-demand refresh of the footprint library.
590 * \par Function Description
591 * Requests a rescan of the footprint library in order to pick up any
592 * new signals, and then updates the library window.
594 static void
595 library_window_callback_refresh_library (GtkButton * button,
596 gpointer user_data)
598 GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (user_data);
599 GtkTreeModel *model;
601 /* Rescan the libraries for symbols */
602 /* TODO: How do we do this in PCB? */
604 /* Refresh the "Library" view */
605 model = (GtkTreeModel *)
606 g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
607 "child-model", create_lib_tree_model (library_window),
608 "virtual-root", NULL, NULL);
610 gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter *) model,
611 lib_model_filter_visible_func,
612 library_window, NULL);
614 gtk_tree_view_set_model (library_window->libtreeview, model);
616 #endif
619 /*! \brief Creates the treeview for the "Library" view */
620 static GtkWidget *
621 create_lib_treeview (GhidLibraryWindow * library_window)
623 GtkWidget *libtreeview, *vbox, *scrolled_win, *label,
624 *hbox, *entry, *button;
625 GtkTreeModel *child_model, *model;
626 GtkTreeSelection *selection;
627 GtkCellRenderer *renderer;
628 GtkTreeViewColumn *column;
630 /* -- library selection view -- */
632 /* vertical box for footprint selection and search entry */
633 vbox = GTK_WIDGET (g_object_new (GTK_TYPE_VBOX,
634 /* GtkContainer */
635 "border-width", 5,
636 /* GtkBox */
637 "homogeneous", FALSE, "spacing", 5, NULL));
639 child_model = create_lib_tree_model (library_window);
640 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (child_model),
641 MENU_NAME_COLUMN, GTK_SORT_ASCENDING);
642 model = (GtkTreeModel *) g_object_new (GTK_TYPE_TREE_MODEL_FILTER,
643 "child-model", child_model,
644 "virtual-root", NULL, NULL);
646 scrolled_win = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
647 /* GtkScrolledWindow */
648 "hscrollbar-policy",
649 GTK_POLICY_AUTOMATIC,
650 "vscrollbar-policy",
651 GTK_POLICY_ALWAYS, "shadow-type",
652 GTK_SHADOW_ETCHED_IN, NULL));
653 /* create the treeview */
654 libtreeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
655 /* GtkTreeView */
656 "model", model,
657 "rules-hint", TRUE,
658 "headers-visible", FALSE, NULL));
660 g_signal_connect (libtreeview,
661 "row-activated",
662 G_CALLBACK (tree_row_activated),
663 NULL);
665 g_signal_connect (libtreeview,
666 "key-press-event",
667 G_CALLBACK (tree_row_key_pressed),
668 NULL);
670 /* connect callback to selection */
671 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (libtreeview));
672 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
673 g_signal_connect (selection,
674 "changed",
675 G_CALLBACK
676 (library_window_callback_tree_selection_changed),
677 library_window);
679 /* insert a column to treeview for library/symbol name */
680 renderer = GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
681 /* GtkCellRendererText */
682 "editable", FALSE, NULL));
683 column = GTK_TREE_VIEW_COLUMN (g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
684 /* GtkTreeViewColumn */
685 "title", _("Components"),
686 NULL));
687 gtk_tree_view_column_pack_start (column, renderer, TRUE);
688 gtk_tree_view_column_set_attributes (column, renderer,
689 "text", MENU_NAME_COLUMN, NULL);
690 gtk_tree_view_append_column (GTK_TREE_VIEW (libtreeview), column);
692 /* add the treeview to the scrolled window */
693 gtk_container_add (GTK_CONTAINER (scrolled_win), libtreeview);
694 /* set directory/footprint treeview of library_window */
695 library_window->libtreeview = GTK_TREE_VIEW (libtreeview);
697 /* add the scrolled window for directories to the vertical box */
698 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
701 /* -- filter area -- */
702 hbox = GTK_WIDGET (g_object_new (GTK_TYPE_HBOX,
703 /* GtkBox */
704 "homogeneous", FALSE, "spacing", 3, NULL));
706 /* create the entry label */
707 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
708 /* GtkMisc */
709 "xalign", 0.0,
710 /* GtkLabel */
711 "label", _("Filter:"), NULL));
712 /* add the search label to the filter area */
713 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
715 /* create the text entry for filter in footprints */
716 entry = GTK_WIDGET (g_object_new (GTK_TYPE_ENTRY,
717 /* GtkEntry */
718 "text", "", NULL));
719 g_signal_connect (entry,
720 "changed",
721 G_CALLBACK (library_window_callback_filter_entry_changed),
722 library_window);
724 /* now that that we have an entry, set the filter func of model */
725 gtk_tree_model_filter_set_visible_func ((GtkTreeModelFilter *) model,
726 lib_model_filter_visible_func,
727 library_window, NULL);
729 /* add the filter entry to the filter area */
730 gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
731 /* set filter entry of library_window */
732 library_window->entry_filter = GTK_ENTRY (entry);
733 /* and init the event source for footprint filter */
734 library_window->filter_timeout = 0;
736 /* create the erase button for filter entry */
737 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
738 /* GtkWidget */
739 "sensitive", FALSE,
740 /* GtkButton */
741 "relief", GTK_RELIEF_NONE, NULL));
743 gtk_container_add (GTK_CONTAINER (button),
744 gtk_image_new_from_stock (GTK_STOCK_CLEAR,
745 GTK_ICON_SIZE_SMALL_TOOLBAR));
746 g_signal_connect (button,
747 "clicked",
748 G_CALLBACK
749 (library_window_callback_filter_button_clicked),
750 library_window);
751 /* add the clear button to the filter area */
752 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
753 /* set clear button of library_window */
754 library_window->button_clear = GTK_BUTTON (button);
756 #if 0
757 /* create the refresh button */
758 button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
759 /* GtkWidget */
760 "sensitive", TRUE,
761 /* GtkButton */
762 "relief", GTK_RELIEF_NONE, NULL));
763 gtk_container_add (GTK_CONTAINER (button),
764 gtk_image_new_from_stock (GTK_STOCK_REFRESH,
765 GTK_ICON_SIZE_SMALL_TOOLBAR));
766 /* add the refresh button to the filter area */
767 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
768 g_signal_connect (button,
769 "clicked",
770 G_CALLBACK (library_window_callback_refresh_library),
771 library_window);
772 #endif
774 /* add the filter area to the vertical box */
775 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
777 library_window->libtreeview = GTK_TREE_VIEW (libtreeview);
779 return vbox;
783 static GObject *
784 library_window_constructor (GType type,
785 guint n_construct_properties,
786 GObjectConstructParam * construct_params)
788 GObject *object;
789 GhidLibraryWindow *library_window;
790 GtkWidget *content_area;
791 GtkWidget *hpaned, *notebook;
792 GtkWidget *libview;
793 GtkWidget *preview;
794 GtkWidget *alignment, *frame;
796 /* chain up to constructor of parent class */
797 object = G_OBJECT_CLASS (library_window_parent_class)->
798 constructor (type, n_construct_properties, construct_params);
799 library_window = GHID_LIBRARY_WINDOW (object);
801 /* dialog initialization */
802 g_object_set (object,
803 /* GtkWindow */
804 "type", GTK_WINDOW_TOPLEVEL,
805 "title", _("Select Footprint..."),
806 "default-height", 300,
807 "default-width", 400,
808 "modal", FALSE, "window-position", GTK_WIN_POS_NONE,
809 /* GtkDialog */
810 "has-separator", TRUE, NULL);
811 g_object_set (gtk_dialog_get_content_area (GTK_DIALOG (library_window)),
812 "homogeneous", FALSE, NULL);
814 /* horizontal pane containing selection and preview */
815 hpaned = GTK_WIDGET (g_object_new (GTK_TYPE_HPANED,
816 /* GtkContainer */
817 "border-width", 5, NULL));
818 library_window->hpaned = hpaned;
820 /* notebook for library views */
821 notebook = GTK_WIDGET (g_object_new (GTK_TYPE_NOTEBOOK,
822 "show-tabs", FALSE, NULL));
823 library_window->viewtabs = GTK_NOTEBOOK (notebook);
825 libview = create_lib_treeview (library_window);
826 gtk_notebook_append_page (GTK_NOTEBOOK (notebook), libview,
827 gtk_label_new (_("Libraries")));
829 /* include the vertical box in horizontal box */
830 gtk_paned_pack1 (GTK_PANED (hpaned), notebook, TRUE, FALSE);
833 /* -- preview area -- */
834 frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
835 /* GtkFrame */
836 "label", _("Preview"), NULL));
837 alignment = GTK_WIDGET (g_object_new (GTK_TYPE_ALIGNMENT,
838 /* GtkAlignment */
839 "left-padding", 5,
840 "right-padding", 5,
841 "top-padding", 5,
842 "bottom-padding", 5,
843 "xscale", 1.0,
844 "yscale", 1.0,
845 "xalign", 0.5, "yalign", 0.5, NULL));
846 preview = (GtkWidget *)g_object_new (GHID_TYPE_PINOUT_PREVIEW,
847 /* GhidPinoutPreview */
848 "element-data", NULL,
849 /* GtkWidget */
850 "width-request", 150, "height-request", 150, NULL);
851 gtk_container_add (GTK_CONTAINER (alignment), preview);
852 gtk_container_add (GTK_CONTAINER (frame), alignment);
853 /* set preview of library_window */
854 library_window->preview = preview;
856 gtk_paned_pack2 (GTK_PANED (hpaned), frame, FALSE, FALSE);
858 /* add the hpaned to the dialog content area */
859 content_area = gtk_dialog_get_content_area (GTK_DIALOG (library_window));
860 gtk_box_pack_start (GTK_BOX (content_area), hpaned, TRUE, TRUE, 0);
861 gtk_widget_show_all (hpaned);
864 /* now add buttons in the action area */
865 gtk_dialog_add_buttons (GTK_DIALOG (library_window),
866 /* - close button */
867 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
869 return object;
872 static void
873 library_window_finalize (GObject * object)
875 GhidLibraryWindow *library_window = GHID_LIBRARY_WINDOW (object);
877 if (library_window->filter_timeout != 0)
879 g_source_remove (library_window->filter_timeout);
880 library_window->filter_timeout = 0;
883 G_OBJECT_CLASS (library_window_parent_class)->finalize (object);
887 static void
888 library_window_class_init (GhidLibraryWindowClass * klass)
890 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
892 gobject_class->constructor = library_window_constructor;
893 gobject_class->finalize = library_window_finalize;
895 library_window_parent_class = (GObjectClass *)g_type_class_peek_parent (klass);
899 GType
900 ghid_library_window_get_type ()
902 static GType library_window_type = 0;
904 if (!library_window_type)
906 static const GTypeInfo library_window_info = {
907 sizeof (GhidLibraryWindowClass),
908 NULL, /* base_init */
909 NULL, /* base_finalize */
910 (GClassInitFunc) library_window_class_init,
911 NULL, /* class_finalize */
912 NULL, /* class_data */
913 sizeof (GhidLibraryWindow),
914 0, /* n_preallocs */
915 NULL /* instance_init */
918 library_window_type = g_type_register_static (GTK_TYPE_DIALOG,
919 "GhidLibraryWindow",
920 &library_window_info, (GTypeFlags)0);
923 return library_window_type;