X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fc9ab22a7692aa822bb3d8e6326dfb73d12a600b..74a8f67d96591cec101def2a7d47c64072aff7fd:/src/gtk/dataview.cpp diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index dcb66b9c9c..ee2ea2b686 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -300,7 +300,7 @@ private: static int LINKAGEMODE wxGtkTreeModelChildCmp( void** id1, void** id2 ) { - int ret = gs_internal->GetDataViewModel()->Compare( *id1, *id2, + int ret = gs_internal->GetDataViewModel()->Compare( wxDataViewItem(*id1), wxDataViewItem(*id2), gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) ); return ret; @@ -493,11 +493,11 @@ static void wxgtk_tree_model_set_sort_func (GtkTreeSortable *s gint sort_column_id, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer data, - GtkDestroyNotify destroy); + GDestroyNotify destroy); static gboolean wxgtk_tree_model_has_default_sort_func (GtkTreeSortable *sortable); /* drag'n'drop */ @@ -966,7 +966,7 @@ wxgtk_tree_model_set_sort_func (GtkTreeSortable *sortable, gint WXUNUSED(sort_column_id), GtkTreeIterCompareFunc func, gpointer WXUNUSED(data), - GtkDestroyNotify WXUNUSED(destroy)) + GDestroyNotify WXUNUSED(destroy)) { g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); g_return_if_fail (func != NULL); @@ -976,7 +976,7 @@ static void wxgtk_tree_model_set_default_sort_func (GtkTreeSortable *sortable, GtkTreeIterCompareFunc func, gpointer WXUNUSED(data), - GtkDestroyNotify WXUNUSED(destroy)) + GDestroyNotify WXUNUSED(destroy)) { g_return_if_fail (GTK_IS_WX_TREE_MODEL (sortable) ); g_return_if_fail (func != NULL); @@ -1333,8 +1333,21 @@ gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer, wxSize size = cell->GetSize(); - gint calc_width = (gint) renderer->xpad * 2 + size.x; - gint calc_height = (gint) renderer->ypad * 2 + size.y; + wxDataViewCtrl * const ctrl = cell->GetOwner()->GetOwner(); + + // Uniform row height, if specified, overrides the value returned by the + // renderer. + if ( !ctrl->HasFlag(wxDV_VARIABLE_LINE_HEIGHT) ) + { + const int uniformHeight = ctrl->GTKGetUniformRowHeight(); + if ( uniformHeight > 0 ) + size.y = uniformHeight; + } + + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + int calc_width = xpad * 2 + size.x; + int calc_height = ypad * 2 + size.y; if (x_offset) *x_offset = 0; @@ -1343,17 +1356,17 @@ gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer, if (cell_area && size.x > 0 && size.y > 0) { + float xalign, yalign; + gtk_cell_renderer_get_alignment(renderer, &xalign, &yalign); if (x_offset) { - *x_offset = (gint)((renderer->xalign * - (cell_area->width - calc_width - 2 * renderer->xpad))); - *x_offset = MAX (*x_offset, 0) + renderer->xpad; + *x_offset = int(xalign * (cell_area->width - calc_width - 2 * xpad)); + *x_offset = MAX(*x_offset, 0) + xpad; } if (y_offset) { - *y_offset = (gint)((renderer->yalign * - (cell_area->height - calc_height - 2 * renderer->ypad))); - *y_offset = MAX (*y_offset, 0) + renderer->ypad; + *y_offset = int(yalign * (cell_area->height - calc_height - 2 * ypad)); + *y_offset = MAX(*y_offset, 0) + ypad; } } @@ -1381,7 +1394,9 @@ gtk_wx_cell_renderer_render (GtkCellRenderer *renderer, background_area, expose_area, flags); wxRect rect(wxRectFromGDKRect(cell_area)); - rect = rect.Deflate(renderer->xpad, renderer->ypad); + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + rect = rect.Deflate(xpad, ypad); wxWindowDC* dc = (wxWindowDC*) cell->GetDC(); wxWindowDCImpl *impl = (wxWindowDCImpl *) dc->GetImpl(); @@ -1431,8 +1446,10 @@ gtk_wx_cell_renderer_activate( rect.x += cell_area->x; rect.y += cell_area->y; - rect.width -= renderer->xpad * 2; - rect.height -= renderer->ypad * 2; + int xpad, ypad; + gtk_cell_renderer_get_padding(renderer, &xpad, &ypad); + rect.width -= xpad * 2; + rect.height -= ypad * 2; wxRect renderrect(wxRectFromGDKRect(&rect)); @@ -1818,7 +1835,7 @@ wxDataViewCellMode wxDataViewRenderer::GetMode() const return ret; } -void wxDataViewRenderer::GtkUpdateAlignment() +void wxDataViewRenderer::GtkApplyAlignment(GtkCellRenderer *renderer) { int align = m_alignment; @@ -1844,7 +1861,7 @@ void wxDataViewRenderer::GtkUpdateAlignment() GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_FLOAT ); g_value_set_float( &gvalue, xalign ); - g_object_set_property( G_OBJECT(m_renderer), "xalign", &gvalue ); + g_object_set_property( G_OBJECT(renderer), "xalign", &gvalue ); g_value_unset( &gvalue ); // vertical alignment: @@ -1858,7 +1875,7 @@ void wxDataViewRenderer::GtkUpdateAlignment() GValue gvalue2 = { 0, }; g_value_init( &gvalue2, G_TYPE_FLOAT ); g_value_set_float( &gvalue2, yalign ); - g_object_set_property( G_OBJECT(m_renderer), "yalign", &gvalue2 ); + g_object_set_property( G_OBJECT(renderer), "yalign", &gvalue2 ); g_value_unset( &gvalue2 ); } @@ -2303,7 +2320,7 @@ public: m_context = window->GTKGetPangoDefaultContext(); m_layout = pango_layout_new( m_context ); - m_fontdesc = pango_font_description_copy( widget->style->font_desc ); + m_fontdesc = pango_font_description_copy(gtk_widget_get_style(widget)->font_desc); m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget ); @@ -2342,13 +2359,20 @@ wxDataViewCustomRenderer::wxDataViewCustomRenderer( const wxString &varianttype, Init(mode, align); } +void wxDataViewCustomRenderer::GtkInitTextRenderer() +{ + m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new()); + g_object_ref_sink(m_text_renderer); + + GtkApplyAlignment(GTK_CELL_RENDERER(m_text_renderer)); +} + GtkCellRendererText *wxDataViewCustomRenderer::GtkGetTextRenderer() const { if ( !m_text_renderer ) { // we create it on demand so need to do it even from a const function - const_cast(this)-> - m_text_renderer = GTK_CELL_RENDERER_TEXT(gtk_cell_renderer_text_new()); + const_cast(this)->GtkInitTextRenderer(); } return m_text_renderer; @@ -2406,7 +2430,7 @@ wxDataViewCustomRenderer::~wxDataViewCustomRenderer() delete m_dc; if (m_text_renderer) - gtk_object_sink( GTK_OBJECT(m_text_renderer) ); + g_object_unref(m_text_renderer); } wxDC *wxDataViewCustomRenderer::GetDC() @@ -2441,15 +2465,20 @@ wxDataViewProgressRenderer::wxDataViewProgressRenderer( const wxString &label, { 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); + +#if !wxUSE_UNICODE + // We can't initialize the renderer just yet because we don't have the + // pointer to the column that uses this renderer yet and so attempt to + // dereference GetOwner() to get the font that is used as a source of + // encoding in multibyte-to-Unicode conversion in GTKSetLabel() in + // non-Unicode builds would crash. So simply remember to do it later. + if ( !m_label.empty() ) + m_needsToSetLabel = true; + else +#endif // !wxUSE_UNICODE + GTKSetLabel(); } else #endif @@ -2463,11 +2492,36 @@ wxDataViewProgressRenderer::~wxDataViewProgressRenderer() { } +void wxDataViewProgressRenderer::GTKSetLabel() +{ + GValue gvalue = { 0, }; + g_value_init( &gvalue, G_TYPE_STRING ); + + // Take care to not use GetOwner() here if the label is empty, we can be + // called from ctor when GetOwner() is still NULL in this case. + g_value_set_string( &gvalue, + m_label.empty() ? "" + : wxGTK_CONV_FONT(m_label, + GetOwner()->GetOwner()->GetFont()) + ); + g_object_set_property( G_OBJECT(m_renderer), "text", &gvalue ); + g_value_unset( &gvalue ); + +#if !wxUSE_UNICODE + m_needsToSetLabel = false; +#endif // !wxUSE_UNICODE +} + bool wxDataViewProgressRenderer::SetValue( const wxVariant &value ) { #ifdef __WXGTK26__ if (!gtk_check_version(2,6,0)) { +#if !wxUSE_UNICODE + if ( m_needsToSetLabel ) + GTKSetLabel(); +#endif // !wxUSE_UNICODE + gint tmp = (long) value; GValue gvalue = { 0, }; g_value_init( &gvalue, G_TYPE_INT ); @@ -3076,7 +3130,7 @@ void wxDataViewColumn::SetBitmap( const wxBitmap &bitmap ) { wxDataViewColumnBase::SetBitmap( bitmap ); - if (bitmap.Ok()) + if (bitmap.IsOk()) { GtkImage *gtk_image = GTK_IMAGE(m_image); @@ -3107,9 +3161,9 @@ void wxDataViewColumn::SetHidden( bool hidden ) gtk_tree_view_column_set_visible( GTK_TREE_VIEW_COLUMN(m_column), !hidden ); } -void wxDataViewColumn::SetResizeable( bool resizeable ) +void wxDataViewColumn::SetResizeable( bool resizable ) { - gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizeable ); + gtk_tree_view_column_set_resizable( GTK_TREE_VIEW_COLUMN(m_column), resizable ); } void wxDataViewColumn::SetAlignment( wxAlignment align ) @@ -3280,7 +3334,7 @@ int wxGtkTreeModelChildWithPosCmp( const void* data1, const void* data2, const v static int LINKAGEMODE wxGtkTreeModelChildPtrCmp( void*** data1, void*** data2 ) { - return gs_internal->GetDataViewModel()->Compare( **data1, **data2, + return gs_internal->GetDataViewModel()->Compare( wxDataViewItem(**data1), wxDataViewItem(**data2), gs_internal->GetSortColumn(), (gs_internal->GetSortOrder() == GTK_SORT_ASCENDING) ); } @@ -3524,6 +3578,7 @@ gboolean wxDataViewCtrlInternal::row_draggable( GtkTreeDragSource *WXUNUSED(drag GtkTreePath *path ) { delete m_dragDataObject; + m_dragDataObject = NULL; wxDataViewItem item(GetOwner()->GTKPathToItem(path)); if ( !item ) @@ -3565,21 +3620,22 @@ gboolean wxDataViewCtrlInternal::drag_data_get( GtkTreeDragSource *WXUNUSED(drag if ( !item ) return FALSE; - if (!m_dragDataObject->IsSupported( selection_data->target )) + GdkAtom target = gtk_selection_data_get_target(selection_data); + if (!m_dragDataObject->IsSupported(target)) return FALSE; - size_t size = m_dragDataObject->GetDataSize( selection_data->target ); + size_t size = m_dragDataObject->GetDataSize(target); if (size == 0) return FALSE; void *buf = malloc( size ); gboolean res = FALSE; - if (m_dragDataObject->GetDataHere( selection_data->target, buf )) + if (m_dragDataObject->GetDataHere(target, buf)) { res = TRUE; - gtk_selection_data_set( selection_data, selection_data->target, + gtk_selection_data_set(selection_data, target, 8, (const guchar*) buf, size ); } @@ -3601,9 +3657,9 @@ wxDataViewCtrlInternal::drag_data_received(GtkTreeDragDest *WXUNUSED(drag_dest), event.SetEventObject( m_owner ); event.SetItem( item ); event.SetModel( m_wx_model ); - event.SetDataFormat( selection_data->target ); - event.SetDataSize( selection_data->length ); - event.SetDataBuffer( selection_data->data ); + event.SetDataFormat(gtk_selection_data_get_target(selection_data)); + event.SetDataSize(gtk_selection_data_get_length(selection_data)); + event.SetDataBuffer(const_cast(gtk_selection_data_get_data(selection_data))); if (!m_owner->HandleWindowEvent( event )) return FALSE; @@ -3626,7 +3682,7 @@ wxDataViewCtrlInternal::row_drop_possible(GtkTreeDragDest *WXUNUSED(drag_dest), event.SetEventObject( m_owner ); event.SetItem( item ); event.SetModel( m_wx_model ); - event.SetDataFormat( selection_data->target ); + event.SetDataFormat(gtk_selection_data_get_target(selection_data)); if (!m_owner->HandleWindowEvent( event )) return FALSE; @@ -4439,6 +4495,22 @@ IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase) wxDataViewCtrl::~wxDataViewCtrl() { + // Stop editing before destroying the control to remove any event handlers + // which are added when editing started: if we didn't do this, the base + // class dtor would assert as it checks for any leftover handlers. + if ( m_treeview ) + { + GtkTreeViewColumn *col; + gtk_tree_view_get_cursor(GTK_TREE_VIEW(m_treeview), NULL, &col); + + wxDataViewColumn * const wxcol = FromGTKColumn(col); + if ( wxcol ) + { + // This won't do anything if we're not editing it + wxcol->GetRenderer()->CancelEditing(); + } + } + m_cols.Clear(); delete m_internal; @@ -4449,6 +4521,8 @@ void wxDataViewCtrl::Init() m_internal = NULL; m_cols.DeleteContents( true ); + + m_uniformRowHeight = -1; } bool wxDataViewCtrl::Create(wxWindow *parent, @@ -4681,10 +4755,9 @@ unsigned int wxDataViewCtrl::GetColumnCount() const return m_cols.GetCount(); } -wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const +wxDataViewColumn* wxDataViewCtrl::FromGTKColumn(GtkTreeViewColumn *gtk_col) const { - GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos ); - if (!gtk_col) + if ( !gtk_col ) return NULL; wxDataViewColumnList::const_iterator iter; @@ -4697,9 +4770,18 @@ wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const } } + wxFAIL_MSG( "No matching column?" ); + return NULL; } +wxDataViewColumn* wxDataViewCtrl::GetColumn( unsigned int pos ) const +{ + GtkTreeViewColumn *gtk_col = gtk_tree_view_get_column( GTK_TREE_VIEW(m_treeview), pos ); + + return FromGTKColumn(gtk_col); +} + bool wxDataViewCtrl::DeleteColumn( wxDataViewColumn *column ) { gtk_tree_view_remove_column( GTK_TREE_VIEW(m_treeview), @@ -4727,7 +4809,7 @@ bool wxDataViewCtrl::ClearColumns() int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const { - GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetConstGtkHandle()); + GtkTreeViewColumn *gtk_column = GTK_TREE_VIEW_COLUMN(column->GetGtkHandle()); GList *list = gtk_tree_view_get_columns( GTK_TREE_VIEW(m_treeview) ); @@ -4804,6 +4886,33 @@ void wxDataViewCtrl::DoSetCurrentItem(const wxDataViewItem& item) gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, NULL, FALSE); } +void wxDataViewCtrl::StartEditor(const wxDataViewItem& item, unsigned int column) +{ + wxCHECK_RET( m_treeview, + "Current item can't be set before creating the control." ); + + // We need to make sure the model knows about this item or the path would + // be invalid and gtk_tree_view_set_cursor() would silently do nothing. + ExpandAncestors(item); + + wxDataViewColumn *dvcolumn = GetColumn(column); + wxASSERT_MSG(dvcolumn, "Could not retrieve column"); + GtkTreeViewColumn *gcolumn = GTK_TREE_VIEW_COLUMN(dvcolumn->GetGtkHandle()); + + // We also need to preserve the existing selection from changing. + // Unfortunately the only way to do it seems to use our own selection + // function and forbid any selection changes during set cursor call. + wxGtkTreeSelectionLock + lock(gtk_tree_view_get_selection(GTK_TREE_VIEW(m_treeview))); + + // Do move the cursor now. + GtkTreeIter iter; + iter.user_data = item.GetID(); + wxGtkTreePath path(m_internal->get_path( &iter )); + + gtk_tree_view_set_cursor(GTK_TREE_VIEW(m_treeview), path, gcolumn, TRUE); +} + wxDataViewItem wxDataViewCtrl::GetSelection() const { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) ); @@ -5044,6 +5153,12 @@ wxDataViewCtrl::GetItemRect(const wxDataViewItem& WXUNUSED(item), return wxRect(); } +bool wxDataViewCtrl::SetRowHeight(int rowHeight) +{ + m_uniformRowHeight = rowHeight; + return true; +} + void wxDataViewCtrl::DoSetExpanderColumn() { gtk_tree_view_set_expander_column( GTK_TREE_VIEW(m_treeview),