1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
5 * Copyright (C) 2011 Sébastien Granjoux
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (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 GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
30 #include <glib/gi18n.h>
32 #include "anjuta-tree-combo.h"
36 *---------------------------------------------------------------------------*/
38 struct _AnjutaTreeComboBoxPrivate
45 GtkWidget
*popup_window
;
46 GtkWidget
*scrolled_window
;
49 GdkDevice
*grab_pointer
;
50 GdkDevice
*grab_keyboard
;
55 gboolean popup_in_progress
;
57 gint active
; /* Only temporary */
58 GtkTreeRowReference
*active_row
; /* Current selected row */
68 static guint signals
[LAST_SIGNAL
] = {0,};
70 #define SCROLL_TIME 100
72 static void anjuta_tree_combo_box_cell_layout_init (GtkCellLayoutIface
*iface
);
74 G_DEFINE_TYPE_WITH_CODE (AnjutaTreeComboBox
, anjuta_tree_combo_box
, GTK_TYPE_TOGGLE_BUTTON
,
75 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT
,
76 anjuta_tree_combo_box_cell_layout_init
))
81 *---------------------------------------------------------------------------*/
84 popup_grab_on_window (GdkWindow
*window
,
89 gdk_device_grab (keyboard
, window
,
90 GDK_OWNERSHIP_WINDOW
, TRUE
,
91 GDK_KEY_PRESS_MASK
| GDK_KEY_RELEASE_MASK
,
92 NULL
, GDK_CURRENT_TIME
) != GDK_GRAB_SUCCESS
)
96 gdk_device_grab (pointer
, window
,
97 GDK_OWNERSHIP_WINDOW
, TRUE
,
98 GDK_BUTTON_PRESS_MASK
| GDK_BUTTON_RELEASE_MASK
|
99 GDK_POINTER_MOTION_MASK
,
100 NULL
, GDK_CURRENT_TIME
) != GDK_GRAB_SUCCESS
)
103 gdk_device_ungrab (keyboard
, GDK_CURRENT_TIME
);
114 *---------------------------------------------------------------------------*/
117 anjuta_tree_combo_box_popup_position (AnjutaTreeComboBox
*combo
,
123 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
124 GtkAllocation allocation
;
127 GdkRectangle monitor
;
128 GtkRequisition popup_req
;
129 GtkPolicyType hpolicy
, vpolicy
;
132 GtkWidget
*widget
= GTK_WIDGET (combo
);
136 gtk_widget_get_allocation (widget
, &allocation
);
138 if (!gtk_widget_get_has_window (widget
))
144 window
= gtk_widget_get_window (widget
);
146 gdk_window_get_root_coords (gtk_widget_get_window (widget
),
149 *width
= allocation
.width
;
151 hpolicy
= vpolicy
= GTK_POLICY_NEVER
;
152 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv
->scrolled_window
),
155 gtk_widget_get_preferred_size (priv
->scrolled_window
, &popup_req
, NULL
);
157 if (popup_req
.width
> *width
)
159 hpolicy
= GTK_POLICY_ALWAYS
;
160 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv
->scrolled_window
),
164 *height
= popup_req
.height
;
166 screen
= gtk_widget_get_screen (GTK_WIDGET (combo
));
167 monitor_num
= gdk_screen_get_monitor_at_window (screen
, window
);
168 gdk_screen_get_monitor_geometry (screen
, monitor_num
, &monitor
);
170 if (gtk_widget_get_direction (GTK_WIDGET (combo
)) == GTK_TEXT_DIR_RTL
)
171 *x
= *x
+ allocation
.width
- *width
;
175 else if (*x
+ *width
> monitor
.x
+ monitor
.width
)
176 *x
= monitor
.x
+ monitor
.width
- *width
;
178 if (*y
+ allocation
.height
+ *height
<= monitor
.y
+ monitor
.height
)
179 *y
+= allocation
.height
;
180 else if (*y
- *height
>= monitor
.y
)
182 else if (monitor
.y
+ monitor
.height
- (*y
+ allocation
.height
) > *y
- monitor
.y
)
184 *y
+= allocation
.height
;
185 *height
= monitor
.y
+ monitor
.height
- *y
;
189 *height
= *y
- monitor
.y
;
193 if (popup_req
.height
> *height
)
195 vpolicy
= GTK_POLICY_ALWAYS
;
197 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv
->scrolled_window
),
203 anjuta_tree_combo_box_popup_for_device (AnjutaTreeComboBox
*combo
,
206 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
207 gint x
, y
, width
, height
;
209 GdkDevice
*keyboard
, *pointer
;
211 g_return_if_fail (ANJUTA_IS_TREE_COMBO_BOX (combo
));
212 g_return_if_fail (GDK_IS_DEVICE (device
));
214 if (!gtk_widget_get_realized (GTK_WIDGET (combo
)))
217 if (gtk_widget_get_mapped (priv
->popup_window
))
220 if (priv
->grab_pointer
&& priv
->grab_keyboard
)
223 if (gdk_device_get_source (device
) == GDK_SOURCE_KEYBOARD
)
226 pointer
= gdk_device_get_associated_device (device
);
231 keyboard
= gdk_device_get_associated_device (device
);
234 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (combo
));
236 if (GTK_IS_WINDOW (toplevel
))
237 gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel
)),
238 GTK_WINDOW (priv
->popup_window
));
240 gtk_widget_show_all (priv
->scrolled_window
);
241 anjuta_tree_combo_box_popup_position (combo
, &x
, &y
, &width
, &height
);
243 gtk_widget_set_size_request (priv
->popup_window
, width
, height
);
244 gtk_window_move (GTK_WINDOW (priv
->popup_window
), x
, y
);
246 gtk_tree_view_set_hover_expand (GTK_TREE_VIEW (priv
->tree_view
),
250 gtk_widget_show (priv
->popup_window
);
252 gtk_widget_grab_focus (priv
->popup_window
);
253 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo
),
256 if (!gtk_widget_has_focus (priv
->tree_view
))
257 gtk_widget_grab_focus (priv
->tree_view
);
259 if (!popup_grab_on_window (gtk_widget_get_window (priv
->popup_window
),
262 gtk_widget_hide (priv
->popup_window
);
266 gtk_device_grab_add (priv
->popup_window
, pointer
, TRUE
);
267 priv
->grab_pointer
= pointer
;
268 priv
->grab_keyboard
= keyboard
;
272 anjuta_tree_combo_box_popup (AnjutaTreeComboBox
*combo
)
276 device
= gtk_get_current_event_device ();
280 GdkDeviceManager
*device_manager
;
284 display
= gtk_widget_get_display (GTK_WIDGET (combo
));
285 device_manager
= gdk_display_get_device_manager (display
);
287 /* No device was set, pick the first master device */
288 devices
= gdk_device_manager_list_devices (device_manager
, GDK_DEVICE_TYPE_MASTER
);
289 device
= devices
->data
;
290 g_list_free (devices
);
293 anjuta_tree_combo_box_popup_for_device (combo
, device
);
297 anjuta_tree_combo_box_popdown (AnjutaTreeComboBox
*combo
)
299 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
301 g_return_if_fail (ANJUTA_IS_TREE_COMBO_BOX (combo
));
303 if (!gtk_widget_get_realized (GTK_WIDGET (combo
)))
306 gtk_device_grab_remove (priv
->popup_window
, priv
->grab_pointer
);
307 gtk_widget_hide (priv
->popup_window
);
308 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo
),
311 priv
->grab_pointer
= NULL
;
312 priv
->grab_keyboard
= NULL
;
316 anjuta_tree_combo_box_unset_model (AnjutaTreeComboBox
*combo
)
318 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
320 if (priv
->model
!= NULL
)
322 g_object_unref (priv
->model
);
326 if (priv
->active_row
)
328 gtk_tree_row_reference_free (priv
->active_row
);
329 priv
->active_row
= NULL
;
334 gtk_cell_view_set_model (GTK_CELL_VIEW (priv
->cell_view
), NULL
);
339 gtk_tree_view_set_model (GTK_TREE_VIEW (priv
->tree_view
), NULL
);
344 anjuta_tree_combo_box_popup_destroy (AnjutaTreeComboBox
*combo
)
346 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
348 if (priv
->scroll_timer
)
350 g_source_remove (priv
->scroll_timer
);
351 priv
->scroll_timer
= 0;
354 if (priv
->resize_idle_id
)
356 g_source_remove (priv
->resize_idle_id
);
357 priv
->resize_idle_id
= 0;
360 if (priv
->popup_window
)
362 gtk_widget_destroy (priv
->popup_window
);
363 priv
->popup_window
= NULL
;
368 anjuta_tree_combo_box_set_active_path (AnjutaTreeComboBox
*combo
,
371 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
374 valid
= gtk_tree_row_reference_valid (priv
->active_row
);
378 GtkTreePath
*active_path
;
381 active_path
= gtk_tree_row_reference_get_path (priv
->active_row
);
382 cmp
= gtk_tree_path_compare (path
, active_path
);
383 gtk_tree_path_free (active_path
);
384 if (cmp
== 0) return;
387 if (priv
->active_row
)
389 gtk_tree_row_reference_free (priv
->active_row
);
390 priv
->active_row
= NULL
;
395 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv
->tree_view
)));
396 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv
->cell_view
), NULL
);
401 priv
->active_row
= gtk_tree_row_reference_new (priv
->model
, path
);
403 gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (priv
->cell_view
), path
);
404 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv
->tree_view
), path
);
405 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv
->tree_view
), path
, NULL
, FALSE
);
406 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv
->tree_view
), path
, NULL
, TRUE
, 0.5, 0.0);
409 g_signal_emit (combo
, signals
[CHANGED
], 0);
414 /* Callbacks functions
415 *---------------------------------------------------------------------------*/
418 anjuta_tree_combo_box_auto_scroll (AnjutaTreeComboBox
*combo
,
423 GtkAllocation allocation
;
424 GtkWidget
*tree_view
= combo
->priv
->tree_view
;
427 gtk_widget_get_allocation (tree_view
, &allocation
);
429 adj
= gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (combo
->priv
->scrolled_window
));
430 if (adj
&& gtk_adjustment_get_upper (adj
) - gtk_adjustment_get_lower (adj
) > gtk_adjustment_get_page_size (adj
))
432 if (x
<= allocation
.x
&&
433 gtk_adjustment_get_lower (adj
) < gtk_adjustment_get_value (adj
))
435 value
= gtk_adjustment_get_value (adj
) - (allocation
.x
- x
+ 1);
436 gtk_adjustment_set_value (adj
, value
);
438 else if (x
>= allocation
.x
+ allocation
.width
&&
439 gtk_adjustment_get_upper (adj
) - gtk_adjustment_get_page_size (adj
) > gtk_adjustment_get_value (adj
))
441 value
= gtk_adjustment_get_value (adj
) + (x
- allocation
.x
- allocation
.width
+ 1);
442 gtk_adjustment_set_value (adj
, MAX (value
, 0.0));
446 adj
= gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (combo
->priv
->scrolled_window
));
447 if (adj
&& gtk_adjustment_get_upper (adj
) - gtk_adjustment_get_lower (adj
) > gtk_adjustment_get_page_size (adj
))
449 if (y
<= allocation
.y
&&
450 gtk_adjustment_get_lower (adj
) < gtk_adjustment_get_value (adj
))
452 value
= gtk_adjustment_get_value (adj
) - (allocation
.y
- y
+ 1);
453 gtk_adjustment_set_value (adj
, value
);
455 else if (y
>= allocation
.height
&&
456 gtk_adjustment_get_upper (adj
) - gtk_adjustment_get_page_size (adj
) > gtk_adjustment_get_value (adj
))
458 value
= gtk_adjustment_get_value (adj
) + (y
- allocation
.height
+ 1);
459 gtk_adjustment_set_value (adj
, MAX (value
, 0.0));
465 anjuta_tree_combo_box_scroll_timeout (AnjutaTreeComboBox
*combo
)
467 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
470 if (priv
->auto_scroll
)
472 gdk_window_get_device_position (gtk_widget_get_window (priv
->tree_view
),
475 anjuta_tree_combo_box_auto_scroll (combo
, x
, y
);
482 anjuta_tree_combo_box_key_press (GtkWidget
*widget
,
486 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
489 if (event
->keyval
== GDK_KEY_Return
|| event
->keyval
== GDK_KEY_ISO_Enter
|| event
->keyval
== GDK_KEY_KP_Enter
||
490 event
->keyval
== GDK_KEY_space
|| event
->keyval
== GDK_KEY_KP_Space
)
492 GtkTreeModel
*model
= NULL
;
494 anjuta_tree_combo_box_popdown (combo
);
496 if (combo
->priv
->model
)
498 GtkTreeSelection
*sel
;
500 sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (combo
->priv
->tree_view
));
502 if (gtk_tree_selection_get_selected (sel
, &model
, &iter
))
503 anjuta_tree_combo_box_set_active_iter (combo
, &iter
);
509 if (!gtk_bindings_activate_event (G_OBJECT (widget
), event
))
511 /* The tree hasn't managed the
512 * event, forward it to the combobox
514 if (gtk_bindings_activate_event (G_OBJECT (combo
), event
)) return TRUE
;
521 anjuta_tree_combo_box_enter_notify (GtkWidget
*widget
,
522 GdkEventCrossing
*event
,
525 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (data
);
527 combo
->priv
->auto_scroll
= TRUE
;
533 anjuta_tree_combo_box_resize_idle (gpointer user_data
)
535 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
536 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
537 gint x
, y
, width
, height
;
539 if (priv
->tree_view
&& gtk_widget_get_mapped (priv
->popup_window
))
541 anjuta_tree_combo_box_popup_position (combo
, &x
, &y
, &width
, &height
);
543 gtk_widget_set_size_request (priv
->popup_window
, width
, height
);
544 gtk_window_move (GTK_WINDOW (priv
->popup_window
), x
, y
);
547 priv
->resize_idle_id
= 0;
553 anjuta_tree_combo_box_popup_resize (AnjutaTreeComboBox
*combo
)
555 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
557 if (!priv
->resize_idle_id
)
559 priv
->resize_idle_id
= gdk_threads_add_idle (anjuta_tree_combo_box_resize_idle
, combo
);
564 anjuta_tree_combo_box_row_expanded (GtkTreeModel
*model
,
569 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
571 anjuta_tree_combo_box_popup_resize (combo
);
575 anjuta_tree_combo_box_button_pressed (GtkWidget
*widget
,
576 GdkEventButton
*event
,
579 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
580 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
582 GtkWidget
*ewidget
= gtk_get_event_widget ((GdkEvent
*)event
);
584 if (ewidget
== priv
->popup_window
)
587 if ((ewidget
!= GTK_WIDGET (combo
)) ||
588 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo
)))
593 if (!gtk_widget_has_focus (GTK_WIDGET (combo
)))
595 gtk_widget_grab_focus (GTK_WIDGET (combo
));
598 anjuta_tree_combo_box_popup_for_device (combo
, event
->device
);
600 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (combo
), TRUE
);
602 priv
->auto_scroll
= FALSE
;
603 if (priv
->scroll_timer
== 0)
604 priv
->scroll_timer
= gdk_threads_add_timeout (SCROLL_TIME
,
605 (GSourceFunc
) anjuta_tree_combo_box_scroll_timeout
,
608 priv
->popup_in_progress
= TRUE
;
614 anjuta_tree_combo_box_button_released (GtkWidget
*widget
,
615 GdkEventButton
*event
,
619 GtkTreePath
*path
= NULL
;
622 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
623 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
625 gboolean popup_in_progress
= FALSE
;
627 GtkWidget
*ewidget
= gtk_get_event_widget ((GdkEvent
*)event
);
629 if (priv
->popup_in_progress
)
631 popup_in_progress
= TRUE
;
632 priv
->popup_in_progress
= FALSE
;
635 gtk_tree_view_set_hover_expand (GTK_TREE_VIEW (priv
->tree_view
),
637 if (priv
->scroll_timer
)
639 g_source_remove (priv
->scroll_timer
);
640 priv
->scroll_timer
= 0;
643 if (ewidget
!= priv
->tree_view
)
645 if ((ewidget
== GTK_WIDGET (combo
)) &&
646 !popup_in_progress
&&
647 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (combo
)))
649 anjuta_tree_combo_box_popdown (combo
);
653 /* released outside treeview */
654 if (ewidget
!= GTK_WIDGET (combo
))
656 anjuta_tree_combo_box_popdown (combo
);
664 /* select something cool */
665 ret
= gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv
->tree_view
),
671 return TRUE
; /* clicked outside window? */
673 gtk_tree_model_get_iter (priv
->model
, &iter
, path
);
674 gtk_tree_path_free (path
);
676 anjuta_tree_combo_box_popdown (combo
);
678 anjuta_tree_combo_box_set_active_iter (combo
, &iter
);
684 anjuta_tree_combo_box_button_toggled (GtkWidget
*widget
,
687 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (user_data
);
689 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget
)))
691 anjuta_tree_combo_box_popup (combo
);
695 anjuta_tree_combo_box_popdown (combo
);
700 anjuta_tree_combo_box_popup_setup (AnjutaTreeComboBox
*combo
)
702 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
703 GtkTreeSelection
*sel
;
706 priv
->popup_window
= gtk_window_new (GTK_WINDOW_POPUP
);
707 gtk_window_set_type_hint (GTK_WINDOW (priv
->popup_window
),
708 GDK_WINDOW_TYPE_HINT_COMBO
);
710 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (combo
));
711 if (GTK_IS_WINDOW (toplevel
))
713 gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel
)),
714 GTK_WINDOW (priv
->popup_window
));
715 gtk_window_set_transient_for (GTK_WINDOW (priv
->popup_window
),
716 GTK_WINDOW (toplevel
));
719 gtk_window_set_resizable (GTK_WINDOW (priv
->popup_window
), FALSE
);
720 gtk_window_set_screen (GTK_WINDOW (priv
->popup_window
),
721 gtk_widget_get_screen (GTK_WIDGET (combo
)));
723 priv
->scrolled_window
= gtk_scrolled_window_new (NULL
, NULL
);
724 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv
->scrolled_window
),
727 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv
->scrolled_window
),
729 gtk_container_add (GTK_CONTAINER (priv
->popup_window
),
730 priv
->scrolled_window
);
733 priv
->tree_view
= gtk_tree_view_new ();
734 sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (priv
->tree_view
));
735 gtk_tree_selection_set_mode (sel
, GTK_SELECTION_BROWSE
);
736 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv
->tree_view
), FALSE
);
737 gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (priv
->tree_view
), TRUE
);
738 gtk_tree_view_append_column (GTK_TREE_VIEW (priv
->tree_view
),
739 gtk_tree_view_column_new_with_area (priv
->area
));
740 gtk_container_add (GTK_CONTAINER (priv
->scrolled_window
),
743 /* set sample/popup widgets */
744 g_signal_connect (priv
->tree_view
, "key-press-event",
745 G_CALLBACK (anjuta_tree_combo_box_key_press
),
747 g_signal_connect (priv
->tree_view
, "enter-notify-event",
748 G_CALLBACK (anjuta_tree_combo_box_enter_notify
),
750 g_signal_connect (priv
->tree_view
, "row-expanded",
751 G_CALLBACK (anjuta_tree_combo_box_row_expanded
),
753 g_signal_connect (priv
->tree_view
, "row-collapsed",
754 G_CALLBACK (anjuta_tree_combo_box_row_expanded
),
756 g_signal_connect (priv
->popup_window
, "button-press-event",
757 G_CALLBACK (anjuta_tree_combo_box_button_pressed
),
759 g_signal_connect (priv
->popup_window
, "button-release-event",
760 G_CALLBACK (anjuta_tree_combo_box_button_released
),
763 gtk_widget_show (priv
->scrolled_window
);
770 *---------------------------------------------------------------------------*/
773 anjuta_tree_combo_box_set_model (AnjutaTreeComboBox
*combo
,
776 g_return_if_fail (ANJUTA_IS_TREE_COMBO_BOX (combo
));
778 anjuta_tree_combo_box_unset_model (combo
);
782 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
784 priv
->model
= g_object_ref (model
);
785 gtk_cell_view_set_model (GTK_CELL_VIEW (priv
->cell_view
), model
);
786 gtk_tree_view_set_model (GTK_TREE_VIEW (priv
->tree_view
), model
);
789 if (priv
->active
!= -1)
791 /* If an index was set in advance, apply it now */
792 anjuta_tree_combo_box_set_active (combo
, priv
->active
);
798 gtk_tree_model_get_iter_first (model
, &iter
);
799 anjuta_tree_combo_box_set_active_iter (combo
, &iter
);
805 anjuta_tree_combo_box_get_model (AnjutaTreeComboBox
*combo
)
807 return combo
->priv
->model
;
811 anjuta_tree_combo_box_set_active (AnjutaTreeComboBox
*combo
,
814 GtkTreePath
*path
= NULL
;
816 g_return_if_fail (ANJUTA_IS_TREE_COMBO_BOX (combo
));
817 g_return_if_fail (index
>= -1);
819 if (combo
->priv
->model
== NULL
)
821 /* Save index, in case the model is set after the index */
822 combo
->priv
->active
= index
;
826 if (index
!= -1) path
= gtk_tree_path_new_from_indices (index
, -1);
828 anjuta_tree_combo_box_set_active_path (combo
, path
);
830 gtk_tree_path_free (path
);
835 anjuta_tree_combo_box_set_active_iter (AnjutaTreeComboBox
*combo
,
838 GtkTreePath
*path
= NULL
;
840 g_return_if_fail (ANJUTA_IS_TREE_COMBO_BOX (combo
));
844 path
= gtk_tree_model_get_path (combo
->priv
->model
, iter
);
847 anjuta_tree_combo_box_set_active_path (combo
, path
);
849 gtk_tree_path_free (path
);
853 anjuta_tree_combo_box_get_active_iter (AnjutaTreeComboBox
*combo
,
856 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
858 gboolean valid
= FALSE
;
860 path
= gtk_tree_row_reference_get_path (priv
->active_row
);
863 valid
= gtk_tree_model_get_iter (priv
->model
, iter
, path
);
864 gtk_tree_path_free (path
);
872 anjuta_tree_combo_box_new (void)
874 return g_object_new (ANJUTA_TYPE_TREE_COMBO_BOX
, NULL
);
879 /* Implement GtkCellLayout interface
880 *---------------------------------------------------------------------------*/
883 anjuta_tree_combo_box_cell_layout_get_area (GtkCellLayout
*cell_layout
)
885 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (cell_layout
);
886 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
893 anjuta_tree_combo_box_cell_layout_init (GtkCellLayoutIface
*iface
)
895 iface
->get_area
= anjuta_tree_combo_box_cell_layout_get_area
;
900 /* Implement GtkWidget functions
901 *---------------------------------------------------------------------------*/
904 anjuta_tree_combo_box_destroy (GtkWidget
*widget
)
906 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (widget
);
907 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
909 anjuta_tree_combo_box_popdown (combo
);
911 GTK_WIDGET_CLASS (anjuta_tree_combo_box_parent_class
)->destroy (widget
);
913 priv
->cell_view
= NULL
;
914 priv
->tree_view
= NULL
;
919 /* Implement GObject functions
920 *---------------------------------------------------------------------------*/
923 anjuta_tree_combo_box_dispose (GObject
*object
)
925 AnjutaTreeComboBox
*combo
= ANJUTA_TREE_COMBO_BOX (object
);
926 AnjutaTreeComboBoxPrivate
*priv
= combo
->priv
;
930 g_object_unref (priv
->area
);
934 anjuta_tree_combo_box_unset_model (combo
);
936 anjuta_tree_combo_box_popup_destroy (combo
);
938 G_OBJECT_CLASS (anjuta_tree_combo_box_parent_class
)->dispose (object
);
942 anjuta_tree_combo_box_init (AnjutaTreeComboBox
*combo
)
944 AnjutaTreeComboBoxPrivate
*priv
;
945 GtkWidget
*box
, *sep
, *arrow
;
947 priv
= G_TYPE_INSTANCE_GET_PRIVATE (combo
,
948 ANJUTA_TYPE_TREE_COMBO_BOX
,
949 AnjutaTreeComboBoxPrivate
);
954 priv
->active_row
= NULL
;
956 gtk_widget_push_composite_child ();
958 gtk_widget_set_halign (GTK_WIDGET (combo
), GTK_ALIGN_FILL
);
959 gtk_widget_show (GTK_WIDGET (combo
));
961 g_signal_connect (combo
, "button-press-event",
962 G_CALLBACK (anjuta_tree_combo_box_button_pressed
), combo
);
963 g_signal_connect (combo
, "toggled",
964 G_CALLBACK (anjuta_tree_combo_box_button_toggled
), combo
);
967 box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
968 gtk_container_add (GTK_CONTAINER (combo
), box
);
969 gtk_widget_show (box
);
971 priv
->area
= gtk_cell_area_box_new ();
972 g_object_ref_sink (priv
->area
);
974 priv
->cell_view
= gtk_cell_view_new_with_context (priv
->area
, NULL
);
975 gtk_box_pack_start (GTK_BOX (box
), priv
->cell_view
, TRUE
, TRUE
, 0);
976 gtk_widget_show (priv
->cell_view
);
978 sep
= gtk_separator_new (GTK_ORIENTATION_VERTICAL
);
979 gtk_box_pack_start (GTK_BOX (box
), sep
, FALSE
, FALSE
, 0);
980 gtk_widget_show (sep
);
982 arrow
= gtk_arrow_new (GTK_ARROW_DOWN
,GTK_SHADOW_NONE
);
983 gtk_box_pack_start (GTK_BOX (box
), arrow
, FALSE
, FALSE
, 0);
984 gtk_widget_show (arrow
);
986 gtk_widget_pop_composite_child ();
988 anjuta_tree_combo_box_popup_setup (combo
);
992 anjuta_tree_combo_box_class_init (AnjutaTreeComboBoxClass
* class)
994 GObjectClass
*gobject_class
;
995 GtkWidgetClass
*widget_class
;
996 GtkBindingSet
*binding_set
;
998 widget_class
= GTK_WIDGET_CLASS (class);
999 widget_class
->destroy
= anjuta_tree_combo_box_destroy
;
1001 gobject_class
= G_OBJECT_CLASS (class);
1002 gobject_class
->dispose
= anjuta_tree_combo_box_dispose
;
1005 signals
[CHANGED
] = g_signal_new ("changed",
1006 G_OBJECT_CLASS_TYPE (class),
1008 G_STRUCT_OFFSET (AnjutaTreeComboBoxClass
, changed
),
1010 g_cclosure_marshal_VOID__VOID
,
1013 signals
[POPUP
] = g_signal_new_class_handler ("popup",
1014 G_OBJECT_CLASS_TYPE (class),
1015 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
1016 G_CALLBACK (anjuta_tree_combo_box_popup
),
1018 g_cclosure_marshal_VOID__VOID
,
1021 signals
[POPDOWN
] = g_signal_new_class_handler ("popdown",
1022 G_OBJECT_CLASS_TYPE (class),
1023 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
1024 G_CALLBACK (anjuta_tree_combo_box_popdown
),
1026 g_cclosure_marshal_VOID__VOID
,
1030 binding_set
= gtk_binding_set_by_class (widget_class
);
1032 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Down
, GDK_MOD1_MASK
,
1034 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Down
, GDK_MOD1_MASK
,
1036 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Up
, GDK_MOD1_MASK
,
1038 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Up
, GDK_MOD1_MASK
,
1040 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Escape
, 0,
1043 g_type_class_add_private (class, sizeof (AnjutaTreeComboBoxPrivate
));