| @@ -100,11 +100,10 @@ public: | |||
| { | |||
| RectangleCoordinates r (boundsValue.toString()); | |||
| Coordinate& coord = getCoord (r); | |||
| ScopedPointer<Coordinate::MarkerResolver> markers (document.createComponentMarkerResolver (compState)); | |||
| if (button == proportionButton) | |||
| { | |||
| coord.toggleProportionality (*markers); | |||
| coord.toggleProportionality (document); | |||
| boundsValue = r.toString(); | |||
| } | |||
| else if (button == anchorButton1) | |||
| @@ -113,7 +112,7 @@ public: | |||
| if (marker.isNotEmpty()) | |||
| { | |||
| coord.changeAnchor1 (marker, *markers); | |||
| coord.changeAnchor1 (marker, document); | |||
| boundsValue = r.toString(); | |||
| } | |||
| } | |||
| @@ -123,7 +122,7 @@ public: | |||
| if (marker.isNotEmpty()) | |||
| { | |||
| coord.changeAnchor2 (marker, *markers); | |||
| coord.changeAnchor2 (marker, document); | |||
| boundsValue = r.toString(); | |||
| } | |||
| } | |||
| @@ -212,18 +211,18 @@ public: | |||
| return r.left; | |||
| } | |||
| const String pickMarker (Component* button, const String& currentMarker) | |||
| const String pickMarker (TextButton* button, const String& currentMarker) | |||
| { | |||
| const StringArray markers (document.getComponentMarkers (type == left || type == right)); | |||
| RectangleCoordinates b (boundsValue.toString()); | |||
| PopupMenu m; | |||
| for (int i = 0; i < markers.size(); ++i) | |||
| m.addItem (i + 1, markers[i], true, currentMarker == markers[i]); | |||
| document.getComponentMarkerMenuItems (compState, getTypeName(), | |||
| getCoord (b), m, button == anchorButton1); | |||
| const int r = m.showAt (button); | |||
| if (r > 0) | |||
| return markers [r - 1]; | |||
| return document.getChosenMarkerMenuItem (compState, getCoord (b), r); | |||
| return String::empty; | |||
| } | |||
| @@ -242,6 +241,20 @@ private: | |||
| { | |||
| return getCoordForType (type, r); | |||
| } | |||
| const String getTypeName() const | |||
| { | |||
| switch (type) | |||
| { | |||
| case left: return "left"; | |||
| case right: return "right"; | |||
| case top: return "top"; | |||
| case bottom: return "bottom"; | |||
| default: jassertfalse; break; | |||
| } | |||
| return String::empty; | |||
| } | |||
| }; | |||
| @@ -265,8 +278,7 @@ Value ComponentTypeHandler::getValue (const var::identifier& name, ValueTree& st | |||
| void ComponentTypeHandler::updateComponent (ComponentDocument& document, Component* comp, const ValueTree& state) | |||
| { | |||
| RectangleCoordinates pos (state [ComponentDocument::compBoundsProperty].toString()); | |||
| ScopedPointer<Coordinate::MarkerResolver> markers (document.createComponentMarkerResolver (state)); | |||
| comp->setBounds (pos.resolve (*markers)); | |||
| comp->setBounds (pos.resolve (document)); | |||
| comp->setName (state [ComponentDocument::compNameProperty]); | |||
| } | |||
| @@ -279,11 +291,54 @@ void ComponentTypeHandler::initialiseNewItem (ComponentDocument& document, Value | |||
| const Rectangle<int> bounds (getDefaultSize().withPosition (Point<int> (Random::getSystemRandom().nextInt (100) + 100, | |||
| Random::getSystemRandom().nextInt (100) + 100))); | |||
| state.setProperty (ComponentDocument::compBoundsProperty, RectangleCoordinates (bounds).toString(), 0); | |||
| state.setProperty (ComponentDocument::compBoundsProperty, RectangleCoordinates (bounds, state [ComponentDocument::memberNameProperty]).toString(), 0); | |||
| } | |||
| //============================================================================== | |||
| class CompMemberNameValueSource : public Value::ValueSource, | |||
| public Value::Listener | |||
| { | |||
| public: | |||
| CompMemberNameValueSource (ComponentDocument& document_, const ValueTree& state_) | |||
| : sourceValue (state_.getPropertyAsValue (ComponentDocument::memberNameProperty, document_.getUndoManager())), | |||
| document (document_), | |||
| state (state_) | |||
| { | |||
| sourceValue.addListener (this); | |||
| } | |||
| ~CompMemberNameValueSource() {} | |||
| void valueChanged (Value&) { sendChangeMessage (true); } | |||
| const var getValue() const { return sourceValue.toString(); } | |||
| void setValue (const var& newValue) | |||
| { | |||
| String newVal (newValue.toString()); | |||
| //xxx check for uniqueness + rename any coords that use the name.. | |||
| newVal = makeValidCppIdentifier (newVal, false, true, false); | |||
| if (sourceValue != newVal) | |||
| sourceValue = newVal; | |||
| } | |||
| private: | |||
| Value sourceValue; | |||
| ComponentDocument& document; | |||
| ValueTree state; | |||
| CompMemberNameValueSource (const CompMemberNameValueSource&); | |||
| const CompMemberNameValueSource& operator= (const CompMemberNameValueSource&); | |||
| }; | |||
| void ComponentTypeHandler::createPropertyEditors (ComponentDocument& document, ValueTree& state, Array <PropertyComponent*>& props) | |||
| { | |||
| props.add (new TextPropertyComponent (Value (new CompMemberNameValueSource (document, state)), "Member Name", 256, false)); | |||
| props.add (new ComponentBoundsEditor (document, "Left", ComponentBoundsEditor::left, state, getValue (ComponentDocument::compBoundsProperty, state, document))); | |||
| props.add (new ComponentBoundsEditor (document, "Right", ComponentBoundsEditor::right, state, getValue (ComponentDocument::compBoundsProperty, state, document))); | |||
| props.add (new ComponentBoundsEditor (document, "Top", ComponentBoundsEditor::top, state, getValue (ComponentDocument::compBoundsProperty, state, document))); | |||
| @@ -54,6 +54,10 @@ public: | |||
| //============================================================================== | |||
| protected: | |||
| const String name, xmlTag, memberNameRoot; | |||
| private: | |||
| ComponentTypeHandler (const ComponentTypeHandler&); | |||
| ComponentTypeHandler& operator= (const ComponentTypeHandler&); | |||
| }; | |||
| @@ -54,9 +54,6 @@ ComponentDocument::ComponentDocument (Project* project_, const File& cppFile_) | |||
| reload(); | |||
| checkRootObject(); | |||
| markersX = new MarkerList (*this, true); | |||
| markersY = new MarkerList (*this, false); | |||
| root.addListener (this); | |||
| } | |||
| @@ -189,6 +186,8 @@ bool ComponentDocument::reload() | |||
| if (newTree.isValid()) | |||
| { | |||
| root = newTree; | |||
| markersX = 0; | |||
| markersY = 0; | |||
| checkRootObject(); | |||
| undoManager.clearUndoHistory(); | |||
| changedSinceSaved = false; | |||
| @@ -218,6 +217,12 @@ void ComponentDocument::checkRootObject() | |||
| createSubTreeIfNotThere (markersGroupXTag); | |||
| createSubTreeIfNotThere (markersGroupYTag); | |||
| if (markersX == 0) | |||
| markersX = new MarkerList (*this, true); | |||
| if (markersY == 0) | |||
| markersY = new MarkerList (*this, false); | |||
| if (getClassName().toString().isEmpty()) | |||
| getClassName() = "NewComponent"; | |||
| @@ -305,34 +310,38 @@ Component* ComponentDocument::createComponent (int index) | |||
| } | |||
| //============================================================================== | |||
| class ComponentMarkerResolver : public Coordinate::MarkerResolver | |||
| const Coordinate ComponentDocument::findMarker (const String& name, bool isHorizontal) const | |||
| { | |||
| public: | |||
| ComponentMarkerResolver (ComponentDocument& doc, const ValueTree& state_, int parentWidth_, int parentHeight_) | |||
| : owner (doc), state (state_), | |||
| parentWidth (parentWidth_), | |||
| parentHeight (parentHeight_) | |||
| {} | |||
| if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) getCanvasWidth().getValue(), isHorizontal); | |||
| if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) getCanvasHeight().getValue(), isHorizontal); | |||
| ~ComponentMarkerResolver() {} | |||
| const Coordinate findMarker (const String& name, bool isHorizontal) | |||
| if (name.containsChar ('.')) | |||
| { | |||
| if (name == "left") return RectangleCoordinates (state [ComponentDocument::compBoundsProperty]).left; | |||
| else if (name == "right") return RectangleCoordinates (state [ComponentDocument::compBoundsProperty]).right; | |||
| else if (name == "top") return RectangleCoordinates (state [ComponentDocument::compBoundsProperty]).top; | |||
| else if (name == "bottom") return RectangleCoordinates (state [ComponentDocument::compBoundsProperty]).bottom; | |||
| else if (name == Coordinate::parentRightMarkerName) return Coordinate (parentWidth, isHorizontal); | |||
| else if (name == Coordinate::parentBottomMarkerName) return Coordinate (parentHeight, isHorizontal); | |||
| return Coordinate (isHorizontal); | |||
| const String compName (name.upToFirstOccurrenceOf (".", false, false).trim()); | |||
| const String edge (name.fromFirstOccurrenceOf (".", false, false).trim()); | |||
| if (compName.isNotEmpty() && edge.isNotEmpty()) | |||
| { | |||
| const ValueTree comp (getComponentWithMemberName (compName)); | |||
| if (comp.isValid()) | |||
| { | |||
| const RectangleCoordinates coords (getCoordsFor (comp)); | |||
| if (edge == "left") return coords.left; | |||
| if (edge == "right") return coords.right; | |||
| if (edge == "top") return coords.top; | |||
| if (edge == "bottom") return coords.bottom; | |||
| } | |||
| } | |||
| } | |||
| private: | |||
| ComponentDocument& owner; | |||
| ValueTree state; | |||
| int parentWidth, parentHeight; | |||
| }; | |||
| const ValueTree marker (getMarkerList (isHorizontal).getMarkerNamed (name)); | |||
| if (marker.isValid()) | |||
| return getMarkerList (isHorizontal).getCoordinate (marker); | |||
| return Coordinate (isHorizontal); | |||
| } | |||
| const RectangleCoordinates ComponentDocument::getCoordsFor (const ValueTree& state) const | |||
| { | |||
| @@ -350,31 +359,97 @@ bool ComponentDocument::setCoordsFor (ValueTree& state, const RectangleCoordinat | |||
| return true; | |||
| } | |||
| Coordinate::MarkerResolver* ComponentDocument::createComponentMarkerResolver (const ValueTree& state) | |||
| void ComponentDocument::addMarkerMenuItem (int i, Coordinate& coord, const String& name, PopupMenu& menu, bool isAnchor1, | |||
| const ValueTree& componentState, const String& coordName) | |||
| { | |||
| return new ComponentMarkerResolver (*this, state, getCanvasWidth().getValue(), getCanvasHeight().getValue()); | |||
| const String componentName (componentState [memberNameProperty].toString()); | |||
| Coordinate requestedCoord (findMarker (name, coord.isHorizontal())); | |||
| const String fullCoordName (componentName + "." + coordName); | |||
| menu.addItem (i, name, | |||
| ! (name == fullCoordName || requestedCoord.referencesIndirectly (fullCoordName, *this)), | |||
| name == (isAnchor1 ? coord.getAnchor1() : coord.getAnchor2())); | |||
| } | |||
| const StringArray ComponentDocument::getComponentMarkers (bool horizontal) const | |||
| void ComponentDocument::getComponentMarkerMenuItems (const ValueTree& componentState, const String& coordName, | |||
| Coordinate& coord, PopupMenu& menu, bool isAnchor1) | |||
| { | |||
| StringArray s; | |||
| const String componentName (componentState [memberNameProperty].toString()); | |||
| if (horizontal) | |||
| if (coord.isHorizontal()) | |||
| { | |||
| s.add (Coordinate::parentLeftMarkerName); | |||
| s.add (Coordinate::parentRightMarkerName); | |||
| s.add ("left"); | |||
| s.add ("right"); | |||
| addMarkerMenuItem (1, coord, Coordinate::parentLeftMarkerName, menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (2, coord, Coordinate::parentRightMarkerName, menu, isAnchor1, componentState, coordName); | |||
| menu.addSeparator(); | |||
| addMarkerMenuItem (3, coord, componentName + ".left", menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (4, coord, componentName + ".right", menu, isAnchor1, componentState, coordName); | |||
| } | |||
| else | |||
| { | |||
| s.add (Coordinate::parentTopMarkerName); | |||
| s.add (Coordinate::parentBottomMarkerName); | |||
| s.add ("top"); | |||
| s.add ("bottom"); | |||
| addMarkerMenuItem (1, coord, Coordinate::parentTopMarkerName, menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (2, coord, Coordinate::parentBottomMarkerName, menu, isAnchor1, componentState, coordName); | |||
| menu.addSeparator(); | |||
| addMarkerMenuItem (3, coord, componentName + ".top", menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (4, coord, componentName + ".bottom", menu, isAnchor1, componentState, coordName); | |||
| } | |||
| menu.addSeparator(); | |||
| const MarkerList& markerList = getMarkerList (coord.isHorizontal()); | |||
| int i; | |||
| for (i = 0; i < markerList.size(); ++i) | |||
| addMarkerMenuItem (100 + i, coord, markerList.getName (markerList.getMarker (i)), menu, isAnchor1, componentState, coordName); | |||
| menu.addSeparator(); | |||
| for (i = 0; i < getNumComponents(); ++i) | |||
| { | |||
| const String compName (getComponent (i) [memberNameProperty].toString()); | |||
| if (compName != componentName) | |||
| { | |||
| if (coord.isHorizontal()) | |||
| { | |||
| addMarkerMenuItem (10000 + i, coord, compName + ".left", menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (10001 + i, coord, compName + ".right", menu, isAnchor1, componentState, coordName); | |||
| } | |||
| else | |||
| { | |||
| addMarkerMenuItem (10002 + i, coord, compName + ".top", menu, isAnchor1, componentState, coordName); | |||
| addMarkerMenuItem (10003 + i, coord, compName + ".bottom", menu, isAnchor1, componentState, coordName); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| const String ComponentDocument::getChosenMarkerMenuItem (const ValueTree& componentState, Coordinate& coord, int i) const | |||
| { | |||
| const String componentName (componentState [memberNameProperty].toString()); | |||
| if (i == 1) return coord.isHorizontal() ? Coordinate::parentLeftMarkerName : Coordinate::parentTopMarkerName; | |||
| if (i == 2) return coord.isHorizontal() ? Coordinate::parentRightMarkerName : Coordinate::parentBottomMarkerName; | |||
| if (i == 3) return componentName + (coord.isHorizontal() ? ".left" : ".top"); | |||
| if (i == 4) return componentName + (coord.isHorizontal() ? ".right" : ".bottom"); | |||
| const MarkerList& markerList = getMarkerList (coord.isHorizontal()); | |||
| if (i >= 100 && i < 10000) | |||
| return markerList.getName (markerList.getMarker (i - 100)); | |||
| if (i >= 10000) | |||
| { | |||
| const String compName (getComponent ((i - 10000) / 4) [memberNameProperty].toString()); | |||
| switch (i & 3) | |||
| { | |||
| case 0: return compName + ".left"; | |||
| case 1: return compName + ".right"; | |||
| case 2: return compName + ".top"; | |||
| case 3: return compName + ".bottom"; | |||
| default: break; | |||
| } | |||
| } | |||
| return s; | |||
| jassertfalse; | |||
| return String::empty; | |||
| } | |||
| void ComponentDocument::updateComponent (Component* comp) | |||
| @@ -436,6 +511,12 @@ bool ComponentDocument::isStateForComponent (const ValueTree& storedState, Compo | |||
| return storedState [idProperty] == comp->getProperties() [idProperty]; | |||
| } | |||
| void ComponentDocument::removeComponent (const ValueTree& state) | |||
| { | |||
| jassert (state.isAChildOf (getComponentGroup())); | |||
| getComponentGroup().removeChild (state, getUndoManager()); | |||
| } | |||
| const String ComponentDocument::getNonExistentMemberName (String suggestedName) | |||
| { | |||
| suggestedName = makeValidCppIdentifier (suggestedName, false, true, false); | |||
| @@ -460,10 +541,10 @@ ComponentDocument::MarkerList::MarkerList (ComponentDocument& document_, const b | |||
| group (document_.getRoot().getChildWithName (isX_ ? markersGroupXTag : markersGroupYTag)), | |||
| isX (isX_) | |||
| { | |||
| jassert (group.isValid()); | |||
| jassert (group.isAChildOf (document_.getRoot())); | |||
| } | |||
| ValueTree ComponentDocument::MarkerList::getGroup() const | |||
| ValueTree& ComponentDocument::MarkerList::getGroup() | |||
| { | |||
| return group; | |||
| } | |||
| @@ -493,6 +574,16 @@ const Coordinate ComponentDocument::MarkerList::getCoordinate (const ValueTree& | |||
| return Coordinate (markerState [markerPosProperty].toString(), isX); | |||
| } | |||
| const String ComponentDocument::MarkerList::getName (const ValueTree& markerState) const | |||
| { | |||
| return markerState [markerNameProperty].toString(); | |||
| } | |||
| Value ComponentDocument::MarkerList::getNameAsValue (const ValueTree& markerState) const | |||
| { | |||
| return markerState.getPropertyAsValue (markerNameProperty, document.getUndoManager()); | |||
| } | |||
| void ComponentDocument::MarkerList::setCoordinate (ValueTree& markerState, const Coordinate& newCoord) | |||
| { | |||
| markerState.setProperty (markerPosProperty, newCoord.toString(), document.getUndoManager()); | |||
| @@ -511,12 +602,16 @@ void ComponentDocument::MarkerList::deleteMarker (ValueTree& markerState) | |||
| group.removeChild (markerState, document.getUndoManager()); | |||
| } | |||
| const Coordinate ComponentDocument::MarkerList::findMarker (const String& name, bool isHorizontal) | |||
| const Coordinate ComponentDocument::MarkerList::findMarker (const String& name, bool isHorizontal) const | |||
| { | |||
| if (isHorizontal == isX) | |||
| { | |||
| if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) document.getCanvasWidth().getValue(), isHorizontal); | |||
| else if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) document.getCanvasHeight().getValue(), isHorizontal); | |||
| if (name == Coordinate::parentRightMarkerName) return Coordinate ((double) document.getCanvasWidth().getValue(), isHorizontal); | |||
| if (name == Coordinate::parentBottomMarkerName) return Coordinate ((double) document.getCanvasHeight().getValue(), isHorizontal); | |||
| const ValueTree marker (document.getMarkerList (isHorizontal).getMarkerNamed (name)); | |||
| if (marker.isValid()) | |||
| return document.getMarkerList (isHorizontal).getCoordinate (marker); | |||
| } | |||
| return Coordinate (isX); | |||
| @@ -534,7 +629,7 @@ const String ComponentDocument::getNonexistentMarkerName (const String& name) | |||
| } | |||
| //============================================================================== | |||
| UndoManager* ComponentDocument::getUndoManager() | |||
| UndoManager* ComponentDocument::getUndoManager() const | |||
| { | |||
| return &undoManager; | |||
| } | |||
| @@ -32,7 +32,8 @@ | |||
| //============================================================================== | |||
| class ComponentDocument : public ValueTree::Listener | |||
| class ComponentDocument : public ValueTree::Listener, | |||
| public Coordinate::MarkerResolver | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| @@ -45,14 +46,12 @@ public: | |||
| bool reload(); | |||
| bool hasChangedSinceLastSave(); | |||
| typedef SelectedItemSet<uint32> SelectedItems; | |||
| //============================================================================== | |||
| Value getClassName() { return getRootValueNonUndoable ("className"); } | |||
| Value getClassDescription() { return getRootValueNonUndoable ("classDesc"); } | |||
| Value getClassName() const { return getRootValueNonUndoable ("className"); } | |||
| Value getClassDescription() const { return getRootValueNonUndoable ("classDesc"); } | |||
| Value getCanvasWidth() { return getRootValueNonUndoable ("width"); } | |||
| Value getCanvasHeight() { return getRootValueNonUndoable ("height"); } | |||
| Value getCanvasWidth() const { return getRootValueNonUndoable ("width"); } | |||
| Value getCanvasHeight() const { return getRootValueNonUndoable ("height"); } | |||
| void createClassProperties (Array <PropertyComponent*>& props); | |||
| @@ -68,11 +67,17 @@ public: | |||
| const ValueTree getComponentState (Component* comp) const; | |||
| void getComponentProperties (Array <PropertyComponent*>& props, Component* comp); | |||
| bool isStateForComponent (const ValueTree& storedState, Component* comp) const; | |||
| Coordinate::MarkerResolver* createComponentMarkerResolver (const ValueTree& state); | |||
| const StringArray getComponentMarkers (bool horizontal) const; | |||
| void removeComponent (const ValueTree& state); | |||
| const RectangleCoordinates getCoordsFor (const ValueTree& componentState) const; | |||
| bool setCoordsFor (ValueTree& componentState, const RectangleCoordinates& newSize); | |||
| // for Coordinate::MarkerResolver: | |||
| const Coordinate findMarker (const String& name, bool isHorizontal) const; | |||
| void getComponentMarkerMenuItems (const ValueTree& componentState, const String& coordName, | |||
| Coordinate& coord, PopupMenu& menu, bool isAnchor1); | |||
| const String getChosenMarkerMenuItem (const ValueTree& componentState, Coordinate& coord, int itemId) const; | |||
| void addNewComponentMenuItems (PopupMenu& menu) const; | |||
| void performNewComponentMenuItem (int menuResultCode); | |||
| @@ -82,28 +87,33 @@ public: | |||
| public: | |||
| MarkerList (ComponentDocument& document, bool isX); | |||
| ValueTree getGroup() const; | |||
| ValueTree& getGroup(); | |||
| int size() const; | |||
| ValueTree getMarker (int index) const; | |||
| ValueTree getMarkerNamed (const String& name) const; | |||
| bool contains (const ValueTree& markerState) const; | |||
| const Coordinate getCoordinate (const ValueTree& markerState) const; | |||
| const String getName (const ValueTree& markerState) const; | |||
| Value getNameAsValue (const ValueTree& markerState) const; | |||
| void setCoordinate (ValueTree& markerState, const Coordinate& newCoord); | |||
| void createMarker (const String& name, int position); | |||
| void deleteMarker (ValueTree& markerState); | |||
| // for Coordinate::MarkerResolver: | |||
| const Coordinate findMarker (const String& name, bool isHorizontal); | |||
| const Coordinate findMarker (const String& name, bool isHorizontal) const; | |||
| private: | |||
| ComponentDocument& document; | |||
| ValueTree group; | |||
| const bool isX; | |||
| MarkerList (const MarkerList&); | |||
| MarkerList& operator= (const MarkerList&); | |||
| }; | |||
| MarkerList& getMarkerListX() { return *markersX; } | |||
| MarkerList& getMarkerListY() { return *markersY; } | |||
| MarkerList& getMarkerList (bool isX) { return isX ? *markersX : *markersY; } | |||
| MarkerList& getMarkerListX() const { return *markersX; } | |||
| MarkerList& getMarkerListY() const { return *markersY; } | |||
| MarkerList& getMarkerList (bool isX) const { return isX ? *markersX : *markersY; } | |||
| const String getNonexistentMarkerName (const String& name); | |||
| @@ -115,7 +125,7 @@ public: | |||
| //============================================================================== | |||
| ValueTree& getRoot() { return root; } | |||
| UndoManager* getUndoManager(); | |||
| UndoManager* getUndoManager() const; | |||
| void beginNewTransaction(); | |||
| void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const var::identifier& property); | |||
| @@ -134,15 +144,17 @@ private: | |||
| File cppFile; | |||
| ValueTree root; | |||
| ScopedPointer<MarkerList> markersX, markersY; | |||
| UndoManager undoManager; | |||
| mutable UndoManager undoManager; | |||
| bool changedSinceSaved; | |||
| void checkRootObject(); | |||
| void createSubTreeIfNotThere (const String& name); | |||
| ValueTree getComponentGroup() const; | |||
| void addMarkerMenuItem (int i, Coordinate& coord, const String& name, PopupMenu& menu, bool isAnchor1, | |||
| const ValueTree& componentState, const String& coordName); | |||
| Value getRootValueUndoable (const var::identifier& name) { return root.getPropertyAsValue (name, getUndoManager()); } | |||
| Value getRootValueNonUndoable (const var::identifier& name) { return root.getPropertyAsValue (name, 0); } | |||
| Value getRootValueUndoable (const var::identifier& name) const { return root.getPropertyAsValue (name, getUndoManager()); } | |||
| Value getRootValueNonUndoable (const var::identifier& name) const { return root.getPropertyAsValue (name, 0); } | |||
| void writeCode (OutputStream& cpp, OutputStream& header); | |||
| void writeMetadata (OutputStream& out); | |||
| @@ -32,23 +32,23 @@ const char* Coordinate::parentRightMarkerName = "parent.right"; | |||
| const char* Coordinate::parentTopMarkerName = "parent.top"; | |||
| const char* Coordinate::parentBottomMarkerName = "parent.bottom"; | |||
| Coordinate::Coordinate (bool isHorizontal_) | |||
| : value (0), isProportion (false), isHorizontal (isHorizontal_) | |||
| Coordinate::Coordinate (bool horizontal_) | |||
| : value (0), isProportion (false), horizontal (horizontal_) | |||
| { | |||
| } | |||
| Coordinate::Coordinate (double absoluteDistanceFromOrigin, bool isHorizontal_) | |||
| : value (absoluteDistanceFromOrigin), isProportion (false), isHorizontal (isHorizontal_) | |||
| Coordinate::Coordinate (double absoluteDistanceFromOrigin, bool horizontal_) | |||
| : value (absoluteDistanceFromOrigin), isProportion (false), horizontal (horizontal_) | |||
| { | |||
| } | |||
| Coordinate::Coordinate (double absoluteDistance, const String& source, bool isHorizontal_) | |||
| : anchor1 (source), value (absoluteDistance), isProportion (false), isHorizontal (isHorizontal_) | |||
| Coordinate::Coordinate (double absoluteDistance, const String& source, bool horizontal_) | |||
| : anchor1 (source), value (absoluteDistance), isProportion (false), horizontal (horizontal_) | |||
| { | |||
| } | |||
| Coordinate::Coordinate (double relativeProportion, const String& pos1, const String& pos2, bool isHorizontal_) | |||
| : anchor1 (pos1), anchor2 (pos2), value (relativeProportion), isProportion (true), isHorizontal (isHorizontal_) | |||
| Coordinate::Coordinate (double relativeProportion, const String& pos1, const String& pos2, bool horizontal_) | |||
| : anchor1 (pos1), anchor2 (pos2), value (relativeProportion), isProportion (true), horizontal (horizontal_) | |||
| { | |||
| } | |||
| @@ -58,12 +58,12 @@ Coordinate::~Coordinate() | |||
| const Coordinate Coordinate::getAnchorPoint1() const | |||
| { | |||
| return Coordinate (0.0, anchor1, isHorizontal); | |||
| return Coordinate (0.0, anchor1, horizontal); | |||
| } | |||
| const Coordinate Coordinate::getAnchorPoint2() const | |||
| { | |||
| return Coordinate (0.0, anchor2, isHorizontal); | |||
| return Coordinate (0.0, anchor2, horizontal); | |||
| } | |||
| bool Coordinate::isOrigin (const String& name) | |||
| @@ -73,12 +73,12 @@ bool Coordinate::isOrigin (const String& name) | |||
| const String Coordinate::getOriginMarkerName() const | |||
| { | |||
| return isHorizontal ? parentLeftMarkerName : parentTopMarkerName; | |||
| return horizontal ? parentLeftMarkerName : parentTopMarkerName; | |||
| } | |||
| const String Coordinate::getExtentMarkerName() const | |||
| { | |||
| return isHorizontal ? parentRightMarkerName : parentBottomMarkerName; | |||
| return horizontal ? parentRightMarkerName : parentBottomMarkerName; | |||
| } | |||
| const String Coordinate::checkName (const String& name) const | |||
| @@ -86,12 +86,12 @@ const String Coordinate::checkName (const String& name) const | |||
| return name.isEmpty() ? getOriginMarkerName() : name; | |||
| } | |||
| double Coordinate::getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const | |||
| double Coordinate::getPosition (const String& name, const MarkerResolver& markerResolver, int recursionCounter) const | |||
| { | |||
| if (isOrigin (name)) | |||
| return 0.0; | |||
| return markerResolver.findMarker (name, isHorizontal) | |||
| return markerResolver.findMarker (name, horizontal) | |||
| .resolve (markerResolver, recursionCounter + 1); | |||
| } | |||
| @@ -99,7 +99,7 @@ struct RecursivePositionException | |||
| { | |||
| }; | |||
| double Coordinate::resolve (MarkerResolver& markerResolver, int recursionCounter) const | |||
| double Coordinate::resolve (const MarkerResolver& markerResolver, int recursionCounter) const | |||
| { | |||
| if (recursionCounter > 100) | |||
| { | |||
| @@ -113,7 +113,7 @@ double Coordinate::resolve (MarkerResolver& markerResolver, int recursionCounter | |||
| : pos1 + value; | |||
| } | |||
| double Coordinate::resolve (MarkerResolver& markerResolver) const | |||
| double Coordinate::resolve (const MarkerResolver& markerResolver) const | |||
| { | |||
| try | |||
| { | |||
| @@ -125,7 +125,7 @@ double Coordinate::resolve (MarkerResolver& markerResolver) const | |||
| return 0.0; | |||
| } | |||
| void Coordinate::moveToAbsolute (double newPos, MarkerResolver& markerResolver) | |||
| void Coordinate::moveToAbsolute (double newPos, const MarkerResolver& markerResolver) | |||
| { | |||
| try | |||
| { | |||
| @@ -147,18 +147,20 @@ void Coordinate::moveToAbsolute (double newPos, MarkerResolver& markerResolver) | |||
| {} | |||
| } | |||
| bool Coordinate::isRecursive (MarkerResolver& markerResolver) const | |||
| bool Coordinate::referencesDirectly (const String& markerName) const | |||
| { | |||
| try | |||
| { | |||
| resolve (markerResolver, 0); | |||
| } | |||
| catch (RecursivePositionException&) | |||
| { | |||
| return true; | |||
| } | |||
| jassert (markerName.isNotEmpty()); | |||
| return anchor1 == markerName || anchor2 == markerName; | |||
| } | |||
| bool Coordinate::referencesIndirectly (const String& markerName, const MarkerResolver& markerResolver) const | |||
| { | |||
| if (isOrigin (anchor1) && ! isProportion) | |||
| return isOrigin (markerName); | |||
| return false; | |||
| return referencesDirectly (markerName) | |||
| || markerResolver.findMarker (anchor1, horizontal).referencesIndirectly (markerName, markerResolver) | |||
| || (isProportion && markerResolver.findMarker (anchor2, horizontal).referencesIndirectly (markerName, markerResolver)); | |||
| } | |||
| void Coordinate::skipWhitespace (const String& s, int& i) | |||
| @@ -215,8 +217,8 @@ double Coordinate::readNumber (const String& s, int& i) | |||
| return value; | |||
| } | |||
| Coordinate::Coordinate (const String& s, bool isHorizontal_) | |||
| : value (0), isProportion (false), isHorizontal (isHorizontal_) | |||
| Coordinate::Coordinate (const String& s, bool horizontal_) | |||
| : value (0), isProportion (false), horizontal (horizontal_) | |||
| { | |||
| int i = 0; | |||
| @@ -311,7 +313,7 @@ void Coordinate::setEditableValue (const double newValue) | |||
| value = isProportion ? newValue / 100.0 : newValue; | |||
| } | |||
| void Coordinate::toggleProportionality (MarkerResolver& markerResolver) | |||
| void Coordinate::toggleProportionality (const MarkerResolver& markerResolver) | |||
| { | |||
| const double oldValue = resolve (markerResolver); | |||
| @@ -322,14 +324,14 @@ void Coordinate::toggleProportionality (MarkerResolver& markerResolver) | |||
| moveToAbsolute (oldValue, markerResolver); | |||
| } | |||
| void Coordinate::changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver) | |||
| void Coordinate::changeAnchor1 (const String& newMarkerName, const MarkerResolver& markerResolver) | |||
| { | |||
| const double oldValue = resolve (markerResolver); | |||
| anchor1 = newMarkerName; | |||
| moveToAbsolute (oldValue, markerResolver); | |||
| } | |||
| void Coordinate::changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver) | |||
| void Coordinate::changeAnchor2 (const String& newMarkerName, const MarkerResolver& markerResolver) | |||
| { | |||
| const double oldValue = resolve (markerResolver); | |||
| anchor2 = newMarkerName; | |||
| @@ -342,11 +344,11 @@ RectangleCoordinates::RectangleCoordinates() | |||
| { | |||
| } | |||
| RectangleCoordinates::RectangleCoordinates (const Rectangle<int>& rect) | |||
| RectangleCoordinates::RectangleCoordinates (const Rectangle<int>& rect, const String& componentName) | |||
| : left (rect.getX(), true), | |||
| right (rect.getWidth(), "left", true), | |||
| right (rect.getWidth(), componentName + ".left", true), | |||
| top (rect.getY(), false), | |||
| bottom (rect.getHeight(), "top", false) | |||
| bottom (rect.getHeight(), componentName + ".top", false) | |||
| { | |||
| } | |||
| @@ -362,13 +364,7 @@ RectangleCoordinates::RectangleCoordinates (const String& stringVersion) | |||
| bottom = Coordinate (tokens [3], false); | |||
| } | |||
| bool RectangleCoordinates::isRecursive (Coordinate::MarkerResolver& markerResolver) const | |||
| { | |||
| return left.isRecursive (markerResolver) || right.isRecursive (markerResolver) | |||
| || top.isRecursive (markerResolver) || bottom.isRecursive (markerResolver); | |||
| } | |||
| const Rectangle<int> RectangleCoordinates::resolve (Coordinate::MarkerResolver& markerResolver) const | |||
| const Rectangle<int> RectangleCoordinates::resolve (const Coordinate::MarkerResolver& markerResolver) const | |||
| { | |||
| const int l = roundToInt (left.resolve (markerResolver)); | |||
| const int r = roundToInt (right.resolve (markerResolver)); | |||
| @@ -378,7 +374,7 @@ const Rectangle<int> RectangleCoordinates::resolve (Coordinate::MarkerResolver& | |||
| return Rectangle<int> (l, t, r - l, b - t); | |||
| } | |||
| void RectangleCoordinates::moveToAbsolute (const Rectangle<int>& newPos, Coordinate::MarkerResolver& markerResolver) | |||
| void RectangleCoordinates::moveToAbsolute (const Rectangle<int>& newPos, const Coordinate::MarkerResolver& markerResolver) | |||
| { | |||
| left.moveToAbsolute (newPos.getX(), markerResolver); | |||
| right.moveToAbsolute (newPos.getRight(), markerResolver); | |||
| @@ -64,17 +64,21 @@ public: | |||
| { | |||
| public: | |||
| virtual ~MarkerResolver() {} | |||
| virtual const Coordinate findMarker (const String& name, bool isHorizontal) = 0; | |||
| virtual const Coordinate findMarker (const String& name, bool isHorizontal) const = 0; | |||
| }; | |||
| /** Calculates the absolute position of this co-ordinate. */ | |||
| double resolve (MarkerResolver& markerResolver) const; | |||
| double resolve (const MarkerResolver& markerResolver) const; | |||
| /** Returns true if this co-ordinate is expressed in terms of markers that form a recursive loop. */ | |||
| bool isRecursive (MarkerResolver& markerResolver) const; | |||
| /** Returns true if this co-ordinate is expressed directly in terms of the specified marker. */ | |||
| bool referencesDirectly (const String& markerName) const; | |||
| /** Returns true if this co-ordinate is expressed in terms of the specified marker at any | |||
| level in its evaluation. */ | |||
| bool referencesIndirectly (const String& markerName, const MarkerResolver& markerResolver) const; | |||
| /** Changes the value of this marker to make it resolve to the specified position. */ | |||
| void moveToAbsolute (double newPos, MarkerResolver& markerResolver); | |||
| void moveToAbsolute (double newPos, const MarkerResolver& markerResolver); | |||
| const Coordinate getAnchorPoint1() const; | |||
| const Coordinate getAnchorPoint2() const; | |||
| @@ -82,14 +86,16 @@ public: | |||
| const double getEditableValue() const; | |||
| void setEditableValue (const double newValue); | |||
| bool isHorizontal() const throw() { return horizontal; } | |||
| bool isProportional() const throw() { return isProportion; } | |||
| void toggleProportionality (MarkerResolver& markerResolver); | |||
| void toggleProportionality (const MarkerResolver& markerResolver); | |||
| const String getAnchor1() const { return checkName (anchor1); } | |||
| void changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver); | |||
| void changeAnchor1 (const String& newMarkerName, const MarkerResolver& markerResolver); | |||
| const String getAnchor2() const { return checkName (anchor2); } | |||
| void changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver); | |||
| void changeAnchor2 (const String& newMarkerName, const MarkerResolver& markerResolver); | |||
| //============================================================================== | |||
| /* | |||
| @@ -103,9 +109,8 @@ public: | |||
| 50% * marker1 -> marker2 = percentage between two markers | |||
| standard marker names: | |||
| "origin" = parent origin | |||
| "size" = parent right or bottom | |||
| "top", "left", "bottom", "right" = refer to the component's own left, right, top and bottom. | |||
| "parent.top", "parent.left", "parent.bottom", "parent.right" | |||
| "componentName.top", "componentName.left", "componentName.bottom", "componentName.right" | |||
| */ | |||
| const String toString() const; | |||
| @@ -119,10 +124,10 @@ private: | |||
| //============================================================================== | |||
| String anchor1, anchor2; | |||
| double value; | |||
| bool isProportion, isHorizontal; | |||
| bool isProportion, horizontal; | |||
| double resolve (MarkerResolver& markerResolver, int recursionCounter) const; | |||
| double getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const; | |||
| double resolve (const MarkerResolver& markerResolver, int recursionCounter) const; | |||
| double getPosition (const String& name, const MarkerResolver& markerResolver, int recursionCounter) const; | |||
| const String checkName (const String& name) const; | |||
| const String getOriginMarkerName() const; | |||
| const String getExtentMarkerName() const; | |||
| @@ -141,13 +146,12 @@ class RectangleCoordinates | |||
| public: | |||
| //============================================================================== | |||
| RectangleCoordinates(); | |||
| explicit RectangleCoordinates (const Rectangle<int>& rect); | |||
| explicit RectangleCoordinates (const Rectangle<int>& rect, const String& componentName); | |||
| explicit RectangleCoordinates (const String& stringVersion); | |||
| //============================================================================== | |||
| const Rectangle<int> resolve (Coordinate::MarkerResolver& markerResolver) const; | |||
| bool isRecursive (Coordinate::MarkerResolver& markerResolver) const; | |||
| void moveToAbsolute (const Rectangle<int>& newPos, Coordinate::MarkerResolver& markerResolver); | |||
| const Rectangle<int> resolve (const Coordinate::MarkerResolver& markerResolver) const; | |||
| void moveToAbsolute (const Rectangle<int>& newPos, const Coordinate::MarkerResolver& markerResolver); | |||
| const String toString() const; | |||
| Coordinate left, right, top, bottom; | |||
| @@ -838,6 +838,9 @@ private: | |||
| << "{{{" << newLine | |||
| << "}}}" << newLine; | |||
| } | |||
| MSVCProjectExporter (const MSVCProjectExporter&); | |||
| MSVCProjectExporter& operator= (const MSVCProjectExporter&); | |||
| }; | |||
| @@ -316,6 +316,9 @@ private: | |||
| { | |||
| return file.withFileExtension (".o").getFileName(); | |||
| } | |||
| MakefileProjectExporter (const MakefileProjectExporter&); | |||
| MakefileProjectExporter& operator= (const MakefileProjectExporter&); | |||
| }; | |||
| @@ -99,6 +99,10 @@ protected: | |||
| name = name + ".a"; | |||
| return name; | |||
| } | |||
| private: | |||
| ProjectExporter (const ProjectExporter&); | |||
| ProjectExporter& operator= (const ProjectExporter&); | |||
| }; | |||
| @@ -351,7 +351,6 @@ private: | |||
| << "#define JucePlugin_IsSynth " << ((bool) project.getPluginIsSynth().getValue() ? 1 : 0) << newLine | |||
| << "#define JucePlugin_WantsMidiInput " << ((bool) project.getPluginWantsMidiInput().getValue() ? 1 : 0) << newLine | |||
| << "#define JucePlugin_ProducesMidiOutput " << ((bool) project.getPluginProducesMidiOut().getValue() ? 1 : 0) << newLine | |||
| << "#define JucePlugin_IsSynth " << ((bool) project.getPluginIsSynth().getValue() ? 1 : 0) << newLine | |||
| << "#define JucePlugin_SilenceInProducesSilenceOut " << ((bool) project.getPluginSilenceInProducesSilenceOut().getValue() ? 1 : 0) << newLine | |||
| << "#define JucePlugin_TailLengthSeconds " << (double) project.getPluginTailLengthSeconds().getValue() << newLine | |||
| << "#define JucePlugin_EditorRequiresKeyboardFocus " << ((bool) project.getPluginEditorNeedsKeyFocus().getValue() ? 1 : 0) << newLine | |||
| @@ -206,15 +206,13 @@ public: | |||
| const Rectangle<int> newBounds (zone.resizeRectangleBy (originalPos, distance)); | |||
| RectangleCoordinates pr (getDocument().getCoordsFor (v)); | |||
| ScopedPointer<Coordinate::MarkerResolver> markers (getDocument().createComponentMarkerResolver (v)); | |||
| pr.moveToAbsolute (newBounds, *markers); | |||
| pr.moveToAbsolute (newBounds, getDocument()); | |||
| return getDocument().setCoordsFor (v, pr); | |||
| } | |||
| //============================================================================== | |||
| private: | |||
| //============================================================================== | |||
| ComponentEditorCanvas& canvas; | |||
| Array <ValueTree> draggedComponents; | |||
| Array <Rectangle<int> > originalPositions; | |||
| @@ -229,8 +227,7 @@ private: | |||
| const Rectangle<float> getComponentPosition (const ValueTree& state) | |||
| { | |||
| RectangleCoordinates relativePos (getDocument().getCoordsFor (state)); | |||
| ScopedPointer<Coordinate::MarkerResolver> markers (getDocument().createComponentMarkerResolver (state)); | |||
| const Rectangle<int> intPos (relativePos.resolve (*markers)); | |||
| const Rectangle<int> intPos (relativePos.resolve (getDocument())); | |||
| originalPositions.add (intPos); | |||
| return intPos.toFloat(); | |||
| @@ -238,7 +238,10 @@ void ComponentEditor::getAllCommands (Array <CommandID>& commands) | |||
| DocumentEditorComponent::getAllCommands (commands); | |||
| const CommandID ids[] = { CommandIDs::undo, | |||
| CommandIDs::redo }; | |||
| CommandIDs::redo, | |||
| CommandIDs::toFront, | |||
| CommandIDs::toBack, | |||
| StandardApplicationCommandIDs::del }; | |||
| commands.addArray (ids, numElementsInArray (ids)); | |||
| } | |||
| @@ -250,18 +253,30 @@ void ComponentEditor::getCommandInfo (CommandID commandID, ApplicationCommandInf | |||
| switch (commandID) | |||
| { | |||
| case CommandIDs::undo: | |||
| result.setInfo ("Undo", "Undoes the last change", | |||
| CommandCategories::general, 0); | |||
| result.setInfo ("Undo", "Undoes the last change", CommandCategories::general, 0); | |||
| result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::commandModifier, 0)); | |||
| break; | |||
| case CommandIDs::redo: | |||
| result.setInfo ("Redo", "Redoes the last change", | |||
| CommandCategories::general, 0); | |||
| result.setInfo ("Redo", "Redoes the last change", CommandCategories::general, 0); | |||
| result.defaultKeypresses.add (KeyPress ('z', ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0)); | |||
| result.defaultKeypresses.add (KeyPress ('y', ModifierKeys::commandModifier, 0)); | |||
| break; | |||
| case CommandIDs::toFront: | |||
| result.setInfo ("Bring to Front", "Brings the selected items to the front", CommandCategories::editing, 0); | |||
| break; | |||
| case CommandIDs::toBack: | |||
| result.setInfo ("Send to Back", "Moves the selected items to the back", CommandCategories::editing, 0); | |||
| break; | |||
| case StandardApplicationCommandIDs::del: | |||
| result.setInfo ("Delete", String::empty, CommandCategories::general, 0); | |||
| result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0)); | |||
| result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0)); | |||
| break; | |||
| default: | |||
| DocumentEditorComponent::getCommandInfo (commandID, result); | |||
| break; | |||
| @@ -280,6 +295,18 @@ bool ComponentEditor::perform (const InvocationInfo& info) | |||
| getDocument().getUndoManager()->redo(); | |||
| return true; | |||
| case CommandIDs::toFront: | |||
| getCanvas()->selectionToFront(); | |||
| return true; | |||
| case CommandIDs::toBack: | |||
| getCanvas()->selectionToBack(); | |||
| return true; | |||
| case StandardApplicationCommandIDs::del: | |||
| getCanvas()->deleteSelection(); | |||
| return true; | |||
| default: | |||
| break; | |||
| } | |||
| @@ -115,13 +115,13 @@ public: | |||
| //============================================================================== | |||
| SizeGuideComponent (ComponentEditorCanvas& canvas_, const ValueTree& state_, Component* component_, Type type_) | |||
| : OverlayItemComponent (canvas_), state (state_), component (component_), type (type_), | |||
| font (10.0f) | |||
| : OverlayItemComponent (canvas_), state (state_), component (component_), type (type_) | |||
| { | |||
| component->addComponentListener (this); | |||
| setAlwaysOnTop (true); | |||
| canvas.addAndMakeVisible (this); | |||
| setInterceptsMouseClicks (false, false); | |||
| updatePosition(); | |||
| } | |||
| @@ -137,25 +137,10 @@ public: | |||
| const float dashes[] = { 4.0f, 3.0f }; | |||
| g.setColour (resizableBorderColour); | |||
| g.drawDashedLine (lineEnd1.getX() + 0.5f, lineEnd1.getY() + 0.5f, | |||
| lineEnd2.getX() + 0.5f, lineEnd2.getY() + 0.5f, | |||
| dashes, 2, 1.0f); | |||
| g.setFont (font); | |||
| g.setColour (Colours::white); | |||
| for (int y = -1; y <= 1; ++y) | |||
| for (int x = -1; x <= 1; ++x) | |||
| g.drawText (getName(), textArea.getX() + x, textArea.getY() + y, textArea.getWidth(), textArea.getHeight(), Justification::centred, 1); | |||
| g.setColour (Colours::black); | |||
| g.drawText (getName(), textArea.getX(), textArea.getY(), textArea.getWidth(), textArea.getHeight(), Justification::centred, 1); | |||
| g.drawDashedLine (0.5f, 0.5f, getWidth() - 0.5f, getHeight() - 0.5f, dashes, 2, 1.0f); | |||
| } | |||
| void componentMovedOrResized (Component&, bool, bool) | |||
| { | |||
| updatePosition(); | |||
| } | |||
| void componentMovedOrResized (Component&, bool, bool) { updatePosition(); } | |||
| void componentBeingDeleted (Component&) | |||
| { | |||
| @@ -166,72 +151,32 @@ public: | |||
| //============================================================================== | |||
| void updatePosition() | |||
| { | |||
| RectangleCoordinates coords (getDocument().getCoordsFor (state)); | |||
| Coordinate coord (false); | |||
| bool isHorizontal = false; | |||
| switch (type) | |||
| if (component != 0) | |||
| { | |||
| case left: coord = coords.left; isHorizontal = true; break; | |||
| case right: coord = coords.right; isHorizontal = true; break; | |||
| case top: coord = coords.top; break; | |||
| case bottom: coord = coords.bottom; break; | |||
| default: jassertfalse; break; | |||
| } | |||
| setName (coord.toString()); | |||
| int textW = (int) font.getStringWidth (getName()); | |||
| int textH = (int) font.getHeight(); | |||
| RectangleCoordinates coords (getDocument().getCoordsFor (state)); | |||
| Coordinate coord (false); | |||
| Rectangle<int> r; | |||
| Point<int> p1, p2; | |||
| switch (type) | |||
| { | |||
| case left: coord = coords.left; r.setBounds (component->getX(), 0, 1, component->getY()); break; | |||
| case right: coord = coords.right; r.setBounds (component->getRight(), 0, 1, component->getY()); break; | |||
| case top: coord = coords.top; r.setBounds (0, component->getY(), component->getX(), 1); break; | |||
| case bottom: coord = coords.bottom; r.setBounds (0, component->getBottom(), component->getX(), 1); break; | |||
| default: jassertfalse; break; | |||
| } | |||
| switch (type) | |||
| { | |||
| case left: | |||
| p1 = Point<int> (component->getX(), 0); | |||
| p2 = Point<int> (component->getX(), component->getY()); | |||
| textArea.setBounds (p1.getX() - textW - 2, 4, textW, textH); | |||
| break; | |||
| case right: | |||
| p1 = Point<int> (component->getRight(), 0); | |||
| p2 = Point<int> (component->getRight(), component->getY()); | |||
| textArea.setBounds (p1.getX() + 2, 4, textW, textH); | |||
| break; | |||
| case top: | |||
| p1 = Point<int> (0, component->getY()); | |||
| p2 = Point<int> (component->getX(), component->getY()); | |||
| textArea.setBounds (4, p1.getY() - textH - 2, textW, textH); | |||
| break; | |||
| case bottom: | |||
| p1 = Point<int> (0, component->getBottom()); | |||
| p2 = Point<int> (component->getX(), component->getBottom()); | |||
| textArea.setBounds (4, p1.getY() + 2, textW, textH); | |||
| break; | |||
| default: | |||
| jassertfalse; | |||
| break; | |||
| setBoundsInTargetSpace (r); | |||
| label.update (getParentComponent(), coord.toString(), resizableBorderColour.withAlpha (0.9f), getX(), getY(), type != left, type != top); | |||
| } | |||
| setBoundsInTargetSpace (Rectangle<int> (p1, p2).expanded (2, 2).getUnion (textArea)); | |||
| lineEnd1 = component->getParentComponent()->relativePositionToOtherComponent (this, p1); | |||
| lineEnd2 = component->getParentComponent()->relativePositionToOtherComponent (this, p2); | |||
| textArea.setPosition (component->getParentComponent()->relativePositionToOtherComponent (this, textArea.getPosition())); | |||
| repaint(); | |||
| } | |||
| private: | |||
| ValueTree state; | |||
| Component* component; | |||
| Type type; | |||
| Font font; | |||
| FloatingLabelComponent label; | |||
| Point<int> lineEnd1, lineEnd2; | |||
| Rectangle<int> textArea; | |||
| }; | |||
| void showSizeGuides() | |||
| @@ -295,21 +240,33 @@ public: | |||
| void paint (Graphics& g) | |||
| { | |||
| g.setColour (Colours::darkgreen); | |||
| g.setColour (Colours::darkgreen.withAlpha (isMouseOverOrDragging() ? 0.8f : 0.4f)); | |||
| g.fillPath (path); | |||
| } | |||
| void updatePosition() | |||
| { | |||
| ComponentDocument& doc = getDocument(); | |||
| Coordinate coord (doc.getMarkerList (isX).getCoordinate (marker)); | |||
| const int pos = roundToInt (coord.resolve (doc.getMarkerList (isX))); | |||
| const int width = 10; | |||
| Coordinate coord (getMarkerList().getCoordinate (marker)); | |||
| const int pos = roundToInt (coord.resolve (getMarkerList())); | |||
| const int width = 8; | |||
| if (isX) | |||
| setBoundsInTargetSpace (Rectangle<int> (pos - width, -headSize, width * 2, getParentHeight())); | |||
| else | |||
| setBoundsInTargetSpace (Rectangle<int> (-headSize, pos - width, getParentWidth(), width * 2)); | |||
| labelText = "name: " + getMarkerList().getName (marker) + "\nposition: " + coord.toString(); | |||
| updateLabel(); | |||
| } | |||
| void updateLabel() | |||
| { | |||
| if (isMouseOverOrDragging() && (getWidth() > 1 || getHeight() > 1)) | |||
| label.update (getParentComponent(), labelText, Colours::darkgreen, | |||
| isX ? getBounds().getCentreX() : getX() + headSize, | |||
| isX ? getY() + headSize : getBounds().getCentreY(), true, true); | |||
| else | |||
| label.remove(); | |||
| } | |||
| bool hitTest (int x, int y) | |||
| @@ -334,10 +291,15 @@ public: | |||
| path.addLineSegment (2.0f, centre, getWidth() + 1.0f, centre, lineThickness); | |||
| path.addTriangle (0.0f, centre * 2.0f - 1.0f, 0.0f, 1.0f, headSize + 1.0f, centre); | |||
| } | |||
| updateLabel(); | |||
| } | |||
| void mouseDown (const MouseEvent& e) | |||
| { | |||
| toFront (false); | |||
| updateLabel(); | |||
| if (e.mods.isPopupMenu()) | |||
| { | |||
| isDragging = false; | |||
| @@ -347,9 +309,8 @@ public: | |||
| isDragging = true; | |||
| getDocument().beginNewTransaction(); | |||
| ComponentDocument& doc = getDocument(); | |||
| Coordinate coord (doc.getMarkerList(isX).getCoordinate (marker)); | |||
| dragStartPos = coord.resolve (doc.getMarkerList (isX)); | |||
| Coordinate coord (getMarkerList().getCoordinate (marker)); | |||
| dragStartPos = coord.resolve (getMarkerList()); | |||
| } | |||
| } | |||
| @@ -360,27 +321,47 @@ public: | |||
| ComponentDocument& doc = getDocument(); | |||
| doc.getUndoManager()->undoCurrentTransactionOnly(); | |||
| Coordinate coord (doc.getMarkerList (isX).getCoordinate (marker)); | |||
| coord.moveToAbsolute (jmax (0.0, dragStartPos + (isX ? e.getDistanceFromDragStartX() | |||
| : e.getDistanceFromDragStartY())), | |||
| doc.getMarkerList (isX)); | |||
| doc.getMarkerList(isX).setCoordinate (marker, coord); | |||
| Rectangle<int> axis; | |||
| if (isX) | |||
| axis.setBounds (0, 0, getParentWidth(), headSize); | |||
| else | |||
| axis.setBounds (0, 0, headSize, getParentHeight()); | |||
| if (axis.expanded (30, 30).contains (e.x, e.y)) | |||
| { | |||
| Coordinate coord (getMarkerList().getCoordinate (marker)); | |||
| coord.moveToAbsolute (jmax (0.0, dragStartPos + (isX ? e.getDistanceFromDragStartX() | |||
| : e.getDistanceFromDragStartY())), | |||
| getMarkerList()); | |||
| getMarkerList().setCoordinate (marker, coord); | |||
| } | |||
| else | |||
| { | |||
| getMarkerList().deleteMarker (marker); | |||
| } | |||
| } | |||
| } | |||
| void mouseUp (const MouseEvent& e) | |||
| { | |||
| getDocument().beginNewTransaction(); | |||
| updateLabel(); | |||
| } | |||
| void mouseEnter (const MouseEvent& e) | |||
| { | |||
| updateLabel(); | |||
| repaint(); | |||
| } | |||
| void mouseExit (const MouseEvent& e) | |||
| { | |||
| updateLabel(); | |||
| repaint(); | |||
| } | |||
| ComponentDocument::MarkerList& getMarkerList() { return getDocument().getMarkerList (isX); } | |||
| void valueTreePropertyChanged (ValueTree&, const var::identifier&) { updatePosition(); } | |||
| void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) {} | |||
| void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) {} | |||
| @@ -393,12 +374,94 @@ private: | |||
| Path path; | |||
| double dragStartPos; | |||
| bool isDragging; | |||
| FloatingLabelComponent label; | |||
| String labelText; | |||
| }; | |||
| //============================================================================== | |||
| class ComponentEditorCanvas::ComponentHolder : public Component | |||
| { | |||
| public: | |||
| ComponentHolder() {} | |||
| ~ComponentHolder() {} | |||
| void updateComponents (ComponentDocument& doc, SelectedItems& selection) | |||
| { | |||
| int i; | |||
| for (i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* c = getChildComponent (i); | |||
| if (! doc.containsComponent (c)) | |||
| { | |||
| selection.deselect (c->getComponentUID()); | |||
| delete c; | |||
| } | |||
| } | |||
| Array <Component*> componentsInOrder; | |||
| const int num = doc.getNumComponents(); | |||
| for (i = 0; i < num; ++i) | |||
| { | |||
| const ValueTree v (doc.getComponent (i)); | |||
| Component* c = getComponentForState (doc, v); | |||
| if (c == 0) | |||
| { | |||
| c = doc.createComponent (i); | |||
| addAndMakeVisible (c); | |||
| } | |||
| doc.updateComponent (c); | |||
| componentsInOrder.add (c); | |||
| } | |||
| // Make sure the z-order is correct.. | |||
| for (i = 0; i < num - 1; ++i) | |||
| componentsInOrder.getUnchecked(i)->toBehind (componentsInOrder.getUnchecked (i + 1)); | |||
| } | |||
| Component* getComponentForState (ComponentDocument& doc, const ValueTree& state) | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* const c = getChildComponent (i); | |||
| if (doc.isStateForComponent (state, c)) | |||
| return c; | |||
| } | |||
| return 0; | |||
| } | |||
| Component* findComponentAt (const Point<int>& pos) const | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* const c = getChildComponent(i); | |||
| if (c->getBounds().contains (pos)) | |||
| return c; | |||
| } | |||
| return 0; | |||
| } | |||
| void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, const Rectangle<int>& lassoArea) | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* c = getChildComponent(i); | |||
| if (c->getBounds().intersects (lassoArea)) | |||
| itemsFound.add (c->getComponentUID()); | |||
| } | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class ComponentEditorCanvas::OverlayComponent : public Component, | |||
| public LassoSource <ComponentDocument::SelectedItems::ItemType>, | |||
| public LassoSource <SelectedItems::ItemType>, | |||
| public ChangeListener, | |||
| public ValueTree::Listener | |||
| { | |||
| @@ -433,31 +496,39 @@ public: | |||
| mouseDownCompUID = 0; | |||
| isDraggingClickedComp = false; | |||
| Component* underMouse = canvas.getComponentHolder()->findComponentAt (e.getEventRelativeTo (canvas.getComponentHolder()).getPosition()); | |||
| if (e.mods.isPopupMenu()) | |||
| { | |||
| if (underMouse != 0) | |||
| { | |||
| if (! canvas.getSelection().isSelected (underMouse->getComponentUID())) | |||
| canvas.getSelection().selectOnly (underMouse->getComponentUID()); | |||
| } | |||
| PopupMenu m; | |||
| getDocument().addNewComponentMenuItems (m); | |||
| const int r = m.show(); | |||
| getDocument().performNewComponentMenuItem (r); | |||
| if (underMouse != 0) | |||
| { | |||
| m.addCommandItem (commandManager, CommandIDs::toFront); | |||
| m.addCommandItem (commandManager, CommandIDs::toBack); | |||
| m.addSeparator(); | |||
| m.addCommandItem (commandManager, StandardApplicationCommandIDs::del); | |||
| const int r = m.show(); | |||
| (void) r; | |||
| } | |||
| else | |||
| { | |||
| getDocument().addNewComponentMenuItems (m); | |||
| const int r = m.show(); | |||
| getDocument().performNewComponentMenuItem (r); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| Component* underMouse = 0; | |||
| for (int i = canvas.getComponentHolder()->getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* const c = canvas.getComponentHolder()->getChildComponent(i); | |||
| if (c->getBounds().contains (e.getPosition())) | |||
| { | |||
| underMouse = c; | |||
| break; | |||
| } | |||
| } | |||
| if (underMouse == 0 || e.mods.isAltDown()) | |||
| { | |||
| addAndMakeVisible (lasso = new LassoComponent <ComponentDocument::SelectedItems::ItemType>()); | |||
| addAndMakeVisible (lasso = new LassoComponent <SelectedItems::ItemType>()); | |||
| lasso->beginLasso (e, this); | |||
| } | |||
| else | |||
| @@ -529,19 +600,13 @@ public: | |||
| } | |||
| } | |||
| void findLassoItemsInArea (Array <ComponentDocument::SelectedItems::ItemType>& itemsFound, int x, int y, int width, int height) | |||
| void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, int x, int y, int width, int height) | |||
| { | |||
| const Rectangle<int> lassoArea (x, y, width, height); | |||
| for (int i = canvas.getComponentHolder()->getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* c = canvas.getComponentHolder()->getChildComponent(i); | |||
| if (c->getBounds().intersects (lassoArea)) | |||
| itemsFound.add (c->getComponentUID()); | |||
| } | |||
| canvas.getComponentHolder()->findLassoItemsInArea (itemsFound, Rectangle<int> (x, y, width, height) | |||
| + relativePositionToOtherComponent (canvas.getComponentHolder(), Point<int>())); | |||
| } | |||
| ComponentDocument::SelectedItems& getLassoSelection() { return canvas.getSelection(); } | |||
| SelectedItems& getLassoSelection() { return canvas.getSelection(); } | |||
| void resized() | |||
| { | |||
| @@ -586,13 +651,13 @@ private: | |||
| //============================================================================== | |||
| ComponentEditorCanvas& canvas; | |||
| ValueTree markerRootX, markerRootY; | |||
| ScopedPointer <LassoComponent <ComponentDocument::SelectedItems::ItemType> > lasso; | |||
| ScopedPointer <LassoComponent <SelectedItems::ItemType> > lasso; | |||
| bool mouseDownResult, isDraggingClickedComp; | |||
| uint32 mouseDownCompUID; | |||
| ComponentDocument& getDocument() { return canvas.getDocument(); } | |||
| Component* getComponentWithUID (const int uid) const | |||
| Component* getComponentWithUID (const uint32 uid) const | |||
| { | |||
| for (int i = canvas.getComponentHolder()->getNumChildComponents(); --i >= 0;) | |||
| { | |||
| @@ -607,7 +672,7 @@ private: | |||
| void updateResizeFrames() | |||
| { | |||
| ComponentDocument::SelectedItems& selection = canvas.getSelection(); | |||
| SelectedItems& selection = canvas.getSelection(); | |||
| Array<int> requiredIds; | |||
| int i; | |||
| @@ -643,11 +708,12 @@ private: | |||
| void updateMarkers (bool isX) | |||
| { | |||
| ComponentDocument& doc = getDocument(); | |||
| ComponentDocument::MarkerList& markerList = doc.getMarkerList (isX); | |||
| Array<ValueTree> requiredMarkers; | |||
| int i; | |||
| for (i = doc.getMarkerList (isX).size(); --i >= 0;) | |||
| requiredMarkers.add (doc.getMarkerList (isX).getMarker (i)); | |||
| requiredMarkers.add (markerList.getMarker (i)); | |||
| for (i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| @@ -657,12 +723,16 @@ private: | |||
| { | |||
| if (requiredMarkers.contains (marker->marker)) | |||
| { | |||
| marker->setVisible (true); | |||
| marker->updatePosition(); | |||
| requiredMarkers.removeValue (marker->marker); | |||
| } | |||
| else | |||
| { | |||
| delete marker; | |||
| if (marker->isMouseButtonDown()) | |||
| marker->setBounds (-1, -1, 1, 1); | |||
| else | |||
| delete marker; | |||
| } | |||
| } | |||
| } | |||
| @@ -684,57 +754,6 @@ private: | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class ComponentEditorCanvas::ComponentHolder : public Component | |||
| { | |||
| public: | |||
| ComponentHolder() {} | |||
| ~ComponentHolder() {} | |||
| void updateComponents (ComponentDocument& doc, ComponentDocument::SelectedItems& selection) | |||
| { | |||
| int i; | |||
| for (i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* c = getChildComponent (i); | |||
| if (! doc.containsComponent (c)) | |||
| { | |||
| selection.deselect (c->getComponentUID()); | |||
| delete c; | |||
| } | |||
| } | |||
| const int num = doc.getNumComponents(); | |||
| for (i = 0; i < num; ++i) | |||
| { | |||
| const ValueTree v (doc.getComponent (i)); | |||
| Component* c = getComponentForState (doc, v); | |||
| if (c == 0) | |||
| { | |||
| c = doc.createComponent (i); | |||
| addAndMakeVisible (c); | |||
| } | |||
| doc.updateComponent (c); | |||
| } | |||
| } | |||
| Component* getComponentForState (ComponentDocument& doc, const ValueTree& state) | |||
| { | |||
| for (int i = getNumChildComponents(); --i >= 0;) | |||
| { | |||
| Component* const c = getChildComponent (i); | |||
| if (doc.isStateForComponent (state, c)) | |||
| return c; | |||
| } | |||
| return 0; | |||
| } | |||
| }; | |||
| //============================================================================== | |||
| class ComponentEditorCanvas::WholeComponentResizer : public Component | |||
| { | |||
| @@ -848,10 +867,10 @@ ComponentEditorCanvas::~ComponentEditorCanvas() | |||
| } | |||
| //============================================================================== | |||
| ComponentEditor& ComponentEditorCanvas::getEditor() { return editor; } | |||
| ComponentDocument& ComponentEditorCanvas::getDocument() { return editor.getDocument(); } | |||
| ComponentDocument::SelectedItems& ComponentEditorCanvas::getSelection() { return selection; } | |||
| Component* ComponentEditorCanvas::getComponentHolder() const { return componentHolder; } | |||
| ComponentEditor& ComponentEditorCanvas::getEditor() { return editor; } | |||
| ComponentDocument& ComponentEditorCanvas::getDocument() { return editor.getDocument(); } | |||
| ComponentEditorCanvas::SelectedItems& ComponentEditorCanvas::getSelection() { return selection; } | |||
| ComponentEditorCanvas::ComponentHolder* ComponentEditorCanvas::getComponentHolder() const { return componentHolder; } | |||
| void ComponentEditorCanvas::timerCallback() | |||
| { | |||
| @@ -944,6 +963,73 @@ void ComponentEditorCanvas::getSelectedItemProperties (Array <PropertyComponent* | |||
| } | |||
| } | |||
| void ComponentEditorCanvas::deleteSelection() | |||
| { | |||
| getDocument().beginNewTransaction(); | |||
| for (int i = selection.getNumSelected(); --i >= 0;) | |||
| { | |||
| Component* c = getComponentForUID (selection.getSelectedItem (0)); | |||
| if (c != 0) | |||
| getDocument().removeComponent (getDocument().getComponentState (c)); | |||
| } | |||
| selection.deselectAll(); | |||
| getDocument().beginNewTransaction(); | |||
| } | |||
| void ComponentEditorCanvas::selectionToFront() | |||
| { | |||
| getDocument().beginNewTransaction(); | |||
| int index = 0; | |||
| for (int i = getDocument().getNumComponents(); --i >= 0;) | |||
| { | |||
| const ValueTree comp (getDocument().getComponent (index)); | |||
| Component* c = componentHolder->getComponentForState (getDocument(), comp); | |||
| if (c != 0 && selection.isSelected (c->getComponentUID())) | |||
| { | |||
| ValueTree parent (comp.getParent()); | |||
| parent.removeChild (comp, getDocument().getUndoManager()); | |||
| parent.addChild (comp, -1, getDocument().getUndoManager()); | |||
| } | |||
| else | |||
| { | |||
| ++index; | |||
| } | |||
| } | |||
| getDocument().beginNewTransaction(); | |||
| } | |||
| void ComponentEditorCanvas::selectionToBack() | |||
| { | |||
| getDocument().beginNewTransaction(); | |||
| int index = getDocument().getNumComponents() - 1; | |||
| for (int i = getDocument().getNumComponents(); --i >= 0;) | |||
| { | |||
| const ValueTree comp (getDocument().getComponent (index)); | |||
| Component* c = componentHolder->getComponentForState (getDocument(), comp); | |||
| if (c != 0 && selection.isSelected (c->getComponentUID())) | |||
| { | |||
| ValueTree parent (comp.getParent()); | |||
| parent.removeChild (comp, getDocument().getUndoManager()); | |||
| parent.addChild (comp, 0, getDocument().getUndoManager()); | |||
| } | |||
| else | |||
| { | |||
| --index; | |||
| } | |||
| } | |||
| getDocument().beginNewTransaction(); | |||
| } | |||
| //============================================================================== | |||
| void ComponentEditorCanvas::showSizeGuides() { overlay->showSizeGuides(); } | |||
| void ComponentEditorCanvas::hideSizeGuides() { overlay->hideSizeGuides(); } | |||
| @@ -44,8 +44,12 @@ public: | |||
| //============================================================================== | |||
| ComponentEditor& getEditor(); | |||
| ComponentDocument& getDocument(); | |||
| ComponentDocument::SelectedItems& getSelection(); | |||
| Component* getComponentHolder() const; | |||
| typedef SelectedItemSet<uint32> SelectedItems; | |||
| SelectedItems& getSelection(); | |||
| class ComponentHolder; | |||
| ComponentHolder* getComponentHolder() const; | |||
| //============================================================================== | |||
| void timerCallback(); | |||
| @@ -64,6 +68,9 @@ public: | |||
| //============================================================================== | |||
| void getSelectedItemProperties (Array <PropertyComponent*>& props); | |||
| void deleteSelection(); | |||
| void selectionToFront(); | |||
| void selectionToBack(); | |||
| //============================================================================== | |||
| void showSizeGuides(); | |||
| @@ -98,7 +105,6 @@ private: | |||
| friend class OverlayItemComponent; | |||
| class ComponentResizeFrame; | |||
| class MarkerComponent; | |||
| class ComponentHolder; | |||
| class WholeComponentResizer; | |||
| class OverlayComponent; | |||
| @@ -106,7 +112,7 @@ private: | |||
| ComponentHolder* componentHolder; | |||
| OverlayComponent* overlay; | |||
| WholeComponentResizer* resizeFrame; | |||
| ComponentDocument::SelectedItems selection; | |||
| SelectedItems selection; | |||
| Component* getComponentForUID (const uint32 uid) const; | |||
| const Array<Component*> getSelectedComps() const; | |||
| @@ -247,6 +247,9 @@ private: | |||
| Project* const project; | |||
| const File file; | |||
| Time fileModificationTime; | |||
| UnknownDocument (const UnknownDocument&); | |||
| UnknownDocument& operator= (const UnknownDocument&); | |||
| }; | |||
| @@ -251,8 +251,9 @@ void ProjectContentComponent::getCommandInfo (const CommandID commandID, Applica | |||
| case StandardApplicationCommandIDs::del: | |||
| result.setInfo ("Delete", String::empty, CommandCategories::general, 0); | |||
| result.setActive (projectTree != 0); | |||
| result.defaultKeypresses.add (KeyPress (KeyPress::deleteKey, 0, 0)); | |||
| result.defaultKeypresses.add (KeyPress (KeyPress::backspaceKey, 0, 0)); | |||
| result.setActive (projectTree != 0); | |||
| break; | |||
| default: | |||
| @@ -575,3 +575,55 @@ const String PropertyPanelWithTooltips::findTip (Component* c) | |||
| return String::empty; | |||
| } | |||
| //============================================================================== | |||
| FloatingLabelComponent::FloatingLabelComponent() | |||
| : font (10.0f) | |||
| { | |||
| setInterceptsMouseClicks (false ,false); | |||
| } | |||
| void FloatingLabelComponent::remove() | |||
| { | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->removeChildComponent (this); | |||
| } | |||
| void FloatingLabelComponent::update (Component* parent, const String& text, const Colour& textColour, int x, int y, bool toRight, bool below) | |||
| { | |||
| colour = textColour; | |||
| Rectangle<int> r; | |||
| if (text != getName()) | |||
| { | |||
| setName (text); | |||
| glyphs.clear(); | |||
| glyphs.addJustifiedText (font, text, 0, 0, 200.0f, Justification::left); | |||
| glyphs.justifyGlyphs (0, std::numeric_limits<int>::max(), 0, 0, 1000, 1000, Justification::topLeft); | |||
| r = glyphs.getBoundingBox (0, std::numeric_limits<int>::max(), false) | |||
| .getSmallestIntegerContainer().expanded (2, 2); | |||
| } | |||
| else | |||
| { | |||
| r = getLocalBounds(); | |||
| } | |||
| r.setPosition (x + (toRight ? 3 : -(r.getWidth() + 3)), y + (below ? 2 : -(r.getHeight() + 2))); | |||
| setBounds (r); | |||
| parent->addAndMakeVisible (this); | |||
| } | |||
| void FloatingLabelComponent::paint (Graphics& g) | |||
| { | |||
| g.setFont (font); | |||
| g.setColour (Colours::white); | |||
| for (int y = -1; y <= 1; ++y) | |||
| for (int x = -1; x <= 1; ++x) | |||
| glyphs.draw (g, AffineTransform::translation (1.0f + x, 1.0f + y)); | |||
| g.setColour (colour); | |||
| glyphs.draw (g, AffineTransform::translation (1.0f, 1.0f)); | |||
| } | |||
| @@ -132,6 +132,21 @@ private: | |||
| const String findTip (Component* c); | |||
| }; | |||
| //============================================================================== | |||
| class FloatingLabelComponent : public Component | |||
| { | |||
| public: | |||
| FloatingLabelComponent(); | |||
| void remove(); | |||
| void update (Component* parent, const String& text, const Colour& textColour, int x, int y, bool toRight, bool below); | |||
| void paint (Graphics& g); | |||
| private: | |||
| Font font; | |||
| Colour colour; | |||
| GlyphArrangement glyphs; | |||
| }; | |||
| //============================================================================== | |||
| static const double tickSizes[] = { 1.0, 2.0, 5.0, | |||
| @@ -236,4 +251,7 @@ private: | |||
| { | |||
| return String (roundToInt (value)); | |||
| } | |||
| TickIterator (const TickIterator&); | |||
| TickIterator& operator= (const TickIterator&); | |||
| }; | |||
| @@ -8224,7 +8224,7 @@ const String URL::removeEscapeChars (const String& s) | |||
| if (nextPercent < 0) | |||
| break; | |||
| juce_wchar replacementChar = result.substring (nextPercent + 1, nextPercent + 3).getHexValue32(); | |||
| juce_wchar replacementChar = (juce_wchar) result.substring (nextPercent + 1, nextPercent + 3).getHexValue32(); | |||
| result = result.replaceSection (nextPercent, 3, String::charToString (replacementChar)); | |||
| ++nextPercent; | |||
| } | |||
| @@ -16286,7 +16286,7 @@ void ValueTree::removeChild (const int childIndex, UndoManager* const undoManage | |||
| object->removeChild (childIndex, undoManager); | |||
| } | |||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) | |||
| void ValueTree::removeChild (const ValueTree& child, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeChild (object->children.indexOf (child.object), undoManager); | |||
| @@ -17660,6 +17660,9 @@ PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSavin | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return; // locking failure.. | |||
| ScopedPointer<InputStream> fileStream (f.createInputStream()); | |||
| if (fileStream != 0) | |||
| @@ -17796,6 +17799,9 @@ bool PropertiesFile::save() | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return false; // locking failure.. | |||
| if (doc.writeToFile (file, String::empty)) | |||
| { | |||
| needsWriting = false; | |||
| @@ -17806,6 +17812,9 @@ bool PropertiesFile::save() | |||
| { | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return false; // locking failure.. | |||
| TemporaryFile tempFile (file); | |||
| ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | |||
| @@ -23815,6 +23824,8 @@ AudioIODeviceType* juce_createAudioIODeviceType_JACK(); | |||
| void AudioDeviceManager::createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& list) | |||
| { | |||
| (void) list; // (to avoid 'unused param' warnings) | |||
| #if JUCE_WINDOWS | |||
| #if JUCE_WASAPI | |||
| if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista) | |||
| @@ -38701,9 +38712,11 @@ void Component::toFront (const bool setAsForeground) | |||
| } | |||
| else if (parentComponent_ != 0) | |||
| { | |||
| if (parentComponent_->childComponentList_.getLast() != this) | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (childList.getLast() != this) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| const int index = childList.indexOf (this); | |||
| if (index >= 0) | |||
| { | |||
| @@ -38711,18 +38724,15 @@ void Component::toFront (const bool setAsForeground) | |||
| if (! flags.alwaysOnTopFlag) | |||
| { | |||
| insertIndex = parentComponent_->childComponentList_.size() - 1; | |||
| insertIndex = childList.size() - 1; | |||
| while (insertIndex > 0 | |||
| && parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| { | |||
| while (insertIndex > 0 && childList.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| --insertIndex; | |||
| } | |||
| } | |||
| if (index != insertIndex) | |||
| { | |||
| parentComponent_->childComponentList_.move (index, insertIndex); | |||
| childList.move (index, insertIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| @@ -38740,28 +38750,31 @@ void Component::toFront (const bool setAsForeground) | |||
| void Component::toBehind (Component* const other) | |||
| { | |||
| if (other != 0) | |||
| if (other != 0 && other != this) | |||
| { | |||
| // the two components must belong to the same parent.. | |||
| jassert (parentComponent_ == other->parentComponent_); | |||
| if (parentComponent_ != 0) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| int otherIndex = parentComponent_->childComponentList_.indexOf (other); | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (index >= 0 | |||
| && otherIndex >= 0 | |||
| && index != otherIndex - 1 | |||
| && other != this) | |||
| const int index = childList.indexOf (this); | |||
| if (index >= 0 && childList [index + 1] != other) | |||
| { | |||
| if (index < otherIndex) | |||
| --otherIndex; | |||
| int otherIndex = childList.indexOf (other); | |||
| parentComponent_->childComponentList_.move (index, otherIndex); | |||
| if (otherIndex >= 0) | |||
| { | |||
| if (index < otherIndex) | |||
| --otherIndex; | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| childList.move (index, otherIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| } | |||
| } | |||
| } | |||
| else if (isOnDesktop()) | |||
| @@ -38783,14 +38796,15 @@ void Component::toBehind (Component* const other) | |||
| void Component::toBack() | |||
| { | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (isOnDesktop()) | |||
| { | |||
| jassertfalse //xxx need to add this to native window | |||
| } | |||
| else if (parentComponent_ != 0 | |||
| && parentComponent_->childComponentList_.getFirst() != this) | |||
| else if (parentComponent_ != 0 && childList.getFirst() != this) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| const int index = childList.indexOf (this); | |||
| if (index > 0) | |||
| { | |||
| @@ -38798,8 +38812,8 @@ void Component::toBack() | |||
| if (flags.alwaysOnTopFlag) | |||
| { | |||
| while (insertIndex < parentComponent_->childComponentList_.size() | |||
| && ! parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| while (insertIndex < childList.size() | |||
| && ! childList.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| { | |||
| ++insertIndex; | |||
| } | |||
| @@ -38807,7 +38821,7 @@ void Component::toBack() | |||
| if (index != insertIndex) | |||
| { | |||
| parentComponent_->childComponentList_.move (index, insertIndex); | |||
| childList.move (index, insertIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| @@ -247892,7 +247906,9 @@ public: | |||
| keyCode: 0]; | |||
| [menu performKeyEquivalent: f35Event]; | |||
| [menu removeItem: item]; // (this throws if the item isn't actually in the menu) | |||
| if ([menu indexOfItem: item] >= 0) | |||
| [menu removeItem: item]; // (this throws if the item isn't actually in the menu) | |||
| } | |||
| [menu release]; | |||
| @@ -6750,7 +6750,7 @@ public: | |||
| void addChild (ValueTree child, int index, UndoManager* const undoManager); | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager); | |||
| void removeChild (const ValueTree& child, UndoManager* const undoManager); | |||
| void removeChild (const int childIndex, UndoManager* const undoManager); | |||
| @@ -6855,6 +6855,9 @@ private: | |||
| private: | |||
| ElementComparator& comparator; | |||
| ComparatorAdapter (const ComparatorAdapter&); | |||
| ComparatorAdapter& operator= (const ComparatorAdapter&); | |||
| }; | |||
| friend class SharedObject; | |||
| @@ -110,6 +110,8 @@ AudioIODeviceType* juce_createAudioIODeviceType_JACK(); | |||
| void AudioDeviceManager::createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& list) | |||
| { | |||
| (void) list; // (to avoid 'unused param' warnings) | |||
| #if JUCE_WINDOWS | |||
| #if JUCE_WASAPI | |||
| if (SystemStats::getOperatingSystemType() >= SystemStats::WinVista) | |||
| @@ -622,7 +622,7 @@ void ValueTree::removeChild (const int childIndex, UndoManager* const undoManage | |||
| object->removeChild (childIndex, undoManager); | |||
| } | |||
| void ValueTree::removeChild (ValueTree& child, UndoManager* const undoManager) | |||
| void ValueTree::removeChild (const ValueTree& child, UndoManager* const undoManager) | |||
| { | |||
| if (object != 0) | |||
| object->removeChild (object->children.indexOf (child.object), undoManager); | |||
| @@ -239,7 +239,7 @@ public: | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| so that this change can be undone. | |||
| */ | |||
| void removeChild (ValueTree& child, UndoManager* const undoManager); | |||
| void removeChild (const ValueTree& child, UndoManager* const undoManager); | |||
| /** Removes a child from this node's child-list. | |||
| If the undoManager parameter is non-null, its UndoManager::perform() method will be used, | |||
| @@ -457,6 +457,9 @@ private: | |||
| private: | |||
| ElementComparator& comparator; | |||
| ComparatorAdapter (const ComparatorAdapter&); | |||
| ComparatorAdapter& operator= (const ComparatorAdapter&); | |||
| }; | |||
| friend class SharedObject; | |||
| @@ -537,9 +537,11 @@ void Component::toFront (const bool setAsForeground) | |||
| } | |||
| else if (parentComponent_ != 0) | |||
| { | |||
| if (parentComponent_->childComponentList_.getLast() != this) | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (childList.getLast() != this) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| const int index = childList.indexOf (this); | |||
| if (index >= 0) | |||
| { | |||
| @@ -547,18 +549,15 @@ void Component::toFront (const bool setAsForeground) | |||
| if (! flags.alwaysOnTopFlag) | |||
| { | |||
| insertIndex = parentComponent_->childComponentList_.size() - 1; | |||
| insertIndex = childList.size() - 1; | |||
| while (insertIndex > 0 | |||
| && parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| { | |||
| while (insertIndex > 0 && childList.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| --insertIndex; | |||
| } | |||
| } | |||
| if (index != insertIndex) | |||
| { | |||
| parentComponent_->childComponentList_.move (index, insertIndex); | |||
| childList.move (index, insertIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| @@ -576,28 +575,31 @@ void Component::toFront (const bool setAsForeground) | |||
| void Component::toBehind (Component* const other) | |||
| { | |||
| if (other != 0) | |||
| if (other != 0 && other != this) | |||
| { | |||
| // the two components must belong to the same parent.. | |||
| jassert (parentComponent_ == other->parentComponent_); | |||
| if (parentComponent_ != 0) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| int otherIndex = parentComponent_->childComponentList_.indexOf (other); | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (index >= 0 | |||
| && otherIndex >= 0 | |||
| && index != otherIndex - 1 | |||
| && other != this) | |||
| const int index = childList.indexOf (this); | |||
| if (index >= 0 && childList [index + 1] != other) | |||
| { | |||
| if (index < otherIndex) | |||
| --otherIndex; | |||
| int otherIndex = childList.indexOf (other); | |||
| parentComponent_->childComponentList_.move (index, otherIndex); | |||
| if (otherIndex >= 0) | |||
| { | |||
| if (index < otherIndex) | |||
| --otherIndex; | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| childList.move (index, otherIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| } | |||
| } | |||
| } | |||
| else if (isOnDesktop()) | |||
| @@ -619,14 +621,15 @@ void Component::toBehind (Component* const other) | |||
| void Component::toBack() | |||
| { | |||
| Array<Component*>& childList = parentComponent_->childComponentList_; | |||
| if (isOnDesktop()) | |||
| { | |||
| jassertfalse //xxx need to add this to native window | |||
| } | |||
| else if (parentComponent_ != 0 | |||
| && parentComponent_->childComponentList_.getFirst() != this) | |||
| else if (parentComponent_ != 0 && childList.getFirst() != this) | |||
| { | |||
| const int index = parentComponent_->childComponentList_.indexOf (this); | |||
| const int index = childList.indexOf (this); | |||
| if (index > 0) | |||
| { | |||
| @@ -634,8 +637,8 @@ void Component::toBack() | |||
| if (flags.alwaysOnTopFlag) | |||
| { | |||
| while (insertIndex < parentComponent_->childComponentList_.size() | |||
| && ! parentComponent_->childComponentList_.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| while (insertIndex < childList.size() | |||
| && ! childList.getUnchecked (insertIndex)->isAlwaysOnTop()) | |||
| { | |||
| ++insertIndex; | |||
| } | |||
| @@ -643,7 +646,7 @@ void Component::toBack() | |||
| if (index != insertIndex) | |||
| { | |||
| parentComponent_->childComponentList_.move (index, insertIndex); | |||
| childList.move (index, insertIndex); | |||
| sendFakeMouseMove(); | |||
| repaintParent(); | |||
| @@ -547,7 +547,7 @@ const String URL::removeEscapeChars (const String& s) | |||
| if (nextPercent < 0) | |||
| break; | |||
| juce_wchar replacementChar = result.substring (nextPercent + 1, nextPercent + 3).getHexValue32(); | |||
| juce_wchar replacementChar = (juce_wchar) result.substring (nextPercent + 1, nextPercent + 3).getHexValue32(); | |||
| result = result.replaceSection (nextPercent, 3, String::charToString (replacementChar)); | |||
| ++nextPercent; | |||
| } | |||
| @@ -184,7 +184,9 @@ public: | |||
| keyCode: 0]; | |||
| [menu performKeyEquivalent: f35Event]; | |||
| [menu removeItem: item]; // (this throws if the item isn't actually in the menu) | |||
| if ([menu indexOfItem: item] >= 0) | |||
| [menu removeItem: item]; // (this throws if the item isn't actually in the menu) | |||
| } | |||
| [menu release]; | |||
| @@ -71,6 +71,9 @@ PropertiesFile::PropertiesFile (const File& f, const int millisecondsBeforeSavin | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return; // locking failure.. | |||
| ScopedPointer<InputStream> fileStream (f.createInputStream()); | |||
| if (fileStream != 0) | |||
| @@ -207,6 +210,9 @@ bool PropertiesFile::save() | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return false; // locking failure.. | |||
| if (doc.writeToFile (file, String::empty)) | |||
| { | |||
| needsWriting = false; | |||
| @@ -217,6 +223,9 @@ bool PropertiesFile::save() | |||
| { | |||
| ProcessScopedLock pl (createProcessLock()); | |||
| if (pl != 0 && ! pl->isLocked()) | |||
| return false; // locking failure.. | |||
| TemporaryFile tempFile (file); | |||
| ScopedPointer <OutputStream> out (tempFile.getFile().createOutputStream()); | |||