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.

258 lines
7.8KB

  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 (const 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. textEditor->getTextValue().referTo (Value (new RemapperValueSourceWithDefault (valueToControl)));
  142. textEditor->setTextToDisplayWhenEmpty (valueToControl.getDefault(), 0.5f);
  143. valueToControl.onDefaultChange = [this, &valueToControl]
  144. {
  145. textEditor->setTextToDisplayWhenEmpty (valueToControl.getDefault(), 0.5f);
  146. repaint();
  147. };
  148. }
  149. TextPropertyComponent::~TextPropertyComponent()
  150. {
  151. }
  152. void TextPropertyComponent::setText (const String& newText)
  153. {
  154. textEditor->setText (newText, sendNotificationSync);
  155. }
  156. String TextPropertyComponent::getText() const
  157. {
  158. return textEditor->getText();
  159. }
  160. Value& TextPropertyComponent::getValue() const
  161. {
  162. return textEditor->getTextValue();
  163. }
  164. void TextPropertyComponent::createEditor (int maxNumChars, bool isEditable)
  165. {
  166. textEditor.reset (new LabelComp (*this, maxNumChars, isMultiLine, isEditable));
  167. addAndMakeVisible (textEditor.get());
  168. if (isMultiLine)
  169. {
  170. textEditor->setJustificationType (Justification::topLeft);
  171. preferredHeight = 100;
  172. }
  173. }
  174. void TextPropertyComponent::refresh()
  175. {
  176. textEditor->setText (getText(), dontSendNotification);
  177. }
  178. void TextPropertyComponent::textWasEdited()
  179. {
  180. auto newText = textEditor->getText();
  181. if (getText() != newText)
  182. setText (newText);
  183. callListeners();
  184. }
  185. void TextPropertyComponent::addListener (TextPropertyComponent::Listener* l) { listenerList.add (l); }
  186. void TextPropertyComponent::removeListener (TextPropertyComponent::Listener* l) { listenerList.remove (l); }
  187. void TextPropertyComponent::callListeners()
  188. {
  189. Component::BailOutChecker checker (this);
  190. listenerList.callChecked (checker, [this] (Listener& l) { l.textPropertyComponentChanged (this); });
  191. }
  192. void TextPropertyComponent::colourChanged()
  193. {
  194. PropertyComponent::colourChanged();
  195. textEditor->updateColours();
  196. }
  197. void TextPropertyComponent::setInterestedInFileDrag (bool isInterested)
  198. {
  199. if (textEditor != nullptr)
  200. textEditor->setInterestedInFileDrag (isInterested);
  201. }
  202. void TextPropertyComponent::setEditable (bool isEditable)
  203. {
  204. if (textEditor != nullptr)
  205. textEditor->setEditable (isEditable, isEditable);
  206. }
  207. } // namespace juce