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.

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