Browse Source

Jucer development.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
fffa698104
18 changed files with 1257 additions and 250 deletions
  1. +3
    -6
      extras/Jucer (experimental)/Source/model/Component/jucer_ComponentDocument.cpp
  2. +132
    -38
      extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp
  3. +9
    -4
      extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h
  4. +413
    -51
      extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.cpp
  5. +20
    -2
      extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h
  6. +21
    -1
      extras/Jucer (experimental)/Source/model/Project/jucer_Project.cpp
  7. +3
    -0
      extras/Jucer (experimental)/Source/model/Project/jucer_Project.h
  8. +11
    -5
      extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h
  9. +52
    -5
      extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp
  10. +1
    -0
      extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h
  11. +182
    -44
      extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h
  12. +101
    -5
      extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorTreeView.h
  13. +84
    -27
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp
  14. +13
    -3
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h
  15. +49
    -24
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h
  16. +14
    -17
      extras/Jucer (experimental)/Source/ui/Project Editor/jucer_ItemPreviewComponent.cpp
  17. +1
    -2
      extras/Jucer (experimental)/Source/ui/Project Editor/jucer_ItemPreviewComponent.h
  18. +148
    -16
      extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h

+ 3
- 6
extras/Jucer (experimental)/Source/model/Component/jucer_ComponentDocument.cpp View File

@@ -761,10 +761,9 @@ void ComponentDocument::MarkerList::addMarkerMenuItems (const ValueTree& markerS
}
menu.addSeparator();
const MarkerList& markerList = document.getMarkerList (isX);
for (int i = 0; i < markerList.size(); ++i)
document.addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)),
for (int i = 0; i < size(); ++i)
document.addMarkerMenuItem (100 + i, coord, getName (getMarker (i)),
String::empty, menu, isAnchor1, fullCoordName);
}
@@ -773,10 +772,8 @@ const String ComponentDocument::MarkerList::getChosenMarkerMenuItem (const Relat
if (i == 1) return isX ? "parent.left" : "parent.top";
if (i == 2) return isX ? "parent.right" : "parent.bottom";
const MarkerList& markerList = document.getMarkerList (isX);
if (i >= 100 && i < 10000)
return markerList.getName (markerList.getMarker (i - 100));
return getName (getMarker (i - 100));
jassertfalse;
return String::empty;


+ 132
- 38
extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.cpp View File

@@ -56,10 +56,10 @@ DrawableDocument::~DrawableDocument()
root.removeListener (this);
}
void DrawableDocument::recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d)
void DrawableDocument::recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d, StringArray& recentlyUsedIdCache)
{
if (d.getID().isEmpty())
d.setID (createUniqueID (d.getState().getType().toString().toLowerCase() + "1"), 0);
d.setID (createUniqueID (d.getState().getType().toString().toLowerCase() + "1", recentlyUsedIdCache), 0);
if (d.getState().getType() == DrawableComposite::valueTreeType)
{
@@ -68,7 +68,7 @@ void DrawableDocument::recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d)
for (int i = 0; i < composite.getNumDrawables(); ++i)
{
Drawable::ValueTreeWrapperBase child (composite.getDrawableState (i));
recursivelyUpdateIDs (child);
recursivelyUpdateIDs (child, recentlyUsedIdCache);
}
}
}
@@ -85,7 +85,13 @@ void DrawableDocument::checkRootObject()
markersY = new MarkerList (*this, false);
DrawableComposite::ValueTreeWrapper rootObject (getRootDrawableNode());
recursivelyUpdateIDs (rootObject);
StringArray idCache;
recursivelyUpdateIDs (rootObject, idCache);
}
const String DrawableDocument::getUniqueId() const
{
return root [Ids::id_];
}
//==============================================================================
@@ -201,26 +207,59 @@ ValueTree DrawableDocument::findDrawableState (const String& objectId, bool recu
return getRootDrawableNode().getDrawableWithId (objectId, recursive);
}
const String DrawableDocument::createUniqueID (const String& name) const
const String DrawableDocument::createUniqueID (const String& name, StringArray& recentlyUsedIdCache) const
{
String n (CodeHelpers::makeValidIdentifier (name, false, true, false));
int suffix = 2;
int cacheIndex = -1;
const String withoutNumbers (n.trimCharactersAtEnd ("0123456789"));
for (int i = 0; i < recentlyUsedIdCache.size(); ++i)
{
if (recentlyUsedIdCache[i].startsWith (withoutNumbers))
{
cacheIndex = i;
suffix = jmax (suffix, recentlyUsedIdCache[i].substring (withoutNumbers.length()).getIntValue() + 1);
n = withoutNumbers + String (suffix++);
break;
}
}
while (markersX->getMarkerNamed (n).isValid() || markersY->getMarkerNamed (n).isValid()
|| findDrawableState (n, true).isValid())
n = n.trimCharactersAtEnd ("0123456789") + String (suffix++);
n = withoutNumbers + String (suffix++);
if (cacheIndex >= 0)
recentlyUsedIdCache.set (cacheIndex, n);
else
recentlyUsedIdCache.add (n);
return n;
}
bool DrawableDocument::createItemProperties (Array <PropertyComponent*>& props, const String& itemId)
{
ValueTree drawable (findDrawableState (itemId, false));
ValueTree drawable (findDrawableState (itemId.upToFirstOccurrenceOf ("/", false, false), false));
if (drawable.isValid())
{
DrawableTypeInstance item (*this, drawable);
item.createProperties (props);
if (itemId.containsChar ('/'))
{
OwnedArray <ControlPoint> points;
item.getAllControlPoints (points);
for (int i = 0; i < points.size(); ++i)
if (points.getUnchecked(i)->getID() == itemId)
points.getUnchecked(i)->createProperties (*this, props);
}
else
{
item.createProperties (props);
}
return true;
}
@@ -264,8 +303,8 @@ const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode)
Random::getSystemRandom().nextFloat() * 100.0f + 100.0f)));
Drawable::ValueTreeWrapperBase wrapper (state);
recursivelyUpdateIDs (wrapper);
StringArray idCache;
recursivelyUpdateIDs (wrapper, idCache);
getRootDrawableNode().addDrawable (state, -1, getUndoManager());
return state;
@@ -274,15 +313,80 @@ const ValueTree DrawableDocument::performNewItemMenuItem (int menuResultCode)
return ValueTree::invalid;
}
const ValueTree DrawableDocument::insertSVG (const File& file, const Point<float>& position)
{
ScopedPointer<Drawable> d (Drawable::createFromImageFile (file));
DrawableComposite* dc = dynamic_cast <DrawableComposite*> (static_cast <Drawable*> (d));
if (dc != 0)
{
ValueTree state (dc->createValueTree (this));
if (state.isValid())
{
Drawable::ValueTreeWrapperBase wrapper (state);
getRootDrawableNode().addDrawable (state, -1, getUndoManager());
StringArray idCache;
recursivelyUpdateIDs (wrapper, idCache);
return state;
}
}
return ValueTree::invalid;
}
//==============================================================================
const Image DrawableDocument::getImageForIdentifier (const var& imageIdentifier)
{
return ImageCache::getFromMemory (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize);
const String s (imageIdentifier.toString());
if (s.startsWithIgnoreCase ("id:"))
{
jassert (project != 0);
if (project != 0)
{
Project::Item item (project->getMainGroup().findItemWithID (s.substring (3).trim()));
if (item.isValid())
{
Image im (ImageCache::getFromFile (item.getFile()));
if (im.isValid())
{
im.setTag (imageIdentifier);
return im;
}
}
}
}
static Image dummy;
if (dummy.isNull())
{
dummy = Image (Image::ARGB, 128, 128, true);
Graphics g (dummy);
g.fillAll (Colours::khaki.withAlpha (0.51f));
g.setColour (Colours::grey);
g.drawRect (0, 0, 128, 128);
for (int i = -128; i < 128; i += 16)
g.drawLine (i, 0, i + 128, 128);
g.setColour (Colours::darkgrey);
g.drawRect (0, 0, 128, 128);
g.setFont (16.0f, Font::bold);
g.drawText ("(Image Missing)", 0, 0, 128, 128, Justification::centred, false);
}
return dummy;
}
const var DrawableDocument::getIdentifierForImage (const Image& image)
{
return var::null; //xxx todo
return image.getTag();
}
//==============================================================================
@@ -403,50 +507,40 @@ bool DrawableDocument::MarkerList::createProperties (Array <PropertyComponent*>&
return false;
}
void DrawableDocument::addMarkerMenuItem (int i, const RelativeCoordinate& coord, const String& objectName, const String& edge, PopupMenu& menu,
bool isAnchor1, const String& fullCoordName)
void DrawableDocument::MarkerList::addMarkerMenuItem (int i, const RelativeCoordinate& coord, const String& name, const String& edge, PopupMenu& menu,
bool isAnchor1, const String& fullCoordName)
{
// RelativeCoordinate requestedCoord (findNamedCoordinate (objectName, edge, coord.isHorizontal()));
RelativeCoordinate requestedCoord (findNamedCoordinate (name, edge));
// menu.addItem (i, name,
// ! (name == fullCoordName || requestedCoord.referencesIndirectly (fullCoordName, *this)),
// name == (isAnchor1 ? coord.getAnchor1() : coord.getAnchor2()));
menu.addItem (i, edge.isEmpty() ? name : (name + "." + edge),
! (name == fullCoordName || (fullCoordName.isNotEmpty() && requestedCoord.references (fullCoordName, this))),
name == (isAnchor1 ? coord.getAnchorName1() : coord.getAnchorName2()));
}
void DrawableDocument::MarkerList::addMarkerMenuItems (const ValueTree& markerState, const RelativeCoordinate& coord, PopupMenu& menu, bool isAnchor1)
{
/* const String fullCoordName (getName (markerState));
const String fullCoordName (getName (markerState));
if (coord.isHorizontal())
{
document.addMarkerMenuItem (1, coord, "parent", "left", menu, isAnchor1, fullCoordName);
document.addMarkerMenuItem (2, coord, "parent", "right", menu, isAnchor1, fullCoordName);
}
if (isHorizontal())
addMarkerMenuItem (1, coord, "parent", "left", menu, isAnchor1, fullCoordName);
else
{
document.addMarkerMenuItem (1, coord, "parent", "top", menu, isAnchor1, fullCoordName);
document.addMarkerMenuItem (2, coord, "parent", "bottom", menu, isAnchor1, fullCoordName);
}
addMarkerMenuItem (1, coord, "parent", "top", menu, isAnchor1, fullCoordName);
menu.addSeparator();
const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
for (int i = 0; i < markerList.size(); ++i)
document.addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)),
String::empty, menu, isAnchor1, fullCoordName);*/
for (int i = 0; i < size(); ++i)
addMarkerMenuItem (100 + i, coord, getName (getMarker (i)),
String::empty, menu, isAnchor1, fullCoordName);
}
const String DrawableDocument::MarkerList::getChosenMarkerMenuItem (const RelativeCoordinate& coord, int i) const
{
/* if (i == 1) return coord.isHorizontal() ? "parent.left" : "parent.top";
if (i == 2) return coord.isHorizontal() ? "parent.right" : "parent.bottom";
const MarkerList& markerList = document.getMarkerList (coord.isHorizontal());
if (i == 1) return isHorizontal() ? "parent.left" : "parent.top";
if (i >= 100 && i < 10000)
return markerList.getName (markerList.getMarker (i - 100));
return getName (getMarker (i - 100));
jassertfalse;*/
jassertfalse;
return String::empty;
}


