-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 selected items
- void RefreshSelected();
-
- // 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;
-
- // bring the selected item into view, scrolling to it if necessary
- void MoveToItem(size_t item);
-
- // bring the current item into view
- void MoveToFocus() { MoveToItem(m_current); }
-
- // start editing the label of the given item
- void EditLabel( long item );
-
- // suspend/resume redrawing the control
- void Freeze();
- void Thaw();
-
- void SetFocus();
-
- void OnRenameTimer();
- void OnRenameAccept();
-
- void OnMouse( wxMouseEvent &event );
-
- // 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(bool noRefresh = FALSE);
-
- // 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);
-
- // change the current (== focused) item, send a notification event
- void ChangeCurrent(size_t current);
- void ResetCurrent() { ChangeCurrent((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;
-
- // get the brush to use for the item highlighting
- wxBrush *GetHighlightBrush() const
- {
- return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
- }
-
-//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;
-
- 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::GetColour(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();
-
- // 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;
-
- // the brushes to use for item highlighting when we do/don't have focus
- wxBrush *m_highlightBrush,
- *m_highlightUnfocusedBrush;
-
- // if this is > 0, the control is frozen and doesn't redraw itself
- size_t m_freezeCount;
-
- 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;
-}
-
-bool wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo,
- bool select,
- wxArrayInt *itemsChanged)
-{
- // 100 is hardcoded but it shouldn't matter much: the important thing is
- // that we don't refresh everything when really few (e.g. 1 or 2) items
- // change state
- static const size_t MANY_ITEMS = 100;
-
- 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);
- }
-
- // many items (> half) changed state
- itemsChanged = NULL;
- }
- 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-- )
- {
- if ( itemsChanged )
- {
- if ( itemsChanged->GetCount() > MANY_ITEMS )
- {
- // stop counting (see comment below)
- itemsChanged = NULL;
- }
- else
- {
- itemsChanged->Add(m_itemsSel[i]);
- }
- }
-
- m_itemsSel.RemoveAt(i);
- }
- }
- }
- }
- else // "few" items change state
- {
- if ( itemsChanged )
- {
- itemsChanged->Empty();
- }
-
- // just add the items to the selection
- for ( size_t item = itemFrom; item <= itemTo; item++ )
- {
- if ( SelectItem(item, select) && itemsChanged )
- {
- itemsChanged->Add(item);
-
- if ( itemsChanged->GetCount() > MANY_ITEMS )
- {
- // stop counting them, we'll just eat gobs of memory
- // for nothing at all - faster to refresh everything in
- // this case
- itemsChanged = NULL;
- }
- }
- }
- }
-
- // we set it to NULL if there are many items changing state
- return itemsChanged != NULL;
-}
-
-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") );