#include "wx/renderer.h"
+#ifdef __WXMAC__
+ #include "wx/mac/private.h"
+#endif
// ----------------------------------------------------------------------------
// events
// ----------------------------------------------------------------------------
// // the height of the header window (FIXME: should depend on its font!)
// static const int HEADER_HEIGHT = 23;
-// the scrollbar units
static const int SCROLL_UNIT_X = 15;
-static const int SCROLL_UNIT_Y = 15;
// the spacing between the lines (in report mode)
static const int LINE_SPACING = 0;
// extra margins around the text label
-static const int EXTRA_WIDTH = 3;
+static const int EXTRA_WIDTH = 4;
static const int EXTRA_HEIGHT = 4;
+// margin between the window and the items
+static const int EXTRA_BORDER_X = 2;
+static const int EXTRA_BORDER_Y = 2;
+
// offset for the header window
static const int HEADER_OFFSET_X = 1;
static const int HEADER_OFFSET_Y = 1;
+// margin between rows of icons in [small] icon view
+static const int MARGIN_BETWEEN_ROWS = 6;
+
// when autosizing the columns, add some slack
static const int AUTOSIZE_COL_MARGIN = 10;
// the part to be highlighted
wxRect m_rectHighlight;
+
+ // extend all our rects to be centered inside theo ne of given width
+ void ExtendWidth(wxCoord w)
+ {
+ wxASSERT_MSG( m_rectAll.width <= w,
+ _T("width can only be increased") );
+
+ m_rectAll.width = w;
+ m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width)/2;
+ m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width)/2;
+ m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width)/2;
+ }
} *m_gi;
// is this item selected? [NB: not used in virtual mode]
void CalculateSize( wxDC *dc, int spacing );
// remember the position this line appears at
- void SetPosition( int x, int y, int window_width, int spacing );
+ void SetPosition( int x, int y, int spacing );
// wxListCtrl API
// do we have a header window?
bool HasHeader() const
- { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
+ { return InReportView() && !HasFlag(wxLC_NO_HEADER); }
void HighlightAll( bool on );
void SetItemState( long item, long state, long stateMask );
int GetItemState( long item, long stateMask ) const;
void GetItemRect( long index, wxRect &rect ) const;
+ wxRect GetViewRect() const;
bool GetItemPosition( long item, wxPoint& pos ) const;
int GetSelectedItemCount() const;
bool m_dirty;
wxColour *m_highlightColour;
- int m_xScroll,
- m_yScroll;
wxImageListType *m_small_image_list;
wxImageListType *m_normal_image_list;
int m_small_spacing;
// common part of all ctors
void Init();
- // intiialize m_[xy]Scroll
- void InitScrolling();
-
// get the line data for the given index
wxListLineData *GetLine(size_t n) const
{
wxListItemData *item = node->GetData();
+ wxString s;
+ wxCoord lw, lh;
+
switch ( GetMode() )
{
case wxLC_ICON:
case wxLC_SMALL_ICON:
- {
- m_gi->m_rectAll.width = spacing;
+ m_gi->m_rectAll.width = spacing;
- wxString s = item->GetText();
+ s = item->GetText();
- wxCoord lw, lh;
- if ( s.empty() )
- {
- lh =
- m_gi->m_rectLabel.width =
- m_gi->m_rectLabel.height = 0;
- }
- else // has label
- {
- dc->GetTextExtent( s, &lw, &lh );
- if (lh < SCROLL_UNIT_Y)
- lh = SCROLL_UNIT_Y;
- lw += EXTRA_WIDTH;
- lh += EXTRA_HEIGHT;
-
- m_gi->m_rectAll.height = spacing + lh;
- if (lw > spacing)
- m_gi->m_rectAll.width = lw;
-
- m_gi->m_rectLabel.width = lw;
- m_gi->m_rectLabel.height = lh;
- }
-
- if (item->HasImage())
- {
- int w, h;
- m_owner->GetImageSize( item->GetImage(), w, h );
- m_gi->m_rectIcon.width = w + 8;
- m_gi->m_rectIcon.height = h + 8;
-
- if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
- m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
- if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
- m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
- }
-
- if ( item->HasText() )
- {
- m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
- m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
- }
- else // no text, highlight the icon
- {
- m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
- m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
- }
+ if ( s.empty() )
+ {
+ lh =
+ m_gi->m_rectLabel.width =
+ m_gi->m_rectLabel.height = 0;
}
- break;
-
- case wxLC_LIST:
+ else // has label
{
- wxString s = item->GetTextForMeasuring();
-
- wxCoord lw,lh;
dc->GetTextExtent( s, &lw, &lh );
- if (lh < SCROLL_UNIT_Y)
- lh = SCROLL_UNIT_Y;
lw += EXTRA_WIDTH;
lh += EXTRA_HEIGHT;
+ m_gi->m_rectAll.height = spacing + lh;
+ if (lw > spacing)
+ m_gi->m_rectAll.width = lw;
+
m_gi->m_rectLabel.width = lw;
m_gi->m_rectLabel.height = lh;
+ }
- m_gi->m_rectAll.width = lw;
- m_gi->m_rectAll.height = lh;
+ if (item->HasImage())
+ {
+ int w, h;
+ m_owner->GetImageSize( item->GetImage(), w, h );
+ m_gi->m_rectIcon.width = w + 8;
+ m_gi->m_rectIcon.height = h + 8;
+
+ if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
+ m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
+ if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
+ m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
+ }
- if (item->HasImage())
- {
- int w, h;
- m_owner->GetImageSize( item->GetImage(), w, h );
- m_gi->m_rectIcon.width = w;
- m_gi->m_rectIcon.height = h;
-
- m_gi->m_rectAll.width += 4 + w;
- if (h > m_gi->m_rectAll.height)
- m_gi->m_rectAll.height = h;
- }
+ if ( item->HasText() )
+ {
+ m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
+ }
+ else // no text, highlight the icon
+ {
+ m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
+ }
+ break;
+
+ case wxLC_LIST:
+ s = item->GetTextForMeasuring();
+
+ dc->GetTextExtent( s, &lw, &lh );
+ lw += EXTRA_WIDTH;
+ lh += EXTRA_HEIGHT;
+
+ m_gi->m_rectLabel.width = lw;
+ m_gi->m_rectLabel.height = lh;
- m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
- m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
+ m_gi->m_rectAll.width = lw;
+ m_gi->m_rectAll.height = lh;
+
+ if (item->HasImage())
+ {
+ int w, h;
+ m_owner->GetImageSize( item->GetImage(), w, h );
+ m_gi->m_rectIcon.width = w;
+ m_gi->m_rectIcon.height = h;
+
+ m_gi->m_rectAll.width += 4 + w;
+ if (h > m_gi->m_rectAll.height)
+ m_gi->m_rectAll.height = h;
}
+
+ m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
+ m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
break;
case wxLC_REPORT:
}
}
-void wxListLineData::SetPosition( int x, int y,
- int WXUNUSED(window_width),
- int spacing )
+void wxListLineData::SetPosition( int x, int y, int spacing )
{
wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
wxCHECK_RET( node, _T("no subitems at all??") );
dc->DrawRectangle( m_gi->m_rectHighlight );
}
+ // just for debugging to better see where the items are
+#if 0
+ dc->SetPen(*wxRED_PEN);
+ dc->SetBrush(*wxTRANSPARENT_BRUSH);
+ dc->DrawRectangle( m_gi->m_rectAll );
+ dc->SetPen(*wxGREEN_PEN);
+ dc->DrawRectangle( m_gi->m_rectIcon );
+#endif // 0
+
wxListItemData *item = node->GetData();
if (item->HasImage())
{
- wxRect rectIcon = m_gi->m_rectIcon;
- m_owner->DrawImage( item->GetImage(), dc,
- rectIcon.x, rectIcon.y );
+ // centre the image inside our rectangle, this looks nicer when items
+ // ae aligned in a row
+ const wxRect& rectIcon = m_gi->m_rectIcon;
+
+ m_owner->DrawImage(item->GetImage(), dc, rectIcon.x, rectIcon.y);
}
if (item->HasText())
{
- wxRect rectLabel = m_gi->m_rectLabel;
+ const wxRect& rectLabel = m_gi->m_rectLabel;
wxDCClipper clipper(*dc, rectLabel);
- dc->DrawText( item->GetText(), rectLabel.x, rectLabel.y );
+ dc->DrawText(item->GetText(), rectLabel.x, rectLabel.y);
}
}
bool wxListLineData::Highlight( bool on )
{
- wxCHECK_MSG( !m_owner->IsVirtual(), FALSE, _T("unexpected call to Highlight") );
+ wxCHECK_MSG( !IsVirtual(), FALSE, _T("unexpected call to Highlight") );
if ( on == m_highlighted )
return FALSE;
// for this we need the width of the text
wxCoord wLabel;
- dc.GetTextExtent(item.GetText(), &wLabel, NULL);
+ wxCoord hLabel;
+ dc.GetTextExtent(item.GetText(), &wLabel, &hLabel);
wLabel += 2*EXTRA_WIDTH;
// and the width of the icon, if any
wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
dc.DrawText( item.GetText(),
- xAligned + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
+ xAligned + EXTRA_WIDTH, h / 2 - hLabel / 2 ); //HEADER_OFFSET_Y + EXTRA_HEIGHT );
x += wCol;
}
{
m_isDragging = TRUE;
m_currentX = x;
- DrawCurrent();
CaptureMouse();
+ DrawCurrent();
}
//else: column resizing was vetoed by the user code
}
void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
{
m_owner->SetFocus();
+ m_owner->Update();
}
bool wxListHeaderWindow::SendListEvent(wxEventType type, wxPoint pos)
{
// We must finish regardless of success, otherwise we'll get focus problems
Finish();
-
+
if ( !AcceptChanges() )
m_owner->OnRenameCancelled( m_itemEdited );
}
-
+
event.Skip();
}
m_freezeCount = 0;
}
-void wxListMainWindow::InitScrolling()
-{
- if ( HasFlag(wxLC_REPORT) )
- {
- m_xScroll = SCROLL_UNIT_X;
- m_yScroll = SCROLL_UNIT_Y;
- }
- else
- {
- m_xScroll = SCROLL_UNIT_Y;
- m_yScroll = 0;
- }
-}
-
wxListMainWindow::wxListMainWindow()
{
Init();
m_highlightBrush =
m_highlightUnfocusedBrush = (wxBrush *) NULL;
-
- m_xScroll =
- m_yScroll = 0;
}
wxListMainWindow::wxListMainWindow( wxWindow *parent,
wxSize sz = size;
sz.y = 25;
- InitScrolling();
- SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
+ SetScrollbars( 0, 0, 0, 0, 0, 0 );
SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_LISTBOX ) );
}
wxCoord wxListMainWindow::GetLineHeight() const
{
- wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
-
// we cache the line height as calling GetTextExtent() is slow
if ( !m_lineHeight )
{
wxCoord y;
dc.GetTextExtent(_T("H"), NULL, &y);
- if ( y < SCROLL_UNIT_Y )
- y = SCROLL_UNIT_Y;
-
if ( m_small_image_list && m_small_image_list->GetImageCount() )
{
int iw = 0;
wxCoord wxListMainWindow::GetLineY(size_t line) const
{
- wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
+ wxASSERT_MSG( InReportView(), _T("only works in report mode") );
return LINE_SPACING + line*GetLineHeight();
}
void wxListMainWindow::RefreshLine( size_t line )
{
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
size_t visibleFrom, visibleTo;
GetVisibleLinesRange(&visibleFrom, &visibleTo);
wxASSERT_MSG( lineTo < GetItemCount(), _T("invalid line range") );
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
size_t visibleFrom, visibleTo;
GetVisibleLinesRange(&visibleFrom, &visibleTo);
void wxListMainWindow::RefreshAfter( size_t lineFrom )
{
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
size_t visibleFrom, visibleTo;
GetVisibleLinesRange(&visibleFrom, &visibleTo);
dc.SetFont( GetFont() );
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
int lineHeight = GetLineHeight();
{
wxPen pen(GetRuleColour(), 1, wxSOLID);
- int col = 0;
wxRect firstItemRect;
wxRect lastItemRect;
GetItemRect(visibleFrom, firstItemRect);
int x = firstItemRect.GetX();
dc.SetPen(pen);
dc.SetBrush(* wxTRANSPARENT_BRUSH);
- for (col = 0; col < GetColumnCount(); col++)
+ for (int col = 0; col < GetColumnCount(); col++)
{
int colWidth = GetColumnWidth(col);
x += colWidth;
}
}
+#ifndef __WXMAC__
+ // Don't draw rect outline under Mac at all.
if ( HasCurrent() )
{
- // don't draw rect outline under Max if we already have the background
- // color but under other platforms only draw it if we do: it is a bit
- // silly to draw "focus rect" if we don't have focus!
-#ifdef __WXMAC__
- if ( !m_hasFocus )
-#else // !__WXMAC__
if ( m_hasFocus )
-#endif // __WXMAC__/!__WXMAC__
{
dc.SetPen( *wxBLACK_PEN );
dc.SetBrush( *wxTRANSPARENT_BRUSH );
dc.DrawRectangle( GetLineHighlightRect(m_current) );
}
}
+#endif
dc.EndDrawing();
}
le.IsAllowed();
}
-#ifdef __VMS__ // Ignore unreacheable code
-# pragma message disable initnotreach
-#endif
-
void wxListMainWindow::OnRenameCancelled(size_t itemEdit)
{
- // wxMSW seems not to notify the program about
- // cancelled label edits.
- return;
-
// let owner know that the edit was cancelled
wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
-
- // These only exist for wxTreeCtrl, which should probably be changed
- // le.m_editCancelled = TRUE;
- // le.m_label = wxEmptyString;
-
+
+ le.SetEditCanceled(TRUE);
+
le.SetEventObject( GetParent() );
le.m_itemIndex = itemEdit;
GetEventHandler()->ProcessEvent( le );
}
-#ifdef __VMS__
-# pragma message enable initnotreach
-#endif
void wxListMainWindow::OnMouse( wxMouseEvent &event )
{
size_t count = GetItemCount(),
current;
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
current = y / GetLineHeight();
if ( current < count )
int client_w, client_h;
GetClientSize( &client_w, &client_h );
- int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
- int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
+ const int hLine = GetLineHeight();
+
+ int view_x = SCROLL_UNIT_X*GetScrollPos( wxHORIZONTAL );
+ int view_y = hLine*GetScrollPos( wxVERTICAL );
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
// the next we need the range of lines shown it might be different, so
// recalculate it
ResetVisibleLinesRange();
if (rect.y < view_y )
- Scroll( -1, rect.y/m_yScroll );
+ Scroll( -1, rect.y/hLine );
if (rect.y+rect.height+5 > view_y+client_h)
- Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
+ Scroll( -1, (rect.y+rect.height-client_h+hLine)/hLine );
}
else // !report
{
if (rect.x-view_x < 5)
- Scroll( (rect.x-5)/m_xScroll, -1 );
+ Scroll( (rect.x-5)/SCROLL_UNIT_X, -1 );
if (rect.x+rect.width-5 > view_x+client_w)
- Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
+ Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/SCROLL_UNIT_X, -1 );
}
}
{
ChangeCurrent(newCurrent);
+ // refresh the old focus to remove it
+ RefreshLine( oldCurrent );
+
// select all the items between the old and the new one
if ( oldCurrent > newCurrent )
{
HighlightAll(FALSE);
ChangeCurrent(newCurrent);
-
+
// refresh the old focus to remove it
RefreshLine( oldCurrent );
HighlightLine( m_current, TRUE );
}
}
-
+
RefreshLine( m_current );
MoveToFocus();
case WXK_PRIOR:
{
- int steps = 0;
- if ( HasFlag(wxLC_REPORT) )
- {
- steps = m_linesPerPage - 1;
- }
- else
- {
- steps = m_current % m_linesPerPage;
- }
+ int steps = InReportView() ? m_linesPerPage - 1 : m_current % m_linesPerPage;
int index = m_current - steps;
if (index < 0)
case WXK_NEXT:
{
- int steps = 0;
- if ( HasFlag(wxLC_REPORT) )
- {
- steps = m_linesPerPage - 1;
- }
- else
- {
- steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
- }
+ int steps = InReportView()
+ ? m_linesPerPage - 1
+ : m_linesPerPage - (m_current % m_linesPerPage) - 1;
size_t index = m_current + steps;
size_t count = GetItemCount();
break;
case WXK_LEFT:
- if ( !HasFlag(wxLC_REPORT) )
+ if ( !InReportView() )
{
int index = m_current - m_linesPerPage;
if (index < 0)
break;
case WXK_RIGHT:
- if ( !HasFlag(wxLC_REPORT) )
+ if ( !InReportView() )
{
size_t index = m_current + m_linesPerPage;
void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
{
+ if ( GetParent() )
+ {
+ wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
+ event.SetEventObject( GetParent() );
+ if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+ return;
+ }
+
// wxGTK sends us EVT_SET_FOCUS events even if we had never got
// EVT_KILL_FOCUS before which means that we finish by redrawing the items
// which are already drawn correctly resulting in horrible flicker - avoid
RefreshSelected();
}
-
- if ( !GetParent() )
- return;
-
- wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
- event.SetEventObject( GetParent() );
- GetParent()->GetEventHandler()->ProcessEvent( event );
}
void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
{
+ if ( GetParent() )
+ {
+ wxFocusEvent event( wxEVT_KILL_FOCUS, GetParent()->GetId() );
+ event.SetEventObject( GetParent() );
+ if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
+ return;
+ }
m_hasFocus = FALSE;
-
RefreshSelected();
}
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
}
- else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
+ else if ( InReportView() && (m_small_image_list))
{
m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
}
{
m_small_image_list->GetSize( index, width, height );
}
- else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
+ else if ( InReportView() && m_small_image_list )
{
m_small_image_list->GetSize( index, width, height );
}
wxCHECK_RET( col >= 0 && col < GetColumnCount(),
_T("invalid column index") );
- wxCHECK_RET( HasFlag(wxLC_REPORT),
+ wxCHECK_RET( InReportView(),
_T("SetColumnWidth() can only be called in report mode.") );
m_dirty = TRUE;
// item position/size
// ----------------------------------------------------------------------------
+wxRect wxListMainWindow::GetViewRect() const
+{
+ wxASSERT_MSG( !HasFlag(wxLC_REPORT | wxLC_LIST),
+ _T("wxListCtrl::GetViewRect() only works in icon mode") );
+
+ // we need to find the longest/tallest label
+ wxCoord xMax = 0,
+ yMax = 0;
+ const int count = GetItemCount();
+ if ( count )
+ {
+ for ( int i = 0; i < count; i++ )
+ {
+ wxRect r;
+ GetItemRect(i, r);
+
+ wxCoord x = r.GetRight(),
+ y = r.GetBottom();
+
+ if ( x > xMax )
+ xMax = x;
+ if ( y > yMax )
+ yMax = y;
+ }
+ }
+
+ // some fudge needed to make it look prettier
+ xMax += 2*EXTRA_BORDER_X;
+ yMax += 2*EXTRA_BORDER_Y;
+
+ // account for the scrollbars if necessary
+ const wxSize sizeAll = GetClientSize();
+ if ( xMax > sizeAll.x )
+ yMax += wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
+ if ( yMax > sizeAll.y )
+ xMax += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
+
+ return wxRect(0, 0, xMax, yMax);
+}
+
void wxListMainWindow::GetItemRect( long index, wxRect &rect ) const
{
wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
wxClientDC dc( this );
dc.SetFont( GetFont() );
+ const size_t count = GetItemCount();
+
int iconSpacing;
if ( HasFlag(wxLC_ICON) )
iconSpacing = m_normal_spacing;
clientHeight;
GetSize( &clientWidth, &clientHeight );
- if ( HasFlag(wxLC_REPORT) )
- {
- // all lines have the same height
- int lineHeight = GetLineHeight();
-
- // scroll one line per step
- m_yScroll = lineHeight;
+ const int lineHeight = GetLineHeight();
- size_t lineCount = GetItemCount();
- int entireHeight = lineCount*lineHeight + LINE_SPACING;
+ if ( InReportView() )
+ {
+ // all lines have the same height and we scroll one line per step
+ int entireHeight = count*lineHeight + LINE_SPACING;
m_linesPerPage = clientHeight / lineHeight;
ResetVisibleLinesRange();
- SetScrollbars( m_xScroll, m_yScroll,
- GetHeaderWidth() / m_xScroll,
- (entireHeight + m_yScroll - 1)/m_yScroll,
+ SetScrollbars( SCROLL_UNIT_X, lineHeight,
+ GetHeaderWidth() / SCROLL_UNIT_X,
+ (entireHeight + lineHeight - 1) / lineHeight,
GetScrollPos(wxHORIZONTAL),
GetScrollPos(wxVERTICAL),
TRUE );
}
else // !report
{
- // at first we try without any scrollbar. if the items don't
- // fit into the window, we recalculate after subtracting an
- // approximated 15 pt for the horizontal scrollbar
-
- int entireWidth = 0;
-
- for (int tries = 0; tries < 2; tries++)
+ // we have 3 different layout strategies: either layout all items
+ // horizontally/vertically (wxLC_ALIGN_XXX styles explicitly given) or
+ // to arrange them in top to bottom, left to right (don't ask me why
+ // not the other way round...) order
+ if ( HasFlag(wxLC_ALIGN_LEFT | wxLC_ALIGN_TOP) )
{
- // We start with 4 for the border around all items
- entireWidth = 4;
-
- if (tries == 1)
- {
- // Now we have decided that the items do not fit into the
- // client area. Unfortunately, wxWindows sometimes thinks
- // that it does fit and therefore NO horizontal scrollbar
- // is inserted. This looks ugly, so we fudge here and make
- // the calculated width bigger than was actually has been
- // calculated. This ensures that wxScrolledWindows puts
- // a scrollbar at the bottom of its client area.
- entireWidth += SCROLL_UNIT_X;
- }
+ int x = EXTRA_BORDER_X;
+ int y = EXTRA_BORDER_Y;
- // Start at 2,2 so the text does not touch the border
- int x = 2;
- int y = 2;
- int maxWidth = 0;
- m_linesPerPage = 0;
- int currentlyVisibleLines = 0;
+ wxCoord widthMax = 0;
- size_t count = GetItemCount();
- for (size_t i = 0; i < count; i++)
+ size_t i;
+ for ( i = 0; i < count; i++ )
{
- currentlyVisibleLines++;
wxListLineData *line = GetLine(i);
line->CalculateSize( &dc, iconSpacing );
- line->SetPosition( x, y, clientWidth, iconSpacing ); // Why clientWidth? (FIXME)
+ line->SetPosition( x, y, iconSpacing );
wxSize sizeLine = GetLineSize(i);
- if ( maxWidth < sizeLine.x )
- maxWidth = sizeLine.x;
+ if ( HasFlag(wxLC_ALIGN_TOP) )
+ {
+ if ( sizeLine.x > widthMax )
+ widthMax = sizeLine.x;
- y += sizeLine.y;
- if (currentlyVisibleLines > m_linesPerPage)
- m_linesPerPage = currentlyVisibleLines;
+ y += sizeLine.y;
+ }
+ else // wxLC_ALIGN_LEFT
+ {
+ x += sizeLine.x + MARGIN_BETWEEN_ROWS;
+ }
+ }
- // Assume that the size of the next one is the same... (FIXME)
- if ( y + sizeLine.y >= clientHeight )
+ if ( HasFlag(wxLC_ALIGN_TOP) )
+ {
+ // traverse the items again and tweak their sizes so that they are
+ // all the same in a row
+ for ( i = 0; i < count; i++ )
{
- currentlyVisibleLines = 0;
- y = 2;
- x += maxWidth+6;
- entireWidth += maxWidth+6;
- maxWidth = 0;
+ wxListLineData *line = GetLine(i);
+ line->m_gi->ExtendWidth(widthMax);
}
+ }
+
- // We have reached the last item.
- if ( i == count - 1 )
- entireWidth += maxWidth;
+ SetScrollbars
+ (
+ SCROLL_UNIT_X,
+ lineHeight,
+ (x + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+ (y + lineHeight) / lineHeight,
+ GetScrollPos( wxHORIZONTAL ),
+ GetScrollPos( wxVERTICAL ),
+ TRUE
+ );
+ }
+ else // "flowed" arrangement, the most complicated case
+ {
+ // at first we try without any scrollbars, if the items don't fit into
+ // the window, we recalculate after subtracting the space taken by the
+ // scrollbar
- if ( (tries == 0) && (entireWidth+SCROLL_UNIT_X > clientWidth) )
+ int entireWidth = 0;
+
+ for (int tries = 0; tries < 2; tries++)
+ {
+ entireWidth = 2*EXTRA_BORDER_X;
+
+ if (tries == 1)
{
- clientHeight -= 15; // We guess the scrollbar height. (FIXME)
- m_linesPerPage = 0;
- currentlyVisibleLines = 0;
- break;
+ // Now we have decided that the items do not fit into the
+ // client area, so we need a scrollbar
+ entireWidth += SCROLL_UNIT_X;
}
- if ( i == count - 1 )
- tries = 1; // Everything fits, no second try required.
+ int x = EXTRA_BORDER_X;
+ int y = EXTRA_BORDER_Y;
+ int maxWidthInThisRow = 0;
+
+ m_linesPerPage = 0;
+ int currentlyVisibleLines = 0;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ currentlyVisibleLines++;
+ wxListLineData *line = GetLine(i);
+ line->CalculateSize( &dc, iconSpacing );
+ line->SetPosition( x, y, iconSpacing );
+
+ wxSize sizeLine = GetLineSize(i);
+
+ if ( maxWidthInThisRow < sizeLine.x )
+ maxWidthInThisRow = sizeLine.x;
+
+ y += sizeLine.y;
+ if (currentlyVisibleLines > m_linesPerPage)
+ m_linesPerPage = currentlyVisibleLines;
+
+ if ( y + sizeLine.y >= clientHeight )
+ {
+ currentlyVisibleLines = 0;
+ y = EXTRA_BORDER_Y;
+ maxWidthInThisRow += MARGIN_BETWEEN_ROWS;
+ x += maxWidthInThisRow;
+ entireWidth += maxWidthInThisRow;
+ maxWidthInThisRow = 0;
+ }
+
+ // We have reached the last item.
+ if ( i == count - 1 )
+ entireWidth += maxWidthInThisRow;
+
+ if ( (tries == 0) &&
+ (entireWidth + SCROLL_UNIT_X > clientWidth) )
+ {
+ clientHeight -= wxSystemSettings::
+ GetMetric(wxSYS_HSCROLL_Y);
+ m_linesPerPage = 0;
+ break;
+ }
+
+ if ( i == count - 1 )
+ tries = 1; // Everything fits, no second try required.
+ }
}
- }
- int scroll_pos = GetScrollPos( wxHORIZONTAL );
- SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
+ SetScrollbars
+ (
+ SCROLL_UNIT_X,
+ lineHeight,
+ (entireWidth + SCROLL_UNIT_X) / SCROLL_UNIT_X,
+ 0,
+ GetScrollPos( wxHORIZONTAL ),
+ 0,
+ TRUE
+ );
+ }
}
if ( !noRefresh )
size_t count = GetItemCount();
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
size_t current = y / GetLineHeight();
if ( current < count )
m_dirty = TRUE;
+ #if 0
+ // this is unused variable
int mode = 0;
- if ( HasFlag(wxLC_REPORT) )
+ #endif
+ if ( InReportView() )
{
+ #if 0
+ // this is unused variable
mode = wxLC_REPORT;
+ #endif
ResetVisibleLinesRange();
}
else if ( HasFlag(wxLC_LIST) )
+ #if 0
+ // this is unused variable
mode = wxLC_LIST;
+ #else
+ {}
+ #endif
else if ( HasFlag(wxLC_ICON) )
+ #if 0
+ // this is unused variable
mode = wxLC_ICON;
+ #else
+ {}
+ #endif
else if ( HasFlag(wxLC_SMALL_ICON) )
+ #if 0
+ // this is unused variable
mode = wxLC_ICON; // no typo
+ #else
+ {}
+ #endif
else
{
wxFAIL_MSG( _T("unknown mode") );
m_dirty = TRUE;
+ // If an item is selected at or below the point of insertion, we need to
+ // increment the member variables because the current row's index has gone
+ // up by one
+ if ( HasCurrent() && m_current >= id )
+ {
+ m_current++;
+ }
+
SendNotify(id, wxEVT_COMMAND_LIST_INSERT_ITEM);
RefreshLines(id, GetItemCount() - 1);
void wxListMainWindow::InsertColumn( long col, wxListItem &item )
{
m_dirty = TRUE;
- if ( HasFlag(wxLC_REPORT) )
+ if ( InReportView() )
{
if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
item.m_width = GetTextLength( item.m_text );
void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
{
- wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
+ wxASSERT_MSG( InReportView(), _T("this is for report mode only") );
if ( m_lineFrom == (size_t)-1 )
{
void wxGenericListCtrl::CalculateAndSetHeaderHeight()
{
- // we use the letter "H" for calculating the needed space, basing on the current font
- int w, h;
- m_headerWin->GetTextExtent(wxT("H"), &w, &h);
- m_headerHeight = h + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
- m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight);
+ if ( m_headerWin )
+ {
+ // we use 'g' to get the descent, too
+ int w, h, d;
+ m_headerWin->GetTextExtent(wxT("Hg"), &w, &h, &d);
+ h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
+
+ // only update if changed
+ if ( h != m_headerHeight )
+ {
+ m_headerHeight = h;
+
+ m_headerWin->SetSize(m_headerWin->GetSize().x, m_headerHeight);
+
+ if ( HasHeader() )
+ ResizeReportView(TRUE);
+ }
+ }
}
void wxGenericListCtrl::CreateHeaderWindow()
m_mainWin = (wxListMainWindow*) NULL;
m_headerWin = (wxListHeaderWindow*) NULL;
+ m_headerHeight = 0;
+
if ( !(style & wxLC_MASK_TYPE) )
{
style = style | wxLC_LIST;
m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
- if ( HasFlag(wxLC_REPORT) )
+#if defined( __WXMAC__ ) && __WXMAC_CARBON__
+ wxFont font ;
+ font.MacCreateThemeFont( kThemeViewsFont ) ;
+ SetFont( font ) ;
+#endif
+ if ( InReportView() )
{
CreateHeaderWindow();
m_mainWin->DeleteEverything();
// has the header visibility changed?
- bool hasHeader = HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER),
- willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
+ bool hasHeader = HasHeader();
+ bool willHaveHeader = (flag & wxLC_REPORT) && !(flag & wxLC_NO_HEADER);
if ( hasHeader != willHaveHeader )
{
return TRUE;
}
+wxRect wxGenericListCtrl::GetViewRect() const
+{
+ return m_mainWin->GetViewRect();
+}
+
bool wxGenericListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
{
m_mainWin->GetItemRect( item, rect );
m_mainWin->SetItemSpacing( spacing, isSmall );
}
+wxSize wxGenericListCtrl::GetItemSpacing() const
+{
+ const int spacing = m_mainWin->GetItemSpacing(HasFlag(wxLC_SMALL_ICON));
+
+ return wxSize(spacing, spacing);
+}
+
int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const
{
return m_mainWin->GetItemSpacing( isSmall );
void wxGenericListCtrl::OnInternalIdle()
{
wxWindow::OnInternalIdle();
-
+
// do it only if needed
if ( !m_mainWin->m_dirty )
return;
return -1;
}
-wxListItemAttr *wxGenericListCtrl::OnGetItemAttr(long item) const
+wxListItemAttr *
+wxGenericListCtrl::OnGetItemAttr(long WXUNUSED_UNLESS_DEBUG(item)) const
{
wxASSERT_MSG( item >= 0 && item < GetItemCount(),
_T("invalid item index in OnGetItemAttr()") );