+ 9
- 4
extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableDocument.h View File

@@ -49,16 +49,20 @@ public:
bool hasChangedSinceLastSave() const;
void changed();
Project* getProject() const throw() { return project; }
const String getUniqueId() const;
ValueTree& getRoot() { return root; }
DrawableComposite::ValueTreeWrapper getRootDrawableNode() const;
ValueTree findDrawableState (const String& objectId, bool recursive) const;
const String createUniqueID (const String& suggestion) const;
const String createUniqueID (const String& suggestion, StringArray& recentlyUsedIdCache) const;
void createItemProperties (Array <PropertyComponent*>& props, const StringArray& selectedItemIds);
void addNewItemMenuItems (PopupMenu& menu) const;
const ValueTree performNewItemMenuItem (int menuResultCode);
const ValueTree insertSVG (const File& file, const Point<float>& position);
//==============================================================================
class MarkerList : public MarkerListBase
@@ -86,6 +90,9 @@ public:
DrawableDocument& document;
DrawableComposite::ValueTreeWrapper object;
void addMarkerMenuItem (int i, const RelativeCoordinate& coord, const String& objectName, const String& edge,
PopupMenu& menu, bool isAnchor1, const String& fullCoordName);
MarkerList (const MarkerList&);
MarkerList& operator= (const MarkerList&);
};
@@ -116,7 +123,7 @@ private:
bool saveAsXml, needsSaving;
void checkRootObject();
void recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d);
void recursivelyUpdateIDs (Drawable::ValueTreeWrapperBase& d, StringArray& recentlyUsedIdCache);
Value getRootValueUndoable (const Identifier& name) const { return root.getPropertyAsValue (name, getUndoManager()); }
Value getRootValueNonUndoable (const Identifier& name) const { return root.getPropertyAsValue (name, 0); }
@@ -127,8 +134,6 @@ private:
bool createItemProperties (Array <PropertyComponent*>& props, const String& itemId);
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const;
void addMarkerMenuItem (int i, const RelativeCoordinate& coord, const String& objectName, const String& edge,
PopupMenu& menu, bool isAnchor1, const String& fullCoordName);
};


+ 413
- 51
extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.cpp View File

