1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
3 * Copyright (C) 1997-1998 Jay Painter <jpaint@serv.net><jpaint@gimp.org>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #include "claws-marshal.h"
35 #include "gtkcmclist.h"
36 #include <gdk/gdkkeysyms.h>
40 /* length of button_actions array */
43 /* the number rows memchunk expands at a time */
44 #define CMCLIST_OPTIMUM_SIZE 64
46 /* the width of the column resize windows */
49 /* minimum allowed width of a column */
50 #define COLUMN_MIN_WIDTH 5
52 /* this defigns the base grid spacing */
53 #define CELL_SPACING 1
55 /* added the horizontal space at the beginning and end of a row*/
56 #define COLUMN_INSET 3
58 /* used for auto-scrolling */
59 #define SCROLL_TIME 100
61 /* gives the top pixel of the given row in context of
62 * the clist's voffset */
63 #define ROW_TOP_YPIXEL(clist, row) (((clist)->row_height * (row)) + \
64 (((row) + 1) * CELL_SPACING) + \
67 /* returns the row index from a y pixel location in the
68 * context of the clist's voffset */
69 #define ROW_FROM_YPIXEL(clist, y) (((y) - (clist)->voffset) / \
70 ((clist)->row_height + CELL_SPACING))
72 /* gives the left pixel of the given column in context of
73 * the clist's hoffset */
74 #define COLUMN_LEFT_XPIXEL(clist, colnum) ((clist)->column[(colnum)].area.x + \
77 static void gtk_cmclist_scrollable_init (GtkScrollableInterface
*iface
);
79 /* returns the column index from a x pixel location in the
80 * context of the clist's hoffset */
82 COLUMN_FROM_XPIXEL (GtkCMCList
* clist
,
87 for (i
= 0; i
< clist
->columns
; i
++)
88 if (clist
->column
[i
].visible
)
90 cx
= clist
->column
[i
].area
.x
+ clist
->hoffset
;
92 if (x
>= (cx
- (COLUMN_INSET
+ CELL_SPACING
)) &&
93 x
<= (cx
+ clist
->column
[i
].area
.width
+ COLUMN_INSET
))
101 /* returns the top pixel of the given row in the context of
103 #define ROW_TOP(clist, row) (((clist)->row_height + CELL_SPACING) * (row))
105 /* returns the left pixel of the given column in the context of
107 #define COLUMN_LEFT(clist, colnum) ((clist)->column[(colnum)].area.x)
109 /* returns the total height of the list */
110 #define LIST_HEIGHT(clist) (((clist)->row_height * ((clist)->rows)) + \
111 (CELL_SPACING * ((clist)->rows + 1)))
114 /* returns the total width of the list */
116 LIST_WIDTH (GtkCMCList
* clist
)
120 for (last_column
= clist
->columns
- 1;
121 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--);
123 if (last_column
>= 0)
124 return (clist
->column
[last_column
].area
.x
+
125 clist
->column
[last_column
].area
.width
+
126 COLUMN_INSET
+ CELL_SPACING
);
130 /* returns the GList item for the nth row */
131 #define ROW_ELEMENT(clist, row) (((row) == (clist)->rows - 1) ? \
132 (clist)->row_list_end : \
133 g_list_nth ((clist)->row_list, (row)))
136 /* redraw the list if it's not frozen */
137 #define CLIST_UNFROZEN(clist) (((GtkCMCList*) (clist))->freeze_count == 0)
138 #define CLIST_REFRESH(clist) G_STMT_START { \
139 if (CLIST_UNFROZEN (clist)) \
140 GTK_CMCLIST_GET_CLASS (clist)->refresh ((GtkCMCList*) (clist)); \
186 /* GtkCMCList Methods */
187 static void gtk_cmclist_class_init (GtkCMCListClass
*klass
);
188 static void gtk_cmclist_init (GtkCMCList
*clist
);
189 static GObject
* gtk_cmclist_constructor (GType type
,
190 guint n_construct_properties
,
191 GObjectConstructParam
*construct_params
);
193 /* GtkObject Methods */
194 static void gtk_cmclist_destroy (GtkWidget
*object
);
195 static void gtk_cmclist_finalize (GObject
*object
);
196 static void gtk_cmclist_set_arg (GObject
*object
,
200 static void gtk_cmclist_get_arg (GObject
*object
,
205 /* GtkWidget Methods */
206 static void gtk_cmclist_realize (GtkWidget
*widget
);
207 static void gtk_cmclist_unrealize (GtkWidget
*widget
);
208 static void gtk_cmclist_map (GtkWidget
*widget
);
209 static void gtk_cmclist_unmap (GtkWidget
*widget
);
210 static gint
gtk_cmclist_draw (GtkWidget
*widget
,
212 static gint
gtk_cmclist_button_press (GtkWidget
*widget
,
213 GdkEventButton
*event
);
214 static gint
gtk_cmclist_button_release (GtkWidget
*widget
,
215 GdkEventButton
*event
);
216 static gint
gtk_cmclist_motion (GtkWidget
*widget
,
217 GdkEventMotion
*event
);
218 static void gtk_cmclist_get_preferred_height (GtkWidget
*widget
,
219 gint
*minimal_height
,
220 gint
*natural_height
);
221 static void gtk_cmclist_get_preferred_width (GtkWidget
*widget
,
223 gint
*natural_width
);
224 static void gtk_cmclist_size_request (GtkWidget
*widget
,
225 GtkRequisition
*requisition
);
226 static void gtk_cmclist_size_allocate (GtkWidget
*widget
,
227 GtkAllocation
*allocation
);
228 static void gtk_cmclist_undraw_focus (GtkWidget
*widget
);
229 static void gtk_cmclist_draw_focus (GtkWidget
*widget
);
230 static gint
gtk_cmclist_focus_in (GtkWidget
*widget
,
231 GdkEventFocus
*event
);
232 static gint
gtk_cmclist_focus_out (GtkWidget
*widget
,
233 GdkEventFocus
*event
);
234 static gint
gtk_cmclist_focus (GtkWidget
*widget
,
235 GtkDirectionType direction
);
236 static void gtk_cmclist_set_focus_child (GtkContainer
*container
,
238 static void gtk_cmclist_style_set (GtkWidget
*widget
,
239 GtkStyle
*previous_style
);
240 static void gtk_cmclist_drag_begin (GtkWidget
*widget
,
241 GdkDragContext
*context
);
242 static gint
gtk_cmclist_drag_motion (GtkWidget
*widget
,
243 GdkDragContext
*context
,
247 static void gtk_cmclist_drag_leave (GtkWidget
*widget
,
248 GdkDragContext
*context
,
250 static void gtk_cmclist_drag_end (GtkWidget
*widget
,
251 GdkDragContext
*context
);
252 static gboolean
gtk_cmclist_drag_drop (GtkWidget
*widget
,
253 GdkDragContext
*context
,
257 static void gtk_cmclist_drag_data_get (GtkWidget
*widget
,
258 GdkDragContext
*context
,
259 GtkSelectionData
*selection_data
,
262 static void gtk_cmclist_drag_data_received (GtkWidget
*widget
,
263 GdkDragContext
*context
,
266 GtkSelectionData
*selection_data
,
270 /* GtkContainer Methods */
271 static void gtk_cmclist_forall (GtkContainer
*container
,
272 gboolean include_internals
,
273 GtkCallback callback
,
274 gpointer callback_data
);
277 static void toggle_row (GtkCMCList
*clist
,
281 static void real_select_row (GtkCMCList
*clist
,
285 static void real_unselect_row (GtkCMCList
*clist
,
289 static void update_extended_selection (GtkCMCList
*clist
,
291 static GList
*selection_find (GtkCMCList
*clist
,
293 GList
*row_list_element
);
294 static void real_select_all (GtkCMCList
*clist
);
295 static void real_unselect_all (GtkCMCList
*clist
);
296 static void move_vertical (GtkCMCList
*clist
,
299 static void move_horizontal (GtkCMCList
*clist
,
301 static void real_undo_selection (GtkCMCList
*clist
);
302 static void fake_unselect_all (GtkCMCList
*clist
,
304 static void fake_toggle_row (GtkCMCList
*clist
,
306 static void resync_selection (GtkCMCList
*clist
,
308 static void sync_selection (GtkCMCList
*clist
,
311 static void set_anchor (GtkCMCList
*clist
,
315 static void start_selection (GtkCMCList
*clist
);
316 static void end_selection (GtkCMCList
*clist
);
317 static void toggle_add_mode (GtkCMCList
*clist
);
318 static void toggle_focus_row (GtkCMCList
*clist
);
319 static void extend_selection (GtkCMCList
*clist
,
320 GtkScrollType scroll_type
,
322 gboolean auto_start_selection
);
323 static gint
get_selection_info (GtkCMCList
*clist
,
330 static void move_focus_row (GtkCMCList
*clist
,
331 GtkScrollType scroll_type
,
333 static void scroll_horizontal (GtkCMCList
*clist
,
334 GtkScrollType scroll_type
,
336 static void scroll_vertical (GtkCMCList
*clist
,
337 GtkScrollType scroll_type
,
339 static void move_horizontal (GtkCMCList
*clist
,
341 static void move_vertical (GtkCMCList
*clist
,
344 static gint
horizontal_timeout (GtkCMCList
*clist
);
345 static gint
vertical_timeout (GtkCMCList
*clist
);
346 static void remove_grab (GtkCMCList
*clist
);
350 static void draw_xor_line (GtkCMCList
*clist
);
351 static gint
new_column_width (GtkCMCList
*clist
,
354 static void column_auto_resize (GtkCMCList
*clist
,
355 GtkCMCListRow
*clist_row
,
358 static void real_resize_column (GtkCMCList
*clist
,
361 static void abort_column_resize (GtkCMCList
*clist
);
362 static void cell_size_request (GtkCMCList
*clist
,
363 GtkCMCListRow
*clist_row
,
365 GtkRequisition
*requisition
);
368 static void column_button_create (GtkCMCList
*clist
,
370 static void column_button_clicked (GtkWidget
*widget
,
374 static void adjust_adjustments (GtkCMCList
*clist
,
375 gboolean block_resize
);
376 static void vadjustment_value_changed (GtkAdjustment
*adjustment
,
378 static void hadjustment_value_changed (GtkAdjustment
*adjustment
,
382 static void get_cell_style (GtkCMCList
*clist
,
383 GtkCMCListRow
*clist_row
,
387 static gint
draw_cell_pixbuf (GdkWindow
*window
,
388 GdkRectangle
*clip_rectangle
,
395 static void draw_row (GtkCMCList
*clist
,
398 GtkCMCListRow
*clist_row
);
399 static void draw_rows (GtkCMCList
*clist
,
401 static void clist_refresh (GtkCMCList
*clist
);
403 /* Size Allocation / Requisition */
404 static void size_allocate_title_buttons (GtkCMCList
*clist
);
405 static void size_allocate_columns (GtkCMCList
*clist
,
406 gboolean block_resize
);
407 static gint
list_requisition_width (GtkCMCList
*clist
);
409 /* Memory Allocation/Distruction Routines */
410 static GtkCMCListColumn
*columns_new (GtkCMCList
*clist
);
411 static void column_title_new (GtkCMCList
*clist
,
414 static void columns_delete (GtkCMCList
*clist
);
415 static GtkCMCListRow
*row_new (GtkCMCList
*clist
);
416 static void row_delete (GtkCMCList
*clist
,
417 GtkCMCListRow
*clist_row
);
418 static void set_cell_contents (GtkCMCList
*clist
,
419 GtkCMCListRow
*clist_row
,
425 static gint
real_insert_row (GtkCMCList
*clist
,
428 static void real_remove_row (GtkCMCList
*clist
,
430 static void real_clear (GtkCMCList
*clist
);
433 static gint
default_compare (GtkCMCList
*clist
,
436 static void real_sort_list (GtkCMCList
*clist
);
437 static GList
*gtk_cmclist_merge (GtkCMCList
*clist
,
440 static GList
*gtk_cmclist_mergesort (GtkCMCList
*clist
,
444 static gboolean
title_focus_in (GtkCMCList
*clist
,
446 static gboolean
title_focus_move (GtkCMCList
*clist
,
449 static void real_row_move (GtkCMCList
*clist
,
452 static gint
column_title_passive_func (GtkWidget
*widget
,
455 static void drag_dest_cell (GtkCMCList
*clist
,
458 GtkCMCListDestInfo
*dest_info
);
462 static guint clist_signals
[LAST_SIGNAL
] = {0};
464 static const GtkTargetEntry clist_target_table
= { "gtk-clist-drag-reorder", 0, 0};
466 G_DEFINE_TYPE_WITH_CODE (GtkCMCList
, gtk_cmclist
, GTK_TYPE_CONTAINER
,
467 G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE
,
468 gtk_cmclist_scrollable_init
))
471 gtk_cmclist_class_init (GtkCMCListClass
*klass
)
473 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
475 GtkWidgetClass
*widget_class
;
476 GtkContainerClass
*container_class
;
477 GtkBindingSet
*binding_set
;
479 object_class
->constructor
= gtk_cmclist_constructor
;
481 widget_class
= (GtkWidgetClass
*) klass
;
482 container_class
= (GtkContainerClass
*) klass
;
484 object_class
->finalize
= gtk_cmclist_finalize
;
485 widget_class
->destroy
= gtk_cmclist_destroy
;
486 object_class
->set_property
= gtk_cmclist_set_arg
;
487 object_class
->get_property
= gtk_cmclist_get_arg
;
490 widget_class
->realize
= gtk_cmclist_realize
;
491 widget_class
->unrealize
= gtk_cmclist_unrealize
;
492 widget_class
->map
= gtk_cmclist_map
;
493 widget_class
->unmap
= gtk_cmclist_unmap
;
494 widget_class
->button_press_event
= gtk_cmclist_button_press
;
495 widget_class
->button_release_event
= gtk_cmclist_button_release
;
496 widget_class
->motion_notify_event
= gtk_cmclist_motion
;
497 widget_class
->draw
= gtk_cmclist_draw
;
499 widget_class
->get_preferred_width
= gtk_cmclist_get_preferred_width
;
500 widget_class
->get_preferred_height
= gtk_cmclist_get_preferred_height
;
501 widget_class
->size_allocate
= gtk_cmclist_size_allocate
;
502 widget_class
->focus_in_event
= gtk_cmclist_focus_in
;
503 widget_class
->focus_out_event
= gtk_cmclist_focus_out
;
504 widget_class
->style_set
= gtk_cmclist_style_set
;
505 widget_class
->drag_begin
= gtk_cmclist_drag_begin
;
506 widget_class
->drag_end
= gtk_cmclist_drag_end
;
507 widget_class
->drag_motion
= gtk_cmclist_drag_motion
;
508 widget_class
->drag_leave
= gtk_cmclist_drag_leave
;
509 widget_class
->drag_drop
= gtk_cmclist_drag_drop
;
510 widget_class
->drag_data_get
= gtk_cmclist_drag_data_get
;
511 widget_class
->drag_data_received
= gtk_cmclist_drag_data_received
;
512 widget_class
->focus
= gtk_cmclist_focus
;
514 /* container_class->add = NULL; use the default GtkContainerClass warning */
515 /* container_class->remove=NULL; use the default GtkContainerClass warning */
517 container_class
->forall
= gtk_cmclist_forall
;
518 container_class
->set_focus_child
= gtk_cmclist_set_focus_child
;
520 klass
->refresh
= clist_refresh
;
521 klass
->select_row
= real_select_row
;
522 klass
->unselect_row
= real_unselect_row
;
523 klass
->row_move
= real_row_move
;
524 klass
->undo_selection
= real_undo_selection
;
525 klass
->resync_selection
= resync_selection
;
526 klass
->selection_find
= selection_find
;
527 klass
->click_column
= NULL
;
528 klass
->resize_column
= real_resize_column
;
529 klass
->draw_row
= draw_row
;
530 klass
->insert_row
= real_insert_row
;
531 klass
->remove_row
= real_remove_row
;
532 klass
->clear
= real_clear
;
533 klass
->sort_list
= real_sort_list
;
534 klass
->select_all
= real_select_all
;
535 klass
->unselect_all
= real_unselect_all
;
536 klass
->fake_unselect_all
= fake_unselect_all
;
537 klass
->scroll_horizontal
= scroll_horizontal
;
538 klass
->scroll_vertical
= scroll_vertical
;
539 klass
->extend_selection
= extend_selection
;
540 klass
->toggle_focus_row
= toggle_focus_row
;
541 klass
->toggle_add_mode
= toggle_add_mode
;
542 klass
->start_selection
= start_selection
;
543 klass
->end_selection
= end_selection
;
544 klass
->abort_column_resize
= abort_column_resize
;
545 klass
->set_cell_contents
= set_cell_contents
;
546 klass
->cell_size_request
= cell_size_request
;
548 g_object_class_install_property (object_class
,
550 g_param_spec_uint ("n-columns",
556 G_PARAM_READWRITE
|G_PARAM_CONSTRUCT_ONLY
));
557 g_object_class_install_property (object_class
,
559 g_param_spec_enum ("shadow-type",
562 GTK_TYPE_SHADOW_TYPE
, 0,
564 g_object_class_install_property (object_class
,
566 g_param_spec_enum ("selection-mode",
569 GTK_TYPE_SELECTION_MODE
, 0,
571 g_object_class_install_property (object_class
,
573 g_param_spec_uint ("row-height",
580 g_object_class_install_property (object_class
,
582 g_param_spec_boolean ("reorderable",
587 g_object_class_install_property (object_class
,
589 g_param_spec_boolean ("titles-active",
594 g_object_class_install_property (object_class
,
596 g_param_spec_boolean ("use-drag-icons",
601 g_object_class_install_property (object_class
,
603 g_param_spec_enum ("sort-type",
606 GTK_TYPE_SORT_TYPE
, 0,
608 /* Scrollable interface properties */
609 g_object_class_override_property (object_class
, ARG_HADJUSTMENT
, "hadjustment");
610 g_object_class_override_property (object_class
, ARG_VADJUSTMENT
, "vadjustment");
611 g_object_class_override_property (object_class
, ARG_HSCROLL_POLICY
, "hscroll-policy");
612 g_object_class_override_property (object_class
, ARG_VSCROLL_POLICY
, "vscroll-policy");
614 clist_signals
[SELECT_ROW
] =
615 g_signal_new ("select_row",
616 G_TYPE_FROM_CLASS (object_class
),
618 G_STRUCT_OFFSET (GtkCMCListClass
, select_row
),
620 claws_marshal_VOID__INT_INT_BOXED
,
624 GDK_TYPE_EVENT
| G_SIGNAL_TYPE_STATIC_SCOPE
);
625 clist_signals
[UNSELECT_ROW
] =
626 g_signal_new ("unselect_row",
627 G_TYPE_FROM_CLASS (object_class
),
629 G_STRUCT_OFFSET (GtkCMCListClass
, unselect_row
),
631 claws_marshal_VOID__INT_INT_BOXED
,
636 clist_signals
[ROW_MOVE
] =
637 g_signal_new ("row_move",
638 G_TYPE_FROM_CLASS (object_class
),
640 G_STRUCT_OFFSET (GtkCMCListClass
, row_move
),
642 claws_marshal_VOID__INT_INT
,
643 G_TYPE_NONE
, 2, G_TYPE_INT
, G_TYPE_INT
);
644 clist_signals
[CLICK_COLUMN
] =
645 g_signal_new ("click_column",
646 G_TYPE_FROM_CLASS (object_class
),
648 G_STRUCT_OFFSET (GtkCMCListClass
, click_column
),
650 claws_marshal_VOID__INT
,
651 G_TYPE_NONE
, 1, G_TYPE_INT
);
652 clist_signals
[RESIZE_COLUMN
] =
653 g_signal_new ("resize_column",
654 G_TYPE_FROM_CLASS (object_class
),
656 G_STRUCT_OFFSET (GtkCMCListClass
, resize_column
),
658 claws_marshal_VOID__INT_INT
,
659 G_TYPE_NONE
, 2, G_TYPE_INT
, G_TYPE_INT
);
661 clist_signals
[TOGGLE_FOCUS_ROW
] =
662 g_signal_new ("toggle_focus_row",
663 G_TYPE_FROM_CLASS (object_class
),
664 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
665 G_STRUCT_OFFSET (GtkCMCListClass
, toggle_focus_row
),
667 claws_marshal_VOID__VOID
,
669 clist_signals
[SELECT_ALL
] =
670 g_signal_new ("select_all",
671 G_TYPE_FROM_CLASS (object_class
),
672 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
673 G_STRUCT_OFFSET (GtkCMCListClass
, select_all
),
675 claws_marshal_VOID__VOID
,
677 clist_signals
[UNSELECT_ALL
] =
678 g_signal_new ("unselect_all",
679 G_TYPE_FROM_CLASS (object_class
),
680 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
681 G_STRUCT_OFFSET (GtkCMCListClass
, unselect_all
),
683 claws_marshal_VOID__VOID
,
685 clist_signals
[UNDO_SELECTION
] =
686 g_signal_new ("undo_selection",
687 G_TYPE_FROM_CLASS (object_class
),
688 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
689 G_STRUCT_OFFSET (GtkCMCListClass
, undo_selection
),
691 claws_marshal_VOID__VOID
,
693 clist_signals
[START_SELECTION
] =
694 g_signal_new ("start_selection",
695 G_TYPE_FROM_CLASS (object_class
),
696 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
697 G_STRUCT_OFFSET (GtkCMCListClass
, start_selection
),
699 claws_marshal_VOID__VOID
,
701 clist_signals
[END_SELECTION
] =
702 g_signal_new ("end_selection",
703 G_TYPE_FROM_CLASS (object_class
),
704 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
705 G_STRUCT_OFFSET (GtkCMCListClass
, end_selection
),
707 claws_marshal_VOID__VOID
,
709 clist_signals
[TOGGLE_ADD_MODE
] =
710 g_signal_new ("toggle_add_mode",
711 G_TYPE_FROM_CLASS (object_class
),
712 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
713 G_STRUCT_OFFSET (GtkCMCListClass
, toggle_add_mode
),
715 claws_marshal_VOID__VOID
,
717 clist_signals
[EXTEND_SELECTION
] =
718 g_signal_new ("extend_selection",
719 G_TYPE_FROM_CLASS (object_class
),
720 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
721 G_STRUCT_OFFSET (GtkCMCListClass
, extend_selection
),
723 claws_marshal_VOID__ENUM_FLOAT_BOOLEAN
,
724 G_TYPE_NONE
, 3, GTK_TYPE_SCROLL_TYPE
, G_TYPE_FLOAT
, G_TYPE_BOOLEAN
);
725 clist_signals
[SCROLL_VERTICAL
] =
726 g_signal_new ("scroll_vertical",
727 G_TYPE_FROM_CLASS (object_class
),
728 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
729 G_STRUCT_OFFSET (GtkCMCListClass
, scroll_vertical
),
731 claws_marshal_VOID__ENUM_FLOAT
,
732 G_TYPE_NONE
, 2, GTK_TYPE_SCROLL_TYPE
, G_TYPE_FLOAT
);
733 clist_signals
[SCROLL_HORIZONTAL
] =
734 g_signal_new ("scroll_horizontal",
735 G_TYPE_FROM_CLASS (object_class
),
736 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
737 G_STRUCT_OFFSET (GtkCMCListClass
, scroll_horizontal
),
739 claws_marshal_VOID__ENUM_FLOAT
,
740 G_TYPE_NONE
, 2, GTK_TYPE_SCROLL_TYPE
, G_TYPE_FLOAT
);
741 clist_signals
[ABORT_COLUMN_RESIZE
] =
742 g_signal_new ("abort_column_resize",
743 G_TYPE_FROM_CLASS (object_class
),
744 G_SIGNAL_RUN_LAST
| G_SIGNAL_ACTION
,
745 G_STRUCT_OFFSET (GtkCMCListClass
, abort_column_resize
),
747 claws_marshal_VOID__VOID
,
750 binding_set
= gtk_binding_set_by_class (klass
);
751 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Up
, 0,
752 "scroll_vertical", 2,
753 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
755 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Up
, 0,
756 "scroll_vertical", 2,
757 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
759 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Down
, 0,
760 "scroll_vertical", 2,
761 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
763 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Down
, 0,
764 "scroll_vertical", 2,
765 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
767 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Page_Up
, 0,
768 "scroll_vertical", 2,
769 G_TYPE_ENUM
, GTK_SCROLL_PAGE_BACKWARD
,
771 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Page_Up
, 0,
772 "scroll_vertical", 2,
773 G_TYPE_ENUM
, GTK_SCROLL_PAGE_BACKWARD
,
775 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Page_Down
, 0,
776 "scroll_vertical", 2,
777 G_TYPE_ENUM
, GTK_SCROLL_PAGE_FORWARD
,
779 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Page_Down
, 0,
780 "scroll_vertical", 2,
781 G_TYPE_ENUM
, GTK_SCROLL_PAGE_FORWARD
,
783 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Home
, GDK_CONTROL_MASK
,
784 "scroll_vertical", 2,
785 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
787 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Home
, GDK_CONTROL_MASK
,
788 "scroll_vertical", 2,
789 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
791 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_End
, GDK_CONTROL_MASK
,
792 "scroll_vertical", 2,
793 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
795 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_End
, GDK_CONTROL_MASK
,
796 "scroll_vertical", 2,
797 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
800 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Up
, GDK_SHIFT_MASK
,
801 "extend_selection", 3,
802 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
803 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
804 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Up
, GDK_SHIFT_MASK
,
805 "extend_selection", 3,
806 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
807 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
808 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Down
, GDK_SHIFT_MASK
,
809 "extend_selection", 3,
810 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
811 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
812 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Down
, GDK_SHIFT_MASK
,
813 "extend_selection", 3,
814 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
815 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
816 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Page_Up
, GDK_SHIFT_MASK
,
817 "extend_selection", 3,
818 G_TYPE_ENUM
, GTK_SCROLL_PAGE_BACKWARD
,
819 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
820 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Page_Up
, GDK_SHIFT_MASK
,
821 "extend_selection", 3,
822 G_TYPE_ENUM
, GTK_SCROLL_PAGE_BACKWARD
,
823 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
824 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Page_Down
, GDK_SHIFT_MASK
,
825 "extend_selection", 3,
826 G_TYPE_ENUM
, GTK_SCROLL_PAGE_FORWARD
,
827 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
828 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Page_Down
, GDK_SHIFT_MASK
,
829 "extend_selection", 3,
830 G_TYPE_ENUM
, GTK_SCROLL_PAGE_FORWARD
,
831 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
832 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Home
,
833 GDK_SHIFT_MASK
| GDK_CONTROL_MASK
,
834 "extend_selection", 3,
835 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
836 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
837 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Home
,
838 GDK_SHIFT_MASK
| GDK_CONTROL_MASK
,
839 "extend_selection", 3,
840 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
841 G_TYPE_FLOAT
, 0.0, G_TYPE_BOOLEAN
, TRUE
);
842 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_End
,
843 GDK_SHIFT_MASK
| GDK_CONTROL_MASK
,
844 "extend_selection", 3,
845 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
846 G_TYPE_FLOAT
, 1.0, G_TYPE_BOOLEAN
, TRUE
);
847 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_End
,
848 GDK_SHIFT_MASK
| GDK_CONTROL_MASK
,
849 "extend_selection", 3,
850 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
851 G_TYPE_FLOAT
, 1.0, G_TYPE_BOOLEAN
, TRUE
);
854 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Left
, 0,
855 "scroll_horizontal", 2,
856 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
858 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Left
, 0,
859 "scroll_horizontal", 2,
860 G_TYPE_ENUM
, GTK_SCROLL_STEP_BACKWARD
,
863 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Right
, 0,
864 "scroll_horizontal", 2,
865 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
867 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Right
, 0,
868 "scroll_horizontal", 2,
869 G_TYPE_ENUM
, GTK_SCROLL_STEP_FORWARD
,
872 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Home
, 0,
873 "scroll_horizontal", 2,
874 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
876 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Home
, 0,
877 "scroll_horizontal", 2,
878 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
881 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_End
, 0,
882 "scroll_horizontal", 2,
883 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
886 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_End
, 0,
887 "scroll_horizontal", 2,
888 G_TYPE_ENUM
, GTK_SCROLL_JUMP
,
891 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Escape
, 0,
892 "undo_selection", 0);
893 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Escape
, 0,
894 "abort_column_resize", 0);
895 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_space
, 0,
896 "toggle_focus_row", 0);
897 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Space
, 0,
898 "toggle_focus_row", 0);
899 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_space
, GDK_CONTROL_MASK
,
900 "toggle_add_mode", 0);
901 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Space
, GDK_CONTROL_MASK
,
902 "toggle_add_mode", 0);
903 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_slash
, GDK_CONTROL_MASK
,
905 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_KP_Divide
, GDK_CONTROL_MASK
,
907 gtk_binding_entry_add_signal (binding_set
, '\\', GDK_CONTROL_MASK
,
909 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Shift_L
,
910 GDK_RELEASE_MASK
| GDK_SHIFT_MASK
,
912 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Shift_R
,
913 GDK_RELEASE_MASK
| GDK_SHIFT_MASK
,
915 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Shift_L
,
916 GDK_RELEASE_MASK
| GDK_SHIFT_MASK
|
919 gtk_binding_entry_add_signal (binding_set
, GDK_KEY_Shift_R
,
920 GDK_RELEASE_MASK
| GDK_SHIFT_MASK
|
926 gtk_cmclist_set_arg (GObject
*object
,
933 clist
= GTK_CMCLIST (object
);
937 case ARG_N_COLUMNS
: /* only set at construction time */
938 clist
->columns
= MAX (1, g_value_get_uint (value
));
940 case ARG_SHADOW_TYPE
:
941 gtk_cmclist_set_shadow_type (clist
, g_value_get_enum (value
));
943 case ARG_SELECTION_MODE
:
944 gtk_cmclist_set_selection_mode (clist
, g_value_get_enum (value
));
947 gtk_cmclist_set_row_height (clist
, g_value_get_uint (value
));
949 case ARG_REORDERABLE
:
950 gtk_cmclist_set_reorderable (clist
, g_value_get_boolean (value
));
952 case ARG_TITLES_ACTIVE
:
953 if (g_value_get_boolean (value
))
954 gtk_cmclist_column_titles_active (clist
);
956 gtk_cmclist_column_titles_passive (clist
);
958 case ARG_USE_DRAG_ICONS
:
959 gtk_cmclist_set_use_drag_icons (clist
, g_value_get_boolean (value
));
962 gtk_cmclist_set_sort_type (clist
, g_value_get_enum (value
));
964 case ARG_HADJUSTMENT
:
965 gtk_cmclist_set_hadjustment (clist
, g_value_get_object (value
));
967 case ARG_VADJUSTMENT
:
968 gtk_cmclist_set_vadjustment (clist
, g_value_get_object (value
));
970 case ARG_HSCROLL_POLICY
:
971 case ARG_VSCROLL_POLICY
:
977 gtk_cmclist_get_arg (GObject
*object
,
984 clist
= GTK_CMCLIST (object
);
991 g_value_set_uint(value
, clist
->columns
);
993 case ARG_SHADOW_TYPE
:
994 g_value_set_enum(value
, clist
->shadow_type
);
996 case ARG_SELECTION_MODE
:
997 g_value_set_enum(value
, clist
->selection_mode
);
1000 g_value_set_uint(value
, GTK_CMCLIST_ROW_HEIGHT_SET(clist
) ? clist
->row_height
: 0);
1002 case ARG_REORDERABLE
:
1003 g_value_set_boolean(value
, GTK_CMCLIST_REORDERABLE (clist
));
1005 case ARG_TITLES_ACTIVE
:
1006 g_value_set_boolean(value
, TRUE
);
1007 for (i
= 0; i
< clist
->columns
; i
++)
1008 if (clist
->column
[i
].button
&&
1009 !gtk_widget_get_sensitive (clist
->column
[i
].button
))
1011 g_value_set_boolean(value
, FALSE
);
1015 case ARG_USE_DRAG_ICONS
:
1016 g_value_set_boolean(value
, GTK_CMCLIST_USE_DRAG_ICONS (clist
));
1019 g_value_set_enum(value
, clist
->sort_type
);
1021 case ARG_HADJUSTMENT
:
1022 g_value_set_object(value
, gtk_cmclist_get_hadjustment(clist
));
1024 case ARG_VADJUSTMENT
:
1025 g_value_set_object(value
, gtk_cmclist_get_vadjustment(clist
));
1027 case ARG_HSCROLL_POLICY
:
1028 case ARG_VSCROLL_POLICY
:
1029 g_value_set_enum(value
, GTK_SCROLL_NATURAL
);
1032 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, arg_id
, spec
);
1038 gtk_cmclist_init (GtkCMCList
*clist
)
1042 gtk_widget_set_has_window (GTK_WIDGET(clist
), TRUE
);
1043 gtk_widget_set_can_focus (GTK_WIDGET(clist
), TRUE
);
1044 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_DRAW_DRAG_LINE
);
1045 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_USE_DRAG_ICONS
);
1047 clist
->freeze_count
= 0;
1050 clist
->row_height
= 0;
1051 clist
->row_list
= NULL
;
1052 clist
->row_list_end
= NULL
;
1056 clist
->title_window
= NULL
;
1057 clist
->column_title_area
.x
= 0;
1058 clist
->column_title_area
.y
= 0;
1059 clist
->column_title_area
.width
= 1;
1060 clist
->column_title_area
.height
= 1;
1062 clist
->clist_window
= NULL
;
1063 clist
->clist_window_width
= 1;
1064 clist
->clist_window_height
= 1;
1069 clist
->shadow_type
= GTK_SHADOW_IN
;
1070 clist
->vadjustment
= NULL
;
1071 clist
->hadjustment
= NULL
;
1073 clist
->button_actions
[0] = GTK_CMBUTTON_SELECTS
| GTK_CMBUTTON_DRAGS
;
1074 clist
->button_actions
[1] = GTK_CMBUTTON_IGNORED
;
1075 clist
->button_actions
[2] = GTK_CMBUTTON_IGNORED
;
1076 clist
->button_actions
[3] = GTK_CMBUTTON_IGNORED
;
1077 clist
->button_actions
[4] = GTK_CMBUTTON_IGNORED
;
1079 clist
->cursor_drag
= NULL
;
1082 clist
->selection_mode
= GTK_SELECTION_SINGLE
;
1083 clist
->selection
= NULL
;
1084 clist
->selection_end
= NULL
;
1085 clist
->undo_selection
= NULL
;
1086 clist
->undo_unselection
= NULL
;
1088 clist
->focus_row
= -1;
1089 clist
->focus_header_column
= -1;
1090 clist
->undo_anchor
= -1;
1093 clist
->anchor_state
= GTK_STATE_SELECTED
;
1094 clist
->drag_pos
= -1;
1098 clist
->click_cell
.row
= -1;
1099 clist
->click_cell
.column
= -1;
1101 clist
->compare
= default_compare
;
1102 clist
->sort_type
= GTK_SORT_ASCENDING
;
1103 clist
->sort_column
= 0;
1105 clist
->drag_highlight_row
= -1;
1110 gtk_cmclist_constructor (GType type
,
1111 guint n_construct_properties
,
1112 GObjectConstructParam
*construct_properties
)
1114 GObject
*object
= G_OBJECT_CLASS (gtk_cmclist_parent_class
)->constructor (type
,
1115 n_construct_properties
,
1116 construct_properties
);
1117 GtkCMCList
*clist
= GTK_CMCLIST (object
);
1119 /* allocate memory for columns */
1120 clist
->column
= columns_new (clist
);
1122 /* there needs to be at least one column button
1123 * because there is alot of code that will break if it
1126 column_button_create (clist
, 0);
1128 clist
->draw_now
= 1;
1133 /* GTKCLIST PUBLIC INTERFACE
1135 * gtk_cmclist_new_with_titles
1136 * gtk_cmclist_set_hadjustment
1137 * gtk_cmclist_set_vadjustment
1138 * gtk_cmclist_get_hadjustment
1139 * gtk_cmclist_get_vadjustment
1140 * gtk_cmclist_set_shadow_type
1141 * gtk_cmclist_set_selection_mode
1142 * gtk_cmclist_freeze
1146 gtk_cmclist_new (gint columns
)
1148 return gtk_cmclist_new_with_titles (columns
, NULL
);
1152 gtk_cmclist_new_with_titles (gint columns
,
1157 clist
= g_object_new (GTK_TYPE_CMCLIST
,
1158 "n_columns", columns
,
1164 for (i
= 0; i
< clist
->columns
; i
++)
1165 gtk_cmclist_set_column_title (clist
, i
, titles
[i
]);
1166 gtk_cmclist_column_titles_show (clist
);
1169 gtk_cmclist_column_titles_hide (clist
);
1171 return GTK_WIDGET (clist
);
1175 gtk_cmclist_set_hadjustment (GtkCMCList
*clist
,
1176 GtkAdjustment
*adjustment
)
1178 GtkAdjustment
*old_adjustment
;
1180 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1182 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment
));
1184 if (clist
->hadjustment
== adjustment
)
1187 old_adjustment
= clist
->hadjustment
;
1189 if (clist
->hadjustment
)
1191 g_signal_handlers_disconnect_matched(G_OBJECT (clist
->hadjustment
), G_SIGNAL_MATCH_DATA
,
1194 g_object_unref (G_OBJECT (clist
->hadjustment
));
1197 clist
->hadjustment
= adjustment
;
1199 if (clist
->hadjustment
)
1201 g_object_ref_sink (clist
->hadjustment
);
1202 g_signal_connect (G_OBJECT (clist
->hadjustment
), "value_changed",
1203 G_CALLBACK( hadjustment_value_changed
),
1207 if (!clist
->hadjustment
|| !old_adjustment
)
1208 gtk_widget_queue_resize (GTK_WIDGET (clist
));
1212 gtk_cmclist_get_hadjustment (GtkCMCList
*clist
)
1214 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
1216 return clist
->hadjustment
;
1220 gtk_cmclist_set_vadjustment (GtkCMCList
*clist
,
1221 GtkAdjustment
*adjustment
)
1223 GtkAdjustment
*old_adjustment
;
1225 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1227 cm_return_if_fail (GTK_IS_ADJUSTMENT (adjustment
));
1229 if (clist
->vadjustment
== adjustment
)
1232 old_adjustment
= clist
->vadjustment
;
1234 if (clist
->vadjustment
)
1236 g_signal_handlers_disconnect_matched(G_OBJECT (clist
->vadjustment
), G_SIGNAL_MATCH_DATA
,
1238 g_object_unref (G_OBJECT (clist
->vadjustment
));
1241 clist
->vadjustment
= adjustment
;
1243 if (clist
->vadjustment
)
1245 g_object_ref_sink (clist
->vadjustment
);
1247 g_signal_connect (G_OBJECT (clist
->vadjustment
), "value_changed",
1248 G_CALLBACK(vadjustment_value_changed
),
1252 if (!clist
->vadjustment
|| !old_adjustment
)
1253 gtk_widget_queue_resize (GTK_WIDGET (clist
));
1257 gtk_cmclist_get_vadjustment (GtkCMCList
*clist
)
1259 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
1261 return clist
->vadjustment
;
1265 gtk_cmclist_set_shadow_type (GtkCMCList
*clist
,
1268 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1270 clist
->shadow_type
= type
;
1272 if (gtk_widget_get_visible (GTK_WIDGET(clist
)))
1273 gtk_widget_queue_resize (GTK_WIDGET (clist
));
1277 gtk_cmclist_set_selection_mode (GtkCMCList
*clist
,
1278 GtkSelectionMode mode
)
1280 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1281 cm_return_if_fail (mode
!= GTK_SELECTION_NONE
);
1283 if (mode
== clist
->selection_mode
)
1286 clist
->selection_mode
= mode
;
1288 clist
->anchor_state
= GTK_STATE_SELECTED
;
1289 clist
->drag_pos
= -1;
1290 clist
->undo_anchor
= clist
->focus_row
;
1292 g_list_free (clist
->undo_selection
);
1293 g_list_free (clist
->undo_unselection
);
1294 clist
->undo_selection
= NULL
;
1295 clist
->undo_unselection
= NULL
;
1299 case GTK_SELECTION_MULTIPLE
:
1301 case GTK_SELECTION_BROWSE
:
1302 case GTK_SELECTION_SINGLE
:
1303 gtk_cmclist_unselect_all (clist
);
1306 /* Someone set it by hand */
1307 g_assert_not_reached ();
1312 gtk_cmclist_freeze (GtkCMCList
*clist
)
1314 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1316 clist
->freeze_count
++;
1320 gtk_cmclist_thaw (GtkCMCList
*clist
)
1322 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1324 if (clist
->freeze_count
)
1326 clist
->freeze_count
--;
1327 CLIST_REFRESH (clist
);
1331 /* PUBLIC COLUMN FUNCTIONS
1332 * gtk_cmclist_column_titles_show
1333 * gtk_cmclist_column_titles_hide
1334 * gtk_cmclist_column_title_active
1335 * gtk_cmclist_column_title_passive
1336 * gtk_cmclist_column_titles_active
1337 * gtk_cmclist_column_titles_passive
1338 * gtk_cmclist_set_column_title
1339 * gtk_cmclist_get_column_title
1340 * gtk_cmclist_set_column_widget
1341 * gtk_cmclist_set_column_justification
1342 * gtk_cmclist_set_column_visibility
1343 * gtk_cmclist_set_column_resizeable
1344 * gtk_cmclist_set_column_auto_resize
1345 * gtk_cmclist_optimal_column_width
1346 * gtk_cmclist_set_column_width
1347 * gtk_cmclist_set_column_min_width
1348 * gtk_cmclist_set_column_max_width
1351 gtk_cmclist_column_titles_show (GtkCMCList
*clist
)
1353 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1355 if (!GTK_CMCLIST_SHOW_TITLES(clist
))
1357 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_SHOW_TITLES
);
1358 if (clist
->title_window
)
1359 gdk_window_show (clist
->title_window
);
1360 gtk_widget_queue_resize (GTK_WIDGET (clist
));
1365 gtk_cmclist_column_titles_hide (GtkCMCList
*clist
)
1367 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1369 if (GTK_CMCLIST_SHOW_TITLES(clist
))
1371 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_SHOW_TITLES
);
1372 if (clist
->title_window
)
1373 gdk_window_hide (clist
->title_window
);
1374 gtk_widget_queue_resize (GTK_WIDGET (clist
));
1379 gtk_cmclist_column_title_active (GtkCMCList
*clist
,
1382 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1384 if (column
< 0 || column
>= clist
->columns
)
1386 if (!clist
->column
[column
].button
|| !clist
->column
[column
].button_passive
)
1389 clist
->column
[column
].button_passive
= FALSE
;
1391 g_signal_handlers_disconnect_matched(G_OBJECT (clist
->column
[column
].button
), G_SIGNAL_MATCH_FUNC
,
1392 0, 0, 0, column_title_passive_func
, 0);
1394 gtk_widget_set_can_focus (clist
->column
[column
].button
, TRUE
);
1395 if (gtk_widget_get_visible (GTK_WIDGET(clist
)))
1396 gtk_widget_queue_draw (clist
->column
[column
].button
);
1400 gtk_cmclist_column_title_passive (GtkCMCList
*clist
,
1403 GtkToggleButton
*button
;
1405 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1407 if (column
< 0 || column
>= clist
->columns
)
1409 if (!clist
->column
[column
].button
|| clist
->column
[column
].button_passive
)
1412 button
= GTK_TOGGLE_BUTTON (clist
->column
[column
].button
);
1414 clist
->column
[column
].button_passive
= TRUE
;
1416 if (gtk_toggle_button_get_active(button
))
1417 g_signal_connect(G_OBJECT (clist
->column
[column
].button
),
1418 "button-release-event",
1419 G_CALLBACK(column_title_passive_func
),
1421 if (gtk_widget_is_focus(gtk_bin_get_child(GTK_BIN(button
))))
1422 g_signal_connect(G_OBJECT (clist
->column
[column
].button
),
1423 "leave-notify-event",
1424 G_CALLBACK(column_title_passive_func
),
1427 g_signal_connect (G_OBJECT (clist
->column
[column
].button
), "event",
1428 G_CALLBACK(column_title_passive_func
), NULL
);
1430 gtk_widget_set_can_focus (clist
->column
[column
].button
, FALSE
);
1431 if (gtk_widget_get_visible (GTK_WIDGET(clist
)))
1432 gtk_widget_queue_draw (clist
->column
[column
].button
);
1436 gtk_cmclist_column_titles_active (GtkCMCList
*clist
)
1440 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1442 for (i
= 0; i
< clist
->columns
; i
++)
1443 gtk_cmclist_column_title_active (clist
, i
);
1447 gtk_cmclist_column_titles_passive (GtkCMCList
*clist
)
1451 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1453 for (i
= 0; i
< clist
->columns
; i
++)
1454 gtk_cmclist_column_title_passive (clist
, i
);
1458 gtk_cmclist_set_column_title (GtkCMCList
*clist
,
1462 gint new_button
= 0;
1463 GtkWidget
*old_widget
;
1464 GtkWidget
*alignment
= NULL
;
1467 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1469 if (column
< 0 || column
>= clist
->columns
)
1472 /* if the column button doesn't currently exist,
1473 * it has to be created first */
1474 if (!clist
->column
[column
].button
)
1476 column_button_create (clist
, column
);
1480 column_title_new (clist
, column
, title
);
1482 /* remove and destroy the old widget */
1483 old_widget
= gtk_bin_get_child (GTK_BIN (clist
->column
[column
].button
));
1485 gtk_container_remove (GTK_CONTAINER (clist
->column
[column
].button
), old_widget
);
1487 /* create new alignment based no column justification */
1488 switch (clist
->column
[column
].justification
)
1490 case GTK_JUSTIFY_LEFT
:
1491 alignment
= gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1494 case GTK_JUSTIFY_RIGHT
:
1495 alignment
= gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
1498 case GTK_JUSTIFY_CENTER
:
1499 alignment
= gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1502 case GTK_JUSTIFY_FILL
:
1503 alignment
= gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
1507 gtk_widget_push_composite_child ();
1508 label
= gtk_label_new (clist
->column
[column
].title
);
1509 gtk_widget_pop_composite_child ();
1510 gtk_container_add (GTK_CONTAINER (alignment
), label
);
1511 gtk_container_add (GTK_CONTAINER (clist
->column
[column
].button
), alignment
);
1512 gtk_widget_show (label
);
1513 gtk_widget_show (alignment
);
1515 /* if this button didn't previously exist, then the
1516 * column button positions have to be re-computed */
1517 if (gtk_widget_get_visible (GTK_WIDGET(clist
)) && new_button
)
1518 size_allocate_title_buttons (clist
);
1522 gtk_cmclist_get_column_title (GtkCMCList
*clist
,
1525 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
1527 if (column
< 0 || column
>= clist
->columns
)
1530 return clist
->column
[column
].title
;
1534 gtk_cmclist_set_column_widget (GtkCMCList
*clist
,
1538 gint new_button
= 0;
1539 GtkWidget
*old_widget
;
1541 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1543 if (column
< 0 || column
>= clist
->columns
)
1546 /* if the column button doesn't currently exist,
1547 * it has to be created first */
1548 if (!clist
->column
[column
].button
)
1550 column_button_create (clist
, column
);
1554 column_title_new (clist
, column
, NULL
);
1556 /* remove and destroy the old widget */
1557 old_widget
= gtk_bin_get_child (GTK_BIN (clist
->column
[column
].button
));
1559 gtk_container_remove (GTK_CONTAINER (clist
->column
[column
].button
),
1562 /* add and show the widget */
1565 gtk_container_add (GTK_CONTAINER (clist
->column
[column
].button
), widget
);
1566 gtk_widget_show (widget
);
1569 /* if this button didn't previously exist, then the
1570 * column button positions have to be re-computed */
1571 if (gtk_widget_get_visible (GTK_WIDGET(clist
)) && new_button
)
1572 size_allocate_title_buttons (clist
);
1576 gtk_cmclist_get_column_widget (GtkCMCList
*clist
,
1579 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
1581 if (column
< 0 || column
>= clist
->columns
)
1584 if (clist
->column
[column
].button
)
1585 return gtk_bin_get_child (GTK_BIN (clist
->column
[column
].button
));
1591 gtk_cmclist_set_column_justification (GtkCMCList
*clist
,
1593 GtkJustification justification
)
1595 GtkWidget
*alignment
;
1597 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1599 if (column
< 0 || column
>= clist
->columns
)
1602 clist
->column
[column
].justification
= justification
;
1604 /* change the alinment of the button title if it's not a
1606 if (clist
->column
[column
].title
)
1608 alignment
= gtk_bin_get_child (GTK_BIN (clist
->column
[column
].button
));
1610 switch (clist
->column
[column
].justification
)
1612 case GTK_JUSTIFY_LEFT
:
1613 gtk_alignment_set (GTK_ALIGNMENT (alignment
), 0.0, 0.5, 0.0, 0.0);
1616 case GTK_JUSTIFY_RIGHT
:
1617 gtk_alignment_set (GTK_ALIGNMENT (alignment
), 1.0, 0.5, 0.0, 0.0);
1620 case GTK_JUSTIFY_CENTER
:
1621 gtk_alignment_set (GTK_ALIGNMENT (alignment
), 0.5, 0.5, 0.0, 0.0);
1624 case GTK_JUSTIFY_FILL
:
1625 gtk_alignment_set (GTK_ALIGNMENT (alignment
), 0.5, 0.5, 0.0, 0.0);
1633 if (CLIST_UNFROZEN (clist
))
1634 draw_rows (clist
, NULL
);
1638 gtk_cmclist_set_column_visibility (GtkCMCList
*clist
,
1642 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1644 if (column
< 0 || column
>= clist
->columns
)
1646 if (clist
->column
[column
].visible
== visible
)
1649 /* don't hide last visible column */
1653 gint vis_columns
= 0;
1655 for (i
= 0, vis_columns
= 0; i
< clist
->columns
&& vis_columns
< 2; i
++)
1656 if (clist
->column
[i
].visible
)
1659 if (vis_columns
< 2)
1663 clist
->column
[column
].visible
= visible
;
1665 if (clist
->column
[column
].button
)
1668 gtk_widget_show (clist
->column
[column
].button
);
1670 gtk_widget_hide (clist
->column
[column
].button
);
1673 gtk_widget_queue_resize (GTK_WIDGET(clist
));
1677 gtk_cmclist_set_column_resizeable (GtkCMCList
*clist
,
1679 gboolean resizeable
)
1681 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1683 if (column
< 0 || column
>= clist
->columns
)
1685 if (clist
->column
[column
].resizeable
== resizeable
)
1688 clist
->column
[column
].resizeable
= resizeable
;
1690 clist
->column
[column
].auto_resize
= FALSE
;
1692 if (gtk_widget_get_visible (GTK_WIDGET(clist
)))
1693 size_allocate_title_buttons (clist
);
1697 gtk_cmclist_set_column_auto_resize (GtkCMCList
*clist
,
1699 gboolean auto_resize
)
1701 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1703 if (column
< 0 || column
>= clist
->columns
)
1705 if (clist
->column
[column
].auto_resize
== auto_resize
)
1708 clist
->column
[column
].auto_resize
= auto_resize
;
1711 clist
->column
[column
].resizeable
= FALSE
;
1712 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
1716 width
= gtk_cmclist_optimal_column_width (clist
, column
);
1717 gtk_cmclist_set_column_width (clist
, column
, width
);
1721 if (gtk_widget_get_visible (GTK_WIDGET(clist
)))
1722 size_allocate_title_buttons (clist
);
1726 gtk_cmclist_columns_autosize (GtkCMCList
*clist
)
1731 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
1733 gtk_cmclist_freeze (clist
);
1735 for (i
= 0; i
< clist
->columns
; i
++)
1737 gtk_cmclist_set_column_width (clist
, i
,
1738 gtk_cmclist_optimal_column_width (clist
, i
));
1740 width
+= clist
->column
[i
].width
;
1743 gtk_cmclist_thaw (clist
);
1748 gtk_cmclist_optimal_column_width (GtkCMCList
*clist
,
1751 GtkRequisition requisition
;
1755 cm_return_val_if_fail (GTK_CMCLIST (clist
), 0);
1757 if (column
< 0 || column
>= clist
->columns
)
1760 if (GTK_CMCLIST_SHOW_TITLES(clist
) && clist
->column
[column
].button
)
1762 gtk_widget_get_requisition (clist
->column
[column
].button
, &requisition
);
1763 width
= requisition
.width
1765 (CELL_SPACING
+ (2 * COLUMN_INSET
)))
1772 for (list
= clist
->row_list
; list
; list
= list
->next
)
1774 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
1775 (clist
, GTK_CMCLIST_ROW (list
), column
, &requisition
);
1776 width
= MAX (width
, requisition
.width
);
1783 gtk_cmclist_set_column_width (GtkCMCList
*clist
,
1787 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1789 if (column
< 0 || column
>= clist
->columns
)
1792 g_signal_emit (G_OBJECT (clist
), clist_signals
[RESIZE_COLUMN
], 0,
1797 gtk_cmclist_set_column_min_width (GtkCMCList
*clist
,
1801 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1803 if (column
< 0 || column
>= clist
->columns
)
1805 if (clist
->column
[column
].min_width
== min_width
)
1808 if (clist
->column
[column
].max_width
>= 0 &&
1809 clist
->column
[column
].max_width
< min_width
)
1810 clist
->column
[column
].min_width
= clist
->column
[column
].max_width
;
1812 clist
->column
[column
].min_width
= min_width
;
1814 if (clist
->column
[column
].area
.width
< clist
->column
[column
].min_width
)
1815 gtk_cmclist_set_column_width (clist
, column
,clist
->column
[column
].min_width
);
1819 gtk_cmclist_set_column_max_width (GtkCMCList
*clist
,
1823 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1825 if (column
< 0 || column
>= clist
->columns
)
1827 if (clist
->column
[column
].max_width
== max_width
)
1830 if (clist
->column
[column
].min_width
>= 0 && max_width
>= 0 &&
1831 clist
->column
[column
].min_width
> max_width
)
1832 clist
->column
[column
].max_width
= clist
->column
[column
].min_width
;
1834 clist
->column
[column
].max_width
= max_width
;
1836 if (clist
->column
[column
].area
.width
> clist
->column
[column
].max_width
)
1837 gtk_cmclist_set_column_width (clist
, column
,clist
->column
[column
].max_width
);
1840 /* PRIVATE COLUMN FUNCTIONS
1841 * column_auto_resize
1842 * real_resize_column
1843 * abort_column_resize
1844 * size_allocate_title_buttons
1845 * size_allocate_columns
1846 * list_requisition_width
1848 * column_button_create
1849 * column_button_clicked
1850 * column_title_passive_func
1853 column_auto_resize (GtkCMCList
*clist
,
1854 GtkCMCListRow
*clist_row
,
1858 /* resize column if needed for auto_resize */
1859 GtkRequisition requisition
;
1861 if (!clist
->column
[column
].auto_resize
||
1862 GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
1866 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
1867 column
, &requisition
);
1869 requisition
.width
= 0;
1871 if (requisition
.width
> clist
->column
[column
].width
)
1872 gtk_cmclist_set_column_width (clist
, column
, requisition
.width
);
1873 else if (requisition
.width
< old_width
&&
1874 old_width
== clist
->column
[column
].width
)
1879 /* run a "gtk_cmclist_optimal_column_width" but break, if
1880 * the column doesn't shrink */
1881 if (GTK_CMCLIST_SHOW_TITLES(clist
) && clist
->column
[column
].button
)
1883 gtk_widget_get_requisition (clist
->column
[column
].button
, &requisition
);
1884 new_width
= (requisition
.width
-
1885 (CELL_SPACING
+ (2 * COLUMN_INSET
)));
1890 for (list
= clist
->row_list
; list
; list
= list
->next
)
1892 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request
1893 (clist
, GTK_CMCLIST_ROW (list
), column
, &requisition
);
1894 new_width
= MAX (new_width
, requisition
.width
);
1895 if (new_width
== clist
->column
[column
].width
)
1898 if (new_width
< clist
->column
[column
].width
)
1899 gtk_cmclist_set_column_width
1900 (clist
, column
, MAX (new_width
, clist
->column
[column
].min_width
));
1905 real_resize_column (GtkCMCList
*clist
,
1909 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1911 if (column
< 0 || column
>= clist
->columns
)
1914 if (width
< MAX (COLUMN_MIN_WIDTH
, clist
->column
[column
].min_width
))
1915 width
= MAX (COLUMN_MIN_WIDTH
, clist
->column
[column
].min_width
);
1916 if (clist
->column
[column
].max_width
>= 0 &&
1917 width
> clist
->column
[column
].max_width
)
1918 width
= clist
->column
[column
].max_width
;
1920 clist
->column
[column
].width
= width
;
1921 clist
->column
[column
].width_set
= TRUE
;
1923 /* FIXME: this is quite expensive to do if the widget hasn't
1924 * been size_allocated yet, and pointless. Should
1927 size_allocate_columns (clist
, TRUE
);
1928 size_allocate_title_buttons (clist
);
1930 CLIST_REFRESH (clist
);
1934 abort_column_resize (GtkCMCList
*clist
)
1936 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
1938 if (!GTK_CMCLIST_IN_DRAG(clist
))
1941 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_IN_DRAG
);
1942 gtk_grab_remove (GTK_WIDGET (clist
));
1943 gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (clist
)),
1945 clist
->drag_pos
= -1;
1947 if (clist
->x_drag
>= 0 && clist
->x_drag
<= clist
->clist_window_width
- 1)
1948 clist_refresh(clist
);
1952 size_allocate_title_buttons (GtkCMCList
*clist
)
1954 GtkAllocation button_allocation
;
1956 gint last_button
= 0;
1959 if (!gtk_widget_get_realized (GTK_WIDGET(clist
)))
1962 /* we're too early, the widget is not yet ready */
1963 if (clist
->column_title_area
.height
<= 1)
1966 button_allocation
.x
= clist
->hoffset
;
1967 button_allocation
.y
= 0;
1968 button_allocation
.width
= 0;
1969 button_allocation
.height
= clist
->column_title_area
.height
;
1971 /* find last visible column */
1972 for (last_column
= clist
->columns
- 1; last_column
>= 0; last_column
--)
1973 if (clist
->column
[last_column
].visible
)
1976 for (i
= 0; i
< last_column
; i
++)
1978 if (!clist
->column
[i
].visible
)
1980 last_button
= i
+ 1;
1981 gdk_window_hide (clist
->column
[i
].window
);
1985 button_allocation
.width
+= (clist
->column
[i
].area
.width
+
1986 CELL_SPACING
+ 2 * COLUMN_INSET
);
1988 if (!clist
->column
[i
+ 1].button
)
1990 gdk_window_hide (clist
->column
[i
].window
);
1994 gtk_widget_size_allocate (clist
->column
[last_button
].button
,
1995 &button_allocation
);
1996 button_allocation
.x
+= button_allocation
.width
;
1997 button_allocation
.width
= 0;
1999 if (clist
->column
[last_button
].resizeable
)
2001 gdk_window_show (clist
->column
[last_button
].window
);
2002 gdk_window_move_resize (clist
->column
[last_button
].window
,
2003 button_allocation
.x
- (DRAG_WIDTH
/ 2),
2005 clist
->column_title_area
.height
);
2008 gdk_window_hide (clist
->column
[last_button
].window
);
2010 last_button
= i
+ 1;
2013 button_allocation
.width
+= (clist
->column
[last_column
].area
.width
+
2014 2 * (CELL_SPACING
+ COLUMN_INSET
));
2015 gtk_widget_size_allocate (clist
->column
[last_button
].button
,
2016 &button_allocation
);
2018 if (clist
->column
[last_button
].resizeable
)
2020 button_allocation
.x
+= button_allocation
.width
;
2022 gdk_window_show (clist
->column
[last_button
].window
);
2023 gdk_window_move_resize (clist
->column
[last_button
].window
,
2024 button_allocation
.x
- (DRAG_WIDTH
/ 2),
2025 0, DRAG_WIDTH
, clist
->column_title_area
.height
);
2028 gdk_window_hide (clist
->column
[last_button
].window
);
2032 size_allocate_columns (GtkCMCList
*clist
,
2033 gboolean block_resize
)
2035 GtkRequisition requisition
;
2036 gint xoffset
= CELL_SPACING
+ COLUMN_INSET
;
2040 /* find last visible column and calculate correct column width */
2041 for (last_column
= clist
->columns
- 1;
2042 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--);
2044 if (last_column
< 0)
2047 for (i
= 0; i
<= last_column
; i
++)
2049 if (!clist
->column
[i
].visible
)
2051 clist
->column
[i
].area
.x
= xoffset
;
2052 if (clist
->column
[i
].width_set
)
2054 if (!block_resize
&& GTK_CMCLIST_SHOW_TITLES(clist
) &&
2055 clist
->column
[i
].auto_resize
&& clist
->column
[i
].button
)
2059 gtk_widget_get_requisition (clist
->column
[i
].button
, &requisition
);
2060 width
= (requisition
.width
-
2061 (CELL_SPACING
+ (2 * COLUMN_INSET
)));
2063 if (width
> clist
->column
[i
].width
)
2064 gtk_cmclist_set_column_width (clist
, i
, width
);
2067 clist
->column
[i
].area
.width
= clist
->column
[i
].width
;
2068 xoffset
+= clist
->column
[i
].width
+ CELL_SPACING
+ (2* COLUMN_INSET
);
2070 else if (GTK_CMCLIST_SHOW_TITLES(clist
) && clist
->column
[i
].button
)
2072 gtk_widget_get_requisition (clist
->column
[i
].button
, &requisition
);
2073 clist
->column
[i
].area
.width
=
2075 (CELL_SPACING
+ (2 * COLUMN_INSET
));
2076 xoffset
+= requisition
.width
;
2080 clist
->column
[last_column
].area
.width
= clist
->column
[last_column
].area
.width
2081 + MAX (0, clist
->clist_window_width
+ COLUMN_INSET
- xoffset
);
2085 list_requisition_width (GtkCMCList
*clist
)
2087 GtkRequisition requisition
;
2088 gint width
= CELL_SPACING
;
2091 for (i
= clist
->columns
- 1; i
>= 0; i
--)
2093 if (!clist
->column
[i
].visible
)
2096 if (clist
->column
[i
].width_set
)
2097 width
+= clist
->column
[i
].width
+ CELL_SPACING
+ (2 * COLUMN_INSET
);
2098 else if (GTK_CMCLIST_SHOW_TITLES(clist
) && clist
->column
[i
].button
)
2100 gtk_widget_get_requisition (clist
->column
[i
].button
, &requisition
);
2101 width
+= requisition
.width
;
2108 /* this function returns the new width of the column being resized given
2109 * the column and x position of the cursor; the x cursor position is passed
2110 * in as a pointer and automagicly corrected if it's beyond min/max limits */
2112 new_column_width (GtkCMCList
*clist
,
2116 gint xthickness
= gtk_widget_get_style (GTK_WIDGET (clist
))->xthickness
;
2122 /* first translate the x position from widget->window
2123 * to clist->clist_window */
2124 cx
= *x
- xthickness
;
2126 for (last_column
= clist
->columns
- 1;
2127 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--);
2129 /* calculate new column width making sure it doesn't end up
2130 * less than the minimum width */
2131 dx
= (COLUMN_LEFT_XPIXEL (clist
, column
) + COLUMN_INSET
+
2132 (column
< last_column
) * CELL_SPACING
);
2135 if (width
< MAX (COLUMN_MIN_WIDTH
, clist
->column
[column
].min_width
))
2137 width
= MAX (COLUMN_MIN_WIDTH
, clist
->column
[column
].min_width
);
2139 *x
= cx
+ xthickness
;
2141 else if (clist
->column
[column
].max_width
>= COLUMN_MIN_WIDTH
&&
2142 width
> clist
->column
[column
].max_width
)
2144 width
= clist
->column
[column
].max_width
;
2145 cx
= dx
+ clist
->column
[column
].max_width
;
2146 *x
= cx
+ xthickness
;
2149 if (cx
< 0 || cx
> clist
->clist_window_width
)
2156 column_button_create (GtkCMCList
*clist
,
2161 gtk_widget_push_composite_child ();
2162 button
= clist
->column
[column
].button
= gtk_button_new ();
2163 GtkRcStyle
*style
= gtk_rc_style_new();
2164 style
->ythickness
= 0;
2165 gtk_widget_modify_style(clist
->column
[column
].button
, style
);
2166 g_object_unref(style
);
2167 gtk_container_set_border_width(GTK_CONTAINER(button
), 0);
2168 gtk_widget_pop_composite_child ();
2170 if (gtk_widget_get_realized (GTK_WIDGET(clist
)) && clist
->title_window
)
2171 gtk_widget_set_parent_window (clist
->column
[column
].button
,
2172 clist
->title_window
);
2173 gtk_widget_set_parent (button
, GTK_WIDGET (clist
));
2175 g_signal_connect (G_OBJECT (button
), "clicked",
2176 G_CALLBACK(column_button_clicked
),
2178 gtk_widget_show (button
);
2182 column_button_clicked (GtkWidget
*widget
,
2188 cm_return_if_fail (widget
!= NULL
);
2189 cm_return_if_fail (GTK_IS_CMCLIST (data
));
2191 clist
= GTK_CMCLIST (data
);
2193 /* find the column who's button was pressed */
2194 for (i
= 0; i
< clist
->columns
; i
++)
2195 if (clist
->column
[i
].button
== widget
)
2198 g_signal_emit (G_OBJECT (clist
), clist_signals
[CLICK_COLUMN
], 0, i
);
2202 column_title_passive_func (GtkWidget
*widget
,
2206 cm_return_val_if_fail (event
!= NULL
, FALSE
);
2208 switch (event
->type
)
2210 case GDK_MOTION_NOTIFY
:
2211 case GDK_BUTTON_PRESS
:
2212 case GDK_2BUTTON_PRESS
:
2213 case GDK_3BUTTON_PRESS
:
2214 case GDK_BUTTON_RELEASE
:
2215 case GDK_ENTER_NOTIFY
:
2216 case GDK_LEAVE_NOTIFY
:
2225 /* PUBLIC CELL FUNCTIONS
2226 * gtk_cmclist_get_cell_type
2227 * gtk_cmclist_set_text
2228 * gtk_cmclist_get_text
2229 * gtk_cmclist_set_pixbuf
2230 * gtk_cmclist_get_pixbuf
2231 * gtk_cmclist_set_pixtext
2232 * gtk_cmclist_get_pixtext
2233 * gtk_cmclist_set_shift
2236 gtk_cmclist_get_cell_type (GtkCMCList
*clist
,
2240 GtkCMCListRow
*clist_row
;
2242 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
2244 if (row
< 0 || row
>= clist
->rows
)
2246 if (column
< 0 || column
>= clist
->columns
)
2249 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2251 return clist_row
->cell
[column
].type
;
2255 gtk_cmclist_set_text (GtkCMCList
*clist
,
2260 GtkCMCListRow
*clist_row
;
2262 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2264 if (row
< 0 || row
>= clist
->rows
)
2266 if (column
< 0 || column
>= clist
->columns
)
2269 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2271 /* if text is null, then the cell is empty */
2272 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
2273 (clist
, clist_row
, column
, GTK_CMCELL_TEXT
, text
, 0, NULL
);
2275 /* redraw the list if it's not frozen */
2276 if (CLIST_UNFROZEN (clist
))
2278 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
2279 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
2284 gtk_cmclist_get_text (GtkCMCList
*clist
,
2289 GtkCMCListRow
*clist_row
;
2291 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
2293 if (row
< 0 || row
>= clist
->rows
)
2295 if (column
< 0 || column
>= clist
->columns
)
2298 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2300 if (clist_row
->cell
[column
].type
!= GTK_CMCELL_TEXT
)
2304 *text
= GTK_CMCELL_TEXT (clist_row
->cell
[column
])->text
;
2310 gtk_cmclist_set_pixbuf (GtkCMCList
*clist
,
2315 GtkCMCListRow
*clist_row
;
2317 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2319 if (row
< 0 || row
>= clist
->rows
)
2321 if (column
< 0 || column
>= clist
->columns
)
2324 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2326 g_object_ref (pixbuf
);
2328 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
2329 (clist
, clist_row
, column
, GTK_CMCELL_PIXBUF
, NULL
, 0, pixbuf
);
2331 /* redraw the list if it's not frozen */
2332 if (CLIST_UNFROZEN (clist
))
2334 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
2335 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
2340 gtk_cmclist_get_pixbuf (GtkCMCList
*clist
,
2345 GtkCMCListRow
*clist_row
;
2347 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
2349 if (row
< 0 || row
>= clist
->rows
)
2351 if (column
< 0 || column
>= clist
->columns
)
2354 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2356 if (clist_row
->cell
[column
].type
!= GTK_CMCELL_PIXBUF
)
2361 *pixbuf
= GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
;
2368 gtk_cmclist_set_pixtext (GtkCMCList
*clist
,
2375 GtkCMCListRow
*clist_row
;
2377 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2379 if (row
< 0 || row
>= clist
->rows
)
2381 if (column
< 0 || column
>= clist
->columns
)
2384 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2386 g_object_ref (pixbuf
);
2387 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
2388 (clist
, clist_row
, column
, GTK_CMCELL_PIXTEXT
, text
, spacing
, pixbuf
);
2390 /* redraw the list if it's not frozen */
2391 if (CLIST_UNFROZEN (clist
))
2393 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
2394 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
2399 gtk_cmclist_get_pixtext (GtkCMCList
*clist
,
2406 GtkCMCListRow
*clist_row
;
2408 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
2410 if (row
< 0 || row
>= clist
->rows
)
2412 if (column
< 0 || column
>= clist
->columns
)
2415 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2417 if (clist_row
->cell
[column
].type
!= GTK_CMCELL_PIXTEXT
)
2421 *text
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
;
2423 *spacing
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
;
2425 *pixbuf
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
;
2431 gtk_cmclist_set_shift (GtkCMCList
*clist
,
2437 GtkRequisition requisition
= { 0 };
2438 GtkCMCListRow
*clist_row
;
2440 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2442 if (row
< 0 || row
>= clist
->rows
)
2444 if (column
< 0 || column
>= clist
->columns
)
2447 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
2449 if (clist
->column
[column
].auto_resize
&&
2450 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2451 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
2452 column
, &requisition
);
2454 clist_row
->cell
[column
].vertical
= vertical
;
2455 clist_row
->cell
[column
].horizontal
= horizontal
;
2457 column_auto_resize (clist
, clist_row
, column
, requisition
.width
);
2459 if (CLIST_UNFROZEN (clist
) && gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
2460 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
2463 /* PRIVATE CELL FUNCTIONS
2468 set_cell_contents (GtkCMCList
*clist
,
2469 GtkCMCListRow
*clist_row
,
2476 GtkRequisition requisition
;
2477 gchar
*old_text
= NULL
;
2478 GdkPixbuf
*old_pixbuf
= NULL
;
2480 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2481 cm_return_if_fail (clist_row
!= NULL
);
2483 if (clist
->column
[column
].auto_resize
&&
2484 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2485 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
2486 column
, &requisition
);
2488 switch (clist_row
->cell
[column
].type
)
2490 case GTK_CMCELL_EMPTY
:
2492 case GTK_CMCELL_TEXT
:
2493 old_text
= GTK_CMCELL_TEXT (clist_row
->cell
[column
])->text
;
2495 case GTK_CMCELL_PIXBUF
:
2496 old_pixbuf
= GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
;
2498 case GTK_CMCELL_PIXTEXT
:
2499 old_text
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
;
2500 old_pixbuf
= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
;
2502 case GTK_CMCELL_WIDGET
:
2509 clist_row
->cell
[column
].type
= GTK_CMCELL_EMPTY
;
2511 /* Note that pixbuf and mask were already ref'ed by the caller
2515 case GTK_CMCELL_TEXT
:
2518 clist_row
->cell
[column
].type
= GTK_CMCELL_TEXT
;
2519 GTK_CMCELL_TEXT (clist_row
->cell
[column
])->text
= g_strdup (text
);
2522 case GTK_CMCELL_PIXBUF
:
2525 clist_row
->cell
[column
].type
= GTK_CMCELL_PIXBUF
;
2526 GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
= pixbuf
;
2529 case GTK_CMCELL_PIXTEXT
:
2532 clist_row
->cell
[column
].type
= GTK_CMCELL_PIXTEXT
;
2533 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->text
= g_strdup (text
);
2534 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
= spacing
;
2535 GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
= pixbuf
;
2542 if (clist
->column
[column
].auto_resize
&&
2543 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
2544 column_auto_resize (clist
, clist_row
, column
, requisition
.width
);
2548 g_object_unref (old_pixbuf
);
2552 _gtk_cmclist_create_cell_layout (GtkCMCList
*clist
,
2553 GtkCMCListRow
*clist_row
,
2556 PangoLayout
*layout
;
2561 get_cell_style (clist
, clist_row
, GTK_STATE_NORMAL
, column
, &style
);
2564 cell
= &clist_row
->cell
[column
];
2567 case GTK_CMCELL_TEXT
:
2568 case GTK_CMCELL_PIXTEXT
:
2569 text
= ((cell
->type
== GTK_CMCELL_PIXTEXT
) ?
2570 GTK_CMCELL_PIXTEXT (*cell
)->text
:
2571 GTK_CMCELL_TEXT (*cell
)->text
);
2576 layout
= gtk_widget_create_pango_layout (GTK_WIDGET (clist
),
2577 ((cell
->type
== GTK_CMCELL_PIXTEXT
) ?
2578 GTK_CMCELL_PIXTEXT (*cell
)->text
:
2579 GTK_CMCELL_TEXT (*cell
)->text
));
2580 pango_layout_set_font_description (layout
, style
->font_desc
);
2590 cell_size_request (GtkCMCList
*clist
,
2591 GtkCMCListRow
*clist_row
,
2593 GtkRequisition
*requisition
)
2597 PangoLayout
*layout
;
2598 PangoRectangle logical_rect
;
2600 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2601 cm_return_if_fail (requisition
!= NULL
);
2603 layout
= _gtk_cmclist_create_cell_layout (clist
, clist_row
, column
);
2606 pango_layout_get_pixel_extents (layout
, NULL
, &logical_rect
);
2608 requisition
->width
= logical_rect
.width
;
2609 requisition
->height
= logical_rect
.height
;
2611 g_object_unref (G_OBJECT (layout
));
2615 requisition
->width
= 0;
2616 requisition
->height
= 0;
2619 if (layout
&& clist_row
->cell
[column
].type
== GTK_CMCELL_PIXTEXT
)
2620 requisition
->width
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->spacing
;
2622 switch (clist_row
->cell
[column
].type
)
2624 case GTK_CMCELL_PIXTEXT
:
2625 width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
);
2626 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row
->cell
[column
])->pixbuf
);
2627 requisition
->width
+= width
;
2628 requisition
->height
= MAX (requisition
->height
, height
);
2630 case GTK_CMCELL_PIXBUF
:
2631 width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
);
2632 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row
->cell
[column
])->pixbuf
);
2633 requisition
->width
+= width
;
2634 requisition
->height
= MAX (requisition
->height
, height
);
2641 requisition
->width
+= clist_row
->cell
[column
].horizontal
;
2642 requisition
->height
+= clist_row
->cell
[column
].vertical
;
2645 /* PUBLIC INSERT/REMOVE ROW FUNCTIONS
2646 * gtk_cmclist_prepend
2647 * gtk_cmclist_append
2648 * gtk_cmclist_insert
2649 * gtk_cmclist_remove
2653 gtk_cmclist_prepend (GtkCMCList
*clist
,
2656 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
2657 cm_return_val_if_fail (text
!= NULL
, -1);
2659 return GTK_CMCLIST_GET_CLASS (clist
)->insert_row (clist
, 0, text
);
2663 gtk_cmclist_append (GtkCMCList
*clist
,
2666 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
2667 cm_return_val_if_fail (text
!= NULL
, -1);
2669 return GTK_CMCLIST_GET_CLASS (clist
)->insert_row (clist
, clist
->rows
, text
);
2673 gtk_cmclist_insert (GtkCMCList
*clist
,
2677 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
2678 cm_return_val_if_fail (text
!= NULL
, -1);
2680 if (row
< 0 || row
> clist
->rows
)
2683 return GTK_CMCLIST_GET_CLASS (clist
)->insert_row (clist
, row
, text
);
2687 gtk_cmclist_remove (GtkCMCList
*clist
,
2690 GTK_CMCLIST_GET_CLASS (clist
)->remove_row (clist
, row
);
2694 gtk_cmclist_clear (GtkCMCList
*clist
)
2696 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2698 GTK_CMCLIST_GET_CLASS (clist
)->clear (clist
);
2701 /* PRIVATE INSERT/REMOVE ROW FUNCTIONS
2708 real_insert_row (GtkCMCList
*clist
,
2713 GtkCMCListRow
*clist_row
;
2715 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
2716 cm_return_val_if_fail (text
!= NULL
, -1);
2718 /* return if out of bounds */
2719 if (row
< 0 || row
> clist
->rows
)
2722 /* create the row */
2723 clist_row
= row_new (clist
);
2725 /* set the text in the row's columns */
2726 for (i
= 0; i
< clist
->columns
; i
++)
2728 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
2729 (clist
, clist_row
, i
, GTK_CMCELL_TEXT
, text
[i
], 0, NULL
);
2733 clist
->row_list
= g_list_append (clist
->row_list
, clist_row
);
2734 clist
->row_list_end
= clist
->row_list
;
2738 if (GTK_CMCLIST_AUTO_SORT(clist
)) /* override insertion pos */
2743 work
= clist
->row_list
;
2745 if (clist
->sort_type
== GTK_SORT_ASCENDING
)
2747 while (row
< clist
->rows
&&
2748 clist
->compare (clist
, clist_row
,
2749 GTK_CMCLIST_ROW (work
)) > 0)
2757 while (row
< clist
->rows
&&
2758 clist
->compare (clist
, clist_row
,
2759 GTK_CMCLIST_ROW (work
)) < 0)
2767 /* reset the row end pointer if we're inserting at the end of the list */
2768 if (row
== clist
->rows
)
2769 clist
->row_list_end
= (g_list_append (clist
->row_list_end
,
2772 clist
->row_list
= g_list_insert (clist
->row_list
, clist_row
, row
);
2777 if (row
< ROW_FROM_YPIXEL (clist
, 0))
2778 clist
->voffset
-= (clist
->row_height
+ CELL_SPACING
);
2780 /* syncronize the selection list */
2781 sync_selection (clist
, row
, SYNC_INSERT
);
2783 if (clist
->rows
== 1)
2785 clist
->focus_row
= 0;
2786 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
)
2787 gtk_cmclist_select_row (clist
, 0, -1);
2790 /* redraw the list if it isn't frozen */
2791 if (CLIST_UNFROZEN (clist
))
2793 adjust_adjustments (clist
, FALSE
);
2795 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
2796 draw_rows (clist
, NULL
);
2803 real_remove_row (GtkCMCList
*clist
,
2808 GtkCMCListRow
*clist_row
;
2810 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2812 /* return if out of bounds */
2813 if (row
< 0 || row
> (clist
->rows
- 1))
2816 was_visible
= (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
);
2818 /* get the row we're going to delete */
2819 list
= ROW_ELEMENT (clist
, row
);
2820 g_assert (list
!= NULL
);
2821 clist_row
= list
->data
;
2823 /* if we're removing a selected row, we have to make sure
2824 * it's properly unselected, and then sync up the clist->selected
2825 * list to reflect the deincrimented indexies of rows after the
2827 if (clist_row
->state
== GTK_STATE_SELECTED
)
2828 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
2831 sync_selection (clist
, row
, SYNC_REMOVE
);
2833 /* reset the row end pointer if we're removing at the end of the list */
2835 if (clist
->row_list
== list
)
2836 clist
->row_list
= g_list_next (list
);
2837 if (clist
->row_list_end
== list
)
2838 clist
->row_list_end
= g_list_previous (list
);
2839 list
= g_list_remove (list
, clist_row
);
2841 if (row
< ROW_FROM_YPIXEL (clist
, 0))
2842 clist
->voffset
+= clist
->row_height
+ CELL_SPACING
;
2844 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
&& !clist
->selection
&&
2845 clist
->focus_row
>= 0)
2846 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
2847 clist
->focus_row
, -1, NULL
);
2850 row_delete (clist
, clist_row
);
2852 /* redraw the row if it isn't frozen */
2853 if (CLIST_UNFROZEN (clist
))
2855 adjust_adjustments (clist
, FALSE
);
2858 draw_rows (clist
, NULL
);
2863 real_clear (GtkCMCList
*clist
)
2867 GtkRequisition requisition
;
2870 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2872 /* free up the selection list */
2873 g_list_free (clist
->selection
);
2874 g_list_free (clist
->undo_selection
);
2875 g_list_free (clist
->undo_unselection
);
2877 clist
->selection
= NULL
;
2878 clist
->selection_end
= NULL
;
2879 clist
->undo_selection
= NULL
;
2880 clist
->undo_unselection
= NULL
;
2882 clist
->focus_row
= -1;
2884 clist
->undo_anchor
= -1;
2885 clist
->anchor_state
= GTK_STATE_SELECTED
;
2886 clist
->drag_pos
= -1;
2888 /* remove all the rows */
2889 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
2890 free_list
= clist
->row_list
;
2891 clist
->row_list
= NULL
;
2892 clist
->row_list_end
= NULL
;
2894 for (list
= free_list
; list
; list
= list
->next
)
2895 row_delete (clist
, GTK_CMCLIST_ROW (list
));
2896 g_list_free (free_list
);
2897 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_AUTO_RESIZE_BLOCKED
);
2898 for (i
= 0; i
< clist
->columns
; i
++)
2899 if (clist
->column
[i
].auto_resize
)
2901 if (GTK_CMCLIST_SHOW_TITLES(clist
) && clist
->column
[i
].button
)
2903 gtk_widget_get_requisition (clist
->column
[i
].button
, &requisition
);
2904 gtk_cmclist_set_column_width
2905 (clist
, i
, (requisition
.width
-
2906 (CELL_SPACING
+ (2 * COLUMN_INSET
))));
2909 gtk_cmclist_set_column_width (clist
, i
, 0);
2911 /* zero-out the scrollbars */
2912 if (clist
->vadjustment
)
2914 gtk_adjustment_set_value (clist
->vadjustment
, 0.0);
2915 CLIST_REFRESH (clist
);
2918 gtk_widget_queue_resize (GTK_WIDGET (clist
));
2922 real_row_move (GtkCMCList
*clist
,
2926 GtkCMCListRow
*clist_row
;
2931 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
2933 if (GTK_CMCLIST_AUTO_SORT(clist
))
2936 if (source_row
< 0 || source_row
>= clist
->rows
||
2937 dest_row
< 0 || dest_row
>= clist
->rows
||
2938 source_row
== dest_row
)
2941 gtk_cmclist_freeze (clist
);
2943 /* unlink source row */
2944 clist_row
= ROW_ELEMENT (clist
, source_row
)->data
;
2945 if (source_row
== clist
->rows
- 1)
2946 clist
->row_list_end
= clist
->row_list_end
->prev
;
2947 clist
->row_list
= g_list_remove (clist
->row_list
, clist_row
);
2950 /* relink source row */
2951 clist
->row_list
= g_list_insert (clist
->row_list
, clist_row
, dest_row
);
2952 if (dest_row
== clist
->rows
)
2953 clist
->row_list_end
= clist
->row_list_end
->next
;
2956 /* sync selection */
2957 if (source_row
> dest_row
)
2970 for (list
= clist
->selection
; list
; list
= list
->next
)
2972 if (list
->data
== GINT_TO_POINTER (source_row
))
2973 list
->data
= GINT_TO_POINTER (dest_row
);
2974 else if (first
<= GPOINTER_TO_INT (list
->data
) &&
2975 last
>= GPOINTER_TO_INT (list
->data
))
2976 list
->data
= GINT_TO_POINTER (GPOINTER_TO_INT (list
->data
) + d
);
2979 if (clist
->focus_row
== source_row
)
2980 clist
->focus_row
= dest_row
;
2981 else if (clist
->focus_row
> first
)
2982 clist
->focus_row
+= d
;
2984 gtk_cmclist_thaw (clist
);
2987 /* PUBLIC ROW FUNCTIONS
2988 * gtk_cmclist_moveto
2989 * gtk_cmclist_set_row_height
2990 * gtk_cmclist_set_row_data
2991 * gtk_cmclist_set_row_data_full
2992 * gtk_cmclist_get_row_data
2993 * gtk_cmclist_find_row_from_data
2994 * gtk_cmclist_swap_rows
2995 * gtk_cmclist_row_move
2996 * gtk_cmclist_row_is_visible
2997 * gtk_cmclist_set_foreground
2998 * gtk_cmclist_set_background
3001 gtk_cmclist_moveto (GtkCMCList
*clist
,
3007 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3009 if (row
< -1 || row
>= clist
->rows
)
3011 if (column
< -1 || column
>= clist
->columns
)
3014 row_align
= CLAMP (row_align
, 0, 1);
3015 col_align
= CLAMP (col_align
, 0, 1);
3017 /* adjust horizontal scrollbar */
3018 if (clist
->hadjustment
&& column
>= 0)
3022 x
= (COLUMN_LEFT (clist
, column
) - CELL_SPACING
- COLUMN_INSET
-
3023 (col_align
* (clist
->clist_window_width
- 2 * COLUMN_INSET
-
3024 CELL_SPACING
- clist
->column
[column
].area
.width
)));
3026 gtk_adjustment_set_value (clist
->hadjustment
, 0.0);
3027 else if (x
> LIST_WIDTH (clist
) - clist
->clist_window_width
)
3028 gtk_adjustment_set_value
3029 (clist
->hadjustment
, LIST_WIDTH (clist
) - clist
->clist_window_width
);
3031 gtk_adjustment_set_value (clist
->hadjustment
, x
);
3034 /* adjust vertical scrollbar */
3035 if (clist
->vadjustment
&& row
>= 0)
3036 move_vertical (clist
, row
, row_align
);
3040 gtk_cmclist_set_row_height (GtkCMCList
*clist
,
3046 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3048 widget
= GTK_WIDGET (clist
);
3050 style
= gtk_widget_get_style (widget
);
3054 clist
->row_height
= height
;
3055 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_ROW_HEIGHT_SET
);
3059 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_ROW_HEIGHT_SET
);
3060 clist
->row_height
= 0;
3063 if (style
->font_desc
)
3065 PangoContext
*context
= gtk_widget_get_pango_context (widget
);
3066 PangoFontMetrics
*metrics
;
3068 metrics
= pango_context_get_metrics (context
,
3070 pango_context_get_language (context
));
3072 if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist
))
3074 clist
->row_height
= (pango_font_metrics_get_ascent (metrics
) +
3075 pango_font_metrics_get_descent (metrics
));
3076 clist
->row_height
= PANGO_PIXELS (clist
->row_height
) + 1;
3079 pango_font_metrics_unref (metrics
);
3082 CLIST_REFRESH (clist
);
3086 gtk_cmclist_set_row_data (GtkCMCList
*clist
,
3090 gtk_cmclist_set_row_data_full (clist
, row
, data
, NULL
);
3094 gtk_cmclist_set_row_data_full (GtkCMCList
*clist
,
3097 GDestroyNotify destroy
)
3099 GtkCMCListRow
*clist_row
;
3101 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3103 if (row
< 0 || row
> (clist
->rows
- 1))
3106 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3108 if (clist_row
->destroy
)
3109 clist_row
->destroy (clist_row
->data
);
3111 clist_row
->data
= data
;
3112 clist_row
->destroy
= destroy
;
3116 gtk_cmclist_get_row_data (GtkCMCList
*clist
,
3119 GtkCMCListRow
*clist_row
;
3121 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
3123 if (row
< 0 || row
> (clist
->rows
- 1))
3126 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3127 return clist_row
->data
;
3131 gtk_cmclist_find_row_from_data (GtkCMCList
*clist
,
3137 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), -1);
3139 for (n
= 0, list
= clist
->row_list
; list
; n
++, list
= list
->next
)
3140 if (GTK_CMCLIST_ROW (list
)->data
== data
)
3147 gtk_cmclist_swap_rows (GtkCMCList
*clist
,
3153 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3154 cm_return_if_fail (row1
!= row2
);
3156 if (GTK_CMCLIST_AUTO_SORT(clist
))
3159 gtk_cmclist_freeze (clist
);
3161 first
= MIN (row1
, row2
);
3162 last
= MAX (row1
, row2
);
3164 gtk_cmclist_row_move (clist
, last
, first
);
3165 gtk_cmclist_row_move (clist
, first
+ 1, last
);
3167 gtk_cmclist_thaw (clist
);
3171 gtk_cmclist_row_move (GtkCMCList
*clist
,
3175 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3177 if (GTK_CMCLIST_AUTO_SORT(clist
))
3180 if (source_row
< 0 || source_row
>= clist
->rows
||
3181 dest_row
< 0 || dest_row
>= clist
->rows
||
3182 source_row
== dest_row
)
3185 g_signal_emit (G_OBJECT (clist
), clist_signals
[ROW_MOVE
], 0,
3186 source_row
, dest_row
);
3190 gtk_cmclist_row_is_visible (GtkCMCList
*clist
,
3195 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
3197 if (row
< 0 || row
>= clist
->rows
)
3198 return GTK_VISIBILITY_NONE
;
3200 if (clist
->row_height
== 0)
3201 return GTK_VISIBILITY_NONE
;
3203 if (row
< ROW_FROM_YPIXEL (clist
, 0))
3204 return GTK_VISIBILITY_NONE
;
3206 if (row
> ROW_FROM_YPIXEL (clist
, clist
->clist_window_height
))
3207 return GTK_VISIBILITY_NONE
;
3209 top
= ROW_TOP_YPIXEL (clist
, row
);
3212 || ((top
+ clist
->row_height
) >= clist
->clist_window_height
))
3213 return GTK_VISIBILITY_PARTIAL
;
3215 return GTK_VISIBILITY_FULL
;
3219 gtk_cmclist_row_is_above_viewport (GtkCMCList
*clist
,
3222 cm_return_val_if_fail(GTK_IS_CMCLIST (clist
), 0);
3224 if (row
< 0 || row
>= clist
->rows
)
3227 if (clist
->row_height
== 0)
3230 if (row
< ROW_FROM_YPIXEL (clist
, 0))
3237 gtk_cmclist_row_is_below_viewport (GtkCMCList
*clist
,
3240 cm_return_val_if_fail(GTK_IS_CMCLIST (clist
), 0);
3242 if (row
< 0 || row
>= clist
->rows
)
3245 if (clist
->row_height
== 0)
3248 if (row
> ROW_FROM_YPIXEL (clist
, clist
->clist_window_height
))
3255 gtk_cmclist_set_foreground (GtkCMCList
*clist
,
3257 const GdkColor
*color
)
3259 GtkCMCListRow
*clist_row
;
3261 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3263 if (row
< 0 || row
>= clist
->rows
)
3266 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3270 clist_row
->foreground
= *color
;
3271 clist_row
->fg_set
= TRUE
;
3274 clist_row
->fg_set
= FALSE
;
3276 if (CLIST_UNFROZEN (clist
) && gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
3277 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3281 gtk_cmclist_set_background (GtkCMCList
*clist
,
3283 const GdkColor
*color
)
3285 GtkCMCListRow
*clist_row
;
3287 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3289 if (row
< 0 || row
>= clist
->rows
)
3292 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3296 clist_row
->background
= *color
;
3297 clist_row
->bg_set
= TRUE
;
3300 clist_row
->bg_set
= FALSE
;
3302 if (CLIST_UNFROZEN (clist
)
3303 && (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
))
3304 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3307 /* PUBLIC ROW/CELL STYLE FUNCTIONS
3308 * gtk_cmclist_set_cell_style
3309 * gtk_cmclist_get_cell_style
3310 * gtk_cmclist_set_row_style
3311 * gtk_cmclist_get_row_style
3314 gtk_cmclist_set_cell_style (GtkCMCList
*clist
,
3319 GtkRequisition requisition
= { 0 };
3320 GtkCMCListRow
*clist_row
;
3322 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3324 if (row
< 0 || row
>= clist
->rows
)
3326 if (column
< 0 || column
>= clist
->columns
)
3329 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3331 if (clist_row
->cell
[column
].style
== style
)
3334 if (clist
->column
[column
].auto_resize
&&
3335 !GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
3336 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
3337 column
, &requisition
);
3339 if (clist_row
->cell
[column
].style
)
3341 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
3342 gtk_style_detach (clist_row
->cell
[column
].style
);
3343 g_object_unref (clist_row
->cell
[column
].style
);
3346 clist_row
->cell
[column
].style
= style
;
3348 if (clist_row
->cell
[column
].style
)
3350 g_object_ref (clist_row
->cell
[column
].style
);
3352 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
3353 clist_row
->cell
[column
].style
=
3354 gtk_style_attach (clist_row
->cell
[column
].style
,
3355 clist
->clist_window
);
3358 column_auto_resize (clist
, clist_row
, column
, requisition
.width
);
3360 /* redraw the list if it's not frozen */
3361 if (CLIST_UNFROZEN (clist
))
3363 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
3364 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3369 gtk_cmclist_get_cell_style (GtkCMCList
*clist
,
3373 GtkCMCListRow
*clist_row
;
3375 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
3377 if (row
< 0 || row
>= clist
->rows
|| column
< 0 || column
>= clist
->columns
)
3380 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3382 return clist_row
->cell
[column
].style
;
3386 gtk_cmclist_set_row_style (GtkCMCList
*clist
,
3390 GtkRequisition requisition
;
3391 GtkCMCListRow
*clist_row
;
3395 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3397 if (row
< 0 || row
>= clist
->rows
)
3400 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3402 if (clist_row
->style
== style
)
3405 old_width
= g_new (gint
, clist
->columns
);
3407 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
3409 for (i
= 0; i
< clist
->columns
; i
++)
3410 if (clist
->column
[i
].auto_resize
)
3412 GTK_CMCLIST_GET_CLASS (clist
)->cell_size_request (clist
, clist_row
,
3414 old_width
[i
] = requisition
.width
;
3418 if (clist_row
->style
)
3420 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
3421 gtk_style_detach (clist_row
->style
);
3422 g_object_unref (clist_row
->style
);
3425 clist_row
->style
= style
;
3427 if (clist_row
->style
)
3429 g_object_ref (clist_row
->style
);
3431 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
3432 clist_row
->style
= gtk_style_attach (clist_row
->style
,
3433 clist
->clist_window
);
3436 if (GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
3437 for (i
= 0; i
< clist
->columns
; i
++)
3438 column_auto_resize (clist
, clist_row
, i
, old_width
[i
]);
3442 /* redraw the list if it's not frozen */
3443 if (CLIST_UNFROZEN (clist
))
3445 if (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
3446 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3451 gtk_cmclist_get_row_style (GtkCMCList
*clist
,
3454 GtkCMCListRow
*clist_row
;
3456 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), NULL
);
3458 if (row
< 0 || row
>= clist
->rows
)
3461 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3463 return clist_row
->style
;
3466 /* PUBLIC SELECTION FUNCTIONS
3467 * gtk_cmclist_set_selectable
3468 * gtk_cmclist_get_selectable
3469 * gtk_cmclist_select_row
3470 * gtk_cmclist_unselect_row
3471 * gtk_cmclist_select_all
3472 * gtk_cmclist_unselect_all
3473 * gtk_cmclist_undo_selection
3476 gtk_cmclist_set_selectable (GtkCMCList
*clist
,
3478 gboolean selectable
)
3480 GtkCMCListRow
*clist_row
;
3482 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3484 if (row
< 0 || row
>= clist
->rows
)
3487 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3489 if (selectable
== clist_row
->selectable
)
3492 clist_row
->selectable
= selectable
;
3494 if (!selectable
&& clist_row
->state
== GTK_STATE_SELECTED
)
3496 if (clist
->anchor
>= 0 &&
3497 clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
3499 clist
->drag_button
= 0;
3500 remove_grab (clist
);
3501 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
3503 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
3509 gtk_cmclist_get_selectable (GtkCMCList
*clist
,
3512 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), FALSE
);
3514 if (row
< 0 || row
>= clist
->rows
)
3517 return GTK_CMCLIST_ROW (ROW_ELEMENT (clist
, row
))->selectable
;
3521 gtk_cmclist_select_row (GtkCMCList
*clist
,
3525 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3527 if (row
< 0 || row
>= clist
->rows
)
3529 if (column
< -1 || column
>= clist
->columns
)
3532 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
3537 gtk_cmclist_unselect_row (GtkCMCList
*clist
,
3541 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3543 if (row
< 0 || row
>= clist
->rows
)
3545 if (column
< -1 || column
>= clist
->columns
)
3548 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
3553 gtk_cmclist_select_all (GtkCMCList
*clist
)
3555 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3557 GTK_CMCLIST_GET_CLASS (clist
)->select_all (clist
);
3561 gtk_cmclist_unselect_all (GtkCMCList
*clist
)
3563 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3565 GTK_CMCLIST_GET_CLASS (clist
)->unselect_all (clist
);
3569 gtk_cmclist_undo_selection (GtkCMCList
*clist
)
3571 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3573 if (clist
->selection_mode
== GTK_SELECTION_MULTIPLE
&&
3574 (clist
->undo_selection
|| clist
->undo_unselection
))
3575 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNDO_SELECTION
], 0);
3578 /* PRIVATE SELECTION FUNCTIONS
3589 * real_undo_selection
3592 * update_extended_selection
3599 selection_find (GtkCMCList
*clist
,
3601 GList
*row_list_element
)
3603 return g_list_find (clist
->selection
, GINT_TO_POINTER (row_number
));
3607 toggle_row (GtkCMCList
*clist
,
3612 GtkCMCListRow
*clist_row
;
3614 switch (clist
->selection_mode
)
3616 case GTK_SELECTION_MULTIPLE
:
3617 case GTK_SELECTION_SINGLE
:
3618 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3623 if (clist_row
->state
== GTK_STATE_SELECTED
)
3625 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
3626 row
, column
, event
);
3630 case GTK_SELECTION_BROWSE
:
3631 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
3632 row
, column
, event
);
3635 g_assert_not_reached ();
3640 fake_toggle_row (GtkCMCList
*clist
,
3645 work
= ROW_ELEMENT (clist
, row
);
3647 if (!work
|| !GTK_CMCLIST_ROW (work
)->selectable
)
3650 if (GTK_CMCLIST_ROW (work
)->state
== GTK_STATE_NORMAL
)
3651 clist
->anchor_state
= GTK_CMCLIST_ROW (work
)->state
= GTK_STATE_SELECTED
;
3653 clist
->anchor_state
= GTK_CMCLIST_ROW (work
)->state
= GTK_STATE_NORMAL
;
3655 if (CLIST_UNFROZEN (clist
) &&
3656 gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
3657 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
,
3658 GTK_CMCLIST_ROW (work
));
3662 clist_has_grab (GtkCMCList
*clist
)
3664 return (gtk_widget_has_grab (GTK_WIDGET(clist
)) &&
3665 gtkut_pointer_is_grabbed(GTK_WIDGET(clist
)));
3669 toggle_focus_row (GtkCMCList
*clist
)
3671 cm_return_if_fail (clist
!= 0);
3672 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3674 if (clist_has_grab (clist
) ||
3675 clist
->focus_row
< 0 || clist
->focus_row
>= clist
->rows
)
3678 switch (clist
->selection_mode
)
3680 case GTK_SELECTION_SINGLE
:
3681 toggle_row (clist
, clist
->focus_row
, 0, NULL
);
3683 case GTK_SELECTION_MULTIPLE
:
3684 g_list_free (clist
->undo_selection
);
3685 g_list_free (clist
->undo_unselection
);
3686 clist
->undo_selection
= NULL
;
3687 clist
->undo_unselection
= NULL
;
3689 clist
->anchor
= clist
->focus_row
;
3690 clist
->drag_pos
= clist
->focus_row
;
3691 clist
->undo_anchor
= clist
->focus_row
;
3693 if (GTK_CMCLIST_ADD_MODE(clist
))
3694 fake_toggle_row (clist
, clist
->focus_row
);
3696 GTK_CMCLIST_GET_CLASS (clist
)->fake_unselect_all (clist
,clist
->focus_row
);
3698 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
3706 toggle_add_mode (GtkCMCList
*clist
)
3708 cm_return_if_fail (clist
!= 0);
3709 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3711 if (clist_has_grab (clist
) ||
3712 clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
3715 gtk_cmclist_undraw_focus (GTK_WIDGET (clist
));
3716 if (!GTK_CMCLIST_ADD_MODE(clist
))
3718 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_ADD_MODE
);
3722 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_ADD_MODE
);
3723 clist
->anchor_state
= GTK_STATE_SELECTED
;
3725 gtk_cmclist_draw_focus (GTK_WIDGET (clist
));
3729 real_select_row (GtkCMCList
*clist
,
3734 GtkCMCListRow
*clist_row
;
3737 gboolean row_selected
;
3739 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3741 if (row
< 0 || row
> (clist
->rows
- 1))
3744 switch (clist
->selection_mode
)
3746 case GTK_SELECTION_SINGLE
:
3747 case GTK_SELECTION_BROWSE
:
3749 row_selected
= FALSE
;
3750 list
= clist
->selection
;
3754 sel_row
= GPOINTER_TO_INT (list
->data
);
3758 row_selected
= TRUE
;
3760 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
3761 sel_row
, column
, event
);
3771 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3773 if (clist_row
->state
!= GTK_STATE_NORMAL
|| !clist_row
->selectable
)
3776 clist_row
->state
= GTK_STATE_SELECTED
;
3777 if (!clist
->selection
)
3779 clist
->selection
= g_list_append (clist
->selection
,
3780 GINT_TO_POINTER (row
));
3781 clist
->selection_end
= clist
->selection
;
3784 clist
->selection_end
=
3785 g_list_append (clist
->selection_end
, GINT_TO_POINTER (row
))->next
;
3787 if (CLIST_UNFROZEN (clist
)
3788 && (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
))
3789 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3793 real_unselect_row (GtkCMCList
*clist
,
3798 GtkCMCListRow
*clist_row
;
3800 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3802 if (row
< 0 || row
> (clist
->rows
- 1))
3805 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
3807 if (clist_row
->state
== GTK_STATE_SELECTED
)
3809 clist_row
->state
= GTK_STATE_NORMAL
;
3811 if (clist
->selection_end
&&
3812 clist
->selection_end
->data
== GINT_TO_POINTER (row
))
3813 clist
->selection_end
= clist
->selection_end
->prev
;
3815 clist
->selection
= g_list_remove (clist
->selection
,
3816 GINT_TO_POINTER (row
));
3818 if (CLIST_UNFROZEN (clist
)
3819 && (gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
))
3820 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
, clist_row
);
3825 real_select_all (GtkCMCList
*clist
)
3827 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3829 if (clist_has_grab (clist
))
3832 switch (clist
->selection_mode
)
3834 case GTK_SELECTION_SINGLE
:
3835 case GTK_SELECTION_BROWSE
:
3838 case GTK_SELECTION_MULTIPLE
:
3839 g_list_free (clist
->undo_selection
);
3840 g_list_free (clist
->undo_unselection
);
3841 clist
->undo_selection
= NULL
;
3842 clist
->undo_unselection
= NULL
;
3845 ((GtkCMCListRow
*) (clist
->row_list
->data
))->state
!=
3847 fake_toggle_row (clist
, 0);
3849 clist
->anchor_state
= GTK_STATE_SELECTED
;
3851 clist
->drag_pos
= 0;
3852 clist
->undo_anchor
= clist
->focus_row
;
3853 update_extended_selection (clist
, clist
->rows
);
3854 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
3857 g_assert_not_reached ();
3862 real_unselect_all (GtkCMCList
*clist
)
3867 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3869 if (clist_has_grab (clist
))
3872 switch (clist
->selection_mode
)
3874 case GTK_SELECTION_BROWSE
:
3875 if (clist
->focus_row
>= 0)
3877 g_signal_emit (G_OBJECT (clist
),
3878 clist_signals
[SELECT_ROW
], 0,
3879 clist
->focus_row
, -1, NULL
);
3883 case GTK_SELECTION_MULTIPLE
:
3884 g_list_free (clist
->undo_selection
);
3885 g_list_free (clist
->undo_unselection
);
3886 clist
->undo_selection
= NULL
;
3887 clist
->undo_unselection
= NULL
;
3890 clist
->drag_pos
= -1;
3891 clist
->undo_anchor
= clist
->focus_row
;
3897 list
= clist
->selection
;
3900 i
= GPOINTER_TO_INT (list
->data
);
3902 g_signal_emit (G_OBJECT (clist
),
3903 clist_signals
[UNSELECT_ROW
], 0, i
, -1, NULL
);
3908 fake_unselect_all (GtkCMCList
*clist
,
3915 if (row
>= 0 && (work
= ROW_ELEMENT (clist
, row
)))
3917 if (GTK_CMCLIST_ROW (work
)->state
== GTK_STATE_NORMAL
&&
3918 GTK_CMCLIST_ROW (work
)->selectable
)
3920 GTK_CMCLIST_ROW (work
)->state
= GTK_STATE_SELECTED
;
3922 if (CLIST_UNFROZEN (clist
) &&
3923 gtk_cmclist_row_is_visible (clist
, row
) != GTK_VISIBILITY_NONE
)
3924 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, row
,
3925 GTK_CMCLIST_ROW (work
));
3929 clist
->undo_selection
= clist
->selection
;
3930 clist
->selection
= NULL
;
3931 clist
->selection_end
= NULL
;
3933 for (list
= clist
->undo_selection
; list
; list
= list
->next
)
3935 if ((i
= GPOINTER_TO_INT (list
->data
)) == row
||
3936 !(work
= g_list_nth (clist
->row_list
, i
)))
3939 GTK_CMCLIST_ROW (work
)->state
= GTK_STATE_NORMAL
;
3940 if (CLIST_UNFROZEN (clist
) &&
3941 gtk_cmclist_row_is_visible (clist
, i
) != GTK_VISIBILITY_NONE
)
3942 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, i
,
3943 GTK_CMCLIST_ROW (work
));
3948 real_undo_selection (GtkCMCList
*clist
)
3952 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
3954 if (clist_has_grab (clist
) ||
3955 clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
3958 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
3960 if (!(clist
->undo_selection
|| clist
->undo_unselection
))
3962 gtk_cmclist_unselect_all (clist
);
3966 for (work
= clist
->undo_selection
; work
; work
= work
->next
)
3967 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
3968 GPOINTER_TO_INT (work
->data
), -1, NULL
);
3970 for (work
= clist
->undo_unselection
; work
; work
= work
->next
)
3972 /* g_print ("unselect %d\n",GPOINTER_TO_INT (work->data)); */
3973 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
3974 GPOINTER_TO_INT (work
->data
), -1, NULL
);
3977 if (gtk_widget_has_focus(GTK_WIDGET(clist
)) && clist
->focus_row
!= clist
->undo_anchor
)
3979 gtk_cmclist_undraw_focus (GTK_WIDGET (clist
));
3980 clist
->focus_row
= clist
->undo_anchor
;
3981 gtk_cmclist_draw_focus (GTK_WIDGET (clist
));
3984 clist
->focus_row
= clist
->undo_anchor
;
3986 clist
->undo_anchor
= -1;
3988 g_list_free (clist
->undo_selection
);
3989 g_list_free (clist
->undo_unselection
);
3990 clist
->undo_selection
= NULL
;
3991 clist
->undo_unselection
= NULL
;
3993 if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) + clist
->row_height
>
3994 clist
->clist_window_height
)
3995 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
3996 else if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) < 0)
3997 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4001 set_anchor (GtkCMCList
*clist
,
4006 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
4008 if (clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
|| clist
->anchor
>= 0)
4011 g_list_free (clist
->undo_selection
);
4012 g_list_free (clist
->undo_unselection
);
4013 clist
->undo_selection
= NULL
;
4014 clist
->undo_unselection
= NULL
;
4017 fake_toggle_row (clist
, anchor
);
4020 GTK_CMCLIST_GET_CLASS (clist
)->fake_unselect_all (clist
, anchor
);
4021 clist
->anchor_state
= GTK_STATE_SELECTED
;
4024 clist
->anchor
= anchor
;
4025 clist
->drag_pos
= anchor
;
4026 clist
->undo_anchor
= undo_anchor
;
4030 resync_selection (GtkCMCList
*clist
,
4037 GtkCMCListRow
*clist_row
;
4039 if (clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
4042 if (clist
->anchor
< 0 || clist
->drag_pos
< 0)
4045 gtk_cmclist_freeze (clist
);
4047 i
= MIN (clist
->anchor
, clist
->drag_pos
);
4048 e
= MAX (clist
->anchor
, clist
->drag_pos
);
4050 if (clist
->undo_selection
)
4052 list
= clist
->selection
;
4053 clist
->selection
= clist
->undo_selection
;
4054 clist
->selection_end
= g_list_last (clist
->selection
);
4055 clist
->undo_selection
= list
;
4056 list
= clist
->selection
;
4059 row
= GPOINTER_TO_INT (list
->data
);
4061 if (row
< i
|| row
> e
)
4063 clist_row
= g_list_nth (clist
->row_list
, row
)->data
;
4064 if (clist_row
->selectable
)
4066 clist_row
->state
= GTK_STATE_SELECTED
;
4067 g_signal_emit (G_OBJECT (clist
),
4068 clist_signals
[UNSELECT_ROW
], 0,
4070 clist
->undo_selection
= g_list_prepend
4071 (clist
->undo_selection
, GINT_TO_POINTER (row
));
4077 if (clist
->anchor
< clist
->drag_pos
)
4079 for (list
= g_list_nth (clist
->row_list
, i
); i
<= e
;
4080 i
++, list
= list
->next
)
4081 if (GTK_CMCLIST_ROW (list
)->selectable
)
4083 if (g_list_find (clist
->selection
, GINT_TO_POINTER(i
)))
4085 if (GTK_CMCLIST_ROW (list
)->state
== GTK_STATE_NORMAL
)
4087 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_SELECTED
;
4088 g_signal_emit (G_OBJECT (clist
),
4089 clist_signals
[UNSELECT_ROW
], 0,
4091 clist
->undo_selection
=
4092 g_list_prepend (clist
->undo_selection
,
4093 GINT_TO_POINTER (i
));
4096 else if (GTK_CMCLIST_ROW (list
)->state
== GTK_STATE_SELECTED
)
4098 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_NORMAL
;
4099 clist
->undo_unselection
=
4100 g_list_prepend (clist
->undo_unselection
,
4101 GINT_TO_POINTER (i
));
4107 for (list
= g_list_nth (clist
->row_list
, e
); i
<= e
;
4108 e
--, list
= list
->prev
)
4109 if (GTK_CMCLIST_ROW (list
)->selectable
)
4111 if (g_list_find (clist
->selection
, GINT_TO_POINTER(e
)))
4113 if (GTK_CMCLIST_ROW (list
)->state
== GTK_STATE_NORMAL
)
4115 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_SELECTED
;
4116 g_signal_emit (G_OBJECT (clist
),
4117 clist_signals
[UNSELECT_ROW
], 0,
4119 clist
->undo_selection
=
4120 g_list_prepend (clist
->undo_selection
,
4121 GINT_TO_POINTER (e
));
4124 else if (GTK_CMCLIST_ROW (list
)->state
== GTK_STATE_SELECTED
)
4126 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_NORMAL
;
4127 clist
->undo_unselection
=
4128 g_list_prepend (clist
->undo_unselection
,
4129 GINT_TO_POINTER (e
));
4134 clist
->undo_unselection
= g_list_reverse (clist
->undo_unselection
);
4135 for (list
= clist
->undo_unselection
; list
; list
= list
->next
)
4136 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
4137 GPOINTER_TO_INT (list
->data
), -1, event
);
4140 clist
->drag_pos
= -1;
4142 gtk_cmclist_thaw (clist
);
4146 update_extended_selection (GtkCMCList
*clist
,
4156 gint y1
= clist
->clist_window_height
;
4157 gint y2
= clist
->clist_window_height
;
4162 if (clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
|| clist
->anchor
== -1)
4167 if (row
>= clist
->rows
)
4168 row
= clist
->rows
- 1;
4170 /* extending downwards */
4171 if (row
> clist
->drag_pos
&& clist
->anchor
<= clist
->drag_pos
)
4173 s2
= clist
->drag_pos
+ 1;
4176 /* extending upwards */
4177 else if (row
< clist
->drag_pos
&& clist
->anchor
>= clist
->drag_pos
)
4180 e2
= clist
->drag_pos
- 1;
4182 else if (row
< clist
->drag_pos
&& clist
->anchor
< clist
->drag_pos
)
4184 e1
= clist
->drag_pos
;
4185 /* row and drag_pos on different sides of anchor :
4186 take back the selection between anchor and drag_pos,
4187 select between anchor and row */
4188 if (row
< clist
->anchor
)
4190 s1
= clist
->anchor
+ 1;
4192 e2
= clist
->anchor
- 1;
4194 /* take back the selection between anchor and drag_pos */
4198 else if (row
> clist
->drag_pos
&& clist
->anchor
> clist
->drag_pos
)
4200 s1
= clist
->drag_pos
;
4201 /* row and drag_pos on different sides of anchor :
4202 take back the selection between anchor and drag_pos,
4203 select between anchor and row */
4204 if (row
> clist
->anchor
)
4206 e1
= clist
->anchor
- 1;
4207 s2
= clist
->anchor
+ 1;
4210 /* take back the selection between anchor and drag_pos */
4215 clist
->drag_pos
= row
;
4218 area
.width
= clist
->clist_window_width
;
4220 /* restore the elements between s1 and e1 */
4223 for (i
= s1
, list
= g_list_nth (clist
->row_list
, i
); i
<= e1
;
4224 i
++, list
= list
->next
)
4225 if (GTK_CMCLIST_ROW (list
)->selectable
)
4227 if (GTK_CMCLIST_GET_CLASS (clist
)->selection_find (clist
, i
, list
))
4228 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_SELECTED
;
4230 GTK_CMCLIST_ROW (list
)->state
= GTK_STATE_NORMAL
;
4233 top
= ROW_TOP_YPIXEL (clist
, clist
->focus_row
);
4235 if (top
+ clist
->row_height
<= 0)
4238 area
.height
= ROW_TOP_YPIXEL (clist
, e1
) + clist
->row_height
;
4239 draw_rows (clist
, &area
);
4240 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4242 else if (top
>= clist
->clist_window_height
)
4244 area
.y
= ROW_TOP_YPIXEL (clist
, s1
) - 1;
4245 area
.height
= clist
->clist_window_height
- area
.y
;
4246 draw_rows (clist
, &area
);
4247 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
4250 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4251 else if (top
+ clist
->row_height
> clist
->clist_window_height
)
4252 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
4254 y1
= ROW_TOP_YPIXEL (clist
, s1
) - 1;
4255 h1
= (e1
- s1
+ 1) * (clist
->row_height
+ CELL_SPACING
);
4258 /* extend the selection between s2 and e2 */
4261 for (i
= s2
, list
= g_list_nth (clist
->row_list
, i
); i
<= e2
;
4262 i
++, list
= list
->next
)
4263 if (GTK_CMCLIST_ROW (list
)->selectable
&&
4264 GTK_CMCLIST_ROW (list
)->state
!= clist
->anchor_state
)
4265 GTK_CMCLIST_ROW (list
)->state
= clist
->anchor_state
;
4267 top
= ROW_TOP_YPIXEL (clist
, clist
->focus_row
);
4269 if (top
+ clist
->row_height
<= 0)
4272 area
.height
= ROW_TOP_YPIXEL (clist
, e2
) + clist
->row_height
;
4273 draw_rows (clist
, &area
);
4274 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4276 else if (top
>= clist
->clist_window_height
)
4278 area
.y
= ROW_TOP_YPIXEL (clist
, s2
) - 1;
4279 area
.height
= clist
->clist_window_height
- area
.y
;
4280 draw_rows (clist
, &area
);
4281 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
4284 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4285 else if (top
+ clist
->row_height
> clist
->clist_window_height
)
4286 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
4288 y2
= ROW_TOP_YPIXEL (clist
, s2
) - 1;
4289 h2
= (e2
- s2
+ 1) * (clist
->row_height
+ CELL_SPACING
);
4292 area
.y
= MAX (0, MIN (y1
, y2
));
4293 if (area
.y
> clist
->clist_window_height
)
4295 area
.height
= MIN (clist
->clist_window_height
, h1
+ h2
);
4296 if (s1
>= 0 && s2
>= 0)
4297 area
.height
+= (clist
->row_height
+ CELL_SPACING
);
4298 draw_rows (clist
, &area
);
4302 start_selection (GtkCMCList
*clist
)
4304 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
4306 if (clist_has_grab (clist
))
4309 set_anchor (clist
, GTK_CMCLIST_ADD_MODE(clist
), clist
->focus_row
,
4314 end_selection (GtkCMCList
*clist
)
4316 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
4318 if (gtkut_pointer_is_grabbed (GTK_WIDGET (clist
)) &&
4319 gtk_widget_has_focus (GTK_WIDGET(clist
)))
4322 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
4326 extend_selection (GtkCMCList
*clist
,
4327 GtkScrollType scroll_type
,
4329 gboolean auto_start_selection
)
4331 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
4333 if (clist_has_grab (clist
) ||
4334 clist
->selection_mode
!= GTK_SELECTION_MULTIPLE
)
4337 if (auto_start_selection
)
4338 set_anchor (clist
, GTK_CMCLIST_ADD_MODE(clist
), clist
->focus_row
,
4340 else if (clist
->anchor
== -1)
4343 move_focus_row (clist
, scroll_type
, position
);
4345 if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) + clist
->row_height
>
4346 clist
->clist_window_height
)
4347 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
4348 else if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) < 0)
4349 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
4351 update_extended_selection (clist
, clist
->focus_row
);
4355 sync_selection (GtkCMCList
*clist
,
4362 if (mode
== SYNC_INSERT
)
4367 if (clist
->focus_row
>= row
)
4369 if (d
> 0 || clist
->focus_row
> row
)
4370 clist
->focus_row
+= d
;
4371 if (clist
->focus_row
== -1 && clist
->rows
>= 1)
4372 clist
->focus_row
= 0;
4373 else if (d
< 0 && clist
->focus_row
>= clist
->rows
- 1)
4374 clist
->focus_row
= clist
->rows
- 2;
4375 else if (clist
->focus_row
>= clist
->rows
) /* Paranoia */
4376 clist
->focus_row
= clist
->rows
- 1;
4379 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
4381 g_list_free (clist
->undo_selection
);
4382 g_list_free (clist
->undo_unselection
);
4383 clist
->undo_selection
= NULL
;
4384 clist
->undo_unselection
= NULL
;
4387 clist
->drag_pos
= -1;
4388 clist
->undo_anchor
= clist
->focus_row
;
4390 list
= clist
->selection
;
4394 if (GPOINTER_TO_INT (list
->data
) >= row
)
4395 list
->data
= ((gchar
*) list
->data
) + d
;
4401 * gtk_cmclist_destroy
4402 * gtk_cmclist_finalize
4404 static void gtk_cmclist_destroy (GtkWidget
*object
)
4410 cm_return_if_fail (GTK_IS_CMCLIST (object
));
4412 clist
= GTK_CMCLIST (object
);
4414 /* freeze the list */
4415 clist
->freeze_count
++;
4417 /* get rid of all the rows */
4418 gtk_cmclist_clear (clist
);
4420 /* Since we don't have a _remove method, unparent the children
4421 * instead of destroying them so the focus will be unset properly.
4422 * (For other containers, the _remove method takes care of the
4423 * unparent) The destroy will happen when the refcount drops
4427 /* unref adjustments */
4428 if (clist
->hadjustment
)
4430 g_signal_handlers_disconnect_matched(G_OBJECT (clist
->hadjustment
), G_SIGNAL_MATCH_DATA
,
4432 g_object_unref (G_OBJECT (clist
->hadjustment
));
4433 clist
->hadjustment
= NULL
;
4435 if (clist
->vadjustment
)
4437 g_signal_handlers_disconnect_matched(G_OBJECT (clist
->vadjustment
), G_SIGNAL_MATCH_DATA
,
4439 g_object_unref (G_OBJECT (clist
->vadjustment
));
4440 clist
->vadjustment
= NULL
;
4443 remove_grab (clist
);
4445 /* destroy the column buttons */
4446 for (i
= 0; i
< clist
->columns
; i
++)
4447 if (clist
->column
[i
].button
)
4449 gtk_widget_unparent (clist
->column
[i
].button
);
4450 clist
->column
[i
].button
= NULL
;
4453 if (GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->destroy
)
4454 (*GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->destroy
) (object
);
4458 gtk_cmclist_finalize (GObject
*object
)
4462 cm_return_if_fail (GTK_IS_CMCLIST (object
));
4464 clist
= GTK_CMCLIST (object
);
4466 columns_delete (clist
);
4468 G_OBJECT_CLASS (gtk_cmclist_parent_class
)->finalize (object
);
4472 * gtk_cmclist_realize
4473 * gtk_cmclist_unrealize
4477 * gtk_cmclist_style_set
4478 * gtk_cmclist_button_press
4479 * gtk_cmclist_button_release
4480 * gtk_cmclist_motion
4481 * gtk_cmclist_size_request
4482 * gtk_cmclist_size_allocate
4485 gtk_cmclist_realize (GtkWidget
*widget
)
4487 GtkAllocation allocation
;
4489 GtkStyle
*style
, *attached_style
;
4491 GdkWindowAttr attributes
;
4492 GtkCMCListRow
*clist_row
;
4494 gint attributes_mask
;
4499 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
4501 clist
= GTK_CMCLIST (widget
);
4503 gtk_widget_set_realized (widget
, TRUE
);
4505 gtk_widget_get_allocation (widget
, &allocation
);
4507 attributes
.window_type
= GDK_WINDOW_CHILD
;
4508 attributes
.x
= allocation
.x
;
4509 attributes
.y
= allocation
.y
;
4510 attributes
.width
= allocation
.width
;
4511 attributes
.height
= allocation
.height
;
4512 attributes
.wclass
= GDK_INPUT_OUTPUT
;
4513 attributes
.visual
= gtk_widget_get_visual (widget
);
4515 event_mask
= gtk_widget_get_events (widget
);
4516 attributes_mask
= GDK_WA_X
| GDK_WA_Y
| GDK_WA_VISUAL
;
4518 attributes
.event_mask
= GDK_VISIBILITY_NOTIFY_MASK
;
4521 window
= gdk_window_new (gtk_widget_get_parent_window (widget
),
4522 &attributes
, attributes_mask
);
4523 gtk_widget_set_window (widget
, window
);
4524 gtk_widget_register_window (widget
, window
);
4526 style
= gtk_widget_get_style (widget
);
4527 attached_style
= gtk_style_attach (style
, window
);
4528 if (attached_style
!= style
) {
4529 gtk_widget_set_style(widget
, attached_style
);
4530 style
= attached_style
;
4533 gtk_style_set_background (style
, window
, GTK_STATE_NORMAL
);
4535 /* column-title window */
4537 attributes
.x
= clist
->column_title_area
.x
;
4538 attributes
.y
= clist
->column_title_area
.y
;
4539 attributes
.width
= clist
->column_title_area
.width
;
4540 attributes
.height
= clist
->column_title_area
.height
;
4542 clist
->title_window
= gdk_window_new (window
, &attributes
,
4544 gtk_widget_register_window (widget
, clist
->title_window
);
4546 gtk_style_set_background (style
, clist
->title_window
,
4548 gdk_window_show (clist
->title_window
);
4550 /* set things up so column buttons are drawn in title window */
4551 for (i
= 0; i
< clist
->columns
; i
++)
4552 if (clist
->column
[i
].button
)
4553 gtk_widget_set_parent_window (clist
->column
[i
].button
,
4554 clist
->title_window
);
4557 attributes
.x
= (clist
->internal_allocation
.x
+
4559 attributes
.y
= (clist
->internal_allocation
.y
+
4561 clist
->column_title_area
.height
);
4562 attributes
.width
= clist
->clist_window_width
;
4563 attributes
.height
= clist
->clist_window_height
;
4564 attributes
.event_mask
= event_mask
|
4566 GDK_SMOOTH_SCROLL_MASK
|
4567 GDK_POINTER_MOTION_MASK
|
4568 GDK_KEY_RELEASE_MASK
|
4569 GDK_BUTTON_PRESS_MASK
|
4570 GDK_BUTTON_RELEASE_MASK
;
4572 clist
->clist_window
= gdk_window_new (window
, &attributes
,
4574 gtk_widget_register_window (widget
, clist
->clist_window
);
4576 gdk_window_set_background (clist
->clist_window
,
4577 &style
->base
[GTK_STATE_NORMAL
]);
4578 gdk_window_show (clist
->clist_window
);
4579 clist
->clist_window_width
= gdk_window_get_width(clist
->clist_window
);
4580 clist
->clist_window_height
= gdk_window_get_height(clist
->clist_window
);
4582 /* create resize windows */
4583 attributes
.wclass
= GDK_INPUT_ONLY
;
4584 attributes_mask
= GDK_WA_CURSOR
;
4585 attributes
.cursor
= gdk_cursor_new_for_display (gtk_widget_get_display (widget
),
4586 GDK_SB_H_DOUBLE_ARROW
);
4587 clist
->cursor_drag
= attributes
.cursor
;
4589 attributes
.x
= LIST_WIDTH (clist
) + 1;
4591 attributes
.width
= 0;
4592 attributes
.height
= 0;
4593 attributes
.event_mask
= event_mask
|
4594 GDK_BUTTON_PRESS_MASK
|
4595 GDK_BUTTON_RELEASE_MASK
|
4596 GDK_POINTER_MOTION_MASK
;
4598 for (i
= 0; i
< clist
->columns
; i
++)
4600 clist
->column
[i
].window
= gdk_window_new (clist
->title_window
,
4601 &attributes
, attributes_mask
);
4602 gtk_widget_register_window (widget
, clist
->column
[i
].window
);
4605 /* This is slightly less efficient than creating them with the
4606 * right size to begin with, but easier
4608 size_allocate_title_buttons (clist
);
4610 /* attach optional row/cell styles, allocate foreground/background colors */
4611 list
= clist
->row_list
;
4612 for (i
= 0; i
< clist
->rows
; i
++)
4614 clist_row
= list
->data
;
4617 if (clist_row
->style
)
4618 clist_row
->style
= gtk_style_attach (clist_row
->style
,
4619 clist
->clist_window
);
4621 for (j
= 0; j
< clist
->columns
; j
++)
4622 if (clist_row
->cell
[j
].style
)
4623 clist_row
->cell
[j
].style
=
4624 gtk_style_attach (clist_row
->cell
[j
].style
, clist
->clist_window
);
4629 gtk_cmclist_unrealize (GtkWidget
*widget
)
4634 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
4636 clist
= GTK_CMCLIST (widget
);
4638 /* freeze the list */
4639 clist
->freeze_count
++;
4641 if (gtk_widget_get_mapped (widget
))
4642 gtk_cmclist_unmap (widget
);
4644 gtk_widget_set_mapped (widget
, FALSE
);
4646 /* detach optional row/cell styles */
4647 if (gtk_widget_get_realized (widget
))
4649 GtkCMCListRow
*clist_row
;
4653 list
= clist
->row_list
;
4654 for (i
= 0; i
< clist
->rows
; i
++)
4656 clist_row
= list
->data
;
4659 if (clist_row
->style
)
4660 gtk_style_detach (clist_row
->style
);
4661 for (j
= 0; j
< clist
->columns
; j
++)
4662 if (clist_row
->cell
[j
].style
)
4663 gtk_style_detach (clist_row
->cell
[j
].style
);
4667 gdk_cursor_unref (clist
->cursor_drag
);
4669 for (i
= 0; i
< clist
->columns
; i
++)
4671 if (clist
->column
[i
].button
)
4672 gtk_widget_unrealize (clist
->column
[i
].button
);
4673 if (clist
->column
[i
].window
)
4675 gtk_widget_unregister_window (widget
, clist
->column
[i
].window
);
4676 gdk_window_destroy (clist
->column
[i
].window
);
4677 clist
->column
[i
].window
= NULL
;
4681 gtk_widget_unregister_window (widget
, clist
->clist_window
);
4682 gdk_window_destroy (clist
->clist_window
);
4683 clist
->clist_window
= NULL
;
4685 gtk_widget_unregister_window (widget
, clist
->title_window
);
4686 gdk_window_destroy (clist
->title_window
);
4687 clist
->title_window
= NULL
;
4689 clist
->cursor_drag
= NULL
;
4691 if (GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->unrealize
)
4692 (* GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->unrealize
) (widget
);
4696 gtk_cmclist_map (GtkWidget
*widget
)
4701 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
4703 clist
= GTK_CMCLIST (widget
);
4705 if (!gtk_widget_get_mapped (widget
))
4707 gtk_widget_set_mapped (widget
, TRUE
);
4709 /* map column buttons */
4710 for (i
= 0; i
< clist
->columns
; i
++)
4712 if (clist
->column
[i
].button
&&
4713 gtk_widget_get_visible (clist
->column
[i
].button
) &&
4714 !gtk_widget_get_mapped (clist
->column
[i
].button
))
4715 gtk_widget_map (clist
->column
[i
].button
);
4718 for (i
= 0; i
< clist
->columns
; i
++)
4719 if (clist
->column
[i
].window
&& clist
->column
[i
].button
)
4721 gdk_window_raise (clist
->column
[i
].window
);
4722 gdk_window_show (clist
->column
[i
].window
);
4725 gdk_window_show (clist
->title_window
);
4726 gdk_window_show (clist
->clist_window
);
4727 gdk_window_show (gtk_widget_get_window (widget
));
4729 /* unfreeze the list */
4730 clist
->freeze_count
= 0;
4735 gtk_cmclist_unmap (GtkWidget
*widget
)
4740 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
4742 clist
= GTK_CMCLIST (widget
);
4744 if (gtk_widget_get_mapped (widget
))
4746 gtk_widget_set_mapped (widget
, FALSE
);
4748 if (clist_has_grab (clist
))
4750 remove_grab (clist
);
4752 GTK_CMCLIST_GET_CLASS (widget
)->resync_selection (clist
, NULL
);
4754 clist
->click_cell
.row
= -1;
4755 clist
->click_cell
.column
= -1;
4756 clist
->drag_button
= 0;
4758 if (GTK_CMCLIST_IN_DRAG(clist
))
4762 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_IN_DRAG
);
4763 drag_data
= g_object_get_data (G_OBJECT (clist
),
4766 g_signal_handlers_unblock_matched(G_OBJECT(clist
), G_SIGNAL_MATCH_DATA
,
4767 0, 0, 0, 0, drag_data
);
4771 for (i
= 0; i
< clist
->columns
; i
++)
4772 if (clist
->column
[i
].window
)
4773 gdk_window_hide (clist
->column
[i
].window
);
4775 gdk_window_hide (clist
->clist_window
);
4776 gdk_window_hide (clist
->title_window
);
4777 gdk_window_hide (gtk_widget_get_window (widget
));
4779 /* unmap column buttons */
4780 for (i
= 0; i
< clist
->columns
; i
++)
4781 if (clist
->column
[i
].button
&&
4782 gtk_widget_get_mapped (clist
->column
[i
].button
))
4783 gtk_widget_unmap (clist
->column
[i
].button
);
4785 /* freeze the list */
4786 clist
->freeze_count
++;
4791 gtk_cmclist_draw (GtkWidget
*widget
,
4796 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
4797 cm_return_val_if_fail (cr
!= NULL
, FALSE
);
4799 if (gtk_widget_is_drawable (widget
))
4801 clist
= GTK_CMCLIST (widget
);
4802 clist
->draw_now
= 0;
4804 /* Draw clist_window */
4805 if (gtk_cairo_should_draw_window (cr
, clist
->clist_window
))
4809 /* The painting area is currently relative to GdkWindow
4810 * of the entire widget, we're only interested in the
4811 * part that is inside clist_window. */
4812 /* First, get geometry of clist_window in coordinates
4813 * relative to the parent window. */
4814 gdk_window_get_position(clist
->clist_window
, &area
.x
, &area
.y
);
4815 area
.height
= gdk_window_get_height(clist
->clist_window
);
4816 area
.width
= gdk_window_get_width(clist
->clist_window
);
4818 /* Store current state of the painting area, as we will
4819 * want to use it for title_window later. */
4822 /* Now clip the painting area to just the part that is inside
4823 * clist_window, and call draw_rows() with a GdkRectangle
4824 * corresponding to that. */
4825 gdk_cairo_rectangle(cr
, &area
);
4828 if (gdk_cairo_get_clip_rectangle (cr
, &area
))
4832 /* Before we pass the area to draw_rows(), we need to
4833 * transform it to coordinates relative to clist_window.
4834 * We already made sure that it is entirely inside
4835 * this window, so no further checks have to be made. */
4836 gdk_window_coords_from_parent(clist
->clist_window
, area
.x
, area
.y
, &x
, &y
);
4840 draw_rows (clist
, &area
);
4843 /* Restore the original painting area for further use. */
4847 /* Draw title_window - just propagate the draw event
4848 * to the individual button widgets, they can draw
4850 if (gtk_cairo_should_draw_window (cr
, clist
->title_window
))
4854 for (i
= 0; i
< clist
->columns
; i
++)
4856 if (clist
->column
[i
].button
) {
4857 gtk_container_propagate_draw (GTK_CONTAINER (clist
), clist
->column
[i
].button
, cr
);
4861 clist
->draw_now
= 1;
4867 gtk_cmclist_style_set (GtkWidget
*widget
,
4868 GtkStyle
*previous_style
)
4873 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
4875 if (GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->style_set
)
4876 (*GTK_WIDGET_CLASS (gtk_cmclist_parent_class
)->style_set
) (widget
, previous_style
);
4878 clist
= GTK_CMCLIST (widget
);
4880 if (gtk_widget_get_realized (widget
))
4882 style
= gtk_widget_get_style (widget
);
4883 gtk_style_set_background (style
, gtk_widget_get_window (widget
),
4884 gtk_widget_get_state(widget
));
4885 gtk_style_set_background (style
, clist
->title_window
, GTK_STATE_NORMAL
);
4886 gdk_window_set_background (clist
->clist_window
, &style
->base
[GTK_STATE_NORMAL
]);
4889 /* Fill in data after widget has correct style */
4891 /* text properties */
4892 if (!GTK_CMCLIST_ROW_HEIGHT_SET(clist
))
4893 /* Reset clist->row_height */
4894 gtk_cmclist_set_row_height (clist
, 0);
4897 if (!GTK_CMCLIST_AUTO_RESIZE_BLOCKED (clist
))
4902 for (i
= 0; i
< clist
->columns
; i
++)
4903 if (clist
->column
[i
].auto_resize
)
4905 width
= gtk_cmclist_optimal_column_width (clist
, i
);
4906 if (width
!= clist
->column
[i
].width
)
4907 gtk_cmclist_set_column_width (clist
, i
, width
);
4913 gtk_cmclist_button_press (GtkWidget
*widget
,
4914 GdkEventButton
*event
)
4922 gint button_actions
;
4924 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
4925 cm_return_val_if_fail (event
!= NULL
, FALSE
);
4927 clist
= GTK_CMCLIST (widget
);
4929 button_actions
= clist
->button_actions
[event
->button
- 1];
4931 if (button_actions
== GTK_CMBUTTON_IGNORED
)
4934 /* selections on the list */
4935 if (event
->window
== clist
->clist_window
)
4940 if (get_selection_info (clist
, x
, y
, &row
, &column
))
4942 gint old_row
= clist
->focus_row
;
4944 if (clist
->focus_row
== -1)
4947 if (event
->type
== GDK_BUTTON_PRESS
)
4949 GdkEventMask mask
= ((1 << (4 + event
->button
)) |
4950 GDK_POINTER_MOTION_HINT_MASK
|
4951 GDK_BUTTON_RELEASE_MASK
);
4953 if (gdk_pointer_grab (clist
->clist_window
, FALSE
, mask
,
4954 NULL
, NULL
, event
->time
))
4956 gtk_grab_add (widget
);
4958 clist
->click_cell
.row
= row
;
4959 clist
->click_cell
.column
= column
;
4960 clist
->drag_button
= event
->button
;
4964 clist
->click_cell
.row
= -1;
4965 clist
->click_cell
.column
= -1;
4967 clist
->drag_button
= 0;
4968 remove_grab (clist
);
4971 if (button_actions
& GTK_CMBUTTON_SELECTS
)
4973 if (GTK_CMCLIST_ADD_MODE(clist
))
4975 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_ADD_MODE
);
4976 if (gtk_widget_has_focus(widget
))
4978 gtk_cmclist_undraw_focus (widget
);
4979 clist
->focus_row
= row
;
4980 gtk_cmclist_draw_focus (widget
);
4984 clist
->focus_row
= row
;
4987 else if (row
!= clist
->focus_row
)
4989 if (gtk_widget_has_focus(widget
))
4991 gtk_cmclist_undraw_focus (widget
);
4992 clist
->focus_row
= row
;
4993 gtk_cmclist_draw_focus (widget
);
4996 clist
->focus_row
= row
;
5000 if (!gtk_widget_has_focus(widget
))
5001 gtk_widget_grab_focus (widget
);
5003 if (button_actions
& GTK_CMBUTTON_SELECTS
)
5005 switch (clist
->selection_mode
)
5007 case GTK_SELECTION_SINGLE
:
5008 if (event
->type
!= GDK_BUTTON_PRESS
)
5010 g_signal_emit (G_OBJECT (clist
),
5011 clist_signals
[SELECT_ROW
], 0,
5012 row
, column
, event
);
5016 clist
->anchor
= row
;
5018 case GTK_SELECTION_BROWSE
:
5019 g_signal_emit (G_OBJECT (clist
),
5020 clist_signals
[SELECT_ROW
], 0,
5021 row
, column
, event
);
5023 case GTK_SELECTION_MULTIPLE
:
5024 if (event
->type
!= GDK_BUTTON_PRESS
)
5026 if (clist
->anchor
!= -1)
5028 update_extended_selection (clist
, clist
->focus_row
);
5029 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection
5030 (clist
, (GdkEvent
*) event
);
5032 g_signal_emit (G_OBJECT (clist
),
5033 clist_signals
[SELECT_ROW
], 0,
5034 row
, column
, event
);
5038 if (event
->state
& GDK_CONTROL_MASK
)
5040 if (event
->state
& GDK_SHIFT_MASK
)
5042 if (clist
->anchor
< 0)
5044 g_list_free (clist
->undo_selection
);
5045 g_list_free (clist
->undo_unselection
);
5046 clist
->undo_selection
= NULL
;
5047 clist
->undo_unselection
= NULL
;
5048 clist
->anchor
= old_row
;
5049 clist
->drag_pos
= old_row
;
5050 clist
->undo_anchor
= old_row
;
5052 update_extended_selection (clist
, clist
->focus_row
);
5056 if (clist
->anchor
== -1)
5057 set_anchor (clist
, TRUE
, row
, old_row
);
5059 update_extended_selection (clist
,
5065 if (event
->state
& GDK_SHIFT_MASK
)
5067 set_anchor (clist
, FALSE
, old_row
, old_row
);
5068 update_extended_selection (clist
, clist
->focus_row
);
5072 if (clist
->anchor
== -1)
5073 set_anchor (clist
, FALSE
, row
, old_row
);
5075 update_extended_selection (clist
, clist
->focus_row
);
5085 /* press on resize windows */
5086 for (i
= 0; i
< clist
->columns
; i
++)
5087 if (clist
->column
[i
].resizeable
&& clist
->column
[i
].window
&&
5088 event
->window
== clist
->column
[i
].window
)
5092 if (gdk_pointer_grab (clist
->column
[i
].window
, FALSE
,
5093 GDK_POINTER_MOTION_HINT_MASK
|
5094 GDK_BUTTON1_MOTION_MASK
|
5095 GDK_BUTTON_RELEASE_MASK
,
5096 NULL
, NULL
, event
->time
))
5099 gtk_grab_add (widget
);
5100 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_IN_DRAG
);
5102 /* block attached dnd signal handler */
5103 drag_data
= g_object_get_data (G_OBJECT (clist
), "gtk-site-data");
5105 g_signal_handlers_block_matched(G_OBJECT(clist
), G_SIGNAL_MATCH_DATA
,
5106 0, 0, 0, 0, drag_data
);
5108 if (!gtk_widget_has_focus(widget
))
5109 gtk_widget_grab_focus (widget
);
5111 clist
->drag_pos
= i
;
5112 clist
->x_drag
= (COLUMN_LEFT_XPIXEL(clist
, i
) + COLUMN_INSET
+
5113 clist
->column
[i
].area
.width
+ CELL_SPACING
);
5122 gtk_cmclist_button_release (GtkWidget
*widget
,
5123 GdkEventButton
*event
)
5126 gint button_actions
;
5128 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
5129 cm_return_val_if_fail (event
!= NULL
, FALSE
);
5131 clist
= GTK_CMCLIST (widget
);
5133 button_actions
= clist
->button_actions
[event
->button
- 1];
5134 if (button_actions
== GTK_CMBUTTON_IGNORED
)
5137 /* release on resize windows */
5138 if (GTK_CMCLIST_IN_DRAG(clist
))
5145 i
= clist
->drag_pos
;
5146 clist
->drag_pos
= -1;
5148 /* unblock attached dnd signal handler */
5149 drag_data
= g_object_get_data (G_OBJECT (clist
), "gtk-site-data");
5151 g_signal_handlers_unblock_matched(G_OBJECT(clist
), G_SIGNAL_MATCH_DATA
,
5152 0, 0, 0, 0, drag_data
);
5154 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_IN_DRAG
);
5155 gtk_widget_get_pointer (widget
, &x
, NULL
);
5156 gtk_grab_remove (widget
);
5157 gdk_display_pointer_ungrab (gtk_widget_get_display (widget
), event
->time
);
5159 if (clist
->x_drag
>= 0)
5160 clist_refresh(clist
);
5162 width
= new_column_width (clist
, i
, &x
);
5163 gtk_cmclist_set_column_width (clist
, i
, width
);
5168 if (clist
->drag_button
== event
->button
)
5173 clist
->drag_button
= 0;
5174 clist
->click_cell
.row
= -1;
5175 clist
->click_cell
.column
= -1;
5177 remove_grab (clist
);
5179 if (button_actions
& GTK_CMBUTTON_SELECTS
)
5181 switch (clist
->selection_mode
)
5183 case GTK_SELECTION_MULTIPLE
:
5184 if (!(event
->state
& GDK_SHIFT_MASK
) ||
5185 !gtk_widget_get_can_focus (widget
) ||
5186 event
->x
< 0 || event
->x
>= clist
->clist_window_width
||
5187 event
->y
< 0 || event
->y
>= clist
->clist_window_height
)
5188 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection
5189 (clist
, (GdkEvent
*) event
);
5191 case GTK_SELECTION_SINGLE
:
5192 if (get_selection_info (clist
, event
->x
, event
->y
,
5195 if (row
>= 0 && row
< clist
->rows
&& clist
->anchor
== row
)
5196 toggle_row (clist
, row
, column
, (GdkEvent
*) event
);
5212 gtk_cmclist_motion (GtkWidget
*widget
,
5213 GdkEventMotion
*event
)
5220 gint button_actions
= 0;
5223 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
5225 clist
= GTK_CMCLIST (widget
);
5226 if (!clist_has_grab (clist
))
5229 if (clist
->drag_button
> 0)
5230 button_actions
= clist
->button_actions
[clist
->drag_button
- 1];
5232 if (GTK_CMCLIST_IN_DRAG(clist
))
5234 if (event
->is_hint
|| event
->window
!= gtk_widget_get_window (widget
))
5235 gtk_widget_get_pointer (widget
, &x
, NULL
);
5239 new_width
= new_column_width (clist
, clist
->drag_pos
, &x
);
5240 if (x
!= clist
->x_drag
)
5242 /* x_drag < 0 indicates that the xor line is already invisible */
5243 if (clist
->x_drag
>= 0)
5244 clist_refresh(clist
);
5248 if (clist
->x_drag
>= 0)
5249 draw_xor_line (clist
);
5252 if (new_width
<= MAX (COLUMN_MIN_WIDTH
+ 1,
5253 clist
->column
[clist
->drag_pos
].min_width
+ 1))
5255 if (COLUMN_LEFT_XPIXEL (clist
, clist
->drag_pos
) < 0 && x
< 0)
5256 gtk_cmclist_moveto (clist
, -1, clist
->drag_pos
, 0, 0);
5259 if (clist
->column
[clist
->drag_pos
].max_width
>= COLUMN_MIN_WIDTH
&&
5260 new_width
>= clist
->column
[clist
->drag_pos
].max_width
)
5262 if (COLUMN_LEFT_XPIXEL (clist
, clist
->drag_pos
) + new_width
>
5263 clist
->clist_window_width
&& x
< 0)
5264 move_horizontal (clist
,
5265 COLUMN_LEFT_XPIXEL (clist
, clist
->drag_pos
) +
5266 new_width
- clist
->clist_window_width
+
5267 COLUMN_INSET
+ CELL_SPACING
);
5272 if (event
->is_hint
|| event
->window
!= clist
->clist_window
) {
5273 GdkDisplay
*display
;
5276 display
= gdk_window_get_display(event
->window
);
5277 seat
= gdk_display_get_default_seat(display
);
5278 gdk_device_get_position(gdk_seat_get_pointer(seat
),
5287 if (GTK_CMCLIST_REORDERABLE(clist
) && button_actions
& GTK_CMBUTTON_DRAGS
)
5289 /* delayed drag start */
5290 if (event
->window
== clist
->clist_window
&&
5291 clist
->click_cell
.row
>= 0 && clist
->click_cell
.column
>= 0 &&
5292 (y
< 0 || y
>= clist
->clist_window_height
||
5293 x
< 0 || x
>= clist
->clist_window_width
||
5294 y
< ROW_TOP_YPIXEL (clist
, clist
->click_cell
.row
) ||
5295 y
>= (ROW_TOP_YPIXEL (clist
, clist
->click_cell
.row
) +
5296 clist
->row_height
) ||
5297 x
< COLUMN_LEFT_XPIXEL (clist
, clist
->click_cell
.column
) ||
5298 x
>= (COLUMN_LEFT_XPIXEL(clist
, clist
->click_cell
.column
) +
5299 clist
->column
[clist
->click_cell
.column
].area
.width
)))
5301 GtkTargetList
*target_list
;
5303 target_list
= gtk_target_list_new (&clist_target_table
, 1);
5304 gtk_drag_begin_with_coordinates(widget
, target_list
, GDK_ACTION_MOVE
,
5305 clist
->drag_button
, (GdkEvent
*)event
, -1, -1);
5311 /* horizontal autoscrolling */
5312 if (clist
->hadjustment
&& LIST_WIDTH (clist
) > clist
->clist_window_width
&&
5313 (x
< 0 || x
>= clist
->clist_window_width
))
5318 clist
->htimer
= gdk_threads_add_timeout
5319 (SCROLL_TIME
, (GSourceFunc
) horizontal_timeout
, clist
);
5320 value
= gtk_adjustment_get_value (clist
->hadjustment
);
5321 if (!((x
< 0 && value
== 0) ||
5322 (x
>= clist
->clist_window_width
&&
5324 LIST_WIDTH (clist
) - clist
->clist_window_width
)))
5327 move_horizontal (clist
, -1 + (x
/2));
5329 move_horizontal (clist
, 1 + (x
- clist
->clist_window_width
) / 2);
5333 if (GTK_CMCLIST_IN_DRAG(clist
))
5336 /* vertical autoscrolling */
5337 row
= ROW_FROM_YPIXEL (clist
, y
);
5339 /* don't scroll on last pixel row if it's a cell spacing */
5340 if (y
== clist
->clist_window_height
- 1 &&
5341 y
== ROW_TOP_YPIXEL (clist
, row
-1) + clist
->row_height
)
5344 if (LIST_HEIGHT (clist
) > clist
->clist_window_height
&&
5345 (y
< 0 || y
>= clist
->clist_window_height
))
5349 clist
->vtimer
= gdk_threads_add_timeout (SCROLL_TIME
,
5350 (GSourceFunc
) vertical_timeout
, clist
);
5351 if (clist
->drag_button
&&
5352 ((y
< 0 && clist
->focus_row
== 0) ||
5353 (y
>= clist
->clist_window_height
&&
5354 clist
->focus_row
== clist
->rows
- 1)))
5358 row
= CLAMP (row
, 0, clist
->rows
- 1);
5360 if (button_actions
& GTK_CMBUTTON_SELECTS
&&
5361 !g_object_get_data (G_OBJECT (widget
), "gtk-site-data"))
5363 if (row
== clist
->focus_row
)
5366 gtk_cmclist_undraw_focus (widget
);
5367 clist
->focus_row
= row
;
5368 gtk_cmclist_draw_focus (widget
);
5370 switch (clist
->selection_mode
)
5372 case GTK_SELECTION_BROWSE
:
5373 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
5374 clist
->focus_row
, -1, event
);
5376 case GTK_SELECTION_MULTIPLE
:
5377 update_extended_selection (clist
, clist
->focus_row
);
5384 if (ROW_TOP_YPIXEL(clist
, row
) < 0)
5385 move_vertical (clist
, row
, 0);
5386 else if (ROW_TOP_YPIXEL(clist
, row
) + clist
->row_height
>
5387 clist
->clist_window_height
)
5388 move_vertical (clist
, row
, 1);
5394 gtk_cmclist_get_preferred_width (GtkWidget
*widget
,
5395 gint
*minimal_width
,
5396 gint
*natural_width
)
5398 GtkRequisition requisition
;
5400 gtk_cmclist_size_request (widget
, &requisition
);
5402 *minimal_width
= *natural_width
= requisition
.width
;
5406 gtk_cmclist_get_preferred_height (GtkWidget
*widget
,
5407 gint
*minimal_height
,
5408 gint
*natural_height
)
5410 GtkRequisition requisition
;
5412 gtk_cmclist_size_request (widget
, &requisition
);
5414 *minimal_height
= *natural_height
= requisition
.height
;
5418 gtk_cmclist_size_request (GtkWidget
*widget
,
5419 GtkRequisition
*requisition
)
5425 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
5426 cm_return_if_fail (requisition
!= NULL
);
5428 clist
= GTK_CMCLIST (widget
);
5429 style
= gtk_widget_get_style (widget
);
5431 requisition
->width
= 0;
5432 requisition
->height
= 0;
5434 /* compute the size of the column title (title) area */
5435 clist
->column_title_area
.height
= 0;
5436 if (GTK_CMCLIST_SHOW_TITLES(clist
)) {
5437 for (i
= 0; i
< clist
->columns
; i
++)
5438 if (clist
->column
[i
].button
)
5440 GtkRequisition child_requisition
;
5442 gtk_widget_get_preferred_size(clist
->column
[i
].button
,
5443 &child_requisition
, NULL
);
5444 clist
->column_title_area
.height
=
5445 MAX (clist
->column_title_area
.height
,
5446 child_requisition
.height
);
5448 //clist->column_title_area.height = font_height;
5450 border_width
= gtk_container_get_border_width (GTK_CONTAINER (widget
));
5451 requisition
->width
+= (style
->xthickness
+
5453 requisition
->height
+= (clist
->column_title_area
.height
+
5454 (style
->ythickness
+
5457 /* if (!clist->hadjustment) */
5458 requisition
->width
+= list_requisition_width (clist
);
5459 /* if (!clist->vadjustment) */
5460 requisition
->height
+= LIST_HEIGHT (clist
);
5464 gtk_cmclist_size_allocate (GtkWidget
*widget
,
5465 GtkAllocation
*allocation
)
5469 GtkAllocation clist_allocation
;
5472 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
5473 cm_return_if_fail (allocation
!= NULL
);
5475 style
= gtk_widget_get_style (widget
);
5476 clist
= GTK_CMCLIST (widget
);
5477 gtk_widget_set_allocation (widget
, allocation
);
5478 border_width
= gtk_container_get_border_width (GTK_CONTAINER (widget
));
5480 if (gtk_widget_get_realized (widget
))
5482 gdk_window_move_resize (gtk_widget_get_window (widget
),
5483 allocation
->x
+ border_width
,
5484 allocation
->y
+ border_width
,
5485 allocation
->width
- border_width
* 2,
5486 allocation
->height
- border_width
* 2);
5489 /* use internal allocation structure for all the math
5490 * because it's easier than always subtracting the container
5492 clist
->internal_allocation
.x
= 0;
5493 clist
->internal_allocation
.y
= 0;
5494 clist
->internal_allocation
.width
= MAX (1, (gint
)allocation
->width
-
5496 clist
->internal_allocation
.height
= MAX (1, (gint
)allocation
->height
-
5499 /* allocate clist window assuming no scrollbars */
5500 clist_allocation
.x
= (clist
->internal_allocation
.x
+
5502 clist_allocation
.y
= (clist
->internal_allocation
.y
+
5504 clist
->column_title_area
.height
);
5505 clist_allocation
.width
= MAX (1, (gint
)clist
->internal_allocation
.width
-
5506 (2 * (gint
)style
->xthickness
));
5507 clist_allocation
.height
= MAX (1, (gint
)clist
->internal_allocation
.height
-
5508 (2 * (gint
)style
->ythickness
) -
5509 (gint
)clist
->column_title_area
.height
);
5511 clist
->clist_window_width
= clist_allocation
.width
;
5512 clist
->clist_window_height
= clist_allocation
.height
;
5514 if (gtk_widget_get_realized (widget
))
5516 gdk_window_move_resize (clist
->clist_window
,
5519 clist_allocation
.width
,
5520 clist_allocation
.height
);
5523 /* position the window which holds the column title buttons */
5524 clist
->column_title_area
.x
= style
->xthickness
;
5525 clist
->column_title_area
.y
= style
->ythickness
;
5526 clist
->column_title_area
.width
= clist_allocation
.width
;
5528 if (gtk_widget_get_realized (widget
))
5530 gdk_window_move_resize (clist
->title_window
,
5531 clist
->column_title_area
.x
,
5532 clist
->column_title_area
.y
,
5533 clist
->column_title_area
.width
,
5534 clist
->column_title_area
.height
);
5537 /* column button allocation */
5538 size_allocate_columns (clist
, FALSE
);
5539 size_allocate_title_buttons (clist
);
5541 adjust_adjustments (clist
, TRUE
);
5545 * gtk_cmclist_forall
5548 gtk_cmclist_forall (GtkContainer
*container
,
5549 gboolean include_internals
,
5550 GtkCallback callback
,
5551 gpointer callback_data
)
5556 cm_return_if_fail (GTK_IS_CMCLIST (container
));
5557 cm_return_if_fail (callback
!= NULL
);
5559 if (!include_internals
)
5562 clist
= GTK_CMCLIST (container
);
5564 /* callback for the column buttons */
5565 for (i
= 0; i
< clist
->columns
; i
++)
5566 if (clist
->column
[i
].button
)
5567 (*callback
) (clist
->column
[i
].button
, callback_data
);
5570 /* PRIVATE DRAWING FUNCTIONS
5579 get_cell_style (GtkCMCList
*clist
,
5580 GtkCMCListRow
*clist_row
,
5587 if (clist_row
->cell
[column
].style
)
5590 *style
= clist_row
->cell
[column
].style
;
5592 else if (clist_row
->style
)
5595 *style
= clist_row
->style
;
5599 gtkstyle
= gtk_widget_get_style (GTK_WIDGET (clist
));
5606 draw_cell_pixbuf (GdkWindow
*window
,
5607 GdkRectangle
*clip_rectangle
,
5618 if (!pixbuf
|| (width
== 0 && height
== 0))
5621 if (x
< clip_rectangle
->x
)
5623 xsrc
= clip_rectangle
->x
- x
;
5625 x
= clip_rectangle
->x
;
5627 if (x
+ width
> clip_rectangle
->x
+ clip_rectangle
->width
)
5628 width
= clip_rectangle
->x
+ clip_rectangle
->width
- x
;
5630 if (y
< clip_rectangle
->y
)
5632 ysrc
= clip_rectangle
->y
- y
;
5634 y
= clip_rectangle
->y
;
5637 if (y
+ height
> clip_rectangle
->y
+ clip_rectangle
->height
)
5638 height
= clip_rectangle
->y
+ clip_rectangle
->height
- y
;
5640 gdk_cairo_set_source_pixbuf(cr
, pixbuf
, x
, y
);
5643 return x
+ MAX (width
, 0);
5646 static void cairo_dash_from_add_mode(GtkCMCList
*clist
, cairo_t
*cr
)
5648 const double dashes
[] = { 4.0, 4.0 };
5649 if (GTK_CMCLIST_ADD_MODE(clist
))
5650 cairo_set_dash(cr
, dashes
, 2, 0);
5652 cairo_set_dash(cr
, NULL
, 0, 0);
5656 draw_row (GtkCMCList
*clist
,
5659 GtkCMCListRow
*clist_row
)
5664 GdkRectangle row_rectangle
;
5665 GdkRectangle cell_rectangle
;
5666 GdkRectangle clip_rectangle
;
5667 GdkRectangle intersect_rectangle
;
5672 cm_return_if_fail (clist
!= NULL
);
5674 if (clist
->draw_now
) {
5675 gtk_widget_queue_draw(GTK_WIDGET(clist
));
5679 /* bail now if we arn't drawable yet */
5680 if (!gtk_widget_is_drawable (GTK_WIDGET(clist
)) || row
< 0 || row
>= clist
->rows
)
5683 widget
= GTK_WIDGET (clist
);
5685 /* if the function is passed the pointer to the row instead of null,
5686 * it avoids this expensive lookup */
5688 clist_row
= ROW_ELEMENT (clist
, row
)->data
;
5690 style
= clist_row
->style
? clist_row
->style
: gtk_widget_get_style (widget
);
5692 /* rectangle of the entire row */
5693 row_rectangle
.x
= 0;
5694 row_rectangle
.y
= ROW_TOP_YPIXEL (clist
, row
);
5695 row_rectangle
.width
= clist
->clist_window_width
;
5696 row_rectangle
.height
= clist
->row_height
;
5698 /* rectangle of the cell spacing above the row */
5699 cell_rectangle
.x
= 0;
5700 cell_rectangle
.y
= row_rectangle
.y
- CELL_SPACING
;
5701 cell_rectangle
.width
= row_rectangle
.width
;
5702 cell_rectangle
.height
= CELL_SPACING
;
5704 /* rectangle used to clip drawing operations, its y and height
5705 * positions only need to be set once, so we set them once here.
5706 * the x and width are set withing the drawing loop below once per
5708 clip_rectangle
.y
= row_rectangle
.y
;
5709 clip_rectangle
.height
= row_rectangle
.height
;
5711 state
= clist_row
->state
;
5712 cr
= gdk_cairo_create(clist
->clist_window
);
5714 /* draw the cell borders and background */
5717 rect
= &intersect_rectangle
;
5718 if (gdk_rectangle_intersect (area
, &cell_rectangle
,
5719 &intersect_rectangle
)) {
5720 gdk_cairo_rectangle(cr
, &intersect_rectangle
);
5721 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
5725 /* the last row has to clear its bottom cell spacing too */
5726 if (clist_row
== clist
->row_list_end
->data
)
5728 cell_rectangle
.y
+= clist
->row_height
+ CELL_SPACING
;
5730 if (gdk_rectangle_intersect (area
, &cell_rectangle
,
5731 &intersect_rectangle
)) {
5732 gdk_cairo_rectangle(cr
, &intersect_rectangle
);
5733 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
5738 if (!gdk_rectangle_intersect (area
, &row_rectangle
,&intersect_rectangle
))
5744 rect
= &clip_rectangle
;
5745 gdk_cairo_rectangle(cr
, &cell_rectangle
);
5746 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
5749 /* the last row has to clear its bottom cell spacing too */
5750 if (clist_row
== clist
->row_list_end
->data
)
5752 cell_rectangle
.y
+= clist
->row_height
+ CELL_SPACING
;
5753 gdk_cairo_rectangle(cr
, &cell_rectangle
);
5754 gdk_cairo_set_source_color(cr
, &style
->base
[GTK_STATE_NORMAL
]);
5759 for (last_column
= clist
->columns
- 1;
5760 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--)
5763 /* iterate and draw all the columns (row cells) and draw their contents */
5764 for (i
= 0; i
< clist
->columns
; i
++)
5767 PangoLayout
*layout
;
5768 PangoRectangle logical_rect
;
5775 if (!clist
->column
[i
].visible
)
5778 get_cell_style (clist
, clist_row
, state
, i
, &style
);
5780 clip_rectangle
.x
= clist
->column
[i
].area
.x
+ clist
->hoffset
;
5781 clip_rectangle
.width
= clist
->column
[i
].area
.width
;
5783 /* calculate clipping region clipping region */
5784 clip_rectangle
.x
-= COLUMN_INSET
+ CELL_SPACING
;
5785 clip_rectangle
.width
+= (2 * COLUMN_INSET
+ CELL_SPACING
+
5786 (i
== last_column
) * CELL_SPACING
);
5788 if (area
&& !gdk_rectangle_intersect (area
, &clip_rectangle
,
5789 &intersect_rectangle
))
5792 gdk_cairo_rectangle(cr
, rect
);
5793 gdk_cairo_set_source_color(cr
, &style
->base
[state
]);
5796 clip_rectangle
.x
+= COLUMN_INSET
+ CELL_SPACING
;
5797 clip_rectangle
.width
-= (2 * COLUMN_INSET
+ CELL_SPACING
+
5798 (i
== last_column
) * CELL_SPACING
);
5801 /* calculate real width for column justification */
5803 layout
= _gtk_cmclist_create_cell_layout (clist
, clist_row
, i
);
5806 pango_layout_get_pixel_extents (layout
, NULL
, &logical_rect
);
5807 width
= logical_rect
.width
;
5815 switch (clist_row
->cell
[i
].type
)
5817 case GTK_CMCELL_PIXBUF
:
5818 pixbuf_width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
);
5819 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
);
5820 width
+= pixbuf_width
;
5822 case GTK_CMCELL_PIXTEXT
:
5823 pixbuf_width
= gdk_pixbuf_get_width(GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
);
5824 height
= gdk_pixbuf_get_height(GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
);
5825 width
+= pixbuf_width
+ GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
5831 switch (clist
->column
[i
].justification
)
5833 case GTK_JUSTIFY_LEFT
:
5834 offset
= clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
;
5836 case GTK_JUSTIFY_RIGHT
:
5837 offset
= (clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
+
5838 clip_rectangle
.width
- width
);
5840 case GTK_JUSTIFY_CENTER
:
5841 case GTK_JUSTIFY_FILL
:
5842 offset
= (clip_rectangle
.x
+ clist_row
->cell
[i
].horizontal
+
5843 (clip_rectangle
.width
/ 2) - (width
/ 2));
5847 /* Draw Text and/or Pixbuf */
5848 switch (clist_row
->cell
[i
].type
)
5850 case GTK_CMCELL_PIXBUF
:
5851 draw_cell_pixbuf (clist
->clist_window
, &clip_rectangle
, cr
,
5852 GTK_CMCELL_PIXBUF (clist_row
->cell
[i
])->pixbuf
,
5854 clip_rectangle
.y
+ clist_row
->cell
[i
].vertical
+
5855 (clip_rectangle
.height
- height
) / 2,
5856 pixbuf_width
, height
);
5858 case GTK_CMCELL_PIXTEXT
:
5860 draw_cell_pixbuf (clist
->clist_window
, &clip_rectangle
, cr
,
5861 GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->pixbuf
,
5863 clip_rectangle
.y
+ clist_row
->cell
[i
].vertical
+
5864 (clip_rectangle
.height
- height
) / 2,
5865 pixbuf_width
, height
);
5866 offset
+= GTK_CMCELL_PIXTEXT (clist_row
->cell
[i
])->spacing
;
5869 case GTK_CMCELL_TEXT
:
5872 gint row_center_offset
= (clist
->row_height
- logical_rect
.height
- 1) / 2;
5873 gdk_cairo_set_source_color(cr
, clist_row
->fg_set
? &clist_row
->foreground
: &style
->text
[state
]);
5874 cairo_move_to(cr
, offset
, row_rectangle
.y
+ row_center_offset
+ clist_row
->cell
[i
].vertical
);
5875 pango_cairo_show_layout(cr
, layout
);
5876 g_object_unref (G_OBJECT (layout
));
5884 /* draw focus rectangle */
5885 cairo_dash_from_add_mode(clist
, cr
);
5886 cairo_set_line_width(cr
, 1.0);
5887 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
5888 if (clist
->focus_row
== row
&&
5889 gtk_widget_get_can_focus (widget
) && gtk_widget_has_focus(widget
))
5892 cairo_rectangle(cr
, row_rectangle
.x
, row_rectangle
.y
,
5893 row_rectangle
.width
+ 1, row_rectangle
.height
);
5894 gdk_cairo_set_source_color(cr
, &style
->text
[GTK_STATE_NORMAL
]);
5897 else if (gdk_rectangle_intersect (area
, &row_rectangle
,
5898 &intersect_rectangle
))
5900 cairo_rectangle(cr
, row_rectangle
.x
, row_rectangle
.y
,
5901 row_rectangle
.width
+ 1, row_rectangle
.height
);
5902 gdk_cairo_set_source_color(cr
, &style
->text
[GTK_STATE_NORMAL
]);
5911 draw_rows (GtkCMCList
*clist
,
5915 GtkCMCListRow
*clist_row
;
5920 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
5922 if (clist
->row_height
== 0 ||
5923 !gtk_widget_is_drawable (GTK_WIDGET(clist
)))
5928 first_row
= ROW_FROM_YPIXEL (clist
, area
->y
);
5929 last_row
= ROW_FROM_YPIXEL (clist
, area
->y
+ area
->height
);
5933 first_row
= ROW_FROM_YPIXEL (clist
, 0);
5934 last_row
= ROW_FROM_YPIXEL (clist
, clist
->clist_window_height
);
5937 /* this is a small special case which exposes the bottom cell line
5938 * on the last row -- it might go away if I change the wall the cell
5939 * spacings are drawn
5941 if (clist
->rows
== first_row
)
5944 list
= ROW_ELEMENT (clist
, first_row
);
5948 clist_row
= list
->data
;
5954 GTK_CMCLIST_GET_CLASS (clist
)->draw_row (clist
, NULL
, i
, clist_row
);
5959 if (!clist
->draw_now
) {
5962 w
= gdk_window_get_width(clist
->clist_window
);
5963 h
= gdk_window_get_height(clist
->clist_window
);
5964 cr
= gdk_cairo_create(clist
->clist_window
);
5965 y
= ROW_TOP_YPIXEL (clist
, i
);
5966 gdk_cairo_set_source_color(cr
, >k_widget_get_style(GTK_WIDGET(clist
))->base
[GTK_STATE_NORMAL
]);
5967 cairo_rectangle(cr
, 0, y
, w
, h
- y
);
5971 gtk_widget_queue_draw(GTK_WIDGET(clist
));
5977 draw_xor_line (GtkCMCList
*clist
)
5980 cr
= gdk_cairo_create(clist
->clist_window
);
5981 cairo_set_line_width(cr
, 1.0);
5982 cairo_move_to(cr
, clist
->x_drag
,
5983 gtk_widget_get_style (GTK_WIDGET(clist
))->ythickness
);
5984 cairo_line_to(cr
, clist
->x_drag
,
5985 clist
->column_title_area
.height
+
5986 clist
->clist_window_height
+ 1);
5992 clist_refresh (GtkCMCList
*clist
)
5994 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
5996 if (CLIST_UNFROZEN (clist
))
5998 adjust_adjustments (clist
, FALSE
);
5999 draw_rows (clist
, NULL
);
6003 /* get cell from coordinates
6004 * get_selection_info
6005 * gtk_cmclist_get_selection_info
6008 get_selection_info (GtkCMCList
*clist
,
6016 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
6018 /* bounds checking, return false if the user clicked
6019 * on a blank area */
6020 trow
= ROW_FROM_YPIXEL (clist
, y
);
6021 if (trow
>= clist
->rows
)
6027 tcol
= COLUMN_FROM_XPIXEL (clist
, x
);
6028 if (tcol
>= clist
->columns
)
6038 gtk_cmclist_get_selection_info (GtkCMCList
*clist
,
6044 cm_return_val_if_fail (GTK_IS_CMCLIST (clist
), 0);
6045 return get_selection_info (clist
, x
, y
, row
, column
);
6048 /* PRIVATE ADJUSTMENT FUNCTIONS
6049 * adjust_adjustments
6050 * vadjustment_changed
6051 * hadjustment_changed
6052 * vadjustment_value_changed
6053 * hadjustment_value_changed
6057 adjust_adjustments (GtkCMCList
*clist
,
6058 gboolean block_resize
)
6060 if (clist
->vadjustment
)
6062 g_object_freeze_notify(G_OBJECT(clist
->vadjustment
));
6063 gtk_adjustment_set_page_size (clist
->vadjustment
, clist
->clist_window_height
);
6064 gtk_adjustment_set_step_increment (clist
->vadjustment
, clist
->row_height
);
6065 gtk_adjustment_set_page_increment (clist
->vadjustment
,
6066 MAX (clist
->clist_window_height
- clist
->row_height
,
6067 clist
->clist_window_height
/ 2));
6068 gtk_adjustment_set_lower (clist
->vadjustment
, 0);
6069 gtk_adjustment_set_upper (clist
->vadjustment
, LIST_HEIGHT (clist
));
6070 g_object_thaw_notify(G_OBJECT(clist
->vadjustment
));
6072 if ((clist
->clist_window_height
- clist
->voffset
) > LIST_HEIGHT (clist
) ||
6073 (clist
->voffset
+ (gint
)gtk_adjustment_get_value (clist
->vadjustment
)) != 0)
6075 gtk_adjustment_set_value (clist
->vadjustment
,
6076 MAX (0, (LIST_HEIGHT (clist
) - clist
->clist_window_height
)));
6077 g_signal_emit_by_name (G_OBJECT (clist
->vadjustment
),
6080 g_signal_emit_by_name (G_OBJECT (clist
->vadjustment
), "changed");
6083 if (clist
->hadjustment
)
6085 g_object_freeze_notify(G_OBJECT(clist
->hadjustment
));
6086 gtk_adjustment_set_page_size (clist
->hadjustment
, clist
->clist_window_width
);
6087 gtk_adjustment_set_step_increment (clist
->hadjustment
, 10);
6088 gtk_adjustment_set_page_increment (clist
->hadjustment
,
6089 MAX (clist
->clist_window_width
-
6090 gtk_adjustment_get_step_increment (clist
->hadjustment
),
6091 clist
->clist_window_width
/ 2));
6092 gtk_adjustment_set_lower (clist
->hadjustment
, 0);
6093 gtk_adjustment_set_upper (clist
->hadjustment
, LIST_WIDTH (clist
));
6094 g_object_thaw_notify(G_OBJECT(clist
->hadjustment
));
6096 if ((clist
->clist_window_width
- clist
->hoffset
) > LIST_WIDTH (clist
) ||
6097 (clist
->hoffset
+ (gint
)gtk_adjustment_get_value (clist
->hadjustment
)) != 0)
6099 gtk_adjustment_set_value (clist
->hadjustment
, MAX (0, (LIST_WIDTH (clist
) -
6100 clist
->clist_window_width
)));
6101 g_signal_emit_by_name (G_OBJECT (clist
->hadjustment
),
6104 g_signal_emit_by_name (G_OBJECT (clist
->hadjustment
), "changed");
6107 if (!block_resize
&& (!clist
->vadjustment
|| !clist
->hadjustment
))
6110 GtkRequisition requisition
;
6111 GtkAllocation allocation
;
6113 widget
= GTK_WIDGET (clist
);
6114 gtk_widget_get_preferred_size(widget
, &requisition
, NULL
);
6115 gtk_widget_get_allocation (widget
, &allocation
);
6117 if ((!clist
->hadjustment
&&
6118 requisition
.width
!= allocation
.width
) ||
6119 (!clist
->vadjustment
&&
6120 requisition
.height
!= allocation
.height
))
6121 gtk_widget_queue_resize (widget
);
6126 vadjustment_value_changed (GtkAdjustment
*adjustment
,
6132 cm_return_if_fail (adjustment
!= NULL
);
6133 cm_return_if_fail (GTK_IS_CMCLIST (data
));
6135 clist
= GTK_CMCLIST (data
);
6137 if (adjustment
!= clist
->vadjustment
)
6140 value
= -gtk_adjustment_get_value (adjustment
);
6141 dy
= value
- clist
->voffset
;
6142 clist
->voffset
= value
;
6144 if (gtk_widget_is_drawable (GTK_WIDGET(clist
)))
6146 gdk_window_scroll (clist
->clist_window
, 0, dy
);
6158 /* The window to which widget->window is relative */
6159 #define ALLOCATION_WINDOW(widget) \
6160 (!gtk_widget_get_has_window (widget) ? \
6161 gtk_widget_get_window (widget) : \
6162 gdk_window_get_parent (gtk_widget_get_window(widget)))
6165 adjust_allocation_recurse (GtkWidget
*widget
,
6168 GtkAllocation allocation
;
6169 ScrollData
*scroll_data
= data
;
6171 gtk_widget_get_allocation (widget
, &allocation
);
6173 if (!gtk_widget_get_realized (widget
))
6175 if (gtk_widget_get_visible (widget
))
6177 GdkRectangle tmp_rectangle
= allocation
;
6178 tmp_rectangle
.x
+= scroll_data
->dx
;
6180 gtk_widget_size_allocate (widget
, &tmp_rectangle
);
6185 if (ALLOCATION_WINDOW (widget
) == scroll_data
->window
)
6187 allocation
.x
+= scroll_data
->dx
;
6188 gtk_widget_set_allocation (widget
, &allocation
);
6190 if (GTK_IS_CONTAINER (widget
))
6191 gtk_container_forall (GTK_CONTAINER (widget
),
6192 adjust_allocation_recurse
,
6199 adjust_allocation (GtkWidget
*widget
,
6202 ScrollData scroll_data
;
6204 if (gtk_widget_get_realized (widget
))
6205 scroll_data
.window
= ALLOCATION_WINDOW (widget
);
6207 scroll_data
.window
= NULL
;
6209 scroll_data
.dx
= dx
;
6211 adjust_allocation_recurse (widget
, &scroll_data
);
6215 hadjustment_value_changed (GtkAdjustment
*adjustment
,
6219 GtkContainer
*container
;
6226 cm_return_if_fail (adjustment
!= NULL
);
6227 cm_return_if_fail (GTK_IS_CMCLIST (data
));
6229 clist
= GTK_CMCLIST (data
);
6230 container
= GTK_CONTAINER (data
);
6232 if (adjustment
!= clist
->hadjustment
)
6235 value
= gtk_adjustment_get_value (adjustment
);
6237 dx
= -value
- clist
->hoffset
;
6239 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
6240 gdk_window_scroll (clist
->title_window
, dx
, 0);
6242 /* adjust the column button's allocations */
6243 for (i
= 0; i
< clist
->columns
; i
++)
6244 if (clist
->column
[i
].button
)
6245 adjust_allocation (clist
->column
[i
].button
, dx
);
6247 clist
->hoffset
= -value
;
6249 cr
= gdk_cairo_create(clist
->clist_window
);
6250 cairo_dash_from_add_mode(clist
, cr
);
6251 cairo_set_line_width(cr
, 1.0);
6252 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
6253 if (gtk_widget_is_drawable (GTK_WIDGET(clist
)))
6255 GtkWidget
*focus_child
= gtk_container_get_focus_child (container
);
6257 gdk_window_scroll (clist
->clist_window
, dx
, 0);
6259 if (gtk_widget_get_can_focus(GTK_WIDGET(clist
)) &&
6260 gtk_widget_has_focus(GTK_WIDGET(clist
)) &&
6261 !focus_child
&& GTK_CMCLIST_ADD_MODE(clist
))
6263 y
= ROW_TOP_YPIXEL (clist
, clist
->focus_row
);
6264 cairo_rectangle(cr
, 0, y
, clist
->clist_window_width
+ 1,
6269 if (gtk_widget_get_can_focus(GTK_WIDGET(clist
)) &&
6270 gtk_widget_has_focus(GTK_WIDGET(clist
)) &&
6273 if (GTK_CMCLIST_ADD_MODE(clist
))
6277 focus_row
= clist
->focus_row
;
6278 clist
->focus_row
= -1;
6279 draw_rows (clist
, NULL
);
6280 clist
->focus_row
= focus_row
;
6282 cairo_rectangle(cr
, 0, y
, clist
->clist_window_width
+ 1,
6293 * Memory Allocation/Distruction Routines for GtkCMCList stuctures
6302 static GtkCMCListColumn
*
6303 columns_new (GtkCMCList
*clist
)
6305 GtkCMCListColumn
*column
;
6308 column
= g_new (GtkCMCListColumn
, clist
->columns
);
6310 for (i
= 0; i
< clist
->columns
; i
++)
6312 column
[i
].area
.x
= 0;
6313 column
[i
].area
.y
= 0;
6314 column
[i
].area
.width
= 0;
6315 column
[i
].area
.height
= 0;
6316 column
[i
].title
= NULL
;
6317 column
[i
].button
= NULL
;
6318 column
[i
].window
= NULL
;
6319 column
[i
].width
= 0;
6320 column
[i
].min_width
= -1;
6321 column
[i
].max_width
= -1;
6322 column
[i
].visible
= TRUE
;
6323 column
[i
].width_set
= FALSE
;
6324 column
[i
].resizeable
= TRUE
;
6325 column
[i
].auto_resize
= FALSE
;
6326 column
[i
].button_passive
= FALSE
;
6327 column
[i
].justification
= GTK_JUSTIFY_LEFT
;
6334 column_title_new (GtkCMCList
*clist
,
6338 g_free (clist
->column
[column
].title
);
6340 clist
->column
[column
].title
= g_strdup (title
);
6344 columns_delete (GtkCMCList
*clist
)
6348 for (i
= 0; i
< clist
->columns
; i
++)
6349 g_free (clist
->column
[i
].title
);
6351 g_free (clist
->column
);
6354 static GtkCMCListRow
*
6355 row_new (GtkCMCList
*clist
)
6358 GtkCMCListRow
*clist_row
;
6360 clist_row
= g_slice_new (GtkCMCListRow
);
6361 clist_row
->cell
= g_slice_alloc (sizeof (GtkCMCell
) * clist
->columns
);
6363 for (i
= 0; i
< clist
->columns
; i
++)
6365 clist_row
->cell
[i
].type
= GTK_CMCELL_EMPTY
;
6366 clist_row
->cell
[i
].vertical
= 0;
6367 clist_row
->cell
[i
].horizontal
= 0;
6368 clist_row
->cell
[i
].style
= NULL
;
6371 clist_row
->fg_set
= FALSE
;
6372 clist_row
->bg_set
= FALSE
;
6373 clist_row
->style
= NULL
;
6374 clist_row
->selectable
= TRUE
;
6375 clist_row
->state
= GTK_STATE_NORMAL
;
6376 clist_row
->data
= NULL
;
6377 clist_row
->destroy
= NULL
;
6383 row_delete (GtkCMCList
*clist
,
6384 GtkCMCListRow
*clist_row
)
6388 for (i
= 0; i
< clist
->columns
; i
++)
6390 GTK_CMCLIST_GET_CLASS (clist
)->set_cell_contents
6391 (clist
, clist_row
, i
, GTK_CMCELL_EMPTY
, NULL
, 0, NULL
);
6392 if (clist_row
->cell
[i
].style
)
6394 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
6395 gtk_style_detach (clist_row
->cell
[i
].style
);
6396 g_object_unref (clist_row
->cell
[i
].style
);
6400 if (clist_row
->style
)
6402 if (gtk_widget_get_realized (GTK_WIDGET(clist
)))
6403 gtk_style_detach (clist_row
->style
);
6404 g_object_unref (clist_row
->style
);
6407 if (clist_row
->destroy
)
6408 clist_row
->destroy (clist_row
->data
);
6410 g_slice_free1 (sizeof (GtkCMCell
) * clist
->columns
, clist_row
->cell
);
6411 g_slice_free (GtkCMCListRow
, clist_row
);
6415 * gtk_cmclist_focus_content_area
6417 * gtk_cmclist_draw_focus
6418 * gtk_cmclist_focus_in
6419 * gtk_cmclist_focus_out
6423 gtk_cmclist_focus_content_area (GtkCMCList
*clist
)
6425 if (clist
->focus_row
< 0)
6427 clist
->focus_row
= 0;
6429 if ((clist
->selection_mode
== GTK_SELECTION_BROWSE
||
6430 clist
->selection_mode
== GTK_SELECTION_MULTIPLE
) &&
6432 g_signal_emit (G_OBJECT (clist
),
6433 clist_signals
[SELECT_ROW
], 0,
6434 clist
->focus_row
, -1, NULL
);
6436 gtk_widget_grab_focus (GTK_WIDGET (clist
));
6440 gtk_cmclist_focus (GtkWidget
*widget
,
6441 GtkDirectionType direction
)
6443 GtkCMCList
*clist
= GTK_CMCLIST (widget
);
6444 GtkWidget
*focus_child
;
6445 gboolean is_current_focus
;
6447 if (!gtk_widget_is_sensitive (widget
))
6450 focus_child
= gtk_container_get_focus_child (GTK_CONTAINER (widget
));
6452 is_current_focus
= gtk_widget_is_focus (GTK_WIDGET (clist
));
6455 gtk_widget_child_focus (focus_child
, direction
))
6464 if (title_focus_move (clist
, direction
))
6467 else if (!is_current_focus
)
6469 gtk_cmclist_focus_content_area (clist
);
6474 case GTK_DIR_TAB_FORWARD
:
6475 if (!focus_child
&& !is_current_focus
)
6477 if (title_focus_in (clist
, direction
))
6481 if (!is_current_focus
&& clist
->rows
)
6483 gtk_cmclist_focus_content_area (clist
);
6488 case GTK_DIR_TAB_BACKWARD
:
6489 if (!focus_child
&& is_current_focus
)
6491 if (title_focus_in (clist
, direction
))
6495 if (!is_current_focus
&& !focus_child
&& clist
->rows
)
6497 gtk_cmclist_focus_content_area (clist
);
6509 gtk_cmclist_set_focus_child (GtkContainer
*container
,
6512 GtkCMCList
*clist
= GTK_CMCLIST (container
);
6515 for (i
= 0; i
< clist
->columns
; i
++)
6516 if (clist
->column
[i
].button
== child
)
6517 clist
->focus_header_column
= i
;
6519 if (GTK_CONTAINER_CLASS (gtk_cmclist_parent_class
)->set_focus_child
)
6520 (*GTK_CONTAINER_CLASS (gtk_cmclist_parent_class
)->set_focus_child
) (container
, child
);
6524 gtk_cmclist_draw_focus (GtkWidget
*widget
)
6529 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
6531 if (!gtk_widget_is_drawable (widget
) || !gtk_widget_get_can_focus (widget
))
6534 clist
= GTK_CMCLIST (widget
);
6535 if (clist
->focus_row
>= 0) {
6536 if (!clist
->draw_now
) {
6537 cr
= gdk_cairo_create(clist
->clist_window
);
6538 cairo_dash_from_add_mode(clist
, cr
);
6539 cairo_set_line_width(cr
, 1.0);
6540 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
6541 cairo_rectangle(cr
, 0, ROW_TOP_YPIXEL(clist
, clist
->focus_row
) + 0.5,
6542 clist
->clist_window_width
+ 1,
6543 clist
->row_height
- 0.5);
6547 gtk_widget_queue_draw(GTK_WIDGET(clist
));
6553 gtk_cmclist_undraw_focus (GtkWidget
*widget
)
6557 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
6559 clist
= GTK_CMCLIST(widget
);
6561 if (clist
->focus_row
< 0)
6564 if (!gtk_widget_is_drawable (widget
) || !gtk_widget_get_can_focus (widget
))
6567 clist
= GTK_CMCLIST (widget
);
6568 if (clist
->focus_row
>= 0) {
6569 if (!clist
->draw_now
) {
6570 cairo_t
*cr
= gdk_cairo_create(clist
->clist_window
);
6571 cairo_set_line_width(cr
, 1.0);
6572 gdk_cairo_set_source_color(cr
, >k_widget_get_style(widget
)->base
[GTK_STATE_NORMAL
]);
6573 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
6574 cairo_rectangle(cr
, 0, ROW_TOP_YPIXEL(clist
, clist
->focus_row
) + 0.5,
6575 clist
->clist_window_width
+ 1,
6576 clist
->row_height
- 0.5);
6580 gtk_widget_queue_draw(GTK_WIDGET(clist
));
6584 row
= clist
->focus_row
;
6585 GTK_CMCLIST_GET_CLASS(GTK_CMCLIST(widget
))->draw_row(clist
, NULL
, row
, ROW_ELEMENT (clist
, row
)->data
);
6589 gtk_cmclist_focus_in (GtkWidget
*widget
,
6590 GdkEventFocus
*event
)
6592 GtkCMCList
*clist
= GTK_CMCLIST (widget
);
6594 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
&&
6595 clist
->selection
== NULL
&& clist
->focus_row
> -1)
6599 list
= g_list_nth (clist
->row_list
, clist
->focus_row
);
6600 if (list
&& GTK_CMCLIST_ROW (list
)->selectable
)
6601 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
6602 clist
->focus_row
, -1, event
);
6604 gtk_cmclist_draw_focus (widget
);
6607 gtk_cmclist_undraw_focus (widget
);
6613 gtk_cmclist_focus_out (GtkWidget
*widget
,
6614 GdkEventFocus
*event
)
6616 GtkCMCList
*clist
= GTK_CMCLIST (widget
);
6618 gtk_cmclist_undraw_focus (widget
);
6620 GTK_CMCLIST_GET_CLASS (widget
)->resync_selection (clist
, (GdkEvent
*) event
);
6626 focus_column (GtkCMCList
*clist
, gint column
, gint dir
)
6628 GtkWidget
*child
= clist
->column
[column
].button
;
6630 if (gtk_widget_child_focus (child
, dir
))
6634 else if (gtk_widget_get_can_focus (child
))
6636 gtk_widget_grab_focus (child
);
6643 /* Focus moved onto the headers. Focus first focusable and visible child.
6644 * (FIXME: focus the last focused child if visible)
6647 title_focus_in (GtkCMCList
*clist
, gint dir
)
6652 if (!GTK_CMCLIST_SHOW_TITLES (clist
))
6655 /* Check last focused column */
6656 if (clist
->focus_header_column
!= -1)
6658 i
= clist
->focus_header_column
;
6660 left
= COLUMN_LEFT_XPIXEL (clist
, i
);
6661 right
= left
+ clist
->column
[i
].area
.width
;
6663 if (left
>= 0 && right
<= clist
->clist_window_width
)
6665 if (focus_column (clist
, i
, dir
))
6670 /* Check fully visible columns */
6671 for (i
= 0 ; i
< clist
->columns
; i
++)
6673 left
= COLUMN_LEFT_XPIXEL (clist
, i
);
6674 right
= left
+ clist
->column
[i
].area
.width
;
6676 if (left
>= 0 && right
<= clist
->clist_window_width
)
6678 if (focus_column (clist
, i
, dir
))
6683 /* Check partially visible columns */
6684 for (i
= 0 ; i
< clist
->columns
; i
++)
6686 left
= COLUMN_LEFT_XPIXEL (clist
, i
);
6687 right
= left
+ clist
->column
[i
].area
.width
;
6689 if ((left
< 0 && right
> 0) ||
6690 (left
< clist
->clist_window_width
&& right
> clist
->clist_window_width
))
6692 if (focus_column (clist
, i
, dir
))
6700 /* Move the focus right or left within the title buttons, scrolling
6701 * as necessary to keep the focused child visible.
6704 title_focus_move (GtkCMCList
*clist
,
6707 GtkWidget
*focus_child
;
6708 gboolean return_val
= FALSE
;
6713 if (!GTK_CMCLIST_SHOW_TITLES(clist
))
6716 focus_child
= gtk_container_get_focus_child (GTK_CONTAINER (clist
));
6717 g_assert (focus_child
);
6719 /* Movement direction within headers
6731 for (i
= 0; i
< clist
->columns
; i
++)
6732 if (clist
->column
[i
].button
== focus_child
)
6735 g_assert (i
!= -1); /* Have a starting column */
6738 while (!return_val
&& j
>= 0 && j
< clist
->columns
)
6740 if (clist
->column
[j
].button
&&
6741 gtk_widget_get_visible (clist
->column
[j
].button
))
6743 if (focus_column (clist
, j
, dir
))
6752 /* If we didn't find it, wrap around and keep looking
6756 j
= d
> 0 ? 0 : clist
->columns
- 1;
6758 while (!return_val
&& j
!= i
)
6760 if (clist
->column
[j
].button
&&
6761 gtk_widget_get_visible (clist
->column
[j
].button
))
6763 if (focus_column (clist
, j
, dir
))
6773 /* Scroll horizontally so focused column is visible
6777 if (COLUMN_LEFT_XPIXEL (clist
, j
) < CELL_SPACING
+ COLUMN_INSET
)
6778 gtk_cmclist_moveto (clist
, -1, j
, 0, 0);
6779 else if (COLUMN_LEFT_XPIXEL(clist
, j
) + clist
->column
[j
].area
.width
>
6780 clist
->clist_window_width
)
6784 for (last_column
= clist
->columns
- 1;
6785 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--);
6787 if (j
== last_column
)
6788 gtk_cmclist_moveto (clist
, -1, j
, 0, 0);
6790 gtk_cmclist_moveto (clist
, -1, j
, 0, 1);
6793 return TRUE
; /* Even if we didn't find a new one, we can keep the
6794 * focus in the same place.
6798 /* PRIVATE SCROLLING FUNCTIONS
6804 * horizontal_timeout
6809 move_focus_row (GtkCMCList
*clist
,
6810 GtkScrollType scroll_type
,
6815 cm_return_if_fail (clist
!= 0);
6816 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
6818 widget
= GTK_WIDGET (clist
);
6820 switch (scroll_type
)
6822 case GTK_SCROLL_STEP_UP
:
6823 case GTK_SCROLL_STEP_BACKWARD
:
6824 if (clist
->focus_row
<= 0)
6826 gtk_cmclist_undraw_focus (widget
);
6828 gtk_cmclist_draw_focus (widget
);
6831 case GTK_SCROLL_STEP_DOWN
:
6832 case GTK_SCROLL_STEP_FORWARD
:
6833 if (clist
->focus_row
>= clist
->rows
- 1)
6835 gtk_cmclist_undraw_focus (widget
);
6837 gtk_cmclist_draw_focus (widget
);
6839 case GTK_SCROLL_PAGE_UP
:
6840 case GTK_SCROLL_PAGE_BACKWARD
:
6841 if (clist
->focus_row
<= 0)
6843 gtk_cmclist_undraw_focus (widget
);
6844 clist
->focus_row
= MAX (0, clist
->focus_row
-
6845 (2 * clist
->clist_window_height
-
6846 clist
->row_height
- CELL_SPACING
) /
6847 (2 * (clist
->row_height
+ CELL_SPACING
)));
6848 gtk_cmclist_draw_focus (widget
);
6850 case GTK_SCROLL_PAGE_DOWN
:
6851 case GTK_SCROLL_PAGE_FORWARD
:
6852 if (clist
->focus_row
>= clist
->rows
- 1)
6854 gtk_cmclist_undraw_focus (widget
);
6855 clist
->focus_row
= MIN (clist
->rows
- 1, clist
->focus_row
+
6856 (2 * clist
->clist_window_height
-
6857 clist
->row_height
- CELL_SPACING
) /
6858 (2 * (clist
->row_height
+ CELL_SPACING
)));
6859 gtk_cmclist_draw_focus (widget
);
6861 case GTK_SCROLL_JUMP
:
6862 if (position
>= 0 && position
<= 1)
6864 gint row
= position
* (clist
->rows
- 1);
6866 if (row
== clist
->focus_row
)
6869 gtk_cmclist_undraw_focus (widget
);
6870 clist
->focus_row
= row
;
6871 gtk_cmclist_draw_focus (widget
);
6880 scroll_horizontal (GtkCMCList
*clist
,
6881 GtkScrollType scroll_type
,
6887 cm_return_if_fail (clist
!= 0);
6888 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
6890 if (clist_has_grab (clist
))
6893 for (last_column
= clist
->columns
- 1;
6894 last_column
>= 0 && !clist
->column
[last_column
].visible
; last_column
--)
6897 switch (scroll_type
)
6899 case GTK_SCROLL_STEP_BACKWARD
:
6900 column
= COLUMN_FROM_XPIXEL (clist
, 0);
6901 if (COLUMN_LEFT_XPIXEL (clist
, column
) - CELL_SPACING
- COLUMN_INSET
>= 0
6905 case GTK_SCROLL_STEP_FORWARD
:
6906 column
= COLUMN_FROM_XPIXEL (clist
, clist
->clist_window_width
);
6909 if (COLUMN_LEFT_XPIXEL (clist
, column
) +
6910 clist
->column
[column
].area
.width
+
6911 CELL_SPACING
+ COLUMN_INSET
- 1 <= clist
->clist_window_width
&&
6912 column
< last_column
)
6915 case GTK_SCROLL_PAGE_BACKWARD
:
6916 case GTK_SCROLL_PAGE_FORWARD
:
6918 case GTK_SCROLL_JUMP
:
6919 if (position
>= 0 && position
<= 1)
6921 gint vis_columns
= 0;
6924 for (i
= 0; i
<= last_column
; i
++)
6925 if (clist
->column
[i
].visible
)
6928 column
= position
* vis_columns
;
6930 for (i
= 0; i
<= last_column
&& column
> 0; i
++)
6931 if (clist
->column
[i
].visible
)
6943 if (COLUMN_LEFT_XPIXEL (clist
, column
) < CELL_SPACING
+ COLUMN_INSET
)
6944 gtk_cmclist_moveto (clist
, -1, column
, 0, 0);
6945 else if (COLUMN_LEFT_XPIXEL (clist
, column
) + CELL_SPACING
+ COLUMN_INSET
- 1
6946 + clist
->column
[column
].area
.width
> clist
->clist_window_width
)
6948 if (column
== last_column
)
6949 gtk_cmclist_moveto (clist
, -1, column
, 0, 0);
6951 gtk_cmclist_moveto (clist
, -1, column
, 0, 1);
6956 scroll_vertical (GtkCMCList
*clist
,
6957 GtkScrollType scroll_type
,
6962 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
6964 if (clist_has_grab (clist
))
6967 switch (clist
->selection_mode
)
6969 case GTK_SELECTION_MULTIPLE
:
6970 if (clist
->anchor
>= 0)
6972 case GTK_SELECTION_BROWSE
:
6974 old_focus_row
= clist
->focus_row
;
6975 move_focus_row (clist
, scroll_type
, position
);
6977 if (old_focus_row
!= clist
->focus_row
)
6979 if (clist
->selection_mode
== GTK_SELECTION_BROWSE
)
6980 g_signal_emit (G_OBJECT (clist
), clist_signals
[UNSELECT_ROW
], 0,
6981 old_focus_row
, -1, NULL
);
6982 else if (!GTK_CMCLIST_ADD_MODE(clist
))
6984 gtk_cmclist_unselect_all (clist
);
6985 clist
->undo_anchor
= old_focus_row
;
6989 switch (gtk_cmclist_row_is_visible (clist
, clist
->focus_row
))
6991 case GTK_VISIBILITY_NONE
:
6992 if (old_focus_row
!= clist
->focus_row
&&
6993 !(clist
->selection_mode
== GTK_SELECTION_MULTIPLE
&&
6994 GTK_CMCLIST_ADD_MODE(clist
)))
6995 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
6996 clist
->focus_row
, -1, NULL
);
6997 switch (scroll_type
)
6999 case GTK_SCROLL_PAGE_UP
:
7000 case GTK_SCROLL_STEP_UP
:
7001 case GTK_SCROLL_STEP_BACKWARD
:
7002 case GTK_SCROLL_PAGE_BACKWARD
:
7003 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
7005 case GTK_SCROLL_PAGE_DOWN
:
7006 case GTK_SCROLL_STEP_DOWN
:
7007 case GTK_SCROLL_STEP_FORWARD
:
7008 case GTK_SCROLL_PAGE_FORWARD
:
7009 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
7011 case GTK_SCROLL_JUMP
:
7012 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0.5, 0);
7018 case GTK_VISIBILITY_PARTIAL
:
7019 switch (scroll_type
)
7021 case GTK_SCROLL_STEP_BACKWARD
:
7022 case GTK_SCROLL_PAGE_BACKWARD
:
7023 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
7025 case GTK_SCROLL_STEP_FORWARD
:
7026 case GTK_SCROLL_PAGE_FORWARD
:
7027 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
7029 case GTK_SCROLL_JUMP
:
7030 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0.5, 0);
7035 /* fallback is intentional */
7037 if (old_focus_row
!= clist
->focus_row
&&
7038 !(clist
->selection_mode
== GTK_SELECTION_MULTIPLE
&&
7039 GTK_CMCLIST_ADD_MODE(clist
)))
7040 g_signal_emit (G_OBJECT (clist
), clist_signals
[SELECT_ROW
], 0,
7041 clist
->focus_row
, -1, NULL
);
7046 move_focus_row (clist
, scroll_type
, position
);
7048 if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) + clist
->row_height
>
7049 clist
->clist_window_height
)
7050 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 1, 0);
7051 else if (ROW_TOP_YPIXEL (clist
, clist
->focus_row
) < 0)
7052 gtk_cmclist_moveto (clist
, clist
->focus_row
, -1, 0, 0);
7058 move_horizontal (GtkCMCList
*clist
,
7063 if (!clist
->hadjustment
)
7066 value
= CLAMP (gtk_adjustment_get_value (clist
->hadjustment
) + diff
, 0.0,
7067 gtk_adjustment_get_upper (clist
->hadjustment
) -
7068 gtk_adjustment_get_page_size (clist
->hadjustment
));
7069 gtk_adjustment_set_value (clist
->hadjustment
, value
);
7073 move_vertical (GtkCMCList
*clist
,
7081 if (!clist
->vadjustment
)
7084 value
= (ROW_TOP_YPIXEL (clist
, row
) - clist
->voffset
-
7085 align
* (clist
->clist_window_height
- clist
->row_height
) +
7086 (2 * align
- 1) * CELL_SPACING
);
7088 upper
= gtk_adjustment_get_upper (clist
->vadjustment
);
7089 page_size
= gtk_adjustment_get_page_size (clist
->vadjustment
);
7090 if ((value
+ page_size
) > upper
)
7091 value
= upper
- page_size
;
7093 gtk_adjustment_set_value (clist
->vadjustment
, value
);
7097 do_fake_motion (GtkWidget
*widget
)
7099 GdkEvent
*event
= gdk_event_new (GDK_MOTION_NOTIFY
);
7101 event
->motion
.send_event
= TRUE
;
7103 gtk_cmclist_motion (widget
, (GdkEventMotion
*)event
);
7104 gdk_event_free (event
);
7108 horizontal_timeout (GtkCMCList
*clist
)
7111 do_fake_motion (GTK_WIDGET (clist
));
7117 vertical_timeout (GtkCMCList
*clist
)
7120 do_fake_motion (GTK_WIDGET (clist
));
7126 remove_grab (GtkCMCList
*clist
)
7128 GtkWidget
*widget
= GTK_WIDGET (clist
);
7130 if (gtk_widget_has_grab (widget
))
7132 GdkDisplay
*display
= gtk_widget_get_display (widget
);
7134 gtk_grab_remove (widget
);
7135 if (gtkut_pointer_is_grabbed (widget
))
7136 gdk_display_pointer_ungrab (display
, GDK_CURRENT_TIME
);
7141 g_source_remove (clist
->htimer
);
7147 g_source_remove (clist
->vtimer
);
7152 /* PUBLIC SORTING FUNCTIONS
7154 * gtk_cmclist_set_compare_func
7155 * gtk_cmclist_set_auto_sort
7156 * gtk_cmclist_set_sort_type
7157 * gtk_cmclist_set_sort_column
7160 gtk_cmclist_sort (GtkCMCList
*clist
)
7162 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7164 GTK_CMCLIST_GET_CLASS (clist
)->sort_list (clist
);
7168 gtk_cmclist_set_compare_func (GtkCMCList
*clist
,
7169 GtkCMCListCompareFunc cmp_func
)
7171 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7173 clist
->compare
= (cmp_func
) ? cmp_func
: default_compare
;
7177 gtk_cmclist_set_auto_sort (GtkCMCList
*clist
,
7180 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7182 if (GTK_CMCLIST_AUTO_SORT(clist
) && !auto_sort
)
7183 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_AUTO_SORT
);
7184 else if (!GTK_CMCLIST_AUTO_SORT(clist
) && auto_sort
)
7186 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_AUTO_SORT
);
7187 gtk_cmclist_sort (clist
);
7192 gtk_cmclist_set_sort_type (GtkCMCList
*clist
,
7193 GtkSortType sort_type
)
7195 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7197 clist
->sort_type
= sort_type
;
7201 gtk_cmclist_set_sort_column (GtkCMCList
*clist
,
7204 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7206 if (column
< 0 || column
>= clist
->columns
)
7209 clist
->sort_column
= column
;
7212 /* PRIVATE SORTING FUNCTIONS
7216 * gtk_cmclist_mergesort
7219 default_compare (GtkCMCList
*clist
,
7226 GtkCMCListRow
*row1
= (GtkCMCListRow
*) ptr1
;
7227 GtkCMCListRow
*row2
= (GtkCMCListRow
*) ptr2
;
7229 switch (row1
->cell
[clist
->sort_column
].type
)
7231 case GTK_CMCELL_TEXT
:
7232 text1
= GTK_CMCELL_TEXT (row1
->cell
[clist
->sort_column
])->text
;
7234 case GTK_CMCELL_PIXTEXT
:
7235 text1
= GTK_CMCELL_PIXTEXT (row1
->cell
[clist
->sort_column
])->text
;
7241 switch (row2
->cell
[clist
->sort_column
].type
)
7243 case GTK_CMCELL_TEXT
:
7244 text2
= GTK_CMCELL_TEXT (row2
->cell
[clist
->sort_column
])->text
;
7246 case GTK_CMCELL_PIXTEXT
:
7247 text2
= GTK_CMCELL_PIXTEXT (row2
->cell
[clist
->sort_column
])->text
;
7254 return (text1
!= NULL
);
7259 return strcmp (text1
, text2
);
7263 real_sort_list (GtkCMCList
*clist
)
7269 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7271 if (clist
->rows
<= 1)
7274 if (clist_has_grab (clist
))
7277 gtk_cmclist_freeze (clist
);
7279 if (clist
->anchor
!= -1 && clist
->selection_mode
== GTK_SELECTION_MULTIPLE
)
7281 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
7282 g_list_free (clist
->undo_selection
);
7283 g_list_free (clist
->undo_unselection
);
7284 clist
->undo_selection
= NULL
;
7285 clist
->undo_unselection
= NULL
;
7288 clist
->row_list
= gtk_cmclist_mergesort (clist
, clist
->row_list
, clist
->rows
);
7290 work
= clist
->selection
;
7292 for (i
= 0, list
= clist
->row_list
; i
< clist
->rows
; i
++, list
= list
->next
)
7294 if (GTK_CMCLIST_ROW (list
)->state
== GTK_STATE_SELECTED
)
7296 work
->data
= GINT_TO_POINTER (i
);
7300 if (i
== clist
->rows
- 1)
7301 clist
->row_list_end
= list
;
7304 gtk_cmclist_thaw (clist
);
7308 gtk_cmclist_merge (GtkCMCList
*clist
,
7309 GList
*a
, /* first list to merge */
7310 GList
*b
) /* second list to merge */
7312 GList z
= { 0 }; /* auxiliary node */
7341 cmp
= clist
->compare (clist
, GTK_CMCLIST_ROW (a
), GTK_CMCLIST_ROW (b
));
7342 if ((cmp
>= 0 && clist
->sort_type
== GTK_SORT_DESCENDING
) ||
7343 (cmp
<= 0 && clist
->sort_type
== GTK_SORT_ASCENDING
))
7361 z
.next
->prev
= NULL
;
7367 gtk_cmclist_mergesort (GtkCMCList
*clist
,
7368 GList
*list
, /* the list to sort */
7369 gint num
) /* the list's length */
7380 /* move "half" to the middle */
7382 for (i
= 0; i
< num
/ 2; i
++)
7385 /* cut the list in two */
7386 half
->prev
->next
= NULL
;
7389 /* recursively sort both lists */
7390 return gtk_cmclist_merge (clist
,
7391 gtk_cmclist_mergesort (clist
, list
, num
/ 2),
7392 gtk_cmclist_mergesort (clist
, half
, num
- num
/ 2));
7396 /************************/
7399 drag_source_info_destroy (gpointer data
)
7401 GtkCMCListCellInfo
*info
= data
;
7407 drag_dest_info_destroy (gpointer data
)
7409 GtkCMCListDestInfo
*info
= data
;
7415 drag_dest_cell (GtkCMCList
*clist
,
7418 GtkCMCListDestInfo
*dest_info
)
7424 widget
= GTK_WIDGET (clist
);
7425 style
= gtk_widget_get_style (widget
);
7427 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_NONE
;
7429 border_width
= gtk_container_get_border_width (GTK_CONTAINER (widget
));
7430 y
-= (border_width
+
7432 clist
->column_title_area
.height
);
7434 dest_info
->cell
.row
= ROW_FROM_YPIXEL (clist
, y
);
7435 if (dest_info
->cell
.row
>= clist
->rows
)
7437 dest_info
->cell
.row
= clist
->rows
- 1;
7438 y
= ROW_TOP_YPIXEL (clist
, dest_info
->cell
.row
) + clist
->row_height
;
7440 if (dest_info
->cell
.row
< -1)
7441 dest_info
->cell
.row
= -1;
7443 x
-= border_width
+ style
->xthickness
;
7445 dest_info
->cell
.column
= COLUMN_FROM_XPIXEL (clist
, x
);
7447 if (dest_info
->cell
.row
>= 0)
7452 y_delta
= y
- ROW_TOP_YPIXEL (clist
, dest_info
->cell
.row
);
7454 if (GTK_CMCLIST_DRAW_DRAG_RECT(clist
))
7456 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_INTO
;
7457 h
= clist
->row_height
/ 4;
7459 else if (GTK_CMCLIST_DRAW_DRAG_LINE(clist
))
7461 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_BEFORE
;
7462 h
= clist
->row_height
/ 2;
7465 if (GTK_CMCLIST_DRAW_DRAG_LINE(clist
))
7468 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_BEFORE
;
7469 else if (clist
->row_height
- y_delta
< h
)
7470 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_AFTER
;
7476 gtk_cmclist_drag_begin (GtkWidget
*widget
,
7477 GdkDragContext
*context
)
7480 GtkCMCListCellInfo
*info
;
7482 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
7483 cm_return_if_fail (context
!= NULL
);
7485 clist
= GTK_CMCLIST (widget
);
7487 clist
->drag_button
= 0;
7488 remove_grab (clist
);
7490 switch (clist
->selection_mode
)
7492 case GTK_SELECTION_MULTIPLE
:
7493 update_extended_selection (clist
, clist
->focus_row
);
7494 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
7496 case GTK_SELECTION_SINGLE
:
7498 case GTK_SELECTION_BROWSE
:
7501 g_assert_not_reached ();
7504 info
= g_dataset_get_data (context
, "gtk-clist-drag-source");
7508 info
= g_new (GtkCMCListCellInfo
, 1);
7510 if (clist
->click_cell
.row
< 0)
7511 clist
->click_cell
.row
= 0;
7512 else if (clist
->click_cell
.row
>= clist
->rows
)
7513 clist
->click_cell
.row
= clist
->rows
- 1;
7514 info
->row
= clist
->click_cell
.row
;
7515 info
->column
= clist
->click_cell
.column
;
7517 g_dataset_set_data_full (context
, "gtk-clist-drag-source", info
,
7518 drag_source_info_destroy
);
7521 if (GTK_CMCLIST_USE_DRAG_ICONS (clist
))
7522 gtk_drag_set_icon_default (context
);
7526 gtk_cmclist_drag_end (GtkWidget
*widget
,
7527 GdkDragContext
*context
)
7531 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
7532 cm_return_if_fail (context
!= NULL
);
7534 clist
= GTK_CMCLIST (widget
);
7536 clist
->click_cell
.row
= -1;
7537 clist
->click_cell
.column
= -1;
7541 gtk_cmclist_drag_leave (GtkWidget
*widget
,
7542 GdkDragContext
*context
,
7546 GtkCMCListDestInfo
*dest_info
;
7548 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
7549 cm_return_if_fail (context
!= NULL
);
7551 clist
= GTK_CMCLIST (widget
);
7553 dest_info
= g_dataset_get_data (context
, "gtk-clist-drag-dest");
7557 if (dest_info
->cell
.row
>= 0 &&
7558 GTK_CMCLIST_REORDERABLE(clist
) &&
7559 gtk_drag_get_source_widget (context
) == widget
)
7561 GdkAtom atom
= gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7562 GdkAtom found
= gtk_drag_dest_find_target(widget
, context
, NULL
);
7566 clist
->drag_highlight_row
= -1;
7569 g_dataset_remove_data (context
, "gtk-clist-drag-dest");
7574 gtk_cmclist_drag_motion (GtkWidget
*widget
,
7575 GdkDragContext
*context
,
7581 GtkCMCListDestInfo new_info
;
7582 GtkCMCListDestInfo
*dest_info
;
7584 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
7586 clist
= GTK_CMCLIST (widget
);
7588 dest_info
= g_dataset_get_data (context
, "gtk-clist-drag-dest");
7592 dest_info
= g_new (GtkCMCListDestInfo
, 1);
7594 dest_info
->insert_pos
= GTK_CMCLIST_DRAG_NONE
;
7595 dest_info
->cell
.row
= -1;
7596 dest_info
->cell
.column
= -1;
7598 g_dataset_set_data_full (context
, "gtk-clist-drag-dest", dest_info
,
7599 drag_dest_info_destroy
);
7602 drag_dest_cell (clist
, x
, y
, &new_info
);
7604 if (GTK_CMCLIST_REORDERABLE (clist
))
7606 GdkAtom atom
= gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7607 GdkAtom found
= gtk_drag_dest_find_target(widget
, context
, NULL
);
7611 if (gtk_drag_get_source_widget (context
) != widget
||
7612 new_info
.insert_pos
== GTK_CMCLIST_DRAG_NONE
||
7613 new_info
.cell
.row
== clist
->click_cell
.row
||
7614 (new_info
.cell
.row
== clist
->click_cell
.row
- 1 &&
7615 new_info
.insert_pos
== GTK_CMCLIST_DRAG_AFTER
) ||
7616 (new_info
.cell
.row
== clist
->click_cell
.row
+ 1 &&
7617 new_info
.insert_pos
== GTK_CMCLIST_DRAG_BEFORE
))
7619 if (dest_info
->cell
.row
< 0)
7621 gdk_drag_status (context
, GDK_ACTION_DEFAULT
, time
);
7627 if (new_info
.cell
.row
!= dest_info
->cell
.row
||
7628 (new_info
.cell
.row
== dest_info
->cell
.row
&&
7629 dest_info
->insert_pos
!= new_info
.insert_pos
))
7632 dest_info
->insert_pos
= new_info
.insert_pos
;
7633 dest_info
->cell
.row
= new_info
.cell
.row
;
7634 dest_info
->cell
.column
= new_info
.cell
.column
;
7636 clist
->drag_highlight_row
= dest_info
->cell
.row
;
7637 clist
->drag_highlight_pos
= dest_info
->insert_pos
;
7639 gdk_drag_status (context
,
7640 gdk_drag_context_get_suggested_action(context
), time
);
7646 dest_info
->insert_pos
= new_info
.insert_pos
;
7647 dest_info
->cell
.row
= new_info
.cell
.row
;
7648 dest_info
->cell
.column
= new_info
.cell
.column
;
7653 gtk_cmclist_drag_drop (GtkWidget
*widget
,
7654 GdkDragContext
*context
,
7659 cm_return_val_if_fail (GTK_IS_CMCLIST (widget
), FALSE
);
7660 cm_return_val_if_fail (context
!= NULL
, FALSE
);
7662 if (GTK_CMCLIST_REORDERABLE (widget
) &&
7663 gtk_drag_get_source_widget (context
) == widget
)
7665 GdkAtom atom
= gdk_atom_intern_static_string ("gtk-clist-drag-reorder");
7666 GdkAtom found
= gtk_drag_dest_find_target(widget
, context
, NULL
);
7675 gtk_cmclist_drag_data_received (GtkWidget
*widget
,
7676 GdkDragContext
*context
,
7679 GtkSelectionData
*selection_data
,
7685 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
7686 cm_return_if_fail (context
!= NULL
);
7687 cm_return_if_fail (selection_data
!= NULL
);
7689 clist
= GTK_CMCLIST (widget
);
7691 if (GTK_CMCLIST_REORDERABLE (clist
) &&
7692 gtk_drag_get_source_widget (context
) == widget
&&
7693 gtk_selection_data_get_target (selection_data
) ==
7694 gdk_atom_intern_static_string ("gtk-clist-drag-reorder") &&
7695 gtk_selection_data_get_format (selection_data
) == 8 &&
7696 gtk_selection_data_get_length (selection_data
) == sizeof (GtkCMCListCellInfo
))
7698 GtkCMCListCellInfo
*source_info
;
7700 source_info
= (GtkCMCListCellInfo
*)(gtk_selection_data_get_data (selection_data
));
7703 GtkCMCListDestInfo dest_info
;
7705 drag_dest_cell (clist
, x
, y
, &dest_info
);
7707 if (dest_info
.insert_pos
== GTK_CMCLIST_DRAG_AFTER
)
7708 dest_info
.cell
.row
++;
7709 if (source_info
->row
< dest_info
.cell
.row
)
7710 dest_info
.cell
.row
--;
7711 if (dest_info
.cell
.row
!= source_info
->row
)
7712 gtk_cmclist_row_move (clist
, source_info
->row
, dest_info
.cell
.row
);
7714 g_dataset_remove_data (context
, "gtk-clist-drag-dest");
7720 gtk_cmclist_drag_data_get (GtkWidget
*widget
,
7721 GdkDragContext
*context
,
7722 GtkSelectionData
*selection_data
,
7727 cm_return_if_fail (GTK_IS_CMCLIST (widget
));
7728 cm_return_if_fail (context
!= NULL
);
7729 cm_return_if_fail (selection_data
!= NULL
);
7731 target
= gtk_selection_data_get_target (selection_data
);
7732 if (target
== gdk_atom_intern_static_string ("gtk-clist-drag-reorder"))
7734 GtkCMCListCellInfo
*info
;
7736 info
= g_dataset_get_data (context
, "gtk-clist-drag-source");
7740 GtkCMCListCellInfo ret_info
;
7742 ret_info
.row
= info
->row
;
7743 ret_info
.column
= info
->column
;
7745 gtk_selection_data_set (selection_data
, target
,
7746 8, (guchar
*) &ret_info
,
7747 sizeof (GtkCMCListCellInfo
));
7753 gtk_cmclist_set_reorderable (GtkCMCList
*clist
,
7754 gboolean reorderable
)
7758 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7760 if ((GTK_CMCLIST_REORDERABLE(clist
) != 0) == reorderable
)
7763 widget
= GTK_WIDGET (clist
);
7767 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_REORDERABLE
);
7768 gtk_drag_dest_set (widget
,
7769 GTK_DEST_DEFAULT_MOTION
| GTK_DEST_DEFAULT_DROP
,
7770 &clist_target_table
, 1, GDK_ACTION_MOVE
);
7774 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_REORDERABLE
);
7775 gtk_drag_dest_unset (GTK_WIDGET (clist
));
7780 gtk_cmclist_set_use_drag_icons (GtkCMCList
*clist
,
7783 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7786 GTK_CMCLIST_SET_FLAG (clist
, CMCLIST_USE_DRAG_ICONS
);
7788 GTK_CMCLIST_UNSET_FLAG (clist
, CMCLIST_USE_DRAG_ICONS
);
7792 gtk_cmclist_set_button_actions (GtkCMCList
*clist
,
7794 guint8 button_actions
)
7796 cm_return_if_fail (GTK_IS_CMCLIST (clist
));
7798 if (button
< MAX_BUTTON
)
7800 if (gtkut_pointer_is_grabbed (GTK_WIDGET(clist
)) ||
7801 gtk_widget_has_grab (GTK_WIDGET(clist
)))
7803 remove_grab (clist
);
7804 clist
->drag_button
= 0;
7807 GTK_CMCLIST_GET_CLASS (clist
)->resync_selection (clist
, NULL
);
7809 clist
->button_actions
[button
] = button_actions
;
7814 gtk_cmclist_get_border (GtkScrollable
*scrollable
,
7817 GtkCMCList
*cmclist
= GTK_CMCLIST(scrollable
);
7819 border
->top
= cmclist
->column_title_area
.height
;
7824 gtk_cmclist_scrollable_init (GtkScrollableInterface
*iface
)
7826 iface
->get_border
= gtk_cmclist_get_border
;