- clean working copy for leaving SVN
This commit is contained in:
+426
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../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);
|
||||
setFocusContainer (true);
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
((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;)
|
||||
{
|
||||
ScopedPointer<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;)
|
||||
{
|
||||
Component* const c = layout.getComponent (i);
|
||||
jassert (c != nullptr);
|
||||
|
||||
ComponentOverlayComponent* overlay = getOverlayCompFor (c);
|
||||
|
||||
bool isNewOverlay = false;
|
||||
|
||||
if (overlay == 0)
|
||||
{
|
||||
ComponentTypeHandler* const 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->setFocusContainer (true);
|
||||
|
||||
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())
|
||||
{
|
||||
ApplicationCommandManager* commandManager = &IntrojucerApp::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.show();
|
||||
}
|
||||
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.mouseWasClicked() && ! 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 (".cpp");
|
||||
}
|
||||
|
||||
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 (".cpp"))
|
||||
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();
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_COMPONENTLAYOUTEDITOR_JUCEHEADER__
|
||||
#define __JUCER_COMPONENTLAYOUTEDITOR_JUCEHEADER__
|
||||
|
||||
#include "jucer_ComponentOverlayComponent.h"
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_SnapGridPainter.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class ComponentLayoutEditor : public Component,
|
||||
public ChangeListener,
|
||||
public FileDragAndDropTarget,
|
||||
public DragAndDropTarget,
|
||||
public LassoSource<Component*>
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentLayoutEditor (JucerDocument& document, ComponentLayout& layout);
|
||||
~ComponentLayoutEditor();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics&) override;
|
||||
void resized() override;
|
||||
void visibilityChanged() override;
|
||||
void changeListenerCallback (ChangeBroadcaster*) 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);
|
||||
|
||||
SelectedItemSet<Component*>& getLassoSelection();
|
||||
|
||||
//==============================================================================
|
||||
void refreshAllComponents();
|
||||
void updateOverlayPositions();
|
||||
|
||||
ComponentOverlayComponent* getOverlayCompFor (Component*) const;
|
||||
|
||||
Rectangle<int> getComponentArea() const;
|
||||
Image createComponentLayerSnapshot() const;
|
||||
|
||||
private:
|
||||
JucerDocument& document;
|
||||
ComponentLayout& layout;
|
||||
Component* subCompHolder;
|
||||
|
||||
LassoComponent<Component*> lassoComp;
|
||||
SnapGridPainter grid;
|
||||
bool firstResize;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_COMPONENTLAYOUTEDITOR_JUCEHEADER__
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_COMPONENTLAYOUTPANEL_JUCEHEADER__
|
||||
#define __JUCER_COMPONENTLAYOUTPANEL_JUCEHEADER__
|
||||
|
||||
#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,
|
||||
public ChangeListener
|
||||
{
|
||||
public:
|
||||
LayoutPropsPanel (JucerDocument& doc, ComponentLayout& l)
|
||||
: document (doc), layout (l)
|
||||
{
|
||||
layout.getSelectedSet().addChangeListener (this);
|
||||
addAndMakeVisible (propsPanel);
|
||||
}
|
||||
|
||||
~LayoutPropsPanel()
|
||||
{
|
||||
layout.getSelectedSet().removeChangeListener (this);
|
||||
clear();
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
propsPanel.setBounds (4, 4, getWidth() - 8, getHeight() - 8);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
updateList();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
propsPanel.clear();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
clear();
|
||||
|
||||
if (layout.getSelectedSet().getNumSelected() == 1) // 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);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
JucerDocument& document;
|
||||
ComponentLayout& layout;
|
||||
PropertyPanel propsPanel;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_COMPONENTLAYOUTPANEL_JUCEHEADER__
|
||||
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../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);
|
||||
|
||||
addChildComponent (border = new ResizableBorderComponent (this, this));
|
||||
|
||||
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);
|
||||
|
||||
if (selected)
|
||||
{
|
||||
const BorderSize<int> borderSize (border->getBorderThickness());
|
||||
|
||||
drawResizableBorder (g, getWidth(), getHeight(), borderSize, (isMouseOverOrDragging() || border->isMouseOverOrDragging()));
|
||||
}
|
||||
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.mouseWasClicked();
|
||||
|
||||
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::getCurrentModifiers().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, const Rectangle<int>& b)
|
||||
{
|
||||
if (component->getBounds() != b)
|
||||
{
|
||||
layout.getDocument()->getUndoManager().undoCurrentTransactionOnly();
|
||||
|
||||
component->setBounds (b);
|
||||
|
||||
if (Component* const 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);
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentOverlayComponent::showPopupMenu()
|
||||
{
|
||||
ComponentTypeHandler::getHandlerFor (*target)->showPopupMenu (target, layout);
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_COMPONENTOVERLAYCOMPONENT_JUCEHEADER__
|
||||
#define __JUCER_COMPONENTOVERLAYCOMPONENT_JUCEHEADER__
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class ComponentOverlayComponent : public Component,
|
||||
public ComponentListener,
|
||||
public ChangeListener,
|
||||
public ComponentBoundsConstrainer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
ComponentOverlayComponent (Component* const targetComponent,
|
||||
ComponentLayout& layout);
|
||||
|
||||
~ComponentOverlayComponent();
|
||||
|
||||
//==============================================================================
|
||||
virtual void showPopupMenu();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g);
|
||||
void resized();
|
||||
|
||||
void mouseDown (const MouseEvent& e);
|
||||
void mouseDrag (const MouseEvent& e);
|
||||
void mouseUp (const MouseEvent& e);
|
||||
|
||||
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized);
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
|
||||
void resizeStart();
|
||||
void resizeEnd();
|
||||
|
||||
void updateBoundsToMatchTarget();
|
||||
|
||||
void checkBounds (Rectangle<int>& bounds,
|
||||
const Rectangle<int>& previousBounds,
|
||||
const Rectangle<int>& limits,
|
||||
bool isStretchingTop,
|
||||
bool isStretchingLeft,
|
||||
bool isStretchingBottom,
|
||||
bool isStretchingRight);
|
||||
|
||||
void applyBoundsToComponent (Component* component, const Rectangle<int>& bounds);
|
||||
|
||||
//==============================================================================
|
||||
Component::SafePointer<Component> target;
|
||||
const int borderThickness;
|
||||
|
||||
private:
|
||||
ScopedPointer<ResizableBorderComponent> border;
|
||||
|
||||
ComponentLayout& layout;
|
||||
|
||||
bool selected, dragging, mouseDownSelectStatus;
|
||||
double originalAspectRatio;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __JUCER_COMPONENTOVERLAYCOMPONENT_JUCEHEADER__
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../jucer_Headers.h"
|
||||
#include "jucer_EditingPanelBase.h"
|
||||
#include "jucer_JucerDocumentEditor.h"
|
||||
|
||||
//==============================================================================
|
||||
class EditingPanelBase::MagnifierComponent : public Component
|
||||
{
|
||||
public:
|
||||
MagnifierComponent (Component* comp)
|
||||
: scaleFactor (1.0), content (comp)
|
||||
{
|
||||
addAndMakeVisible (content);
|
||||
childBoundsChanged (content);
|
||||
}
|
||||
|
||||
void childBoundsChanged (Component* child)
|
||||
{
|
||||
const Rectangle<int> 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;
|
||||
ScopedPointer<Component> content;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class ZoomingViewport : public Viewport
|
||||
{
|
||||
public:
|
||||
ZoomingViewport (EditingPanelBase* const p)
|
||||
: panel (p), isSpaceDown (false)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DraggerOverlayComp* const dc = new DraggerOverlayComp();
|
||||
addAndMakeVisible (dc);
|
||||
dc->setBounds (getLocalBounds());
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = getNumChildComponents(); --i >= 0;)
|
||||
ScopedPointer<DraggerOverlayComp> deleter (dynamic_cast <DraggerOverlayComp*> (getChildComponent (i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
EditingPanelBase* const panel;
|
||||
bool isSpaceDown;
|
||||
|
||||
//==============================================================================
|
||||
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));
|
||||
|
||||
magnifier->setLookAndFeel (&lookAndFeel);
|
||||
}
|
||||
|
||||
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::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);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_EDITINGPANELBASE_JUCEHEADER__
|
||||
#define __JUCER_EDITINGPANELBASE_JUCEHEADER__
|
||||
|
||||
#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();
|
||||
|
||||
//==============================================================================
|
||||
void resized();
|
||||
void visibilityChanged();
|
||||
|
||||
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;
|
||||
LookAndFeel_V2 lookAndFeel;
|
||||
|
||||
Viewport* viewport;
|
||||
MagnifierComponent* magnifier;
|
||||
Component* editor;
|
||||
Component* propsPanel;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_EDITINGPANELBASE_JUCEHEADER__
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
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
|
||||
};
|
||||
}
|
||||
+1199
File diff suppressed because it is too large
Load Diff
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_JUCERDOCUMENTEDITOR_JUCEHEADER__
|
||||
#define __JUCER_JUCERDOCUMENTEDITOR_JUCEHEADER__
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "jucer_ComponentLayoutEditor.h"
|
||||
#include "jucer_PaintRoutineEditor.h"
|
||||
#include "jucer_ComponentLayoutPanel.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class JucerDocumentEditor : public Component,
|
||||
public ApplicationCommandTarget,
|
||||
public ChangeListener
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
JucerDocumentEditor (JucerDocument* const document);
|
||||
~JucerDocumentEditor();
|
||||
|
||||
JucerDocument* getDocument() const noexcept { return document; }
|
||||
|
||||
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);
|
||||
void resized();
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
bool keyPressed (const KeyPress&);
|
||||
|
||||
//==============================================================================
|
||||
ApplicationCommandTarget* getNextCommandTarget();
|
||||
void getAllCommands (Array <CommandID>&);
|
||||
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result);
|
||||
bool perform (const InvocationInfo&);
|
||||
|
||||
static JucerDocumentEditor* getActiveDocumentHolder();
|
||||
|
||||
private:
|
||||
ScopedPointer<JucerDocument> document;
|
||||
TabbedComponent tabbedComponent;
|
||||
ComponentLayoutPanel* compLayoutPanel;
|
||||
|
||||
bool isSomethingSelected() const;
|
||||
int lastViewportX, lastViewportY;
|
||||
|
||||
double currentZoomLevel;
|
||||
|
||||
// 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 (const int index);
|
||||
void addComponent (const int index);
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_JUCERDOCUMENTEDITOR_JUCEHEADER__
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../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 (PaintElement* const e = dynamic_cast <PaintElement*> (getChildComponent (i)))
|
||||
if (! graphics.containsElement (e))
|
||||
removeChildComponent (e);
|
||||
|
||||
Component* last = nullptr;
|
||||
|
||||
for (int i = graphics.getNumElements(); --i >= 0;)
|
||||
{
|
||||
PaintElement* const 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 = &IntrojucerApp::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.show();
|
||||
}
|
||||
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.mouseWasClicked() && ! 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())
|
||||
{
|
||||
ScopedPointer<Drawable> d (Drawable::createFromImageFile (f));
|
||||
|
||||
if (d != nullptr)
|
||||
{
|
||||
d = nullptr;
|
||||
|
||||
document.beginTransaction();
|
||||
|
||||
graphics.dropImageAt (f,
|
||||
jlimit (10, getWidth() - 10, x),
|
||||
jlimit (10, getHeight() - 10, y));
|
||||
|
||||
document.beginTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_PAINTROUTINEEDITOR_JUCEHEADER__
|
||||
#define __JUCER_PAINTROUTINEEDITOR_JUCEHEADER__
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
#include "../jucer_PaintRoutine.h"
|
||||
#include "jucer_SnapGridPainter.h"
|
||||
class JucerDocumentEditor;
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class PaintRoutineEditor : public Component,
|
||||
public ChangeListener,
|
||||
public LassoSource <PaintElement*>,
|
||||
public FileDragAndDropTarget
|
||||
{
|
||||
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();
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_PAINTROUTINEEDITOR_JUCEHEADER__
|
||||
+183
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../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()
|
||||
{
|
||||
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,
|
||||
public ChangeListener
|
||||
{
|
||||
public:
|
||||
GraphicsPropsPanel (PaintRoutine& paintRoutine_,
|
||||
JucerDocument* doc)
|
||||
: paintRoutine (paintRoutine_),
|
||||
document (doc)
|
||||
{
|
||||
paintRoutine.getSelectedElements().addChangeListener (this);
|
||||
paintRoutine.getSelectedPoints().addChangeListener (this);
|
||||
|
||||
addAndMakeVisible (propsPanel = new PropertyPanel());
|
||||
}
|
||||
|
||||
~GraphicsPropsPanel()
|
||||
{
|
||||
paintRoutine.getSelectedPoints().removeChangeListener (this);
|
||||
paintRoutine.getSelectedElements().removeChangeListener (this);
|
||||
|
||||
clear();
|
||||
deleteAllChildren();
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
propsPanel->setBounds (4, 4, getWidth() - 8, getHeight() - 8);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
updateList();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
propsPanel->clear();
|
||||
}
|
||||
|
||||
void updateList()
|
||||
{
|
||||
ScopedPointer<XmlElement> 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);
|
||||
|
||||
if (paintRoutine.getSelectedElements().getNumSelected() == 1) // xxx need to cope with multiple
|
||||
{
|
||||
if (PaintElement* const pe = paintRoutine.getSelectedElements().getSelectedItem (0))
|
||||
{
|
||||
if (paintRoutine.containsElement (pe))
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
pe->getEditableProperties (props);
|
||||
|
||||
propsPanel->addSection (pe->getTypeName(), props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paintRoutine.getSelectedPoints().getNumSelected() == 1) // xxx need to cope with multiple
|
||||
{
|
||||
if (PathPoint* const point = paintRoutine.getSelectedPoints().getSelectedItem (0))
|
||||
{
|
||||
Array <PropertyComponent*> props;
|
||||
point->getEditableProperties (props);
|
||||
|
||||
propsPanel->addSection ("Path segment", props);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_PAINTROUTINEPANEL_JUCEHEADER__
|
||||
#define __JUCER_PAINTROUTINEPANEL_JUCEHEADER__
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_PAINTROUTINEPANEL_JUCEHEADER__
|
||||
+762
@@ -0,0 +1,762 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_RELATIVEPOSITIONEDRECTANGLE_JUCEHEADER__
|
||||
#define __JUCER_RELATIVEPOSITIONEDRECTANGLE_JUCEHEADER__
|
||||
|
||||
class ComponentLayout;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A rectangle whose coordinates can be defined in terms of absolute or
|
||||
proportional distances.
|
||||
|
||||
Designed mainly for storing component positions, this gives you a lot of
|
||||
control over how each coordinate is stored, either as an absolute position,
|
||||
or as a proportion of the size of a parent rectangle.
|
||||
|
||||
It also allows you to define the anchor points by which the rectangle is
|
||||
positioned, so for example you could specify that the top right of the
|
||||
rectangle should be an absolute distance from its parent's bottom-right corner.
|
||||
|
||||
This object can be stored as a string, which takes the form "x y w h", including
|
||||
symbols like '%' and letters to indicate the anchor point. See its toString()
|
||||
method for more info.
|
||||
|
||||
Example usage:
|
||||
@code
|
||||
class MyComponent
|
||||
{
|
||||
void resized()
|
||||
{
|
||||
// this will set the child component's x to be 20% of our width, its y
|
||||
// to be 30, its width to be 150, and its height to be 50% of our
|
||||
// height..
|
||||
const PositionedRectangle pos1 ("20% 30 150 50%");
|
||||
pos1.applyToComponent (*myChildComponent1);
|
||||
|
||||
// this will inset the child component with a gap of 10 pixels
|
||||
// around each of its edges..
|
||||
const PositionedRectangle pos2 ("10 10 20M 20M");
|
||||
pos2.applyToComponent (*myChildComponent2);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class PositionedRectangle
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty rectangle with all coordinates set to zero.
|
||||
|
||||
The default anchor point is top-left; the default
|
||||
*/
|
||||
PositionedRectangle() noexcept
|
||||
: x (0.0), y (0.0), w (0.0), h (0.0),
|
||||
xMode (anchorAtLeftOrTop | absoluteFromParentTopLeft),
|
||||
yMode (anchorAtLeftOrTop | absoluteFromParentTopLeft),
|
||||
wMode (absoluteSize), hMode (absoluteSize)
|
||||
{
|
||||
}
|
||||
|
||||
/** Initialises a PositionedRectangle from a saved string version.
|
||||
|
||||
The string must be in the format generated by toString().
|
||||
*/
|
||||
PositionedRectangle (const String& stringVersion) noexcept
|
||||
{
|
||||
StringArray tokens;
|
||||
tokens.addTokens (stringVersion, false);
|
||||
|
||||
decodePosString (tokens [0], xMode, x);
|
||||
decodePosString (tokens [1], yMode, y);
|
||||
decodeSizeString (tokens [2], wMode, w);
|
||||
decodeSizeString (tokens [3], hMode, h);
|
||||
}
|
||||
|
||||
/** Creates a copy of another PositionedRectangle. */
|
||||
PositionedRectangle (const PositionedRectangle& other) noexcept
|
||||
: x (other.x), y (other.y), w (other.w), h (other.h),
|
||||
xMode (other.xMode), yMode (other.yMode),
|
||||
wMode (other.wMode), hMode (other.hMode)
|
||||
{
|
||||
}
|
||||
|
||||
/** Copies another PositionedRectangle. */
|
||||
PositionedRectangle& operator= (const PositionedRectangle& other) noexcept
|
||||
{
|
||||
x = other.x;
|
||||
y = other.y;
|
||||
w = other.w;
|
||||
h = other.h;
|
||||
xMode = other.xMode;
|
||||
yMode = other.yMode;
|
||||
wMode = other.wMode;
|
||||
hMode = other.hMode;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns a string version of this position, from which it can later be
|
||||
re-generated.
|
||||
|
||||
The format is four coordinates, "x y w h".
|
||||
|
||||
- If a coordinate is absolute, it is stored as an integer, e.g. "100".
|
||||
- If a coordinate is proportional to its parent's width or height, it is stored
|
||||
as a percentage, e.g. "80%".
|
||||
- If the X or Y coordinate is relative to the parent's right or bottom edge, the
|
||||
number has "R" appended to it, e.g. "100R" means a distance of 100 pixels from
|
||||
the parent's right-hand edge.
|
||||
- If the X or Y coordinate is relative to the parent's centre, the number has "C"
|
||||
appended to it, e.g. "-50C" would be 50 pixels left of the parent's centre.
|
||||
- If the X or Y coordinate should be anchored at the component's right or bottom
|
||||
edge, then it has "r" appended to it. So "-50Rr" would mean that this component's
|
||||
right-hand edge should be 50 pixels left of the parent's right-hand edge.
|
||||
- If the X or Y coordinate should be anchored at the component's centre, then it
|
||||
has "c" appended to it. So "-50Rc" would mean that this component's
|
||||
centre should be 50 pixels left of the parent's right-hand edge. "40%c" means that
|
||||
this component's centre should be placed 40% across the parent's width.
|
||||
- If it's a width or height that should use the parentSizeMinusAbsolute mode, then
|
||||
the number has "M" appended to it.
|
||||
|
||||
To reload a stored string, use the constructor that takes a string parameter.
|
||||
*/
|
||||
String toString() const
|
||||
{
|
||||
String s;
|
||||
s.preallocateBytes (32);
|
||||
addPosDescription (s, xMode, x); s << ' ';
|
||||
addPosDescription (s, yMode, y); s << ' ';
|
||||
addSizeDescription (s, wMode, w); s << ' ';
|
||||
addSizeDescription (s, hMode, h);
|
||||
return s;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Calculates the absolute position, given the size of the space that
|
||||
it should go in.
|
||||
|
||||
This will work out any proportional distances and sizes relative to the
|
||||
target rectangle, and will return the absolute position.
|
||||
|
||||
@see applyToComponent
|
||||
*/
|
||||
Rectangle<int> getRectangle (const Rectangle<int>& target) const noexcept
|
||||
{
|
||||
jassert (! target.isEmpty());
|
||||
|
||||
double x_, y_, w_, h_;
|
||||
applyPosAndSize (x_, w_, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
applyPosAndSize (y_, h_, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
return Rectangle<int> (roundToInt (x_), roundToInt (y_), roundToInt (w_), roundToInt (h_));
|
||||
}
|
||||
|
||||
/** Same as getRectangle(), but returning the values as doubles rather than ints. */
|
||||
void getRectangleDouble (const Rectangle<int>& target,
|
||||
double& x_, double& y_, double& w_, double& h_) const noexcept
|
||||
{
|
||||
jassert (! target.isEmpty());
|
||||
applyPosAndSize (x_, w_, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
applyPosAndSize (y_, h_, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
|
||||
/** This sets the bounds of the given component to this position.
|
||||
|
||||
This is equivalent to writing:
|
||||
@code
|
||||
comp.setBounds (getRectangle (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight())));
|
||||
@endcode
|
||||
|
||||
@see getRectangle, updateFromComponent
|
||||
*/
|
||||
void applyToComponent (Component& comp) const noexcept
|
||||
{
|
||||
comp.setBounds (getRectangle (Rectangle<int> (comp.getParentWidth(), comp.getParentHeight())));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Updates this object's coordinates to match the given rectangle.
|
||||
|
||||
This will set all coordinates based on the given rectangle, re-calculating
|
||||
any proportional distances, and using the current anchor points.
|
||||
|
||||
So for example if the x coordinate mode is currently proportional, this will
|
||||
re-calculate x based on the rectangle's relative position within the target
|
||||
rectangle's width.
|
||||
|
||||
If the target rectangle's width or height are zero then it may not be possible
|
||||
to re-calculate some proportional coordinates. In this case, those coordinates
|
||||
will not be changed.
|
||||
*/
|
||||
void updateFrom (const Rectangle<int>& newPosition,
|
||||
const Rectangle<int>& targetSpaceToBeRelativeTo) noexcept
|
||||
{
|
||||
updatePosAndSize (x, w, newPosition.getX(), newPosition.getWidth(), xMode, wMode, targetSpaceToBeRelativeTo.getX(), targetSpaceToBeRelativeTo.getWidth());
|
||||
updatePosAndSize (y, h, newPosition.getY(), newPosition.getHeight(), yMode, hMode, targetSpaceToBeRelativeTo.getY(), targetSpaceToBeRelativeTo.getHeight());
|
||||
}
|
||||
|
||||
/** Same functionality as updateFrom(), but taking doubles instead of ints.
|
||||
*/
|
||||
void updateFromDouble (const double newX, const double newY,
|
||||
const double newW, const double newH,
|
||||
const Rectangle<int>& target) noexcept
|
||||
{
|
||||
updatePosAndSize (x, w, newX, newW, xMode, wMode, target.getX(), target.getWidth());
|
||||
updatePosAndSize (y, h, newY, newH, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
|
||||
/** Updates this object's coordinates to match the bounds of this component.
|
||||
|
||||
This is equivalent to calling updateFrom() with the component's bounds and
|
||||
it parent size.
|
||||
|
||||
If the component doesn't currently have a parent, then proportional coordinates
|
||||
might not be updated because it would need to know the parent's size to do the
|
||||
maths for this.
|
||||
*/
|
||||
void updateFromComponent (const Component& comp) noexcept
|
||||
{
|
||||
if (comp.getParentComponent() == 0 && ! comp.isOnDesktop())
|
||||
updateFrom (comp.getBounds(), Rectangle<int>());
|
||||
else
|
||||
updateFrom (comp.getBounds(), Rectangle<int> (comp.getParentWidth(), comp.getParentHeight()));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Specifies the point within the rectangle, relative to which it should be positioned. */
|
||||
enum AnchorPoint
|
||||
{
|
||||
anchorAtLeftOrTop = 1 << 0, /**< The x or y coordinate specifies where the left or top edge of the rectangle should be. */
|
||||
anchorAtRightOrBottom = 1 << 1, /**< The x or y coordinate specifies where the right or bottom edge of the rectangle should be. */
|
||||
anchorAtCentre = 1 << 2 /**< The x or y coordinate specifies where the centre of the rectangle should be. */
|
||||
};
|
||||
|
||||
/** Specifies how an x or y coordinate should be interpreted. */
|
||||
enum PositionMode
|
||||
{
|
||||
absoluteFromParentTopLeft = 1 << 3, /**< The x or y coordinate specifies an absolute distance from the parent's top or left edge. */
|
||||
absoluteFromParentBottomRight = 1 << 4, /**< The x or y coordinate specifies an absolute distance from the parent's bottom or right edge. */
|
||||
absoluteFromParentCentre = 1 << 5, /**< The x or y coordinate specifies an absolute distance from the parent's centre. */
|
||||
proportionOfParentSize = 1 << 6 /**< The x or y coordinate specifies a proportion of the parent's width or height, measured from the parent's top or left. */
|
||||
};
|
||||
|
||||
/** Specifies how the width or height should be interpreted. */
|
||||
enum SizeMode
|
||||
{
|
||||
absoluteSize = 1 << 0, /**< The width or height specifies an absolute size. */
|
||||
parentSizeMinusAbsolute = 1 << 1, /**< The width or height is an amount that should be subtracted from the parent's width or height. */
|
||||
proportionalSize = 1 << 2, /**< The width or height specifies a proportion of the parent's width or height. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Sets all options for all coordinates.
|
||||
|
||||
This requires a reference rectangle to be specified, because if you're changing any
|
||||
of the modes from proportional to absolute or vice-versa, then it'll need to convert
|
||||
the coordinates, and will need to know the parent size so it can calculate this.
|
||||
*/
|
||||
void setModes (const AnchorPoint xAnchor, const PositionMode xMode_,
|
||||
const AnchorPoint yAnchor, const PositionMode yMode_,
|
||||
const SizeMode widthMode, const SizeMode heightMode,
|
||||
const Rectangle<int>& target) noexcept
|
||||
{
|
||||
if (xMode != (xAnchor | xMode_) || wMode != widthMode)
|
||||
{
|
||||
double tx, tw;
|
||||
applyPosAndSize (tx, tw, x, w, xMode, wMode, target.getX(), target.getWidth());
|
||||
|
||||
xMode = (uint8) (xAnchor | xMode_);
|
||||
wMode = (uint8) widthMode;
|
||||
|
||||
updatePosAndSize (x, w, tx, tw, xMode, wMode, target.getX(), target.getWidth());
|
||||
}
|
||||
|
||||
if (yMode != (yAnchor | yMode_) || hMode != heightMode)
|
||||
{
|
||||
double ty, th;
|
||||
applyPosAndSize (ty, th, y, h, yMode, hMode, target.getY(), target.getHeight());
|
||||
|
||||
yMode = (uint8) (yAnchor | yMode_);
|
||||
hMode = (uint8) heightMode;
|
||||
|
||||
updatePosAndSize (y, h, ty, th, yMode, hMode, target.getY(), target.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the anchoring mode for the x coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
AnchorPoint getAnchorPointX() const noexcept
|
||||
{
|
||||
return (AnchorPoint) (xMode & (anchorAtLeftOrTop | anchorAtRightOrBottom | anchorAtCentre));
|
||||
}
|
||||
|
||||
/** Returns the positioning mode for the x coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
PositionMode getPositionModeX() const noexcept
|
||||
{
|
||||
return (PositionMode) (xMode & (absoluteFromParentTopLeft | absoluteFromParentBottomRight
|
||||
| absoluteFromParentCentre | proportionOfParentSize));
|
||||
}
|
||||
|
||||
/** Returns the raw x coordinate.
|
||||
|
||||
If the x position mode is absolute, then this will be the absolute value. If it's
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
width of the parent space.
|
||||
*/
|
||||
double getX() const noexcept { return x; }
|
||||
|
||||
/** Sets the raw value of the x coordinate.
|
||||
See getX() for the meaning of this value.
|
||||
*/
|
||||
void setX (const double newX) noexcept { x = newX; }
|
||||
|
||||
/** Returns the anchoring mode for the y coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
AnchorPoint getAnchorPointY() const noexcept
|
||||
{
|
||||
return (AnchorPoint) (yMode & (anchorAtLeftOrTop | anchorAtRightOrBottom | anchorAtCentre));
|
||||
}
|
||||
|
||||
/** Returns the positioning mode for the y coordinate.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
PositionMode getPositionModeY() const noexcept
|
||||
{
|
||||
return (PositionMode) (yMode & (absoluteFromParentTopLeft | absoluteFromParentBottomRight
|
||||
| absoluteFromParentCentre | proportionOfParentSize));
|
||||
}
|
||||
|
||||
/** Returns the raw y coordinate.
|
||||
|
||||
If the y position mode is absolute, then this will be the absolute value. If it's
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
height of the parent space.
|
||||
*/
|
||||
double getY() const noexcept { return y; }
|
||||
|
||||
/** Sets the raw value of the y coordinate.
|
||||
See getY() for the meaning of this value.
|
||||
*/
|
||||
void setY (const double newY) noexcept { y = newY; }
|
||||
|
||||
/** Returns the mode used to calculate the width.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
SizeMode getWidthMode() const noexcept { return (SizeMode) wMode; }
|
||||
|
||||
/** Returns the raw width value.
|
||||
|
||||
If the width mode is absolute, then this will be the absolute value. If the mode is
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
width of the parent space.
|
||||
*/
|
||||
double getWidth() const noexcept { return w; }
|
||||
|
||||
/** Sets the raw width value.
|
||||
|
||||
See getWidth() for the details about what this value means.
|
||||
*/
|
||||
void setWidth (const double newWidth) noexcept { w = newWidth; }
|
||||
|
||||
/** Returns the mode used to calculate the height.
|
||||
To change any of the modes, use setModes().
|
||||
*/
|
||||
SizeMode getHeightMode() const noexcept { return (SizeMode) hMode; }
|
||||
|
||||
/** Returns the raw height value.
|
||||
|
||||
If the height mode is absolute, then this will be the absolute value. If the mode is
|
||||
proportional, then this will be a fractional proportion, where 1.0 means the full
|
||||
height of the parent space.
|
||||
*/
|
||||
double getHeight() const noexcept { return h; }
|
||||
|
||||
/** Sets the raw height value.
|
||||
|
||||
See getHeight() for the details about what this value means.
|
||||
*/
|
||||
void setHeight (const double newHeight) noexcept { h = newHeight; }
|
||||
|
||||
//==============================================================================
|
||||
/** If the size and position are constance, and wouldn't be affected by changes
|
||||
in the parent's size, then this will return true.
|
||||
*/
|
||||
bool isPositionAbsolute() const noexcept
|
||||
{
|
||||
return xMode == absoluteFromParentTopLeft
|
||||
&& yMode == absoluteFromParentTopLeft
|
||||
&& wMode == absoluteSize
|
||||
&& hMode == absoluteSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Compares two objects. */
|
||||
bool operator== (const PositionedRectangle& other) const noexcept
|
||||
{
|
||||
return x == other.x && y == other.y
|
||||
&& w == other.w && h == other.h
|
||||
&& xMode == other.xMode && yMode == other.yMode
|
||||
&& wMode == other.wMode && hMode == other.hMode;
|
||||
}
|
||||
|
||||
/** Compares two objects. */
|
||||
bool operator!= (const PositionedRectangle& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
double x, y, w, h;
|
||||
uint8 xMode, yMode, wMode, hMode;
|
||||
|
||||
void addPosDescription (String& s, const uint8 mode, const double value) const noexcept
|
||||
{
|
||||
if ((mode & proportionOfParentSize) != 0)
|
||||
{
|
||||
s << (roundToInt (value * 100000.0) / 1000.0) << '%';
|
||||
}
|
||||
else
|
||||
{
|
||||
s << (roundToInt (value * 100.0) / 100.0);
|
||||
|
||||
if ((mode & absoluteFromParentBottomRight) != 0)
|
||||
s << 'R';
|
||||
else if ((mode & absoluteFromParentCentre) != 0)
|
||||
s << 'C';
|
||||
}
|
||||
|
||||
if ((mode & anchorAtRightOrBottom) != 0)
|
||||
s << 'r';
|
||||
else if ((mode & anchorAtCentre) != 0)
|
||||
s << 'c';
|
||||
}
|
||||
|
||||
void addSizeDescription (String& s, const uint8 mode, const double value) const noexcept
|
||||
{
|
||||
if (mode == proportionalSize)
|
||||
s << (roundToInt (value * 100000.0) / 1000.0) << '%';
|
||||
else if (mode == parentSizeMinusAbsolute)
|
||||
s << (roundToInt (value * 100.0) / 100.0) << 'M';
|
||||
else
|
||||
s << (roundToInt (value * 100.0) / 100.0);
|
||||
}
|
||||
|
||||
void decodePosString (const String& s, uint8& mode, double& value) noexcept
|
||||
{
|
||||
if (s.containsChar ('r'))
|
||||
mode = anchorAtRightOrBottom;
|
||||
else if (s.containsChar ('c'))
|
||||
mode = anchorAtCentre;
|
||||
else
|
||||
mode = anchorAtLeftOrTop;
|
||||
|
||||
if (s.containsChar ('%'))
|
||||
{
|
||||
mode |= proportionOfParentSize;
|
||||
value = s.removeCharacters ("%rcRC").getDoubleValue() / 100.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.containsChar ('R'))
|
||||
mode |= absoluteFromParentBottomRight;
|
||||
else if (s.containsChar ('C'))
|
||||
mode |= absoluteFromParentCentre;
|
||||
else
|
||||
mode |= absoluteFromParentTopLeft;
|
||||
|
||||
value = s.removeCharacters ("rcRC").getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
void decodeSizeString (const String& s, uint8& mode, double& value) noexcept
|
||||
{
|
||||
if (s.containsChar ('%'))
|
||||
{
|
||||
mode = proportionalSize;
|
||||
value = s.upToFirstOccurrenceOf ("%", false, false).getDoubleValue() / 100.0;
|
||||
}
|
||||
else if (s.containsChar ('M'))
|
||||
{
|
||||
mode = parentSizeMinusAbsolute;
|
||||
value = s.getDoubleValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = absoluteSize;
|
||||
value = s.getDoubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
void applyPosAndSize (double& xOut, double& wOut, const double x_, const double w_,
|
||||
const uint8 xMode_, const uint8 wMode_,
|
||||
const int parentPos, const int parentSize) const noexcept
|
||||
{
|
||||
if (wMode_ == proportionalSize)
|
||||
wOut = roundToInt (w_ * parentSize);
|
||||
else if (wMode_ == parentSizeMinusAbsolute)
|
||||
wOut = jmax (0, parentSize - roundToInt (w_));
|
||||
else
|
||||
wOut = roundToInt (w_);
|
||||
|
||||
if ((xMode_ & proportionOfParentSize) != 0)
|
||||
xOut = parentPos + x_ * parentSize;
|
||||
else if ((xMode_ & absoluteFromParentBottomRight) != 0)
|
||||
xOut = (parentPos + parentSize) - x_;
|
||||
else if ((xMode_ & absoluteFromParentCentre) != 0)
|
||||
xOut = x_ + (parentPos + parentSize / 2);
|
||||
else
|
||||
xOut = x_ + parentPos;
|
||||
|
||||
if ((xMode_ & anchorAtRightOrBottom) != 0)
|
||||
xOut -= wOut;
|
||||
else if ((xMode_ & anchorAtCentre) != 0)
|
||||
xOut -= wOut / 2;
|
||||
}
|
||||
|
||||
void updatePosAndSize (double& xOut, double& wOut, double x_, const double w_,
|
||||
const uint8 xMode_, const uint8 wMode_,
|
||||
const int parentPos, const int parentSize) const noexcept
|
||||
{
|
||||
if (wMode_ == proportionalSize)
|
||||
{
|
||||
if (parentSize > 0)
|
||||
wOut = w_ / parentSize;
|
||||
}
|
||||
else if (wMode_ == parentSizeMinusAbsolute)
|
||||
wOut = parentSize - w_;
|
||||
else
|
||||
wOut = w_;
|
||||
|
||||
if ((xMode_ & anchorAtRightOrBottom) != 0)
|
||||
x_ += w_;
|
||||
else if ((xMode_ & anchorAtCentre) != 0)
|
||||
x_ += w_ / 2;
|
||||
|
||||
if ((xMode_ & proportionOfParentSize) != 0)
|
||||
{
|
||||
if (parentSize > 0)
|
||||
xOut = (x_ - parentPos) / parentSize;
|
||||
}
|
||||
else if ((xMode_ & absoluteFromParentBottomRight) != 0)
|
||||
xOut = (parentPos + parentSize) - x_;
|
||||
else if ((xMode_ & absoluteFromParentCentre) != 0)
|
||||
xOut = x_ - (parentPos + parentSize / 2);
|
||||
else
|
||||
xOut = x_ - parentPos;
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
struct RelativePositionedRectangle
|
||||
{
|
||||
//==============================================================================
|
||||
RelativePositionedRectangle()
|
||||
: relativeToX (0),
|
||||
relativeToY (0),
|
||||
relativeToW (0),
|
||||
relativeToH (0)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePositionedRectangle (const RelativePositionedRectangle& other)
|
||||
: rect (other.rect),
|
||||
relativeToX (other.relativeToX),
|
||||
relativeToY (other.relativeToY),
|
||||
relativeToW (other.relativeToW),
|
||||
relativeToH (other.relativeToH)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePositionedRectangle& operator= (const RelativePositionedRectangle& other)
|
||||
{
|
||||
rect = other.rect;
|
||||
relativeToX = other.relativeToX;
|
||||
relativeToY = other.relativeToY;
|
||||
relativeToW = other.relativeToW;
|
||||
relativeToH = other.relativeToH;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const RelativePositionedRectangle& other) const noexcept
|
||||
{
|
||||
return rect == other.rect
|
||||
&& relativeToX == other.relativeToX
|
||||
&& relativeToY == other.relativeToY
|
||||
&& relativeToW == other.relativeToW
|
||||
&& relativeToH == other.relativeToH;
|
||||
}
|
||||
|
||||
bool operator!= (const RelativePositionedRectangle& other) const noexcept
|
||||
{
|
||||
return ! operator== (other);
|
||||
}
|
||||
|
||||
template <typename LayoutType>
|
||||
void getRelativeTargetBounds (const Rectangle<int>& parentArea,
|
||||
const LayoutType* layout,
|
||||
int& x, int& xw, int& y, int& yh,
|
||||
int& w, int& h) const
|
||||
{
|
||||
Component* rx = 0;
|
||||
Component* ry = 0;
|
||||
Component* rw = 0;
|
||||
Component* rh = 0;
|
||||
|
||||
if (layout != 0)
|
||||
{
|
||||
rx = layout->findComponentWithId (relativeToX);
|
||||
ry = layout->findComponentWithId (relativeToY);
|
||||
rw = layout->findComponentWithId (relativeToW);
|
||||
rh = layout->findComponentWithId (relativeToH);
|
||||
}
|
||||
|
||||
x = parentArea.getX() + (rx != 0 ? rx->getX() : 0);
|
||||
y = parentArea.getY() + (ry != 0 ? ry->getY() : 0);
|
||||
w = rw != 0 ? rw->getWidth() : parentArea.getWidth();
|
||||
h = rh != 0 ? rh->getHeight() : parentArea.getHeight();
|
||||
xw = rx != 0 ? rx->getWidth() : parentArea.getWidth();
|
||||
yh = ry != 0 ? ry->getHeight() : parentArea.getHeight();
|
||||
}
|
||||
|
||||
Rectangle<int> getRectangle (const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (parentArea, layout, x, xw, y, yh, w, h);
|
||||
|
||||
const Rectangle<int> xyRect ((xw <= 0 || yh <= 0) ? Rectangle<int>()
|
||||
: rect.getRectangle (Rectangle<int> (x, y, xw, yh)));
|
||||
|
||||
const Rectangle<int> whRect ((w <= 0 || h <= 0) ? Rectangle<int>()
|
||||
: rect.getRectangle (Rectangle<int> (x, y, w, h)));
|
||||
|
||||
return Rectangle<int> (xyRect.getX(), xyRect.getY(),
|
||||
whRect.getWidth(), whRect.getHeight());
|
||||
}
|
||||
|
||||
void getRectangleDouble (double& x, double& y, double& w, double& h,
|
||||
const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
int rx, rxw, ry, ryh, rw, rh;
|
||||
getRelativeTargetBounds (parentArea, layout, rx, rxw, ry, ryh, rw, rh);
|
||||
|
||||
double dummy1, dummy2;
|
||||
rect.getRectangleDouble (Rectangle<int> (rx, ry, rxw, ryh), x, y, dummy1, dummy2);
|
||||
rect.getRectangleDouble (Rectangle<int> (rx, ry, rw, rh), dummy1, dummy2, w, h);
|
||||
}
|
||||
|
||||
void updateFromComponent (const Component& comp, const ComponentLayout* layout)
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (Rectangle<int> (0, 0, comp.getParentWidth(), comp.getParentHeight()),
|
||||
layout, x, xw, y, yh, w, h);
|
||||
|
||||
PositionedRectangle xyRect (rect), whRect (rect);
|
||||
xyRect.updateFrom (comp.getBounds(), Rectangle<int> (x, y, xw, yh));
|
||||
whRect.updateFrom (comp.getBounds(), Rectangle<int> (x, y, w, h));
|
||||
|
||||
rect.setX (xyRect.getX());
|
||||
rect.setY (xyRect.getY());
|
||||
rect.setWidth (whRect.getWidth());
|
||||
rect.setHeight (whRect.getHeight());
|
||||
}
|
||||
|
||||
void updateFrom (double newX, double newY, double newW, double newH,
|
||||
const Rectangle<int>& parentArea, const ComponentLayout* layout)
|
||||
{
|
||||
int x, xw, y, yh, w, h;
|
||||
getRelativeTargetBounds (parentArea, layout, x, xw, y, yh, w, h);
|
||||
|
||||
PositionedRectangle xyRect (rect), whRect (rect);
|
||||
xyRect.updateFromDouble (newX, newY, newW, newH, Rectangle<int> (x, y, xw, yh));
|
||||
whRect.updateFromDouble (newX, newY, newW, newH, Rectangle<int> (x, y, w, h));
|
||||
|
||||
rect.setX (xyRect.getX());
|
||||
rect.setY (xyRect.getY());
|
||||
rect.setWidth (whRect.getWidth());
|
||||
rect.setHeight (whRect.getHeight());
|
||||
}
|
||||
|
||||
void applyToXml (XmlElement& e) const
|
||||
{
|
||||
e.setAttribute ("pos", rect.toString());
|
||||
|
||||
if (relativeToX != 0) e.setAttribute ("posRelativeX", String::toHexString (relativeToX));
|
||||
if (relativeToY != 0) e.setAttribute ("posRelativeY", String::toHexString (relativeToY));
|
||||
if (relativeToW != 0) e.setAttribute ("posRelativeW", String::toHexString (relativeToW));
|
||||
if (relativeToH != 0) e.setAttribute ("posRelativeH", String::toHexString (relativeToH));
|
||||
}
|
||||
|
||||
void restoreFromXml (const XmlElement& e, const RelativePositionedRectangle& defaultPos)
|
||||
{
|
||||
rect = PositionedRectangle (e.getStringAttribute ("pos", defaultPos.rect.toString()));
|
||||
relativeToX = e.getStringAttribute ("posRelativeX", String::toHexString (defaultPos.relativeToX)).getHexValue64();
|
||||
relativeToY = e.getStringAttribute ("posRelativeY", String::toHexString (defaultPos.relativeToY)).getHexValue64();
|
||||
relativeToW = e.getStringAttribute ("posRelativeW", String::toHexString (defaultPos.relativeToW)).getHexValue64();
|
||||
relativeToH = e.getStringAttribute ("posRelativeH", String::toHexString (defaultPos.relativeToH)).getHexValue64();
|
||||
}
|
||||
|
||||
String toString() const
|
||||
{
|
||||
StringArray toks;
|
||||
toks.addTokens (rect.toString(), false);
|
||||
|
||||
return toks[0] + " " + toks[1];
|
||||
}
|
||||
|
||||
Point<float> toXY (const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
double x, y, w, h;
|
||||
getRectangleDouble (x, y, w, h, parentArea, layout);
|
||||
return Point<float> ((float) x, (float) y);
|
||||
}
|
||||
|
||||
void getXY (double& x, double& y,
|
||||
const Rectangle<int>& parentArea,
|
||||
const ComponentLayout* layout) const
|
||||
{
|
||||
double w, h;
|
||||
getRectangleDouble (x, y, w, h, parentArea, layout);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
PositionedRectangle rect;
|
||||
int64 relativeToX;
|
||||
int64 relativeToY;
|
||||
int64 relativeToW;
|
||||
int64 relativeToH;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_RELATIVEPOSITIONEDRECTANGLE_JUCEHEADER__
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../jucer_Headers.h"
|
||||
#include "jucer_ResourceEditorPanel.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
class ResourceListButton : public Component,
|
||||
private ButtonListener
|
||||
{
|
||||
public:
|
||||
ResourceListButton (JucerDocument& doc)
|
||||
: document (doc), reloadButton ("Reload"), row (0)
|
||||
{
|
||||
setInterceptsMouseClicks (false, true);
|
||||
addAndMakeVisible (reloadButton);
|
||||
reloadButton.addListener (this);
|
||||
}
|
||||
|
||||
void update (int newRow)
|
||||
{
|
||||
row = newRow;
|
||||
reloadButton.setVisible (document.getResources() [row] != nullptr);
|
||||
}
|
||||
|
||||
void resized()
|
||||
{
|
||||
reloadButton.setBoundsInset (BorderSize<int> (2));
|
||||
}
|
||||
|
||||
void buttonClicked (Button*)
|
||||
{
|
||||
if (const BinaryResources::BinaryResource* const r = document.getResources() [row])
|
||||
document.getResources()
|
||||
.browseForResource ("Select a file to replace this resource",
|
||||
"*",
|
||||
File (r->originalFilename),
|
||||
r->name);
|
||||
}
|
||||
|
||||
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.addListener (this);
|
||||
|
||||
addAndMakeVisible (reloadAllButton);
|
||||
reloadAllButton.addListener (this);
|
||||
|
||||
addAndMakeVisible (delButton);
|
||||
delButton.addListener (this);
|
||||
delButton.setEnabled (false);
|
||||
|
||||
addAndMakeVisible (listBox = new TableListBox (String::empty, this));
|
||||
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->setColour (ListBox::backgroundColourId, Colours::lightgrey);
|
||||
listBox->setColour (ListBox::outlineColourId, Colours::darkgrey);
|
||||
listBox->setOutlineThickness (1);
|
||||
listBox->updateContent();
|
||||
|
||||
document.addChangeListener (this);
|
||||
handleCommandMessage (1);
|
||||
}
|
||||
|
||||
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 (TextEditor::highlightColourId));
|
||||
}
|
||||
|
||||
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 (r->data.getSize());
|
||||
|
||||
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 (r->data.getSize());
|
||||
|
||||
widest = jmax (widest, f.getStringWidth (text));
|
||||
}
|
||||
|
||||
return widest + 10;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
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()
|
||||
{
|
||||
listBox->setBounds (6, 4, getWidth() - 12, getHeight() - 38);
|
||||
|
||||
addButton.changeWidthToFitText (22);
|
||||
addButton.setTopLeftPosition (8, getHeight() - 30);
|
||||
|
||||
reloadAllButton.changeWidthToFitText (22);
|
||||
reloadAllButton.setTopLeftPosition (addButton.getRight() + 10, getHeight() - 30);
|
||||
|
||||
delButton.changeWidthToFitText (22);
|
||||
delButton.setTopRightPosition (getWidth() - 8, getHeight() - 30);
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::visibilityChanged()
|
||||
{
|
||||
if (isVisible())
|
||||
listBox->updateContent();
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::changeListenerCallback (ChangeBroadcaster*)
|
||||
{
|
||||
if (isVisible())
|
||||
listBox->updateContent();
|
||||
}
|
||||
|
||||
void ResourceEditorPanel::buttonClicked (Button* b)
|
||||
{
|
||||
if (b == &addButton)
|
||||
{
|
||||
document.getResources()
|
||||
.browseForResource ("Select a file to add as a resource",
|
||||
"*",
|
||||
File::nonexistent,
|
||||
String::empty);
|
||||
}
|
||||
else if (b == &delButton)
|
||||
{
|
||||
document.getResources().remove (listBox->getSelectedRow (0));
|
||||
}
|
||||
else if (b == &reloadAllButton)
|
||||
{
|
||||
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::showMessageBox (AlertWindow::WarningIcon,
|
||||
TRANS("Reloading resources"),
|
||||
TRANS("The following resources couldn't be reloaded from their original files:\n\n")
|
||||
+ failed.joinIntoString (", "));
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_RESOURCEEDITORPANEL_JUCEHEADER__
|
||||
#define __JUCER_RESOURCEEDITORPANEL_JUCEHEADER__
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
//==============================================================================
|
||||
class ResourceEditorPanel : public Component,
|
||||
private TableListBoxModel,
|
||||
private ChangeListener,
|
||||
private ButtonListener
|
||||
{
|
||||
public:
|
||||
ResourceEditorPanel (JucerDocument& document);
|
||||
~ResourceEditorPanel();
|
||||
|
||||
void resized();
|
||||
void visibilityChanged();
|
||||
void changeListenerCallback (ChangeBroadcaster*);
|
||||
void buttonClicked (Button*);
|
||||
|
||||
int getNumRows();
|
||||
void paintRowBackground (Graphics& g, int rowNumber, int width, int height, bool rowIsSelected);
|
||||
void paintCell (Graphics& g, int rowNumber, int columnId, int width, int height, bool rowIsSelected);
|
||||
Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected, Component* existingComponentToUpdate);
|
||||
int getColumnAutoSizeWidth (int columnId);
|
||||
void sortOrderChanged (int newSortColumnId, bool isForwards);
|
||||
void selectedRowsChanged (int lastRowSelected);
|
||||
|
||||
private:
|
||||
JucerDocument& document;
|
||||
ScopedPointer<TableListBox> listBox;
|
||||
TextButton addButton, reloadAllButton, delButton;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_RESOURCEEDITORPANEL_JUCEHEADER__
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_SNAPGRIDPAINTER_JUCEHEADER__
|
||||
#define __JUCER_SNAPGRIDPAINTER_JUCEHEADER__
|
||||
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_SNAPGRIDPAINTER_JUCEHEADER__
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include "../../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 (&lookAndFeel);
|
||||
}
|
||||
|
||||
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 File::nonexistent;
|
||||
|
||||
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 = nullptr;
|
||||
|
||||
filename = newName;
|
||||
lastModificationTime = findFile().getLastModificationTime();
|
||||
|
||||
loadedDocument = 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 ("Introjucer 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();
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
|
||||
Permission is granted to use this software under the terms of either:
|
||||
a) the GPL v2 (or any later version)
|
||||
b) the Affero GPL v3
|
||||
|
||||
Details of these licenses can be found at: www.gnu.org/licenses
|
||||
|
||||
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
To release a closed-source product which uses JUCE, commercial licenses are
|
||||
available: visit www.juce.com for more information.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __JUCER_TESTCOMPONENT_JUCEHEADER__
|
||||
#define __JUCER_TESTCOMPONENT_JUCEHEADER__
|
||||
|
||||
#include "../jucer_JucerDocument.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
*/
|
||||
class TestComponent : public Component
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
TestComponent (JucerDocument* const ownerDocument,
|
||||
JucerDocument* const loadedDocument,
|
||||
const bool alwaysFillBackground);
|
||||
|
||||
~TestComponent();
|
||||
|
||||
//==============================================================================
|
||||
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; }
|
||||
JucerDocument* getOwnerDocument() const noexcept { return ownerDocument; }
|
||||
|
||||
void setToInitialSize();
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g);
|
||||
void resized();
|
||||
|
||||
static void showInDialogBox (JucerDocument& design);
|
||||
|
||||
// reloads any test comps that need to do so
|
||||
static void reloadAll();
|
||||
|
||||
private:
|
||||
JucerDocument* ownerDocument;
|
||||
ScopedPointer<JucerDocument> loadedDocument;
|
||||
String filename, constructorParams;
|
||||
Time lastModificationTime;
|
||||
LookAndFeel_V2 lookAndFeel;
|
||||
const bool alwaysFillBackground;
|
||||
|
||||
void updateContents();
|
||||
void reload();
|
||||
};
|
||||
|
||||
|
||||
#endif // __JUCER_TESTCOMPONENT_JUCEHEADER__
|
||||
Reference in New Issue
Block a user