@@ -24,7 +24,92 @@
*/
#include "jucer_DrawableTypeHandler.h"
#include "../../utility/jucer_ColourPropertyComponent.h"
//==============================================================================
class ControlPointPropertyComp : public CoordinatePropertyComponent
{
public:
ControlPointPropertyComp (DrawableTypeInstance& item_, ControlPoint* cp, const String& name, bool isHorizontal_, UndoManager* undoManager)
: CoordinatePropertyComponent (0, name, Value (new CoordExtractor (cp->getPositionValue (undoManager), isHorizontal_)), isHorizontal_),
item (item_)
{
nameSource = &item;
}
~ControlPointPropertyComp()
{
}
const String pickMarker (TextButton* button, const String& currentMarker, bool isAnchor1)
{
RelativeCoordinate coord (getCoordinate());
PopupMenu m;
item.getDocument().getMarkerList (isHorizontal).addMarkerMenuItems (ValueTree::invalid, coord, m, isAnchor1);
const int r = m.showAt (button);
if (r > 0)
return item.getDocument().getMarkerList (isHorizontal).getChosenMarkerMenuItem (coord, r);
return String::empty;
}
DrawableTypeInstance item;
//==============================================================================
class CoordExtractor : public Value::ValueSource,
public Value::Listener
{
public:
CoordExtractor (const Value& sourceValue_, const bool isX_)
: sourceValue (sourceValue_), isX (isX_)
{
sourceValue.addListener (this);
}
~CoordExtractor() {}
const var getValue() const
{
RelativePoint p (sourceValue.toString());
return getCoord (p).toString();
}
void setValue (const var& newValue)
{
RelativePoint p (sourceValue.toString());
RelativeCoordinate& coord = getCoord (p);
coord = RelativeCoordinate (newValue.toString(), isX);
const String newVal (p.toString());
if (sourceValue != newVal)
sourceValue = newVal;
}
void valueChanged (Value&)
{
sendChangeMessage (true);
}
//==============================================================================
juce_UseDebuggingNewOperator
protected:
Value sourceValue;
bool isX;
RelativeCoordinate& getCoord (RelativePoint& p) const
{
return isX ? p.x : p.y;
}
CoordExtractor (const CoordExtractor&);
const CoordExtractor& operator= (const CoordExtractor&);
};
};
//==============================================================================
class DrawablePathHandler : public DrawableTypeHandler
@@ -73,7 +158,8 @@ public:
{
public:
DrawablePathFillPropComp (DrawableTypeInstance& item_, const String& name, const ValueTree& fill)
: FillTypePropertyComponent (item_.getDocument().getUndoManager(), name, fill),
: FillTypePropertyComponent (item_.getDocument().getUndoManager(), name, fill,
&item_.getDocument(), item_.getProject()),
item (item_)
{}
@@ -110,9 +196,9 @@ public:
class GradientControlPoint : public ControlPoint
{
public:
GradientControlPoint (const ValueTree& item_,
GradientControlPoint (const String& id_, const ValueTree& item_,
const bool isStart_, const bool isStroke_)
: item (item_), isStart (isStart_), isStroke (isStroke_)
: ControlPoint (id_), item (item_), isStart (isStart_), isStroke (isStroke_)
{}
~GradientControlPoint() {}
@@ -124,7 +210,8 @@ public:
RelativePoint p;
const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState(),
isStart ? &p : 0,
isStart ? 0 : &p, 0));
isStart ? 0 : &p, 0,
0));
jassert (fill.isGradient());
return p;
}
@@ -135,7 +222,7 @@ public:
RelativePoint p1, p2;
ValueTree fillState (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState());
const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (fillState, &p1, &p2, 0));
const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (fillState, &p1, &p2, 0, 0));
jassert (fill.isGradient());
if (isStart)
@@ -143,11 +230,32 @@ public:
else
p2 = newPoint;
Drawable::ValueTreeWrapperBase::writeFillType (fillState, fill, &p1, &p2, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, fill, &p1, &p2, 0, undoManager);
}
bool hasLine() { return false; }
RelativePoint getEndOfLine() { return RelativePoint(); }
bool hasLine() { return isStart; }
RelativePoint getEndOfLine()
{
RelativePoint p;
DrawablePath::ValueTreeWrapper wrapper (item);
ValueTree fillState (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState());
Drawable::ValueTreeWrapperBase::readFillType (fillState, 0, &p, 0, 0);
return p;
}
const Value getPositionValue (UndoManager* undoManager)
{
DrawablePath::ValueTreeWrapper wrapper (item);
ValueTree fillState (isStroke ? wrapper.getStrokeFillState() : wrapper.getMainFillState());
return fillState.getPropertyAsValue (isStart ? Drawable::ValueTreeWrapperBase::gradientPoint1 : Drawable::ValueTreeWrapperBase::gradientPoint2, undoManager);
}
void createProperties (DrawableDocument& document, Array <PropertyComponent*>& props)
{
DrawableTypeInstance instance (document, item);
props.add (new ControlPointPropertyComp (instance, this, "X", true, document.getUndoManager()));
props.add (new ControlPointPropertyComp (instance, this, "Y", false, document.getUndoManager()));
}
private:
ValueTree item;
@@ -158,8 +266,10 @@ public:
class PathControlPoint : public ControlPoint
{
public:
PathControlPoint (const DrawablePath::ValueTreeWrapper::Element& element_, const int cpNum_)
: element (element_), cpNum (cpNum_)
PathControlPoint (const String& id_,
const DrawablePath::ValueTreeWrapper::Element& element_,
const DrawablePath::ValueTreeWrapper::Element& previousElement_, const int cpNum_, const int numCps_)
: ControlPoint (id_), element (element_), previousElement (previousElement_), cpNum (cpNum_), numCps (numCps_)
{}
~PathControlPoint() {}
@@ -174,45 +284,133 @@ public:
element.setControlPoint (cpNum, newPoint, undoManager);
}
bool hasLine() { return false; }
RelativePoint getEndOfLine() { return RelativePoint(); }
const Value getPositionValue (UndoManager* undoManager)
{
return element.getControlPointValue (cpNum, undoManager);
}
bool hasLine() { return numCps > 1 && cpNum == 0 || cpNum == 1; }
RelativePoint getEndOfLine()
{
if (cpNum == 0)
return previousElement.getEndPoint();
else
return element.getControlPoint (2);
}
void createProperties (DrawableDocument& document, Array <PropertyComponent*>& props)
{
DrawableTypeInstance instance (document, element.getParent().getState());
props.add (new ControlPointPropertyComp (instance, this, "X", true, document.getUndoManager()));
props.add (new ControlPointPropertyComp (instance, this, "Y", false, document.getUndoManager()));
}
private:
DrawablePath::ValueTreeWrapper::Element element;
int cpNum;
DrawablePath::ValueTreeWrapper::Element element, previousElement;
int cpNum, numCps;
};
void getGradientControlPoints (DrawablePath::ValueTreeWrapper& wrapper, DrawableTypeInstance& item,
OwnedArray <ControlPoint>& points, const String& itemId)
{
const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getMainFillState(), 0, 0, 0, 0));
if (fill.isGradient())
{
points.add (new GradientControlPoint (itemId + "/gf1", item.getState(), true, false));
points.add (new GradientControlPoint (itemId + "/gf2", item.getState(), false, false));
}
const FillType stroke (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getStrokeFillState(), 0, 0, 0, 0));
if (stroke.isGradient())
{
points.add (new GradientControlPoint (itemId + "/gs1", item.getState(), true, true));
points.add (new GradientControlPoint (itemId + "/gs1", item.getState(), false, true));
}
}
void getAllControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points)
{
DrawablePath::ValueTreeWrapper wrapper (item.getState());
const ValueTree pathTree (wrapper.getPathState());
const int numElements = pathTree.getNumChildren();
const String itemId (item.getID());
for (int i = 0; i < numElements; ++i)
if (numElements > 0)
{
const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
const int numCps = e.getNumControlPoints();
DrawablePath::ValueTreeWrapper::Element last (pathTree.getChild(0));
for (int j = 0; j < numCps; ++j)
points.add (new PathControlPoint (e, j));
}
for (int i = 0; i < numElements; ++i)
{
const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
const int numCps = e.getNumControlPoints();
const FillType fill (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getMainFillState(), 0, 0, 0));
for (int j = 0; j < numCps; ++j)
points.add (new PathControlPoint (itemId + "/" + String(i) + "/" + String(j), e, last, j, numCps));
if (fill.isGradient())
{
points.add (new GradientControlPoint (item.getState(), true, false));
points.add (new GradientControlPoint (item.getState(), false, false));
last = e;
}
}
const FillType stroke (Drawable::ValueTreeWrapperBase::readFillType (wrapper.getStrokeFillState(), 0, 0, 0));
getGradientControlPoints (wrapper, item, points, itemId);
}
if (stroke.isGradient())
void getVisibleControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems& selection)
{
DrawablePath::ValueTreeWrapper wrapper (item.getState());
const ValueTree pathTree (wrapper.getPathState());
const int numElements = pathTree.getNumChildren();
const String itemId (item.getID());
if (numElements > 0)
{
points.add (new GradientControlPoint (item.getState(), true, true));
points.add (new GradientControlPoint (item.getState(), false, true));
DrawablePath::ValueTreeWrapper::Element last (pathTree.getChild(0));
bool lastWasSelected = false;
for (int i = 0; i < numElements; ++i)
{
const String elementIdRoot (itemId + "/" + String(i) + "/");
const DrawablePath::ValueTreeWrapper::Element e (pathTree.getChild(i));
int numCps = e.getNumControlPoints();
bool pointIsSelected = false;
for (int k = numCps; --k >= 0;)
{
if (selection.isSelected (elementIdRoot + String (k)))
{
pointIsSelected = true;
break;
}
}
if (numCps > 1)
{
if (pointIsSelected || lastWasSelected)
{
for (int j = 0; j < numCps; ++j)
points.add (new PathControlPoint (elementIdRoot + String(j), e, last, j, numCps));
}
else
{
points.add (new PathControlPoint (elementIdRoot + String (numCps - 1), e, last, numCps - 1, numCps));
}
}
else
{
for (int j = 0; j < numCps; ++j)
points.add (new PathControlPoint (elementIdRoot + String(j), e, last, j, numCps));
}
last = e;
lastWasSelected = pointIsSelected;
}
}
getGradientControlPoints (wrapper, item, points, itemId);
}
};
@@ -244,6 +442,34 @@ public:
void createPropertyEditors (DrawableTypeInstance& item, Array <PropertyComponent*>& props)
{
DrawableImage::ValueTreeWrapper wrapper (item.getState());
if (item.getDocument().getProject() != 0)
{
OwnedArray<Project::Item> images;
item.getDocument().getProject()->findAllImageItems (images);
StringArray choices;
Array<var> ids;
for (int i = 0; i < images.size(); ++i)
{
choices.add (images.getUnchecked(i)->getName().toString());
ids.add (images.getUnchecked(i)->getImageFileID());
}
props.add (new ChoicePropertyComponent (wrapper.getImageIdentifierValue (item.getDocument().getUndoManager()),
"Image", choices, ids));
}
props.add (new SliderPropertyComponent (wrapper.getOpacityValue (item.getDocument().getUndoManager()),
"Opacity", 0, 1.0, 0.001));
props.add (new ColourPropertyComponent (item.getDocument().getUndoManager(), "Overlay Colour",
wrapper.getOverlayColourValue (item.getDocument().getUndoManager()),
Colours::transparentBlack, true));
props.add (new ResetButtonPropertyComponent (item, wrapper));
}
void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
@@ -254,8 +480,8 @@ public:
class ImageControlPoint : public ControlPoint
{
public:
ImageControlPoint (const DrawableTypeInstance& item_, const int cpNum_)
: item (item_), cpNum (cpNum_)
ImageControlPoint (const String& id_, const DrawableTypeInstance& item_, const int cpNum_)
: ControlPoint (id_), item (item_), cpNum (cpNum_)
{}
~ImageControlPoint() {}
@@ -288,9 +514,29 @@ public:
}
}
const Value getPositionValue (UndoManager* undoManager)
{
DrawableImage::ValueTreeWrapper wrapper (item.getState());
switch (cpNum)
{
case 0: return item.getState().getPropertyAsValue (DrawableImage::ValueTreeWrapper::topLeft, undoManager);
case 1: return item.getState().getPropertyAsValue (DrawableImage::ValueTreeWrapper::topRight, undoManager);
case 2: return item.getState().getPropertyAsValue (DrawableImage::ValueTreeWrapper::bottomLeft, undoManager);
default: jassertfalse; break;
}
return Value();
}
bool hasLine() { return false; }
RelativePoint getEndOfLine() { return RelativePoint(); }
void createProperties (DrawableDocument& document, Array <PropertyComponent*>& props)
{
props.add (new ControlPointPropertyComp (item, this, "X", true, document.getUndoManager()));
props.add (new ControlPointPropertyComp (item, this, "Y", false, document.getUndoManager()));
}
private:
DrawableTypeInstance item;
int cpNum;
@@ -298,9 +544,52 @@ public:
void getAllControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points)
{
const String itemIDRoot (item.getID() + "/");
for (int i = 0; i < 3; ++i)
points.add (new ImageControlPoint (item, i));
points.add (new ImageControlPoint (itemIDRoot + String (i), item, i));
}
void getVisibleControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems&)
{
return getAllControlPoints (item, points);
}
//==============================================================================
class ResetButtonPropertyComponent : public ButtonPropertyComponent
{
public:
ResetButtonPropertyComponent (DrawableTypeInstance& item_,
const DrawableImage::ValueTreeWrapper& wrapper_)
: ButtonPropertyComponent ("Reset", false),
item (item_), wrapper (wrapper_)
{
}
const String getButtonText() const { return "Reset to Original Size"; }
void buttonClicked()
{
Image im (item.getDocument().getImageForIdentifier (wrapper.getImageIdentifier()));
if (im.isValid())
{
RelativePoint topLeft (wrapper.getTargetPositionForTopLeft());
RelativePoint topRight (wrapper.getTargetPositionForTopRight());
RelativePoint bottomLeft (wrapper.getTargetPositionForBottomLeft());
topRight.moveToAbsolute (topLeft.resolve (&item) + Point<float> (im.getWidth(), 0.0f), &item);
bottomLeft.moveToAbsolute (topLeft.resolve (&item) + Point<float> (0.0f, im.getHeight()), &item);
wrapper.setTargetPositionForTopRight (topRight, item.getDocument().getUndoManager());
wrapper.setTargetPositionForBottomLeft (bottomLeft, item.getDocument().getUndoManager());
}
}
private:
DrawableTypeInstance item;
DrawableImage::ValueTreeWrapper wrapper;
};
};
//==============================================================================
@@ -312,33 +601,20 @@ public:
void createPropertyEditors (DrawableTypeInstance& item, Array <PropertyComponent*>& props)
{
DrawableComposite::ValueTreeWrapper wrapper (item.getState());
props.add (new ResetButtonPropertyComponent (item, wrapper));
}
void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)
{
}
const RelativeCoordinate findNamedCoordinate (const DrawableTypeInstance& item, const String& objectName, const String& edge) const
{
DrawableComposite::ValueTreeWrapper wrapper (const_cast <DrawableTypeInstance&> (item).getState());
ValueTree markerState (wrapper.getMarkerState (true, objectName));
if (markerState.isValid())
return wrapper.getMarker (true, markerState).position;
markerState = wrapper.getMarkerState (false, objectName);
if (markerState.isValid())
return wrapper.getMarker (false, markerState).position;
return RelativeCoordinate();
}
//==============================================================================
class CompositeControlPoint : public ControlPoint
{
public:
CompositeControlPoint (const ValueTree& item_, const int cpNum_)
: item (item_), cpNum (cpNum_)
CompositeControlPoint (const String& id_, const ValueTree& item_, const int cpNum_)
: ControlPoint (id_), item (item_), cpNum (cpNum_)
{}
~CompositeControlPoint() {}
@@ -371,9 +647,22 @@ public:
}
}
const Value getPositionValue (UndoManager* undoManager)
{
jassertfalse
return Value();
}
bool hasLine() { return false; }
RelativePoint getEndOfLine() { return RelativePoint(); }
void createProperties (DrawableDocument& document, Array <PropertyComponent*>& props)
{
DrawableTypeInstance instance (document, item);
props.add (new ControlPointPropertyComp (instance, this, "X", true, document.getUndoManager()));
props.add (new ControlPointPropertyComp (instance, this, "Y", false, document.getUndoManager()));
}
private:
ValueTree item;
int cpNum;
@@ -381,9 +670,47 @@ public:
void getAllControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points)
{
const String itemIDRoot (item.getID() + "/");
for (int i = 0; i < 3; ++i)
points.add (new CompositeControlPoint (item.getState(), i));
points.add (new CompositeControlPoint (itemIDRoot + String(i), item.getState(), i));
}
void getVisibleControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems&)
{
return getAllControlPoints (item, points);
}
//==============================================================================
class ResetButtonPropertyComponent : public ButtonPropertyComponent
{
public:
ResetButtonPropertyComponent (DrawableTypeInstance& item_,
const DrawableComposite::ValueTreeWrapper& wrapper_)
: ButtonPropertyComponent ("Reset", false),
item (item_), wrapper (wrapper_)
{
}
const String getButtonText() const { return "Reset to Original Size"; }
void buttonClicked()
{
RelativePoint topLeft (wrapper.getTargetPositionForOrigin());
RelativePoint topRight (wrapper.getTargetPositionForX1Y0());
RelativePoint bottomLeft (wrapper.getTargetPositionForX0Y1());
topRight.moveToAbsolute (topLeft.resolve (&item) + Point<float> (1.0f, 0.0f), &item);
bottomLeft.moveToAbsolute (topLeft.resolve (&item) + Point<float> (0.0f, 1.0f), &item);
wrapper.setTargetPositionForX1Y0 (topRight, item.getDocument().getUndoManager());
wrapper.setTargetPositionForX0Y1 (bottomLeft, item.getDocument().getUndoManager());
}
private:
DrawableTypeInstance item;
DrawableComposite::ValueTreeWrapper wrapper;
};
};
@@ -459,7 +786,21 @@ DrawableTypeHandler* DrawableTypeInstance::getHandler() const
const RelativeCoordinate DrawableTypeInstance::findNamedCoordinate (const String& objectName, const String& edge) const
{
return getHandler()->findNamedCoordinate (*this, objectName, edge);
ValueTree v (state);
while (v.getParent().isValid() && ! v.hasType (DrawableComposite::valueTreeType))
v = v.getParent();
DrawableComposite::ValueTreeWrapper wrapper (v);
ValueTree markerState (wrapper.getMarkerState (true, objectName));
if (markerState.isValid())
return wrapper.getMarker (true, markerState).position;
markerState = wrapper.getMarkerState (false, objectName);
if (markerState.isValid())
return wrapper.getMarker (false, markerState).position;
return RelativeCoordinate();
}
const Rectangle<float> DrawableTypeInstance::getBounds()
@@ -485,7 +826,28 @@ void DrawableTypeInstance::setBounds (Drawable* drawable, const Rectangle<float>
return getHandler()->setBounds (*this, drawable, newBounds);
}
void DrawableTypeInstance::applyTransform (Drawable* drawable, const AffineTransform& transform)
{
OwnedArray <ControlPoint> points;
getAllControlPoints (points);
for (int i = points.size(); --i >= 0;)
{
RelativePoint rp (points.getUnchecked(i)->getPosition());
Point<float> p (rp.resolve (drawable->getParent()));
p.applyTransform (transform);
rp.moveToAbsolute (p, drawable->getParent());
points.getUnchecked(i)->setPosition (rp, document.getUndoManager());
}
}
void DrawableTypeInstance::getAllControlPoints (OwnedArray <ControlPoint>& points)
{
return getHandler()->getAllControlPoints (*this, points);
}
void DrawableTypeInstance::getVisibleControlPoints (OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems& selection)
{
return getHandler()->getVisibleControlPoints (*this, points, selection);
}

