1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-02 03:20:06 +00:00

Projucer: Added some layout features to the GUI editor to allow alignment of selected components and paint elements and multi-select positioning and resizing

This commit is contained in:
ed 2017-07-31 17:24:57 +01:00
parent 52fb43b1a7
commit b1ea737d54
43 changed files with 971 additions and 294 deletions

View file

@ -36,25 +36,30 @@ public:
defaultWidth_, defaultHeight_)
{}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
Button* const b = dynamic_cast<Button*> (component);
if (multipleSelected)
return;
props.add (new ButtonTextProperty (b, document));
if (auto* b = dynamic_cast<Button*> (component))
{
props.add (new ButtonTextProperty (b, document));
props.add (new ButtonCallbackProperty (b, document));
props.add (new ButtonCallbackProperty (b, document));
props.add (new ButtonRadioGroupProperty (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));
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)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
Button* const b = dynamic_cast<Button*> (comp);
@ -67,7 +72,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
Button* const b = dynamic_cast<Button*> (comp);
@ -82,12 +87,12 @@ public:
return true;
}
String getCreationParameters (GeneratedCode&, Component* component)
String getCreationParameters (GeneratedCode&, Component* component) override
{
return quotedString (component->getName(), false);
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
@ -131,7 +136,7 @@ public:
code.constructorCode << memberVariableName << "->addListener (this);\n";
}
void fillInGeneratedCode (Component* component, GeneratedCode& code)
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
{
ComponentTypeHandler::fillInGeneratedCode (component, code);

View file

@ -31,12 +31,12 @@ public:
: ComponentTypeHandler ("Combo Box", "ComboBox", typeid (ComboBox), 150, 24)
{}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new ComboBox ("new combo box");
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
ComboBox* const c = dynamic_cast<ComboBox*> (comp);
jassert (c != nullptr);
@ -52,7 +52,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -73,26 +73,30 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
ComboBox* const c = dynamic_cast<ComboBox*> (component);
jassert (c != nullptr);
if (multipleSelected)
return;
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));
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)
String getCreationParameters (GeneratedCode&, Component* component) override
{
return quotedString (component->getName(), false);
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
@ -126,7 +130,7 @@ public:
code.constructorCode += s;
}
void fillInGeneratedCode (Component* component, GeneratedCode& code)
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
{
ComponentTypeHandler::fillInGeneratedCode (component, code);

View file

@ -78,7 +78,7 @@ ComponentOverlayComponent* ComponentTypeHandler::createOverlayComponent (Compone
static void dummyMenuCallback (int, int) {}
void ComponentTypeHandler::showPopupMenu (Component*, ComponentLayout&)
void ComponentTypeHandler::showPopupMenu (Component*, ComponentLayout& layout)
{
PopupMenu m;
@ -87,6 +87,16 @@ void ComponentTypeHandler::showPopupMenu (Component*, ComponentLayout&)
m.addCommandItem (commandManager, JucerCommandIDs::toFront);
m.addCommandItem (commandManager, JucerCommandIDs::toBack);
m.addSeparator();
if (layout.getSelectedSet().getNumSelected() > 1)
{
m.addCommandItem (commandManager, JucerCommandIDs::alignTop);
m.addCommandItem (commandManager, JucerCommandIDs::alignRight);
m.addCommandItem (commandManager, JucerCommandIDs::alignBottom);
m.addCommandItem (commandManager, JucerCommandIDs::alignLeft);
m.addSeparator();
}
m.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
m.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
m.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);
@ -346,7 +356,12 @@ public:
void setPosition (const RelativePositionedRectangle& newPos)
{
document.getComponentLayout()->setComponentPosition (component, newPos, true);
auto* layout = document.getComponentLayout();
if (layout->getSelectedSet().getNumSelected() > 1)
positionOtherSelectedComponents (ComponentTypeHandler::getComponentPosition (component), newPos);
layout->setComponentPosition (component, newPos, true);
}
RelativePositionedRectangle getPosition() const
@ -356,6 +371,41 @@ public:
private:
JucerDocument& document;
void positionOtherSelectedComponents (const RelativePositionedRectangle& oldPos, const RelativePositionedRectangle& newPos)
{
for (auto* s : document.getComponentLayout()->getSelectedSet())
{
if (s != component)
{
auto currentPos = ComponentTypeHandler::getComponentPosition (s);
auto diff = 0.0;
if (dimension == ComponentPositionDimension::componentX)
{
diff = newPos.rect.getX() - oldPos.rect.getX();
currentPos.rect.setX (currentPos.rect.getX() + diff);
}
else if (dimension == ComponentPositionDimension::componentY)
{
diff = newPos.rect.getY() - oldPos.rect.getY();
currentPos.rect.setY (currentPos.rect.getY() + diff);
}
else if (dimension == ComponentPositionDimension::componentWidth)
{
diff = newPos.rect.getWidth() - oldPos.rect.getWidth();
currentPos.rect.setWidth (currentPos.rect.getWidth() + diff);
}
else if (dimension == ComponentPositionDimension::componentHeight)
{
diff = newPos.rect.getHeight() - oldPos.rect.getHeight();
currentPos.rect.setHeight (currentPos.rect.getHeight() + diff);
}
document.getComponentLayout()->setComponentPosition (s, currentPos, true);
}
}
}
};
@ -413,27 +463,32 @@ private:
//==============================================================================
void ComponentTypeHandler::getEditableProperties (Component* component,
JucerDocument& document,
Array<PropertyComponent*>& props)
Array<PropertyComponent*>& props,
bool multipleSelected)
{
props.add (new ComponentMemberNameProperty (component, document));
props.add (new ComponentNameProperty (component, document));
props.add (new ComponentVirtualClassProperty (component, document));
if (! multipleSelected)
{
props.add (new ComponentMemberNameProperty (component, document));
props.add (new ComponentNameProperty (component, document));
props.add (new ComponentVirtualClassProperty (component, document));
if (dynamic_cast<SettableTooltipClient*> (component) != nullptr)
props.add (new TooltipProperty (component, document));
props.add (new FocusOrderProperty (component, document));
}
props.add (new ComponentPositionProperty (component, document, "x", ComponentPositionProperty::componentX));
props.add (new ComponentPositionProperty (component, document, "y", ComponentPositionProperty::componentY));
props.add (new ComponentPositionProperty (component, document, "width", ComponentPositionProperty::componentWidth));
props.add (new ComponentPositionProperty (component, document, "height", ComponentPositionProperty::componentHeight));
if (dynamic_cast<SettableTooltipClient*> (component) != nullptr)
props.add (new TooltipProperty (component, document));
props.add (new FocusOrderProperty (component, document));
}
void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, JucerDocument& document, PropertyPanel& panel)
void ComponentTypeHandler::addPropertiesToPropertyPanel (Component* comp, JucerDocument& document,
PropertyPanel& panel, bool multipleSelected)
{
Array <PropertyComponent*> props;
getEditableProperties (comp, document, props);
getEditableProperties (comp, document, props, multipleSelected);
panel.addSection (getClassName (comp), props);
}

View file

