+
+ wxVariant value = tmp;
+ if (!cell->Validate( value ))
+ return;
+
+ wxDataViewModel *model = cell->GetOwner()->GetOwner()->GetModel();
+
+ GtkTreePath *gtk_path = gtk_tree_path_new_from_string( path );
+ GtkTreeIter iter;
+ cell->GetOwner()->GetOwner()->GtkGetInternal()->get_iter( &iter, gtk_path );
+ wxDataViewItem item( (void*) iter.user_data );;
+ gtk_tree_path_free( gtk_path );
+
+ unsigned int model_col = cell->GetOwner()->GetModelColumn();
+
+ model->SetValue( value, item, model_col );
+ model->ValueChanged( item, model_col );
+}
+
+IMPLEMENT_CLASS(wxDataViewToggleRenderer, wxDataViewRenderer)
+
+wxDataViewToggleRenderer::wxDataViewToggleRenderer( const wxString &varianttype,
+ wxDataViewCellMode mode, int align ) :
+ wxDataViewRenderer( varianttype, mode, align )
+{
+ m_renderer = (GtkCellRenderer*) gtk_cell_renderer_toggle_new();
+
+ if (mode & wxDATAVIEW_CELL_ACTIVATABLE)
+ {
+ g_signal_connect_after( m_renderer, "toggled",
+ G_CALLBACK(wxGtkToggleRendererToggledCallback), this );
+ }
+ else
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, false );
+ g_object_set_property( G_OBJECT(m_renderer), "activatable", &gvalue );
+ g_value_unset( &gvalue );
+ }
+
+ SetMode(mode);
+ SetAlignment(align);
+}
+
+bool wxDataViewToggleRenderer::SetValue( const wxVariant &value )
+{
+ bool tmp = value;
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, tmp );
+ g_object_set_property( G_OBJECT(m_renderer), "active", &gvalue );
+ g_value_unset( &gvalue );
+
+ return true;
+}
+
+bool wxDataViewToggleRenderer::GetValue( wxVariant &value ) const
+{
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_object_get_property( G_OBJECT(m_renderer), "active", &gvalue );
+ bool tmp = g_value_get_boolean( &gvalue );
+ g_value_unset( &gvalue );
+
+ value = tmp;
+
+ return true;
+}
+
+// ---------------------------------------------------------
+// wxDataViewCustomRenderer
+// ---------------------------------------------------------
+
+class wxDataViewCtrlDCImpl: public wxWindowDCImpl
+{
+public:
+ wxDataViewCtrlDCImpl( wxDC *owner, wxDataViewCtrl *window ) :
+ wxWindowDCImpl( owner )
+ {
+ GtkWidget *widget = window->m_treeview;
+ // Set later
+ m_gdkwindow = NULL;
+
+ m_window = window;
+
+ m_context = window->GTKGetPangoDefaultContext();
+ m_layout = pango_layout_new( m_context );
+ m_fontdesc = pango_font_description_copy( widget->style->font_desc );
+
+ m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
+
+ // Set m_gdkwindow later
+ // SetUpDC();
+ }
+};
+
+class wxDataViewCtrlDC: public wxWindowDC
+{
+public:
+ wxDataViewCtrlDC( wxDataViewCtrl *window ) :
+ wxWindowDC( new wxDataViewCtrlDCImpl( this, window ) )
+ { }
+};
+
+
+// ---------------------------------------------------------
+// wxDataViewCustomRenderer
+// ---------------------------------------------------------
+
+IMPLEMENT_CLASS(wxDataViewCustomRenderer, wxDataViewRenderer)
+
+wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype,
+ wxDataViewCellMode mode, int align,
+ bool no_init ) :
+ wxDataViewRenderer( varianttype, mode, align )
+{
+ m_dc = NULL;
+ m_text_renderer = NULL;
+
+ if (no_init)
+ m_renderer = NULL;
+ else
+ Init(mode, align);
+}
+
+void wxDataViewCustomRenderer::RenderText( const wxString &text, int xoffset,
+ wxRect WXUNUSED(cell), wxDC *WXUNUSED(dc), int WXUNUSED(state) )
+{
+#if 0
+ wxDataViewCtrl *view = GetOwner()->GetOwner();
+ wxColour col = (state & wxDATAVIEW_CELL_SELECTED) ?
+ wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT) :
+ view->GetForegroundColour();
+ dc->SetTextForeground(col);
+ dc->DrawText( text, cell.x + xoffset, cell.y + ((cell.height - dc->GetCharHeight()) / 2));
+#else
+ if (!m_text_renderer)
+ m_text_renderer = gtk_cell_renderer_text_new();
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_STRING );
+ g_value_set_string( &gvalue, wxGTK_CONV_FONT( text, GetOwner()->GetOwner()->GetFont() ) );
+ g_object_set_property( G_OBJECT(m_text_renderer), "text", &gvalue );
+ g_value_unset( &gvalue );
+
+ ((GdkRectangle*) cell_area)->x += xoffset;
+ ((GdkRectangle*) cell_area)->width -= xoffset;
+
+ gtk_cell_renderer_render( m_text_renderer,
+ window,
+ widget,
+ (GdkRectangle*) background_area,
+ (GdkRectangle*) cell_area,
+ (GdkRectangle*) expose_area,
+ (GtkCellRendererState) flags );
+
+ ((GdkRectangle*) cell_area)->x -= xoffset;
+ ((GdkRectangle*) cell_area)->width += xoffset;
+#endif
+}
+
+bool wxDataViewCustomRenderer::Init(wxDataViewCellMode mode, int align)
+{
+ GtkWxCellRenderer *renderer = (GtkWxCellRenderer *) gtk_wx_cell_renderer_new();
+ renderer->cell = this;
+
+ m_renderer = (GtkCellRenderer*) renderer;
+
+ SetMode(mode);
+ SetAlignment(align);
+
+ GtkInitHandlers();
+
+ return true;
+}
+
+wxDataViewCustomRenderer::~wxDataViewCustomRenderer()
+{
+ if (m_dc)
+ delete m_dc;
+
+ if (m_text_renderer)
+ gtk_object_sink( GTK_OBJECT(m_text_renderer) );
+}
+
+wxDC *wxDataViewCustomRenderer::GetDC()
+{
+ if (m_dc == NULL)
+ {
+ if (GetOwner() == NULL)
+ return NULL;
+ if (GetOwner()->GetOwner() == NULL)
+ return NULL;
+ m_dc = new wxDataViewCtrlDC( GetOwner()->GetOwner() );
+ }
+
+ return m_dc;
+}
+
+// ---------------------------------------------------------
+// wxDataViewProgressRenderer
+// ---------------------------------------------------------
+
+IMPLEMENT_CLASS(wxDataViewProgressRenderer, wxDataViewCustomRenderer)
+
+wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label,
+ const wxString &varianttype, wxDataViewCellMode mode, int align ) :
+ wxDataViewCustomRenderer( varianttype, mode, align, true )
+{
+ m_label = label;
+ m_value = 0;
+
+#ifdef __WXGTK26__
+ if (!gtk_check_version(2,6,0))
+ {
+ m_renderer = (GtkCellRenderer*) gtk_cell_renderer_progress_new();
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_STRING );
+
+ g_value_set_string( &gvalue, wxGTK_CONV_FONT( m_label, GetOwner()->GetOwner()->GetFont() ) );
+ g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
+ g_value_unset( &gvalue );
+
+ SetMode(mode);
+ SetAlignment(align);
+ }
+ else
+#endif
+ {
+ // Use custom cell code
+ wxDataViewCustomRenderer::Init(mode, align);
+ }
+}
+
+wxDataViewProgressRenderer::~wxDataViewProgressRenderer()
+{
+}
+
+bool wxDataViewProgressRenderer::SetValue( const wxVariant &value )
+{
+#ifdef __WXGTK26__
+ if (!gtk_check_version(2,6,0))
+ {
+ gint tmp = (long) value;
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_INT );
+ g_value_set_int( &gvalue, tmp );
+ g_object_set_property( G_OBJECT(m_renderer), "value", &gvalue );
+ g_value_unset( &gvalue );
+ }
+ else
+#endif
+ {
+ m_value = (long) value;
+
+ if (m_value < 0) m_value = 0;
+ if (m_value > 100) m_value = 100;
+ }
+
+ return true;
+}
+
+bool wxDataViewProgressRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
+{
+ return false;
+}
+
+bool wxDataViewProgressRenderer::Render( wxRect cell, wxDC *dc, int WXUNUSED(state) )
+{
+ double pct = (double)m_value / 100.0;
+ wxRect bar = cell;
+ bar.width = (int)(cell.width * pct);
+ dc->SetPen( *wxTRANSPARENT_PEN );
+ dc->SetBrush( *wxBLUE_BRUSH );
+ dc->DrawRectangle( bar );
+
+ dc->SetBrush( *wxTRANSPARENT_BRUSH );
+ dc->SetPen( *wxBLACK_PEN );
+ dc->DrawRectangle( cell );
+
+ return true;
+}
+
+wxSize wxDataViewProgressRenderer::GetSize() const
+{
+ return wxSize(40,12);
+}
+
+// -------------------------------------
+// wxDataViewChoiceRenderer
+// -------------------------------------
+
+wxDataViewChoiceRenderer::wxDataViewChoiceRenderer( const wxArrayString &choices,
+ wxDataViewCellMode mode, int alignment ) :
+ wxDataViewCustomRenderer( "string", mode, alignment, true )
+{
+ m_choices = choices;
+
+#ifdef __WXGTK26__
+ if (!gtk_check_version(2,6,0))
+ {
+ m_renderer = (GtkCellRenderer*) gtk_cell_renderer_combo_new();
+
+ GtkListStore *store = gtk_list_store_new( 1, G_TYPE_STRING );
+ for (size_t n = 0; n < m_choices.GetCount(); n++)
+ {
+ gtk_list_store_insert_with_values(
+ store, NULL, n, 0,
+ static_cast<const char *>(m_choices[n].utf8_str()), -1 );
+ }
+
+ g_object_set (m_renderer,
+ "model", store,
+ "text-column", 0,
+ "has-entry", FALSE,
+ NULL);
+
+ bool editable = (mode & wxDATAVIEW_CELL_EDITABLE);
+ g_object_set (m_renderer, "editable", editable, NULL);
+
+ SetAlignment(alignment);
+
+ g_signal_connect_after( m_renderer, "edited", G_CALLBACK(wxGtkTextRendererEditedCallback), this );
+
+ GtkInitHandlers();
+ }
+ else
+#endif
+ {
+ // Use custom cell code
+ wxDataViewCustomRenderer::Init(mode, alignment);
+ }
+}
+
+bool wxDataViewChoiceRenderer::Render( wxRect rect, wxDC *dc, int state )
+{
+ RenderText( m_data, 0, rect, dc, state );
+ return true;
+}
+
+wxSize wxDataViewChoiceRenderer::GetSize() const
+{
+ return wxSize(70,20);
+}
+
+bool wxDataViewChoiceRenderer::SetValue( const wxVariant &value )
+{
+
+#ifdef __WXGTK26__
+ if (!gtk_check_version(2,6,0))
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_STRING );
+ g_value_set_string( &gvalue, wxGTK_CONV_FONT( value.GetString(), GetOwner()->GetOwner()->GetFont() ) );
+ g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue );
+ g_value_unset( &gvalue );
+ }
+ else
+#endif
+ m_data = value.GetString();
+
+ return true;
+}
+
+bool wxDataViewChoiceRenderer::GetValue( wxVariant &value ) const
+{
+#ifdef __WXGTK26__
+ if (!gtk_check_version(2,6,0))
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_STRING );
+ g_object_get_property( G_OBJECT(m_renderer), "text", &gvalue );
+ wxString temp = wxGTK_CONV_BACK_FONT( g_value_get_string( &gvalue ),
+ const_cast<wxDataViewChoiceRenderer*>(this)->GetOwner()->GetOwner()->GetFont() );
+ g_value_unset( &gvalue );
+ value = temp;
+
+ //wxPrintf( "temp %s\n", temp );
+ // TODO: remove this code
+ }
+ else
+#endif
+ value = m_data;
+
+ return true;
+}
+
+void wxDataViewChoiceRenderer::SetAlignment( int align )
+{
+ wxDataViewCustomRenderer::SetAlignment(align);
+
+ if (gtk_check_version(2,10,0))
+ return;
+
+ // horizontal alignment:
+ PangoAlignment pangoAlign = PANGO_ALIGN_LEFT;
+ if (align & wxALIGN_RIGHT)
+ pangoAlign = PANGO_ALIGN_RIGHT;
+ else if (align & wxALIGN_CENTER_HORIZONTAL)
+ pangoAlign = PANGO_ALIGN_CENTER;
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, gtk_cell_renderer_mode_get_type() );
+ g_value_set_enum( &gvalue, pangoAlign );
+ g_object_set_property( G_OBJECT(m_renderer), "alignment", &gvalue );
+ g_value_unset( &gvalue );
+}
+
+// ---------------------------------------------------------
+// wxDataViewDateRenderer
+// ---------------------------------------------------------
+
+class wxDataViewDateRendererPopupTransient: public wxPopupTransientWindow
+{
+public:
+ wxDataViewDateRendererPopupTransient( wxWindow* parent, wxDateTime *value,
+ wxDataViewModel *model, const wxDataViewItem &item, unsigned int col ) :
+ wxPopupTransientWindow( parent, wxBORDER_SIMPLE )
+ {
+ m_model = model;
+ m_item = item;
+ m_col = col;
+ m_cal = new wxCalendarCtrl( this, -1, *value );
+ wxBoxSizer *sizer = new wxBoxSizer( wxHORIZONTAL );
+ sizer->Add( m_cal, 1, wxGROW );
+ SetSizer( sizer );
+ sizer->Fit( this );
+ }
+
+ virtual void OnDismiss()
+ {
+ }
+
+ void OnCalendar( wxCalendarEvent &event );
+
+ wxCalendarCtrl *m_cal;
+ wxDataViewModel *m_model;
+ wxDataViewItem m_item;
+ unsigned int m_col;
+
+private:
+ DECLARE_EVENT_TABLE()
+};
+
+BEGIN_EVENT_TABLE(wxDataViewDateRendererPopupTransient,wxPopupTransientWindow)
+ EVT_CALENDAR( -1, wxDataViewDateRendererPopupTransient::OnCalendar )
+END_EVENT_TABLE()
+
+void wxDataViewDateRendererPopupTransient::OnCalendar( wxCalendarEvent &event )
+{
+ wxDateTime date = event.GetDate();
+ wxVariant value = date;
+ m_model->SetValue( value, m_item, m_col );
+ m_model->ValueChanged( m_item, m_col );
+ DismissAndNotify();
+}
+
+IMPLEMENT_CLASS(wxDataViewDateRenderer, wxDataViewCustomRenderer)
+
+wxDataViewDateRenderer::wxDataViewDateRenderer( const wxString &varianttype,
+ wxDataViewCellMode mode, int align ) :
+ wxDataViewCustomRenderer( varianttype, mode, align )
+{
+ SetMode(mode);
+ SetAlignment(align);
+}
+
+bool wxDataViewDateRenderer::SetValue( const wxVariant &value )
+{
+ m_date = value.GetDateTime();
+
+ return true;
+}
+
+bool wxDataViewDateRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
+{
+ return false;
+}
+
+bool wxDataViewDateRenderer::Render( wxRect cell, wxDC *dc, int state )
+{
+ dc->SetFont( GetOwner()->GetOwner()->GetFont() );
+ wxString tmp = m_date.FormatDate();
+ RenderText( tmp, 0, cell, dc, state );
+ return true;
+}
+
+wxSize wxDataViewDateRenderer::GetSize() const
+{
+ wxString tmp = m_date.FormatDate();
+ wxCoord x,y,d;
+ GetView()->GetTextExtent( tmp, &x, &y, &d );
+ return wxSize(x,y+d);
+}
+
+bool wxDataViewDateRenderer::Activate( wxRect WXUNUSED(cell), wxDataViewModel *model,
+ const wxDataViewItem &item, unsigned int col )
+{
+ wxVariant variant;
+ model->GetValue( variant, item, col );
+ wxDateTime value = variant.GetDateTime();
+
+ wxDataViewDateRendererPopupTransient *popup = new wxDataViewDateRendererPopupTransient(
+ GetOwner()->GetOwner()->GetParent(), &value, model, item, col );
+ wxPoint pos = wxGetMousePosition();
+ popup->Move( pos );
+ popup->Layout();
+ popup->Popup( popup->m_cal );
+
+ return true;
+}
+
+
+// ---------------------------------------------------------
+// wxDataViewIconTextRenderer
+// ---------------------------------------------------------
+
+IMPLEMENT_CLASS(wxDataViewIconTextRenderer, wxDataViewCustomRenderer)
+
+wxDataViewIconTextRenderer::wxDataViewIconTextRenderer(
+ const wxString &varianttype, wxDataViewCellMode mode, int align ) :
+ wxDataViewCustomRenderer( varianttype, mode, align )
+{
+ SetMode(mode);
+ SetAlignment(align);
+}
+
+wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer()
+{
+}
+
+bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value )
+{
+ m_value << value;
+ return true;
+}
+
+bool wxDataViewIconTextRenderer::GetValue( wxVariant &WXUNUSED(value) ) const
+{
+ return false;
+}
+
+bool wxDataViewIconTextRenderer::Render( wxRect cell, wxDC *dc, int state )
+{
+ const wxIcon &icon = m_value.GetIcon();
+ int offset = 0;
+ if (icon.IsOk())
+ {
+ int yoffset = wxMax( 0, (cell.height - icon.GetHeight()) / 2 );
+ dc->DrawIcon( icon, cell.x, cell.y + yoffset );
+ offset = icon.GetWidth() + 4;
+ }
+
+ RenderText( m_value.GetText(), offset, cell, dc, state );
+
+ return true;
+}
+
+wxSize wxDataViewIconTextRenderer::GetSize() const
+{
+ wxSize size;
+ if (m_value.GetIcon().IsOk())
+ size.x = 4 + m_value.GetIcon().GetWidth();
+ wxCoord x,y,d;
+ GetView()->GetTextExtent( m_value.GetText(), &x, &y, &d );
+ size.x += x;
+ size.y = y+d;
+ return size;
+}
+
+wxControl* wxDataViewIconTextRenderer::CreateEditorCtrl(
+ wxWindow *WXUNUSED(parent), wxRect WXUNUSED(labelRect), const wxVariant &WXUNUSED(value) )
+{
+ return NULL;
+}
+
+bool wxDataViewIconTextRenderer::GetValueFromEditorCtrl(
+ wxControl* WXUNUSED(editor), wxVariant &WXUNUSED(value) )
+{
+ return false;
+}
+
+// ---------------------------------------------------------
+// wxDataViewColumn
+// ---------------------------------------------------------
+
+
+static gboolean
+gtk_dataview_header_button_press_callback( GtkWidget *WXUNUSED(widget),
+ GdkEventButton *gdk_event,
+ wxDataViewColumn *column )
+{
+ if (gdk_event->type != GDK_BUTTON_PRESS)
+ return FALSE;
+
+ if (gdk_event->button == 1)
+ {
+ gs_lastLeftClickHeader = column;
+
+ wxDataViewCtrl *dv = column->GetOwner();
+ wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, dv->GetId() );
+ event.SetDataViewColumn( column );
+ event.SetModel( dv->GetModel() );
+ if (dv->HandleWindowEvent( event ))
+ return FALSE;
+ }
+
+ if (gdk_event->button == 3)
+ {
+ wxDataViewCtrl *dv = column->GetOwner();
+ wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, dv->GetId() );
+ event.SetDataViewColumn( column );
+ event.SetModel( dv->GetModel() );
+ if (dv->HandleWindowEvent( event ))
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+extern "C" {
+static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data );
+}
+
+
+static void wxGtkTreeCellDataFunc( GtkTreeViewColumn *WXUNUSED(column),
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data )
+{
+ g_return_if_fail (GTK_IS_WX_TREE_MODEL (model));
+ GtkWxTreeModel *tree_model = (GtkWxTreeModel *) model;
+
+ wxDataViewRenderer *cell = (wxDataViewRenderer*) data;
+
+ wxDataViewItem item( (void*) iter->user_data );
+
+ wxDataViewModel *wx_model = tree_model->internal->GetDataViewModel();
+
+ if (!wx_model->IsVirtualListModel())
+ {
+
+ if (wx_model->IsContainer( item ))
+ {
+ if (wx_model->HasContainerColumns( item ) || (cell->GetOwner()->GetModelColumn() == 0))
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, TRUE );
+ g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
+ g_value_unset( &gvalue );
+ }
+ else
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, FALSE );
+ g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
+ g_value_unset( &gvalue );
+
+ return;
+ }
+ }
+ else
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, TRUE );
+ g_object_set_property( G_OBJECT(renderer), "visible", &gvalue );
+ g_value_unset( &gvalue );
+ }
+
+ }
+
+ wxVariant value;
+ wx_model->GetValue( value, item, cell->GetOwner()->GetModelColumn() );
+
+ if (value.GetType() != cell->GetVariantType())
+ wxLogError( wxT("Wrong type, required: %s but: %s"),
+ value.GetType().c_str(),
+ cell->GetVariantType().c_str() );
+
+ cell->SetValue( value );
+
+ if (cell->GtkHasAttributes())
+ {
+ wxDataViewItemAttr attr;
+ bool colour_set = false;
+ bool style_set = false;
+ bool weight_set = false;
+
+ if (wx_model->GetAttr( item, cell->GetOwner()->GetModelColumn(), attr ))
+ {
+ // this must be a GtkCellRendererText
+ wxColour colour = attr.GetColour();
+ if (colour.IsOk())
+ {
+ const GdkColor * const gcol = colour.GetColor();
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, GDK_TYPE_COLOR );
+ g_value_set_boxed( &gvalue, gcol );
+ g_object_set_property( G_OBJECT(renderer), "foreground_gdk", &gvalue );
+ g_value_unset( &gvalue );
+
+ colour_set = true;
+ }
+
+ if (attr.GetItalic())
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, PANGO_TYPE_STYLE );
+ g_value_set_enum( &gvalue, PANGO_STYLE_ITALIC );
+ g_object_set_property( G_OBJECT(renderer), "style", &gvalue );
+ g_value_unset( &gvalue );
+
+ style_set = true;
+ }
+
+ if (attr.GetBold())
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, PANGO_TYPE_WEIGHT );
+ g_value_set_enum( &gvalue, PANGO_WEIGHT_BOLD );
+ g_object_set_property( G_OBJECT(renderer), "weight", &gvalue );
+ g_value_unset( &gvalue );
+
+ weight_set = true;
+ }
+ }
+
+ if (!style_set)
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, FALSE );
+ g_object_set_property( G_OBJECT(renderer), "style-set", &gvalue );
+ g_value_unset( &gvalue );
+ }
+
+ if (!weight_set)
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, FALSE );
+ g_object_set_property( G_OBJECT(renderer), "weight-set", &gvalue );
+ g_value_unset( &gvalue );
+ }
+
+ if (!colour_set)
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, FALSE );
+ g_object_set_property( G_OBJECT(renderer), "foreground-set", &gvalue );
+ g_value_unset( &gvalue );
+ }
+ }
+
+#if 0
+ if (attr.HasBackgroundColour())
+ {
+ wxColour colour = attr.GetBackgroundColour();
+ const GdkColor * const gcol = colour.GetColor();
+
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, GDK_TYPE_COLOR );
+ g_value_set_boxed( &gvalue, gcol );
+ g_object_set_property( G_OBJECT(renderer), "cell-background_gdk", &gvalue );
+ g_value_unset( &gvalue );
+ }
+ else
+ {
+ GValue gvalue = { 0, };
+ g_value_init( &gvalue, G_TYPE_BOOLEAN );
+ g_value_set_boolean( &gvalue, FALSE );
+ g_object_set_property( G_OBJECT(renderer), "cell-background-set", &gvalue );
+ g_value_unset( &gvalue );
+ }
+#endif
+
+}
+
+#include <wx/listimpl.cpp>
+WX_DEFINE_LIST(wxDataViewColumnList)
+
+wxDataViewColumn::wxDataViewColumn( const wxString &title, wxDataViewRenderer *cell,
+ unsigned int model_column, int width,
+ wxAlignment align, int flags )
+ : wxDataViewColumnBase( cell, model_column )
+{
+ Init( align, flags, width );
+
+ SetTitle( title );
+}
+
+wxDataViewColumn::wxDataViewColumn( const wxBitmap &bitmap, wxDataViewRenderer *cell,
+ unsigned int model_column, int width,
+ wxAlignment align, int flags )
+ : wxDataViewColumnBase( bitmap, cell, model_column )
+{
+ Init( align, flags, width );
+
+ SetBitmap( bitmap );
+}
+
+void wxDataViewColumn::Init(wxAlignment align, int flags, int width)
+{
+ m_isConnected = false;
+
+ GtkCellRenderer *renderer = (GtkCellRenderer *) GetRenderer()->GetGtkHandle();
+ GtkTreeViewColumn *column = gtk_tree_view_column_new();
+ m_column = (GtkWidget*) column;
+
+ SetFlags( flags );
+ SetAlignment( align );
+
+ SetWidth( width );
+
+ // Create container for icon and label
+ GtkWidget *box = gtk_hbox_new( FALSE, 1 );
+ gtk_widget_show( box );
+ // gtk_container_set_border_width((GtkContainer*)box, 2);
+ m_image = gtk_image_new();
+ gtk_box_pack_start(GTK_BOX(box), m_image, FALSE, FALSE, 1);
+ m_label = gtk_label_new("");
+ gtk_box_pack_end( GTK_BOX(box), GTK_WIDGET(m_label), FALSE, FALSE, 1 );
+ gtk_tree_view_column_set_widget( column, box );
+
+ gtk_tree_view_column_pack_end( column, renderer, TRUE );
+
+ gtk_tree_view_column_set_cell_data_func( column, renderer,
+ wxGtkTreeCellDataFunc, (gpointer) GetRenderer(), NULL );
+}
+
+void wxDataViewColumn::OnInternalIdle()
+{
+ if (m_isConnected)
+ return;
+
+ if (GTK_WIDGET_REALIZED(GetOwner()->m_treeview))
+ {
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+ if (column->button)
+ {
+ g_signal_connect(column->button, "button_press_event",
+ G_CALLBACK (gtk_dataview_header_button_press_callback), this);
+
+ m_isConnected = true;
+ }
+ }
+}
+
+void wxDataViewColumn::SetOwner( wxDataViewCtrl *owner )
+{
+ wxDataViewColumnBase::SetOwner( owner );
+
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+
+ gtk_tree_view_column_set_title( column, wxGTK_CONV_FONT(GetTitle(), GetOwner()->GetFont() ) );
+}
+
+void wxDataViewColumn::SetTitle( const wxString &title )
+{
+ wxDataViewCtrl *ctrl = GetOwner();
+ gtk_label_set_text( GTK_LABEL(m_label), ctrl ? wxGTK_CONV_FONT(title, ctrl->GetFont())
+ : wxGTK_CONV_SYS(title) );
+ if (title.empty())
+ gtk_widget_hide( m_label );
+ else
+ gtk_widget_show( m_label );
+}
+
+wxString wxDataViewColumn::GetTitle() const
+{
+ return wxGTK_CONV_BACK_FONT(
+ gtk_label_get_text( GTK_LABEL(m_label) ),
+ GetOwner()->GetFont()
+ );
+}
+
+void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap )
+{
+ wxDataViewColumnBase::SetBitmap( bitmap );
+
+ if (bitmap.Ok())
+ {
+ GtkImage *gtk_image = GTK_IMAGE(m_image);
+
+ GdkBitmap *mask = NULL;
+ if (bitmap.GetMask())
+ mask = bitmap.GetMask()->GetBitmap();
+
+ if (bitmap.HasPixbuf())
+ {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(gtk_image),
+ bitmap.GetPixbuf());
+ }
+ else
+ {
+ gtk_image_set_from_pixmap(GTK_IMAGE(gtk_image),
+ bitmap.GetPixmap(), mask);
+ }
+ gtk_widget_show( m_image );
+ }
+ else
+ {
+ gtk_widget_hide( m_image );
+ }
+}
+
+void wxDataViewColumn::SetHidden( bool hidden )
+{
+ gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden );
+}
+
+void wxDataViewColumn::SetResizeable( bool resizeable )
+{
+ gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable );
+}
+
+void wxDataViewColumn::SetAlignment( wxAlignment align )
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+
+ gfloat xalign = 0.0;
+ if (align == wxALIGN_RIGHT)
+ xalign = 1.0;
+ if (align == wxALIGN_CENTER_HORIZONTAL ||
+ align == wxALIGN_CENTER)
+ xalign = 0.5;
+
+ gtk_tree_view_column_set_alignment( column, xalign );
+
+ if (m_renderer && m_renderer->GetAlignment() == -1)
+ m_renderer->GtkUpdateAlignment();
+}
+
+wxAlignment wxDataViewColumn::GetAlignment() const
+{
+ gfloat xalign = gtk_tree_view_column_get_alignment( GTK_TREE_VIEW_COLUMN(m_column) );
+
+ if (xalign == 1.0)
+ return wxALIGN_RIGHT;
+ if (xalign == 0.5)
+ return wxALIGN_CENTER_HORIZONTAL;
+
+ return wxALIGN_LEFT;
+}
+
+void wxDataViewColumn::SetSortable( bool sortable )
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+
+ if ( sortable )
+ {
+ gtk_tree_view_column_set_sort_column_id( column, GetModelColumn() );
+ }
+ else
+ {
+ gtk_tree_view_column_set_sort_column_id( column, -1 );
+ gtk_tree_view_column_set_sort_indicator( column, FALSE );
+ gtk_tree_view_column_set_clickable( column, FALSE );
+ }
+}
+
+bool wxDataViewColumn::IsSortable() const
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+ return gtk_tree_view_column_get_clickable( column );
+}
+
+void wxDataViewColumn::SetAsSortKey( bool WXUNUSED(sort) )
+{
+ // it might not make sense to have this function in wxHeaderColumn at
+ // all in fact, changing of the sort order should only be done using the
+ // associated control API
+ wxFAIL_MSG( "not implemented" );
+}
+
+bool wxDataViewColumn::IsSortKey() const
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+ return gtk_tree_view_column_get_sort_indicator( column );
+}
+
+bool wxDataViewColumn::IsResizeable() const
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+ return gtk_tree_view_column_get_resizable( column );
+}
+
+bool wxDataViewColumn::IsHidden() const
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+ return !gtk_tree_view_column_get_visible( column );
+}
+
+void wxDataViewColumn::SetSortOrder( bool ascending )
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+
+ if (ascending)
+ gtk_tree_view_column_set_sort_order( column, GTK_SORT_ASCENDING );
+ else
+ gtk_tree_view_column_set_sort_order( column, GTK_SORT_DESCENDING );
+
+ gtk_tree_view_column_set_sort_indicator( column, TRUE );
+}
+
+bool wxDataViewColumn::IsSortOrderAscending() const
+{
+ GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(m_column);
+
+ return (gtk_tree_view_column_get_sort_order( column ) != GTK_SORT_DESCENDING);
+}
+
+void wxDataViewColumn::SetMinWidth( int width )
+{
+ gtk_tree_view_column_set_min_width( GTK_TREE_VIEW_COLUMN(m_column), width );
+}
+
+int wxDataViewColumn::GetMinWidth() const
+{
+ return gtk_tree_view_column_get_min_width( GTK_TREE_VIEW_COLUMN(m_column) );
+}
+
+int wxDataViewColumn::GetWidth() const
+{
+ return gtk_tree_view_column_get_width( GTK_TREE_VIEW_COLUMN(m_column) );
+}
+
+void wxDataViewColumn::SetWidth( int width )
+{
+ if (width < 0)
+ {
+#if 1
+ gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
+
+ // TODO find a better calculation
+ gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), wxDVC_DEFAULT_WIDTH );
+#else
+ // this is unpractical for large numbers of items and disables
+ // user resizing, which is totally unexpected
+ gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_AUTOSIZE );
+#endif
+ }
+ else
+ {
+ gtk_tree_view_column_set_sizing( GTK_TREE_VIEW_COLUMN(m_column), GTK_TREE_VIEW_COLUMN_FIXED );
+
+ gtk_tree_view_column_set_fixed_width( GTK_TREE_VIEW_COLUMN(m_column), width );
+ }
+}
+
+void wxDataViewColumn::SetReorderable( bool reorderable )
+{
+ gtk_tree_view_column_set_reorderable( GTK_TREE_VIEW_COLUMN(m_column), reorderable );
+}
+
+bool wxDataViewColumn::IsReorderable() const
+{
+ return gtk_tree_view_column_get_reorderable( GTK_TREE_VIEW_COLUMN(m_column) );
+}
+
+//-----------------------------------------------------------------------------
+// wxGtkTreeModelNode
+//-----------------------------------------------------------------------------
+
+#if 0
+class wxGtkTreeModelChildWithPos
+{
+public:
+ unsigned int pos;
+ void *id;
+};
+
+static
+int wxGtkTreeModelChildWithPosCmp( const void* data1, const void* data2, const void* user_data )
+{
+ const wxGtkTreeModelChildWithPos* child1 = (const wxGtkTreeModelChildWithPos*) data1;
+ const wxGtkTreeModelChildWithPos* child2 = (const wxGtkTreeModelChildWithPos*) data2;
+ const wxDataViewCtrlInternal *internal = (const wxDataViewCtrlInternal *) user_data;
+ int ret = internal->GetDataViewModel()->Compare( child1->id, child2->id,
+ internal->GetSortColumn(), (internal->GetSortOrder() == GTK_SORT_DESCENDING) );
+
+ return ret;
+}
+#else
+static
+int LINKAGEMODE wxGtkTreeModelChildPtrCmp( void*** data1, void*** data2 )
+{
+ return gs_internal->GetDataViewModel()->Compare( **data1, **data2,
+ gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) );
+}
+
+WX_DEFINE_ARRAY_PTR( void**, wxGtkTreeModelChildrenPtr );
+#endif
+
+void wxGtkTreeModelNode::Resort()
+{
+ size_t child_count = GetChildCount();
+ if (child_count == 0)
+ return;
+
+ size_t node_count = GetNodesCount();
+
+ if (child_count == 1)
+ {
+ if (node_count == 1)
+ {
+ wxGtkTreeModelNode *node = m_nodes.Item( 0 );
+ node->Resort();
+ }
+ return;
+ }
+
+ gint *new_order = new gint[child_count];
+
+#if 1
+ // m_children has the original *void
+ // ptrs points to these
+ wxGtkTreeModelChildrenPtr ptrs;
+ size_t i;
+ for (i = 0; i < child_count; i++)
+ ptrs.Add( &(m_children[i]) );
+ // Sort the ptrs
+ gs_internal = m_internal;
+ ptrs.Sort( &wxGtkTreeModelChildPtrCmp );
+
+ wxGtkTreeModelChildren temp;
+ void** base_ptr = &(m_children[0]);
+ // Transfer positions to new_order array and
+ // IDs to temp
+ for (i = 0; i < child_count; i++)
+ {
+ new_order[i] = ptrs[i] - base_ptr;
+ temp.Add( *ptrs[i] );
+ }
+
+ // Transfer IDs back to m_children
+ m_children.Clear();
+ WX_APPEND_ARRAY( temp, m_children );
+#endif
+#if 0
+ // Too slow
+
+ // Build up array with IDs and original positions
+ wxGtkTreeModelChildWithPos* temp = new wxGtkTreeModelChildWithPos[child_count];
+ size_t i;
+ for (i = 0; i < child_count; i++)
+ {
+ temp[i].pos = i;
+ temp[i].id = m_children[i];
+ }
+ // Sort array keeping original positions
+ wxQsort( temp, child_count, sizeof(wxGtkTreeModelChildWithPos),
+ &wxGtkTreeModelChildWithPosCmp, m_internal );
+ // Transfer positions to new_order array and
+ // IDs to m_children
+ m_children.Clear();
+ for (i = 0; i < child_count; i++)
+ {
+ new_order[i] = temp[i].pos;
+ m_children.Add( temp[i].id );
+ }
+ // Delete array
+ delete [] temp;
+#endif
+
+#if 0
+ // Too slow