+ 20
- 2
extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h View File

@@ -28,22 +28,36 @@
#include "jucer_DrawableDocument.h"
#include "../../utility/jucer_FillTypePropertyComponent.h"
#include "../../ui/Editor Base/jucer_EditorCanvas.h"
class DrawableTypeHandler;
//==============================================================================
class ControlPoint
{
public:
ControlPoint() {}
ControlPoint (const String& pointID_) : pointID (pointID_) {}
virtual ~ControlPoint() {}
const String& getID() const throw() { return pointID; }
virtual const RelativePoint getPosition() = 0;
virtual void setPosition (const RelativePoint& newPoint, UndoManager* undoManager) = 0;
virtual bool hasLine() = 0;
virtual RelativePoint getEndOfLine() = 0;
virtual const Value getPositionValue (UndoManager* undoManager) = 0;
virtual void createProperties (DrawableDocument& document, Array <PropertyComponent*>& props) = 0;
private:
const String pointID;
ControlPoint (const ControlPoint&);
ControlPoint& operator= (const ControlPoint&);
};
//==============================================================================
class DrawableTypeInstance : public RelativeCoordinate::NamedCoordinateFinder
{
@@ -52,13 +66,17 @@ public:
//==============================================================================
DrawableDocument& getDocument() throw() { return document; }
Project* getProject() { return document.getProject(); }
ValueTree& getState() throw() { return state; }
const String getID() const { return Drawable::ValueTreeWrapperBase (state).getID(); }
Value getValue (const Identifier& name) const;
void createProperties (Array <PropertyComponent*>& props);
const Rectangle<float> getBounds();
void setBounds (Drawable* drawable, const Rectangle<float>& newBounds);
void applyTransform (Drawable* drawable, const AffineTransform& transform);
void getAllControlPoints (OwnedArray <ControlPoint>& points);
void getVisibleControlPoints (OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems& selection);
const RelativeCoordinate findNamedCoordinate (const String& objectName, const String& edge) const;
@@ -87,7 +105,7 @@ public:
virtual void createPropertyEditors (DrawableTypeInstance& item, Array <PropertyComponent*>& props) = 0;
virtual void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item) = 0;
virtual void getAllControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points) = 0;
virtual const RelativeCoordinate findNamedCoordinate (const DrawableTypeInstance& item, const String& objectName, const String& edge) const { return RelativeCoordinate(); }
virtual void getVisibleControlPoints (DrawableTypeInstance& item, OwnedArray <ControlPoint>& points, const EditorCanvasBase::SelectedItems& selection) = 0;
const String& getDisplayName() const { return displayName; }
const Identifier& getValueTreeType() const { return valueTreeType; }


+ 21
- 1
extras/Jucer (experimental)/Source/model/Project/jucer_Project.cpp View File

@@ -411,6 +411,25 @@ Project::Item Project::createNewItem (const File& file)
return item;
}
static void findImages (const Project::Item& item, OwnedArray<Project::Item>& found)
{
if (item.isFile())
{
if (item.getFile().hasFileExtension ("png;jpg;jpeg;gif"))
found.add (new Project::Item (item));
}
else if (item.isGroup())
{
for (int i = 0; i < item.getNumChildren(); ++i)
findImages (item.getChild (i), found);
}
}
void Project::findAllImageItems (OwnedArray<Project::Item>& items)
{
findImages (getMainGroup(), items);
}
//==============================================================================
Project::Item::Item (Project& project_, const ValueTree& node_)
: project (project_), node (node_)
@@ -426,7 +445,8 @@ Project::Item::~Item()
{
}
const String Project::Item::getID() const { return node [Ids::id_]; }
const String Project::Item::getID() const { return node [Ids::id_]; }
const String Project::Item::getImageFileID() const { return "id:" + getID(); }
bool Project::Item::isFile() const { return node.hasType (Tags::file); }
bool Project::Item::isGroup() const { return node.hasType (Tags::group) || isMainGroup(); }


+ 3
- 0
extras/Jucer (experimental)/Source/model/Project/jucer_Project.h View File

