From 1e510b1e2d0270caf227c3fc0cf34ae2e7dd6794 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Tue, 17 Apr 2007 12:08:10 +0000 Subject: [PATCH] Implemented the same simple API for creating customized in-place editing controls for GTK+ and the generic version and demonstrate its use in the sample using a wxSpinCtrl. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45518 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 40 +++++++++++++ include/wx/generic/dataview.h | 40 +------------ include/wx/gtk/dataview.h | 3 + samples/dataview/dataview.cpp | 91 ++++++++++++++++++++++++++++- src/common/datavcmn.cpp | 100 ++++++++++++++++++++++++++++++++ src/generic/datavgen.cpp | 104 +--------------------------------- src/gtk/dataview.cpp | 100 ++++++++++++++++++++++++++++++++ 7 files changed, 335 insertions(+), 143 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 52176d2319..2f6548ad36 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -233,6 +233,30 @@ private: void InitStatics(); // BAD }; +//----------------------------------------------------------------------------- +// wxDataViewEditorCtrlEvtHandler +//----------------------------------------------------------------------------- + +class wxDataViewEditorCtrlEvtHandler: public wxEvtHandler +{ +public: + wxDataViewEditorCtrlEvtHandler( wxControl *editor, wxDataViewRenderer *owner ); + + void AcceptChangesAndFinish(); + +protected: + void OnChar( wxKeyEvent &event ); + void OnKillFocus( wxFocusEvent &event ); + +private: + wxDataViewRenderer *m_owner; + wxControl *m_editorCtrl; + bool m_finished; + +private: + DECLARE_EVENT_TABLE() +}; + // --------------------------------------------------------- // wxDataViewRendererBase // --------------------------------------------------------- @@ -281,9 +305,25 @@ public: virtual void SetAlignment( int align ) = 0; virtual int GetAlignment() const = 0; + // in-place editing + virtual bool HasEditorCtrl() + { return false; } + virtual wxControl* CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value ) + { return NULL; } + virtual bool GetValueFromEditorCtrl( wxControl* editor, wxVariant &value ) + { return false; } + + virtual bool StartEditing( unsigned int row, wxRect labelRect ); + virtual void CancelEditing(); + virtual bool FinishEditing(); + + wxControl *GetEditorCtrl() { return m_editorCtrl; } + protected: wxString m_variantType; wxDataViewColumn *m_owner; + wxControl *m_editorCtrl; + unsigned int m_row; // for m_editorCtrl // internal utility: const wxDataViewCtrl* GetView() const; diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index b62bc9eee6..13ce60fc6a 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -25,30 +25,6 @@ class WXDLLIMPEXP_ADV wxDataViewCtrl; class WXDLLIMPEXP_ADV wxDataViewMainWindow; class WXDLLIMPEXP_ADV wxDataViewHeaderWindow; -//----------------------------------------------------------------------------- -// wxDataViewEditorCtrlEvtHandler -//----------------------------------------------------------------------------- - -class wxDataViewEditorCtrlEvtHandler: public wxEvtHandler -{ -public: - wxDataViewEditorCtrlEvtHandler( wxControl *editor, wxDataViewRenderer *owner ); - - void AcceptChangesAndFinish(); - -protected: - void OnChar( wxKeyEvent &event ); - void OnKillFocus( wxFocusEvent &event ); - -private: - wxDataViewRenderer *m_owner; - wxControl *m_editorCtrl; - bool m_finished; - -private: - DECLARE_EVENT_TABLE() -}; - // --------------------------------------------------------- // wxDataViewRenderer // --------------------------------------------------------- @@ -102,24 +78,10 @@ public: // Create DC on request virtual wxDC *GetDC(); - // in-place editing - virtual bool HasEditorCtrl() - { return false; } - virtual wxControl* CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value ) - { return NULL; } - virtual bool GetValueFromEditorCtrl( wxControl* editor, wxVariant &value ) - { return false; } - - virtual bool StartEditing( unsigned int row, wxRect labelRect ); - virtual void CancelEditing(); - virtual bool FinishEditing(); - private: wxDC *m_dc; int m_align; wxDataViewCellMode m_mode; - wxControl *m_editorCtrl; - unsigned int m_row; // for m_editorCtrl protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewRenderer) @@ -406,7 +368,7 @@ public: // utility functions not part of the API // updates the header window after a change in a column setting void OnColumnChange(); - wxDataViewMainWindow* GetMainWindow() { return m_clientArea; } + wxWindow *GetMainWindow() { return (wxWindow*) m_clientArea; } private: wxDataViewListModelNotifier *m_notifier; diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index cb4043722c..9677f1c24e 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -317,6 +317,9 @@ public: static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); + GtkWidget *GtkGetTreeView() { return m_treeview; } + wxWindow *GetMainWindow() { return (wxWindow*) this; } + private: friend class wxDataViewCtrlDC; friend class wxDataViewColumn; diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index c69df0c9ec..788508256b 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -26,6 +26,7 @@ #include "wx/choicdlg.h" #include "wx/numdlg.h" #include "wx/dataview.h" +#include "wx/spinctrl.h" #ifndef __WXMSW__ #include "../sample.xpm" @@ -159,7 +160,6 @@ public: { wxMessageDialog dlg( NULL, wxT("string too long") , wxT("Error") ); dlg.ShowModal(); - // Activate(); return false; } @@ -220,6 +220,63 @@ private: wxString m_colour; }; +// ------------------------------------- +// MySpinCtrlInPlaceRenderer +// ------------------------------------- + +class MySpinCtrlInPlaceRenderer: public wxDataViewCustomRenderer +{ +public: + MySpinCtrlInPlaceRenderer() : + wxDataViewCustomRenderer( wxT("long"), wxDATAVIEW_CELL_EDITABLE ) { } + + + virtual bool HasEditorCtrl() + { + return true; + } + virtual wxControl* CreateEditorCtrl( wxWindow *parent, wxRect labelRect, const wxVariant &value ) + { + long l = value; + return new wxSpinCtrl( parent, wxID_ANY, wxEmptyString, + labelRect.GetTopLeft(), labelRect.GetSize(), 0, 0, 100, l ); + } + virtual bool GetValueFromEditorCtrl( wxControl* editor, wxVariant &value ) + { + wxSpinCtrl *sc = (wxSpinCtrl*) editor; + long l = sc->GetValue(); + value = l; + return true; + } + + bool Render( wxRect rect, wxDC *dc, int WXUNUSED(state) ) + { + wxString str; + str.Printf( wxT("%d"), (int) m_data ); + dc->SetTextForeground( *wxBLACK ); + dc->DrawText( str, rect.x, rect.y ); + return true; + } + wxSize GetSize() const + { + return wxSize(80,16); + } + bool SetValue( const wxVariant &value ) + { + m_data = value.GetLong(); + return true; + } + bool GetValue( wxVariant &value ) const + { + value = m_data; + return true; + } + + +private: + long m_data; +}; + // ------------------------------------- // MyUnsortedTextModel // ------------------------------------- @@ -237,6 +294,14 @@ public: m_list.Add( wxT("of") ); m_list.Add( wxT("words.") ); + m_ilist.Add( 0 ); + m_ilist.Add( 1); + m_ilist.Add( 2 ); + m_ilist.Add( 3 ); + m_ilist.Add( 4 ); + m_ilist.Add( 5 ); + m_ilist.Add( 6 ); + m_bitmap = wxBitmap( null_xpm ); } @@ -247,7 +312,7 @@ public: virtual unsigned int GetColumnCount() const { - return 2; + return 4; } virtual wxString GetColumnType( unsigned int WXUNUSED(col) ) const @@ -261,12 +326,18 @@ public: { variant = m_list[row]; return; - } + } else if ((col == 2) || (col == 3)) { variant << m_bitmap; return; + } else + if (col == 4) + { + variant = (long) m_ilist[row]; + return; } + wxString tmp; tmp.Printf( wxT("item(%d;%d)"), (int)row, (int)col ); variant = tmp; @@ -278,6 +349,11 @@ public: { m_list[row] = variant.GetString(); return true; + } else + if (col == 4) + { + m_ilist[row] = variant.GetLong(); + return true; } return false; @@ -286,28 +362,33 @@ public: void AppendRow( const wxString &text ) { m_list.Add( text ); + m_ilist.Add( 0 ); RowAppended(); } void PrependRow( const wxString &text ) { m_list.Insert( text, 0 ); + m_ilist.Insert( 0, 0 ); RowPrepended(); } void InsertRowAt1( const wxString &text ) { m_list.Insert( text, 1 ); + m_ilist.Insert( 0, 1 ); RowInserted( 1 ); } void DeleteRow( unsigned int index ) { m_list.RemoveAt( index ); + m_ilist.RemoveAt( index ); RowDeleted( index ); } wxArrayString m_list; + wxArrayInt m_ilist; wxBitmap m_bitmap; }; @@ -948,6 +1029,10 @@ MySortingFrame::MySortingFrame(wxFrame *frame, wxChar *title, int x, int y, int dataview_right->AppendColumn( column ); dataview_right->AppendTextColumn( wxT("second"), 1 ); + + MySpinCtrlInPlaceRenderer *sr = new MySpinCtrlInPlaceRenderer; + column = new wxDataViewColumn( wxT("spin"), sr, 4, -1, wxALIGN_CENTER ); + dataview_right->AppendColumn( column ); // layout dataview controls. diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 73fa33d507..633822e6b5 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -706,6 +706,8 @@ wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype, int WXUNUSED(align) ) { m_variantType = varianttype; + m_editorCtrl = NULL; + m_row = (unsigned int) -1; } const wxDataViewCtrl* wxDataViewRendererBase::GetView() const @@ -713,6 +715,104 @@ const wxDataViewCtrl* wxDataViewRendererBase::GetView() const return wx_const_cast(wxDataViewRendererBase*, this)->GetOwner()->GetOwner(); } +bool wxDataViewRendererBase::StartEditing( unsigned int row, wxRect labelRect ) +{ + m_row = row; // remember for later + + unsigned int col = GetOwner()->GetModelColumn(); + wxVariant value; + GetOwner()->GetOwner()->GetModel()->GetValue( value, col, row ); + + m_editorCtrl = CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect, value ); + + m_editorCtrl->PushEventHandler( + new wxDataViewEditorCtrlEvtHandler( m_editorCtrl, (wxDataViewRenderer*) this ) ); + + m_editorCtrl->SetFocus(); + + return true; +} + +void wxDataViewRendererBase::CancelEditing() +{ + // m_editorCtrl->PopEventHandler( true ); + + delete m_editorCtrl; + + GetOwner()->GetOwner()->GetMainWindow()->SetFocus(); +} + +bool wxDataViewRendererBase::FinishEditing() +{ + // m_editorCtrl->PopEventHandler( true ); + + wxVariant value; + GetValueFromEditorCtrl( m_editorCtrl, value ); + + delete m_editorCtrl; + + GetOwner()->GetOwner()->GetMainWindow()->SetFocus(); + + if (!Validate(value)) + return false; + + unsigned int col = GetOwner()->GetModelColumn(); + GetOwner()->GetOwner()->GetModel()->SetValue( value, col, m_row ); + GetOwner()->GetOwner()->GetModel()->ValueChanged( col, m_row ); + + return true; +} + +//----------------------------------------------------------------------------- +// wxDataViewEditorCtrlEvtHandler +//----------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler, wxEvtHandler) + EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar) + EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus) +END_EVENT_TABLE() + +wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler( + wxControl *editorCtrl, + wxDataViewRenderer *owner ) +{ + m_owner = owner; + m_editorCtrl = editorCtrl; + + m_finished = false; +} + +void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event ) +{ + switch ( event.m_keyCode ) + { + case WXK_RETURN: + m_finished = true; + m_owner->FinishEditing(); + break; + + case WXK_ESCAPE: + m_finished = true; + m_owner->CancelEditing(); + break; + + default: + event.Skip(); + } +} + +void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent &event ) +{ + if (!m_finished) + { + m_finished = true; + m_owner->FinishEditing(); + } + + // We must let the native text control handle focus + event.Skip(); +} + // --------------------------------------------------------- // wxDataViewColumnBase // --------------------------------------------------------- diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 579c2a9db6..c03a08ff92 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -418,106 +418,6 @@ wxDC *wxDataViewRenderer::GetDC() return m_dc; } -bool wxDataViewRenderer::StartEditing( unsigned int row, wxRect labelRect ) -{ - GetView()->CalcScrolledPosition( labelRect.x, labelRect.y, - &labelRect.x, &labelRect.y); - - m_row = row; // remember for later - - unsigned int col = GetOwner()->GetModelColumn(); - wxVariant value; - GetOwner()->GetOwner()->GetModel()->GetValue( value, col, row ); - - m_editorCtrl = CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect, value ); - - m_editorCtrl->PushEventHandler( new wxDataViewEditorCtrlEvtHandler( m_editorCtrl, this ) ); - - m_editorCtrl->SetFocus(); - - return true; -} - -void wxDataViewRenderer::CancelEditing() -{ - // m_editorCtrl->PopEventHandler( true ); - - delete m_editorCtrl; - - GetOwner()->GetOwner()->GetMainWindow()->SetFocus(); -} - -bool wxDataViewRenderer::FinishEditing() -{ - // m_editorCtrl->PopEventHandler( true ); - - wxVariant value; - GetValueFromEditorCtrl( m_editorCtrl, value ); - - delete m_editorCtrl; - - GetOwner()->GetOwner()->GetMainWindow()->SetFocus(); - - if (!Validate(value)) - return false; - - unsigned int col = GetOwner()->GetModelColumn(); - GetOwner()->GetOwner()->GetModel()->SetValue( value, col, m_row ); - GetOwner()->GetOwner()->GetModel()->ValueChanged( col, m_row ); - - return true; -} - -//----------------------------------------------------------------------------- -// wxDataViewEditorCtrlEvtHandler -//----------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler, wxEvtHandler) - EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar) - EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus) -END_EVENT_TABLE() - -wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler( - wxControl *editorCtrl, - wxDataViewRenderer *owner ) -{ - m_owner = owner; - m_editorCtrl = editorCtrl; - - m_finished = false; -} - -void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event ) -{ - switch ( event.m_keyCode ) - { - case WXK_RETURN: - m_finished = true; - m_owner->FinishEditing(); - break; - - case WXK_ESCAPE: - m_finished = true; - m_owner->CancelEditing(); - break; - - default: - event.Skip(); - } -} - -void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent &event ) -{ - if (!m_finished) - { - m_finished = true; - m_owner->FinishEditing(); - } - - // We must let the native text control handle focus - event.Skip(); -} - // --------------------------------------------------------- // wxDataViewCustomRenderer // --------------------------------------------------------- @@ -1665,7 +1565,6 @@ void wxDataViewMainWindow::OnRenameTimer() if ( m_dirty ) wxSafeYield(); - int xpos = 0; unsigned int cols = GetOwner()->GetColumnCount(); unsigned int i; @@ -1682,6 +1581,9 @@ void wxDataViewMainWindow::OnRenameTimer() wxRect labelRect( xpos, m_currentRow * m_lineHeight, m_currentCol->GetWidth(), m_lineHeight ); + GetOwner()->CalcScrolledPosition( labelRect.x, labelRect.y, + &labelRect.x, &labelRect.y); + m_currentCol->GetRenderer()->StartEditing( m_currentRow, labelRect ); } diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 27008e6b0a..792d56f905 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -480,6 +480,15 @@ static gboolean gtk_wx_cell_renderer_activate( GdkRectangle *background_area, GdkRectangle *cell_area, GtkCellRendererState flags ); +static GtkCellEditable *gtk_wx_cell_renderer_start_editing( + GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags ); + static GObjectClass *cell_parent_class = NULL; @@ -532,6 +541,7 @@ gtk_wx_cell_renderer_class_init (GtkWxCellRendererClass *klass) cell_class->get_size = gtk_wx_cell_renderer_get_size; cell_class->render = gtk_wx_cell_renderer_render; cell_class->activate = gtk_wx_cell_renderer_activate; + cell_class->start_editing = gtk_wx_cell_renderer_start_editing; } static void @@ -547,6 +557,48 @@ gtk_wx_cell_renderer_new (void) return (GtkCellRenderer*) g_object_new (GTK_TYPE_WX_CELL_RENDERER, NULL); } + + +static GtkCellEditable *gtk_wx_cell_renderer_start_editing( + GtkCellRenderer *renderer, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags ) +{ + GtkWxCellRenderer *wxrenderer = (GtkWxCellRenderer *) renderer; + wxDataViewCustomRenderer *cell = wxrenderer->cell; + if (!cell->HasEditorCtrl()) + return NULL; + + GdkRectangle rect; + gtk_wx_cell_renderer_get_size (renderer, widget, cell_area, + &rect.x, + &rect.y, + &rect.width, + &rect.height); + + rect.x += cell_area->x; + rect.y += cell_area->y; +// rect.width -= renderer->xpad * 2; +// rect.height -= renderer->ypad * 2; + +// wxRect renderrect( rect.x, rect.y, rect.width, rect.height ); + wxRect renderrect( cell_area->x, cell_area->y, cell_area->width, cell_area->height ); + + wxDataViewListModel *model = cell->GetOwner()->GetOwner()->GetModel(); + + GtkTreePath *treepath = gtk_tree_path_new_from_string( path ); + unsigned int model_row = (unsigned int)gtk_tree_path_get_indices (treepath)[0]; + gtk_tree_path_free( treepath ); + + cell->StartEditing( model_row, renderrect ); + + return NULL; +} + static void gtk_wx_cell_renderer_get_size (GtkCellRenderer *renderer, GtkWidget *widget, @@ -1870,6 +1922,49 @@ wxdataview_row_activated_callback( GtkTreeView* treeview, GtkTreePath *path, // wxDataViewCtrl //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// InsertChild for wxDataViewCtrl +//----------------------------------------------------------------------------- + +static void wxInsertChildInDataViewCtrl( wxWindowGTK* parent, wxWindowGTK* child ) +{ + wxDataViewCtrl * dvc = (wxDataViewCtrl*) parent; + GtkWidget *treeview = dvc->GtkGetTreeView(); + + // Insert widget in GtkTreeView + if (GTK_WIDGET_REALIZED(treeview)) + gtk_widget_set_parent_window( child->m_widget, + gtk_tree_view_get_bin_window( GTK_TREE_VIEW(treeview) ) ); + gtk_widget_set_parent( child->m_widget, treeview ); +} + +static +void gtk_dataviewctrl_size_callback( GtkWidget *WXUNUSED(widget), + GtkAllocation *alloc, + wxDataViewCtrl *win ) +{ + + wxWindowList::Node *node = win->GetChildren().GetFirst(); + while (node) + { + wxWindow *child = node->GetData(); + + GtkRequisition req; + gtk_widget_size_request( child->m_widget, &req ); + + GtkAllocation alloc; + alloc.x = child->m_x; + alloc.y = child->m_y; + alloc.width = child->m_width; + alloc.height = child->m_height; + gtk_widget_size_allocate( child->m_widget, &alloc ); + + node = node->GetNext(); + } +} + + + IMPLEMENT_DYNAMIC_CLASS(wxDataViewCtrl, wxDataViewCtrlBase) wxDataViewCtrl::~wxDataViewCtrl() @@ -1902,12 +1997,17 @@ bool wxDataViewCtrl::Create(wxWindow *parent, wxWindowID id, return false; } + m_insertCallback = wxInsertChildInDataViewCtrl; + m_widget = gtk_scrolled_window_new (NULL, NULL); GtkScrolledWindowSetBorder(m_widget, style); m_treeview = gtk_tree_view_new(); gtk_container_add (GTK_CONTAINER (m_widget), m_treeview); + + g_signal_connect (m_treeview, "size_allocate", + G_CALLBACK (gtk_dataviewctrl_size_callback), this); #ifdef __WXGTK26__ if (!gtk_check_version(2,6,0)) -- 2.45.2