| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: wx/univ/listbox.h |
| 3 | // Purpose: the universal listbox |
| 4 | // Author: Vadim Zeitlin |
| 5 | // Modified by: |
| 6 | // Created: 30.08.00 |
| 7 | // RCS-ID: $Id$ |
| 8 | // Copyright: (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> |
| 9 | // Licence: wxWindows licence |
| 10 | /////////////////////////////////////////////////////////////////////////////// |
| 11 | |
| 12 | #ifndef _WX_UNIV_LISTBOX_H_ |
| 13 | #define _WX_UNIV_LISTBOX_H_ |
| 14 | |
| 15 | #include "wx/scrolwin.h" // for wxScrollHelper |
| 16 | #include "wx/dynarray.h" |
| 17 | #include "wx/arrstr.h" |
| 18 | |
| 19 | // ---------------------------------------------------------------------------- |
| 20 | // the actions supported by this control |
| 21 | // ---------------------------------------------------------------------------- |
| 22 | |
| 23 | // change the current item |
| 24 | #define wxACTION_LISTBOX_SETFOCUS _T("setfocus") // select the item |
| 25 | #define wxACTION_LISTBOX_MOVEDOWN _T("down") // select item below |
| 26 | #define wxACTION_LISTBOX_MOVEUP _T("up") // select item above |
| 27 | #define wxACTION_LISTBOX_PAGEDOWN _T("pagedown") // go page down |
| 28 | #define wxACTION_LISTBOX_PAGEUP _T("pageup") // go page up |
| 29 | #define wxACTION_LISTBOX_START _T("start") // go to first item |
| 30 | #define wxACTION_LISTBOX_END _T("end") // go to last item |
| 31 | #define wxACTION_LISTBOX_FIND _T("find") // find item by 1st letter |
| 32 | |
| 33 | // do something with the current item |
| 34 | #define wxACTION_LISTBOX_ACTIVATE _T("activate") // activate (choose) |
| 35 | #define wxACTION_LISTBOX_TOGGLE _T("toggle") // togglee selected state |
| 36 | #define wxACTION_LISTBOX_SELECT _T("select") // sel this, unsel others |
| 37 | #define wxACTION_LISTBOX_SELECTADD _T("selectadd") // add to selection |
| 38 | #define wxACTION_LISTBOX_UNSELECT _T("unselect") // unselect |
| 39 | #define wxACTION_LISTBOX_ANCHOR _T("selanchor") // anchor selection |
| 40 | |
| 41 | // do something with the selection globally (not for single selection ones) |
| 42 | #define wxACTION_LISTBOX_SELECTALL _T("selectall") // select all items |
| 43 | #define wxACTION_LISTBOX_UNSELECTALL _T("unselectall") // unselect all items |
| 44 | #define wxACTION_LISTBOX_SELTOGGLE _T("togglesel") // invert the selection |
| 45 | #define wxACTION_LISTBOX_EXTENDSEL _T("extend") // extend to item |
| 46 | |
| 47 | // ---------------------------------------------------------------------------- |
| 48 | // wxListBox: a list of selectable items |
| 49 | // ---------------------------------------------------------------------------- |
| 50 | |
| 51 | class WXDLLEXPORT wxListBox : public wxListBoxBase, public wxScrollHelper |
| 52 | { |
| 53 | public: |
| 54 | // ctors and such |
| 55 | wxListBox() : wxScrollHelper(this) { Init(); } |
| 56 | wxListBox(wxWindow *parent, |
| 57 | wxWindowID id, |
| 58 | const wxPoint& pos = wxDefaultPosition, |
| 59 | const wxSize& size = wxDefaultSize, |
| 60 | int n = 0, const wxString choices[] = (const wxString *) NULL, |
| 61 | long style = 0, |
| 62 | const wxValidator& validator = wxDefaultValidator, |
| 63 | const wxString& name = wxListBoxNameStr ) |
| 64 | : wxScrollHelper(this) |
| 65 | { |
| 66 | Init(); |
| 67 | |
| 68 | Create(parent, id, pos, size, n, choices, style, validator, name); |
| 69 | } |
| 70 | wxListBox(wxWindow *parent, |
| 71 | wxWindowID id, |
| 72 | const wxPoint& pos, |
| 73 | const wxSize& size, |
| 74 | const wxArrayString& choices, |
| 75 | long style = 0, |
| 76 | const wxValidator& validator = wxDefaultValidator, |
| 77 | const wxString& name = wxListBoxNameStr ); |
| 78 | |
| 79 | virtual ~wxListBox(); |
| 80 | |
| 81 | bool Create(wxWindow *parent, |
| 82 | wxWindowID id, |
| 83 | const wxPoint& pos = wxDefaultPosition, |
| 84 | const wxSize& size = wxDefaultSize, |
| 85 | int n = 0, const wxString choices[] = (const wxString *) NULL, |
| 86 | long style = 0, |
| 87 | const wxValidator& validator = wxDefaultValidator, |
| 88 | const wxString& name = wxListBoxNameStr); |
| 89 | bool Create(wxWindow *parent, |
| 90 | wxWindowID id, |
| 91 | const wxPoint& pos, |
| 92 | const wxSize& size, |
| 93 | const wxArrayString& choices, |
| 94 | long style = 0, |
| 95 | const wxValidator& validator = wxDefaultValidator, |
| 96 | const wxString& name = wxListBoxNameStr); |
| 97 | |
| 98 | // implement the listbox interface defined by wxListBoxBase |
| 99 | virtual void Clear(); |
| 100 | virtual void Delete(unsigned int n); |
| 101 | |
| 102 | virtual unsigned int GetCount() const |
| 103 | { return (unsigned int)m_strings->GetCount(); } |
| 104 | virtual wxString GetString(unsigned int n) const |
| 105 | { return m_strings->Item(n); } |
| 106 | virtual void SetString(unsigned int n, const wxString& s); |
| 107 | virtual int FindString(const wxString& s, bool bCase = false) const |
| 108 | { return m_strings->Index(s, bCase); } |
| 109 | |
| 110 | virtual bool IsSelected(int n) const |
| 111 | { return m_selections.Index(n) != wxNOT_FOUND; } |
| 112 | virtual int GetSelection() const; |
| 113 | virtual int GetSelections(wxArrayInt& aSelections) const; |
| 114 | |
| 115 | protected: |
| 116 | virtual void DoSetSelection(int n, bool select); |
| 117 | virtual int DoAppendOnly(const wxString& item); |
| 118 | virtual int DoAppend(const wxString& item); |
| 119 | virtual void DoInsertItems(const wxArrayString& items, unsigned int pos); |
| 120 | virtual void DoSetItems(const wxArrayString& items, void **clientData); |
| 121 | |
| 122 | virtual void DoSetFirstItem(int n); |
| 123 | |
| 124 | virtual void DoSetItemClientData(unsigned int n, void* clientData); |
| 125 | virtual void* DoGetItemClientData(unsigned int n) const; |
| 126 | virtual void DoSetItemClientObject(unsigned int n, wxClientData* clientData); |
| 127 | virtual wxClientData* DoGetItemClientObject(unsigned int n) const; |
| 128 | |
| 129 | public: |
| 130 | // override some more base class methods |
| 131 | virtual bool SetFont(const wxFont& font); |
| 132 | |
| 133 | // the wxUniversal-specific methods |
| 134 | // -------------------------------- |
| 135 | |
| 136 | // the current item is the same as the selected one for wxLB_SINGLE |
| 137 | // listboxes but for the other ones it is just the focused item which may |
| 138 | // be selected or not |
| 139 | int GetCurrentItem() const { return m_current; } |
| 140 | void SetCurrentItem(int n); |
| 141 | |
| 142 | // select the item which is diff items below the current one |
| 143 | void ChangeCurrent(int diff); |
| 144 | |
| 145 | // activate (i.e. send a LISTBOX_DOUBLECLICKED message) the specified or |
| 146 | // current (if -1) item |
| 147 | void Activate(int item = -1); |
| 148 | |
| 149 | // select or unselect the specified or current (if -1) item |
| 150 | void DoSelect(int item = -1, bool sel = true); |
| 151 | |
| 152 | // more readable wrapper |
| 153 | void DoUnselect(int item) { DoSelect(item, false); } |
| 154 | |
| 155 | // select an item and send a notification about it |
| 156 | void SelectAndNotify(int item); |
| 157 | |
| 158 | // ensure that the given item is visible by scrolling it into view |
| 159 | virtual void EnsureVisible(int n); |
| 160 | |
| 161 | // find the first item [strictly] after the current one which starts with |
| 162 | // the given string and make it the current one, return true if the current |
| 163 | // item changed |
| 164 | bool FindItem(const wxString& prefix, bool strictlyAfter = false); |
| 165 | bool FindNextItem(const wxString& prefix) { return FindItem(prefix, true); } |
| 166 | |
| 167 | // extend the selection to span the range from the anchor (see below) to |
| 168 | // the specified or current item |
| 169 | void ExtendSelection(int itemTo = -1); |
| 170 | |
| 171 | // make this item the new selection anchor: extending selection with |
| 172 | // ExtendSelection() will work with it |
| 173 | void AnchorSelection(int itemFrom) { m_selAnchor = itemFrom; } |
| 174 | |
| 175 | // get, calculating it if necessary, the number of items per page, the |
| 176 | // height of each line and the max width of an item |
| 177 | int GetItemsPerPage() const; |
| 178 | wxCoord GetLineHeight() const; |
| 179 | wxCoord GetMaxWidth() const; |
| 180 | |
| 181 | // override the wxControl virtual methods |
| 182 | virtual bool PerformAction(const wxControlAction& action, |
| 183 | long numArg = 0l, |
| 184 | const wxString& strArg = wxEmptyString); |
| 185 | |
| 186 | // idle processing |
| 187 | virtual void OnInternalIdle(); |
| 188 | |
| 189 | protected: |
| 190 | // geometry |
| 191 | virtual wxSize DoGetBestClientSize() const; |
| 192 | virtual void DoSetSize(int x, int y, |
| 193 | int width, int height, |
| 194 | int sizeFlags = wxSIZE_AUTO); |
| 195 | |
| 196 | virtual void DoDraw(wxControlRenderer *renderer); |
| 197 | virtual wxBorder GetDefaultBorder() const; |
| 198 | |
| 199 | // common part of all ctors |
| 200 | void Init(); |
| 201 | |
| 202 | // event handlers |
| 203 | void OnSize(wxSizeEvent& event); |
| 204 | |
| 205 | // common part of Clear() and DoSetItems(): clears everything |
| 206 | virtual void DoClear(); |
| 207 | |
| 208 | // refresh the given item(s) or everything |
| 209 | void RefreshItems(int from, int count); |
| 210 | void RefreshItem(int n); |
| 211 | void RefreshFromItemToEnd(int n); |
| 212 | void RefreshAll(); |
| 213 | |
| 214 | // send an event of the given type (using m_current by default) |
| 215 | bool SendEvent(wxEventType type, int item = -1); |
| 216 | |
| 217 | // calculate the number of items per page using our current size |
| 218 | void CalcItemsPerPage(); |
| 219 | |
| 220 | // can/should we have a horz scrollbar? |
| 221 | bool HasHorzScrollbar() const |
| 222 | { return (m_windowStyle & wxLB_HSCROLL) != 0; } |
| 223 | |
| 224 | // redraw the items in the given range only: called from DoDraw() |
| 225 | virtual void DoDrawRange(wxControlRenderer *renderer, |
| 226 | int itemFirst, int itemLast); |
| 227 | |
| 228 | // update the scrollbars and then ensure that the item is visible |
| 229 | void DoEnsureVisible(int n); |
| 230 | |
| 231 | // mark horz scrollbar for updating |
| 232 | void RefreshHorzScrollbar(); |
| 233 | |
| 234 | // update (show/hide/adjust) the scrollbars |
| 235 | void UpdateScrollbars(); |
| 236 | |
| 237 | // refresh the items specified by m_updateCount and m_updateFrom |
| 238 | void UpdateItems(); |
| 239 | |
| 240 | // the array containing all items (it is sorted if the listbox has |
| 241 | // wxLB_SORT style) |
| 242 | wxArrayString* m_strings; |
| 243 | |
| 244 | // this array contains the indices of the selected items (for the single |
| 245 | // selection listboxes only the first element of it is used and contains |
| 246 | // the current selection) |
| 247 | wxArrayInt m_selections; |
| 248 | |
| 249 | // and this one the client data (either void or wxClientData) |
| 250 | wxArrayPtrVoid m_itemsClientData; |
| 251 | |
| 252 | // the current item |
| 253 | int m_current; |
| 254 | |
| 255 | private: |
| 256 | // the range of elements which must be updated: if m_updateCount is 0 no |
| 257 | // update is needed, if it is -1 everything must be updated, otherwise |
| 258 | // m_updateCount items starting from m_updateFrom have to be redrawn |
| 259 | int m_updateFrom, |
| 260 | m_updateCount; |
| 261 | |
| 262 | // the height of one line in the listbox (all lines have the same height) |
| 263 | wxCoord m_lineHeight; |
| 264 | |
| 265 | // the maximal width of a listbox item and the item which has it |
| 266 | wxCoord m_maxWidth; |
| 267 | int m_maxWidthItem; |
| 268 | |
| 269 | // the extents of horz and vert scrollbars |
| 270 | int m_scrollRangeX, |
| 271 | m_scrollRangeY; |
| 272 | |
| 273 | // the number of items per page |
| 274 | size_t m_itemsPerPage; |
| 275 | |
| 276 | // if the number of items has changed we may need to show/hide the |
| 277 | // scrollbar |
| 278 | bool m_updateScrollbarX, m_updateScrollbarY, |
| 279 | m_showScrollbarX, m_showScrollbarY; |
| 280 | |
| 281 | // if the current item has changed, we might need to scroll if it went out |
| 282 | // of the window |
| 283 | bool m_currentChanged; |
| 284 | |
| 285 | // the anchor from which the selection is extended for the listboxes with |
| 286 | // wxLB_EXTENDED style - this is set to the last item which was selected |
| 287 | // by not extending the selection but by choosing it directly |
| 288 | int m_selAnchor; |
| 289 | |
| 290 | DECLARE_EVENT_TABLE() |
| 291 | DECLARE_DYNAMIC_CLASS(wxListBox) |
| 292 | }; |
| 293 | |
| 294 | // ---------------------------------------------------------------------------- |
| 295 | // wxStdListboxInputHandler: handles mouse and kbd in a single or multi |
| 296 | // selection listbox |
| 297 | // ---------------------------------------------------------------------------- |
| 298 | |
| 299 | class WXDLLEXPORT wxStdListboxInputHandler : public wxStdInputHandler |
| 300 | { |
| 301 | public: |
| 302 | // if pressing the mouse button in a multiselection listbox should toggle |
| 303 | // the item under mouse immediately, then specify true as the second |
| 304 | // parameter (this is the standard behaviour, under GTK the item is toggled |
| 305 | // only when the mouse is released in the multi selection listbox) |
| 306 | wxStdListboxInputHandler(wxInputHandler *inphand, |
| 307 | bool toggleOnPressAlways = true); |
| 308 | |
| 309 | // base class methods |
| 310 | virtual bool HandleKey(wxInputConsumer *consumer, |
| 311 | const wxKeyEvent& event, |
| 312 | bool pressed); |
| 313 | virtual bool HandleMouse(wxInputConsumer *consumer, |
| 314 | const wxMouseEvent& event); |
| 315 | virtual bool HandleMouseMove(wxInputConsumer *consumer, |
| 316 | const wxMouseEvent& event); |
| 317 | |
| 318 | protected: |
| 319 | // return the item under mouse, 0 if the mouse is above the listbox or |
| 320 | // GetCount() if it is below it |
| 321 | int HitTest(const wxListBox *listbox, const wxMouseEvent& event); |
| 322 | |
| 323 | // parts of HitTest(): first finds the pseudo (because not in range) index |
| 324 | // of the item and the second one adjusts it if necessary - that is if the |
| 325 | // third one returns false |
| 326 | int HitTestUnsafe(const wxListBox *listbox, const wxMouseEvent& event); |
| 327 | int FixItemIndex(const wxListBox *listbox, int item); |
| 328 | bool IsValidIndex(const wxListBox *listbox, int item); |
| 329 | |
| 330 | // init m_btnCapture and m_actionMouse |
| 331 | wxControlAction SetupCapture(wxListBox *lbox, |
| 332 | const wxMouseEvent& event, |
| 333 | int item); |
| 334 | |
| 335 | wxRenderer *m_renderer; |
| 336 | |
| 337 | // the button which initiated the mouse capture (currently 0 or 1) |
| 338 | int m_btnCapture; |
| 339 | |
| 340 | // the action to perform when the mouse moves while we capture it |
| 341 | wxControlAction m_actionMouse; |
| 342 | |
| 343 | // the ctor parameter toggleOnPressAlways (see comments near it) |
| 344 | bool m_toggleOnPressAlways; |
| 345 | |
| 346 | // do we track the mouse outside the window when it is captured? |
| 347 | bool m_trackMouseOutside; |
| 348 | }; |
| 349 | |
| 350 | #endif // _WX_UNIV_LISTBOX_H_ |