@@ -166,6 +166,7 @@ public:
const String getID() const;
Item findItemWithID (const String& targetId) const; // (recursive search)
const String getImageFileID() const;
//==============================================================================
Value getName() const;
@@ -207,6 +208,8 @@ public:
Item createNewGroup();
Item createNewItem (const File& file);
void findAllImageItems (OwnedArray<Item>& items);
//==============================================================================
class BuildConfiguration
{


+ 11
- 5
extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h View File

@@ -175,10 +175,10 @@ public:
{
public:
DragOperation (ComponentEditorCanvas* canvas_,
const MouseEvent& e, const Point<int>& mousePos,
const Point<int>& mousePos,
Component* snapGuideParentComp_,
const ResizableBorderComponent::Zone& zone_)
: EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_)
: EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, false)
{
}
@@ -262,12 +262,18 @@ public:
ComponentDocument& doc = getDocument();
return (float) doc.getMarkerList (isX).getCoordinate (marker).resolve (&doc);
}
void transformObject (ValueTree& state, const AffineTransform& transform)
{
}
};
DragOperation* createDragOperation (const MouseEvent& e, Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone)
bool canRotate() const { return false; }
DragOperation* createDragOperation (const Point<int>& mouseDownPos, Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone, bool isRotating)
{
DragOperation* d = new DragOperation (this, e, e.getPosition() - origin, snapGuideParentComponent, zone);
DragOperation* d = new DragOperation (this, mouseDownPos, snapGuideParentComponent, zone);
Array<ValueTree> selected, unselected;


+ 52
- 5
extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.cpp View File

@@ -115,14 +115,57 @@ const StringArray DrawableEditor::getSelectedIds() const
void DrawableEditor::deleteSelection()
{
getUndoManager()->beginNewTransaction();
DrawableComposite::ValueTreeWrapper root (getDocument().getRootDrawableNode());
const StringArray ids (getSelectedIds());
for (int i = ids.size(); --i >= 0;)
{
const ValueTree v (root.getDrawableWithId (ids[i], false));
root.removeDrawable (v, getUndoManager());
}
getUndoManager()->beginNewTransaction();
}
void DrawableEditor::selectionToFront()
{
getUndoManager()->beginNewTransaction();
DrawableComposite::ValueTreeWrapper root (getDocument().getRootDrawableNode());
int index = 0;
for (int i = root.getNumDrawables(); --i >= 0;)
{
const Drawable::ValueTreeWrapperBase d (root.getDrawableState (index));
if (getSelection().isSelected (d.getID()))
root.moveDrawableOrder (index, -1, getUndoManager());
else
++index;
}
getUndoManager()->beginNewTransaction();
}
void DrawableEditor::selectionToBack()
{
getUndoManager()->beginNewTransaction();
DrawableComposite::ValueTreeWrapper root (getDocument().getRootDrawableNode());
int index = root.getNumDrawables() - 1;
for (int i = root.getNumDrawables(); --i >= 0;)
{
const Drawable::ValueTreeWrapperBase d (root.getDrawableState (index));
if (getSelection().isSelected (d.getID()))
root.moveDrawableOrder (index, 0, getUndoManager());
else
--index;
}
getUndoManager()->beginNewTransaction();
}
void DrawableEditor::showNewShapeMenu (Component* componentToAttachTo)
@@ -130,7 +173,11 @@ void DrawableEditor::showNewShapeMenu (Component* componentToAttachTo)
PopupMenu m;
getDocument().addNewItemMenuItems (m);
const int r = m.showAt (componentToAttachTo);
getDocument().performNewItemMenuItem (r);
ValueTree newItem (getDocument().performNewItemMenuItem (r));
if (newItem.isValid())
getSelection().selectOnly (Drawable::ValueTreeWrapperBase (newItem).getID());
}
//==============================================================================
@@ -213,13 +260,13 @@ bool DrawableEditor::perform (const InvocationInfo& info)
switch (info.commandID)
{
case CommandIDs::undo:
getDocument().getUndoManager()->beginNewTransaction();
getDocument().getUndoManager()->undo();
getUndoManager()->beginNewTransaction();
getUndoManager()->undo();
return true;
case CommandIDs::redo:
getDocument().getUndoManager()->beginNewTransaction();
getDocument().getUndoManager()->redo();
getUndoManager()->beginNewTransaction();
getUndoManager()->redo();
return true;
case CommandIDs::toFront:


+ 1
- 0
extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditor.h View File

@@ -59,6 +59,7 @@ public:
//==============================================================================
DrawableDocument& getDocument() const { return *drawableDocument; }
UndoManager* getUndoManager() const { return getDocument().getUndoManager(); }
EditorCanvasBase::SelectedItems& getSelection() { return selection; }


+ 182
- 44
extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h View File

@@ -32,6 +32,7 @@
//==============================================================================
class DrawableEditorCanvas : public EditorCanvasBase,
public FileDragAndDropTarget,
public Timer
{
public:
@@ -124,9 +125,7 @@ public:
}
else
{
getDocument().addNewItemMenuItems (m);
const int r = m.show();
getDocument().performNewItemMenuItem (r);
editor.showNewShapeMenu (0);
}
}
@@ -210,6 +209,21 @@ public:
return getObjectPositionFloat (state).getSmallestIntegerContainer();
}
void transformObject (ValueTree& state, const AffineTransform& transform)
{
if (drawable != 0)
{
Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
if (d != 0)
{
d->refreshFromValueTree (state, &getDocument());
DrawableTypeInstance di (getDocument(), state);
di.applyTransform (d, transform);
}
}
}
RelativeRectangle getObjectCoords (const ValueTree& state)
{
return RelativeRectangle();
@@ -221,9 +235,10 @@ public:
public:
ControlPointComponent (DrawableEditorCanvas* canvas, const ValueTree& drawableState_, int controlPointNum_)
: OverlayItemComponent (canvas), drawableState (drawableState_),
controlPointNum (controlPointNum_), isDragging (false), mouseDownResult (false), selected (false)
controlPointNum (controlPointNum_), isDragging (false), mouseDownResult (false), selected (false),
sizeNormal (7), sizeOver (11)
{
selectionId = getControlPointId (drawableState, controlPointNum);
setRepaintsOnMouseActivity (true);
}
~ControlPointComponent()
@@ -232,11 +247,24 @@ public:
void paint (Graphics& g)
{
Rectangle<int> r (getLocalBounds());
if (! isMouseOverOrDragging())
r = r.reduced ((sizeOver - sizeNormal) / 2, (sizeOver - sizeNormal) / 2);
g.setColour (Colour (selected ? 0xaaaaaaaa : 0xaa333333));
g.drawRect (0, 0, getWidth(), getHeight());
g.drawRect (r);
g.setColour (Colour (selected ? 0xaa000000 : 0x99ffffff));
g.fillRect (1, 1, getWidth() - 2, getHeight() - 2);
g.fillRect (r.reduced (1, 1));
}
bool hitTest (int x, int y)
{
if (isMouseOverOrDragging())
return true;
return getLocalBounds().reduced ((sizeOver - sizeNormal) / 2, (sizeOver - sizeNormal) / 2).contains (x, y);
}
void mouseDown (const MouseEvent& e)
@@ -261,7 +289,7 @@ public:
isDragging = true;
canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()).getEventRelativeTo (getParentComponent()),
ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre));
ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre), false, Point<float>());
}
if (isDragging)
@@ -273,9 +301,12 @@ public:
void mouseUp (const MouseEvent& e)
{
if (isDragging)
if (! e.mods.isPopupMenu())
{
canvas->endDrag (e.getEventRelativeTo (getParentComponent()));
if (isDragging)
canvas->endDrag (e.getEventRelativeTo (getParentComponent()));
else
canvas->getSelection().addToSelectionOnMouseUp (selectionId, e.mods, false, mouseDownResult);
}
}
@@ -283,10 +314,50 @@ public:
{
}
class LineComponent : public OverlayItemComponent
{
public:
LineComponent (EditorCanvasBase* canvas)
: OverlayItemComponent (canvas)
{}
~LineComponent() {}
void setLine (const Line<float>& newLine)
{
if (line != newLine)
{
line = newLine;
setBoundsInTargetSpace (Rectangle<float> (line.getStart(), line.getEnd())
.getSmallestIntegerContainer().expanded (2, 2));
repaint();
}
}
void paint (Graphics& g)
{
g.setColour (Colours::black.withAlpha (0.6f));
g.drawLine (Line<float> (pointToLocalSpace (line.getStart()),
pointToLocalSpace (line.getEnd())), 1.0f);
}
bool hitTest (int, int)
{
return false;
}
private:
Line<float> line;
};
void updatePosition (ControlPoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
{
selectionId = point.getID();
const Point<float> p (point.getPosition().resolve (nameFinder));
setBoundsInTargetSpace (Rectangle<int> (roundToInt (p.getX()) - 2, roundToInt (p.getY()) - 2, 7, 7));
setBoundsInTargetSpace (Rectangle<int> (roundToInt (p.getX()) - sizeOver / 2,
roundToInt (p.getY()) - sizeOver / 2,
sizeOver, sizeOver));
const bool nowSelected = canvas->getSelection().isSelected (selectionId);
@@ -295,6 +366,21 @@ public:
selected = nowSelected;
repaint();
}
if (point.hasLine())
{
if (line == 0)
{
line = new LineComponent (canvas);
getParentComponent()->addAndMakeVisible (line, 0);
}
line->setLine (Line<float> (p, point.getEndOfLine().resolve (nameFinder)));
}
else
{
line = 0;
}
}
private:
@@ -302,6 +388,8 @@ public:
int controlPointNum;
bool isDragging, mouseDownResult, selected;
String selectionId;
ScopedPointer <LineComponent> line;
const int sizeNormal, sizeOver;
};
void updateControlPointComponents (Component* parent, OwnedArray<OverlayItemComponent>& comps)
@@ -314,7 +402,7 @@ public:
DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
OwnedArray <ControlPoint> points;
item.getAllControlPoints (points);
item.getVisibleControlPoints (points, getSelection());
Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (controlPointEditingTarget).getID());
DrawableComposite* parentDrawable = d->getParent();
@@ -366,12 +454,31 @@ public:
if (drawable != 0)
{
for (int i = drawable->getNumDrawables(); --i >= 0;)
if (isControlPointMode())
{
Drawable* d = drawable->getDrawable (i);
DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
OwnedArray <ControlPoint> points;
item.getVisibleControlPoints (points, getSelection());
const Rectangle<float> floatArea (area.toFloat());
for (int i = 0; i < points.size(); ++i)
{
const Point<float> p (points.getUnchecked(i)->getPosition().resolve (drawable));
if (floatArea.contains (p))
itemsFound.add (points.getUnchecked(i)->getID());
}
}
else
{
for (int i = drawable->getNumDrawables(); --i >= 0;)
{
Drawable* d = drawable->getDrawable (i);
if (d->getBounds().intersects (floatArea))
itemsFound.add (d->getName());
if (d->getBounds().intersects (floatArea))
itemsFound.add (d->getName());
}
}
}
}
@@ -381,20 +488,14 @@ public:
return itemId.containsChar ('/');
}
static const String getControlPointId (const ValueTree& drawableState, int index)
{
return Drawable::ValueTreeWrapperBase (drawableState).getID() + "/" + String (index);
}
//==============================================================================
class ObjectDragOperation : public EditorDragOperation
{
public:
ObjectDragOperation (DrawableEditorCanvas* canvas_,
const MouseEvent& e, const Point<int>& mousePos,
Component* snapGuideParentComp_,
const ResizableBorderComponent::Zone& zone_)
: EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_), drawableCanvas (canvas_)
ObjectDragOperation (DrawableEditorCanvas* canvas_, const Point<int>& mousePos,
Component* snapGuideParentComp_, const ResizableBorderComponent::Zone& zone_, bool isRotating)
: EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, isRotating),
drawableCanvas (canvas_)
{
}
@@ -423,6 +524,11 @@ public:
drawableCanvas->setObjectPositionFloat (state, newBounds);
}
void transformObject (ValueTree& state, const AffineTransform& transform)
{
drawableCanvas->transformObject (state, transform);
}
float getMarkerPosition (const ValueTree& marker, bool isX)
{
return 0;
@@ -438,14 +544,14 @@ public:
public:
ControlPointDragOperation (DrawableEditorCanvas* canvas_,
const DrawableTypeInstance& drawableItem_,
Drawable* drawable_,
const MouseEvent& e, const Point<int>& mousePos,
DrawableComposite* drawable_,
const Point<int>& mousePos,
Component* snapGuideParentComp_,
const ResizableBorderComponent::Zone& zone_)
: EditorDragOperation (canvas_, e, mousePos, snapGuideParentComp_, zone_),
: EditorDragOperation (canvas_, mousePos, snapGuideParentComp_, zone_, false),
drawableCanvas (canvas_), drawableItem (drawableItem_), drawable (drawable_)
{
drawableItem.getAllControlPoints (points);
drawableItem.getVisibleControlPoints (points, canvas_->getSelection());
}
~ControlPointDragOperation() {}
@@ -467,27 +573,31 @@ public:
const Rectangle<float> getObjectPosition (const ValueTree& state)
{
int index = state [Ids::id_].toString().fromFirstOccurrenceOf ("/", false, false).getIntValue();
int index = state [Ids::id_];
ControlPoint* cp = points[index];
if (cp == 0)
return Rectangle<float>();
Point<float> p (cp->getPosition().resolve (drawable->getParent()));
Point<float> p (cp->getPosition().resolve (drawable));
return Rectangle<float> (p, p);
}
void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds)
{
int index = state [Ids::id_].toString().fromFirstOccurrenceOf ("/", false, false).getIntValue();
int index = state [Ids::id_];
ControlPoint* cp = points[index];
if (cp != 0)
{
RelativePoint p (cp->getPosition());
p.moveToAbsolute (newBounds.getPosition(), drawable->getParent());
p.moveToAbsolute (newBounds.getPosition(), drawable);
cp->setPosition (p, getDocument().getUndoManager());
}
}
void transformObject (ValueTree& state, const AffineTransform& transform)
{
}
float getMarkerPosition (const ValueTree& marker, bool isX)
{
return 0;
@@ -496,30 +606,30 @@ public:
private:
DrawableEditorCanvas* drawableCanvas;
DrawableTypeInstance drawableItem;
Drawable* drawable;
DrawableComposite* drawable;
};
//==============================================================================
DragOperation* createDragOperation (const MouseEvent& e, Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone)
bool canRotate() const { return true; }
DragOperation* createDragOperation (const Point<int>& mouseDownPos, Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone, bool isRotating)
{
Array<ValueTree> selected, unselected;
EditorDragOperation* drag = 0;
if (isControlPointMode())
{
Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (controlPointEditingTarget).getID());
DrawableTypeInstance item (getDocument(), controlPointEditingTarget);
ControlPointDragOperation* cpd = new ControlPointDragOperation (this, item, d, e, e.getPosition() - origin, snapGuideParentComponent, zone);
ControlPointDragOperation* cpd = new ControlPointDragOperation (this, item, drawable, mouseDownPos, snapGuideParentComponent, zone);
drag = cpd;
for (int i = 0; i < cpd->points.size(); ++i)
{
const String pointId (getControlPointId (item.getState(), i));
const String pointId (cpd->points.getUnchecked(i)->getID());
ValueTree v (Ids::controlPoint);
v.setProperty (Ids::id_, pointId, 0);
v.setProperty (Ids::id_, i, 0);
if (editor.getSelection().isSelected (pointId))
selected.add (v);
@@ -529,9 +639,8 @@ public:
}
else
{
drag = new ObjectDragOperation (this, e, e.getPosition() - origin, snapGuideParentComponent, zone);
DrawableComposite::ValueTreeWrapper mainGroup (getDocument().getRootDrawableNode());
drag = new ObjectDragOperation (this, mouseDownPos, snapGuideParentComponent, zone, isRotating);
for (int i = mainGroup.getNumDrawables(); --i >= 0;)
{
@@ -556,6 +665,35 @@ public:
getUndoManager().beginNewTransaction();
}
//==============================================================================
bool isInterestedInFileDrag (const StringArray& files)
{
for (int i = files.size(); --i >= 0;)
if (File (files[i]).hasFileExtension ("svg;jpg;jpeg;gif;png"))
return true;
return false;
}
void filesDropped (const StringArray& files, int x, int y)
{
for (int i = files.size(); --i >= 0;)
{
const File f (files[i]);
if (f.hasFileExtension ("svg"))
{
ValueTree newItem (getDocument().insertSVG (f, screenSpaceToObjectSpace (Point<int> (x, y).toFloat())));
if (newItem.isValid())
getSelection().selectOnly (Drawable::ValueTreeWrapperBase (newItem).getID());
}
else if (f.hasFileExtension ("jpg;jpeg;gif;png"))
{
}
}
}
//==============================================================================
class DrawableComponent : public Component
{


+ 101
- 5
extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorTreeView.h View File

@@ -32,7 +32,8 @@
*/
class DrawableTreeViewItem : public JucerTreeViewBase,
public ValueTree::Listener,
public ChangeListener
public ChangeListener,
public AsyncUpdater
{
public:
DrawableTreeViewItem (DrawableEditor& editor_, const ValueTree& drawableRoot)
@@ -51,18 +52,25 @@ public:
//==============================================================================
void valueTreePropertyChanged (ValueTree& tree, const Identifier& property)
{
if (property == Drawable::ValueTreeWrapperBase::idProperty)
repaintItem();
}
void valueTreeChildrenChanged (ValueTree& tree)
{
if (tree == node.getState())
refreshSubItems();
if (tree == node.getState() || tree.isAChildOf (node.getState()))
triggerAsyncUpdate();
}
void valueTreeParentChanged (ValueTree& tree)
{
}
void handleAsyncUpdate()
{
refreshSubItems();
}
//==============================================================================
// TreeViewItem stuff..
bool mightContainSubItems()
@@ -157,9 +165,14 @@ public:
return String::empty;
}
static const String getDragIdFor (DrawableEditor& editor)
{
return drawableItemDragType + editor.getDocument().getUniqueId();
}
const String getDragSourceDescription()
{
return drawableItemDragType;
return getDragIdFor (editor);
}
//==============================================================================
@@ -175,11 +188,94 @@ public:
bool isInterestedInDragSource (const String& sourceDescription, Component* sourceComponent)
{
return false;
return node.getState().getType() == DrawableComposite::valueTreeType
&& sourceDescription == getDragIdFor (editor)
&& editor.getSelection().getNumSelected() > 0;
}
void itemDropped (const String& sourceDescription, Component* sourceComponent, int insertIndex)
{
if (editor.getSelection().getNumSelected() > 0)
{
TreeView* tree = getOwnerView();
const ScopedPointer <XmlElement> oldOpenness (tree->getOpennessState (false));
Array <ValueTree> selectedComps;
// scan the source tree rather than look at the selection manager, because it might
// be from a different editor, and the order needs to be correct.
getAllSelectedNodesInTree (sourceComponent, selectedComps);
insertItems (selectedComps, insertIndex);
if (oldOpenness != 0)
tree->restoreOpennessState (*oldOpenness);
}
}
static void getAllSelectedNodesInTree (Component* componentInTree, Array<ValueTree>& selectedItems)
{
TreeView* tree = dynamic_cast <TreeView*> (componentInTree);
if (tree == 0)
tree = componentInTree->findParentComponentOfClass ((TreeView*) 0);
if (tree != 0)
{
const int numSelected = tree->getNumSelectedItems();
for (int i = 0; i < numSelected; ++i)
{
DrawableTreeViewItem* const item = dynamic_cast <DrawableTreeViewItem*> (tree->getSelectedItem (i));
if (item != 0)
selectedItems.add (item->node.getState());
}
}
}
void insertItems (Array <ValueTree>& items, int insertIndex)
{
DrawableComposite::ValueTreeWrapper composite (node.getState());
int i;
for (i = items.size(); --i >= 0;)
if (node.getState() == items.getReference(i) || composite.getState().isAChildOf (items.getReference(i))) // Check for recursion.
return;
// Don't include any nodes that are children of other selected nodes..
for (i = items.size(); --i >= 0;)
{
const ValueTree& n = items.getReference(i);
for (int j = items.size(); --j >= 0;)
{
if (j != i && n.isAChildOf (items.getReference(j)))
{
items.remove (i);
break;
}
}
}
// Remove and re-insert them one at a time..
for (i = 0; i < items.size(); ++i)
{
ValueTree& n = items.getReference(i);
int index = composite.indexOfDrawable (n);
if (index >= 0 && index < insertIndex)
--insertIndex;
if (index >= 0)
{
composite.moveDrawableOrder (index, insertIndex++, editor.getDocument().getUndoManager());
}
else
{
n.getParent().removeChild (n, editor.getDocument().getUndoManager());
composite.addDrawable (n, insertIndex++, editor.getDocument().getUndoManager());
}
}
}
//==============================================================================


+ 84
- 27
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp View File

@@ -38,7 +38,9 @@ public:
objectState (objectState_),
objectId (objectId_),
borderThickness (4),
isDragging (false)
isDragging (false),
isRotating (false),
canRotate (canvas_->canRotate())
{
jassert (objectState.isValid());
}
@@ -49,8 +51,13 @@ public:
void paint (Graphics& g)
{
g.setColour (resizableBorderColour);
g.drawRect (0, 0, getWidth(), getHeight(), borderThickness);
if (! canvas->isRotating())
{
g.setColour (resizableBorderColour);
g.drawRect (0, 0, getWidth(), getHeight(), borderThickness);
g.fillRect (rotateArea);
}
}
void mouseEnter (const MouseEvent& e) { updateDragZone (e.getPosition()); }
@@ -60,36 +67,47 @@ public:
void mouseDown (const MouseEvent& e)
{
updateDragZone (e.getPosition());
isDragging = false;
if (e.mods.isPopupMenu())
{
isDragging = false;
canvas->showPopupMenu (true);
}
else
{
isDragging = true;
canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()).getEventRelativeTo (getParentComponent()), dragZone);
canvas->showSizeGuides();
}
}
void mouseDrag (const MouseEvent& e)
{
if (! (isDragging || e.mods.isPopupMenu() || e.mouseWasClicked()))
{
isDragging = true;
bool isRotating = rotateArea.contains (e.getMouseDownPosition());
canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()),
dragZone, isRotating, canvas->getObjectPosition (objectState).getCentre().toFloat());
if (! isRotating)
canvas->showSizeGuides();
repaint();
}
if (isDragging)
{
canvas->continueDrag (e.getEventRelativeTo (getParentComponent()));
canvas->continueDrag (e);
autoScrollForMouseEvent (e);
}
}
void mouseUp (const MouseEvent& e)
{
if (isDragging)
if (isDragging || isRotating)
{
isRotating = false;
canvas->hideSizeGuides();
canvas->endDrag (e.getEventRelativeTo (getParentComponent()));
canvas->endDrag (e);
updateDragZone (e.getPosition());
repaint();
}
}
@@ -101,7 +119,7 @@ public:
bool hitTest (int x, int y)
{
if (ModifierKeys::getCurrentModifiers().isAnyModifierKeyDown())
return ! getCentreArea().contains (x, y);
return rotateArea.contains (x, y) || ! getCentreArea().contains (x, y);
return true;
}
@@ -114,6 +132,9 @@ public:
const Rectangle<int> bounds (canvas->getObjectPosition (objectState));
setBoundsInTargetSpace (bounds.expanded (borderThickness, borderThickness));
if (canRotate)
rotateArea = Rectangle<int> (2, 2, 10, 10);
int i;
for (i = sizeGuides.size(); --i >= 0;)
{
@@ -126,7 +147,6 @@ public:
const String& getTargetObjectID() const { return objectId; }
//==============================================================================
class SizeGuideComponent : public OverlayItemComponent,
public ComponentListener
@@ -200,7 +220,8 @@ private:
ResizableBorderComponent::Zone dragZone;
const int borderThickness;
OwnedArray <SizeGuideComponent> sizeGuides;
bool isDragging;
Rectangle<int> rotateArea;
bool isDragging, canRotate, isRotating;
const Rectangle<int> getCentreArea() const
{
@@ -467,7 +488,9 @@ public:
isDraggingClickedComp = true;
canvas->enableResizingMode();
getSelection().addToSelectionOnMouseUp (mouseDownCompUID, e.mods, true, mouseDownResult);
canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()), ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre));
canvas->beginDrag (e.withNewPosition (e.getMouseDownPosition()),
ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre),
false, Point<float>());
}
if (isDraggingClickedComp)
@@ -843,6 +866,16 @@ const Point<int> EditorCanvasBase::objectSpaceToScreenSpace (const Point<int>& p
return p + origin;
}
const Point<float> EditorCanvasBase::screenSpaceToObjectSpace (const Point<float>& p) const
{
return p - origin.toFloat();
}
const Point<float> EditorCanvasBase::objectSpaceToScreenSpace (const Point<float>& p) const
{
return p + origin.toFloat();
}
const Rectangle<int> EditorCanvasBase::screenSpaceToObjectSpace (const Rectangle<int>& r) const
{
return r - origin;
@@ -868,6 +901,11 @@ void EditorCanvasBase::enableControlPointMode (const ValueTree& objectToEdit)
}
}
bool EditorCanvasBase::isRotating() const
{
return dragger != 0 && dragger->isRotating();
}
//==============================================================================
void EditorCanvasBase::paint (Graphics& g)
{
@@ -927,6 +965,9 @@ void EditorCanvasBase::handleAsyncUpdate()
const Rectangle<int> canvasBounds (getCanvasBounds());
const Point<int> newOrigin (jmax (0, -canvasBounds.getX()), jmax (0, -canvasBounds.getY()));
const int newWidth = jmax (canvasBounds.getWidth(), canvasBounds.getRight()) + border.getLeftAndRight();
const int newHeight = jmax (canvasBounds.getHeight(), canvasBounds.getBottom()) + border.getTopAndBottom();
if (origin != newOrigin)
{
repaint();
@@ -936,16 +977,16 @@ void EditorCanvasBase::handleAsyncUpdate()
setBounds (jmin (0, getX() + oldOrigin.getX() - origin.getX()),
jmin (0, getY() + oldOrigin.getY() - origin.getY()),
jmax (canvasBounds.getWidth(), canvasBounds.getRight()) + border.getLeftAndRight(),
jmax (canvasBounds.getHeight(), canvasBounds.getBottom()) + border.getTopAndBottom());
newWidth, newHeight);
}
else if (getWidth() != newWidth || getHeight() != newHeight)
{
setSize (newWidth, newHeight);
}
else
{
setSize (jmax (canvasBounds.getWidth(), canvasBounds.getRight()) + border.getLeftAndRight(),
jmax (canvasBounds.getHeight(), canvasBounds.getBottom()) + border.getTopAndBottom());
overlay->update();
}
overlay->update();
}
void EditorCanvasBase::resized()
@@ -954,6 +995,7 @@ void EditorCanvasBase::resized()
overlay->setBounds (getLocalBounds());
resizeFrame->setBounds (getLocalBounds());
overlay->update();
handleUpdateNowIfNeeded();
}
//==============================================================================
@@ -962,25 +1004,33 @@ void EditorCanvasBase::hideSizeGuides() { overlay->hideSizeGuides(); }
//==============================================================================
void EditorCanvasBase::beginDrag (const MouseEvent& e, const ResizableBorderComponent::Zone& zone)
void EditorCanvasBase::beginDrag (const MouseEvent& e, const ResizableBorderComponent::Zone& zone,
bool isRotating, const Point<float>& rotationCentre)
{
dragger = createDragOperation (e, overlay, zone);
dragger = createDragOperation (e.getEventRelativeTo (overlay).getPosition() - origin, overlay, zone, isRotating);
dragger->setRotationCentre (rotationCentre);
repaint();
}
void EditorCanvasBase::continueDrag (const MouseEvent& e)
{
MouseEvent e2 (e.getEventRelativeTo (overlay));
if (dragger != 0)
dragger->drag (e, e.getPosition() - origin);
dragger->drag (e2, e2.getPosition() - origin);
}
void EditorCanvasBase::endDrag (const MouseEvent& e)
{
if (dragger != 0)
{
dragger->drag (e, e.getPosition() - origin);
MouseEvent e2 (e.getEventRelativeTo (overlay));
dragger->drag (e2, e2.getPosition() - origin);
dragger = 0;
getUndoManager().beginNewTransaction();
repaint();
}
}
@@ -999,3 +1049,10 @@ void EditorCanvasBase::OverlayItemComponent::setBoundsInTargetSpace (const Recta
setBounds (canvas->objectSpaceToScreenSpace (r)
+ canvas->getComponentHolder()->relativePositionToOtherComponent (getParentComponent(), Point<int>()));
}
const Point<float> EditorCanvasBase::OverlayItemComponent::pointToLocalSpace (const Point<float>& p) const
{
return canvas->objectSpaceToScreenSpace (p)
+ (canvas->getComponentHolder()->relativePositionToOtherComponent (getParentComponent(), Point<int>())
- getPosition()).toFloat();
}

