diff --git a/include/wx/generic/listctrl.h b/include/wx/generic/listctrl.h index 60e034f1af..8bd63b7ae5 100644 --- a/include/wx/generic/listctrl.h +++ b/include/wx/generic/listctrl.h @@ -189,6 +189,8 @@ public: virtual bool SetFont( const wxFont &font ) wxOVERRIDE; virtual bool SetCursor( const wxCursor &cursor ) wxOVERRIDE; + virtual void ExtendRulesAndAlternateColour(bool extend = true) wxOVERRIDE; + #if wxUSE_DRAG_AND_DROP virtual void SetDropTarget( wxDropTarget *dropTarget ) wxOVERRIDE; virtual wxDropTarget *GetDropTarget() const wxOVERRIDE; diff --git a/include/wx/generic/private/listctrl.h b/include/wx/generic/private/listctrl.h index 4087889098..e0da92797f 100644 --- a/include/wx/generic/private/listctrl.h +++ b/include/wx/generic/private/listctrl.h @@ -740,6 +740,12 @@ public: return true; } + void ExtendRulesAndAlternateColour(bool extend) + { + m_extendRulesAndAlternateColour = extend; + } + + // these are for wxListLineData usage only // get the backpointer to the list ctrl @@ -775,6 +781,10 @@ public: selected ? ++m_selCount : --m_selCount; } + void DrawInReportModeOnBlank ( wxDC *dc, + const wxRect& rect, + int lineNumber ); + protected: // the array of all line objects for a non virtual list control (for the // virtual list control we only ever use m_lines[0]) @@ -936,6 +946,9 @@ private: // NULL if no item is being edited wxListTextCtrlWrapper *m_textctrlWrapper; + // tells whether or not to paint empty rows with alternate colour and draw + // rulers on empty rows + bool m_extendRulesAndAlternateColour; wxDECLARE_EVENT_TABLE(); diff --git a/include/wx/listbase.h b/include/wx/listbase.h index 8b1da7599c..f786bfd278 100644 --- a/include/wx/listbase.h +++ b/include/wx/listbase.h @@ -417,6 +417,8 @@ public: void SetAlternateRowColour(const wxColour& colour); wxColour GetAlternateRowColour() const { return m_alternateRowColour.GetBackgroundColour(); } + virtual void ExtendRulesAndAlternateColour(bool WXUNUSED(extend) = true) { } + // Header attributes support: only implemented in wxMSW currently. virtual bool SetHeaderAttr(const wxItemAttr& WXUNUSED(attr)) { return false; } diff --git a/interface/wx/listctrl.h b/interface/wx/listctrl.h index d574a4723d..d44b21d8b5 100644 --- a/interface/wx/listctrl.h +++ b/interface/wx/listctrl.h @@ -1333,6 +1333,33 @@ public: */ void CheckItem(long item, bool check); + /** + Extend rules and alternate rows background to the entire client area. + + Bu default, the rules (when enabled with wxLC_HRULES and wxLC_VRULES) + and alternate row background (when EnableAlternateRowColours() was + called) are only shown in the part of the control occupied by the + items, which can be smaller than the entire window if there are few + items in the control. + + Calling this function extends the display of the rules and alternate + background rows to the entire client area. + + Similarly to EnableAlternateRowColours(), this method can only be used + with controls having ::wxLC_REPORT and ::wxLC_VIRTUAL styles. + + Note that this method is currently not implemented in the native MSW + version and does nothing there. + + @param extend + if @true, draws horizontal rules and vertical rules on empty rows + and uses the colour parameter to paint the background of + alternate rows when those rows are blank, empty, with no data. + + @since 3.1.5 + */ + void ExtendRulesAndAlternateColour(bool extend = true); + protected: /** diff --git a/samples/listctrl/listtest.cpp b/samples/listctrl/listtest.cpp index 016d297c99..92ae0a1926 100644 --- a/samples/listctrl/listtest.cpp +++ b/samples/listctrl/listtest.cpp @@ -134,6 +134,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_MENU(LIST_SET_FG_COL, MyFrame::OnSetFgColour) EVT_MENU(LIST_SET_BG_COL, MyFrame::OnSetBgColour) EVT_MENU(LIST_ROW_LINES, MyFrame::OnSetRowLines) + EVT_MENU(LIST_ROW_LINES_ON_BLANK, MyFrame::OnSetRowLinesOnBlank) EVT_MENU(LIST_CUSTOM_HEADER_ATTR, MyFrame::OnCustomHeaderAttr) EVT_MENU(LIST_TOGGLE_MULTI_SEL, MyFrame::OnToggleMultiSel) EVT_MENU(LIST_SHOW_COL_INFO, MyFrame::OnShowColInfo) @@ -165,6 +166,7 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_UPDATE_UI(LIST_TOGGLE_CHECKBOXES, MyFrame::OnUpdateToggleCheckBoxes) EVT_UPDATE_UI(LIST_TOGGLE_HEADER, MyFrame::OnUpdateToggleHeader) EVT_UPDATE_UI(LIST_ROW_LINES, MyFrame::OnUpdateRowLines) + EVT_UPDATE_UI(LIST_ROW_LINES_ON_BLANK, MyFrame::OnUpdateUIEnableInReport) wxEND_EVENT_TABLE() // My frame constructor @@ -277,6 +279,7 @@ MyFrame::MyFrame(const wxString& title) menuCol->Append(LIST_SET_FG_COL, "&Foreground colour..."); menuCol->Append(LIST_SET_BG_COL, "&Background colour..."); menuCol->AppendCheckItem(LIST_ROW_LINES, "Alternating colours"); + menuCol->AppendCheckItem(LIST_ROW_LINES_ON_BLANK, "Extend to whole window"); menuCol->AppendCheckItem(LIST_CUSTOM_HEADER_ATTR, "&Custom header attributes"); wxMenuBar *menubar = new wxMenuBar; @@ -520,6 +523,7 @@ void MyFrame::RecreateList(long flags, bool withText) } GetMenuBar()->Check(LIST_ROW_LINES, false); + GetMenuBar()->Check(LIST_ROW_LINES_ON_BLANK, false); m_logWindow->Clear(); } @@ -940,6 +944,11 @@ void MyFrame::OnSetRowLines(wxCommandEvent& event) m_listCtrl->Refresh(); } +void MyFrame::OnSetRowLinesOnBlank(wxCommandEvent& event) +{ + m_listCtrl->ExtendRulesAndAlternateColour(event.IsChecked()); +} + void MyFrame::OnCustomHeaderAttr(wxCommandEvent& event) { wxItemAttr attr; @@ -1426,7 +1435,10 @@ void MyListCtrl::OnListKeyDown(wxListEvent& event) } else // !virtual { - InsertItemInReportView(event.GetIndex()); + int idx = event.GetIndex(); + if ( idx == -1 ) + idx = 0; + InsertItemInReportView(idx); } break; } diff --git a/samples/listctrl/listtest.h b/samples/listctrl/listtest.h index 40af8628cb..c40ee918ca 100644 --- a/samples/listctrl/listtest.h +++ b/samples/listctrl/listtest.h @@ -133,6 +133,7 @@ protected: void OnSetFgColour(wxCommandEvent& event); void OnSetBgColour(wxCommandEvent& event); void OnSetRowLines(wxCommandEvent& event); + void OnSetRowLinesOnBlank(wxCommandEvent& event); void OnCustomHeaderAttr(wxCommandEvent& event); void OnToggleMultiSel(wxCommandEvent& event); void OnShowColInfo(wxCommandEvent& event); @@ -223,6 +224,7 @@ enum LIST_SET_FG_COL, LIST_SET_BG_COL, LIST_ROW_LINES, + LIST_ROW_LINES_ON_BLANK, LIST_CUSTOM_HEADER_ATTR, LIST_TOGGLE_MULTI_SEL, LIST_TOGGLE_HEADER, diff --git a/src/generic/listctrl.cpp b/src/generic/listctrl.cpp index 1497aaa289..6907d2fa9c 100644 --- a/src/generic/listctrl.cpp +++ b/src/generic/listctrl.cpp @@ -1601,6 +1601,7 @@ void wxListMainWindow::Init() m_anchor = (size_t)-1; m_hasCheckBoxes = false; + m_extendRulesAndAlternateColour = false; } wxListMainWindow::wxListMainWindow() @@ -2072,8 +2073,23 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) int lineHeight = GetLineHeight(); size_t visibleFrom, visibleTo; + const size_t linesPerPage = (unsigned int) m_linesPerPage; GetVisibleLinesRange(&visibleFrom, &visibleTo); + // We may need to iterate beyond visibleTo if we want to draw striped + // background across the entire window. + size_t visibleEnd; + wxColour colAlt; + if ( m_extendRulesAndAlternateColour ) + { + colAlt = GetListCtrl()->GetAlternateRowColour(); + visibleEnd = wxMax(linesPerPage, visibleTo); + } + else + { + visibleEnd = visibleTo; + } + wxRect rectLine; int xOrig = dc.LogicalToDeviceX( 0 ); int yOrig = dc.LogicalToDeviceY( 0 ); @@ -2090,7 +2106,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) GetParent()->GetEventHandler()->ProcessEvent( evCache ); } - for ( size_t line = visibleFrom; line <= visibleTo; line++ ) + for ( size_t line = visibleFrom; line <= visibleEnd; line++ ) { rectLine = GetLineRect(line); @@ -2102,6 +2118,21 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) continue; } + if ( line > visibleTo ) + { + // We only iterate beyond visibleTo when we have to draw the + // odd rows background, so do this if needed. + if ( line % 2 ) + { + dc.SetBrush(colAlt); + dc.SetPen(*wxTRANSPARENT_PEN); + dc.DrawRectangle(rectLine); + } + + // But don't do anything else, as there is no valid item. + continue; + } + GetLine(line)->DrawInReportMode( &dc, rectLine, GetLineHighlightRect(line), @@ -2116,7 +2147,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) size_t i = visibleFrom; if (i == 0) i = 1; // Don't draw the first one - for ( ; i <= visibleTo; i++ ) + for ( ; i <= visibleEnd; i++ ) { dc.SetPen(pen); dc.SetBrush( *wxTRANSPARENT_BRUSH ); @@ -2125,7 +2156,7 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) } // Draw last horizontal rule - if ( visibleTo == GetItemCount() - 1 ) + if ( visibleEnd == GetItemCount() - 1 ) { dc.SetPen( pen ); dc.SetBrush( *wxTRANSPARENT_BRUSH ); @@ -2135,7 +2166,8 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) } // Draw vertical rules if required - if ( HasFlag(wxLC_VRULES) && !IsEmpty() ) + if ( HasFlag(wxLC_VRULES) && + (m_extendRulesAndAlternateColour || !IsEmpty()) ) { wxPen pen(GetRuleColour(), 1, wxPENSTYLE_SOLID); wxRect firstItemRect, lastItemRect; @@ -2146,14 +2178,22 @@ void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) dc.SetPen(pen); dc.SetBrush(* wxTRANSPARENT_BRUSH); + int clientHeight, clientWidth; + GetSize( &clientWidth, &clientHeight ); + for (int col = 0; col < GetColumnCount(); col++) { int colWidth = GetColumnWidth(col); x += colWidth; int x_pos = x - dev_x; if (col < GetColumnCount()-1) x_pos -= 2; + + int ruleHeight = m_extendRulesAndAlternateColour + ? clientHeight + : lastItemRect.GetBottom() + 1 - dev_y; + dc.DrawLine(x_pos, firstItemRect.GetY() - 1 - dev_y, - x_pos, lastItemRect.GetBottom() + 1 - dev_y); + x_pos, ruleHeight); } } } @@ -4947,6 +4987,16 @@ bool wxGenericListCtrl::Create(wxWindow *parent, return true; } +void wxGenericListCtrl::ExtendRulesAndAlternateColour(bool state) +{ + wxCHECK_RET( m_mainWin, "can't be called before creation" ); + + wxASSERT_MSG( InReportView(), "can only be called in report mode" ); + + m_mainWin->ExtendRulesAndAlternateColour(state); + m_mainWin->Refresh(); +} + wxBorder wxGenericListCtrl::GetDefaultBorder() const { return wxBORDER_THEME;