@ -63,11 +63,13 @@ public:
virtual void getEditableProperties (Component* component,
JucerDocument& document,
Array<PropertyComponent*>& props);
Array<PropertyComponent*>& props,
bool multipleSelected);
virtual void addPropertiesToPropertyPanel (Component* component,
JucerDocument& document,
PropertyPanel& panel);
PropertyPanel& panel,
bool multipleSelected);
void registerEditableColour (int colourId,

View file

@ -75,12 +75,12 @@ public:
: ComponentTypeHandler ("Generic Component", "GenericComponent", typeid (GenericComponent), 150, 24)
{}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new GenericComponent();
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
e->setAttribute ("class", ((GenericComponent*) comp)->actualClassName);
@ -89,7 +89,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -99,25 +99,29 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
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
String getClassName (Component* comp) const override
{
return static_cast<GenericComponent*> (comp)->actualClassName;
}
String getCreationParameters (GeneratedCode&, Component* comp)
String getCreationParameters (GeneratedCode&, Component* comp) override
{
return static_cast<GenericComponent*> (comp)->constructorParams;
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -34,12 +34,12 @@ public:
registerColour (GroupComponent::textColourId, "text", "textcol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new GroupComponent ("new group", "group");
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
GroupComponent* const g = (GroupComponent*) comp;
@ -54,7 +54,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
GroupComponent* const g = (GroupComponent*) comp;
@ -67,7 +67,7 @@ public:
return true;
}
String getCreationParameters (GeneratedCode& code, Component* component)
String getCreationParameters (GeneratedCode& code, Component* component) override
{
GroupComponent* g = dynamic_cast<GroupComponent*> (component);
@ -76,7 +76,7 @@ public:
+ quotedString (g->getText(), code.shouldUseTransMacro());
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
@ -99,12 +99,19 @@ public:
code.constructorCode += s;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
props.add (new GroupTitleProperty ((GroupComponent*) component, document));
props.add (new GroupJustificationProperty ((GroupComponent*) component, document));
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);
}

View file

@ -33,7 +33,7 @@ public:
registerColour (HyperlinkButton::textColourId, "text", "textCol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
HyperlinkButton* hb = new HyperlinkButton ("new hyperlink", URL ("http://www.juce.com"));
@ -41,15 +41,21 @@ public:
return hb;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
HyperlinkButton* const hb = (HyperlinkButton*) component;
ButtonHandler::getEditableProperties (component, document, props);
props.add (new HyperlinkURLProperty (hb, document));
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)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
HyperlinkButton* const hb = (HyperlinkButton*) comp;
XmlElement* const e = ButtonHandler::createXmlFor (comp, layout);
@ -57,7 +63,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
HyperlinkButton* const hb = (HyperlinkButton*) comp;
@ -69,7 +75,7 @@ public:
return true;
}
String getCreationParameters (GeneratedCode& code, Component* comp)
String getCreationParameters (GeneratedCode& code, Component* comp) override
{
HyperlinkButton* const hb = dynamic_cast<HyperlinkButton*> (comp);
@ -79,7 +85,7 @@ public:
+ ")";
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ButtonHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -40,37 +40,42 @@ public:
{
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new ImageButton ("new button");
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ButtonHandler::getEditableProperties (component, document, props);
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
if (multipleSelected)
return;
addColourProperties (component, document, props);
ImageButton* const ib = (ImageButton*) component;
if (auto* ib = dynamic_cast<ImageButton*> (component))
{
auto& layout = *document.getComponentLayout();
ComponentLayout& layout = *document.getComponentLayout();
props.add (new ImageButtonProportionProperty (layout, ib));
props.add (new ImageButtonProportionProperty (layout, ib));
props.add (new ImageButtonResourceProperty (layout, ib, normalImage, "normal image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", normalImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", normalImage));
props.add (new ImageButtonResourceProperty (layout, ib, normalImage, "normal image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", normalImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", normalImage));
props.add (new ImageButtonResourceProperty (layout, ib, overImage, "over image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", overImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", overImage));
props.add (new ImageButtonResourceProperty (layout, ib, overImage, "over image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", overImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", overImage));
props.add (new ImageButtonResourceProperty (layout, ib, downImage, "down image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", downImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", downImage));
props.add (new ImageButtonResourceProperty (layout, ib, downImage, "down image"));
props.add (new ImageButtonOpacityProperty (layout, ib, "opacity", downImage));
props.add (new ImageButtonColourProperty (layout, ib, "overlay col.", downImage));
}
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
XmlElement* e = ButtonHandler::createXmlFor (comp, layout);
@ -93,7 +98,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ButtonHandler::restoreFromXml (xml, comp, layout))
return false;
@ -118,7 +123,7 @@ public:
return true;
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ButtonHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -42,14 +42,14 @@ public:
typeid (TestComponent), 300, 200)
{}
Component* createNewComponent (JucerDocument* doc)
Component* createNewComponent (JucerDocument* doc) override
{
return new TestComponent (doc, 0, false);
}
String getXmlTagName() const noexcept { return "JUCERCOMP"; }
String getXmlTagName() const noexcept override { return "JUCERCOMP"; }
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
TestComponent* const tc = dynamic_cast<TestComponent*> (comp);
@ -60,7 +60,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
TestComponent* const tc = dynamic_cast<TestComponent*> (comp);
@ -73,7 +73,7 @@ public:
return true;
}
String getClassName (Component* comp) const
String getClassName (Component* comp) const override
{
TestComponent* const tc = dynamic_cast<TestComponent*> (comp);
@ -88,23 +88,28 @@ public:
return jucerCompClassName;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
TestComponent* const tc = dynamic_cast<TestComponent*> (component);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
ComponentTypeHandler::getEditableProperties (component, document, props);
if (multipleSelected)
return;
props.add (new JucerCompFileProperty (tc, document));
props.add (new ConstructorParamsProperty (tc, document));
props.add (new JucerCompOpenDocProperty (tc));
if (auto* const 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)
String getCreationParameters (GeneratedCode&, Component* component) override
{
return dynamic_cast<TestComponent*> (component)->getConstructorParams().trim();
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -38,12 +38,12 @@ public:
registerColour (TextEditor::highlightColourId, "highlight", "hiliteCol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new Label ("new label", "label text");
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
Label* const l = dynamic_cast<Label*> (comp);
@ -68,7 +68,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
Label* const l = dynamic_cast<Label*> (comp);
@ -109,7 +109,7 @@ public:
label->setFont (f);
}
String getCreationParameters (GeneratedCode& code, Component* component)
String getCreationParameters (GeneratedCode& code, Component* component) override
{
Label* const l = dynamic_cast<Label*> (component);
@ -118,7 +118,7 @@ public:
+ quotedString (l->getText(), code.shouldUseTransMacro());
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);
@ -146,7 +146,7 @@ public:
code.constructorCode += s;
}
void fillInGeneratedCode (Component* component, GeneratedCode& code)
void fillInGeneratedCode (Component* component, GeneratedCode& code) override
{
ComponentTypeHandler::fillInGeneratedCode (component, code);
@ -169,24 +169,30 @@ public:
}
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
Label* const l = dynamic_cast<Label*> (component);
props.add (new LabelTextProperty (l, document));
props.add (new LabelJustificationProperty (l, document));
props.add (new FontNameProperty (l, document));
props.add (new FontStyleProperty (l, document));
props.add (new FontSizeProperty (l, document));
props.add (new FontKerningProperty (l, document));
if (multipleSelected)
return;
if (auto* const l = dynamic_cast<Label*> (component))
{
props.add (new LabelTextProperty (l, document));
props.add (new LabelJustificationProperty (l, document));
props.add (new FontNameProperty (l, document));
props.add (new FontStyleProperty (l, document));
props.add (new FontSizeProperty (l, document));
props.add (new FontKerningProperty (l, document));
props.add (new LabelEditableProperty (l, document));
if (l->isEditableOnDoubleClick() || l->isEditableOnSingleClick())
props.add (new LabelLossOfFocusProperty (l, document));
}
addColourProperties (component, document, props);
props.add (new LabelEditableProperty (l, document));
if (l->isEditableOnDoubleClick() || l->isEditableOnSingleClick())
props.add (new LabelLossOfFocusProperty (l, document));
}
static bool needsCallback (Component* label)

View file

@ -172,23 +172,27 @@ struct SliderHandler : public ComponentTypeHandler
}
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props) override
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
Slider* s = dynamic_cast<Slider*> (component);
jassert (s != 0);
if (multipleSelected)
return;
props.add (new SliderRangeProperty (s, document, "minimum", 0));
props.add (new SliderRangeProperty (s, document, "maximum", 1));
props.add (new SliderRangeProperty (s, document, "interval", 2));
props.add (new SliderTypeProperty (s, document));
props.add (new SliderTextboxProperty (s, document));
props.add (new SliderTextboxEditableProperty (s, document));
props.add (new SliderTextboxSizeProperty (s, document, true));
props.add (new SliderTextboxSizeProperty (s, document, false));
props.add (new SliderSkewProperty (s, document));
props.add (new SliderCallbackProperty (s, document));
if (auto* s = dynamic_cast<Slider*> (component))
{
props.add (new SliderRangeProperty (s, document, "minimum", 0));
props.add (new SliderRangeProperty (s, document, "maximum", 1));
props.add (new SliderRangeProperty (s, document, "interval", 2));
props.add (new SliderTypeProperty (s, document));
props.add (new SliderTextboxProperty (s, document));
props.add (new SliderTextboxEditableProperty (s, document));
props.add (new SliderTextboxSizeProperty (s, document, true));
props.add (new SliderTextboxSizeProperty (s, document, false));
props.add (new SliderSkewProperty (s, document));
props.add (new SliderCallbackProperty (s, document));
}
addColourProperties (component, document, props);
}

View file

@ -31,7 +31,7 @@ public:
: ComponentTypeHandler ("Tabbed Component", "TabbedComponent", typeid (TabbedComponent), 200, 150)
{}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
TabbedComponent* const t = new TabbedComponent (TabbedButtonBar::TabsAtTop);
t->setName ("new tabbed component");
@ -42,7 +42,7 @@ public:
return t;
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
TabbedComponent* const t = dynamic_cast<TabbedComponent*> (comp);
XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
@ -61,7 +61,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -90,27 +90,33 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& doc, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& doc,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, doc, props);
ComponentTypeHandler::getEditableProperties (component, doc, props, multipleSelected);
TabbedComponent* const t = dynamic_cast<TabbedComponent*> (component);
if (multipleSelected)
return;
props.add (new TabOrientationProperty (t, doc));
props.add (new TabDepthProperty (t, doc));
if (auto* t = dynamic_cast<TabbedComponent*> (component))
{
props.add (new TabOrientationProperty (t, doc));
props.add (new TabDepthProperty (t, doc));
if (t->getNumTabs() > 0)
props.add (new TabInitialTabProperty (t, doc));
if (t->getNumTabs() > 0)
props.add (new TabInitialTabProperty (t, doc));
props.add (new TabAddTabProperty (t, doc));
props.add (new TabAddTabProperty (t, doc));
if (t->getNumTabs() > 0)
props.add (new TabRemoveTabProperty (t, doc));
if (t->getNumTabs() > 0)
props.add (new TabRemoveTabProperty (t, doc));
}
}
void addPropertiesToPropertyPanel (Component* comp, JucerDocument& doc, PropertyPanel& panel)
void addPropertiesToPropertyPanel (Component* comp, JucerDocument& doc,
PropertyPanel& panel, bool multipleSelected) override
{
ComponentTypeHandler::addPropertiesToPropertyPanel (comp, doc, panel);
ComponentTypeHandler::addPropertiesToPropertyPanel (comp, doc, panel, multipleSelected);
TabbedComponent* const t = dynamic_cast<TabbedComponent*> (comp);
@ -136,7 +142,7 @@ public:
}
}
String getCreationParameters (GeneratedCode&, Component* comp)
String getCreationParameters (GeneratedCode&, Component* comp) override
{
TabbedComponent* const t = dynamic_cast<TabbedComponent*> (comp);
@ -152,7 +158,7 @@ public:
return {};
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
TabbedComponent* const t = dynamic_cast<TabbedComponent*> (component);

View file

@ -36,28 +36,33 @@ public:
registerColour (TextButton::textColourOnId, "text colour (on)", "textColOn");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new TextButton ("new button", String());
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ButtonHandler::getEditableProperties (component, document, props);
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
if (multipleSelected)
return;
addColourProperties (component, document, props);
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
return ButtonHandler::createXmlFor (comp, layout);
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* 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)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ButtonHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -38,12 +38,12 @@ public:
registerColour (CaretComponent::caretColourId, "caret", "caretcol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new TextEditor ("new text editor");
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
XmlElement* e = ComponentTypeHandler::createXmlFor (comp, layout);
TextEditor* te = (TextEditor*) comp;
@ -60,7 +60,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -81,29 +81,33 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
TextEditor* const t = dynamic_cast<TextEditor*> (component);
jassert (t != nullptr);
if (multipleSelected)
return;
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));
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);
addColourProperties (t, document, props);
}
}
String getCreationParameters (GeneratedCode&, Component* component)
String getCreationParameters (GeneratedCode&, Component* component) override
{
return quotedString (component->getName(), false);
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ComponentTypeHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -33,21 +33,26 @@ public:
registerColour (ToggleButton::textColourId, "text colour", "txtcol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new ToggleButton ("new toggle button");
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ButtonHandler::getEditableProperties (component, document, props);
ButtonHandler::getEditableProperties (component, document, props, multipleSelected);
props.add (new ToggleButtonStateProperty ((ToggleButton*) component, document));
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)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
ToggleButton* tb = (ToggleButton*) comp;
@ -57,7 +62,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
ToggleButton* const tb = (ToggleButton*) comp;
@ -68,7 +73,7 @@ public:
return true;
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
ButtonHandler::fillInCreationCode (code, component, memberVariableName);

View file

@ -34,12 +34,12 @@ public:
registerColour (TreeView::linesColourId, "lines", "linecol");
}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
return new DemoTreeView();
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
TreeView* const t = dynamic_cast<TreeView*> (comp);
XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
@ -50,7 +50,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -64,10 +64,15 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
TreeView* const t = dynamic_cast<TreeView*> (component);
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));
@ -75,12 +80,12 @@ public:
addColourProperties (t, document, props);
}
String getCreationParameters (GeneratedCode&, Component* comp)
String getCreationParameters (GeneratedCode&, Component* comp) override
{
return quotedString (comp->getName(), false);
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
TreeView defaultTreeView;
TreeView* const t = dynamic_cast<TreeView*> (component);

View file

@ -31,7 +31,7 @@ public:
: ComponentTypeHandler ("Viewport", "Viewport", typeid (UpdatingViewport), 150, 150)
{}
Component* createNewComponent (JucerDocument*)
Component* createNewComponent (JucerDocument*) override
{
Viewport* const v = new UpdatingViewport ("new viewport");
v->setViewedComponent (new ViewportDemoContentComp());
@ -39,7 +39,7 @@ public:
return v;
}
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout)
XmlElement* createXmlFor (Component* comp, const ComponentLayout* layout) override
{
Viewport* const v = dynamic_cast<Viewport*> (comp);
XmlElement* const e = ComponentTypeHandler::createXmlFor (comp, layout);
@ -56,7 +56,7 @@ public:
return e;
}
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout)
bool restoreFromXml (const XmlElement& xml, Component* comp, const ComponentLayout* layout) override
{
if (! ComponentTypeHandler::restoreFromXml (xml, comp, layout))
return false;
@ -76,11 +76,15 @@ public:
return true;
}
void getEditableProperties (Component* component, JucerDocument& document, Array<PropertyComponent*>& props)
void getEditableProperties (Component* component, JucerDocument& document,
Array<PropertyComponent*>& props, bool multipleSelected) override
{
ComponentTypeHandler::getEditableProperties (component, document, props);
ComponentTypeHandler::getEditableProperties (component, document, props, multipleSelected);
Viewport* const v = dynamic_cast<Viewport*> (component);
if (multipleSelected)
return;
auto* v = dynamic_cast<Viewport*> (component);
props.add (new ViewportScrollbarShownProperty (v, document, true));
props.add (new ViewportScrollbarShownProperty (v, document, false));
@ -99,12 +103,12 @@ public:
}
}
String getCreationParameters (GeneratedCode&, Component* comp)
String getCreationParameters (GeneratedCode&, Component* comp) override
{
return quotedString (comp->getName(), false);
}
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName)
void fillInCreationCode (GeneratedCode& code, Component* component, const String& memberVariableName) override
{
Viewport defaultViewport;
Viewport* const v = dynamic_cast<Viewport*> (component);

View file

@ -331,6 +331,68 @@ void ComponentLayout::selectedToBack()
componentToBack (temp.getSelectedItem(i), true);
}
void ComponentLayout::alignTop()
{
if (selected.getNumSelected() > 1)
{
auto* main = selected.getSelectedItem (0);
auto yPos = main->getY();
for (auto* other : selected)
{
if (other != main)
setComponentBoundsAndProperties (other,
other->getBounds().withPosition (other->getX(), yPos),
main, true);
}
}
}
void ComponentLayout::alignRight()
{
if (selected.getNumSelected() > 1)
{
auto* main = selected.getSelectedItem (0);
auto rightPos = main->getRight();
for (auto* other : selected)
{
if (other != main)
setComponentBoundsAndProperties (other, other->getBounds().withPosition (rightPos - other->getWidth(), other->getY()), main, true);
}
}
}
void ComponentLayout::alignBottom()
{
if (selected.getNumSelected() > 1)
{
auto* main = selected.getSelectedItem (0);
auto bottomPos = main->getBottom();
for (auto* other : selected)
{
if (other != main)
setComponentBoundsAndProperties (other, other->getBounds().withPosition (other->getX(), bottomPos - other->getHeight()), main, true);
}
}
}
void ComponentLayout::alignLeft()
{
if (selected.getNumSelected() > 1)
{
auto* main = selected.getSelectedItem (0);
auto xPos = main->getX();
for (auto* other : selected)
{
if (other != main)
setComponentBoundsAndProperties (other, other->getBounds().withPosition (xPos, other->getY()), main, true);
}
}
}
void ComponentLayout::bringLostItemsBackOnScreen (int width, int height)
{
for (int i = components.size(); --i >= 0;)
@ -558,6 +620,42 @@ private:
RelativePositionedRectangle newPos, oldPos;
};
class ChangeCompBoundsAndPropertiesAction : public ComponentUndoableAction<Component>
{
public:
ChangeCompBoundsAndPropertiesAction (Component* const comp, ComponentLayout& l,
const Rectangle<int>& bounds, const NamedValueSet& props)
: ComponentUndoableAction <Component> (comp, l),
newBounds (bounds),
oldBounds (comp->getBounds()),
newProps (props),
oldProps(comp->getProperties())
{
}
bool perform()
{
showCorrectTab();
getComponent()->setBounds (newBounds);
getComponent()->getProperties() = newProps;
layout.updateStoredComponentPosition (getComponent(), false);
return true;
}
bool undo()
{
showCorrectTab();
getComponent()->setBounds (oldBounds);
getComponent()->getProperties() = oldProps;
layout.updateStoredComponentPosition (getComponent(), false);
return true;
}
private:
Rectangle<int> newBounds, oldBounds;
NamedValueSet newProps, oldProps;
};
void ComponentLayout::setComponentPosition (Component* comp,
const RelativePositionedRectangle& newPos,
const bool undoable)
@ -576,6 +674,42 @@ void ComponentLayout::setComponentPosition (Component* comp,
}
}
void ComponentLayout::setComponentBoundsAndProperties (Component* componentToPosition, const Rectangle<int>& newBounds,
Component* referenceComponent, const bool undoable)
{
auto props = NamedValueSet (componentToPosition->getProperties());
auto rect = ComponentTypeHandler::getComponentPosition (componentToPosition).rect;
auto referenceComponentPosition = ComponentTypeHandler::getComponentPosition (referenceComponent);
auto referenceComponentRect = referenceComponentPosition.rect;
rect.setModes (referenceComponentRect.getAnchorPointX(), referenceComponentRect.getPositionModeX(),
referenceComponentRect.getAnchorPointY(), referenceComponentRect.getPositionModeY(),
referenceComponentRect.getWidthMode(), referenceComponentRect.getHeightMode(),
componentToPosition->getBounds());
props.set ("pos", rect.toString());
props.set ("relativeToX", String::toHexString (referenceComponentPosition.relativeToX));
props.set ("relativeToY", String::toHexString (referenceComponentPosition.relativeToY));
props.set ("relativeToW", String::toHexString (referenceComponentPosition.relativeToW));
props.set ("relativeToH", String::toHexString (referenceComponentPosition.relativeToH));
if (componentToPosition->getBounds() != newBounds || componentToPosition->getProperties() != props)
{
if (undoable)
{
perform (new ChangeCompBoundsAndPropertiesAction (componentToPosition, *this, newBounds, props), "Change component bounds");
}
else
{
componentToPosition->setBounds (newBounds);
componentToPosition->getProperties() = props;
updateStoredComponentPosition (componentToPosition, false);
changed();
}
}
}
void ComponentLayout::updateStoredComponentPosition (Component* comp, const bool undoable)
{
RelativePositionedRectangle newPos (ComponentTypeHandler::getComponentPosition (comp));

View file

@ -65,6 +65,7 @@ public:
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);
//==============================================================================
@ -96,6 +97,11 @@ public:
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();

