The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
14KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. //==============================================================================
  21. /**
  22. One of these is used by a TableListBox as the data model for the table's contents.
  23. The virtual methods that you override in this class take care of drawing the
  24. table cells, and reacting to events.
  25. @see TableListBox
  26. @tags{GUI}
  27. */
  28. class JUCE_API TableListBoxModel
  29. {
  30. public:
  31. //==============================================================================
  32. TableListBoxModel() = default;
  33. /** Destructor. */
  34. virtual ~TableListBoxModel() = default;
  35. //==============================================================================
  36. /** This must return the number of rows currently in the table.
  37. If the number of rows changes, you must call TableListBox::updateContent() to
  38. cause it to refresh the list.
  39. */
  40. virtual int getNumRows() = 0;
  41. /** This must draw the background behind one of the rows in the table.
  42. The graphics context has its origin at the row's top-left, and your method
  43. should fill the area specified by the width and height parameters.
  44. Note that the rowNumber value may be greater than the number of rows in your
  45. list, so be careful that you don't assume it's less than getNumRows().
  46. */
  47. virtual void paintRowBackground (Graphics&,
  48. int rowNumber,
  49. int width, int height,
  50. bool rowIsSelected) = 0;
  51. /** This must draw one of the cells.
  52. The graphics context's origin will already be set to the top-left of the cell,
  53. whose size is specified by (width, height).
  54. Note that the rowNumber value may be greater than the number of rows in your
  55. list, so be careful that you don't assume it's less than getNumRows().
  56. */
  57. virtual void paintCell (Graphics&,
  58. int rowNumber,
  59. int columnId,
  60. int width, int height,
  61. bool rowIsSelected) = 0;
  62. //==============================================================================
  63. /** This is used to create or update a custom component to go in a cell.
  64. Any cell may contain a custom component, or can just be drawn with the paintCell() method
  65. and handle mouse clicks with cellClicked().
  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.
  68. If you don't need a custom component for the specified cell, then return nullptr.
  69. (Bear in mind that even if you're not creating a new component, you may still need to
  70. delete existingComponentToUpdate if it's non-null).
  71. If you do want a custom component, and the existingComponentToUpdate is null, then
  72. this method must create a new component suitable for the cell, and return it.
  73. If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created
  74. by this method. In this case, the method must either update it to make sure it's correctly representing
  75. the given cell (which may be different from the one that the component was created for), or it can
  76. delete this component and return a new one.
  77. */
  78. virtual Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected,
  79. Component* existingComponentToUpdate);
  80. //==============================================================================
  81. /** This callback is made when the user clicks on one of the cells in the table.
  82. The mouse event's coordinates will be relative to the entire table row.
  83. @see cellDoubleClicked, backgroundClicked
  84. */
  85. virtual void cellClicked (int rowNumber, int columnId, const MouseEvent&);
  86. /** This callback is made when the user clicks on one of the cells in the table.
  87. The mouse event's coordinates will be relative to the entire table row.
  88. @see cellClicked, backgroundClicked
  89. */
  90. virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent&);
  91. /** This can be overridden to react to the user double-clicking on a part of the list where
  92. there are no rows.
  93. @see cellClicked
  94. */
  95. virtual void backgroundClicked (const MouseEvent&);
  96. //==============================================================================
  97. /** This callback is made when the table's sort order is changed.
  98. This could be because the user has clicked a column header, or because the
  99. TableHeaderComponent::setSortColumnId() method was called.
  100. If you implement this, your method should re-sort the table using the given
  101. column as the key.
  102. */
  103. virtual void sortOrderChanged (int newSortColumnId, bool isForwards);
  104. //==============================================================================
  105. /** Returns the best width for one of the columns.
  106. If you implement this method, you should measure the width of all the items
  107. in this column, and return the best size.
  108. Returning 0 means that the column shouldn't be changed.
  109. This is used by TableListBox::autoSizeColumn() and TableListBox::autoSizeAllColumns().
  110. */
  111. virtual int getColumnAutoSizeWidth (int columnId);
  112. /** Returns a tooltip for a particular cell in the table. */
  113. virtual String getCellTooltip (int rowNumber, int columnId);
  114. //==============================================================================
  115. /** Override this to be informed when rows are selected or deselected.
  116. @see ListBox::selectedRowsChanged()
  117. */
  118. virtual void selectedRowsChanged (int lastRowSelected);
  119. /** Override this to be informed when the delete key is pressed.
  120. @see ListBox::deleteKeyPressed()
  121. */
  122. virtual void deleteKeyPressed (int lastRowSelected);
  123. /** Override this to be informed when the return key is pressed.
  124. @see ListBox::returnKeyPressed()
  125. */
  126. virtual void returnKeyPressed (int lastRowSelected);
  127. /** Override this to be informed when the list is scrolled.
  128. This might be caused by the user moving the scrollbar, or by programmatic changes
  129. to the list position.
  130. */
  131. virtual void listWasScrolled();
  132. /** To allow rows from your table to be dragged-and-dropped, implement this method.
  133. If this returns a non-null variant then when the user drags a row, the table will try to
  134. find a DragAndDropContainer in its parent hierarchy, and will use it to trigger a
  135. drag-and-drop operation, using this string as the source description, and the listbox
  136. itself as the source component.
  137. @see getDragSourceCustomData, DragAndDropContainer::startDragging
  138. */
  139. virtual var getDragSourceDescription (const SparseSet<int>& currentlySelectedRows);
  140. /** Called when starting a drag operation on a list row to determine whether the item may be
  141. dragged to other windows. Returns true by default.
  142. */
  143. virtual bool mayDragToExternalWindows() const { return true; }
  144. };
  145. //==============================================================================
  146. /**
  147. A table of cells, using a TableHeaderComponent as its header.
  148. This component makes it easy to create a table by providing a TableListBoxModel as
  149. the data source.
  150. @see TableListBoxModel, TableHeaderComponent
  151. @tags{GUI}
  152. */
  153. class JUCE_API TableListBox : public ListBox,
  154. private ListBoxModel,
  155. private TableHeaderComponent::Listener
  156. {
  157. public:
  158. //==============================================================================
  159. /** Creates a TableListBox.
  160. The model pointer passed-in can be null, in which case you can set it later
  161. with setModel(). The TableListBox does not take ownership of the model - it's
  162. the caller's responsibility to manage its lifetime and make sure it
  163. doesn't get deleted while still being used.
  164. */
  165. TableListBox (const String& componentName = String(),
  166. TableListBoxModel* model = nullptr);
  167. /** Destructor. */
  168. ~TableListBox() override;
  169. //==============================================================================
  170. /** Changes the TableListBoxModel that is being used for this table.
  171. The TableListBox does not take ownership of the model - it's the caller's responsibility
  172. to manage its lifetime and make sure it doesn't get deleted while still being used.
  173. */
  174. void setModel (TableListBoxModel* newModel);
  175. /** Returns the model currently in use. */
  176. TableListBoxModel* getTableListBoxModel() const noexcept { return model; }
  177. //==============================================================================
  178. /** Returns the header component being used in this table. */
  179. TableHeaderComponent& getHeader() const noexcept { return *header; }
  180. /** Sets the header component to use for the table.
  181. The table will take ownership of the component that you pass in, and will delete it
  182. when it's no longer needed.
  183. The pointer passed in may not be null.
  184. */
  185. void setHeader (std::unique_ptr<TableHeaderComponent> newHeader);
  186. /** Changes the height of the table header component.
  187. @see getHeaderHeight
  188. */
  189. void setHeaderHeight (int newHeight);
  190. /** Returns the height of the table header.
  191. @see setHeaderHeight
  192. */
  193. int getHeaderHeight() const noexcept;
  194. //==============================================================================
  195. /** Resizes a column to fit its contents.
  196. This uses TableListBoxModel::getColumnAutoSizeWidth() to find the best width,
  197. and applies that to the column.
  198. @see autoSizeAllColumns, TableHeaderComponent::setColumnWidth
  199. */
  200. void autoSizeColumn (int columnId);
  201. /** Calls autoSizeColumn() for all columns in the table. */
  202. void autoSizeAllColumns();
  203. /** Enables or disables the auto size options on the popup menu.
  204. By default, these are enabled.
  205. */
  206. void setAutoSizeMenuOptionShown (bool shouldBeShown) noexcept;
  207. /** True if the auto-size options should be shown on the menu.
  208. @see setAutoSizeMenuOptionShown
  209. */
  210. bool isAutoSizeMenuOptionShown() const noexcept { return autoSizeOptionsShown; }
  211. /** Returns the position of one of the cells in the table.
  212. If relativeToComponentTopLeft is true, the coordinates are relative to
  213. the table component's top-left. The row number isn't checked to see if it's
  214. in-range, but the column ID must exist or this will return an empty rectangle.
  215. If relativeToComponentTopLeft is false, the coordinates are relative to the
  216. top-left of the table's top-left cell.
  217. */
  218. Rectangle<int> getCellPosition (int columnId, int rowNumber,
  219. bool relativeToComponentTopLeft) const;
  220. /** Returns the component that currently represents a given cell.
  221. If the component for this cell is off-screen or if the position is out-of-range,
  222. this may return nullptr.
  223. @see getCellPosition
  224. */
  225. Component* getCellComponent (int columnId, int rowNumber) const;
  226. /** Scrolls horizontally if necessary to make sure that a particular column is visible.
  227. @see ListBox::scrollToEnsureRowIsOnscreen
  228. */
  229. void scrollToEnsureColumnIsOnscreen (int columnId);
  230. //==============================================================================
  231. /** @internal */
  232. int getNumRows() override;
  233. /** @internal */
  234. void paintListBoxItem (int, Graphics&, int, int, bool) override;
  235. /** @internal */
  236. Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate) override;
  237. /** @internal */
  238. void selectedRowsChanged (int row) override;
  239. /** @internal */
  240. void deleteKeyPressed (int currentSelectedRow) override;
  241. /** @internal */
  242. void returnKeyPressed (int currentSelectedRow) override;
  243. /** @internal */
  244. void backgroundClicked (const MouseEvent&) override;
  245. /** @internal */
  246. void listWasScrolled() override;
  247. /** @internal */
  248. void tableColumnsChanged (TableHeaderComponent*) override;
  249. /** @internal */
  250. void tableColumnsResized (TableHeaderComponent*) override;
  251. /** @internal */
  252. void tableSortOrderChanged (TableHeaderComponent*) override;
  253. /** @internal */
  254. void tableColumnDraggingChanged (TableHeaderComponent*, int) override;
  255. /** @internal */
  256. void resized() override;
  257. /** @internal */
  258. std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
  259. /** Returns the model currently in use. */
  260. [[deprecated ("This function hides the non-virtual ListBox::getModel, use getTableListBoxModel instead")]]
  261. TableListBoxModel* getModel() const noexcept { return getTableListBoxModel(); }
  262. private:
  263. //==============================================================================
  264. class Header;
  265. class RowComp;
  266. TableHeaderComponent* header = nullptr;
  267. TableListBoxModel* model;
  268. int columnIdNowBeingDragged = 0;
  269. bool autoSizeOptionsShown = true;
  270. void updateColumnComponents() const;
  271. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableListBox)
  272. };
  273. } // namespace juce