git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
389
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ButtonHandler.h
vendored
Normal file
389
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ButtonHandler.h
vendored
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ButtonHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
ButtonHandler (const String& typeDescription_,
|
||||
const String& className_,
|
||||
const std::type_info& componentClass,
|
||||
const int defaultWidth_,
|
||||
const int defaultHeight_)
|
||||
: ComponentTypeHandler (typeDescription_, className_, componentClass,
|
||||
defaultWidth_, defaultHeight_)
|
||||
{}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* b = dynamic_cast<Button*> (component))
|
||||
{
|
||||
props.add (new ButtonTextProperty (b, document));
|
||||
|
||||
props.add (new ButtonCallbackProperty (b, document));
|
||||
|
||||
props.add (new ButtonRadioGroupProperty (b, document));
|
||||
|
||||
props.add (new ButtonConnectedEdgeProperty ("connected left", Button::ConnectedOnLeft, b, document));
|
||||
props.add (new ButtonConnectedEdgeProperty ("connected right", Button::ConnectedOnRight, b, document));
|
||||
props.add (new ButtonConnectedEdgeProperty ("connected top", Button::ConnectedOnTop, b, document));
|
||||
props.add (new ButtonConnectedEdgeProperty ("connected bottom", Button::ConnectedOnBottom, b, document));
|
||||
}
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
Button* const b = dynamic_cast<Button*> (comp);
|
||||
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("buttonText", b->getButtonText());
|
||||
e->setAttribute ("connectedEdges", b->getConnectedEdgeFlags());
|
||||
e->setAttribute ("needsCallback", needsButtonListener (b));
|
||||
e->setAttribute ("radioGroupId", b->getRadioGroupId());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
Button* const b = dynamic_cast<Button*> (comp);
|
||||
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
b->setButtonText (xml.getStringAttribute ("buttonText", b->getButtonText()));
|
||||
b->setConnectedEdges (xml.getIntAttribute ("connectedEdges", 0));
|
||||
setNeedsButtonListener (b, xml.getBoolAttribute ("needsCallback", true));
|
||||
b->setRadioGroupId (xml.getIntAttribute ("radioGroupId", 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* component) override
|
||||
{
|
||||
return quotedString (component->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
Button* const b = dynamic_cast<Button*> (component);
|
||||
|
||||
if (b->getButtonText() != b->getName())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setButtonText ("
|
||||
<< quotedString (b->getButtonText(), code.shouldUseTransMacro()) << ");\n";
|
||||
}
|
||||
|
||||
if (b->getConnectedEdgeFlags() != 0)
|
||||
{
|
||||
StringArray flags;
|
||||
|
||||
if (b->isConnectedOnLeft())
|
||||
flags.add ("juce::Button::ConnectedOnLeft");
|
||||
|
||||
if (b->isConnectedOnRight())
|
||||
flags.add ("juce::Button::ConnectedOnRight");
|
||||
|
||||
if (b->isConnectedOnTop())
|
||||
flags.add ("juce::Button::ConnectedOnTop");
|
||||
|
||||
if (b->isConnectedOnBottom())
|
||||
flags.add ("juce::Button::ConnectedOnBottom");
|
||||
|
||||
String s;
|
||||
s << memberVariableName << "->setConnectedEdges ("
|
||||
<< flags.joinIntoString (" | ") << ");\n";
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
if (b->getRadioGroupId() != 0)
|
||||
code.constructorCode << memberVariableName << "->setRadioGroupId ("
|
||||
<< b->getRadioGroupId() << ");\n";
|
||||
|
||||
if (needsButtonListener (component))
|
||||
code.constructorCode << memberVariableName << "->addListener (this);\n";
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
|
||||
{
|
||||
ComponentTypeHandler::fillInGeneratedCode (component, code);
|
||||
|
||||
if (needsButtonListener (component))
|
||||
{
|
||||
String& callback = code.getCallbackCode ("public juce::Button::Listener",
|
||||
"void",
|
||||
"buttonClicked (juce::Button* buttonThatWasClicked)",
|
||||
true);
|
||||
|
||||
if (callback.isNotEmpty())
|
||||
callback << "else ";
|
||||
|
||||
const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
|
||||
const String userCodeComment ("UserButtonCode_" + memberVariableName);
|
||||
|
||||
callback
|
||||
<< "if (buttonThatWasClicked == " << memberVariableName << ".get())\n"
|
||||
<< "{\n //[" << userCodeComment << "] -- add your button handler code here..\n //[/" << userCodeComment << "]\n}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static bool needsButtonListener (Component* button)
|
||||
{
|
||||
return button->getProperties().getWithDefault ("generateListenerCallback", true);
|
||||
}
|
||||
|
||||
static void setNeedsButtonListener (Component* button, const bool shouldDoCallback)
|
||||
{
|
||||
button->getProperties().set ("generateListenerCallback", shouldDoCallback);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class ButtonTextProperty : public ComponentTextProperty <Button>
|
||||
{
|
||||
public:
|
||||
ButtonTextProperty (Button* button_, JucerDocument& doc)
|
||||
: ComponentTextProperty <Button> ("text", 100, false, button_, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ButtonTextChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change button text");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getButtonText();
|
||||
}
|
||||
|
||||
private:
|
||||
class ButtonTextChangeAction : public ComponentUndoableAction <Button>
|
||||
{
|
||||
public:
|
||||
ButtonTextChangeAction (Button* const comp, ComponentLayout& l, const String& newName_)
|
||||
: ComponentUndoableAction <Button> (comp, l),
|
||||
newName (newName_)
|
||||
{
|
||||
oldName = comp->getButtonText();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setButtonText (newName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setButtonText (oldName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newName, oldName;
|
||||
};
|
||||
};
|
||||
|
||||
class ButtonCallbackProperty : public ComponentBooleanProperty <Button>
|
||||
{
|
||||
public:
|
||||
ButtonCallbackProperty (Button* b, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <Button> ("callback", "Generate ButtonListener", "Generate ButtonListener", b, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new ButtonCallbackChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change button callback");
|
||||
}
|
||||
|
||||
bool getState() const { return needsButtonListener (component); }
|
||||
|
||||
private:
|
||||
class ButtonCallbackChangeAction : public ComponentUndoableAction <Button>
|
||||
{
|
||||
public:
|
||||
ButtonCallbackChangeAction (Button* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <Button> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = needsButtonListener (comp);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
setNeedsButtonListener (getComponent(), newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
setNeedsButtonListener (getComponent(), oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
class ButtonRadioGroupProperty : public ComponentTextProperty <Button>
|
||||
{
|
||||
public:
|
||||
ButtonRadioGroupProperty (Button* const button_, JucerDocument& doc)
|
||||
: ComponentTextProperty <Button> ("radio group", 10, false, button_, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ButtonRadioGroupChangeAction (component, *document.getComponentLayout(), newText.getIntValue()),
|
||||
"Change radio group ID");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return String (component->getRadioGroupId());
|
||||
}
|
||||
|
||||
private:
|
||||
class ButtonRadioGroupChangeAction : public ComponentUndoableAction <Button>
|
||||
{
|
||||
public:
|
||||
ButtonRadioGroupChangeAction (Button* const comp, ComponentLayout& l, const int newId_)
|
||||
: ComponentUndoableAction <Button> (comp, l),
|
||||
newId (newId_)
|
||||
{
|
||||
oldId = comp->getRadioGroupId();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRadioGroupId (newId);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRadioGroupId (oldId);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newId, oldId;
|
||||
};
|
||||
};
|
||||
|
||||
class ButtonConnectedEdgeProperty : public ComponentBooleanProperty <Button>
|
||||
{
|
||||
public:
|
||||
ButtonConnectedEdgeProperty (const String& name, const int flag_,
|
||||
Button* b, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <Button> (name, "Connected", "Connected", b, doc),
|
||||
flag (flag_)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new ButtonConnectedChangeAction (component, *document.getComponentLayout(), flag, newState),
|
||||
"Change button connected edges");
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return (component->getConnectedEdgeFlags() & flag) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const int flag;
|
||||
|
||||
class ButtonConnectedChangeAction : public ComponentUndoableAction <Button>
|
||||
{
|
||||
public:
|
||||
ButtonConnectedChangeAction (Button* const comp, ComponentLayout& l, const int flag_, const bool newState_)
|
||||
: ComponentUndoableAction <Button> (comp, l),
|
||||
flag (flag_),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = ((comp->getConnectedEdgeFlags() & flag) != 0);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (newState)
|
||||
getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() | flag);
|
||||
else
|
||||
getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() & ~flag);
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (oldState)
|
||||
getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() | flag);
|
||||
else
|
||||
getComponent()->setConnectedEdges (getComponent()->getConnectedEdgeFlags() & ~flag);
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
const int flag;
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
446
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComboBoxHandler.h
vendored
Normal file
446
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComboBoxHandler.h
vendored
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ComboBoxHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
ComboBoxHandler()
|
||||
: ComponentTypeHandler ("Combo Box", "juce::ComboBox", typeid (ComboBox), 150, 24)
|
||||
{}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new ComboBox ("new combo box");
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (auto* const c = dynamic_cast<ComboBox*> (comp))
|
||||
{
|
||||
if (auto* e = ComponentTypeHandler::createXmlFor (comp, layout))
|
||||
{
|
||||
e->setAttribute ("editable", c->isTextEditable());
|
||||
e->setAttribute ("layout", c->getJustificationType().getFlags());
|
||||
e->setAttribute ("items", c->getProperties() ["items"].toString());
|
||||
e->setAttribute ("textWhenNonSelected", c->getTextWhenNothingSelected());
|
||||
e->setAttribute ("textWhenNoItems", c->getTextWhenNoChoicesAvailable());
|
||||
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
ComboBox defaultBox;
|
||||
|
||||
if (ComboBox* const c = dynamic_cast<ComboBox*> (comp))
|
||||
{
|
||||
c->setEditableText (xml.getBoolAttribute ("editable", defaultBox.isTextEditable()));
|
||||
c->setJustificationType (Justification (xml.getIntAttribute ("layout", defaultBox.getJustificationType().getFlags())));
|
||||
c->getProperties().set ("items", xml.getStringAttribute ("items", String()));
|
||||
c->setTextWhenNothingSelected (xml.getStringAttribute ("textWhenNonSelected", defaultBox.getTextWhenNothingSelected()));
|
||||
c->setTextWhenNoChoicesAvailable (xml.getStringAttribute ("textWhenNoItems", defaultBox.getTextWhenNoChoicesAvailable()));
|
||||
|
||||
updateItems (c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* c = dynamic_cast<ComboBox*> (component))
|
||||
{
|
||||
props.add (new ComboItemsProperty (c, document));
|
||||
props.add (new ComboEditableProperty (c, document));
|
||||
props.add (new ComboJustificationProperty (c, document));
|
||||
props.add (new ComboTextWhenNoneSelectedProperty (c, document));
|
||||
props.add (new ComboTextWhenNoItemsProperty (c, document));
|
||||
}
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* component) override
|
||||
{
|
||||
return quotedString (component->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
ComboBox* const c = dynamic_cast<ComboBox*> (component);
|
||||
|
||||
if (c == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
String s;
|
||||
s << memberVariableName << "->setEditableText (" << CodeHelpers::boolLiteral (c->isTextEditable()) << ");\n"
|
||||
<< memberVariableName << "->setJustificationType (" << CodeHelpers::justificationToCode (c->getJustificationType()) << ");\n"
|
||||
<< memberVariableName << "->setTextWhenNothingSelected (" << quotedString (c->getTextWhenNothingSelected(), code.shouldUseTransMacro()) << ");\n"
|
||||
<< memberVariableName << "->setTextWhenNoChoicesAvailable (" << quotedString (c->getTextWhenNoChoicesAvailable(), code.shouldUseTransMacro()) << ");\n";
|
||||
|
||||
StringArray lines;
|
||||
lines.addLines (c->getProperties() ["items"].toString());
|
||||
int itemId = 1;
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (lines[i].trim().isEmpty())
|
||||
s << memberVariableName << "->addSeparator();\n";
|
||||
else
|
||||
s << memberVariableName << "->addItem ("
|
||||
<< quotedString (lines[i], code.shouldUseTransMacro()) << ", " << itemId++ << ");\n";
|
||||
}
|
||||
|
||||
if (needsCallback (component))
|
||||
s << memberVariableName << "->addListener (this);\n";
|
||||
|
||||
s << '\n';
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
|
||||
{
|
||||
ComponentTypeHandler::fillInGeneratedCode (component, code);
|
||||
|
||||
if (needsCallback (component))
|
||||
{
|
||||
String& callback = code.getCallbackCode ("public juce::ComboBox::Listener",
|
||||
"void",
|
||||
"comboBoxChanged (juce::ComboBox* comboBoxThatHasChanged)",
|
||||
true);
|
||||
|
||||
if (callback.trim().isNotEmpty())
|
||||
callback << "else ";
|
||||
|
||||
const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
|
||||
const String userCodeComment ("UserComboBoxCode_" + memberVariableName);
|
||||
|
||||
callback
|
||||
<< "if (comboBoxThatHasChanged == " << memberVariableName << ".get())\n"
|
||||
<< "{\n //[" << userCodeComment << "] -- add your combo box handling code here..\n //[/" << userCodeComment << "]\n}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void updateItems (ComboBox* c)
|
||||
{
|
||||
StringArray lines;
|
||||
lines.addLines (c->getProperties() ["items"].toString());
|
||||
|
||||
c->clear();
|
||||
int itemId = 1;
|
||||
|
||||
for (int i = 0; i < lines.size(); ++i)
|
||||
{
|
||||
if (lines[i].trim().isEmpty())
|
||||
c->addSeparator();
|
||||
else
|
||||
c->addItem (lines[i], itemId++);
|
||||
}
|
||||
}
|
||||
|
||||
static bool needsCallback (Component*)
|
||||
{
|
||||
return true; // xxx should be configurable
|
||||
}
|
||||
|
||||
private:
|
||||
class ComboEditableProperty : public ComponentBooleanProperty <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboEditableProperty (ComboBox* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <ComboBox> ("editable", "Text is editable", "Text is editable", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new ComboEditableChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change combo box editability");
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return component->isTextEditable();
|
||||
}
|
||||
|
||||
private:
|
||||
class ComboEditableChangeAction : public ComponentUndoableAction <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboEditableChangeAction (ComboBox* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <ComboBox> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isTextEditable();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditableText (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditableText (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComboJustificationProperty : public JustificationProperty
|
||||
{
|
||||
public:
|
||||
ComboJustificationProperty (ComboBox* comp, JucerDocument& doc)
|
||||
: JustificationProperty ("text layout", false),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setJustification (Justification newJustification)
|
||||
{
|
||||
document.perform (new ComboJustifyChangeAction (component, *document.getComponentLayout(), newJustification),
|
||||
"Change combo box justification");
|
||||
}
|
||||
|
||||
Justification getJustification() const { return component->getJustificationType(); }
|
||||
|
||||
private:
|
||||
ComboBox* const component;
|
||||
JucerDocument& document;
|
||||
|
||||
class ComboJustifyChangeAction : public ComponentUndoableAction <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboJustifyChangeAction (ComboBox* const comp, ComponentLayout& l, Justification newState_)
|
||||
: ComponentUndoableAction <ComboBox> (comp, l),
|
||||
newState (newState_),
|
||||
oldState (comp->getJustificationType())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setJustificationType (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setJustificationType (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Justification newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComboItemsProperty : public ComponentTextProperty <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboItemsProperty (ComboBox* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <ComboBox> ("items", 10000, true, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ComboItemsChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change combo box items");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getProperties() ["items"];
|
||||
}
|
||||
|
||||
private:
|
||||
class ComboItemsChangeAction : public ComponentUndoableAction <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboItemsChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <ComboBox> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getProperties() ["items"];
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->getProperties().set ("items", newState);
|
||||
ComboBoxHandler::updateItems (getComponent());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->getProperties().set ("items", oldState);
|
||||
ComboBoxHandler::updateItems (getComponent());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComboTextWhenNoneSelectedProperty : public ComponentTextProperty <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboTextWhenNoneSelectedProperty (ComboBox* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <ComboBox> ("text when none selected", 200, false, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ComboNonSelTextChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change combo box text when nothing selected");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getTextWhenNothingSelected();
|
||||
}
|
||||
|
||||
private:
|
||||
class ComboNonSelTextChangeAction : public ComponentUndoableAction <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboNonSelTextChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <ComboBox> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getTextWhenNothingSelected();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextWhenNothingSelected (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextWhenNothingSelected (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComboTextWhenNoItemsProperty : public ComponentTextProperty <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboTextWhenNoItemsProperty (ComboBox* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <ComboBox> ("text when no items", 200, false, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ComboNoItemTextChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change combo box 'no items' text");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getTextWhenNoChoicesAvailable();
|
||||
}
|
||||
|
||||
private:
|
||||
class ComboNoItemTextChangeAction : public ComponentUndoableAction <ComboBox>
|
||||
{
|
||||
public:
|
||||
ComboNoItemTextChangeAction (ComboBox* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <ComboBox> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getTextWhenNoChoicesAvailable();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextWhenNoChoicesAvailable (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextWhenNoChoicesAvailable (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
178
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentNameProperty.h
vendored
Normal file
178
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentNameProperty.h
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ComponentTypeHandler.h"
|
||||
#include "jucer_ComponentUndoableAction.h"
|
||||
#include "../Properties/jucer_ComponentTextProperty.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentNameProperty : public ComponentTextProperty <Component>
|
||||
{
|
||||
public:
|
||||
ComponentNameProperty (Component* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Component> ("name", 40, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new CompNameChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change component name");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getName();
|
||||
}
|
||||
|
||||
private:
|
||||
class CompNameChangeAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
CompNameChangeAction (Component* const comp, ComponentLayout& l, const String& nm)
|
||||
: ComponentUndoableAction <Component> (comp, l),
|
||||
newName (nm), oldName (comp->getName())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setName (newName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setName (oldName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newName, oldName;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComponentMemberNameProperty : public ComponentTextProperty <Component>
|
||||
{
|
||||
public:
|
||||
ComponentMemberNameProperty (Component* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Component> ("member name", 40, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new CompMemberNameChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change component member name");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return document.getComponentLayout()->getComponentMemberVariableName (component);
|
||||
}
|
||||
|
||||
private:
|
||||
class CompMemberNameChangeAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
CompMemberNameChangeAction (Component* const comp, ComponentLayout& l, const String& nm)
|
||||
: ComponentUndoableAction <Component> (comp, l),
|
||||
newName (nm), oldName (layout.getComponentMemberVariableName (comp))
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
layout.setComponentMemberVariableName (getComponent(), newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
layout.setComponentMemberVariableName (getComponent(), oldName);
|
||||
return true;
|
||||
}
|
||||
|
||||
String newName, oldName;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ComponentVirtualClassProperty : public ComponentTextProperty <Component>
|
||||
{
|
||||
public:
|
||||
ComponentVirtualClassProperty (Component* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Component> ("virtual class", 40, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new CompVirtualClassChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change component virtual class name");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return document.getComponentLayout()->getComponentVirtualClassName (component);
|
||||
}
|
||||
|
||||
private:
|
||||
class CompVirtualClassChangeAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
CompVirtualClassChangeAction (Component* const comp, ComponentLayout& l, const String& nm)
|
||||
: ComponentUndoableAction <Component> (comp, l),
|
||||
newName (nm), oldName (layout.getComponentVirtualClassName (comp))
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
layout.setComponentVirtualClassName (getComponent(), newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
layout.setComponentVirtualClassName (getComponent(), oldName);
|
||||
return true;
|
||||
}
|
||||
|
||||
String newName, oldName;
|
||||
};
|
||||
};
|
||||
638
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentTypeHandler.cpp
vendored
Normal file
638
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentTypeHandler.cpp
vendored
Normal file
@@ -0,0 +1,638 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
#include "../jucer_ObjectTypes.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
#include "../UI/jucer_JucerCommandIDs.h"
|
||||
#include "../UI/jucer_ComponentOverlayComponent.h"
|
||||
#include "jucer_ComponentNameProperty.h"
|
||||
#include "../Properties/jucer_PositionPropertyBase.h"
|
||||
#include "../Properties/jucer_ComponentColourProperty.h"
|
||||
#include "../UI/jucer_TestComponent.h"
|
||||
|
||||
static String getTypeInfoName (const std::type_info& info)
|
||||
{
|
||||
#if JUCE_MSVC
|
||||
return info.raw_name();
|
||||
#else
|
||||
return info.name();
|
||||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
ComponentTypeHandler::ComponentTypeHandler (const String& typeName_,
|
||||
const String& className_,
|
||||
const std::type_info& componentClass_,
|
||||
const int defaultWidth_,
|
||||
const int defaultHeight_)
|
||||
: typeName (typeName_),
|
||||
className (className_),
|
||||
componentClassRawName (getTypeInfoName (componentClass_)),
|
||||
defaultWidth (defaultWidth_),
|
||||
defaultHeight (defaultHeight_)
|
||||
{
|
||||
}
|
||||
|
||||
Component* ComponentTypeHandler::createCopyOf (JucerDocument* document, Component& existing)
|
||||
{
|
||||
jassert (getHandlerFor (existing) == this);
|
||||
|
||||
Component* const newOne = createNewComponent (document);
|
||||
std::unique_ptr<XmlElement> xml (createXmlFor (&existing, document->getComponentLayout()));
|
||||
|
||||
if (xml != nullptr)
|
||||
restoreFromXml (*xml, newOne, document->getComponentLayout());
|
||||
|
||||
return newOne;
|
||||
}
|
||||
|
||||
ComponentOverlayComponent* ComponentTypeHandler::createOverlayComponent (Component* child, ComponentLayout& layout)
|
||||
{
|
||||
return new ComponentOverlayComponent (child, layout);
|
||||
}
|
||||
|
||||
static void dummyMenuCallback (int, int) {}
|
||||
|
||||
void ComponentTypeHandler::showPopupMenu (Component*, ComponentLayout& layout)
|
||||
{
|
||||
PopupMenu m;
|
||||
|
||||
ApplicationCommandManager* commandManager = &ProjucerApplication::getCommandManager();
|
||||
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::toFront);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::toBack);
|
||||
m.addSeparator();
|
||||
|
||||
if (layout.getSelectedSet().getNumSelected() > 1)
|
||||
{
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignTop);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignRight);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignBottom);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignLeft);
|
||||
m.addSeparator();
|
||||
}
|
||||
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options(),
|
||||
ModalCallbackFunction::create (dummyMenuCallback, 0));
|
||||
}
|
||||
|
||||
JucerDocument* ComponentTypeHandler::findParentDocument (Component* component)
|
||||
{
|
||||
Component* p = component->getParentComponent();
|
||||
|
||||
while (p != nullptr)
|
||||
{
|
||||
if (JucerDocumentEditor* const ed = dynamic_cast<JucerDocumentEditor*> (p))
|
||||
return ed->getDocument();
|
||||
|
||||
if (TestComponent* const t = dynamic_cast<TestComponent*> (p))
|
||||
return t->getDocument();
|
||||
|
||||
p = p->getParentComponent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool ComponentTypeHandler::canHandle (Component& component) const
|
||||
{
|
||||
return componentClassRawName == getTypeInfoName (typeid (component));
|
||||
}
|
||||
|
||||
ComponentTypeHandler* ComponentTypeHandler::getHandlerFor (Component& component)
|
||||
{
|
||||
for (int i = 0; i < ObjectTypes::numComponentTypes; ++i)
|
||||
if (ObjectTypes::componentTypeHandlers[i]->canHandle (component))
|
||||
return ObjectTypes::componentTypeHandlers[i];
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ComponentTypeHandler* ComponentTypeHandler::getHandlerForXmlTag (const String& tagName)
|
||||
{
|
||||
for (int i = 0; i < ObjectTypes::numComponentTypes; ++i)
|
||||
if (ObjectTypes::componentTypeHandlers[i]->getXmlTagName().equalsIgnoreCase (tagName))
|
||||
return ObjectTypes::componentTypeHandlers[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XmlElement* ComponentTypeHandler::createXmlFor (Component* comp, const ComponentLayout* layout)
|
||||
{
|
||||
XmlElement* e = new XmlElement (getXmlTagName());
|
||||
|
||||
e->setAttribute ("name", comp->getName());
|
||||
e->setAttribute ("id", String::toHexString (getComponentId (comp)));
|
||||
e->setAttribute ("memberName", comp->getProperties() ["memberName"].toString());
|
||||
e->setAttribute ("virtualName", comp->getProperties() ["virtualName"].toString());
|
||||
e->setAttribute ("explicitFocusOrder", comp->getExplicitFocusOrder());
|
||||
|
||||
RelativePositionedRectangle pos (getComponentPosition (comp));
|
||||
pos.updateFromComponent (*comp, layout);
|
||||
pos.applyToXml (*e);
|
||||
|
||||
if (SettableTooltipClient* const ttc = dynamic_cast<SettableTooltipClient*> (comp))
|
||||
if (ttc->getTooltip().isNotEmpty())
|
||||
e->setAttribute ("tooltip", ttc->getTooltip());
|
||||
|
||||
for (int i = 0; i < colours.size(); ++i)
|
||||
{
|
||||
if (comp->isColourSpecified (colours[i]->colourId))
|
||||
{
|
||||
e->setAttribute (colours[i]->xmlTagName,
|
||||
comp->findColour (colours[i]->colourId).toString());
|
||||
}
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool ComponentTypeHandler::restoreFromXml (const XmlElement& xml,
|
||||
Component* comp,
|
||||
const ComponentLayout* layout)
|
||||
{
|
||||
jassert (xml.hasTagName (getXmlTagName()));
|
||||
|
||||
if (! xml.hasTagName (getXmlTagName()))
|
||||
return false;
|
||||
|
||||
comp->setName (xml.getStringAttribute ("name", comp->getName()));
|
||||
setComponentId (comp, xml.getStringAttribute ("id").getHexValue64());
|
||||
comp->getProperties().set ("memberName", xml.getStringAttribute ("memberName"));
|
||||
comp->getProperties().set ("virtualName", xml.getStringAttribute ("virtualName"));
|
||||
comp->setExplicitFocusOrder (xml.getIntAttribute ("explicitFocusOrder"));
|
||||
|
||||
RelativePositionedRectangle currentPos (getComponentPosition (comp));
|
||||
currentPos.updateFromComponent (*comp, layout);
|
||||
|
||||
RelativePositionedRectangle rpr;
|
||||
rpr.restoreFromXml (xml, currentPos);
|
||||
|
||||
jassert (layout != nullptr);
|
||||
setComponentPosition (comp, rpr, layout);
|
||||
|
||||
if (SettableTooltipClient* const ttc = dynamic_cast<SettableTooltipClient*> (comp))
|
||||
ttc->setTooltip (xml.getStringAttribute ("tooltip"));
|
||||
|
||||
for (int i = 0; i < colours.size(); ++i)
|
||||
{
|
||||
const String col (xml.getStringAttribute (colours[i]->xmlTagName, String()));
|
||||
|
||||
if (col.isNotEmpty())
|
||||
comp->setColour (colours[i]->colourId, Colour::fromString (col));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int64 ComponentTypeHandler::getComponentId (Component* comp)
|
||||
{
|
||||
if (comp == nullptr)
|
||||
return 0;
|
||||
|
||||
int64 compId = comp->getProperties() ["jucerCompId"].toString().getHexValue64();
|
||||
|
||||
if (compId == 0)
|
||||
{
|
||||
compId = Random::getSystemRandom().nextInt64();
|
||||
setComponentId (comp, compId);
|
||||
}
|
||||
|
||||
return compId;
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::setComponentId (Component* comp, const int64 newID)
|
||||
{
|
||||
jassert (comp != nullptr);
|
||||
if (newID != 0)
|
||||
comp->getProperties().set ("jucerCompId", String::toHexString (newID));
|
||||
}
|
||||
|
||||
RelativePositionedRectangle ComponentTypeHandler::getComponentPosition (Component* comp)
|
||||
{
|
||||
RelativePositionedRectangle rp;
|
||||
rp.rect = PositionedRectangle (comp->getProperties() ["pos"]);
|
||||
rp.relativeToX = comp->getProperties() ["relativeToX"].toString().getHexValue64();
|
||||
rp.relativeToY = comp->getProperties() ["relativeToY"].toString().getHexValue64();
|
||||
rp.relativeToW = comp->getProperties() ["relativeToW"].toString().getHexValue64();
|
||||
rp.relativeToH = comp->getProperties() ["relativeToH"].toString().getHexValue64();
|
||||
|
||||
return rp;
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::setComponentPosition (Component* comp,
|
||||
const RelativePositionedRectangle& newPos,
|
||||
const ComponentLayout* layout)
|
||||
{
|
||||
comp->getProperties().set ("pos", newPos.rect.toString());
|
||||
comp->getProperties().set ("relativeToX", String::toHexString (newPos.relativeToX));
|
||||
comp->getProperties().set ("relativeToY", String::toHexString (newPos.relativeToY));
|
||||
comp->getProperties().set ("relativeToW", String::toHexString (newPos.relativeToW));
|
||||
comp->getProperties().set ("relativeToH", String::toHexString (newPos.relativeToH));
|
||||
|
||||
comp->setBounds (newPos.getRectangle (Rectangle<int> (0, 0, comp->getParentWidth(), comp->getParentHeight()),
|
||||
layout));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class TooltipProperty : public ComponentTextProperty <Component>
|
||||
{
|
||||
public:
|
||||
TooltipProperty (Component* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty<Component> ("tooltip", 1024, true, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
SettableTooltipClient* ttc = dynamic_cast<SettableTooltipClient*> (component);
|
||||
return ttc->getTooltip();
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new SetTooltipAction (component, *document.getComponentLayout(), newText),
|
||||
"Change tooltip");
|
||||
}
|
||||
|
||||
private:
|
||||
class SetTooltipAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
SetTooltipAction (Component* const comp, ComponentLayout& l, const String& newValue_)
|
||||
: ComponentUndoableAction<Component> (comp, l),
|
||||
newValue (newValue_)
|
||||
{
|
||||
SettableTooltipClient* ttc = dynamic_cast<SettableTooltipClient*> (comp);
|
||||
jassert (ttc != nullptr);
|
||||
oldValue = ttc->getTooltip();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (SettableTooltipClient* ttc = dynamic_cast<SettableTooltipClient*> (getComponent()))
|
||||
{
|
||||
ttc->setTooltip (newValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (SettableTooltipClient* ttc = dynamic_cast<SettableTooltipClient*> (getComponent()))
|
||||
{
|
||||
ttc->setTooltip (oldValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String newValue, oldValue;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ComponentPositionProperty : public PositionPropertyBase
|
||||
{
|
||||
public:
|
||||
ComponentPositionProperty (Component* comp,
|
||||
JucerDocument& doc,
|
||||
const String& name,
|
||||
ComponentPositionDimension dimension_)
|
||||
: PositionPropertyBase (comp, name, dimension_,
|
||||
true, true,
|
||||
doc.getComponentLayout()),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentPositionProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setPosition (const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
auto* l = document.getComponentLayout();
|
||||
|
||||
if (l->getSelectedSet().getNumSelected() > 1)
|
||||
positionOtherSelectedComponents (ComponentTypeHandler::getComponentPosition (component), newPos);
|
||||
|
||||
l->setComponentPosition (component, newPos, true);
|
||||
}
|
||||
|
||||
RelativePositionedRectangle getPosition() const
|
||||
{
|
||||
return ComponentTypeHandler::getComponentPosition (component);
|
||||
}
|
||||
|
||||
private:
|
||||
JucerDocument& document;
|
||||
|
||||
void positionOtherSelectedComponents (const RelativePositionedRectangle& oldPos, const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
for (auto* s : document.getComponentLayout()->getSelectedSet())
|
||||
{
|
||||
if (s != component)
|
||||
{
|
||||
auto currentPos = ComponentTypeHandler::getComponentPosition (s);
|
||||
auto diff = 0.0;
|
||||
|
||||
if (dimension == ComponentPositionDimension::componentX)
|
||||
{
|
||||
diff = newPos.rect.getX() - oldPos.rect.getX();
|
||||
currentPos.rect.setX (currentPos.rect.getX() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentY)
|
||||
{
|
||||
diff = newPos.rect.getY() - oldPos.rect.getY();
|
||||
currentPos.rect.setY (currentPos.rect.getY() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentWidth)
|
||||
{
|
||||
diff = newPos.rect.getWidth() - oldPos.rect.getWidth();
|
||||
currentPos.rect.setWidth (currentPos.rect.getWidth() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentHeight)
|
||||
{
|
||||
diff = newPos.rect.getHeight() - oldPos.rect.getHeight();
|
||||
currentPos.rect.setHeight (currentPos.rect.getHeight() + diff);
|
||||
}
|
||||
|
||||
document.getComponentLayout()->setComponentPosition (s, currentPos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FocusOrderProperty : public ComponentTextProperty <Component>
|
||||
{
|
||||
public:
|
||||
FocusOrderProperty (Component* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Component> ("focus order", 8, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return String (component->getExplicitFocusOrder());
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new SetFocusOrderAction (component, *document.getComponentLayout(), jmax (0, newText.getIntValue())),
|
||||
"Change focus order");
|
||||
}
|
||||
|
||||
private:
|
||||
class SetFocusOrderAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
SetFocusOrderAction (Component* const comp, ComponentLayout& l, const int newOrder_)
|
||||
: ComponentUndoableAction <Component> (comp, l),
|
||||
newValue (newOrder_)
|
||||
{
|
||||
oldValue = comp->getExplicitFocusOrder();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setExplicitFocusOrder (newValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setExplicitFocusOrder (oldValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newValue, oldValue;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void ComponentTypeHandler::getEditableProperties (Component* component,
|
||||
JucerDocument& document,
|
||||
Array<PropertyComponent*>& props,
|
||||
bool multipleSelected)
|
||||
{
|
||||
if (! multipleSelected)
|
||||
{
|
||||
props.add (new ComponentMemberNameProperty (component, document));
|
||||
props.add (new ComponentNameProperty (component, document));
|
||||
props.add (new ComponentVirtualClassProperty (component, document));
|
||||
|
||||
if (dynamic_cast<SettableTooltipClient*> (component) != nullptr)
|
||||
props.add (new TooltipProperty (component, document));
|
||||
|
||||
props.add (new FocusOrderProperty (component, document));
|
||||
}
|
||||
|
||||
props.add (new ComponentPositionProperty (component, document, "x", ComponentPositionProperty::componentX));
|
||||
props.add (new ComponentPositionProperty (component, document, "y", ComponentPositionProperty::componentY));
|
||||
props.add (new ComponentPositionProperty (component, document, "width", ComponentPositionProperty::componentWidth));
|
||||
props.add (new ComponentPositionProperty (component, document, "height", ComponentPositionProperty::componentHeight));
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, JucerDocument& document,
|
||||
PropertyPanel& panel, bool multipleSelected)
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
getEditableProperties (comp, document, props, multipleSelected);
|
||||
|
||||
panel.addSection (getClassName (comp), props);
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::registerEditableColour (int colourId,
|
||||
const String& colourIdCode,
|
||||
const String& colourName, const String& xmlTagName)
|
||||
{
|
||||
ComponentColourInfo* const c = new ComponentColourInfo();
|
||||
|
||||
c->colourId = colourId;
|
||||
c->colourIdCode = colourIdCode;
|
||||
c->colourName = colourName;
|
||||
c->xmlTagName = xmlTagName;
|
||||
|
||||
colours.add (c);
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::addColourProperties (Component* component,
|
||||
JucerDocument& document,
|
||||
Array<PropertyComponent*>& props)
|
||||
{
|
||||
for (int i = 0; i < colours.size(); ++i)
|
||||
props.add (new ComponentColourIdProperty (component, document,
|
||||
colours[i]->colourId,
|
||||
colours[i]->colourName,
|
||||
true));
|
||||
}
|
||||
|
||||
String ComponentTypeHandler::getColourIntialisationCode (Component* component,
|
||||
const String& objectName)
|
||||
{
|
||||
String s;
|
||||
|
||||
for (int i = 0; i < colours.size(); ++i)
|
||||
{
|
||||
if (component->isColourSpecified (colours[i]->colourId))
|
||||
{
|
||||
s << objectName << "->setColour ("
|
||||
<< colours[i]->colourIdCode
|
||||
<< ", "
|
||||
<< CodeHelpers::colourToCode (component->findColour (colours[i]->colourId))
|
||||
<< ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ComponentTypeHandler::fillInGeneratedCode (Component* component, GeneratedCode& code)
|
||||
{
|
||||
const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
|
||||
|
||||
fillInMemberVariableDeclarations (code, component, memberVariableName);
|
||||
fillInCreationCode (code, component, memberVariableName);
|
||||
fillInDeletionCode (code, component, memberVariableName);
|
||||
fillInResizeCode (code, component, memberVariableName);
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::fillInMemberVariableDeclarations (GeneratedCode& code, Component* component, const String& memberVariableName)
|
||||
{
|
||||
String clsName (component->getProperties() ["virtualName"].toString());
|
||||
|
||||
if (clsName.isNotEmpty())
|
||||
clsName = build_tools::makeValidIdentifier (clsName, false, false, true);
|
||||
else
|
||||
clsName = getClassName (component);
|
||||
|
||||
code.privateMemberDeclarations
|
||||
<< "std::unique_ptr<" << clsName << "> " << memberVariableName << ";\n";
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::fillInResizeCode (GeneratedCode& code, Component* component, const String& memberVariableName)
|
||||
{
|
||||
const RelativePositionedRectangle pos (getComponentPosition (component));
|
||||
|
||||
String x, y, w, h, r;
|
||||
positionToCode (pos, code.document->getComponentLayout(), x, y, w, h);
|
||||
|
||||
r << memberVariableName << "->setBounds ("
|
||||
<< x << ", " << y << ", " << w << ", " << h << ");\n";
|
||||
|
||||
if (pos.rect.isPositionAbsolute() && ! code.document->getComponentLayout()->isComponentPositionRelative (component))
|
||||
code.constructorCode += r + "\n";
|
||||
else
|
||||
code.getCallbackCode (String(), "void", "resized()", false) += r;
|
||||
}
|
||||
|
||||
String ComponentTypeHandler::getCreationParameters (GeneratedCode&, Component*)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
|
||||
{
|
||||
String params (getCreationParameters (code, component));
|
||||
const String virtualName (component->getProperties() ["virtualName"].toString());
|
||||
|
||||
String s;
|
||||
s << memberVariableName << ".reset (new ";
|
||||
|
||||
if (virtualName.isNotEmpty())
|
||||
s << build_tools::makeValidIdentifier (virtualName, false, false, true);
|
||||
else
|
||||
s << getClassName (component);
|
||||
|
||||
if (params.isEmpty())
|
||||
{
|
||||
s << "());\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
StringArray lines;
|
||||
lines.addLines (params);
|
||||
|
||||
params = lines.joinIntoString ("\n" + String::repeatedString (" ", s.length() + 2));
|
||||
|
||||
s << " (" << params << "));\n";
|
||||
}
|
||||
|
||||
s << "addAndMakeVisible (" << memberVariableName << ".get());\n";
|
||||
|
||||
|
||||
if (auto* ttc = dynamic_cast<SettableTooltipClient*> (component))
|
||||
{
|
||||
if (ttc->getTooltip().isNotEmpty())
|
||||
{
|
||||
s << memberVariableName << "->setTooltip ("
|
||||
<< quotedString (ttc->getTooltip(), code.shouldUseTransMacro())
|
||||
<< ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (component != nullptr && component->getExplicitFocusOrder() > 0)
|
||||
s << memberVariableName << "->setExplicitFocusOrder ("
|
||||
<< component->getExplicitFocusOrder()
|
||||
<< ");\n";
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
void ComponentTypeHandler::fillInDeletionCode (GeneratedCode& code, Component*,
|
||||
const String& memberVariableName)
|
||||
{
|
||||
code.destructorCode
|
||||
<< memberVariableName << " = nullptr;\n";
|
||||
}
|
||||
147
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentTypeHandler.h
vendored
Normal file
147
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentTypeHandler.h
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class ComponentOverlayComponent;
|
||||
class ComponentLayout;
|
||||
#include "../jucer_GeneratedCode.h"
|
||||
#include "../UI/jucer_RelativePositionedRectangle.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for handlers that can understand the properties of all the component classes.
|
||||
*/
|
||||
class ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentTypeHandler (const String& typeDescription_,
|
||||
const String& className_,
|
||||
const std::type_info& componentClass,
|
||||
const int defaultWidth_,
|
||||
const int defaultHeight_);
|
||||
|
||||
virtual ~ComponentTypeHandler() {}
|
||||
|
||||
//==============================================================================
|
||||
virtual bool canHandle (Component& component) const;
|
||||
|
||||
static ComponentTypeHandler* getHandlerFor (Component& component);
|
||||
|
||||
//==============================================================================
|
||||
virtual String getXmlTagName() const noexcept
|
||||
{
|
||||
if (className.startsWith ("juce::"))
|
||||
return className.substring (6).toUpperCase();
|
||||
|
||||
return className.toUpperCase();
|
||||
}
|
||||
|
||||
static ComponentTypeHandler* getHandlerForXmlTag (const String& tagName);
|
||||
|
||||
virtual XmlElement* createXmlFor (Component* component, const ComponentLayout* layout);
|
||||
virtual bool restoreFromXml (const XmlElement& xml, Component* component, const ComponentLayout* layout);
|
||||
|
||||
virtual void getEditableProperties (Component* component,
|
||||
JucerDocument& document,
|
||||
Array<PropertyComponent*>& props,
|
||||
bool multipleSelected);
|
||||
|
||||
virtual void addPropertiesToPropertyPanel (Component* component,
|
||||
JucerDocument& document,
|
||||
PropertyPanel& panel,
|
||||
bool multipleSelected);
|
||||
|
||||
|
||||
void registerEditableColour (int colourId,
|
||||
const String& colourIdCode,
|
||||
const String& colourName,
|
||||
const String& xmlTagName);
|
||||
|
||||
#define registerColour(colourId, colourName, xmlTagName) \
|
||||
registerEditableColour (colourId, #colourId, colourName, xmlTagName)
|
||||
|
||||
void addColourProperties (Component* component,
|
||||
JucerDocument& document,
|
||||
Array<PropertyComponent*>& props);
|
||||
|
||||
String getColourIntialisationCode (Component* component,
|
||||
const String& objectName);
|
||||
|
||||
//==============================================================================
|
||||
virtual Component* createNewComponent (JucerDocument*) = 0;
|
||||
|
||||
virtual Component* createCopyOf (JucerDocument*, Component& existing);
|
||||
|
||||
virtual ComponentOverlayComponent* createOverlayComponent (Component* child, ComponentLayout& layout);
|
||||
|
||||
virtual void showPopupMenu (Component* component,
|
||||
ComponentLayout& layout);
|
||||
|
||||
//==============================================================================
|
||||
// Code-generation methods:
|
||||
|
||||
virtual void fillInGeneratedCode (Component* component, GeneratedCode& code);
|
||||
|
||||
virtual void fillInMemberVariableDeclarations (GeneratedCode&, Component*, const String& memberVariableName);
|
||||
virtual void fillInResizeCode (GeneratedCode&, Component*, const String& memberVariableName);
|
||||
virtual void fillInCreationCode (GeneratedCode&, Component*, const String& memberVariableName);
|
||||
virtual String getCreationParameters (GeneratedCode&, Component*);
|
||||
virtual void fillInDeletionCode (GeneratedCode&, Component*, const String& memberVariableName);
|
||||
|
||||
//==============================================================================
|
||||
const String& getTypeName() const noexcept { return typeName; }
|
||||
virtual String getClassName (Component*) const { return className; }
|
||||
|
||||
int getDefaultWidth() const noexcept { return defaultWidth; }
|
||||
int getDefaultHeight() const noexcept { return defaultHeight; }
|
||||
|
||||
static int64 getComponentId (Component* comp);
|
||||
static void setComponentId (Component* comp, const int64 newID);
|
||||
|
||||
static RelativePositionedRectangle getComponentPosition (Component* comp);
|
||||
static void setComponentPosition (Component* comp,
|
||||
const RelativePositionedRectangle& newPos,
|
||||
const ComponentLayout* layout);
|
||||
|
||||
static JucerDocument* findParentDocument (Component* component);
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
const String typeName, className, virtualClass, componentClassRawName;
|
||||
int defaultWidth, defaultHeight;
|
||||
|
||||
struct ComponentColourInfo
|
||||
{
|
||||
int colourId;
|
||||
String colourIdCode, colourName, xmlTagName;
|
||||
};
|
||||
|
||||
OwnedArray<ComponentColourInfo> colours;
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE (ComponentTypeHandler)
|
||||
};
|
||||
75
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentUndoableAction.h
vendored
Normal file
75
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ComponentUndoableAction.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UI/jucer_JucerDocumentEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
template <class ComponentType>
|
||||
class ComponentUndoableAction : public UndoableAction
|
||||
{
|
||||
public:
|
||||
ComponentUndoableAction (ComponentType* const comp,
|
||||
ComponentLayout& layout_)
|
||||
: layout (layout_),
|
||||
componentIndex (layout_.indexOfComponent (comp))
|
||||
{
|
||||
jassert (comp != nullptr);
|
||||
jassert (componentIndex >= 0);
|
||||
}
|
||||
|
||||
ComponentType* getComponent() const
|
||||
{
|
||||
ComponentType* const c = dynamic_cast<ComponentType*> (layout.getComponent (componentIndex));
|
||||
jassert (c != nullptr);
|
||||
return c;
|
||||
}
|
||||
|
||||
int getSizeInUnits() { return 2; }
|
||||
|
||||
protected:
|
||||
ComponentLayout& layout;
|
||||
const int componentIndex;
|
||||
|
||||
void changed() const
|
||||
{
|
||||
jassert (layout.getDocument() != nullptr);
|
||||
layout.getDocument()->changed();
|
||||
}
|
||||
|
||||
void showCorrectTab() const
|
||||
{
|
||||
if (JucerDocumentEditor* const ed = JucerDocumentEditor::getActiveDocumentHolder())
|
||||
ed->showLayout();
|
||||
|
||||
if (layout.getSelectedSet().getNumSelected() == 0)
|
||||
if (ComponentType* const c = dynamic_cast<ComponentType*> (layout.getComponent (componentIndex)))
|
||||
layout.getSelectedSet().selectOnly (getComponent());
|
||||
}
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentUndoableAction)
|
||||
};
|
||||
241
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_GenericComponentHandler.h
vendored
Normal file
241
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_GenericComponentHandler.h
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class GenericComponent : public Component
|
||||
{
|
||||
public:
|
||||
GenericComponent()
|
||||
: Component ("new component"),
|
||||
actualClassName ("juce::Component")
|
||||
{
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (Colours::white.withAlpha (0.25f));
|
||||
|
||||
g.setColour (Colours::black.withAlpha (0.5f));
|
||||
g.drawRect (getLocalBounds());
|
||||
g.drawLine (0.0f, 0.0f, (float) getWidth(), (float) getHeight());
|
||||
g.drawLine (0.0f, (float) getHeight(), (float) getWidth(), 0.0f);
|
||||
|
||||
g.setFont (14.0f);
|
||||
g.drawText (actualClassName, 0, 0, getWidth(), getHeight() / 2, Justification::centred, true);
|
||||
}
|
||||
|
||||
void setClassName (const String& newName)
|
||||
{
|
||||
if (actualClassName != newName)
|
||||
{
|
||||
actualClassName = newName;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void setParams (const String& newParams)
|
||||
{
|
||||
if (constructorParams != newParams)
|
||||
{
|
||||
constructorParams = newParams;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
String actualClassName, constructorParams;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class GenericComponentHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
GenericComponentHandler()
|
||||
: ComponentTypeHandler ("Generic Component", "GenericComponent", typeid (GenericComponent), 150, 24)
|
||||
{}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new GenericComponent();
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("class", ((GenericComponent*) comp)->actualClassName);
|
||||
e->setAttribute ("params", ((GenericComponent*) comp)->constructorParams);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
((GenericComponent*) comp)->actualClassName = xml.getStringAttribute ("class", "juce::Component");
|
||||
((GenericComponent*) comp)->constructorParams = xml.getStringAttribute ("params", String());
|
||||
return true;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
props.add (new GenericCompClassProperty (dynamic_cast<GenericComponent*> (component), document));
|
||||
props.add (new GenericCompParamsProperty (dynamic_cast<GenericComponent*> (component), document));
|
||||
}
|
||||
|
||||
String getClassName (Component* comp) const override
|
||||
{
|
||||
return static_cast<GenericComponent*> (comp)->actualClassName;
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* comp) override
|
||||
{
|
||||
return static_cast<GenericComponent*> (comp)->constructorParams;
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
if (component->getName().isNotEmpty())
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setName ("
|
||||
<< quotedString (component->getName(), false)
|
||||
<< ");\n\n";
|
||||
else
|
||||
code.constructorCode << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
class GenericCompClassProperty : public ComponentTextProperty <GenericComponent>
|
||||
{
|
||||
public:
|
||||
GenericCompClassProperty (GenericComponent* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <GenericComponent> ("class", 300, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new GenericCompClassChangeAction (component, *document.getComponentLayout(),
|
||||
build_tools::makeValidIdentifier (newText, false, false, true)),
|
||||
"Change generic component class");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->actualClassName;
|
||||
}
|
||||
|
||||
private:
|
||||
class GenericCompClassChangeAction : public ComponentUndoableAction <GenericComponent>
|
||||
{
|
||||
public:
|
||||
GenericCompClassChangeAction (GenericComponent* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <GenericComponent> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->actualClassName;
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setClassName (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setClassName (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
class GenericCompParamsProperty : public ComponentTextProperty <GenericComponent>
|
||||
{
|
||||
public:
|
||||
GenericCompParamsProperty (GenericComponent* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <GenericComponent> ("constructor params", 1024, true, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new GenericCompParamsChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change generic component class");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->constructorParams;
|
||||
}
|
||||
|
||||
private:
|
||||
class GenericCompParamsChangeAction : public ComponentUndoableAction <GenericComponent>
|
||||
{
|
||||
public:
|
||||
GenericCompParamsChangeAction (GenericComponent* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <GenericComponent> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->constructorParams;
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setParams (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setParams (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
237
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_GroupComponentHandler.h
vendored
Normal file
237
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_GroupComponentHandler.h
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class GroupComponentHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
GroupComponentHandler()
|
||||
: ComponentTypeHandler ("Group Box", "juce::GroupComponent", typeid (GroupComponent), 200, 150)
|
||||
{
|
||||
registerColour (juce::GroupComponent::outlineColourId, "outline", "outlinecol");
|
||||
registerColour (juce::GroupComponent::textColourId, "text", "textcol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new GroupComponent ("new group", "group");
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
GroupComponent* const g = (GroupComponent*) comp;
|
||||
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("title", g->getText());
|
||||
|
||||
GroupComponent defaultComp;
|
||||
|
||||
if (g->getTextLabelPosition().getFlags() != defaultComp.getTextLabelPosition().getFlags())
|
||||
e->setAttribute ("textpos", g->getTextLabelPosition().getFlags());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
GroupComponent* const g = (GroupComponent*) comp;
|
||||
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
g->setText (xml.getStringAttribute ("title", g->getText()));
|
||||
g->setTextLabelPosition (Justification (xml.getIntAttribute ("textpos", g->getTextLabelPosition().getFlags())));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode& code, Component* component) override
|
||||
{
|
||||
GroupComponent* g = dynamic_cast<GroupComponent*> (component);
|
||||
|
||||
return quotedString (component->getName(), false)
|
||||
+ ",\n"
|
||||
+ quotedString (g->getText(), code.shouldUseTransMacro());
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
GroupComponent* const g = dynamic_cast<GroupComponent*> (component);
|
||||
|
||||
String s;
|
||||
|
||||
GroupComponent defaultComp;
|
||||
|
||||
if (g->getTextLabelPosition().getFlags() != defaultComp.getTextLabelPosition().getFlags())
|
||||
{
|
||||
s << memberVariableName << "->setTextLabelPosition ("
|
||||
<< CodeHelpers::justificationToCode (g->getTextLabelPosition())
|
||||
<< ");\n";
|
||||
}
|
||||
|
||||
s << getColourIntialisationCode (component, memberVariableName)
|
||||
<< '\n';
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* gc = dynamic_cast<GroupComponent*> (component))
|
||||
{
|
||||
props.add (new GroupTitleProperty (gc, document));
|
||||
props.add (new GroupJustificationProperty (gc, document));
|
||||
}
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class GroupTitleProperty : public ComponentTextProperty <GroupComponent>
|
||||
{
|
||||
public:
|
||||
GroupTitleProperty (GroupComponent* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <GroupComponent> ("text", 200, false, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new GroupTitleChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change group title");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getText();
|
||||
}
|
||||
|
||||
private:
|
||||
class GroupTitleChangeAction : public ComponentUndoableAction <GroupComponent>
|
||||
{
|
||||
public:
|
||||
GroupTitleChangeAction (GroupComponent* const comp, ComponentLayout& l, const String& newName_)
|
||||
: ComponentUndoableAction <GroupComponent> (comp, l),
|
||||
newName (newName_)
|
||||
{
|
||||
oldName = comp->getText();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (newName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (oldName);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newName, oldName;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class GroupJustificationProperty : public JustificationProperty,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
GroupJustificationProperty (GroupComponent* const group_, JucerDocument& doc)
|
||||
: JustificationProperty ("layout", true),
|
||||
group (group_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~GroupJustificationProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setJustification (Justification newJustification) override
|
||||
{
|
||||
document.perform (new GroupJustifyChangeAction (group, *document.getComponentLayout(), newJustification),
|
||||
"Change text label position");
|
||||
}
|
||||
|
||||
Justification getJustification() const override
|
||||
{
|
||||
return group->getTextLabelPosition();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
GroupComponent* const group;
|
||||
JucerDocument& document;
|
||||
|
||||
class GroupJustifyChangeAction : public ComponentUndoableAction <GroupComponent>
|
||||
{
|
||||
public:
|
||||
GroupJustifyChangeAction (GroupComponent* const comp, ComponentLayout& l, Justification newState_)
|
||||
: ComponentUndoableAction <GroupComponent> (comp, l),
|
||||
newState (newState_),
|
||||
oldState (comp->getTextLabelPosition())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextLabelPosition (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextLabelPosition (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Justification newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
149
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_HyperlinkButtonHandler.h
vendored
Normal file
149
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_HyperlinkButtonHandler.h
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class HyperlinkButtonHandler : public ButtonHandler
|
||||
{
|
||||
public:
|
||||
HyperlinkButtonHandler()
|
||||
: ButtonHandler ("Hyperlink Button", "juce::HyperlinkButton", typeid (HyperlinkButton), 150, 24)
|
||||
{
|
||||
registerColour (juce::HyperlinkButton::textColourId, "text", "textCol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
HyperlinkButton* hb = new HyperlinkButton ("new hyperlink", URL ("http://www.juce.com"));
|
||||
|
||||
setNeedsButtonListener (hb, false);
|
||||
return hb;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* hb = dynamic_cast<HyperlinkButton*> (component))
|
||||
props.add (new HyperlinkURLProperty (hb, document));
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
HyperlinkButton* const hb = (HyperlinkButton*) comp;
|
||||
XmlElement* const e = ButtonHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("url", hb->getURL().toString (false));
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
HyperlinkButton* const hb = (HyperlinkButton*) comp;
|
||||
|
||||
if (! ButtonHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
hb->setURL (URL (xml.getStringAttribute ("url", hb->getURL().toString (false))));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode& code, Component* comp) override
|
||||
{
|
||||
HyperlinkButton* const hb = dynamic_cast<HyperlinkButton*> (comp);
|
||||
|
||||
return quotedString (hb->getButtonText(), code.shouldUseTransMacro())
|
||||
+ ",\nURL ("
|
||||
+ quotedString (hb->getURL().toString (false), false)
|
||||
+ ")";
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ButtonHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
code.constructorCode << getColourIntialisationCode (component, memberVariableName)
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class HyperlinkURLProperty : public ComponentTextProperty <HyperlinkButton>
|
||||
{
|
||||
public:
|
||||
HyperlinkURLProperty (HyperlinkButton* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <HyperlinkButton> ("URL", 512, false, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new HyperlinkURLChangeAction (component, *document.getComponentLayout(), URL::createWithoutParsing (newText)),
|
||||
"Change hyperlink URL");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getURL().toString (false);
|
||||
}
|
||||
|
||||
private:
|
||||
class HyperlinkURLChangeAction : public ComponentUndoableAction <HyperlinkButton>
|
||||
{
|
||||
public:
|
||||
HyperlinkURLChangeAction (HyperlinkButton* const comp, ComponentLayout& l, const URL& newState_)
|
||||
: ComponentUndoableAction <HyperlinkButton> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getURL();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setURL (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setURL (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
URL newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
526
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ImageButtonHandler.h
vendored
Normal file
526
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ImageButtonHandler.h
vendored
Normal file
@@ -0,0 +1,526 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ImageButtonHandler : public ButtonHandler
|
||||
{
|
||||
public:
|
||||
enum ImageRole
|
||||
{
|
||||
normalImage = 0,
|
||||
overImage = 1,
|
||||
downImage = 2
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ImageButtonHandler()
|
||||
: ButtonHandler ("Image Button", "juce::ImageButton", typeid (ImageButton), 150, 24)
|
||||
{
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new ImageButton ("new button");
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
|
||||
if (auto* ib = dynamic_cast<ImageButton*> (component))
|
||||
{
|
||||
auto& layout = *document.getComponentLayout();
|
||||
|
||||
props.add (new ImageButtonProportionProperty (layout, ib));
|
||||
|
||||
props.add (new ImageButtonResourceProperty (layout, ib, normalImage, "normal image"));
|
||||
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", normalImage));
|
||||
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", normalImage));
|
||||
|
||||
props.add (new ImageButtonResourceProperty (layout, ib, overImage, "over image"));
|
||||
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", overImage));
|
||||
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", overImage));
|
||||
|
||||
props.add (new ImageButtonResourceProperty (layout, ib, downImage, "down image"));
|
||||
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", downImage));
|
||||
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", downImage));
|
||||
}
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
XmlElement* e = ButtonHandler::createXmlFor (comp, layout);
|
||||
|
||||
ImageButton* const ib = (ImageButton*) comp;
|
||||
|
||||
e->setAttribute ("keepProportions", doesImageKeepProportions (ib));
|
||||
|
||||
e->setAttribute ("resourceNormal", getImageResource (ib, normalImage));
|
||||
e->setAttribute ("opacityNormal", getImageOpacity (ib, normalImage));
|
||||
e->setAttribute ("colourNormal", getImageColour (ib, normalImage).toString());
|
||||
|
||||
e->setAttribute ("resourceOver", getImageResource (ib, overImage));
|
||||
e->setAttribute ("opacityOver", getImageOpacity (ib, overImage));
|
||||
e->setAttribute ("colourOver", getImageColour (ib, overImage).toString());
|
||||
|
||||
e->setAttribute ("resourceDown", getImageResource (ib, downImage));
|
||||
e->setAttribute ("opacityDown", getImageOpacity (ib, downImage));
|
||||
e->setAttribute ("colourDown", getImageColour (ib, downImage).toString());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ButtonHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
ImageButton* const ib = (ImageButton*) comp;
|
||||
ComponentLayout& l = const_cast<ComponentLayout&> (*layout);
|
||||
|
||||
setImageKeepProportions (l, ib, xml.getBoolAttribute ("keepProportions", true), false);
|
||||
|
||||
setImageResource (l, ib, normalImage, xml.getStringAttribute ("resourceNormal", String()), false);
|
||||
setImageOpacity (l, ib, normalImage, (float) xml.getDoubleAttribute ("opacityNormal", 1.0f), false);
|
||||
setImageColour (l, ib, normalImage, Colour::fromString (xml.getStringAttribute ("colourNormal", "0")), false);
|
||||
|
||||
setImageResource (l, ib, overImage, xml.getStringAttribute ("resourceOver", String()), false);
|
||||
setImageOpacity (l, ib, overImage, (float) xml.getDoubleAttribute ("opacityOver", 1.0f), false);
|
||||
setImageColour (l, ib, overImage, Colour::fromString (xml.getStringAttribute ("colourOver", "0")), false);
|
||||
|
||||
setImageResource (l, ib, downImage, xml.getStringAttribute ("resourceDown", String()), false);
|
||||
setImageOpacity (l, ib, downImage, (float) xml.getDoubleAttribute ("opacityDown", 1.0f), false);
|
||||
setImageColour (l, ib, downImage, Colour::fromString (xml.getStringAttribute ("colourDown", "0")), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ButtonHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
ImageButton* const ib = dynamic_cast<ImageButton*> (component);
|
||||
|
||||
String s;
|
||||
|
||||
s << getColourIntialisationCode (component, memberVariableName)
|
||||
<< '\n';
|
||||
|
||||
const String indent (String::repeatedString (" ", memberVariableName.length() + 13));
|
||||
|
||||
s << memberVariableName << "->setImages (false, true, "
|
||||
<< CodeHelpers::boolLiteral (doesImageKeepProportions (ib)) << ",\n"
|
||||
<< indent
|
||||
<< getImageCreationCode (ib, normalImage) << ", "
|
||||
<< CodeHelpers::floatLiteral (getImageOpacity (ib, normalImage), 3) << ", "
|
||||
<< CodeHelpers::colourToCode (getImageColour (ib, normalImage)) << ",\n"
|
||||
<< indent
|
||||
<< getImageCreationCode (ib, overImage) << ", "
|
||||
<< CodeHelpers::floatLiteral (getImageOpacity (ib, overImage), 3) << ", "
|
||||
<< CodeHelpers::colourToCode (getImageColour (ib, overImage)) << ",\n"
|
||||
<< indent
|
||||
<< getImageCreationCode (ib, downImage) << ", "
|
||||
<< CodeHelpers::floatLiteral (getImageOpacity (ib, downImage), 3) << ", "
|
||||
<< CodeHelpers::colourToCode (getImageColour (ib, downImage))
|
||||
<< ");\n";
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
static String getImageCreationCode (ImageButton* ib, const ImageRole role)
|
||||
{
|
||||
const String resName (getImageResource (ib, role));
|
||||
|
||||
if (resName.isEmpty())
|
||||
return "juce::Image()";
|
||||
|
||||
return "juce::ImageCache::getFromMemory (" + resName + ", " + resName + "Size)";
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ImageButtonResourceProperty : public ImageResourceProperty<ImageButton>
|
||||
{
|
||||
public:
|
||||
ImageButtonResourceProperty (ComponentLayout& layout_, ImageButton* const owner_, const ImageRole role_, const String& name)
|
||||
: ImageResourceProperty<ImageButton> (*layout_.getDocument(), owner_, name, true),
|
||||
role (role_),
|
||||
layout (layout_)
|
||||
{
|
||||
}
|
||||
|
||||
void setResource (const String& newName)
|
||||
{
|
||||
setImageResource (layout, element, role, newName, true);
|
||||
}
|
||||
|
||||
String getResource() const
|
||||
{
|
||||
return getImageResource (element, role);
|
||||
}
|
||||
|
||||
private:
|
||||
const ImageRole role;
|
||||
ComponentLayout& layout;
|
||||
};
|
||||
|
||||
class SetImageResourceAction : public ComponentUndoableAction<ImageButton>
|
||||
{
|
||||
public:
|
||||
SetImageResourceAction (ImageButton* const button,
|
||||
ComponentLayout& layout_,
|
||||
const ImageRole role_,
|
||||
const String& newResource_)
|
||||
: ComponentUndoableAction<ImageButton> (button, layout_),
|
||||
newResource (newResource_),
|
||||
role (role_)
|
||||
{
|
||||
oldResource = ImageButtonHandler::getImageResource (button, role_);
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageResource (layout, getComponent(), role, newResource, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageResource (layout, getComponent(), role, oldResource, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
String newResource, oldResource;
|
||||
const ImageRole role;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static void setImageResource (ComponentLayout& layout, ImageButton* button, const ImageRole role, const String& newName, const bool undoable)
|
||||
{
|
||||
jassert (role < 3);
|
||||
|
||||
if (role < 3 && getImageResource (button, role) != newName)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
layout.getDocument()->perform (new SetImageResourceAction (button, layout, role, newName),
|
||||
"Change image resource");
|
||||
}
|
||||
else
|
||||
{
|
||||
button->getProperties().set ("resource" + String ((int) role), newName);
|
||||
updateButtonImages (*layout.getDocument(), button);
|
||||
layout.changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String getImageResource (ImageButton* button, const ImageRole role)
|
||||
{
|
||||
jassert (role < 3);
|
||||
return button->getProperties() ["resource" + String ((int) role)].toString();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SetImageKeepsPropAction : public ComponentUndoableAction<ImageButton>
|
||||
{
|
||||
public:
|
||||
SetImageKeepsPropAction (ImageButton* const button,
|
||||
ComponentLayout& layout_,
|
||||
const bool newState_)
|
||||
: ComponentUndoableAction<ImageButton> (button, layout_),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = ImageButtonHandler::doesImageKeepProportions (button);
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageKeepProportions (layout, getComponent(), newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageKeepProportions (layout, getComponent(), oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool newState, oldState;
|
||||
};
|
||||
|
||||
static bool doesImageKeepProportions (ImageButton* button)
|
||||
{
|
||||
return button->getProperties().getWithDefault ("keepImageProp", true);
|
||||
}
|
||||
|
||||
static void setImageKeepProportions (ComponentLayout& layout, ImageButton* button, const bool newState, const bool undoable)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
layout.perform (new SetImageKeepsPropAction (button, layout, newState), "change imagebutton proportion mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
button->getProperties().set ("keepImageProp", newState);
|
||||
updateButtonImages (*layout.getDocument(), button);
|
||||
layout.changed();
|
||||
}
|
||||
}
|
||||
|
||||
class ImageButtonProportionProperty : public ComponentBooleanProperty<ImageButton>
|
||||
{
|
||||
public:
|
||||
ImageButtonProportionProperty (ComponentLayout& layout_, ImageButton* const owner_)
|
||||
: ComponentBooleanProperty<ImageButton> ("proportional", "maintain image proportions", "scale to fit",
|
||||
owner_, *layout_.getDocument()),
|
||||
layout (layout_)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
setImageKeepProportions (layout, component, newState, true);
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return doesImageKeepProportions (component);
|
||||
}
|
||||
|
||||
private:
|
||||
ComponentLayout& layout;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SetImageOpacityAction : public ComponentUndoableAction<ImageButton>
|
||||
{
|
||||
public:
|
||||
SetImageOpacityAction (ImageButton* const button,
|
||||
ComponentLayout& layout_,
|
||||
const ImageRole role_,
|
||||
const float newState_)
|
||||
: ComponentUndoableAction<ImageButton> (button, layout_),
|
||||
role (role_),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = ImageButtonHandler::getImageOpacity (button, role_);
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageOpacity (layout, getComponent(), role, newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageOpacity (layout, getComponent(), role, oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const ImageRole role;
|
||||
float newState, oldState;
|
||||
};
|
||||
|
||||
static float getImageOpacity (ImageButton* button, const ImageRole role)
|
||||
{
|
||||
return (float) button->getProperties().getWithDefault ("imageOpacity" + String ((int) role), 1.0f);
|
||||
}
|
||||
|
||||
static void setImageOpacity (ComponentLayout& layout, ImageButton* button, const ImageRole role, const float opacity, const bool undoable)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
layout.perform (new SetImageOpacityAction (button, layout, role, opacity), "change imagebutton opacity");
|
||||
}
|
||||
else
|
||||
{
|
||||
button->getProperties().set ("imageOpacity" + String ((int) role), opacity);
|
||||
updateButtonImages (*layout.getDocument(), button);
|
||||
layout.changed();
|
||||
}
|
||||
}
|
||||
|
||||
class ImageButtonOpacityProperty : public SliderPropertyComponent
|
||||
{
|
||||
public:
|
||||
ImageButtonOpacityProperty (ComponentLayout& layout_, ImageButton* const owner_,
|
||||
const String& name, const ImageRole role_)
|
||||
: SliderPropertyComponent (name, 0.0, 1.0, 0.0),
|
||||
owner (owner_),
|
||||
layout (layout_),
|
||||
role (role_)
|
||||
{
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
setImageOpacity (layout, owner, role, (float) newValue, true);
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return getImageOpacity (owner, role);
|
||||
}
|
||||
|
||||
private:
|
||||
ImageButton* const owner;
|
||||
ComponentLayout& layout;
|
||||
const ImageRole role;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SetImageColourAction : public ComponentUndoableAction<ImageButton>
|
||||
{
|
||||
public:
|
||||
SetImageColourAction (ImageButton* const button,
|
||||
ComponentLayout& layout_,
|
||||
const ImageRole role_,
|
||||
Colour newState_)
|
||||
: ComponentUndoableAction<ImageButton> (button, layout_),
|
||||
role (role_),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = ImageButtonHandler::getImageColour (button, role_);
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageColour (layout, getComponent(), role, newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
ImageButtonHandler::setImageColour (layout, getComponent(), role, oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const ImageRole role;
|
||||
Colour newState, oldState;
|
||||
};
|
||||
|
||||
static Colour getImageColour (ImageButton* button, const ImageRole role)
|
||||
{
|
||||
return Colour::fromString (button->getProperties().getWithDefault ("imageColour" + String ((int) role), "0").toString());
|
||||
}
|
||||
|
||||
static void setImageColour (ComponentLayout& layout, ImageButton* button,
|
||||
const ImageRole role, Colour colour, const bool undoable)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
layout.perform (new SetImageColourAction (button, layout, role, colour), "change imagebutton colour");
|
||||
}
|
||||
else
|
||||
{
|
||||
button->getProperties().set ("imageColour" + String ((int) role), colour.toString());
|
||||
updateButtonImages (*layout.getDocument(), button);
|
||||
layout.changed();
|
||||
}
|
||||
}
|
||||
|
||||
class ImageButtonColourProperty : public JucerColourPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ImageButtonColourProperty (ComponentLayout& layout_, ImageButton* const owner_,
|
||||
const String& name, const ImageRole role_)
|
||||
: JucerColourPropertyComponent (name, false),
|
||||
owner (owner_),
|
||||
layout (layout_),
|
||||
role (role_)
|
||||
{
|
||||
layout_.getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~ImageButtonColourProperty() override
|
||||
{
|
||||
layout.getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setColour (Colour newColour) override
|
||||
{
|
||||
setImageColour (layout, owner, role, newColour, true);
|
||||
}
|
||||
|
||||
Colour getColour() const override
|
||||
{
|
||||
return getImageColour (owner, role);
|
||||
}
|
||||
|
||||
void resetToDefault() override {}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
ImageButton* const owner;
|
||||
ComponentLayout& layout;
|
||||
const ImageRole role;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static void updateButtonImages (JucerDocument& document, ImageButton* const ib)
|
||||
{
|
||||
Image norm = document.getResources().getImageFromCache (getImageResource (ib, normalImage));
|
||||
Image over = document.getResources().getImageFromCache (getImageResource (ib, overImage));
|
||||
Image down = document.getResources().getImageFromCache (getImageResource (ib, downImage));
|
||||
|
||||
ib->setImages (false, true, doesImageKeepProportions (ib),
|
||||
norm,
|
||||
getImageOpacity (ib, normalImage),
|
||||
getImageColour (ib, normalImage),
|
||||
over,
|
||||
getImageOpacity (ib, overImage),
|
||||
getImageColour (ib, overImage),
|
||||
down,
|
||||
getImageOpacity (ib, downImage),
|
||||
getImageColour (ib, downImage));
|
||||
}
|
||||
};
|
||||
273
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_JucerComponentHandler.h
vendored
Normal file
273
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_JucerComponentHandler.h
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UI/jucer_TestComponent.h"
|
||||
#include "../Properties/jucer_FilePropertyComponent.h"
|
||||
#include "../Properties/jucer_ComponentTextProperty.h"
|
||||
#include "jucer_ComponentUndoableAction.h"
|
||||
#include "../../Project/UI/jucer_ProjectContentComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class JucerComponentHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
JucerComponentHandler()
|
||||
: ComponentTypeHandler ("Projucer Component", "xxx",
|
||||
typeid (TestComponent), 300, 200)
|
||||
{}
|
||||
|
||||
Component* createNewComponent (JucerDocument* doc) override
|
||||
{
|
||||
return new TestComponent (doc, nullptr, false);
|
||||
}
|
||||
|
||||
String getXmlTagName() const noexcept override { return "JUCERCOMP"; }
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
TestComponent* const tc = dynamic_cast<TestComponent*> (comp);
|
||||
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("sourceFile", tc->getFilename());
|
||||
e->setAttribute ("constructorParams", tc->getConstructorParams());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
auto tc = dynamic_cast<TestComponent*> (comp);
|
||||
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
tc->setFilename (xml.getStringAttribute ("sourceFile", tc->getFilename()));
|
||||
tc->setConstructorParams (xml.getStringAttribute ("constructorParams"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getClassName (Component* comp) const override
|
||||
{
|
||||
auto tc = dynamic_cast<TestComponent*> (comp);
|
||||
|
||||
String jucerCompClassName;
|
||||
|
||||
if (tc->getDocument() != nullptr)
|
||||
jucerCompClassName = tc->getDocument()->getClassName();
|
||||
|
||||
if (jucerCompClassName.isEmpty())
|
||||
jucerCompClassName = "juce::Component";
|
||||
|
||||
return jucerCompClassName;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto tc = dynamic_cast<TestComponent*> (component))
|
||||
{
|
||||
props.add (new JucerCompFileProperty (tc, document));
|
||||
props.add (new ConstructorParamsProperty (tc, document));
|
||||
props.add (new JucerCompOpenDocProperty (tc));
|
||||
}
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* component) override
|
||||
{
|
||||
return dynamic_cast<TestComponent*> (component)->getConstructorParams().trim();
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
if (auto tc = dynamic_cast<TestComponent*> (component))
|
||||
code.includeFilesH.add (tc->findFile().withFileExtension (".h"));
|
||||
else
|
||||
jassertfalse;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JucerCompFileChangeAction : public ComponentUndoableAction <TestComponent>
|
||||
{
|
||||
public:
|
||||
JucerCompFileChangeAction (TestComponent* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <TestComponent> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getFilename();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setFilename (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setFilename (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
|
||||
static void setJucerComponentFile (JucerDocument& document, TestComponent* comp, const String& newFilename)
|
||||
{
|
||||
jassert (comp != nullptr);
|
||||
|
||||
if (comp != nullptr)
|
||||
document.perform (new JucerCompFileChangeAction (comp, *document.getComponentLayout(), newFilename),
|
||||
"Change Projucer component file");
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class JucerCompFileProperty : public FilePropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
JucerCompFileProperty (TestComponent* const comp, JucerDocument& doc)
|
||||
: FilePropertyComponent ("Jucer file", false, true),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~JucerCompFileProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setFile (const File& newFile) override
|
||||
{
|
||||
setJucerComponentFile (document, component,
|
||||
newFile.getRelativePathFrom (document.getCppFile().getParentDirectory())
|
||||
.replaceCharacter ('\\', '/'));
|
||||
}
|
||||
|
||||
File getFile() const override
|
||||
{
|
||||
return component->findFile();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
TestComponent* const component;
|
||||
JucerDocument& document;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct JucerCompOpenDocProperty : public ButtonPropertyComponent
|
||||
{
|
||||
JucerCompOpenDocProperty (TestComponent* const c)
|
||||
: ButtonPropertyComponent ("edit", false),
|
||||
component (c)
|
||||
{
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
if (ProjectContentComponent* const pcc = findParentComponentOfClass<ProjectContentComponent>())
|
||||
pcc->showEditorForFile (component->findFile(), true);
|
||||
}
|
||||
|
||||
String getButtonText() const
|
||||
{
|
||||
return "Open file for editing";
|
||||
}
|
||||
|
||||
TestComponent* const component;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct ConstructorParamsProperty : public ComponentTextProperty <TestComponent>
|
||||
{
|
||||
ConstructorParamsProperty (TestComponent* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <TestComponent> ("constructor params", 512, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ConstructorParamChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change Viewport content constructor params");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getConstructorParams();
|
||||
}
|
||||
|
||||
private:
|
||||
struct ConstructorParamChangeAction : public ComponentUndoableAction <TestComponent>
|
||||
{
|
||||
ConstructorParamChangeAction (TestComponent* const comp, ComponentLayout& l, const String& newValue_)
|
||||
: ComponentUndoableAction <TestComponent> (comp, l),
|
||||
newValue (newValue_)
|
||||
{
|
||||
oldValue = comp->getConstructorParams();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setConstructorParams (newValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setConstructorParams (oldValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newValue, oldValue;
|
||||
};
|
||||
};
|
||||
};
|
||||
774
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_LabelHandler.h
vendored
Normal file
774
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_LabelHandler.h
vendored
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class LabelHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
LabelHandler()
|
||||
: ComponentTypeHandler ("Label", "juce::Label", typeid (Label), 150, 24)
|
||||
{
|
||||
registerColour (juce::Label::backgroundColourId, "background", "bkgCol");
|
||||
registerColour (juce::Label::textColourId, "text", "textCol");
|
||||
registerColour (juce::Label::outlineColourId, "outline", "outlineCol");
|
||||
registerColour (juce::TextEditor::textColourId, "editor text", "edTextCol");
|
||||
registerColour (juce::TextEditor::backgroundColourId, "editor bkg", "edBkgCol");
|
||||
registerColour (juce::TextEditor::highlightColourId, "highlight", "hiliteCol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new Label ("new label", "label text");
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
Label* const l = dynamic_cast<Label*> (comp);
|
||||
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("labelText", l->getText());
|
||||
|
||||
e->setAttribute ("editableSingleClick", l->isEditableOnSingleClick());
|
||||
e->setAttribute ("editableDoubleClick", l->isEditableOnDoubleClick());
|
||||
e->setAttribute ("focusDiscardsChanges", l->doesLossOfFocusDiscardChanges());
|
||||
|
||||
e->setAttribute ("fontname", l->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()).toString());
|
||||
e->setAttribute ("fontsize", roundToInt (l->getFont().getHeight() * 100.0) / 100.0);
|
||||
e->setAttribute ("kerning", roundToInt (l->getFont().getExtraKerningFactor() * 1000.0) / 1000.0);
|
||||
e->setAttribute ("bold", l->getFont().isBold());
|
||||
e->setAttribute ("italic", l->getFont().isItalic());
|
||||
e->setAttribute ("justification", l->getJustificationType().getFlags());
|
||||
if (l->getFont().getTypefaceStyle() != "Regular")
|
||||
{
|
||||
e->setAttribute ("typefaceStyle", l->getFont().getTypefaceStyle());
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
Label* const l = dynamic_cast<Label*> (comp);
|
||||
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
Label defaultLabel;
|
||||
|
||||
Font font;
|
||||
font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0));
|
||||
font.setBold (xml.getBoolAttribute ("bold", false));
|
||||
font.setItalic (xml.getBoolAttribute ("italic", false));
|
||||
font.setExtraKerningFactor ((float) xml.getDoubleAttribute ("kerning", 0.0));
|
||||
auto fontStyle = xml.getStringAttribute ("typefaceStyle");
|
||||
if (! fontStyle.isEmpty())
|
||||
font.setTypefaceStyle (fontStyle);
|
||||
|
||||
l->setFont (font);
|
||||
|
||||
l->getProperties().set ("typefaceName", xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont()));
|
||||
updateLabelFont (l);
|
||||
|
||||
l->setJustificationType (Justification (xml.getIntAttribute ("justification", Justification::centred)));
|
||||
|
||||
l->setText (xml.getStringAttribute ("labelText", "Label Text"), dontSendNotification);
|
||||
|
||||
l->setEditable (xml.getBoolAttribute ("editableSingleClick", defaultLabel.isEditableOnSingleClick()),
|
||||
xml.getBoolAttribute ("editableDoubleClick", defaultLabel.isEditableOnDoubleClick()),
|
||||
xml.getBoolAttribute ("focusDiscardsChanges", defaultLabel.doesLossOfFocusDiscardChanges()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void updateLabelFont (Label* label)
|
||||
{
|
||||
Font f (label->getFont());
|
||||
f = FontPropertyComponent::applyNameToFont (label->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()), f);
|
||||
label->setFont (f);
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode& code, Component* component) override
|
||||
{
|
||||
Label* const l = dynamic_cast<Label*> (component);
|
||||
|
||||
return quotedString (component->getName(), false)
|
||||
+ ",\n"
|
||||
+ quotedString (l->getText(), code.shouldUseTransMacro());
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
Label* const l = dynamic_cast<Label*> (component);
|
||||
|
||||
String s;
|
||||
|
||||
s << memberVariableName << "->setFont ("
|
||||
<< FontPropertyComponent::getCompleteFontCode (l->getFont(), l->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont()))
|
||||
<< ");\n"
|
||||
<< memberVariableName << "->setJustificationType ("
|
||||
<< CodeHelpers::justificationToCode (l->getJustificationType())
|
||||
<< ");\n"
|
||||
<< memberVariableName << "->setEditable ("
|
||||
<< CodeHelpers::boolLiteral (l->isEditableOnSingleClick()) << ", "
|
||||
<< CodeHelpers::boolLiteral (l->isEditableOnDoubleClick()) << ", "
|
||||
<< CodeHelpers::boolLiteral (l->doesLossOfFocusDiscardChanges()) << ");\n"
|
||||
<< getColourIntialisationCode (component, memberVariableName);
|
||||
|
||||
if (needsCallback (component))
|
||||
s << memberVariableName << "->addListener (this);\n";
|
||||
|
||||
s << '\n';
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
|
||||
{
|
||||
ComponentTypeHandler::fillInGeneratedCode (component, code);
|
||||
|
||||
if (needsCallback (component))
|
||||
{
|
||||
String& callback = code.getCallbackCode ("public juce::Label::Listener",
|
||||
"void",
|
||||
"labelTextChanged (juce::Label* labelThatHasChanged)",
|
||||
true);
|
||||
|
||||
if (callback.trim().isNotEmpty())
|
||||
callback << "else ";
|
||||
|
||||
const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
|
||||
const String userCodeComment ("UserLabelCode_" + memberVariableName);
|
||||
|
||||
callback
|
||||
<< "if (labelThatHasChanged == " << memberVariableName << ".get())\n"
|
||||
<< "{\n //[" << userCodeComment << "] -- add your label text handling code here..\n //[/" << userCodeComment << "]\n}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* const l = dynamic_cast<Label*> (component))
|
||||
{
|
||||
props.add (new LabelTextProperty (l, document));
|
||||
props.add (new LabelJustificationProperty (l, document));
|
||||
props.add (new FontNameProperty (l, document));
|
||||
props.add (new FontStyleProperty (l, document));
|
||||
props.add (new FontSizeProperty (l, document));
|
||||
props.add (new FontKerningProperty (l, document));
|
||||
|
||||
props.add (new LabelEditableProperty (l, document));
|
||||
|
||||
if (l->isEditableOnDoubleClick() || l->isEditableOnSingleClick())
|
||||
props.add (new LabelLossOfFocusProperty (l, document));
|
||||
}
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
static bool needsCallback (Component* label)
|
||||
{
|
||||
return ((Label*) label)->isEditableOnSingleClick()
|
||||
|| ((Label*) label)->isEditableOnDoubleClick(); // xxx should be configurable
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//==============================================================================
|
||||
class LabelTextProperty : public ComponentTextProperty <Label>
|
||||
{
|
||||
public:
|
||||
LabelTextProperty (Label* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Label> ("text", 10000, true, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new LabelTextChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change Label text");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getText();
|
||||
}
|
||||
|
||||
private:
|
||||
class LabelTextChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
LabelTextChangeAction (Label* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getText();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (newState, dontSendNotification);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (oldState, dontSendNotification);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class LabelEditableProperty : public ComponentChoiceProperty <Label>
|
||||
{
|
||||
public:
|
||||
LabelEditableProperty (Label* comp, JucerDocument& doc)
|
||||
: ComponentChoiceProperty <Label> ("editing", comp, doc)
|
||||
{
|
||||
choices.add ("read-only");
|
||||
choices.add ("edit on single-click");
|
||||
choices.add ("edit on double-click");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
document.perform (new LabelEditableChangeAction (component, *document.getComponentLayout(), newIndex),
|
||||
"Change Label editability");
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return component->isEditableOnSingleClick()
|
||||
? 1
|
||||
: (component->isEditableOnDoubleClick() ? 2 : 0);
|
||||
}
|
||||
|
||||
private:
|
||||
class LabelEditableChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
LabelEditableChangeAction (Label* const comp, ComponentLayout& l, const int newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isEditableOnSingleClick()
|
||||
? 1
|
||||
: (comp->isEditableOnDoubleClick() ? 2 : 0);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditable (newState == 1, newState >= 1, getComponent()->doesLossOfFocusDiscardChanges());
|
||||
changed();
|
||||
layout.getSelectedSet().changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditable (oldState == 1, oldState >= 1, getComponent()->doesLossOfFocusDiscardChanges());
|
||||
changed();
|
||||
layout.getSelectedSet().changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class LabelLossOfFocusProperty : public ComponentChoiceProperty <Label>
|
||||
{
|
||||
public:
|
||||
LabelLossOfFocusProperty (Label* comp, JucerDocument& doc)
|
||||
: ComponentChoiceProperty <Label> ("focus", comp, doc)
|
||||
{
|
||||
choices.add ("loss of focus discards changes");
|
||||
choices.add ("loss of focus commits changes");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
document.perform (new LabelFocusLossChangeAction (component, *document.getComponentLayout(), newIndex == 0),
|
||||
"Change Label focus behaviour");
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return component->doesLossOfFocusDiscardChanges() ? 0 : 1;
|
||||
}
|
||||
|
||||
private:
|
||||
class LabelFocusLossChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
LabelFocusLossChangeAction (Label* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->doesLossOfFocusDiscardChanges();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditable (getComponent()->isEditableOnSingleClick(),
|
||||
getComponent()->isEditableOnDoubleClick(),
|
||||
newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setEditable (getComponent()->isEditableOnSingleClick(),
|
||||
getComponent()->isEditableOnDoubleClick(),
|
||||
oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class LabelJustificationProperty : public JustificationProperty,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
LabelJustificationProperty (Label* const label_, JucerDocument& doc)
|
||||
: JustificationProperty ("layout", false),
|
||||
label (label_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~LabelJustificationProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setJustification (Justification newJustification) override
|
||||
{
|
||||
document.perform (new LabelJustifyChangeAction (label, *document.getComponentLayout(), newJustification),
|
||||
"Change Label justification");
|
||||
}
|
||||
|
||||
Justification getJustification() const override
|
||||
{
|
||||
return label->getJustificationType();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
Label* const label;
|
||||
JucerDocument& document;
|
||||
|
||||
class LabelJustifyChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
LabelJustifyChangeAction (Label* const comp, ComponentLayout& l, Justification newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_),
|
||||
oldState (comp->getJustificationType())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setJustificationType (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setJustificationType (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Justification newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontNameProperty : public FontPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
FontNameProperty (Label* const label_, JucerDocument& doc)
|
||||
: FontPropertyComponent ("font"),
|
||||
label (label_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontNameProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setTypefaceName (const String& newFontName) override
|
||||
{
|
||||
document.perform (new FontNameChangeAction (label, *document.getComponentLayout(), newFontName),
|
||||
"Change Label typeface");
|
||||
}
|
||||
|
||||
String getTypefaceName() const override
|
||||
{
|
||||
return label->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont());
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
Label* const label;
|
||||
JucerDocument& document;
|
||||
|
||||
class FontNameChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
FontNameChangeAction (Label* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getProperties().getWithDefault ("typefaceName", FontPropertyComponent::getDefaultFont());
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->getProperties().set ("typefaceName", newState);
|
||||
LabelHandler::updateLabelFont (getComponent());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->getProperties().set ("typefaceName", oldState);
|
||||
LabelHandler::updateLabelFont (getComponent());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontSizeProperty : public SliderPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
FontSizeProperty (Label* const label_, JucerDocument& doc)
|
||||
: SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3),
|
||||
label (label_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontSizeProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
document.getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
document.perform (new FontSizeChangeAction (label, *document.getComponentLayout(), (float) newValue),
|
||||
"Change Label font size");
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return label->getFont().getHeight();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
Label* const label;
|
||||
JucerDocument& document;
|
||||
|
||||
class FontSizeChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
FontSizeChangeAction (Label* const comp, ComponentLayout& l, const float newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getFont().getHeight();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
Font f (getComponent()->getFont());
|
||||
f.setHeight ((float) newState);
|
||||
getComponent()->setFont (f);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
Font f (getComponent()->getFont());
|
||||
f.setHeight ((float) oldState);
|
||||
getComponent()->setFont (f);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
float newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontStyleProperty : public ChoicePropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
FontStyleProperty (Label* const label_, JucerDocument& doc)
|
||||
: ChoicePropertyComponent ("style"),
|
||||
label (label_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
|
||||
updateStylesList (label->getFont());
|
||||
}
|
||||
|
||||
~FontStyleProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void updateStylesList (const Font& newFont)
|
||||
{
|
||||
if (getNumChildComponents() > 0)
|
||||
{
|
||||
if (auto cb = dynamic_cast<ComboBox*> (getChildComponent (0)))
|
||||
cb->clear();
|
||||
|
||||
getChildComponent (0)->setVisible (false);
|
||||
removeAllChildren();
|
||||
}
|
||||
|
||||
choices.clear();
|
||||
|
||||
choices.add ("Regular");
|
||||
choices.add ("Bold");
|
||||
choices.add ("Italic");
|
||||
choices.add ("Bold Italic");
|
||||
|
||||
choices.mergeArray (newFont.getAvailableStyles());
|
||||
refresh();
|
||||
}
|
||||
|
||||
void setIndex (int newIndex) override
|
||||
{
|
||||
Font f (label->getFont());
|
||||
|
||||
if (f.getAvailableStyles().contains (choices[newIndex]))
|
||||
{
|
||||
f.setBold (false);
|
||||
f.setItalic (false);
|
||||
f.setTypefaceStyle (choices[newIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.setTypefaceStyle ("Regular");
|
||||
f.setBold (newIndex == 1 || newIndex == 3);
|
||||
f.setItalic (newIndex == 2 || newIndex == 3);
|
||||
}
|
||||
|
||||
document.perform (new FontStyleChangeAction (label, *document.getComponentLayout(), f),
|
||||
"Change Label font style");
|
||||
}
|
||||
|
||||
int getIndex() const override
|
||||
{
|
||||
auto f = label->getFont();
|
||||
|
||||
const auto typefaceIndex = choices.indexOf (f.getTypefaceStyle());
|
||||
if (typefaceIndex == -1)
|
||||
{
|
||||
if (f.isBold() && f.isItalic())
|
||||
return 3;
|
||||
else if (f.isBold())
|
||||
return 1;
|
||||
else if (f.isItalic())
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return typefaceIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
updateStylesList (label->getFont());
|
||||
}
|
||||
|
||||
Label* const label;
|
||||
JucerDocument& document;
|
||||
|
||||
class FontStyleChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
FontStyleChangeAction (Label* const comp, ComponentLayout& l, const Font& newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getFont();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setFont (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setFont (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Font newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontKerningProperty : public SliderPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
FontKerningProperty (Label* const label_, JucerDocument& doc)
|
||||
: SliderPropertyComponent ("kerning", -0.5, 0.5, 0.001),
|
||||
label (label_),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontKerningProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
document.getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
document.perform (new FontKerningChangeAction (label, *document.getComponentLayout(), (float) newValue),
|
||||
"Change Label font kerning");
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return label->getFont().getExtraKerningFactor();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
Label* const label;
|
||||
JucerDocument& document;
|
||||
|
||||
class FontKerningChangeAction : public ComponentUndoableAction <Label>
|
||||
{
|
||||
public:
|
||||
FontKerningChangeAction (Label* const comp, ComponentLayout& l, const float newState_)
|
||||
: ComponentUndoableAction <Label> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getFont().getExtraKerningFactor();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
Font f (getComponent()->getFont());
|
||||
f.setExtraKerningFactor ((float) newState);
|
||||
getComponent()->setFont (f);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
Font f (getComponent()->getFont());
|
||||
f.setExtraKerningFactor ((float) oldState);
|
||||
getComponent()->setFont (f);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
float newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
709
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h
vendored
Normal file
709
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_SliderHandler.h
vendored
Normal file
@@ -0,0 +1,709 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static const Slider::SliderStyle sliderStyleTypes[] =
|
||||
{
|
||||
Slider::LinearHorizontal,
|
||||
Slider::LinearVertical,
|
||||
Slider::LinearBar,
|
||||
Slider::LinearBarVertical,
|
||||
Slider::Rotary,
|
||||
Slider::RotaryHorizontalDrag,
|
||||
Slider::RotaryVerticalDrag,
|
||||
Slider::RotaryHorizontalVerticalDrag,
|
||||
Slider::IncDecButtons,
|
||||
Slider::TwoValueHorizontal,
|
||||
Slider::TwoValueVertical,
|
||||
Slider::ThreeValueHorizontal,
|
||||
Slider::ThreeValueVertical
|
||||
};
|
||||
|
||||
static const Slider::TextEntryBoxPosition sliderTextBoxPositions[] =
|
||||
{
|
||||
Slider::NoTextBox,
|
||||
Slider::TextBoxLeft,
|
||||
Slider::TextBoxRight,
|
||||
Slider::TextBoxAbove,
|
||||
Slider::TextBoxBelow
|
||||
};
|
||||
|
||||
|
||||
struct SliderHandler : public ComponentTypeHandler
|
||||
{
|
||||
SliderHandler()
|
||||
: ComponentTypeHandler ("Slider", "juce::Slider", typeid (Slider), 150, 24)
|
||||
{
|
||||
registerColour (juce::Slider::backgroundColourId, "background", "bkgcol");
|
||||
registerColour (juce::Slider::thumbColourId, "thumb", "thumbcol");
|
||||
registerColour (juce::Slider::trackColourId, "track", "trackcol");
|
||||
registerColour (juce::Slider::rotarySliderFillColourId, "rotary fill", "rotarysliderfill");
|
||||
registerColour (juce::Slider::rotarySliderOutlineColourId, "rotary outln", "rotaryslideroutline");
|
||||
registerColour (juce::Slider::textBoxTextColourId, "textbox text", "textboxtext");
|
||||
registerColour (juce::Slider::textBoxBackgroundColourId, "textbox bkgd", "textboxbkgd");
|
||||
registerColour (juce::Slider::textBoxHighlightColourId, "textbox highlt", "textboxhighlight");
|
||||
registerColour (juce::Slider::textBoxOutlineColourId, "textbox outln", "textboxoutline");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new Slider ("new slider");
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
|
||||
Slider* s = dynamic_cast<Slider*> (comp);
|
||||
e->setAttribute ("min", s->getMinimum());
|
||||
e->setAttribute ("max", s->getMaximum());
|
||||
e->setAttribute ("int", s->getInterval());
|
||||
e->setAttribute ("style", sliderStyleToString (s->getSliderStyle()));
|
||||
e->setAttribute ("textBoxPos", textBoxPosToString (s->getTextBoxPosition()));
|
||||
e->setAttribute ("textBoxEditable", s->isTextBoxEditable());
|
||||
e->setAttribute ("textBoxWidth", s->getTextBoxWidth());
|
||||
e->setAttribute ("textBoxHeight", s->getTextBoxHeight());
|
||||
e->setAttribute ("skewFactor", s->getSkewFactor());
|
||||
e->setAttribute ("needsCallback", needsSliderListener (s));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
Slider* const s = dynamic_cast<Slider*> (comp);
|
||||
|
||||
s->setRange (xml.getDoubleAttribute ("min", 0.0),
|
||||
xml.getDoubleAttribute ("max", 10.0),
|
||||
xml.getDoubleAttribute ("int", 0.0));
|
||||
|
||||
s->setSliderStyle (sliderStringToStyle (xml.getStringAttribute ("style", "LinearHorizontal")));
|
||||
|
||||
s->setTextBoxStyle (stringToTextBoxPos (xml.getStringAttribute ("textBoxPos", "TextBoxLeft")),
|
||||
! xml.getBoolAttribute ("textBoxEditable", true),
|
||||
xml.getIntAttribute ("textBoxWidth", 80),
|
||||
xml.getIntAttribute ("textBoxHeight", 20));
|
||||
|
||||
s->setSkewFactor (xml.getDoubleAttribute ("skewFactor", 1.0));
|
||||
|
||||
setNeedsSliderListener (s, xml.getBoolAttribute ("needsCallback", true));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* component) override
|
||||
{
|
||||
return quotedString (component->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
Slider* const s = dynamic_cast<Slider*> (component);
|
||||
|
||||
String r;
|
||||
r << memberVariableName << "->setRange ("
|
||||
<< s->getMinimum() << ", " << s->getMaximum() << ", " << s->getInterval()
|
||||
<< ");\n"
|
||||
<< memberVariableName << "->setSliderStyle (juce::Slider::"
|
||||
<< sliderStyleToString (s->getSliderStyle()) << ");\n"
|
||||
<< memberVariableName << "->setTextBoxStyle (juce::Slider::"
|
||||
<< textBoxPosToString (s->getTextBoxPosition())
|
||||
<< ", " << CodeHelpers::boolLiteral (! s->isTextBoxEditable())
|
||||
<< ", " << s->getTextBoxWidth() << ", " << s->getTextBoxHeight() << ");\n"
|
||||
<< getColourIntialisationCode (component, memberVariableName);
|
||||
|
||||
if (needsSliderListener (component))
|
||||
r << memberVariableName << "->addListener (this);\n";
|
||||
|
||||
if (s->getSkewFactor() != 1.0)
|
||||
r << memberVariableName << "->setSkewFactor (" << s->getSkewFactor() << ");\n";
|
||||
|
||||
r << '\n';
|
||||
code.constructorCode += r;
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
|
||||
{
|
||||
ComponentTypeHandler::fillInGeneratedCode (component, code);
|
||||
|
||||
if (needsSliderListener (component))
|
||||
{
|
||||
String& callback = code.getCallbackCode ("public juce::Slider::Listener",
|
||||
"void",
|
||||
"sliderValueChanged (juce::Slider* sliderThatWasMoved)",
|
||||
true);
|
||||
|
||||
if (callback.isNotEmpty())
|
||||
callback << "else ";
|
||||
|
||||
const String memberVariableName (code.document->getComponentLayout()->getComponentMemberVariableName (component));
|
||||
const String userCodeComment ("UserSliderCode_" + memberVariableName);
|
||||
|
||||
callback
|
||||
<< "if (sliderThatWasMoved == " << memberVariableName << ".get())\n"
|
||||
<< "{\n //[" << userCodeComment << "] -- add your slider handling code here..\n //[/" << userCodeComment << "]\n}\n";
|
||||
}
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* s = dynamic_cast<Slider*> (component))
|
||||
{
|
||||
props.add (new SliderRangeProperty (s, document, "minimum", 0));
|
||||
props.add (new SliderRangeProperty (s, document, "maximum", 1));
|
||||
props.add (new SliderRangeProperty (s, document, "interval", 2));
|
||||
props.add (new SliderTypeProperty (s, document));
|
||||
props.add (new SliderTextboxProperty (s, document));
|
||||
props.add (new SliderTextboxEditableProperty (s, document));
|
||||
props.add (new SliderTextboxSizeProperty (s, document, true));
|
||||
props.add (new SliderTextboxSizeProperty (s, document, false));
|
||||
props.add (new SliderSkewProperty (s, document));
|
||||
props.add (new SliderCallbackProperty (s, document));
|
||||
}
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
static bool needsSliderListener (Component* slider)
|
||||
{
|
||||
return slider->getProperties().getWithDefault ("generateListenerCallback", true);
|
||||
}
|
||||
|
||||
static void setNeedsSliderListener (Component* slider, bool shouldDoCallback)
|
||||
{
|
||||
slider->getProperties().set ("generateListenerCallback", shouldDoCallback);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
struct SliderTypeProperty : public ComponentChoiceProperty<Slider>
|
||||
{
|
||||
SliderTypeProperty (Slider* slider, JucerDocument& doc)
|
||||
: ComponentChoiceProperty<Slider> ("type", slider, doc)
|
||||
{
|
||||
choices.add ("Linear Horizontal");
|
||||
choices.add ("Linear Vertical");
|
||||
choices.add ("Linear Bar Horizontal");
|
||||
choices.add ("Linear Bar Vertical");
|
||||
choices.add ("Rotary");
|
||||
choices.add ("Rotary HorizontalDrag");
|
||||
choices.add ("Rotary VerticalDrag");
|
||||
choices.add ("Rotary HorizontalVerticalDrag");
|
||||
choices.add ("Inc/Dec Buttons");
|
||||
choices.add ("Two Value Horizontal");
|
||||
choices.add ("Two Value Vertical");
|
||||
choices.add ("Three Value Horizontal");
|
||||
choices.add ("Three Value Vertical");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex) override
|
||||
{
|
||||
if (newIndex >= 0 && newIndex < numElementsInArray (sliderStyleTypes))
|
||||
document.perform (new SliderTypeChangeAction (component, *document.getComponentLayout(),
|
||||
sliderStyleTypes[newIndex]),
|
||||
"Change Slider style");
|
||||
}
|
||||
|
||||
int getIndex() const override
|
||||
{
|
||||
for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
|
||||
if (sliderStyleTypes[i] == dynamic_cast<Slider*> (component)->getSliderStyle())
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SliderTypeChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderTypeChangeAction (Slider* comp, ComponentLayout& l, Slider::SliderStyle newState_)
|
||||
: ComponentUndoableAction<Slider> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getSliderStyle();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setSliderStyle (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setSliderStyle (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Slider::SliderStyle newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderTextboxProperty : public ComponentChoiceProperty<Slider>
|
||||
{
|
||||
SliderTextboxProperty (Slider* slider, JucerDocument& doc)
|
||||
: ComponentChoiceProperty<Slider> ("text position", slider, doc)
|
||||
{
|
||||
choices.add ("No text box");
|
||||
choices.add ("Text box on left");
|
||||
choices.add ("Text box on right");
|
||||
choices.add ("Text box above");
|
||||
choices.add ("Text box below");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex) override
|
||||
{
|
||||
if (newIndex >= 0 && newIndex < numElementsInArray (sliderTextBoxPositions))
|
||||
document.perform (new SliderTextBoxChangeAction (component, *document.getComponentLayout(),
|
||||
sliderTextBoxPositions[newIndex]),
|
||||
"Change Slider textbox");
|
||||
}
|
||||
|
||||
int getIndex() const override
|
||||
{
|
||||
for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
|
||||
if (sliderTextBoxPositions[i] == component->getTextBoxPosition())
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
struct SliderTextBoxChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderTextBoxChangeAction (Slider* comp, ComponentLayout& l, Slider::TextEntryBoxPosition newState_)
|
||||
: ComponentUndoableAction<Slider> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getTextBoxPosition();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextBoxStyle (newState,
|
||||
! getComponent()->isTextBoxEditable(),
|
||||
getComponent()->getTextBoxWidth(),
|
||||
getComponent()->getTextBoxHeight());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextBoxStyle (oldState,
|
||||
! getComponent()->isTextBoxEditable(),
|
||||
getComponent()->getTextBoxWidth(),
|
||||
getComponent()->getTextBoxHeight());
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
Slider::TextEntryBoxPosition newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderTextboxEditableProperty : public ComponentBooleanProperty<Slider>
|
||||
{
|
||||
SliderTextboxEditableProperty (Slider* slider, JucerDocument& doc)
|
||||
: ComponentBooleanProperty<Slider> ("text box mode", "Editable", "Editable", slider, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState) override
|
||||
{
|
||||
document.perform (new SliderEditableChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change Slider editability");
|
||||
}
|
||||
|
||||
bool getState() const override
|
||||
{
|
||||
return component->isTextBoxEditable();
|
||||
}
|
||||
|
||||
private:
|
||||
struct SliderEditableChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderEditableChangeAction (Slider* const comp, ComponentLayout& l, bool newState_)
|
||||
: ComponentUndoableAction<Slider> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isTextBoxEditable();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextBoxIsEditable (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setTextBoxIsEditable (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderCallbackProperty : public ComponentBooleanProperty<Slider>
|
||||
{
|
||||
SliderCallbackProperty (Slider* s, JucerDocument& doc)
|
||||
: ComponentBooleanProperty<Slider> ("callback", "Generate SliderListener",
|
||||
"Generate SliderListener", s, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState) override
|
||||
{
|
||||
document.perform (new SliderCallbackChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change button callback");
|
||||
}
|
||||
|
||||
bool getState() const override { return needsSliderListener (component); }
|
||||
|
||||
struct SliderCallbackChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderCallbackChangeAction (Slider* comp, ComponentLayout& l, bool newState_)
|
||||
: ComponentUndoableAction<Slider> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = needsSliderListener (comp);
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
setNeedsSliderListener (getComponent(), newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
setNeedsSliderListener (getComponent(), oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderTextboxSizeProperty : public ComponentTextProperty<Slider>
|
||||
{
|
||||
SliderTextboxSizeProperty (Slider* slider, JucerDocument& doc, bool isWidth_)
|
||||
: ComponentTextProperty<Slider> (isWidth_ ? "text box width" : "text box height",
|
||||
12, false, slider, doc),
|
||||
isWidth (isWidth_)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new SliderBoxSizeChangeAction (component, *document.getComponentLayout(), isWidth, newText.getIntValue()),
|
||||
"Change Slider textbox size");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return String (isWidth ? component->getTextBoxWidth()
|
||||
: component->getTextBoxHeight());
|
||||
}
|
||||
|
||||
private:
|
||||
const bool isWidth;
|
||||
|
||||
struct SliderBoxSizeChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderBoxSizeChangeAction (Slider* const comp, ComponentLayout& l, bool isWidth_, int newSize_)
|
||||
: ComponentUndoableAction<Slider> (comp, l),
|
||||
isWidth (isWidth_),
|
||||
newSize (newSize_)
|
||||
{
|
||||
oldSize = isWidth ? comp->getTextBoxWidth()
|
||||
: comp->getTextBoxHeight();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
Slider& c = *getComponent();
|
||||
|
||||
if (isWidth)
|
||||
c.setTextBoxStyle (c.getTextBoxPosition(),
|
||||
! c.isTextBoxEditable(),
|
||||
newSize,
|
||||
c.getTextBoxHeight());
|
||||
else
|
||||
c.setTextBoxStyle (c.getTextBoxPosition(),
|
||||
! c.isTextBoxEditable(),
|
||||
c.getTextBoxWidth(),
|
||||
newSize);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
Slider& c = *getComponent();
|
||||
|
||||
if (isWidth)
|
||||
c.setTextBoxStyle (c.getTextBoxPosition(),
|
||||
! c.isTextBoxEditable(),
|
||||
oldSize,
|
||||
c.getTextBoxHeight());
|
||||
else
|
||||
c.setTextBoxStyle (c.getTextBoxPosition(),
|
||||
! c.isTextBoxEditable(),
|
||||
c.getTextBoxWidth(),
|
||||
oldSize);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isWidth;
|
||||
int newSize, oldSize;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderRangeProperty : public ComponentTextProperty<Slider>
|
||||
{
|
||||
SliderRangeProperty (Slider* slider, JucerDocument& doc,
|
||||
const String& name, int rangeParam_)
|
||||
: ComponentTextProperty<Slider> (name, 15, false, slider, doc),
|
||||
rangeParam (rangeParam_)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
double state [3];
|
||||
state [0] = component->getMinimum();
|
||||
state [1] = component->getMaximum();
|
||||
state [2] = component->getInterval();
|
||||
|
||||
state [rangeParam] = newText.getDoubleValue();
|
||||
|
||||
document.perform (new SliderRangeChangeAction (component, *document.getComponentLayout(), state),
|
||||
"Change Slider range");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
if (auto* s = dynamic_cast<Slider*> (component))
|
||||
{
|
||||
switch (rangeParam)
|
||||
{
|
||||
case 0: return String (s->getMinimum());
|
||||
case 1: return String (s->getMaximum());
|
||||
case 2: return String (s->getInterval());
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
const int rangeParam;
|
||||
|
||||
struct SliderRangeChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderRangeChangeAction (Slider* comp, ComponentLayout& l, const double newState_[3])
|
||||
: ComponentUndoableAction<Slider> (comp, l)
|
||||
{
|
||||
newState[0] = newState_ [0];
|
||||
newState[1] = newState_ [1];
|
||||
newState[2] = newState_ [2];
|
||||
|
||||
oldState[0] = comp->getMinimum();
|
||||
oldState[1] = comp->getMaximum();
|
||||
oldState[2] = comp->getInterval();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRange (newState[0], newState[1], newState[2]);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRange (oldState[0], oldState[1], oldState[2]);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
double newState[3], oldState[3];
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct SliderSkewProperty : public ComponentTextProperty<Slider>
|
||||
{
|
||||
SliderSkewProperty (Slider* slider, JucerDocument& doc)
|
||||
: ComponentTextProperty<Slider> ("skew factor", 12, false, slider, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
const double skew = jlimit (0.001, 1000.0, newText.getDoubleValue());
|
||||
|
||||
document.perform (new SliderSkewChangeAction (component, *document.getComponentLayout(), skew),
|
||||
"Change Slider skew");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
if (auto* s = dynamic_cast<Slider*> (component))
|
||||
return String (s->getSkewFactor());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
struct SliderSkewChangeAction : public ComponentUndoableAction<Slider>
|
||||
{
|
||||
SliderSkewChangeAction (Slider* comp, ComponentLayout& l, double newValue_)
|
||||
: ComponentUndoableAction<Slider> (comp, l)
|
||||
{
|
||||
newValue = newValue_;
|
||||
oldValue = comp->getSkewFactor();
|
||||
}
|
||||
|
||||
bool perform() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setSkewFactor (newValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo() override
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setSkewFactor (oldValue);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
double newValue, oldValue;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static String sliderStyleToString (Slider::SliderStyle style)
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case Slider::LinearHorizontal: return "LinearHorizontal";
|
||||
case Slider::LinearVertical: return "LinearVertical";
|
||||
case Slider::LinearBar: return "LinearBar";
|
||||
case Slider::LinearBarVertical: return "LinearBarVertical";
|
||||
case Slider::Rotary: return "Rotary";
|
||||
case Slider::RotaryHorizontalDrag: return "RotaryHorizontalDrag";
|
||||
case Slider::RotaryVerticalDrag: return "RotaryVerticalDrag";
|
||||
case Slider::RotaryHorizontalVerticalDrag: return "RotaryHorizontalVerticalDrag";
|
||||
case Slider::IncDecButtons: return "IncDecButtons";
|
||||
case Slider::TwoValueHorizontal: return "TwoValueHorizontal";
|
||||
case Slider::TwoValueVertical: return "TwoValueVertical";
|
||||
case Slider::ThreeValueHorizontal: return "ThreeValueHorizontal";
|
||||
case Slider::ThreeValueVertical: return "ThreeValueVertical";
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Slider::SliderStyle sliderStringToStyle (const String& s)
|
||||
{
|
||||
for (int i = 0; i < numElementsInArray (sliderStyleTypes); ++i)
|
||||
if (s == sliderStyleToString (sliderStyleTypes[i]))
|
||||
return sliderStyleTypes[i];
|
||||
|
||||
jassertfalse;
|
||||
return Slider::LinearHorizontal;
|
||||
}
|
||||
|
||||
static String textBoxPosToString (const Slider::TextEntryBoxPosition pos)
|
||||
{
|
||||
switch (pos)
|
||||
{
|
||||
case Slider::NoTextBox: return "NoTextBox";
|
||||
case Slider::TextBoxLeft: return "TextBoxLeft";
|
||||
case Slider::TextBoxRight: return "TextBoxRight";
|
||||
case Slider::TextBoxAbove: return "TextBoxAbove";
|
||||
case Slider::TextBoxBelow: return "TextBoxBelow";
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static Slider::TextEntryBoxPosition stringToTextBoxPos (const String& s)
|
||||
{
|
||||
for (int i = 0; i < numElementsInArray (sliderTextBoxPositions); ++i)
|
||||
if (s == textBoxPosToString (sliderTextBoxPositions[i]))
|
||||
return sliderTextBoxPositions[i];
|
||||
|
||||
jassertfalse;
|
||||
return Slider::TextBoxLeft;
|
||||
}
|
||||
};
|
||||
1195
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TabbedComponentHandler.h
vendored
Normal file
1195
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TabbedComponentHandler.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
79
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TextButtonHandler.h
vendored
Normal file
79
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TextButtonHandler.h
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class TextButtonHandler : public ButtonHandler
|
||||
{
|
||||
public:
|
||||
TextButtonHandler()
|
||||
: ButtonHandler ("Text Button", "juce::TextButton", typeid (TextButton), 150, 24)
|
||||
{
|
||||
registerColour (juce::TextButton::buttonColourId, "background (normal)", "bgColOff");
|
||||
registerColour (juce::TextButton::buttonOnColourId, "background (on)", "bgColOn");
|
||||
registerColour (juce::TextButton::textColourOffId, "text colour (normal)", "textCol");
|
||||
registerColour (juce::TextButton::textColourOnId, "text colour (on)", "textColOn");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new TextButton ("new button", String());
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
return ButtonHandler::createXmlFor (comp, layout);
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
return ButtonHandler::restoreFromXml (xml, comp, layout);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ButtonHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
String s;
|
||||
|
||||
s << getColourIntialisationCode (component, memberVariableName)
|
||||
<< '\n';
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
};
|
||||
433
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TextEditorHandler.h
vendored
Normal file
433
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TextEditorHandler.h
vendored
Normal file
@@ -0,0 +1,433 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
TextEditorHandler()
|
||||
: ComponentTypeHandler ("Text Editor", "juce::TextEditor", typeid (TextEditor), 150, 24)
|
||||
{
|
||||
registerColour (juce::TextEditor::textColourId, "text", "textcol");
|
||||
registerColour (juce::TextEditor::backgroundColourId, "background", "bkgcol");
|
||||
registerColour (juce::TextEditor::highlightColourId, "highlight", "hilitecol");
|
||||
registerColour (juce::TextEditor::outlineColourId, "outline", "outlinecol");
|
||||
registerColour (juce::TextEditor::shadowColourId, "shadow", "shadowcol");
|
||||
registerColour (juce::CaretComponent::caretColourId, "caret", "caretcol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new TextEditor ("new text editor");
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
TextEditor* te = (TextEditor*) comp;
|
||||
|
||||
e->setAttribute ("initialText", comp->getProperties() ["initialText"].toString());
|
||||
|
||||
e->setAttribute ("multiline", te->isMultiLine());
|
||||
e->setAttribute ("retKeyStartsLine", te->getReturnKeyStartsNewLine());
|
||||
e->setAttribute ("readonly", te->isReadOnly());
|
||||
e->setAttribute ("scrollbars", te->areScrollbarsShown());
|
||||
e->setAttribute ("caret", te->isCaretVisible());
|
||||
e->setAttribute ("popupmenu", te->isPopupMenuEnabled());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
TextEditor* te = (TextEditor*) comp;
|
||||
TextEditor defaultEditor;
|
||||
|
||||
te->setMultiLine (xml.getBoolAttribute ("multiline", defaultEditor.isMultiLine()));
|
||||
te->setReturnKeyStartsNewLine (xml.getBoolAttribute ("retKeyStartsLine", defaultEditor.getReturnKeyStartsNewLine()));
|
||||
te->setReadOnly (xml.getBoolAttribute ("readonly", defaultEditor.isReadOnly()));
|
||||
te->setScrollbarsShown (xml.getBoolAttribute ("scrollbars", defaultEditor.areScrollbarsShown()));
|
||||
te->setCaretVisible (xml.getBoolAttribute ("caret", defaultEditor.isCaretVisible()));
|
||||
te->setPopupMenuEnabled (xml.getBoolAttribute ("popupmenu", defaultEditor.isPopupMenuEnabled()));
|
||||
|
||||
const String initialText (xml.getStringAttribute ("initialText"));
|
||||
te->setText (initialText, false);
|
||||
te->getProperties().set ("initialText", initialText);
|
||||
return true;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* t = dynamic_cast<TextEditor*> (component))
|
||||
{
|
||||
props.add (new TextEditorInitialTextProperty (t, document));
|
||||
props.add (new TextEditorMultiLineProperty (t, document));
|
||||
props.add (new TextEditorReadOnlyProperty (t, document));
|
||||
props.add (new TextEditorScrollbarsProperty (t, document));
|
||||
props.add (new TextEditorCaretProperty (t, document));
|
||||
props.add (new TextEditorPopupMenuProperty (t, document));
|
||||
|
||||
addColourProperties (t, document, props);
|
||||
}
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* component) override
|
||||
{
|
||||
return quotedString (component->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
if (auto* te = dynamic_cast<TextEditor*> (component))
|
||||
{
|
||||
String s;
|
||||
s << memberVariableName << "->setMultiLine (" << CodeHelpers::boolLiteral (te->isMultiLine()) << ");\n"
|
||||
<< memberVariableName << "->setReturnKeyStartsNewLine (" << CodeHelpers::boolLiteral (te->getReturnKeyStartsNewLine()) << ");\n"
|
||||
<< memberVariableName << "->setReadOnly (" << CodeHelpers::boolLiteral (te->isReadOnly()) << ");\n"
|
||||
<< memberVariableName << "->setScrollbarsShown (" << CodeHelpers::boolLiteral (te->areScrollbarsShown()) << ");\n"
|
||||
<< memberVariableName << "->setCaretVisible (" << CodeHelpers::boolLiteral (te->isCaretVisible()) << ");\n"
|
||||
<< memberVariableName << "->setPopupMenuEnabled (" << CodeHelpers::boolLiteral (te->isPopupMenuEnabled()) << ");\n"
|
||||
<< getColourIntialisationCode (component, memberVariableName)
|
||||
<< memberVariableName << "->setText (" << quotedString (te->getProperties() ["initialText"].toString(), code.shouldUseTransMacro()) << ");\n\n";
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class TextEditorMultiLineProperty : public ComponentChoiceProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorMultiLineProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentChoiceProperty <TextEditor> ("mode", comp, doc)
|
||||
{
|
||||
choices.add ("single line");
|
||||
choices.add ("multi-line, return key starts new line");
|
||||
choices.add ("multi-line, return key disabled");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
document.perform (new TextEditorMultilineChangeAction (component, *document.getComponentLayout(), newIndex),
|
||||
"Change TextEditor multiline mode");
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return component->isMultiLine() ? (component->getReturnKeyStartsNewLine() ? 1 : 2) : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
class TextEditorMultilineChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorMultilineChangeAction (TextEditor* const comp, ComponentLayout& l, const int newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isMultiLine() ? (comp->getReturnKeyStartsNewLine() ? 1 : 2) : 0;
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setMultiLine (newState > 0);
|
||||
getComponent()->setReturnKeyStartsNewLine (newState == 1);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setMultiLine (oldState > 0);
|
||||
getComponent()->setReturnKeyStartsNewLine (oldState == 1);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorReadOnlyProperty : public ComponentBooleanProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorReadOnlyProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <TextEditor> ("editable", "Editable", "Editable", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new TextEditorReadonlyChangeAction (component, *document.getComponentLayout(), ! newState),
|
||||
"Change TextEditor read-only mode");
|
||||
}
|
||||
|
||||
bool getState() const { return ! component->isReadOnly(); }
|
||||
|
||||
private:
|
||||
class TextEditorReadonlyChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorReadonlyChangeAction (TextEditor* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isReadOnly();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setReadOnly (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setReadOnly (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorScrollbarsProperty : public ComponentBooleanProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorScrollbarsProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <TextEditor> ("scrollbars", "Scrollbars enabled", "Scrollbars enabled", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new TextEditorScrollbarChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change TextEditor scrollbars");
|
||||
}
|
||||
|
||||
bool getState() const { return component->areScrollbarsShown(); }
|
||||
|
||||
private:
|
||||
class TextEditorScrollbarChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorScrollbarChangeAction (TextEditor* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->areScrollbarsShown();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setScrollbarsShown (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setScrollbarsShown (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorCaretProperty : public ComponentBooleanProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorCaretProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <TextEditor> ("caret", "Caret visible", "Caret visible", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new TextEditorCaretChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change TextEditor caret");
|
||||
}
|
||||
|
||||
bool getState() const { return component->isCaretVisible(); }
|
||||
|
||||
private:
|
||||
class TextEditorCaretChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorCaretChangeAction (TextEditor* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isCaretVisible();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setCaretVisible (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setCaretVisible (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorPopupMenuProperty : public ComponentBooleanProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorPopupMenuProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <TextEditor> ("popup menu", "Popup menu enabled", "Popup menu enabled", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new TextEditorPopupMenuChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change TextEditor popup menu");
|
||||
}
|
||||
|
||||
bool getState() const { return component->isPopupMenuEnabled(); }
|
||||
|
||||
private:
|
||||
class TextEditorPopupMenuChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorPopupMenuChangeAction (TextEditor* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isPopupMenuEnabled();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setPopupMenuEnabled (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setPopupMenuEnabled (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextEditorInitialTextProperty : public ComponentTextProperty <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorInitialTextProperty (TextEditor* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <TextEditor> ("initial text", 10000, true, comp, doc)
|
||||
{}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new TextEditorInitialTextChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change TextEditor initial text");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return component->getProperties() ["initialText"];
|
||||
}
|
||||
|
||||
private:
|
||||
class TextEditorInitialTextChangeAction : public ComponentUndoableAction <TextEditor>
|
||||
{
|
||||
public:
|
||||
TextEditorInitialTextChangeAction (TextEditor* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <TextEditor> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getProperties() ["initialText"];
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (newState, false);
|
||||
getComponent()->getProperties().set ("initialText", newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setText (oldState, false);
|
||||
getComponent()->getProperties().set ("initialText", oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
146
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ToggleButtonHandler.h
vendored
Normal file
146
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ToggleButtonHandler.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ToggleButtonHandler : public ButtonHandler
|
||||
{
|
||||
public:
|
||||
ToggleButtonHandler()
|
||||
: ButtonHandler ("Toggle Button", "juce::ToggleButton", typeid (ToggleButton), 150, 24)
|
||||
{
|
||||
registerColour (juce::ToggleButton::textColourId, "text colour", "txtcol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new ToggleButton ("new toggle button");
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
if (auto* tb = dynamic_cast<ToggleButton*> (component))
|
||||
props.add (new ToggleButtonStateProperty (tb, document));
|
||||
|
||||
addColourProperties (component, document, props);
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
ToggleButton* tb = (ToggleButton*) comp;
|
||||
|
||||
XmlElement* e = ButtonHandler::createXmlFor (comp, layout);
|
||||
e->setAttribute ("state", tb->getToggleState());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
ToggleButton* const tb = (ToggleButton*) comp;
|
||||
|
||||
if (! ButtonHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
tb->setToggleState (xml.getBoolAttribute ("state", false), dontSendNotification);
|
||||
return true;
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
ButtonHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
ToggleButton* const tb = dynamic_cast<ToggleButton*> (component);
|
||||
|
||||
String s;
|
||||
|
||||
if (tb->getToggleState())
|
||||
s << memberVariableName << "->setToggleState (true, juce::dontSendNotification);\n";
|
||||
|
||||
s << getColourIntialisationCode (component, memberVariableName)
|
||||
<< '\n';
|
||||
|
||||
code.constructorCode += s;
|
||||
}
|
||||
|
||||
private:
|
||||
class ToggleButtonStateProperty : public ComponentBooleanProperty <ToggleButton>
|
||||
{
|
||||
public:
|
||||
ToggleButtonStateProperty (ToggleButton* button_, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <ToggleButton> ("initial state", "on", "off", button_, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new ToggleStateChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change ToggleButton state");
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return component->getToggleState();
|
||||
}
|
||||
|
||||
private:
|
||||
class ToggleStateChangeAction : public ComponentUndoableAction <ToggleButton>
|
||||
{
|
||||
public:
|
||||
ToggleStateChangeAction (ToggleButton* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <ToggleButton> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getToggleState();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setToggleState (newState, dontSendNotification);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setToggleState (oldState, dontSendNotification);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
265
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TreeViewHandler.h
vendored
Normal file
265
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_TreeViewHandler.h
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class TreeViewHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
TreeViewHandler()
|
||||
: ComponentTypeHandler ("TreeView", "juce::TreeView", typeid (DemoTreeView), 150, 150)
|
||||
{
|
||||
registerColour (juce::TreeView::backgroundColourId, "background", "backgroundColour");
|
||||
registerColour (juce::TreeView::linesColourId, "lines", "linecol");
|
||||
}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
return new DemoTreeView();
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
TreeView* const t = dynamic_cast<TreeView*> (comp);
|
||||
XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
|
||||
e->setAttribute ("rootVisible", t->isRootItemVisible());
|
||||
e->setAttribute ("openByDefault", t->areItemsOpenByDefault());
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
TreeView defaultTreeView;
|
||||
TreeView* const t = dynamic_cast<TreeView*> (comp);
|
||||
|
||||
t->setRootItemVisible (xml.getBoolAttribute ("rootVisible", defaultTreeView.isRootItemVisible()));
|
||||
t->setDefaultOpenness (xml.getBoolAttribute ("openByDefault", defaultTreeView.areItemsOpenByDefault()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
auto* t = dynamic_cast<TreeView*> (component);
|
||||
|
||||
props.add (new TreeViewRootItemProperty (t, document));
|
||||
props.add (new TreeViewRootOpennessProperty (t, document));
|
||||
|
||||
addColourProperties (t, document, props);
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* comp) override
|
||||
{
|
||||
return quotedString (comp->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
TreeView defaultTreeView;
|
||||
TreeView* const t = dynamic_cast<TreeView*> (component);
|
||||
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
if (defaultTreeView.isRootItemVisible() != t->isRootItemVisible())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setRootItemVisible ("
|
||||
<< CodeHelpers::boolLiteral (t->isRootItemVisible()) << ");\n";
|
||||
}
|
||||
|
||||
if (defaultTreeView.areItemsOpenByDefault() != t->areItemsOpenByDefault())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setDefaultOpenness ("
|
||||
<< CodeHelpers::boolLiteral (t->areItemsOpenByDefault()) << ");\n";
|
||||
}
|
||||
|
||||
code.constructorCode << getColourIntialisationCode (component, memberVariableName);
|
||||
code.constructorCode << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class DemoTreeView : public TreeView
|
||||
{
|
||||
public:
|
||||
DemoTreeView()
|
||||
: TreeView ("new treeview")
|
||||
{
|
||||
setRootItem (new DemoTreeViewItem ("Demo root node", 4));
|
||||
}
|
||||
|
||||
~DemoTreeView()
|
||||
{
|
||||
deleteRootItem();
|
||||
}
|
||||
|
||||
private:
|
||||
class DemoTreeViewItem : public TreeViewItem
|
||||
{
|
||||
public:
|
||||
DemoTreeViewItem (const String& name_, const int numItems)
|
||||
: name (name_)
|
||||
{
|
||||
for (int i = 0; i < numItems; ++i)
|
||||
addSubItem (new DemoTreeViewItem ("Demo sub-node " + String (i), numItems - 1));
|
||||
}
|
||||
|
||||
void paintItem (Graphics& g, int width, int height) override
|
||||
{
|
||||
if (isSelected())
|
||||
g.fillAll (Colours::lightblue);
|
||||
|
||||
g.setColour (Colours::black);
|
||||
g.setFont ((float) height * 0.7f);
|
||||
g.drawText (name, 4, 0, width - 4, height, Justification::centredLeft, true);
|
||||
}
|
||||
|
||||
bool mightContainSubItems() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const String name;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreeViewRootItemProperty : public ComponentBooleanProperty <TreeView>
|
||||
{
|
||||
public:
|
||||
TreeViewRootItemProperty (TreeView* comp, JucerDocument& doc)
|
||||
: ComponentBooleanProperty <TreeView> ("show root item", "Root item visible", "Root item visible", comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new TreeviewRootChangeAction (component, *document.getComponentLayout(), newState),
|
||||
"Change TreeView root item");
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return component->isRootItemVisible();
|
||||
}
|
||||
|
||||
private:
|
||||
class TreeviewRootChangeAction : public ComponentUndoableAction <TreeView>
|
||||
{
|
||||
public:
|
||||
TreeviewRootChangeAction (TreeView* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TreeView> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->isRootItemVisible();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRootItemVisible (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setRootItemVisible (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TreeViewRootOpennessProperty : public ComponentChoiceProperty <TreeView>
|
||||
{
|
||||
public:
|
||||
TreeViewRootOpennessProperty (TreeView* comp, JucerDocument& doc)
|
||||
: ComponentChoiceProperty <TreeView> ("default openness", comp, doc)
|
||||
{
|
||||
choices.add ("Items open by default");
|
||||
choices.add ("Items closed by default");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
document.perform (new TreeviewOpennessChangeAction (component, *document.getComponentLayout(), newIndex == 0),
|
||||
"Change TreeView openness");
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return component->areItemsOpenByDefault() ? 0 : 1;
|
||||
}
|
||||
|
||||
private:
|
||||
class TreeviewOpennessChangeAction : public ComponentUndoableAction <TreeView>
|
||||
{
|
||||
public:
|
||||
TreeviewOpennessChangeAction (TreeView* const comp, ComponentLayout& l, const bool newState_)
|
||||
: ComponentUndoableAction <TreeView> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->areItemsOpenByDefault();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setDefaultOpenness (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setDefaultOpenness (oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool newState, oldState;
|
||||
};
|
||||
};
|
||||
};
|
||||
666
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ViewportHandler.h
vendored
Normal file
666
deps/juce/extras/Projucer/Source/ComponentEditor/Components/jucer_ViewportHandler.h
vendored
Normal file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ViewportHandler : public ComponentTypeHandler
|
||||
{
|
||||
public:
|
||||
ViewportHandler()
|
||||
: ComponentTypeHandler ("Viewport", "juce::Viewport", typeid (UpdatingViewport), 150, 150)
|
||||
{}
|
||||
|
||||
Component* createNewComponent (JucerDocument*) override
|
||||
{
|
||||
Viewport* const v = new UpdatingViewport ("new viewport");
|
||||
v->setViewedComponent (new ViewportDemoContentComp());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
Viewport* const v = dynamic_cast<Viewport*> (comp);
|
||||
XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
|
||||
|
||||
e->setAttribute ("vscroll", v->isVerticalScrollBarShown());
|
||||
e->setAttribute ("hscroll", v->isHorizontalScrollBarShown());
|
||||
e->setAttribute ("scrollbarThickness", v->getScrollBarThickness());
|
||||
|
||||
e->setAttribute ("contentType", getViewportContentType (v));
|
||||
e->setAttribute ("jucerFile", getViewportJucerComponentFile (v));
|
||||
e->setAttribute ("contentClass", getViewportGenericComponentClass (v));
|
||||
e->setAttribute ("constructorParams", getViewportConstructorParams (v));
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
|
||||
{
|
||||
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
|
||||
return false;
|
||||
|
||||
Viewport defaultViewport;
|
||||
Viewport* const v = dynamic_cast<Viewport*> (comp);
|
||||
v->setScrollBarsShown (xml.getBoolAttribute ("vscroll", defaultViewport.isVerticalScrollBarShown()),
|
||||
xml.getBoolAttribute ("hscroll", defaultViewport.isHorizontalScrollBarShown()));
|
||||
|
||||
v->setScrollBarThickness (xml.getIntAttribute ("scrollbarThickness", defaultViewport.getScrollBarThickness()));
|
||||
|
||||
setViewportJucerComponentFile (v, xml.getStringAttribute ("jucerFile", String()));
|
||||
setViewportGenericComponentClass (v, xml.getStringAttribute ("contentClass"));
|
||||
setViewportContentType (v, xml.getIntAttribute ("contentType", 0));
|
||||
setViewportConstructorParams (v, xml.getStringAttribute ("constructorParams"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void getEditableProperties (Component* component, JucerDocument& document,
|
||||
Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
auto* v = dynamic_cast<Viewport*> (component);
|
||||
|
||||
props.add (new ViewportScrollbarShownProperty (v, document, true));
|
||||
props.add (new ViewportScrollbarShownProperty (v, document, false));
|
||||
props.add (new ViewportScrollbarSizeProperty (v, document));
|
||||
props.add (new ViewportContentTypeProperty (v, document));
|
||||
|
||||
if (getViewportContentType (v) == 1)
|
||||
{
|
||||
props.add (new ViewportJucerFileProperty (v, document));
|
||||
props.add (new ConstructorParamsProperty (v, document));
|
||||
}
|
||||
else if (getViewportContentType (v) == 2)
|
||||
{
|
||||
props.add (new ViewportContentClassProperty (v, document));
|
||||
props.add (new ConstructorParamsProperty (v, document));
|
||||
}
|
||||
}
|
||||
|
||||
String getCreationParameters (GeneratedCode&, Component* comp) override
|
||||
{
|
||||
return quotedString (comp->getName(), false);
|
||||
}
|
||||
|
||||
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
|
||||
{
|
||||
Viewport defaultViewport;
|
||||
Viewport* const v = dynamic_cast<Viewport*> (component);
|
||||
|
||||
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
|
||||
|
||||
if (defaultViewport.isVerticalScrollBarShown() != v->isVerticalScrollBarShown()
|
||||
|| defaultViewport.isHorizontalScrollBarShown() != v->isHorizontalScrollBarShown())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setScrollBarsShown ("
|
||||
<< CodeHelpers::boolLiteral (v->isVerticalScrollBarShown()) << ", "
|
||||
<< CodeHelpers::boolLiteral (v->isHorizontalScrollBarShown()) << ");\n";
|
||||
}
|
||||
|
||||
if (defaultViewport.getScrollBarThickness() != v->getScrollBarThickness())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setScrollBarThickness ("
|
||||
<< v->getScrollBarThickness() << ");\n";
|
||||
}
|
||||
|
||||
if (getViewportContentType (v) != 0)
|
||||
{
|
||||
String classNm (getViewportGenericComponentClass (v));
|
||||
|
||||
if (getViewportContentType (v) == 1)
|
||||
{
|
||||
File file;
|
||||
|
||||
const String filename (getViewportJucerComponentFile (v));
|
||||
|
||||
if (filename.isNotEmpty())
|
||||
file = code.document->getCppFile().getSiblingFile (filename);
|
||||
|
||||
std::unique_ptr<JucerDocument> doc (JucerDocument::createForCppFile (nullptr, file));
|
||||
|
||||
if (doc != nullptr)
|
||||
{
|
||||
code.includeFilesCPP.add (File::createFileWithoutCheckingPath (doc->getHeaderFile()
|
||||
.getRelativePathFrom (code.document->getCppFile().getParentDirectory())
|
||||
.replaceCharacter ('\\', '/')));
|
||||
classNm = doc->getClassName();
|
||||
}
|
||||
else
|
||||
{
|
||||
classNm = String();
|
||||
}
|
||||
}
|
||||
|
||||
if (classNm.isNotEmpty())
|
||||
{
|
||||
code.constructorCode
|
||||
<< memberVariableName << "->setViewedComponent (new "
|
||||
<< classNm;
|
||||
|
||||
if (getViewportConstructorParams (v).trim().isNotEmpty())
|
||||
{
|
||||
code.constructorCode << " (" << getViewportConstructorParams (v).trim() << "));\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
code.constructorCode << "());\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code.constructorCode << "\n";
|
||||
}
|
||||
|
||||
static void updateViewportContentComp (Viewport* vp)
|
||||
{
|
||||
if (getViewportContentType (vp) == 1)
|
||||
{
|
||||
JucerDocument* doc = findParentDocument (vp);
|
||||
auto tc = new TestComponent (doc, nullptr, false);
|
||||
|
||||
tc->setFilename (getViewportJucerComponentFile (vp));
|
||||
tc->setToInitialSize();
|
||||
|
||||
vp->setViewedComponent (tc);
|
||||
}
|
||||
else
|
||||
{
|
||||
vp->setViewedComponent (new ViewportDemoContentComp());
|
||||
}
|
||||
}
|
||||
|
||||
static int getViewportContentType (Viewport* vp)
|
||||
{
|
||||
return vp->getProperties() ["contentType"];
|
||||
}
|
||||
|
||||
static void setViewportContentType (Viewport* vp, int newValue)
|
||||
{
|
||||
if (newValue != getViewportContentType (vp))
|
||||
{
|
||||
vp->getProperties().set ("contentType", newValue);
|
||||
updateViewportContentComp (vp);
|
||||
}
|
||||
}
|
||||
|
||||
static String getViewportJucerComponentFile (Viewport* vp)
|
||||
{
|
||||
return vp->getProperties() ["jucerFile"].toString();
|
||||
}
|
||||
|
||||
static void setViewportJucerComponentFile (Viewport* vp, const String& file)
|
||||
{
|
||||
if (file != getViewportJucerComponentFile (vp))
|
||||
{
|
||||
vp->getProperties().set ("jucerFile", file);
|
||||
updateViewportContentComp (vp);
|
||||
}
|
||||
}
|
||||
|
||||
static String getViewportGenericComponentClass (Viewport* vp)
|
||||
{
|
||||
return vp->getProperties() ["contentClass"].toString();
|
||||
}
|
||||
|
||||
static void setViewportGenericComponentClass (Viewport* vp, const String& name)
|
||||
{
|
||||
if (name != getViewportGenericComponentClass (vp))
|
||||
{
|
||||
vp->getProperties().set ("contentClass", name);
|
||||
updateViewportContentComp (vp);
|
||||
}
|
||||
}
|
||||
|
||||
static String getViewportConstructorParams (Viewport* vp)
|
||||
{
|
||||
return vp->getProperties() ["constructorParams"].toString();
|
||||
}
|
||||
|
||||
static void setViewportConstructorParams (Viewport* vp, const String& newParams)
|
||||
{
|
||||
if (newParams != getViewportConstructorParams (vp))
|
||||
{
|
||||
vp->getProperties().set ("constructorParams", newParams);
|
||||
updateViewportContentComp (vp);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class UpdatingViewport : public Viewport
|
||||
{
|
||||
public:
|
||||
UpdatingViewport (const String& name)
|
||||
: Viewport (name)
|
||||
{
|
||||
}
|
||||
|
||||
void parentHierarchyChanged()
|
||||
{
|
||||
Viewport::parentHierarchyChanged();
|
||||
updateViewportContentComp (this);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct ViewportDemoContentComp : public Component
|
||||
{
|
||||
ViewportDemoContentComp()
|
||||
{
|
||||
setSize (2048, 2048);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillCheckerBoard (getLocalBounds().toFloat(), 50.0f, 50.0f,
|
||||
Colours::lightgrey.withAlpha (0.5f),
|
||||
Colours::darkgrey.withAlpha (0.5f));
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ViewportScrollbarShownProperty : public ComponentBooleanProperty <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportScrollbarShownProperty (Viewport* comp, JucerDocument& doc, const bool vertical_)
|
||||
: ComponentBooleanProperty <Viewport> (vertical_ ? "V scrollbar" : "H scrollbar",
|
||||
"enabled", "enabled",
|
||||
comp, doc),
|
||||
vertical (vertical_)
|
||||
{
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.perform (new ViewportScrollbarChangeAction (component, *document.getComponentLayout(), vertical, newState),
|
||||
"Change Viewport scrollbar");
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return vertical ? component->isVerticalScrollBarShown()
|
||||
: component->isHorizontalScrollBarShown();
|
||||
}
|
||||
|
||||
const bool vertical;
|
||||
|
||||
private:
|
||||
class ViewportScrollbarChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportScrollbarChangeAction (Viewport* const comp, ComponentLayout& l, const bool vertical_, const bool newState_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
vertical (vertical_),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = vertical ? comp->isVerticalScrollBarShown()
|
||||
: comp->isHorizontalScrollBarShown();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
if (vertical)
|
||||
getComponent()->setScrollBarsShown (newState, getComponent()->isHorizontalScrollBarShown());
|
||||
else
|
||||
getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), newState);
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
if (vertical)
|
||||
getComponent()->setScrollBarsShown (oldState, getComponent()->isHorizontalScrollBarShown());
|
||||
else
|
||||
getComponent()->setScrollBarsShown (getComponent()->isVerticalScrollBarShown(), oldState);
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vertical, newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ViewportScrollbarSizeProperty : public SliderPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ViewportScrollbarSizeProperty (Viewport* comp, JucerDocument& doc)
|
||||
: SliderPropertyComponent ("scrollbar size", 3.0, 30.0, 1.0, 1.0),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ViewportScrollbarSizeProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
document.getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
document.perform (new ViewportScrollbarSizeChangeAction (component, *document.getComponentLayout(), roundToInt (newValue)),
|
||||
"Change Viewport scrollbar size");
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return component->getScrollBarThickness();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
Viewport* component;
|
||||
JucerDocument& document;
|
||||
|
||||
private:
|
||||
class ViewportScrollbarSizeChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportScrollbarSizeChangeAction (Viewport* const comp, ComponentLayout& l, const int newState_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = comp->getScrollBarThickness();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setScrollBarThickness (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getComponent()->setScrollBarThickness (newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ViewportContentTypeProperty : public ComponentChoiceProperty <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportContentTypeProperty (Viewport* comp, JucerDocument& doc)
|
||||
: ComponentChoiceProperty <Viewport> ("content", comp, doc)
|
||||
{
|
||||
choices.add ("No content component");
|
||||
choices.add ("Jucer content component");
|
||||
choices.add ("Named content component");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
document.perform (new ViewportContentTypeChangeAction (component, *document.getComponentLayout(), newIndex),
|
||||
"Change Viewport content type");
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return getViewportContentType (component);
|
||||
}
|
||||
|
||||
private:
|
||||
class ViewportContentTypeChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportContentTypeChangeAction (Viewport* const comp, ComponentLayout& l, const int newValue_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
newValue (newValue_)
|
||||
{
|
||||
oldValue = getViewportContentType (comp);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportContentType (getComponent(), newValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportContentType (getComponent(), oldValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
int newValue, oldValue;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ViewportJucerFileProperty : public FilePropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ViewportJucerFileProperty (Viewport* const comp, JucerDocument& doc)
|
||||
: FilePropertyComponent ("Jucer file", false, true),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ViewportJucerFileProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setFile (const File& newFile) override
|
||||
{
|
||||
document.perform (new JucerCompFileChangeAction (component, *document.getComponentLayout(),
|
||||
newFile.getRelativePathFrom (document.getCppFile().getParentDirectory())
|
||||
.replaceCharacter ('\\', '/')),
|
||||
"Change Projucer component file");
|
||||
}
|
||||
|
||||
File getFile() const override
|
||||
{
|
||||
auto filename = getViewportJucerComponentFile (component);
|
||||
|
||||
if (filename.isEmpty())
|
||||
return {};
|
||||
|
||||
return document.getCppFile().getSiblingFile (filename);
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
Viewport* const component;
|
||||
JucerDocument& document;
|
||||
|
||||
class JucerCompFileChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
JucerCompFileChangeAction (Viewport* const comp, ComponentLayout& l, const String& newState_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = getViewportJucerComponentFile (comp);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportJucerComponentFile (getComponent(), newState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportJucerComponentFile (getComponent(), oldState);
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newState, oldState;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ViewportContentClassProperty : public ComponentTextProperty <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportContentClassProperty (Viewport* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Viewport> ("content class", 256, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ViewportClassNameChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change Viewport content class");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return getViewportGenericComponentClass (component);
|
||||
}
|
||||
|
||||
private:
|
||||
class ViewportClassNameChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
ViewportClassNameChangeAction (Viewport* const comp, ComponentLayout& l, const String& newValue_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
newValue (newValue_)
|
||||
{
|
||||
oldValue = getViewportGenericComponentClass (comp);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportGenericComponentClass (getComponent(), newValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportGenericComponentClass (getComponent(), oldValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newValue, oldValue;
|
||||
};
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ConstructorParamsProperty : public ComponentTextProperty <Viewport>
|
||||
{
|
||||
public:
|
||||
ConstructorParamsProperty (Viewport* comp, JucerDocument& doc)
|
||||
: ComponentTextProperty <Viewport> ("constructor params", 512, false, comp, doc)
|
||||
{
|
||||
}
|
||||
|
||||
void setText (const String& newText) override
|
||||
{
|
||||
document.perform (new ConstructorParamChangeAction (component, *document.getComponentLayout(), newText),
|
||||
"Change Viewport content constructor params");
|
||||
}
|
||||
|
||||
String getText() const override
|
||||
{
|
||||
return getViewportConstructorParams (component);
|
||||
}
|
||||
|
||||
private:
|
||||
class ConstructorParamChangeAction : public ComponentUndoableAction <Viewport>
|
||||
{
|
||||
public:
|
||||
ConstructorParamChangeAction (Viewport* const comp, ComponentLayout& l, const String& newValue_)
|
||||
: ComponentUndoableAction <Viewport> (comp, l),
|
||||
newValue (newValue_)
|
||||
{
|
||||
oldValue = getViewportConstructorParams (comp);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportConstructorParams (getComponent(), newValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
setViewportConstructorParams (getComponent(), oldValue);
|
||||
changed();
|
||||
layout.getDocument()->refreshAllPropertyComps();
|
||||
return true;
|
||||
}
|
||||
|
||||
String newValue, oldValue;
|
||||
};
|
||||
};
|
||||
};
|
||||
411
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ButtonDocument.cpp
vendored
Normal file
411
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ButtonDocument.cpp
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ButtonDocument.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
|
||||
//==============================================================================
|
||||
static const int normalOff = 0;
|
||||
static const int overOff = 1;
|
||||
static const int downOff = 2;
|
||||
static const int normalOn = 3;
|
||||
static const int overOn = 4;
|
||||
static const int downOn = 5;
|
||||
static const int background = 6;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
ButtonDocument::ButtonDocument (SourceCodeDocument* c)
|
||||
: JucerDocument (c)
|
||||
{
|
||||
paintStatesEnabled [normalOff] = true;
|
||||
paintStatesEnabled [overOff] = true;
|
||||
paintStatesEnabled [downOff] = true;
|
||||
paintStatesEnabled [normalOn] = false;
|
||||
paintStatesEnabled [overOn] = false;
|
||||
paintStatesEnabled [downOn] = false;
|
||||
paintStatesEnabled [background] = false;
|
||||
|
||||
parentClasses = "public juce::Button";
|
||||
|
||||
for (int i = 7; --i >= 0;)
|
||||
{
|
||||
paintRoutines[i].reset (new PaintRoutine());
|
||||
paintRoutines[i]->setDocument (this);
|
||||
paintRoutines[i]->setBackgroundColour (Colours::transparentBlack);
|
||||
}
|
||||
}
|
||||
|
||||
ButtonDocument::~ButtonDocument()
|
||||
{
|
||||
}
|
||||
|
||||
static const char* const stateNames[] =
|
||||
{
|
||||
"normal", "over", "down",
|
||||
"normal on", "over on", "down on",
|
||||
"common background"
|
||||
};
|
||||
|
||||
static int stateNameToIndex (const String& name)
|
||||
{
|
||||
for (int i = 7; --i >= 0;)
|
||||
if (name.equalsIgnoreCase (stateNames[i]))
|
||||
return i;
|
||||
|
||||
jassertfalse;
|
||||
return normalOff;
|
||||
}
|
||||
|
||||
|
||||
int ButtonDocument::getNumPaintRoutines() const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (int i = 7; --i >= 0;)
|
||||
if (paintStatesEnabled [i])
|
||||
++n;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
StringArray ButtonDocument::getPaintRoutineNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
if (paintStatesEnabled [i])
|
||||
s.add (stateNames [i]);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
PaintRoutine* ButtonDocument::getPaintRoutine (const int index) const
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
if (paintStatesEnabled [i])
|
||||
{
|
||||
if (index == n)
|
||||
return paintRoutines[i].get();
|
||||
|
||||
++n;
|
||||
}
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}
|
||||
|
||||
void ButtonDocument::setStatePaintRoutineEnabled (const int index, bool b)
|
||||
{
|
||||
jassert (index > 0 && index < 7);
|
||||
|
||||
if (paintStatesEnabled [index] != b)
|
||||
{
|
||||
paintStatesEnabled [index] = b;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
bool ButtonDocument::isStatePaintRoutineEnabled (const int index) const
|
||||
{
|
||||
return paintStatesEnabled [index];
|
||||
}
|
||||
|
||||
int ButtonDocument::chooseBestEnabledPaintRoutine (int paintRoutineWanted) const
|
||||
{
|
||||
switch (paintRoutineWanted)
|
||||
{
|
||||
case normalOff: return normalOff;
|
||||
case overOff: return paintStatesEnabled [overOff] ? overOff : normalOff;
|
||||
case downOff: return paintStatesEnabled [downOff] ? downOff : chooseBestEnabledPaintRoutine (overOff);
|
||||
case normalOn: return paintStatesEnabled [normalOn] ? normalOn : normalOff;
|
||||
case overOn: return paintStatesEnabled [overOn] ? overOn : (paintStatesEnabled [normalOn] ? normalOn : chooseBestEnabledPaintRoutine (overOff));
|
||||
case downOn: return paintStatesEnabled [downOn] ? downOn : ((paintStatesEnabled [overOn] || paintStatesEnabled [normalOn])
|
||||
? chooseBestEnabledPaintRoutine (overOn)
|
||||
: chooseBestEnabledPaintRoutine (downOff));
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return normalOff;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String ButtonDocument::getTypeName() const
|
||||
{
|
||||
return "Button";
|
||||
}
|
||||
|
||||
JucerDocument* ButtonDocument::createCopy()
|
||||
{
|
||||
auto newOne = new ButtonDocument (cpp);
|
||||
newOne->resources = resources;
|
||||
newOne->loadFromXml (*createXml());
|
||||
return newOne;
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> ButtonDocument::createXml() const
|
||||
{
|
||||
auto doc = JucerDocument::createXml();
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
auto e = paintRoutines[i]->createXml();
|
||||
e->setAttribute ("buttonState", stateNames [i]);
|
||||
e->setAttribute ("enabled", paintStatesEnabled [i]);
|
||||
|
||||
doc->addChildElement (e);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
bool ButtonDocument::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (JucerDocument::loadFromXml (xml))
|
||||
{
|
||||
for (int i = 7; --i >= 0;)
|
||||
paintStatesEnabled [i] = false;
|
||||
|
||||
for (auto* e : xml.getChildWithTagNameIterator (PaintRoutine::xmlTagName))
|
||||
{
|
||||
const int stateIndex = stateNameToIndex (e->getStringAttribute ("buttonState"));
|
||||
|
||||
paintRoutines [stateIndex]->loadFromXml (*e);
|
||||
paintStatesEnabled [stateIndex] = e->getBoolAttribute ("enabled", stateIndex < normalOn);
|
||||
}
|
||||
|
||||
changed();
|
||||
getUndoManager().clearUndoHistory();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ButtonDocument::getOptionalMethods (StringArray& baseClasses,
|
||||
StringArray& returnValues,
|
||||
StringArray& methods,
|
||||
StringArray& initialContents) const
|
||||
{
|
||||
JucerDocument::getOptionalMethods (baseClasses, returnValues, methods, initialContents);
|
||||
|
||||
addMethod ("juce::Button", "void", "clicked()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Button", "void", "buttonStateChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ButtonStatePaintEnabledProperty : public BooleanPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ButtonStatePaintEnabledProperty (const String& name, ButtonDocument& doc, const int stateMethod_)
|
||||
: BooleanPropertyComponent (name, "enabled", "disabled"),
|
||||
document (doc),
|
||||
stateMethod (stateMethod_)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ButtonStatePaintEnabledProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setState (bool newState)
|
||||
{
|
||||
document.setStatePaintRoutineEnabled (stateMethod, newState);
|
||||
}
|
||||
|
||||
bool getState() const
|
||||
{
|
||||
return document.isStatePaintRoutineEnabled (stateMethod);
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
ButtonDocument& document;
|
||||
const int stateMethod;
|
||||
};
|
||||
|
||||
void ButtonDocument::addExtraClassProperties (PropertyPanel& panel)
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
|
||||
for (int i = 1; i < 7; ++i)
|
||||
props.add (new ButtonStatePaintEnabledProperty (stateNames[i], *this, i));
|
||||
|
||||
panel.addSection ("Button paint routines", props);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ButtonTestComponent : public Button
|
||||
{
|
||||
public:
|
||||
ButtonTestComponent (ButtonDocument* const doc, const bool fillBackground)
|
||||
: Button (String()),
|
||||
document (doc),
|
||||
alwaysFillBackground (fillBackground)
|
||||
{
|
||||
setClickingTogglesState (true);
|
||||
}
|
||||
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
|
||||
{
|
||||
if (document->paintStatesEnabled [background])
|
||||
{
|
||||
document->paintRoutines [background]->fillWithBackground (g, alwaysFillBackground);
|
||||
document->paintRoutines [background]->drawElements (g, getLocalBounds());
|
||||
}
|
||||
|
||||
const int stateIndex
|
||||
= getToggleState()
|
||||
? (isButtonDown ? document->chooseBestEnabledPaintRoutine (downOn)
|
||||
: (isMouseOverButton ? document->chooseBestEnabledPaintRoutine (overOn)
|
||||
: document->chooseBestEnabledPaintRoutine (normalOn)))
|
||||
: (isButtonDown ? document->chooseBestEnabledPaintRoutine (downOff)
|
||||
: (isMouseOverButton ? document->chooseBestEnabledPaintRoutine (overOff)
|
||||
: normalOff));
|
||||
|
||||
document->paintRoutines [stateIndex]->fillWithBackground (g, ! document->paintStatesEnabled [background]);
|
||||
document->paintRoutines [stateIndex]->drawElements (g, getLocalBounds());
|
||||
}
|
||||
|
||||
private:
|
||||
ButtonDocument* const document;
|
||||
const bool alwaysFillBackground;
|
||||
};
|
||||
|
||||
Component* ButtonDocument::createTestComponent (const bool alwaysFillBackground)
|
||||
{
|
||||
return new ButtonTestComponent (this, alwaysFillBackground);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ButtonDocument::fillInGeneratedCode (GeneratedCode& code) const
|
||||
{
|
||||
JucerDocument::fillInGeneratedCode (code);
|
||||
|
||||
code.parentClassInitialiser = "Button (" + quotedString (code.componentName, false) + ")";
|
||||
code.removeCallback ("void", "paint (Graphics& g)");
|
||||
}
|
||||
|
||||
void ButtonDocument::fillInPaintCode (GeneratedCode& code) const
|
||||
{
|
||||
jassert (paintStatesEnabled [normalOff]);
|
||||
String paintCode [7];
|
||||
|
||||
for (int i = 0; i < 7; ++i)
|
||||
if (paintStatesEnabled [i])
|
||||
paintRoutines[i]->fillInGeneratedCode (code, paintCode [i]);
|
||||
|
||||
String& s = code.getCallbackCode ("public juce::Button",
|
||||
"void",
|
||||
"paintButton (juce::Graphics& g, bool isMouseOverButton, bool isButtonDown)",
|
||||
false);
|
||||
|
||||
int numPaintRoutines = getNumPaintRoutines();
|
||||
|
||||
if (paintStatesEnabled [background])
|
||||
{
|
||||
s << paintCode [background] << "\n";
|
||||
--numPaintRoutines;
|
||||
}
|
||||
|
||||
if (numPaintRoutines == 1)
|
||||
{
|
||||
s << paintCode [normalOff];
|
||||
}
|
||||
else if (numPaintRoutines == downOff && (paintStatesEnabled [overOff] || paintStatesEnabled [downOff] || paintStatesEnabled [normalOn]))
|
||||
{
|
||||
if (paintStatesEnabled [normalOn])
|
||||
{
|
||||
s << "if (getToggleState())\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [normalOn], 4, false).trimEnd();
|
||||
}
|
||||
else if (paintStatesEnabled [overOff])
|
||||
{
|
||||
s << "if (isButtonDown || isMouseOverButton)\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [overOff], 4, false).trimEnd();
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "if (isButtonDown)\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [downOff], 4, false).trimEnd();
|
||||
}
|
||||
|
||||
s << "\n}\nelse\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [normalOff], 4, false).trimEnd()
|
||||
<< "\n}\n";
|
||||
}
|
||||
else if (numPaintRoutines == normalOn && paintStatesEnabled [overOff] && paintStatesEnabled [downOff])
|
||||
{
|
||||
s << "if (isButtonDown)\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [downOff], 4, false).trimEnd()
|
||||
<< "\n}\nelse if (isMouseOverButton)\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [overOff], 4, false).trimEnd()
|
||||
<< "\n}\nelse\n{\n "
|
||||
<< CodeHelpers::indent (paintCode [normalOff], 4, false).trimEnd()
|
||||
<< "\n}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (paintStatesEnabled [normalOn] || paintStatesEnabled [overOn] || paintStatesEnabled [downOn])
|
||||
{
|
||||
s << "switch (getToggleState() ? (isButtonDown ? "
|
||||
<< chooseBestEnabledPaintRoutine (downOn) << " : (isMouseOverButton ? "
|
||||
<< chooseBestEnabledPaintRoutine (overOn) << " : "
|
||||
<< chooseBestEnabledPaintRoutine (normalOn) << "))\n : (isButtonDown ? "
|
||||
<< chooseBestEnabledPaintRoutine (downOff) << " : (isMouseOverButton ? "
|
||||
<< chooseBestEnabledPaintRoutine (overOff) << " : 0)))\n{\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "switch (isButtonDown ? " << chooseBestEnabledPaintRoutine (downOff)
|
||||
<< " : (isMouseOverButton ? " << chooseBestEnabledPaintRoutine (overOff)
|
||||
<< " : 0))\n{\n";
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
if (paintStatesEnabled [i])
|
||||
{
|
||||
s << "case " << i << ":\n {\n "
|
||||
<< CodeHelpers::indent (paintCode [i], 8, false).trimEnd()
|
||||
<< "\n break;\n }\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
s << "default:\n break;\n}\n";
|
||||
}
|
||||
}
|
||||
71
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ButtonDocument.h
vendored
Normal file
71
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ButtonDocument.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class ButtonDocument : public JucerDocument
|
||||
{
|
||||
public:
|
||||
ButtonDocument (SourceCodeDocument* cpp);
|
||||
~ButtonDocument();
|
||||
|
||||
//==============================================================================
|
||||
String getTypeName() const;
|
||||
|
||||
JucerDocument* createCopy();
|
||||
Component* createTestComponent (const bool alwaysFillBackground);
|
||||
|
||||
int getNumPaintRoutines() const;
|
||||
StringArray getPaintRoutineNames() const;
|
||||
PaintRoutine* getPaintRoutine (const int index) const;
|
||||
|
||||
void setStatePaintRoutineEnabled (const int index, bool b);
|
||||
bool isStatePaintRoutineEnabled (const int index) const;
|
||||
|
||||
int chooseBestEnabledPaintRoutine (int paintRoutineWanted) const;
|
||||
|
||||
ComponentLayout* getComponentLayout() const { return nullptr; }
|
||||
|
||||
void addExtraClassProperties (PropertyPanel&);
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<XmlElement> createXml() const;
|
||||
bool loadFromXml (const XmlElement&);
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code) const;
|
||||
void fillInPaintCode (GeneratedCode& code) const;
|
||||
|
||||
void getOptionalMethods (StringArray& baseClasses,
|
||||
StringArray& returnValues,
|
||||
StringArray& methods,
|
||||
StringArray& initialContents) const;
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<PaintRoutine> paintRoutines[7];
|
||||
bool paintStatesEnabled [7];
|
||||
};
|
||||
170
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ComponentDocument.cpp
vendored
Normal file
170
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ComponentDocument.cpp
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ComponentDocument.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
ComponentDocument::ComponentDocument (SourceCodeDocument* c)
|
||||
: JucerDocument (c)
|
||||
{
|
||||
components.reset (new ComponentLayout());
|
||||
components->setDocument (this);
|
||||
|
||||
backgroundGraphics.reset (new PaintRoutine());
|
||||
backgroundGraphics->setDocument (this);
|
||||
}
|
||||
|
||||
ComponentDocument::~ComponentDocument()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String ComponentDocument::getTypeName() const
|
||||
{
|
||||
return "Component";
|
||||
}
|
||||
|
||||
JucerDocument* ComponentDocument::createCopy()
|
||||
{
|
||||
auto newOne = new ComponentDocument (cpp);
|
||||
|
||||
newOne->resources = resources;
|
||||
newOne->loadFromXml (*createXml());
|
||||
|
||||
return newOne;
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> ComponentDocument::createXml() const
|
||||
{
|
||||
auto doc = JucerDocument::createXml();
|
||||
|
||||
doc->addChildElement (backgroundGraphics->createXml());
|
||||
components->addToXml (*doc);
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
bool ComponentDocument::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (JucerDocument::loadFromXml (xml))
|
||||
{
|
||||
components->clearComponents();
|
||||
|
||||
for (auto* e : xml.getChildIterator())
|
||||
{
|
||||
if (e->hasTagName (PaintRoutine::xmlTagName))
|
||||
backgroundGraphics->loadFromXml (*e);
|
||||
else
|
||||
components->addComponentFromXml (*e, false);
|
||||
}
|
||||
|
||||
changed();
|
||||
getUndoManager().clearUndoHistory();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ComponentDocument::applyCustomPaintSnippets (StringArray& snippets)
|
||||
{
|
||||
backgroundGraphics->applyCustomPaintSnippets (snippets);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class NormalTestComponent : public Component
|
||||
{
|
||||
public:
|
||||
NormalTestComponent (ComponentDocument* const doc, const bool fillBackground)
|
||||
: document (doc),
|
||||
alwaysFillBackground (fillBackground)
|
||||
{
|
||||
ComponentLayout* const layout = document->getComponentLayout();
|
||||
|
||||
for (int i = 0; i < layout->getNumComponents(); ++i)
|
||||
addAndMakeVisible (layout->getComponent (i));
|
||||
}
|
||||
|
||||
~NormalTestComponent() override
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
removeChildComponent (i);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
document->getPaintRoutine (0)->fillWithBackground (g, alwaysFillBackground);
|
||||
document->getPaintRoutine (0)->drawElements (g, getLocalBounds());
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (! getBounds().isEmpty())
|
||||
{
|
||||
int numTimesToTry = 10;
|
||||
|
||||
while (--numTimesToTry >= 0)
|
||||
{
|
||||
bool anyCompsMoved = false;
|
||||
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
Component* comp = getChildComponent (i);
|
||||
|
||||
if (ComponentTypeHandler* const type = ComponentTypeHandler::getHandlerFor (*comp))
|
||||
{
|
||||
const Rectangle<int> newBounds (type->getComponentPosition (comp)
|
||||
.getRectangle (getLocalBounds(),
|
||||
document->getComponentLayout()));
|
||||
|
||||
anyCompsMoved = anyCompsMoved || (comp->getBounds() != newBounds);
|
||||
comp->setBounds (newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
// repeat this loop until they've all stopped shuffling (might require a few
|
||||
// loops for all the relative positioned comps to settle down)
|
||||
if (! anyCompsMoved)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ComponentDocument* const document;
|
||||
const bool alwaysFillBackground;
|
||||
};
|
||||
|
||||
Component* ComponentDocument::createTestComponent (const bool alwaysFillBackground)
|
||||
{
|
||||
return new NormalTestComponent (this, alwaysFillBackground);
|
||||
}
|
||||
|
||||
void ComponentDocument::fillInGeneratedCode (GeneratedCode& code) const
|
||||
{
|
||||
JucerDocument::fillInGeneratedCode (code);
|
||||
}
|
||||
59
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ComponentDocument.h
vendored
Normal file
59
deps/juce/extras/Projucer/Source/ComponentEditor/Documents/jucer_ComponentDocument.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentDocument : public JucerDocument
|
||||
{
|
||||
public:
|
||||
ComponentDocument (SourceCodeDocument* cpp);
|
||||
~ComponentDocument();
|
||||
|
||||
//==============================================================================
|
||||
String getTypeName() const;
|
||||
|
||||
JucerDocument* createCopy();
|
||||
Component* createTestComponent (const bool alwaysFillBackground);
|
||||
|
||||
int getNumPaintRoutines() const { return 1; }
|
||||
StringArray getPaintRoutineNames() const { return StringArray ("Graphics"); }
|
||||
PaintRoutine* getPaintRoutine (const int index) const { return index == 0 ? backgroundGraphics.get() : nullptr; }
|
||||
|
||||
ComponentLayout* getComponentLayout() const { return components.get(); }
|
||||
|
||||
//==============================================================================
|
||||
std::unique_ptr<XmlElement> createXml() const;
|
||||
bool loadFromXml (const XmlElement& xml);
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code) const;
|
||||
void applyCustomPaintSnippets (StringArray&);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ComponentLayout> components;
|
||||
std::unique_ptr<PaintRoutine> backgroundGraphics;
|
||||
};
|
||||
936
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ColouredElement.cpp
vendored
Normal file
936
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ColouredElement.cpp
vendored
Normal file
@@ -0,0 +1,936 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ColouredElement.h"
|
||||
#include "jucer_GradientPointComponent.h"
|
||||
#include "../Properties/jucer_PositionPropertyBase.h"
|
||||
#include "../Properties/jucer_ColourPropertyComponent.h"
|
||||
#include "jucer_PaintElementUndoableAction.h"
|
||||
#include "jucer_PaintElementPath.h"
|
||||
#include "jucer_ImageResourceProperty.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ElementFillModeProperty : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
ElementFillModeProperty (ColouredElement* const e, const bool isForStroke_)
|
||||
: ChoicePropertyComponent ("fill mode"), listener (e),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
|
||||
choices.add ("Solid Colour");
|
||||
choices.add ("Linear Gradient");
|
||||
choices.add ("Radial Gradient");
|
||||
choices.add ("Image Brush");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
JucerFillType fill (isForStroke ? listener.owner->getStrokeType().fill
|
||||
: listener.owner->getFillType());
|
||||
|
||||
switch (newIndex)
|
||||
{
|
||||
case 0: fill.mode = JucerFillType::solidColour; break;
|
||||
case 1: fill.mode = JucerFillType::linearGradient; break;
|
||||
case 2: fill.mode = JucerFillType::radialGradient; break;
|
||||
case 3: fill.mode = JucerFillType::imageBrush; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (! isForStroke)
|
||||
listener.owner->setFillType (fill, true);
|
||||
else
|
||||
listener.owner->setStrokeFill (fill, true);
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
switch (isForStroke ? listener.owner->getStrokeType().fill.mode
|
||||
: listener.owner->getFillType().mode)
|
||||
{
|
||||
case JucerFillType::solidColour: return 0;
|
||||
case JucerFillType::linearGradient: return 1;
|
||||
case JucerFillType::radialGradient: return 2;
|
||||
case JucerFillType::imageBrush: return 3;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<ColouredElement> listener;
|
||||
const bool isForStroke;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ElementFillColourProperty : public JucerColourPropertyComponent
|
||||
{
|
||||
public:
|
||||
enum ColourType
|
||||
{
|
||||
solidColour,
|
||||
gradientColour1,
|
||||
gradientColour2
|
||||
};
|
||||
|
||||
ElementFillColourProperty (const String& name,
|
||||
ColouredElement* const owner_,
|
||||
const ColourType type_,
|
||||
const bool isForStroke_)
|
||||
: JucerColourPropertyComponent (name, false),
|
||||
listener (owner_),
|
||||
type (type_),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setColour (Colour newColour) override
|
||||
{
|
||||
listener.owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
JucerFillType fill (isForStroke ? listener.owner->getStrokeType().fill
|
||||
: listener.owner->getFillType());
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case solidColour: fill.colour = newColour; break;
|
||||
case gradientColour1: fill.gradCol1 = newColour; break;
|
||||
case gradientColour2: fill.gradCol2 = newColour; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (! isForStroke)
|
||||
listener.owner->setFillType (fill, true);
|
||||
else
|
||||
listener.owner->setStrokeFill (fill, true);
|
||||
}
|
||||
|
||||
Colour getColour() const override
|
||||
{
|
||||
const JucerFillType fill (isForStroke ? listener.owner->getStrokeType().fill
|
||||
: listener.owner->getFillType());
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case solidColour: return fill.colour; break;
|
||||
case gradientColour1: return fill.gradCol1; break;
|
||||
case gradientColour2: return fill.gradCol2; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return Colours::black;
|
||||
}
|
||||
|
||||
void resetToDefault() override
|
||||
{
|
||||
jassertfalse; // option shouldn't be visible
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<ColouredElement> listener;
|
||||
const ColourType type;
|
||||
const bool isForStroke;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ElementFillPositionProperty : public PositionPropertyBase
|
||||
{
|
||||
public:
|
||||
ElementFillPositionProperty (ColouredElement* const owner_,
|
||||
const String& name,
|
||||
ComponentPositionDimension dimension_,
|
||||
const bool isStart_,
|
||||
const bool isForStroke_)
|
||||
: PositionPropertyBase (owner_, name, dimension_, false, false,
|
||||
owner_->getDocument()->getComponentLayout()),
|
||||
listener (owner_),
|
||||
isStart (isStart_),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setPosition (const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
JucerFillType fill (isForStroke ? listener.owner->getStrokeType().fill
|
||||
: listener.owner->getFillType());
|
||||
|
||||
if (isStart)
|
||||
fill.gradPos1 = newPos;
|
||||
else
|
||||
fill.gradPos2 = newPos;
|
||||
|
||||
if (! isForStroke)
|
||||
listener.owner->setFillType (fill, true);
|
||||
else
|
||||
listener.owner->setStrokeFill (fill, true);
|
||||
}
|
||||
|
||||
RelativePositionedRectangle getPosition() const
|
||||
{
|
||||
const JucerFillType fill (isForStroke ? listener.owner->getStrokeType().fill
|
||||
: listener.owner->getFillType());
|
||||
|
||||
return isStart ? fill.gradPos1
|
||||
: fill.gradPos2;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<ColouredElement> listener;
|
||||
const bool isStart, isForStroke;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class EnableStrokeProperty : public BooleanPropertyComponent
|
||||
{
|
||||
public:
|
||||
explicit EnableStrokeProperty (ColouredElement* const owner_)
|
||||
: BooleanPropertyComponent ("outline", "Outline enabled", "No outline"),
|
||||
listener (owner_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setState (bool newState) { listener.owner->enableStroke (newState, true); }
|
||||
bool getState() const { return listener.owner->isStrokeEnabled(); }
|
||||
|
||||
ElementListener<ColouredElement> listener;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class StrokeThicknessProperty : public SliderPropertyComponent
|
||||
{
|
||||
public:
|
||||
explicit StrokeThicknessProperty (ColouredElement* const owner_)
|
||||
: SliderPropertyComponent ("outline thickness", 0.1, 200.0, 0.1, 0.3),
|
||||
listener (owner_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setValue (double newValue)
|
||||
{
|
||||
listener.owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
listener.owner->setStrokeType (PathStrokeType ((float) newValue,
|
||||
listener.owner->getStrokeType().stroke.getJointStyle(),
|
||||
listener.owner->getStrokeType().stroke.getEndStyle()),
|
||||
true);
|
||||
}
|
||||
|
||||
double getValue() const { return listener.owner->getStrokeType().stroke.getStrokeThickness(); }
|
||||
|
||||
ElementListener<ColouredElement> listener;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class StrokeJointProperty : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
explicit StrokeJointProperty (ColouredElement* const owner_)
|
||||
: ChoicePropertyComponent ("joint style"),
|
||||
listener (owner_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
|
||||
choices.add ("mitered");
|
||||
choices.add ("curved");
|
||||
choices.add ("beveled");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
const PathStrokeType::JointStyle joints[] = { PathStrokeType::mitered,
|
||||
PathStrokeType::curved,
|
||||
PathStrokeType::beveled };
|
||||
|
||||
if (! isPositiveAndBelow (newIndex, numElementsInArray (joints)))
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
listener.owner->setStrokeType (PathStrokeType (listener.owner->getStrokeType().stroke.getStrokeThickness(),
|
||||
joints [newIndex],
|
||||
listener.owner->getStrokeType().stroke.getEndStyle()),
|
||||
true);
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
switch (listener.owner->getStrokeType().stroke.getJointStyle())
|
||||
{
|
||||
case PathStrokeType::mitered: return 0;
|
||||
case PathStrokeType::curved: return 1;
|
||||
case PathStrokeType::beveled: return 2;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElementListener<ColouredElement> listener;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class StrokeEndCapProperty : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
explicit StrokeEndCapProperty (ColouredElement* const owner_)
|
||||
: ChoicePropertyComponent ("end-cap style"),
|
||||
listener (owner_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
|
||||
choices.add ("butt");
|
||||
choices.add ("square");
|
||||
choices.add ("round");
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
const PathStrokeType::EndCapStyle ends[] = { PathStrokeType::butt,
|
||||
PathStrokeType::square,
|
||||
PathStrokeType::rounded };
|
||||
|
||||
if (! isPositiveAndBelow (newIndex, numElementsInArray (ends)))
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
listener.owner->setStrokeType (PathStrokeType (listener.owner->getStrokeType().stroke.getStrokeThickness(),
|
||||
listener.owner->getStrokeType().stroke.getJointStyle(),
|
||||
ends [newIndex]),
|
||||
true);
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
switch (listener.owner->getStrokeType().stroke.getEndStyle())
|
||||
{
|
||||
case PathStrokeType::butt: return 0;
|
||||
case PathStrokeType::square: return 1;
|
||||
case PathStrokeType::rounded: return 2;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElementListener<ColouredElement> listener;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ImageBrushResourceProperty : public ImageResourceProperty <ColouredElement>
|
||||
{
|
||||
public:
|
||||
ImageBrushResourceProperty (ColouredElement* const e, const bool isForStroke_)
|
||||
: ImageResourceProperty <ColouredElement> (e, isForStroke_ ? "stroke image"
|
||||
: "fill image"),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setResource (const String& newName)
|
||||
{
|
||||
if (element != nullptr)
|
||||
{
|
||||
if (isForStroke)
|
||||
{
|
||||
JucerFillType type (element->getStrokeType().fill);
|
||||
type.imageResourceName = newName;
|
||||
|
||||
element->setStrokeFill (type, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JucerFillType type (element->getFillType());
|
||||
type.imageResourceName = newName;
|
||||
|
||||
element->setFillType (type, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getResource() const
|
||||
{
|
||||
if (element == nullptr)
|
||||
return {};
|
||||
|
||||
if (isForStroke)
|
||||
return element->getStrokeType().fill.imageResourceName;
|
||||
|
||||
return element->getFillType().imageResourceName;
|
||||
}
|
||||
|
||||
private:
|
||||
bool isForStroke;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ImageBrushPositionProperty : public PositionPropertyBase
|
||||
{
|
||||
public:
|
||||
ImageBrushPositionProperty (ColouredElement* const owner_,
|
||||
const String& name,
|
||||
ComponentPositionDimension dimension_,
|
||||
const bool isForStroke_)
|
||||
: PositionPropertyBase (owner_, name, dimension_, false, false,
|
||||
owner_->getDocument()->getComponentLayout()),
|
||||
listener (owner_),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setPosition (const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
if (isForStroke)
|
||||
{
|
||||
JucerFillType type (listener.owner->getStrokeType().fill);
|
||||
type.imageAnchor = newPos;
|
||||
listener.owner->setStrokeFill (type, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JucerFillType type (listener.owner->getFillType());
|
||||
type.imageAnchor = newPos;
|
||||
listener.owner->setFillType (type, true);
|
||||
}
|
||||
}
|
||||
|
||||
RelativePositionedRectangle getPosition() const
|
||||
{
|
||||
if (isForStroke)
|
||||
return listener.owner->getStrokeType().fill.imageAnchor;
|
||||
|
||||
return listener.owner->getFillType().imageAnchor;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<ColouredElement> listener;
|
||||
const bool isForStroke;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ImageBrushOpacityProperty : public SliderPropertyComponent
|
||||
{
|
||||
public:
|
||||
ImageBrushOpacityProperty (ColouredElement* const e, const bool isForStroke_)
|
||||
: SliderPropertyComponent ("opacity", 0.0, 1.0, 0.001),
|
||||
listener (e),
|
||||
isForStroke (isForStroke_)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setValue (double newValue)
|
||||
{
|
||||
if (listener.owner != nullptr)
|
||||
{
|
||||
listener.owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
if (isForStroke)
|
||||
{
|
||||
JucerFillType type (listener.owner->getStrokeType().fill);
|
||||
type.imageOpacity = newValue;
|
||||
|
||||
listener.owner->setStrokeFill (type, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JucerFillType type (listener.owner->getFillType());
|
||||
type.imageOpacity = newValue;
|
||||
|
||||
listener.owner->setFillType (type, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double getValue() const
|
||||
{
|
||||
if (listener.owner == nullptr)
|
||||
return 0;
|
||||
|
||||
if (isForStroke)
|
||||
return listener.owner->getStrokeType().fill.imageOpacity;
|
||||
|
||||
return listener.owner->getFillType().imageOpacity;
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<ColouredElement> listener;
|
||||
|
||||
bool isForStroke;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
ColouredElement::ColouredElement (PaintRoutine* owner_,
|
||||
const String& name,
|
||||
const bool showOutline_,
|
||||
const bool showJointAndEnd_)
|
||||
: PaintElement (owner_, name),
|
||||
isStrokePresent (false),
|
||||
showOutline (showOutline_),
|
||||
showJointAndEnd (showJointAndEnd_)
|
||||
{
|
||||
}
|
||||
|
||||
ColouredElement::~ColouredElement()
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ColouredElement::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
|
||||
{
|
||||
PaintElement::getEditableProperties (props, multipleSelected);
|
||||
|
||||
if (! multipleSelected)
|
||||
getColourSpecificProperties (props);
|
||||
}
|
||||
|
||||
void ColouredElement::getColourSpecificProperties (Array <PropertyComponent*>& props)
|
||||
{
|
||||
props.add (new ElementFillModeProperty (this, false));
|
||||
|
||||
switch (getFillType().mode)
|
||||
{
|
||||
case JucerFillType::solidColour:
|
||||
props.add (new ElementFillColourProperty ("colour", this, ElementFillColourProperty::solidColour, false));
|
||||
break;
|
||||
|
||||
case JucerFillType::linearGradient:
|
||||
case JucerFillType::radialGradient:
|
||||
props.add (new ElementFillColourProperty ("colour 1", this, ElementFillColourProperty::gradientColour1, false));
|
||||
props.add (new ElementFillPositionProperty (this, "x1", PositionPropertyBase::componentX, true, false));
|
||||
props.add (new ElementFillPositionProperty (this, "y1", PositionPropertyBase::componentY, true, false));
|
||||
props.add (new ElementFillColourProperty ("colour 2", this, ElementFillColourProperty::gradientColour2, false));
|
||||
props.add (new ElementFillPositionProperty (this, "x2", PositionPropertyBase::componentX, false, false));
|
||||
props.add (new ElementFillPositionProperty (this, "y2", PositionPropertyBase::componentY, false, false));
|
||||
break;
|
||||
|
||||
case JucerFillType::imageBrush:
|
||||
props.add (new ImageBrushResourceProperty (this, false));
|
||||
props.add (new ImageBrushPositionProperty (this, "anchor x", PositionPropertyBase::componentX, false));
|
||||
props.add (new ImageBrushPositionProperty (this, "anchor y", PositionPropertyBase::componentY, false));
|
||||
props.add (new ImageBrushOpacityProperty (this, false));
|
||||
break;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
if (showOutline)
|
||||
{
|
||||
props.add (new EnableStrokeProperty (this));
|
||||
|
||||
if (isStrokePresent)
|
||||
{
|
||||
props.add (new StrokeThicknessProperty (this));
|
||||
|
||||
if (showJointAndEnd)
|
||||
{
|
||||
props.add (new StrokeJointProperty (this));
|
||||
props.add (new StrokeEndCapProperty (this));
|
||||
}
|
||||
|
||||
props.add (new ElementFillModeProperty (this, true));
|
||||
|
||||
switch (getStrokeType().fill.mode)
|
||||
{
|
||||
case JucerFillType::solidColour:
|
||||
props.add (new ElementFillColourProperty ("colour", this, ElementFillColourProperty::solidColour, true));
|
||||
break;
|
||||
|
||||
case JucerFillType::linearGradient:
|
||||
case JucerFillType::radialGradient:
|
||||
props.add (new ElementFillColourProperty ("colour 1", this, ElementFillColourProperty::gradientColour1, true));
|
||||
props.add (new ElementFillPositionProperty (this, "x1", PositionPropertyBase::componentX, true, true));
|
||||
props.add (new ElementFillPositionProperty (this, "y1", PositionPropertyBase::componentY, true, true));
|
||||
props.add (new ElementFillColourProperty ("colour 2", this, ElementFillColourProperty::gradientColour2, true));
|
||||
props.add (new ElementFillPositionProperty (this, "x2", PositionPropertyBase::componentX, false, true));
|
||||
props.add (new ElementFillPositionProperty (this, "y2", PositionPropertyBase::componentY, false, true));
|
||||
break;
|
||||
|
||||
case JucerFillType::imageBrush:
|
||||
props.add (new ImageBrushResourceProperty (this, true));
|
||||
props.add (new ImageBrushPositionProperty (this, "stroke anchor x", PositionPropertyBase::componentX, true));
|
||||
props.add (new ImageBrushPositionProperty (this, "stroke anchor y", PositionPropertyBase::componentY, true));
|
||||
props.add (new ImageBrushOpacityProperty (this, true));
|
||||
break;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const JucerFillType& ColouredElement::getFillType() noexcept
|
||||
{
|
||||
return fillType;
|
||||
}
|
||||
|
||||
class FillTypeChangeAction : public PaintElementUndoableAction <ColouredElement>
|
||||
{
|
||||
public:
|
||||
FillTypeChangeAction (ColouredElement* const element, const JucerFillType& newState_)
|
||||
: PaintElementUndoableAction <ColouredElement> (element),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = element->getFillType();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setFillType (newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setFillType (oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
JucerFillType newState, oldState;
|
||||
};
|
||||
|
||||
void ColouredElement::setFillType (const JucerFillType& newType, const bool undoable)
|
||||
{
|
||||
if (fillType != newType)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new FillTypeChangeAction (this, newType),
|
||||
"Change fill type");
|
||||
}
|
||||
else
|
||||
{
|
||||
repaint();
|
||||
|
||||
if (fillType.mode != newType.mode)
|
||||
{
|
||||
owner->getSelectedElements().changed();
|
||||
siblingComponentsChanged();
|
||||
}
|
||||
|
||||
fillType = newType;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool ColouredElement::isStrokeEnabled() const noexcept
|
||||
{
|
||||
return isStrokePresent && showOutline;
|
||||
}
|
||||
|
||||
class StrokeEnableChangeAction : public PaintElementUndoableAction <ColouredElement>
|
||||
{
|
||||
public:
|
||||
StrokeEnableChangeAction (ColouredElement* const element, const bool newState_)
|
||||
: PaintElementUndoableAction <ColouredElement> (element),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = element->isStrokeEnabled();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->enableStroke (newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->enableStroke (oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool newState, oldState;
|
||||
};
|
||||
|
||||
void ColouredElement::enableStroke (bool enable, const bool undoable)
|
||||
{
|
||||
enable = enable && showOutline;
|
||||
|
||||
if (isStrokePresent != enable)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new StrokeEnableChangeAction (this, enable),
|
||||
"Change stroke mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
repaint();
|
||||
isStrokePresent = enable;
|
||||
|
||||
siblingComponentsChanged();
|
||||
owner->changed();
|
||||
owner->getSelectedElements().changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const StrokeType& ColouredElement::getStrokeType() noexcept
|
||||
{
|
||||
return strokeType;
|
||||
}
|
||||
|
||||
class StrokeTypeChangeAction : public PaintElementUndoableAction <ColouredElement>
|
||||
{
|
||||
public:
|
||||
StrokeTypeChangeAction (ColouredElement* const element, const PathStrokeType& newState_)
|
||||
: PaintElementUndoableAction <ColouredElement> (element),
|
||||
newState (newState_),
|
||||
oldState (element->getStrokeType().stroke)
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStrokeType (newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStrokeType (oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
PathStrokeType newState, oldState;
|
||||
};
|
||||
|
||||
void ColouredElement::setStrokeType (const PathStrokeType& newType, const bool undoable)
|
||||
{
|
||||
if (strokeType.stroke != newType)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new StrokeTypeChangeAction (this, newType),
|
||||
"Change stroke type");
|
||||
}
|
||||
else
|
||||
{
|
||||
repaint();
|
||||
strokeType.stroke = newType;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StrokeFillTypeChangeAction : public PaintElementUndoableAction <ColouredElement>
|
||||
{
|
||||
public:
|
||||
StrokeFillTypeChangeAction (ColouredElement* const element, const JucerFillType& newState_)
|
||||
: PaintElementUndoableAction <ColouredElement> (element),
|
||||
newState (newState_)
|
||||
{
|
||||
oldState = element->getStrokeType().fill;
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStrokeFill (newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStrokeFill (oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
JucerFillType newState, oldState;
|
||||
};
|
||||
|
||||
void ColouredElement::setStrokeFill (const JucerFillType& newType, const bool undoable)
|
||||
{
|
||||
if (strokeType.fill != newType)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new StrokeFillTypeChangeAction (this, newType),
|
||||
"Change stroke fill type");
|
||||
}
|
||||
else
|
||||
{
|
||||
repaint();
|
||||
|
||||
if (strokeType.fill.mode != newType.mode)
|
||||
{
|
||||
siblingComponentsChanged();
|
||||
owner->getSelectedElements().changed();
|
||||
}
|
||||
|
||||
strokeType.fill = newType;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ColouredElement::createSiblingComponents()
|
||||
{
|
||||
{
|
||||
GradientPointComponent* g1 = new GradientPointComponent (this, false, true);
|
||||
siblingComponents.add (g1);
|
||||
|
||||
GradientPointComponent* g2 = new GradientPointComponent (this, false, false);
|
||||
siblingComponents.add (g2);
|
||||
|
||||
getParentComponent()->addAndMakeVisible (g1);
|
||||
getParentComponent()->addAndMakeVisible (g2);
|
||||
|
||||
g1->updatePosition();
|
||||
g2->updatePosition();
|
||||
}
|
||||
|
||||
if (isStrokePresent && showOutline)
|
||||
{
|
||||
GradientPointComponent* g1 = new GradientPointComponent (this, true, true);
|
||||
siblingComponents.add (g1);
|
||||
|
||||
GradientPointComponent* g2 = new GradientPointComponent (this, true, false);
|
||||
siblingComponents.add (g2);
|
||||
|
||||
getParentComponent()->addAndMakeVisible (g1);
|
||||
getParentComponent()->addAndMakeVisible (g2);
|
||||
|
||||
g1->updatePosition();
|
||||
g2->updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle<int> ColouredElement::getCurrentBounds (const Rectangle<int>& parentArea) const
|
||||
{
|
||||
int borderSize = 0;
|
||||
|
||||
if (isStrokePresent)
|
||||
borderSize = (int) strokeType.stroke.getStrokeThickness() / 2 + 1;
|
||||
|
||||
return position.getRectangle (parentArea, getDocument()->getComponentLayout())
|
||||
.expanded (borderSize);
|
||||
}
|
||||
|
||||
void ColouredElement::setCurrentBounds (const Rectangle<int>& newBounds,
|
||||
const Rectangle<int>& parentArea,
|
||||
const bool undoable)
|
||||
{
|
||||
Rectangle<int> r (newBounds);
|
||||
|
||||
if (isStrokePresent)
|
||||
{
|
||||
r = r.expanded (-((int) strokeType.stroke.getStrokeThickness() / 2 + 1));
|
||||
|
||||
r.setSize (jmax (1, r.getWidth()), jmax (1, r.getHeight()));
|
||||
}
|
||||
|
||||
RelativePositionedRectangle pr (position);
|
||||
pr.updateFrom (r.getX() - parentArea.getX(),
|
||||
r.getY() - parentArea.getY(),
|
||||
r.getWidth(), r.getHeight(),
|
||||
Rectangle<int> (0, 0, parentArea.getWidth(), parentArea.getHeight()),
|
||||
getDocument()->getComponentLayout());
|
||||
setPosition (pr, undoable);
|
||||
|
||||
updateBounds (parentArea);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ColouredElement::addColourAttributes (XmlElement* const e) const
|
||||
{
|
||||
e->setAttribute ("fill", fillType.toString());
|
||||
e->setAttribute ("hasStroke", isStrokePresent);
|
||||
|
||||
if (isStrokePresent && showOutline)
|
||||
{
|
||||
e->setAttribute ("stroke", strokeType.toString());
|
||||
e->setAttribute ("strokeColour", strokeType.fill.toString());
|
||||
}
|
||||
}
|
||||
|
||||
bool ColouredElement::loadColourAttributes (const XmlElement& xml)
|
||||
{
|
||||
fillType.restoreFromString (xml.getStringAttribute ("fill", String()));
|
||||
|
||||
isStrokePresent = showOutline && xml.getBoolAttribute ("hasStroke", false);
|
||||
|
||||
strokeType.restoreFromString (xml.getStringAttribute ("stroke", String()));
|
||||
strokeType.fill.restoreFromString (xml.getStringAttribute ("strokeColour", String()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ColouredElement::convertToNewPathElement (const Path& path)
|
||||
{
|
||||
if (! path.isEmpty())
|
||||
{
|
||||
PaintElementPath newElement (getOwner());
|
||||
newElement.setToPath (path);
|
||||
newElement.setFillType (fillType, false);
|
||||
newElement.enableStroke (isStrokeEnabled(), false);
|
||||
newElement.setStrokeType (getStrokeType().stroke, false);
|
||||
newElement.setStrokeFill (getStrokeType().fill, false);
|
||||
|
||||
std::unique_ptr<XmlElement> xml (newElement.createXml());
|
||||
|
||||
PaintElement* e = getOwner()->addElementFromXml (*xml, getOwner()->indexOfElement (this), true);
|
||||
|
||||
getOwner()->getSelectedElements().selectOnly (e);
|
||||
getOwner()->removeElement (this, true);
|
||||
}
|
||||
}
|
||||
80
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ColouredElement.h
vendored
Normal file
80
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ColouredElement.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_PaintRoutine.h"
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_StrokeType.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for paint elements that have a fill colour and stroke.
|
||||
|
||||
*/
|
||||
class ColouredElement : public PaintElement
|
||||
{
|
||||
public:
|
||||
ColouredElement (PaintRoutine* owner,
|
||||
const String& name,
|
||||
const bool showOutline_,
|
||||
const bool showJointAndEnd_);
|
||||
|
||||
~ColouredElement() override;
|
||||
|
||||
//==============================================================================
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override;
|
||||
void getColourSpecificProperties (Array<PropertyComponent*>& props);
|
||||
|
||||
//==============================================================================
|
||||
const JucerFillType& getFillType() noexcept;
|
||||
void setFillType (const JucerFillType& newType, const bool undoable);
|
||||
|
||||
bool isStrokeEnabled() const noexcept;
|
||||
void enableStroke (bool enable, const bool undoable);
|
||||
|
||||
const StrokeType& getStrokeType() noexcept;
|
||||
void setStrokeType (const PathStrokeType& newType, const bool undoable);
|
||||
void setStrokeFill (const JucerFillType& newType, const bool undoable);
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const override;
|
||||
void setCurrentBounds (const Rectangle<int>& newBounds, const Rectangle<int>& parentArea, const bool undoable) override;
|
||||
|
||||
void createSiblingComponents() override;
|
||||
|
||||
//==============================================================================
|
||||
void addColourAttributes (XmlElement* const e) const;
|
||||
bool loadColourAttributes (const XmlElement& xml);
|
||||
|
||||
protected:
|
||||
JucerFillType fillType;
|
||||
|
||||
bool isStrokePresent;
|
||||
const bool showOutline, showJointAndEnd;
|
||||
StrokeType strokeType;
|
||||
|
||||
void convertToNewPathElement (const Path& path);
|
||||
};
|
||||
55
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ElementSiblingComponent.h
vendored
Normal file
55
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ElementSiblingComponent.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//==============================================================================
|
||||
class ElementSiblingComponent : public Component,
|
||||
public ChangeListener
|
||||
{
|
||||
public:
|
||||
ElementSiblingComponent (PaintElement* const owner_)
|
||||
: owner (owner_)
|
||||
{
|
||||
setAlwaysOnTop (true);
|
||||
|
||||
owner->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~ElementSiblingComponent() override
|
||||
{
|
||||
owner->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
virtual void updatePosition() = 0;
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
protected:
|
||||
PaintElement* const owner;
|
||||
};
|
||||
427
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h
vendored
Normal file
427
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_FillType.h
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
#include "../../ProjectSaving/jucer_ResourceFile.h"
|
||||
|
||||
//==============================================================================
|
||||
class JucerFillType
|
||||
{
|
||||
public:
|
||||
JucerFillType()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
JucerFillType (const JucerFillType& other)
|
||||
{
|
||||
image = Image();
|
||||
mode = other.mode;
|
||||
colour = other.colour;
|
||||
gradCol1 = other.gradCol1;
|
||||
gradCol2 = other.gradCol2;
|
||||
gradPos1 = other.gradPos1;
|
||||
gradPos2 = other.gradPos2;
|
||||
imageResourceName = other.imageResourceName;
|
||||
imageOpacity = other.imageOpacity;
|
||||
imageAnchor = other.imageAnchor;
|
||||
}
|
||||
|
||||
JucerFillType& operator= (const JucerFillType& other)
|
||||
{
|
||||
image = Image();
|
||||
mode = other.mode;
|
||||
colour = other.colour;
|
||||
gradCol1 = other.gradCol1;
|
||||
gradCol2 = other.gradCol2;
|
||||
gradPos1 = other.gradPos1;
|
||||
gradPos2 = other.gradPos2;
|
||||
imageResourceName = other.imageResourceName;
|
||||
imageOpacity = other.imageOpacity;
|
||||
imageAnchor = other.imageAnchor;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator== (const JucerFillType& other) const
|
||||
{
|
||||
return mode == other.mode
|
||||
&& colour == other.colour
|
||||
&& gradCol1 == other.gradCol1
|
||||
&& gradCol2 == other.gradCol2
|
||||
&& gradPos1 == other.gradPos1
|
||||
&& gradPos2 == other.gradPos2
|
||||
&& imageResourceName == other.imageResourceName
|
||||
&& imageOpacity == other.imageOpacity
|
||||
&& imageAnchor == other.imageAnchor;
|
||||
}
|
||||
|
||||
bool operator!= (const JucerFillType& other) const
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setFillType (Graphics& g, JucerDocument* const document, const Rectangle<int>& parentArea)
|
||||
{
|
||||
if (document == nullptr)
|
||||
{
|
||||
jassertfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == solidColour)
|
||||
{
|
||||
image = Image();
|
||||
g.setColour (colour);
|
||||
}
|
||||
else if (mode == imageBrush)
|
||||
{
|
||||
loadImage (document);
|
||||
|
||||
Rectangle<int> r (imageAnchor.getRectangle (parentArea, document->getComponentLayout()));
|
||||
|
||||
g.setTiledImageFill (image, r.getX(), r.getY(), (float) imageOpacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
image = Image();
|
||||
|
||||
Rectangle<int> r1 (gradPos1.getRectangle (parentArea, document->getComponentLayout()));
|
||||
Rectangle<int> r2 (gradPos2.getRectangle (parentArea, document->getComponentLayout()));
|
||||
|
||||
g.setGradientFill (ColourGradient (gradCol1, (float) r1.getX(), (float) r1.getY(),
|
||||
gradCol2, (float) r2.getX(), (float) r2.getY(),
|
||||
mode == radialGradient));
|
||||
}
|
||||
}
|
||||
|
||||
String generateVariablesCode (String type) const
|
||||
{
|
||||
String s;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case solidColour:
|
||||
s << "juce::Colour " << type << "Colour = " << CodeHelpers::colourToCode (colour) << ";\n";
|
||||
break;
|
||||
|
||||
case linearGradient:
|
||||
case radialGradient:
|
||||
s << "juce::Colour " << type << "Colour1 = " << CodeHelpers::colourToCode (gradCol1) << ", " << type << "Colour2 = " << CodeHelpers::colourToCode (gradCol2) << ";\n";
|
||||
break;
|
||||
|
||||
case imageBrush:
|
||||
break;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (String type, RelativePositionedRectangle relativeTo, GeneratedCode& code, String& paintMethodCode) const
|
||||
{
|
||||
String s;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case solidColour:
|
||||
s << "g.setColour (" << type << "Colour);\n";
|
||||
break;
|
||||
|
||||
case linearGradient:
|
||||
case radialGradient:
|
||||
{
|
||||
String x0, y0, x1, y1, w, h, x2, y2;
|
||||
positionToCode (relativeTo, code.document->getComponentLayout(), x0, y0, w, h);
|
||||
positionToCode (gradPos1, code.document->getComponentLayout(), x1, y1, w, h);
|
||||
positionToCode (gradPos2, code.document->getComponentLayout(), x2, y2, w, h);
|
||||
|
||||
s << "g.setGradientFill (juce::ColourGradient (";
|
||||
|
||||
auto indent = String::repeatedString (" ", s.length());
|
||||
|
||||
s << type << "Colour1,\n"
|
||||
<< indent << castToFloat (x1) << " - " << castToFloat (x0) << " + x,\n"
|
||||
<< indent << castToFloat (y1) << " - " << castToFloat (y0) << " + y,\n"
|
||||
<< indent << type << "Colour2,\n"
|
||||
<< indent << castToFloat (x2) << " - " << castToFloat (x0) << " + x,\n"
|
||||
<< indent << castToFloat (y2) << " - " << castToFloat (y0) << " + y,\n"
|
||||
<< indent << CodeHelpers::boolLiteral (mode == radialGradient) << "));\n";
|
||||
break;
|
||||
}
|
||||
|
||||
case imageBrush:
|
||||
{
|
||||
auto imageVariable = "cachedImage_" + imageResourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix());
|
||||
|
||||
code.addImageResourceLoader (imageVariable, imageResourceName);
|
||||
|
||||
String x0, y0, x1, y1, w, h;
|
||||
positionToCode (relativeTo, code.document->getComponentLayout(), x0, y0, w, h);
|
||||
positionToCode (imageAnchor, code.document->getComponentLayout(), x1, y1, w, h);
|
||||
|
||||
s << "g.setTiledImageFill (";
|
||||
|
||||
const String indent (String::repeatedString (" ", s.length()));
|
||||
|
||||
s << imageVariable << ",\n"
|
||||
<< indent << x1 << " - " << x0 << " + x,\n"
|
||||
<< indent << y1 << " - " << y0 << " + y,\n"
|
||||
<< indent << CodeHelpers::floatLiteral (imageOpacity, 4) << ");\n";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
paintMethodCode += s;
|
||||
}
|
||||
|
||||
String toString() const
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case solidColour:
|
||||
return "solid: " + colour.toString();
|
||||
|
||||
case linearGradient:
|
||||
case radialGradient:
|
||||
return (mode == linearGradient ? "linear: "
|
||||
: " radial: ")
|
||||
+ gradPos1.toString()
|
||||
+ ", "
|
||||
+ gradPos2.toString()
|
||||
+ ", 0=" + gradCol1.toString()
|
||||
+ ", 1=" + gradCol2.toString();
|
||||
|
||||
case imageBrush:
|
||||
return "image: " + imageResourceName.replaceCharacter (':', '#')
|
||||
+ ", "
|
||||
+ String (imageOpacity)
|
||||
+ ", "
|
||||
+ imageAnchor.toString();
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void restoreFromString (const String& s)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (s.isNotEmpty())
|
||||
{
|
||||
StringArray toks;
|
||||
toks.addTokens (s, ",:", StringRef());
|
||||
toks.trim();
|
||||
|
||||
if (toks[0] == "solid")
|
||||
{
|
||||
mode = solidColour;
|
||||
colour = Colour::fromString (toks[1]);
|
||||
}
|
||||
else if (toks[0] == "linear"
|
||||
|| toks[0] == "radial")
|
||||
{
|
||||
mode = (toks[0] == "linear") ? linearGradient : radialGradient;
|
||||
|
||||
gradPos1 = RelativePositionedRectangle();
|
||||
gradPos1.rect = PositionedRectangle (toks[1]);
|
||||
gradPos2 = RelativePositionedRectangle();
|
||||
gradPos2.rect = PositionedRectangle (toks[2]);
|
||||
|
||||
gradCol1 = Colour::fromString (toks[3].fromFirstOccurrenceOf ("=", false, false));
|
||||
gradCol2 = Colour::fromString (toks[4].fromFirstOccurrenceOf ("=", false, false));
|
||||
}
|
||||
else if (toks[0] == "image")
|
||||
{
|
||||
mode = imageBrush;
|
||||
imageResourceName = toks[1].replaceCharacter ('#', ':');
|
||||
imageOpacity = toks[2].getDoubleValue();
|
||||
imageAnchor= RelativePositionedRectangle();
|
||||
imageAnchor.rect = PositionedRectangle (toks[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool isOpaque() const
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case solidColour:
|
||||
return colour.isOpaque();
|
||||
|
||||
case linearGradient:
|
||||
case radialGradient:
|
||||
return gradCol1.isOpaque() && gradCol2.isOpaque();
|
||||
|
||||
case imageBrush:
|
||||
return image.isValid()
|
||||
&& imageOpacity >= 1.0f
|
||||
&& ! image.hasAlphaChannel();
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInvisible() const
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case solidColour:
|
||||
return colour.isTransparent();
|
||||
|
||||
case linearGradient:
|
||||
case radialGradient:
|
||||
return gradCol1.isTransparent() && gradCol2.isTransparent();
|
||||
|
||||
case imageBrush:
|
||||
return imageOpacity == 0.0;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
enum FillMode
|
||||
{
|
||||
solidColour,
|
||||
linearGradient,
|
||||
radialGradient,
|
||||
imageBrush
|
||||
};
|
||||
|
||||
FillMode mode;
|
||||
Colour colour, gradCol1, gradCol2;
|
||||
|
||||
// just the x, y, of these are used
|
||||
RelativePositionedRectangle gradPos1, gradPos2;
|
||||
|
||||
String imageResourceName;
|
||||
double imageOpacity;
|
||||
RelativePositionedRectangle imageAnchor;
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
Image image;
|
||||
|
||||
void reset()
|
||||
{
|
||||
image = Image();
|
||||
mode = solidColour;
|
||||
colour = Colours::brown.withHue (Random::getSystemRandom().nextFloat());
|
||||
gradCol1 = Colours::red;
|
||||
gradCol2 = Colours::green;
|
||||
gradPos1 = RelativePositionedRectangle();
|
||||
gradPos1.rect = PositionedRectangle ("50 50");
|
||||
gradPos2 = RelativePositionedRectangle();
|
||||
gradPos2.rect = PositionedRectangle ("100 100");
|
||||
|
||||
imageResourceName.clear();
|
||||
imageOpacity = 1.0;
|
||||
imageAnchor = RelativePositionedRectangle();
|
||||
imageAnchor.rect = PositionedRectangle ("0 0");
|
||||
}
|
||||
|
||||
void loadImage (JucerDocument* const document)
|
||||
{
|
||||
if (image.isNull())
|
||||
{
|
||||
if (document != nullptr)
|
||||
{
|
||||
if (imageResourceName.contains ("::"))
|
||||
{
|
||||
if (Project* project = document->getCppDocument().getProject())
|
||||
{
|
||||
JucerResourceFile resourceFile (*project);
|
||||
|
||||
for (int i = 0; i < resourceFile.getNumFiles(); ++i)
|
||||
{
|
||||
const File& file = resourceFile.getFile(i);
|
||||
|
||||
if (imageResourceName == resourceFile.getClassName() + "::" + resourceFile.getDataVariableFor (file))
|
||||
{
|
||||
image = ImageCache::getFromFile (file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
image = document->getResources().getImageFromCache (imageResourceName);
|
||||
}
|
||||
}
|
||||
|
||||
if (image.isNull())
|
||||
{
|
||||
const int hashCode = 0x3437856f;
|
||||
image = ImageCache::getFromHashCode (hashCode);
|
||||
|
||||
if (image.isNull())
|
||||
{
|
||||
image = Image (Image::RGB, 100, 100, true);
|
||||
|
||||
Graphics g (image);
|
||||
g.fillCheckerBoard (image.getBounds().toFloat(),
|
||||
(float) image.getWidth() * 0.5f, (float) image.getHeight() * 0.5f,
|
||||
Colours::white, Colours::lightgrey);
|
||||
|
||||
g.setFont (12.0f);
|
||||
g.setColour (Colours::grey);
|
||||
g.drawText ("(image missing)", 0, 0, image.getWidth(), image.getHeight() / 2, Justification::centred, true);
|
||||
|
||||
ImageCache::addImageToCache (image, hashCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
99
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_GradientPointComponent.h
vendored
Normal file
99
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_GradientPointComponent.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_PointComponent.h"
|
||||
#include "jucer_ColouredElement.h"
|
||||
|
||||
//==============================================================================
|
||||
class GradientPointComponent : public PointComponent
|
||||
{
|
||||
public:
|
||||
GradientPointComponent (ColouredElement* const owner_,
|
||||
const bool isStroke_,
|
||||
const bool isStart_)
|
||||
: PointComponent (owner_),
|
||||
isStroke (isStroke_),
|
||||
isStart (isStart_)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePositionedRectangle getPosition()
|
||||
{
|
||||
ColouredElement* e = dynamic_cast<ColouredElement*> (owner);
|
||||
|
||||
if (isStroke)
|
||||
return isStart ? e->getStrokeType().fill.gradPos1
|
||||
: e->getStrokeType().fill.gradPos2;
|
||||
|
||||
return isStart ? e->getFillType().gradPos1
|
||||
: e->getFillType().gradPos2;
|
||||
}
|
||||
|
||||
void setPosition (const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
ColouredElement* e = dynamic_cast<ColouredElement*> (owner);
|
||||
|
||||
if (isStroke)
|
||||
{
|
||||
JucerFillType f (e->getStrokeType().fill);
|
||||
|
||||
if (isStart)
|
||||
f.gradPos1 = newPos;
|
||||
else
|
||||
f.gradPos2 = newPos;
|
||||
|
||||
e->setStrokeFill (f, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
JucerFillType f (e->getFillType());
|
||||
|
||||
if (isStart)
|
||||
f.gradPos1 = newPos;
|
||||
else
|
||||
f.gradPos2 = newPos;
|
||||
|
||||
e->setFillType (f, true);
|
||||
}
|
||||
}
|
||||
|
||||
void updatePosition()
|
||||
{
|
||||
PointComponent::updatePosition();
|
||||
|
||||
ColouredElement* e = dynamic_cast<ColouredElement*> (owner);
|
||||
|
||||
JucerFillType f (isStroke ? e->getStrokeType().fill
|
||||
: e->getFillType());
|
||||
|
||||
setVisible (f.mode == JucerFillType::linearGradient
|
||||
|| f.mode == JucerFillType::radialGradient);
|
||||
}
|
||||
|
||||
private:
|
||||
bool isStroke, isStart;
|
||||
};
|
||||
144
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ImageResourceProperty.h
vendored
Normal file
144
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_ImageResourceProperty.h
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../ProjectSaving/jucer_ResourceFile.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A property that lets you pick a resource to use as an image, or create a
|
||||
new one with a file selector.
|
||||
*/
|
||||
template <class ElementType>
|
||||
class ImageResourceProperty : public ChoicePropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ImageResourceProperty (JucerDocument& doc,
|
||||
ElementType* const e,
|
||||
const String& name,
|
||||
const bool allowChoiceOfNoResource_)
|
||||
: ChoicePropertyComponent (name),
|
||||
element (e), document (doc),
|
||||
allowChoiceOfNoResource (allowChoiceOfNoResource_)
|
||||
{
|
||||
refreshChoices();
|
||||
doc.addChangeListener (this);
|
||||
}
|
||||
|
||||
ImageResourceProperty (ElementType* const e, const String& name,
|
||||
const bool allowChoiceOfNoResource_ = false)
|
||||
: ChoicePropertyComponent (name),
|
||||
element (e), document (*e->getDocument()),
|
||||
allowChoiceOfNoResource (allowChoiceOfNoResource_)
|
||||
{
|
||||
refreshChoices();
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ImageResourceProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
virtual void setResource (const String& newName) = 0;
|
||||
|
||||
virtual String getResource() const = 0;
|
||||
|
||||
//==============================================================================
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
if (newIndex == 0)
|
||||
{
|
||||
document.getResources()
|
||||
.browseForResource ("Select an image file to add as a resource",
|
||||
"*.jpg;*.jpeg;*.png;*.gif;*.svg",
|
||||
File(),
|
||||
String(),
|
||||
[this] (String resource)
|
||||
{
|
||||
if (resource.isNotEmpty())
|
||||
setResource (resource);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (choices[newIndex] == getNoneText() && allowChoiceOfNoResource)
|
||||
setResource (String());
|
||||
else
|
||||
setResource (choices [newIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
if (getResource().isEmpty())
|
||||
return -1;
|
||||
|
||||
return choices.indexOf (getResource());
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void refreshChoices()
|
||||
{
|
||||
choices.clear();
|
||||
|
||||
choices.add ("-- create a new image resource -- ");
|
||||
choices.add (String());
|
||||
|
||||
if (allowChoiceOfNoResource)
|
||||
choices.add (getNoneText());
|
||||
|
||||
choices.addArray (document.getResources().getResourceNames());
|
||||
|
||||
const SourceCodeDocument& cpp = document.getCppDocument();
|
||||
|
||||
if (Project* project = cpp.getProject())
|
||||
{
|
||||
JucerResourceFile resourceFile (*project);
|
||||
|
||||
for (int i = 0; i < resourceFile.getNumFiles(); ++i)
|
||||
{
|
||||
const File& file = resourceFile.getFile(i);
|
||||
|
||||
if (ImageFileFormat::findImageFormatForFileExtension(file))
|
||||
choices.add (resourceFile.getClassName() + "::" + resourceFile.getDataVariableFor (file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* getNoneText() noexcept { return "<< none >>"; }
|
||||
|
||||
protected:
|
||||
mutable Component::SafePointer<ElementType> element;
|
||||
JucerDocument& document;
|
||||
const bool allowChoiceOfNoResource;
|
||||
};
|
||||
688
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElement.cpp
vendored
Normal file
688
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElement.cpp
vendored
Normal file
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
#include "../jucer_PaintRoutine.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
#include "../UI/jucer_JucerCommandIDs.h"
|
||||
#include "../UI/jucer_PaintRoutineEditor.h"
|
||||
#include "../Properties/jucer_PositionPropertyBase.h"
|
||||
#include "jucer_ElementSiblingComponent.h"
|
||||
#include "jucer_PaintElementUndoableAction.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
PaintElement::PaintElement (PaintRoutine* owner_,
|
||||
const String& typeName_)
|
||||
: borderThickness (4),
|
||||
owner (owner_),
|
||||
typeName (typeName_),
|
||||
selected (false),
|
||||
dragging (false),
|
||||
originalAspectRatio (1.0)
|
||||
{
|
||||
setRepaintsOnMouseActivity (true);
|
||||
|
||||
position.rect.setWidth (100);
|
||||
position.rect.setHeight (100);
|
||||
|
||||
setMinimumOnscreenAmounts (0, 0, 0, 0);
|
||||
setSizeLimits (borderThickness * 2 + 1, borderThickness * 2 + 1, 8192, 8192);
|
||||
|
||||
border.reset (new ResizableBorderComponent (this, this));
|
||||
addChildComponent (border.get());
|
||||
|
||||
border->setBorderThickness (BorderSize<int> (borderThickness));
|
||||
|
||||
if (owner != nullptr)
|
||||
owner->getSelectedElements().addChangeListener (this);
|
||||
|
||||
selfChangeListenerList.addChangeListener (this);
|
||||
siblingComponentsChanged();
|
||||
}
|
||||
|
||||
PaintElement::~PaintElement()
|
||||
{
|
||||
siblingComponents.clear();
|
||||
|
||||
if (owner != nullptr)
|
||||
{
|
||||
owner->getSelectedElements().deselect (this);
|
||||
owner->getSelectedElements().removeChangeListener (this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void PaintElement::setInitialBounds (int parentWidth, int parentHeight)
|
||||
{
|
||||
RelativePositionedRectangle pr (getPosition());
|
||||
pr.rect.setX (parentWidth / 4 + Random::getSystemRandom().nextInt (parentWidth / 4) - parentWidth / 8);
|
||||
pr.rect.setY (parentHeight / 3 + Random::getSystemRandom().nextInt (parentHeight / 4) - parentHeight / 8);
|
||||
setPosition (pr, false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const RelativePositionedRectangle& PaintElement::getPosition() const
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
class PaintElementMoveAction : public PaintElementUndoableAction <PaintElement>
|
||||
{
|
||||
public:
|
||||
PaintElementMoveAction (PaintElement* const element, const RelativePositionedRectangle& newState_)
|
||||
: PaintElementUndoableAction <PaintElement> (element),
|
||||
newState (newState_),
|
||||
oldState (element->getPosition())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setPosition (newState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setPosition (oldState, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
RelativePositionedRectangle newState, oldState;
|
||||
};
|
||||
|
||||
class ChangePaintElementBoundsAction : public PaintElementUndoableAction <PaintElement>
|
||||
{
|
||||
public:
|
||||
ChangePaintElementBoundsAction (PaintElement* const element, const Rectangle<int>& bounds)
|
||||
: PaintElementUndoableAction <PaintElement> (element),
|
||||
newBounds (bounds),
|
||||
oldBounds (element->getBounds())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setBounds (newBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setBounds (oldBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Rectangle<int> newBounds, oldBounds;
|
||||
};
|
||||
|
||||
class ChangePaintElementBoundsAndPropertiesAction : public PaintElementUndoableAction <PaintElement>
|
||||
{
|
||||
public:
|
||||
ChangePaintElementBoundsAndPropertiesAction (PaintElement* const element, const Rectangle<int>& bounds,
|
||||
const NamedValueSet& props)
|
||||
: PaintElementUndoableAction <PaintElement> (element),
|
||||
newBounds (bounds),
|
||||
oldBounds (element->getBounds()),
|
||||
newProps (props),
|
||||
oldProps (element->getProperties())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getElement()->getParentComponent()))
|
||||
getElement()->setCurrentBounds (newBounds, pe->getComponentArea(), false);
|
||||
|
||||
getElement()->getProperties() = newProps;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getElement()->getParentComponent()))
|
||||
getElement()->setCurrentBounds (oldBounds, pe->getComponentArea(), false);
|
||||
|
||||
getElement()->getProperties() = oldProps;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Rectangle<int> newBounds, oldBounds;
|
||||
NamedValueSet newProps, oldProps;
|
||||
};
|
||||
|
||||
void PaintElement::setPosition (const RelativePositionedRectangle& newPosition, const bool undoable)
|
||||
{
|
||||
if (position != newPosition)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new PaintElementMoveAction (this, newPosition),
|
||||
"Move " + getTypeName());
|
||||
}
|
||||
else
|
||||
{
|
||||
position = newPosition;
|
||||
|
||||
if (owner != nullptr)
|
||||
owner->changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::setPaintElementBounds (const Rectangle<int>& newBounds, const bool undoable)
|
||||
{
|
||||
if (getBounds() != newBounds)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new ChangePaintElementBoundsAction (this, newBounds), "Change paint element bounds");
|
||||
}
|
||||
else
|
||||
{
|
||||
setBounds (newBounds);
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::setPaintElementBoundsAndProperties (PaintElement* elementToPosition, const Rectangle<int>& newBounds,
|
||||
PaintElement* referenceElement, const bool undoable)
|
||||
{
|
||||
auto props = NamedValueSet (elementToPosition->getProperties());
|
||||
|
||||
auto rect = elementToPosition->getPosition().rect;
|
||||
auto referenceElementPosition = referenceElement->getPosition();
|
||||
auto referenceElementRect = referenceElementPosition.rect;
|
||||
|
||||
rect.setModes (referenceElementRect.getAnchorPointX(), referenceElementRect.getPositionModeX(),
|
||||
referenceElementRect.getAnchorPointY(), referenceElementRect.getPositionModeY(),
|
||||
referenceElementRect.getWidthMode(), referenceElementRect.getHeightMode(),
|
||||
elementToPosition->getBounds());
|
||||
|
||||
props.set ("pos", rect.toString());
|
||||
props.set ("relativeToX", String::toHexString (referenceElementPosition.relativeToX));
|
||||
props.set ("relativeToY", String::toHexString (referenceElementPosition.relativeToY));
|
||||
props.set ("relativeToW", String::toHexString (referenceElementPosition.relativeToW));
|
||||
props.set ("relativeToH", String::toHexString (referenceElementPosition.relativeToH));
|
||||
|
||||
if (elementToPosition->getBounds() != newBounds || elementToPosition->getProperties() != props)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new ChangePaintElementBoundsAndPropertiesAction (elementToPosition, newBounds, props),
|
||||
"Change paint element bounds");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (elementToPosition->getParentComponent()))
|
||||
elementToPosition->setCurrentBounds (newBounds, pe->getComponentArea(), false);
|
||||
|
||||
elementToPosition->getProperties() = props;
|
||||
owner->changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Rectangle<int> PaintElement::getCurrentBounds (const Rectangle<int>& parentArea) const
|
||||
{
|
||||
return position.getRectangle (parentArea, getDocument()->getComponentLayout());
|
||||
}
|
||||
|
||||
void PaintElement::setCurrentBounds (const Rectangle<int>& newBounds,
|
||||
const Rectangle<int>& parentArea,
|
||||
const bool undoable)
|
||||
{
|
||||
RelativePositionedRectangle pr (position);
|
||||
pr.updateFrom (newBounds.getX() - parentArea.getX(),
|
||||
newBounds.getY() - parentArea.getY(),
|
||||
jmax (1, newBounds.getWidth()),
|
||||
jmax (1, newBounds.getHeight()),
|
||||
Rectangle<int> (0, 0, parentArea.getWidth(), parentArea.getHeight()),
|
||||
getDocument()->getComponentLayout());
|
||||
|
||||
setPosition (pr, undoable);
|
||||
|
||||
updateBounds (parentArea);
|
||||
}
|
||||
|
||||
void PaintElement::updateBounds (const Rectangle<int>& parentArea)
|
||||
{
|
||||
if (! parentArea.isEmpty())
|
||||
{
|
||||
setBounds (getCurrentBounds (parentArea)
|
||||
.expanded (borderThickness,
|
||||
borderThickness));
|
||||
|
||||
for (int i = siblingComponents.size(); --i >= 0;)
|
||||
siblingComponents.getUnchecked(i)->updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ElementPositionProperty : public PositionPropertyBase
|
||||
{
|
||||
public:
|
||||
ElementPositionProperty (PaintElement* e, const String& name,
|
||||
ComponentPositionDimension dimension_)
|
||||
: PositionPropertyBase (e, name, dimension_, true, false,
|
||||
e->getDocument()->getComponentLayout()),
|
||||
listener (e),
|
||||
element (e)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void setPosition (const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
if (element->getOwner()->getSelectedElements().getNumSelected() > 1)
|
||||
positionOtherSelectedElements (getPosition(), newPos);
|
||||
|
||||
listener.owner->setPosition (newPos, true);
|
||||
}
|
||||
|
||||
RelativePositionedRectangle getPosition() const
|
||||
{
|
||||
return listener.owner->getPosition();
|
||||
}
|
||||
|
||||
private:
|
||||
ElementListener<PaintElement> listener;
|
||||
PaintElement* element;
|
||||
|
||||
void positionOtherSelectedElements (const RelativePositionedRectangle& oldPos, const RelativePositionedRectangle& newPos)
|
||||
{
|
||||
for (auto* s : element->getOwner()->getSelectedElements())
|
||||
{
|
||||
if (s != element)
|
||||
{
|
||||
auto currentPos = s->getPosition();
|
||||
auto diff = 0.0;
|
||||
|
||||
if (dimension == ComponentPositionDimension::componentX)
|
||||
{
|
||||
diff = newPos.rect.getX() - oldPos.rect.getX();
|
||||
currentPos.rect.setX (currentPos.rect.getX() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentY)
|
||||
{
|
||||
diff = newPos.rect.getY() - oldPos.rect.getY();
|
||||
currentPos.rect.setY (currentPos.rect.getY() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentWidth)
|
||||
{
|
||||
diff = newPos.rect.getWidth() - oldPos.rect.getWidth();
|
||||
currentPos.rect.setWidth (currentPos.rect.getWidth() + diff);
|
||||
}
|
||||
else if (dimension == ComponentPositionDimension::componentHeight)
|
||||
{
|
||||
diff = newPos.rect.getHeight() - oldPos.rect.getHeight();
|
||||
currentPos.rect.setHeight (currentPos.rect.getHeight() + diff);
|
||||
}
|
||||
|
||||
s->setPosition (currentPos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void PaintElement::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
|
||||
{
|
||||
ignoreUnused (multipleSelected);
|
||||
|
||||
props.add (new ElementPositionProperty (this, "x", PositionPropertyBase::componentX));
|
||||
props.add (new ElementPositionProperty (this, "y", PositionPropertyBase::componentY));
|
||||
props.add (new ElementPositionProperty (this, "width", PositionPropertyBase::componentWidth));
|
||||
props.add (new ElementPositionProperty (this, "height", PositionPropertyBase::componentHeight));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
JucerDocument* PaintElement::getDocument() const
|
||||
{
|
||||
return owner->getDocument();
|
||||
}
|
||||
|
||||
void PaintElement::changed()
|
||||
{
|
||||
repaint();
|
||||
owner->changed();
|
||||
}
|
||||
|
||||
bool PaintElement::perform (UndoableAction* action, const String& actionName)
|
||||
{
|
||||
return owner->perform (action, actionName);
|
||||
}
|
||||
|
||||
void PaintElement::parentHierarchyChanged()
|
||||
{
|
||||
updateSiblingComps();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintElement::drawExtraEditorGraphics (Graphics&, const Rectangle<int>& /*relativeTo*/)
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElement::paint (Graphics& g)
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
{
|
||||
auto area = pe->getComponentArea();
|
||||
|
||||
g.saveState();
|
||||
g.setOrigin (area.getPosition() - Component::getPosition());
|
||||
area.setPosition (0, 0);
|
||||
|
||||
g.saveState();
|
||||
g.reduceClipRegion (0, 0, area.getWidth(), area.getHeight());
|
||||
|
||||
draw (g, getDocument()->getComponentLayout(), area);
|
||||
|
||||
g.restoreState();
|
||||
|
||||
drawExtraEditorGraphics (g, area);
|
||||
g.restoreState();
|
||||
|
||||
if (selected)
|
||||
{
|
||||
const BorderSize<int> borderSize (border->getBorderThickness());
|
||||
auto baseColour = findColour (defaultHighlightColourId);
|
||||
|
||||
drawResizableBorder (g, getWidth(), getHeight(), borderSize,
|
||||
(isMouseOverOrDragging() || border->isMouseOverOrDragging()),
|
||||
baseColour.withAlpha (owner->getSelectedElements().getSelectedItem (0) == this ? 1.0f : 0.3f));
|
||||
}
|
||||
else if (isMouseOverOrDragging())
|
||||
{
|
||||
drawMouseOverCorners (g, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::resized()
|
||||
{
|
||||
border->setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void PaintElement::mouseDown (const MouseEvent& e)
|
||||
{
|
||||
dragging = false;
|
||||
|
||||
if (owner != nullptr)
|
||||
{
|
||||
owner->getSelectedPoints().deselectAll();
|
||||
mouseDownSelectStatus = owner->getSelectedElements().addToSelectionOnMouseDown (this, e.mods);
|
||||
}
|
||||
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
showPopupMenu();
|
||||
return; // this may be deleted now..
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
if (! e.mods.isPopupMenu())
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
{
|
||||
auto area = pe->getComponentArea();
|
||||
|
||||
if (selected && ! dragging)
|
||||
{
|
||||
dragging = e.mouseWasDraggedSinceMouseDown();
|
||||
|
||||
if (dragging)
|
||||
owner->startDragging (area);
|
||||
}
|
||||
|
||||
if (dragging)
|
||||
owner->dragSelectedComps (e.getDistanceFromDragStartX(),
|
||||
e.getDistanceFromDragStartY(),
|
||||
area);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (owner != nullptr)
|
||||
{
|
||||
if (dragging)
|
||||
owner->endDragging();
|
||||
|
||||
if (owner != nullptr)
|
||||
owner->getSelectedElements().addToSelectionOnMouseUp (this, e.mods, dragging, mouseDownSelectStatus);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::resizeStart()
|
||||
{
|
||||
if (getHeight() > 0)
|
||||
originalAspectRatio = getWidth() / (double) getHeight();
|
||||
else
|
||||
originalAspectRatio = 1.0;
|
||||
}
|
||||
|
||||
void PaintElement::resizeEnd()
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElement::checkBounds (Rectangle<int>& b,
|
||||
const Rectangle<int>& previousBounds,
|
||||
const Rectangle<int>& limits,
|
||||
const bool isStretchingTop,
|
||||
const bool isStretchingLeft,
|
||||
const bool isStretchingBottom,
|
||||
const bool isStretchingRight)
|
||||
{
|
||||
if (ModifierKeys::currentModifiers.isShiftDown())
|
||||
setFixedAspectRatio (originalAspectRatio);
|
||||
else
|
||||
setFixedAspectRatio (0.0);
|
||||
|
||||
ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
|
||||
|
||||
if (auto* document = getDocument())
|
||||
{
|
||||
if (document->isSnapActive (true))
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
{
|
||||
auto area = pe->getComponentArea();
|
||||
|
||||
int x = b.getX();
|
||||
int y = b.getY();
|
||||
int w = b.getWidth();
|
||||
int h = b.getHeight();
|
||||
|
||||
x += borderThickness - area.getX();
|
||||
y += borderThickness - area.getY();
|
||||
w -= borderThickness * 2;
|
||||
h -= borderThickness * 2;
|
||||
|
||||
int right = x + w;
|
||||
int bottom = y + h;
|
||||
|
||||
if (isStretchingRight)
|
||||
right = document->snapPosition (right);
|
||||
|
||||
if (isStretchingBottom)
|
||||
bottom = document->snapPosition (bottom);
|
||||
|
||||
if (isStretchingLeft)
|
||||
x = document->snapPosition (x);
|
||||
|
||||
if (isStretchingTop)
|
||||
y = document->snapPosition (y);
|
||||
|
||||
w = (right - x) + borderThickness * 2;
|
||||
h = (bottom - y) + borderThickness * 2;
|
||||
x -= borderThickness - area.getX();
|
||||
y -= borderThickness - area.getY();
|
||||
|
||||
b = { x, y, w, h };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::applyBoundsToComponent (Component&, Rectangle<int> newBounds)
|
||||
{
|
||||
if (getBounds() != newBounds)
|
||||
{
|
||||
getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
auto dX = newBounds.getX() - getX();
|
||||
auto dY = newBounds.getY() - getY();
|
||||
auto dW = newBounds.getWidth() - getWidth();
|
||||
auto dH = newBounds.getHeight() - getHeight();
|
||||
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
setCurrentBounds (newBounds.expanded (-borderThickness, -borderThickness),
|
||||
pe->getComponentArea(), true);
|
||||
|
||||
if (owner->getSelectedElements().getNumSelected() > 1)
|
||||
{
|
||||
for (auto selectedElement : owner->getSelectedElements())
|
||||
{
|
||||
if (selectedElement != nullptr && selectedElement != this)
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (selectedElement->getParentComponent()))
|
||||
{
|
||||
Rectangle<int> r { selectedElement->getX() + dX, selectedElement->getY() + dY,
|
||||
selectedElement->getWidth() + dW, selectedElement->getHeight() + dH };
|
||||
|
||||
selectedElement->setCurrentBounds (r.expanded (-borderThickness, -borderThickness),
|
||||
pe->getComponentArea(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle<int> PaintElement::getCurrentAbsoluteBounds() const
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
return position.getRectangle (pe->getComponentArea(), getDocument()->getComponentLayout());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void PaintElement::getCurrentAbsoluteBoundsDouble (double& x, double& y, double& w, double& h) const
|
||||
{
|
||||
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
position.getRectangleDouble (x, y, w, h, pe->getComponentArea(), getDocument()->getComponentLayout());
|
||||
}
|
||||
|
||||
void PaintElement::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
const bool nowSelected = owner != nullptr && owner->getSelectedElements().isSelected (this);
|
||||
|
||||
if (selected != nowSelected)
|
||||
{
|
||||
selected = nowSelected;
|
||||
border->setVisible (nowSelected);
|
||||
repaint();
|
||||
|
||||
selectionChanged (nowSelected);
|
||||
}
|
||||
|
||||
updateSiblingComps();
|
||||
}
|
||||
|
||||
void PaintElement::selectionChanged (const bool /*isSelected*/)
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElement::createSiblingComponents()
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElement::siblingComponentsChanged()
|
||||
{
|
||||
siblingComponents.clear();
|
||||
selfChangeListenerList.sendChangeMessage();
|
||||
}
|
||||
|
||||
void PaintElement::updateSiblingComps()
|
||||
{
|
||||
if (selected && getParentComponent() != nullptr && owner->getSelectedElements().getNumSelected() == 1)
|
||||
{
|
||||
if (siblingComponents.size() == 0)
|
||||
createSiblingComponents();
|
||||
|
||||
for (int i = siblingComponents.size(); --i >= 0;)
|
||||
siblingComponents.getUnchecked(i)->updatePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
siblingComponents.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElement::showPopupMenu()
|
||||
{
|
||||
auto* commandManager = &ProjucerApplication::getCommandManager();
|
||||
|
||||
PopupMenu m;
|
||||
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::toFront);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::toBack);
|
||||
m.addSeparator();
|
||||
|
||||
if (owner != nullptr && owner->getSelectedElements().getNumSelected() > 1)
|
||||
{
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignTop);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignRight);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignBottom);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::alignLeft);
|
||||
m.addSeparator();
|
||||
}
|
||||
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
|
||||
m.addCommandItem (commandManager, StandardApplicationCommandIDs::del);
|
||||
|
||||
m.showMenuAsync ({});
|
||||
}
|
||||
175
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElement.h
vendored
Normal file
175
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElement.h
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_GeneratedCode.h"
|
||||
#include "../UI/jucer_RelativePositionedRectangle.h"
|
||||
class FillType;
|
||||
class PaintRoutine;
|
||||
class JucerDocument;
|
||||
class ElementSiblingComponent;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for objects that can be used in a PaintRoutine.
|
||||
|
||||
*/
|
||||
class PaintElement : public Component,
|
||||
public ComponentBoundsConstrainer,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PaintElement (PaintRoutine* owner, const String& typeName);
|
||||
~PaintElement() override;
|
||||
|
||||
//==============================================================================
|
||||
virtual void setInitialBounds (int parentWidth, int parentHeight);
|
||||
|
||||
virtual Rectangle<int> getCurrentBounds (const Rectangle<int>& activeArea) const;
|
||||
virtual void setCurrentBounds (const Rectangle<int>& newBounds, const Rectangle<int>& activeArea, const bool undoable);
|
||||
|
||||
const RelativePositionedRectangle& getPosition() const;
|
||||
void setPosition (const RelativePositionedRectangle& newPosition, const bool undoable);
|
||||
void setPaintElementBounds (const Rectangle<int>& newBounds, const bool undoable);
|
||||
void setPaintElementBoundsAndProperties (PaintElement* elementToPosition, const Rectangle<int>& newBounds,
|
||||
PaintElement* referenceElement, const bool undoable);
|
||||
|
||||
void updateBounds (const Rectangle<int>& activeArea);
|
||||
|
||||
const String& getTypeName() const noexcept { return typeName; }
|
||||
PaintRoutine* getOwner() const noexcept { return owner; }
|
||||
|
||||
//==============================================================================
|
||||
virtual void draw (Graphics& g,
|
||||
const ComponentLayout* layout,
|
||||
const Rectangle<int>& parentArea) = 0;
|
||||
|
||||
virtual void drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo);
|
||||
|
||||
virtual void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected);
|
||||
|
||||
virtual void showPopupMenu();
|
||||
|
||||
//==============================================================================
|
||||
virtual XmlElement* createXml() const = 0;
|
||||
virtual bool loadFromXml (const XmlElement& xml) = 0;
|
||||
|
||||
//==============================================================================
|
||||
virtual void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) = 0;
|
||||
|
||||
JucerDocument* getDocument() const;
|
||||
|
||||
virtual void changed();
|
||||
bool perform (UndoableAction* action, const String& actionName);
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
void mouseDown (const MouseEvent&) override;
|
||||
void mouseDrag (const MouseEvent&) override;
|
||||
void mouseUp (const MouseEvent&) override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
void parentHierarchyChanged() override;
|
||||
|
||||
virtual void applyCustomPaintSnippets (StringArray&) {}
|
||||
|
||||
int borderThickness;
|
||||
|
||||
protected:
|
||||
PaintRoutine* const owner;
|
||||
RelativePositionedRectangle position;
|
||||
|
||||
void resizeStart() override;
|
||||
void resizeEnd() override;
|
||||
void checkBounds (Rectangle<int>& bounds,
|
||||
const Rectangle<int>& previousBounds,
|
||||
const Rectangle<int>& limits,
|
||||
bool isStretchingTop,
|
||||
bool isStretchingLeft,
|
||||
bool isStretchingBottom,
|
||||
bool isStretchingRight) override;
|
||||
|
||||
void applyBoundsToComponent (Component&, Rectangle<int>) override;
|
||||
|
||||
Rectangle<int> getCurrentAbsoluteBounds() const;
|
||||
void getCurrentAbsoluteBoundsDouble (double& x, double& y, double& w, double& h) const;
|
||||
|
||||
virtual void selectionChanged (const bool isSelected);
|
||||
|
||||
virtual void createSiblingComponents();
|
||||
|
||||
void siblingComponentsChanged();
|
||||
|
||||
OwnedArray<ElementSiblingComponent> siblingComponents;
|
||||
|
||||
void updateSiblingComps();
|
||||
|
||||
private:
|
||||
std::unique_ptr<ResizableBorderComponent> border;
|
||||
String typeName;
|
||||
bool selected, dragging, mouseDownSelectStatus;
|
||||
double originalAspectRatio;
|
||||
ChangeBroadcaster selfChangeListenerList;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
template <typename ElementType>
|
||||
class ElementListener : private ChangeListener
|
||||
{
|
||||
public:
|
||||
ElementListener (ElementType* e)
|
||||
: owner (e), broadcaster (*owner->getDocument()),
|
||||
propToRefresh (nullptr)
|
||||
{
|
||||
broadcaster.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ElementListener() override
|
||||
{
|
||||
jassert (propToRefresh != nullptr);
|
||||
broadcaster.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setPropertyToRefresh (PropertyComponent& pc)
|
||||
{
|
||||
propToRefresh = &pc;
|
||||
}
|
||||
|
||||
mutable Component::SafePointer<ElementType> owner;
|
||||
ChangeBroadcaster& broadcaster;
|
||||
PropertyComponent* propToRefresh;
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
jassert (propToRefresh != nullptr);
|
||||
if (propToRefresh != nullptr && owner != nullptr)
|
||||
propToRefresh->refresh();
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (ElementListener)
|
||||
};
|
||||
173
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementEllipse.h
vendored
Normal file
173
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementEllipse.h
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementEllipse : public ColouredElement
|
||||
{
|
||||
public:
|
||||
PaintElementEllipse (PaintRoutine* pr)
|
||||
: ColouredElement (pr, "Ellipse", true, false)
|
||||
{
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
|
||||
{
|
||||
fillType.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
Rectangle<int> r (position.getRectangle (parentArea, layout));
|
||||
g.fillEllipse ((float) r.getX(), (float) r.getY(), (float) r.getWidth(), (float) r.getHeight());
|
||||
|
||||
if (isStrokePresent)
|
||||
{
|
||||
strokeType.fill.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
g.drawEllipse ((float) r.getX(), (float) r.getY(), (float) r.getWidth(), (float) r.getHeight(),
|
||||
getStrokeType().stroke.getStrokeThickness());
|
||||
}
|
||||
}
|
||||
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ColouredElement::getEditableProperties (props, multipleSelected);
|
||||
props.add (new ShapeToPathProperty (this));
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
|
||||
{
|
||||
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
|
||||
return;
|
||||
|
||||
String x, y, w, h, s;
|
||||
positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
|
||||
|
||||
s << "{\n"
|
||||
<< " float x = " << castToFloat (x) << ", y = " << castToFloat (y) << ", "
|
||||
<< "width = " << castToFloat (w) << ", height = " << castToFloat (h) << ";\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
s << " " << fillType.generateVariablesCode ("fill");
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
s << " " << strokeType.fill.generateVariablesCode ("stroke");
|
||||
|
||||
s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n"
|
||||
<< customPaintCode
|
||||
<< " //[/UserPaintCustomArguments]\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
fillType.fillInGeneratedCode ("fill", position, code, s);
|
||||
s << " g.fillEllipse (x, y, width, height);\n";
|
||||
}
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
strokeType.fill.fillInGeneratedCode ("stroke", position, code, s);
|
||||
s << " g.drawEllipse (x, y, width, height, " << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n";
|
||||
}
|
||||
|
||||
s << "}\n\n";
|
||||
|
||||
paintMethodCode += s;
|
||||
}
|
||||
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override
|
||||
{
|
||||
customPaintCode.clear();
|
||||
|
||||
if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible())))
|
||||
{
|
||||
customPaintCode = snippets[0];
|
||||
snippets.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getTagName() noexcept { return "ELLIPSE"; }
|
||||
|
||||
XmlElement* createXml() const override
|
||||
{
|
||||
XmlElement* e = new XmlElement (getTagName());
|
||||
position.applyToXml (*e);
|
||||
addColourAttributes (e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool loadFromXml (const XmlElement& xml) override
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
position.restoreFromXml (xml, position);
|
||||
loadColourAttributes (xml);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void convertToPath()
|
||||
{
|
||||
double x, y, w, h;
|
||||
getCurrentAbsoluteBoundsDouble (x, y, w, h);
|
||||
|
||||
Path path;
|
||||
path.addEllipse ((float) x, (float) y, (float) w, (float) h);
|
||||
|
||||
convertToNewPathElement (path);
|
||||
}
|
||||
|
||||
private:
|
||||
String customPaintCode;
|
||||
|
||||
//==============================================================================
|
||||
struct ShapeToPathProperty : public ButtonPropertyComponent
|
||||
{
|
||||
ShapeToPathProperty (PaintElementEllipse* const e)
|
||||
: ButtonPropertyComponent ("path", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
element->convertToPath();
|
||||
}
|
||||
|
||||
String getButtonText() const
|
||||
{
|
||||
return "convert to a path";
|
||||
}
|
||||
|
||||
PaintElementEllipse* element;
|
||||
};
|
||||
};
|
||||
226
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementGroup.cpp
vendored
Normal file
226
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementGroup.cpp
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_PaintElementGroup.h"
|
||||
|
||||
PaintElementGroup::PaintElementGroup (PaintRoutine* pr)
|
||||
: PaintElement (pr, "Group")
|
||||
{
|
||||
}
|
||||
|
||||
PaintElementGroup::~PaintElementGroup() {}
|
||||
|
||||
void PaintElementGroup::ungroup (const bool undoable)
|
||||
{
|
||||
getOwner()->getSelectedElements().deselectAll();
|
||||
getOwner()->getSelectedPoints().deselectAll();
|
||||
|
||||
const int index = getOwner()->indexOfElement (this);
|
||||
|
||||
for (int i = 0; i < subElements.size(); ++i)
|
||||
{
|
||||
std::unique_ptr<XmlElement> xml (subElements.getUnchecked(i)->createXml());
|
||||
|
||||
PaintElement* newOne = getOwner()->addElementFromXml (*xml, index, undoable);
|
||||
getOwner()->getSelectedElements().addToSelection (newOne);
|
||||
}
|
||||
|
||||
getOwner()->removeElement (this, undoable);
|
||||
}
|
||||
|
||||
void PaintElementGroup::groupSelected (PaintRoutine* routine)
|
||||
{
|
||||
if (routine->getSelectedElements().getNumSelected() > 1)
|
||||
{
|
||||
auto* newGroup = new PaintElementGroup (routine);
|
||||
int frontIndex = -1;
|
||||
|
||||
for (int i = 0; i < routine->getNumElements(); ++i)
|
||||
{
|
||||
if (routine->getSelectedElements().isSelected (routine->getElement (i)))
|
||||
{
|
||||
std::unique_ptr<XmlElement> xml (routine->getElement(i)->createXml());
|
||||
|
||||
if (auto* newOne = ObjectTypes::createElementForXml (xml.get(), routine))
|
||||
newGroup->subElements.add (newOne);
|
||||
|
||||
if (i > frontIndex)
|
||||
frontIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
routine->deleteSelected();
|
||||
|
||||
auto* g = routine->addNewElement (newGroup, frontIndex, true);
|
||||
routine->getSelectedElements().selectOnly (g);
|
||||
}
|
||||
}
|
||||
|
||||
int PaintElementGroup::getNumElements() const noexcept { return subElements.size(); }
|
||||
|
||||
PaintElement* PaintElementGroup::getElement (const int index) const noexcept { return subElements [index]; }
|
||||
|
||||
int PaintElementGroup::indexOfElement (const PaintElement* element) const noexcept { return subElements.indexOf (element); }
|
||||
|
||||
bool PaintElementGroup::containsElement (const PaintElement* element) const
|
||||
{
|
||||
if (subElements.contains (element))
|
||||
return true;
|
||||
|
||||
for (int i = subElements.size(); --i >= 0;)
|
||||
if (PaintElementGroup* pg = dynamic_cast<PaintElementGroup*> (subElements.getUnchecked(i)))
|
||||
if (pg->containsElement (element))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintElementGroup::setInitialBounds (int /*parentWidth*/, int /*parentHeight*/)
|
||||
{
|
||||
}
|
||||
|
||||
Rectangle<int> PaintElementGroup::getCurrentBounds (const Rectangle<int>& parentArea) const
|
||||
{
|
||||
Rectangle<int> r;
|
||||
|
||||
if (subElements.size() > 0)
|
||||
{
|
||||
r = subElements.getUnchecked(0)->getCurrentBounds (parentArea);
|
||||
|
||||
for (int i = 1; i < subElements.size(); ++i)
|
||||
r = r.getUnion (subElements.getUnchecked(i)->getCurrentBounds (parentArea));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void PaintElementGroup::setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable)
|
||||
{
|
||||
Rectangle<int> newBounds (b);
|
||||
newBounds.setSize (jmax (1, newBounds.getWidth()),
|
||||
jmax (1, newBounds.getHeight()));
|
||||
|
||||
const Rectangle<int> current (getCurrentBounds (parentArea));
|
||||
|
||||
if (newBounds != current)
|
||||
{
|
||||
const int dx = newBounds.getX() - current.getX();
|
||||
const int dy = newBounds.getY() - current.getY();
|
||||
|
||||
const double scaleStartX = current.getX();
|
||||
const double scaleStartY = current.getY();
|
||||
const double scaleX = newBounds.getWidth() / (double) current.getWidth();
|
||||
const double scaleY = newBounds.getHeight() / (double) current.getHeight();
|
||||
|
||||
for (int i = 0; i < subElements.size(); ++i)
|
||||
{
|
||||
PaintElement* const e = subElements.getUnchecked(i);
|
||||
|
||||
Rectangle<int> pos (e->getCurrentBounds (parentArea));
|
||||
|
||||
const int newX = roundToInt ((pos.getX() - scaleStartX) * scaleX + scaleStartX + dx);
|
||||
const int newY = roundToInt ((pos.getY() - scaleStartY) * scaleY + scaleStartY + dy);
|
||||
|
||||
pos.setBounds (newX, newY,
|
||||
roundToInt ((pos.getRight() - scaleStartX) * scaleX + scaleStartX + dx) - newX,
|
||||
roundToInt ((pos.getBottom() - scaleStartY) * scaleY + scaleStartY + dy) - newY);
|
||||
|
||||
e->setCurrentBounds (pos, parentArea, undoable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintElementGroup::draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
|
||||
{
|
||||
for (int i = 0; i < subElements.size(); ++i)
|
||||
subElements.getUnchecked(i)->draw (g, layout, parentArea);
|
||||
}
|
||||
|
||||
void PaintElementGroup::getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected)
|
||||
{
|
||||
if (! multipleSelected)
|
||||
props.add (new UngroupProperty (this));
|
||||
}
|
||||
|
||||
void PaintElementGroup::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
|
||||
{
|
||||
for (int i = 0; i < subElements.size(); ++i)
|
||||
subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode);
|
||||
}
|
||||
|
||||
const char* PaintElementGroup::getTagName() noexcept { return "GROUP"; }
|
||||
|
||||
XmlElement* PaintElementGroup::createXml() const
|
||||
{
|
||||
XmlElement* e = new XmlElement (getTagName());
|
||||
|
||||
for (int i = 0; i < subElements.size(); ++i)
|
||||
{
|
||||
XmlElement* const sub = subElements.getUnchecked(i)->createXml();
|
||||
e->addChildElement (sub);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool PaintElementGroup::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
for (auto* e : xml.getChildIterator())
|
||||
if (PaintElement* const pe = ObjectTypes::createElementForXml (e, owner))
|
||||
subElements.add (pe);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void PaintElementGroup::applyCustomPaintSnippets (StringArray& snippets)
|
||||
{
|
||||
for (auto* e : subElements)
|
||||
e->applyCustomPaintSnippets (snippets);
|
||||
}
|
||||
|
||||
PaintElementGroup::UngroupProperty::UngroupProperty (PaintElementGroup* const e)
|
||||
: ButtonPropertyComponent ("ungroup", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElementGroup::UngroupProperty::buttonClicked()
|
||||
{
|
||||
element->ungroup (true);
|
||||
}
|
||||
|
||||
String PaintElementGroup::UngroupProperty::getButtonText() const
|
||||
{
|
||||
return "Ungroup";
|
||||
}
|
||||
81
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementGroup.h
vendored
Normal file
81
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementGroup.h
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_PaintElement.h"
|
||||
#include "../jucer_ObjectTypes.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementGroup : public PaintElement
|
||||
{
|
||||
public:
|
||||
PaintElementGroup (PaintRoutine*);
|
||||
~PaintElementGroup() override;
|
||||
|
||||
void ungroup (const bool);
|
||||
|
||||
static void groupSelected (PaintRoutine* const);
|
||||
|
||||
int getNumElements() const noexcept;
|
||||
|
||||
PaintElement* getElement (const int index) const noexcept;
|
||||
int indexOfElement (const PaintElement* element) const noexcept;
|
||||
|
||||
bool containsElement (const PaintElement* element) const;
|
||||
|
||||
//==============================================================================
|
||||
void setInitialBounds (int, int) override;
|
||||
Rectangle<int> getCurrentBounds (const Rectangle<int>&) const override;
|
||||
void setCurrentBounds (const Rectangle<int>&, const Rectangle<int>&, const bool) override;
|
||||
|
||||
//==============================================================================
|
||||
void draw (Graphics&, const ComponentLayout*, const Rectangle<int>&) override;
|
||||
|
||||
void getEditableProperties (Array<PropertyComponent*>&, bool) override;
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode&, String&) override;
|
||||
|
||||
static const char* getTagName() noexcept;
|
||||
|
||||
XmlElement* createXml() const override;
|
||||
|
||||
bool loadFromXml (const XmlElement&) override;
|
||||
|
||||
void applyCustomPaintSnippets (StringArray&) override;
|
||||
|
||||
private:
|
||||
OwnedArray<PaintElement> subElements;
|
||||
|
||||
struct UngroupProperty : public ButtonPropertyComponent
|
||||
{
|
||||
UngroupProperty (PaintElementGroup* const);
|
||||
|
||||
void buttonClicked();
|
||||
String getButtonText() const;
|
||||
|
||||
PaintElementGroup* element;
|
||||
};
|
||||
};
|
||||
428
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp
vendored
Normal file
428
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.cpp
vendored
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_PaintElementImage.h"
|
||||
|
||||
PaintElementImage::PaintElementImage (PaintRoutine* pr)
|
||||
: PaintElement (pr, "Image"),
|
||||
opacity (1.0),
|
||||
mode (stretched)
|
||||
{
|
||||
}
|
||||
|
||||
PaintElementImage::~PaintElementImage() {}
|
||||
|
||||
const Drawable* PaintElementImage::getDrawable()
|
||||
{
|
||||
if (JucerDocument* const document = getDocument())
|
||||
return document->getResources().getDrawable (resourceName);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PaintElementImage::draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
|
||||
{
|
||||
const Rectangle<int> r (position.getRectangle (parentArea, layout));
|
||||
|
||||
if (const Drawable* const image = getDrawable())
|
||||
{
|
||||
image->drawWithin (g, r.toFloat(),
|
||||
mode == stretched ? RectanglePlacement::stretchToFit
|
||||
: (mode == proportionalReducingOnly ? (RectanglePlacement::centred | RectanglePlacement::onlyReduceInSize)
|
||||
: RectanglePlacement::centred),
|
||||
(float) opacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
g.setColour (Colours::grey.withAlpha (0.5f));
|
||||
g.fillRect (r);
|
||||
|
||||
g.setColour (Colours::black);
|
||||
g.drawText ("(image missing)",
|
||||
r.getX(), r.getY(), r.getWidth(), r.getHeight(),
|
||||
Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintElementImage::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
|
||||
{
|
||||
PaintElement::getEditableProperties (props, multipleSelected);
|
||||
|
||||
props.add (new ImageElementResourceProperty (this));
|
||||
props.add (new StretchModeProperty (this));
|
||||
props.add (new OpacityProperty (this));
|
||||
props.add (new ResetSizeProperty (this));
|
||||
}
|
||||
|
||||
void PaintElementImage::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
|
||||
{
|
||||
if (opacity > 0)
|
||||
{
|
||||
String x, y, w, h, r;
|
||||
positionToCode (position, getDocument()->getComponentLayout(), x, y, w, h);
|
||||
r << "{\n"
|
||||
<< " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n"
|
||||
<< " //[UserPaintCustomArguments] Customize the painting arguments here..\n"
|
||||
<< customPaintCode
|
||||
<< " //[/UserPaintCustomArguments]\n";
|
||||
|
||||
if (dynamic_cast<const DrawableImage*> (getDrawable()))
|
||||
{
|
||||
const String imageVariable ("cachedImage_" + resourceName.replace ("::", "_") + "_" + String (code.getUniqueSuffix()));
|
||||
|
||||
code.addImageResourceLoader (imageVariable, resourceName);
|
||||
|
||||
if (opacity >= 254.0 / 255.0)
|
||||
r << " g.setColour (juce::Colours::black);\n";
|
||||
else
|
||||
r << " g.setColour (juce::Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n";
|
||||
|
||||
if (mode == stretched)
|
||||
{
|
||||
r << " g.drawImage (" << imageVariable << ",\n"
|
||||
<< " x, y, width, height,\n"
|
||||
<< " 0, 0, " << imageVariable << ".getWidth(), " << imageVariable << ".getHeight());\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
r << " g.drawImageWithin (" << imageVariable << ",\n"
|
||||
<< " x, y, width, height,\n"
|
||||
<< " ";
|
||||
|
||||
if (mode == proportionalReducingOnly)
|
||||
r << "juce::RectanglePlacement::centred | juce::RectanglePlacement::onlyReduceInSize";
|
||||
else
|
||||
r << "juce::RectanglePlacement::centred";
|
||||
|
||||
r << ",\n"
|
||||
<< " false);\n";
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (resourceName.isNotEmpty())
|
||||
{
|
||||
const String imageVariable ("drawable" + String (code.getUniqueSuffix()));
|
||||
|
||||
code.privateMemberDeclarations
|
||||
<< "std::unique_ptr<juce::Drawable> " << imageVariable << ";\n";
|
||||
|
||||
code.constructorCode
|
||||
<< imageVariable << " = juce::Drawable::createFromImageData ("
|
||||
<< resourceName << ", " << resourceName << "Size);\n";
|
||||
|
||||
code.destructorCode
|
||||
<< imageVariable << " = nullptr;\n";
|
||||
|
||||
if (opacity >= 254.0 / 255.0)
|
||||
r << " g.setColour (juce::Colours::black);\n";
|
||||
else
|
||||
r << " g.setColour (juce::Colours::black.withAlpha (" << CodeHelpers::floatLiteral (opacity, 3) << "));\n";
|
||||
|
||||
r << " jassert (" << imageVariable << " != nullptr);\n"
|
||||
<< " if (" << imageVariable << " != nullptr)\n"
|
||||
<< " " << imageVariable << "->drawWithin (g, juce::Rectangle<int> (x, y, width, height).toFloat(),\n"
|
||||
<< " " << String::repeatedString (" ", imageVariable.length() + 18)
|
||||
<< (mode == stretched ? "juce::RectanglePlacement::stretchToFit"
|
||||
: (mode == proportionalReducingOnly ? "juce::RectanglePlacement::centred | juce::RectanglePlacement::onlyReduceInSize"
|
||||
: "juce::RectanglePlacement::centred"))
|
||||
<< ", " << CodeHelpers::floatLiteral (opacity, 3) << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
r << "}\n\n";
|
||||
|
||||
paintMethodCode += r;
|
||||
}
|
||||
}
|
||||
|
||||
void PaintElementImage::applyCustomPaintSnippets (StringArray& snippets)
|
||||
{
|
||||
customPaintCode.clear();
|
||||
|
||||
if (! snippets.isEmpty() && opacity > 0)
|
||||
{
|
||||
customPaintCode = snippets[0];
|
||||
snippets.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PaintElementImage::SetResourceAction::SetResourceAction (PaintElementImage* const element, const String& newResource_)
|
||||
: PaintElementUndoableAction <PaintElementImage> (element),
|
||||
newResource (newResource_)
|
||||
{
|
||||
oldResource = element->getResource();
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetResourceAction::perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setResource (newResource, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetResourceAction::undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setResource (oldResource, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PaintElementImage::setResource (const String& newName, const bool undoable)
|
||||
{
|
||||
if (resourceName != newName)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetResourceAction (this, newName),
|
||||
"Change image resource");
|
||||
}
|
||||
else
|
||||
{
|
||||
resourceName = newName;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
String PaintElementImage::getResource() const
|
||||
{
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PaintElementImage::SetOpacityAction::SetOpacityAction (PaintElementImage* const element, const double newOpacity_)
|
||||
: PaintElementUndoableAction <PaintElementImage> (element),
|
||||
newOpacity (newOpacity_)
|
||||
{
|
||||
oldOpacity = element->getOpacity();
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetOpacityAction::perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setOpacity (newOpacity, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetOpacityAction::undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setOpacity (oldOpacity, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
void PaintElementImage::setOpacity (double newOpacity, const bool undoable)
|
||||
{
|
||||
newOpacity = jlimit (0.0, 1.0, newOpacity);
|
||||
|
||||
if (opacity != newOpacity)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetOpacityAction (this, newOpacity),
|
||||
"Change image opacity");
|
||||
}
|
||||
else
|
||||
{
|
||||
opacity = newOpacity;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double PaintElementImage::getOpacity() const noexcept { return opacity; }
|
||||
|
||||
//==============================================================================
|
||||
const char* PaintElementImage::getTagName() noexcept { return "IMAGE"; }
|
||||
|
||||
void PaintElementImage::resetToImageSize()
|
||||
{
|
||||
if (const Drawable* const image = getDrawable())
|
||||
{
|
||||
if (PaintRoutineEditor* ed = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
{
|
||||
const Rectangle<int> parentArea (ed->getComponentArea());
|
||||
|
||||
Rectangle<int> r (getCurrentBounds (parentArea));
|
||||
Rectangle<float> b (image->getDrawableBounds());
|
||||
|
||||
r.setSize ((int) (b.getWidth() + 0.999f),
|
||||
(int) (b.getHeight() + 0.999f));
|
||||
|
||||
setCurrentBounds (r, parentArea, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PaintElementImage::SetStretchModeAction::SetStretchModeAction (PaintElementImage* const element, const StretchMode newValue_)
|
||||
: PaintElementUndoableAction <PaintElementImage> (element),
|
||||
newValue (newValue_)
|
||||
{
|
||||
oldValue = element->getStretchMode();
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetStretchModeAction::perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStretchMode (newValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PaintElementImage::SetStretchModeAction::undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setStretchMode (oldValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
PaintElementImage::StretchMode PaintElementImage::getStretchMode() const noexcept { return mode; }
|
||||
|
||||
void PaintElementImage::setStretchMode (const StretchMode newMode, const bool undoable)
|
||||
{
|
||||
if (mode != newMode)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetStretchModeAction (this, newMode),
|
||||
"Change image mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = newMode;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
XmlElement* PaintElementImage::createXml() const
|
||||
{
|
||||
XmlElement* e = new XmlElement (getTagName());
|
||||
position.applyToXml (*e);
|
||||
e->setAttribute ("resource", resourceName);
|
||||
e->setAttribute ("opacity", opacity);
|
||||
e->setAttribute ("mode", (int) mode);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool PaintElementImage::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
position.restoreFromXml (xml, position);
|
||||
resourceName = xml.getStringAttribute ("resource", String());
|
||||
opacity = xml.getDoubleAttribute ("opacity", 1.0);
|
||||
mode = (StretchMode) xml.getIntAttribute ("mode", (int) stretched);
|
||||
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PaintElementImage::ImageElementResourceProperty::ImageElementResourceProperty (PaintElementImage* const e)
|
||||
: ImageResourceProperty <PaintElementImage> (e, "image source")
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElementImage::ImageElementResourceProperty::setResource (const String& newName)
|
||||
{
|
||||
if (element != nullptr)
|
||||
element->setResource (newName, true);
|
||||
}
|
||||
|
||||
String PaintElementImage::ImageElementResourceProperty::getResource() const
|
||||
{
|
||||
if (element != nullptr)
|
||||
return element->getResource();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
PaintElementImage::OpacityProperty::OpacityProperty (PaintElementImage* const e)
|
||||
: SliderPropertyComponent ("opacity", 0.0, 1.0, 0.001),
|
||||
listener (e)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
}
|
||||
|
||||
void PaintElementImage::OpacityProperty::setValue (double newValue)
|
||||
{
|
||||
listener.owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
listener.owner->setOpacity (newValue, true);
|
||||
}
|
||||
|
||||
double PaintElementImage::OpacityProperty::getValue() const
|
||||
{
|
||||
return listener.owner->getOpacity();
|
||||
}
|
||||
|
||||
PaintElementImage::StretchModeProperty::StretchModeProperty (PaintElementImage* const e)
|
||||
: ChoicePropertyComponent ("stretch mode"),
|
||||
listener (e)
|
||||
{
|
||||
listener.setPropertyToRefresh (*this);
|
||||
|
||||
choices.add ("Stretched to fit");
|
||||
choices.add ("Maintain aspect ratio");
|
||||
choices.add ("Maintain aspect ratio, only reduce in size");
|
||||
}
|
||||
|
||||
void PaintElementImage::StretchModeProperty::setIndex (int newIndex)
|
||||
{
|
||||
listener.owner->setStretchMode ((StretchMode) newIndex, true);
|
||||
}
|
||||
|
||||
int PaintElementImage::StretchModeProperty::getIndex() const
|
||||
{
|
||||
return (int) listener.owner->getStretchMode();
|
||||
}
|
||||
|
||||
PaintElementImage::ResetSizeProperty::ResetSizeProperty (PaintElementImage* const e)
|
||||
: ButtonPropertyComponent ("reset", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void PaintElementImage::ResetSizeProperty::buttonClicked()
|
||||
{
|
||||
element->resetToImageSize();
|
||||
}
|
||||
|
||||
String PaintElementImage::ResetSizeProperty::getButtonText() const { return "reset to image size"; }
|
||||
165
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.h
vendored
Normal file
165
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementImage.h
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
#include "../Properties/jucer_FilePropertyComponent.h"
|
||||
#include "jucer_ImageResourceProperty.h"
|
||||
#include "jucer_PaintElementUndoableAction.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementImage : public PaintElement
|
||||
{
|
||||
public:
|
||||
PaintElementImage (PaintRoutine*);
|
||||
~PaintElementImage() override;
|
||||
|
||||
enum StretchMode
|
||||
{
|
||||
stretched = 0,
|
||||
proportional = 1,
|
||||
proportionalReducingOnly = 2
|
||||
};
|
||||
|
||||
const Drawable* getDrawable();
|
||||
void draw (Graphics&, const ComponentLayout*, const Rectangle<int>&) override;
|
||||
|
||||
//==============================================================================
|
||||
void getEditableProperties (Array <PropertyComponent*>&, bool) override;
|
||||
void fillInGeneratedCode (GeneratedCode&, String&) override;
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override;
|
||||
|
||||
//==============================================================================
|
||||
class SetResourceAction : public PaintElementUndoableAction <PaintElementImage>
|
||||
{
|
||||
public:
|
||||
SetResourceAction (PaintElementImage* const, const String&);
|
||||
|
||||
bool perform();
|
||||
bool undo();
|
||||
|
||||
private:
|
||||
String newResource, oldResource;
|
||||
};
|
||||
|
||||
void setResource (const String&, const bool);
|
||||
|
||||
String getResource() const;
|
||||
|
||||
//==============================================================================
|
||||
class SetOpacityAction : public PaintElementUndoableAction <PaintElementImage>
|
||||
{
|
||||
public:
|
||||
SetOpacityAction (PaintElementImage* const, const double);
|
||||
|
||||
bool perform();
|
||||
bool undo();
|
||||
|
||||
private:
|
||||
double newOpacity, oldOpacity;
|
||||
};
|
||||
|
||||
void setOpacity (double, const bool);
|
||||
double getOpacity() const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
static const char* getTagName() noexcept;
|
||||
|
||||
void resetToImageSize();
|
||||
|
||||
//==============================================================================
|
||||
class SetStretchModeAction : public PaintElementUndoableAction <PaintElementImage>
|
||||
{
|
||||
public:
|
||||
SetStretchModeAction (PaintElementImage* const, const StretchMode);
|
||||
|
||||
bool perform();
|
||||
bool undo();
|
||||
|
||||
private:
|
||||
StretchMode newValue, oldValue;
|
||||
};
|
||||
|
||||
StretchMode getStretchMode() const noexcept;
|
||||
|
||||
void setStretchMode (const StretchMode, const bool);
|
||||
|
||||
//==============================================================================
|
||||
XmlElement* createXml() const override;
|
||||
|
||||
bool loadFromXml (const XmlElement&) override;
|
||||
|
||||
private:
|
||||
String resourceName;
|
||||
double opacity;
|
||||
StretchMode mode;
|
||||
String customPaintCode;
|
||||
|
||||
//==============================================================================
|
||||
class ImageElementResourceProperty : public ImageResourceProperty <PaintElementImage>
|
||||
{
|
||||
public:
|
||||
ImageElementResourceProperty (PaintElementImage* const);
|
||||
|
||||
void setResource (const String&);
|
||||
String getResource() const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class OpacityProperty : public SliderPropertyComponent
|
||||
{
|
||||
public:
|
||||
OpacityProperty (PaintElementImage* const);
|
||||
|
||||
void setValue (double);
|
||||
double getValue() const;
|
||||
|
||||
ElementListener<PaintElementImage> listener;
|
||||
};
|
||||
|
||||
class StretchModeProperty : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
StretchModeProperty (PaintElementImage* const);
|
||||
|
||||
void setIndex (int);
|
||||
int getIndex() const;
|
||||
|
||||
ElementListener<PaintElementImage> listener;
|
||||
};
|
||||
|
||||
class ResetSizeProperty : public ButtonPropertyComponent
|
||||
{
|
||||
public:
|
||||
ResetSizeProperty (PaintElementImage* const);
|
||||
|
||||
void buttonClicked();
|
||||
String getButtonText() const;
|
||||
|
||||
private:
|
||||
PaintElementImage* const element;
|
||||
};
|
||||
};
|
||||
1668
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementPath.cpp
vendored
Normal file
1668
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementPath.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
176
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementPath.h
vendored
Normal file
176
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementPath.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
#include "jucer_ElementSiblingComponent.h"
|
||||
class PathPointComponent;
|
||||
class PaintElementPath;
|
||||
|
||||
//==============================================================================
|
||||
class PathPoint
|
||||
{
|
||||
public:
|
||||
PathPoint (PaintElementPath* const owner);
|
||||
PathPoint (const PathPoint& other);
|
||||
PathPoint& operator= (const PathPoint& other);
|
||||
~PathPoint();
|
||||
|
||||
static constexpr auto maxRects = 3;
|
||||
|
||||
PaintElementPath* owner;
|
||||
Path::Iterator::PathElementType type;
|
||||
RelativePositionedRectangle pos [maxRects];
|
||||
|
||||
int getNumPoints() const;
|
||||
|
||||
void changePointType (const Path::Iterator::PathElementType newType,
|
||||
const Rectangle<int>& parentArea,
|
||||
const bool undoable);
|
||||
|
||||
void deleteFromPath();
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected);
|
||||
|
||||
private:
|
||||
PathPoint withChangedPointType (const Path::Iterator::PathElementType newType,
|
||||
const Rectangle<int>& parentArea) const;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementPath : public ColouredElement
|
||||
{
|
||||
public:
|
||||
PaintElementPath (PaintRoutine* owner);
|
||||
~PaintElementPath() override;
|
||||
|
||||
//==============================================================================
|
||||
void setInitialBounds (int parentWidth, int parentHeight) override;
|
||||
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const override;
|
||||
void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable) override;
|
||||
|
||||
//==============================================================================
|
||||
bool getPoint (int index, int pointNumber, double& x, double& y, const Rectangle<int>& parentArea) const;
|
||||
void movePoint (int index, int pointNumber, double newX, double newY, const Rectangle<int>& parentArea, const bool undoable);
|
||||
|
||||
RelativePositionedRectangle getPoint (int index, int pointNumber) const;
|
||||
void setPoint (int index, int pointNumber, const RelativePositionedRectangle& newPoint, const bool undoable);
|
||||
|
||||
int getNumPoints() const noexcept { return points.size(); }
|
||||
PathPoint* getPoint (int index) const noexcept { return points [index]; }
|
||||
int indexOfPoint (PathPoint* const p) const noexcept { return points.indexOf (p); }
|
||||
|
||||
PathPoint* addPoint (int pointIndexToAddItAfter, const bool undoable);
|
||||
void deletePoint (int pointIndex, const bool undoable);
|
||||
|
||||
void pointListChanged();
|
||||
|
||||
int findSegmentAtXY (int x, int y) const;
|
||||
|
||||
//==============================================================================
|
||||
bool isSubpathClosed (int pointIndex) const;
|
||||
void setSubpathClosed (int pointIndex, const bool closed, const bool undoable);
|
||||
|
||||
bool isNonZeroWinding() const noexcept { return nonZeroWinding; }
|
||||
void setNonZeroWinding (const bool nonZero, const bool undoable);
|
||||
|
||||
//==============================================================================
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override;
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override;
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override;
|
||||
|
||||
//==============================================================================
|
||||
static const char* getTagName() noexcept { return "PATH"; }
|
||||
XmlElement* createXml() const override;
|
||||
bool loadFromXml (const XmlElement& xml) override;
|
||||
|
||||
void setToPath (const Path& p);
|
||||
|
||||
//==============================================================================
|
||||
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override;
|
||||
void drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo) override;
|
||||
|
||||
void resized() override;
|
||||
void parentSizeChanged() override;
|
||||
|
||||
void mouseDown (const MouseEvent& e) override;
|
||||
void mouseDrag (const MouseEvent& e) override;
|
||||
void mouseUp (const MouseEvent& e) override;
|
||||
|
||||
void createSiblingComponents() override;
|
||||
void changed() override;
|
||||
|
||||
private:
|
||||
friend class PathPoint;
|
||||
friend class PathPointComponent;
|
||||
OwnedArray<PathPoint> points;
|
||||
bool nonZeroWinding;
|
||||
mutable Path path;
|
||||
mutable Rectangle<int> lastPathBounds;
|
||||
int mouseDownOnSegment;
|
||||
bool mouseDownSelectSegmentStatus;
|
||||
String customPaintCode;
|
||||
|
||||
String pathToString() const;
|
||||
void restorePathFromString (const String& s);
|
||||
void updateStoredPath (const ComponentLayout* layout, const Rectangle<int>& parentArea) const;
|
||||
int getBorderSize() const;
|
||||
|
||||
void rescalePoint (RelativePositionedRectangle& pos, int dx, int dy,
|
||||
double scaleX, double scaleY,
|
||||
double scaleStartX, double scaleStartY,
|
||||
const Rectangle<int>& parentArea) const;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class PathPointComponent : public ElementSiblingComponent
|
||||
{
|
||||
public:
|
||||
PathPointComponent (PaintElementPath* const path_,
|
||||
const int index, const int pointNumber);
|
||||
|
||||
~PathPointComponent();
|
||||
|
||||
void updatePosition();
|
||||
void showPopupMenu();
|
||||
|
||||
void paint (Graphics& g);
|
||||
void mouseDown (const MouseEvent& e);
|
||||
void mouseDrag (const MouseEvent& e);
|
||||
void mouseUp (const MouseEvent& e);
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
|
||||
private:
|
||||
PaintElementPath* const path;
|
||||
PaintRoutine* const routine;
|
||||
const int index;
|
||||
const int pointNumber;
|
||||
int dragX, dragY;
|
||||
bool selected, dragging, mouseDownSelectStatus;
|
||||
};
|
||||
184
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRectangle.h
vendored
Normal file
184
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRectangle.h
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementRectangle : public ColouredElement
|
||||
{
|
||||
public:
|
||||
PaintElementRectangle (PaintRoutine* pr)
|
||||
: ColouredElement (pr, "Rectangle", true, false)
|
||||
{
|
||||
}
|
||||
|
||||
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const override
|
||||
{
|
||||
return PaintElement::getCurrentBounds (parentArea); // bypass the ColouredElement implementation
|
||||
}
|
||||
|
||||
void setCurrentBounds (const Rectangle<int>& newBounds, const Rectangle<int>& parentArea, const bool undoable) override
|
||||
{
|
||||
PaintElement::setCurrentBounds (newBounds, parentArea, undoable); // bypass the ColouredElement implementation
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
|
||||
{
|
||||
Component tempParentComp;
|
||||
tempParentComp.setBounds (parentArea);
|
||||
|
||||
fillType.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
const Rectangle<int> r (position.getRectangle (parentArea, layout));
|
||||
g.fillRect (r);
|
||||
|
||||
if (isStrokePresent)
|
||||
{
|
||||
strokeType.fill.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
g.drawRect (r.getX(), r.getY(), r.getWidth(), r.getHeight(),
|
||||
roundToInt (getStrokeType().stroke.getStrokeThickness()));
|
||||
}
|
||||
}
|
||||
|
||||
void getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ColouredElement::getEditableProperties (props, multipleSelected);
|
||||
|
||||
props.add (new ShapeToPathProperty (this));
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
|
||||
{
|
||||
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
|
||||
return;
|
||||
|
||||
String x, y, w, h, s;
|
||||
positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
|
||||
|
||||
s << "{\n"
|
||||
<< " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
s << " " << fillType.generateVariablesCode ("fill");
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
s << " " << strokeType.fill.generateVariablesCode ("stroke");
|
||||
|
||||
s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n"
|
||||
<< customPaintCode
|
||||
<< " //[/UserPaintCustomArguments]\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
fillType.fillInGeneratedCode ("fill", position, code, s);
|
||||
s << " g.fillRect (x, y, width, height);\n";
|
||||
}
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
strokeType.fill.fillInGeneratedCode ("stroke", position, code, s);
|
||||
s << " g.drawRect (x, y, width, height, " << roundToInt (strokeType.stroke.getStrokeThickness()) << ");\n\n";
|
||||
}
|
||||
|
||||
s << "}\n\n";
|
||||
|
||||
paintMethodCode += s;
|
||||
}
|
||||
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override
|
||||
{
|
||||
customPaintCode.clear();
|
||||
|
||||
if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible())))
|
||||
{
|
||||
customPaintCode = snippets[0];
|
||||
snippets.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getTagName() noexcept { return "RECT"; }
|
||||
|
||||
XmlElement* createXml() const override
|
||||
{
|
||||
XmlElement* e = new XmlElement (getTagName());
|
||||
position.applyToXml (*e);
|
||||
|
||||
addColourAttributes (e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool loadFromXml (const XmlElement& xml) override
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
position.restoreFromXml (xml, position);
|
||||
loadColourAttributes (xml);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void convertToPath()
|
||||
{
|
||||
Path path;
|
||||
path.addRectangle (getCurrentAbsoluteBounds());
|
||||
convertToNewPathElement (path);
|
||||
}
|
||||
|
||||
private:
|
||||
String customPaintCode;
|
||||
|
||||
class ShapeToPathProperty : public ButtonPropertyComponent
|
||||
{
|
||||
public:
|
||||
ShapeToPathProperty (PaintElementRectangle* const e)
|
||||
: ButtonPropertyComponent ("path", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
element->convertToPath();
|
||||
}
|
||||
|
||||
String getButtonText() const
|
||||
{
|
||||
return "convert to a path";
|
||||
}
|
||||
|
||||
private:
|
||||
PaintElementRectangle* const element;
|
||||
};
|
||||
};
|
||||
267
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h
vendored
Normal file
267
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementRoundedRectangle.h
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementRoundedRectangle : public ColouredElement
|
||||
{
|
||||
public:
|
||||
PaintElementRoundedRectangle (PaintRoutine* pr)
|
||||
: ColouredElement (pr, "Rounded Rectangle", true, false)
|
||||
{
|
||||
cornerSize = 10.0;
|
||||
}
|
||||
|
||||
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
|
||||
{
|
||||
double x, y, w, h;
|
||||
position.getRectangleDouble (x, y, w, h, parentArea, layout);
|
||||
|
||||
fillType.setFillType (g, getDocument(), parentArea);
|
||||
g.fillRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
|
||||
|
||||
if (isStrokePresent)
|
||||
{
|
||||
strokeType.fill.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
g.drawRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize,
|
||||
getStrokeType().stroke.getStrokeThickness());
|
||||
}
|
||||
}
|
||||
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
props.add (new CornerSizeProperty (this));
|
||||
|
||||
ColouredElement::getEditableProperties (props, multipleSelected);
|
||||
|
||||
props.add (new ShapeToPathProperty (this));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SetCornerSizeAction : public PaintElementUndoableAction <PaintElementRoundedRectangle>
|
||||
{
|
||||
public:
|
||||
SetCornerSizeAction (PaintElementRoundedRectangle* const element, const double newSize_)
|
||||
: PaintElementUndoableAction <PaintElementRoundedRectangle> (element),
|
||||
newSize (newSize_)
|
||||
{
|
||||
oldSize = element->getCornerSize();
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setCornerSize (newSize, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setCornerSize (oldSize, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
double newSize, oldSize;
|
||||
};
|
||||
|
||||
void setCornerSize (const double newSize, const bool undoable)
|
||||
{
|
||||
if (newSize != cornerSize)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetCornerSizeAction (this, newSize),
|
||||
"Change rounded rectangle corner size");
|
||||
}
|
||||
else
|
||||
{
|
||||
cornerSize = newSize;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double getCornerSize() const noexcept { return cornerSize; }
|
||||
|
||||
//==============================================================================
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
|
||||
{
|
||||
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
|
||||
return;
|
||||
|
||||
String x, y, w, h, s;
|
||||
positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
|
||||
|
||||
s << "{\n"
|
||||
<< " float x = " << castToFloat (x) << ", y = " << castToFloat (y) << ", "
|
||||
<< "width = " << castToFloat (w) << ", height = " << castToFloat (h) << ";\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
s << " " << fillType.generateVariablesCode ("fill");
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
s << " " << strokeType.fill.generateVariablesCode ("stroke");
|
||||
|
||||
s << " //[UserPaintCustomArguments] Customize the painting arguments here..\n"
|
||||
<< customPaintCode
|
||||
<< " //[/UserPaintCustomArguments]\n";
|
||||
|
||||
if (! fillType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
fillType.fillInGeneratedCode ("fill", position, code, s);
|
||||
s << " g.fillRoundedRectangle (x, y, width, height, " << CodeHelpers::floatLiteral (cornerSize, 3) << ");\n";
|
||||
}
|
||||
|
||||
if (isStrokePresent && ! strokeType.isInvisible())
|
||||
{
|
||||
s << " ";
|
||||
strokeType.fill.fillInGeneratedCode ("stroke", position, code, s);
|
||||
s << " g.drawRoundedRectangle (x, y, width, height, " << CodeHelpers::floatLiteral (cornerSize, 3)
|
||||
<< ", " << CodeHelpers::floatLiteral (strokeType.stroke.getStrokeThickness(), 3) << ");\n";
|
||||
}
|
||||
|
||||
s << "}\n\n";
|
||||
|
||||
paintMethodCode += s;
|
||||
}
|
||||
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override
|
||||
{
|
||||
customPaintCode.clear();
|
||||
|
||||
if (! snippets.isEmpty() && (! fillType.isInvisible() || (isStrokePresent && ! strokeType.isInvisible())))
|
||||
{
|
||||
customPaintCode = snippets[0];
|
||||
snippets.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getTagName() noexcept { return "ROUNDRECT"; }
|
||||
|
||||
XmlElement* createXml() const override
|
||||
{
|
||||
XmlElement* const e = new XmlElement (getTagName());
|
||||
|
||||
position.applyToXml (*e);
|
||||
e->setAttribute ("cornerSize", cornerSize);
|
||||
addColourAttributes (e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool loadFromXml (const XmlElement& xml) override
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
position.restoreFromXml (xml, position);
|
||||
cornerSize = xml.getDoubleAttribute ("cornerSize", 10.0);
|
||||
loadColourAttributes (xml);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
void convertToPath()
|
||||
{
|
||||
double x, y, w, h;
|
||||
getCurrentAbsoluteBoundsDouble (x, y, w, h);
|
||||
|
||||
Path path;
|
||||
path.addRoundedRectangle ((float) x, (float) y, (float) w, (float) h, (float) cornerSize);
|
||||
|
||||
convertToNewPathElement (path);
|
||||
}
|
||||
|
||||
private:
|
||||
double cornerSize;
|
||||
String customPaintCode;
|
||||
|
||||
//==============================================================================
|
||||
class CornerSizeProperty : public SliderPropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
CornerSizeProperty (PaintElementRoundedRectangle* const owner_)
|
||||
: SliderPropertyComponent ("corner size", 1.0, 200.0, 0.5, 0.4),
|
||||
owner (owner_)
|
||||
{
|
||||
owner->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~CornerSizeProperty() override
|
||||
{
|
||||
owner->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
owner->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
owner->setCornerSize (newValue, true);
|
||||
}
|
||||
|
||||
double getValue() const override { return owner->getCornerSize(); }
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
PaintElementRoundedRectangle* const owner;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ShapeToPathProperty : public ButtonPropertyComponent
|
||||
{
|
||||
public:
|
||||
ShapeToPathProperty (PaintElementRoundedRectangle* const e)
|
||||
: ButtonPropertyComponent ("path", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
element->convertToPath();
|
||||
}
|
||||
|
||||
String getButtonText() const
|
||||
{
|
||||
return "convert to a path";
|
||||
}
|
||||
|
||||
private:
|
||||
PaintElementRoundedRectangle* const element;
|
||||
};
|
||||
};
|
||||
672
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h
vendored
Normal file
672
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementText.h
vendored
Normal file
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColouredElement.h"
|
||||
#include "../Properties/jucer_FontPropertyComponent.h"
|
||||
#include "../Properties/jucer_JustificationProperty.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintElementText : public ColouredElement
|
||||
{
|
||||
public:
|
||||
PaintElementText (PaintRoutine* pr)
|
||||
: ColouredElement (pr, "Text", false, false),
|
||||
text ("Your text goes here"),
|
||||
font (15.0f),
|
||||
typefaceName (FontPropertyComponent::getDefaultFont()),
|
||||
justification (Justification::centred)
|
||||
{
|
||||
fillType.colour = Colours::black;
|
||||
position.rect.setWidth (200);
|
||||
position.rect.setHeight (30);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
|
||||
{
|
||||
fillType.setFillType (g, getDocument(), parentArea);
|
||||
|
||||
font = FontPropertyComponent::applyNameToFont (typefaceName, font);
|
||||
g.setFont (font);
|
||||
|
||||
g.drawText (replaceStringTranslations (text, owner->getDocument()),
|
||||
position.getRectangle (parentArea, layout), justification, true);
|
||||
}
|
||||
|
||||
static String replaceStringTranslations (String s, JucerDocument* document)
|
||||
{
|
||||
s = s.replace ("%%getName()%%", document->getComponentName());
|
||||
s = s.replace ("%%getButtonText()%%", document->getComponentName());
|
||||
return s;
|
||||
}
|
||||
|
||||
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
|
||||
{
|
||||
ColouredElement::getEditableProperties (props, multipleSelected);
|
||||
|
||||
if (multipleSelected)
|
||||
return;
|
||||
|
||||
props.add (new TextProperty (this));
|
||||
props.add (new FontNameProperty (this));
|
||||
props.add (new FontStyleProperty (this));
|
||||
props.add (new FontSizeProperty (this));
|
||||
props.add (new FontKerningProperty (this));
|
||||
props.add (new TextJustificationProperty (this));
|
||||
props.add (new TextToPathProperty (this));
|
||||
}
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
|
||||
{
|
||||
if (! fillType.isInvisible())
|
||||
{
|
||||
String x, y, w, h, r;
|
||||
positionToCode (position, code.document->getComponentLayout(), x, y, w, h);
|
||||
r << "{\n"
|
||||
<< " int x = " << x << ", y = " << y << ", width = " << w << ", height = " << h << ";\n"
|
||||
<< " juce::String text (" << quotedString (text, code.shouldUseTransMacro()) << ");\n"
|
||||
<< " " << fillType.generateVariablesCode ("fill")
|
||||
<< " //[UserPaintCustomArguments] Customize the painting arguments here..\n"
|
||||
<< customPaintCode
|
||||
<< " //[/UserPaintCustomArguments]\n"
|
||||
<< " ";
|
||||
fillType.fillInGeneratedCode ("fill", position, code, r);
|
||||
r << " g.setFont (" << FontPropertyComponent::getCompleteFontCode (font, typefaceName) << ");\n"
|
||||
<< " g.drawText (text, x, y, width, height,\n"
|
||||
<< " " << CodeHelpers::justificationToCode (justification) << ", true);\n"
|
||||
<< "}\n\n";
|
||||
|
||||
paintMethodCode += r;
|
||||
}
|
||||
}
|
||||
|
||||
void applyCustomPaintSnippets (StringArray& snippets) override
|
||||
{
|
||||
customPaintCode.clear();
|
||||
|
||||
if (! snippets.isEmpty() && ! fillType.isInvisible())
|
||||
{
|
||||
customPaintCode = snippets[0];
|
||||
snippets.remove (0);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getTagName() noexcept { return "TEXT"; }
|
||||
|
||||
XmlElement* createXml() const override
|
||||
{
|
||||
XmlElement* e = new XmlElement (getTagName());
|
||||
position.applyToXml (*e);
|
||||
addColourAttributes (e);
|
||||
e->setAttribute ("text", text);
|
||||
e->setAttribute ("fontname", typefaceName);
|
||||
e->setAttribute ("fontsize", roundToInt (font.getHeight() * 100.0) / 100.0);
|
||||
e->setAttribute ("kerning", roundToInt (font.getExtraKerningFactor() * 1000.0) / 1000.0);
|
||||
e->setAttribute ("bold", font.isBold());
|
||||
e->setAttribute ("italic", font.isItalic());
|
||||
e->setAttribute ("justification", justification.getFlags());
|
||||
if (font.getTypefaceStyle() != "Regular")
|
||||
{
|
||||
e->setAttribute ("typefaceStyle", font.getTypefaceStyle());
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
bool loadFromXml (const XmlElement& xml) override
|
||||
{
|
||||
if (xml.hasTagName (getTagName()))
|
||||
{
|
||||
position.restoreFromXml (xml, position);
|
||||
loadColourAttributes (xml);
|
||||
|
||||
text = xml.getStringAttribute ("text", "Hello World");
|
||||
typefaceName = xml.getStringAttribute ("fontname", FontPropertyComponent::getDefaultFont());
|
||||
font = FontPropertyComponent::applyNameToFont (typefaceName, font);
|
||||
font.setHeight ((float) xml.getDoubleAttribute ("fontsize", 15.0));
|
||||
font.setBold (xml.getBoolAttribute ("bold", false));
|
||||
font.setItalic (xml.getBoolAttribute ("italic", false));
|
||||
font.setExtraKerningFactor ((float) xml.getDoubleAttribute ("kerning", 0.0));
|
||||
justification = Justification (xml.getIntAttribute ("justification", Justification::centred));
|
||||
auto fontStyle = xml.getStringAttribute ("typefaceStyle");
|
||||
if (! fontStyle.isEmpty())
|
||||
font.setTypefaceStyle (fontStyle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const String& getText() const noexcept { return text; }
|
||||
|
||||
class SetTextAction : public PaintElementUndoableAction <PaintElementText>
|
||||
{
|
||||
public:
|
||||
SetTextAction (PaintElementText* const element, const String& newText_)
|
||||
: PaintElementUndoableAction <PaintElementText> (element),
|
||||
newText (newText_),
|
||||
oldText (element->getText())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setText (newText, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setText (oldText, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
String newText, oldText;
|
||||
};
|
||||
|
||||
void setText (const String& t, const bool undoable)
|
||||
{
|
||||
if (t != text)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetTextAction (this, t),
|
||||
"Change text element text");
|
||||
}
|
||||
else
|
||||
{
|
||||
text = t;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const Font& getFont() const { return font; }
|
||||
|
||||
class SetFontAction : public PaintElementUndoableAction <PaintElementText>
|
||||
{
|
||||
public:
|
||||
SetFontAction (PaintElementText* const element, const Font& newFont_)
|
||||
: PaintElementUndoableAction <PaintElementText> (element),
|
||||
newFont (newFont_),
|
||||
oldFont (element->getFont())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setFont (newFont, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setFont (oldFont, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Font newFont, oldFont;
|
||||
};
|
||||
|
||||
void setFont (const Font& newFont, const bool undoable)
|
||||
{
|
||||
if (font != newFont)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetFontAction (this, newFont),
|
||||
"Change text element font");
|
||||
}
|
||||
else
|
||||
{
|
||||
font = newFont;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class SetTypefaceAction : public PaintElementUndoableAction <PaintElementText>
|
||||
{
|
||||
public:
|
||||
SetTypefaceAction (PaintElementText* const element, const String& newValue_)
|
||||
: PaintElementUndoableAction <PaintElementText> (element),
|
||||
newValue (newValue_),
|
||||
oldValue (element->getTypefaceName())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setTypefaceName (newValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setTypefaceName (oldValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
String newValue, oldValue;
|
||||
};
|
||||
|
||||
void setTypefaceName (const String& newFontName, const bool undoable)
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetTypefaceAction (this, newFontName),
|
||||
"Change text element typeface");
|
||||
}
|
||||
else
|
||||
{
|
||||
typefaceName = newFontName;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
String getTypefaceName() const noexcept { return typefaceName; }
|
||||
|
||||
//==============================================================================
|
||||
Justification getJustification() const noexcept { return justification; }
|
||||
|
||||
class SetJustifyAction : public PaintElementUndoableAction <PaintElementText>
|
||||
{
|
||||
public:
|
||||
SetJustifyAction (PaintElementText* const element, Justification newValue_)
|
||||
: PaintElementUndoableAction <PaintElementText> (element),
|
||||
newValue (newValue_),
|
||||
oldValue (element->getJustification())
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setJustification (newValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
getElement()->setJustification (oldValue, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
Justification newValue, oldValue;
|
||||
};
|
||||
|
||||
void setJustification (Justification j, const bool undoable)
|
||||
{
|
||||
if (justification.getFlags() != j.getFlags())
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new SetJustifyAction (this, j),
|
||||
"Change text element justification");
|
||||
}
|
||||
else
|
||||
{
|
||||
justification = j;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void convertToPath()
|
||||
{
|
||||
if (PaintRoutineEditor* parent = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
|
||||
{
|
||||
|
||||
font = FontPropertyComponent::applyNameToFont (typefaceName, font);
|
||||
|
||||
const Rectangle<int> r =
|
||||
getCurrentBounds (parent->getComponentArea().withZeroOrigin());
|
||||
|
||||
GlyphArrangement arr;
|
||||
arr.addCurtailedLineOfText (font, text,
|
||||
0.0f, 0.0f, (float) r.getWidth(),
|
||||
true);
|
||||
|
||||
arr.justifyGlyphs (0, arr.getNumGlyphs(),
|
||||
(float) r.getX(), (float) r.getY(),
|
||||
(float) r.getWidth(), (float) r.getHeight(),
|
||||
justification);
|
||||
|
||||
Path path;
|
||||
arr.createPath (path);
|
||||
|
||||
convertToNewPathElement (path);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
String text;
|
||||
Font font;
|
||||
String typefaceName;
|
||||
Justification justification;
|
||||
String customPaintCode;
|
||||
|
||||
Array <Justification> justificationTypes;
|
||||
|
||||
//==============================================================================
|
||||
class TextProperty : public TextPropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
TextProperty (PaintElementText* const e)
|
||||
: TextPropertyComponent ("text", 2048, false),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~TextProperty() override
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setText (const String& newText) override { element->setText (newText, true); }
|
||||
String getText() const override { return element->getText(); }
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontNameProperty : public FontPropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
FontNameProperty (PaintElementText* const e)
|
||||
: FontPropertyComponent ("font"),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontNameProperty()
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setTypefaceName (const String& newFontName) { element->setTypefaceName (newFontName, true); }
|
||||
String getTypefaceName() const { return element->getTypefaceName(); }
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) { refresh(); }
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontStyleProperty : public ChoicePropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
FontStyleProperty (PaintElementText* const e)
|
||||
: ChoicePropertyComponent ("style"),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
|
||||
updateStylesList (element->getTypefaceName());
|
||||
}
|
||||
|
||||
~FontStyleProperty()
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void updateStylesList (const String& name)
|
||||
{
|
||||
if (getNumChildComponents() > 0)
|
||||
{
|
||||
if (auto cb = dynamic_cast<ComboBox*> (getChildComponent (0)))
|
||||
cb->clear();
|
||||
|
||||
getChildComponent (0)->setVisible (false);
|
||||
removeAllChildren();
|
||||
}
|
||||
|
||||
choices.clear();
|
||||
|
||||
choices.add ("Regular");
|
||||
choices.add ("Bold");
|
||||
choices.add ("Italic");
|
||||
choices.add ("Bold Italic");
|
||||
|
||||
choices.mergeArray (Font::findAllTypefaceStyles (name));
|
||||
refresh();
|
||||
}
|
||||
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
Font f (element->getFont());
|
||||
|
||||
if (f.getAvailableStyles().contains (choices[newIndex]))
|
||||
{
|
||||
f.setBold (false);
|
||||
f.setItalic (false);
|
||||
f.setTypefaceStyle (choices[newIndex]);
|
||||
}
|
||||
else
|
||||
{
|
||||
f.setTypefaceStyle ("Regular");
|
||||
f.setBold (newIndex == 1 || newIndex == 3);
|
||||
f.setItalic (newIndex == 2 || newIndex == 3);
|
||||
}
|
||||
|
||||
element->setFont (f, true);
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
auto f = element->getFont();
|
||||
|
||||
const auto typefaceIndex = choices.indexOf (f.getTypefaceStyle());
|
||||
if (typefaceIndex == -1)
|
||||
{
|
||||
if (f.isBold() && f.isItalic())
|
||||
return 3;
|
||||
else if (f.isBold())
|
||||
return 1;
|
||||
else if (f.isItalic())
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return typefaceIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
updateStylesList (element->getTypefaceName());
|
||||
}
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontSizeProperty : public SliderPropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
FontSizeProperty (PaintElementText* const e)
|
||||
: SliderPropertyComponent ("size", 1.0, 250.0, 0.1, 0.3),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontSizeProperty() override
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
element->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
Font f (element->getFont());
|
||||
f.setHeight ((float) newValue);
|
||||
|
||||
element->setFont (f, true);
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return element->getFont().getHeight();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class FontKerningProperty : public SliderPropertyComponent,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
FontKerningProperty (PaintElementText* const e)
|
||||
: SliderPropertyComponent ("kerning", -0.5, 0.5, 0.001),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~FontKerningProperty() override
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setValue (double newValue) override
|
||||
{
|
||||
element->getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
Font f (element->getFont());
|
||||
f.setExtraKerningFactor ((float) newValue);
|
||||
|
||||
element->setFont (f, true);
|
||||
}
|
||||
|
||||
double getValue() const override
|
||||
{
|
||||
return element->getFont().getExtraKerningFactor();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextJustificationProperty : public JustificationProperty,
|
||||
private juce::ChangeListener
|
||||
{
|
||||
public:
|
||||
TextJustificationProperty (PaintElementText* const e)
|
||||
: JustificationProperty ("layout", false),
|
||||
element (e)
|
||||
{
|
||||
element->getDocument()->addChangeListener (this);
|
||||
}
|
||||
|
||||
~TextJustificationProperty() override
|
||||
{
|
||||
element->getDocument()->removeChangeListener (this);
|
||||
}
|
||||
|
||||
void setJustification (Justification newJustification) override
|
||||
{
|
||||
element->setJustification (newJustification, true);
|
||||
}
|
||||
|
||||
Justification getJustification() const override
|
||||
{
|
||||
return element->getJustification();
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override { refresh(); }
|
||||
|
||||
PaintElementText* const element;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class TextToPathProperty : public ButtonPropertyComponent
|
||||
{
|
||||
public:
|
||||
TextToPathProperty (PaintElementText* const e)
|
||||
: ButtonPropertyComponent ("path", false),
|
||||
element (e)
|
||||
{
|
||||
}
|
||||
|
||||
void buttonClicked()
|
||||
{
|
||||
element->convertToPath();
|
||||
}
|
||||
|
||||
String getButtonText() const
|
||||
{
|
||||
return "convert text to a path";
|
||||
}
|
||||
|
||||
private:
|
||||
PaintElementText* const element;
|
||||
};
|
||||
};
|
||||
142
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementUndoableAction.h
vendored
Normal file
142
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PaintElementUndoableAction.h
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UI/jucer_JucerDocumentEditor.h"
|
||||
#include "jucer_PaintElementGroup.h"
|
||||
|
||||
//==============================================================================
|
||||
template <class ElementType>
|
||||
class PaintElementUndoableAction : public UndoableAction
|
||||
{
|
||||
public:
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6011)
|
||||
|
||||
PaintElementUndoableAction (ElementType* const element)
|
||||
: routine (*element->getOwner()),
|
||||
elementIndex (element->getOwner()->indexOfElement (element))
|
||||
{
|
||||
jassert (element != nullptr);
|
||||
|
||||
if (element != nullptr && elementIndex < 0)
|
||||
findGroupIndices (element->getOwner(), element);
|
||||
|
||||
jassert (elementIndex >= 0);
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
|
||||
ElementType* getElement() const
|
||||
{
|
||||
if (containerGroups.size() > 0)
|
||||
{
|
||||
auto group = dynamic_cast<PaintElementGroup*> (routine.getElement (containerGroups.getFirst()));
|
||||
|
||||
if (group == nullptr)
|
||||
return nullptr;
|
||||
|
||||
for (int i = 1; i < containerGroups.size(); ++i)
|
||||
{
|
||||
group = dynamic_cast<PaintElementGroup*> (group->getElement (containerGroups.getUnchecked(i)));
|
||||
|
||||
if (group == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto e = dynamic_cast<ElementType*> (group->getElement (elementIndex));
|
||||
jassert (e != nullptr);
|
||||
return e;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto e = dynamic_cast<ElementType*> (routine.getElement (elementIndex));
|
||||
jassert (e != nullptr);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
int getSizeInUnits() { return 2; }
|
||||
|
||||
protected:
|
||||
PaintRoutine& routine;
|
||||
int elementIndex;
|
||||
Array <int> containerGroups;
|
||||
|
||||
void changed() const
|
||||
{
|
||||
jassert (routine.getDocument() != nullptr);
|
||||
routine.getDocument()->changed();
|
||||
}
|
||||
|
||||
void showCorrectTab() const
|
||||
{
|
||||
if (JucerDocumentEditor* const docHolder = JucerDocumentEditor::getActiveDocumentHolder())
|
||||
docHolder->showGraphics (&routine);
|
||||
|
||||
if (routine.getSelectedElements().getNumSelected() == 0)
|
||||
if (ElementType* const e = dynamic_cast<ElementType*> (routine.getElement (elementIndex)))
|
||||
routine.getSelectedElements().selectOnly (e);
|
||||
}
|
||||
|
||||
private:
|
||||
void findGroupIndices (PaintRoutine* const pr, PaintElement* const element)
|
||||
{
|
||||
for (int i = pr->getNumElements(); --i >= 0;)
|
||||
{
|
||||
if (auto pg = dynamic_cast<PaintElementGroup*> (pr->getElement (i)))
|
||||
{
|
||||
if (pg->containsElement (element))
|
||||
{
|
||||
containerGroups.add (i);
|
||||
findGroupIndices (pg, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void findGroupIndices (PaintElementGroup* const group, PaintElement* const element)
|
||||
{
|
||||
elementIndex = group->indexOfElement (element);
|
||||
|
||||
if (elementIndex < 0)
|
||||
{
|
||||
for (int i = group->getNumElements(); --i >= 0;)
|
||||
{
|
||||
if (auto pg = dynamic_cast<PaintElementGroup*> (group->getElement (i)))
|
||||
{
|
||||
if (pg->containsElement (element))
|
||||
{
|
||||
containerGroups.add (i);
|
||||
findGroupIndices (pg, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PaintElementUndoableAction (const PaintElementUndoableAction&);
|
||||
PaintElementUndoableAction& operator= (const PaintElementUndoableAction&);
|
||||
};
|
||||
107
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PointComponent.h
vendored
Normal file
107
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_PointComponent.h
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ElementSiblingComponent.h"
|
||||
#include "../UI/jucer_PaintRoutineEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
class PointComponent : public ElementSiblingComponent
|
||||
{
|
||||
public:
|
||||
PointComponent (PaintElement* const e)
|
||||
: ElementSiblingComponent (e)
|
||||
{
|
||||
setSize (11, 11);
|
||||
setMouseCursor (MouseCursor::UpDownLeftRightResizeCursor);
|
||||
}
|
||||
|
||||
virtual RelativePositionedRectangle getPosition() = 0;
|
||||
virtual void setPosition (const RelativePositionedRectangle& newPos) = 0;
|
||||
|
||||
void updatePosition() override
|
||||
{
|
||||
if (dynamic_cast<PaintRoutineEditor*> (getParentComponent()) != nullptr)
|
||||
{
|
||||
const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
|
||||
const Rectangle<int> r (getPosition().getRectangle (area, owner->getDocument()->getComponentLayout()));
|
||||
|
||||
setCentrePosition (r.getX(), r.getY());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.setColour (Colours::white);
|
||||
g.drawEllipse (2.0f, 2.0f, (float) getWidth() - 4.0f, (float) getHeight() - 4.0f, 2.0f);
|
||||
|
||||
g.setColour (Colours::black);
|
||||
g.drawEllipse (1.0f, 1.0f, (float) getWidth() - 2.0f, (float) getHeight() - 2.0f, 2.0f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void mouseDown (const MouseEvent&) override
|
||||
{
|
||||
const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
|
||||
dragX = getX() + getWidth() / 2 - area.getX();
|
||||
dragY = getY() + getHeight() / 2 - area.getY();
|
||||
}
|
||||
|
||||
void mouseDrag (const MouseEvent& e) override
|
||||
{
|
||||
const Rectangle<int> area (((PaintRoutineEditor*) getParentComponent())->getComponentArea());
|
||||
int x = dragX + e.getDistanceFromDragStartX();
|
||||
int y = dragY + e.getDistanceFromDragStartY();
|
||||
|
||||
if (JucerDocument* const document = owner->getDocument())
|
||||
{
|
||||
x = document->snapPosition (x);
|
||||
y = document->snapPosition (y);
|
||||
|
||||
const RelativePositionedRectangle original (getPosition());
|
||||
RelativePositionedRectangle pr (original);
|
||||
|
||||
Rectangle<int> r (pr.getRectangle (Rectangle<int> (0, 0, area.getWidth(), area.getHeight()),
|
||||
document->getComponentLayout()));
|
||||
r.setPosition (x, y);
|
||||
|
||||
pr.updateFrom (r.getX(), r.getY(), r.getWidth(), r.getHeight(),
|
||||
Rectangle<int> (0, 0, area.getWidth(), area.getHeight()),
|
||||
document->getComponentLayout());
|
||||
|
||||
if (pr != original)
|
||||
setPosition (pr);
|
||||
}
|
||||
}
|
||||
|
||||
void mouseUp (const MouseEvent&) override
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
int dragX, dragY;
|
||||
};
|
||||
157
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_StrokeType.h
vendored
Normal file
157
deps/juce/extras/Projucer/Source/ComponentEditor/PaintElements/jucer_StrokeType.h
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_FillType.h"
|
||||
|
||||
//==============================================================================
|
||||
class StrokeType
|
||||
{
|
||||
public:
|
||||
StrokeType() : stroke (1.0f)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
String getPathStrokeCode() const
|
||||
{
|
||||
PathStrokeType defaultStroke (1.0f);
|
||||
|
||||
String s;
|
||||
|
||||
s << "juce::PathStrokeType (" << CodeHelpers::floatLiteral (stroke.getStrokeThickness(), 3);
|
||||
|
||||
if (stroke.getJointStyle() != defaultStroke.getJointStyle()
|
||||
|| stroke.getEndStyle() != defaultStroke.getEndStyle())
|
||||
{
|
||||
s << ", ";
|
||||
|
||||
switch (stroke.getJointStyle())
|
||||
{
|
||||
case PathStrokeType::mitered: s << "juce::PathStrokeType::mitered"; break;
|
||||
case PathStrokeType::curved: s << "juce::PathStrokeType::curved"; break;
|
||||
case PathStrokeType::beveled: s << "juce::PathStrokeType::beveled"; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (stroke.getEndStyle() != defaultStroke.getEndStyle())
|
||||
{
|
||||
s << ", ";
|
||||
|
||||
switch (stroke.getEndStyle())
|
||||
{
|
||||
case PathStrokeType::butt: s << "juce::PathStrokeType::butt"; break;
|
||||
case PathStrokeType::square: s << "juce::PathStrokeType::square"; break;
|
||||
case PathStrokeType::rounded: s << "juce::PathStrokeType::rounded"; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s << ")";
|
||||
return s;
|
||||
}
|
||||
|
||||
String toString() const
|
||||
{
|
||||
String s;
|
||||
s << stroke.getStrokeThickness();
|
||||
|
||||
switch (stroke.getJointStyle())
|
||||
{
|
||||
case PathStrokeType::mitered: s << ", mitered"; break;
|
||||
case PathStrokeType::curved: s << ", curved"; break;
|
||||
case PathStrokeType::beveled: s << ", beveled"; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
switch (stroke.getEndStyle())
|
||||
{
|
||||
case PathStrokeType::butt: s << ", butt"; break;
|
||||
case PathStrokeType::square: s << ", square"; break;
|
||||
case PathStrokeType::rounded: s << ", rounded"; break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void restoreFromString (const String& s)
|
||||
{
|
||||
reset();
|
||||
|
||||
if (s.isNotEmpty())
|
||||
{
|
||||
const float thickness = (float) s.upToFirstOccurrenceOf (",", false, false).getDoubleValue();
|
||||
|
||||
PathStrokeType::JointStyle joint = stroke.getJointStyle();
|
||||
|
||||
if (s.containsIgnoreCase ("miter")) joint = PathStrokeType::mitered;
|
||||
else if (s.containsIgnoreCase ("curve")) joint = PathStrokeType::curved;
|
||||
else if (s.containsIgnoreCase ("bevel")) joint = PathStrokeType::beveled;
|
||||
|
||||
PathStrokeType::EndCapStyle end = stroke.getEndStyle();
|
||||
|
||||
if (s.containsIgnoreCase ("butt")) end = PathStrokeType::butt;
|
||||
else if (s.containsIgnoreCase ("square")) end = PathStrokeType::square;
|
||||
else if (s.containsIgnoreCase ("round")) end = PathStrokeType::rounded;
|
||||
|
||||
stroke = PathStrokeType (thickness, joint, end);
|
||||
}
|
||||
}
|
||||
|
||||
bool isOpaque() const
|
||||
{
|
||||
return fill.isOpaque();
|
||||
}
|
||||
|
||||
bool isInvisible() const
|
||||
{
|
||||
return fill.isInvisible() || stroke.getStrokeThickness() <= 0.0f;
|
||||
}
|
||||
|
||||
bool operator== (const StrokeType& other) const noexcept
|
||||
{
|
||||
return stroke == other.stroke && fill == other.fill;
|
||||
}
|
||||
|
||||
bool operator!= (const StrokeType& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PathStrokeType stroke;
|
||||
JucerFillType fill;
|
||||
|
||||
private:
|
||||
void reset()
|
||||
{
|
||||
stroke = PathStrokeType (5.0f);
|
||||
fill = JucerFillType();
|
||||
fill.colour = Colours::black;
|
||||
}
|
||||
};
|
||||
209
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ColourPropertyComponent.h
vendored
Normal file
209
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ColourPropertyComponent.h
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class JucerColourPropertyComponent : public PropertyComponent
|
||||
{
|
||||
public:
|
||||
JucerColourPropertyComponent (const String& name,
|
||||
const bool canReset)
|
||||
: PropertyComponent (name)
|
||||
{
|
||||
colourPropEditor.reset (new ColourPropEditorComponent (this, canReset));
|
||||
addAndMakeVisible (colourPropEditor.get());
|
||||
}
|
||||
|
||||
virtual void setColour (Colour newColour) = 0;
|
||||
virtual Colour getColour() const = 0;
|
||||
virtual void resetToDefault() = 0;
|
||||
|
||||
void refresh() override
|
||||
{
|
||||
((ColourPropEditorComponent*) getChildComponent (0))->refresh();
|
||||
}
|
||||
|
||||
class ColourEditorComponent : public Component,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ColourEditorComponent (const bool canReset)
|
||||
: canResetToDefault (canReset)
|
||||
{
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (Colours::grey);
|
||||
|
||||
g.fillCheckerBoard (getLocalBounds().reduced (2, 2).toFloat(),
|
||||
10.0f, 10.0f,
|
||||
Colour (0xffdddddd).overlaidWith (colour),
|
||||
Colour (0xffffffff).overlaidWith (colour));
|
||||
|
||||
g.setColour (Colours::white.overlaidWith (colour).contrasting());
|
||||
g.setFont (Font ((float) getHeight() * 0.6f, Font::bold));
|
||||
g.drawFittedText (colour.toDisplayString (true),
|
||||
2, 1, getWidth() - 4, getHeight() - 1,
|
||||
Justification::centred, 1);
|
||||
}
|
||||
|
||||
virtual void setColour (Colour newColour) = 0;
|
||||
virtual void resetToDefault() = 0;
|
||||
virtual Colour getColour() const = 0;
|
||||
|
||||
void refresh()
|
||||
{
|
||||
const Colour col (getColour());
|
||||
|
||||
if (col != colour)
|
||||
{
|
||||
colour = col;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&) override
|
||||
{
|
||||
CallOutBox::launchAsynchronously (std::make_unique<ColourSelectorComp> (this, canResetToDefault),
|
||||
getScreenBounds(),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
class ColourSelectorComp : public Component
|
||||
{
|
||||
public:
|
||||
ColourSelectorComp (ColourEditorComponent* owner_,
|
||||
const bool canReset)
|
||||
: owner (owner_),
|
||||
defaultButton ("Reset to Default")
|
||||
{
|
||||
addAndMakeVisible (selector);
|
||||
selector.setName ("Colour");
|
||||
selector.setCurrentColour (owner->getColour());
|
||||
selector.addChangeListener (owner);
|
||||
|
||||
if (canReset)
|
||||
{
|
||||
addAndMakeVisible (defaultButton);
|
||||
|
||||
defaultButton.onClick = [this]
|
||||
{
|
||||
owner->resetToDefault();
|
||||
owner->refresh();
|
||||
selector.setCurrentColour (owner->getColour());
|
||||
};
|
||||
}
|
||||
|
||||
setSize (300, 400);
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (defaultButton.isVisible())
|
||||
{
|
||||
selector.setBounds (0, 0, getWidth(), getHeight() - 30);
|
||||
defaultButton.changeWidthToFitText (22);
|
||||
defaultButton.setTopLeftPosition (10, getHeight() - 26);
|
||||
}
|
||||
else
|
||||
{
|
||||
selector.setBounds (getLocalBounds());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class ColourSelectorWithSwatches : public ColourSelector
|
||||
{
|
||||
public:
|
||||
ColourSelectorWithSwatches()
|
||||
{
|
||||
}
|
||||
|
||||
int getNumSwatches() const override
|
||||
{
|
||||
return getAppSettings().swatchColours.size();
|
||||
}
|
||||
|
||||
Colour getSwatchColour (int index) const override
|
||||
{
|
||||
return getAppSettings().swatchColours [index];
|
||||
}
|
||||
|
||||
void setSwatchColour (int index, const Colour& newColour) override
|
||||
{
|
||||
getAppSettings().swatchColours.set (index, newColour);
|
||||
}
|
||||
};
|
||||
|
||||
ColourEditorComponent* owner;
|
||||
ColourSelectorWithSwatches selector;
|
||||
TextButton defaultButton;
|
||||
};
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster* source) override
|
||||
{
|
||||
const ColourSelector* const cs = (const ColourSelector*) source;
|
||||
|
||||
if (cs->getCurrentColour() != getColour())
|
||||
setColour (cs->getCurrentColour());
|
||||
}
|
||||
|
||||
Colour colour;
|
||||
bool canResetToDefault;
|
||||
};
|
||||
|
||||
class ColourPropEditorComponent : public ColourEditorComponent
|
||||
{
|
||||
JucerColourPropertyComponent* const owner;
|
||||
|
||||
public:
|
||||
ColourPropEditorComponent (JucerColourPropertyComponent* const owner_,
|
||||
const bool canReset)
|
||||
: ColourEditorComponent (canReset),
|
||||
owner (owner_)
|
||||
{}
|
||||
|
||||
void setColour (Colour newColour) override
|
||||
{
|
||||
owner->setColour (newColour);
|
||||
}
|
||||
|
||||
Colour getColour() const override
|
||||
{
|
||||
return owner->getColour();
|
||||
}
|
||||
|
||||
void resetToDefault() override
|
||||
{
|
||||
owner->resetToDefault();
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ColourPropEditorComponent> colourPropEditor;
|
||||
};
|
||||
60
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentBooleanProperty.h
vendored
Normal file
60
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentBooleanProperty.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <class ComponentType>
|
||||
class ComponentBooleanProperty : public BooleanPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ComponentBooleanProperty (const String& name,
|
||||
const String& onText_,
|
||||
const String& offText_,
|
||||
ComponentType* comp,
|
||||
JucerDocument& doc)
|
||||
: BooleanPropertyComponent (name, onText_, offText_),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentBooleanProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected:
|
||||
ComponentType* component;
|
||||
JucerDocument& document;
|
||||
};
|
||||
58
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentChoiceProperty.h
vendored
Normal file
58
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentChoiceProperty.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <class ComponentType>
|
||||
class ComponentChoiceProperty : public ChoicePropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ComponentChoiceProperty (const String& name,
|
||||
ComponentType* comp,
|
||||
JucerDocument& doc)
|
||||
: ChoicePropertyComponent (name),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentChoiceProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected:
|
||||
ComponentType* component;
|
||||
JucerDocument& document;
|
||||
};
|
||||
165
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentColourProperty.h
vendored
Normal file
165
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentColourProperty.h
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ColourPropertyComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
template <class ComponentType>
|
||||
class ComponentColourProperty : public JucerColourPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ComponentColourProperty (const String& name,
|
||||
ComponentType* comp,
|
||||
JucerDocument& doc,
|
||||
const bool canResetToDefault)
|
||||
: JucerColourPropertyComponent (name, canResetToDefault),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentColourProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected:
|
||||
ComponentType* component;
|
||||
JucerDocument& document;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ComponentColourIdProperty : public ComponentColourProperty <Component>
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentColourIdProperty (Component* const comp,
|
||||
JucerDocument& doc,
|
||||
const int colourId_,
|
||||
const String& name,
|
||||
const bool canResetToDefault)
|
||||
: ComponentColourProperty <Component> (name, comp, doc, canResetToDefault),
|
||||
colourId (colourId_)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Colour getColour() const
|
||||
{
|
||||
return component->findColour (colourId);
|
||||
}
|
||||
|
||||
void setColour (Colour newColour)
|
||||
{
|
||||
if (component->findColour (colourId) != newColour)
|
||||
{
|
||||
document.getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
document.perform (new ColourChangeAction (component,
|
||||
*document.getComponentLayout(),
|
||||
colourId,
|
||||
newColour,
|
||||
false),
|
||||
"Change colour");
|
||||
}
|
||||
}
|
||||
|
||||
void resetToDefault()
|
||||
{
|
||||
document.getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
document.perform (new ColourChangeAction (component,
|
||||
*document.getComponentLayout(),
|
||||
colourId,
|
||||
Colours::black,
|
||||
true),
|
||||
"Reset colour");
|
||||
}
|
||||
|
||||
private:
|
||||
const int colourId;
|
||||
|
||||
class ColourChangeAction : public ComponentUndoableAction <Component>
|
||||
{
|
||||
public:
|
||||
ColourChangeAction (Component* const comp,
|
||||
ComponentLayout& l,
|
||||
const int colourId_,
|
||||
Colour newColour_,
|
||||
const bool newColourIsDefault)
|
||||
: ComponentUndoableAction<Component> (comp, l),
|
||||
colourId (colourId_),
|
||||
newColour (newColour_),
|
||||
isDefault (newColourIsDefault)
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
wasSpecified = getComponent()->isColourSpecified (colourId);
|
||||
oldColour = getComponent()->findColour (colourId);
|
||||
|
||||
if (isDefault)
|
||||
getComponent()->removeColour (colourId);
|
||||
else
|
||||
getComponent()->setColour (colourId, newColour);
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
if (wasSpecified)
|
||||
getComponent()->setColour (colourId, oldColour);
|
||||
else
|
||||
getComponent()->removeColour (colourId);
|
||||
|
||||
if (TextEditor* const te = dynamic_cast<TextEditor*> (getComponent()))
|
||||
te->applyFontToAllText (te->getFont());
|
||||
|
||||
changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
int colourId;
|
||||
Colour newColour, oldColour;
|
||||
bool isDefault, wasSpecified;
|
||||
};
|
||||
};
|
||||
60
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentTextProperty.h
vendored
Normal file
60
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_ComponentTextProperty.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
template <class ComponentType>
|
||||
class ComponentTextProperty : public TextPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ComponentTextProperty (const String& name,
|
||||
const int maxNumChars_,
|
||||
const bool isMultiLine_,
|
||||
ComponentType* const comp,
|
||||
JucerDocument& doc)
|
||||
: TextPropertyComponent (name, maxNumChars_, isMultiLine_),
|
||||
component (comp),
|
||||
document (doc)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentTextProperty()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
protected:
|
||||
ComponentType* component;
|
||||
JucerDocument& document;
|
||||
};
|
||||
63
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_FilePropertyComponent.h
vendored
Normal file
63
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_FilePropertyComponent.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FilePropertyComponent : public PropertyComponent,
|
||||
private FilenameComponentListener
|
||||
{
|
||||
public:
|
||||
FilePropertyComponent (const String& name,
|
||||
const bool isDirectory,
|
||||
const bool allowEditingOfFilename,
|
||||
const String& fileBrowserWildcard = "*")
|
||||
: PropertyComponent (name),
|
||||
filenameComp (name, File(), allowEditingOfFilename,
|
||||
isDirectory, false, fileBrowserWildcard,
|
||||
String(), String())
|
||||
{
|
||||
addAndMakeVisible (filenameComp);
|
||||
filenameComp.addListener (this);
|
||||
}
|
||||
|
||||
virtual void setFile (const File& newFile) = 0;
|
||||
virtual File getFile() const = 0;
|
||||
|
||||
void refresh() override
|
||||
{
|
||||
filenameComp.setCurrentFile (getFile(), false);
|
||||
}
|
||||
|
||||
private:
|
||||
void filenameComponentChanged (FilenameComponent*) override
|
||||
{
|
||||
if (getFile() != filenameComp.getCurrentFile())
|
||||
setFile (filenameComp.getCurrentFile());
|
||||
}
|
||||
|
||||
FilenameComponent filenameComp;
|
||||
};
|
||||
142
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h
vendored
Normal file
142
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_FontPropertyComponent.h
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class FontPropertyComponent : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
FontPropertyComponent (const String& name)
|
||||
: ChoicePropertyComponent (name)
|
||||
{
|
||||
choices.add (getDefaultFont());
|
||||
choices.add (getDefaultSans());
|
||||
choices.add (getDefaultSerif());
|
||||
choices.add (getDefaultMono());
|
||||
choices.add (String());
|
||||
|
||||
static StringArray fontNames;
|
||||
|
||||
if (fontNames.size() == 0)
|
||||
{
|
||||
Array<Font> fonts;
|
||||
Font::findFonts (fonts);
|
||||
|
||||
for (int i = 0; i < fonts.size(); ++i)
|
||||
fontNames.add (fonts[i].getTypefaceName());
|
||||
}
|
||||
|
||||
choices.addArray (fontNames);
|
||||
}
|
||||
|
||||
static String getDefaultFont() { return "Default font"; }
|
||||
static String getDefaultSans() { return "Default sans-serif font"; }
|
||||
static String getDefaultSerif() { return "Default serif font"; }
|
||||
static String getDefaultMono() { return "Default monospaced font"; }
|
||||
|
||||
//==============================================================================
|
||||
virtual void setTypefaceName (const String& newFontName) = 0;
|
||||
virtual String getTypefaceName() const = 0;
|
||||
|
||||
//==============================================================================
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
String type (choices [newIndex]);
|
||||
|
||||
if (type.isEmpty())
|
||||
type = getDefaultFont();
|
||||
|
||||
if (getTypefaceName() != type)
|
||||
setTypefaceName (type);
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
return choices.indexOf (getTypefaceName());
|
||||
}
|
||||
|
||||
static Font applyNameToFont (const String& typefaceName, const Font& font)
|
||||
{
|
||||
auto extraKerning = font.getExtraKerningFactor();
|
||||
|
||||
if (typefaceName == getDefaultFont()) return Font (font.getHeight(), font.getStyleFlags()).withExtraKerningFactor (extraKerning);
|
||||
if (typefaceName == getDefaultSans()) return Font (Font::getDefaultSansSerifFontName(), font.getHeight(), font.getStyleFlags()).withExtraKerningFactor (extraKerning);
|
||||
if (typefaceName == getDefaultSerif()) return Font (Font::getDefaultSerifFontName(), font.getHeight(), font.getStyleFlags()).withExtraKerningFactor (extraKerning);
|
||||
if (typefaceName == getDefaultMono()) return Font (Font::getDefaultMonospacedFontName(), font.getHeight(), font.getStyleFlags()).withExtraKerningFactor (extraKerning);
|
||||
|
||||
auto f = Font (typefaceName, font.getHeight(), font.getStyleFlags()).withExtraKerningFactor (extraKerning);
|
||||
|
||||
if (f.getAvailableStyles().contains (font.getTypefaceStyle()))
|
||||
f.setTypefaceStyle (font.getTypefaceStyle());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static String getTypefaceNameCode (const String& typefaceName)
|
||||
{
|
||||
if (typefaceName == getDefaultFont()) return {};
|
||||
if (typefaceName == getDefaultSans()) return "juce::Font::getDefaultSansSerifFontName(), ";
|
||||
if (typefaceName == getDefaultSerif()) return "juce::Font::getDefaultSerifFontName(), ";
|
||||
if (typefaceName == getDefaultMono()) return "juce::Font::getDefaultMonospacedFontName(), ";
|
||||
|
||||
return "\"" + typefaceName + "\", ";
|
||||
}
|
||||
|
||||
static String getFontStyleCode (const Font& font)
|
||||
{
|
||||
if (font.isBold() && font.isItalic()) return "juce::Font::bold | juce::Font::italic";
|
||||
if (font.isBold()) return "juce::Font::bold";
|
||||
if (font.isItalic()) return "juce::Font::italic";
|
||||
|
||||
return "juce::Font::plain";
|
||||
}
|
||||
|
||||
static String getCompleteFontCode (const Font& font, const String& typefaceName)
|
||||
{
|
||||
String s;
|
||||
|
||||
s << "juce::Font ("
|
||||
<< getTypefaceNameCode (typefaceName)
|
||||
<< CodeHelpers::floatLiteral (font.getHeight(), 2)
|
||||
<< ", ";
|
||||
|
||||
if (font.getAvailableStyles().contains(font.getTypefaceStyle()))
|
||||
s << "juce::Font::plain).withTypefaceStyle ("
|
||||
<< CodeHelpers::stringLiteral (font.getTypefaceStyle())
|
||||
<< ")";
|
||||
else
|
||||
s << getFontStyleCode (font)
|
||||
<< ")";
|
||||
|
||||
if (font.getExtraKerningFactor() != 0.0f)
|
||||
s << ".withExtraKerningFactor ("
|
||||
<< CodeHelpers::floatLiteral (font.getExtraKerningFactor(), 3)
|
||||
<< ")";
|
||||
|
||||
return s;
|
||||
}
|
||||
};
|
||||
100
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_JustificationProperty.h
vendored
Normal file
100
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_JustificationProperty.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class JustificationProperty : public ChoicePropertyComponent
|
||||
{
|
||||
public:
|
||||
JustificationProperty (const String& name, const bool onlyHorizontalOptions)
|
||||
: ChoicePropertyComponent (name)
|
||||
{
|
||||
if (onlyHorizontalOptions)
|
||||
{
|
||||
choices.add ("centre");
|
||||
choices.add ("left");
|
||||
choices.add ("right");
|
||||
}
|
||||
else
|
||||
{
|
||||
choices.add ("centred");
|
||||
choices.add ("centred left");
|
||||
choices.add ("centred right");
|
||||
choices.add ("centred top");
|
||||
choices.add ("centred bottom");
|
||||
choices.add ("top left");
|
||||
choices.add ("top right");
|
||||
choices.add ("bottom left");
|
||||
choices.add ("bottom right");
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
virtual void setJustification (Justification newJustification) = 0;
|
||||
virtual Justification getJustification() const = 0;
|
||||
|
||||
//==============================================================================
|
||||
void setIndex (int newIndex)
|
||||
{
|
||||
const int types[] = { Justification::centred,
|
||||
Justification::centredLeft,
|
||||
Justification::centredRight,
|
||||
Justification::centredTop,
|
||||
Justification::centredBottom,
|
||||
Justification::topLeft,
|
||||
Justification::topRight,
|
||||
Justification::bottomLeft,
|
||||
Justification::bottomRight };
|
||||
|
||||
if (((unsigned int) newIndex) < (unsigned int) numElementsInArray (types)
|
||||
&& types [newIndex] != getJustification().getFlags())
|
||||
{
|
||||
setJustification (Justification (types [newIndex]));
|
||||
}
|
||||
}
|
||||
|
||||
int getIndex() const
|
||||
{
|
||||
const int types[] = { Justification::centred,
|
||||
Justification::centredLeft,
|
||||
Justification::centredRight,
|
||||
Justification::centredTop,
|
||||
Justification::centredBottom,
|
||||
Justification::topLeft,
|
||||
Justification::topRight,
|
||||
Justification::bottomLeft,
|
||||
Justification::bottomRight };
|
||||
|
||||
const int rawFlags = getJustification().getFlags();
|
||||
|
||||
for (int i = numElementsInArray (types); --i >= 0;)
|
||||
if (types[i] == rawFlags)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
463
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_PositionPropertyBase.h
vendored
Normal file
463
deps/juce/extras/Projucer/Source/ComponentEditor/Properties/jucer_PositionPropertyBase.h
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../UI/jucer_PaintRoutineEditor.h"
|
||||
#include "../UI/jucer_ComponentLayoutEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for a property that edits the x, y, w, or h of a PositionedRectangle.
|
||||
*/
|
||||
class PositionPropertyBase : public PropertyComponent,
|
||||
protected ChangeListener
|
||||
{
|
||||
public:
|
||||
enum ComponentPositionDimension
|
||||
{
|
||||
componentX = 0,
|
||||
componentY = 1,
|
||||
componentWidth = 2,
|
||||
componentHeight = 3
|
||||
};
|
||||
|
||||
PositionPropertyBase (Component* comp,
|
||||
const String& name,
|
||||
ComponentPositionDimension dimension_,
|
||||
const bool includeAnchorOptions_,
|
||||
const bool allowRelativeOptions_,
|
||||
ComponentLayout* layout_)
|
||||
: PropertyComponent (name),
|
||||
layout (layout_),
|
||||
button ("mode"),
|
||||
component (comp),
|
||||
dimension (dimension_),
|
||||
includeAnchorOptions (includeAnchorOptions_),
|
||||
allowRelativeOptions (allowRelativeOptions_)
|
||||
{
|
||||
addAndMakeVisible (button);
|
||||
button.setTriggeredOnMouseDown (true);
|
||||
button.setConnectedEdges (TextButton::ConnectedOnLeft | TextButton::ConnectedOnRight);
|
||||
button.onClick = [this]
|
||||
{
|
||||
SafePointer<PositionPropertyBase> safeThis { this };
|
||||
showMenu (layout, [safeThis] (bool shouldRefresh)
|
||||
{
|
||||
if (safeThis == nullptr)
|
||||
return;
|
||||
|
||||
if (shouldRefresh)
|
||||
safeThis->refresh(); // (to clear the text editor if it's got focus)
|
||||
});
|
||||
};
|
||||
|
||||
textEditor.reset (new PositionPropLabel (*this));
|
||||
addAndMakeVisible (textEditor.get());
|
||||
}
|
||||
|
||||
String getText() const
|
||||
{
|
||||
RelativePositionedRectangle rpr (getPosition());
|
||||
PositionedRectangle& p = rpr.rect;
|
||||
String s;
|
||||
|
||||
switch (dimension)
|
||||
{
|
||||
case componentX:
|
||||
if (p.getPositionModeX() == PositionedRectangle::proportionOfParentSize)
|
||||
s << valueToString (p.getX() * 100.0) << '%';
|
||||
else
|
||||
s << valueToString (p.getX());
|
||||
break;
|
||||
|
||||
case componentY:
|
||||
if (p.getPositionModeY() == PositionedRectangle::proportionOfParentSize)
|
||||
s << valueToString (p.getY() * 100.0) << '%';
|
||||
else
|
||||
s << valueToString (p.getY());
|
||||
break;
|
||||
|
||||
case componentWidth:
|
||||
if (p.getWidthMode() == PositionedRectangle::proportionalSize)
|
||||
s << valueToString (p.getWidth() * 100.0) << '%';
|
||||
else
|
||||
s << valueToString (p.getWidth());
|
||||
break;
|
||||
|
||||
case componentHeight:
|
||||
if (p.getHeightMode() == PositionedRectangle::proportionalSize)
|
||||
s << valueToString (p.getHeight() * 100.0) << '%';
|
||||
else
|
||||
s << valueToString (p.getHeight());
|
||||
break;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
};
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static String valueToString (const double n)
|
||||
{
|
||||
return String (roundToInt (n * 1000.0) / 1000.0);
|
||||
}
|
||||
|
||||
void setText (const String& newText)
|
||||
{
|
||||
RelativePositionedRectangle rpr (getPosition());
|
||||
PositionedRectangle p (rpr.rect);
|
||||
const double value = newText.getDoubleValue();
|
||||
|
||||
switch (dimension)
|
||||
{
|
||||
case componentX:
|
||||
if (p.getPositionModeX() == PositionedRectangle::proportionOfParentSize)
|
||||
p.setX (value / 100.0);
|
||||
else
|
||||
p.setX (value);
|
||||
break;
|
||||
|
||||
case componentY:
|
||||
if (p.getPositionModeY() == PositionedRectangle::proportionOfParentSize)
|
||||
p.setY (value / 100.0);
|
||||
else
|
||||
p.setY (value);
|
||||
break;
|
||||
|
||||
case componentWidth:
|
||||
if (p.getWidthMode() == PositionedRectangle::proportionalSize)
|
||||
p.setWidth (value / 100.0);
|
||||
else
|
||||
p.setWidth (value);
|
||||
break;
|
||||
|
||||
case componentHeight:
|
||||
if (p.getHeightMode() == PositionedRectangle::proportionalSize)
|
||||
p.setHeight (value / 100.0);
|
||||
else
|
||||
p.setHeight (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
jassertfalse;
|
||||
break;
|
||||
};
|
||||
|
||||
if (p != rpr.rect)
|
||||
{
|
||||
rpr.rect = p;
|
||||
setPosition (rpr);
|
||||
}
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void showMenu (ComponentLayout* compLayout, std::function<void (bool)> callback)
|
||||
{
|
||||
RelativePositionedRectangle rpr (getPosition());
|
||||
PositionedRectangle p (rpr.rect);
|
||||
|
||||
PositionedRectangle::AnchorPoint xAnchor = p.getAnchorPointX();
|
||||
PositionedRectangle::AnchorPoint yAnchor = p.getAnchorPointY();
|
||||
PositionedRectangle::PositionMode xMode = p.getPositionModeX();
|
||||
PositionedRectangle::PositionMode yMode = p.getPositionModeY();
|
||||
PositionedRectangle::SizeMode sizeW = p.getWidthMode();
|
||||
PositionedRectangle::SizeMode sizeH = p.getHeightMode();
|
||||
|
||||
String relCompName ("parent");
|
||||
|
||||
if (Component* const relComp = compLayout != nullptr ? compLayout->getComponentRelativePosTarget (component, (int) dimension)
|
||||
: nullptr)
|
||||
relCompName = compLayout->getComponentMemberVariableName (relComp);
|
||||
|
||||
jassert (relCompName.isNotEmpty());
|
||||
|
||||
PopupMenu m;
|
||||
|
||||
if (dimension == componentX || dimension == componentY)
|
||||
{
|
||||
const PositionedRectangle::PositionMode posMode = (dimension == componentX) ? xMode : yMode;
|
||||
|
||||
m.addItem (10, ((dimension == componentX) ? "Absolute distance from left of "
|
||||
: "Absolute distance from top of ") + relCompName,
|
||||
true, posMode == PositionedRectangle::absoluteFromParentTopLeft);
|
||||
|
||||
m.addItem (11, ((dimension == componentX) ? "Absolute distance from right of "
|
||||
: "Absolute distance from bottom of ") + relCompName,
|
||||
true, posMode == PositionedRectangle::absoluteFromParentBottomRight);
|
||||
|
||||
m.addItem (12, "Absolute distance from centre of " + relCompName,
|
||||
true, posMode == PositionedRectangle::absoluteFromParentCentre);
|
||||
|
||||
m.addItem (13, ((dimension == componentX) ? "Percentage of width of "
|
||||
: "Percentage of height of ") + relCompName,
|
||||
true, posMode == PositionedRectangle::proportionOfParentSize);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
if (includeAnchorOptions)
|
||||
{
|
||||
const PositionedRectangle::AnchorPoint anchor = (dimension == componentX) ? xAnchor : yAnchor;
|
||||
|
||||
m.addItem (14, (dimension == componentX) ? "Anchored at left of component"
|
||||
: "Anchored at top of component",
|
||||
true, anchor == PositionedRectangle::anchorAtLeftOrTop);
|
||||
|
||||
m.addItem (15, "Anchored at centre of component", true, anchor == PositionedRectangle::anchorAtCentre);
|
||||
|
||||
m.addItem (16, (dimension == componentX) ? "Anchored at right of component"
|
||||
: "Anchored at bottom of component",
|
||||
true, anchor == PositionedRectangle::anchorAtRightOrBottom);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const PositionedRectangle::SizeMode sizeMode = (dimension == componentWidth) ? sizeW : sizeH;
|
||||
|
||||
m.addItem (20, (dimension == componentWidth) ? "Absolute width"
|
||||
: "Absolute height",
|
||||
true, sizeMode == PositionedRectangle::absoluteSize);
|
||||
|
||||
m.addItem (21, ((dimension == componentWidth) ? "Percentage of width of "
|
||||
: "Percentage of height of ") + relCompName,
|
||||
true, sizeMode == PositionedRectangle::proportionalSize);
|
||||
|
||||
m.addItem (22, ((dimension == componentWidth) ? "Subtracted from width of "
|
||||
: "Subtracted from height of ") + relCompName,
|
||||
true, sizeMode == PositionedRectangle::parentSizeMinusAbsolute);
|
||||
}
|
||||
|
||||
|
||||
if (allowRelativeOptions && compLayout != nullptr)
|
||||
{
|
||||
m.addSeparator();
|
||||
m.addSubMenu ("Relative to", compLayout->getRelativeTargetMenu (component, (int) dimension));
|
||||
}
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options().withTargetComponent (&button),
|
||||
[compLayout, callback, xAnchor, yAnchor, xMode, yMode, sizeW, sizeH, p, rpr,
|
||||
ref = SafePointer<PositionPropertyBase> { this }] (int menuResult) mutable
|
||||
{
|
||||
if (menuResult == 0 || ref == nullptr)
|
||||
{
|
||||
callback (false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (menuResult)
|
||||
{
|
||||
case 10:
|
||||
if (ref->dimension == componentX)
|
||||
xMode = PositionedRectangle::absoluteFromParentTopLeft;
|
||||
else
|
||||
yMode = PositionedRectangle::absoluteFromParentTopLeft;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
if (ref->dimension == componentX)
|
||||
xMode = PositionedRectangle::absoluteFromParentBottomRight;
|
||||
else
|
||||
yMode = PositionedRectangle::absoluteFromParentBottomRight;
|
||||
break;
|
||||
|
||||
case 12:
|
||||
if (ref->dimension == componentX)
|
||||
xMode = PositionedRectangle::absoluteFromParentCentre;
|
||||
else
|
||||
yMode = PositionedRectangle::absoluteFromParentCentre;
|
||||
break;
|
||||
|
||||
case 13:
|
||||
if (ref->dimension == componentX)
|
||||
xMode = PositionedRectangle::proportionOfParentSize;
|
||||
else
|
||||
yMode = PositionedRectangle::proportionOfParentSize;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (ref->dimension == componentX)
|
||||
xAnchor = PositionedRectangle::anchorAtLeftOrTop;
|
||||
else
|
||||
yAnchor = PositionedRectangle::anchorAtLeftOrTop;
|
||||
break;
|
||||
|
||||
case 15:
|
||||
if (ref->dimension == componentX)
|
||||
xAnchor = PositionedRectangle::anchorAtCentre;
|
||||
else
|
||||
yAnchor = PositionedRectangle::anchorAtCentre;
|
||||
break;
|
||||
|
||||
case 16:
|
||||
if (ref->dimension == componentX)
|
||||
xAnchor = PositionedRectangle::anchorAtRightOrBottom;
|
||||
else
|
||||
yAnchor = PositionedRectangle::anchorAtRightOrBottom;
|
||||
break;
|
||||
|
||||
case 20:
|
||||
if (ref->dimension == componentWidth)
|
||||
sizeW = PositionedRectangle::absoluteSize;
|
||||
else
|
||||
sizeH = PositionedRectangle::absoluteSize;
|
||||
break;
|
||||
|
||||
case 21:
|
||||
if (ref->dimension == componentWidth)
|
||||
sizeW = PositionedRectangle::proportionalSize;
|
||||
else
|
||||
sizeH = PositionedRectangle::proportionalSize;
|
||||
break;
|
||||
|
||||
case 22:
|
||||
if (ref->dimension == componentWidth)
|
||||
sizeW = PositionedRectangle::parentSizeMinusAbsolute;
|
||||
else
|
||||
sizeH = PositionedRectangle::parentSizeMinusAbsolute;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (ref->allowRelativeOptions && compLayout != nullptr)
|
||||
compLayout->processRelativeTargetMenuResult (ref->component, (int) ref->dimension, menuResult);
|
||||
break;
|
||||
}
|
||||
|
||||
const auto parentArea = [&]() -> Rectangle<int>
|
||||
{
|
||||
if (ref->component->findParentComponentOfClass<ComponentLayoutEditor>() != nullptr)
|
||||
return { ref->component->getParentWidth(), ref->component->getParentHeight() };
|
||||
|
||||
if (auto pre = dynamic_cast<PaintRoutineEditor*> (ref->component->getParentComponent()))
|
||||
return pre->getComponentArea();
|
||||
|
||||
jassertfalse;
|
||||
return {};
|
||||
}();
|
||||
|
||||
int x, xw, y, yh, w, h;
|
||||
rpr.getRelativeTargetBounds (parentArea, compLayout, x, xw, y, yh, w, h);
|
||||
|
||||
PositionedRectangle xyRect (p);
|
||||
PositionedRectangle whRect (p);
|
||||
|
||||
xyRect.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
|
||||
Rectangle<int> (x, y, xw, yh));
|
||||
|
||||
whRect.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
|
||||
Rectangle<int> (x, y, w, h));
|
||||
|
||||
p.setModes (xAnchor, xMode, yAnchor, yMode, sizeW, sizeH,
|
||||
Rectangle<int> (x, y, xw, yh));
|
||||
|
||||
p.setX (xyRect.getX());
|
||||
p.setY (xyRect.getY());
|
||||
p.setWidth (whRect.getWidth());
|
||||
p.setHeight (whRect.getHeight());
|
||||
|
||||
if (p != rpr.rect)
|
||||
{
|
||||
rpr.rect = p;
|
||||
ref->setPosition (rpr);
|
||||
}
|
||||
|
||||
callback (true);
|
||||
});
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
const Rectangle<int> r (getLookAndFeel().getPropertyComponentContentPosition (*this));
|
||||
|
||||
button.changeWidthToFitText (r.getHeight());
|
||||
button.setTopRightPosition (r.getRight(), r.getY());
|
||||
|
||||
textEditor->setBounds (r.getX(), r.getY(), button.getX() - r.getX(), r.getHeight());
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
textEditor->setText (getText(), dontSendNotification);
|
||||
}
|
||||
|
||||
void textWasEdited()
|
||||
{
|
||||
const String newText (textEditor->getText());
|
||||
if (getText() != newText)
|
||||
setText (newText);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
virtual void setPosition (const RelativePositionedRectangle& newPos) = 0;
|
||||
|
||||
virtual RelativePositionedRectangle getPosition() const = 0;
|
||||
|
||||
protected:
|
||||
class PositionPropLabel : public Label
|
||||
{
|
||||
PositionPropertyBase& owner;
|
||||
|
||||
public:
|
||||
PositionPropLabel (PositionPropertyBase& owner_)
|
||||
: Label (String(), String()),
|
||||
owner (owner_)
|
||||
{
|
||||
setEditable (true, true, false);
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
TextEditor* createEditorComponent() override
|
||||
{
|
||||
TextEditor* ed = Label::createEditorComponent();
|
||||
ed->setInputRestrictions (14, "0123456789.-%");
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
void textWasEdited() override
|
||||
{
|
||||
owner.textWasEdited();
|
||||
}
|
||||
|
||||
void lookAndFeelChanged() override
|
||||
{
|
||||
setColour (backgroundColourId, findColour (widgetBackgroundColourId));
|
||||
setColour (textColourId, findColour (widgetTextColourId));
|
||||
}
|
||||
};
|
||||
|
||||
ComponentLayout* layout;
|
||||
std::unique_ptr<PositionPropLabel> textEditor;
|
||||
TextButton button;
|
||||
|
||||
Component* component;
|
||||
ComponentPositionDimension dimension;
|
||||
const bool includeAnchorOptions, allowRelativeOptions;
|
||||
};
|
||||
430
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp
vendored
Normal file
430
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.cpp
vendored
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
#include "../UI/jucer_JucerCommandIDs.h"
|
||||
#include "../jucer_ObjectTypes.h"
|
||||
#include "../Components/jucer_JucerComponentHandler.h"
|
||||
|
||||
//==============================================================================
|
||||
class SubComponentHolderComp : public Component
|
||||
{
|
||||
public:
|
||||
SubComponentHolderComp (JucerDocument& doc,
|
||||
SnapGridPainter& g)
|
||||
: document (doc), grid (g),
|
||||
dontFillBackground (false)
|
||||
{
|
||||
setInterceptsMouseClicks (false, false);
|
||||
setWantsKeyboardFocus (false);
|
||||
setFocusContainerType (FocusContainerType::keyboardFocusContainer);
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
if (! dontFillBackground)
|
||||
{
|
||||
if (PaintRoutine* const background = document.getPaintRoutine (0))
|
||||
{
|
||||
background->fillWithBackground (g, false);
|
||||
background->drawElements (g, getLocalBounds());
|
||||
|
||||
grid.draw (g, background);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.draw (g, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
if (! getBounds().isEmpty())
|
||||
{
|
||||
int numTimesToTry = 10;
|
||||
|
||||
while (--numTimesToTry >= 0)
|
||||
{
|
||||
bool anyCompsMoved = false;
|
||||
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
{
|
||||
Component* comp = getChildComponent (i);
|
||||
|
||||
if (ComponentTypeHandler* const type = ComponentTypeHandler::getHandlerFor (*comp))
|
||||
{
|
||||
const Rectangle<int> newBounds (type->getComponentPosition (comp)
|
||||
.getRectangle (getLocalBounds(),
|
||||
document.getComponentLayout()));
|
||||
|
||||
anyCompsMoved = anyCompsMoved || (comp->getBounds() != newBounds);
|
||||
comp->setBounds (newBounds);
|
||||
}
|
||||
}
|
||||
|
||||
// repeat this loop until they've all stopped shuffling (might require a few
|
||||
// loops for all the relative positioned comps to settle down)
|
||||
if (! anyCompsMoved)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void moved() override
|
||||
{
|
||||
((ComponentLayoutEditor*) getParentComponent())->updateOverlayPositions();
|
||||
}
|
||||
|
||||
JucerDocument& document;
|
||||
SnapGridPainter& grid;
|
||||
|
||||
bool dontFillBackground;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ComponentLayoutEditor::ComponentLayoutEditor (JucerDocument& doc, ComponentLayout& cl)
|
||||
: document (doc), layout (cl), firstResize (true)
|
||||
{
|
||||
setWantsKeyboardFocus (true);
|
||||
|
||||
addAndMakeVisible (subCompHolder = new SubComponentHolderComp (document, grid));
|
||||
|
||||
refreshAllComponents();
|
||||
|
||||
setSize (document.getInitialWidth(),
|
||||
document.getInitialHeight());
|
||||
}
|
||||
|
||||
ComponentLayoutEditor::~ComponentLayoutEditor()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
|
||||
removeChildComponent (&lassoComp);
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ComponentLayoutEditor::visibilityChanged()
|
||||
{
|
||||
document.beginTransaction();
|
||||
|
||||
if (isVisible())
|
||||
{
|
||||
refreshAllComponents();
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
else
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refreshAllComponents();
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::paint (Graphics&)
|
||||
{
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::resized()
|
||||
{
|
||||
if (firstResize && getWidth() > 0 && getHeight() > 0)
|
||||
{
|
||||
firstResize = false;
|
||||
refreshAllComponents();
|
||||
}
|
||||
|
||||
subCompHolder->setBounds (getComponentArea());
|
||||
updateOverlayPositions();
|
||||
}
|
||||
|
||||
Rectangle<int> ComponentLayoutEditor::getComponentArea() const
|
||||
{
|
||||
const int editorEdgeGap = 4;
|
||||
|
||||
if (document.isFixedSize())
|
||||
return Rectangle<int> ((getWidth() - document.getInitialWidth()) / 2,
|
||||
(getHeight() - document.getInitialHeight()) / 2,
|
||||
document.getInitialWidth(),
|
||||
document.getInitialHeight());
|
||||
|
||||
return Rectangle<int> (editorEdgeGap, editorEdgeGap,
|
||||
getWidth() - editorEdgeGap * 2,
|
||||
getHeight() - editorEdgeGap * 2);
|
||||
}
|
||||
|
||||
Image ComponentLayoutEditor::createComponentLayerSnapshot() const
|
||||
{
|
||||
((SubComponentHolderComp*) subCompHolder)->dontFillBackground = true;
|
||||
Image im = subCompHolder->createComponentSnapshot (Rectangle<int> (0, 0, subCompHolder->getWidth(), subCompHolder->getHeight()));
|
||||
((SubComponentHolderComp*) subCompHolder)->dontFillBackground = false;
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::updateOverlayPositions()
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
if (ComponentOverlayComponent* const overlay = dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)))
|
||||
overlay->updateBoundsToMatchTarget();
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::refreshAllComponents()
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
std::unique_ptr<ComponentOverlayComponent> overlay (dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)));
|
||||
|
||||
if (overlay != nullptr && layout.containsComponent (overlay->target))
|
||||
overlay.release();
|
||||
}
|
||||
|
||||
for (int i = subCompHolder->getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
Component* const comp = subCompHolder->getChildComponent (i);
|
||||
|
||||
if (! layout.containsComponent (comp))
|
||||
subCompHolder->removeChildComponent (comp);
|
||||
}
|
||||
|
||||
Component* lastComp = nullptr;
|
||||
Component* lastOverlay = nullptr;
|
||||
|
||||
for (int i = layout.getNumComponents(); --i >= 0;)
|
||||
{
|
||||
auto c = layout.getComponent (i);
|
||||
jassert (c != nullptr);
|
||||
|
||||
auto overlay = getOverlayCompFor (c);
|
||||
|
||||
bool isNewOverlay = false;
|
||||
|
||||
if (overlay == nullptr)
|
||||
{
|
||||
auto handler = ComponentTypeHandler::getHandlerFor (*c);
|
||||
jassert (handler != nullptr);
|
||||
|
||||
overlay = handler->createOverlayComponent (c, layout);
|
||||
|
||||
addAndMakeVisible (overlay);
|
||||
isNewOverlay = true;
|
||||
}
|
||||
|
||||
if (lastOverlay != nullptr)
|
||||
overlay->toBehind (lastOverlay);
|
||||
else
|
||||
overlay->toFront (false);
|
||||
|
||||
lastOverlay = overlay;
|
||||
|
||||
subCompHolder->addAndMakeVisible (c);
|
||||
|
||||
if (lastComp != nullptr)
|
||||
c->toBehind (lastComp);
|
||||
else
|
||||
c->toFront (false);
|
||||
|
||||
lastComp = c;
|
||||
|
||||
c->setWantsKeyboardFocus (false);
|
||||
c->setFocusContainerType (FocusContainerType::keyboardFocusContainer);
|
||||
|
||||
if (isNewOverlay)
|
||||
overlay->updateBoundsToMatchTarget();
|
||||
}
|
||||
|
||||
if (grid.updateFromDesign (document))
|
||||
subCompHolder->repaint();
|
||||
|
||||
subCompHolder->setBounds (getComponentArea());
|
||||
subCompHolder->resized();
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::mouseDown (const MouseEvent& e)
|
||||
{
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
auto commandManager = &ProjucerApplication::getCommandManager();
|
||||
|
||||
PopupMenu m;
|
||||
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::editCompLayout);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::editCompGraphics);
|
||||
m.addSeparator();
|
||||
|
||||
for (int i = 0; i < ObjectTypes::numComponentTypes; ++i)
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::newComponentBase + i);
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options());
|
||||
}
|
||||
else
|
||||
{
|
||||
addChildComponent (lassoComp);
|
||||
lassoComp.beginLasso (e, this);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
lassoComp.toFront (false);
|
||||
lassoComp.dragLasso (e);
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
lassoComp.endLasso();
|
||||
removeChildComponent (&lassoComp);
|
||||
|
||||
if (! (e.mouseWasDraggedSinceMouseDown() || e.mods.isAnyModifierKeyDown()))
|
||||
layout.getSelectedSet().deselectAll();
|
||||
}
|
||||
|
||||
static void moveOrStretch (ComponentLayout& layout, int x, int y, bool snap, bool stretch)
|
||||
{
|
||||
if (stretch)
|
||||
layout.stretchSelectedComps (x, y, snap);
|
||||
else
|
||||
layout.moveSelectedComps (x, y, snap);
|
||||
}
|
||||
|
||||
bool ComponentLayoutEditor::keyPressed (const KeyPress& key)
|
||||
{
|
||||
const bool snap = key.getModifiers().isAltDown();
|
||||
const bool stretch = key.getModifiers().isShiftDown();
|
||||
|
||||
const int amount = snap ? document.getSnappingGridSize() + 1
|
||||
: 1;
|
||||
|
||||
if (key.isKeyCode (KeyPress::rightKey))
|
||||
{
|
||||
moveOrStretch (layout, amount, 0, snap, stretch);
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::downKey))
|
||||
{
|
||||
moveOrStretch (layout, 0,amount, snap, stretch);
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::leftKey))
|
||||
{
|
||||
moveOrStretch (layout, -amount, 0, snap, stretch);
|
||||
}
|
||||
else if (key.isKeyCode (KeyPress::upKey))
|
||||
{
|
||||
moveOrStretch (layout, 0, -amount, snap, stretch);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ComponentLayoutEditor::isInterestedInFileDrag (const StringArray& filenames)
|
||||
{
|
||||
const File f (filenames [0]);
|
||||
return f.hasFileExtension (cppFileExtensions);
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
{
|
||||
const File f (filenames [0]);
|
||||
|
||||
if (JucerDocument::isValidJucerCppFile (f))
|
||||
{
|
||||
JucerComponentHandler jucerDocHandler;
|
||||
layout.getDocument()->beginTransaction();
|
||||
|
||||
if (TestComponent* newOne = dynamic_cast<TestComponent*> (layout.addNewComponent (&jucerDocHandler,
|
||||
x - subCompHolder->getX(),
|
||||
y - subCompHolder->getY())))
|
||||
{
|
||||
JucerComponentHandler::setJucerComponentFile (*layout.getDocument(), newOne,
|
||||
f.getRelativePathFrom (document.getCppFile().getParentDirectory()));
|
||||
layout.getSelectedSet().selectOnly (newOne);
|
||||
}
|
||||
|
||||
layout.getDocument()->beginTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
bool ComponentLayoutEditor::isInterestedInDragSource (const SourceDetails& dragSourceDetails)
|
||||
{
|
||||
if (dragSourceDetails.description != projectItemDragType)
|
||||
return false;
|
||||
|
||||
OwnedArray<Project::Item> selectedNodes;
|
||||
ProjectContentComponent::getSelectedProjectItemsBeingDragged (dragSourceDetails, selectedNodes);
|
||||
|
||||
return selectedNodes.size() > 0;
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::itemDropped (const SourceDetails& dragSourceDetails)
|
||||
{
|
||||
OwnedArray<Project::Item> selectedNodes;
|
||||
ProjectContentComponent::getSelectedProjectItemsBeingDragged (dragSourceDetails, selectedNodes);
|
||||
|
||||
StringArray filenames;
|
||||
|
||||
for (int i = 0; i < selectedNodes.size(); ++i)
|
||||
if (selectedNodes.getUnchecked(i)->getFile().hasFileExtension (cppFileExtensions))
|
||||
filenames.add (selectedNodes.getUnchecked(i)->getFile().getFullPathName());
|
||||
|
||||
filesDropped (filenames, dragSourceDetails.localPosition.x, dragSourceDetails.localPosition.y);
|
||||
}
|
||||
|
||||
ComponentOverlayComponent* ComponentLayoutEditor::getOverlayCompFor (Component* compToFind) const
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
{
|
||||
if (ComponentOverlayComponent* const overlay = dynamic_cast<ComponentOverlayComponent*> (getChildComponent (i)))
|
||||
if (overlay->target == compToFind)
|
||||
return overlay;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ComponentLayoutEditor::findLassoItemsInArea (Array <Component*>& results, const Rectangle<int>& area)
|
||||
{
|
||||
const Rectangle<int> lasso (area - subCompHolder->getPosition());
|
||||
|
||||
for (int i = 0; i < subCompHolder->getNumChildComponents(); ++i)
|
||||
{
|
||||
Component* c = subCompHolder->getChildComponent (i);
|
||||
|
||||
if (c->getBounds().intersects (lasso))
|
||||
results.add (c);
|
||||
}
|
||||
}
|
||||
|
||||
SelectedItemSet <Component*>& ComponentLayoutEditor::getLassoSelection()
|
||||
{
|
||||
return layout.getSelectedSet();
|
||||
}
|
||||
86
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.h
vendored
Normal file
86
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutEditor.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ComponentOverlayComponent.h"
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_SnapGridPainter.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentLayoutEditor : public Component,
|
||||
public FileDragAndDropTarget,
|
||||
public DragAndDropTarget,
|
||||
public LassoSource<Component*>,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentLayoutEditor (JucerDocument&, ComponentLayout&);
|
||||
~ComponentLayoutEditor() override;
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
void visibilityChanged() override;
|
||||
|
||||
void mouseDown (const MouseEvent&) override;
|
||||
void mouseDrag (const MouseEvent&) override;
|
||||
void mouseUp (const MouseEvent&) override;
|
||||
bool keyPressed (const KeyPress&) override;
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files) override;
|
||||
void filesDropped (const StringArray& filenames, int x, int y) override;
|
||||
|
||||
bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) override;
|
||||
void itemDropped (const SourceDetails& dragSourceDetails) override;
|
||||
|
||||
|
||||
ComponentLayout& getLayout() const noexcept { return layout; }
|
||||
|
||||
void findLassoItemsInArea (Array <Component*>& results, const Rectangle<int>& area) override;
|
||||
|
||||
SelectedItemSet<Component*>& getLassoSelection() override;
|
||||
|
||||
//==============================================================================
|
||||
void refreshAllComponents();
|
||||
void updateOverlayPositions();
|
||||
|
||||
ComponentOverlayComponent* getOverlayCompFor (Component*) const;
|
||||
|
||||
Rectangle<int> getComponentArea() const;
|
||||
Image createComponentLayerSnapshot() const;
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
|
||||
JucerDocument& document;
|
||||
ComponentLayout& layout;
|
||||
Component* subCompHolder;
|
||||
|
||||
LassoComponent<Component*> lassoComp;
|
||||
SnapGridPainter grid;
|
||||
bool firstResize;
|
||||
};
|
||||
118
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutPanel.h
vendored
Normal file
118
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentLayoutPanel.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
#include "jucer_EditingPanelBase.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentLayoutPanel : public EditingPanelBase
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentLayoutPanel (JucerDocument& doc, ComponentLayout& l)
|
||||
: EditingPanelBase (doc,
|
||||
new LayoutPropsPanel (doc, l),
|
||||
new ComponentLayoutEditor (doc, l)),
|
||||
layout (l)
|
||||
{
|
||||
}
|
||||
|
||||
~ComponentLayoutPanel()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void updatePropertiesList()
|
||||
{
|
||||
((LayoutPropsPanel*) propsPanel)->updateList();
|
||||
}
|
||||
|
||||
Rectangle<int> getComponentArea() const
|
||||
{
|
||||
return ((ComponentLayoutEditor*) editor)->getComponentArea();
|
||||
}
|
||||
|
||||
Image createComponentSnapshot() const
|
||||
{
|
||||
return ((ComponentLayoutEditor*) editor)->createComponentLayerSnapshot();
|
||||
}
|
||||
|
||||
ComponentLayout& layout;
|
||||
|
||||
private:
|
||||
class LayoutPropsPanel : public Component,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
LayoutPropsPanel (JucerDocument& doc, ComponentLayout& l)
|
||||
: document (doc), layout (l)
|
||||
{
|
||||
layout.getSelectedSet().addChangeListener (this);
|
||||
addAndMakeVisible (propsPanel);
|
||||
}
|
||||
|
||||
~LayoutPropsPanel() override
|
||||
{
|
||||
layout.getSelectedSet().removeChangeListener (this);
|
||||
clear();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
propsPanel.setBounds (4, 4, getWidth() - 8, getHeight() - 8);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
propsPanel.clear();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
clear();
|
||||
|
||||
auto numSelected = layout.getSelectedSet().getNumSelected();
|
||||
|
||||
if (numSelected > 0) // xxx need to cope with multiple
|
||||
{
|
||||
if (auto* comp = layout.getSelectedSet().getSelectedItem (0))
|
||||
if (auto* type = ComponentTypeHandler::getHandlerFor (*comp))
|
||||
type->addPropertiesToPropertyPanel (comp, document, propsPanel, numSelected > 1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
updateList();
|
||||
}
|
||||
|
||||
JucerDocument& document;
|
||||
ComponentLayout& layout;
|
||||
PropertyPanel propsPanel;
|
||||
};
|
||||
};
|
||||
278
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentOverlayComponent.cpp
vendored
Normal file
278
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentOverlayComponent.cpp
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
#include "../jucer_UtilityFunctions.h"
|
||||
|
||||
//==============================================================================
|
||||
ComponentOverlayComponent::ComponentOverlayComponent (Component* const target_,
|
||||
ComponentLayout& layout_)
|
||||
: target (target_),
|
||||
borderThickness (4),
|
||||
layout (layout_),
|
||||
selected (false),
|
||||
dragging (false),
|
||||
originalAspectRatio (1.0)
|
||||
{
|
||||
setMinimumOnscreenAmounts (0, 0, 0, 0);
|
||||
setSizeLimits (borderThickness * 2 + 2, borderThickness * 2 + 2, 8192, 8192);
|
||||
|
||||
border.reset (new ResizableBorderComponent (this, this));
|
||||
addChildComponent (border.get());
|
||||
|
||||
border->setBorderThickness (BorderSize<int> (borderThickness));
|
||||
|
||||
target->addComponentListener (this);
|
||||
|
||||
changeListenerCallback (nullptr);
|
||||
layout.getSelectedSet().addChangeListener (this);
|
||||
|
||||
setRepaintsOnMouseActivity (true);
|
||||
border->setRepaintsOnMouseActivity (true);
|
||||
}
|
||||
|
||||
ComponentOverlayComponent::~ComponentOverlayComponent()
|
||||
{
|
||||
layout.getSelectedSet().removeChangeListener (this);
|
||||
|
||||
if (target != nullptr)
|
||||
target->removeComponentListener (this);
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
const bool nowSelected = layout.getSelectedSet().isSelected (target);
|
||||
|
||||
if (selected != nowSelected)
|
||||
{
|
||||
selected = nowSelected;
|
||||
border->setVisible (nowSelected);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::paint (Graphics& g)
|
||||
{
|
||||
jassert (target != nullptr);
|
||||
|
||||
border->setColour (backgroundColourId, Colours::transparentBlack);
|
||||
if (selected)
|
||||
{
|
||||
auto selectedItems = layout.getSelectedSet();
|
||||
auto baseColour = findColour (defaultHighlightColourId);
|
||||
|
||||
const BorderSize<int> borderSize (border->getBorderThickness());
|
||||
|
||||
drawResizableBorder (g, getWidth(), getHeight(), borderSize,
|
||||
(isMouseOverOrDragging() || border->isMouseOverOrDragging()),
|
||||
baseColour.withAlpha (selectedItems.getSelectedItem (0) == target ? 1.0f : 0.3f));
|
||||
}
|
||||
else if (isMouseOverOrDragging())
|
||||
{
|
||||
drawMouseOverCorners (g, getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::resized()
|
||||
{
|
||||
jassert (target != nullptr);
|
||||
|
||||
border->setBounds (getLocalBounds());
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::mouseDown (const MouseEvent& e)
|
||||
{
|
||||
dragging = false;
|
||||
mouseDownSelectStatus = layout.getSelectedSet().addToSelectionOnMouseDown (target, e.mods);
|
||||
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
showPopupMenu();
|
||||
return; // this may be deleted now..
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
if (! e.mods.isPopupMenu())
|
||||
{
|
||||
if (selected && ! dragging)
|
||||
{
|
||||
dragging = e.mouseWasDraggedSinceMouseDown();
|
||||
|
||||
if (dragging)
|
||||
layout.startDragging();
|
||||
}
|
||||
|
||||
if (dragging)
|
||||
{
|
||||
layout.dragSelectedComps (e.getDistanceFromDragStartX(),
|
||||
e.getDistanceFromDragStartY());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
if (dragging)
|
||||
layout.endDragging();
|
||||
|
||||
layout.getSelectedSet().addToSelectionOnMouseUp (target, e.mods, dragging, mouseDownSelectStatus);
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::componentMovedOrResized (Component&, bool /*wasMoved*/, bool /*wasResized*/)
|
||||
{
|
||||
updateBoundsToMatchTarget();
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::updateBoundsToMatchTarget()
|
||||
{
|
||||
if (Component* const parent = target->getParentComponent())
|
||||
{
|
||||
const int dx = parent->getX();
|
||||
const int dy = parent->getY();
|
||||
|
||||
setBounds (dx + target->getX() - borderThickness,
|
||||
dy + target->getY() - borderThickness,
|
||||
target->getWidth() + borderThickness * 2,
|
||||
target->getHeight() + borderThickness * 2);
|
||||
}
|
||||
|
||||
if (border->isMouseButtonDown())
|
||||
layout.changed();
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::resizeStart()
|
||||
{
|
||||
if (getHeight() > 0)
|
||||
originalAspectRatio = getWidth() / (double) getHeight();
|
||||
else
|
||||
originalAspectRatio = 1.0;
|
||||
|
||||
layout.getDocument()->beginTransaction ("Resize components");
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::resizeEnd()
|
||||
{
|
||||
layout.getDocument()->beginTransaction();
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::checkBounds (Rectangle<int>& b,
|
||||
const Rectangle<int>& previousBounds,
|
||||
const Rectangle<int>& limits,
|
||||
const bool isStretchingTop,
|
||||
const bool isStretchingLeft,
|
||||
const bool isStretchingBottom,
|
||||
const bool isStretchingRight)
|
||||
{
|
||||
if (ModifierKeys::currentModifiers.isShiftDown())
|
||||
setFixedAspectRatio (originalAspectRatio);
|
||||
else
|
||||
setFixedAspectRatio (0.0);
|
||||
|
||||
ComponentBoundsConstrainer::checkBounds (b, previousBounds, limits, isStretchingTop, isStretchingLeft, isStretchingBottom, isStretchingRight);
|
||||
|
||||
if (layout.getDocument()->isSnapActive (true))
|
||||
{
|
||||
if (Component* const parent = target->getParentComponent())
|
||||
{
|
||||
const int dx = parent->getX();
|
||||
const int dy = parent->getY();
|
||||
|
||||
int x = b.getX();
|
||||
int y = b.getY();
|
||||
int w = b.getWidth();
|
||||
int h = b.getHeight();
|
||||
|
||||
x += borderThickness - dx;
|
||||
y += borderThickness - dy;
|
||||
w -= borderThickness * 2;
|
||||
h -= borderThickness * 2;
|
||||
|
||||
int right = x + w;
|
||||
int bottom = y + h;
|
||||
|
||||
if (isStretchingRight)
|
||||
right = layout.getDocument()->snapPosition (right);
|
||||
|
||||
if (isStretchingBottom)
|
||||
bottom = layout.getDocument()->snapPosition (bottom);
|
||||
|
||||
if (isStretchingLeft)
|
||||
x = layout.getDocument()->snapPosition (x);
|
||||
|
||||
if (isStretchingTop)
|
||||
y = layout.getDocument()->snapPosition (y);
|
||||
|
||||
w = (right - x) + borderThickness * 2;
|
||||
h = (bottom - y) + borderThickness * 2;
|
||||
x -= borderThickness - dx;
|
||||
y -= borderThickness - dy;
|
||||
|
||||
b = Rectangle<int> (x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Rectangle<int> b)
|
||||
{
|
||||
if (component.getBounds() != b)
|
||||
{
|
||||
layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
auto dX = b.getX() - component.getX();
|
||||
auto dY = b.getY() - component.getY();
|
||||
auto dW = b.getWidth() - component.getWidth();
|
||||
auto dH = b.getHeight() - component.getHeight();
|
||||
|
||||
component.setBounds (b);
|
||||
|
||||
if (auto* parent = target->getParentComponent())
|
||||
target->setBounds (b.getX() + borderThickness - parent->getX(),
|
||||
b.getY() + borderThickness - parent->getY(),
|
||||
b.getWidth() - borderThickness * 2,
|
||||
b.getHeight() - borderThickness * 2);
|
||||
|
||||
layout.updateStoredComponentPosition (target, true);
|
||||
|
||||
if (layout.getSelectedSet().getNumSelected() > 1)
|
||||
{
|
||||
for (auto s : layout.getSelectedSet())
|
||||
{
|
||||
if (s != target)
|
||||
{
|
||||
s->setBounds (s->getX() + dX, s->getY() + dY, s->getWidth() + dW, s->getHeight() + dH);
|
||||
layout.updateStoredComponentPosition (s, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::showPopupMenu()
|
||||
{
|
||||
ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
|
||||
}
|
||||
84
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentOverlayComponent.h
vendored
Normal file
84
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ComponentOverlayComponent.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentOverlayComponent : public Component,
|
||||
private ComponentBoundsConstrainer,
|
||||
private ComponentListener,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentOverlayComponent (Component* const targetComponent,
|
||||
ComponentLayout& layout);
|
||||
|
||||
~ComponentOverlayComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
virtual void showPopupMenu();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
void mouseDown (const MouseEvent&) override;
|
||||
void mouseDrag (const MouseEvent&) override;
|
||||
void mouseUp (const MouseEvent&) override;
|
||||
|
||||
void updateBoundsToMatchTarget();
|
||||
|
||||
//==============================================================================
|
||||
Component::SafePointer<Component> target;
|
||||
const int borderThickness;
|
||||
|
||||
private:
|
||||
void resizeStart() override;
|
||||
void resizeEnd() override;
|
||||
|
||||
void checkBounds (Rectangle<int>& bounds,
|
||||
const Rectangle<int>& previousBounds,
|
||||
const Rectangle<int>& limits,
|
||||
bool isStretchingTop,
|
||||
bool isStretchingLeft,
|
||||
bool isStretchingBottom,
|
||||
bool isStretchingRight) override;
|
||||
|
||||
void applyBoundsToComponent (Component&, Rectangle<int>) override;
|
||||
|
||||
void componentMovedOrResized (Component&, bool wasMoved, bool wasResized) override;
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
|
||||
std::unique_ptr<ResizableBorderComponent> border;
|
||||
|
||||
ComponentLayout& layout;
|
||||
|
||||
bool selected, dragging, mouseDownSelectStatus;
|
||||
double originalAspectRatio;
|
||||
};
|
||||
243
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_EditingPanelBase.cpp
vendored
Normal file
243
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_EditingPanelBase.cpp
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_EditingPanelBase.h"
|
||||
#include "jucer_JucerDocumentEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
class EditingPanelBase::MagnifierComponent : public Component
|
||||
{
|
||||
public:
|
||||
explicit MagnifierComponent (Component* c) : content (c)
|
||||
{
|
||||
addAndMakeVisible (content.get());
|
||||
childBoundsChanged (content.get());
|
||||
}
|
||||
|
||||
void childBoundsChanged (Component* child)
|
||||
{
|
||||
auto childArea = getLocalArea (child, child->getLocalBounds());
|
||||
setSize (childArea.getWidth(), childArea.getHeight());
|
||||
}
|
||||
|
||||
double getScaleFactor() const { return scaleFactor; }
|
||||
|
||||
void setScaleFactor (double newScale)
|
||||
{
|
||||
scaleFactor = newScale;
|
||||
content->setTransform (AffineTransform::scale ((float) scaleFactor));
|
||||
}
|
||||
|
||||
private:
|
||||
double scaleFactor = 1.0;
|
||||
std::unique_ptr<Component> content;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ZoomingViewport : public Viewport
|
||||
{
|
||||
public:
|
||||
explicit ZoomingViewport (EditingPanelBase* p) : panel (p)
|
||||
{
|
||||
}
|
||||
|
||||
void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel)
|
||||
{
|
||||
if (e.mods.isCtrlDown() || e.mods.isAltDown() || e.mods.isCommandDown())
|
||||
mouseMagnify (e, 1.0f / (1.0f - wheel.deltaY));
|
||||
else
|
||||
Viewport::mouseWheelMove (e, wheel);
|
||||
}
|
||||
|
||||
void mouseMagnify (const MouseEvent& e, float factor)
|
||||
{
|
||||
panel->setZoom (panel->getZoom() * factor, e.x, e.y);
|
||||
}
|
||||
|
||||
void dragKeyHeldDown (const bool isKeyDown)
|
||||
{
|
||||
if (isSpaceDown != isKeyDown)
|
||||
{
|
||||
isSpaceDown = isKeyDown;
|
||||
|
||||
if (isSpaceDown)
|
||||
{
|
||||
auto dc = new DraggerOverlayComp();
|
||||
addAndMakeVisible (dc);
|
||||
dc->setBounds (getLocalBounds());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
std::unique_ptr<DraggerOverlayComp> deleter (dynamic_cast<DraggerOverlayComp*> (getChildComponent (i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EditingPanelBase* const panel;
|
||||
bool isSpaceDown = false;
|
||||
|
||||
//==============================================================================
|
||||
class DraggerOverlayComp : public Component
|
||||
{
|
||||
public:
|
||||
DraggerOverlayComp()
|
||||
{
|
||||
setMouseCursor (MouseCursor::DraggingHandCursor);
|
||||
setAlwaysOnTop (true);
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&)
|
||||
{
|
||||
if (Viewport* viewport = findParentComponentOfClass<Viewport>())
|
||||
{
|
||||
startX = viewport->getViewPositionX();
|
||||
startY = viewport->getViewPositionY();
|
||||
}
|
||||
}
|
||||
|
||||
void mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
if (Viewport* viewport = findParentComponentOfClass<Viewport>())
|
||||
viewport->setViewPosition (jlimit (0, jmax (0, viewport->getViewedComponent()->getWidth() - viewport->getViewWidth()),
|
||||
startX - e.getDistanceFromDragStartX()),
|
||||
jlimit (0, jmax (0, viewport->getViewedComponent()->getHeight() - viewport->getViewHeight()),
|
||||
startY - e.getDistanceFromDragStartY()));
|
||||
}
|
||||
|
||||
private:
|
||||
int startX, startY;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
EditingPanelBase::EditingPanelBase (JucerDocument& doc, Component* props, Component* editorComp)
|
||||
: document (doc),
|
||||
editor (editorComp),
|
||||
propsPanel (props)
|
||||
{
|
||||
addAndMakeVisible (viewport = new ZoomingViewport (this));
|
||||
addAndMakeVisible (propsPanel);
|
||||
|
||||
viewport->setViewedComponent (magnifier = new MagnifierComponent (editor));
|
||||
}
|
||||
|
||||
EditingPanelBase::~EditingPanelBase()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void EditingPanelBase::resized()
|
||||
{
|
||||
const int contentW = jmax (1, getWidth() - 260);
|
||||
|
||||
propsPanel->setBounds (contentW + 4, 4, jmax (100, getWidth() - contentW - 8), getHeight() - 8);
|
||||
|
||||
viewport->setBounds (4, 4, contentW - 8, getHeight() - 8);
|
||||
|
||||
if (document.isFixedSize())
|
||||
editor->setSize (jmax (document.getInitialWidth(),
|
||||
roundToInt ((viewport->getWidth() - viewport->getScrollBarThickness()) / getZoom())),
|
||||
jmax (document.getInitialHeight(),
|
||||
roundToInt ((viewport->getHeight() - viewport->getScrollBarThickness()) / getZoom())));
|
||||
else
|
||||
editor->setSize (viewport->getWidth(),
|
||||
viewport->getHeight());
|
||||
}
|
||||
|
||||
void EditingPanelBase::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void EditingPanelBase::visibilityChanged()
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
updatePropertiesList();
|
||||
|
||||
if (Component* p = getParentComponent())
|
||||
{
|
||||
resized();
|
||||
|
||||
if (JucerDocumentEditor* const cdh = dynamic_cast<JucerDocumentEditor*> (p->getParentComponent()))
|
||||
cdh->setViewportToLastPos (viewport, *this);
|
||||
|
||||
resized();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Component* p = getParentComponent())
|
||||
if (JucerDocumentEditor* const cdh = dynamic_cast<JucerDocumentEditor*> (p->getParentComponent()))
|
||||
cdh->storeLastViewportPos (viewport, *this);
|
||||
}
|
||||
|
||||
editor->setVisible (isVisible());
|
||||
}
|
||||
|
||||
double EditingPanelBase::getZoom() const
|
||||
{
|
||||
return magnifier->getScaleFactor();
|
||||
}
|
||||
|
||||
void EditingPanelBase::setZoom (double newScale)
|
||||
{
|
||||
setZoom (jlimit (1.0 / 8.0, 16.0, newScale),
|
||||
viewport->getWidth() / 2,
|
||||
viewport->getHeight() / 2);
|
||||
}
|
||||
|
||||
void EditingPanelBase::setZoom (double newScale, int anchorX, int anchorY)
|
||||
{
|
||||
Point<int> anchor (editor->getLocalPoint (viewport, Point<int> (anchorX, anchorY)));
|
||||
|
||||
magnifier->setScaleFactor (newScale);
|
||||
|
||||
resized();
|
||||
|
||||
jassert (viewport != nullptr);
|
||||
anchor = viewport->getLocalPoint (editor, anchor);
|
||||
|
||||
viewport->setViewPosition (jlimit (0, jmax (0, viewport->getViewedComponent()->getWidth() - viewport->getViewWidth()),
|
||||
viewport->getViewPositionX() + anchor.getX() - anchorX),
|
||||
jlimit (0, jmax (0, viewport->getViewedComponent()->getHeight() - viewport->getViewHeight()),
|
||||
viewport->getViewPositionY() + anchor.getY() - anchorY));
|
||||
}
|
||||
|
||||
void EditingPanelBase::xyToTargetXY (int& x, int& y) const
|
||||
{
|
||||
Point<int> pos (editor->getLocalPoint (this, Point<int> (x, y)));
|
||||
x = pos.getX();
|
||||
y = pos.getY();
|
||||
}
|
||||
|
||||
void EditingPanelBase::dragKeyHeldDown (bool isKeyDown)
|
||||
{
|
||||
((ZoomingViewport*) viewport)->dragKeyHeldDown (isKeyDown);
|
||||
}
|
||||
75
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_EditingPanelBase.h
vendored
Normal file
75
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_EditingPanelBase.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
class LayoutPropsPanel;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class for the layout and graphics panels - this takes care of arranging
|
||||
the properties panel and managing the viewport for the content.
|
||||
|
||||
*/
|
||||
class EditingPanelBase : public Component
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
EditingPanelBase (JucerDocument& document,
|
||||
Component* propsPanel,
|
||||
Component* editorComp);
|
||||
|
||||
~EditingPanelBase() override;
|
||||
|
||||
//==============================================================================
|
||||
void resized() override;
|
||||
void paint (Graphics& g) override;
|
||||
void visibilityChanged() override;
|
||||
|
||||
virtual void updatePropertiesList() = 0;
|
||||
|
||||
virtual Rectangle<int> getComponentArea() const = 0;
|
||||
|
||||
double getZoom() const;
|
||||
void setZoom (double newScale);
|
||||
void setZoom (double newScale, int anchorX, int anchorY);
|
||||
|
||||
// convert a pos relative to this component into a pos on the editor
|
||||
void xyToTargetXY (int& x, int& y) const;
|
||||
|
||||
void dragKeyHeldDown (bool isKeyDown);
|
||||
|
||||
class MagnifierComponent;
|
||||
|
||||
protected:
|
||||
JucerDocument& document;
|
||||
|
||||
Viewport* viewport;
|
||||
MagnifierComponent* magnifier;
|
||||
Component* editor;
|
||||
Component* propsPanel;
|
||||
};
|
||||
71
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerCommandIDs.h
vendored
Normal file
71
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerCommandIDs.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A namespace to hold all the possible command IDs.
|
||||
*/
|
||||
namespace JucerCommandIDs
|
||||
{
|
||||
enum
|
||||
{
|
||||
test = 0xf20009,
|
||||
toFront = 0xf2000a,
|
||||
toBack = 0xf2000b,
|
||||
|
||||
group = 0xf20017,
|
||||
ungroup = 0xf20018,
|
||||
|
||||
showGrid = 0xf2000e,
|
||||
enableSnapToGrid = 0xf2000f,
|
||||
|
||||
editCompLayout = 0xf20010,
|
||||
editCompGraphics = 0xf20011,
|
||||
|
||||
bringBackLostItems = 0xf20012,
|
||||
|
||||
zoomIn = 0xf20013,
|
||||
zoomOut = 0xf20014,
|
||||
zoomNormal = 0xf20015,
|
||||
spaceBarDrag = 0xf20016,
|
||||
|
||||
compOverlay0 = 0xf20020,
|
||||
compOverlay33 = 0xf20021,
|
||||
compOverlay66 = 0xf20022,
|
||||
compOverlay100 = 0xf20023,
|
||||
|
||||
newDocumentBase = 0xf32001,
|
||||
newComponentBase = 0xf30001,
|
||||
newElementBase = 0xf31001,
|
||||
|
||||
alignTop = 0xf33000,
|
||||
alignRight = 0xf33001,
|
||||
alignBottom = 0xf33002,
|
||||
alignLeft = 0xf33003,
|
||||
};
|
||||
}
|
||||
1324
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp
vendored
Normal file
1324
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
104
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.h
vendored
Normal file
104
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_JucerDocumentEditor.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
#include "jucer_PaintRoutineEditor.h"
|
||||
#include "jucer_ComponentLayoutPanel.h"
|
||||
|
||||
//==============================================================================
|
||||
class JucerDocumentEditor : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
JucerDocumentEditor (JucerDocument* const document);
|
||||
~JucerDocumentEditor() override;
|
||||
|
||||
JucerDocument* getDocument() const noexcept { return document.get(); }
|
||||
|
||||
void refreshPropertiesPanel() const;
|
||||
void updateTabs();
|
||||
|
||||
void showLayout();
|
||||
void showGraphics (PaintRoutine* routine);
|
||||
|
||||
void setViewportToLastPos (Viewport* vp, EditingPanelBase& editor);
|
||||
void storeLastViewportPos (Viewport* vp, EditingPanelBase& editor);
|
||||
|
||||
Image createComponentLayerSnapshot() const;
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override;
|
||||
void resized() override;
|
||||
bool keyPressed (const KeyPress&) override;
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* getNextCommandTarget() override;
|
||||
void getAllCommands (Array<CommandID>&) override;
|
||||
void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
|
||||
bool perform (const InvocationInfo&) override;
|
||||
|
||||
static JucerDocumentEditor* getActiveDocumentHolder();
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
|
||||
std::unique_ptr<JucerDocument> document;
|
||||
ComponentLayoutPanel* compLayoutPanel = nullptr;
|
||||
|
||||
struct JucerDocumentTabs : public TabbedComponent
|
||||
{
|
||||
JucerDocumentTabs (JucerDocument* d) : TabbedComponent (TabbedButtonBar::TabsAtTop), document (d) {}
|
||||
void currentTabChanged (int, const String&) override { document->refreshCustomCodeFromDocument(); }
|
||||
|
||||
JucerDocument* document;
|
||||
};
|
||||
|
||||
JucerDocumentTabs tabbedComponent;
|
||||
|
||||
int lastViewportX = 0, lastViewportY = 0;
|
||||
double currentZoomLevel = 1.0;
|
||||
|
||||
void saveLastSelectedTab() const;
|
||||
void restoreLastSelectedTab();
|
||||
|
||||
bool isSomethingSelected() const;
|
||||
bool areMultipleThingsSelected() const;
|
||||
|
||||
// only non-zero if a layout tab is selected
|
||||
ComponentLayout* getCurrentLayout() const;
|
||||
// only non-zero if a graphics tab is selected
|
||||
PaintRoutine* getCurrentPaintRoutine() const;
|
||||
|
||||
void setZoom (double scale);
|
||||
double getZoom() const;
|
||||
|
||||
void addElement (int index);
|
||||
void addComponent (int index);
|
||||
};
|
||||
281
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp
vendored
Normal file
281
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.cpp
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "../../Application/jucer_Application.h"
|
||||
#include "../UI/jucer_JucerCommandIDs.h"
|
||||
#include "jucer_PaintRoutineEditor.h"
|
||||
#include "../jucer_ObjectTypes.h"
|
||||
#include "jucer_JucerDocumentEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
PaintRoutineEditor::PaintRoutineEditor (PaintRoutine& pr, JucerDocument& doc,
|
||||
JucerDocumentEditor* docHolder)
|
||||
: graphics (pr),
|
||||
document (doc),
|
||||
documentHolder (docHolder),
|
||||
componentOverlay (nullptr),
|
||||
componentOverlayOpacity (0.0f)
|
||||
{
|
||||
refreshAllElements();
|
||||
|
||||
setSize (document.getInitialWidth(),
|
||||
document.getInitialHeight());
|
||||
}
|
||||
|
||||
PaintRoutineEditor::~PaintRoutineEditor()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
removeAllElementComps();
|
||||
removeChildComponent (&lassoComp);
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::removeAllElementComps()
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
|
||||
removeChildComponent (e);
|
||||
}
|
||||
|
||||
Rectangle<int> PaintRoutineEditor::getComponentArea() const
|
||||
{
|
||||
if (document.isFixedSize())
|
||||
return Rectangle<int> ((getWidth() - document.getInitialWidth()) / 2,
|
||||
(getHeight() - document.getInitialHeight()) / 2,
|
||||
document.getInitialWidth(),
|
||||
document.getInitialHeight());
|
||||
|
||||
return getLocalBounds().reduced (4);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintRoutineEditor::paint (Graphics& g)
|
||||
{
|
||||
const Rectangle<int> clip (getComponentArea());
|
||||
|
||||
g.reduceClipRegion (clip);
|
||||
g.setOrigin (clip.getPosition());
|
||||
|
||||
graphics.fillWithBackground (g, true);
|
||||
grid.draw (g, &graphics);
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::paintOverChildren (Graphics& g)
|
||||
{
|
||||
if (componentOverlay.isNull() && document.getComponentOverlayOpacity() > 0.0f)
|
||||
updateComponentOverlay();
|
||||
|
||||
if (componentOverlay.isValid())
|
||||
{
|
||||
const Rectangle<int> clip (getComponentArea());
|
||||
g.drawImageAt (componentOverlay, clip.getX(), clip.getY());
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::resized()
|
||||
{
|
||||
if (getWidth() > 0 && getHeight() > 0)
|
||||
{
|
||||
componentOverlay = Image();
|
||||
refreshAllElements();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::updateChildBounds()
|
||||
{
|
||||
const Rectangle<int> clip (getComponentArea());
|
||||
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
|
||||
e->updateBounds (clip);
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::updateComponentOverlay()
|
||||
{
|
||||
if (componentOverlay.isValid())
|
||||
repaint();
|
||||
|
||||
componentOverlay = Image();
|
||||
componentOverlayOpacity = document.getComponentOverlayOpacity();
|
||||
|
||||
if (componentOverlayOpacity > 0.0f)
|
||||
{
|
||||
if (documentHolder != nullptr)
|
||||
componentOverlay = documentHolder->createComponentLayerSnapshot();
|
||||
|
||||
if (componentOverlay.isValid())
|
||||
{
|
||||
componentOverlay.multiplyAllAlphas (componentOverlayOpacity);
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::visibilityChanged()
|
||||
{
|
||||
document.beginTransaction();
|
||||
|
||||
if (isVisible())
|
||||
{
|
||||
refreshAllElements();
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
else
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
componentOverlay = Image();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::refreshAllElements()
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
if (auto* e = dynamic_cast<PaintElement*> (getChildComponent (i)))
|
||||
if (! graphics.containsElement (e))
|
||||
removeChildComponent (e);
|
||||
|
||||
Component* last = nullptr;
|
||||
|
||||
for (int i = graphics.getNumElements(); --i >= 0;)
|
||||
{
|
||||
auto* e = graphics.getElement (i);
|
||||
|
||||
addAndMakeVisible (e);
|
||||
|
||||
if (last != nullptr)
|
||||
e->toBehind (last);
|
||||
else
|
||||
e->toFront (false);
|
||||
|
||||
last = e;
|
||||
}
|
||||
|
||||
updateChildBounds();
|
||||
|
||||
if (grid.updateFromDesign (document))
|
||||
repaint();
|
||||
|
||||
if (currentBackgroundColour != graphics.getBackgroundColour())
|
||||
{
|
||||
currentBackgroundColour = graphics.getBackgroundColour();
|
||||
repaint();
|
||||
}
|
||||
|
||||
if (componentOverlayOpacity != document.getComponentOverlayOpacity())
|
||||
{
|
||||
componentOverlay = Image();
|
||||
componentOverlayOpacity = document.getComponentOverlayOpacity();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
refreshAllElements();
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::mouseDown (const MouseEvent& e)
|
||||
{
|
||||
if (e.mods.isPopupMenu())
|
||||
{
|
||||
ApplicationCommandManager* commandManager = &ProjucerApplication::getCommandManager();
|
||||
|
||||
PopupMenu m;
|
||||
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::editCompLayout);
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::editCompGraphics);
|
||||
m.addSeparator();
|
||||
|
||||
for (int i = 0; i < ObjectTypes::numElementTypes; ++i)
|
||||
m.addCommandItem (commandManager, JucerCommandIDs::newElementBase + i);
|
||||
|
||||
m.showMenuAsync (PopupMenu::Options());
|
||||
}
|
||||
else
|
||||
{
|
||||
addChildComponent (lassoComp);
|
||||
lassoComp.beginLasso (e, this);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
lassoComp.toFront (false);
|
||||
lassoComp.dragLasso (e);
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::mouseUp (const MouseEvent& e)
|
||||
{
|
||||
lassoComp.endLasso();
|
||||
|
||||
if (! (e.mouseWasDraggedSinceMouseDown() || e.mods.isAnyModifierKeyDown()))
|
||||
{
|
||||
graphics.getSelectedElements().deselectAll();
|
||||
graphics.getSelectedPoints().deselectAll();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::findLassoItemsInArea (Array <PaintElement*>& results, const Rectangle<int>& lasso)
|
||||
{
|
||||
for (int i = 0; i < getNumChildComponents(); ++i)
|
||||
if (PaintElement* const e = dynamic_cast<PaintElement*> (getChildComponent (i)))
|
||||
if (e->getBounds().expanded (-e->borderThickness).intersects (lasso))
|
||||
results.add (e);
|
||||
}
|
||||
|
||||
SelectedItemSet <PaintElement*>& PaintRoutineEditor::getLassoSelection()
|
||||
{
|
||||
return graphics.getSelectedElements();
|
||||
}
|
||||
|
||||
bool PaintRoutineEditor::isInterestedInFileDrag (const StringArray& files)
|
||||
{
|
||||
return File::createFileWithoutCheckingPath (files[0])
|
||||
.hasFileExtension ("jpg;jpeg;png;gif;svg");
|
||||
}
|
||||
|
||||
void PaintRoutineEditor::filesDropped (const StringArray& filenames, int x, int y)
|
||||
{
|
||||
const File f (filenames [0]);
|
||||
|
||||
if (f.existsAsFile())
|
||||
{
|
||||
std::unique_ptr<Drawable> d (Drawable::createFromImageFile (f));
|
||||
|
||||
if (d != nullptr)
|
||||
{
|
||||
d.reset();
|
||||
|
||||
document.beginTransaction();
|
||||
|
||||
graphics.dropImageAt (f,
|
||||
jlimit (10, getWidth() - 10, x),
|
||||
jlimit (10, getHeight() - 10, y));
|
||||
|
||||
document.beginTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
83
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.h
vendored
Normal file
83
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutineEditor.h
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "../jucer_PaintRoutine.h"
|
||||
#include "jucer_SnapGridPainter.h"
|
||||
class JucerDocumentEditor;
|
||||
|
||||
//==============================================================================
|
||||
class PaintRoutineEditor : public Component,
|
||||
public LassoSource <PaintElement*>,
|
||||
public FileDragAndDropTarget,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PaintRoutineEditor (PaintRoutine& graphics,
|
||||
JucerDocument& document,
|
||||
JucerDocumentEditor* const docHolder);
|
||||
~PaintRoutineEditor();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g);
|
||||
void paintOverChildren (Graphics& g);
|
||||
void resized();
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
|
||||
void mouseDown (const MouseEvent& e);
|
||||
void mouseDrag (const MouseEvent& e);
|
||||
void mouseUp (const MouseEvent& e);
|
||||
void visibilityChanged();
|
||||
|
||||
void findLassoItemsInArea (Array <PaintElement*>& results, const Rectangle<int>& area);
|
||||
|
||||
SelectedItemSet <PaintElement*>& getLassoSelection();
|
||||
|
||||
bool isInterestedInFileDrag (const StringArray& files);
|
||||
void filesDropped (const StringArray& filenames, int x, int y);
|
||||
|
||||
Rectangle<int> getComponentArea() const;
|
||||
|
||||
//==============================================================================
|
||||
void refreshAllElements();
|
||||
|
||||
private:
|
||||
PaintRoutine& graphics;
|
||||
JucerDocument& document;
|
||||
JucerDocumentEditor* const documentHolder;
|
||||
LassoComponent <PaintElement*> lassoComp;
|
||||
SnapGridPainter grid;
|
||||
Image componentOverlay;
|
||||
float componentOverlayOpacity;
|
||||
|
||||
Colour currentBackgroundColour;
|
||||
|
||||
void removeAllElementComps();
|
||||
void updateComponentOverlay();
|
||||
void updateChildBounds();
|
||||
};
|
||||
185
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutinePanel.cpp
vendored
Normal file
185
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutinePanel.cpp
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_PaintRoutinePanel.h"
|
||||
#include "../Properties/jucer_ColourPropertyComponent.h"
|
||||
#include "../PaintElements/jucer_PaintElementPath.h"
|
||||
|
||||
//==============================================================================
|
||||
class ComponentBackgroundColourProperty : public JucerColourPropertyComponent,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ComponentBackgroundColourProperty (JucerDocument& doc,
|
||||
PaintRoutine& routine_)
|
||||
: JucerColourPropertyComponent ("background", false),
|
||||
document (doc),
|
||||
routine (routine_)
|
||||
{
|
||||
document.addChangeListener (this);
|
||||
}
|
||||
|
||||
~ComponentBackgroundColourProperty() override
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void setColour (Colour newColour) override { routine.setBackgroundColour (newColour); }
|
||||
Colour getColour() const override { return routine.getBackgroundColour(); }
|
||||
|
||||
void resetToDefault() override
|
||||
{
|
||||
jassertfalse; // option shouldn't be visible
|
||||
}
|
||||
|
||||
protected:
|
||||
JucerDocument& document;
|
||||
PaintRoutine& routine;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class GraphicsPropsPanel : public Component,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
GraphicsPropsPanel (PaintRoutine& paintRoutine_,
|
||||
JucerDocument* doc)
|
||||
: paintRoutine (paintRoutine_),
|
||||
document (doc)
|
||||
{
|
||||
paintRoutine.getSelectedElements().addChangeListener (this);
|
||||
paintRoutine.getSelectedPoints().addChangeListener (this);
|
||||
|
||||
addAndMakeVisible (propsPanel = new PropertyPanel());
|
||||
}
|
||||
|
||||
~GraphicsPropsPanel() override
|
||||
{
|
||||
paintRoutine.getSelectedPoints().removeChangeListener (this);
|
||||
paintRoutine.getSelectedElements().removeChangeListener (this);
|
||||
|
||||
clear();
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
propsPanel->setBounds (4, 4, getWidth() - 8, getHeight() - 8);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
propsPanel->clear();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
auto state = propsPanel->getOpennessState();
|
||||
|
||||
clear();
|
||||
|
||||
if (document != nullptr)
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
props.add (new ComponentBackgroundColourProperty (*document, paintRoutine));
|
||||
|
||||
propsPanel->addSection ("Class Properties", props);
|
||||
}
|
||||
|
||||
if (state != nullptr)
|
||||
propsPanel->restoreOpennessState (*state);
|
||||
|
||||
auto numSelected = paintRoutine.getSelectedElements().getNumSelected();
|
||||
|
||||
if (numSelected > 0) // xxx need to cope with multiple
|
||||
{
|
||||
if (auto* pe = paintRoutine.getSelectedElements().getSelectedItem (0))
|
||||
{
|
||||
if (paintRoutine.containsElement (pe))
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
pe->getEditableProperties (props, numSelected > 1);
|
||||
|
||||
propsPanel->addSection (pe->getTypeName(), props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paintRoutine.getSelectedPoints().getNumSelected() == 1) // xxx need to cope with multiple
|
||||
{
|
||||
if (auto* point = paintRoutine.getSelectedPoints().getSelectedItem (0))
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
point->getEditableProperties (props, false);
|
||||
|
||||
propsPanel->addSection ("Path segment", props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void changeListenerCallback (ChangeBroadcaster*) override
|
||||
{
|
||||
updateList();
|
||||
}
|
||||
|
||||
PaintRoutine& paintRoutine;
|
||||
JucerDocument* document;
|
||||
|
||||
PropertyPanel* propsPanel;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
PaintRoutinePanel::PaintRoutinePanel (JucerDocument& doc, PaintRoutine& pr,
|
||||
JucerDocumentEditor* documentHolder)
|
||||
: EditingPanelBase (doc,
|
||||
new GraphicsPropsPanel (pr, &doc),
|
||||
new PaintRoutineEditor (pr, doc, documentHolder)),
|
||||
routine (pr)
|
||||
{
|
||||
}
|
||||
|
||||
PaintRoutinePanel::~PaintRoutinePanel()
|
||||
{
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void PaintRoutinePanel::updatePropertiesList()
|
||||
{
|
||||
((GraphicsPropsPanel*) propsPanel)->updateList();
|
||||
}
|
||||
|
||||
Rectangle<int> PaintRoutinePanel::getComponentArea() const
|
||||
{
|
||||
return ((PaintRoutineEditor*) editor)->getComponentArea();
|
||||
}
|
||||
45
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutinePanel.h
vendored
Normal file
45
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_PaintRoutinePanel.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_PaintRoutineEditor.h"
|
||||
#include "jucer_EditingPanelBase.h"
|
||||
|
||||
//==============================================================================
|
||||
class PaintRoutinePanel : public EditingPanelBase
|
||||
{
|
||||
public:
|
||||
PaintRoutinePanel (JucerDocument&, PaintRoutine&, JucerDocumentEditor*);
|
||||
~PaintRoutinePanel();
|
||||
|
||||
PaintRoutine& getPaintRoutine() const noexcept { return routine; }
|
||||
|
||||
void updatePropertiesList();
|
||||
Rectangle<int> getComponentArea() const;
|
||||
|
||||
private:
|
||||
PaintRoutine& routine;
|
||||
};
|
||||
759
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h
vendored
Normal file
759
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_RelativePositionedRectangle.h
vendored
Normal file
@@ -0,0 +1,759 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class ComponentLayout;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A rectangle whose coordinates can be defined in terms of absolute or
|
||||
proportional distances.
|
||||
|
||||
Designed mainly for storing component positions, this gives you a lot of
|
||||
control over how each coordinate is stored, either as an absolute position,
|
||||
or as a proportion of the size of a parent rectangle.
|
||||
|
||||
It also allows you to define the anchor points by which the rectangle is
|
||||
positioned, so for example you could specify that the top right of the
|
||||
rectangle should be an absolute distance from its parent's bottom-right corner.
|
||||
|
||||
This object can be stored as a string, which takes the form "x y w h", including
|
||||
symbols like '%' and letters to indicate the anchor point. See its toString()
|
||||
method for more info.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
class MyComponent
|
||||
{
|
||||
void resized()
|
||||
{
|
||||
// this will set the child component's x to be 20% of our width, its y
|
||||
// to be 30, its width to be 150, and its height to be 50% of our
|
||||
// height..
|
||||
const PositionedRectangle pos1 ("20% 30 150 50%");
|
||||
pos1.applyToComponent (*myChildComponent1);
|
||||
|
||||
// this will inset the child component with a gap of 10 pixels
|
||||
// around each of its edges..
|
||||
const PositionedRectangle pos2 ("10 10 20M 20M");
|
||||
pos2.applyToComponent (*myChildComponent2);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class PositionedRectangle
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty rectangle with all coordinates set to zero.
|
||||
|
||||
The default anchor point is top-left; the default
|
||||
*/
|
||||
PositionedRectangle() noexcept
|
||||
: x (0.0), y (0.0), w (0.0), h (0.0),
|
||||
xMode ((int) anchorAtLeftOrTop | (int) absoluteFromParentTopLeft),
|
||||
yMode ((int) anchorAtLeftOrTop | (int) absoluteFromParentTopLeft),
|
||||
wMode (absoluteSize), hMode (absoluteSize)
|
||||
{
|
||||
}
|
||||
|
||||
/** Initialises a PositionedRectangle from a saved string version.
|
||||
|
||||
The string must be in the format generated by toString().
|
||||
*/
|
||||
PositionedRectangle (const String& stringVersion) noexcept
|
||||
{
|
||||
StringArray tokens;
|
||||
tokens.addTokens (stringVersion, false);
|
||||
|
||||
decodePosString (tokens [0], xMode, x);
|
||||
decodePosString (tokens [1], yMode, y);
|
||||
decodeSizeString (tokens [2], wMode, w);
|
||||
decodeSizeString (tokens [3], hMode, h);
|
||||
}
|
||||
|
||||
/** Creates a copy of another PositionedRectangle. */
|
||||
PositionedRectangle (const PositionedRectangle& other) noexcept
|
||||
: x (other.x), y (other.y), w (other.w), h (other.h),
|
||||
xMode (other.xMode), yMode (other.yMode),
|
||||
wMode (other.wMode), hMode (other.hMode)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another PositionedRectangle. */
|
||||
PositionedRectangle& operator= (const PositionedRectangle& other) noexcept
|
||||
{
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
w = other.w;
|
||||
h = other.h;
|
||||
xMode = other.xMode;
|
||||
yMode = other.yMode;
|
||||
wMode = other.wMode;
|
||||
hMode = other.hMode;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string version of this position, from which it can later be
|
||||
re-generated.
|
||||
|
||||
The format is four coordinates, "x y w h".
|
||||
|
||||
- If a coordinate is absolute, it is stored as an integer, e.g. "100".
|
||||
- If a coordinate is proportional to its parent's width or height, it is stored
|
||||
as a percentage, e.g. "80%".
|
||||
- If the X or Y coordinate is relative to the parent's right or bottom edge, the
|
||||
number has "R" appended to it, e.g. "100R" means a distance of 100 pixels from
|
||||
the parent's right-hand edge.
|
||||
- If the X or Y coordinate is relative to the parent's centre, the number has "C"
|
||||
appended to it, e.g. "-50C" would be 50 pixels left of the parent's centre.
|
||||
- If the X or Y coordinate should be anchored at the component's right or bottom
|
||||
edge, then it has "r" appended to it. So "-50Rr" would mean that this component's
|
||||
right-hand edge should be 50 pixels left of the parent's right-hand edge.
|
||||
- If the X or Y coordinate should be anchored at the component's centre, then it
|
||||
has "c" appended to it. So "-50Rc" would mean that this component's
|
||||
centre should be 50 pixels left of the parent's right-hand edge. "40%c" means that
|
||||
this component's centre should be placed 40% across the parent's width.
|
||||
- If it's a width or height that should use the parentSizeMinusAbsolute mode, then
|
||||
the number has "M" appended to it.
|
||||
|
||||
To reload a stored string, use the constructor that takes a string parameter.
|
||||
*/
|
||||
String toString() const
|
||||
{
|
||||
String s;
|
||||
s.preallocateBytes (32);
|
||||
addPosDescription (s, xMode, x); s << ' ';
|
||||
addPosDescription (s, yMode, y); s << ' ';
|
||||
addSizeDescription (s, wMode, w); s << ' ';
|
||||
addSizeDescription (s, hMode, h);
|
||||
return s;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calculates the absolute position, given the size of the space that
|
||||
it should go in.
|
||||
|
||||
This will work out any proportional distances and sizes relative to the
|
||||
target rectangle, and will return the absolute position.
|
||||
|
||||
@see applyToComponent
|
||||
*/
|
||||
Rectangle<int> getRectangle (const Rectangle<int>& target) const noexcept
|
||||
{
|
||||
jassert (! target.isEmpty());
|
||||
|
||||
double x_, y_, w_, h_;
|
||||
applyPosAndSize (x_, w_, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
applyPosAndSize (y_, h_, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
return Rectangle<int> (roundToInt (x_), roundToInt (y_), roundToInt (w_), roundToInt (h_));
|
||||
}
|
||||
|
||||
/** Same as getRectangle(), but returning the values as doubles rather than ints. */
|
||||
void getRectangleDouble (const Rectangle<int>& target,
|
||||
double& x_, double& y_, double& w_, double& h_) const noexcept
|
||||
{
|
||||
jassert (! target.isEmpty());
|
||||
applyPosAndSize (x_, w_, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
applyPosAndSize (y_, h_, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
|
||||
/** This sets the bounds of the given component to this position.
|
||||
|
||||
This is equivalent to writing:
|
||||
@code
|
||||
comp.setBounds (getRectangle (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight())));
|
||||
@endcode
|
||||
|
||||
@see getRectangle, updateFromComponent
|
||||
*/
|
||||
void applyToComponent (Component& comp) const noexcept
|
||||
{
|
||||
comp.setBounds (getRectangle (Rectangle<int> (comp.getParentWidth(), comp.getParentHeight())));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Updates this object's coordinates to match the given rectangle.
|
||||
|
||||
This will set all coordinates based on the given rectangle, re-calculating
|
||||
any proportional distances, and using the current anchor points.
|
||||
|
||||
So for example if the x coordinate mode is currently proportional, this will
|
||||
re-calculate x based on the rectangle's relative position within the target
|
||||
rectangle's width.
|
||||
|
||||
If the target rectangle's width or height are zero then it may not be possible
|
||||
to re-calculate some proportional coordinates. In this case, those coordinates
|
||||
will not be changed.
|
||||
*/
|
||||
void updateFrom (const Rectangle<int>& newPosition,
|
||||
const Rectangle<int>& targetSpaceToBeRelativeTo) noexcept
|
||||
{
|
||||
updatePosAndSize (x, w, newPosition.getX(), newPosition.getWidth(), xMode, wMode, targetSpaceToBeRelativeTo.getX(), targetSpaceToBeRelativeTo.getWidth());
|
||||
updatePosAndSize (y, h, newPosition.getY(), newPosition.getHeight(), yMode, hMode, targetSpaceToBeRelativeTo.getY(), targetSpaceToBeRelativeTo.getHeight());
|
||||
}
|
||||
|
||||
/** Same functionality as updateFrom(), but taking doubles instead of ints.
|
||||
*/
|
||||
void updateFromDouble (const double newX, const double newY,
|
||||
const double newW, const double newH,
|
||||
const Rectangle<int>& target) noexcept
|
||||
{
|
||||
updatePosAndSize (x, w, newX, newW, xMode, wMode, target.getX(), target.getWidth());
|
||||
updatePosAndSize (y, h, newY, newH, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
|
||||
/** Updates this object's coordinates to match the bounds of this component.
|
||||
|
||||
This is equivalent to calling updateFrom() with the component's bounds and
|
||||
it parent size.
|
||||
|
||||
If the component doesn't currently have a parent, then proportional coordinates
|
||||
might not be updated because it would need to know the parent's size to do the
|
||||
maths for this.
|
||||
*/
|
||||
void updateFromComponent (const Component& comp) noexcept
|
||||
{
|
||||
if (comp.getParentComponent() == nullptr && ! comp.isOnDesktop())
|
||||
updateFrom (comp.getBounds(), Rectangle<int>());
|
||||
else
|
||||
updateFrom (comp.getBounds(), Rectangle<int> (comp.getParentWidth(), comp.getParentHeight()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Specifies the point within the rectangle, relative to which it should be positioned. */
|
||||
enum AnchorPoint
|
||||
{
|
||||
anchorAtLeftOrTop = 1 << 0, /**< The x or y coordinate specifies where the left or top edge of the rectangle should be. */
|
||||
anchorAtRightOrBottom = 1 << 1, /**< The x or y coordinate specifies where the right or bottom edge of the rectangle should be. */
|
||||
anchorAtCentre = 1 << 2 /**< The x or y coordinate specifies where the centre of the rectangle should be. */
|
||||
};
|
||||
|
||||
/** Specifies how an x or y coordinate should be interpreted. */
|
||||
enum PositionMode
|
||||
{
|
||||
absoluteFromParentTopLeft = 1 << 3, /**< The x or y coordinate specifies an absolute distance from the parent's top or left edge. */
|
||||
absoluteFromParentBottomRight = 1 << 4, /**< The x or y coordinate specifies an absolute distance from the parent's bottom or right edge. */
|
||||
absoluteFromParentCentre = 1 << 5, /**< The x or y coordinate specifies an absolute distance from the parent's centre. */
|
||||
proportionOfParentSize = 1 << 6 /**< The x or y coordinate specifies a proportion of the parent's width or height, measured from the parent's top or left. */
|
||||
};
|
||||
|
||||
/** Specifies how the width or height should be interpreted. */
|
||||
enum SizeMode
|
||||
{
|
||||
absoluteSize = 1 << 0, /**< The width or height specifies an absolute size. */
|
||||
parentSizeMinusAbsolute = 1 << 1, /**< The width or height is an amount that should be subtracted from the parent's width or height. */
|
||||
proportionalSize = 1 << 2, /**< The width or height specifies a proportion of the parent's width or height. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Sets all options for all coordinates.
|
||||
|
||||
This requires a reference rectangle to be specified, because if you're changing any
|
||||
of the modes from proportional to absolute or vice-versa, then it'll need to convert
|
||||
the coordinates, and will need to know the parent size so it can calculate this.
|
||||
*/
|
||||
void setModes (const AnchorPoint xAnchor, const PositionMode xMode_,
|
||||
const AnchorPoint yAnchor, const PositionMode yMode_,
|
||||
const SizeMode widthMode, const SizeMode heightMode,
|
||||
const Rectangle<int>& target) noexcept
|
||||
{
|
||||
if (xMode != ((int) xAnchor | (int) xMode_) || wMode != widthMode)
|
||||
{
|
||||
double tx, tw;
|
||||
applyPosAndSize (tx, tw, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
|
||||
xMode = (uint8) ((int) xAnchor | (int) xMode_);
|
||||
wMode = (uint8) widthMode;
|
||||
|
||||
updatePosAndSize (x, w, tx, tw, xMode, wMode, target.getX(), target.getWidth());
|
||||
}
|
||||
|
||||
if (yMode != ((int) yAnchor | (int) yMode_) || hMode != heightMode)
|
||||
{
|
||||
double ty, th;
|
||||
applyPosAndSize (ty, th, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
|
||||
yMode = (uint8) ((int) yAnchor | (int) yMode_);
|
||||
hMode = (uint8) heightMode;
|
||||
|
||||
updatePosAndSize (y, h, ty, th, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the anchoring mode for the x coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
AnchorPoint getAnchorPointX() const noexcept
|
||||
{
|
||||
return (AnchorPoint) (xMode & (anchorAtLeftOrTop | anchorAtRightOrBottom | anchorAtCentre));
|
||||
}
|
||||
|
||||
/** Returns the positioning mode for the x coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
PositionMode getPositionModeX() const noexcept
|
||||
{
|
||||
return (PositionMode) (xMode & (absoluteFromParentTopLeft | absoluteFromParentBottomRight
|
||||
| absoluteFromParentCentre | proportionOfParentSize));
|
||||
}
|
||||
|
||||
/** Returns the raw x coordinate.
|
||||
|
||||
If the x position mode is absolute, then this will be the absolute value. If it's
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
width of the parent space.
|
||||
*/
|
||||
double getX() const noexcept { return x; }
|
||||
|
||||
/** Sets the raw value of the x coordinate.
|
||||
See getX() for the meaning of this value.
|
||||
*/
|
||||
void setX (const double newX) noexcept { x = newX; }
|
||||
|
||||
/** Returns the anchoring mode for the y coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
AnchorPoint getAnchorPointY() const noexcept
|
||||
{
|
||||
return (AnchorPoint) (yMode & (anchorAtLeftOrTop | anchorAtRightOrBottom | anchorAtCentre));
|
||||
}
|
||||
|
||||
/** Returns the positioning mode for the y coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
PositionMode getPositionModeY() const noexcept
|
||||
{
|
||||
return (PositionMode) (yMode & (absoluteFromParentTopLeft | absoluteFromParentBottomRight
|
||||
| absoluteFromParentCentre | proportionOfParentSize));
|
||||
}
|
||||
|
||||
/** Returns the raw y coordinate.
|
||||
|
||||
If the y position mode is absolute, then this will be the absolute value. If it's
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
height of the parent space.
|
||||
*/
|
||||
double getY() const noexcept { return y; }
|
||||
|
||||
/** Sets the raw value of the y coordinate.
|
||||
See getY() for the meaning of this value.
|
||||
*/
|
||||
void setY (const double newY) noexcept { y = newY; }
|
||||
|
||||
/** Returns the mode used to calculate the width.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
SizeMode getWidthMode() const noexcept { return (SizeMode) wMode; }
|
||||
|
||||
/** Returns the raw width value.
|
||||
|
||||
If the width mode is absolute, then this will be the absolute value. If the mode is
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
width of the parent space.
|
||||
*/
|
||||
double getWidth() const noexcept { return w; }
|
||||
|
||||
/** Sets the raw width value.
|
||||
|
||||
See getWidth() for the details about what this value means.
|
||||
*/
|
||||
void setWidth (const double newWidth) noexcept { w = newWidth; }
|
||||
|
||||
/** Returns the mode used to calculate the height.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
SizeMode getHeightMode() const noexcept { return (SizeMode) hMode; }
|
||||
|
||||
/** Returns the raw height value.
|
||||
|
||||
If the height mode is absolute, then this will be the absolute value. If the mode is
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
height of the parent space.
|
||||
*/
|
||||
double getHeight() const noexcept { return h; }
|
||||
|
||||
/** Sets the raw height value.
|
||||
|
||||
See getHeight() for the details about what this value means.
|
||||
*/
|
||||
void setHeight (const double newHeight) noexcept { h = newHeight; }
|
||||
|
||||
//==============================================================================
|
||||
/** If the size and position are constance, and wouldn't be affected by changes
|
||||
in the parent's size, then this will return true.
|
||||
*/
|
||||
bool isPositionAbsolute() const noexcept
|
||||
{
|
||||
return (xMode & ~anchorAtLeftOrTop) == absoluteFromParentTopLeft
|
||||
&& (yMode & ~anchorAtLeftOrTop) == absoluteFromParentTopLeft
|
||||
&& wMode == absoluteSize
|
||||
&& hMode == absoluteSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Compares two objects. */
|
||||
bool operator== (const PositionedRectangle& other) const noexcept
|
||||
{
|
||||
return x == other.x && y == other.y
|
||||
&& w == other.w && h == other.h
|
||||
&& xMode == other.xMode && yMode == other.yMode
|
||||
&& wMode == other.wMode && hMode == other.hMode;
|
||||
}
|
||||
|
||||
/** Compares two objects. */
|
||||
bool operator!= (const PositionedRectangle& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
double x, y, w, h;
|
||||
uint8 xMode, yMode, wMode, hMode;
|
||||
|
||||
void addPosDescription (String& s, const uint8 mode, const double value) const noexcept
|
||||
{
|
||||
if ((mode & proportionOfParentSize) != 0)
|
||||
{
|
||||
s << (roundToInt (value * 100000.0) / 1000.0) << '%';
|
||||
}
|
||||
else
|
||||
{
|
||||
s << (roundToInt (value * 100.0) / 100.0);
|
||||
|
||||
if ((mode & absoluteFromParentBottomRight) != 0)
|
||||
s << 'R';
|
||||
else if ((mode & absoluteFromParentCentre) != 0)
|
||||
s << 'C';
|
||||
}
|
||||
|
||||
if ((mode & anchorAtRightOrBottom) != 0)
|
||||
s << 'r';
|
||||
else if ((mode & anchorAtCentre) != 0)
|
||||
s << 'c';
|
||||
}
|
||||
|
||||
void addSizeDescription (String& s, const uint8 mode, const double value) const noexcept
|
||||
{
|
||||
if (mode == proportionalSize)
|
||||
s << (roundToInt (value * 100000.0) / 1000.0) << '%';
|
||||
else if (mode == parentSizeMinusAbsolute)
|
||||
s << (roundToInt (value * 100.0) / 100.0) << 'M';
|
||||
else
|
||||
s << (roundToInt (value * 100.0) / 100.0);
|
||||
}
|
||||
|
||||
void decodePosString (const String& s, uint8& mode, double& value) noexcept
|
||||
{
|
||||
if (s.containsChar ('r'))
|
||||
mode = anchorAtRightOrBottom;
|
||||
else if (s.containsChar ('c'))
|
||||
mode = anchorAtCentre;
|
||||
else
|
||||
mode = anchorAtLeftOrTop;
|
||||
|
||||
if (s.containsChar ('%'))
|
||||
{
|
||||
mode |= proportionOfParentSize;
|
||||
value = s.removeCharacters ("%rcRC").getDoubleValue() / 100.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.containsChar ('R'))
|
||||
mode |= absoluteFromParentBottomRight;
|
||||
else if (s.containsChar ('C'))
|
||||
mode |= absoluteFromParentCentre;
|
||||
else
|
||||
mode |= absoluteFromParentTopLeft;
|
||||
|
||||
value = s.removeCharacters ("rcRC").getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
void decodeSizeString (const String& s, uint8& mode, double& value) noexcept
|
||||
{
|
||||
if (s.containsChar ('%'))
|
||||
{
|
||||
mode = proportionalSize;
|
||||
value = s.upToFirstOccurrenceOf ("%", false, false).getDoubleValue() / 100.0;
|
||||
}
|
||||
else if (s.containsChar ('M'))
|
||||
{
|
||||
mode = parentSizeMinusAbsolute;
|
||||
value = s.getDoubleValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = absoluteSize;
|
||||
value = s.getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
void applyPosAndSize (double& xOut, double& wOut, const double x_, const double w_,
|
||||
const uint8 xMode_, const uint8 wMode_,
|
||||
const int parentPos, const int parentSize) const noexcept
|
||||
{
|
||||
if (wMode_ == proportionalSize)
|
||||
wOut = roundToInt (w_ * parentSize);
|
||||
else if (wMode_ == parentSizeMinusAbsolute)
|
||||
wOut = jmax (0, parentSize - roundToInt (w_));
|
||||
else
|
||||
wOut = roundToInt (w_);
|
||||
|
||||
if ((xMode_ & proportionOfParentSize) != 0)
|
||||
xOut = parentPos + x_ * parentSize;
|
||||
else if ((xMode_ & absoluteFromParentBottomRight) != 0)
|
||||
xOut = (parentPos + parentSize) - x_;
|
||||
else if ((xMode_ & absoluteFromParentCentre) != 0)
|
||||
xOut = x_ + (parentPos + parentSize / 2);
|
||||
else
|
||||
xOut = x_ + parentPos;
|
||||
|
||||
if ((xMode_ & anchorAtRightOrBottom) != 0)
|
||||
xOut -= wOut;
|
||||
else if ((xMode_ & anchorAtCentre) != 0)
|
||||
xOut -= wOut / 2;
|
||||
}
|
||||
|
||||
void updatePosAndSize (double& xOut, double& wOut, double x_, const double w_,
|
||||
const uint8 xMode_, const uint8 wMode_,
|
||||
const int parentPos, const int parentSize) const noexcept
|
||||
{
|
||||
if (wMode_ == proportionalSize)
|
||||
{
|
||||
if (parentSize > 0)
|
||||
wOut = w_ / parentSize;
|
||||
}
|
||||
else if (wMode_ == parentSizeMinusAbsolute)
|
||||
wOut = parentSize - w_;
|
||||
else
|
||||
wOut = w_;
|
||||
|
||||
if ((xMode_ & anchorAtRightOrBottom) != 0)
|
||||
x_ += w_;
|
||||
else if ((xMode_ & anchorAtCentre) != 0)
|
||||
x_ += w_ / 2;
|
||||
|
||||
if ((xMode_ & proportionOfParentSize) != 0)
|
||||
{
|
||||
if (parentSize > 0)
|
||||
xOut = (x_ - parentPos) / parentSize;
|
||||
}
|
||||
else if ((xMode_ & absoluteFromParentBottomRight) != 0)
|
||||
xOut = (parentPos + parentSize) - x_;
|
||||
else if ((xMode_ & absoluteFromParentCentre) != 0)
|
||||
xOut = x_ - (parentPos + parentSize / 2);
|
||||
else
|
||||
xOut = x_ - parentPos;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct RelativePositionedRectangle
|
||||
{
|
||||
//==============================================================================
|
||||
RelativePositionedRectangle()
|
||||
: relativeToX (0),
|
||||
relativeToY (0),
|
||||
relativeToW (0),
|
||||
relativeToH (0)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePositionedRectangle (const RelativePositionedRectangle& other)
|
||||
: rect (other.rect),
|
||||
relativeToX (other.relativeToX),
|
||||
relativeToY (other.relativeToY),
|
||||
relativeToW (other.relativeToW),
|
||||
relativeToH (other.relativeToH)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePositionedRectangle& operator= (const RelativePositionedRectangle& other)
|
||||
{
|
||||
rect = other.rect;
|
||||
relativeToX = other.relativeToX;
|
||||
relativeToY = other.relativeToY;
|
||||
relativeToW = other.relativeToW;
|
||||
relativeToH = other.relativeToH;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const RelativePositionedRectangle& other) const noexcept
|
||||
{
|
||||
return rect == other.rect
|
||||
&& relativeToX == other.relativeToX
|
||||
&& relativeToY == other.relativeToY
|
||||
&& relativeToW == other.relativeToW
|
||||
&& relativeToH == other.relativeToH;
|
||||
}
|
||||
|
||||
bool operator!= (const RelativePositionedRectangle& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
template <typename LayoutType>
|
||||
void getRelativeTargetBounds (const Rectangle<int>& parentArea,
|
||||
const LayoutType* layout,
|
||||
int& x, int& xw, int& y, int& yh,
|
||||
int& w, int& h) const
|
||||
{
|
||||
Component* rx = {};
|
||||
Component* ry = {};
|
||||
Component* rw = {};
|
||||
Component* rh = {};
|
||||
|
||||
if (layout != nullptr)
|
||||
{
|
||||
rx = layout->findComponentWithId (relativeToX);
|
||||
ry = layout->findComponentWithId (relativeToY);
|
||||
rw = layout->findComponentWithId (relativeToW);
|
||||
rh = layout->findComponentWithId (relativeToH);
|
||||
}
|
||||
|
||||
x = parentArea.getX() + (rx != nullptr ? rx->getX() : 0);
|
||||
y = parentArea.getY() + (ry != nullptr ? ry->getY() : 0);
|
||||
w = rw != nullptr ? rw->getWidth() : parentArea.getWidth();
|
||||
h = rh != nullptr ? rh->getHeight() : parentArea.getHeight();
|
||||
xw = rx != nullptr ? rx->getWidth() : parentArea.getWidth();
|
||||
yh = ry != nullptr ? ry->getHeight() : parentArea.getHeight();
|
||||
}
|
||||
|
||||
Rectangle<int> getRectangle (const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (parentArea, layout, x, xw, y, yh, w, h);
|
||||
|
||||
const Rectangle<int> xyRect ((xw <= 0 || yh <= 0) ? Rectangle<int>()
|
||||
: rect.getRectangle (Rectangle<int> (x, y, xw, yh)));
|
||||
|
||||
const Rectangle<int> whRect ((w <= 0 || h <= 0) ? Rectangle<int>()
|
||||
: rect.getRectangle (Rectangle<int> (x, y, w, h)));
|
||||
|
||||
return Rectangle<int> (xyRect.getX(), xyRect.getY(),
|
||||
whRect.getWidth(), whRect.getHeight());
|
||||
}
|
||||
|
||||
void getRectangleDouble (double& x, double& y, double& w, double& h,
|
||||
const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
int rx, rxw, ry, ryh, rw, rh;
|
||||
getRelativeTargetBounds (parentArea, layout, rx, rxw, ry, ryh, rw, rh);
|
||||
|
||||
double dummy1, dummy2;
|
||||
rect.getRectangleDouble (Rectangle<int> (rx, ry, rxw, ryh), x, y, dummy1, dummy2);
|
||||
rect.getRectangleDouble (Rectangle<int> (rx, ry, rw, rh), dummy1, dummy2, w, h);
|
||||
}
|
||||
|
||||
void updateFromComponent (const Component& comp, const ComponentLayout* layout)
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight()),
|
||||
layout, x, xw, y, yh, w, h);
|
||||
|
||||
PositionedRectangle xyRect (rect), whRect (rect);
|
||||
xyRect.updateFrom (comp.getBounds(), Rectangle<int> (x, y, xw, yh));
|
||||
whRect.updateFrom (comp.getBounds(), Rectangle<int> (x, y, w, h));
|
||||
|
||||
rect.setX (xyRect.getX());
|
||||
rect.setY (xyRect.getY());
|
||||
rect.setWidth (whRect.getWidth());
|
||||
rect.setHeight (whRect.getHeight());
|
||||
}
|
||||
|
||||
void updateFrom (double newX, double newY, double newW, double newH,
|
||||
const Rectangle<int>& parentArea, const ComponentLayout* layout)
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (parentArea, layout, x, xw, y, yh, w, h);
|
||||
|
||||
PositionedRectangle xyRect (rect), whRect (rect);
|
||||
xyRect.updateFromDouble (newX, newY, newW, newH, Rectangle<int> (x, y, xw, yh));
|
||||
whRect.updateFromDouble (newX, newY, newW, newH, Rectangle<int> (x, y, w, h));
|
||||
|
||||
rect.setX (xyRect.getX());
|
||||
rect.setY (xyRect.getY());
|
||||
rect.setWidth (whRect.getWidth());
|
||||
rect.setHeight (whRect.getHeight());
|
||||
}
|
||||
|
||||
void applyToXml (XmlElement& e) const
|
||||
{
|
||||
e.setAttribute ("pos", rect.toString());
|
||||
|
||||
if (relativeToX != 0) e.setAttribute ("posRelativeX", String::toHexString (relativeToX));
|
||||
if (relativeToY != 0) e.setAttribute ("posRelativeY", String::toHexString (relativeToY));
|
||||
if (relativeToW != 0) e.setAttribute ("posRelativeW", String::toHexString (relativeToW));
|
||||
if (relativeToH != 0) e.setAttribute ("posRelativeH", String::toHexString (relativeToH));
|
||||
}
|
||||
|
||||
void restoreFromXml (const XmlElement& e, const RelativePositionedRectangle& defaultPos)
|
||||
{
|
||||
rect = PositionedRectangle (e.getStringAttribute ("pos", defaultPos.rect.toString()));
|
||||
relativeToX = e.getStringAttribute ("posRelativeX", String::toHexString (defaultPos.relativeToX)).getHexValue64();
|
||||
relativeToY = e.getStringAttribute ("posRelativeY", String::toHexString (defaultPos.relativeToY)).getHexValue64();
|
||||
relativeToW = e.getStringAttribute ("posRelativeW", String::toHexString (defaultPos.relativeToW)).getHexValue64();
|
||||
relativeToH = e.getStringAttribute ("posRelativeH", String::toHexString (defaultPos.relativeToH)).getHexValue64();
|
||||
}
|
||||
|
||||
String toString() const
|
||||
{
|
||||
StringArray toks;
|
||||
toks.addTokens (rect.toString(), false);
|
||||
|
||||
return toks[0] + " " + toks[1];
|
||||
}
|
||||
|
||||
Point<float> toXY (const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
double x, y, w, h;
|
||||
getRectangleDouble (x, y, w, h, parentArea, layout);
|
||||
return { (float) x, (float) y };
|
||||
}
|
||||
|
||||
void getXY (double& x, double& y,
|
||||
const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
double w, h;
|
||||
getRectangleDouble (x, y, w, h, parentArea, layout);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PositionedRectangle rect;
|
||||
int64 relativeToX;
|
||||
int64 relativeToY;
|
||||
int64 relativeToW;
|
||||
int64 relativeToH;
|
||||
};
|
||||
272
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp
vendored
Normal file
272
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.cpp
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_ResourceEditorPanel.h"
|
||||
|
||||
//==============================================================================
|
||||
class ResourceListButton : public Component
|
||||
{
|
||||
public:
|
||||
explicit ResourceListButton (JucerDocument& doc)
|
||||
: document (doc), reloadButton ("Reload"), row (0)
|
||||
{
|
||||
setInterceptsMouseClicks (false, true);
|
||||
addAndMakeVisible (reloadButton);
|
||||
reloadButton.onClick = [this]
|
||||
{
|
||||
if (auto* r = document.getResources() [row])
|
||||
document.getResources().browseForResource ("Select a file to replace this resource", "*",
|
||||
File (r->originalFilename), r->name, nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
void update (int newRow)
|
||||
{
|
||||
row = newRow;
|
||||
reloadButton.setVisible (document.getResources() [row] != nullptr);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
reloadButton.setBoundsInset (BorderSize<int> (2));
|
||||
}
|
||||
|
||||
private:
|
||||
JucerDocument& document;
|
||||
TextButton reloadButton;
|
||||
int row;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
ResourceEditorPanel::ResourceEditorPanel (JucerDocument& doc)
|
||||
: document (doc),
|
||||
addButton ("Add new resource..."),
|
||||
reloadAllButton ("Reload all resources"),
|
||||
delButton ("Delete selected resources")
|
||||
{
|
||||
addAndMakeVisible (addButton);
|
||||
addButton.onClick = [this]
|
||||
{
|
||||
document.getResources().browseForResource ("Select a file to add as a resource", "*", {}, {}, nullptr);
|
||||
};
|
||||
|
||||
addAndMakeVisible (reloadAllButton);
|
||||
reloadAllButton.onClick = [this] { reloadAll(); };
|
||||
|
||||
addAndMakeVisible (delButton);
|
||||
delButton.setEnabled (false);
|
||||
delButton.onClick = [this] { document.getResources().remove (listBox->getSelectedRow (0)); };
|
||||
|
||||
listBox.reset (new TableListBox (String(), this));
|
||||
addAndMakeVisible (listBox.get());
|
||||
listBox->getHeader().addColumn ("name", 1, 150, 80, 400);
|
||||
listBox->getHeader().addColumn ("original file", 2, 350, 80, 800);
|
||||
listBox->getHeader().addColumn ("size", 3, 100, 40, 150);
|
||||
listBox->getHeader().addColumn ("reload", 4, 100, 100, 100, TableHeaderComponent::notResizableOrSortable);
|
||||
listBox->getHeader().setStretchToFitActive (true);
|
||||
|
||||
listBox->setOutlineThickness (1);
|
||||
listBox->updateContent();
|
||||
|
||||
document.addChangeListener (this);
|
||||
handleCommandMessage (1);
|
||||
|
||||
lookAndFeelChanged();
|
||||
}
|
||||
|
||||
ResourceEditorPanel::~ResourceEditorPanel()
|
||||
{
|
||||
document.removeChangeListener (this);
|
||||
}
|
||||
|
||||
int ResourceEditorPanel::getNumRows()
|
||||
{
|
||||
return document.getResources().size();
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::paintRowBackground (Graphics& g, int /*rowNumber*/,
|
||||
int /*width*/, int /*height*/, bool rowIsSelected)
|
||||
{
|
||||
if (rowIsSelected)
|
||||
g.fillAll (findColour (defaultHighlightColourId));
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::paintCell (Graphics& g, int rowNumber, int columnId, int width, int height,
|
||||
bool rowIsSelected)
|
||||
{
|
||||
if (const BinaryResources::BinaryResource* const r = document.getResources() [rowNumber])
|
||||
{
|
||||
String text;
|
||||
|
||||
if (columnId == 1)
|
||||
text = r->name;
|
||||
else if (columnId == 2)
|
||||
text = r->originalFilename;
|
||||
else if (columnId == 3)
|
||||
text = File::descriptionOfSizeInBytes ((int64) r->data.getSize());
|
||||
|
||||
if (rowIsSelected)
|
||||
g.setColour (findColour (defaultHighlightedTextColourId));
|
||||
else
|
||||
g.setColour (findColour (defaultTextColourId));
|
||||
|
||||
g.setFont (13.0f);
|
||||
g.drawText (text, 4, 0, width - 6, height, Justification::centredLeft, true);
|
||||
}
|
||||
}
|
||||
|
||||
Component* ResourceEditorPanel::refreshComponentForCell (int rowNumber, int columnId, bool /*isRowSelected*/,
|
||||
Component* existingComponentToUpdate)
|
||||
{
|
||||
if (columnId != 4)
|
||||
return nullptr;
|
||||
|
||||
if (existingComponentToUpdate == nullptr)
|
||||
existingComponentToUpdate = new ResourceListButton (document);
|
||||
|
||||
((ResourceListButton*) existingComponentToUpdate)->update (rowNumber);
|
||||
|
||||
return existingComponentToUpdate;
|
||||
}
|
||||
|
||||
int ResourceEditorPanel::getColumnAutoSizeWidth (int columnId)
|
||||
{
|
||||
if (columnId == 4)
|
||||
return 0;
|
||||
|
||||
Font f (13.0f);
|
||||
int widest = 40;
|
||||
|
||||
for (int i = document.getResources().size(); --i >= 0;)
|
||||
{
|
||||
const BinaryResources::BinaryResource* const r = document.getResources() [i];
|
||||
jassert (r != nullptr);
|
||||
String text;
|
||||
|
||||
if (columnId == 1)
|
||||
text = r->name;
|
||||
else if (columnId == 2)
|
||||
text = r->originalFilename;
|
||||
else if (columnId == 3)
|
||||
text = File::descriptionOfSizeInBytes ((int64) r->data.getSize());
|
||||
|
||||
widest = jmax (widest, f.getStringWidth (text));
|
||||
}
|
||||
|
||||
return widest + 10;
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::lookAndFeelChanged()
|
||||
{
|
||||
listBox->setColour (ListBox::backgroundColourId, findColour (secondaryBackgroundColourId));
|
||||
listBox->setColour (ListBox::outlineColourId, Colours::transparentBlack);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class ResourceSorter
|
||||
{
|
||||
public:
|
||||
ResourceSorter (const int columnId_, const bool forwards)
|
||||
: columnId (columnId_),
|
||||
direction (forwards ? 1 : -1)
|
||||
{
|
||||
}
|
||||
|
||||
int compareElements (BinaryResources::BinaryResource* first, BinaryResources::BinaryResource* second)
|
||||
{
|
||||
if (columnId == 1) return direction * first->name.compare (second->name);
|
||||
if (columnId == 2) return direction * first->originalFilename.compare (second->originalFilename);
|
||||
if (columnId == 3) return direction * (int) first->data.getSize() - (int) second->data.getSize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const int columnId, direction;
|
||||
ResourceSorter (const ResourceSorter&);
|
||||
ResourceSorter& operator= (const ResourceSorter&);
|
||||
};
|
||||
|
||||
void ResourceEditorPanel::sortOrderChanged (int newSortColumnId, const bool isForwards)
|
||||
{
|
||||
ResourceSorter sorter (newSortColumnId, isForwards);
|
||||
document.getResources().sort (sorter);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void ResourceEditorPanel::selectedRowsChanged (int /*lastRowSelected*/)
|
||||
{
|
||||
delButton.setEnabled (listBox->getNumSelectedRows() > 0);
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::resized()
|
||||
{
|
||||
auto bounds = getLocalBounds();
|
||||
|
||||
auto buttonSlice = bounds.removeFromBottom (40).reduced (5, 5);
|
||||
|
||||
addButton.setBounds (buttonSlice.removeFromLeft (125));
|
||||
buttonSlice.removeFromLeft (10);
|
||||
|
||||
reloadAllButton.setBounds (buttonSlice.removeFromLeft (125));
|
||||
|
||||
delButton.setBounds (buttonSlice.removeFromRight (125));
|
||||
|
||||
listBox->setBounds (bounds);
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (findColour (secondaryBackgroundColourId));
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::visibilityChanged()
|
||||
{
|
||||
if (isVisible())
|
||||
listBox->updateContent();
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
if (isVisible())
|
||||
listBox->updateContent();
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::reloadAll()
|
||||
{
|
||||
StringArray failed;
|
||||
|
||||
for (int i = 0; i < document.getResources().size(); ++i)
|
||||
if (! document.getResources().reload (i))
|
||||
failed.add (document.getResources().getResourceNames() [i]);
|
||||
|
||||
if (failed.size() > 0)
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
TRANS("Reloading resources"),
|
||||
TRANS("The following resources couldn't be reloaded from their original files:\n\n")
|
||||
+ failed.joinIntoString (", "));
|
||||
}
|
||||
59
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h
vendored
Normal file
59
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_ResourceEditorPanel.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class ResourceEditorPanel : public Component,
|
||||
private TableListBoxModel,
|
||||
private ChangeListener
|
||||
{
|
||||
public:
|
||||
ResourceEditorPanel (JucerDocument& document);
|
||||
~ResourceEditorPanel() override;
|
||||
|
||||
void resized() override;
|
||||
void paint (Graphics& g) override;
|
||||
void visibilityChanged() override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) override;
|
||||
|
||||
int getNumRows() override;
|
||||
void paintRowBackground (Graphics& g, int rowNumber, int width, int height, bool rowIsSelected) override;
|
||||
void paintCell (Graphics& g, int rowNumber, int columnId, int width, int height, bool rowIsSelected) override;
|
||||
Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected, Component* existingComponentToUpdate) override;
|
||||
int getColumnAutoSizeWidth (int columnId) override;
|
||||
void sortOrderChanged (int newSortColumnId, bool isForwards) override;
|
||||
void selectedRowsChanged (int lastRowSelected) override;
|
||||
|
||||
private:
|
||||
void lookAndFeelChanged() override;
|
||||
void reloadAll();
|
||||
|
||||
JucerDocument& document;
|
||||
std::unique_ptr<TableListBox> listBox;
|
||||
TextButton addButton, reloadAllButton, delButton;
|
||||
};
|
||||
80
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_SnapGridPainter.h
vendored
Normal file
80
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_SnapGridPainter.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "../jucer_PaintRoutine.h"
|
||||
|
||||
//==============================================================================
|
||||
class SnapGridPainter
|
||||
{
|
||||
public:
|
||||
SnapGridPainter()
|
||||
: snapGridSize (-1), snapShown (false)
|
||||
{
|
||||
}
|
||||
|
||||
bool updateFromDesign (JucerDocument& design)
|
||||
{
|
||||
if (snapGridSize != design.getSnappingGridSize()
|
||||
|| snapShown != (design.isSnapShown() && design.isSnapActive (false)))
|
||||
{
|
||||
snapGridSize = design.getSnappingGridSize();
|
||||
snapShown = design.isSnapShown() && design.isSnapActive (false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw (Graphics& g, PaintRoutine* backgroundGraphics)
|
||||
{
|
||||
if (snapShown && snapGridSize > 2)
|
||||
{
|
||||
Colour col (Colours::black);
|
||||
|
||||
if (backgroundGraphics != nullptr)
|
||||
col = backgroundGraphics->getBackgroundColour().contrasting();
|
||||
|
||||
const Rectangle<int> clip (g.getClipBounds());
|
||||
|
||||
RectangleList<float> gridLines;
|
||||
|
||||
for (int x = clip.getX() - (clip.getX() % snapGridSize); x < clip.getRight(); x += snapGridSize)
|
||||
gridLines.addWithoutMerging (Rectangle<float> ((float) x, 0.0f, 1.0f, (float) clip.getBottom()));
|
||||
|
||||
for (int y = clip.getY() - (clip.getY() % snapGridSize); y < clip.getBottom(); y += snapGridSize)
|
||||
gridLines.addWithoutMerging (Rectangle<float> (0.0f, (float) y, (float) clip.getRight(), 1.0f));
|
||||
|
||||
g.setColour (col.withAlpha (0.1f));
|
||||
g.fillRectList (gridLines);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int snapGridSize;
|
||||
bool snapShown;
|
||||
};
|
||||
179
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_TestComponent.cpp
vendored
Normal file
179
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_TestComponent.cpp
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../Application/jucer_Headers.h"
|
||||
#include "jucer_TestComponent.h"
|
||||
#include "../jucer_ObjectTypes.h"
|
||||
|
||||
static Array <TestComponent*> testComponents;
|
||||
|
||||
//==============================================================================
|
||||
TestComponent::TestComponent (JucerDocument* const doc,
|
||||
JucerDocument* const loaded,
|
||||
const bool alwaysFill)
|
||||
: ownerDocument (doc),
|
||||
loadedDocument (loaded),
|
||||
alwaysFillBackground (alwaysFill)
|
||||
{
|
||||
setToInitialSize();
|
||||
updateContents();
|
||||
testComponents.add (this);
|
||||
|
||||
setLookAndFeel (&getLookAndFeel());
|
||||
}
|
||||
|
||||
TestComponent::~TestComponent()
|
||||
{
|
||||
testComponents.removeFirstMatchingValue (this);
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void TestComponent::reloadAll()
|
||||
{
|
||||
for (int i = testComponents.size(); --i >= 0;)
|
||||
testComponents.getUnchecked(i)->reload();
|
||||
}
|
||||
|
||||
void TestComponent::reload()
|
||||
{
|
||||
if (findFile().exists() && lastModificationTime != findFile().getLastModificationTime())
|
||||
setFilename (filename);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static StringArray recursiveFiles;
|
||||
|
||||
File TestComponent::findFile() const
|
||||
{
|
||||
if (filename.isEmpty())
|
||||
return {};
|
||||
|
||||
if (ownerDocument != nullptr)
|
||||
return ownerDocument->getCppFile().getSiblingFile (filename);
|
||||
|
||||
return File::getCurrentWorkingDirectory().getChildFile (filename);
|
||||
}
|
||||
|
||||
void TestComponent::setFilename (const String& newName)
|
||||
{
|
||||
File newFile;
|
||||
|
||||
if (newName.isNotEmpty())
|
||||
{
|
||||
if (ownerDocument != nullptr)
|
||||
newFile = ownerDocument->getCppFile().getSiblingFile (newName);
|
||||
else
|
||||
newFile = File::getCurrentWorkingDirectory().getChildFile (newName);
|
||||
}
|
||||
|
||||
if (! recursiveFiles.contains (newFile.getFullPathName()))
|
||||
{
|
||||
recursiveFiles.add (newFile.getFullPathName());
|
||||
|
||||
loadedDocument.reset();
|
||||
|
||||
filename = newName;
|
||||
lastModificationTime = findFile().getLastModificationTime();
|
||||
|
||||
loadedDocument.reset (JucerDocument::createForCppFile (nullptr, findFile()));
|
||||
|
||||
updateContents();
|
||||
repaint();
|
||||
|
||||
recursiveFiles.remove (recursiveFiles.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void TestComponent::setConstructorParams (const String& newParams)
|
||||
{
|
||||
constructorParams = newParams;
|
||||
}
|
||||
|
||||
void TestComponent::updateContents()
|
||||
{
|
||||
deleteAllChildren();
|
||||
repaint();
|
||||
|
||||
if (loadedDocument != nullptr)
|
||||
{
|
||||
addAndMakeVisible (loadedDocument->createTestComponent (alwaysFillBackground));
|
||||
resized();
|
||||
}
|
||||
}
|
||||
|
||||
void TestComponent::setToInitialSize()
|
||||
{
|
||||
if (loadedDocument != nullptr)
|
||||
setSize (loadedDocument->getInitialWidth(),
|
||||
loadedDocument->getInitialHeight());
|
||||
else
|
||||
setSize (100, 100);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void TestComponent::paint (Graphics& g)
|
||||
{
|
||||
if (loadedDocument == nullptr)
|
||||
{
|
||||
g.fillAll (Colours::white.withAlpha (0.25f));
|
||||
|
||||
g.setColour (Colours::black.withAlpha (0.5f));
|
||||
g.drawRect (getLocalBounds());
|
||||
g.drawLine (0.0f, 0.0f, (float) getWidth(), (float) getHeight());
|
||||
g.drawLine (0.0f, (float) getHeight(), (float) getWidth(), 0.0f);
|
||||
|
||||
g.setFont (14.0f);
|
||||
g.drawText ("Projucer Component",
|
||||
0, 0, getWidth(), getHeight() / 2,
|
||||
Justification::centred, true);
|
||||
g.drawText ("(no file loaded)",
|
||||
0, getHeight() / 2, getWidth(), getHeight() / 2,
|
||||
Justification::centred, true);
|
||||
}
|
||||
}
|
||||
|
||||
void TestComponent::resized()
|
||||
{
|
||||
if (Component* const c = getChildComponent (0))
|
||||
{
|
||||
setOpaque (c->isOpaque());
|
||||
c->setBounds (getLocalBounds());
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void TestComponent::showInDialogBox (JucerDocument& document)
|
||||
{
|
||||
DialogWindow::LaunchOptions o;
|
||||
o.content.setOwned (new TestComponent (nullptr, document.createCopy(), true));
|
||||
o.dialogTitle = "Testing: " + document.getClassName();
|
||||
o.dialogBackgroundColour = Colours::azure;
|
||||
o.escapeKeyTriggersCloseButton = true;
|
||||
o.useNativeTitleBar = false;
|
||||
o.resizable = true;
|
||||
|
||||
o.launchAsync();
|
||||
}
|
||||
73
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_TestComponent.h
vendored
Normal file
73
deps/juce/extras/Projucer/Source/ComponentEditor/UI/jucer_TestComponent.h
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class TestComponent : public Component
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
TestComponent (JucerDocument* const ownerDocument,
|
||||
JucerDocument* const loadedDocument,
|
||||
const bool alwaysFillBackground);
|
||||
|
||||
~TestComponent() override;
|
||||
|
||||
//==============================================================================
|
||||
void setFilename (const String& fn);
|
||||
const String& getFilename() const noexcept { return filename; }
|
||||
|
||||
void setConstructorParams (const String& newParams);
|
||||
const String& getConstructorParams() const noexcept { return constructorParams; }
|
||||
|
||||
File findFile() const;
|
||||
|
||||
JucerDocument* getDocument() const noexcept { return loadedDocument.get(); }
|
||||
JucerDocument* getOwnerDocument() const noexcept { return ownerDocument; }
|
||||
|
||||
void setToInitialSize();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
static void showInDialogBox (JucerDocument&);
|
||||
|
||||
// reloads any test comps that need to do so
|
||||
static void reloadAll();
|
||||
|
||||
private:
|
||||
JucerDocument* ownerDocument;
|
||||
std::unique_ptr<JucerDocument> loadedDocument;
|
||||
String filename, constructorParams;
|
||||
Time lastModificationTime;
|
||||
const bool alwaysFillBackground;
|
||||
|
||||
void updateContents();
|
||||
void reload();
|
||||
};
|
||||
337
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp
vendored
Normal file
337
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.cpp
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
BinaryResources& BinaryResources::operator= (const BinaryResources& other)
|
||||
{
|
||||
for (auto* r : other.resources)
|
||||
add (r->name, r->originalFilename, r->data);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void BinaryResources::changed()
|
||||
{
|
||||
if (document != nullptr)
|
||||
{
|
||||
document->changed();
|
||||
document->refreshAllPropertyComps();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void BinaryResources::clear()
|
||||
{
|
||||
if (resources.size() > 0)
|
||||
{
|
||||
resources.clear();
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
StringArray BinaryResources::getResourceNames() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (auto* r : resources)
|
||||
s.add (r->name);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
BinaryResources::BinaryResource* BinaryResources::findResource (const String& name) const noexcept
|
||||
{
|
||||
for (auto* r : resources)
|
||||
if (r->name == name)
|
||||
return r;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const BinaryResources::BinaryResource* BinaryResources::getResource (const String& name) const
|
||||
{
|
||||
return findResource (name);
|
||||
}
|
||||
|
||||
const BinaryResources::BinaryResource* BinaryResources::getResourceForFile (const File& file) const
|
||||
{
|
||||
for (auto* r : resources)
|
||||
if (r->originalFilename == file.getFullPathName())
|
||||
return r;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool BinaryResources::add (const String& name, const File& file)
|
||||
{
|
||||
MemoryBlock mb;
|
||||
|
||||
if (! file.loadFileAsData (mb))
|
||||
return false;
|
||||
|
||||
add (name, file.getFullPathName(), mb);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BinaryResources::add (const String& name, const String& originalFileName, const MemoryBlock& data)
|
||||
{
|
||||
auto* r = findResource (name);
|
||||
|
||||
if (r == nullptr)
|
||||
{
|
||||
resources.add (r = new BinaryResource());
|
||||
r->name = name;
|
||||
}
|
||||
|
||||
r->originalFilename = originalFileName;
|
||||
r->data = data;
|
||||
r->drawable.reset();
|
||||
|
||||
changed();
|
||||
}
|
||||
|
||||
bool BinaryResources::reload (const int index)
|
||||
{
|
||||
return resources[index] != nullptr
|
||||
&& add (resources [index]->name,
|
||||
File (resources [index]->originalFilename));
|
||||
}
|
||||
|
||||
void BinaryResources::browseForResource (const String& title,
|
||||
const String& wildcard,
|
||||
const File& fileToStartFrom,
|
||||
const String& resourceToReplace,
|
||||
std::function<void (String)> callback)
|
||||
{
|
||||
chooser = std::make_unique<FileChooser> (title, fileToStartFrom, wildcard);
|
||||
auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles;
|
||||
|
||||
chooser->launchAsync (flags, [this, resourceToReplace, callback] (const FileChooser& fc)
|
||||
{
|
||||
if (fc.getResult() == File{})
|
||||
callback ({});
|
||||
|
||||
String name (resourceToReplace);
|
||||
|
||||
if (name.isEmpty())
|
||||
name = findUniqueName (fc.getResult().getFileName());
|
||||
|
||||
if (! add (name, fc.getResult()))
|
||||
{
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
TRANS("Adding Resource"),
|
||||
TRANS("Failed to load the file!"));
|
||||
|
||||
name.clear();
|
||||
}
|
||||
|
||||
callback (name);
|
||||
});
|
||||
}
|
||||
|
||||
String BinaryResources::findUniqueName (const String& rootName) const
|
||||
{
|
||||
auto nameRoot = build_tools::makeValidIdentifier (rootName, true, true, false);
|
||||
auto name = nameRoot;
|
||||
|
||||
auto names = getResourceNames();
|
||||
int suffix = 1;
|
||||
|
||||
while (names.contains (name))
|
||||
name = nameRoot + String (++suffix);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void BinaryResources::remove (int i)
|
||||
{
|
||||
if (resources[i] != nullptr)
|
||||
{
|
||||
resources.remove (i);
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
const Drawable* BinaryResources::getDrawable (const String& name) const
|
||||
{
|
||||
if (auto* res = const_cast<BinaryResources::BinaryResource*> (getResource (name)))
|
||||
{
|
||||
if (res->drawable == nullptr && res->data.getSize() > 0)
|
||||
res->drawable = Drawable::createFromImageData (res->data.getData(),
|
||||
res->data.getSize());
|
||||
|
||||
return res->drawable.get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image BinaryResources::getImageFromCache (const String& name) const
|
||||
{
|
||||
if (auto* res = getResource (name))
|
||||
if (res->data.getSize() > 0)
|
||||
return ImageCache::getFromMemory (res->data.getData(), (int) res->data.getSize());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void BinaryResources::loadFromCpp (const File& cppFileLocation, const String& cppFile)
|
||||
{
|
||||
StringArray cpp;
|
||||
cpp.addLines (cppFile);
|
||||
|
||||
clear();
|
||||
|
||||
for (int i = 0; i < cpp.size(); ++i)
|
||||
{
|
||||
if (cpp[i].contains ("JUCER_RESOURCE:"))
|
||||
{
|
||||
StringArray tokens;
|
||||
tokens.addTokens (cpp[i].fromFirstOccurrenceOf (":", false, false), ",", "\"'");
|
||||
tokens.trim();
|
||||
tokens.removeEmptyStrings();
|
||||
|
||||
auto resourceName = tokens[0];
|
||||
auto resourceSize = tokens[1].getIntValue();
|
||||
auto originalFileName = cppFileLocation.getSiblingFile (tokens[2].unquoted()).getFullPathName();
|
||||
|
||||
jassert (resourceName.isNotEmpty() && resourceSize > 0);
|
||||
|
||||
if (resourceName.isNotEmpty() && resourceSize > 0)
|
||||
{
|
||||
auto firstLine = i;
|
||||
|
||||
while (i < cpp.size())
|
||||
if (cpp [i++].contains ("}"))
|
||||
break;
|
||||
|
||||
auto dataString = cpp.joinIntoString (" ", firstLine, i - firstLine)
|
||||
.fromFirstOccurrenceOf ("{", false, false);
|
||||
|
||||
MemoryOutputStream out;
|
||||
String::CharPointerType t (dataString.getCharPointer());
|
||||
int n = 0;
|
||||
|
||||
while (! t.isEmpty())
|
||||
{
|
||||
auto c = t.getAndAdvance();
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
n = n * 10 + (int) (c - '0');
|
||||
}
|
||||
else if (c == ',')
|
||||
{
|
||||
out.writeByte ((char) n);
|
||||
n = 0;
|
||||
}
|
||||
else if (c == '}')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
jassert (resourceSize < (int) out.getDataSize() && resourceSize > (int) out.getDataSize() - 2);
|
||||
|
||||
MemoryBlock mb (out.getData(), out.getDataSize());
|
||||
mb.setSize ((size_t) resourceSize);
|
||||
|
||||
add (resourceName, originalFileName, mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void BinaryResources::fillInGeneratedCode (GeneratedCode& code) const
|
||||
{
|
||||
if (resources.size() > 0)
|
||||
{
|
||||
code.publicMemberDeclarations << "// Binary resources:\n";
|
||||
|
||||
MemoryOutputStream defs;
|
||||
|
||||
defs << "//==============================================================================\n";
|
||||
defs << "// Binary resources - be careful not to edit any of these sections!\n\n";
|
||||
|
||||
for (auto* r : resources)
|
||||
{
|
||||
code.publicMemberDeclarations
|
||||
<< "static const char* "
|
||||
<< r->name
|
||||
<< ";\nstatic const int "
|
||||
<< r->name
|
||||
<< "Size;\n";
|
||||
|
||||
auto name = r->name;
|
||||
auto& mb = r->data;
|
||||
|
||||
defs << "// JUCER_RESOURCE: " << name << ", " << (int) mb.getSize()
|
||||
<< ", \""
|
||||
<< File (r->originalFilename)
|
||||
.getRelativePathFrom (code.document->getCppFile())
|
||||
.replaceCharacter ('\\', '/')
|
||||
<< "\"\n";
|
||||
|
||||
String line1;
|
||||
line1 << "static const unsigned char resource_"
|
||||
<< code.className << "_" << name << "[] = { ";
|
||||
|
||||
defs << line1;
|
||||
|
||||
int charsOnLine = line1.length();
|
||||
|
||||
for (size_t j = 0; j < mb.getSize(); ++j)
|
||||
{
|
||||
auto num = (int) (unsigned char) mb[j];
|
||||
defs << num << ',';
|
||||
|
||||
charsOnLine += 2;
|
||||
if (num >= 10) ++charsOnLine;
|
||||
if (num >= 100) ++charsOnLine;
|
||||
|
||||
if (charsOnLine >= 200)
|
||||
{
|
||||
charsOnLine = 0;
|
||||
defs << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
defs
|
||||
<< "0,0};\n\n"
|
||||
"const char* " << code.className << "::" << name
|
||||
<< " = (const char*) resource_" << code.className << "_" << name
|
||||
<< ";\nconst int "
|
||||
<< code.className << "::" << name << "Size = "
|
||||
<< (int) mb.getSize()
|
||||
<< ";\n\n";
|
||||
}
|
||||
|
||||
code.staticMemberDefinitions << defs.toString();
|
||||
}
|
||||
}
|
||||
96
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h
vendored
Normal file
96
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_BinaryResources.h
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class JucerDocument;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Manages a list of binary data objects that a JucerDocument wants to embed in
|
||||
the code it generates.
|
||||
*/
|
||||
class BinaryResources
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
BinaryResources& operator= (const BinaryResources& other);
|
||||
|
||||
void loadFromCpp (const File& cppFileLocation, const String& cpp);
|
||||
|
||||
//==============================================================================
|
||||
struct BinaryResource
|
||||
{
|
||||
String name;
|
||||
String originalFilename;
|
||||
MemoryBlock data;
|
||||
std::unique_ptr<Drawable> drawable;
|
||||
};
|
||||
|
||||
void clear();
|
||||
bool add (const String& name, const File& file);
|
||||
void add (const String& name, const String& originalFileName, const MemoryBlock& data);
|
||||
void remove (const int index);
|
||||
bool reload (const int index);
|
||||
void browseForResource (const String& title, const String& wildcard,
|
||||
const File& fileToStartFrom, const String& resourceToReplace,
|
||||
std::function<void (String)> callback);
|
||||
|
||||
String findUniqueName (const String& rootName) const;
|
||||
|
||||
int size() const noexcept { return resources.size(); }
|
||||
const BinaryResource* operator[] (const int index) const noexcept { return resources [index]; }
|
||||
|
||||
const BinaryResource* getResource (const String& resourceName) const;
|
||||
const BinaryResource* getResourceForFile (const File& file) const;
|
||||
|
||||
StringArray getResourceNames() const;
|
||||
|
||||
const Drawable* getDrawable (const String& name) const;
|
||||
Image getImageFromCache (const String& name) const;
|
||||
|
||||
template <class ElementComparator>
|
||||
void sort (ElementComparator& sorter)
|
||||
{
|
||||
resources.sort (sorter, true);
|
||||
changed();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void setDocument (JucerDocument* const doc) { document = doc; }
|
||||
JucerDocument* getDocument() const noexcept { return document; }
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
BinaryResource* findResource (const String& name) const noexcept;
|
||||
void changed();
|
||||
|
||||
//==============================================================================
|
||||
JucerDocument* document;
|
||||
OwnedArray<BinaryResource> resources;
|
||||
std::unique_ptr<FileChooser> chooser;
|
||||
};
|
||||
1111
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.cpp
vendored
Normal file
1111
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
138
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.h
vendored
Normal file
138
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ComponentLayout.h
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Components/jucer_ComponentTypeHandler.h"
|
||||
class JucerDocument;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Manages the set of sub-components for a JucerDocument.
|
||||
|
||||
*/
|
||||
class ComponentLayout
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentLayout();
|
||||
~ComponentLayout();
|
||||
|
||||
//==============================================================================
|
||||
void changed();
|
||||
|
||||
int getNumComponents() const noexcept { return components.size(); }
|
||||
Component* getComponent (const int index) const noexcept { return components [index]; }
|
||||
int indexOfComponent (Component* const comp) const noexcept { return components.indexOf (comp); }
|
||||
bool containsComponent (Component* const comp) const noexcept { return components.contains (comp); }
|
||||
|
||||
//==============================================================================
|
||||
void clearComponents();
|
||||
void removeComponent (Component* comp, const bool undoable);
|
||||
|
||||
Component* addNewComponent (ComponentTypeHandler* const type, int x, int y);
|
||||
Component* addComponentFromXml (const XmlElement& xml, const bool undoable);
|
||||
|
||||
Component* findComponentWithId (const int64 componentId) const;
|
||||
|
||||
//==============================================================================
|
||||
void componentToFront (Component* comp, const bool undoable);
|
||||
void componentToBack (Component* comp, const bool undoable);
|
||||
|
||||
void setComponentPosition (Component* comp, const RelativePositionedRectangle& newPos, const bool undoable);
|
||||
void setComponentBoundsAndProperties (Component* comp, const Rectangle<int>& newBounds, Component* referenceComponent, const bool undoable);
|
||||
void updateStoredComponentPosition (Component* comp, const bool undoable);
|
||||
|
||||
//==============================================================================
|
||||
Component* getComponentRelativePosTarget (Component* comp, int whichDimension) const;
|
||||
void setComponentRelativeTarget (Component* comp, int whichDimension, Component* compToBeRelativeTo);
|
||||
// checks recursively whether the comp depends on the given comp for its position
|
||||
bool dependsOnComponentForRelativePos (Component* comp, Component* possibleDependee) const;
|
||||
bool isComponentPositionRelative (Component* comp) const;
|
||||
|
||||
PopupMenu getRelativeTargetMenu (Component* comp, int whichDimension) const;
|
||||
void processRelativeTargetMenuResult (Component* comp, int whichDimension, int menuResultID);
|
||||
|
||||
//==============================================================================
|
||||
void setComponentMemberVariableName (Component* comp, const String& newName);
|
||||
String getComponentMemberVariableName (Component* comp) const;
|
||||
|
||||
//==============================================================================
|
||||
void setComponentVirtualClassName (Component* comp, const String& newName);
|
||||
String getComponentVirtualClassName (Component* comp) const;
|
||||
|
||||
//==============================================================================
|
||||
SelectedItemSet <Component*>& getSelectedSet() { return selected; }
|
||||
|
||||
static const char* const clipboardXmlTag;
|
||||
void copySelectedToClipboard();
|
||||
void paste();
|
||||
void deleteSelected();
|
||||
void selectAll();
|
||||
|
||||
void selectedToFront();
|
||||
void selectedToBack();
|
||||
|
||||
void alignTop();
|
||||
void alignRight();
|
||||
void alignBottom();
|
||||
void alignLeft();
|
||||
|
||||
void startDragging();
|
||||
void dragSelectedComps (int dxFromDragStart, int dyFromDragStart, const bool allowSnap = true);
|
||||
void endDragging();
|
||||
|
||||
void moveSelectedComps (int dx, int dy, bool snap);
|
||||
void stretchSelectedComps (int dw, int dh, bool allowSnap);
|
||||
|
||||
void bringLostItemsBackOnScreen (int width, int height);
|
||||
|
||||
//==============================================================================
|
||||
void setDocument (JucerDocument* const doc) { document = doc; }
|
||||
JucerDocument* getDocument() const noexcept { return document; }
|
||||
|
||||
//==============================================================================
|
||||
void addToXml (XmlElement& xml) const;
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code) const;
|
||||
|
||||
void perform (UndoableAction* action, const String& actionName);
|
||||
|
||||
private:
|
||||
JucerDocument* document;
|
||||
OwnedArray<Component> components;
|
||||
SelectedItemSet <Component*> selected;
|
||||
int nextCompUID;
|
||||
|
||||
String getUnusedMemberName (String nameRoot, Component* comp) const;
|
||||
|
||||
friend class FrontBackCompAction;
|
||||
friend class DeleteCompAction;
|
||||
void moveComponentZOrder (int oldIndex, int newIndex);
|
||||
};
|
||||
|
||||
void positionToCode (const RelativePositionedRectangle& position,
|
||||
const ComponentLayout* layout,
|
||||
String& x, String& y, String& w, String& h);
|
||||
348
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp
vendored
Normal file
348
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.cpp
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_GeneratedCode.h"
|
||||
#include "jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
GeneratedCode::GeneratedCode (const JucerDocument* const doc)
|
||||
: document (doc), suffix (0)
|
||||
{
|
||||
}
|
||||
|
||||
GeneratedCode::~GeneratedCode()
|
||||
{
|
||||
}
|
||||
|
||||
int GeneratedCode::getUniqueSuffix()
|
||||
{
|
||||
return ++suffix;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String& GeneratedCode::getCallbackCode (const String& requiredParentClass,
|
||||
const String& returnType,
|
||||
const String& prototype,
|
||||
const bool hasPrePostUserSections)
|
||||
{
|
||||
String parentClass (requiredParentClass);
|
||||
if (parentClass.isNotEmpty()
|
||||
&& ! (parentClass.startsWith ("public ")
|
||||
|| parentClass.startsWith ("private ")
|
||||
|| parentClass.startsWith ("protected ")))
|
||||
{
|
||||
parentClass = "public " + parentClass;
|
||||
}
|
||||
|
||||
for (int i = callbacks.size(); --i >= 0;)
|
||||
{
|
||||
CallbackMethod* const cm = callbacks.getUnchecked(i);
|
||||
|
||||
if (cm->requiredParentClass == parentClass
|
||||
&& cm->returnType == returnType
|
||||
&& cm->prototype == prototype)
|
||||
return cm->content;
|
||||
}
|
||||
|
||||
CallbackMethod* const cm = new CallbackMethod();
|
||||
callbacks.add (cm);
|
||||
|
||||
cm->requiredParentClass = parentClass;
|
||||
cm->returnType = returnType;
|
||||
cm->prototype = prototype;
|
||||
cm->hasPrePostUserSections = hasPrePostUserSections;
|
||||
return cm->content;
|
||||
}
|
||||
|
||||
void GeneratedCode::removeCallback (const String& returnType, const String& prototype)
|
||||
{
|
||||
for (int i = callbacks.size(); --i >= 0;)
|
||||
{
|
||||
CallbackMethod* const cm = callbacks.getUnchecked(i);
|
||||
|
||||
if (cm->returnType == returnType && cm->prototype == prototype)
|
||||
callbacks.remove (i);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratedCode::addImageResourceLoader (const String& imageMemberName, const String& resourceName)
|
||||
{
|
||||
privateMemberDeclarations
|
||||
<< "juce::Image " << imageMemberName << ";\n";
|
||||
|
||||
if (resourceName.isNotEmpty())
|
||||
constructorCode << imageMemberName << " = juce::ImageCache::getFromMemory ("
|
||||
<< resourceName << ", " << resourceName << "Size);\n";
|
||||
}
|
||||
|
||||
StringArray GeneratedCode::getExtraParentClasses() const
|
||||
{
|
||||
StringArray s;
|
||||
|
||||
for (int i = 0; i < callbacks.size(); ++i)
|
||||
{
|
||||
CallbackMethod* const cm = callbacks.getUnchecked(i);
|
||||
s.add (cm->requiredParentClass);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
String GeneratedCode::getCallbackDeclarations() const
|
||||
{
|
||||
String s;
|
||||
|
||||
for (int i = 0; i < callbacks.size(); ++i)
|
||||
{
|
||||
CallbackMethod* const cm = callbacks.getUnchecked(i);
|
||||
|
||||
s << cm->returnType << " " << cm->prototype << " override;\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
String GeneratedCode::getCallbackDefinitions() const
|
||||
{
|
||||
String s;
|
||||
|
||||
for (int i = 0; i < callbacks.size(); ++i)
|
||||
{
|
||||
CallbackMethod* const cm = callbacks.getUnchecked(i);
|
||||
|
||||
const String userCodeBlockName ("User"
|
||||
+ build_tools::makeValidIdentifier (cm->prototype.upToFirstOccurrenceOf ("(", false, false),
|
||||
true, true, false).trim());
|
||||
|
||||
if (userCodeBlockName.isNotEmpty() && cm->hasPrePostUserSections)
|
||||
{
|
||||
s << cm->returnType << " " << className << "::" << cm->prototype
|
||||
<< "\n{\n //[" << userCodeBlockName << "_Pre]\n //[/" << userCodeBlockName
|
||||
<< "_Pre]\n\n "
|
||||
<< CodeHelpers::indent (cm->content.trim(), 4, false)
|
||||
<< "\n\n //[" << userCodeBlockName << "_Post]\n //[/" << userCodeBlockName
|
||||
<< "_Post]\n}\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
s << cm->returnType << " " << className << "::" << cm->prototype
|
||||
<< "\n{\n "
|
||||
<< CodeHelpers::indent (cm->content.trim(), 4, false)
|
||||
<< "\n}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String GeneratedCode::getClassDeclaration() const
|
||||
{
|
||||
StringArray parentClassLines;
|
||||
parentClassLines.addTokens (parentClasses, ",", StringRef());
|
||||
parentClassLines.addArray (getExtraParentClasses());
|
||||
|
||||
parentClassLines = getCleanedStringArray (parentClassLines);
|
||||
|
||||
if (parentClassLines.contains ("public juce::Button", false))
|
||||
parentClassLines.removeString ("public juce::Component", false);
|
||||
|
||||
String r ("class ");
|
||||
r << className << " : ";
|
||||
|
||||
r += parentClassLines.joinIntoString (",\n" + String::repeatedString (" ", r.length()));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
String GeneratedCode::getInitialiserList() const
|
||||
{
|
||||
StringArray inits (initialisers);
|
||||
|
||||
if (parentClassInitialiser.isNotEmpty())
|
||||
inits.insert (0, parentClassInitialiser);
|
||||
|
||||
inits = getCleanedStringArray (inits);
|
||||
|
||||
String s;
|
||||
|
||||
if (inits.size() == 0)
|
||||
return s;
|
||||
|
||||
s << " : ";
|
||||
|
||||
for (int i = 0; i < inits.size(); ++i)
|
||||
{
|
||||
String init (inits[i]);
|
||||
|
||||
while (init.endsWithChar (','))
|
||||
init = init.dropLastCharacters (1);
|
||||
|
||||
s << init;
|
||||
|
||||
if (i < inits.size() - 1)
|
||||
s << ",\n ";
|
||||
else
|
||||
s << "\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static String getIncludeFileCode (const Array<File>& files, const File& targetFile)
|
||||
{
|
||||
String s;
|
||||
|
||||
for (int i = 0; i < files.size(); ++i)
|
||||
s << CodeHelpers::createIncludeStatement (files.getReference(i), targetFile) << newLine;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool GeneratedCode::shouldUseTransMacro() const noexcept
|
||||
{
|
||||
return document->shouldUseTransMacro();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void replaceTemplate (String& text, const String& itemName, const String& value)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
const int index = text.indexOf ("%%" + itemName + "%%");
|
||||
|
||||
if (index < 0)
|
||||
break;
|
||||
|
||||
int indentLevel = 0;
|
||||
|
||||
for (int i = index; --i >= 0;)
|
||||
{
|
||||
if (text[i] == '\n')
|
||||
break;
|
||||
|
||||
++indentLevel;
|
||||
}
|
||||
|
||||
text = text.replaceSection (index, itemName.length() + 4,
|
||||
CodeHelpers::indent (value, indentLevel, false));
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static bool getUserSection (const StringArray& lines, const String& tag, StringArray& resultLines)
|
||||
{
|
||||
const int start = indexOfLineStartingWith (lines, "//[" + tag + "]", 0);
|
||||
|
||||
if (start < 0)
|
||||
return false;
|
||||
|
||||
const int end = indexOfLineStartingWith (lines, "//[/" + tag + "]", start + 1);
|
||||
|
||||
for (int i = start + 1; i < end; ++i)
|
||||
resultLines.add (lines [i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void copyAcrossUserSections (String& dest, const String& src)
|
||||
{
|
||||
StringArray srcLines, dstLines;
|
||||
srcLines.addLines (src);
|
||||
dstLines.addLines (dest);
|
||||
|
||||
for (int i = 0; i < dstLines.size(); ++i)
|
||||
{
|
||||
if (dstLines[i].trimStart().startsWith ("//["))
|
||||
{
|
||||
String tag (dstLines[i].trimStart().substring (3));
|
||||
tag = tag.upToFirstOccurrenceOf ("]", false, false);
|
||||
|
||||
jassert (! tag.startsWithChar ('/'));
|
||||
|
||||
if (! tag.startsWithChar ('/'))
|
||||
{
|
||||
const int endLine = indexOfLineStartingWith (dstLines,
|
||||
"//[/" + tag + "]",
|
||||
i + 1);
|
||||
|
||||
if (endLine > i)
|
||||
{
|
||||
StringArray sourceLines;
|
||||
|
||||
if (tag != "UserPaintCustomArguments" && getUserSection (srcLines, tag, sourceLines))
|
||||
{
|
||||
for (int j = endLine - i; --j > 0;)
|
||||
dstLines.remove (i + 1);
|
||||
|
||||
for (int j = 0; j < sourceLines.size(); ++j)
|
||||
dstLines.insert (++i, sourceLines [j].trimEnd());
|
||||
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = endLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dstLines.set (i, dstLines[i].trimEnd());
|
||||
}
|
||||
|
||||
dest = dstLines.joinIntoString ("\n") + "\n";
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void GeneratedCode::applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const
|
||||
{
|
||||
replaceTemplate (code, "version", JUCEApplicationBase::getInstance()->getApplicationVersion());
|
||||
replaceTemplate (code, "creationTime", Time::getCurrentTime().toString (true, true, true));
|
||||
|
||||
replaceTemplate (code, "class_name", className);
|
||||
replaceTemplate (code, "constructor_params", constructorParams);
|
||||
replaceTemplate (code, "initialisers", getInitialiserList());
|
||||
|
||||
replaceTemplate (code, "class_declaration", getClassDeclaration());
|
||||
replaceTemplate (code, "private_member_declarations", privateMemberDeclarations);
|
||||
replaceTemplate (code, "public_member_declarations", getCallbackDeclarations() + newLine + publicMemberDeclarations);
|
||||
|
||||
replaceTemplate (code, "method_definitions", getCallbackDefinitions());
|
||||
|
||||
replaceTemplate (code, "include_juce", CodeHelpers::createIncludePathIncludeStatement (Project::getJuceSourceHFilename()));
|
||||
|
||||
replaceTemplate (code, "include_files_h", getIncludeFileCode (includeFilesH, targetFile));
|
||||
replaceTemplate (code, "include_files_cpp", getIncludeFileCode (includeFilesCPP, targetFile));
|
||||
|
||||
replaceTemplate (code, "constructor", constructorCode);
|
||||
replaceTemplate (code, "destructor", destructorCode);
|
||||
|
||||
replaceTemplate (code, "metadata", jucerMetadata);
|
||||
replaceTemplate (code, "static_member_definitions", staticMemberDefinitions);
|
||||
|
||||
copyAcrossUserSections (code, oldFileWithUserData);
|
||||
}
|
||||
95
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h
vendored
Normal file
95
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_GeneratedCode.h
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Project/jucer_Project.h"
|
||||
class JucerDocument;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class for collecting the various snippets of c++ that will be assembled into
|
||||
the final cpp and header files.
|
||||
*/
|
||||
class GeneratedCode
|
||||
{
|
||||
public:
|
||||
GeneratedCode (const JucerDocument*);
|
||||
~GeneratedCode();
|
||||
|
||||
//==============================================================================
|
||||
void applyToCode (String& code, const File& targetFile, const String& oldFileWithUserData) const;
|
||||
int getUniqueSuffix();
|
||||
|
||||
//==============================================================================
|
||||
const JucerDocument* const document;
|
||||
|
||||
String className;
|
||||
String componentName;
|
||||
String parentClassInitialiser; // optional parent class initialiser to go before the items in the initialisers list
|
||||
StringArray initialisers; // (a list of the member variables that need initialising after the constructor declaration)
|
||||
String parentClasses;
|
||||
String constructorParams;
|
||||
String privateMemberDeclarations;
|
||||
String publicMemberDeclarations;
|
||||
Array<File> includeFilesH, includeFilesCPP;
|
||||
String constructorCode;
|
||||
String destructorCode;
|
||||
String staticMemberDefinitions;
|
||||
String jucerMetadata;
|
||||
|
||||
struct CallbackMethod
|
||||
{
|
||||
String requiredParentClass;
|
||||
String returnType;
|
||||
String prototype;
|
||||
String content;
|
||||
bool hasPrePostUserSections;
|
||||
};
|
||||
|
||||
OwnedArray<CallbackMethod> callbacks;
|
||||
|
||||
String& getCallbackCode (const String& requiredParentClass,
|
||||
const String& returnType,
|
||||
const String& prototype,
|
||||
const bool hasPrePostUserSections);
|
||||
|
||||
void removeCallback (const String& returnType, const String& prototype);
|
||||
|
||||
void addImageResourceLoader (const String& imageMemberName, const String& resourceName);
|
||||
|
||||
String getCallbackDeclarations() const;
|
||||
String getCallbackDefinitions() const;
|
||||
StringArray getExtraParentClasses() const;
|
||||
|
||||
bool shouldUseTransMacro() const noexcept;
|
||||
|
||||
private:
|
||||
String getClassDeclaration() const;
|
||||
String getInitialiserList() const;
|
||||
int suffix;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GeneratedCode)
|
||||
};
|
||||
835
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp
vendored
Normal file
835
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.cpp
vendored
Normal file
@@ -0,0 +1,835 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "../Application/jucer_Application.h"
|
||||
#include "../Utility/Helpers/jucer_NewFileWizard.h"
|
||||
#include "jucer_JucerDocument.h"
|
||||
#include "jucer_ObjectTypes.h"
|
||||
#include "UI/jucer_JucerDocumentEditor.h"
|
||||
#include "UI/jucer_TestComponent.h"
|
||||
#include "jucer_UtilityFunctions.h"
|
||||
#include "Documents/jucer_ComponentDocument.h"
|
||||
#include "Documents/jucer_ButtonDocument.h"
|
||||
|
||||
const char* const defaultClassName = "NewComponent";
|
||||
const char* const defaultParentClasses = "public juce::Component";
|
||||
|
||||
//==============================================================================
|
||||
JucerDocument::JucerDocument (SourceCodeDocument* c)
|
||||
: cpp (c),
|
||||
className (defaultClassName),
|
||||
parentClasses (defaultParentClasses)
|
||||
{
|
||||
jassert (cpp != nullptr);
|
||||
resources.setDocument (this);
|
||||
|
||||
ProjucerApplication::getCommandManager().commandStatusChanged();
|
||||
cpp->getCodeDocument().addListener (this);
|
||||
}
|
||||
|
||||
JucerDocument::~JucerDocument()
|
||||
{
|
||||
cpp->getCodeDocument().removeListener (this);
|
||||
ProjucerApplication::getCommandManager().commandStatusChanged();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JucerDocument::changed()
|
||||
{
|
||||
sendChangeMessage();
|
||||
ProjucerApplication::getCommandManager().commandStatusChanged();
|
||||
startTimer (800);
|
||||
}
|
||||
|
||||
struct UserDocChangeTimer : public Timer
|
||||
{
|
||||
explicit UserDocChangeTimer (JucerDocument& d) : doc (d) {}
|
||||
void timerCallback() override { doc.reloadFromDocument(); }
|
||||
|
||||
JucerDocument& doc;
|
||||
};
|
||||
|
||||
void JucerDocument::userEditedCpp()
|
||||
{
|
||||
if (userDocChangeTimer == nullptr)
|
||||
userDocChangeTimer.reset (new UserDocChangeTimer (*this));
|
||||
|
||||
userDocChangeTimer->startTimer (500);
|
||||
}
|
||||
|
||||
void JucerDocument::beginTransaction()
|
||||
{
|
||||
getUndoManager().beginNewTransaction();
|
||||
}
|
||||
|
||||
void JucerDocument::beginTransaction (const String& name)
|
||||
{
|
||||
getUndoManager().beginNewTransaction (name);
|
||||
}
|
||||
|
||||
void JucerDocument::timerCallback()
|
||||
{
|
||||
if (! Component::isMouseButtonDownAnywhere())
|
||||
{
|
||||
stopTimer();
|
||||
beginTransaction();
|
||||
|
||||
flushChangesToDocuments (nullptr, false);
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::codeDocumentTextInserted (const String&, int) { userEditedCpp(); }
|
||||
void JucerDocument::codeDocumentTextDeleted (int, int) { userEditedCpp(); }
|
||||
|
||||
bool JucerDocument::perform (UndoableAction* const action, const String& actionName)
|
||||
{
|
||||
return undoManager.perform (action, actionName);
|
||||
}
|
||||
|
||||
void JucerDocument::refreshAllPropertyComps()
|
||||
{
|
||||
if (ComponentLayout* l = getComponentLayout())
|
||||
l->getSelectedSet().changed();
|
||||
|
||||
for (int i = getNumPaintRoutines(); --i >= 0;)
|
||||
{
|
||||
getPaintRoutine (i)->getSelectedElements().changed();
|
||||
getPaintRoutine (i)->getSelectedPoints().changed();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JucerDocument::setClassName (const String& newName)
|
||||
{
|
||||
if (newName != className
|
||||
&& build_tools::makeValidIdentifier (newName, false, false, true).isNotEmpty())
|
||||
{
|
||||
className = build_tools::makeValidIdentifier (newName, false, false, true);
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setComponentName (const String& newName)
|
||||
{
|
||||
if (newName != componentName)
|
||||
{
|
||||
componentName = newName;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setParentClasses (const String& classes)
|
||||
{
|
||||
if (classes != parentClasses)
|
||||
{
|
||||
StringArray parentClassLines (getCleanedStringArray (StringArray::fromTokens (classes, ",", StringRef())));
|
||||
|
||||
for (int i = parentClassLines.size(); --i >= 0;)
|
||||
{
|
||||
String s (parentClassLines[i]);
|
||||
String type;
|
||||
|
||||
if (s.startsWith ("public ")
|
||||
|| s.startsWith ("protected ")
|
||||
|| s.startsWith ("private "))
|
||||
{
|
||||
type = s.upToFirstOccurrenceOf (" ", true, false);
|
||||
s = s.fromFirstOccurrenceOf (" ", false, false);
|
||||
|
||||
if (s.trim().isEmpty())
|
||||
type = s = String();
|
||||
}
|
||||
|
||||
s = type + build_tools::makeValidIdentifier (s.trim(), false, false, true, true);
|
||||
|
||||
parentClassLines.set (i, s);
|
||||
}
|
||||
|
||||
parentClasses = parentClassLines.joinIntoString (", ");
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setConstructorParams (const String& newParams)
|
||||
{
|
||||
if (constructorParams != newParams)
|
||||
{
|
||||
constructorParams = newParams;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setVariableInitialisers (const String& newInitlialisers)
|
||||
{
|
||||
if (variableInitialisers != newInitlialisers)
|
||||
{
|
||||
variableInitialisers = newInitlialisers;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setFixedSize (const bool isFixed)
|
||||
{
|
||||
if (fixedSize != isFixed)
|
||||
{
|
||||
fixedSize = isFixed;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setInitialSize (int w, int h)
|
||||
{
|
||||
w = jmax (1, w);
|
||||
h = jmax (1, h);
|
||||
|
||||
if (initialWidth != w || initialHeight != h)
|
||||
{
|
||||
initialWidth = w;
|
||||
initialHeight = h;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool JucerDocument::isSnapActive (const bool disableIfCtrlKeyDown) const noexcept
|
||||
{
|
||||
return snapActive != (disableIfCtrlKeyDown && ModifierKeys::currentModifiers.isCtrlDown());
|
||||
}
|
||||
|
||||
int JucerDocument::snapPosition (int pos) const noexcept
|
||||
{
|
||||
if (isSnapActive (true))
|
||||
{
|
||||
jassert (snapGridPixels > 0);
|
||||
pos = ((pos + snapGridPixels * 1024 + snapGridPixels / 2) / snapGridPixels - 1024) * snapGridPixels;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void JucerDocument::setSnappingGrid (const int numPixels, const bool active, const bool shown)
|
||||
{
|
||||
if (numPixels != snapGridPixels
|
||||
|| active != snapActive
|
||||
|| shown != snapShown)
|
||||
{
|
||||
snapGridPixels = numPixels;
|
||||
snapActive = active;
|
||||
snapShown = shown;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::setComponentOverlayOpacity (const float alpha)
|
||||
{
|
||||
if (alpha != componentOverlayOpacity)
|
||||
{
|
||||
componentOverlayOpacity = alpha;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void JucerDocument::addMethod (const String& base, const String& returnVal, const String& method, const String& initialContent,
|
||||
StringArray& baseClasses, StringArray& returnValues, StringArray& methods, StringArray& initialContents)
|
||||
{
|
||||
baseClasses.add (base);
|
||||
returnValues.add (returnVal);
|
||||
methods.add (method);
|
||||
initialContents.add (initialContent);
|
||||
}
|
||||
|
||||
void JucerDocument::getOptionalMethods (StringArray& baseClasses,
|
||||
StringArray& returnValues,
|
||||
StringArray& methods,
|
||||
StringArray& initialContents) const
|
||||
{
|
||||
addMethod ("juce::Component", "void", "visibilityChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "moved()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "parentHierarchyChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "parentSizeChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "lookAndFeelChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "bool", "hitTest (int x, int y)", "return true;", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "broughtToFront()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "filesDropped (const juce::StringArray& filenames, int mouseX, int mouseY)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "handleCommandMessage (int commandId)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "childrenChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "enablementChanged()", "", baseClasses, returnValues, methods, initialContents);
|
||||
|
||||
addMethod ("juce::Component", "void", "mouseMove (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseEnter (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseExit (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseDown (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseDrag (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseUp (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseDoubleClick (const juce::MouseEvent& e)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "mouseWheelMove (const juce::MouseEvent& e, const juce::MouseWheelDetails& wheel)", "", baseClasses, returnValues, methods, initialContents);
|
||||
|
||||
addMethod ("juce::Component", "bool", "keyPressed (const juce::KeyPress& key)", "return false; // Return true if your handler uses this key event, or false to allow it to be passed-on.", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "bool", "keyStateChanged (bool isKeyDown)", "return false; // Return true if your handler uses this key event, or false to allow it to be passed-on.", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "modifierKeysChanged (const juce::ModifierKeys& modifiers)", "", baseClasses, returnValues, methods, initialContents);
|
||||
|
||||
addMethod ("juce::Component", "void", "focusGained (FocusChangeType cause)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "focusLost (FocusChangeType cause)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "focusOfChildComponentChanged (FocusChangeType cause)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "modifierKeysChanged (const juce::ModifierKeys& modifiers)", "", baseClasses, returnValues, methods, initialContents);
|
||||
addMethod ("juce::Component", "void", "inputAttemptWhenModal()", "", baseClasses, returnValues, methods, initialContents);
|
||||
}
|
||||
|
||||
void JucerDocument::setOptionalMethodEnabled (const String& methodSignature, const bool enable)
|
||||
{
|
||||
if (enable)
|
||||
activeExtraMethods.addIfNotAlreadyThere (methodSignature);
|
||||
else
|
||||
activeExtraMethods.removeString (methodSignature);
|
||||
|
||||
changed();
|
||||
}
|
||||
|
||||
bool JucerDocument::isOptionalMethodEnabled (const String& sig) const noexcept
|
||||
{
|
||||
return activeExtraMethods.contains (sig)
|
||||
|| activeExtraMethods.contains (sig.replace ("juce::", {}));
|
||||
}
|
||||
|
||||
void JucerDocument::addExtraClassProperties (PropertyPanel&)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const JucerDocument::jucerCompXmlTag = "JUCER_COMPONENT";
|
||||
|
||||
std::unique_ptr<XmlElement> JucerDocument::createXml() const
|
||||
{
|
||||
auto doc = std::make_unique<XmlElement> (jucerCompXmlTag);
|
||||
|
||||
doc->setAttribute ("documentType", getTypeName());
|
||||
doc->setAttribute ("className", className);
|
||||
|
||||
if (templateFile.trim().isNotEmpty())
|
||||
doc->setAttribute ("template", templateFile);
|
||||
|
||||
doc->setAttribute ("componentName", componentName);
|
||||
doc->setAttribute ("parentClasses", parentClasses);
|
||||
doc->setAttribute ("constructorParams", constructorParams);
|
||||
doc->setAttribute ("variableInitialisers", variableInitialisers);
|
||||
doc->setAttribute ("snapPixels", snapGridPixels);
|
||||
doc->setAttribute ("snapActive", snapActive);
|
||||
doc->setAttribute ("snapShown", snapShown);
|
||||
doc->setAttribute ("overlayOpacity", String (componentOverlayOpacity, 3));
|
||||
doc->setAttribute ("fixedSize", fixedSize);
|
||||
doc->setAttribute ("initialWidth", initialWidth);
|
||||
doc->setAttribute ("initialHeight", initialHeight);
|
||||
|
||||
if (activeExtraMethods.size() > 0)
|
||||
{
|
||||
XmlElement* extraMethods = new XmlElement ("METHODS");
|
||||
doc->addChildElement (extraMethods);
|
||||
|
||||
for (int i = 0; i < activeExtraMethods.size(); ++i)
|
||||
{
|
||||
XmlElement* e = new XmlElement ("METHOD");
|
||||
extraMethods ->addChildElement (e);
|
||||
e->setAttribute ("name", activeExtraMethods[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
bool JucerDocument::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (jucerCompXmlTag)
|
||||
&& getTypeName().equalsIgnoreCase (xml.getStringAttribute ("documentType")))
|
||||
{
|
||||
className = xml.getStringAttribute ("className", defaultClassName);
|
||||
templateFile = xml.getStringAttribute ("template", String());
|
||||
componentName = xml.getStringAttribute ("componentName", String());
|
||||
parentClasses = xml.getStringAttribute ("parentClasses", defaultParentClasses);
|
||||
constructorParams = xml.getStringAttribute ("constructorParams", String());
|
||||
variableInitialisers = xml.getStringAttribute ("variableInitialisers", String());
|
||||
|
||||
fixedSize = xml.getBoolAttribute ("fixedSize", false);
|
||||
initialWidth = xml.getIntAttribute ("initialWidth", 300);
|
||||
initialHeight = xml.getIntAttribute ("initialHeight", 200);
|
||||
|
||||
snapGridPixels = xml.getIntAttribute ("snapPixels", snapGridPixels);
|
||||
snapActive = xml.getBoolAttribute ("snapActive", snapActive);
|
||||
snapShown = xml.getBoolAttribute ("snapShown", snapShown);
|
||||
|
||||
componentOverlayOpacity = (float) xml.getDoubleAttribute ("overlayOpacity", 0.0);
|
||||
|
||||
activeExtraMethods.clear();
|
||||
|
||||
if (XmlElement* const methods = xml.getChildByName ("METHODS"))
|
||||
for (auto* e : methods->getChildWithTagNameIterator ("METHOD"))
|
||||
activeExtraMethods.addIfNotAlreadyThere (e->getStringAttribute ("name"));
|
||||
|
||||
activeExtraMethods.trim();
|
||||
activeExtraMethods.removeEmptyStrings();
|
||||
|
||||
changed();
|
||||
getUndoManager().clearUndoHistory();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//==============================================================================
|
||||
void JucerDocument::fillInGeneratedCode (GeneratedCode& code) const
|
||||
{
|
||||
code.className = className;
|
||||
code.componentName = componentName;
|
||||
code.parentClasses = parentClasses;
|
||||
code.constructorParams = constructorParams;
|
||||
code.initialisers.addLines (variableInitialisers);
|
||||
|
||||
if (! componentName.isEmpty())
|
||||
code.constructorCode << "setName (" + quotedString (componentName, false) + ");\n";
|
||||
|
||||
// call these now, just to make sure they're the first two methods in the list.
|
||||
code.getCallbackCode (String(), "void", "paint (juce::Graphics& g)", false)
|
||||
<< "//[UserPrePaint] Add your own custom painting code here..\n//[/UserPrePaint]\n\n";
|
||||
|
||||
code.getCallbackCode (String(), "void", "resized()", false)
|
||||
<< "//[UserPreResize] Add your own custom resize code here..\n//[/UserPreResize]\n\n";
|
||||
|
||||
if (ComponentLayout* l = getComponentLayout())
|
||||
l->fillInGeneratedCode (code);
|
||||
|
||||
fillInPaintCode (code);
|
||||
|
||||
std::unique_ptr<XmlElement> e (createXml());
|
||||
jassert (e != nullptr);
|
||||
code.jucerMetadata = e->toString (XmlElement::TextFormat().withoutHeader());
|
||||
|
||||
resources.fillInGeneratedCode (code);
|
||||
|
||||
code.constructorCode
|
||||
<< "\n//[UserPreSize]\n"
|
||||
"//[/UserPreSize]\n";
|
||||
|
||||
if (initialWidth > 0 || initialHeight > 0)
|
||||
code.constructorCode << "\nsetSize (" << initialWidth << ", " << initialHeight << ");\n";
|
||||
|
||||
code.getCallbackCode (String(), "void", "paint (juce::Graphics& g)", false)
|
||||
<< "//[UserPaint] Add your own custom painting code here..\n//[/UserPaint]";
|
||||
|
||||
code.getCallbackCode (String(), "void", "resized()", false)
|
||||
<< "//[UserResized] Add your own custom resize handling here..\n//[/UserResized]";
|
||||
|
||||
// add optional methods
|
||||
StringArray baseClasses, returnValues, methods, initialContents;
|
||||
getOptionalMethods (baseClasses, returnValues, methods, initialContents);
|
||||
|
||||
for (int i = 0; i < methods.size(); ++i)
|
||||
{
|
||||
if (isOptionalMethodEnabled (methods[i]))
|
||||
{
|
||||
String baseClassToAdd (baseClasses[i]);
|
||||
|
||||
if (baseClassToAdd == "juce::Component" || baseClassToAdd == "juce::Button")
|
||||
baseClassToAdd.clear();
|
||||
|
||||
String& s = code.getCallbackCode (baseClassToAdd, returnValues[i], methods[i], false);
|
||||
|
||||
if (! s.contains ("//["))
|
||||
{
|
||||
String userCommentTag ("UserCode_");
|
||||
userCommentTag += methods[i].upToFirstOccurrenceOf ("(", false, false).trim();
|
||||
|
||||
s << "\n//[" << userCommentTag << "] -- Add your code here...\n"
|
||||
<< initialContents[i];
|
||||
|
||||
if (initialContents[i].isNotEmpty() && ! initialContents[i].endsWithChar ('\n'))
|
||||
s << '\n';
|
||||
|
||||
s << "//[/" << userCommentTag << "]\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JucerDocument::fillInPaintCode (GeneratedCode& code) const
|
||||
{
|
||||
for (int i = 0; i < getNumPaintRoutines(); ++i)
|
||||
getPaintRoutine (i)
|
||||
->fillInGeneratedCode (code, code.getCallbackCode (String(), "void", "paint (juce::Graphics& g)", false));
|
||||
}
|
||||
|
||||
void JucerDocument::setTemplateFile (const String& newFile)
|
||||
{
|
||||
if (templateFile != newFile)
|
||||
{
|
||||
templateFile = newFile;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool JucerDocument::findTemplateFiles (String& headerContent, String& cppContent) const
|
||||
{
|
||||
if (templateFile.isNotEmpty())
|
||||
{
|
||||
const File f (getCppFile().getSiblingFile (templateFile));
|
||||
|
||||
const File templateCpp (f.withFileExtension (".cpp"));
|
||||
const File templateH (f.withFileExtension (".h"));
|
||||
|
||||
headerContent = templateH.loadFileAsString();
|
||||
cppContent = templateCpp.loadFileAsString();
|
||||
|
||||
if (headerContent.isNotEmpty() && cppContent.isNotEmpty())
|
||||
return true;
|
||||
}
|
||||
|
||||
headerContent = BinaryData::jucer_ComponentTemplate_h;
|
||||
cppContent = BinaryData::jucer_ComponentTemplate_cpp;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JucerDocument::flushChangesToDocuments (Project* project, bool isInitial)
|
||||
{
|
||||
String headerTemplate, cppTemplate;
|
||||
if (! findTemplateFiles (headerTemplate, cppTemplate))
|
||||
return false;
|
||||
|
||||
GeneratedCode generated (this);
|
||||
fillInGeneratedCode (generated);
|
||||
|
||||
const File headerFile (getHeaderFile());
|
||||
generated.includeFilesCPP.insert (0, headerFile);
|
||||
|
||||
OpenDocumentManager& odm = ProjucerApplication::getApp().openDocumentManager;
|
||||
|
||||
if (SourceCodeDocument* header = dynamic_cast<SourceCodeDocument*> (odm.openFile (nullptr, headerFile)))
|
||||
{
|
||||
String existingHeader (header->getCodeDocument().getAllContent());
|
||||
String existingCpp (cpp->getCodeDocument().getAllContent());
|
||||
|
||||
generated.applyToCode (headerTemplate, headerFile, existingHeader);
|
||||
generated.applyToCode (cppTemplate, headerFile.withFileExtension (".cpp"), existingCpp);
|
||||
|
||||
if (isInitial)
|
||||
{
|
||||
jassert (project != nullptr);
|
||||
|
||||
auto lineFeed = project->getProjectLineFeed();
|
||||
|
||||
headerTemplate = replaceLineFeeds (headerTemplate, lineFeed);
|
||||
cppTemplate = replaceLineFeeds (cppTemplate, lineFeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
headerTemplate = replaceLineFeeds (headerTemplate, getLineFeedForFile (existingHeader));
|
||||
cppTemplate = replaceLineFeeds (cppTemplate, getLineFeedForFile (existingCpp));
|
||||
}
|
||||
|
||||
if (header->getCodeDocument().getAllContent() != headerTemplate)
|
||||
header->getCodeDocument().replaceAllContent (headerTemplate);
|
||||
|
||||
if (cpp->getCodeDocument().getAllContent() != cppTemplate)
|
||||
cpp->getCodeDocument().replaceAllContent (cppTemplate);
|
||||
}
|
||||
|
||||
userDocChangeTimer.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JucerDocument::reloadFromDocument()
|
||||
{
|
||||
const String cppContent (cpp->getCodeDocument().getAllContent());
|
||||
|
||||
std::unique_ptr<XmlElement> newXML (pullMetaDataFromCppFile (cppContent));
|
||||
|
||||
if (newXML == nullptr || ! newXML->hasTagName (jucerCompXmlTag))
|
||||
return false;
|
||||
|
||||
if (currentXML != nullptr && currentXML->isEquivalentTo (newXML.get(), true))
|
||||
return true;
|
||||
|
||||
currentXML.reset (newXML.release());
|
||||
stopTimer();
|
||||
|
||||
resources.loadFromCpp (getCppFile(), cppContent);
|
||||
|
||||
bool result = loadFromXml (*currentXML);
|
||||
extractCustomPaintSnippetsFromCppFile (cppContent);
|
||||
return result;
|
||||
}
|
||||
|
||||
void JucerDocument::refreshCustomCodeFromDocument()
|
||||
{
|
||||
const String cppContent (cpp->getCodeDocument().getAllContent());
|
||||
extractCustomPaintSnippetsFromCppFile (cppContent);
|
||||
}
|
||||
|
||||
void JucerDocument::extractCustomPaintSnippetsFromCppFile (const String& cppContent)
|
||||
{
|
||||
StringArray customPaintSnippets;
|
||||
|
||||
auto lines = StringArray::fromLines (cppContent);
|
||||
int last = 0;
|
||||
|
||||
while (last >= 0)
|
||||
{
|
||||
const int start = indexOfLineStartingWith (lines, "//[UserPaintCustomArguments]", last);
|
||||
if (start < 0)
|
||||
break;
|
||||
|
||||
const int end = indexOfLineStartingWith (lines, "//[/UserPaintCustomArguments]", start);
|
||||
if (end < 0)
|
||||
break;
|
||||
|
||||
last = end + 1;
|
||||
String result;
|
||||
|
||||
for (int i = start + 1; i < end; ++i)
|
||||
result << lines [i] << newLine;
|
||||
|
||||
customPaintSnippets.add (CodeHelpers::unindent (result, 4));
|
||||
}
|
||||
|
||||
applyCustomPaintSnippets (customPaintSnippets);
|
||||
}
|
||||
|
||||
std::unique_ptr<XmlElement> JucerDocument::pullMetaDataFromCppFile (const String& cpp)
|
||||
{
|
||||
auto lines = StringArray::fromLines (cpp);
|
||||
auto startLine = indexOfLineStartingWith (lines, "BEGIN_JUCER_METADATA", 0);
|
||||
|
||||
if (startLine > 0)
|
||||
{
|
||||
auto endLine = indexOfLineStartingWith (lines, "END_JUCER_METADATA", startLine);
|
||||
|
||||
if (endLine > startLine)
|
||||
return parseXML (lines.joinIntoString ("\n", startLine + 1, endLine - startLine - 1));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool JucerDocument::isValidJucerCppFile (const File& f)
|
||||
{
|
||||
if (f.hasFileExtension (cppFileExtensions))
|
||||
{
|
||||
std::unique_ptr<XmlElement> xml (pullMetaDataFromCppFile (f.loadFileAsString()));
|
||||
|
||||
if (xml != nullptr)
|
||||
return xml->hasTagName (jucerCompXmlTag);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static JucerDocument* createDocument (SourceCodeDocument* cpp)
|
||||
{
|
||||
auto& codeDoc = cpp->getCodeDocument();
|
||||
|
||||
std::unique_ptr<XmlElement> xml (JucerDocument::pullMetaDataFromCppFile (codeDoc.getAllContent()));
|
||||
|
||||
if (xml == nullptr || ! xml->hasTagName (JucerDocument::jucerCompXmlTag))
|
||||
return nullptr;
|
||||
|
||||
const String docType (xml->getStringAttribute ("documentType"));
|
||||
|
||||
std::unique_ptr<JucerDocument> newDoc;
|
||||
|
||||
if (docType.equalsIgnoreCase ("Button"))
|
||||
newDoc.reset (new ButtonDocument (cpp));
|
||||
|
||||
if (docType.equalsIgnoreCase ("Component") || docType.isEmpty())
|
||||
newDoc.reset (new ComponentDocument (cpp));
|
||||
|
||||
if (newDoc != nullptr && newDoc->reloadFromDocument())
|
||||
return newDoc.release();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JucerDocument* JucerDocument::createForCppFile (Project* p, const File& file)
|
||||
{
|
||||
OpenDocumentManager& odm = ProjucerApplication::getApp().openDocumentManager;
|
||||
|
||||
if (SourceCodeDocument* cpp = dynamic_cast<SourceCodeDocument*> (odm.openFile (p, file)))
|
||||
if (dynamic_cast<SourceCodeDocument*> (odm.openFile (p, file.withFileExtension (".h"))) != nullptr)
|
||||
return createDocument (cpp);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class JucerComponentDocument : public SourceCodeDocument
|
||||
{
|
||||
public:
|
||||
JucerComponentDocument (Project* p, const File& f)
|
||||
: SourceCodeDocument (p, f)
|
||||
{
|
||||
}
|
||||
|
||||
void saveAsync (std::function<void (bool)> callback) override
|
||||
{
|
||||
SourceCodeDocument::saveAsync ([parent = WeakReference<JucerComponentDocument> { this }, callback] (bool saveResult)
|
||||
{
|
||||
if (parent == nullptr)
|
||||
return;
|
||||
|
||||
if (! saveResult)
|
||||
{
|
||||
callback (false);
|
||||
return;
|
||||
}
|
||||
|
||||
parent->saveHeaderAsync ([parent, callback] (bool headerSaveResult)
|
||||
{
|
||||
if (parent != nullptr)
|
||||
callback (headerSaveResult);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void saveHeaderAsync (std::function<void (bool)> callback)
|
||||
{
|
||||
auto& odm = ProjucerApplication::getApp().openDocumentManager;
|
||||
|
||||
if (auto* header = odm.openFile (nullptr, getFile().withFileExtension (".h")))
|
||||
{
|
||||
header->saveAsync ([parent = WeakReference<JucerComponentDocument> { this }, callback] (bool saveResult)
|
||||
{
|
||||
if (parent == nullptr)
|
||||
return;
|
||||
|
||||
if (saveResult)
|
||||
ProjucerApplication::getApp()
|
||||
.openDocumentManager
|
||||
.closeFileWithoutSaving (parent->getFile().withFileExtension (".h"));
|
||||
|
||||
callback (saveResult);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback (false);
|
||||
}
|
||||
|
||||
std::unique_ptr<Component> createEditor() override
|
||||
{
|
||||
if (ProjucerApplication::getApp().isGUIEditorEnabled())
|
||||
{
|
||||
std::unique_ptr<JucerDocument> jucerDoc (JucerDocument::createForCppFile (getProject(), getFile()));
|
||||
|
||||
if (jucerDoc != nullptr)
|
||||
return std::make_unique<JucerDocumentEditor> (jucerDoc.release());
|
||||
}
|
||||
|
||||
return SourceCodeDocument::createEditor();
|
||||
}
|
||||
|
||||
struct Type : public OpenDocumentManager::DocumentType
|
||||
{
|
||||
Type() {}
|
||||
|
||||
bool canOpenFile (const File& f) override { return JucerDocument::isValidJucerCppFile (f); }
|
||||
Document* openFile (Project* p, const File& f) override { return new JucerComponentDocument (p, f); }
|
||||
};
|
||||
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (JucerComponentDocument)
|
||||
};
|
||||
|
||||
OpenDocumentManager::DocumentType* createGUIDocumentType();
|
||||
OpenDocumentManager::DocumentType* createGUIDocumentType()
|
||||
{
|
||||
return new JucerComponentDocument::Type();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct NewGUIComponentWizard : public NewFileWizard::Type
|
||||
{
|
||||
NewGUIComponentWizard (Project& proj)
|
||||
: project (proj)
|
||||
{}
|
||||
|
||||
String getName() override { return "GUI Component"; }
|
||||
|
||||
void createNewFile (Project& p, Project::Item parent) override
|
||||
{
|
||||
jassert (&p == &project);
|
||||
|
||||
askUserToChooseNewFile (String (defaultClassName) + ".h", "*.h;*.cpp", parent, [this, parent] (File newFile) mutable
|
||||
{
|
||||
if (newFile != File())
|
||||
{
|
||||
auto headerFile = newFile.withFileExtension (".h");
|
||||
auto cppFile = newFile.withFileExtension (".cpp");
|
||||
|
||||
headerFile.replaceWithText (String());
|
||||
cppFile.replaceWithText (String());
|
||||
|
||||
auto& odm = ProjucerApplication::getApp().openDocumentManager;
|
||||
|
||||
if (auto* cpp = dynamic_cast<SourceCodeDocument*> (odm.openFile (&project, cppFile)))
|
||||
{
|
||||
if (auto* header = dynamic_cast<SourceCodeDocument*> (odm.openFile (&project, headerFile)))
|
||||
{
|
||||
std::unique_ptr<JucerDocument> jucerDoc (new ComponentDocument (cpp));
|
||||
|
||||
if (jucerDoc != nullptr)
|
||||
{
|
||||
jucerDoc->setClassName (newFile.getFileNameWithoutExtension());
|
||||
|
||||
jucerDoc->flushChangesToDocuments (&project, true);
|
||||
jucerDoc.reset();
|
||||
|
||||
for (auto* doc : { cpp, header })
|
||||
{
|
||||
doc->saveAsync ([doc] (bool)
|
||||
{
|
||||
ProjucerApplication::getApp()
|
||||
.openDocumentManager
|
||||
.closeDocumentAsync (doc, OpenDocumentManager::SaveIfNeeded::yes, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
parent.addFileRetainingSortOrder (headerFile, true);
|
||||
parent.addFileRetainingSortOrder (cppFile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Project& project;
|
||||
};
|
||||
|
||||
NewFileWizard::Type* createGUIComponentWizard (Project&);
|
||||
NewFileWizard::Type* createGUIComponentWizard (Project& p)
|
||||
{
|
||||
return new NewGUIComponentWizard (p);
|
||||
}
|
||||
180
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h
vendored
Normal file
180
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_JucerDocument.h
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../CodeEditor/jucer_OpenDocumentManager.h"
|
||||
#include "../CodeEditor/jucer_SourceCodeEditor.h"
|
||||
#include "Components/jucer_ComponentTypeHandler.h"
|
||||
#include "jucer_PaintRoutine.h"
|
||||
#include "jucer_ComponentLayout.h"
|
||||
#include "jucer_BinaryResources.h"
|
||||
|
||||
//==============================================================================
|
||||
class JucerDocument : public ChangeBroadcaster,
|
||||
private Timer,
|
||||
private CodeDocument::Listener
|
||||
{
|
||||
public:
|
||||
JucerDocument (SourceCodeDocument* cpp);
|
||||
~JucerDocument() override;
|
||||
|
||||
static bool isValidJucerCppFile (const File&);
|
||||
static std::unique_ptr<XmlElement> pullMetaDataFromCppFile (const String& cpp);
|
||||
static JucerDocument* createForCppFile (Project*, const File&);
|
||||
|
||||
void changed();
|
||||
void beginTransaction();
|
||||
void beginTransaction (const String& name);
|
||||
|
||||
virtual JucerDocument* createCopy() = 0;
|
||||
virtual String getTypeName() const = 0;
|
||||
|
||||
SourceCodeDocument& getCppDocument() const { return *cpp; }
|
||||
|
||||
File getCppFile() const { return cpp->getFile(); }
|
||||
File getHeaderFile() const { return getCppFile().withFileExtension (".h"); }
|
||||
|
||||
bool flushChangesToDocuments (Project*, bool);
|
||||
bool reloadFromDocument();
|
||||
|
||||
//==============================================================================
|
||||
UndoManager& getUndoManager() noexcept { return undoManager; }
|
||||
|
||||
bool perform (UndoableAction* const action, const String& actionName);
|
||||
|
||||
void refreshAllPropertyComps();
|
||||
|
||||
//==============================================================================
|
||||
const String& getClassName() const noexcept { return className; }
|
||||
void setClassName (const String& newName);
|
||||
|
||||
const String& getComponentName() const noexcept { return componentName; }
|
||||
void setComponentName (const String& newName);
|
||||
|
||||
String getParentClassString() const { return parentClasses; }
|
||||
void setParentClasses (const String& classes);
|
||||
|
||||
String getConstructorParams() const { return constructorParams; }
|
||||
void setConstructorParams (const String& newParams);
|
||||
|
||||
String getVariableInitialisers() const { return variableInitialisers; }
|
||||
void setVariableInitialisers (const String& newInitlialisers);
|
||||
|
||||
void setFixedSize (const bool isFixed);
|
||||
bool isFixedSize() const noexcept { return fixedSize; }
|
||||
|
||||
void setInitialSize (int w, int h);
|
||||
|
||||
int getInitialWidth() const noexcept { return initialWidth; }
|
||||
int getInitialHeight() const noexcept { return initialHeight; }
|
||||
|
||||
//==============================================================================
|
||||
virtual int getNumPaintRoutines() const = 0;
|
||||
virtual StringArray getPaintRoutineNames() const = 0;
|
||||
virtual PaintRoutine* getPaintRoutine (const int index) const = 0;
|
||||
virtual ComponentLayout* getComponentLayout() const = 0;
|
||||
virtual Component* createTestComponent (const bool alwaysFillBackground) = 0;
|
||||
virtual void addExtraClassProperties (PropertyPanel&);
|
||||
|
||||
//==============================================================================
|
||||
virtual void getOptionalMethods (StringArray& baseClasses,
|
||||
StringArray& returnValues,
|
||||
StringArray& methods,
|
||||
StringArray& initialContents) const;
|
||||
|
||||
void setOptionalMethodEnabled (const String& methodSignature, const bool enable);
|
||||
bool isOptionalMethodEnabled (const String& methodSignature) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
BinaryResources& getResources() noexcept { return resources; }
|
||||
|
||||
//==============================================================================
|
||||
void setSnappingGrid (const int numPixels, const bool active, const bool shown);
|
||||
|
||||
int getSnappingGridSize() const noexcept { return snapGridPixels; }
|
||||
bool isSnapActive (const bool disableIfCtrlKeyDown) const noexcept;
|
||||
bool isSnapShown() const noexcept { return snapShown; }
|
||||
|
||||
int snapPosition (int pos) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
void setComponentOverlayOpacity (const float alpha);
|
||||
float getComponentOverlayOpacity() const noexcept { return componentOverlayOpacity; }
|
||||
|
||||
//==============================================================================
|
||||
static const char* const jucerCompXmlTag;
|
||||
|
||||
bool findTemplateFiles (String& templateH, String& templateCpp) const;
|
||||
|
||||
String getTemplateFile() const { return templateFile; }
|
||||
void setTemplateFile (const String&);
|
||||
|
||||
static bool shouldUseTransMacro() noexcept { return true; }
|
||||
|
||||
//==============================================================================
|
||||
void refreshCustomCodeFromDocument();
|
||||
|
||||
protected:
|
||||
SourceCodeDocument* cpp;
|
||||
|
||||
String className, componentName, templateFile;
|
||||
String parentClasses, constructorParams, variableInitialisers;
|
||||
|
||||
bool fixedSize = false;
|
||||
int initialWidth = 600, initialHeight = 400;
|
||||
|
||||
BinaryResources resources;
|
||||
|
||||
virtual std::unique_ptr<XmlElement> createXml() const;
|
||||
virtual bool loadFromXml (const XmlElement&);
|
||||
|
||||
virtual void fillInGeneratedCode (GeneratedCode&) const;
|
||||
virtual void fillInPaintCode (GeneratedCode&) const;
|
||||
|
||||
virtual void applyCustomPaintSnippets (StringArray&) {}
|
||||
|
||||
static void addMethod (const String& base, const String& returnVal,
|
||||
const String& method, const String& initialContent,
|
||||
StringArray& baseClasses, StringArray& returnValues,
|
||||
StringArray& methods, StringArray& initialContents);
|
||||
|
||||
private:
|
||||
UndoManager undoManager;
|
||||
int snapGridPixels = 8;
|
||||
bool snapActive = true, snapShown = true;
|
||||
float componentOverlayOpacity = 0.33f;
|
||||
StringArray activeExtraMethods;
|
||||
std::unique_ptr<XmlElement> currentXML;
|
||||
std::unique_ptr<Timer> userDocChangeTimer;
|
||||
|
||||
void timerCallback() override;
|
||||
void codeDocumentTextInserted (const String& newText, int insertIndex) override;
|
||||
void codeDocumentTextDeleted (int startIndex, int endIndex) override;
|
||||
void userEditedCpp();
|
||||
void extractCustomPaintSnippetsFromCppFile (const String& cpp);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JucerDocument)
|
||||
};
|
||||
163
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ObjectTypes.cpp
vendored
Normal file
163
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ObjectTypes.cpp
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
|
||||
#include "jucer_JucerDocument.h"
|
||||
#include "Components/jucer_ComponentUndoableAction.h"
|
||||
#include "Properties/jucer_JustificationProperty.h"
|
||||
#include "Properties/jucer_FontPropertyComponent.h"
|
||||
#include "Properties/jucer_ComponentBooleanProperty.h"
|
||||
#include "Properties/jucer_ComponentChoiceProperty.h"
|
||||
#include "Properties/jucer_ComponentTextProperty.h"
|
||||
#include "Properties/jucer_ComponentColourProperty.h"
|
||||
#include "Properties/jucer_FilePropertyComponent.h"
|
||||
#include "PaintElements/jucer_ImageResourceProperty.h"
|
||||
|
||||
#include "jucer_ObjectTypes.h"
|
||||
|
||||
#include "PaintElements/jucer_PaintElementUndoableAction.h"
|
||||
#include "PaintElements/jucer_PaintElementRectangle.h"
|
||||
#include "PaintElements/jucer_PaintElementRoundedRectangle.h"
|
||||
#include "PaintElements/jucer_PaintElementImage.h"
|
||||
#include "PaintElements/jucer_PaintElementEllipse.h"
|
||||
#include "PaintElements/jucer_PaintElementPath.h"
|
||||
#include "PaintElements/jucer_PaintElementText.h"
|
||||
#include "PaintElements/jucer_PaintElementGroup.h"
|
||||
|
||||
#include "Components/jucer_ButtonHandler.h"
|
||||
#include "Components/jucer_TextButtonHandler.h"
|
||||
#include "Components/jucer_ToggleButtonHandler.h"
|
||||
#include "Components/jucer_SliderHandler.h"
|
||||
#include "Components/jucer_LabelHandler.h"
|
||||
#include "Components/jucer_TextEditorHandler.h"
|
||||
#include "Components/jucer_ComboBoxHandler.h"
|
||||
#include "Components/jucer_GroupComponentHandler.h"
|
||||
#include "Components/jucer_JucerComponentHandler.h"
|
||||
#include "Components/jucer_HyperlinkButtonHandler.h"
|
||||
#include "Components/jucer_ViewportHandler.h"
|
||||
#include "Components/jucer_TabbedComponentHandler.h"
|
||||
#include "Components/jucer_TreeViewHandler.h"
|
||||
#include "Components/jucer_GenericComponentHandler.h"
|
||||
#include "Components/jucer_ImageButtonHandler.h"
|
||||
|
||||
namespace ObjectTypes
|
||||
{
|
||||
|
||||
static const char* const elementNames[] =
|
||||
{
|
||||
"Rectangle",
|
||||
"Rounded Rectangle",
|
||||
"Ellipse",
|
||||
"Path",
|
||||
"Image",
|
||||
"Text",
|
||||
nullptr
|
||||
};
|
||||
|
||||
const char* const* const elementTypeNames = (const char* const*) elementNames;
|
||||
const int numElementTypes = (sizeof (elementNames) / sizeof (elementNames[0])) - 1;
|
||||
|
||||
PaintElement* createNewElement (const int index, PaintRoutine* owner)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return new PaintElementRectangle (owner);
|
||||
case 1: return new PaintElementRoundedRectangle (owner);
|
||||
case 2: return new PaintElementEllipse (owner);
|
||||
case 3: return new PaintElementPath (owner);
|
||||
case 4: return new PaintElementImage (owner);
|
||||
case 5: return new PaintElementText (owner);
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PaintElement* createNewImageElement (PaintRoutine* owner)
|
||||
{
|
||||
return new PaintElementImage (owner);
|
||||
}
|
||||
|
||||
PaintElement* createElementForXml (const XmlElement* const e, PaintRoutine* const owner)
|
||||
{
|
||||
jassert (e != nullptr);
|
||||
|
||||
std::unique_ptr<PaintElement> pe;
|
||||
|
||||
if (e->hasTagName (PaintElementRectangle::getTagName())) pe.reset (new PaintElementRectangle (owner));
|
||||
else if (e->hasTagName (PaintElementRoundedRectangle::getTagName())) pe.reset (new PaintElementRoundedRectangle (owner));
|
||||
else if (e->hasTagName (PaintElementEllipse::getTagName())) pe.reset (new PaintElementEllipse (owner));
|
||||
else if (e->hasTagName (PaintElementImage::getTagName())) pe.reset (new PaintElementImage (owner));
|
||||
else if (e->hasTagName (PaintElementPath::getTagName())) pe.reset (new PaintElementPath (owner));
|
||||
else if (e->hasTagName (PaintElementText::getTagName())) pe.reset (new PaintElementText (owner));
|
||||
else if (e->hasTagName (PaintElementGroup::getTagName())) pe.reset (new PaintElementGroup (owner));
|
||||
|
||||
if (pe != nullptr && pe->loadFromXml (*e))
|
||||
return pe.release();
|
||||
|
||||
jassertfalse;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static TextButtonHandler textButton;
|
||||
static ToggleButtonHandler toggleButton;
|
||||
static SliderHandler slider;
|
||||
static LabelHandler label;
|
||||
static TextEditorHandler textEditor;
|
||||
static ComboBoxHandler comboBox;
|
||||
static JucerComponentHandler jucerCompHandler;
|
||||
static GroupComponentHandler group;
|
||||
static HyperlinkButtonHandler hyperlink;
|
||||
static ViewportHandler viewport;
|
||||
static TabbedComponentHandler tabbedComp;
|
||||
static TreeViewHandler treeview;
|
||||
static GenericComponentHandler genericHandler;
|
||||
static ImageButtonHandler imageButtonHandler;
|
||||
|
||||
static ComponentTypeHandler* const compTypes[] =
|
||||
{
|
||||
&textButton,
|
||||
&toggleButton,
|
||||
&slider,
|
||||
&label,
|
||||
&textEditor,
|
||||
&comboBox,
|
||||
&group,
|
||||
&jucerCompHandler,
|
||||
&hyperlink,
|
||||
&viewport,
|
||||
&tabbedComp,
|
||||
&treeview,
|
||||
&genericHandler,
|
||||
&imageButtonHandler,
|
||||
nullptr
|
||||
};
|
||||
|
||||
ComponentTypeHandler* const* const componentTypeHandlers = (ComponentTypeHandler* const*) compTypes;
|
||||
const int numComponentTypes = numElementsInArray (compTypes) - 1;
|
||||
|
||||
}
|
||||
47
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ObjectTypes.h
vendored
Normal file
47
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_ObjectTypes.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "jucer_JucerDocument.h"
|
||||
#include "PaintElements/jucer_PaintElement.h"
|
||||
|
||||
//==============================================================================
|
||||
namespace ObjectTypes
|
||||
{
|
||||
//==============================================================================
|
||||
// Component types
|
||||
extern ComponentTypeHandler* const* const componentTypeHandlers;
|
||||
extern const int numComponentTypes;
|
||||
|
||||
//==============================================================================
|
||||
// Element types
|
||||
extern const char* const* const elementTypeNames;
|
||||
extern const int numElementTypes;
|
||||
|
||||
PaintElement* createNewElement (const int index, PaintRoutine* owner);
|
||||
PaintElement* createNewImageElement (PaintRoutine* owner);
|
||||
PaintElement* createElementForXml (const XmlElement* const e, PaintRoutine* const owner);
|
||||
}
|
||||
636
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp
vendored
Normal file
636
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.cpp
vendored
Normal file
@@ -0,0 +1,636 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../Application/jucer_Headers.h"
|
||||
#include "jucer_PaintRoutine.h"
|
||||
#include "jucer_JucerDocument.h"
|
||||
#include "jucer_ObjectTypes.h"
|
||||
#include "PaintElements/jucer_PaintElementUndoableAction.h"
|
||||
#include "PaintElements/jucer_PaintElementPath.h"
|
||||
#include "PaintElements/jucer_PaintElementImage.h"
|
||||
#include "PaintElements/jucer_PaintElementGroup.h"
|
||||
#include "UI/jucer_JucerDocumentEditor.h"
|
||||
#include "../Application/jucer_Application.h"
|
||||
|
||||
//==============================================================================
|
||||
PaintRoutine::PaintRoutine()
|
||||
: document (nullptr),
|
||||
backgroundColour (ProjucerApplication::getApp().lookAndFeel.findColour (backgroundColourId))
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
PaintRoutine::~PaintRoutine()
|
||||
{
|
||||
elements.clear(); // do this explicitly before the scalar destructor because these
|
||||
// objects will be listeners on this object
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintRoutine::changed()
|
||||
{
|
||||
if (document != nullptr)
|
||||
document->changed();
|
||||
}
|
||||
|
||||
bool PaintRoutine::perform (UndoableAction* action, const String& actionName)
|
||||
{
|
||||
if (document != nullptr)
|
||||
return document->getUndoManager().perform (action, actionName);
|
||||
|
||||
std::unique_ptr<UndoableAction> deleter (action);
|
||||
action->perform();
|
||||
return false;
|
||||
}
|
||||
|
||||
void PaintRoutine::setBackgroundColour (Colour newColour) noexcept
|
||||
{
|
||||
backgroundColour = newColour;
|
||||
changed();
|
||||
}
|
||||
|
||||
void PaintRoutine::clear()
|
||||
{
|
||||
if (elements.size() > 0)
|
||||
{
|
||||
elements.clear();
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class AddXmlElementAction : public UndoableAction
|
||||
{
|
||||
public:
|
||||
AddXmlElementAction (PaintRoutine& routine_, XmlElement* xml_)
|
||||
: routine (routine_), xml (xml_)
|
||||
{
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
PaintElement* newElement = routine.addElementFromXml (*xml, -1, false);
|
||||
jassert (newElement != nullptr);
|
||||
|
||||
indexAdded = routine.indexOfElement (newElement);
|
||||
jassert (indexAdded >= 0);
|
||||
return indexAdded >= 0;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
routine.removeElement (routine.getElement (indexAdded), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
int getSizeInUnits() { return 10; }
|
||||
|
||||
int indexAdded;
|
||||
|
||||
private:
|
||||
PaintRoutine& routine;
|
||||
std::unique_ptr<XmlElement> xml;
|
||||
|
||||
void showCorrectTab() const
|
||||
{
|
||||
if (JucerDocumentEditor* const ed = JucerDocumentEditor::getActiveDocumentHolder())
|
||||
ed->showGraphics (&routine);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AddXmlElementAction)
|
||||
};
|
||||
|
||||
PaintElement* PaintRoutine::addElementFromXml (const XmlElement& xml, const int index, const bool undoable)
|
||||
{
|
||||
selectedPoints.deselectAll();
|
||||
|
||||
if (undoable && document != nullptr)
|
||||
{
|
||||
AddXmlElementAction* action = new AddXmlElementAction (*this, new XmlElement (xml));
|
||||
document->getUndoManager().perform (action, "Add new element");
|
||||
|
||||
return elements [action->indexAdded];
|
||||
}
|
||||
|
||||
if (PaintElement* const newElement = ObjectTypes::createElementForXml (&xml, this))
|
||||
{
|
||||
elements.insert (index, newElement);
|
||||
changed();
|
||||
|
||||
return newElement;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PaintElement* PaintRoutine::addNewElement (PaintElement* e, const int index, const bool undoable)
|
||||
{
|
||||
if (e != nullptr)
|
||||
{
|
||||
std::unique_ptr<PaintElement> deleter (e);
|
||||
std::unique_ptr<XmlElement> xml (e->createXml());
|
||||
|
||||
e = addElementFromXml (*xml, index, undoable);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class DeleteElementAction : public PaintElementUndoableAction <PaintElement>
|
||||
{
|
||||
public:
|
||||
explicit DeleteElementAction (PaintElement* const element)
|
||||
: PaintElementUndoableAction <PaintElement> (element),
|
||||
oldIndex (-1)
|
||||
{
|
||||
xml.reset (element->createXml());
|
||||
oldIndex = routine.indexOfElement (element);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
routine.removeElement (getElement(), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
PaintElement* newElement = routine.addElementFromXml (*xml, oldIndex, false);
|
||||
showCorrectTab();
|
||||
return newElement != nullptr;
|
||||
}
|
||||
|
||||
int getSizeInUnits() { return 10; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<XmlElement> xml;
|
||||
int oldIndex;
|
||||
};
|
||||
|
||||
|
||||
void PaintRoutine::removeElement (PaintElement* element, const bool undoable)
|
||||
{
|
||||
if (elements.contains (element))
|
||||
{
|
||||
if (undoable)
|
||||
{
|
||||
perform (new DeleteElementAction (element),
|
||||
"Delete " + element->getTypeName());
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedElements.deselect (element);
|
||||
selectedPoints.deselectAll();
|
||||
|
||||
selectedPoints.changed (true);
|
||||
selectedElements.changed (true);
|
||||
|
||||
elements.removeObject (element);
|
||||
changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class FrontOrBackElementAction : public PaintElementUndoableAction <PaintElement>
|
||||
{
|
||||
public:
|
||||
FrontOrBackElementAction (PaintElement* const element, int newIndex_)
|
||||
: PaintElementUndoableAction <PaintElement> (element),
|
||||
newIndex (newIndex_)
|
||||
{
|
||||
oldIndex = routine.indexOfElement (element);
|
||||
}
|
||||
|
||||
bool perform()
|
||||
{
|
||||
showCorrectTab();
|
||||
|
||||
PaintElement* e = routine.getElement (oldIndex);
|
||||
routine.moveElementZOrder (oldIndex, newIndex);
|
||||
newIndex = routine.indexOfElement (e);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool undo()
|
||||
{
|
||||
showCorrectTab();
|
||||
routine.moveElementZOrder (newIndex, oldIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
int newIndex, oldIndex;
|
||||
};
|
||||
|
||||
void PaintRoutine::moveElementZOrder (int oldIndex, int newIndex)
|
||||
{
|
||||
jassert (elements [oldIndex] != nullptr);
|
||||
|
||||
if (oldIndex != newIndex && elements [oldIndex] != nullptr)
|
||||
{
|
||||
elements.move (oldIndex, newIndex);
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::elementToFront (PaintElement* element, const bool undoable)
|
||||
{
|
||||
if (element != nullptr && elements.contains (element))
|
||||
{
|
||||
if (undoable)
|
||||
perform (new FrontOrBackElementAction (element, -1), "Move elements to front");
|
||||
else
|
||||
moveElementZOrder (elements.indexOf (element), -1);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::elementToBack (PaintElement* element, const bool undoable)
|
||||
{
|
||||
if (element != nullptr && elements.contains (element))
|
||||
{
|
||||
if (undoable)
|
||||
perform (new FrontOrBackElementAction (element, 0), "Move elements to back");
|
||||
else
|
||||
moveElementZOrder (elements.indexOf (element), 0);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* const PaintRoutine::clipboardXmlTag = "PAINTELEMENTS";
|
||||
|
||||
void PaintRoutine::copySelectedToClipboard()
|
||||
{
|
||||
if (selectedElements.getNumSelected() == 0)
|
||||
return;
|
||||
|
||||
XmlElement clip (clipboardXmlTag);
|
||||
|
||||
for (auto* pe : elements)
|
||||
if (selectedElements.isSelected (pe))
|
||||
clip.addChildElement (pe->createXml());
|
||||
|
||||
SystemClipboard::copyTextToClipboard (clip.toString());
|
||||
}
|
||||
|
||||
void PaintRoutine::paste()
|
||||
{
|
||||
if (auto doc = parseXMLIfTagMatches (SystemClipboard::getTextFromClipboard(), clipboardXmlTag))
|
||||
{
|
||||
selectedElements.deselectAll();
|
||||
selectedPoints.deselectAll();
|
||||
|
||||
for (auto* e : doc->getChildIterator())
|
||||
if (PaintElement* newElement = addElementFromXml (*e, -1, true))
|
||||
selectedElements.addToSelection (newElement);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::deleteSelected()
|
||||
{
|
||||
const SelectedItemSet<PaintElement*> temp1 (selectedElements);
|
||||
const SelectedItemSet<PathPoint*> temp2 (selectedPoints);
|
||||
|
||||
if (temp2.getNumSelected() > 0)
|
||||
{
|
||||
selectedPoints.deselectAll();
|
||||
selectedPoints.changed (true); // synchronous message to get rid of any property components
|
||||
|
||||
// if any points are selected, just delete them, and not the element, which may
|
||||
// also be selected..
|
||||
for (int i = temp2.getNumSelected(); --i >= 0;)
|
||||
temp2.getSelectedItem (i)->deleteFromPath();
|
||||
|
||||
changed();
|
||||
}
|
||||
else if (temp1.getNumSelected() > 0)
|
||||
{
|
||||
selectedElements.deselectAll();
|
||||
selectedElements.changed (true);
|
||||
|
||||
for (int i = temp1.getNumSelected(); --i >= 0;)
|
||||
removeElement (temp1.getSelectedItem (i), true);
|
||||
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::selectAll()
|
||||
{
|
||||
if (selectedPoints.getNumSelected() > 0)
|
||||
{
|
||||
if (const PaintElementPath* path = selectedPoints.getSelectedItem (0)->owner)
|
||||
for (int i = 0; i < path->getNumPoints(); ++i)
|
||||
selectedPoints.addToSelection (path->getPoint (i));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < elements.size(); ++i)
|
||||
selectedElements.addToSelection (elements.getUnchecked (i));
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::selectedToFront()
|
||||
{
|
||||
const SelectedItemSet<PaintElement*> temp (selectedElements);
|
||||
|
||||
for (int i = temp.getNumSelected(); --i >= 0;)
|
||||
elementToFront (temp.getSelectedItem(i), true);
|
||||
}
|
||||
|
||||
void PaintRoutine::selectedToBack()
|
||||
{
|
||||
const SelectedItemSet<PaintElement*> temp (selectedElements);
|
||||
|
||||
for (int i = 0; i < temp.getNumSelected(); ++i)
|
||||
elementToBack (temp.getSelectedItem(i), true);
|
||||
}
|
||||
|
||||
void PaintRoutine::alignTop()
|
||||
{
|
||||
if (selectedElements.getNumSelected() > 1)
|
||||
{
|
||||
auto* main = selectedElements.getSelectedItem (0);
|
||||
auto yPos = main->getY();
|
||||
|
||||
for (auto* other : selectedElements)
|
||||
{
|
||||
if (other != main)
|
||||
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (other->getX(),
|
||||
yPos), main, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void PaintRoutine::alignRight()
|
||||
{
|
||||
if (selectedElements.getNumSelected() > 1)
|
||||
{
|
||||
auto* main = selectedElements.getSelectedItem (0);
|
||||
auto rightPos = main->getRight();
|
||||
|
||||
for (auto* other : selectedElements)
|
||||
{
|
||||
if (other != main)
|
||||
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (rightPos - other->getWidth(),
|
||||
other->getY()), main, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::alignBottom()
|
||||
{
|
||||
if (selectedElements.getNumSelected() > 1)
|
||||
{
|
||||
auto* main = selectedElements.getSelectedItem (0);
|
||||
auto bottomPos = main->getBottom();
|
||||
|
||||
for (auto* other : selectedElements)
|
||||
{
|
||||
if (other != main)
|
||||
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (other->getX(),
|
||||
bottomPos - other->getHeight()), main, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
void PaintRoutine::alignLeft()
|
||||
{
|
||||
if (selectedElements.getNumSelected() > 1)
|
||||
{
|
||||
auto* main = selectedElements.getSelectedItem (0);
|
||||
auto xPos = main->getX();
|
||||
|
||||
for (auto* other : selectedElements)
|
||||
{
|
||||
if (other != main)
|
||||
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (xPos,
|
||||
other->getY()), main, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::groupSelected()
|
||||
{
|
||||
PaintElementGroup::groupSelected (this);
|
||||
}
|
||||
|
||||
void PaintRoutine::ungroupSelected()
|
||||
{
|
||||
const SelectedItemSet<PaintElement*> temp (selectedElements);
|
||||
|
||||
for (int i = 0; i < temp.getNumSelected(); ++i)
|
||||
if (PaintElementGroup* const pg = dynamic_cast<PaintElementGroup*> (temp.getSelectedItem (i)))
|
||||
pg->ungroup (true);
|
||||
}
|
||||
|
||||
void PaintRoutine::bringLostItemsBackOnScreen (const Rectangle<int>& parentArea)
|
||||
{
|
||||
for (auto* c : elements)
|
||||
{
|
||||
auto r = c->getCurrentBounds (parentArea);
|
||||
|
||||
if (! r.intersects (parentArea))
|
||||
{
|
||||
r.setPosition (parentArea.getCentreX(), parentArea.getCentreY());
|
||||
c->setCurrentBounds (r, parentArea, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::startDragging (const Rectangle<int>& parentArea)
|
||||
{
|
||||
for (auto* c : elements)
|
||||
{
|
||||
auto r = c->getCurrentBounds (parentArea);
|
||||
|
||||
c->getProperties().set ("xDragStart", r.getX());
|
||||
c->getProperties().set ("yDragStart", r.getY());
|
||||
}
|
||||
|
||||
getDocument()->beginTransaction();
|
||||
}
|
||||
|
||||
void PaintRoutine::dragSelectedComps (int dx, int dy, const Rectangle<int>& parentArea)
|
||||
{
|
||||
getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
if (document != nullptr && selectedElements.getNumSelected() > 1)
|
||||
{
|
||||
dx = document->snapPosition (dx);
|
||||
dy = document->snapPosition (dy);
|
||||
}
|
||||
|
||||
for (int i = 0; i < selectedElements.getNumSelected(); ++i)
|
||||
{
|
||||
PaintElement* const c = selectedElements.getSelectedItem (i);
|
||||
|
||||
const int startX = c->getProperties() ["xDragStart"];
|
||||
const int startY = c->getProperties() ["yDragStart"];
|
||||
|
||||
Rectangle<int> r (c->getCurrentBounds (parentArea));
|
||||
|
||||
if (document != nullptr && selectedElements.getNumSelected() == 1)
|
||||
{
|
||||
r.setPosition (document->snapPosition (startX + dx),
|
||||
document->snapPosition (startY + dy));
|
||||
}
|
||||
else
|
||||
{
|
||||
r.setPosition (startX + dx,
|
||||
startY + dy);
|
||||
}
|
||||
|
||||
c->setCurrentBounds (r, parentArea, true);
|
||||
}
|
||||
|
||||
changed();
|
||||
}
|
||||
|
||||
void PaintRoutine::endDragging()
|
||||
{
|
||||
getDocument()->beginTransaction();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintRoutine::fillWithBackground (Graphics& g, const bool drawOpaqueBackground)
|
||||
{
|
||||
if ((! backgroundColour.isOpaque()) && drawOpaqueBackground)
|
||||
{
|
||||
g.fillCheckerBoard (Rectangle<float> ((float) g.getClipBounds().getRight(),
|
||||
(float) g.getClipBounds().getBottom()),
|
||||
50.0f, 50.0f,
|
||||
Colour (0xffdddddd).overlaidWith (backgroundColour),
|
||||
Colour (0xffffffff).overlaidWith (backgroundColour));
|
||||
}
|
||||
else
|
||||
{
|
||||
g.fillAll (backgroundColour);
|
||||
}
|
||||
}
|
||||
|
||||
void PaintRoutine::drawElements (Graphics& g, const Rectangle<int>& relativeTo)
|
||||
{
|
||||
Component temp;
|
||||
temp.setBounds (relativeTo);
|
||||
|
||||
for (auto* e : elements)
|
||||
e->draw (g, getDocument()->getComponentLayout(), relativeTo);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void PaintRoutine::dropImageAt (const File& f, int x, int y)
|
||||
{
|
||||
std::unique_ptr<Drawable> d (Drawable::createFromImageFile (f));
|
||||
|
||||
if (d != nullptr)
|
||||
{
|
||||
auto bounds = d->getDrawableBounds();
|
||||
d.reset();
|
||||
|
||||
auto* newElement = addNewElement (ObjectTypes::createNewImageElement (this), -1, true);
|
||||
|
||||
if (auto* pei = dynamic_cast<PaintElementImage*> (newElement))
|
||||
{
|
||||
String resourceName (getDocument()->getResources().findUniqueName (f.getFileName()));
|
||||
|
||||
if (auto* existingResource = getDocument()->getResources().getResourceForFile (f))
|
||||
{
|
||||
resourceName = existingResource->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryBlock data;
|
||||
f.loadFileAsData (data);
|
||||
|
||||
getDocument()->getResources().add (resourceName, f.getFullPathName(), data);
|
||||
}
|
||||
|
||||
pei->setResource (resourceName, true);
|
||||
|
||||
const int imageW = (int) (bounds.getRight() + 0.999f);
|
||||
const int imageH = (int) (bounds.getBottom() + 0.999f);
|
||||
|
||||
RelativePositionedRectangle pr;
|
||||
pr.rect.setX (x - imageW / 2);
|
||||
pr.rect.setY (y - imageH / 2);
|
||||
pr.rect.setWidth (imageW);
|
||||
pr.rect.setHeight (imageH);
|
||||
|
||||
pei->setPosition (pr, true);
|
||||
|
||||
getSelectedElements().selectOnly (pei);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char* PaintRoutine::xmlTagName = "BACKGROUND";
|
||||
|
||||
XmlElement* PaintRoutine::createXml() const
|
||||
{
|
||||
auto* xml = new XmlElement (xmlTagName);
|
||||
xml->setAttribute ("backgroundColour", backgroundColour.toString());
|
||||
|
||||
for (auto* e : elements)
|
||||
xml->addChildElement (e->createXml());
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
bool PaintRoutine::loadFromXml (const XmlElement& xml)
|
||||
{
|
||||
if (xml.hasTagName (xmlTagName))
|
||||
{
|
||||
backgroundColour = Colour::fromString (xml.getStringAttribute ("backgroundColour", Colours::white.toString()));
|
||||
|
||||
clear();
|
||||
|
||||
for (auto* e : xml.getChildIterator())
|
||||
if (auto* newElement = ObjectTypes::createElementForXml (e, this))
|
||||
elements.add (newElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PaintRoutine::fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const
|
||||
{
|
||||
if (! backgroundColour.isTransparent())
|
||||
paintMethodCode << "g.fillAll (" << CodeHelpers::colourToCode (backgroundColour) << ");\n\n";
|
||||
|
||||
for (auto* e : elements)
|
||||
e->fillInGeneratedCode (code, paintMethodCode);
|
||||
}
|
||||
|
||||
void PaintRoutine::applyCustomPaintSnippets (StringArray& snippets)
|
||||
{
|
||||
for (auto* e : elements)
|
||||
e->applyCustomPaintSnippets (snippets);
|
||||
}
|
||||
122
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h
vendored
Normal file
122
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_PaintRoutine.h
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PaintElements/jucer_PaintElement.h"
|
||||
class JucerDocument;
|
||||
class PathPoint;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Contains a set of PaintElements that constitute some kind of paint() method.
|
||||
*/
|
||||
class PaintRoutine
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
PaintRoutine();
|
||||
~PaintRoutine();
|
||||
|
||||
//==============================================================================
|
||||
void changed();
|
||||
bool perform (UndoableAction* action, const String& actionName);
|
||||
|
||||
//==============================================================================
|
||||
int getNumElements() const noexcept { return elements.size(); }
|
||||
PaintElement* getElement (const int index) const noexcept { return elements [index]; }
|
||||
int indexOfElement (PaintElement* e) const noexcept { return elements.indexOf (e); }
|
||||
bool containsElement (PaintElement* e) const noexcept { return elements.contains (e); }
|
||||
|
||||
//==============================================================================
|
||||
void clear();
|
||||
PaintElement* addElementFromXml (const XmlElement& xml, const int index, const bool undoable);
|
||||
PaintElement* addNewElement (PaintElement* elementToCopy, const int index, const bool undoable);
|
||||
void removeElement (PaintElement* element, const bool undoable);
|
||||
|
||||
void elementToFront (PaintElement* element, const bool undoable);
|
||||
void elementToBack (PaintElement* element, const bool undoable);
|
||||
|
||||
const Colour getBackgroundColour() const noexcept { return backgroundColour; }
|
||||
void setBackgroundColour (Colour newColour) noexcept;
|
||||
|
||||
void fillWithBackground (Graphics& g, const bool drawOpaqueBackground);
|
||||
void drawElements (Graphics& g, const Rectangle<int>& relativeTo);
|
||||
|
||||
void dropImageAt (const File& f, int x, int y);
|
||||
|
||||
//==============================================================================
|
||||
SelectedItemSet <PaintElement*>& getSelectedElements() noexcept { return selectedElements; }
|
||||
SelectedItemSet <PathPoint*>& getSelectedPoints() noexcept { return selectedPoints; }
|
||||
|
||||
static const char* const clipboardXmlTag;
|
||||
void copySelectedToClipboard();
|
||||
void paste();
|
||||
void deleteSelected();
|
||||
void selectAll();
|
||||
|
||||
void selectedToFront();
|
||||
void selectedToBack();
|
||||
|
||||
void alignTop();
|
||||
void alignRight();
|
||||
void alignBottom();
|
||||
void alignLeft();
|
||||
|
||||
void groupSelected();
|
||||
void ungroupSelected();
|
||||
|
||||
void startDragging (const Rectangle<int>& parentArea);
|
||||
void dragSelectedComps (int dxFromDragStart, int dyFromDragStart, const Rectangle<int>& parentArea);
|
||||
void endDragging();
|
||||
|
||||
void bringLostItemsBackOnScreen (const Rectangle<int>& parentArea);
|
||||
|
||||
//==============================================================================
|
||||
void setDocument (JucerDocument* const doc) { document = doc; }
|
||||
JucerDocument* getDocument() const noexcept { return document; }
|
||||
|
||||
//==============================================================================
|
||||
static const char* xmlTagName;
|
||||
XmlElement* createXml() const;
|
||||
bool loadFromXml (const XmlElement& xml);
|
||||
|
||||
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) const;
|
||||
|
||||
void applyCustomPaintSnippets (StringArray&);
|
||||
|
||||
//==============================================================================
|
||||
private:
|
||||
OwnedArray<PaintElement> elements;
|
||||
SelectedItemSet <PaintElement*> selectedElements;
|
||||
SelectedItemSet <PathPoint*> selectedPoints;
|
||||
JucerDocument* document;
|
||||
|
||||
Colour backgroundColour;
|
||||
|
||||
friend class DeleteElementAction;
|
||||
friend class FrontOrBackElementAction;
|
||||
void moveElementZOrder (int oldIndex, int newIndex);
|
||||
};
|
||||
118
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_UtilityFunctions.h
vendored
Normal file
118
deps/juce/extras/Projucer/Source/ComponentEditor/jucer_UtilityFunctions.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//==============================================================================
|
||||
inline String quotedString (const String& s, bool wrapInTransMacro)
|
||||
{
|
||||
const int embeddedIndex = s.indexOfIgnoreCase ("%%");
|
||||
|
||||
if (embeddedIndex >= 0)
|
||||
{
|
||||
String s1 (s.substring (0, embeddedIndex));
|
||||
String s2 (s.substring (embeddedIndex + 2));
|
||||
String code;
|
||||
|
||||
const int closeIndex = s2.indexOf ("%%");
|
||||
|
||||
if (closeIndex > 0)
|
||||
{
|
||||
code = s2.substring (0, closeIndex).trim();
|
||||
s2 = s2.substring (closeIndex + 2);
|
||||
}
|
||||
|
||||
if (code.isNotEmpty())
|
||||
{
|
||||
String result;
|
||||
|
||||
if (s1.isNotEmpty())
|
||||
result << quotedString (s1, wrapInTransMacro) << " + ";
|
||||
|
||||
result << code;
|
||||
|
||||
if (s2.isNotEmpty())
|
||||
result << " + " << quotedString (s2, wrapInTransMacro);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
String lit (CodeHelpers::stringLiteral (s));
|
||||
|
||||
if (wrapInTransMacro && lit.startsWithChar ('"'))
|
||||
return "TRANS(" + lit + ")";
|
||||
|
||||
return lit;
|
||||
}
|
||||
|
||||
inline String castToFloat (const String& expression)
|
||||
{
|
||||
if (expression.containsOnly ("0123456789.f"))
|
||||
{
|
||||
String s (expression.getFloatValue());
|
||||
|
||||
if (s.containsChar ('.'))
|
||||
return s + "f";
|
||||
|
||||
return s + ".0f";
|
||||
}
|
||||
|
||||
return "static_cast<float> (" + expression + ")";
|
||||
}
|
||||
|
||||
inline void drawResizableBorder (Graphics& g, int w, int h,
|
||||
const BorderSize<int> borderSize,
|
||||
const bool isMouseOver,
|
||||
Colour borderColour)
|
||||
{
|
||||
ignoreUnused (isMouseOver);
|
||||
g.setColour (borderColour);
|
||||
|
||||
g.fillRect (0, 0, w, borderSize.getTop());
|
||||
g.fillRect (0, 0, borderSize.getLeft(), h);
|
||||
g.fillRect (0, h - borderSize.getBottom(), w, borderSize.getBottom());
|
||||
g.fillRect (w - borderSize.getRight(), 0, borderSize.getRight(), h);
|
||||
|
||||
g.drawRect (borderSize.getLeft() - 1, borderSize.getTop() - 1,
|
||||
w - borderSize.getRight() - borderSize.getLeft() + 2,
|
||||
h - borderSize.getTop() - borderSize.getBottom() + 2);
|
||||
}
|
||||
|
||||
inline void drawMouseOverCorners (Graphics& g, int w, int h)
|
||||
{
|
||||
RectangleList<int> r (Rectangle<int> (0, 0, w, h));
|
||||
r.subtract (Rectangle<int> (1, 1, w - 2, h - 2));
|
||||
|
||||
const int size = jmin (w / 3, h / 3, 12);
|
||||
r.subtract (Rectangle<int> (size, 0, w - size - size, h));
|
||||
r.subtract (Rectangle<int> (0, size, w, h - size - size));
|
||||
|
||||
g.setColour (Colours::black);
|
||||
|
||||
for (int i = r.getNumRectangles(); --i >= 0;)
|
||||
g.fillRect (r.getRectangle (i));
|
||||
}
|
||||
Reference in New Issue
Block a user