View file

@ -221,6 +221,15 @@ void JucerDocument::setInitialSize (int w, int h)
}
}
void JucerDocument::setLastSelectedTabIndex (int index)
{
if (index != lastTab)
{
lastTab = index;
flushChangesToDocuments (nullptr);
}
}
//==============================================================================
bool JucerDocument::isSnapActive (const bool disableIfCtrlKeyDown) const noexcept
{
@ -350,6 +359,7 @@ XmlElement* JucerDocument::createXml() const
doc->setAttribute ("fixedSize", fixedSize);
doc->setAttribute ("initialWidth", initialWidth);
doc->setAttribute ("initialHeight", initialHeight);
doc->setAttribute ("lastSelectedTab", lastTab);
if (activeExtraMethods.size() > 0)
{
@ -382,6 +392,7 @@ bool JucerDocument::loadFromXml (const XmlElement& xml)
fixedSize = xml.getBoolAttribute ("fixedSize", false);
initialWidth = xml.getIntAttribute ("initialWidth", 300);
initialHeight = xml.getIntAttribute ("initialHeight", 200);
lastTab = xml.getIntAttribute ("lastSelectedTab", 1);
snapGridPixels = xml.getIntAttribute ("snapPixels", snapGridPixels);
snapActive = xml.getBoolAttribute ("snapActive", snapActive);

View file

@ -93,6 +93,9 @@ public:
int getInitialWidth() const noexcept { return initialWidth; }
int getInitialHeight() const noexcept { return initialHeight; }
void setLastSelectedTabIndex (int index);
int getLastSelectedTabIndex() const noexcept { return lastTab; }
//==============================================================================
virtual int getNumPaintRoutines() const = 0;
virtual StringArray getPaintRoutineNames() const = 0;
@ -147,6 +150,7 @@ protected:
bool fixedSize = false;
int initialWidth = 600, initialHeight = 400;
int lastTab = 1;
BinaryResources resources;

View file

@ -376,6 +376,68 @@ void PaintRoutine::selectedToBack()
elementToBack (temp.getSelectedItem(i), true);
}
void PaintRoutine::alignTop()
{
if (selectedElements.getNumSelected() > 1)
{
auto* main = selectedElements.getSelectedItem (0);
auto yPos = main->getY();
for (auto* other : selectedElements)
{
if (other != main)
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (other->getX(),
yPos), main, true);
}
}
}
void PaintRoutine::alignRight()
{
if (selectedElements.getNumSelected() > 1)
{
auto* main = selectedElements.getSelectedItem (0);
auto rightPos = main->getRight();
for (auto* other : selectedElements)
{
if (other != main)
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (rightPos - other->getWidth(),
other->getY()), main, true);
}
}
}
void PaintRoutine::alignBottom()
{
if (selectedElements.getNumSelected() > 1)
{
auto* main = selectedElements.getSelectedItem (0);
auto bottomPos = main->getBottom();
for (auto* other : selectedElements)
{
if (other != main)
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (other->getX(),
bottomPos - other->getHeight()), main, true);
}
}
}
void PaintRoutine::alignLeft()
{
if (selectedElements.getNumSelected() > 1)
{
auto* main = selectedElements.getSelectedItem (0);
auto xPos = main->getX();
for (auto* other : selectedElements)
{
if (other != main)
other->setPaintElementBoundsAndProperties (other, other->getBounds().withPosition (xPos,
other->getY()), main, true);
}
}
}
void PaintRoutine::groupSelected()
{
PaintElementGroup::groupSelected (this);

View file

@ -83,6 +83,11 @@ public:
void selectedToFront();
void selectedToBack();
void alignTop();
void alignRight();
void alignBottom();
void alignLeft();
void groupSelected();
void ungroupSelected();

View file

@ -88,7 +88,7 @@ inline void drawResizableBorder (Graphics& g, int w, int h,
const bool isMouseOver,
Colour borderColour)
{
g.setColour (borderColour.withAlpha (isMouseOver ? 0.6f : 0.5f));
g.setColour (borderColour);
g.fillRect (0, 0, w, borderSize.getTop());
g.fillRect (0, 0, borderSize.getLeft(), h);

View file

@ -506,10 +506,12 @@ ColouredElement::~ColouredElement()
}
//==============================================================================
void ColouredElement::getEditableProperties (Array <PropertyComponent*>& props)
void ColouredElement::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
{
PaintElement::getEditableProperties (props);
getColourSpecificProperties (props);
PaintElement::getEditableProperties (props, multipleSelected);
if (! multipleSelected)
getColourSpecificProperties (props);
}
void ColouredElement::getColourSpecificProperties (Array <PropertyComponent*>& props)

View file

@ -47,7 +47,7 @@ public:
~ColouredElement();
//==============================================================================
void getEditableProperties (Array<PropertyComponent*>& props);
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override;
void getColourSpecificProperties (Array<PropertyComponent*>& props);
//==============================================================================
@ -62,10 +62,10 @@ public:
void setStrokeFill (const JucerFillType& newType, const bool undoable);
//==============================================================================
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const;
void setCurrentBounds (const Rectangle<int>& newBounds, const Rectangle<int>& parentArea, 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();
void createSiblingComponents() override;
//==============================================================================
void addColourAttributes (XmlElement* const e) const;

View file

@ -118,6 +118,74 @@ public:
RelativePositionedRectangle newState, oldState;
};
class ChangePaintElementBoundsAction : public PaintElementUndoableAction <PaintElement>
{
public:
ChangePaintElementBoundsAction (PaintElement* const element, const Rectangle<int>& bounds)
: PaintElementUndoableAction <PaintElement> (element),
newBounds (bounds),
oldBounds (element->getBounds())
{
}
bool perform()
{
showCorrectTab();
getElement()->setBounds (newBounds);
return true;
}
bool undo()
{
showCorrectTab();
getElement()->setBounds (oldBounds);
return true;
}
private:
Rectangle<int> newBounds, oldBounds;
};
class ChangePaintElementBoundsAndPropertiesAction : public PaintElementUndoableAction <PaintElement>
{
public:
ChangePaintElementBoundsAndPropertiesAction (PaintElement* const element, const Rectangle<int>& bounds,
const NamedValueSet& props)
: PaintElementUndoableAction <PaintElement> (element),
newBounds (bounds),
oldBounds (element->getBounds()),
newProps (props),
oldProps (element->getProperties())
{
}
bool perform()
{
showCorrectTab();
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getElement()->getParentComponent()))
getElement()->setCurrentBounds (newBounds, pe->getComponentArea(), false);
getElement()->getProperties() = newProps;
return true;
}
bool undo()
{
showCorrectTab();
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getElement()->getParentComponent()))
getElement()->setCurrentBounds (oldBounds, pe->getComponentArea(), false);
getElement()->getProperties() = oldProps;
return true;
}
private:
Rectangle<int> newBounds, oldBounds;
NamedValueSet newProps, oldProps;
};
void PaintElement::setPosition (const RelativePositionedRectangle& newPosition, const bool undoable)
{
if (position != newPosition)
@ -137,6 +205,60 @@ void PaintElement::setPosition (const RelativePositionedRectangle& newPosition,
}
}
void PaintElement::setPaintElementBounds (const Rectangle<int>& newBounds, const bool undoable)
{
if (getBounds() != newBounds)
{
if (undoable)
{
perform (new ChangePaintElementBoundsAction (this, newBounds), "Change paint element bounds");
}
else
{
setBounds (newBounds);
changed();
}
}
}
void PaintElement::setPaintElementBoundsAndProperties (PaintElement* elementToPosition, const Rectangle<int>& newBounds,
PaintElement* referenceElement, const bool undoable)
{
auto props = NamedValueSet (elementToPosition->getProperties());
auto rect = elementToPosition->getPosition().rect;
auto referenceElementPosition = referenceElement->getPosition();
auto referenceElementRect = referenceElementPosition.rect;
rect.setModes (referenceElementRect.getAnchorPointX(), referenceElementRect.getPositionModeX(),
referenceElementRect.getAnchorPointY(), referenceElementRect.getPositionModeY(),
referenceElementRect.getWidthMode(), referenceElementRect.getHeightMode(),
elementToPosition->getBounds());
props.set ("pos", rect.toString());
props.set ("relativeToX", String::toHexString (referenceElementPosition.relativeToX));
props.set ("relativeToY", String::toHexString (referenceElementPosition.relativeToY));
props.set ("relativeToW", String::toHexString (referenceElementPosition.relativeToW));
props.set ("relativeToH", String::toHexString (referenceElementPosition.relativeToH));
if (elementToPosition->getBounds() != newBounds || elementToPosition->getProperties() != props)
{
if (undoable)
{
perform (new ChangePaintElementBoundsAndPropertiesAction (elementToPosition, newBounds, props),
"Change paint element bounds");
}
else
{
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (elementToPosition->getParentComponent()))
elementToPosition->setCurrentBounds (newBounds, pe->getComponentArea(), false);
elementToPosition->getProperties() = props;
owner->changed();
}
}
}
//==============================================================================
Rectangle<int> PaintElement::getCurrentBounds (const Rectangle<int>& parentArea) const
{
@ -181,13 +303,17 @@ public:
ComponentPositionDimension dimension_)
: PositionPropertyBase (e, name, dimension_, true, false,
e->getDocument()->getComponentLayout()),
listener (e)
listener (e),
element (e)
{
listener.setPropertyToRefresh (*this);
}
void setPosition (const RelativePositionedRectangle& newPos)
{
if (element->getOwner()->getSelectedElements().getNumSelected() > 1)
positionOtherSelectedElements (getPosition(), newPos);
listener.owner->setPosition (newPos, true);
}
@ -196,12 +322,51 @@ public:
return listener.owner->getPosition();
}
private:
ElementListener<PaintElement> listener;
PaintElement* element;
void positionOtherSelectedElements (const RelativePositionedRectangle& oldPos, const RelativePositionedRectangle& newPos)
{
for (auto* s : element->getOwner()->getSelectedElements())
{
if (s != element)
{
auto currentPos = s->getPosition();
auto diff = 0.0;
if (dimension == ComponentPositionDimension::componentX)
{
diff = newPos.rect.getX() - oldPos.rect.getX();
currentPos.rect.setX (currentPos.rect.getX() + diff);
}
else if (dimension == ComponentPositionDimension::componentY)
{
diff = newPos.rect.getY() - oldPos.rect.getY();
currentPos.rect.setY (currentPos.rect.getY() + diff);
}
else if (dimension == ComponentPositionDimension::componentWidth)
{
diff = newPos.rect.getWidth() - oldPos.rect.getWidth();
currentPos.rect.setWidth (currentPos.rect.getWidth() + diff);
}
else if (dimension == ComponentPositionDimension::componentHeight)
{
diff = newPos.rect.getHeight() - oldPos.rect.getHeight();
currentPos.rect.setHeight (currentPos.rect.getHeight() + diff);
}
s->setPosition (currentPos, true);
}
}
}
};
//==============================================================================
void PaintElement::getEditableProperties (Array <PropertyComponent*>& props)
void PaintElement::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
{
ignoreUnused (multipleSelected);
props.add (new ElementPositionProperty (this, "x", PositionPropertyBase::componentX));
props.add (new ElementPositionProperty (this, "y", PositionPropertyBase::componentY));
props.add (new ElementPositionProperty (this, "width", PositionPropertyBase::componentWidth));
@ -258,10 +423,11 @@ void PaintElement::paint (Graphics& g)
if (selected)
{
const BorderSize<int> borderSize (border->getBorderThickness());
auto baseColour = findColour (defaultHighlightColourId);
drawResizableBorder (g, getWidth(), getHeight(), borderSize,
(isMouseOverOrDragging() || border->isMouseOverOrDragging()),
findColour (defaultHighlightColourId));
baseColour.withAlpha (owner->getSelectedElements().getSelectedItem (0) == this ? 1.0f : 0.3f));
}
else if (isMouseOverOrDragging())
{
@ -405,9 +571,32 @@ void PaintElement::applyBoundsToComponent (Component&, Rectangle<int> newBounds)
{
getDocument()->getUndoManager().undoCurrentTransactionOnly();
auto dX = newBounds.getX() - getX();
auto dY = newBounds.getY() - getY();
auto dW = newBounds.getWidth() - getWidth();
auto dH = newBounds.getHeight() - getHeight();
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (getParentComponent()))
setCurrentBounds (newBounds.expanded (-borderThickness, -borderThickness),
pe->getComponentArea(), true);
pe->getComponentArea(), true);
if (owner->getSelectedElements().getNumSelected() > 1)
{
for (auto selectedElement : owner->getSelectedElements())
{
if (selectedElement != this)
{
if (auto* pe = dynamic_cast<PaintRoutineEditor*> (selectedElement->getParentComponent()))
{
Rectangle<int> r { selectedElement->getX() + dX, selectedElement->getY() + dY,
selectedElement->getWidth() + dW, selectedElement->getHeight() + dH };
selectedElement->setCurrentBounds (r.expanded (-borderThickness, -borderThickness),
pe->getComponentArea(), true);
}
}
}
}
}
}
@ -481,6 +670,16 @@ void PaintElement::showPopupMenu()
m.addCommandItem (commandManager, JucerCommandIDs::toFront);
m.addCommandItem (commandManager, JucerCommandIDs::toBack);
m.addSeparator();
if (owner->getSelectedElements().getNumSelected() > 1)
{
m.addCommandItem (commandManager, JucerCommandIDs::alignTop);
m.addCommandItem (commandManager, JucerCommandIDs::alignRight);
m.addCommandItem (commandManager, JucerCommandIDs::alignBottom);
m.addCommandItem (commandManager, JucerCommandIDs::alignLeft);
m.addSeparator();
}
m.addCommandItem (commandManager, StandardApplicationCommandIDs::cut);
m.addCommandItem (commandManager, StandardApplicationCommandIDs::copy);
m.addCommandItem (commandManager, StandardApplicationCommandIDs::paste);

