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.

512 lines
20KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_BUTTON_JUCEHEADER__
  19. #define __JUCE_BUTTON_JUCEHEADER__
  20. #include "../juce_Component.h"
  21. #include "../keyboard/juce_KeyListener.h"
  22. #include "../../../application/juce_ApplicationCommandManager.h"
  23. #include "../../../containers/juce_SortedSet.h"
  24. #include "../../../containers/juce_Value.h"
  25. #include "../windows/juce_TooltipWindow.h"
  26. //==============================================================================
  27. /**
  28. A base class for buttons.
  29. This contains all the logic for button behaviours such as enabling/disabling,
  30. responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons
  31. and radio groups, etc.
  32. @see TextButton, DrawableButton, ToggleButton
  33. */
  34. class JUCE_API Button : public Component,
  35. public SettableTooltipClient,
  36. public ApplicationCommandManagerListener,
  37. public Value::Listener,
  38. private KeyListener
  39. {
  40. protected:
  41. //==============================================================================
  42. /** Creates a button.
  43. @param buttonName the text to put in the button (the component's name is also
  44. initially set to this string, but these can be changed later
  45. using the setName() and setButtonText() methods)
  46. */
  47. explicit Button (const String& buttonName);
  48. public:
  49. /** Destructor. */
  50. virtual ~Button();
  51. //==============================================================================
  52. /** Changes the button's text.
  53. @see getButtonText
  54. */
  55. void setButtonText (const String& newText);
  56. /** Returns the text displayed in the button.
  57. @see setButtonText
  58. */
  59. const String getButtonText() const { return text; }
  60. //==============================================================================
  61. /** Returns true if the button is currently being held down by the mouse.
  62. @see isOver
  63. */
  64. bool isDown() const throw();
  65. /** Returns true if the mouse is currently over the button.
  66. This will be also be true if the mouse is being held down.
  67. @see isDown
  68. */
  69. bool isOver() const throw();
  70. //==============================================================================
  71. /** A button has an on/off state associated with it, and this changes that.
  72. By default buttons are 'off' and for simple buttons that you click to perform
  73. an action you won't change this. Toggle buttons, however will want to
  74. change their state when turned on or off.
  75. @param shouldBeOn whether to set the button's toggle state to be on or
  76. off. If it's a member of a button group, this will
  77. always try to turn it on, and to turn off any other
  78. buttons in the group
  79. @param sendChangeNotification if true, a callback will be made to clicked(); if false
  80. the button will be repainted but no notification will
  81. be sent
  82. @see getToggleState, setRadioGroupId
  83. */
  84. void setToggleState (bool shouldBeOn,
  85. bool sendChangeNotification);
  86. /** Returns true if the button in 'on'.
  87. By default buttons are 'off' and for simple buttons that you click to perform
  88. an action you won't change this. Toggle buttons, however will want to
  89. change their state when turned on or off.
  90. @see setToggleState
  91. */
  92. bool getToggleState() const throw() { return isOn.getValue(); }
  93. /** Returns the Value object that represents the botton's toggle state.
  94. You can use this Value object to connect the button's state to external values or setters,
  95. either by taking a copy of the Value, or by using Value::referTo() to make it point to
  96. your own Value object.
  97. @see getToggleState, Value
  98. */
  99. Value& getToggleStateValue() { return isOn; }
  100. /** This tells the button to automatically flip the toggle state when
  101. the button is clicked.
  102. If set to true, then before the clicked() callback occurs, the toggle-state
  103. of the button is flipped.
  104. */
  105. void setClickingTogglesState (bool shouldToggle) throw();
  106. /** Returns true if this button is set to be an automatic toggle-button.
  107. This returns the last value that was passed to setClickingTogglesState().
  108. */
  109. bool getClickingTogglesState() const throw();
  110. //==============================================================================
  111. /** Enables the button to act as a member of a mutually-exclusive group
  112. of 'radio buttons'.
  113. If the group ID is set to a non-zero number, then this button will
  114. act as part of a group of buttons with the same ID, only one of
  115. which can be 'on' at the same time. Note that when it's part of
  116. a group, clicking a toggle-button that's 'on' won't turn it off.
  117. To find other buttons with the same ID, this button will search through
  118. its sibling components for ToggleButtons, so all the buttons for a
  119. particular group must be placed inside the same parent component.
  120. Set the group ID back to zero if you want it to act as a normal toggle
  121. button again.
  122. @see getRadioGroupId
  123. */
  124. void setRadioGroupId (int newGroupId);
  125. /** Returns the ID of the group to which this button belongs.
  126. (See setRadioGroupId() for an explanation of this).
  127. */
  128. int getRadioGroupId() const throw() { return radioGroupId; }
  129. //==============================================================================
  130. /**
  131. Used to receive callbacks when a button is clicked.
  132. @see Button::addButtonListener, Button::removeButtonListener
  133. */
  134. class JUCE_API Listener
  135. {
  136. public:
  137. /** Destructor. */
  138. virtual ~Listener() {}
  139. /** Called when the button is clicked. */
  140. virtual void buttonClicked (Button* button) = 0;
  141. /** Called when the button's state changes. */
  142. virtual void buttonStateChanged (Button*) {}
  143. };
  144. /** Registers a listener to receive events when this button's state changes.
  145. If the listener is already registered, this will not register it again.
  146. @see removeButtonListener
  147. */
  148. void addButtonListener (Listener* newListener);
  149. /** Removes a previously-registered button listener
  150. @see addButtonListener
  151. */
  152. void removeButtonListener (Listener* listener);
  153. //==============================================================================
  154. /** Causes the button to act as if it's been clicked.
  155. This will asynchronously make the button draw itself going down and up, and
  156. will then call back the clicked() method as if mouse was clicked on it.
  157. @see clicked
  158. */
  159. virtual void triggerClick();
  160. //==============================================================================
  161. /** Sets a command ID for this button to automatically invoke when it's clicked.
  162. When the button is pressed, it will use the given manager to trigger the
  163. command ID.
  164. Obviously be careful that the ApplicationCommandManager doesn't get deleted
  165. before this button is. To disable the command triggering, call this method and
  166. pass 0 for the parameters.
  167. If generateTooltip is true, then the button's tooltip will be automatically
  168. generated based on the name of this command and its current shortcut key.
  169. @see addShortcut, getCommandID
  170. */
  171. void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse,
  172. int commandID,
  173. bool generateTooltip);
  174. /** Returns the command ID that was set by setCommandToTrigger().
  175. */
  176. int getCommandID() const throw() { return commandID; }
  177. //==============================================================================
  178. /** Assigns a shortcut key to trigger the button.
  179. The button registers itself with its top-level parent component for keypresses.
  180. Note that a different way of linking buttons to keypresses is by using the
  181. setCommandToTrigger() method to invoke a command.
  182. @see clearShortcuts
  183. */
  184. void addShortcut (const KeyPress& key);
  185. /** Removes all key shortcuts that had been set for this button.
  186. @see addShortcut
  187. */
  188. void clearShortcuts();
  189. /** Returns true if the given keypress is a shortcut for this button.
  190. @see addShortcut
  191. */
  192. bool isRegisteredForShortcut (const KeyPress& key) const;
  193. //==============================================================================
  194. /** Sets an auto-repeat speed for the button when it is held down.
  195. (Auto-repeat is disabled by default).
  196. @param initialDelayInMillisecs how long to wait after the mouse is pressed before
  197. triggering the next click. If this is zero, auto-repeat
  198. is disabled
  199. @param repeatDelayInMillisecs the frequently subsequent repeated clicks should be
  200. triggered
  201. @param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will
  202. get faster, the longer the button is held down, up to the
  203. minimum interval specified here
  204. */
  205. void setRepeatSpeed (int initialDelayInMillisecs,
  206. int repeatDelayInMillisecs,
  207. int minimumDelayInMillisecs = -1) throw();
  208. /** Sets whether the button click should happen when the mouse is pressed or released.
  209. By default the button is only considered to have been clicked when the mouse is
  210. released, but setting this to true will make it call the clicked() method as soon
  211. as the button is pressed.
  212. This is useful if the button is being used to show a pop-up menu, as it allows
  213. the click to be used as a drag onto the menu.
  214. */
  215. void setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) throw();
  216. /** Returns the number of milliseconds since the last time the button
  217. went into the 'down' state.
  218. */
  219. uint32 getMillisecondsSinceButtonDown() const throw();
  220. //==============================================================================
  221. /** (overridden from Component to do special stuff). */
  222. void setVisible (bool shouldBeVisible);
  223. //==============================================================================
  224. /** Sets the tooltip for this button.
  225. @see TooltipClient, TooltipWindow
  226. */
  227. void setTooltip (const String& newTooltip);
  228. // (implementation of the TooltipClient method)
  229. const String getTooltip();
  230. //==============================================================================
  231. /** A combination of these flags are used by setConnectedEdges().
  232. */
  233. enum ConnectedEdgeFlags
  234. {
  235. ConnectedOnLeft = 1,
  236. ConnectedOnRight = 2,
  237. ConnectedOnTop = 4,
  238. ConnectedOnBottom = 8
  239. };
  240. /** Hints about which edges of the button might be connected to adjoining buttons.
  241. The value passed in is a bitwise combination of any of the values in the
  242. ConnectedEdgeFlags enum.
  243. E.g. if you are placing two buttons adjacent to each other, you could use this to
  244. indicate which edges are touching, and the LookAndFeel might choose to drawn them
  245. without rounded corners on the edges that connect. It's only a hint, so the
  246. LookAndFeel can choose to ignore it if it's not relevent for this type of
  247. button.
  248. */
  249. void setConnectedEdges (int connectedEdgeFlags);
  250. /** Returns the set of flags passed into setConnectedEdges(). */
  251. int getConnectedEdgeFlags() const throw() { return connectedEdgeFlags; }
  252. /** Indicates whether the button adjoins another one on its left edge.
  253. @see setConnectedEdges
  254. */
  255. bool isConnectedOnLeft() const throw() { return (connectedEdgeFlags & ConnectedOnLeft) != 0; }
  256. /** Indicates whether the button adjoins another one on its right edge.
  257. @see setConnectedEdges
  258. */
  259. bool isConnectedOnRight() const throw() { return (connectedEdgeFlags & ConnectedOnRight) != 0; }
  260. /** Indicates whether the button adjoins another one on its top edge.
  261. @see setConnectedEdges
  262. */
  263. bool isConnectedOnTop() const throw() { return (connectedEdgeFlags & ConnectedOnTop) != 0; }
  264. /** Indicates whether the button adjoins another one on its bottom edge.
  265. @see setConnectedEdges
  266. */
  267. bool isConnectedOnBottom() const throw() { return (connectedEdgeFlags & ConnectedOnBottom) != 0; }
  268. //==============================================================================
  269. /** Used by setState(). */
  270. enum ButtonState
  271. {
  272. buttonNormal,
  273. buttonOver,
  274. buttonDown
  275. };
  276. /** Can be used to force the button into a particular state.
  277. This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks
  278. from happening.
  279. The state that you set here will only last until it is automatically changed when the mouse
  280. enters or exits the button, or the mouse-button is pressed or released.
  281. */
  282. void setState (const ButtonState newState);
  283. //==============================================================================
  284. juce_UseDebuggingNewOperator
  285. protected:
  286. //==============================================================================
  287. /** This method is called when the button has been clicked.
  288. Subclasses can override this to perform whatever they actions they need
  289. to do.
  290. Alternatively, a ButtonListener can be added to the button, and these listeners
  291. will be called when the click occurs.
  292. @see triggerClick
  293. */
  294. virtual void clicked();
  295. /** This method is called when the button has been clicked.
  296. By default it just calls clicked(), but you might want to override it to handle
  297. things like clicking when a modifier key is pressed, etc.
  298. @see ModifierKeys
  299. */
  300. virtual void clicked (const ModifierKeys& modifiers);
  301. /** Subclasses should override this to actually paint the button's contents.
  302. It's better to use this than the paint method, because it gives you information
  303. about the over/down state of the button.
  304. @param g the graphics context to use
  305. @param isMouseOverButton true if the button is either in the 'over' or
  306. 'down' state
  307. @param isButtonDown true if the button should be drawn in the 'down' position
  308. */
  309. virtual void paintButton (Graphics& g,
  310. bool isMouseOverButton,
  311. bool isButtonDown) = 0;
  312. /** Called when the button's up/down/over state changes.
  313. Subclasses can override this if they need to do something special when the button
  314. goes up or down.
  315. @see isDown, isOver
  316. */
  317. virtual void buttonStateChanged();
  318. //==============================================================================
  319. /** @internal */
  320. virtual void internalClickCallback (const ModifierKeys& modifiers);
  321. /** @internal */
  322. void handleCommandMessage (int commandId);
  323. /** @internal */
  324. void mouseEnter (const MouseEvent& e);
  325. /** @internal */
  326. void mouseExit (const MouseEvent& e);
  327. /** @internal */
  328. void mouseDown (const MouseEvent& e);
  329. /** @internal */
  330. void mouseDrag (const MouseEvent& e);
  331. /** @internal */
  332. void mouseUp (const MouseEvent& e);
  333. /** @internal */
  334. bool keyPressed (const KeyPress& key);
  335. /** @internal */
  336. bool keyPressed (const KeyPress& key, Component* originatingComponent);
  337. /** @internal */
  338. bool keyStateChanged (bool isKeyDown, Component* originatingComponent);
  339. /** @internal */
  340. void paint (Graphics& g);
  341. /** @internal */
  342. void parentHierarchyChanged();
  343. /** @internal */
  344. void focusGained (FocusChangeType cause);
  345. /** @internal */
  346. void focusLost (FocusChangeType cause);
  347. /** @internal */
  348. void enablementChanged();
  349. /** @internal */
  350. void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&);
  351. /** @internal */
  352. void applicationCommandListChanged();
  353. /** @internal */
  354. void valueChanged (Value& value);
  355. private:
  356. //==============================================================================
  357. Array <KeyPress> shortcuts;
  358. Component::SafePointer<Component> keySource;
  359. String text;
  360. ListenerList <Listener> buttonListeners;
  361. class RepeatTimer;
  362. friend class RepeatTimer;
  363. friend class ScopedPointer <RepeatTimer>;
  364. ScopedPointer <RepeatTimer> repeatTimer;
  365. uint32 buttonPressTime, lastTimeCallbackTime;
  366. ApplicationCommandManager* commandManagerToUse;
  367. int autoRepeatDelay, autoRepeatSpeed, autoRepeatMinimumDelay;
  368. int radioGroupId, commandID, connectedEdgeFlags;
  369. ButtonState buttonState;
  370. Value isOn;
  371. bool lastToggleState : 1;
  372. bool clickTogglesState : 1;
  373. bool needsToRelease : 1;
  374. bool needsRepainting : 1;
  375. bool isKeyDown : 1;
  376. bool triggerOnMouseDown : 1;
  377. bool generateTooltip : 1;
  378. void repeatTimerCallback();
  379. RepeatTimer& getRepeatTimer();
  380. ButtonState updateState (const MouseEvent* const e);
  381. bool isShortcutPressed() const;
  382. void turnOffOtherButtonsInGroup (const bool sendChangeNotification);
  383. void flashButtonState();
  384. void sendClickMessage (const ModifierKeys& modifiers);
  385. void sendStateMessage();
  386. Button (const Button&);
  387. Button& operator= (const Button&);
  388. };
  389. /** This typedef is just for compatibility with old code - newer code should use Button::Listener instead. */
  390. typedef Button::Listener ButtonListener;
  391. #endif // __JUCE_BUTTON_JUCEHEADER__