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.

262 lines
8.0KB

  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. return valueWithDefault->isUsingDefault() ? var() : valueWithDefault->get();
  108. }
  109. void setValue (const var& newValue) override
  110. {
  111. if (newValue.toString().isEmpty())
  112. valueWithDefault->resetToDefault();
  113. else
  114. *valueWithDefault = newValue;
  115. }
  116. private:
  117. ValueWithDefault* valueWithDefault;
  118. //==============================================================================
  119. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RemapperValueSourceWithDefault)
  120. };
  121. //==============================================================================
  122. TextPropertyComponent::TextPropertyComponent (const String& name,
  123. int maxNumChars,
  124. bool multiLine,
  125. bool isEditable)
  126. : PropertyComponent (name),
  127. isMultiLine (multiLine)
  128. {
  129. createEditor (maxNumChars, isEditable);
  130. }
  131. TextPropertyComponent::TextPropertyComponent (const Value& valueToControl, const String& name,
  132. int maxNumChars, bool multiLine, bool isEditable)
  133. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  134. {
  135. textEditor->getTextValue().referTo (valueToControl);
  136. }
  137. TextPropertyComponent::TextPropertyComponent (ValueWithDefault& valueToControl, const String& name,
  138. int maxNumChars, bool multiLine, bool isEditable)
  139. : TextPropertyComponent (name, maxNumChars, multiLine, isEditable)
  140. {
  141. valueWithDefault = &valueToControl;
  142. textEditor->getTextValue().referTo (Value (new RemapperValueSourceWithDefault (valueWithDefault)));
  143. textEditor->setTextToDisplayWhenEmpty (valueWithDefault->getDefault(), 0.5f);
  144. valueWithDefault->onDefaultChange = [this]
  145. {
  146. textEditor->setTextToDisplayWhenEmpty (valueWithDefault->getDefault(), 0.5f);
  147. repaint();
  148. };
  149. }
  150. TextPropertyComponent::~TextPropertyComponent()
  151. {
  152. if (valueWithDefault != nullptr)
  153. valueWithDefault->onDefaultChange = nullptr;
  154. }
  155. void TextPropertyComponent::setText (const String& newText)
  156. {
  157. textEditor->setText (newText, sendNotificationSync);
  158. }
  159. String TextPropertyComponent::getText() const
  160. {
  161. return textEditor->getText();
  162. }
  163. Value& TextPropertyComponent::getValue() const
  164. {
  165. return textEditor->getTextValue();
  166. }
  167. void TextPropertyComponent::createEditor (int maxNumChars, bool isEditable)
  168. {
  169. textEditor.reset (new LabelComp (*this, maxNumChars, isMultiLine, isEditable));
  170. addAndMakeVisible (textEditor.get());
  171. if (isMultiLine)
  172. {
  173. textEditor->setJustificationType (Justification::topLeft);
  174. preferredHeight = 100;
  175. }
  176. }
  177. void TextPropertyComponent::refresh()
  178. {
  179. textEditor->setText (getText(), dontSendNotification);
  180. }
  181. void TextPropertyComponent::textWasEdited()
  182. {
  183. auto newText = textEditor->getText();
  184. if (getText() != newText)
  185. setText (newText);
  186. callListeners();
  187. }
  188. void TextPropertyComponent::addListener (TextPropertyComponent::Listener* l) { listenerList.add (l); }
  189. void TextPropertyComponent::removeListener (TextPropertyComponent::Listener* l) { listenerList.remove (l); }
  190. void TextPropertyComponent::callListeners()
  191. {
  192. Component::BailOutChecker checker (this);
  193. listenerList.callChecked (checker, [this] (Listener& l) { l.textPropertyComponentChanged (this); });
  194. }
  195. void TextPropertyComponent::colourChanged()
  196. {
  197. PropertyComponent::colourChanged();
  198. textEditor->updateColours();
  199. }
  200. void TextPropertyComponent::setInterestedInFileDrag (bool isInterested)
  201. {
  202. if (textEditor != nullptr)
  203. textEditor->setInterestedInFileDrag (isInterested);
  204. }
  205. void TextPropertyComponent::setEditable (bool isEditable)
  206. {
  207. if (textEditor != nullptr)
  208. textEditor->setEditable (isEditable, isEditable);
  209. }
  210. } // namespace juce