/////////////////////////////////////////////////////////////////////////////
-// Name: generic/listctrl.cpp
+// Name: src/generic/listctrl.cpp
// Purpose: generic implementation of wxListCtrl
// Author: Robert Roebling
// Vadim Zeitlin (virtual list control support)
#include "wx/wxprec.h"
#ifdef __BORLANDC__
-#pragma hdrstop
+ #pragma hdrstop
#endif
#if wxUSE_LISTCTRL
-#ifndef WX_PRECOMP
- #include "wx/app.h"
- #include "wx/dynarray.h"
- #include "wx/dcscreen.h"
- #include "wx/textctrl.h"
-#endif
-
-// under Win32 we always use the native version and also may use the generic
-// one, however some things should be done only if we use only the generic
-// version
-#if defined(__WIN32__) && !defined(__WXUNIVERSAL__)
- #define HAVE_NATIVE_LISTCTRL
-#endif
-
-// if we have the native control, wx/listctrl.h declares it and not this one
-#ifdef HAVE_NATIVE_LISTCTRL
- #include "wx/generic/listctrl.h"
-#else // !HAVE_NATIVE_LISTCTRL
- #include "wx/listctrl.h"
+#include "wx/listctrl.h"
+#if (!defined(__WXMSW__) || defined(__WXUNIVERSAL__)) && !defined(__WXMAC__)
// if we have a native version, its implementation file does all this
IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxGenericListCtrl)
-#endif // HAVE_NATIVE_LISTCTRL/!HAVE_NATIVE_LISTCTRL
+#endif
+#ifndef WX_PRECOMP
+ #include "wx/scrolwin.h"
+ #include "wx/timer.h"
+ #include "wx/settings.h"
+ #include "wx/dynarray.h"
+ #include "wx/dcclient.h"
+ #include "wx/dcscreen.h"
+ #include "wx/math.h"
+#endif
+
+#include "wx/imaglist.h"
#include "wx/selstore.h"
#include "wx/renderer.h"
-#include "wx/math.h"
#ifdef __WXMAC__
#include "wx/mac/private.h"
#define _USE_VISATTR 0
-// ----------------------------------------------------------------------------
-// events
-// ----------------------------------------------------------------------------
-
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
-#if WXWIN_COMPATIBILITY_2_4
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
-#endif
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
-DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
-
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// draw the text on the DC with the correct justification; also add an
// ellipsis if the text is too large to fit in the current width
- void DrawTextFormatted(wxDC *dc, const wxString &text, int col, int x, int y, int width);
+ void DrawTextFormatted(wxDC *dc,
+ const wxString &text,
+ int col,
+ int x,
+ int yMid, // this is middle, not top, of the text
+ int width);
};
WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
{
protected:
wxListMainWindow *m_owner;
- wxCursor *m_currentCursor;
+ const wxCursor *m_currentCursor;
wxCursor *m_resizeCursor;
bool m_isDragging;
void GetImageSize( int index, int &width, int &height ) const;
int GetTextLength( const wxString &s ) const;
- void SetImageList( wxImageListType *imageList, int which );
+ void SetImageList( wxImageList *imageList, int which );
void SetItemSpacing( int spacing, bool isSmall = false );
int GetItemSpacing( bool isSmall = false );
long FindItem( long start, const wxString& str, bool partial = false );
long FindItem( long start, wxUIntPtr data);
long FindItem( const wxPoint& pt );
- long HitTest( int x, int y, int &flags );
+ long HitTest( int x, int y, int &flags ) const;
void InsertItem( wxListItem &item );
void InsertColumn( long col, wxListItem &item );
int GetItemWidthWithImage(wxListItem * item);
bool m_dirty;
wxColour *m_highlightColour;
- wxImageListType *m_small_image_list;
- wxImageListType *m_normal_image_list;
+ wxImageList *m_small_image_list;
+ wxImageList *m_normal_image_list;
int m_small_spacing;
int m_normal_spacing;
bool m_hasFocus;
if ( info.HasAttributes() )
{
if ( m_attr )
- *m_attr = *info.GetAttributes();
+ m_attr->AssignFrom(*info.GetAttributes());
else
m_attr = new wxListItemAttr(*info.GetAttributes());
}
{
wxCHECK_MSG( m_rect, false, _T("can't be called in this mode") );
- return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x, y);
+ return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Contains(x, y);
}
int wxListItemData::GetX() const
// arithmetics on wxColour, unfortunately)
wxColour colText;
if ( highlighted )
+#ifdef __WXMAC__
+ colText = *wxWHITE;
+#else
colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+#endif
else if ( attr && attr->HasTextColour() )
colText = attr->GetTextColour();
else
dc->DrawRectangle( rectHL );
wxCoord x = rect.x + HEADER_OFFSET_X,
- y = rect.y + (LINE_SPACING + EXTRA_HEIGHT) / 2;
+ yMid = rect.y + rect.height/2;
size_t col = 0;
for ( wxListItemDataList::compatibility_iterator node = m_items.GetFirst();
if ( item->HasImage() )
{
int ix, iy;
- m_owner->DrawImage( item->GetImage(), dc, xOld, y );
m_owner->GetImageSize( item->GetImage(), ix, iy );
+ m_owner->DrawImage( item->GetImage(), dc, xOld, yMid - iy/2 );
ix += IMAGE_MARGIN_IN_REPORT_MODE;
width -= ix;
}
- wxDCClipper clipper(*dc, xOld, y, width - 8, rect.height);
-
if ( item->HasText() )
- DrawTextFormatted(dc, item->GetText(), col, xOld, y, width - 8);
+ DrawTextFormatted(dc, item->GetText(), col, xOld, yMid, width - 8);
}
}
const wxString &text,
int col,
int x,
- int y,
+ int yMid,
int width)
{
- wxString drawntext, ellipsis;
- wxCoord w, h, base_w;
- wxListItem item;
+ wxCoord w, h;
+ dc->GetTextExtent(text, &w, &h);
+
+ const wxCoord y = yMid - (h + 1)/2;
+
+ wxDCClipper clipper(*dc, x, y, width, h);
// determine if the string can fit inside the current width
- dc->GetTextExtent(text, &w, &h);
if (w <= width)
{
// it can, draw it using the items alignment
+ wxListItem item;
m_owner->GetColumn(col, item);
switch ( item.GetAlign() )
{
else // otherwise, truncate and add an ellipsis if possible
{
// determine the base width
- ellipsis = wxString(wxT("..."));
+ wxString ellipsis(wxT("..."));
+ wxCoord base_w;
dc->GetTextExtent(ellipsis, &base_w, &h);
// continue until we have enough space or only one character left
wxCoord w_c, h_c;
- size_t len = text.Length();
- drawntext = text.Left(len);
+ size_t len = text.length();
+ wxString drawntext = text.Left(len);
while (len > 1)
{
dc->GetTextExtent(drawntext.Last(), &w_c, &h_c);
}
// if still not enough space, remove ellipsis characters
- while (ellipsis.Length() > 0 && w + base_w > width)
+ while (ellipsis.length() > 0 && w + base_w > width)
{
- ellipsis = ellipsis.Left(ellipsis.Length() - 1);
+ ellipsis = ellipsis.Left(ellipsis.length() - 1);
dc->GetTextExtent(ellipsis, &base_w, &h);
}
int xpix;
m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
- int x;
- m_owner->GetViewStart( &x, NULL );
+ int view_start;
+ m_owner->GetViewStart( &view_start, NULL );
+
+
+ int org_x = 0;
+ int org_y = 0;
+ dc.GetDeviceOrigin( &org_x, &org_y );
// account for the horz scrollbar offset
- dc.SetDeviceOrigin( -x * xpix, 0 );
+#ifdef __WXGTK__
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ // Maybe we just have to check for m_signX
+ // in the DC, but I leave the #ifdef __WXGTK__
+ // for now
+ dc.SetDeviceOrigin( org_x + (view_start * xpix), org_y );
+ }
+ else
+#endif
+ dc.SetDeviceOrigin( org_x - (view_start * xpix), org_y );
}
void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
static const int MARGIN_BETWEEN_TEXT_AND_ICON = 2;
int ix = 0, iy = 0; // init them just to suppress the compiler warnings
const int image = item.m_image;
- wxImageListType *imageList;
+ wxImageList *imageList;
if ( image != -1 )
{
imageList = m_owner->m_small_image_list;
m_text->Create(owner, wxID_ANY, m_startValue,
wxPoint(rectLabel.x-4,rectLabel.y-4),
wxSize(rectLabel.width+11,rectLabel.height+8));
+ m_text->SetFocus();
+
m_text->PushEventHandler(this);
}
{
m_finished = true;
- m_text->PopEventHandler(this);
+ m_text->RemoveEventHandler(this);
m_owner->FinishEditing(m_text);
- delete this;
+ wxPendingDelete.Append( this );
}
}
break;
case WXK_ESCAPE:
- Finish();
m_owner->OnRenameCancelled( m_itemEdited );
+ Finish();
break;
default:
{
if ( !m_finished && !m_aboutToFinish )
{
- // We must finish regardless of success, otherwise we'll get
- // focus problems:
- Finish();
-
if ( !AcceptChanges() )
m_owner->OnRenameCancelled( m_itemEdited );
+
+ Finish();
}
- // We must let the native text control handle focus, too, otherwise
- // it could have problems with the cursor (e.g., in wxGTK).
+ // We must let the native text control handle focus
event.Skip();
}
m_headerWidth =
m_lineHeight = 0;
- m_small_image_list = (wxImageListType *) NULL;
- m_normal_image_list = (wxImageListType *) NULL;
+ m_small_image_list = (wxImageList *) NULL;
+ m_normal_image_list = (wxImageList *) NULL;
m_small_spacing = 30;
m_normal_spacing = 40;
{
Init();
+
+#ifdef __WXMAC__
+ // OS X sel item highlight color differs from text highlight color, which is
+ // what wxSYS_COLOUR_HIGHLIGHT returns.
+ RGBColor hilight;
+ GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &hilight);
+ m_highlightBrush = new wxBrush( wxColour(hilight.red, hilight.green, hilight.blue ), wxSOLID );
+#else
m_highlightBrush = new wxBrush
- (
+ (
wxSystemSettings::GetColour
(
wxSYS_COLOUR_HIGHLIGHT
),
wxSOLID
- );
+ );
+#endif
+#ifdef __WXMAC__
+ // on Mac, this color also differs from the wxSYS_COLOUR_BTNSHADOW, enough to be noticable.
+ // I don't know if BTNSHADOW is appropriate in other contexts, so I'm just changing it here.
+ GetThemeBrushAsColor(kThemeBrushSecondaryHighlightColor, 32, true, &hilight);
+ m_highlightUnfocusedBrush = new wxBrush( wxColour(hilight.red, hilight.green, hilight.blue ), wxSOLID );
+#else
m_highlightUnfocusedBrush = new wxBrush
- (
- wxSystemSettings::GetColour
- (
- wxSYS_COLOUR_BTNSHADOW
- ),
- wxSOLID
- );
+ (
+ wxSystemSettings::GetColour
+ (
+ wxSYS_COLOUR_BTNSHADOW
+ ),
+ wxSOLID
+ );
+#endif
SetScrollbars( 0, 0, 0, 0, 0, 0 );
wxListLineData *ld = GetLine(line);
- if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
+ if ( ld->HasImage() && GetLineIconRect(line).Contains(x, y) )
return wxLIST_HITTEST_ONITEMICON;
// VS: Testing for "ld->HasText() || InReportView()" instead of
wxRect rect = InReportView() ? GetLineRect(line)
: GetLineLabelRect(line);
- if ( rect.Inside(x, y) )
+ if ( rect.Contains(x, y) )
return wxLIST_HITTEST_ONITEMLABEL;
}
GetVisibleLinesRange(&visibleFrom, &visibleTo);
wxRect rectLine;
- wxCoord xOrig, yOrig;
- CalcUnscrolledPosition(0, 0, &xOrig, &yOrig);
-
+ int xOrig = dc.LogicalToDeviceX( 0 );
+ int yOrig = dc.LogicalToDeviceY( 0 );
+
// tell the caller cache to cache the data
if ( IsVirtual() )
{
{
rectLine = GetLineRect(line);
- if ( !IsExposed(rectLine.x - xOrig, rectLine.y - yOrig,
+
+ if ( !IsExposed(rectLine.x + xOrig, rectLine.y + yOrig,
rectLine.width, rectLine.height) )
{
// don't redraw unaffected lines to avoid flicker
void wxListMainWindow::OnMouse( wxMouseEvent &event )
{
+
#ifdef __WXMAC__
// On wxMac we can't depend on the EVT_KILL_FOCUS event to properly
// shutdown the edit control when the mouse is clicked elsewhere on the
}
if ( !HasCurrent() || IsEmpty() )
+ {
+ if (event.RightDown())
+ {
+ SendNotify( (size_t)-1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
+ // Allow generation of context menu event
+ event.Skip();
+ }
return;
+ }
if (m_dirty)
return;
if ( !hitResult )
{
// outside of any item
+ if (event.RightDown())
+ {
+ SendNotify( (size_t) -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, event.GetPosition() );
+ // Allow generation of context menu event
+ event.Skip();
+ }
+ else
+ {
+ // reset the selection and bail out
+ HighlightAll(false);
+ }
+
return;
}
return;
}
- switch (event.GetKeyCode())
+ // don't use m_linesPerPage directly as it might not be computed yet
+ const int pageSize = GetCountPerPage();
+ wxCHECK_RET( pageSize, _T("should have non zero page size") );
+
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ if (event.GetKeyCode() == WXK_RIGHT)
+ event.m_keyCode = WXK_LEFT;
+ else if (event.GetKeyCode() == WXK_LEFT)
+ event.m_keyCode = WXK_RIGHT;
+ }
+
+ switch ( event.GetKeyCode() )
{
case WXK_UP:
if ( m_current > 0 )
OnArrowChar( 0, event );
break;
- case WXK_PRIOR:
+ case WXK_PAGEUP:
{
- int steps = InReportView() ? m_linesPerPage - 1 : m_current % m_linesPerPage;
+ int steps = InReportView() ? pageSize - 1
+ : m_current % pageSize;
int index = m_current - steps;
if (index < 0)
}
break;
- case WXK_NEXT:
+ case WXK_PAGEDOWN:
{
int steps = InReportView()
- ? m_linesPerPage - 1
- : m_linesPerPage - (m_current % m_linesPerPage) - 1;
+ ? pageSize - 1
+ : pageSize - (m_current % pageSize) - 1;
size_t index = m_current + steps;
size_t count = GetItemCount();
case WXK_LEFT:
if ( !InReportView() )
{
- int index = m_current - m_linesPerPage;
+ int index = m_current - pageSize;
if (index < 0)
index = 0;
case WXK_RIGHT:
if ( !InReportView() )
{
- size_t index = m_current + m_linesPerPage;
+ size_t index = m_current + pageSize;
size_t count = GetItemCount();
if ( index >= count )
return lw + AUTOSIZE_COL_MARGIN;
}
-void wxListMainWindow::SetImageList( wxImageListType *imageList, int which )
+void wxListMainWindow::SetImageList( wxImageList *imageList, int which )
{
m_dirty = true;
void wxListMainWindow::RecalculatePositions(bool noRefresh)
{
+ const int lineHeight = GetLineHeight();
+
wxClientDC dc( this );
dc.SetFont( GetFont() );
clientHeight;
GetSize( &clientWidth, &clientHeight );
- const int lineHeight = GetLineHeight();
-
if ( InReportView() )
{
// all lines have the same height and we scroll one line per step
return wxNOT_FOUND;
}
-long wxListMainWindow::HitTest( int x, int y, int &flags )
+long wxListMainWindow::HitTest( int x, int y, int &flags ) const
{
CalcUnscrolledPosition( x, y, &x, &y );
wxGenericListCtrl::wxGenericListCtrl()
{
- m_imageListNormal = (wxImageListType *) NULL;
- m_imageListSmall = (wxImageListType *) NULL;
- m_imageListState = (wxImageListType *) NULL;
+ m_imageListNormal = (wxImageList *) NULL;
+ m_imageListSmall = (wxImageList *) NULL;
+ m_imageListState = (wxImageList *) NULL;
m_ownsImageListNormal =
m_ownsImageListSmall =
{
m_imageListNormal =
m_imageListSmall =
- m_imageListState = (wxImageListType *) NULL;
+ m_imageListState = (wxImageList *) NULL;
m_ownsImageListNormal =
m_ownsImageListSmall =
m_ownsImageListState = false;
bool
wxGenericListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
+{
+ return SetItemColumnImage(item, 0, image);
+}
+
+bool
+wxGenericListCtrl::SetItemColumnImage( long item, long column, int image )
{
wxListItem info;
info.m_image = image;
info.m_mask = wxLIST_MASK_IMAGE;
info.m_itemId = item;
+ info.m_col = column;
m_mainWin->SetItem( info );
return true;
}
return wxSize(spacing, spacing);
}
+#if WXWIN_COMPATIBILITY_2_6
int wxGenericListCtrl::GetItemSpacing( bool isSmall ) const
{
return m_mainWin->GetItemSpacing( isSmall );
}
+#endif // WXWIN_COMPATIBILITY_2_6
void wxGenericListCtrl::SetItemTextColour( long item, const wxColour &col )
{
return m_mainWin->GetNextItem( item, geom, state );
}
-wxImageListType *wxGenericListCtrl::GetImageList(int which) const
+wxImageList *wxGenericListCtrl::GetImageList(int which) const
{
if (which == wxIMAGE_LIST_NORMAL)
return m_imageListNormal;
else if (which == wxIMAGE_LIST_STATE)
return m_imageListState;
- return (wxImageListType *) NULL;
+ return (wxImageList *) NULL;
}
-void wxGenericListCtrl::SetImageList( wxImageListType *imageList, int which )
+void wxGenericListCtrl::SetImageList( wxImageList *imageList, int which )
{
if ( which == wxIMAGE_LIST_NORMAL )
{
m_mainWin->SetImageList( imageList, which );
}
-void wxGenericListCtrl::AssignImageList(wxImageListType *imageList, int which)
+void wxGenericListCtrl::AssignImageList(wxImageList *imageList, int which)
{
SetImageList(imageList, which);
if ( which == wxIMAGE_LIST_NORMAL )
return m_mainWin->FindItem( pt );
}
-long wxGenericListCtrl::HitTest( const wxPoint &point, int &flags )
+// TODO: sub item hit testing
+long wxGenericListCtrl::HitTest(const wxPoint& point, int& flags, long *) const
{
return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
}
{
m_headerWin->SetSize( 0, 0, cw, m_headerHeight );
if(ch > m_headerHeight)
- m_mainWin->SetSize( 0, m_headerHeight + 1,
+ m_mainWin->SetSize( 0, m_headerHeight + 1,
cw, ch - m_headerHeight - 1 );
else
- m_mainWin->SetSize( 0, m_headerHeight + 1,
+ m_mainWin->SetSize( 0, m_headerHeight + 1,
cw, 0);
}
else // no header window
return true;
}
-#if _USE_VISATTR
-#include "wx/listbox.h"
-#endif
-
// static
wxVisualAttributes
wxGenericListCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
void wxGenericListCtrl::DoClientToScreen( int *x, int *y ) const
{
- return m_mainWin->DoClientToScreen(x, y);
+ m_mainWin->DoClientToScreen(x, y);
}
void wxGenericListCtrl::DoScreenToClient( int *x, int *y ) const
{
- return m_mainWin->DoScreenToClient(x, y);
+ m_mainWin->DoScreenToClient(x, y);
}
void wxGenericListCtrl::SetFocus()
}
#endif // wxUSE_LISTCTRL
-