29#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR
31namespace LiveConstantEditor
35class AllComponentRepainter :
private Timer,
36 private DeletedAtShutdown
39 AllComponentRepainter() {}
40 ~AllComponentRepainter()
override { clearSingletonInstance(); }
46 if (! isTimerRunning())
51 void timerCallback()
override
55 Array<Component*> alreadyDone;
57 for (
int i = TopLevelWindow::getNumTopLevelWindows(); --
i >= 0;)
58 if (
auto*
c = TopLevelWindow::getTopLevelWindow(
i))
59 repaintAndResizeAllComps (
c, alreadyDone);
61 auto& desktop = Desktop::getInstance();
63 for (
int i = desktop.getNumComponents(); --
i >= 0;)
64 if (
auto*
c = desktop.getComponent(
i))
65 repaintAndResizeAllComps (
c, alreadyDone);
68 static void repaintAndResizeAllComps (Component::SafePointer<Component>
c,
69 Array<Component*>& alreadyDone)
71 if (
c->isVisible() && ! alreadyDone.
contains (
c))
76 for (
int i =
c->getNumChildComponents(); --
i >= 0;)
78 if (
auto* child =
c->getChildComponent(
i))
80 repaintAndResizeAllComps (child, alreadyDone);
81 alreadyDone.
add (child);
99 if (
s.startsWithChar (
'-'))
100 return -parseInt (
s.substring (1));
102 if (
s.startsWith (
"0x"))
103 return s.substring(2).getHexValue64();
105 return s.getLargeIntValue();
108double parseDouble (
const String&
s)
110 return s.retainCharacters (
"0123456789.eE-").getDoubleValue();
113String intToString (
int v,
bool preferHex) {
return preferHex ?
"0x" +
String::toHexString (
v) : String (
v); }
117LiveValueBase::LiveValueBase (
const char*
file,
int line)
118 : sourceFile (
file), sourceLine (line)
123LiveValueBase::~LiveValueBase()
128LivePropertyEditorBase::LivePropertyEditorBase (LiveValueBase&
v, CodeDocument&
d)
129 :
value (
v), document (
d), sourceEditor (document, &tokeniser)
133 addAndMakeVisible (
name);
134 addAndMakeVisible (resetButton);
135 addAndMakeVisible (valueEditor);
136 addAndMakeVisible (sourceEditor);
138 findOriginalValueInCode();
139 selectOriginalValue();
141 name.setFont (13.0f);
142 name.setText (
v.name, dontSendNotification);
143 valueEditor.setMultiLine (
v.isString());
144 valueEditor.setReturnKeyStartsNewLine (
v.isString());
145 valueEditor.setText (
v.getStringValue (wasHex), dontSendNotification);
146 valueEditor.onTextChange = [
this] { applyNewValue (valueEditor.getText()); };
147 sourceEditor.setReadOnly (
true);
148 sourceEditor.setFont (sourceEditor.getFont().withHeight (13.0f));
149 resetButton.onClick = [
this] { applyNewValue (
value.getOriginalStringValue (wasHex)); };
152void LivePropertyEditorBase::paint (Graphics&
g)
154 g.setColour (Colours::white);
155 g.fillRect (getLocalBounds().removeFromBottom (1));
158void LivePropertyEditorBase::resized()
160 auto r = getLocalBounds().reduced (0, 3).withTrimmedBottom (1);
162 auto left =
r.removeFromLeft (
jmax (200,
r.getWidth() / 3));
164 auto top =
left.removeFromTop (25);
165 resetButton.setBounds (top.removeFromRight (35).reduced (0, 3));
166 name.setBounds (top);
168 if (customComp !=
nullptr)
170 valueEditor.setBounds (
left.removeFromTop (25));
171 left.removeFromTop (2);
172 customComp->setBounds (
left);
176 valueEditor.setBounds (
left);
179 r.removeFromLeft (4);
180 sourceEditor.setBounds (
r);
183void LivePropertyEditorBase::applyNewValue (
const String&
s)
187 document.replaceSection (valueStart.getPosition(), valueEnd.getPosition(),
value.getCodeValue (wasHex));
188 document.clearUndoHistory();
189 selectOriginalValue();
191 valueEditor.setText (
s, dontSendNotification);
192 AllComponentRepainter::getInstance()->trigger();
195void LivePropertyEditorBase::selectOriginalValue()
197 sourceEditor.selectRegion (valueStart, valueEnd);
200void LivePropertyEditorBase::findOriginalValueInCode()
202 CodeDocument::Position pos (document,
value.sourceLine, 0);
203 auto line = pos.getLineText();
204 auto p = line.getCharPointer();
206 p = CharacterFunctions::find (
p, CharPointer_ASCII (
"JUCE_LIVE_CONSTANT"));
215 p += (
int) (
sizeof (
"JUCE_LIVE_CONSTANT") - 1);
216 p.incrementToEndOfWhitespace();
218 if (! CharacterFunctions::find (
p, CharPointer_ASCII (
"JUCE_LIVE_CONSTANT")).isEmpty())
226 if (
p.getAndAdvance() ==
'(')
232 while (!
end.isEmpty())
234 auto c =
end.getAndAdvance();
236 if (
c ==
'(') ++depth;
237 if (
c ==
')') --depth;
248 valueStart = CodeDocument::Position (document,
value.sourceLine, (
int) (
start - line.getCharPointer()));
249 valueEnd = CodeDocument::Position (document,
value.sourceLine, (
int) (end - line.getCharPointer()));
251 valueStart.setPositionMaintained (
true);
252 valueEnd.setPositionMaintained (
true);
260class ValueListHolderComponent :
public Component
263 ValueListHolderComponent (ValueList&
l) : valueList (
l)
268 void addItem (
int width, LiveValueBase&
v, CodeDocument& doc)
270 addAndMakeVisible (editors.add (
v.createPropertyComponent (doc)));
274 void layout (
int width)
276 setSize (
width, editors.size() * itemHeight);
280 void resized()
override
282 auto r = getLocalBounds().reduced (2, 0);
284 for (
int i = 0;
i < editors.size(); ++
i)
285 editors.getUnchecked(
i)->setBounds (
r.removeFromTop (itemHeight));
288 enum { itemHeight = 120 };
290 ValueList& valueList;
291 OwnedArray<LivePropertyEditorBase> editors;
295class ValueList::EditorWindow :
public DocumentWindow,
296 private DeletedAtShutdown
299 EditorWindow (ValueList& list)
300 : DocumentWindow (
"Live Values", Colours::
lightgrey, DocumentWindow::closeButton)
302 setLookAndFeel (&lookAndFeel);
303 setUsingNativeTitleBar (
true);
305 viewport.setViewedComponent (
new ValueListHolderComponent (list),
true);
306 viewport.setSize (700, 600);
307 viewport.setScrollBarsShown (
true,
false);
309 setContentNonOwned (&viewport,
true);
310 setResizable (
true,
false);
311 setResizeLimits (500, 400, 10000, 10000);
312 centreWithSize (getWidth(), getHeight());
316 ~EditorWindow()
override
318 setLookAndFeel (
nullptr);
321 void closeButtonPressed()
override
326 void updateItems (ValueList& list)
328 if (
auto*
l =
dynamic_cast<ValueListHolderComponent*
> (viewport.getViewedComponent()))
330 while (
l->getNumChildComponents() <
list.values.size())
332 if (
auto*
v =
list.values [
l->getNumChildComponents()])
333 l->addItem (viewport.getMaximumVisibleWidth(), *
v,
list.getDocument (
v->sourceFile));
342 void resized()
override
344 DocumentWindow::resized();
346 if (
auto*
l =
dynamic_cast<ValueListHolderComponent*
> (viewport.getViewedComponent()))
347 l->layout (viewport.getMaximumVisibleWidth());
351 LookAndFeel_V3 lookAndFeel;
355ValueList::ValueList() {}
356ValueList::~ValueList() { clearSingletonInstance(); }
358void ValueList::addValue (LiveValueBase*
v)
361 triggerAsyncUpdate();
364void ValueList::handleAsyncUpdate()
366 if (editorWindow ==
nullptr)
367 editorWindow =
new EditorWindow (*
this);
369 editorWindow->updateItems (*
this);
372CodeDocument& ValueList::getDocument (
const File&
file)
374 const int index = documentFiles.indexOf (
file.getFullPathName());
377 return *documents.getUnchecked (index);
379 auto* doc = documents.add (
new CodeDocument());
380 documentFiles.add (
file);
381 doc->replaceAllContent (
file.loadFileAsString());
382 doc->clearUndoHistory();
387struct ColourEditorComp :
public Component,
388 private ChangeListener
390 ColourEditorComp (LivePropertyEditorBase&
e) : editor (
e)
392 setMouseCursor (MouseCursor::PointingHandCursor);
395 Colour getColour()
const
397 return Colour ((
uint32) parseInt (editor.value.getStringValue (
false)));
400 void paint (Graphics&
g)
override
402 g.fillCheckerBoard (getLocalBounds().
toFloat(), 6.0f, 6.0f,
403 Colour (0xffdddddd).overlaidWith (getColour()),
404 Colour (0xffffffff).overlaidWith (getColour()));
407 void mouseDown (
const MouseEvent&)
override
409 auto colourSelector = std::make_unique<ColourSelector>();
410 colourSelector->setName (
"Colour");
411 colourSelector->setCurrentColour (getColour());
412 colourSelector->addChangeListener (
this);
413 colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
414 colourSelector->setSize (300, 400);
416 CallOutBox::launchAsynchronously (std::move (colourSelector), getScreenBounds(),
nullptr);
419 void changeListenerCallback (ChangeBroadcaster* source)
override
421 if (
auto* cs =
dynamic_cast<ColourSelector*
> (source))
422 editor.applyNewValue (getAsString (cs->getCurrentColour(),
true));
427 LivePropertyEditorBase& editor;
430Component* createColourEditor (LivePropertyEditorBase& editor)
432 return new ColourEditorComp (editor);
436struct SliderComp :
public Component
438 SliderComp (LivePropertyEditorBase&
e,
bool useFloat)
439 : editor (
e), isFloat (useFloat)
441 slider.setTextBoxStyle (Slider::NoTextBox,
true, 0, 0);
442 addAndMakeVisible (slider);
444 slider.onDragEnd = [
this] { updateRange(); };
445 slider.onValueChange = [
this]
447 editor.applyNewValue (isFloat ? getAsString ((
double)
slider.getValue(), editor.wasHex)
448 : getAsString ((
int64)
slider.getValue(), editor.wasHex));
452 virtual void updateRange()
454 double v = isFloat ? parseDouble (editor.value.getStringValue (
false))
455 : (double) parseInt (editor.
value.getStringValue (
false));
457 double range = isFloat ? 10 : 100;
459 slider.setRange (
v - range,
v + range);
460 slider.setValue (
v, dontSendNotification);
463 void resized()
override
465 slider.setBounds (getLocalBounds().removeFromTop (25));
468 LivePropertyEditorBase& editor;
474struct BoolSliderComp :
public SliderComp
476 BoolSliderComp (LivePropertyEditorBase&
e)
479 slider.onValueChange = [
this] { editor.applyNewValue (
slider.getValue() > 0.5 ?
"true" :
"false"); };
482 void updateRange()
override
484 slider.setRange (0.0, 1.0, dontSendNotification);
485 slider.setValue (editor.value.getStringValue (
false) ==
"true", dontSendNotification);
489Component* createIntegerSlider (LivePropertyEditorBase& editor) {
return new SliderComp (editor,
false); }
490Component* createFloatSlider (LivePropertyEditorBase& editor) {
return new SliderComp (editor,
true); }
491Component* createBoolSlider (LivePropertyEditorBase& editor) {
return new BoolSliderComp (editor); }
Type jmax(const Type a, const Type b)
Definition MathsFunctions.h:48
int64_t int64
Definition basics.h:91
uint32_t uint32
Definition basics.h:90
bool add(const ElementType &newElement) noexcept
Definition Array.h:354
bool contains(ParameterType elementToLookFor) const
Definition Array.h:336
String getFileName() const
Definition File.cpp:373
static String toHexString(int number)
Definition String.cpp:1830
bool containsIgnoreCase(StringRef text) const noexcept
Definition String.cpp:926
* e
Definition inflate.c:1404
int * l
Definition inflate.c:1579
unsigned v[N_MAX]
Definition inflate.c:1584
unsigned d
Definition inflate.c:940
int g
Definition inflate.c:1573
register unsigned i
Definition inflate.c:1575
unsigned s
Definition inflate.c:1555
struct @113205115357366127300225113341150224053346037032::@137033172036070230260373056156374243321245367362 left
static PuglViewHint int value
Definition pugl.h:1708
static const char * name
Definition pugl.h:1582
static int width
Definition pugl.h:1593
virtual ASIOError start()=0
#define JUCE_IMPLEMENT_SINGLETON(Classname)
Definition juce_Singleton.h:201
#define JUCE_DECLARE_SINGLETON(Classname, doNotRecreateAfterDeletion)
Definition juce_Singleton.h:184
const Colour lightgrey
Definition juce_Colours.h:111
Definition carla_juce.cpp:31
RangedDirectoryIterator end(const RangedDirectoryIterator &)
Definition juce_RangedDirectoryIterator.h:184
@ list
Definition juce_AccessibilityRole.h:56
@ slider
Definition juce_AccessibilityRole.h:43
float toFloat(const QString &str, bool *ok=nullptr)
Definition LocaleHelper.h:58
#define false
Definition ordinals.h:83
uch * p
Definition crypt.c:594
return c
Definition crypt.c:175
int r
Definition crypt.c:458
typedef int(UZ_EXP MsgFn)()
#define void
Definition unzip.h:396
struct zdirent * file
Definition win32.c:1500