1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/dataview.cpp
3 // Purpose: wxDataViewCtrl GTK+2 implementation
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
13 #if wxUSE_DATAVIEWCTRL
15 #include "wx/dataview.h"
17 #ifndef wxUSE_GENERICDATAVIEWCTRL
21 #include "wx/dcclient.h"
25 #include "wx/stockitem.h"
26 #include "wx/calctrl.h"
27 #include "wx/popupwin.h"
31 #include "wx/gtk/private.h"
32 #include "wx/gtk/win_gtk.h"
34 #include <gobject/gvaluecollector.h>
35 #include <gtk/gtktreemodel.h>
36 #include <gtk/gtktreednd.h>
38 #include <gdk/gdkkeysyms.h>
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
48 //-----------------------------------------------------------------------------
50 extern bool g_blockEventsOnDrag
;
52 //-----------------------------------------------------------------------------
53 // define new GTK+ class wxGtkTreeModel
54 //-----------------------------------------------------------------------------
58 #define GTK_TYPE_WX_TREE_MODEL (gtk_wx_tree_model_get_type ())
59 #define GTK_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModel))
60 #define GTK_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
61 #define GTK_IS_WX_TREE_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_TREE_MODEL))
62 #define GTK_IS_WX_TREE_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_TREE_MODEL))
63 #define GTK_WX_TREE_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_TREE_MODEL, GtkWxTreeModelClass))
65 GType
gtk_wx_tree_model_get_type (void);
67 typedef struct _GtkWxTreeModel GtkWxTreeModel
;
68 typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass
;
70 struct _GtkWxTreeModel
76 wxDataViewModel
*model
;
79 struct _GtkWxTreeModelClass
81 GObjectClass list_parent_class
;
84 static GtkWxTreeModel
*wxgtk_tree_model_new (void);
85 static void wxgtk_tree_model_init (GtkWxTreeModel
*tree_model
);
86 static void wxgtk_tree_model_class_init (GtkWxTreeModelClass
*klass
);
87 static void wxgtk_tree_model_tree_model_init (GtkTreeModelIface
*iface
);
88 static void wxgtk_tree_model_finalize (GObject
*object
);
89 static GtkTreeModelFlags
wxgtk_tree_model_get_flags (GtkTreeModel
*tree_model
);
90 static gint
wxgtk_tree_model_get_n_columns (GtkTreeModel
*tree_model
);
91 static GType
wxgtk_tree_model_get_column_type (GtkTreeModel
*tree_model
,
93 static gboolean
wxgtk_tree_model_get_iter (GtkTreeModel
*tree_model
,
96 static GtkTreePath
*wxgtk_tree_model_get_path (GtkTreeModel
*tree_model
,
98 static void wxgtk_tree_model_get_value (GtkTreeModel
*tree_model
,
102 static gboolean
wxgtk_tree_model_iter_next (GtkTreeModel
*tree_model
,
104 static gboolean
wxgtk_tree_model_iter_children (GtkTreeModel
*tree_model
,
106 GtkTreeIter
*parent
);
107 static gboolean
wxgtk_tree_model_iter_has_child (GtkTreeModel
*tree_model
,
109 static gint
wxgtk_tree_model_iter_n_children (GtkTreeModel
*tree_model
,
111 static gboolean
wxgtk_tree_model_iter_nth_child (GtkTreeModel
*tree_model
,
115 static gboolean
wxgtk_tree_model_iter_parent (GtkTreeModel
*tree_model
,
119 static GObjectClass
*list_parent_class
= NULL
;
122 gtk_wx_tree_model_get_type (void)
124 static GType tree_model_type
= 0;
126 if (!tree_model_type
)
128 const GTypeInfo tree_model_info
=
130 sizeof (GtkWxTreeModelClass
),
131 NULL
, /* base_init */
132 NULL
, /* base_finalize */
133 (GClassInitFunc
) wxgtk_tree_model_class_init
,
134 NULL
, /* class_finalize */
135 NULL
, /* class_data */
136 sizeof (GtkWxTreeModel
),
138 (GInstanceInitFunc
) wxgtk_tree_model_init
,
141 static const GInterfaceInfo tree_model_iface_info
=
143 (GInterfaceInitFunc
) wxgtk_tree_model_tree_model_init
,
148 tree_model_type
= g_type_register_static (G_TYPE_OBJECT
, "GtkWxTreeModel",
149 &tree_model_info
, (GTypeFlags
)0 );
151 g_type_add_interface_static (tree_model_type
,
153 &tree_model_iface_info
);
156 return tree_model_type
;
159 static GtkWxTreeModel
*
160 wxgtk_tree_model_new(void)
162 GtkWxTreeModel
*retval
= (GtkWxTreeModel
*) g_object_new (GTK_TYPE_WX_TREE_MODEL
, NULL
);
167 wxgtk_tree_model_class_init (GtkWxTreeModelClass
*klass
)
169 list_parent_class
= (GObjectClass
*) g_type_class_peek_parent (klass
);
170 GObjectClass
*object_class
= (GObjectClass
*) klass
;
171 object_class
->finalize
= wxgtk_tree_model_finalize
;
175 wxgtk_tree_model_tree_model_init (GtkTreeModelIface
*iface
)
177 iface
->get_flags
= wxgtk_tree_model_get_flags
;
178 iface
->get_n_columns
= wxgtk_tree_model_get_n_columns
;
179 iface
->get_column_type
= wxgtk_tree_model_get_column_type
;
180 iface
->get_iter
= wxgtk_tree_model_get_iter
;
181 iface
->get_path
= wxgtk_tree_model_get_path
;
182 iface
->get_value
= wxgtk_tree_model_get_value
;
183 iface
->iter_next
= wxgtk_tree_model_iter_next
;
184 iface
->iter_children
= wxgtk_tree_model_iter_children
;
185 iface
->iter_has_child
= wxgtk_tree_model_iter_has_child
;
186 iface
->iter_n_children
= wxgtk_tree_model_iter_n_children
;
187 iface
->iter_nth_child
= wxgtk_tree_model_iter_nth_child
;
188 iface
->iter_parent
= wxgtk_tree_model_iter_parent
;
192 wxgtk_tree_model_init (GtkWxTreeModel
*tree_model
)
194 tree_model
->model
= NULL
;
195 tree_model
->stamp
= g_random_int();
199 wxgtk_tree_model_finalize (GObject
*object
)
201 /* GtkWxTreeModel *tree_model = GTK_WX_LIST_STORE (object); */
203 /* we need to sort out, which class deletes what */
204 /* delete tree_model->model; */
207 (* list_parent_class
->finalize
) (object
);
212 //-----------------------------------------------------------------------------
213 // implement callbacks from wxGtkTreeModel class by letting
214 // them call the methods of wxWidgets' wxDataViewModel
215 //-----------------------------------------------------------------------------
217 static GtkTreeModelFlags
218 wxgtk_tree_model_get_flags (GtkTreeModel
*tree_model
)
220 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (tree_model
), (GtkTreeModelFlags
)0 );
222 return GTK_TREE_MODEL_ITERS_PERSIST
;
226 wxgtk_tree_model_get_n_columns (GtkTreeModel
*tree_model
)
228 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
229 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), 0);
231 return wxtree_model
->model
->GetColumnCount();
235 wxgtk_tree_model_get_column_type (GtkTreeModel
*tree_model
,
238 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
239 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), G_TYPE_INVALID
);
241 GType gtype
= G_TYPE_INVALID
;
243 wxString wxtype
= wxtree_model
->model
->GetColumnType( (unsigned int) index
);
245 if (wxtype
== wxT("string"))
246 gtype
= G_TYPE_STRING
;
249 wxFAIL_MSG( _T("non-string columns not supported yet") );
256 wxgtk_tree_model_get_iter (GtkTreeModel
*tree_model
,
260 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
261 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
262 g_return_val_if_fail (gtk_tree_path_get_depth (path
) > 0, FALSE
);
264 wxDataViewModel
*model
= wxtree_model
->model
;
266 int depth
= gtk_tree_path_get_depth( path
);
271 for (i
= 0; i
< depth
; i
++)
273 gint pos
= gtk_tree_path_get_indices (path
)[i
];
274 item
= model
->GetNthChild( item
, (unsigned int) pos
);
278 wxPrintf( wxT("wrong item from path\n") );
283 iter
->stamp
= wxtree_model
->stamp
;
284 iter
->user_data
= (gpointer
) item
.GetID();
290 wxgtk_tree_model_get_path (GtkTreeModel
*tree_model
,
293 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
294 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), NULL
);
295 g_return_val_if_fail (iter
->stamp
== GTK_WX_TREE_MODEL (wxtree_model
)->stamp
, NULL
);
297 GtkTreePath
*retval
= gtk_tree_path_new ();
298 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
300 wxDataViewModel
*model
= wxtree_model
->model
;
305 wxDataViewItem parent
= model
->GetParent( item
);
308 wxPrintf( wxT("wrong parent\n") );
310 wxDataViewItem node
= model
->GetFirstChild( parent
);
312 while (node
.GetID() != item
.GetID())
314 node
= model
->GetNextSibling( node
);
317 wxPrintf( wxT("wrong node\n") );
322 gtk_tree_path_prepend_index( retval
, n
);
324 item
= model
->GetParent( item
);
331 wxgtk_tree_model_get_value (GtkTreeModel
*tree_model
,
336 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
337 g_return_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
) );
339 wxDataViewModel
*model
= wxtree_model
->model
;
340 wxString mtype
= model
->GetColumnType( (unsigned int) column
);
341 if (mtype
== wxT("string"))
344 g_value_init( value
, G_TYPE_STRING
);
345 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
346 model
->GetValue( variant
, item
, (unsigned int) column
);
348 g_value_set_string( value
, variant
.GetString().utf8_str() );
352 wxFAIL_MSG( _T("non-string columns not supported yet") );
357 wxgtk_tree_model_iter_next (GtkTreeModel
*tree_model
,
360 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
361 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
363 g_return_val_if_fail (wxtree_model
->stamp
== iter
->stamp
, FALSE
);
365 wxDataViewModel
*model
= wxtree_model
->model
;
367 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
368 item
= model
->GetNextSibling( item
);
372 iter
->user_data
= (gpointer
) item
.GetID();
378 wxgtk_tree_model_iter_children (GtkTreeModel
*tree_model
,
382 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
383 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
385 g_return_val_if_fail (wxtree_model
->stamp
== parent
->stamp
, FALSE
);
387 wxDataViewModel
*model
= wxtree_model
->model
;
389 wxDataViewItem
item( (wxUint32
) parent
->user_data
);
390 item
= model
->GetFirstChild( item
);
394 iter
->stamp
= wxtree_model
->stamp
;
395 iter
->user_data
= (gpointer
) item
.GetID();
401 wxgtk_tree_model_iter_has_child (GtkTreeModel
*tree_model
,
404 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
405 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
407 g_return_val_if_fail (wxtree_model
->stamp
== iter
->stamp
, FALSE
);
409 wxDataViewModel
*model
= wxtree_model
->model
;
411 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
413 return model
->HasChildren( item
);
417 wxgtk_tree_model_iter_n_children (GtkTreeModel
*tree_model
,
420 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
421 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
423 g_return_val_if_fail (wxtree_model
->stamp
== iter
->stamp
, 0);
425 wxDataViewModel
*model
= wxtree_model
->model
;
427 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
429 return model
->GetChildCount( item
);
433 wxgtk_tree_model_iter_nth_child (GtkTreeModel
*tree_model
,
438 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
439 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
441 g_return_val_if_fail (wxtree_model
->stamp
== parent
->stamp
, FALSE
);
443 wxDataViewModel
*model
= wxtree_model
->model
;
445 wxDataViewItem
item( (wxUint32
) parent
->user_data
);
446 item
= model
->GetNthChild( item
, n
);
451 iter
->stamp
= wxtree_model
->stamp
;
452 iter
->user_data
= (gpointer
) item
.GetID();
458 wxgtk_tree_model_iter_parent (GtkTreeModel
*tree_model
,
462 GtkWxTreeModel
*wxtree_model
= (GtkWxTreeModel
*) tree_model
;
463 g_return_val_if_fail (GTK_IS_WX_TREE_MODEL (wxtree_model
), FALSE
);
465 g_return_val_if_fail (wxtree_model
->stamp
== child
->stamp
, FALSE
);
467 wxDataViewModel
*model
= wxtree_model
->model
;
469 wxDataViewItem
item( (wxUint32
) child
->user_data
);
470 item
= model
->GetParent( item
);
475 iter
->stamp
= wxtree_model
->stamp
;
476 iter
->user_data
= (gpointer
) item
.GetID();
481 //-----------------------------------------------------------------------------
482 // define new GTK+ class wxGtkRendererRenderer
483 //-----------------------------------------------------------------------------
487 #define GTK_TYPE_WX_CELL_RENDERER (gtk_wx_cell_renderer_get_type ())
488 #define GTK_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRenderer))
489 #define GTK_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
490 #define GTK_IS_WX_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WX_CELL_RENDERER))
491 #define GTK_IS_WX_CELL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_WX_CELL_RENDERER))
492 #define GTK_WX_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_WX_CELL_RENDERER, GtkWxCellRendererClass))
494 GType
gtk_wx_cell_renderer_get_type (void);
496 typedef struct _GtkWxCellRenderer GtkWxCellRenderer
;
497 typedef struct _GtkWxCellRendererClass GtkWxCellRendererClass
;
499 struct _GtkWxCellRenderer
501 GtkCellRenderer parent
;
504 wxDataViewCustomRenderer
*cell
;
508 struct _GtkWxCellRendererClass
510 GtkCellRendererClass cell_parent_class
;
514 static GtkCellRenderer
*gtk_wx_cell_renderer_new (void);
515 static void gtk_wx_cell_renderer_init (
516 GtkWxCellRenderer
*cell
);
517 static void gtk_wx_cell_renderer_class_init(
518 GtkWxCellRendererClass
*klass
);
519 static void gtk_wx_cell_renderer_finalize (
521 static void gtk_wx_cell_renderer_get_size (
522 GtkCellRenderer
*cell
,
524 GdkRectangle
*rectangle
,
529 static void gtk_wx_cell_renderer_render (
530 GtkCellRenderer
*cell
,
533 GdkRectangle
*background_area
,
534 GdkRectangle
*cell_area
,
535 GdkRectangle
*expose_area
,
536 GtkCellRendererState flags
);
537 static gboolean
gtk_wx_cell_renderer_activate(
538 GtkCellRenderer
*cell
,
542 GdkRectangle
*background_area
,
543 GdkRectangle
*cell_area
,
544 GtkCellRendererState flags
);
545 static GtkCellEditable
*gtk_wx_cell_renderer_start_editing(
546 GtkCellRenderer
*cell
,
550 GdkRectangle
*background_area
,
551 GdkRectangle
*cell_area
,
552 GtkCellRendererState flags
);
555 static GObjectClass
*cell_parent_class
= NULL
;
560 gtk_wx_cell_renderer_get_type (void)
562 static GType cell_wx_type
= 0;
566 const GTypeInfo cell_wx_info
=
568 sizeof (GtkWxCellRendererClass
),
569 NULL
, /* base_init */
570 NULL
, /* base_finalize */
571 (GClassInitFunc
) gtk_wx_cell_renderer_class_init
,
572 NULL
, /* class_finalize */
573 NULL
, /* class_data */
574 sizeof (GtkWxCellRenderer
),
576 (GInstanceInitFunc
) gtk_wx_cell_renderer_init
,
579 cell_wx_type
= g_type_register_static( GTK_TYPE_CELL_RENDERER
,
580 "GtkWxCellRenderer", &cell_wx_info
, (GTypeFlags
)0 );
587 gtk_wx_cell_renderer_init (GtkWxCellRenderer
*cell
)
590 cell
->last_click
= 0;
594 gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass
*klass
)
596 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
597 GtkCellRendererClass
*cell_class
= GTK_CELL_RENDERER_CLASS (klass
);
599 cell_parent_class
= (GObjectClass
*) g_type_class_peek_parent (klass
);
601 object_class
->finalize
= gtk_wx_cell_renderer_finalize
;
603 cell_class
->get_size
= gtk_wx_cell_renderer_get_size
;
604 cell_class
->render
= gtk_wx_cell_renderer_render
;
605 cell_class
->activate
= gtk_wx_cell_renderer_activate
;
606 cell_class
->start_editing
= gtk_wx_cell_renderer_start_editing
;
610 gtk_wx_cell_renderer_finalize (GObject
*object
)
613 (* G_OBJECT_CLASS (cell_parent_class
)->finalize
) (object
);
617 gtk_wx_cell_renderer_new (void)
619 return (GtkCellRenderer
*) g_object_new (GTK_TYPE_WX_CELL_RENDERER
, NULL
);
624 static GtkCellEditable
*gtk_wx_cell_renderer_start_editing(
625 GtkCellRenderer
*renderer
,
629 GdkRectangle
*background_area
,
630 GdkRectangle
*cell_area
,
631 GtkCellRendererState flags
)
633 GtkWxCellRenderer
*wxrenderer
= (GtkWxCellRenderer
*) renderer
;
634 wxDataViewCustomRenderer
*cell
= wxrenderer
->cell
;
635 if (!cell
->HasEditorCtrl())
639 gtk_wx_cell_renderer_get_size (renderer
, widget
, cell_area
,
645 rect
.x
+= cell_area
->x
;
646 rect
.y
+= cell_area
->y
;
647 // rect.width -= renderer->xpad * 2;
648 // rect.height -= renderer->ypad * 2;
650 // wxRect renderrect( rect.x, rect.y, rect.width, rect.height );
651 wxRect
renderrect( cell_area
->x
, cell_area
->y
, cell_area
->width
, cell_area
->height
);
653 // wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel();
655 GtkTreePath
*treepath
= gtk_tree_path_new_from_string( path
);
656 unsigned int model_row
= (unsigned int)gtk_tree_path_get_indices (treepath
)[0];
657 gtk_tree_path_free( treepath
);
659 cell
->StartEditing( model_row
, renderrect
);
665 gtk_wx_cell_renderer_get_size (GtkCellRenderer
*renderer
,
667 GdkRectangle
*cell_area
,
673 GtkWxCellRenderer
*wxrenderer
= (GtkWxCellRenderer
*) renderer
;
674 wxDataViewCustomRenderer
*cell
= wxrenderer
->cell
;
676 wxSize size
= cell
->GetSize();
678 gint calc_width
= (gint
) renderer
->xpad
* 2 + size
.x
;
679 gint calc_height
= (gint
) renderer
->ypad
* 2 + size
.y
;
686 if (cell_area
&& size
.x
> 0 && size
.y
> 0)
690 *x_offset
= (gint
)((renderer
->xalign
*
691 (cell_area
->width
- calc_width
- 2 * renderer
->xpad
)));
692 *x_offset
= MAX (*x_offset
, 0) + renderer
->xpad
;
696 *y_offset
= (gint
)((renderer
->yalign
*
697 (cell_area
->height
- calc_height
- 2 * renderer
->ypad
)));
698 *y_offset
= MAX (*y_offset
, 0) + renderer
->ypad
;
706 *height
= calc_height
;
710 gtk_wx_cell_renderer_render (GtkCellRenderer
*renderer
,
713 GdkRectangle
*background_area
,
714 GdkRectangle
*cell_area
,
715 GdkRectangle
*expose_area
,
716 GtkCellRendererState flags
)
719 GtkWxCellRenderer
*wxrenderer
= (GtkWxCellRenderer
*) renderer
;
720 wxDataViewCustomRenderer
*cell
= wxrenderer
->cell
;
723 gtk_wx_cell_renderer_get_size (renderer
, widget
, cell_area
,
729 rect
.x
+= cell_area
->x
;
730 rect
.y
+= cell_area
->y
;
731 rect
.width
-= renderer
->xpad
* 2;
732 rect
.height
-= renderer
->ypad
* 2;
735 if (gdk_rectangle_intersect (expose_area
, &rect
, &dummy
))
737 wxRect
renderrect( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
738 wxWindowDC
* dc
= (wxWindowDC
*) cell
->GetDC();
739 if (dc
->m_window
== NULL
)
741 dc
->m_window
= window
;
746 if (flags
& GTK_CELL_RENDERER_SELECTED
)
747 state
|= wxDATAVIEW_CELL_SELECTED
;
748 if (flags
& GTK_CELL_RENDERER_PRELIT
)
749 state
|= wxDATAVIEW_CELL_PRELIT
;
750 if (flags
& GTK_CELL_RENDERER_INSENSITIVE
)
751 state
|= wxDATAVIEW_CELL_INSENSITIVE
;
752 if (flags
& GTK_CELL_RENDERER_INSENSITIVE
)
753 state
|= wxDATAVIEW_CELL_INSENSITIVE
;
754 if (flags
& GTK_CELL_RENDERER_FOCUSED
)
755 state
|= wxDATAVIEW_CELL_FOCUSED
;
756 cell
->Render( renderrect
, dc
, state
);
761 gtk_wx_cell_renderer_activate(
762 GtkCellRenderer
*renderer
,
766 GdkRectangle
*background_area
,
767 GdkRectangle
*cell_area
,
768 GtkCellRendererState flags
)
770 GtkWxCellRenderer
*wxrenderer
= (GtkWxCellRenderer
*) renderer
;
771 wxDataViewCustomRenderer
*cell
= wxrenderer
->cell
;
774 gtk_wx_cell_renderer_get_size (renderer
, widget
, cell_area
,
780 rect
.x
+= cell_area
->x
;
781 rect
.y
+= cell_area
->y
;
782 rect
.width
-= renderer
->xpad
* 2;
783 rect
.height
-= renderer
->ypad
* 2;
785 wxRect
renderrect( rect
.x
, rect
.y
, rect
.width
, rect
.height
);
787 wxDataViewModel
*model
= cell
->GetOwner()->GetOwner()->GetModel();
789 GtkTreePath
*treepath
= gtk_tree_path_new_from_string( path
);
790 unsigned int model_row
= (unsigned int)gtk_tree_path_get_indices (treepath
)[0];
791 gtk_tree_path_free( treepath
);
793 unsigned int model_col
= cell
->GetOwner()->GetModelColumn();
799 // activated by <ENTER>
800 if (cell
->Activate( renderrect
, model
, model_col
, model_row
))
805 else if (event
->type
== GDK_BUTTON_PRESS
)
807 GdkEventButton
*button_event
= (GdkEventButton
*) event
;
808 wxPoint
pt( ((int) button_event
->x
) - renderrect
.x
,
809 ((int) button_event
->y
) - renderrect
.y
);
812 if (button_event
->button
== 1)
814 if (cell
->LeftClick( pt
, renderrect
, model
, model_col
, model_row
))
816 // TODO: query system double-click time
817 if (button_event
->time
- wxrenderer
->last_click
< 400)
818 if (cell
->Activate( renderrect
, model
, model_col
, model_row
))
821 if (button_event
->button
== 3)
823 if (cell
->RightClick( pt
, renderrect
, model
, model_col
, model_row
))
827 wxrenderer
->last_click
= button_event
->time
;
835 // ---------------------------------------------------------
836 // wxGtkDataViewModelNotifier
837 // ---------------------------------------------------------
839 class wxGtkDataViewModelNotifier
: public wxDataViewModelNotifier
842 wxGtkDataViewModelNotifier( GtkWxTreeModel
*wxgtk_model
,
843 wxDataViewModel
*wx_model
,
844 wxDataViewCtrl
*ctrl
);
845 ~wxGtkDataViewModelNotifier();
847 virtual bool ItemAdded( const wxDataViewItem
&parent
, const wxDataViewItem
&item
);
848 virtual bool ItemDeleted( const wxDataViewItem
&item
);
849 virtual bool ItemChanged( const wxDataViewItem
&item
);
850 virtual bool ValueChanged( const wxDataViewItem
&item
, unsigned int col
);
851 virtual bool Cleared();
853 GtkWxTreeModel
*m_wxgtk_model
;
854 wxDataViewModel
*m_wx_model
;
855 wxDataViewCtrl
*m_owner
;
858 // ---------------------------------------------------------
859 // wxGtkDataViewListModelNotifier
860 // ---------------------------------------------------------
862 wxGtkDataViewModelNotifier::wxGtkDataViewModelNotifier(
863 GtkWxTreeModel
* wxgtk_model
, wxDataViewModel
*wx_model
,
864 wxDataViewCtrl
*ctrl
)
866 m_wxgtk_model
= wxgtk_model
;
867 m_wx_model
= wx_model
;
871 wxGtkDataViewModelNotifier::~wxGtkDataViewModelNotifier()
874 m_wxgtk_model
= NULL
;
877 bool wxGtkDataViewModelNotifier::ItemAdded( const wxDataViewItem
&parent
, const wxDataViewItem
&item
)
880 iter
.stamp
= m_wxgtk_model
->stamp
;
881 iter
.user_data
= (gpointer
) item
.GetID();
883 GtkTreePath
*path
= wxgtk_tree_model_get_path(
884 GTK_TREE_MODEL(m_wxgtk_model
), &iter
);
885 gtk_tree_model_row_inserted(
886 GTK_TREE_MODEL(m_wxgtk_model
), path
, &iter
);
887 gtk_tree_path_free (path
);
892 bool wxGtkDataViewModelNotifier::ItemDeleted( const wxDataViewItem
&item
)
895 iter
.stamp
= m_wxgtk_model
->stamp
;
896 iter
.user_data
= (gpointer
) item
.GetID();
898 GtkTreePath
*path
= wxgtk_tree_model_get_path(
899 GTK_TREE_MODEL(m_wxgtk_model
), &iter
);
900 gtk_tree_model_row_deleted(
901 GTK_TREE_MODEL(m_wxgtk_model
), path
);
902 gtk_tree_path_free (path
);
907 bool wxGtkDataViewModelNotifier::ItemChanged( const wxDataViewItem
&item
)
910 iter
.stamp
= m_wxgtk_model
->stamp
;
911 iter
.user_data
= (gpointer
) item
.GetID();
913 GtkTreePath
*path
= wxgtk_tree_model_get_path(
914 GTK_TREE_MODEL(m_wxgtk_model
), &iter
);
915 gtk_tree_model_row_changed(
916 GTK_TREE_MODEL(m_wxgtk_model
), path
, &iter
);
917 gtk_tree_path_free (path
);
922 bool wxGtkDataViewModelNotifier::ValueChanged( const wxDataViewItem
&item
, unsigned int model_col
)
924 // This adds GTK+'s missing MVC logic for ValueChanged
926 for (index
= 0; index
< m_owner
->GetColumnCount(); index
++)
928 wxDataViewColumn
*column
= m_owner
->GetColumn( index
);
929 if (column
->GetModelColumn() == model_col
)
931 GtkTreeView
*widget
= GTK_TREE_VIEW(m_owner
->m_treeview
);
932 GtkTreeViewColumn
*gcolumn
= GTK_TREE_VIEW_COLUMN(column
->GetGtkHandle());
936 iter
.stamp
= m_wxgtk_model
->stamp
;
937 iter
.user_data
= (gpointer
) item
.GetID();
938 GtkTreePath
*path
= wxgtk_tree_model_get_path(
939 GTK_TREE_MODEL(m_wxgtk_model
), &iter
);
940 GdkRectangle cell_area
;
941 gtk_tree_view_get_cell_area( widget
, path
, gcolumn
, &cell_area
);
942 gtk_tree_path_free( path
);
944 GtkAdjustment
* hadjust
= gtk_tree_view_get_hadjustment( widget
);
945 double d
= gtk_adjustment_get_value( hadjust
);
948 int ydiff
= gcolumn
->button
->allocation
.height
;
950 gtk_widget_queue_draw_area( GTK_WIDGET(widget
),
951 cell_area
.x
- xdiff
, ydiff
+ cell_area
.y
, cell_area
.width
, cell_area
.height
);
958 bool wxGtkDataViewModelNotifier::Cleared()
963 // ---------------------------------------------------------
964 // wxDataViewRenderer
965 // ---------------------------------------------------------
967 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRenderer
, wxDataViewRendererBase
)
969 wxDataViewRenderer::wxDataViewRenderer( const wxString
&varianttype
, wxDataViewCellMode mode
,
971 wxDataViewRendererBase( varianttype
, mode
, align
)
975 // NOTE: SetMode() and SetAlignment() needs to be called in the renderer's ctor,
976 // after the m_renderer pointer has been initialized
979 void wxDataViewRenderer::SetMode( wxDataViewCellMode mode
)
981 GtkCellRendererMode gtkMode
;
984 case wxDATAVIEW_CELL_INERT
:
985 gtkMode
= GTK_CELL_RENDERER_MODE_INERT
;
987 case wxDATAVIEW_CELL_ACTIVATABLE
:
988 gtkMode
= GTK_CELL_RENDERER_MODE_ACTIVATABLE
;
990 case wxDATAVIEW_CELL_EDITABLE
:
991 gtkMode
= GTK_CELL_RENDERER_MODE_EDITABLE
;
995 GValue gvalue
= { 0, };
996 g_value_init( &gvalue
, gtk_cell_renderer_mode_get_type() );
997 g_value_set_enum( &gvalue
, gtkMode
);
998 g_object_set_property( G_OBJECT(m_renderer
), "mode", &gvalue
);
999 g_value_unset( &gvalue
);
1002 wxDataViewCellMode
wxDataViewRenderer::GetMode() const
1004 wxDataViewCellMode ret
;
1007 g_object_get( G_OBJECT(m_renderer
), "mode", &gvalue
, NULL
);
1009 switch (g_value_get_enum(&gvalue
))
1011 case GTK_CELL_RENDERER_MODE_INERT
:
1012 ret
= wxDATAVIEW_CELL_INERT
;
1014 case GTK_CELL_RENDERER_MODE_ACTIVATABLE
:
1015 ret
= wxDATAVIEW_CELL_ACTIVATABLE
;
1017 case GTK_CELL_RENDERER_MODE_EDITABLE
:
1018 ret
= wxDATAVIEW_CELL_EDITABLE
;
1022 g_value_unset( &gvalue
);
1027 void wxDataViewRenderer::SetAlignment( int align
)
1029 // horizontal alignment:
1031 gfloat xalign
= 0.0;
1032 if (align
& wxALIGN_RIGHT
)
1034 else if (align
& wxALIGN_CENTER_HORIZONTAL
)
1037 GValue gvalue
= { 0, };
1038 g_value_init( &gvalue
, G_TYPE_FLOAT
);
1039 g_value_set_float( &gvalue
, xalign
);
1040 g_object_set_property( G_OBJECT(m_renderer
), "xalign", &gvalue
);
1041 g_value_unset( &gvalue
);
1043 // vertical alignment:
1045 gfloat yalign
= 0.0;
1046 if (align
& wxALIGN_BOTTOM
)
1048 else if (align
& wxALIGN_CENTER_VERTICAL
)
1051 GValue gvalue2
= { 0, };
1052 g_value_init( &gvalue2
, G_TYPE_FLOAT
);
1053 g_value_set_float( &gvalue2
, yalign
);
1054 g_object_set_property( G_OBJECT(m_renderer
), "yalign", &gvalue2
);
1055 g_value_unset( &gvalue2
);
1058 int wxDataViewRenderer::GetAlignment() const
1063 // horizontal alignment:
1065 g_object_get( G_OBJECT(m_renderer
), "xalign", &gvalue
, NULL
);
1066 float xalign
= g_value_get_float( &gvalue
);
1068 ret
|= wxALIGN_LEFT
;
1069 else if (xalign
== 0.5)
1070 ret
|= wxALIGN_CENTER_HORIZONTAL
;
1072 ret
|= wxALIGN_RIGHT
;
1073 g_value_unset( &gvalue
);
1076 // vertical alignment:
1078 g_object_get( G_OBJECT(m_renderer
), "yalign", &gvalue
, NULL
);
1079 float yalign
= g_value_get_float( &gvalue
);
1082 else if (yalign
== 0.5)
1083 ret
|= wxALIGN_CENTER_VERTICAL
;
1085 ret
|= wxALIGN_BOTTOM
;
1086 g_value_unset( &gvalue
);
1093 // ---------------------------------------------------------
1094 // wxDataViewTextRenderer
1095 // ---------------------------------------------------------
1098 static void wxGtkTextRendererEditedCallback( GtkCellRendererText
*renderer
,
1099 gchar
*arg1
, gchar
*arg2
, gpointer user_data
);
1102 static void wxGtkTextRendererEditedCallback( GtkCellRendererText
*renderer
,
1103 gchar
*arg1
, gchar
*arg2
, gpointer user_data
)
1105 wxDataViewTextRenderer
*cell
= (wxDataViewTextRenderer
*) user_data
;
1107 wxString tmp
= wxGTK_CONV_BACK_FONT(arg2
, cell
->GetOwner()->GetOwner()->GetFont());
1108 wxVariant value
= tmp
;
1109 if (!cell
->Validate( value
))
1112 wxDataViewModel
*model
= cell
->GetOwner()->GetOwner()->GetModel();
1114 GtkTreePath
*path
= gtk_tree_path_new_from_string( arg1
);
1115 unsigned int model_row
= (unsigned int)gtk_tree_path_get_indices (path
)[0];
1116 gtk_tree_path_free( path
);
1118 unsigned int model_col
= cell
->GetOwner()->GetModelColumn();
1120 model
->SetValue( value
, model_col
, model_row
);
1121 model
->ValueChanged( model_col
, model_row
);
1124 IMPLEMENT_CLASS(wxDataViewTextRenderer
, wxDataViewRenderer
)
1126 wxDataViewTextRenderer::wxDataViewTextRenderer( const wxString
&varianttype
, wxDataViewCellMode mode
,
1128 wxDataViewRenderer( varianttype
, mode
, align
)
1130 m_renderer
= (GtkCellRenderer
*) gtk_cell_renderer_text_new();
1132 if (mode
& wxDATAVIEW_CELL_EDITABLE
)
1134 GValue gvalue
= { 0, };
1135 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1136 g_value_set_boolean( &gvalue
, true );
1137 g_object_set_property( G_OBJECT(m_renderer
), "editable", &gvalue
);
1138 g_value_unset( &gvalue
);
1140 g_signal_connect_after( m_renderer
, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback
), this );
1144 SetAlignment(align
);
1147 bool wxDataViewTextRenderer::SetValue( const wxVariant
&value
)
1149 wxString tmp
= value
;
1151 GValue gvalue
= { 0, };
1152 g_value_init( &gvalue
, G_TYPE_STRING
);
1153 g_value_set_string( &gvalue
, wxGTK_CONV_FONT( tmp
, GetOwner()->GetOwner()->GetFont() ) );
1154 g_object_set_property( G_OBJECT(m_renderer
), "text", &gvalue
);
1155 g_value_unset( &gvalue
);
1160 bool wxDataViewTextRenderer::GetValue( wxVariant
&value
) const
1162 GValue gvalue
= { 0, };
1163 g_value_init( &gvalue
, G_TYPE_STRING
);
1164 g_object_get_property( G_OBJECT(m_renderer
), "text", &gvalue
);
1165 wxString tmp
= wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue
),
1166 wx_const_cast(wxDataViewTextRenderer
*, this)->GetOwner()->GetOwner()->GetFont() );
1167 g_value_unset( &gvalue
);
1174 void wxDataViewTextRenderer::SetAlignment( int align
)
1176 wxDataViewRenderer::SetAlignment(align
);
1178 if (gtk_check_version(2,10,0))
1181 // horizontal alignment:
1182 PangoAlignment pangoAlign
= PANGO_ALIGN_LEFT
;
1183 if (align
& wxALIGN_RIGHT
)
1184 pangoAlign
= PANGO_ALIGN_RIGHT
;
1185 else if (align
& wxALIGN_CENTER_HORIZONTAL
)
1186 pangoAlign
= PANGO_ALIGN_CENTER
;
1188 GValue gvalue
= { 0, };
1189 g_value_init( &gvalue
, gtk_cell_renderer_mode_get_type() );
1190 g_value_set_enum( &gvalue
, pangoAlign
);
1191 g_object_set_property( G_OBJECT(m_renderer
), "alignment", &gvalue
);
1192 g_value_unset( &gvalue
);
1195 // ---------------------------------------------------------
1196 // wxDataViewBitmapRenderer
1197 // ---------------------------------------------------------
1199 IMPLEMENT_CLASS(wxDataViewBitmapRenderer
, wxDataViewRenderer
)
1201 wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString
&varianttype
, wxDataViewCellMode mode
,
1203 wxDataViewRenderer( varianttype
, mode
, align
)
1205 m_renderer
= (GtkCellRenderer
*) gtk_cell_renderer_pixbuf_new();
1208 SetAlignment(align
);
1211 bool wxDataViewBitmapRenderer::SetValue( const wxVariant
&value
)
1213 if (value
.GetType() == wxT("wxBitmap"))
1218 // This may create a Pixbuf representation in the
1219 // wxBitmap object (and it will stay there)
1220 GdkPixbuf
*pixbuf
= bitmap
.GetPixbuf();
1222 GValue gvalue
= { 0, };
1223 g_value_init( &gvalue
, G_TYPE_OBJECT
);
1224 g_value_set_object( &gvalue
, pixbuf
);
1225 g_object_set_property( G_OBJECT(m_renderer
), "pixbuf", &gvalue
);
1226 g_value_unset( &gvalue
);
1231 if (value
.GetType() == wxT("wxIcon"))
1236 // This may create a Pixbuf representation in the
1237 // wxBitmap object (and it will stay there)
1238 GdkPixbuf
*pixbuf
= bitmap
.GetPixbuf();
1240 GValue gvalue
= { 0, };
1241 g_value_init( &gvalue
, G_TYPE_OBJECT
);
1242 g_value_set_object( &gvalue
, pixbuf
);
1243 g_object_set_property( G_OBJECT(m_renderer
), "pixbuf", &gvalue
);
1244 g_value_unset( &gvalue
);
1252 bool wxDataViewBitmapRenderer::GetValue( wxVariant
&value
) const
1257 // ---------------------------------------------------------
1258 // wxDataViewToggleRenderer
1259 // ---------------------------------------------------------
1262 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle
*renderer
,
1263 gchar
*path
, gpointer user_data
);
1266 static void wxGtkToggleRendererToggledCallback( GtkCellRendererToggle
*renderer
,
1267 gchar
*path
, gpointer user_data
)
1269 wxDataViewToggleRenderer
*cell
= (wxDataViewToggleRenderer
*) user_data
;
1272 GValue gvalue
= { 0, };
1273 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1274 g_object_get_property( G_OBJECT(renderer
), "active", &gvalue
);
1275 bool tmp
= g_value_get_boolean( &gvalue
);
1276 g_value_unset( &gvalue
);
1280 wxVariant value
= tmp
;
1281 if (!cell
->Validate( value
))
1284 wxDataViewModel
*model
= cell
->GetOwner()->GetOwner()->GetModel();
1286 GtkTreePath
*gtk_path
= gtk_tree_path_new_from_string( path
);
1287 unsigned int model_row
= (unsigned int)gtk_tree_path_get_indices (gtk_path
)[0];
1288 gtk_tree_path_free( gtk_path
);
1290 unsigned int model_col
= cell
->GetOwner()->GetModelColumn();
1292 model
->SetValue( value
, model_col
, model_row
);
1293 model
->ValueChanged( model_col
, model_row
);
1296 IMPLEMENT_CLASS(wxDataViewToggleRenderer
, wxDataViewRenderer
)
1298 wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString
&varianttype
,
1299 wxDataViewCellMode mode
, int align
) :
1300 wxDataViewRenderer( varianttype
, mode
, align
)
1302 m_renderer
= (GtkCellRenderer
*) gtk_cell_renderer_toggle_new();
1304 if (mode
& wxDATAVIEW_CELL_ACTIVATABLE
)
1306 g_signal_connect_after( m_renderer
, "toggled",
1307 G_CALLBACK(wxGtkToggleRendererToggledCallback
), this );
1311 GValue gvalue
= { 0, };
1312 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1313 g_value_set_boolean( &gvalue
, false );
1314 g_object_set_property( G_OBJECT(m_renderer
), "activatable", &gvalue
);
1315 g_value_unset( &gvalue
);
1319 SetAlignment(align
);
1322 bool wxDataViewToggleRenderer::SetValue( const wxVariant
&value
)
1326 GValue gvalue
= { 0, };
1327 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1328 g_value_set_boolean( &gvalue
, tmp
);
1329 g_object_set_property( G_OBJECT(m_renderer
), "active", &gvalue
);
1330 g_value_unset( &gvalue
);
1335 bool wxDataViewToggleRenderer::GetValue( wxVariant
&value
) const
1337 GValue gvalue
= { 0, };
1338 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1339 g_object_get_property( G_OBJECT(m_renderer
), "active", &gvalue
);
1340 bool tmp
= g_value_get_boolean( &gvalue
);
1341 g_value_unset( &gvalue
);
1348 // ---------------------------------------------------------
1349 // wxDataViewCustomRenderer
1350 // ---------------------------------------------------------
1352 class wxDataViewCtrlDC
: public wxWindowDC
1355 wxDataViewCtrlDC( wxDataViewCtrl
*window
)
1357 GtkWidget
*widget
= window
->m_treeview
;
1361 m_context
= window
->GtkGetPangoDefaultContext();
1362 m_layout
= pango_layout_new( m_context
);
1363 m_fontdesc
= pango_font_description_copy( widget
->style
->font_desc
);
1365 m_cmap
= gtk_widget_get_colormap( widget
? widget
: window
->m_widget
);
1367 // Set m_window later
1369 // m_owner = window;
1373 // ---------------------------------------------------------
1374 // wxDataViewCustomRenderer
1375 // ---------------------------------------------------------
1377 IMPLEMENT_CLASS(wxDataViewCustomRenderer
, wxDataViewRenderer
)
1379 wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString
&varianttype
,
1380 wxDataViewCellMode mode
, int align
,
1382 wxDataViewRenderer( varianttype
, mode
, align
)
1392 bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode
, int align
)
1394 GtkWxCellRenderer
*renderer
= (GtkWxCellRenderer
*) gtk_wx_cell_renderer_new();
1395 renderer
->cell
= this;
1397 m_renderer
= (GtkCellRenderer
*) renderer
;
1400 SetAlignment(align
);
1405 wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
1411 wxDC
*wxDataViewCustomRenderer::GetDC()
1415 if (GetOwner() == NULL
)
1417 if (GetOwner()->GetOwner() == NULL
)
1419 m_dc
= new wxDataViewCtrlDC( GetOwner()->GetOwner() );
1425 // ---------------------------------------------------------
1426 // wxDataViewProgressRenderer
1427 // ---------------------------------------------------------
1429 IMPLEMENT_CLASS(wxDataViewProgressRenderer
, wxDataViewCustomRenderer
)
1431 wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString
&label
,
1432 const wxString
&varianttype
, wxDataViewCellMode mode
, int align
) :
1433 wxDataViewCustomRenderer( varianttype
, mode
, align
, true )
1439 if (!gtk_check_version(2,6,0))
1441 m_renderer
= (GtkCellRenderer
*) gtk_cell_renderer_progress_new();
1443 GValue gvalue
= { 0, };
1444 g_value_init( &gvalue
, G_TYPE_STRING
);
1446 // FIXME: font encoding support
1447 g_value_set_string( &gvalue
, wxGTK_CONV_SYS(m_label
) );
1448 g_object_set_property( G_OBJECT(m_renderer
), "text", &gvalue
);
1449 g_value_unset( &gvalue
);
1452 SetAlignment(align
);
1457 // Use custom cell code
1458 wxDataViewCustomRenderer::Init(mode
, align
);
1462 wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
1466 bool wxDataViewProgressRenderer::SetValue( const wxVariant
&value
)
1469 if (!gtk_check_version(2,6,0))
1471 gint tmp
= (long) value
;
1472 GValue gvalue
= { 0, };
1473 g_value_init( &gvalue
, G_TYPE_INT
);
1474 g_value_set_int( &gvalue
, tmp
);
1475 g_object_set_property( G_OBJECT(m_renderer
), "value", &gvalue
);
1476 g_value_unset( &gvalue
);
1481 m_value
= (long) value
;
1483 if (m_value
< 0) m_value
= 0;
1484 if (m_value
> 100) m_value
= 100;
1490 bool wxDataViewProgressRenderer::GetValue( wxVariant
&value
) const
1495 bool wxDataViewProgressRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
1497 double pct
= (double)m_value
/ 100.0;
1499 bar
.width
= (int)(cell
.width
* pct
);
1500 dc
->SetPen( *wxTRANSPARENT_PEN
);
1501 dc
->SetBrush( *wxBLUE_BRUSH
);
1502 dc
->DrawRectangle( bar
);
1504 dc
->SetBrush( *wxTRANSPARENT_BRUSH
);
1505 dc
->SetPen( *wxBLACK_PEN
);
1506 dc
->DrawRectangle( cell
);
1511 wxSize
wxDataViewProgressRenderer::GetSize() const
1513 return wxSize(40,12);
1516 // ---------------------------------------------------------
1517 // wxDataViewDateRenderer
1518 // ---------------------------------------------------------
1520 class wxDataViewDateRendererPopupTransient
: public wxPopupTransientWindow
1523 wxDataViewDateRendererPopupTransient( wxWindow
* parent
, wxDateTime
*value
,
1524 wxDataViewModel
*model
, const wxDataViewItem
&item
, unsigned int col
) :
1525 wxPopupTransientWindow( parent
, wxBORDER_SIMPLE
)
1530 m_cal
= new wxCalendarCtrl( this, -1, *value
);
1531 wxBoxSizer
*sizer
= new wxBoxSizer( wxHORIZONTAL
);
1532 sizer
->Add( m_cal
, 1, wxGROW
);
1537 virtual void OnDismiss()
1541 void OnCalendar( wxCalendarEvent
&event
);
1543 wxCalendarCtrl
*m_cal
;
1544 wxDataViewModel
*m_model
;
1545 wxDataViewItem m_item
;
1549 DECLARE_EVENT_TABLE()
1552 BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient
,wxPopupTransientWindow
)
1553 EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar
)
1556 void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent
&event
)
1558 wxDateTime date
= event
.GetDate();
1559 wxVariant value
= date
;
1560 m_model
->SetValue( value
, m_item
, m_col
);
1561 m_model
->ValueChanged( m_item
, m_col
);
1565 IMPLEMENT_CLASS(wxDataViewDateRenderer
, wxDataViewCustomRenderer
)
1567 wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString
&varianttype
,
1568 wxDataViewCellMode mode
, int align
) :
1569 wxDataViewCustomRenderer( varianttype
, mode
, align
)
1572 SetAlignment(align
);
1575 bool wxDataViewDateRenderer::SetValue( const wxVariant
&value
)
1577 m_date
= value
.GetDateTime();
1582 bool wxDataViewDateRenderer::GetValue( wxVariant
&value
) const
1587 bool wxDataViewDateRenderer::Render( wxRect cell
, wxDC
*dc
, int state
)
1589 dc
->SetFont( GetOwner()->GetOwner()->GetFont() );
1590 wxString tmp
= m_date
.FormatDate();
1591 dc
->DrawText( tmp
, cell
.x
, cell
.y
);
1596 wxSize
wxDataViewDateRenderer::GetSize() const
1598 wxString tmp
= m_date
.FormatDate();
1600 GetView()->GetTextExtent( tmp
, &x
, &y
, &d
);
1601 return wxSize(x
,y
+d
);
1604 bool wxDataViewDateRenderer::Activate( wxRect cell
, wxDataViewModel
*model
,
1605 const wxDataViewItem
&item
, unsigned int col
)
1608 model
->GetValue( variant
, item
, col
);
1609 wxDateTime value
= variant
.GetDateTime();
1611 wxDataViewDateRendererPopupTransient
*popup
= new wxDataViewDateRendererPopupTransient(
1612 GetOwner()->GetOwner()->GetParent(), &value
, model
, item
, col
);
1613 wxPoint pos
= wxGetMousePosition();
1616 popup
->Popup( popup
->m_cal
);
1621 // ---------------------------------------------------------
1623 // ---------------------------------------------------------
1627 gtk_dataview_header_button_press_callback( GtkWidget
*widget
,
1628 GdkEventButton
*gdk_event
,
1629 wxDataViewColumn
*column
)
1631 if (gdk_event
->type
!= GDK_BUTTON_PRESS
)
1634 if (gdk_event
->button
== 1)
1636 wxDataViewCtrl
*dv
= column
->GetOwner();
1637 wxDataViewEvent
event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
, dv
->GetId() );
1638 event
.SetDataViewColumn( column
);
1639 event
.SetModel( dv
->GetModel() );
1640 dv
->GetEventHandler()->ProcessEvent( event
);
1647 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn
*column
,
1648 GtkCellRenderer
*cell
,
1649 GtkTreeModel
*model
,
1655 static void wxGtkTreeCellDataFunc( GtkTreeViewColumn
*column
,
1656 GtkCellRenderer
*renderer
,
1657 GtkTreeModel
*model
,
1661 g_return_if_fail (GTK_IS_WX_TREE_MODEL (model
));
1662 GtkWxTreeModel
*tree_model
= (GtkWxTreeModel
*) model
;
1664 wxDataViewRenderer
*cell
= (wxDataViewRenderer
*) data
;
1666 wxDataViewItem
item( (wxUint32
) iter
->user_data
);
1669 tree_model
->model
->GetValue( value
, item
, cell
->GetOwner()->GetModelColumn() );
1671 if (value
.GetType() != cell
->GetVariantType())
1672 wxLogError( wxT("Wrong type, required: %s but: %s"),
1673 value
.GetType().c_str(),
1674 cell
->GetVariantType().c_str() );
1676 cell
->SetValue( value
);
1679 wxListItemAttr attr
;
1680 tree_model
->model
->GetAttr( attr
, cell
->GetOwner()->GetModelColumn(), model_row
);
1682 if (attr
.HasBackgroundColour())
1684 wxColour colour
= attr
.GetBackgroundColour();
1685 const GdkColor
* const gcol
= colour
.GetColor();
1687 GValue gvalue
= { 0, };
1688 g_value_init( &gvalue
, GDK_TYPE_COLOR
);
1689 g_value_set_boxed( &gvalue
, gcol
);
1690 g_object_set_property( G_OBJECT(renderer
), "cell-background_gdk", &gvalue
);
1691 g_value_unset( &gvalue
);
1695 GValue gvalue
= { 0, };
1696 g_value_init( &gvalue
, G_TYPE_BOOLEAN
);
1697 g_value_set_boolean( &gvalue
, FALSE
);
1698 g_object_set_property( G_OBJECT(renderer
), "cell-background-set", &gvalue
);
1699 g_value_unset( &gvalue
);
1705 IMPLEMENT_CLASS(wxDataViewColumn
, wxDataViewColumnBase
)
1707 wxDataViewColumn::wxDataViewColumn( const wxString
&title
, wxDataViewRenderer
*cell
,
1708 unsigned int model_column
, int width
,
1709 wxAlignment align
, int flags
) :
1710 wxDataViewColumnBase( title
, cell
, model_column
, width
, align
, flags
)
1712 Init( align
, flags
, width
);
1714 gtk_tree_view_column_set_clickable( GTK_TREE_VIEW_COLUMN(m_column
), TRUE
);
1718 wxDataViewColumn::wxDataViewColumn( const wxBitmap
&bitmap
, wxDataViewRenderer
*cell
,
1719 unsigned int model_column
, int width
,
1720 wxAlignment align
, int flags
) :
1721 wxDataViewColumnBase( bitmap
, cell
, model_column
, width
, align
, flags
)
1723 Init( align
, flags
, width
);
1725 SetBitmap( bitmap
);
1728 void wxDataViewColumn::Init(wxAlignment align
, int flags
, int width
)
1730 m_isConnected
= false;
1732 GtkCellRenderer
*renderer
= (GtkCellRenderer
*) GetRenderer()->GetGtkHandle();
1733 GtkTreeViewColumn
*column
= gtk_tree_view_column_new();
1734 m_column
= (GtkWidget
*) column
;
1737 SetAlignment( align
);
1739 // NOTE: we prefer not to call SetMinWidth(wxDVC_DEFAULT_MINWIDTH);
1740 // as GTK+ is smart and unless explicitely told, will set the minimal
1741 // width to the title's lenght, which is a better default
1743 // the GTK_TREE_VIEW_COLUMN_FIXED is required by the "fixed height" mode
1744 // that we use for the wxDataViewCtrl
1745 gtk_tree_view_column_set_fixed_width( column
, width
< 0 ? wxDVC_DEFAULT_WIDTH
: width
);
1746 gtk_tree_view_column_set_sizing( column
, GTK_TREE_VIEW_COLUMN_FIXED
);
1748 gtk_tree_view_column_pack_end( column
, renderer
, TRUE
);
1750 gtk_tree_view_column_set_cell_data_func( column
, renderer
,
1751 wxGtkTreeCellDataFunc
, (gpointer
) GetRenderer(), NULL
);
1754 wxDataViewColumn::~wxDataViewColumn()
1758 void wxDataViewColumn::OnInternalIdle()
1763 if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview
))
1765 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1768 g_signal_connect(column
->button
, "button_press_event",
1769 G_CALLBACK (gtk_dataview_header_button_press_callback
), this);
1771 m_isConnected
= true;
1776 void wxDataViewColumn::SetOwner( wxDataViewCtrl
*owner
)
1778 wxDataViewColumnBase::SetOwner( owner
);
1780 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1782 gtk_tree_view_column_set_title( column
, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
1785 void wxDataViewColumn::SetTitle( const wxString
&title
)
1787 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1791 // disconnect before column->button gets recreated
1792 g_signal_handlers_disconnect_by_func( column
->button
,
1793 (GtkWidget
*) gtk_dataview_header_button_press_callback
, this);
1795 m_isConnected
= false;
1798 // FIXME: can it really happen that we don't have the owner here??
1799 wxDataViewCtrl
*ctrl
= GetOwner();
1800 gtk_tree_view_column_set_title( column
, ctrl
? wxGTK_CONV_FONT(title
, ctrl
->GetFont())
1801 : wxGTK_CONV_SYS(title
) );
1803 gtk_tree_view_column_set_widget( column
, NULL
);
1806 wxString
wxDataViewColumn::GetTitle() const
1808 const gchar
*str
= gtk_tree_view_column_get_title( GTK_TREE_VIEW_COLUMN(m_column
) );
1809 return wxConvFileName
->cMB2WX(str
);
1812 void wxDataViewColumn::SetBitmap( const wxBitmap
&bitmap
)
1814 wxDataViewColumnBase::SetBitmap( bitmap
);
1816 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1819 GtkImage
*gtk_image
= GTK_IMAGE( gtk_image_new() );
1821 GdkBitmap
*mask
= (GdkBitmap
*) NULL
;
1822 if (bitmap
.GetMask())
1823 mask
= bitmap
.GetMask()->GetBitmap();
1825 if (bitmap
.HasPixbuf())
1827 gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image
),
1828 bitmap
.GetPixbuf());
1832 gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image
),
1833 bitmap
.GetPixmap(), mask
);
1835 gtk_widget_show( GTK_WIDGET(gtk_image
) );
1837 gtk_tree_view_column_set_widget( column
, GTK_WIDGET(gtk_image
) );
1841 gtk_tree_view_column_set_widget( column
, NULL
);
1845 void wxDataViewColumn::SetHidden( bool hidden
)
1847 gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column
), !hidden
);
1850 void wxDataViewColumn::SetResizeable( bool resizeable
)
1852 gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column
), resizeable
);
1855 void wxDataViewColumn::SetAlignment( wxAlignment align
)
1857 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1859 gfloat xalign
= 0.0;
1860 if (align
== wxALIGN_RIGHT
)
1862 if (align
== wxALIGN_CENTER_HORIZONTAL
||
1863 align
== wxALIGN_CENTER
)
1866 gtk_tree_view_column_set_alignment( column
, xalign
);
1869 wxAlignment
wxDataViewColumn::GetAlignment() const
1871 gfloat xalign
= gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column
) );
1874 return wxALIGN_RIGHT
;
1876 return wxALIGN_CENTER_HORIZONTAL
;
1878 return wxALIGN_LEFT
;
1881 void wxDataViewColumn::SetSortable( bool sortable
)
1883 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1884 gtk_tree_view_column_set_sort_indicator( column
, sortable
);
1887 bool wxDataViewColumn::IsSortable() const
1889 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1890 return gtk_tree_view_column_get_sort_indicator( column
);
1893 bool wxDataViewColumn::IsResizeable() const
1895 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1896 return gtk_tree_view_column_get_resizable( column
);
1899 bool wxDataViewColumn::IsHidden() const
1901 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1902 return !gtk_tree_view_column_get_visible( column
);
1905 void wxDataViewColumn::SetSortOrder( bool ascending
)
1907 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1910 gtk_tree_view_column_set_sort_order( column
, GTK_SORT_ASCENDING
);
1912 gtk_tree_view_column_set_sort_order( column
, GTK_SORT_DESCENDING
);
1915 bool wxDataViewColumn::IsSortOrderAscending() const
1917 GtkTreeViewColumn
*column
= GTK_TREE_VIEW_COLUMN(m_column
);
1919 return (gtk_tree_view_column_get_sort_order( column
) != GTK_SORT_DESCENDING
);
1922 void wxDataViewColumn::SetMinWidth( int width
)
1924 gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column
), width
);
1927 int wxDataViewColumn::GetMinWidth() const
1929 return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column
) );
1932 int wxDataViewColumn::GetWidth() const
1934 return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column
) );
1937 void wxDataViewColumn::SetWidth( int width
)
1939 gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column
), width
);
1943 //-----------------------------------------------------------------------------
1944 // wxDataViewCtrl signal callbacks
1945 //-----------------------------------------------------------------------------
1948 wxdataview_selection_changed_callback( GtkTreeSelection
* selection
, wxDataViewCtrl
*dv
)
1950 if (!GTK_WIDGET_REALIZED(dv
->m_widget
))
1953 wxDataViewEvent
event( wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED
, dv
->GetId() );
1955 event
.SetModel( dv
->GetModel() );
1956 dv
->GetEventHandler()->ProcessEvent( event
);
1960 wxdataview_row_activated_callback( GtkTreeView
* treeview
, GtkTreePath
*path
,
1961 GtkTreeViewColumn
*column
, wxDataViewCtrl
*dv
)
1963 wxDataViewEvent
event( wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
, dv
->GetId() );
1965 event
.SetModel( dv
->GetModel() );
1966 dv
->GetEventHandler()->ProcessEvent( event
);
1969 //-----------------------------------------------------------------------------
1971 //-----------------------------------------------------------------------------
1973 //-----------------------------------------------------------------------------
1974 // InsertChild for wxDataViewCtrl
1975 //-----------------------------------------------------------------------------
1977 static void wxInsertChildInDataViewCtrl( wxWindowGTK
* parent
, wxWindowGTK
* child
)
1979 wxDataViewCtrl
* dvc
= (wxDataViewCtrl
*) parent
;
1980 GtkWidget
*treeview
= dvc
->GtkGetTreeView();
1982 // Insert widget in GtkTreeView
1983 if (GTK_WIDGET_REALIZED(treeview
))
1984 gtk_widget_set_parent_window( child
->m_widget
,
1985 gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview
) ) );
1986 gtk_widget_set_parent( child
->m_widget
, treeview
);
1990 void gtk_dataviewctrl_size_callback( GtkWidget
*WXUNUSED(widget
),
1991 GtkAllocation
*alloc
,
1992 wxDataViewCtrl
*win
)
1995 wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
1998 wxWindow
*child
= node
->GetData();
2001 gtk_widget_size_request( child
->m_widget
, &req
);
2003 GtkAllocation alloc
;
2004 alloc
.x
= child
->m_x
;
2005 alloc
.y
= child
->m_y
;
2006 alloc
.width
= child
->m_width
;
2007 alloc
.height
= child
->m_height
;
2008 gtk_widget_size_allocate( child
->m_widget
, &alloc
);
2010 node
= node
->GetNext();
2016 IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl
, wxDataViewCtrlBase
)
2018 wxDataViewCtrl::~wxDataViewCtrl()
2021 GetModel()->RemoveNotifier( m_notifier
);
2023 // remove the model from the GtkTreeView before it gets destroyed by the
2024 // wxDataViewCtrlBase's dtor
2025 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview
), NULL
);
2028 void wxDataViewCtrl::Init()
2033 bool wxDataViewCtrl::Create(wxWindow
*parent
, wxWindowID id
,
2034 const wxPoint
& pos
, const wxSize
& size
,
2035 long style
, const wxValidator
& validator
)
2039 if (!PreCreation( parent
, pos
, size
) ||
2040 !CreateBase( parent
, id
, pos
, size
, style
, validator
))
2042 wxFAIL_MSG( wxT("wxDataViewCtrl creation failed") );
2046 m_insertCallback
= wxInsertChildInDataViewCtrl
;
2048 m_widget
= gtk_scrolled_window_new (NULL
, NULL
);
2050 GtkScrolledWindowSetBorder(m_widget
, style
);
2052 m_treeview
= gtk_tree_view_new();
2053 gtk_container_add (GTK_CONTAINER (m_widget
), m_treeview
);
2055 g_signal_connect (m_treeview
, "size_allocate",
2056 G_CALLBACK (gtk_dataviewctrl_size_callback
), this);
2059 if (!gtk_check_version(2,6,0))
2060 gtk_tree_view_set_fixed_height_mode( GTK_TREE_VIEW(m_treeview
), TRUE
);
2063 if (style
& wxDV_MULTIPLE
)
2065 GtkTreeSelection
*selection
= gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview
) );
2066 gtk_tree_selection_set_mode( selection
, GTK_SELECTION_MULTIPLE
);
2069 gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(m_treeview
), (style
& wxDV_NO_HEADER
) == 0 );
2072 if (!gtk_check_version(2,10,0))
2074 GtkTreeViewGridLines grid
= GTK_TREE_VIEW_GRID_LINES_NONE
;
2076 if ((style
& wxDV_HORIZ_RULES
) != 0 &&
2077 (style
& wxDV_VERT_RULES
) != 0)
2078 grid
= GTK_TREE_VIEW_GRID_LINES_BOTH
;
2079 else if (style
& wxDV_VERT_RULES
)
2080 grid
= GTK_TREE_VIEW_GRID_LINES_VERTICAL
;
2081 else if (style
& wxDV_HORIZ_RULES
)
2082 grid
= GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
;
2084 gtk_tree_view_set_grid_lines( GTK_TREE_VIEW(m_treeview
), grid
);
2089 gtk_tree_view_set_rules_hint( GTK_TREE_VIEW(m_treeview
), (style
& wxDV_HORIZ_RULES
) != 0 );
2092 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (m_widget
),
2093 GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
2094 gtk_widget_show (m_treeview
);
2096 m_parent
->DoAddChild( this );
2100 GtkEnableSelectionEvents();
2102 g_signal_connect_after (m_treeview
, "row_activated",
2103 G_CALLBACK (wxdataview_row_activated_callback
), this);
2108 void wxDataViewCtrl::OnInternalIdle()
2110 wxWindow::OnInternalIdle();
2112 unsigned int cols
= GetColumnCount();
2114 for (i
= 0; i
< cols
; i
++)
2116 wxDataViewColumn
*col
= GetColumn( i
);
2117 col
->OnInternalIdle();
2121 bool wxDataViewCtrl::AssociateModel( wxDataViewModel
*model
)
2123 if (!wxDataViewCtrlBase::AssociateModel( model
))
2126 GtkWxTreeModel
*gtk_store
= wxgtk_tree_model_new();
2127 gtk_store
->model
= model
;
2129 m_notifier
= new wxGtkDataViewModelNotifier( gtk_store
, model
, this );
2131 model
->AddNotifier( m_notifier
);
2133 gtk_tree_view_set_model( GTK_TREE_VIEW(m_treeview
), GTK_TREE_MODEL(gtk_store
) );
2134 g_object_unref( gtk_store
);
2139 bool wxDataViewCtrl::AppendColumn( wxDataViewColumn
*col
)
2141 if (!wxDataViewCtrlBase::AppendColumn(col
))
2144 GtkTreeViewColumn
*column
= (GtkTreeViewColumn
*)col
->GetGtkHandle();
2146 gtk_tree_view_append_column( GTK_TREE_VIEW(m_treeview
), column
);
2151 void wxDataViewCtrl::GtkDisableSelectionEvents()
2153 GtkTreeSelection
*selection
= gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview
) );
2154 g_signal_connect_after (selection
, "changed",
2155 G_CALLBACK (wxdataview_selection_changed_callback
), this);
2158 void wxDataViewCtrl::GtkEnableSelectionEvents()
2160 GtkTreeSelection
*selection
= gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview
) );
2161 g_signal_handlers_disconnect_by_func( selection
,
2162 (gpointer
) (wxdataview_selection_changed_callback
), this);
2167 wxDataViewCtrl::GetClassDefaultAttributes(wxWindowVariant
WXUNUSED(variant
))
2169 return GetDefaultAttributesFromGTKWidget(gtk_tree_view_new
);
2174 // !wxUSE_GENERICDATAVIEWCTRL
2177 // wxUSE_DATAVIEWCTRL