2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #ifndef __JUCE_LISTBOX_JUCEHEADER__
27 #define __JUCE_LISTBOX_JUCEHEADER__
29 #include "../layout/juce_Viewport.h"
30 #include "../../../containers/juce_SparseSet.h"
34 //==============================================================================
36 A subclass of this is used to drive a ListBox.
40 class JUCE_API ListBoxModel
43 //==============================================================================
45 virtual ~ListBoxModel() {}
47 //==============================================================================
48 /** This has to return the number of items in the list.
50 @see ListBox::getNumRows()
52 virtual int getNumRows() = 0;
54 /** This method must be implemented to draw a row of the list.
56 virtual void paintListBoxItem (int rowNumber
,
58 int width
, int height
,
59 bool rowIsSelected
) = 0;
61 /** This is used to create or update a custom component to go in a row of the list.
63 Any row may contain a custom component, or can just be drawn with the paintListBoxItem() method
64 and handle mouse clicks with listBoxItemClicked().
66 This method will be called whenever a custom component might need to be updated - e.g.
67 when the table is changed, or TableListBox::updateContent() is called.
69 If you don't need a custom component for the specified row, then return 0.
71 If you do want a custom component, and the existingComponentToUpdate is null, then
72 this method must create a suitable new component and return it.
74 If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created
75 by this method. In this case, the method must either update it to make sure it's correctly representing
76 the given row (which may be different from the one that the component was created for), or it can
77 delete this component and return a new one.
79 The component that your method returns will be deleted by the ListBox when it is no longer needed.
81 virtual Component
* refreshComponentForRow (int rowNumber
, bool isRowSelected
,
82 Component
* existingComponentToUpdate
);
84 /** This can be overridden to react to the user clicking on a row.
86 @see listBoxItemDoubleClicked
88 virtual void listBoxItemClicked (int row
, const MouseEvent
& e
);
90 /** This can be overridden to react to the user double-clicking on a row.
92 @see listBoxItemClicked
94 virtual void listBoxItemDoubleClicked (int row
, const MouseEvent
& e
);
96 /** This can be overridden to react to the user double-clicking on a part of the list where
99 @see listBoxItemClicked
101 virtual void backgroundClicked();
103 /** Override this to be informed when rows are selected or deselected.
105 This will be called whenever a row is selected or deselected. If a range of
106 rows is selected all at once, this will just be called once for that event.
108 @param lastRowSelected the last row that the user selected. If no
109 rows are currently selected, this may be -1.
111 virtual void selectedRowsChanged (int lastRowSelected
);
113 /** Override this to be informed when the delete key is pressed.
115 If no rows are selected when they press the key, this won't be called.
117 @param lastRowSelected the last row that had been selected when they pressed the
118 key - if there are multiple selections, this might not be
121 virtual void deleteKeyPressed (int lastRowSelected
);
123 /** Override this to be informed when the return key is pressed.
125 If no rows are selected when they press the key, this won't be called.
127 @param lastRowSelected the last row that had been selected when they pressed the
128 key - if there are multiple selections, this might not be
131 virtual void returnKeyPressed (int lastRowSelected
);
133 /** Override this to be informed when the list is scrolled.
135 This might be caused by the user moving the scrollbar, or by programmatic changes
136 to the list position.
138 virtual void listWasScrolled();
140 /** To allow rows from your list to be dragged-and-dropped, implement this method.
142 If this returns a non-null variant then when the user drags a row, the listbox will
143 try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
144 a drag-and-drop operation, using this string as the source description, with the listbox
145 itself as the source component.
147 @see DragAndDropContainer::startDragging
149 virtual const var
getDragSourceDescription (const SparseSet
<int>& currentlySelectedRows
);
151 /** You can override this to provide tool tips for specific rows.
154 virtual const String
getTooltipForRow (int row
);
158 //==============================================================================
160 A list of items that can be scrolled vertically.
162 To create a list, you'll need to create a subclass of ListBoxModel. This can
163 either paint each row of the list and respond to events via callbacks, or for
164 more specialised tasks, it can supply a custom component to fill each row.
166 @see ComboBox, TableListBox
168 class JUCE_API ListBox
: public Component
,
169 public SettableTooltipClient
172 //==============================================================================
173 /** Creates a ListBox.
175 The model pointer passed-in can be null, in which case you can set it later
178 ListBox (const String
& componentName
= String::empty
,
179 ListBoxModel
* model
= 0);
185 //==============================================================================
186 /** Changes the current data model to display. */
187 void setModel (ListBoxModel
* newModel
);
189 /** Returns the current list model. */
190 ListBoxModel
* getModel() const noexcept
{ return model
; }
193 //==============================================================================
194 /** Causes the list to refresh its content.
196 Call this when the number of rows in the list changes, or if you want it
197 to call refreshComponentForRow() on all the row components.
199 This must only be called from the main message thread.
201 void updateContent();
203 //==============================================================================
204 /** Turns on multiple-selection of rows.
206 By default this is disabled.
208 When your row component gets clicked you'll need to call the
209 selectRowsBasedOnModifierKeys() method to tell the list that it's been
210 clicked and to get it to do the appropriate selection based on whether
211 the ctrl/shift keys are held down.
213 void setMultipleSelectionEnabled (bool shouldBeEnabled
);
215 /** Makes the list react to mouse moves by selecting the row that the mouse if over.
217 This function is here primarily for the ComboBox class to use, but might be
218 useful for some other purpose too.
220 void setMouseMoveSelectsRows (bool shouldSelect
);
222 //==============================================================================
225 If the row is already selected, this won't do anything.
227 @param rowNumber the row to select
228 @param dontScrollToShowThisRow if true, the list's position won't change; if false and
229 the selected row is off-screen, it'll scroll to make
230 sure that row is on-screen
231 @param deselectOthersFirst if true and there are multiple selections, these will
232 first be deselected before this item is selected
233 @see isRowSelected, selectRowsBasedOnModifierKeys, flipRowSelection, deselectRow,
234 deselectAllRows, selectRangeOfRows
236 void selectRow (int rowNumber
,
237 bool dontScrollToShowThisRow
= false,
238 bool deselectOthersFirst
= true);
240 /** Selects a set of rows.
242 This will add these rows to the current selection, so you might need to
243 clear the current selection first with deselectAllRows()
245 @param firstRow the first row to select (inclusive)
246 @param lastRow the last row to select (inclusive)
248 void selectRangeOfRows (int firstRow
,
253 If it's not currently selected, this will do nothing.
255 @see selectRow, deselectAllRows
257 void deselectRow (int rowNumber
);
259 /** Deselects any currently selected rows.
263 void deselectAllRows();
265 /** Selects or deselects a row.
267 If the row's currently selected, this deselects it, and vice-versa.
269 void flipRowSelection (int rowNumber
);
271 /** Returns a sparse set indicating the rows that are currently selected.
275 const SparseSet
<int> getSelectedRows() const;
277 /** Sets the rows that should be selected, based on an explicit set of ranges.
279 If sendNotificationEventToModel is true, the ListBoxModel::selectedRowsChanged()
280 method will be called. If it's false, no notification will be sent to the model.
284 void setSelectedRows (const SparseSet
<int>& setOfRowsToBeSelected
,
285 bool sendNotificationEventToModel
= true);
287 /** Checks whether a row is selected.
289 bool isRowSelected (int rowNumber
) const;
291 /** Returns the number of rows that are currently selected.
293 @see getSelectedRow, isRowSelected, getLastRowSelected
295 int getNumSelectedRows() const;
297 /** Returns the row number of a selected row.
299 This will return the row number of the Nth selected row. The row numbers returned will
300 be sorted in order from low to high.
302 @param index the index of the selected row to return, (from 0 to getNumSelectedRows() - 1)
303 @returns the row number, or -1 if the index was out of range or if there aren't any rows
305 @see getNumSelectedRows, isRowSelected, getLastRowSelected
307 int getSelectedRow (int index
= 0) const;
309 /** Returns the last row that the user selected.
311 This isn't the same as the highest row number that is currently selected - if the user
312 had multiply-selected rows 10, 5 and then 6 in that order, this would return 6.
314 If nothing is selected, it will return -1.
316 int getLastRowSelected() const;
318 /** Multiply-selects rows based on the modifier keys.
320 If no modifier keys are down, this will select the given row and
323 If the ctrl (or command on the Mac) key is down, it'll flip the
324 state of the selected row.
326 If the shift key is down, it'll select up to the given row from the
331 void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn
,
332 const ModifierKeys
& modifiers
,
333 bool isMouseUpEvent
);
335 //==============================================================================
336 /** Scrolls the list to a particular position.
338 The proportion is between 0 and 1.0, so 0 scrolls to the top of the list,
339 1.0 scrolls to the bottom.
341 If the total number of rows all fit onto the screen at once, then this
342 method won't do anything.
344 @see getVerticalPosition
346 void setVerticalPosition (double newProportion
);
348 /** Returns the current vertical position as a proportion of the total.
350 This can be used in conjunction with setVerticalPosition() to save and restore
351 the list's position. It returns a value in the range 0 to 1.
353 @see setVerticalPosition
355 double getVerticalPosition() const;
357 /** Scrolls if necessary to make sure that a particular row is visible.
359 void scrollToEnsureRowIsOnscreen (int row
);
361 /** Returns a pointer to the scrollbar.
363 (Unlikely to be useful for most people).
365 ScrollBar
* getVerticalScrollBar() const noexcept
;
367 /** Returns a pointer to the scrollbar.
369 (Unlikely to be useful for most people).
371 ScrollBar
* getHorizontalScrollBar() const noexcept
;
373 /** Finds the row index that contains a given x,y position.
375 The position is relative to the ListBox's top-left.
377 If no row exists at this position, the method will return -1.
379 @see getComponentForRowNumber
381 int getRowContainingPosition (int x
, int y
) const noexcept
;
383 /** Finds a row index that would be the most suitable place to insert a new
384 item for a given position.
386 This is useful when the user is e.g. dragging and dropping onto the listbox,
387 because it lets you easily choose the best position to insert the item that
388 they drop, based on where they drop it.
390 If the position is out of range, this will return -1. If the position is
391 beyond the end of the list, it will return getNumRows() to indicate the end
394 @see getComponentForRowNumber
396 int getInsertionIndexForPosition (int x
, int y
) const noexcept
;
398 /** Returns the position of one of the rows, relative to the top-left of
401 This may be off-screen, and the range of the row number that is passed-in is
402 not checked to see if it's a valid row.
404 const Rectangle
<int> getRowPosition (int rowNumber
,
405 bool relativeToComponentTopLeft
) const noexcept
;
407 /** Finds the row component for a given row in the list.
409 The component returned will have been created using createRowComponent().
411 If the component for this row is off-screen or if the row is out-of-range,
414 @see getRowContainingPosition
416 Component
* getComponentForRowNumber (int rowNumber
) const noexcept
;
418 /** Returns the row number that the given component represents.
420 If the component isn't one of the list's rows, this will return -1.
422 int getRowNumberOfComponent (Component
* rowComponent
) const noexcept
;
424 /** Returns the width of a row (which may be less than the width of this component
425 if there's a scrollbar).
427 int getVisibleRowWidth() const noexcept
;
429 //==============================================================================
430 /** Sets the height of each row in the list.
432 The default height is 22 pixels.
436 void setRowHeight (int newHeight
);
438 /** Returns the height of a row in the list.
442 int getRowHeight() const noexcept
{ return rowHeight
; }
444 /** Returns the number of rows actually visible.
446 This is the number of whole rows which will fit on-screen, so the value might
447 be more than the actual number of rows in the list.
449 int getNumRowsOnScreen() const noexcept
;
451 //==============================================================================
452 /** A set of colour IDs to use to change the colour of various aspects of the label.
454 These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
457 @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
461 backgroundColourId
= 0x1002800, /**< The background colour to fill the list with.
462 Make this transparent if you don't want the background to be filled. */
463 outlineColourId
= 0x1002810, /**< An optional colour to use to draw a border around the list.
464 Make this transparent to not have an outline. */
465 textColourId
= 0x1002820 /**< The preferred colour to use for drawing text in the listbox. */
468 /** Sets the thickness of a border that will be drawn around the box.
470 To set the colour of the outline, use @code setColour (ListBox::outlineColourId, colourXYZ); @endcode
473 void setOutlineThickness (int outlineThickness
);
475 /** Returns the thickness of outline that will be drawn around the listbox.
477 @see setOutlineColour
479 int getOutlineThickness() const noexcept
{ return outlineThickness
; }
481 /** Sets a component that the list should use as a header.
483 This will position the given component at the top of the list, maintaining the
484 height of the component passed-in, but rescaling it horizontally to match the
485 width of the items in the listbox.
487 The component will be deleted when setHeaderComponent() is called with a
488 different component, or when the listbox is deleted.
490 void setHeaderComponent (Component
* newHeaderComponent
);
492 /** Changes the width of the rows in the list.
494 This can be used to make the list's row components wider than the list itself - the
495 width of the rows will be either the width of the list or this value, whichever is
496 greater, and if the rows become wider than the list, a horizontal scrollbar will
499 The default value for this is 0, which means that the rows will always
500 be the same width as the list.
502 void setMinimumContentWidth (int newMinimumWidth
);
504 /** Returns the space currently available for the row items, taking into account
505 borders, scrollbars, etc.
507 int getVisibleContentWidth() const noexcept
;
509 /** Repaints one of the rows.
511 This is a lightweight alternative to calling updateContent, and just causes a
512 repaint of the row's area.
514 void repaintRow (int rowNumber
) noexcept
;
516 /** This fairly obscure method creates an image that just shows the currently
517 selected row components.
519 It's a handy method for doing drag-and-drop, as it can be passed to the
520 DragAndDropContainer for use as the drag image.
522 Note that it will make the row components temporarily invisible, so if you're
523 using custom components this could affect them if they're sensitive to that
526 @see Component::createComponentSnapshot
528 virtual const Image
createSnapshotOfSelectedRows (int& x
, int& y
);
530 /** Returns the viewport that this ListBox uses.
532 You may need to use this to change parameters such as whether scrollbars
535 Viewport
* getViewport() const noexcept
;
538 //==============================================================================
540 bool keyPressed (const KeyPress
& key
);
542 bool keyStateChanged (bool isKeyDown
);
544 void paint (Graphics
& g
);
546 void paintOverChildren (Graphics
& g
);
550 void visibilityChanged();
552 void mouseWheelMove (const MouseEvent
& e
, float wheelIncrementX
, float wheelIncrementY
);
554 void mouseMove (const MouseEvent
&);
556 void mouseExit (const MouseEvent
&);
558 void mouseUp (const MouseEvent
&);
560 void colourChanged();
562 void startDragAndDrop (const MouseEvent
& e
, const var
& dragDescription
, bool allowDraggingToOtherWindows
= true);
565 //==============================================================================
566 friend class ListViewport
;
567 friend class TableListBox
;
569 ScopedPointer
<ListViewport
> viewport
;
570 ScopedPointer
<Component
> headerComponent
;
571 int totalItems
, rowHeight
, minimumRowWidth
;
572 int outlineThickness
;
574 bool mouseMoveSelects
, multipleSelection
, hasDoneInitialUpdate
;
575 SparseSet
<int> selected
;
577 void selectRowInternal (int rowNumber
,
578 bool dontScrollToShowThisRow
,
579 bool deselectOthersFirst
,
582 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ListBox
);
586 #endif // __JUCE_LISTBOX_JUCEHEADER__