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