2 * This program is based on gtkflist.c
19 static void gtk_sctree_class_init (GtkSCTreeClass
*class);
20 static void gtk_sctree_init (GtkSCTree
*sctree
);
22 static gint
gtk_sctree_button_press (GtkWidget
*widget
, GdkEventButton
*event
);
23 static gint
gtk_sctree_button_release (GtkWidget
*widget
, GdkEventButton
*event
);
24 static gint
gtk_sctree_motion (GtkWidget
*widget
, GdkEventMotion
*event
);
25 static void gtk_sctree_drag_begin (GtkWidget
*widget
, GdkDragContext
*context
);
26 static void gtk_sctree_drag_end (GtkWidget
*widget
, GdkDragContext
*context
);
27 static void gtk_sctree_drag_data_get (GtkWidget
*widget
, GdkDragContext
*context
,
28 GtkSelectionData
*data
, guint info
, guint time
);
29 static void gtk_sctree_drag_leave (GtkWidget
*widget
, GdkDragContext
*context
, guint time
);
30 static gboolean
gtk_sctree_drag_motion (GtkWidget
*widget
, GdkDragContext
*context
,
31 gint x
, gint y
, guint time
);
32 static gboolean
gtk_sctree_drag_drop (GtkWidget
*widget
, GdkDragContext
*context
,
33 gint x
, gint y
, guint time
);
34 static void gtk_sctree_drag_data_received (GtkWidget
*widget
, GdkDragContext
*context
,
35 gint x
, gint y
, GtkSelectionData
*data
,
36 guint info
, guint time
);
38 static void gtk_sctree_clear (GtkCList
*clist
);
39 static void gtk_sctree_collapse (GtkCTree
*ctree
, GtkCTreeNode
*node
);
41 static GtkCTreeClass
*parent_class
;
43 static guint sctree_signals
[LAST_SIGNAL
];
47 * gtk_sctree_get_type:
50 * Creates the GtkSCTree class and its type information
52 * Return value: The type ID for GtkSCTreeClass
55 gtk_sctree_get_type (void)
57 static GtkType sctree_type
= 0;
60 GtkTypeInfo sctree_info
= {
63 sizeof (GtkSCTreeClass
),
64 (GtkClassInitFunc
) gtk_sctree_class_init
,
65 (GtkObjectInitFunc
) gtk_sctree_init
,
66 NULL
, /* reserved_1 */
67 NULL
, /* reserved_2 */
68 (GtkClassInitFunc
) NULL
71 sctree_type
= gtk_type_unique (gtk_ctree_get_type (), &sctree_info
);
77 /* Standard class initialization function */
79 gtk_sctree_class_init (GtkSCTreeClass
*klass
)
81 GtkObjectClass
*object_class
;
82 GtkWidgetClass
*widget_class
;
83 GtkCListClass
*clist_class
;
84 GtkCTreeClass
*ctree_class
;
86 object_class
= (GtkObjectClass
*) klass
;
87 widget_class
= (GtkWidgetClass
*) klass
;
88 clist_class
= (GtkCListClass
*) klass
;
89 ctree_class
= (GtkCTreeClass
*) klass
;
91 parent_class
= gtk_type_class (gtk_ctree_get_type ());
93 sctree_signals
[ROW_POPUP_MENU
] =
94 gtk_signal_new ("row_popup_menu",
97 GTK_SIGNAL_OFFSET (GtkSCTreeClass
, row_popup_menu
),
98 gtk_marshal_NONE__POINTER
,
101 sctree_signals
[EMPTY_POPUP_MENU
] =
102 gtk_signal_new ("empty_popup_menu",
105 GTK_SIGNAL_OFFSET (GtkSCTreeClass
, empty_popup_menu
),
106 gtk_marshal_NONE__POINTER
,
109 sctree_signals
[OPEN_ROW
] =
110 gtk_signal_new ("open_row",
113 GTK_SIGNAL_OFFSET (GtkSCTreeClass
, open_row
),
114 gtk_marshal_NONE__NONE
,
116 sctree_signals
[START_DRAG
] =
117 gtk_signal_new ("start_drag",
120 GTK_SIGNAL_OFFSET (GtkSCTreeClass
, start_drag
),
121 gtk_marshal_NONE__INT_POINTER
,
126 gtk_object_class_add_signals (object_class
, sctree_signals
, LAST_SIGNAL
);
128 clist_class
->clear
= gtk_sctree_clear
;
129 ctree_class
->tree_collapse
= gtk_sctree_collapse
;
131 widget_class
->button_press_event
= gtk_sctree_button_press
;
132 widget_class
->button_release_event
= gtk_sctree_button_release
;
133 widget_class
->motion_notify_event
= gtk_sctree_motion
;
134 widget_class
->drag_begin
= gtk_sctree_drag_begin
;
135 widget_class
->drag_end
= gtk_sctree_drag_end
;
136 widget_class
->drag_data_get
= gtk_sctree_drag_data_get
;
137 widget_class
->drag_leave
= gtk_sctree_drag_leave
;
138 widget_class
->drag_motion
= gtk_sctree_drag_motion
;
139 widget_class
->drag_drop
= gtk_sctree_drag_drop
;
140 widget_class
->drag_data_received
= gtk_sctree_drag_data_received
;
143 /* Standard object initialization function */
145 gtk_sctree_init (GtkSCTree
*sctree
)
147 sctree
->anchor_row
= -1;
149 /* GtkCTree does not specify pointer motion by default */
150 gtk_widget_add_events (GTK_WIDGET (sctree
), GDK_POINTER_MOTION_MASK
);
151 gtk_widget_add_events (GTK_WIDGET (sctree
), GDK_POINTER_MOTION_MASK
);
154 /* Get information the specified row is selected. */
157 row_is_selected(GtkSCTree
*sctree
, gint row
)
159 GtkCListRow
*clist_row
;
160 clist_row
= g_list_nth (GTK_CLIST(sctree
)->row_list
, row
)->data
;
161 return clist_row
? clist_row
->state
== GTK_STATE_SELECTED
: FALSE
;
164 /* Selects the rows between the anchor to the specified row, inclusive. */
166 select_range (GtkSCTree
*sctree
, gint row
)
171 if (sctree
->anchor_row
== -1)
172 sctree
->anchor_row
= row
;
174 if (row
< sctree
->anchor_row
) {
176 max
= sctree
->anchor_row
;
178 min
= sctree
->anchor_row
;
181 for (i
= min
; i
<= max
; i
++)
182 gtk_clist_select_row (GTK_CLIST (sctree
), i
, -1);
185 /* Handles row selection according to the specified modifier state */
187 select_row (GtkSCTree
*sctree
, gint row
, gint col
, guint state
)
189 gboolean range
, additive
;
190 g_return_if_fail (sctree
!= NULL
);
191 g_return_if_fail (GTK_IS_SCTREE (sctree
));
193 range
= ((state
& GDK_SHIFT_MASK
) != 0) &&
194 (GTK_CLIST(sctree
)->selection_mode
!= GTK_SELECTION_SINGLE
) &&
195 (GTK_CLIST(sctree
)->selection_mode
!= GTK_SELECTION_BROWSE
);
196 additive
= ((state
& GDK_CONTROL_MASK
) != 0) &&
197 (GTK_CLIST(sctree
)->selection_mode
!= GTK_SELECTION_SINGLE
) &&
198 (GTK_CLIST(sctree
)->selection_mode
!= GTK_SELECTION_BROWSE
);
200 gtk_clist_freeze (GTK_CLIST (sctree
));
201 gtkut_clist_set_focus_row(GTK_CLIST(sctree
), row
);
203 gtk_clist_unselect_all (GTK_CLIST (sctree
));
206 /*No need to manage overlapped list*/
208 if (row_is_selected(sctree
, row
))
209 gtk_clist_unselect_row (GTK_CLIST (sctree
), row
, col
);
211 gtk_signal_emit_by_name
212 (GTK_OBJECT (sctree
),
214 gtk_ctree_node_nth (GTK_CTREE(sctree
), row
),
217 gtk_signal_emit_by_name
218 (GTK_OBJECT (sctree
),
220 gtk_ctree_node_nth (GTK_CTREE(sctree
), row
),
223 sctree
->anchor_row
= row
;
225 select_range (sctree
, row
);
226 gtk_clist_thaw (GTK_CLIST (sctree
));
229 /* Our handler for button_press events. We override all of GtkCList's broken
233 gtk_sctree_button_press (GtkWidget
*widget
, GdkEventButton
*event
)
242 g_return_val_if_fail (widget
!= NULL
, FALSE
);
243 g_return_val_if_fail (GTK_IS_SCTREE (widget
), FALSE
);
244 g_return_val_if_fail (event
!= NULL
, FALSE
);
246 sctree
= GTK_SCTREE (widget
);
247 clist
= GTK_CLIST (widget
);
250 if (event
->window
!= clist
->clist_window
)
251 return (* GTK_WIDGET_CLASS (parent_class
)->button_press_event
) (widget
, event
);
253 on_row
= gtk_clist_get_selection_info (clist
, event
->x
, event
->y
, &row
, &col
);
255 if (on_row
&& !GTK_WIDGET_HAS_FOCUS(widget
))
256 gtk_widget_grab_focus (widget
);
258 if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree
), event
->x
, event
->y
)) {
259 gtk_ctree_toggle_expansion
261 gtk_ctree_node_nth(GTK_CTREE(sctree
), row
));
265 switch (event
->type
) {
266 case GDK_BUTTON_PRESS
:
267 if (event
->button
== 1 || event
->button
== 2) {
268 if (event
->button
== 2)
269 event
->state
&= ~(GDK_SHIFT_MASK
| GDK_CONTROL_MASK
);
271 /* Save the mouse info for DnD */
272 sctree
->dnd_press_button
= event
->button
;
273 sctree
->dnd_press_x
= event
->x
;
274 sctree
->dnd_press_y
= event
->y
;
276 /* Handle selection */
277 if ((row_is_selected (sctree
, row
)
278 && !(event
->state
& (GDK_CONTROL_MASK
| GDK_SHIFT_MASK
)))
279 || ((event
->state
& GDK_CONTROL_MASK
)
280 && !(event
->state
& GDK_SHIFT_MASK
))) {
281 sctree
->dnd_select_pending
= TRUE
;
282 sctree
->dnd_select_pending_state
= event
->state
;
283 sctree
->dnd_select_pending_row
= row
;
285 select_row (sctree
, row
, col
, event
->state
);
287 gtk_clist_unselect_all (clist
);
290 } else if (event
->button
== 3) {
291 /* Emit *_popup_menu signal*/
293 if (!row_is_selected(sctree
,row
))
294 select_row (sctree
, row
, col
, 0);
295 gtk_signal_emit (GTK_OBJECT (sctree
),
296 sctree_signals
[ROW_POPUP_MENU
],
299 gtk_clist_unselect_all(clist
);
300 gtk_signal_emit (GTK_OBJECT (sctree
),
301 sctree_signals
[EMPTY_POPUP_MENU
],
309 case GDK_2BUTTON_PRESS
:
310 if (event
->button
!= 1)
313 sctree
->dnd_select_pending
= FALSE
;
314 sctree
->dnd_select_pending_state
= 0;
317 gtk_signal_emit (GTK_OBJECT (sctree
),
318 sctree_signals
[OPEN_ROW
]);
330 /* Our handler for button_release events. We override all of GtkCList's broken
334 gtk_sctree_button_release (GtkWidget
*widget
, GdkEventButton
*event
)
342 g_return_val_if_fail (widget
!= NULL
, FALSE
);
343 g_return_val_if_fail (GTK_IS_SCTREE (widget
), FALSE
);
344 g_return_val_if_fail (event
!= NULL
, FALSE
);
346 sctree
= GTK_SCTREE (widget
);
347 clist
= GTK_CLIST (widget
);
350 if (event
->window
!= clist
->clist_window
)
351 return (* GTK_WIDGET_CLASS (parent_class
)->button_release_event
) (widget
, event
);
353 on_row
= gtk_clist_get_selection_info (clist
, event
->x
, event
->y
, &row
, &col
);
355 if (!(event
->button
== 1 || event
->button
== 2))
358 sctree
->dnd_press_button
= 0;
359 sctree
->dnd_press_x
= 0;
360 sctree
->dnd_press_y
= 0;
363 if (sctree
->dnd_select_pending
) {
364 select_row (sctree
, row
, col
, sctree
->dnd_select_pending_state
);
365 sctree
->dnd_select_pending
= FALSE
;
366 sctree
->dnd_select_pending_state
= 0;
375 /* Our handler for motion_notify events. We override all of GtkCList's broken
379 gtk_sctree_motion (GtkWidget
*widget
, GdkEventMotion
*event
)
384 g_return_val_if_fail (widget
!= NULL
, FALSE
);
385 g_return_val_if_fail (GTK_IS_SCTREE (widget
), FALSE
);
386 g_return_val_if_fail (event
!= NULL
, FALSE
);
388 sctree
= GTK_SCTREE (widget
);
389 clist
= GTK_CLIST (widget
);
391 if (event
->window
!= clist
->clist_window
)
392 return (* GTK_WIDGET_CLASS (parent_class
)->motion_notify_event
) (widget
, event
);
394 if (!((sctree
->dnd_press_button
== 1 && (event
->state
& GDK_BUTTON1_MASK
))
395 || (sctree
->dnd_press_button
== 2 && (event
->state
& GDK_BUTTON2_MASK
))))
398 /* This is the same threshold value that is used in gtkdnd.c */
400 if (MAX (abs (sctree
->dnd_press_x
- event
->x
),
401 abs (sctree
->dnd_press_y
- event
->y
)) <= 3)
404 /* Handle any pending selections */
406 if (sctree
->dnd_select_pending
) {
407 if (!row_is_selected(sctree
,sctree
->dnd_select_pending_row
))
409 sctree
->dnd_select_pending_row
,
411 sctree
->dnd_select_pending_state
);
413 sctree
->dnd_select_pending
= FALSE
;
414 sctree
->dnd_select_pending_state
= 0;
417 gtk_signal_emit (GTK_OBJECT (sctree
),
418 sctree_signals
[START_DRAG
],
419 sctree
->dnd_press_button
,
424 /* We override the drag_begin signal to do nothing */
426 gtk_sctree_drag_begin (GtkWidget
*widget
, GdkDragContext
*context
)
431 /* We override the drag_end signal to do nothing */
433 gtk_sctree_drag_end (GtkWidget
*widget
, GdkDragContext
*context
)
438 /* We override the drag_data_get signal to do nothing */
440 gtk_sctree_drag_data_get (GtkWidget
*widget
, GdkDragContext
*context
,
441 GtkSelectionData
*data
, guint info
, guint time
)
446 /* We override the drag_leave signal to do nothing */
448 gtk_sctree_drag_leave (GtkWidget
*widget
, GdkDragContext
*context
, guint time
)
453 /* We override the drag_motion signal to do nothing */
455 gtk_sctree_drag_motion (GtkWidget
*widget
, GdkDragContext
*context
,
456 gint x
, gint y
, guint time
)
461 /* We override the drag_drop signal to do nothing */
463 gtk_sctree_drag_drop (GtkWidget
*widget
, GdkDragContext
*context
,
464 gint x
, gint y
, guint time
)
469 /* We override the drag_data_received signal to do nothing */
471 gtk_sctree_drag_data_received (GtkWidget
*widget
, GdkDragContext
*context
,
472 gint x
, gint y
, GtkSelectionData
*data
,
473 guint info
, guint time
)
478 /* Our handler for the clear signal of the clist. We have to reset the anchor
482 gtk_sctree_clear (GtkCList
*clist
)
486 g_return_if_fail (clist
!= NULL
);
487 g_return_if_fail (GTK_IS_SCTREE (clist
));
489 sctree
= GTK_SCTREE (clist
);
490 sctree
->anchor_row
= -1;
492 if (((GtkCListClass
*)parent_class
)->clear
)
493 (* ((GtkCListClass
*)parent_class
)->clear
) (clist
);
496 /* Our handler for the change_focus_row_expansion signal of the ctree.
497 We have to set the anchor to parent visible node.
500 gtk_sctree_collapse (GtkCTree
*ctree
, GtkCTreeNode
*node
)
504 g_return_if_fail (ctree
!= NULL
);
505 g_return_if_fail (GTK_IS_SCTREE (ctree
));
507 (* parent_class
->tree_collapse
) (ctree
, node
);
508 sctree
= GTK_SCTREE (ctree
);
509 sctree
->anchor_row
= GTK_CLIST(ctree
)->focus_row
;
512 GtkWidget
*gtk_sctree_new_with_titles (gint columns
,
518 sctree
= gtk_type_new (gtk_sctree_get_type ());
519 gtk_ctree_construct (GTK_CTREE (sctree
), columns
, tree_column
, titles
);
520 gtk_clist_set_selection_mode(GTK_CLIST(sctree
), GTK_SELECTION_EXTENDED
);
522 return GTK_WIDGET (sctree
);
525 void gtk_sctree_select (GtkSCTree
*sctree
,
529 gtkut_ctree_get_nth_from_node(GTK_CTREE(sctree
),node
),
533 void gtk_sctree_unselect_all (GtkSCTree
*sctree
)
535 gtk_clist_unselect_all(GTK_CLIST(sctree
));
536 sctree
->anchor_row
= -1;