View file

@ -56,6 +56,9 @@ public:
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);
@ -69,7 +72,7 @@ public:
virtual void drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo);
virtual void getEditableProperties (Array<PropertyComponent*>& props);
virtual void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected);
virtual void showPopupMenu();

View file

@ -38,7 +38,7 @@ public:
{
}
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
{
fillType.setFillType (g, getDocument(), parentArea);
@ -54,13 +54,13 @@ public:
}
}
void getEditableProperties (Array<PropertyComponent*>& props)
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
{
ColouredElement::getEditableProperties (props);
ColouredElement::getEditableProperties (props, multipleSelected);
props.add (new ShapeToPathProperty (this));
}
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
return;
@ -101,7 +101,7 @@ public:
paintMethodCode += s;
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
customPaintCode.clear();
@ -114,7 +114,7 @@ public:
static const char* getTagName() noexcept { return "ELLIPSE"; }
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* e = new XmlElement (getTagName());
position.applyToXml (*e);
@ -123,7 +123,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{

View file

@ -106,11 +106,11 @@ public:
}
//==============================================================================
void setInitialBounds (int /*parentWidth*/, int /*parentHeight*/)
void setInitialBounds (int /*parentWidth*/, int /*parentHeight*/) override
{
}
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const override
{
Rectangle<int> r;
@ -125,7 +125,7 @@ public:
return r;
}
void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable)
void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable) override
{
Rectangle<int> newBounds (b);
newBounds.setSize (jmax (1, newBounds.getWidth()),
@ -162,18 +162,19 @@ public:
}
//==============================================================================
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
{
for (int i = 0; i < subElements.size(); ++i)
subElements.getUnchecked(i)->draw (g, layout, parentArea);
}
void getEditableProperties (Array<PropertyComponent*>& props)
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
{
props.add (new UngroupProperty (this));
if (! multipleSelected)
props.add (new UngroupProperty (this));
}
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
for (int i = 0; i < subElements.size(); ++i)
subElements.getUnchecked(i)->fillInGeneratedCode (code, paintMethodCode);
@ -181,7 +182,7 @@ public:
static const char* getTagName() noexcept { return "GROUP"; }
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* e = new XmlElement (getTagName());
@ -194,7 +195,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{
@ -209,7 +210,7 @@ public:
return false;
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
for (auto* e : subElements)
e->applyCustomPaintSnippets (snippets);

View file

@ -58,7 +58,7 @@ public:
return nullptr;
}
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
{
const Rectangle<int> r (position.getRectangle (parentArea, layout));
@ -83,9 +83,9 @@ public:
}
//==============================================================================
void getEditableProperties (Array <PropertyComponent*>& props)
void getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected) override
{
PaintElement::getEditableProperties (props);
PaintElement::getEditableProperties (props, multipleSelected);
props.add (new ImageElementResourceProperty (this));
props.add (new StretchModeProperty (this));
@ -93,7 +93,7 @@ public:
props.add (new ResetSizeProperty (this));
}
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
if (opacity > 0)
{
@ -177,7 +177,7 @@ public:
}
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
customPaintCode.clear();
@ -362,7 +362,7 @@ public:
}
//==============================================================================
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* e = new XmlElement (getTagName());
position.applyToXml (*e);
@ -373,7 +373,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{

View file

@ -349,8 +349,11 @@ void PaintElementPath::pointListChanged()
}
//==============================================================================
void PaintElementPath::getEditableProperties (Array <PropertyComponent*>& props)
void PaintElementPath::getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected)
{
if (multipleSelected)
return;
props.add (new PathWindingModeProperty (this));
getColourSpecificProperties (props);
}
@ -1453,9 +1456,12 @@ void PathPoint::changePointType (const Path::Iterator::PathElementType newType,
}
}
void PathPoint::getEditableProperties (Array<PropertyComponent*>& props)
void PathPoint::getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected)
{
const int index = owner->points.indexOf (this);
if (multipleSelected)
return;
auto index = owner->points.indexOf (this);
jassert (index >= 0);
switch (type)

View file

@ -52,7 +52,7 @@ public:
const bool undoable);
void deleteFromPath();
void getEditableProperties (Array<PropertyComponent*>& props);
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected);
private:
PathPoint withChangedPointType (const Path::Iterator::PathElementType newType,
@ -68,9 +68,9 @@ public:
~PaintElementPath();
//==============================================================================
void setInitialBounds (int parentWidth, int parentHeight);
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const;
void setCurrentBounds (const Rectangle<int>& b, const Rectangle<int>& parentArea, const bool undoable);
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;
@ -98,31 +98,31 @@ public:
void setNonZeroWinding (const bool nonZero, const bool undoable);
//==============================================================================
void getEditableProperties (Array<PropertyComponent*>& props);
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override;
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode);
void applyCustomPaintSnippets (StringArray& snippets);
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override;
void applyCustomPaintSnippets (StringArray& snippets) override;
//==============================================================================
static const char* getTagName() noexcept { return "PATH"; }
XmlElement* createXml() const;
bool loadFromXml (const XmlElement& xml);
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);
void drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo);
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override;
void drawExtraEditorGraphics (Graphics& g, const Rectangle<int>& relativeTo) override;
void resized();
void parentSizeChanged();
void resized() override;
void parentSizeChanged() override;
void mouseDown (const MouseEvent& e);
void mouseDrag (const MouseEvent& e);
void mouseUp (const MouseEvent& e);
void mouseDown (const MouseEvent& e) override;
void mouseDrag (const MouseEvent& e) override;
void mouseUp (const MouseEvent& e) override;
void createSiblingComponents();
void changed();
void createSiblingComponents() override;
void changed() override;
private:
friend class PathPoint;

