migrating to the latest JUCE version
This commit is contained in:
@@ -1,389 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,446 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,178 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,147 +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)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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)
|
||||
};
|
||||
|
||||
@@ -1,75 +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)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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)
|
||||
};
|
||||
|
||||
@@ -1,241 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,237 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,149 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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())
|
||||
+ ",\njuce::URL ("
|
||||
+ 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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,273 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,79 +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;
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,433 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,146 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,265 +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;
|
||||
};
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,411 +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";
|
||||
}
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,71 +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];
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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];
|
||||
};
|
||||
|
||||
@@ -1,170 +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);
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
|
||||
@@ -1,59 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,80 +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);
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
};
|
||||
|
||||
@@ -1,55 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,427 +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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,99 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,144 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,175 +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)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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)
|
||||
};
|
||||
|
||||
@@ -1,173 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,226 +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";
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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";
|
||||
}
|
||||
|
||||
@@ -1,81 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,428 +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"; }
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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"; }
|
||||
|
||||
@@ -1,165 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,176 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,184 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,267 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,142 +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&);
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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&);
|
||||
};
|
||||
|
||||
@@ -1,107 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,157 +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;
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,209 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,60 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,58 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,165 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,60 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,63 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,142 +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;
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,100 +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;
|
||||
}
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,463 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,430 +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();
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
}
|
||||
|
||||
@@ -1,86 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,118 +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;
|
||||
};
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,278 +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);
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
|
||||
@@ -1,84 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,243 +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);
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
|
||||
@@ -1,75 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,71 +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,
|
||||
};
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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,
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,104 +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);
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
};
|
||||
|
||||
@@ -1,281 +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();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +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();
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
};
|
||||
|
||||
@@ -1,185 +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();
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
}
|
||||
|
||||
@@ -1,45 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,272 +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 (", "));
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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 (", "));
|
||||
}
|
||||
|
||||
@@ -1,59 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,80 +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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
};
|
||||
|
||||
@@ -1,179 +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();
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
}
|
||||
|
||||
@@ -1,73 +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();
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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();
|
||||
};
|
||||
|
||||
@@ -1,337 +1,356 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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, [safeThis = WeakReference<BinaryResources> { this },
|
||||
resourceToReplace,
|
||||
callback] (const FileChooser& fc)
|
||||
{
|
||||
if (safeThis == nullptr)
|
||||
{
|
||||
if (callback != nullptr)
|
||||
callback ({});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const auto result = fc.getResult();
|
||||
|
||||
auto resourceName = [safeThis, result, resourceToReplace]() -> String
|
||||
{
|
||||
if (result == File())
|
||||
return {};
|
||||
|
||||
if (resourceToReplace.isEmpty())
|
||||
return safeThis->findUniqueName (result.getFileName());
|
||||
|
||||
return resourceToReplace;
|
||||
}();
|
||||
|
||||
if (resourceName.isNotEmpty())
|
||||
{
|
||||
if (! safeThis->add (resourceName, result))
|
||||
{
|
||||
AlertWindow::showMessageBoxAsync (MessageBoxIconType::WarningIcon,
|
||||
TRANS("Adding Resource"),
|
||||
TRANS("Failed to load the file!"));
|
||||
|
||||
resourceName.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (callback != nullptr)
|
||||
callback (resourceName);
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +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
|
||||
|
||||
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;
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_WEAK_REFERENCEABLE (BinaryResources)
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,138 +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);
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
|
||||
@@ -1,348 +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);
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
|
||||
@@ -1,95 +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)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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)
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,180 +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)
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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)
|
||||
};
|
||||
|
||||
@@ -1,163 +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;
|
||||
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,47 +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);
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,122 +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);
|
||||
};
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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);
|
||||
};
|
||||
|
||||
@@ -1,118 +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));
|
||||
}
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2022 - 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 7 End-User License
|
||||
Agreement and JUCE Privacy Policy.
|
||||
|
||||
End User License Agreement: www.juce.com/juce-7-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