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.

457 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-9 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. #include "../../../core/juce_StandardHeader.h"
  19. BEGIN_JUCE_NAMESPACE
  20. #include "juce_Label.h"
  21. #include "../lookandfeel/juce_LookAndFeel.h"
  22. //==============================================================================
  23. Label::Label (const String& componentName,
  24. const String& labelText)
  25. : Component (componentName),
  26. text (labelText),
  27. font (15.0f),
  28. justification (Justification::centredLeft),
  29. listeners (2),
  30. ownerComponent (0),
  31. horizontalBorderSize (3),
  32. verticalBorderSize (1),
  33. minimumHorizontalScale (0.7f),
  34. editSingleClick (false),
  35. editDoubleClick (false),
  36. lossOfFocusDiscardsChanges (false)
  37. {
  38. setColour (TextEditor::textColourId, Colours::black);
  39. setColour (TextEditor::backgroundColourId, Colours::transparentBlack);
  40. setColour (TextEditor::outlineColourId, Colours::transparentBlack);
  41. }
  42. Label::~Label()
  43. {
  44. if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
  45. ownerComponent->removeComponentListener (this);
  46. editor = 0;
  47. }
  48. //==============================================================================
  49. void Label::setText (const String& newText,
  50. const bool broadcastChangeMessage)
  51. {
  52. hideEditor (true);
  53. if (text != newText)
  54. {
  55. text = newText;
  56. repaint();
  57. textWasChanged();
  58. if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
  59. componentMovedOrResized (*ownerComponent, true, true);
  60. if (broadcastChangeMessage)
  61. callChangeListeners();
  62. }
  63. }
  64. const String Label::getText (const bool returnActiveEditorContents) const throw()
  65. {
  66. return (returnActiveEditorContents && isBeingEdited())
  67. ? editor->getText()
  68. : text;
  69. }
  70. void Label::setFont (const Font& newFont) throw()
  71. {
  72. font = newFont;
  73. repaint();
  74. }
  75. const Font& Label::getFont() const throw()
  76. {
  77. return font;
  78. }
  79. void Label::setEditable (const bool editOnSingleClick,
  80. const bool editOnDoubleClick,
  81. const bool lossOfFocusDiscardsChanges_) throw()
  82. {
  83. editSingleClick = editOnSingleClick;
  84. editDoubleClick = editOnDoubleClick;
  85. lossOfFocusDiscardsChanges = lossOfFocusDiscardsChanges_;
  86. setWantsKeyboardFocus (editOnSingleClick || editOnDoubleClick);
  87. setFocusContainer (editOnSingleClick || editOnDoubleClick);
  88. }
  89. void Label::setJustificationType (const Justification& justification_) throw()
  90. {
  91. justification = justification_;
  92. repaint();
  93. }
  94. void Label::setBorderSize (int h, int v)
  95. {
  96. horizontalBorderSize = h;
  97. verticalBorderSize = v;
  98. repaint();
  99. }
  100. //==============================================================================
  101. void Label::attachToComponent (Component* owner,
  102. const bool onLeft)
  103. {
  104. if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
  105. ownerComponent->removeComponentListener (this);
  106. deletionWatcher = 0;
  107. ownerComponent = owner;
  108. leftOfOwnerComp = onLeft;
  109. if (ownerComponent != 0)
  110. {
  111. deletionWatcher = new ComponentDeletionWatcher (owner);
  112. setVisible (owner->isVisible());
  113. ownerComponent->addComponentListener (this);
  114. componentParentHierarchyChanged (*ownerComponent);
  115. componentMovedOrResized (*ownerComponent, true, true);
  116. }
  117. }
  118. void Label::componentMovedOrResized (Component& component,
  119. bool /*wasMoved*/,
  120. bool /*wasResized*/)
  121. {
  122. if (leftOfOwnerComp)
  123. {
  124. setSize (jmin (getFont().getStringWidth (text) + 8, component.getX()),
  125. component.getHeight());
  126. setTopRightPosition (component.getX(), component.getY());
  127. }
  128. else
  129. {
  130. setSize (component.getWidth(),
  131. 8 + roundFloatToInt (getFont().getHeight()));
  132. setTopLeftPosition (component.getX(), component.getY() - getHeight());
  133. }
  134. }
  135. void Label::componentParentHierarchyChanged (Component& component)
  136. {
  137. if (component.getParentComponent() != 0)
  138. component.getParentComponent()->addChildComponent (this);
  139. }
  140. void Label::componentVisibilityChanged (Component& component)
  141. {
  142. setVisible (component.isVisible());
  143. }
  144. //==============================================================================
  145. void Label::textWasEdited()
  146. {
  147. }
  148. void Label::textWasChanged()
  149. {
  150. }
  151. void Label::showEditor()
  152. {
  153. if (editor == 0)
  154. {
  155. addAndMakeVisible (editor = createEditorComponent());
  156. editor->setText (getText(), false);
  157. editor->addListener (this);
  158. editor->grabKeyboardFocus();
  159. editor->setHighlightedRegion (0, text.length());
  160. editor->addListener (this);
  161. resized();
  162. repaint();
  163. editorShown (editor);
  164. enterModalState();
  165. editor->grabKeyboardFocus();
  166. }
  167. }
  168. void Label::editorShown (TextEditor* editorComponent)
  169. {
  170. }
  171. void Label::editorAboutToBeHidden (TextEditor* editorComponent)
  172. {
  173. }
  174. bool Label::updateFromTextEditorContents()
  175. {
  176. jassert (editor != 0);
  177. const String newText (editor->getText());
  178. if (text != newText)
  179. {
  180. text = newText;
  181. repaint();
  182. textWasChanged();
  183. if (ownerComponent != 0 && ! deletionWatcher->hasBeenDeleted())
  184. componentMovedOrResized (*ownerComponent, true, true);
  185. return true;
  186. }
  187. return false;
  188. }
  189. void Label::hideEditor (const bool discardCurrentEditorContents)
  190. {
  191. if (editor != 0)
  192. {
  193. editorAboutToBeHidden (editor);
  194. const bool changed = (! discardCurrentEditorContents)
  195. && updateFromTextEditorContents();
  196. editor = 0;
  197. repaint();
  198. if (changed)
  199. textWasEdited();
  200. exitModalState (0);
  201. if (changed && isValidComponent())
  202. callChangeListeners();
  203. }
  204. }
  205. void Label::inputAttemptWhenModal()
  206. {
  207. if (editor != 0)
  208. {
  209. if (lossOfFocusDiscardsChanges)
  210. textEditorEscapeKeyPressed (*editor);
  211. else
  212. textEditorReturnKeyPressed (*editor);
  213. }
  214. }
  215. bool Label::isBeingEdited() const throw()
  216. {
  217. return editor != 0;
  218. }
  219. TextEditor* Label::createEditorComponent()
  220. {
  221. TextEditor* const ed = new TextEditor (getName());
  222. ed->setFont (font);
  223. // copy these colours from our own settings..
  224. const int cols[] = { TextEditor::backgroundColourId,
  225. TextEditor::textColourId,
  226. TextEditor::highlightColourId,
  227. TextEditor::highlightedTextColourId,
  228. TextEditor::caretColourId,
  229. TextEditor::outlineColourId,
  230. TextEditor::focusedOutlineColourId,
  231. TextEditor::shadowColourId };
  232. for (int i = 0; i < numElementsInArray (cols); ++i)
  233. ed->setColour (cols[i], findColour (cols[i]));
  234. return ed;
  235. }
  236. //==============================================================================
  237. void Label::paint (Graphics& g)
  238. {
  239. getLookAndFeel().drawLabel (g, *this);
  240. }
  241. void Label::mouseUp (const MouseEvent& e)
  242. {
  243. if (editSingleClick
  244. && e.mouseWasClicked()
  245. && contains (e.x, e.y)
  246. && ! e.mods.isPopupMenu())
  247. {
  248. showEditor();
  249. }
  250. }
  251. void Label::mouseDoubleClick (const MouseEvent& e)
  252. {
  253. if (editDoubleClick && ! e.mods.isPopupMenu())
  254. showEditor();
  255. }
  256. void Label::resized()
  257. {
  258. if (editor != 0)
  259. editor->setBoundsInset (BorderSize (0));
  260. }
  261. void Label::focusGained (FocusChangeType cause)
  262. {
  263. if (editSingleClick && cause == focusChangedByTabKey)
  264. showEditor();
  265. }
  266. void Label::enablementChanged()
  267. {
  268. repaint();
  269. }
  270. void Label::colourChanged()
  271. {
  272. repaint();
  273. }
  274. void Label::setMinimumHorizontalScale (const float newScale)
  275. {
  276. if (minimumHorizontalScale != newScale)
  277. {
  278. minimumHorizontalScale = newScale;
  279. repaint();
  280. }
  281. }
  282. //==============================================================================
  283. // We'll use a custom focus traverser here to make sure focus goes from the
  284. // text editor to another component rather than back to the label itself.
  285. class LabelKeyboardFocusTraverser : public KeyboardFocusTraverser
  286. {
  287. public:
  288. LabelKeyboardFocusTraverser() {}
  289. Component* getNextComponent (Component* current)
  290. {
  291. return KeyboardFocusTraverser::getNextComponent (dynamic_cast <TextEditor*> (current) != 0
  292. ? current->getParentComponent() : current);
  293. }
  294. Component* getPreviousComponent (Component* current)
  295. {
  296. return KeyboardFocusTraverser::getPreviousComponent (dynamic_cast <TextEditor*> (current) != 0
  297. ? current->getParentComponent() : current);
  298. }
  299. };
  300. KeyboardFocusTraverser* Label::createFocusTraverser()
  301. {
  302. return new LabelKeyboardFocusTraverser();
  303. }
  304. //==============================================================================
  305. void Label::addListener (LabelListener* const listener) throw()
  306. {
  307. jassert (listener != 0);
  308. if (listener != 0)
  309. listeners.add (listener);
  310. }
  311. void Label::removeListener (LabelListener* const listener) throw()
  312. {
  313. listeners.removeValue (listener);
  314. }
  315. void Label::callChangeListeners()
  316. {
  317. for (int i = listeners.size(); --i >= 0;)
  318. {
  319. ((LabelListener*) listeners.getUnchecked (i))->labelTextChanged (this);
  320. i = jmin (i, listeners.size());
  321. }
  322. }
  323. //==============================================================================
  324. void Label::textEditorTextChanged (TextEditor& ed)
  325. {
  326. if (editor != 0)
  327. {
  328. jassert (&ed == editor);
  329. if (! (hasKeyboardFocus (true) || isCurrentlyBlockedByAnotherModalComponent()))
  330. {
  331. if (lossOfFocusDiscardsChanges)
  332. textEditorEscapeKeyPressed (ed);
  333. else
  334. textEditorReturnKeyPressed (ed);
  335. }
  336. }
  337. }
  338. void Label::textEditorReturnKeyPressed (TextEditor& ed)
  339. {
  340. if (editor != 0)
  341. {
  342. jassert (&ed == editor);
  343. (void) ed;
  344. const bool changed = updateFromTextEditorContents();
  345. hideEditor (true);
  346. if (changed)
  347. {
  348. textWasEdited();
  349. if (isValidComponent())
  350. callChangeListeners();
  351. }
  352. }
  353. }
  354. void Label::textEditorEscapeKeyPressed (TextEditor& ed)
  355. {
  356. if (editor != 0)
  357. {
  358. jassert (&ed == editor);
  359. (void) ed;
  360. editor->setText (text, false);
  361. hideEditor (true);
  362. }
  363. }
  364. void Label::textEditorFocusLost (TextEditor& ed)
  365. {
  366. textEditorTextChanged (ed);
  367. }
  368. END_JUCE_NAMESPACE