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.

260 lines
7.8KB

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