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.

268 lines
8.1KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. //==============================================================================
  22. class TextPropertyComponent::LabelComp : public Label,
  23. public FileDragAndDropTarget
  24. {
  25. public:
  26. LabelComp (TextPropertyComponent& tpc, int charLimit, bool multiline, bool editable)
  27. : Label ({}, {}),
  28. owner (tpc),
  29. maxChars (charLimit),
  30. isMultiline (multiline)
  31. {
  32. setEditable (editable, editable);
  33. updateColours();
  34. }
  35. bool isInterestedInFileDrag (const StringArray&) override
  36. {
  37. return interestedInFileDrag;
  38. }
  39. void filesDropped (const StringArray& files, int, int) override
  40. {
  41. setText (getText() + files.joinIntoString (isMultiline ? "\n" : ", "), sendNotificationSync);
  42. showEditor();
  43. }
  44. TextEditor* createEditorComponent() override
  45. {
  46. auto* ed = Label::createEditorComponent();
  47. ed->setInputRestrictions (maxChars);
  48. if (isMultiline)
  49. {
  50. ed->setMultiLine (true, true);
  51. ed->setReturnKeyStartsNewLine (true);
  52. }
  53. return ed;
  54. }
  55. void textWasEdited() override
  56. {
  57. owner.textWasEdited();
  58. }
  59. void updateColours()
  60. {
  61. setColour (backgroundColourId, owner.findColour (TextPropertyComponent::backgroundColourId));
  62. setColour (outlineColourId, owner.findColour (TextPropertyComponent::outlineColourId));
  63. setColour (textColourId, owner.findColour (TextPropertyComponent::textColourId));
  64. repaint();
  65. }
  66. void setInterestedInFileDrag (bool isInterested)
  67. {
  68. interestedInFileDrag = isInterested;
  69. }
  70. void setTextToDisplayWhenEmpty (const String& text, float alpha)
  71. {
  72. textToDisplayWhenEmpty = text;
  73. alphaToUseForEmptyText = alpha;
  74. }
  75. void paintOverChildren (Graphics& g) override
  76. {
  77. if (getText().isEmpty() && ! isBeingEdited())
  78. {
  79. auto& lf = owner.getLookAndFeel();
  80. auto textArea = lf.getLabelBorderSize (*this).subtractedFrom (getLocalBounds());
  81. auto labelFont = lf.getLabelFont (*this);
  82. g.setColour (owner.findColour (TextPropertyComponent::textColourId).withAlpha (alphaToUseForEmptyText));
  83. g.setFont (labelFont);
  84. g.drawFittedText (textToDisplayWhenEmpty, textArea, getJustificationType(),
  85. jmax (1, (int) (textArea.getHeight() / labelFont.getHeight())),
  86. getMinimumHorizontalScale());
  87. }
  88. }
  89. private:
  90. TextPropertyComponent& owner;
  91. int maxChars;
  92. bool isMultiline;
  93. bool interestedInFileDrag = true;
  94. String textToDisplayWhenEmpty;
  95. float alphaToUseForEmptyText = 0.0f;
  96. };
  97. //==============================================================================
  98. class TextPropertyComponent::RemapperValueSourceWithDefault : public Value::ValueSource
  99. {
  100. public:
  101. RemapperValueSourceWithDefault (ValueWithDefault* vwd)
  102. : valueWithDefault (vwd)
  103. {
  104. }
  105. var getValue() const override
  106. {
  107. if (valueWithDefault == nullptr || valueWithDefault->isUsingDefault())
  108. return {};
  109. return valueWithDefault->get();
  110. }
  111. void setValue (const var& newValue) override
  112. {
  113. if (valueWithDefault == nullptr)
  114. return;
  115. if (newValue.toString().isEmpty())
  116. valueWithDefault->resetToDefault();
  117. else
  118. *valueWithDefault = newValue;
  119. }
  120. private:
  121. WeakReference<ValueWithDefault> valueWithDefault;
  122. //==============================================================================
  123. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
  124. };
  125. //==============================================================================
  126. TextPropertyComponent::TextPropertyComponent (const String& name,
  127. int maxNumChars,
  128. bool multiLine,
  129. bool isEditable)
  130. : PropertyComponent (name),
  131. isMultiLine (multiLine)
  132. {
  133. createEditor (maxNumChars, isEditable);
  134. }
  135. TextPropertyComponent::TextPropertyComponent (const Value& valueToControl, const String& name,
  136. int maxNumChars, bool multiLine, bool isEditable)
  137. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  138. {
  139. textEditor->getTextValue().referTo (valueToControl);
  140. }
  141. TextPropertyComponent::TextPropertyComponent (ValueWithDefault& valueToControl, const String& name,
  142. int maxNumChars, bool multiLine, bool isEditable)
  143. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  144. {
  145. valueWithDefault = &valueToControl;
  146. textEditor->getTextValue().referTo (Value (new RemapperValueSourceWithDefault (valueWithDefault)));
  147. textEditor->setTextToDisplayWhenEmpty (valueWithDefault->getDefault(), 0.5f);
  148. valueWithDefault->onDefaultChange = [this]
  149. {
  150. textEditor->setTextToDisplayWhenEmpty (valueWithDefault->getDefault(), 0.5f);
  151. repaint();
  152. };
  153. }
  154. TextPropertyComponent::~TextPropertyComponent()
  155. {
  156. if (valueWithDefault != nullptr)
  157. valueWithDefault->onDefaultChange = nullptr;
  158. }
  159. void TextPropertyComponent::setText (const String& newText)
  160. {
  161. textEditor->setText (newText, sendNotificationSync);
  162. }
  163. String TextPropertyComponent::getText() const
  164. {
  165. return textEditor->getText();
  166. }
  167. Value& TextPropertyComponent::getValue() const
  168. {
  169. return textEditor->getTextValue();
  170. }
  171. void TextPropertyComponent::createEditor (int maxNumChars, bool isEditable)
  172. {
  173. textEditor.reset (new LabelComp (*this, maxNumChars, isMultiLine, isEditable));
  174. addAndMakeVisible (textEditor.get());
  175. if (isMultiLine)
  176. {
  177. textEditor->setJustificationType (Justification::topLeft);
  178. preferredHeight = 100;
  179. }
  180. }
  181. void TextPropertyComponent::refresh()
  182. {
  183. textEditor->setText (getText(), dontSendNotification);
  184. }
  185. void TextPropertyComponent::textWasEdited()
  186. {
  187. auto newText = textEditor->getText();
  188. if (getText() != newText)
  189. setText (newText);
  190. callListeners();
  191. }
  192. void TextPropertyComponent::addListener (TextPropertyComponent::Listener* l) { listenerList.add (l); }
  193. void TextPropertyComponent::removeListener (TextPropertyComponent::Listener* l) { listenerList.remove (l); }
  194. void TextPropertyComponent::callListeners()
  195. {
  196. Component::BailOutChecker checker (this);
  197. listenerList.callChecked (checker, [this] (Listener& l) { l.textPropertyComponentChanged (this); });
  198. }
  199. void TextPropertyComponent::colourChanged()
  200. {
  201. PropertyComponent::colourChanged();
  202. textEditor->updateColours();
  203. }
  204. void TextPropertyComponent::setInterestedInFileDrag (bool isInterested)
  205. {
  206. if (textEditor != nullptr)
  207. textEditor->setInterestedInFileDrag (isInterested);
  208. }
  209. void TextPropertyComponent::setEditable (bool isEditable)
  210. {
  211. if (textEditor != nullptr)
  212. textEditor->setEditable (isEditable, isEditable);
  213. }
  214. } // namespace juce