1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/generic/private/listctrl.h
3 // Purpose: private definitions of wxListCtrl helpers
4 // Author: Robert Roebling
5 // Vadim Zeitlin (virtual list control support)
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #ifndef _WX_GENERIC_LISTCTRL_PRIVATE_H_
11 #define _WX_GENERIC_LISTCTRL_PRIVATE_H_
17 #include "wx/listctrl.h"
18 #include "wx/selstore.h"
20 #include "wx/settings.h"
22 // ============================================================================
24 // ============================================================================
26 //-----------------------------------------------------------------------------
27 // wxColWidthInfo (internal)
28 //-----------------------------------------------------------------------------
33 bool bNeedsUpdate; // only set to true when an item whose
34 // width == nMaxWidth is removed
36 wxColWidthInfo(int w = 0, bool needsUpdate = false)
39 bNeedsUpdate = needsUpdate;
43 WX_DEFINE_ARRAY_PTR(wxColWidthInfo *, ColWidthArray);
45 //-----------------------------------------------------------------------------
46 // wxListItemData (internal)
47 //-----------------------------------------------------------------------------
52 wxListItemData(wxListMainWindow *owner);
55 void SetItem( const wxListItem &info );
56 void SetImage( int image ) { m_image = image; }
57 void SetData( wxUIntPtr data ) { m_data = data; }
58 void SetPosition( int x, int y );
59 void SetSize( int width, int height );
61 bool HasText() const { return !m_text.empty(); }
62 const wxString& GetText() const { return m_text; }
63 void SetText(const wxString& text) { m_text = text; }
65 // we can't use empty string for measuring the string width/height, so
66 // always return something
67 wxString GetTextForMeasuring() const
69 wxString s = GetText();
76 bool IsHit( int x, int y ) const;
81 int GetHeight() const;
83 int GetImage() const { return m_image; }
84 bool HasImage() const { return GetImage() != -1; }
86 void GetItem( wxListItem &info ) const;
88 void SetAttr(wxListItemAttr *attr) { m_attr = attr; }
89 wxListItemAttr *GetAttr() const { return m_attr; }
92 // the item image or -1
95 // user data associated with the item
98 // the item coordinates are not used in report mode; instead this pointer is
99 // NULL and the owner window is used to retrieve the item position and size
102 // the list ctrl we are in
103 wxListMainWindow *m_owner;
105 // custom attributes or NULL
106 wxListItemAttr *m_attr;
109 // common part of all ctors
115 //-----------------------------------------------------------------------------
116 // wxListHeaderData (internal)
117 //-----------------------------------------------------------------------------
119 class wxListHeaderData : public wxObject
123 wxListHeaderData( const wxListItem &info );
124 void SetItem( const wxListItem &item );
125 void SetPosition( int x, int y );
126 void SetWidth( int w );
127 void SetState( int state );
128 void SetFormat( int format );
129 void SetHeight( int h );
130 bool HasImage() const;
132 bool HasText() const { return !m_text.empty(); }
133 const wxString& GetText() const { return m_text; }
134 void SetText(const wxString& text) { m_text = text; }
136 void GetItem( wxListItem &item );
138 bool IsHit( int x, int y ) const;
139 int GetImage() const;
140 int GetWidth() const;
141 int GetFormat() const;
142 int GetState() const;
159 //-----------------------------------------------------------------------------
160 // wxListLineData (internal)
161 //-----------------------------------------------------------------------------
163 WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
168 // the list of subitems: only may have more than one item in report mode
169 wxListItemDataList m_items;
171 // this is not used in report view
183 // the part to be highlighted
184 wxRect m_rectHighlight;
186 // extend all our rects to be centered inside the one of given width
187 void ExtendWidth(wxCoord w)
189 wxASSERT_MSG( m_rectAll.width <= w,
190 wxT("width can only be increased") );
193 m_rectLabel.x = m_rectAll.x + (w - m_rectLabel.width) / 2;
194 m_rectIcon.x = m_rectAll.x + (w - m_rectIcon.width) / 2;
195 m_rectHighlight.x = m_rectAll.x + (w - m_rectHighlight.width) / 2;
200 // is this item selected? [NB: not used in virtual mode]
203 // back pointer to the list ctrl
204 wxListMainWindow *m_owner;
207 wxListLineData(wxListMainWindow *owner);
211 WX_CLEAR_LIST(wxListItemDataList, m_items);
215 // called by the owner when it toggles report view
216 void SetReportView(bool inReportView)
218 // we only need m_gi when we're not in report view so update as needed
226 m_gi = new GeometryInfo;
230 // are we in report mode?
231 inline bool InReportView() const;
233 // are we in virtual report mode?
234 inline bool IsVirtual() const;
236 // these 2 methods shouldn't be called for report view controls, in that
237 // case we determine our position/size ourselves
239 // calculate the size of the line
240 void CalculateSize( wxDC *dc, int spacing );
242 // remember the position this line appears at
243 void SetPosition( int x, int y, int spacing );
247 void SetImage( int image ) { SetImage(0, image); }
248 int GetImage() const { return GetImage(0); }
249 void SetImage( int index, int image );
250 int GetImage( int index ) const;
252 bool HasImage() const { return GetImage() != -1; }
253 bool HasText() const { return !GetText(0).empty(); }
255 void SetItem( int index, const wxListItem &info );
256 void GetItem( int index, wxListItem &info );
258 wxString GetText(int index) const;
259 void SetText( int index, const wxString& s );
261 wxListItemAttr *GetAttr() const;
262 void SetAttr(wxListItemAttr *attr);
264 // return true if the highlighting really changed
265 bool Highlight( bool on );
267 void ReverseHighlight();
269 bool IsHighlighted() const
271 wxASSERT_MSG( !IsVirtual(), wxT("unexpected call to IsHighlighted") );
273 return m_highlighted;
276 // draw the line on the given DC in icon/list mode
277 void Draw( wxDC *dc, bool current );
279 // the same in report mode: it needs more parameters as we don't store
280 // everything in the item in report mode
281 void DrawInReportMode( wxDC *dc,
283 const wxRect& rectHL,
285 bool current, long line ); // 2013.12.10. Toshi Nagata; add 'line' argument
288 // set the line to contain num items (only can be > 1 in report mode)
289 void InitItems( int num );
291 // get the mode (i.e. style) of the list control
292 inline int GetMode() const;
294 // Apply this item attributes to the given DC: set the text font and colour
295 // and also erase the background appropriately.
296 void ApplyAttributes(wxDC *dc,
297 const wxRect& rectHL,
299 bool current, wxListItemAttr *override = NULL); // 2013.12.10. Add "override" argument
301 // draw the text on the DC with the correct justification; also add an
302 // ellipsis if the text is too large to fit in the current width
303 void DrawTextFormatted(wxDC *dc,
304 const wxString &text,
307 int yMid, // this is middle, not top, of the text
311 WX_DECLARE_OBJARRAY(wxListLineData, wxListLineDataArray);
313 //-----------------------------------------------------------------------------
314 // wxListHeaderWindow (internal)
315 //-----------------------------------------------------------------------------
317 class wxListHeaderWindow : public wxWindow
320 wxListMainWindow *m_owner;
321 const wxCursor *m_currentCursor;
322 wxCursor *m_resizeCursor;
325 // column being resized or -1
328 // divider line position in logical (unscrolled) coords
331 // minimal position beyond which the divider line
332 // can't be dragged in logical coords
336 wxListHeaderWindow();
338 // We provide only Create(), not the ctor, because we need to create the
339 // C++ object before creating the window, see the explanations in
340 // CreateOrDestroyHeaderWindowAsNeeded()
341 bool Create( wxWindow *win,
343 wxListMainWindow *owner,
344 const wxPoint &pos = wxDefaultPosition,
345 const wxSize &size = wxDefaultSize,
347 const wxString &name = wxT("wxlistctrlcolumntitles") );
349 virtual ~wxListHeaderWindow();
351 // We never need focus as we don't have any keyboard interface.
352 virtual bool AcceptsFocus() const { return false; }
355 void AdjustDC( wxDC& dc );
357 void OnPaint( wxPaintEvent &event );
358 void OnMouse( wxMouseEvent &event );
360 // 2014.01.14. Toshi Nagata
361 // Sync the header window position with the list main window
362 void QueueListCtrlEvent(wxCommandEvent &event);
363 void OnListCtrlEvent(wxCommandEvent &event);
369 // Update main window's column later
370 bool m_sendSetColumnWidth;
374 virtual void OnInternalIdle();
377 // common part of all ctors
380 // generate and process the list event of the given type, return true if
381 // it wasn't vetoed, i.e. if we should proceed
382 bool SendListEvent(wxEventType type, const wxPoint& pos);
384 DECLARE_EVENT_TABLE()
387 //-----------------------------------------------------------------------------
388 // wxListRenameTimer (internal)
389 //-----------------------------------------------------------------------------
391 class wxListRenameTimer: public wxTimer
394 wxListMainWindow *m_owner;
397 wxListRenameTimer( wxListMainWindow *owner );
401 //-----------------------------------------------------------------------------
402 // wxListFindTimer (internal)
403 //-----------------------------------------------------------------------------
405 class wxListFindTimer: public wxTimer
408 // reset the current prefix after half a second of inactivity
409 enum { DELAY = 500 };
411 wxListFindTimer( wxListMainWindow *owner )
416 virtual void Notify();
419 wxListMainWindow *m_owner;
422 //-----------------------------------------------------------------------------
423 // wxListTextCtrlWrapper: wraps a wxTextCtrl to make it work for inline editing
424 //-----------------------------------------------------------------------------
426 class wxListTextCtrlWrapper : public wxEvtHandler
429 // NB: text must be a valid object but not Create()d yet
430 wxListTextCtrlWrapper(wxListMainWindow *owner,
434 wxTextCtrl *GetText() const { return m_text; }
436 // Check if the given key event should stop editing and return true if it
437 // does or false otherwise.
438 bool CheckForEndEditKey(const wxKeyEvent& event);
440 // Different reasons for calling EndEdit():
442 // It was called because:
445 End_Accept, // user has accepted the changes.
446 End_Discard, // user has cancelled editing.
447 End_Destroy // the entire control is being destroyed.
450 void EndEdit(EndReason reason);
453 void OnChar( wxKeyEvent &event );
454 void OnKeyUp( wxKeyEvent &event );
455 void OnKillFocus( wxFocusEvent &event );
457 bool AcceptChanges();
458 void Finish( bool setfocus );
461 wxListMainWindow *m_owner;
463 wxString m_startValue;
465 bool m_aboutToFinish;
467 DECLARE_EVENT_TABLE()
470 //-----------------------------------------------------------------------------
471 // wxListMainWindow (internal)
472 //-----------------------------------------------------------------------------
474 WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
476 class wxListMainWindow : public wxWindow
480 wxListMainWindow( wxWindow *parent,
483 const wxSize& size );
485 virtual ~wxListMainWindow();
487 // called by the main control when its mode changes
488 void SetReportView(bool inReportView);
490 // helper to simplify testing for wxLC_XXX flags
491 bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
493 // return true if this is a virtual list control
494 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
496 // return true if the control is in report mode
497 bool InReportView() const { return HasFlag(wxLC_REPORT); }
499 // return true if we are in single selection mode, false if multi sel
500 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
502 // do we have a header window?
503 bool HasHeader() const
504 { return InReportView() && !HasFlag(wxLC_NO_HEADER); }
506 void HighlightAll( bool on );
508 // all these functions only do something if the line is currently visible
510 // change the line "selected" state, return true if it really changed
511 bool HighlightLine( size_t line, bool highlight = true);
513 // as HighlightLine() but do it for the range of lines: this is incredibly
514 // more efficient for virtual list controls!
516 // NB: unlike HighlightLine() this one does refresh the lines on screen
517 void HighlightLines( size_t lineFrom, size_t lineTo, bool on = true );
519 // toggle the line state and refresh it
520 void ReverseHighlight( size_t line )
521 { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
523 // return true if the line is highlighted
524 bool IsHighlighted(size_t line) const;
526 // refresh one or several lines at once
527 void RefreshLine( size_t line );
528 void RefreshLines( size_t lineFrom, size_t lineTo );
530 // refresh all selected items
531 void RefreshSelected();
533 // refresh all lines below the given one: the difference with
534 // RefreshLines() is that the index here might not be a valid one (happens
535 // when the last line is deleted)
536 void RefreshAfter( size_t lineFrom );
538 // the methods which are forwarded to wxListLineData itself in list/icon
539 // modes but are here because the lines don't store their positions in the
542 // get the bound rect for the entire line
543 wxRect GetLineRect(size_t line) const;
545 // get the bound rect of the label
546 wxRect GetLineLabelRect(size_t line) const;
548 // get the bound rect of the items icon (only may be called if we do have
550 wxRect GetLineIconRect(size_t line) const;
552 // get the rect to be highlighted when the item has focus
553 wxRect GetLineHighlightRect(size_t line) const;
555 // get the size of the total line rect
556 wxSize GetLineSize(size_t line) const
557 { return GetLineRect(line).GetSize(); }
559 // return the hit code for the corresponding position (in this line)
560 long HitTestLine(size_t line, int x, int y) const;
562 // bring the selected item into view, scrolling to it if necessary
563 void MoveToItem(size_t item);
565 bool ScrollList( int WXUNUSED(dx), int dy );
567 // bring the current item into view
568 void MoveToFocus() { MoveToItem(m_current); }
570 // start editing the label of the given item
571 wxTextCtrl *EditLabel(long item,
572 wxClassInfo* textControlClass = wxCLASSINFO(wxTextCtrl));
574 bool EndEditLabel(bool cancel);
576 wxTextCtrl *GetEditControl() const
578 return m_textctrlWrapper ? m_textctrlWrapper->GetText() : NULL;
581 void ResetTextControl(wxTextCtrl *text)
584 m_textctrlWrapper = NULL;
587 void OnRenameTimer();
588 bool OnRenameAccept(size_t itemEdit, const wxString& value);
589 void OnRenameCancelled(size_t itemEdit);
592 // set whether or not to ring the find bell
593 // (does nothing on MSW - bell is always rung)
594 void EnableBellOnNoMatch( bool on );
596 void OnMouse( wxMouseEvent &event );
598 // called to switch the selection from the current item to newCurrent,
599 void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
601 void OnCharHook( wxKeyEvent &event );
602 void OnChar( wxKeyEvent &event );
603 void OnKeyDown( wxKeyEvent &event );
604 void OnKeyUp( wxKeyEvent &event );
605 void OnSetFocus( wxFocusEvent &event );
606 void OnKillFocus( wxFocusEvent &event );
607 void OnScroll( wxScrollWinEvent& event );
609 void OnPaint( wxPaintEvent &event );
611 void OnChildFocus(wxChildFocusEvent& event);
613 void DrawImage( int index, wxDC *dc, int x, int y );
614 void GetImageSize( int index, int &width, int &height ) const;
616 void SetImageList( wxImageList *imageList, int which );
617 void SetItemSpacing( int spacing, bool isSmall = false );
618 int GetItemSpacing( bool isSmall = false );
620 void SetColumn( int col, const wxListItem &item );
621 void SetColumnWidth( int col, int width );
622 void GetColumn( int col, wxListItem &item ) const;
623 int GetColumnWidth( int col ) const;
624 int GetColumnCount() const { return m_columns.GetCount(); }
626 // returns the sum of the heights of all columns
627 int GetHeaderWidth() const;
629 int GetCountPerPage() const;
631 void SetItem( wxListItem &item );
632 void GetItem( wxListItem &item ) const;
633 void SetItemState( long item, long state, long stateMask );
634 void SetItemStateAll( long state, long stateMask );
635 int GetItemState( long item, long stateMask ) const;
636 bool GetItemRect( long item, wxRect &rect ) const
638 return GetSubItemRect(item, wxLIST_GETSUBITEMRECT_WHOLEITEM, rect);
640 bool GetSubItemRect( long item, long subItem, wxRect& rect ) const;
641 wxRect GetViewRect() const;
642 bool GetItemPosition( long item, wxPoint& pos ) const;
643 int GetSelectedItemCount() const;
645 wxString GetItemText(long item, int col = 0) const
648 info.m_mask = wxLIST_MASK_TEXT;
649 info.m_itemId = item;
655 void SetItemText(long item, const wxString& value)
658 info.m_mask = wxLIST_MASK_TEXT;
659 info.m_itemId = item;
664 wxImageList* GetSmallImageList() const
665 { return m_small_image_list; }
667 // set the scrollbars and update the positions of the items
668 void RecalculatePositions(bool noRefresh = false);
670 // refresh the window and the header
673 long GetNextItem( long item, int geometry, int state ) const;
674 void DeleteItem( long index );
675 void DeleteAllItems();
676 void DeleteColumn( int col );
677 void DeleteEverything();
678 void EnsureVisible( long index );
679 long FindItem( long start, const wxString& str, bool partial = false );
680 long FindItem( long start, wxUIntPtr data);
681 long FindItem( const wxPoint& pt );
682 long HitTest( int x, int y, int &flags ) const;
683 void InsertItem( wxListItem &item );
684 long InsertColumn( long col, const wxListItem &item );
685 int GetItemWidthWithImage(wxListItem * item);
686 void SortItems( wxListCtrlCompare fn, wxIntPtr data );
688 size_t GetItemCount() const;
689 bool IsEmpty() const { return GetItemCount() == 0; }
690 void SetItemCount(long count);
692 // change the current (== focused) item, send a notification event
693 void ChangeCurrent(size_t current);
694 void ResetCurrent() { ChangeCurrent((size_t)-1); }
695 bool HasCurrent() const { return m_current != (size_t)-1; }
697 // send out a wxListEvent
698 void SendNotify( size_t line,
700 const wxPoint& point = wxDefaultPosition );
702 // override base class virtual to reset m_lineHeight when the font changes
703 virtual bool SetFont(const wxFont& font)
705 if ( !wxWindow::SetFont(font) )
713 // these are for wxListLineData usage only
715 // get the backpointer to the list ctrl
716 wxGenericListCtrl *GetListCtrl() const
718 return wxStaticCast(GetParent(), wxGenericListCtrl);
721 // get the height of all lines (assuming they all do have the same height)
722 wxCoord GetLineHeight() const;
724 // get the y position of the given line (only for report view)
725 wxCoord GetLineY(size_t line) const;
727 // get the brush to use for the item highlighting
728 wxBrush *GetHighlightBrush() const
730 return m_hasFocus ? m_highlightBrush : m_highlightUnfocusedBrush;
733 bool HasFocus() const
739 // the array of all line objects for a non virtual list control (for the
740 // virtual list control we only ever use m_lines[0])
741 wxListLineDataArray m_lines;
743 // the list of column objects
744 wxListHeaderDataList m_columns;
746 // currently focused item or -1
749 // the number of lines per page
752 // this flag is set when something which should result in the window
753 // redrawing happens (i.e. an item was added or deleted, or its appearance
754 // changed) and OnPaint() doesn't redraw the window while it is set which
755 // allows to minimize the number of repaintings when a lot of items are
756 // being added. The real repainting occurs only after the next OnIdle()
760 wxColour *m_highlightColour;
761 wxImageList *m_small_image_list;
762 wxImageList *m_normal_image_list;
764 int m_normal_spacing;
768 wxTimer *m_renameTimer;
770 // incremental search data
771 wxString m_findPrefix;
772 wxTimer *m_findTimer;
773 // This flag is set to 0 if the bell is disabled, 1 if it is enabled and -1
774 // if it is globally enabled but has been temporarily disabled because we
775 // had already beeped for this particular search.
781 ColWidthArray m_aColWidths;
783 // for double click logic
784 size_t m_lineLastClicked,
785 m_lineBeforeLastClicked,
786 m_lineSelectSingleOnUp;
789 wxWindow *GetMainWindowOfCompositeControl() { return GetParent(); }
791 // the total count of items in a virtual list control
794 // the object maintaining the items selection state, only used in virtual
796 wxSelectionStore m_selStore;
798 // common part of all ctors
801 // get the line data for the given index
802 wxListLineData *GetLine(size_t n) const
804 wxASSERT_MSG( n != (size_t)-1, wxT("invalid line index") );
808 wxConstCast(this, wxListMainWindow)->CacheLineData(n);
815 // get a dummy line which can be used for geometry calculations and such:
816 // you must use GetLine() if you want to really draw the line
817 wxListLineData *GetDummyLine() const;
819 // cache the line data of the n-th line in m_lines[0]
820 void CacheLineData(size_t line);
822 // get the range of visible lines
823 void GetVisibleLinesRange(size_t *from, size_t *to);
825 // force us to recalculate the range of visible lines
826 void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
828 // find the first item starting with the given prefix after the given item
829 size_t PrefixFindItem(size_t item, const wxString& prefix) const;
831 // get the colour to be used for drawing the rules
832 wxColour GetRuleColour() const
834 return wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
838 // initialize the current item if needed
839 void UpdateCurrent();
841 // delete all items but don't refresh: called from dtor
842 void DoDeleteAllItems();
844 // Compute the minimal width needed to fully display the column header.
845 int ComputeMinHeaderWidth(const wxListHeaderData* header) const;
848 // the height of one line using the current font
849 wxCoord m_lineHeight;
851 // the total header width or 0 if not calculated yet
852 wxCoord m_headerWidth;
854 // the first and last lines being shown on screen right now (inclusive),
855 // both may be -1 if they must be calculated so never access them directly:
856 // use GetVisibleLinesRange() above instead
860 // the brushes to use for item highlighting when we do/don't have focus
861 wxBrush *m_highlightBrush,
862 *m_highlightUnfocusedBrush;
864 // wrapper around the text control currently used for in place editing or
865 // NULL if no item is being edited
866 wxListTextCtrlWrapper *m_textctrlWrapper;
869 DECLARE_EVENT_TABLE()
871 friend class wxGenericListCtrl;
872 friend class wxListCtrlMaxWidthCalculator;
875 #endif // wxUSE_LISTCTRL
876 #endif // _WX_GENERIC_LISTCTRL_PRIVATE_H_