View file

@ -38,17 +38,17 @@ public:
{
}
Rectangle<int> getCurrentBounds (const Rectangle<int>& parentArea) const
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)
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)
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
{
Component tempParentComp;
tempParentComp.setBounds (parentArea);
@ -67,14 +67,14 @@ public:
}
}
void getEditableProperties (Array <PropertyComponent*>& props)
void getEditableProperties (Array <PropertyComponent*>& props, bool multipleSelected) override
{
ColouredElement::getEditableProperties (props);
ColouredElement::getEditableProperties (props, multipleSelected);
props.add (new ShapeToPathProperty (this));
}
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
return;
@ -114,7 +114,7 @@ public:
paintMethodCode += s;
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
customPaintCode.clear();
@ -127,7 +127,7 @@ public:
static const char* getTagName() noexcept { return "RECT"; }
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* e = new XmlElement (getTagName());
position.applyToXml (*e);
@ -137,7 +137,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{

View file

@ -39,7 +39,7 @@ public:
cornerSize = 10.0;
}
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
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);
@ -56,11 +56,11 @@ public:
}
}
void getEditableProperties (Array<PropertyComponent*>& props)
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
{
props.add (new CornerSizeProperty (this));
ColouredElement::getEditableProperties (props);
ColouredElement::getEditableProperties (props, multipleSelected);
props.add (new ShapeToPathProperty (this));
}
@ -114,7 +114,7 @@ public:
double getCornerSize() const noexcept { return cornerSize; }
//==============================================================================
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
if (fillType.isInvisible() && (strokeType.isInvisible() || ! isStrokePresent))
return;
@ -156,7 +156,7 @@ public:
paintMethodCode += s;
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
customPaintCode.clear();
@ -169,7 +169,7 @@ public:
static const char* getTagName() noexcept { return "ROUNDRECT"; }
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* const e = new XmlElement (getTagName());
@ -180,7 +180,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{

View file

@ -48,7 +48,7 @@ public:
}
//==============================================================================
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea)
void draw (Graphics& g, const ComponentLayout* layout, const Rectangle<int>& parentArea) override
{
fillType.setFillType (g, getDocument(), parentArea);
@ -66,10 +66,13 @@ public:
return s;
}
void getEditableProperties (Array<PropertyComponent*>& props)
void getEditableProperties (Array<PropertyComponent*>& props, bool multipleSelected) override
{
ColouredElement::getEditableProperties (props);
ColouredElement::getEditableProperties (props, multipleSelected);
if (multipleSelected)
return;
props.add (new TextProperty (this));
props.add (new FontNameProperty (this));
props.add (new FontStyleProperty (this));
@ -79,7 +82,7 @@ public:
props.add (new TextToPathProperty (this));
}
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode)
void fillInGeneratedCode (GeneratedCode& code, String& paintMethodCode) override
{
if (! fillType.isInvisible())
{
@ -103,7 +106,7 @@ public:
}
}
void applyCustomPaintSnippets (StringArray& snippets)
void applyCustomPaintSnippets (StringArray& snippets) override
{
customPaintCode.clear();
@ -116,7 +119,7 @@ public:
static const char* getTagName() noexcept { return "TEXT"; }
XmlElement* createXml() const
XmlElement* createXml() const override
{
XmlElement* e = new XmlElement (getTagName());
position.applyToXml (*e);
@ -136,7 +139,7 @@ public:
return e;
}
bool loadFromXml (const XmlElement& xml)
bool loadFromXml (const XmlElement& xml) override
{
if (xml.hasTagName (getTagName()))
{

View file

@ -102,11 +102,13 @@ private:
{
clear();
if (layout.getSelectedSet().getNumSelected() == 1) // xxx need to cope with multiple
auto numSelected = layout.getSelectedSet().getNumSelected();
if (numSelected > 0) // xxx need to cope with multiple
{
if (Component* comp = layout.getSelectedSet().getSelectedItem (0))
if (ComponentTypeHandler* const type = ComponentTypeHandler::getHandlerFor (*comp))
type->addPropertiesToPropertyPanel (comp, document, propsPanel);
if (auto* comp = layout.getSelectedSet().getSelectedItem (0))
if (auto* type = ComponentTypeHandler::getHandlerFor (*comp))
type->addPropertiesToPropertyPanel (comp, document, propsPanel, numSelected > 1);
}
}

View file

@ -81,11 +81,14 @@ void ComponentOverlayComponent::paint (Graphics& g)
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()),
findColour (defaultHighlightColourId));
baseColour.withAlpha (selectedItems.getSelectedItem (0) == target ? 1.0f : 0.3f));
}
else if (isMouseOverOrDragging())
{
@ -240,6 +243,11 @@ void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Re
{
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())
@ -249,6 +257,18 @@ void ComponentOverlayComponent::applyBoundsToComponent (Component& component, Re
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);
}
}
}
}
}