+ 13
- 3
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h View File

@@ -96,13 +96,19 @@ public:
virtual ~DragOperation() {}
virtual void drag (const MouseEvent& e, const Point<int>& newPos) = 0;
virtual void setRotationCentre (const Point<float>& rotationCentre) = 0;
virtual bool isRotating() const = 0;
};
virtual DragOperation* createDragOperation (const MouseEvent& e,
virtual DragOperation* createDragOperation (const Point<int>& mouseDownPos,
Component* snapGuideParentComponent,
const ResizableBorderComponent::Zone& zone) = 0;
const ResizableBorderComponent::Zone& zone,
bool isRotating) = 0;
void beginDrag (const MouseEvent& e, const ResizableBorderComponent::Zone& zone);
virtual bool canRotate() const = 0;
void beginDrag (const MouseEvent& e, const ResizableBorderComponent::Zone& zone,
bool isRotating, const Point<float>& rotationCentre);
void continueDrag (const MouseEvent& e);
void endDrag (const MouseEvent& e);
@@ -111,6 +117,7 @@ public:
bool isResizingMode() const { return ! isControlPointMode(); }
bool isControlPointMode() const { return controlPointEditingTarget.isValid(); }
bool isRotating() const;
//==============================================================================
Component* getComponentHolder() const { return componentHolder; }
@@ -118,7 +125,9 @@ public:
const Point<int>& getOrigin() const throw() { return origin; }
const Point<int> screenSpaceToObjectSpace (const Point<int>& p) const;
const Point<float> screenSpaceToObjectSpace (const Point<float>& p) const;
const Point<int> objectSpaceToScreenSpace (const Point<int>& p) const;
const Point<float> objectSpaceToScreenSpace (const Point<float>& p) const;
const Rectangle<int> screenSpaceToObjectSpace (const Rectangle<int>& r) const;
const Rectangle<int> objectSpaceToScreenSpace (const Rectangle<int>& r) const;
@@ -130,6 +139,7 @@ public:
~OverlayItemComponent();
void setBoundsInTargetSpace (const Rectangle<int>& r);
const Point<float> pointToLocalSpace (const Point<float>& p) const;
protected:
EditorCanvasBase* canvas;


