void ChangeCurrentRow( unsigned int row );
bool TryAdvanceCurrentColumn(wxDataViewTreeNode *node, bool forward);
+ wxDataViewColumn *GetCurrentColumn() const { return m_currentCol; }
+ void ClearCurrentColumn() { m_currentCol = NULL; }
+
bool IsSingleSel() const { return !GetParent()->HasFlag(wxDV_MULTIPLE); }
bool IsEmpty() { return GetRowCount() == 0; }
// the displaying number of the tree are changing along with the
// expanding/collapsing of the tree nodes
unsigned int GetLastVisibleRow();
- unsigned int GetRowCount();
+ unsigned int GetRowCount() const;
const wxDataViewSelection& GetSelections() const { return m_selection; }
void SetSelections( const wxDataViewSelection & sel )
void StartEditing(const wxDataViewItem& item, const wxDataViewColumn* col);
private:
- int RecalculateCount();
+ int RecalculateCount() const;
// Return false only if the event was vetoed by its handler.
bool SendExpanderEvent(wxEventType type, const wxDataViewItem& item);
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;
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:
m_useCellFocus = false;
m_currentRow = 0;
- m_lineHeight = wxMax( 17, GetCharHeight() + 4 ); // 17 = mini icon height + 1
+#ifdef __WXMSW__
+ // We would like to use the same line height that Explorer uses. This is
+ // different from standard ListView control since Vista.
+ if ( wxGetWinVersion() >= wxWinVersion_Vista )
+ m_lineHeight = wxMax(16, GetCharHeight()) + 6; // 16 = mini icon height
+ else
+#endif // __WXMSW__
+ m_lineHeight = wxMax(16, GetCharHeight()) + 1; // 16 = mini icon height
#if wxUSE_DRAG_AND_DROP
m_dragCount = 0;
x_last += col->GetWidth();
}
+ // Draw background of alternate rows specially if required
+ if ( m_owner->HasFlag(wxDV_ROW_LINES) )
+ {
+ wxColour altRowColour = m_owner->m_alternateRowColour;
+ if ( !altRowColour.IsOk() )
+ {
+ // Determine the alternate rows colour automatically from the
+ // background colour.
+ const wxColour bgColour = m_owner->GetBackgroundColour();
+
+ // Depending on the background, alternate row color
+ // will be 3% more dark or 50% brighter.
+ int alpha = bgColour.GetRGB() > 0x808080 ? 97 : 150;
+ altRowColour = bgColour.ChangeLightness(alpha);
+ }
+
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ dc.SetBrush(wxBrush(altRowColour));
+
+ for (unsigned int item = item_start; item < item_last; item++)
+ {
+ if ( item % 2 )
+ {
+ dc.DrawRectangle(x_start,
+ GetLineStart(item),
+ GetClientSize().GetWidth(),
+ GetLineHeight(item));
+ }
+ }
+ }
+
// Draw horizontal rules if required
if ( m_owner->HasFlag(wxDV_HORIZ_RULES) )
{
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
const wxDataViewColumn* col)
{
wxDataViewRenderer* renderer = col->GetRenderer();
- if (renderer->GetMode() != wxDATAVIEW_CELL_EDITABLE)
+ if ( !IsCellEditableInMode(item, col, wxDATAVIEW_CELL_EDITABLE) )
return;
const wxRect itemRect = GetItemRect(item, col);
return wxMin( GetRowCount()-1, row );
}
-unsigned int wxDataViewMainWindow::GetRowCount()
+unsigned int wxDataViewMainWindow::GetRowCount() const
{
if ( m_count == -1 )
{
- m_count = RecalculateCount();
- UpdateDisplay();
+ wxDataViewMainWindow* const
+ self = const_cast<wxDataViewMainWindow*>(this);
+ self->m_count = RecalculateCount();
+ self->UpdateDisplay();
}
return m_count;
}
wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) const
{
+ wxDataViewItem item;
if (IsVirtualList())
{
- return wxDataViewItem( wxUIntToPtr(row+1) );
+ if ( row < GetRowCount() )
+ item = wxDataViewItem(wxUIntToPtr(row+1));
}
else
{
wxDataViewTreeNode *node = GetTreeNodeByRow(row);
- return node ? node->GetItem() : wxDataViewItem();
+ if ( node )
+ item = node->GetItem();
}
+
+ return item;
}
bool
return itemRect;
}
-int wxDataViewMainWindow::RecalculateCount()
+int wxDataViewMainWindow::RecalculateCount() const
{
if (IsVirtualList())
{
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 )
switch ( event.GetKeyCode() )
{
case WXK_RETURN:
+ if ( event.HasModifiers() )
+ {
+ event.Skip();
+ break;
+ }
+ else
{
// Enter activates the item, i.e. sends wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED to
// it. Only if that event is not handled do we activate column renderer (which
}
case WXK_SPACE:
+ if ( event.HasModifiers() )
+ {
+ event.Skip();
+ break;
+ }
+ else
{
// Space toggles activatable items or -- if not activatable --
// starts inline editing (this is normally done using F2 on
}
case WXK_F2:
+ if ( event.HasModifiers() )
+ {
+ event.Skip();
+ break;
+ }
+ else
{
if( !m_selection.empty() )
{
wxDataViewColumn *editableCol = FindColumnForEditing(item, wxDATAVIEW_CELL_EDITABLE);
if ( editableCol )
- GetOwner()->StartEditor(item, GetOwner()->GetColumnIndex(editableCol));
+ GetOwner()->EditItem(item, editableCol);
}
}
break;
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());
m_clientArea->GetRowHeight());
if ( m_headerArea )
- {
- int header_width = m_headerArea->GetTextExtent(column->GetTitle()).x;
- // Labels on native MSW header are indented on both sides
- header_width +=
- wxRendererNative::Get().GetHeaderButtonMargin(m_headerArea);
- calculator.UpdateWithWidth(header_width);
- }
+ calculator.UpdateWithWidth(m_headerArea->GetColumnTitleWidth(*column));
// The code below deserves some explanation. For very large controls, we
// simply can't afford to calculate sizes for all items, it takes too
m_colsBestWidths.erase(m_colsBestWidths.begin() + GetColumnIndex(column));
m_cols.Erase(ret);
+
+ if ( m_clientArea->GetCurrentColumn() == column )
+ m_clientArea->ClearCurrentColumn();
+
OnColumnsCountChanged();
return true;
SetExpanderColumn(NULL);
m_cols.Clear();
m_colsBestWidths.clear();
+
+ m_clientArea->ClearCurrentColumn();
+
OnColumnsCountChanged();
+
return true;
}
int wxDataViewCtrl::GetColumnPosition( const wxDataViewColumn *column ) const
{
-#if 1
unsigned int len = GetColumnCount();
for ( unsigned int i = 0; i < len; i++ )
{
}
return wxNOT_FOUND;
-#else
- // This returns the position in pixels which is not what we want.
- int ret = 0,
- dummy = 0;
- unsigned int len = GetColumnCount();
- for ( unsigned int i = 0; i < len; i++ )
- {
- wxDataViewColumn * col = GetColumnAt(i);
- if (col->IsHidden())
- continue;
- ret += col->GetWidth();
- if (column==col)
- {
- CalcScrolledPosition( ret, dummy, &ret, &dummy );
- break;
- }
- }
- return ret;
-#endif
}
wxDataViewColumn *wxDataViewCtrl::GetSortingColumn() const
}
}
+wxDataViewColumn *wxDataViewCtrl::GetCurrentColumn() const
+{
+ return m_clientArea->GetCurrentColumn();
+}
+
int wxDataViewCtrl::GetSelectedItemsCount() const
{
return m_clientArea->GetSelections().size();
return false;
}
+void wxDataViewCtrl::SetAlternateRowColour(const wxColour& colour)
+{
+ m_alternateRowColour = colour;
+}
+
void wxDataViewCtrl::SelectAll()
{
m_clientArea->SelectAllRows(true);
return false;
}
-void wxDataViewCtrl::StartEditor( const wxDataViewItem & item, unsigned int column )
+void wxDataViewCtrl::EditItem(const wxDataViewItem& item, const wxDataViewColumn *column)
{
- wxDataViewColumn* col = GetColumn( column );
- if (!col)
- return;
+ wxCHECK_RET( item.IsOk(), "invalid item" );
+ wxCHECK_RET( column, "no column provided" );
- m_clientArea->StartEditing(item, col);
+ m_clientArea->StartEditing(item, column);
}
#endif // !wxUSE_GENERICDATAVIEWCTRL