Audio plugin host https://kx.studio/carla
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.

263 lines
7.8KB

  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. class TextPropertyComponent::LabelComp : public Label,
  22. public FileDragAndDropTarget
  23. {
  24. public:
  25. LabelComp (TextPropertyComponent& tpc, int charLimit, bool multiline, bool editable)
  26. : Label ({}, {}),
  27. owner (tpc),
  28. maxChars (charLimit),
  29. isMultiline (multiline)
  30. {
  31. setEditable (editable, editable);
  32. updateColours();
  33. }
  34. bool isInterestedInFileDrag (const StringArray&) override
  35. {
  36. return interestedInFileDrag;
  37. }
  38. void filesDropped (const StringArray& files, int, int) override
  39. {
  40. setText (getText() + files.joinIntoString (isMultiline ? "\n" : ", "), sendNotificationSync);
  41. showEditor();
  42. }
  43. TextEditor* createEditorComponent() override
  44. {
  45. auto* ed = Label::createEditorComponent();
  46. ed->setInputRestrictions (maxChars);
  47. if (isMultiline)
  48. {
  49. ed->setMultiLine (true, true);
  50. ed->setReturnKeyStartsNewLine (true);
  51. }
  52. return ed;
  53. }
  54. void textWasEdited() override
  55. {
  56. owner.textWasEdited();
  57. }
  58. void updateColours()
  59. {
  60. setColour (backgroundColourId, owner.findColour (TextPropertyComponent::backgroundColourId));
  61. setColour (outlineColourId, owner.findColour (TextPropertyComponent::outlineColourId));
  62. setColour (textColourId, owner.findColour (TextPropertyComponent::textColourId));
  63. repaint();
  64. }
  65. void setInterestedInFileDrag (bool isInterested)
  66. {
  67. interestedInFileDrag = isInterested;
  68. }
  69. void setTextToDisplayWhenEmpty (const String& text, float alpha)
  70. {
  71. textToDisplayWhenEmpty = text;
  72. alphaToUseForEmptyText = alpha;
  73. }
  74. void paintOverChildren (Graphics& g) override
  75. {
  76. if (getText().isEmpty() && ! isBeingEdited())
  77. {
  78. auto& lf = owner.getLookAndFeel();
  79. auto textArea = lf.getLabelBorderSize (*this).subtractedFrom (getLocalBounds());
  80. auto labelFont = lf.getLabelFont (*this);
  81. g.setColour (owner.findColour (TextPropertyComponent::textColourId).withAlpha (alphaToUseForEmptyText));
  82. g.setFont (labelFont);
  83. g.drawFittedText (textToDisplayWhenEmpty, textArea, getJustificationType(),
  84. jmax (1, (int) ((float) textArea.getHeight() / labelFont.getHeight())),
  85. getMinimumHorizontalScale());
  86. }
  87. }
  88. private:
  89. TextPropertyComponent& owner;
  90. int maxChars;
  91. bool isMultiline;
  92. bool interestedInFileDrag = true;
  93. String textToDisplayWhenEmpty;
  94. float alphaToUseForEmptyText = 0.0f;
  95. };
  96. //==============================================================================
  97. class TextRemapperValueSourceWithDefault : public Value::ValueSource
  98. {
  99. public:
  100. TextRemapperValueSourceWithDefault (const ValueTreePropertyWithDefault& v)
  101. : value (v)
  102. {
  103. }
  104. var getValue() const override
  105. {
  106. if (value.isUsingDefault())
  107. return {};
  108. return value.get();
  109. }
  110. void setValue (const var& newValue) override
  111. {
  112. if (newValue.toString().isEmpty())
  113. {
  114. value.resetToDefault();
  115. return;
  116. }
  117. value = newValue;
  118. }
  119. private:
  120. ValueTreePropertyWithDefault value;
  121. //==============================================================================
  122. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextRemapperValueSourceWithDefault)
  123. };
  124. //==============================================================================
  125. TextPropertyComponent::TextPropertyComponent (const String& name,
  126. int maxNumChars,
  127. bool multiLine,
  128. bool isEditable)
  129. : PropertyComponent (name),
  130. isMultiLine (multiLine)
  131. {
  132. createEditor (maxNumChars, isEditable);
  133. }
  134. TextPropertyComponent::TextPropertyComponent (const Value& valueToControl, const String& name,
  135. int maxNumChars, bool multiLine, bool isEditable)
  136. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  137. {
  138. textEditor->getTextValue().referTo (valueToControl);
  139. }
  140. TextPropertyComponent::TextPropertyComponent (const ValueTreePropertyWithDefault& valueToControl, const String& name,
  141. int maxNumChars, bool multiLine, bool isEditable)
  142. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  143. {
  144. value = valueToControl;
  145. textEditor->getTextValue().referTo (Value (new TextRemapperValueSourceWithDefault (value)));
  146. textEditor->setTextToDisplayWhenEmpty (value.getDefault(), 0.5f);
  147. value.onDefaultChange = [this]
  148. {
  149. textEditor->setTextToDisplayWhenEmpty (value.getDefault(), 0.5f);
  150. repaint();
  151. };
  152. }
  153. TextPropertyComponent::~TextPropertyComponent() {}
  154. void TextPropertyComponent::setText (const String& newText)
  155. {
  156. textEditor->setText (newText, sendNotificationSync);
  157. }
  158. String TextPropertyComponent::getText() const
  159. {
  160. return textEditor->getText();
  161. }
  162. Value& TextPropertyComponent::getValue() const
  163. {
  164. return textEditor->getTextValue();
  165. }
  166. void TextPropertyComponent::createEditor (int maxNumChars, bool isEditable)
  167. {
  168. textEditor.reset (new LabelComp (*this, maxNumChars, isMultiLine, isEditable));
  169. addAndMakeVisible (textEditor.get());
  170. if (isMultiLine)
  171. {
  172. textEditor->setJustificationType (Justification::topLeft);
  173. preferredHeight = 100;
  174. }
  175. }
  176. void TextPropertyComponent::refresh()
  177. {
  178. textEditor->setText (getText(), dontSendNotification);
  179. }
  180. void TextPropertyComponent::textWasEdited()
  181. {
  182. auto newText = textEditor->getText();
  183. if (getText() != newText)
  184. setText (newText);
  185. callListeners();
  186. }
  187. void TextPropertyComponent::addListener (TextPropertyComponent::Listener* l) { listenerList.add (l); }
  188. void TextPropertyComponent::removeListener (TextPropertyComponent::Listener* l) { listenerList.remove (l); }
  189. void TextPropertyComponent::callListeners()
  190. {
  191. Component::BailOutChecker checker (this);
  192. listenerList.callChecked (checker, [this] (Listener& l) { l.textPropertyComponentChanged (this); });
  193. }
  194. void TextPropertyComponent::colourChanged()
  195. {
  196. PropertyComponent::colourChanged();
  197. textEditor->updateColours();
  198. }
  199. void TextPropertyComponent::setInterestedInFileDrag (bool isInterested)
  200. {
  201. if (textEditor != nullptr)
  202. textEditor->setInterestedInFileDrag (isInterested);
  203. }
  204. void TextPropertyComponent::setEditable (bool isEditable)
  205. {
  206. if (textEditor != nullptr)
  207. textEditor->setEditable (isEditable, isEditable);
  208. }
  209. } // namespace juce