+ 49
- 24
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h View File

@@ -33,13 +33,14 @@
class EditorDragOperation : public EditorCanvasBase::DragOperation
{
public:
EditorDragOperation (EditorCanvasBase* canvas_, const MouseEvent& e, const Point<int>& mousePos,
Component* snapGuideParentComp_,
const ResizableBorderComponent::Zone& zone_)
EditorDragOperation (EditorCanvasBase* canvas_, const Point<int>& mousePos,
Component* snapGuideParentComp_, const ResizableBorderComponent::Zone& zone_,
bool rotating_)
: canvas (canvas_),
snapGuideParentComp (snapGuideParentComp_),
zone (zone_),
mouseDownPos (mousePos)
mouseDownPos (mousePos),
rotating (rotating_)
{
}
@@ -141,6 +142,16 @@ public:
getUndoManager().beginNewTransaction();
}
void setRotationCentre (const Point<float>& rotationCentre)
{
centre = rotationCentre;
}
bool isRotating() const
{
return rotating;
}
//==============================================================================
struct SnapLine
{
@@ -195,31 +206,35 @@ public:
{
getUndoManager().undoCurrentTransactionOnly();
// (can't use getOffsetFromDragStart() because of auto-scrolling)
Point<int> distance (newPos - mouseDownPos);
if (! isDraggingLeftRight())
distance = distance.withX (0);
if (rotating)
{
const float angle = centre.getAngleToPoint (mouseDownPos.toFloat()) - centre.getAngleToPoint (newPos.toFloat());
const AffineTransform transform (AffineTransform::rotation (angle, centre.getX(), centre.getY()));
if (! isDraggingUpDown())
distance = distance.withY (0);
for (int i = 0; i < updateList.size(); ++i)
transformObject (updateList.getReference(i), transform);
}
else
{
// (can't use getOffsetFromDragStart() because of auto-scrolling)
Point<int> distance (newPos - mouseDownPos);
if (! isDraggingLeftRight())
distance = distance.withX (0);
snapGuides.clear();
if (! isDraggingUpDown())
distance = distance.withY (0);
if (canvas->getPanel()->isSnappingEnabled() != (e.mods.isCommandDown() || e.mods.isCtrlDown()))
{
performSnap (verticalSnapTargets, getVerticalSnapPositions (distance), true, distance);
performSnap (horizontalSnapTargets, getHorizontalSnapPositions (distance), false, distance);
}
snapGuides.clear();
for (int i = 0; i < updateList.size(); ++i)
dragItem (updateList.getReference(i), distance, originalPositions.getReference(i));
}
if (canvas->getPanel()->isSnappingEnabled() != (e.mods.isCommandDown() || e.mods.isCtrlDown()))
{
performSnap (verticalSnapTargets, getVerticalSnapPositions (distance), true, distance);
performSnap (horizontalSnapTargets, getHorizontalSnapPositions (distance), false, distance);
}
void dragItem (ValueTree& v, const Point<int>& distance, const Rectangle<float>& originalPos)
{
const Rectangle<float> newBounds (zone.resizeRectangleBy (originalPos, Point<float> ((float) distance.getX(),
(float) distance.getY())));
setObjectPosition (v, newBounds);
for (int i = 0; i < updateList.size(); ++i)
dragItem (updateList.getReference(i), distance, originalPositions.getReference(i));
}
}
protected:
@@ -231,6 +246,7 @@ protected:
virtual void getObjectDependencies (const ValueTree& state, Array<ValueTree>& deps) = 0;
virtual const Rectangle<float> getObjectPosition (const ValueTree& state) = 0;
virtual void setObjectPosition (ValueTree& state, const Rectangle<float>& newBounds) = 0;
virtual void transformObject (ValueTree& state, const AffineTransform& transform) = 0;
virtual UndoManager& getUndoManager() = 0;
@@ -246,6 +262,15 @@ private:
OwnedArray<Component> snapGuides;
Component* snapGuideParentComp;
Point<int> mouseDownPos;
Point<float> centre;
bool rotating;
void dragItem (ValueTree& v, const Point<int>& distance, const Rectangle<float>& originalPos)
{
const Rectangle<float> newBounds (zone.resizeRectangleBy (originalPos, Point<float> ((float) distance.getX(),
(float) distance.getY())));
setObjectPosition (v, newBounds);
}
void getCompleteDependencyList (const ValueTree& object, Array <ValueTree>& deps, const Array<ValueTree>& activeObjects)
{


+ 14
- 17
extras/Jucer (experimental)/Source/ui/Project Editor/jucer_ItemPreviewComponent.cpp View File

@@ -31,44 +31,41 @@
ItemPreviewComponent::ItemPreviewComponent (const File& file_)
: file (file_)
{
facts.add (file.getFullPathName());
tryToLoadImage (file.createInputStream());
facts.removeEmptyStrings (true);
}
ItemPreviewComponent::ItemPreviewComponent (InputStream* input, const String& name)
{
facts.add (name);
tryToLoadImage (input);
facts.removeEmptyStrings (true);
tryToLoadImage();
}
ItemPreviewComponent::~ItemPreviewComponent()
{
}
void ItemPreviewComponent::tryToLoadImage (InputStream* in)
void ItemPreviewComponent::tryToLoadImage()
{
if (in != 0)
{
ScopedPointer <InputStream> input (in);
facts.clear();
facts.add (file.getFullPathName());
image = Image();
ScopedPointer <InputStream> input (file.createInputStream());
if (input != 0)
{
const int64 totalSize = input->getTotalLength();
ImageFileFormat* format = ImageFileFormat::findImageFormatForStream (*input);
input = 0;
String formatName;
if (format != 0)
formatName = " " + format->getFormatName();
image = ImageFileFormat::loadFrom (*input);
image = ImageCache::getFromFile (file);
if (image.isValid())
facts.add (String (image.getWidth()) + " x " + String (image.getHeight()) + formatName);
const int64 totalSize = input->getTotalLength();
if (totalSize > 0)
facts.add (File::descriptionOfSizeInBytes (totalSize));
}
facts.removeEmptyStrings (true);
}
void ItemPreviewComponent::paint (Graphics& g)


+ 1
- 2
extras/Jucer (experimental)/Source/ui/Project Editor/jucer_ItemPreviewComponent.h View File

@@ -35,7 +35,6 @@ class ItemPreviewComponent : public Component
public:
//==============================================================================
// This will delete the stream
ItemPreviewComponent (InputStream* input, const String& name);
ItemPreviewComponent (const File& file);
~ItemPreviewComponent();
@@ -50,7 +49,7 @@ private:
File file;
Image image;
void tryToLoadImage (InputStream* input);
void tryToLoadImage();
};


+ 148
- 16
extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h View File

@@ -26,19 +26,25 @@
#ifndef __JUCER_FILLTYPEPROPERTYCOMPONENT_H_88CF1300__
#define __JUCER_FILLTYPEPROPERTYCOMPONENT_H_88CF1300__
#include "../model/Project/jucer_Project.h"
class FillTypeEditorComponent;
//==============================================================================
class PopupFillSelector : public Component,
public ChangeListener,
public ValueTree::Listener,
public ButtonListener
public ButtonListener,
public AsyncUpdater
{
public:
PopupFillSelector (const ValueTree& fillState_, const ColourGradient& defaultGradient_, UndoManager* undoManager_)
PopupFillSelector (const ValueTree& fillState_, const ColourGradient& defaultGradient_,
Drawable::ImageProvider* imageProvider_, Project* project, UndoManager* undoManager_)
: gradientPicker (defaultGradient_),
defaultGradient (defaultGradient_),
tilePicker (imageProvider_, project),
fillState (fillState_),
imageProvider (imageProvider_),
undoManager (undoManager_)
{
colourButton.setButtonText ("Colour");
@@ -60,6 +66,9 @@ public:
addChildComponent (&gradientPicker);
gradientPicker.addChangeListener (this);
addChildComponent (&tilePicker);
tilePicker.addChangeListener (this);
fillState.addListener (this);
colourButton.setRadioGroupId (123);
@@ -90,6 +99,7 @@ public:
const Rectangle<int> content (2, y + h + 4, getWidth() - 4, getHeight() - (y + h + 6));
colourPicker.setBounds (content);
gradientPicker.setBounds (content);
tilePicker.setBounds (content);
}
void buttonClicked (Button* b)
@@ -109,7 +119,7 @@ public:
// Use a cunning trick to make the wrapper dig out the earlier gradient settings, if there are any..
FillType newFill (defaultGradient);
ValueTree temp ("dummy");
Drawable::ValueTreeWrapperBase::writeFillType (temp, newFill, 0, 0, 0);
Drawable::ValueTreeWrapperBase::writeFillType (temp, newFill, 0, 0, 0, 0);
fillState.setProperty (Drawable::ValueTreeWrapperBase::type, temp [Drawable::ValueTreeWrapperBase::type], undoManager);
newFill = readFillType (&gp1, &gp2);
@@ -117,11 +127,11 @@ public:
if (newFill.gradient->getNumColours() <= 1)
{
newFill = FillType (defaultGradient);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, imageProvider, undoManager);
}
else
{
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, imageProvider, undoManager);
}
refresh();
@@ -137,7 +147,7 @@ public:
const FillType readFillType (RelativePoint* gp1, RelativePoint* gp2) const
{
return Drawable::ValueTreeWrapperBase::readFillType (fillState, gp1, gp2, 0);
return Drawable::ValueTreeWrapperBase::readFillType (fillState, gp1, gp2, 0, imageProvider);
}
void setFillType (const FillType& newFill)
@@ -150,7 +160,7 @@ public:
if (undoManager != 0)
undoManager->undoCurrentTransactionOnly();
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, imageProvider, undoManager);
refresh();
}
}
@@ -163,6 +173,8 @@ public:
setFillType (colourPicker.getCurrentColour());
else if (currentFill.isGradient())
setFillType (gradientPicker.getGradient());
else if (currentFill.isTiledImage())
setFillType (tilePicker.getFill());
}
void refresh()
@@ -171,6 +183,7 @@ public:
colourPicker.setVisible (newFill.isColour());
gradientPicker.setVisible (newFill.isGradient());
tilePicker.setVisible (newFill.isTiledImage());
if (newFill.isColour())
{
@@ -182,7 +195,7 @@ public:
if (newFill.gradient->getNumColours() <= 1)
{
newFill = FillType (defaultGradient);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, 0, 0, imageProvider, undoManager);
}
gradientButton.setToggleState (true, false);
@@ -190,12 +203,14 @@ public:
}
else
{
tilePicker.setFill (newFill);
imageButton.setToggleState (true, false);
}
}
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) { refresh(); }
void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) { refresh(); }
void handleAsyncUpdate() { refresh(); }
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) { triggerAsyncUpdate(); }
void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) { triggerAsyncUpdate(); }
void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) {}
private:
@@ -433,12 +448,124 @@ private:
}
};
//==============================================================================
class TiledFillDesigner : public Component,
public ChangeBroadcaster,
public ComboBoxListener,
public SliderListener
{
public:
TiledFillDesigner (Drawable::ImageProvider* imageProvider_, Project* project_)
: imageProvider (imageProvider_), project (project_)
{
addAndMakeVisible (&imageBox);
addAndMakeVisible (&opacitySlider);
opacitySlider.setRange (0.0, 1.0, 0.001);
sliderLabel.setText ("Opacity:", false);
sliderLabel.attachToComponent (&opacitySlider, false);
OwnedArray<Project::Item> images;
project->findAllImageItems (images);
for (int i = 0; i < images.size(); ++i)
imageBox.addItem (images.getUnchecked(i)->getName().toString(), i + 1);
imageBox.setTextWhenNothingSelected ("Select an image...");
opacitySlider.addListener (this);
imageBox.addListener (this);
}
~TiledFillDesigner()
{
}
const FillType getFill() const
{
return fill;
}
void setFill (const FillType& newFill)
{
if (fill != newFill)
{
fill = newFill;
OwnedArray<Project::Item> images;
project->findAllImageItems (images);
const String currentID (imageProvider->getIdentifierForImage (fill.image).toString());
int idToSelect = -1;
for (int i = 0; i < images.size(); ++i)
{
if (images.getUnchecked(i)->getImageFileID() == currentID)
{
idToSelect = i + 1;
break;
}
}
imageBox.setSelectedId (idToSelect, true);
opacitySlider.setValue (fill.getOpacity(), false, false);
}
}
void resized()
{
imageBox.setBounds (20, 10, getWidth() - 40, 22);
opacitySlider.setBounds (20, 60, getWidth() - 40, 22);
}
void sliderValueChanged (Slider* slider)
{
if (opacitySlider.getValue() != fill.getOpacity())
{
FillType f (fill);
f.setOpacity ((float) opacitySlider.getValue());
setFill (f);
sendChangeMessage (this);
}
}
void comboBoxChanged (ComboBox* comboBoxThatHasChanged)
{
OwnedArray<Project::Item> images;
project->findAllImageItems (images);
Project::Item* item = images [imageBox.getSelectedId() - 1];
if (item != 0)
{
Image im (imageProvider->getImageForIdentifier (item->getImageFileID()));
if (im.isValid() && im != fill.image)
{
FillType f (fill);
f.image = im;
setFill (f);
sendChangeMessage (this);
}
}
}
private:
FillType fill;
Drawable::ImageProvider* imageProvider;
Project* project;
ComboBox imageBox;
Slider opacitySlider;
Label sliderLabel;
};
//==============================================================================
FillTypeEditorComponent* owner;
StoredSettings::ColourSelectorWithSwatches colourPicker;
GradientDesigner gradientPicker;
TiledFillDesigner tilePicker;
ColourGradient defaultGradient;
ValueTree fillState;
Drawable::ImageProvider* imageProvider;
UndoManager* undoManager;
TextButton colourButton, gradientButton, imageButton;
@@ -454,8 +581,10 @@ class FillTypeEditorComponent : public Component,
public ValueTree::Listener
{
public:
FillTypeEditorComponent (const ValueTree& fillState_, UndoManager* undoManager_)
: fillState (fillState_), undoManager (undoManager_)
FillTypeEditorComponent (const ValueTree& fillState_, Drawable::ImageProvider* imageProvider_,
Project* project_, UndoManager* undoManager_)
: fillState (fillState_), undoManager (undoManager_),
imageProvider (imageProvider_), project (project_)
{
fillState.addListener (this);
refresh();
@@ -498,7 +627,7 @@ public:
void refresh()
{
const FillType newFill (Drawable::ValueTreeWrapperBase::readFillType (fillState, 0, 0, 0));
const FillType newFill (Drawable::ValueTreeWrapperBase::readFillType (fillState, 0, 0, 0, imageProvider));
if (newFill != fillType)
{
@@ -511,7 +640,7 @@ public:
{
undoManager->beginNewTransaction();
PopupFillSelector popup (fillState, getDefaultGradient(), undoManager);
PopupFillSelector popup (fillState, getDefaultGradient(), imageProvider, project, undoManager);
PopupMenu m;
m.addCustomItem (1234, &popup, 300, 450, false);
@@ -526,7 +655,9 @@ public:
private:
ValueTree fillState;
Drawable::ImageProvider* imageProvider;
UndoManager* undoManager;
Project* project;
FillType fillType;
};
@@ -536,9 +667,10 @@ class FillTypePropertyComponent : public PropertyComponent
{
public:
//==============================================================================
FillTypePropertyComponent (UndoManager* undoManager, const String& name, const ValueTree& fill)
FillTypePropertyComponent (UndoManager* undoManager, const String& name, const ValueTree& fill,
Drawable::ImageProvider* imageProvider, Project* project)
: PropertyComponent (name),
editor (fill, undoManager)
editor (fill, imageProvider, project, undoManager)
{
jassert (fill.isValid());
addAndMakeVisible (&editor);


Loading…
Cancel
Save