#include "wx/headerctrl.h"
#include "wx/dnd.h"
#include "wx/stopwatch.h"
+#include "wx/weakref.h"
//-----------------------------------------------------------------------------
// classes
wxBitmap CreateItemBitmap( unsigned int row, int &indent );
#endif // wxUSE_DRAG_AND_DROP
void OnPaint( wxPaintEvent &event );
+ void OnCharHook( wxKeyEvent &event );
void OnChar( wxKeyEvent &event );
void OnVerticalNavigation(unsigned int newCurrent, const wxKeyEvent& event);
void OnLeftKey();
int GetLineAt( unsigned int y ) const; // y / m_lineHeight in fixed mode
void SetRowHeight( int lineHeight ) { m_lineHeight = lineHeight; }
+ int GetRowHeight() const { return m_lineHeight; }
// Some useful functions for row and item mapping
wxDataViewItem GetItemByRow( unsigned int row ) const;
int GetRowByItem( const wxDataViewItem & item ) const;
+ wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row ) const;
+ // We did not need this temporarily
+ // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
+
// Methods for building the mapping tree
void BuildTree( wxDataViewModel * model );
void DestroyTree();
void OnColumnsCountChanged();
-private:
- wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row ) const;
- // We did not need this temporarily
- // wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item );
+ // Called by wxDataViewCtrl and our own OnRenameTimer() to start edit the
+ // specified item in the given column.
+ void StartEditing(const wxDataViewItem& item, const wxDataViewColumn* col);
+private:
int RecalculateCount();
// Return false only if the event was vetoed by its handler.
wxDataViewColumn *FindColumnForEditing(const wxDataViewItem& item, wxDataViewCellMode mode);
+ bool IsCellEditableInMode(const wxDataViewItem& item, const wxDataViewColumn *col, wxDataViewCellMode mode) const;
+
+ void DrawCellBackground( wxDataViewRenderer* cell, wxDC& dc, const wxRect& rect );
+
private:
wxDataViewCtrl *m_owner;
int m_lineHeight;
// This is the tree node under the cursor
wxDataViewTreeNode * m_underMouse;
+ // The control used for editing or NULL.
+ wxWeakRef<wxWindow> m_editorCtrl;
+
+ // Id m_editorCtrl is non-NULL, pointer to the associated renderer.
+ wxDataViewRenderer* m_editorRenderer;
+
private:
DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow)
DECLARE_EVENT_TABLE()
unsigned int col,
const wxMouseEvent *mouseEvent)
{
- if ( !model->IsEnabled(item, col) )
- return false;
-
if ( mouseEvent )
{
// only react to clicks directly on the checkbox, not elsewhere in the same cell:
EVT_MOUSE_EVENTS (wxDataViewMainWindow::OnMouse)
EVT_SET_FOCUS (wxDataViewMainWindow::OnSetFocus)
EVT_KILL_FOCUS (wxDataViewMainWindow::OnKillFocus)
+ EVT_CHAR_HOOK (wxDataViewMainWindow::OnCharHook)
EVT_CHAR (wxDataViewMainWindow::OnChar)
END_EVENT_TABLE()
{
SetOwner( parent );
+ m_editorRenderer = NULL;
+
m_lastOnSame = false;
m_renameTimer = new wxDataViewRenameTimer( this );
m_useCellFocus = false;
m_currentRow = 0;
- m_lineHeight = wxMax( 17, GetCharHeight() + 2 ); // 17 = mini icon height + 1
+ m_lineHeight = wxMax( 17, GetCharHeight() + 4 ); // 17 = mini icon height + 1
#if wxUSE_DRAG_AND_DROP
m_dragCount = 0;
cell_rect.y = GetLineStart( item );
cell_rect.height = GetLineHeight( item );
+ // draw the background
+ bool selected = m_selection.Index( item ) != wxNOT_FOUND;
+ if ( !selected )
+ DrawCellBackground( cell, dc, cell_rect );
+
// deal with the expander
int indent = 0;
if ((!IsList()) && (col == expander))
continue;
int state = 0;
- if (m_hasFocus && (m_selection.Index(item) != wxNOT_FOUND))
+ if (m_hasFocus && selected)
state |= wxDATAVIEW_CELL_SELECTED;
// TODO: it would be much more efficient to create a clipping
}
}
+
+void wxDataViewMainWindow::DrawCellBackground( wxDataViewRenderer* cell, wxDC& dc, const wxRect& rect )
+{
+ wxRect rectBg( rect );
+
+ // don't overlap the horizontal rules
+ if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
+ {
+ rectBg.x++;
+ rectBg.width--;
+ }
+
+ // don't overlap the vertical rules
+ if ( m_owner->HasFlag(wxDV_VERT_RULES) )
+ {
+ rectBg.y++;
+ rectBg.height--;
+ }
+
+ cell->RenderBackground(&dc, rectBg);
+}
+
void wxDataViewMainWindow::OnRenameTimer()
{
// We have to call this here because changes may just have
wxDataViewItem item = GetItemByRow( m_currentRow );
- wxRect labelRect = GetItemRect(item, m_currentCol);
+ StartEditing( item, m_currentCol );
+}
- m_currentCol->GetRenderer()->StartEditing( item, labelRect );
+void
+wxDataViewMainWindow::StartEditing(const wxDataViewItem& item,
+ const wxDataViewColumn* col)
+{
+ wxDataViewRenderer* renderer = col->GetRenderer();
+ if ( !IsCellEditableInMode(item, col, wxDATAVIEW_CELL_EDITABLE) )
+ return;
+
+ const wxRect itemRect = GetItemRect(item, col);
+ if ( renderer->StartEditing(item, itemRect) )
+ {
+ // Save the renderer to be able to finish/cancel editing it later and
+ // save the control to be able to detect if we're still editing it.
+ m_editorRenderer = renderer;
+ m_editorCtrl = renderer->GetEditorCtrl();
+ }
}
//-----------------------------------------------------------------------------
int x, y;
m_owner->GetScrollPixelsPerUnit( &x, &y );
int sy = GetLineStart( rows )/y;
- int sx = 0;
+ int sx = -1;
if( column != -1 )
{
wxRect rect = GetClientRect();
wxDataViewColumn *candidate = m_currentCol;
if ( candidate &&
- candidate->GetRenderer()->GetMode() != mode &&
+ !IsCellEditableInMode(item, candidate, mode) &&
!m_currentColSetByKeyboard )
{
// If current column was set by mouse to something not editable (in
if ( c->IsHidden() )
continue;
- if ( c->GetRenderer()->GetMode() == mode )
+ if ( IsCellEditableInMode(item, c, mode) )
{
candidate = c;
break;
if ( !candidate )
return NULL;
- if ( candidate->GetRenderer()->GetMode() != mode )
+ if ( !IsCellEditableInMode(item, candidate, mode) )
return NULL;
return candidate;
}
+bool wxDataViewMainWindow::IsCellEditableInMode(const wxDataViewItem& item,
+ const wxDataViewColumn *col,
+ wxDataViewCellMode mode) const
+{
+ if ( col->GetRenderer()->GetMode() != mode )
+ return false;
+
+ if ( !GetModel()->IsEnabled(item, col->GetModelColumn()) )
+ return false;
+
+ return true;
+}
+
+void wxDataViewMainWindow::OnCharHook(wxKeyEvent& event)
+{
+ if ( m_editorCtrl )
+ {
+ // Handle any keys special for the in-place editor and return without
+ // calling Skip() below.
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_ESCAPE:
+ m_editorRenderer->CancelEditing();
+ return;
+
+ case WXK_RETURN:
+ m_editorRenderer->FinishEditing();
+ return;
+ }
+ }
+
+ event.Skip();
+}
+
void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
{
wxWindow * const parent = GetParent();
if ( idx >= (int)GetOwner()->GetColumnCount() )
return false;
+ GetOwner()->EnsureVisible(m_currentRow, idx);
+
if ( idx < 1 )
{
// We are going to the left of the second column. Reset to whole-row
if (m_lastOnSame && !ignore_other_columns)
{
if ((col == m_currentCol) && (current == m_currentRow) &&
- (cell->GetMode() & wxDATAVIEW_CELL_EDITABLE) )
+ IsCellEditableInMode(item, col, wxDATAVIEW_CELL_EDITABLE) )
{
m_renameTimer->Start( 100, true );
}
(current == oldCurrentRow)) && oldWasSelected;
// Call ActivateCell() after everything else as under GTK+
- if (cell->GetMode() & wxDATAVIEW_CELL_ACTIVATABLE)
+ if ( IsCellEditableInMode(item, col, wxDATAVIEW_CELL_ACTIVATABLE) )
{
// notify cell about click
cell->PrepareForItem(model, item, col->GetModelColumn());
class MaxWidthCalculator
{
public:
- MaxWidthCalculator(wxDataViewMainWindow *clientArea,
+ MaxWidthCalculator(const wxDataViewCtrl *dvc,
+ wxDataViewMainWindow *clientArea,
wxDataViewRenderer *renderer,
const wxDataViewModel *model,
- unsigned column)
+ unsigned column,
+ int expanderSize)
: m_width(0),
+ m_dvc(dvc),
m_clientArea(clientArea),
m_renderer(renderer),
m_model(model),
- m_column(column)
+ m_column(column),
+ m_expanderSize(expanderSize)
+
{
+ m_isExpanderCol =
+ !clientArea->IsList() &&
+ (column == 0 ||
+ GetExpanderColumnOrFirstOne(const_cast<wxDataViewCtrl*>(dvc)) == dvc->GetColumnAt(column));
}
void UpdateWithWidth(int width)
void UpdateWithRow(int row)
{
- wxDataViewItem item = m_clientArea->GetItemByRow(row);
+ int indent = 0;
+ wxDataViewItem item;
+
+ if ( m_isExpanderCol )
+ {
+ wxDataViewTreeNode *node = m_clientArea->GetTreeNodeByRow(row);
+ item = node->GetItem();
+ indent = m_dvc->GetIndent() * node->GetIndentLevel() + m_expanderSize;
+ }
+ else
+ {
+ item = m_clientArea->GetItemByRow(row);
+ }
+
m_renderer->PrepareForItem(m_model, item, m_column);
- m_width = wxMax(m_width, m_renderer->GetSize().x);
+ m_width = wxMax(m_width, m_renderer->GetSize().x + indent);
}
int GetMaxWidth() const { return m_width; }
private:
int m_width;
+ const wxDataViewCtrl *m_dvc;
wxDataViewMainWindow *m_clientArea;
wxDataViewRenderer *m_renderer;
const wxDataViewModel *m_model;
unsigned m_column;
+ bool m_isExpanderCol;
+ int m_expanderSize;
};
- MaxWidthCalculator calculator(m_clientArea, renderer,
- GetModel(), column->GetModelColumn());
+ MaxWidthCalculator calculator(this, m_clientArea, renderer,
+ GetModel(), column->GetModelColumn(),
+ m_clientArea->GetRowHeight());
if ( m_headerArea )
{
if (!col)
return;
- wxDataViewRenderer* renderer = col->GetRenderer();
- if (renderer->GetMode() != wxDATAVIEW_CELL_EDITABLE)
- return;
-
- const wxRect itemRect = GetItemRect(item, col);
- renderer->StartEditing(item, itemRect);
+ m_clientArea->StartEditing(item, col);
}
#endif // !wxUSE_GENERICDATAVIEWCTRL