+// ----------------------------------------------------------------------------
+// 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)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
+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_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_CACHE_HINT)
+
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+// 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_HEIGHT = 4;
+
+// offset for the header window
+static const int HEADER_OFFSET_X = 1;
+static const int HEADER_OFFSET_Y = 1;
+
+// when autosizing the columns, add some slack
+static const int AUTOSIZE_COL_MARGIN = 10;
+
+// default and minimal widths for the header columns
+static const int WIDTH_COL_DEFAULT = 80;
+static const int WIDTH_COL_MIN = 10;
+
+// ============================================================================
+// private classes
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxSelectionStore
+// ----------------------------------------------------------------------------
+
+int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; }
+
+WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray);
+
+// this class is used to store the selected items in the virtual list control
+// (but it is not tied to list control and so can be used with other controls
+// such as wxListBox in wxUniv)
+//
+// the idea is to make it really smart later (i.e. store the selections as an
+// array of ranes + individual items) but, as I don't have time to do it now
+// (this would require writing code to merge/break ranges and much more) keep
+// it simple but define a clean interface to it which allows it to be made
+// smarter later
+class WXDLLEXPORT wxSelectionStore
+{
+public:
+ wxSelectionStore() : m_itemsSel(wxSizeTCmpFn) { Init(); }
+
+ // set the total number of items we handle
+ void SetItemCount(size_t count) { m_count = count; }
+
+ // special case of SetItemCount(0)
+ void Clear() { m_itemsSel.Clear(); m_count = 0; }
+
+ // must be called when a new item is inserted/added
+ void OnItemAdd(size_t item) { wxFAIL_MSG( _T("TODO") ); }
+
+ // must be called when an item is deleted
+ void OnItemDelete(size_t item);
+
+ // select one item, use SelectRange() insted if possible!
+ //
+ // returns true if the items selection really changed
+ bool SelectItem(size_t item, bool select = TRUE);
+
+ // select the range of items
+ void SelectRange(size_t itemFrom, size_t itemTo, bool select = TRUE);
+
+ // return true if the given item is selected
+ bool IsSelected(size_t item) const;
+
+ // return the total number of selected items
+ size_t GetSelectedCount() const
+ {
+ return m_defaultState ? m_count - m_itemsSel.GetCount()
+ : m_itemsSel.GetCount();
+ }
+
+private:
+ // (re)init
+ void Init() { m_defaultState = FALSE; }
+
+ // the total number of items we handle
+ size_t m_count;
+
+ // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
+ // there are more selected items than non selected ones - this allows to
+ // handle selection of all items efficiently
+ bool m_defaultState;
+
+ // the array of items whose selection state is different from default
+ wxIndexArray m_itemsSel;
+
+ DECLARE_NO_COPY_CLASS(wxSelectionStore)
+};
+
+//-----------------------------------------------------------------------------
+// wxListItemData (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListItemData
+{
+public:
+ wxListItemData(wxListMainWindow *owner);
+ ~wxListItemData();
+
+ void SetItem( const wxListItem &info );
+ void SetImage( int image ) { m_image = image; }
+ void SetData( long data ) { m_data = data; }
+ void SetPosition( int x, int y );
+ void SetSize( int width, int height );
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ // we can't use empty string for measuring the string width/height, so
+ // always return something
+ wxString GetTextForMeasuring() const
+ {
+ wxString s = GetText();
+ if ( s.empty() )
+ s = _T('H');
+
+ return s;
+ }
+
+ bool IsHit( int x, int y ) const;
+
+ int GetX() const;
+ int GetY() const;
+ int GetWidth() const;
+ int GetHeight() const;
+
+ int GetImage() const { return m_image; }
+ bool HasImage() const { return GetImage() != -1; }
+
+ void GetItem( wxListItem &info ) const;
+
+ void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
+ wxListItemAttr *GetAttr() const { return m_attr; }
+
+public:
+ // the item image or -1
+ int m_image;
+
+ // user data associated with the item
+ long m_data;
+
+ // the item coordinates are not used in report mode, instead this pointer
+ // is NULL and the owner window is used to retrieve the item position and
+ // size
+ wxRect *m_rect;
+
+ // the list ctrl we are in
+ wxListMainWindow *m_owner;
+
+ // custom attributes or NULL
+ wxListItemAttr *m_attr;
+
+protected:
+ // common part of all ctors
+ void Init();
+
+ wxString m_text;
+};
+
+//-----------------------------------------------------------------------------
+// wxListHeaderData (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListHeaderData : public wxObject
+{
+protected:
+ long m_mask;
+ int m_image;
+ wxString m_text;
+ int m_format;
+ int m_width;
+ int m_xpos,
+ m_ypos;
+ int m_height;
+
+public:
+ wxListHeaderData();
+ wxListHeaderData( const wxListItem &info );
+ void SetItem( const wxListItem &item );
+ void SetPosition( int x, int y );
+ void SetWidth( int w );
+ void SetFormat( int format );
+ void SetHeight( int h );
+ bool HasImage() const;
+
+ bool HasText() const { return !m_text.empty(); }
+ const wxString& GetText() const { return m_text; }
+ void SetText(const wxString& text) { m_text = text; }
+
+ void GetItem( wxListItem &item );
+
+ bool IsHit( int x, int y ) const;
+ int GetImage() const;
+ int GetWidth() const;
+ int GetFormat() const;
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListHeaderData);
+};
+
+//-----------------------------------------------------------------------------
+// wxListLineData (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListItemDataList);
+
+class WXDLLEXPORT wxListLineData
+{
+public:
+ // the list of subitems: only may have more than one item in report mode
+ wxListItemDataList m_items;
+
+ // this is not used in report view
+ struct GeometryInfo
+ {
+ // total item rect
+ wxRect m_rectAll;
+
+ // label only
+ wxRect m_rectLabel;
+
+ // icon only
+ wxRect m_rectIcon;
+
+ // the part to be highlighted
+ wxRect m_rectHighlight;
+ } *m_gi;
+
+ // is this item selected? [NB: not used in virtual mode]
+ bool m_highlighted;
+
+ // back pointer to the list ctrl
+ wxListMainWindow *m_owner;
+
+public:
+ wxListLineData(wxListMainWindow *owner);
+
+ ~wxListLineData() { delete m_gi; }
+
+ // are we in report mode?
+ inline bool InReportView() const;
+
+ // are we in virtual report mode?
+ inline bool IsVirtual() const;
+
+ // these 2 methods shouldn't be called for report view controls, in that
+ // case we determine our position/size ourselves
+
+ // calculate the size of the line
+ void CalculateSize( wxDC *dc, int spacing );
+
+ // remember the position this line appears at
+ void SetPosition( int x, int y, int window_width, int spacing );
+
+ // wxListCtrl API
+
+ void SetImage( int image ) { SetImage(0, image); }
+ int GetImage() const { return GetImage(0); }
+ bool HasImage() const { return GetImage() != -1; }
+ bool HasText() const { return !GetText(0).empty(); }
+
+ void SetItem( int index, const wxListItem &info );
+ void GetItem( int index, wxListItem &info );
+
+ wxString GetText(int index) const;
+ void SetText( int index, const wxString s );
+
+ wxListItemAttr *GetAttr() const;
+ void SetAttr(wxListItemAttr *attr);
+
+ // return true if the highlighting really changed
+ bool Highlight( bool on );
+
+ void ReverseHighlight();
+
+ bool IsHighlighted() const
+ {
+ wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
+
+ return m_highlighted;
+ }
+
+ // draw the line on the given DC in icon/list mode
+ void Draw( wxDC *dc );
+
+ // the same in report mode
+ void DrawInReportMode( wxDC *dc,
+ const wxRect& rect,
+ const wxRect& rectHL,
+ bool highlighted );
+
+private:
+ // set the line to contain num items (only can be > 1 in report mode)
+ void InitItems( int num );
+
+ // get the mode (i.e. style) of the list control
+ inline int GetMode() const;
+
+ void SetAttributes(wxDC *dc,
+ const wxListItemAttr *attr,
+ const wxColour& colText,
+ const wxFont& font,
+ bool highlight);
+
+ // these are only used by GetImage/SetImage above, we don't support images
+ // with subitems at the public API level yet
+ void SetImage( int index, int image );
+ int GetImage( int index ) const;
+};
+
+WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
+#include "wx/arrimpl.cpp"
+WX_DEFINE_OBJARRAY(wxListLineDataArray);
+
+//-----------------------------------------------------------------------------
+// wxListHeaderWindow (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListHeaderWindow : public wxWindow
+{
+protected:
+ wxListMainWindow *m_owner;
+ wxCursor *m_currentCursor;
+ wxCursor *m_resizeCursor;
+ bool m_isDragging;
+
+ // column being resized
+ int m_column;
+
+ // divider line position in logical (unscrolled) coords
+ int m_currentX;
+
+ // minimal position beyond which the divider line can't be dragged in
+ // logical coords
+ int m_minX;
+
+public:
+ wxListHeaderWindow();
+ virtual ~wxListHeaderWindow();
+
+ wxListHeaderWindow( wxWindow *win,
+ wxWindowID id,
+ wxListMainWindow *owner,
+ const wxPoint &pos = wxDefaultPosition,
+ const wxSize &size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = "wxlistctrlcolumntitles" );
+
+ void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
+ void DrawCurrent();
+ void AdjustDC(wxDC& dc);
+
+ void OnPaint( wxPaintEvent &event );
+ void OnMouse( wxMouseEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+
+ // needs refresh
+ bool m_dirty;
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListRenameTimer (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListRenameTimer: public wxTimer
+{
+private:
+ wxListMainWindow *m_owner;
+
+public:
+ wxListRenameTimer( wxListMainWindow *owner );
+ void Notify();
+};
+
+//-----------------------------------------------------------------------------
+// wxListTextCtrl (internal)
+//-----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxListTextCtrl: public wxTextCtrl
+{
+private:
+ bool *m_accept;
+ wxString *m_res;
+ wxListMainWindow *m_owner;
+ wxString m_startValue;
+
+public:
+ wxListTextCtrl() {}
+ wxListTextCtrl( wxWindow *parent, const wxWindowID id,
+ bool *accept, wxString *res, wxListMainWindow *owner,
+ const wxString &value = "",
+ const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize,
+ int style = 0,
+ const wxValidator& validator = wxDefaultValidator,
+ const wxString &name = "listctrltextctrl" );
+ void OnChar( wxKeyEvent &event );
+ void OnKeyUp( wxKeyEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxListTextCtrl);
+ DECLARE_EVENT_TABLE()
+};
+
+//-----------------------------------------------------------------------------
+// wxListMainWindow (internal)
+//-----------------------------------------------------------------------------
+
+WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListHeaderDataList);
+
+class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow
+{
+public:
+ wxListMainWindow();
+ wxListMainWindow( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString &name = _T("listctrlmainwindow") );
+
+ virtual ~wxListMainWindow();
+
+ bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
+
+ // return true if this is a virtual list control
+ bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
+
+ // return true if the control is in report mode
+ bool InReportView() const { return HasFlag(wxLC_REPORT); }
+
+ // return true if we are in single selection mode, false if multi sel
+ bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
+
+ // do we have a header window?
+ bool HasHeader() const
+ { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
+
+ void HighlightAll( bool on );
+
+ // all these functions only do something if the line is currently visible
+
+ // change the line "selected" state, return TRUE if it really changed
+ bool HighlightLine( size_t line, bool highlight = TRUE);
+
+ // as HighlightLine() but do it for the range of lines: this is incredibly
+ // more efficient for virtual list controls!
+ //
+ // NB: unlike HighlightLine() this one does refresh the lines on screen
+ void HighlightLines( size_t lineFrom, size_t lineTo, bool on = TRUE );
+
+ // toggle the line state and refresh it
+ void ReverseHighlight( size_t line )
+ { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
+
+ // return true if the line is highlighted
+ bool IsHighlighted(size_t line) const;
+
+ // refresh one or several lines at once
+ void RefreshLine( size_t line );
+ void RefreshLines( size_t lineFrom, size_t lineTo );
+
+ // refresh all lines below the given one: the difference with
+ // RefreshLines() is that the index here might not be a valid one (happens
+ // when the last line is deleted)
+ void RefreshAfter( size_t lineFrom );
+
+ // the methods which are forwarded to wxListLineData itself in list/icon
+ // modes but are here because the lines don't store their positions in the
+ // report mode
+
+ // get the bound rect for the entire line
+ wxRect GetLineRect(size_t line) const;
+
+ // get the bound rect of the label
+ wxRect GetLineLabelRect(size_t line) const;
+
+ // get the bound rect of the items icon (only may be called if we do have
+ // an icon!)
+ wxRect GetLineIconRect(size_t line) const;
+
+ // get the rect to be highlighted when the item has focus
+ wxRect GetLineHighlightRect(size_t line) const;
+
+ // get the size of the total line rect
+ wxSize GetLineSize(size_t line) const
+ { return GetLineRect(line).GetSize(); }
+
+ // return the hit code for the corresponding position (in this line)
+ long HitTestLine(size_t line, int x, int y) const;
+
+ void EditLabel( long item );
+ void OnRenameTimer();
+ void OnRenameAccept();
+
+ void OnMouse( wxMouseEvent &event );
+ void MoveToFocus();
+
+ // called to switch the selection from the current item to newCurrent,
+ void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
+
+ void OnChar( wxKeyEvent &event );
+ void OnKeyDown( wxKeyEvent &event );
+ void OnSetFocus( wxFocusEvent &event );
+ void OnKillFocus( wxFocusEvent &event );
+ void OnScroll(wxScrollWinEvent& event) ;
+
+ void OnPaint( wxPaintEvent &event );
+
+ void DrawImage( int index, wxDC *dc, int x, int y );
+ void GetImageSize( int index, int &width, int &height ) const;
+ int GetTextLength( const wxString &s ) const;
+
+ void SetImageList( wxImageList *imageList, int which );
+ void SetItemSpacing( int spacing, bool isSmall = FALSE );
+ int GetItemSpacing( bool isSmall = FALSE );
+
+ void SetColumn( int col, wxListItem &item );
+ void SetColumnWidth( int col, int width );
+ void GetColumn( int col, wxListItem &item ) const;
+ int GetColumnWidth( int col ) const;
+ int GetColumnCount() const { return m_columns.GetCount(); }
+
+ // returns the sum of the heights of all columns
+ int GetHeaderWidth() const;
+
+ int GetCountPerPage() const;
+
+ void SetItem( wxListItem &item );
+ void GetItem( wxListItem &item );
+ void SetItemState( long item, long state, long stateMask );
+ int GetItemState( long item, long stateMask );
+ void GetItemRect( long index, wxRect &rect );
+ bool GetItemPosition( long item, wxPoint& pos );
+ int GetSelectedItemCount();
+
+ // set the scrollbars and update the positions of the items
+ void RecalculatePositions();
+
+ // refresh the window and the header
+ void RefreshAll();
+
+ long GetNextItem( long item, int geometry, int state );
+ void DeleteItem( long index );
+ void DeleteAllItems();
+ void DeleteColumn( int col );
+ void DeleteEverything();
+ void EnsureVisible( long index );
+ long FindItem( long start, const wxString& str, bool partial = FALSE );
+ long FindItem( long start, long data);
+ long HitTest( int x, int y, int &flags );
+ void InsertItem( wxListItem &item );
+ void InsertColumn( long col, wxListItem &item );
+ void SortItems( wxListCtrlCompare fn, long data );
+
+ size_t GetItemCount() const;
+ bool IsEmpty() const { return GetItemCount() == 0; }
+ void SetItemCount(long count);
+
+ void ResetCurrent() { m_current = (size_t)-1; }
+ bool HasCurrent() const { return m_current != (size_t)-1; }
+
+ // send out a wxListEvent
+ void SendNotify( size_t line,
+ wxEventType command,
+ wxPoint point = wxDefaultPosition );
+
+ // override base class virtual to reset m_lineHeight when the font changes
+ virtual bool SetFont(const wxFont& font)
+ {
+ if ( !wxScrolledWindow::SetFont(font) )
+ return FALSE;
+
+ m_lineHeight = 0;
+
+ return TRUE;
+ }
+
+ // these are for wxListLineData usage only
+
+ // get the backpointer to the list ctrl
+ wxListCtrl *GetListCtrl() const
+ {
+ return wxStaticCast(GetParent(), wxListCtrl);
+ }
+
+ // get the height of all lines (assuming they all do have the same height)
+ wxCoord GetLineHeight() const;
+
+ // get the y position of the given line (only for report view)
+ wxCoord GetLineY(size_t line) const;
+
+//protected:
+ // the array of all line objects for a non virtual list control
+ wxListLineDataArray m_lines;
+
+ // the list of column objects
+ wxListHeaderDataList m_columns;
+
+ // currently focused item or -1
+ size_t m_current;
+
+ // the item currently being edited or -1
+ size_t m_currentEdit;
+
+ // the number of lines per page
+ int m_linesPerPage;
+
+ // this flag is set when something which should result in the window
+ // redrawing happens (i.e. an item was added or deleted, or its appearance
+ // changed) and OnPaint() doesn't redraw the window while it is set which
+ // allows to minimize the number of repaintings when a lot of items are
+ // being added. The real repainting occurs only after the next OnIdle()
+ // call
+ bool m_dirty;
+
+ wxBrush *m_highlightBrush;
+ wxColour *m_highlightColour;
+ int m_xScroll,
+ m_yScroll;
+ wxImageList *m_small_image_list;
+ wxImageList *m_normal_image_list;
+ int m_small_spacing;
+ int m_normal_spacing;
+ bool m_hasFocus;
+
+ bool m_lastOnSame;
+ wxTimer *m_renameTimer;
+ bool m_renameAccept;
+ wxString m_renameRes;
+ bool m_isCreated;
+ int m_dragCount;
+ wxPoint m_dragStart;
+
+ // for double click logic
+ size_t m_lineLastClicked,
+ m_lineBeforeLastClicked;
+
+protected:
+ // the total count of items in a virtual list control
+ size_t m_countVirt;
+
+ // the object maintaining the items selection state, only used in virtual
+ // controls
+ wxSelectionStore m_selStore;
+
+ // 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
+ {
+ wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") );
+
+ if ( IsVirtual() )
+ {
+ wxConstCast(this, wxListMainWindow)->CacheLineData(n);
+
+ n = 0;
+ }
+
+ return &m_lines[n];
+ }
+
+ // get a dummy line which can be used for geometry calculations and such:
+ // you must use GetLine() if you want to really draw the line
+ wxListLineData *GetDummyLine() const;
+
+ // cache the line data of the n-th line in m_lines[0]
+ void CacheLineData(size_t line);
+
+ // get the range of visible lines
+ void GetVisibleLinesRange(size_t *from, size_t *to);
+
+ // force us to recalculate the range of visible lines
+ void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
+
+ // get the colour to be used for drawing the rules
+ wxColour GetRuleColour() const
+ {
+#ifdef __WXMAC__
+ return *wxWHITE;
+#else
+ return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
+#endif
+ }
+
+private:
+ // initialize the current item if needed
+ void UpdateCurrent();
+
+ // delete all items but don't refresh: called from dtor
+ void DoDeleteAllItems();
+
+ // called when an item is [un]focuded, i.e. becomes [not] current
+ //
+ // currently unused
+ void OnFocusLine( size_t line );
+ void OnUnfocusLine( size_t line );
+
+ // the height of one line using the current font
+ wxCoord m_lineHeight;
+
+ // the total header width or 0 if not calculated yet
+ wxCoord m_headerWidth;
+
+ // the first and last lines being shown on screen right now (inclusive),
+ // both may be -1 if they must be calculated so never access them directly:
+ // use GetVisibleLinesRange() above instead
+ size_t m_lineFrom,
+ m_lineTo;
+
+ DECLARE_DYNAMIC_CLASS(wxListMainWindow);
+ DECLARE_EVENT_TABLE()
+};
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxSelectionStore
+// ----------------------------------------------------------------------------
+
+bool wxSelectionStore::IsSelected(size_t item) const
+{
+ bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
+
+ // if the default state is to be selected, being in m_itemsSel means that
+ // the item is not selected, so we have to inverse the logic
+ return m_defaultState ? !isSel : isSel;
+}
+
+bool wxSelectionStore::SelectItem(size_t item, bool select)
+{
+ // search for the item ourselves as like this we get the index where to
+ // insert it later if needed, so we do only one search in the array instead
+ // of two (adding item to a sorted array requires a search)
+ size_t index = m_itemsSel.IndexForInsert(item);
+ bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
+
+ if ( select != m_defaultState )
+ {
+ if ( !isSel )
+ {
+ m_itemsSel.AddAt(item, index);
+
+ return TRUE;
+ }
+ }
+ else // reset to default state
+ {
+ if ( isSel )
+ {
+ m_itemsSel.RemoveAt(index);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, bool select)
+{
+ wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") );
+
+ // are we going to have more [un]selected items than the other ones?
+ if ( itemTo - itemFrom > m_count / 2 )
+ {
+ if ( select != m_defaultState )
+ {
+ // the default state now becomes the same as 'select'
+ m_defaultState = select;
+
+ // so all the old selections (which had state select) shouldn't be
+ // selected any more, but all the other ones should
+ wxIndexArray selOld = m_itemsSel;
+ m_itemsSel.Empty();
+
+ // TODO: it should be possible to optimize the searches a bit
+ // knowing the possible range
+
+ size_t item;
+ for ( item = 0; item < itemFrom; item++ )
+ {
+ if ( selOld.Index(item) == wxNOT_FOUND )
+ m_itemsSel.Add(item);
+ }
+
+ for ( item = itemTo + 1; item < m_count; item++ )
+ {
+ if ( selOld.Index(item) == wxNOT_FOUND )
+ m_itemsSel.Add(item);
+ }
+ }
+ else // select == m_defaultState
+ {
+ // get the inclusive range of items between itemFrom and itemTo
+ size_t count = m_itemsSel.GetCount(),
+ start = m_itemsSel.IndexForInsert(itemFrom),
+ end = m_itemsSel.IndexForInsert(itemTo);
+
+ if ( start == count || m_itemsSel[start] < itemFrom )
+ {
+ start++;
+ }
+
+ if ( end == count || m_itemsSel[end] > itemTo )
+ {
+ end--;
+ }
+
+ if ( start <= end )
+ {
+ // delete all of them (from end to avoid changing indices)
+ for ( int i = end; i >= (int)start; i-- )
+ {
+ m_itemsSel.RemoveAt(i);
+ }
+ }
+ }
+ }
+ else // "few" items change state
+ {
+ // just add the items to the selection
+ for ( size_t item = itemFrom; item <= itemTo; item++ )
+ {
+ SelectItem(item, select);
+ }
+ }
+}
+
+void wxSelectionStore::OnItemDelete(size_t item)
+{
+ size_t count = m_itemsSel.GetCount(),
+ i = m_itemsSel.IndexForInsert(item);
+
+ if ( i < count && m_itemsSel[i] == item )
+ {
+ // this item itself was in m_itemsSel, remove it from there
+ m_itemsSel.RemoveAt(i);
+
+ count--;
+ }
+
+ // and adjust the index of all which follow it
+ while ( i < count )
+ {
+ // all following elements must be greater than the one we deleted
+ wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") );
+
+ m_itemsSel[i++]--;
+ }
+}
+