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.

juce_LiveConstantEditor.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  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 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. #if JUCE_ENABLE_LIVE_CONSTANT_EDITOR && ! DOXYGEN
  21. //==============================================================================
  22. /** You can safely ignore all the stuff in this namespace - it's a bunch of boilerplate
  23. code used to implement the JUCE_LIVE_CONSTANT functionality.
  24. */
  25. namespace LiveConstantEditor
  26. {
  27. int64 parseInt (String);
  28. double parseDouble (const String&);
  29. String intToString (int, bool preferHex);
  30. String intToString (int64, bool preferHex);
  31. template <typename Type>
  32. static void setFromString (Type& v, const String& s) { v = static_cast<Type> (s); }
  33. inline void setFromString (char& v, const String& s) { v = (char) parseInt (s); }
  34. inline void setFromString (unsigned char& v, const String& s) { v = (unsigned char) parseInt (s); }
  35. inline void setFromString (short& v, const String& s) { v = (short) parseInt (s); }
  36. inline void setFromString (unsigned short& v, const String& s) { v = (unsigned short) parseInt (s); }
  37. inline void setFromString (int& v, const String& s) { v = (int) parseInt (s); }
  38. inline void setFromString (unsigned int& v, const String& s) { v = (unsigned int) parseInt (s); }
  39. inline void setFromString (long& v, const String& s) { v = (long) parseInt (s); }
  40. inline void setFromString (unsigned long& v, const String& s) { v = (unsigned long) parseInt (s); }
  41. inline void setFromString (int64& v, const String& s) { v = (int64) parseInt (s); }
  42. inline void setFromString (uint64& v, const String& s) { v = (uint64) parseInt (s); }
  43. inline void setFromString (double& v, const String& s) { v = parseDouble (s); }
  44. inline void setFromString (float& v, const String& s) { v = (float) parseDouble (s); }
  45. inline void setFromString (bool& v, const String& s) { v = (s == "true"); }
  46. inline void setFromString (String& v, const String& s) { v = s; }
  47. inline void setFromString (Colour& v, const String& s) { v = Colour ((uint32) parseInt (s)); }
  48. template <typename Type>
  49. inline String getAsString (const Type& v, bool) { return String (v); }
  50. inline String getAsString (char v, bool preferHex) { return intToString ((int) v, preferHex); }
  51. inline String getAsString (unsigned char v, bool preferHex) { return intToString ((int) v, preferHex); }
  52. inline String getAsString (short v, bool preferHex) { return intToString ((int) v, preferHex); }
  53. inline String getAsString (unsigned short v, bool preferHex) { return intToString ((int) v, preferHex); }
  54. inline String getAsString (int v, bool preferHex) { return intToString ((int) v, preferHex); }
  55. inline String getAsString (unsigned int v, bool preferHex) { return intToString ((int) v, preferHex); }
  56. inline String getAsString (bool v, bool) { return v ? "true" : "false"; }
  57. inline String getAsString (int64 v, bool preferHex) { return intToString ((int64) v, preferHex); }
  58. inline String getAsString (uint64 v, bool preferHex) { return intToString ((int64) v, preferHex); }
  59. inline String getAsString (Colour v, bool) { return intToString ((int) v.getARGB(), true); }
  60. template <typename Type> struct isStringType { enum { value = 0 }; };
  61. template <> struct isStringType<String> { enum { value = 1 }; };
  62. template <typename Type>
  63. inline String getAsCode (Type& v, bool preferHex) { return getAsString (v, preferHex); }
  64. inline String getAsCode (Colour v, bool) { return "Colour (0x" + String::toHexString ((int) v.getARGB()).paddedLeft ('0', 8) + ")"; }
  65. inline String getAsCode (const String& v, bool) { return CppTokeniserFunctions::addEscapeChars(v).quoted(); }
  66. inline String getAsCode (const char* v, bool) { return getAsCode (String (v), false); }
  67. template <typename Type>
  68. inline const char* castToCharPointer (const Type&) { return ""; }
  69. inline const char* castToCharPointer (const String& s) { return s.toRawUTF8(); }
  70. struct LivePropertyEditorBase;
  71. //==============================================================================
  72. struct JUCE_API LiveValueBase
  73. {
  74. LiveValueBase (const char* file, int line);
  75. virtual ~LiveValueBase();
  76. virtual LivePropertyEditorBase* createPropertyComponent (CodeDocument&) = 0;
  77. virtual String getStringValue (bool preferHex) const = 0;
  78. virtual String getCodeValue (bool preferHex) const = 0;
  79. virtual void setStringValue (const String&) = 0;
  80. virtual String getOriginalStringValue (bool preferHex) const = 0;
  81. virtual bool isString() const = 0;
  82. String name, sourceFile;
  83. int sourceLine;
  84. JUCE_DECLARE_NON_COPYABLE (LiveValueBase)
  85. };
  86. //==============================================================================
  87. struct JUCE_API LivePropertyEditorBase : public Component
  88. {
  89. LivePropertyEditorBase (LiveValueBase&, CodeDocument&);
  90. void paint (Graphics&) override;
  91. void resized() override;
  92. void applyNewValue (const String&);
  93. void selectOriginalValue();
  94. void findOriginalValueInCode();
  95. LiveValueBase& value;
  96. Label name;
  97. TextEditor valueEditor;
  98. TextButton resetButton { "reset" };
  99. CodeDocument& document;
  100. CPlusPlusCodeTokeniser tokeniser;
  101. CodeEditorComponent sourceEditor;
  102. CodeDocument::Position valueStart, valueEnd;
  103. std::unique_ptr<Component> customComp;
  104. bool wasHex = false;
  105. JUCE_DECLARE_NON_COPYABLE (LivePropertyEditorBase)
  106. };
  107. //==============================================================================
  108. Component* createColourEditor (LivePropertyEditorBase&);
  109. Component* createIntegerSlider (LivePropertyEditorBase&);
  110. Component* createFloatSlider (LivePropertyEditorBase&);
  111. Component* createBoolSlider (LivePropertyEditorBase&);
  112. template <typename Type> struct CustomEditor { static Component* create (LivePropertyEditorBase&) { return nullptr; } };
  113. template<> struct CustomEditor<char> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  114. template<> struct CustomEditor<unsigned char> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  115. template<> struct CustomEditor<int> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  116. template<> struct CustomEditor<unsigned int> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  117. template<> struct CustomEditor<short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  118. template<> struct CustomEditor<unsigned short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  119. template<> struct CustomEditor<int64> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  120. template<> struct CustomEditor<uint64> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
  121. template<> struct CustomEditor<float> { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
  122. template<> struct CustomEditor<double> { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
  123. template<> struct CustomEditor<Colour> { static Component* create (LivePropertyEditorBase& e) { return createColourEditor (e); } };
  124. template<> struct CustomEditor<bool> { static Component* create (LivePropertyEditorBase& e) { return createBoolSlider (e); } };
  125. template <typename Type>
  126. struct LivePropertyEditor : public LivePropertyEditorBase
  127. {
  128. template <typename ValueType>
  129. LivePropertyEditor (ValueType& v, CodeDocument& d) : LivePropertyEditorBase (v, d)
  130. {
  131. customComp.reset (CustomEditor<Type>::create (*this));
  132. addAndMakeVisible (customComp.get());
  133. }
  134. };
  135. //==============================================================================
  136. template <typename Type>
  137. struct LiveValue : public LiveValueBase
  138. {
  139. LiveValue (const char* file, int line, const Type& initialValue)
  140. : LiveValueBase (file, line), value (initialValue), originalValue (initialValue)
  141. {}
  142. operator Type() const noexcept { return value; }
  143. Type get() const noexcept { return value; }
  144. operator const char*() const { return castToCharPointer (value); }
  145. LivePropertyEditorBase* createPropertyComponent (CodeDocument& doc) override
  146. {
  147. return new LivePropertyEditor<Type> (*this, doc);
  148. }
  149. String getStringValue (bool preferHex) const override { return getAsString (value, preferHex); }
  150. String getCodeValue (bool preferHex) const override { return getAsCode (value, preferHex); }
  151. String getOriginalStringValue (bool preferHex) const override { return getAsString (originalValue, preferHex); }
  152. void setStringValue (const String& s) override { setFromString (value, s); }
  153. bool isString() const override { return isStringType<Type>::value; }
  154. Type value, originalValue;
  155. JUCE_DECLARE_NON_COPYABLE (LiveValue)
  156. };
  157. //==============================================================================
  158. class JUCE_API ValueList : private AsyncUpdater,
  159. private DeletedAtShutdown
  160. {
  161. public:
  162. ValueList();
  163. ~ValueList() override;
  164. JUCE_DECLARE_SINGLETON (ValueList, false)
  165. template <typename Type>
  166. LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
  167. {
  168. const ScopedLock sl (lock);
  169. using ValueType = LiveValue<Type>;
  170. for (auto* v : values)
  171. if (v->sourceLine == line && v->sourceFile == file)
  172. return *static_cast<ValueType*> (v);
  173. auto v = new ValueType (file, line, initialValue);
  174. addValue (v);
  175. return *v;
  176. }
  177. private:
  178. OwnedArray<LiveValueBase> values;
  179. OwnedArray<CodeDocument> documents;
  180. Array<File> documentFiles;
  181. class EditorWindow;
  182. Component::SafePointer<EditorWindow> editorWindow;
  183. CriticalSection lock;
  184. CodeDocument& getDocument (const File&);
  185. void addValue (LiveValueBase*);
  186. void handleAsyncUpdate() override;
  187. };
  188. template <typename Type>
  189. inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
  190. {
  191. // If you hit this assertion then the __FILE__ macro is providing a
  192. // relative path instead of an absolute path. On Windows this will be
  193. // a path relative to the build directory rather than the currently
  194. // running application. To fix this you must compile with the /FC flag.
  195. jassert (File::isAbsolutePath (file));
  196. return ValueList::getInstance()->getValue (file, line, initialValue);
  197. }
  198. inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue)
  199. {
  200. return getValue (file, line, String (initialValue));
  201. }
  202. }
  203. #endif
  204. //==============================================================================
  205. #if JUCE_ENABLE_LIVE_CONSTANT_EDITOR || DOXYGEN
  206. /**
  207. This macro wraps a primitive constant value in some cunning boilerplate code that allows
  208. its value to be interactively tweaked in a popup window while your application is running.
  209. In a release build, this macro disappears and is replaced by only the constant that it
  210. wraps, but if JUCE_ENABLE_LIVE_CONSTANT_EDITOR is enabled, it injects a class wrapper
  211. that automatically pops-up a window containing an editor that allows the value to be
  212. tweaked at run-time. The editor window will also force all visible components to be
  213. resized and repainted whenever a value is changed, so that if you use this to wrap
  214. a colour or layout parameter, you'll be able to immediately see the effects of changing it.
  215. The editor will also load the original source-file that contains each JUCE_LIVE_CONSTANT
  216. macro, and will display a preview of the modified source code as you adjust the values.
  217. Things to note:
  218. - Only one of these per line! The __FILE__ and __LINE__ macros are used to identify
  219. the value, so things will get confused if you have more than one per line
  220. - Obviously because it needs to load the source code based on the __FILE__ macro,
  221. it'll only work if the source files are stored locally in the same location as they
  222. were when you compiled the program.
  223. - It's only designed to cope with simple types: primitives, string literals, and
  224. the Colour class, so if you try using it for other classes or complex expressions,
  225. good luck!
  226. - The editor window will get popped up whenever a new value is used for the first
  227. time. You can close the window, but there's no way to get it back without restarting
  228. the app!
  229. e.g. in this example the colours, font size, and text used in the paint method can
  230. all be adjusted live:
  231. @code
  232. void MyComp::paint (Graphics& g) override
  233. {
  234. g.fillAll (JUCE_LIVE_CONSTANT (Colour (0xffddddff)));
  235. Colour fontColour = JUCE_LIVE_CONSTANT (Colour (0xff005500));
  236. float fontSize = JUCE_LIVE_CONSTANT (16.0f);
  237. g.setColour (fontColour);
  238. g.setFont (fontSize);
  239. g.drawFittedText (JUCE_LIVE_CONSTANT ("Hello world!"),
  240. getLocalBounds(), Justification::centred, 2);
  241. }
  242. @endcode
  243. */
  244. #define JUCE_LIVE_CONSTANT(initialValue) \
  245. (juce::LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue).get())
  246. #else
  247. #define JUCE_LIVE_CONSTANT(initialValue) \
  248. (initialValue)
  249. #endif
  250. } // namespace juce