View file

@ -58,6 +58,11 @@ namespace JucerCommandIDs
newDocumentBase = 0xf32001,
newComponentBase = 0xf30001,
newElementBase = 0xf31001
newElementBase = 0xf31001,
alignTop = 0xf33000,
alignRight = 0xf33001,
alignBottom = 0xf33002,
alignLeft = 0xf33003,
};
}

View file

@ -348,7 +348,7 @@ JucerDocumentEditor::JucerDocumentEditor (JucerDocument* const doc)
updateTabs();
tabbedComponent.setCurrentTabIndex (1);
tabbedComponent.setCurrentTabIndex (document->getLastSelectedTabIndex());
document->addChangeListener (this);
@ -361,6 +361,9 @@ JucerDocumentEditor::JucerDocumentEditor (JucerDocument* const doc)
JucerDocumentEditor::~JucerDocumentEditor()
{
if (document != nullptr)
document->setLastSelectedTabIndex (tabbedComponent.getCurrentTabIndex());
tabbedComponent.clearTabs();
}
@ -598,15 +601,26 @@ void JucerDocumentEditor::addComponent (const int index)
//==============================================================================
bool JucerDocumentEditor::isSomethingSelected() const
{
if (ComponentLayout* layout = getCurrentLayout())
if (auto* layout = getCurrentLayout())
return layout->getSelectedSet().getNumSelected() > 0;
if (PaintRoutine* routine = getCurrentPaintRoutine())
if (auto* routine = getCurrentPaintRoutine())
return routine->getSelectedElements().getNumSelected() > 0;
return false;
}
bool JucerDocumentEditor::areMultipleThingsSelected() const
{
if (auto* layout = getCurrentLayout())
return layout->getSelectedSet().getNumSelected() > 1;
if (auto* routine = getCurrentPaintRoutine())
return routine->getSelectedElements().getNumSelected() > 1;
return false;
}
//==============================================================================
void JucerDocumentEditor::getAllCommands (Array <CommandID>& commands)
{
@ -630,6 +644,10 @@ void JucerDocumentEditor::getAllCommands (Array <CommandID>& commands)
JucerCommandIDs::compOverlay33,
JucerCommandIDs::compOverlay66,
JucerCommandIDs::compOverlay100,
JucerCommandIDs::alignTop,
JucerCommandIDs::alignRight,
JucerCommandIDs::alignBottom,
JucerCommandIDs::alignLeft,
StandardApplicationCommandIDs::undo,
StandardApplicationCommandIDs::redo,
StandardApplicationCommandIDs::cut,
@ -812,6 +830,34 @@ void JucerDocumentEditor::getCommandInfo (const CommandID commandID, Application
}
break;
case JucerCommandIDs::alignTop:
result.setInfo (TRANS ("Align top"),
TRANS ("Aligns the top edges of all selected components to the first component that was selected."),
CommandCategories::editing, 0);
result.setActive (areMultipleThingsSelected());
break;
case JucerCommandIDs::alignRight:
result.setInfo (TRANS ("Align right"),
TRANS ("Aligns the right edges of all selected components to the first component that was selected."),
CommandCategories::editing, 0);
result.setActive (areMultipleThingsSelected());
break;
case JucerCommandIDs::alignBottom:
result.setInfo (TRANS ("Align bottom"),
TRANS ("Aligns the bottom edges of all selected components to the first component that was selected."),
CommandCategories::editing, 0);
result.setActive (areMultipleThingsSelected());
break;
case JucerCommandIDs::alignLeft:
result.setInfo (TRANS ("Align left"),
TRANS ("Aligns the left edges of all selected components to the first component that was selected."),
CommandCategories::editing, 0);
result.setActive (areMultipleThingsSelected());
break;
case StandardApplicationCommandIDs::undo:
result.setInfo (TRANS ("Undo"), TRANS ("Undo"), "Editing", 0);
result.setActive (document != nullptr && document->getUndoManager().canUndo());
@ -1005,6 +1051,38 @@ bool JucerDocumentEditor::perform (const InvocationInfo& info)
currentPaintRoutine->ungroupSelected();
break;
case JucerCommandIDs::alignTop:
if (currentLayout != nullptr)
currentLayout->alignTop();
else if (currentPaintRoutine != nullptr)
currentPaintRoutine->alignTop();
break;
case JucerCommandIDs::alignRight:
if (currentLayout != nullptr)
currentLayout->alignRight();
else if (currentPaintRoutine != nullptr)
currentPaintRoutine->alignRight();
break;
case JucerCommandIDs::alignBottom:
if (currentLayout != nullptr)
currentLayout->alignBottom();
else if (currentPaintRoutine != nullptr)
currentPaintRoutine->alignBottom();
break;
case JucerCommandIDs::alignLeft:
if (currentLayout != nullptr)
currentLayout->alignLeft();
else if (currentPaintRoutine != nullptr)
currentPaintRoutine->alignLeft();
break;
case StandardApplicationCommandIDs::cut:
if (currentLayout != nullptr)
{

View file

@ -89,6 +89,7 @@ private:
double currentZoomLevel = 1.0;
bool isSomethingSelected() const;
bool areMultipleThingsSelected() const;
// only non-zero if a layout tab is selected
ComponentLayout* getCurrentLayout() const;

View file

@ -125,14 +125,16 @@ public:
if (state != nullptr)
propsPanel->restoreOpennessState (*state);
if (paintRoutine.getSelectedElements().getNumSelected() == 1) // xxx need to cope with multiple
auto numSelected = paintRoutine.getSelectedElements().getNumSelected();
if (numSelected > 0) // xxx need to cope with multiple
{
if (PaintElement* const pe = paintRoutine.getSelectedElements().getSelectedItem (0))
if (auto* pe = paintRoutine.getSelectedElements().getSelectedItem (0))
{
if (paintRoutine.containsElement (pe))
{
Array <PropertyComponent*> props;
pe->getEditableProperties (props);
pe->getEditableProperties (props, numSelected);
propsPanel->addSection (pe->getTypeName(), props);
}
@ -141,10 +143,10 @@ public:
if (paintRoutine.getSelectedPoints().getNumSelected() == 1) // xxx need to cope with multiple
{
if (PathPoint* const point = paintRoutine.getSelectedPoints().getSelectedItem (0))
if (auto* point = paintRoutine.getSelectedPoints().getSelectedItem (0))
{
Array <PropertyComponent*> props;
point->getEditableProperties (props);
point->getEditableProperties (props, false);
propsPanel->addSection ("Path segment", props);
}

View file

@ -571,4 +571,5 @@ void ProjucerLookAndFeel::setupColours()
setColour (TreeView::selectedItemBackgroundColourId, findColour (defaultHighlightColourId));
setColour (PopupMenu::highlightedBackgroundColourId, findColour (defaultHighlightColourId).withAlpha (0.75f));
setColour (PopupMenu::highlightedTextColourId, findColour (defaultHighlightedTextColourId));
setColour (0x1000440, /*LassoComponent::lassoFillColourId*/ findColour (defaultHighlightColourId).withAlpha (0.3f));
}