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.

281 lines
10KB

  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. #include "../../../Application/jucer_Headers.h"
  20. #include "jucer_DependencyPathPropertyComponent.h"
  21. //==============================================================================
  22. DependencyPathValueSource::DependencyPathValueSource (const Value& projectSettingsPath,
  23. Identifier globalSettingsKey,
  24. DependencyPathOS osThisSettingAppliesTo)
  25. : projectSettingsValue (projectSettingsPath),
  26. globalKey (globalSettingsKey),
  27. os (osThisSettingAppliesTo),
  28. globalSettingsValue (getAppSettings().getStoredPath (globalKey)),
  29. fallbackValue (getAppSettings().getFallbackPathForOS (globalKey, os))
  30. {
  31. globalSettingsValue.addListener (this);
  32. fallbackValue.addListener (this);
  33. }
  34. bool DependencyPathValueSource::isValidPath (const File& relativeTo) const
  35. {
  36. // if we are on another OS than the one which this path setting is for,
  37. // we have no way of knowing whether the path is valid - so just assume it is:
  38. if (! appliesToThisOS())
  39. return true;
  40. return getAppSettings().isGlobalPathValid (relativeTo, globalKey, getValue().toString());
  41. }
  42. bool DependencyPathValueSource::isValidPath() const
  43. {
  44. return isValidPath (File::getCurrentWorkingDirectory());
  45. }
  46. //==============================================================================
  47. DependencyPathPropertyComponent::DependencyPathPropertyComponent (const File& pathRelativeToUse,
  48. const Value& value,
  49. const String& propertyName)
  50. try : TextPropertyComponent (propertyName, 1024, false),
  51. pathRelativeTo (pathRelativeToUse),
  52. pathValue (value),
  53. pathValueSource (dynamic_cast<DependencyPathValueSource&> (pathValue.getValueSource()))
  54. {
  55. bool initialValueIsEmpty = ! pathValueSource.isUsingProjectSettings();
  56. getValue().referTo (pathValue);
  57. // the following step is necessary because the above referTo() has internally called setValue(),
  58. // which has set the project value to whatever is displayed in the label (this may be the
  59. // global/fallback value). In this case we have to reset the project value to blank:
  60. if (initialValueIsEmpty)
  61. getValue().setValue (String());
  62. getValue().addListener (this);
  63. if (auto* label = dynamic_cast<Label*> (getChildComponent (0)))
  64. label->onEditorShow = [this, label] { setEditorText (label); };
  65. else
  66. jassertfalse;
  67. lookAndFeelChanged();
  68. }
  69. catch (const std::bad_cast&)
  70. {
  71. // a DependencyPathPropertyComponent must be initialised with a Value
  72. // that is referring to a DependencyPathValueSource!
  73. jassertfalse;
  74. throw;
  75. }
  76. void DependencyPathPropertyComponent::valueChanged (Value& value)
  77. {
  78. // this callback handles the update of this setting in case
  79. // the user changed the global preferences.
  80. if (value.refersToSameSourceAs (pathValue) && pathValueSource.isUsingGlobalSettings())
  81. textWasEdited();
  82. }
  83. void DependencyPathPropertyComponent::textWasEdited()
  84. {
  85. setColour (textColourId, getTextColourToDisplay());
  86. TextPropertyComponent::textWasEdited();
  87. }
  88. Colour DependencyPathPropertyComponent::getTextColourToDisplay() const
  89. {
  90. if (! pathValueSource.isUsingProjectSettings())
  91. return pathValueSource.isValidPath (pathRelativeTo) ? findColour (widgetTextColourId).withMultipliedAlpha (0.5f)
  92. : Colours::red.withMultipliedAlpha (0.5f);
  93. return pathValueSource.isValidPath (pathRelativeTo) ? findColour (widgetTextColourId)
  94. : Colours::red;
  95. }
  96. void DependencyPathPropertyComponent::setEditorText (Label* label)
  97. {
  98. if (! pathValueSource.isUsingProjectSettings())
  99. if (auto editor = label->getCurrentTextEditor())
  100. editor->setText (String(), dontSendNotification);
  101. }
  102. void DependencyPathPropertyComponent::lookAndFeelChanged()
  103. {
  104. textWasEdited();
  105. }
  106. //==============================================================================
  107. DependencyFilePathPropertyComponent::DependencyFilePathPropertyComponent (Value& value,
  108. const String& propertyDescription,
  109. bool isDir,
  110. const String& wc,
  111. const File& rootToUseForRelativePaths)
  112. try : TextPropertyComponent (propertyDescription, 1024, false),
  113. pathRelativeTo (rootToUseForRelativePaths),
  114. pathValue (value),
  115. pathValueSource (dynamic_cast<DependencyPathValueSource&> (pathValue.getValueSource())),
  116. browseButton ("..."),
  117. isDirectory (isDir),
  118. wildcards (wc)
  119. {
  120. auto initialValueIsEmpty = ! pathValueSource.isUsingProjectSettings();
  121. getValue().referTo (pathValue);
  122. if (initialValueIsEmpty)
  123. getValue().setValue (String());
  124. getValue().addListener (this);
  125. if (auto* label = dynamic_cast<Label*> (getChildComponent (0)))
  126. label->onEditorShow = [this, label] { setEditorText (label); };
  127. else
  128. jassertfalse;
  129. setInterestedInFileDrag (false);
  130. addAndMakeVisible (browseButton);
  131. browseButton.onClick = [this] { browse(); };
  132. lookAndFeelChanged();
  133. }
  134. catch (const std::bad_cast&)
  135. {
  136. // a DependencyPathPropertyComponent must be initialised with a Value
  137. // that is referring to a DependencyPathValueSource!
  138. jassertfalse;
  139. throw;
  140. }
  141. void DependencyFilePathPropertyComponent::resized()
  142. {
  143. auto bounds = getLookAndFeel().getPropertyComponentContentPosition (*this);
  144. browseButton.setBounds (bounds.removeFromRight (30));
  145. getChildComponent (0)->setBounds (bounds);
  146. }
  147. void DependencyFilePathPropertyComponent::paintOverChildren (Graphics& g)
  148. {
  149. if (highlightForDragAndDrop)
  150. {
  151. g.setColour (findColour (defaultHighlightColourId).withAlpha (0.5f));
  152. g.fillRect (getChildComponent (0)->getBounds());
  153. }
  154. }
  155. void DependencyFilePathPropertyComponent::filesDropped (const StringArray& files, int, int)
  156. {
  157. const File firstFile (files[0]);
  158. if (isDirectory)
  159. setTo (firstFile.isDirectory() ? firstFile
  160. : firstFile.getParentDirectory());
  161. else
  162. setTo (firstFile);
  163. highlightForDragAndDrop = false;
  164. }
  165. void DependencyFilePathPropertyComponent::setTo (const File& f)
  166. {
  167. pathValue = (pathRelativeTo == File()) ? f.getFullPathName()
  168. : f.getRelativePathFrom (pathRelativeTo);
  169. textWasEdited();
  170. }
  171. void DependencyFilePathPropertyComponent::enablementChanged()
  172. {
  173. getValue().referTo (isEnabled() ? pathValue
  174. : pathValueSource.appliesToThisOS() ? pathValueSource.getGlobalSettingsValue()
  175. : pathValueSource.getFallbackSettingsValue());
  176. textWasEdited();
  177. repaint();
  178. }
  179. void DependencyFilePathPropertyComponent::textWasEdited()
  180. {
  181. setColour (textColourId, getTextColourToDisplay());
  182. TextPropertyComponent::textWasEdited();
  183. }
  184. void DependencyFilePathPropertyComponent::valueChanged (Value& value)
  185. {
  186. if ((value.refersToSameSourceAs (pathValue) && pathValueSource.isUsingGlobalSettings())
  187. || value.refersToSameSourceAs (pathValueSource.getGlobalSettingsValue()))
  188. textWasEdited();
  189. }
  190. void DependencyFilePathPropertyComponent::setEditorText (Label* label)
  191. {
  192. if (! pathValueSource.isUsingProjectSettings())
  193. if (auto editor = label->getCurrentTextEditor())
  194. editor->setText (String(), dontSendNotification);
  195. }
  196. void DependencyFilePathPropertyComponent::browse()
  197. {
  198. auto currentFile = pathRelativeTo.getChildFile (pathValue.toString());
  199. if (isDirectory)
  200. {
  201. FileChooser chooser ("Select directory", currentFile);
  202. if (chooser.browseForDirectory())
  203. setTo (chooser.getResult());
  204. }
  205. else
  206. {
  207. FileChooser chooser ("Select file", currentFile, wildcards);
  208. if (chooser.browseForFileToOpen())
  209. setTo (chooser.getResult());
  210. }
  211. }
  212. Colour DependencyFilePathPropertyComponent::getTextColourToDisplay() const
  213. {
  214. auto alpha = 1.0f;
  215. auto key = pathValueSource.getKey();
  216. const auto& globalSettingsValue = pathValueSource.getGlobalSettingsValue();
  217. if (! pathValueSource.isUsingProjectSettings() && isEnabled())
  218. alpha = 0.5f;
  219. if ((key == Ids::defaultUserModulePath && getValue().toString().contains (";")) || ! pathValueSource.appliesToThisOS())
  220. return findColour (widgetTextColourId).withMultipliedAlpha (alpha);
  221. auto usingGlobalPath = (getValue().refersToSameSourceAs (globalSettingsValue));
  222. auto isValidPath = getAppSettings().isGlobalPathValid (pathRelativeTo, key,
  223. (usingGlobalPath ? globalSettingsValue : pathValue).toString());
  224. return isValidPath ? findColour (widgetTextColourId).withMultipliedAlpha (alpha)
  225. : Colours::red.withMultipliedAlpha (alpha);
  226. }