From a612dfdc2f84d47dc6e18def416508a7b29e853a Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Sat, 17 Apr 2010 16:22:18 +0100 Subject: [PATCH] String fix. Minor additional methods for FileBasedDocument and Slider. Jucer development. --- .../Builds/Linux/Makefile | 14 +- .../The Jucer.xcodeproj/project.pbxproj | 6 + .../Builds/VisualStudio2005/The Jucer.vcproj | 2 + .../Builds/VisualStudio2008/The Jucer.vcproj | 2 + extras/Jucer (experimental)/Jucer.jucer | 4 + .../Source/model/jucer_ComponentDocument.cpp | 254 +++++------- .../Source/model/jucer_ComponentDocument.h | 8 +- .../Source/model/jucer_Coordinate.cpp | 392 ++++++++++++++++++ .../Source/model/jucer_Coordinate.h | 157 +++++++ .../Source/model/jucer_ProjectExport_Make.h | 2 +- .../jucer_ComponentEditor.cpp | 370 ++++++++++++----- .../Source/utility/jucer_UtilityFunctions.cpp | 360 ---------------- .../Source/utility/jucer_UtilityFunctions.h | 202 ++++----- extras/amalgamator/Builds/Linux/Makefile | 8 +- .../audio plugin host/Builds/Linux/Makefile | 8 +- extras/binarybuilder/Builds/Linux/Makefile | 8 +- extras/example projects/Builds/Linux/Makefile | 8 +- extras/juce demo/Builds/Linux/Makefile | 8 +- juce_amalgamated.cpp | 22 +- juce_amalgamated.h | 6 +- src/core/juce_Atomic.h | 2 +- src/core/juce_StandardHeader.h | 2 +- src/gui/components/controls/juce_Slider.cpp | 11 +- src/gui/components/controls/juce_Slider.h | 8 + src/text/juce_String.cpp | 3 +- src/text/juce_String.h | 4 +- src/utilities/juce_FileBasedDocument.cpp | 8 +- 27 files changed, 1093 insertions(+), 786 deletions(-) create mode 100644 extras/Jucer (experimental)/Source/model/jucer_Coordinate.cpp create mode 100644 extras/Jucer (experimental)/Source/model/jucer_Coordinate.h diff --git a/extras/Jucer (experimental)/Builds/Linux/Makefile b/extras/Jucer (experimental)/Builds/Linux/Makefile index dd941d0490..1e17ee19c8 100644 --- a/extras/Jucer (experimental)/Builds/Linux/Makefile +++ b/extras/Jucer (experimental)/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := Jucer @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O3 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := Jucer @@ -44,6 +44,7 @@ endif OBJECTS := \ $(OBJDIR)/jucer_ComponentDocument.o \ + $(OBJDIR)/jucer_Coordinate.o \ $(OBJDIR)/jucer_DrawableDocument.o \ $(OBJDIR)/jucer_NewFileWizard.o \ $(OBJDIR)/jucer_Project.o \ @@ -92,6 +93,11 @@ $(OBJDIR)/jucer_ComponentDocument.o: ../../Source/model/jucer_ComponentDocument. @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" +$(OBJDIR)/jucer_Coordinate.o: ../../Source/model/jucer_Coordinate.cpp + -@mkdir -p $(OBJDIR) + @echo $(notdir $<) + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + $(OBJDIR)/jucer_DrawableDocument.o: ../../Source/model/jucer_DrawableDocument.cpp -@mkdir -p $(OBJDIR) @echo $(notdir $<) diff --git a/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj b/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj index 6eccf9dd47..7ad9077590 100644 --- a/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj +++ b/extras/Jucer (experimental)/Builds/MacOSX/The Jucer.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 93C9F3F27602A33DDC9C2250 = { isa = PBXBuildFile; fileRef = 2767E1D082874D301D5D5F43; }; 2E6836738CE7EB452FDC7E9A = { isa = PBXBuildFile; fileRef = D9FB1A5365FEEB854A0FF7BF; }; CD4226951C3F7FE19CF8A7CE = { isa = PBXBuildFile; fileRef = 2D6D6985B452EA0B67A18914; }; + 1DF9688E29753A0459E6C32A = { isa = PBXBuildFile; fileRef = 45C80436FD5A8438D0E6BE17; }; 1174D3512AF8207950094C56 = { isa = PBXBuildFile; fileRef = FF625CB50FB5C3536BA40604; }; 087CCE9E7146F1EC4F241254 = { isa = PBXBuildFile; fileRef = DA142548FCADFAC50648ED3C; }; E9935BFB0EFA8CCCD41DC08E = { isa = PBXBuildFile; fileRef = D47A40CB3CF6AAE14B3C7796; }; @@ -62,6 +63,8 @@ E18C99BDD4EF3DFD767F3770 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_TextButton.h; path = "../../Source/model/Component Types/jucer_TextButton.h"; sourceTree = SOURCE_ROOT; }; 2D6D6985B452EA0B67A18914 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_ComponentDocument.cpp; path = ../../Source/model/jucer_ComponentDocument.cpp; sourceTree = SOURCE_ROOT; }; E6CC3A04349F6B227FDAB26F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_ComponentDocument.h; path = ../../Source/model/jucer_ComponentDocument.h; sourceTree = SOURCE_ROOT; }; + 45C80436FD5A8438D0E6BE17 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_Coordinate.cpp; path = ../../Source/model/jucer_Coordinate.cpp; sourceTree = SOURCE_ROOT; }; + 420E4189E7DE25E9D0D8E5B8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_Coordinate.h; path = ../../Source/model/jucer_Coordinate.h; sourceTree = SOURCE_ROOT; }; FF625CB50FB5C3536BA40604 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_DrawableDocument.cpp; path = ../../Source/model/jucer_DrawableDocument.cpp; sourceTree = SOURCE_ROOT; }; A490098DA6400B3881F336D0 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = jucer_DrawableDocument.h; path = ../../Source/model/jucer_DrawableDocument.h; sourceTree = SOURCE_ROOT; }; DA142548FCADFAC50648ED3C = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = jucer_NewFileWizard.cpp; path = ../../Source/model/jucer_NewFileWizard.cpp; sourceTree = SOURCE_ROOT; }; @@ -144,6 +147,8 @@ D3D6EC2C17524688F2E803EB, 2D6D6985B452EA0B67A18914, E6CC3A04349F6B227FDAB26F, + 45C80436FD5A8438D0E6BE17, + 420E4189E7DE25E9D0D8E5B8, FF625CB50FB5C3536BA40604, A490098DA6400B3881F336D0, DA142548FCADFAC50648ED3C, @@ -319,6 +324,7 @@ 87CCE4CB1FAB40B6F21DEACE = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 5362E03ADF975A126C1F2F7B = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( CD4226951C3F7FE19CF8A7CE, + 1DF9688E29753A0459E6C32A, 1174D3512AF8207950094C56, 087CCE9E7146F1EC4F241254, E9935BFB0EFA8CCCD41DC08E, diff --git a/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj b/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj index 2b631f124a..f9c87c4459 100644 --- a/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj +++ b/extras/Jucer (experimental)/Builds/VisualStudio2005/The Jucer.vcproj @@ -139,6 +139,8 @@ + + diff --git a/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj b/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj index 47d686acf7..42ebc2f4ca 100644 --- a/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj +++ b/extras/Jucer (experimental)/Builds/VisualStudio2008/The Jucer.vcproj @@ -139,6 +139,8 @@ + + diff --git a/extras/Jucer (experimental)/Jucer.jucer b/extras/Jucer (experimental)/Jucer.jucer index f9af100483..9dc62a9a97 100644 --- a/extras/Jucer (experimental)/Jucer.jucer +++ b/extras/Jucer (experimental)/Jucer.jucer @@ -37,6 +37,10 @@ resource="0" file="Source/model/jucer_ComponentDocument.cpp"/> + + setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnTop | Button::ConnectedOnRight | Button::ConnectedOnBottom); + anchorButton1->setTriggeredOnMouseDown (true); anchorButton1->addButtonListener (this); addAndMakeVisible (anchorButton2 = new TextButton (String::empty)); anchorButton2->setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnTop | Button::ConnectedOnRight | Button::ConnectedOnBottom); + anchorButton2->setTriggeredOnMouseDown (true); anchorButton2->addButtonListener (this); + + boundsValue.addListener (this); + valueChanged (boundsValue); } ~ComponentBoundsEditor() { + boundsValue.removeListener (this); deleteAllChildren(); } @@ -87,8 +95,16 @@ public: label->setBounds (r.getX(), r.getY(), r.getWidth() / 2, r.getHeight() / 2); proportionButton->setBounds (r.getX() + r.getWidth() / 2, r.getY(), r.getWidth() / 2, r.getHeight() / 2); - anchorButton1->setBounds (r.getX(), r.getY() + r.getHeight() / 2, r.getWidth() / 2, r.getHeight() / 2); - anchorButton2->setBounds (r.getX() + r.getWidth() / 2, r.getY() + r.getHeight() / 2, r.getWidth() / 2, r.getHeight() / 2); + + if (anchorButton2->isVisible()) + { + anchorButton1->setBounds (r.getX(), r.getY() + r.getHeight() / 2, r.getWidth() / 2, r.getHeight() / 2); + anchorButton2->setBounds (r.getX() + r.getWidth() / 2, r.getY() + r.getHeight() / 2, r.getWidth() / 2, r.getHeight() / 2); + } + else + { + anchorButton1->setBounds (r.getX(), r.getY() + r.getHeight() / 2, r.getWidth(), r.getHeight() / 2); + } } void refresh() @@ -97,24 +113,49 @@ public: void buttonClicked (Button* button) { + RectangleCoordinates r (boundsValue.toString()); + Coordinate& coord = getCoord (r); + ScopedPointer markers (document.createMarkerResolver (compState)); + if (button == proportionButton) { - RectangleCoordinates r (boundsValue.toString()); - Coordinate& coord = getCoord (r); - - ScopedPointer markers (document.createMarkerResolver (compState)); - coord.toggleProportionality (*markers); boundsValue = r.toString(); } else if (button == anchorButton1) { + const String marker (pickMarker (anchorButton1, coord.getAnchor1())); + + if (marker.isNotEmpty()) + { + coord.changeAnchor1 (marker, *markers); + boundsValue = r.toString(); + } } else if (button == anchorButton2) { + const String marker (pickMarker (anchorButton2, coord.getAnchor2())); + + if (marker.isNotEmpty()) + { + coord.changeAnchor2 (marker, *markers); + boundsValue = r.toString(); + } } } + void valueChanged (Value&) + { + RectangleCoordinates r (boundsValue.toString()); + Coordinate& coord = getCoord (r); + + anchorButton1->setButtonText (coord.getAnchor1()); + + anchorButton2->setVisible (coord.isProportional()); + anchorButton2->setButtonText (coord.getAnchor2()); + resized(); + } + //============================================================================== class BoundsCoordValueSource : public Value::ValueSource, public Value::Listener @@ -186,6 +227,22 @@ public: return r.left; } + const String pickMarker (Component* button, const String& currentMarker) + { + const StringArray markers (document.getComponentMarkers (type == left || type == right)); + + PopupMenu m; + for (int i = 0; i < markers.size(); ++i) + m.addItem (i + 1, markers[i], true, currentMarker == markers[i]); + + const int r = m.showAt (button); + + if (r > 0) + return markers [r - 1]; + + return String::empty; + } + private: ComponentDocument& document; Type type; @@ -588,11 +645,44 @@ const RectangleCoordinates ComponentDocument::getCoordsFor (const ValueTree& sta return RectangleCoordinates (state [compBoundsProperty]); } +bool ComponentDocument::setCoordsFor (ValueTree& state, const RectangleCoordinates& pr) +{ + const String newBoundsString (pr.toString()); + + if (state[compBoundsProperty] == newBoundsString) + return false; + + state.setProperty (compBoundsProperty, newBoundsString, getUndoManager()); + return true; +} + Coordinate::MarkerResolver* ComponentDocument::createMarkerResolver (const ValueTree& state) { return new ComponentMarkerResolver (*this, state, getCanvasWidth().getValue(), getCanvasHeight().getValue()); } +const StringArray ComponentDocument::getComponentMarkers (bool horizontal) const +{ + StringArray s; + + if (horizontal) + { + s.add (Coordinate::parentLeftMarkerName); + s.add (Coordinate::parentRightMarkerName); + s.add ("left"); + s.add ("right"); + } + else + { + s.add (Coordinate::parentTopMarkerName); + s.add (Coordinate::parentBottomMarkerName); + s.add ("top"); + s.add ("bottom"); + } + + return s; +} + void ComponentDocument::updateComponent (Component* comp) { const ValueTree v (getComponentState (comp)); @@ -675,151 +765,3 @@ UndoManager* ComponentDocument::getUndoManager() { return &undoManager; } - -//============================================================================== -class ComponentDocument::DragHandler -{ -public: - DragHandler (ComponentDocument& document_, - const Array& items, - const MouseEvent& e, - const ResizableBorderComponent::Zone& zone_, - Component* parentForOverlays) - : document (document_), - zone (zone_) - { - for (int i = 0; i < items.size(); ++i) - { - Component* comp = items.getUnchecked(i); - jassert (comp != 0); - - const ValueTree v (document.getComponentState (comp)); - draggedComponents.add (v); - - Rectangle pos; - - { - RectangleCoordinates relativePos (v [compBoundsProperty].toString()); - ScopedPointer markers (document.createMarkerResolver (v)); - pos = relativePos.resolve (*markers); - originalPositions.add (pos); - } - - const Rectangle floatPos ((float) pos.getX(), (float) pos.getY(), - (float) pos.getWidth(), (float) pos.getHeight()); - - if (zone.isDraggingWholeObject() || zone.isDraggingLeftEdge()) - verticalSnapPositions.add (floatPos.getX()); - - if (zone.isDraggingWholeObject() || zone.isDraggingLeftEdge() || zone.isDraggingRightEdge()) - verticalSnapPositions.add (floatPos.getCentreX()); - - if (zone.isDraggingWholeObject() || zone.isDraggingRightEdge()) - verticalSnapPositions.add (floatPos.getRight()); - - if (zone.isDraggingWholeObject() || zone.isDraggingTopEdge()) - horizontalSnapPositions.add (floatPos.getY()); - - if (zone.isDraggingWholeObject() || zone.isDraggingTopEdge() || zone.isDraggingBottomEdge()) - verticalSnapPositions.add (floatPos.getCentreY()); - - if (zone.isDraggingWholeObject() || zone.isDraggingBottomEdge()) - horizontalSnapPositions.add (floatPos.getBottom()); - } - - document.beginNewTransaction(); - } - - ~DragHandler() - { - document.beginNewTransaction(); - } - - void drag (const MouseEvent& e) - { - document.getUndoManager()->undoCurrentTransactionOnly(); - - for (int n = 50;;) - { - // Need to repeatedly apply the new positions until they all settle down, in case some of - // the coords are relative to each other.. - bool anyUpdated = false; - - for (int i = 0; i < draggedComponents.size(); ++i) - if (dragItem (draggedComponents.getReference(i), e.getOffsetFromDragStart(), originalPositions.getReference(i))) - anyUpdated = true; - - if (! anyUpdated) - break; - - if (--n == 0) - { - jassertfalse; - break; - } - } - } - - bool dragItem (ValueTree& v, const Point& distance, const Rectangle& originalPos) - { - const Rectangle newBounds (zone.resizeRectangleBy (originalPos, distance)); - - RectangleCoordinates pr (v [compBoundsProperty].toString()); - ScopedPointer markers (document.createMarkerResolver (v)); - - pr.moveToAbsolute (newBounds, *markers); - const String newBoundsString (pr.toString()); - - if (v[compBoundsProperty] == newBoundsString) - return false; - - v.setProperty (compBoundsProperty, newBoundsString, document.getUndoManager()); - return true; - } - - const Array getVerticalSnapPositions (const Point& distance) const - { - Array p (verticalSnapPositions); - for (int i = p.size(); --i >= 0;) - p.set (i, p.getUnchecked(i) + distance.getX()); - - return p; - } - - const Array getHorizontalSnapPositions (const Point& distance) const - { - Array p (horizontalSnapPositions); - for (int i = p.size(); --i >= 0;) - p.set (i, p.getUnchecked(i) + distance.getY()); - - return p; - } - -private: - ComponentDocument& document; - Array draggedComponents; - Array > originalPositions; - Array verticalSnapPositions, horizontalSnapPositions; - const ResizableBorderComponent::Zone zone; -}; - -void ComponentDocument::beginDrag (const Array& items, const MouseEvent& e, - Component* parentForOverlays, const ResizableBorderComponent::Zone& zone) -{ - dragger = new DragHandler (*this, items, e, zone, parentForOverlays); -} - -void ComponentDocument::continueDrag (const MouseEvent& e) -{ - if (dragger != 0) - dragger->drag (e); -} - -void ComponentDocument::endDrag (const MouseEvent& e) -{ - if (dragger != 0) - { - dragger->drag (e); - dragger = 0; - } -} diff --git a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h index b889ccf93e..d0691ac627 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h +++ b/extras/Jucer (experimental)/Source/model/jucer_ComponentDocument.h @@ -28,6 +28,7 @@ #include "../jucer_Headers.h" #include "jucer_Project.h" +#include "jucer_Coordinate.h" //============================================================================== @@ -66,7 +67,9 @@ public: void getComponentProperties (Array & props, Component* comp); bool isStateForComponent (const ValueTree& storedState, Component* comp) const; Coordinate::MarkerResolver* createMarkerResolver (const ValueTree& state); - const RectangleCoordinates getCoordsFor (const ValueTree& state) const; + const StringArray getComponentMarkers (bool horizontal) const; + const RectangleCoordinates getCoordsFor (const ValueTree& componentState) const; + bool setCoordsFor (ValueTree& componentState, const RectangleCoordinates& newSize); void addNewComponentMenuItems (PopupMenu& menu) const; void performNewComponentMenuItem (int menuResultCode); @@ -93,9 +96,6 @@ private: UndoManager undoManager; bool changedSinceSaved; - class DragHandler; - ScopedPointer dragger; - void checkRootObject(); ValueTree getComponentGroup() const; Value getRootValue (const var::identifier& name) { return root.getPropertyAsValue (name, getUndoManager()); } diff --git a/extras/Jucer (experimental)/Source/model/jucer_Coordinate.cpp b/extras/Jucer (experimental)/Source/model/jucer_Coordinate.cpp new file mode 100644 index 0000000000..ac2725f5da --- /dev/null +++ b/extras/Jucer (experimental)/Source/model/jucer_Coordinate.cpp @@ -0,0 +1,392 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-9 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#include "jucer_Coordinate.h" + + +//============================================================================== +const char* Coordinate::parentLeftMarkerName = "parent.left"; +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 (double absoluteDistanceFromOrigin, bool isHorizontal_) + : value (absoluteDistanceFromOrigin), isProportion (false), isHorizontal (isHorizontal_) +{ +} + +Coordinate::Coordinate (double absoluteDistance, const String& source, bool isHorizontal_) + : anchor1 (source), value (absoluteDistance), isProportion (false), isHorizontal (isHorizontal_) +{ +} + +Coordinate::Coordinate (double relativeProportion, const String& pos1, const String& pos2, bool isHorizontal_) + : anchor1 (pos1), anchor2 (pos2), value (relativeProportion), isProportion (true), isHorizontal (isHorizontal_) +{ +} + +Coordinate::~Coordinate() +{ +} + +const Coordinate Coordinate::getAnchorPoint1() const +{ + return Coordinate (0.0, anchor1, isHorizontal); +} + +const Coordinate Coordinate::getAnchorPoint2() const +{ + return Coordinate (0.0, anchor2, isHorizontal); +} + +bool Coordinate::isOrigin (const String& name) +{ + return name.isEmpty() || name == parentLeftMarkerName || name == parentTopMarkerName; +} + +const String Coordinate::getOriginMarkerName() const +{ + return isHorizontal ? parentLeftMarkerName : parentTopMarkerName; +} + +const String Coordinate::getExtentMarkerName() const +{ + return isHorizontal ? parentRightMarkerName : parentBottomMarkerName; +} + +const String Coordinate::checkName (const String& name) const +{ + return name.isEmpty() ? getOriginMarkerName() : name; +} + +double Coordinate::getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const +{ + if (isOrigin (name)) + return 0.0; + + return markerResolver.findMarker (name, isHorizontal) + .resolve (markerResolver, recursionCounter + 1); +} + +struct RecursivePositionException +{ +}; + +double Coordinate::resolve (MarkerResolver& markerResolver, int recursionCounter) const +{ + if (recursionCounter > 100) + { + jassertfalse + throw RecursivePositionException(); + } + + const double pos1 = getPosition (anchor1, markerResolver, recursionCounter); + + return isProportion ? pos1 + (getPosition (anchor2, markerResolver, recursionCounter) - pos1) * value + : pos1 + value; +} + +double Coordinate::resolve (MarkerResolver& markerResolver) const +{ + try + { + return resolve (markerResolver, 0); + } + catch (RecursivePositionException&) + {} + + return 0.0; +} + +void Coordinate::moveToAbsolute (double newPos, MarkerResolver& markerResolver) +{ + try + { + const double pos1 = getPosition (anchor1, markerResolver, 0); + + if (isProportion) + { + const double size = getPosition (anchor2, markerResolver, 0) - pos1; + + if (size != 0) + value = (newPos - pos1) / size; + } + else + { + value = newPos - pos1; + } + } + catch (RecursivePositionException&) + {} +} + +bool Coordinate::isRecursive (MarkerResolver& markerResolver) const +{ + try + { + resolve (markerResolver, 0); + } + catch (RecursivePositionException&) + { + return true; + } + + return false; +} + +void Coordinate::skipWhitespace (const String& s, int& i) +{ + while (CharacterFunctions::isWhitespace (s[i])) + ++i; +} + +const String Coordinate::readMarkerName (const String& s, int& i) +{ + skipWhitespace (s, i); + + if (CharacterFunctions::isLetter (s[i]) || s[i] == '_') + { + int start = i; + + while (CharacterFunctions::isLetterOrDigit (s[i]) || s[i] == '_' || s[i] == '.') + ++i; + + return s.substring (start, i); + } + + return String::empty; +} + +double Coordinate::readNumber (const String& s, int& i) +{ + skipWhitespace (s, i); + + int start = i; + + if (CharacterFunctions::isDigit (s[i]) || s[i] == '.' || s[i] == '-') + ++i; + + while (CharacterFunctions::isDigit (s[i]) || s[i] == '.') + ++i; + + if ((s[i] == 'e' || s[i] == 'E') + && (CharacterFunctions::isDigit (s[i + 1]) + || s[i + 1] == '-' + || s[i + 1] == '+')) + { + i += 2; + + while (CharacterFunctions::isDigit (s[i])) + ++i; + } + + const double value = s.substring (start, i).getDoubleValue(); + + while (CharacterFunctions::isWhitespace (s[i]) || s[i] == ',') + ++i; + + return value; +} + +Coordinate::Coordinate (const String& s, bool isHorizontal_) + : value (0), isProportion (false), isHorizontal (isHorizontal_) +{ + int i = 0; + + anchor1 = readMarkerName (s, i); + + if (anchor1.isNotEmpty()) + { + skipWhitespace (s, i); + + if (s[i] == '+') + value = readNumber (s, ++i); + else if (s[i] == '-') + value = -readNumber (s, ++i); + } + else + { + value = readNumber (s, i); + skipWhitespace (s, i); + + if (s[i] == '%') + { + isProportion = true; + value /= 100.0; + skipWhitespace (s, ++i); + + if (s[i] == '*') + { + anchor1 = readMarkerName (s, ++i); + skipWhitespace (s, i); + + if (s[i] == '-' && s[i + 1] == '>') + { + i += 2; + anchor2 = readMarkerName (s, i); + } + else + { + anchor2 = anchor1; + anchor1 = getOriginMarkerName(); + } + } + else + { + anchor1 = getOriginMarkerName(); + anchor2 = getExtentMarkerName(); + } + } + } +} + +static const String limitedAccuracyString (const double n) +{ + return String (n, 3).trimCharactersAtEnd ("0").trimCharactersAtEnd ("."); +} + +const String Coordinate::toString() const +{ + if (isProportion) + { + const String percent (limitedAccuracyString (value * 100.0)); + + if (isOrigin (anchor1)) + { + if (anchor2 == parentRightMarkerName || anchor2 == parentBottomMarkerName) + return percent + "%"; + else + return percent + "% * " + checkName (anchor2); + } + else + return percent + "% * " + checkName (anchor1) + " -> " + checkName (anchor2); + } + else + { + if (isOrigin (anchor1)) + return limitedAccuracyString (value); + else if (value > 0) + return checkName (anchor1) + " + " + limitedAccuracyString (value); + else if (value < 0) + return checkName (anchor1) + " - " + limitedAccuracyString (-value); + else + return checkName (anchor1); + } +} + +const double Coordinate::getEditableValue() const +{ + return isProportion ? value * 100.0 : value; +} + +void Coordinate::setEditableValue (const double newValue) +{ + value = isProportion ? newValue / 100.0 : newValue; +} + +void Coordinate::toggleProportionality (MarkerResolver& markerResolver) +{ + const double oldValue = resolve (markerResolver); + + isProportion = ! isProportion; + anchor1 = getOriginMarkerName(); + anchor2 = getExtentMarkerName(); + + moveToAbsolute (oldValue, markerResolver); +} + +void Coordinate::changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver) +{ + const double oldValue = resolve (markerResolver); + anchor1 = newMarkerName; + moveToAbsolute (oldValue, markerResolver); +} + +void Coordinate::changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver) +{ + const double oldValue = resolve (markerResolver); + anchor2 = newMarkerName; + moveToAbsolute (oldValue, markerResolver); +} + +//============================================================================== +RectangleCoordinates::RectangleCoordinates() + : left (true), right (true), top (false), bottom (false) +{ +} + +RectangleCoordinates::RectangleCoordinates (const Rectangle& rect) + : left (rect.getX(), true), + right (rect.getWidth(), "left", true), + top (rect.getY(), false), + bottom (rect.getHeight(), "top", false) +{ +} + +RectangleCoordinates::RectangleCoordinates (const String& stringVersion) + : left (true), right (true), top (false), bottom (false) +{ + StringArray tokens; + tokens.addTokens (stringVersion, ",", String::empty); + + left = Coordinate (tokens [0], true); + top = Coordinate (tokens [1], false); + right = Coordinate (tokens [2], true); + 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 RectangleCoordinates::resolve (Coordinate::MarkerResolver& markerResolver) const +{ + const int l = roundToInt (left.resolve (markerResolver)); + const int r = roundToInt (right.resolve (markerResolver)); + const int t = roundToInt (top.resolve (markerResolver)); + const int b = roundToInt (bottom.resolve (markerResolver)); + + return Rectangle (l, t, r - l, b - t); +} + +void RectangleCoordinates::moveToAbsolute (const Rectangle& newPos, Coordinate::MarkerResolver& markerResolver) +{ + left.moveToAbsolute (newPos.getX(), markerResolver); + right.moveToAbsolute (newPos.getRight(), markerResolver); + top.moveToAbsolute (newPos.getY(), markerResolver); + bottom.moveToAbsolute (newPos.getBottom(), markerResolver); +} + +const String RectangleCoordinates::toString() const +{ + return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); +} diff --git a/extras/Jucer (experimental)/Source/model/jucer_Coordinate.h b/extras/Jucer (experimental)/Source/model/jucer_Coordinate.h new file mode 100644 index 0000000000..5fdc6ba212 --- /dev/null +++ b/extras/Jucer (experimental)/Source/model/jucer_Coordinate.h @@ -0,0 +1,157 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-9 by Raw Material Software Ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the GNU General + Public License (Version 2), as published by the Free Software Foundation. + A copy of the license is included in the JUCE distribution, or can be found + online at www.gnu.org/licenses. + + JUCE is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + ------------------------------------------------------------------------------ + + To release a closed-source product which uses JUCE, commercial licenses are + available: visit www.rawmaterialsoftware.com/juce for more information. + + ============================================================================== +*/ + +#ifndef __JUCER_COORDINATE_H_EF56ACFA__ +#define __JUCER_COORDINATE_H_EF56ACFA__ + +#include "../jucer_Headers.h" + + +//============================================================================== +/** + Holds a co-ordinate along the x or y axis, expressed either as an absolute + position, or relative to other named marker positions. +*/ +class Coordinate +{ +public: + //============================================================================== + /** Creates a zero coordinate. */ + explicit Coordinate (bool isHorizontal); + + /** Recreates a coordinate from its stringified version. */ + Coordinate (const String& stringVersion, bool isHorizontal); + + /** Creates an absolute position from the parent origin. */ + Coordinate (double absoluteDistanceFromOrigin, bool isHorizontal); + + /** Creates an absolute position relative to a named marker. */ + Coordinate (double absolutePosition, const String& relativeToMarker, bool isHorizontal); + + /** Creates a relative position between two named markers. */ + Coordinate (double relativePosition, const String& marker1, const String& marker2, bool isHorizontal); + + /** Destructor. */ + ~Coordinate(); + + //============================================================================== + /** + Provides an interface for looking up the position of a named marker. + */ + class MarkerResolver + { + public: + virtual ~MarkerResolver() {} + virtual const Coordinate findMarker (const String& name, bool isHorizontal) = 0; + }; + + /** Calculates the absolute position of this co-ordinate. */ + double resolve (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; + + /** Changes the value of this marker to make it resolve to the specified position. */ + void moveToAbsolute (double newPos, MarkerResolver& markerResolver); + + const Coordinate getAnchorPoint1() const; + const Coordinate getAnchorPoint2() const; + + const double getEditableValue() const; + void setEditableValue (const double newValue); + + bool isProportional() const throw() { return isProportion; } + void toggleProportionality (MarkerResolver& markerResolver); + + const String getAnchor1() const { return checkName (anchor1); } + void changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver); + + const String getAnchor2() const { return checkName (anchor2); } + void changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver); + + //============================================================================== + /* + Position string formats: + 123 = absolute pixels from parent origin + marker + marker + 123 + marker - 123 + 50% = percentage between parent origin and parent extent + 50% * marker = percentage between parent origin and marker + 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. + */ + const String toString() const; + + //============================================================================== + static const char* parentLeftMarkerName; + static const char* parentRightMarkerName; + static const char* parentTopMarkerName; + static const char* parentBottomMarkerName; + +private: + //============================================================================== + String anchor1, anchor2; + double value; + bool isProportion, isHorizontal; + + double resolve (MarkerResolver& markerResolver, int recursionCounter) const; + double getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const; + const String checkName (const String& name) const; + const String getOriginMarkerName() const; + const String getExtentMarkerName() const; + static bool isOrigin (const String& name); + static void skipWhitespace (const String& s, int& i); + static const String readMarkerName (const String& s, int& i); + static double readNumber (const String& s, int& i); +}; + +//============================================================================== +/** + Describes a rectangle as a set of Coordinate values. +*/ +class RectangleCoordinates +{ +public: + //============================================================================== + RectangleCoordinates(); + explicit RectangleCoordinates (const Rectangle& rect); + explicit RectangleCoordinates (const String& stringVersion); + + //============================================================================== + const Rectangle resolve (Coordinate::MarkerResolver& markerResolver) const; + bool isRecursive (Coordinate::MarkerResolver& markerResolver) const; + void moveToAbsolute (const Rectangle& newPos, Coordinate::MarkerResolver& markerResolver); + const String toString() const; + + Coordinate left, right, top, bottom; +}; + + +#endif // __JUCER_COORDINATE_H_EF56ACFA__ diff --git a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_Make.h b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_Make.h index 51c072d7b4..89e79ab24e 100644 --- a/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_Make.h +++ b/extras/Jucer (experimental)/Source/model/jucer_ProjectExport_Make.h @@ -164,7 +164,7 @@ private: void writeLinkerFlags (OutputStream& out, const Project::BuildConfiguration& config) { - out << " LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows"; + out << " LDFLAGS += -L$(BINDIR) -L$(LIBDIR)"; { Array libraryPaths; diff --git a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditor.cpp b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditor.cpp index 5b75b07f42..e6cd3c1803 100644 --- a/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditor.cpp +++ b/extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditor.cpp @@ -159,112 +159,6 @@ private: Rectangle textArea; }; -//============================================================================== -static const double tickSizes[] = { 1.0, 2.0, 5.0, - 10.0, 20.0, 50.0, - 100.0, 200.0, 500.0, 1000.0 }; - -class TickIterator -{ -public: - TickIterator (const double startValue_, const double endValue_, const double valuePerPixel_, - int minPixelsPerTick, int minWidthForLabels) - : startValue (startValue_), - endValue (endValue_), - valuePerPixel (valuePerPixel_) - { - tickLevelIndex = findLevelIndexForValue (valuePerPixel * minPixelsPerTick); - labelLevelIndex = findLevelIndexForValue (valuePerPixel * minWidthForLabels); - - tickPosition = pixelsToValue (-minWidthForLabels); - tickPosition = snapValueDown (tickPosition, tickLevelIndex); - } - - bool getNextTick (float& pixelX, float& tickLength, String& label) - { - const double tickUnits = tickSizes [tickLevelIndex]; - tickPosition += tickUnits; - - const int totalLevels = sizeof (tickSizes) / sizeof (*tickSizes); - int highestIndex = tickLevelIndex; - - while (++highestIndex < totalLevels) - { - const double ticksAtThisLevel = tickPosition / tickSizes [highestIndex]; - - if (fabs (ticksAtThisLevel - floor (ticksAtThisLevel + 0.5)) > 0.000001) - break; - } - - --highestIndex; - - if (highestIndex >= labelLevelIndex) - label = getDescriptionOfValue (tickPosition, labelLevelIndex); - else - label = String::empty; - - tickLength = (highestIndex + 1 - tickLevelIndex) / (float) (totalLevels + 1 - tickLevelIndex); - pixelX = valueToPixels (tickPosition); - - return tickPosition < endValue; - } - -private: - double tickPosition; - int tickLevelIndex, labelLevelIndex; - const double startValue, endValue, valuePerPixel; - - int findLevelIndexForValue (const double value) const - { - int i; - for (i = 0; i < sizeof (tickSizes) / sizeof (*tickSizes); ++i) - if (tickSizes [i] >= value) - break; - - return i; - } - - double pixelsToValue (int pixels) const - { - return startValue + pixels * valuePerPixel; - } - - float valueToPixels (double value) const - { - return (float) ((value - startValue) / valuePerPixel); - } - - static double snapValueToNearest (const double t, const int valueLevelIndex) - { - const double unitsPerInterval = tickSizes [valueLevelIndex]; - return unitsPerInterval * floor (t / unitsPerInterval + 0.5); - } - - static double snapValueDown (const double t, const int valueLevelIndex) - { - const double unitsPerInterval = tickSizes [valueLevelIndex]; - return unitsPerInterval * floor (t / unitsPerInterval); - } - - static inline int roundDoubleToInt (const double value) - { - union { int asInt[2]; double asDouble; } n; - n.asDouble = value + 6755399441055744.0; - - #if TARGET_RT_BIG_ENDIAN - return n.asInt [1]; - #else - return n.asInt [0]; - #endif - } - - static const String getDescriptionOfValue (const double value, const int valueLevelIndex) - { - return String (roundToInt (value)); - } -}; - - //============================================================================== class ComponentEditor::Canvas : public Component, public ValueTree::Listener, @@ -287,6 +181,7 @@ public: ~Canvas() { + dragger = 0; getDocument().getRoot().removeListener (this); componentHolder->deleteAllChildren(); deleteAllChildren(); @@ -508,10 +403,260 @@ public: void showSizeGuides() { overlay->showSizeGuides(); } void hideSizeGuides() { overlay->hideSizeGuides(); } + //============================================================================== + class DragOperation + { + public: + DragOperation (Canvas& canvas_, + const Array& items, + const MouseEvent& e, + const ResizableBorderComponent::Zone& zone_) + : canvas (canvas_), + zone (zone_) + { + for (int i = 0; i < items.size(); ++i) + { + Component* comp = items.getUnchecked(i); + jassert (comp != 0); + + const ValueTree v (getDocument().getComponentState (comp)); + draggedComponents.add (v); + + Rectangle pos; + + { + RectangleCoordinates relativePos (getDocument().getCoordsFor (v)); + ScopedPointer markers (getDocument().createMarkerResolver (v)); + pos = relativePos.resolve (*markers); + originalPositions.add (pos); + } + + const Rectangle floatPos ((float) pos.getX(), (float) pos.getY(), + (float) pos.getWidth(), (float) pos.getHeight()); + + if (zone.isDraggingWholeObject() || zone.isDraggingLeftEdge()) + verticalSnapPositions.add (SnapLine (floatPos.getX(), floatPos.getY(), floatPos.getBottom())); + + if (zone.isDraggingWholeObject() || (zone.isDraggingLeftEdge() && zone.isDraggingRightEdge())) + verticalSnapPositions.add (SnapLine (floatPos.getCentreX(), floatPos.getY(), floatPos.getBottom())); + + if (zone.isDraggingWholeObject() || zone.isDraggingRightEdge()) + verticalSnapPositions.add (SnapLine (floatPos.getRight(), floatPos.getY(), floatPos.getBottom())); + + if (zone.isDraggingWholeObject() || zone.isDraggingTopEdge()) + horizontalSnapPositions.add (SnapLine (floatPos.getY(), floatPos.getX(), floatPos.getRight())); + + if (zone.isDraggingWholeObject() || (zone.isDraggingTopEdge() && zone.isDraggingBottomEdge())) + horizontalSnapPositions.add (SnapLine (floatPos.getCentreY(), floatPos.getX(), floatPos.getRight())); + + if (zone.isDraggingWholeObject() || zone.isDraggingBottomEdge()) + horizontalSnapPositions.add (SnapLine (floatPos.getBottom(), floatPos.getX(), floatPos.getRight())); + } + + verticalSnapTargets.add (SnapLine (0, 0, 10000.0f)); + verticalSnapTargets.add (SnapLine (getDocument().getCanvasWidth().getValue(), 0, 10000.0f)); + + if (zone.isDraggingWholeObject() || (zone.isDraggingLeftEdge() && zone.isDraggingRightEdge())) + verticalSnapTargets.add (SnapLine ((float) getDocument().getCanvasWidth().getValue() / 2.0f, 0, 10000.0f)); + + horizontalSnapTargets.add (SnapLine (0, 0, 10000.0f)); + horizontalSnapTargets.add (SnapLine (getDocument().getCanvasHeight().getValue(), 0, 10000.0f)); + + if (zone.isDraggingWholeObject() || (zone.isDraggingTopEdge() && zone.isDraggingBottomEdge())) + horizontalSnapTargets.add (SnapLine ((float) getDocument().getCanvasHeight().getValue() / 2.0f, 0, 10000.0f)); + + getDocument().beginNewTransaction(); + } + + ~DragOperation() + { + getDocument().beginNewTransaction(); + } + + struct SnapLine + { + SnapLine (float position_, float start_, float end_) + : position (position_), start (start_), end (end_) + {} + + float position, start, end; + }; + + class SnapGuideComponent : public Component + { + public: + SnapGuideComponent (const SnapLine& line_, bool isVertical_, Component* parent) + : line (line_), isVertical (isVertical_) + { + if (isVertical) + setBounds (roundToInt (line.position), roundToInt (line.start), 1, roundToInt (line.end - line.start)); + else + setBounds (roundToInt (line.start), roundToInt (line.position), roundToInt (line.end - line.start), 1); + + parent->addAndMakeVisible (this); + } + + void paint (Graphics& g) + { + g.fillAll (Colours::blue.withAlpha (0.3f)); + } + + private: + const SnapLine line; + const bool isVertical; + + SnapGuideComponent (const SnapGuideComponent&); + SnapGuideComponent& operator= (const SnapGuideComponent&); + }; + + void drag (const MouseEvent& e) + { + const float snapThreshold = 8.0f; + + getDocument().getUndoManager()->undoCurrentTransactionOnly(); + + Point distance (e.getOffsetFromDragStart()); + snapGuides.clear(); + + SnapLine snap (0, 0, 0); + const float snapX = findBestSnapDistance (verticalSnapTargets, getVerticalSnapPositions (distance), snap); + if (fabsf (snapX) < snapThreshold) + { + distance = Point (distance.getX() + snapX, distance.getY()); + + if (snap.position != 0) + snapGuides.add (new SnapGuideComponent (snap, true, canvas.overlay)); + } + + const float snapY = findBestSnapDistance (horizontalSnapTargets, getHorizontalSnapPositions (distance), snap); + if (fabsf (snapY) < snapThreshold) + { + distance = Point (distance.getX(), distance.getY() + snapY); + + if (snap.position != 0) + snapGuides.add (new SnapGuideComponent (snap, false, canvas.overlay)); + } + + for (int n = 50;;) + { + // Need to repeatedly apply the new positions until they all settle down, in case some of + // the coords are relative to each other.. + bool anyUpdated = false; + + for (int i = 0; i < draggedComponents.size(); ++i) + if (dragItem (draggedComponents.getReference(i), distance, originalPositions.getReference(i))) + anyUpdated = true; + + if (! anyUpdated) + break; + + if (--n == 0) + { + jassertfalse; + break; + } + } + } + + bool dragItem (ValueTree& v, const Point& distance, const Rectangle& originalPos) + { + const Rectangle newBounds (zone.resizeRectangleBy (originalPos, distance)); + + RectangleCoordinates pr (getDocument().getCoordsFor (v)); + ScopedPointer markers (getDocument().createMarkerResolver (v)); + + pr.moveToAbsolute (newBounds, *markers); + + return getDocument().setCoordsFor (v, pr); + } + + const Array getVerticalSnapPositions (const Point& distance) const + { + Array p (verticalSnapPositions); + for (int i = p.size(); --i >= 0;) + p.getReference(i).position += distance.getX(); + + return p; + } + + const Array getHorizontalSnapPositions (const Point& distance) const + { + Array p (horizontalSnapPositions); + for (int i = p.size(); --i >= 0;) + p.getReference(i).position += distance.getY(); + + return p; + } + + static float findBestSnapDistance (const Array& targets, const Array& sources, SnapLine& line) + { + if (targets.size() == 0 || sources.size() == 0) + return 0.0f; + + float best = 1.0e10f; + float absBest = fabsf (best); + line = SnapLine (1.0e10f, 0, 0); + + for (int i = 0; i < targets.size(); ++i) + { + for (int j = 0; j < sources.size(); ++j) + { + SnapLine& target = targets.getReference(i); + SnapLine& source = sources.getReference(j); + const float diff = target.position - source.position; + const float absDiff = fabsf (diff); + + if (absDiff < absBest) + { + line = SnapLine (target.position, jmin (target.start, source.start), jmax (target.end, source.end)); + best = diff; + absBest = absDiff; + } + } + } + + jassert (absBest < 1.0e10f); + return best; + } + + private: + Canvas& canvas; + Array draggedComponents; + Array > originalPositions; + + Array verticalSnapPositions, horizontalSnapPositions; + Array verticalSnapTargets, horizontalSnapTargets; + const ResizableBorderComponent::Zone zone; + OwnedArray snapGuides; + + ComponentDocument& getDocument() throw() { return canvas.getDocument(); } + }; + + void beginDrag (const MouseEvent& e, const ResizableBorderComponent::Zone& zone) + { + dragger = new DragOperation (*this, getSelectedComps(), e, zone); + } + + void continueDrag (const MouseEvent& e) + { + if (dragger != 0) + dragger->drag (e); + } + + void endDrag (const MouseEvent& e) + { + if (dragger != 0) + { + dragger->drag (e); + dragger = 0; + } + } + private: ComponentEditor& editor; const BorderSize border; const int resizerThickness; + ScopedPointer dragger; ResizableBorderComponent::Zone dragZone; int dragStartWidth, dragStartHeight; @@ -571,7 +716,7 @@ private: if (component != 0) { updateDragZone (e.getPosition()); - canvas.getDocument().beginDrag (canvas.getSelectedComps(), e, getParentComponent(), dragZone); + canvas.beginDrag (e, dragZone); canvas.showSizeGuides(); } } @@ -579,7 +724,7 @@ private: void mouseDrag (const MouseEvent& e) { if (component != 0) - canvas.getDocument().continueDrag (e); + canvas.continueDrag (e); } void mouseUp (const MouseEvent& e) @@ -587,7 +732,7 @@ private: canvas.hideSizeGuides(); if (component != 0) - canvas.getDocument().endDrag (e); + canvas.endDrag (e); updateDragZone (e.getPosition()); } @@ -720,11 +865,10 @@ private: { isDraggingClickedComp = true; canvas.getSelection().addToSelectionOnMouseUp (mouseDownCompUID, e.mods, true, mouseDownResult); - canvas.getDocument().beginDrag (canvas.getSelectedComps(), e, getParentComponent(), - ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre)); + canvas.beginDrag (e, ResizableBorderComponent::Zone (ResizableBorderComponent::Zone::centre)); } - canvas.getDocument().continueDrag (e); + canvas.continueDrag (e); showSizeGuides(); } } @@ -747,7 +891,7 @@ private: canvas.getSelection().addToSelectionOnMouseUp (mouseDownCompUID, e.mods, ! e.mouseWasClicked(), mouseDownResult); } - canvas.getDocument().endDrag (e); + canvas.endDrag (e); } void findLassoItemsInArea (Array & itemsFound, int x, int y, int width, int height) diff --git a/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.cpp b/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.cpp index 6ed8b3d87b..a1768d9d81 100644 --- a/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.cpp +++ b/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.cpp @@ -503,363 +503,3 @@ int indexOfLineStartingWith (const StringArray& lines, const String& text, int s return -1; } - -//============================================================================== -const char* Coordinate::parentLeftMarkerName = "parent.left"; -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 (double absoluteDistanceFromOrigin, bool isHorizontal_) - : value (absoluteDistanceFromOrigin), isProportion (false), isHorizontal (isHorizontal_) -{ -} - -Coordinate::Coordinate (double absoluteDistance, const String& source, bool isHorizontal_) - : anchor1 (source), value (absoluteDistance), isProportion (false), isHorizontal (isHorizontal_) -{ -} - -Coordinate::Coordinate (double relativeProportion, const String& pos1, const String& pos2, bool isHorizontal_) - : anchor1 (pos1), anchor2 (pos2), value (relativeProportion), isProportion (true), isHorizontal (isHorizontal_) -{ -} - -Coordinate::~Coordinate() -{ -} - -const Coordinate Coordinate::getAnchorPoint1() const -{ - return Coordinate (0.0, anchor1, isHorizontal); -} - -const Coordinate Coordinate::getAnchorPoint2() const -{ - return Coordinate (0.0, anchor2, isHorizontal); -} - -bool Coordinate::isOrigin (const String& name) -{ - return name.isEmpty() || name == parentLeftMarkerName || name == parentTopMarkerName; -} - -const String Coordinate::getOriginMarkerName() const -{ - return isHorizontal ? parentLeftMarkerName : parentTopMarkerName; -} - -const String Coordinate::getExtentMarkerName() const -{ - return isHorizontal ? parentRightMarkerName : parentBottomMarkerName; -} - -const String Coordinate::checkName (const String& name) const -{ - return name.isEmpty() ? getOriginMarkerName() : name; -} - -double Coordinate::getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const -{ - if (isOrigin (name)) - return 0.0; - - return markerResolver.findMarker (name, isHorizontal) - .resolve (markerResolver, recursionCounter + 1); -} - -struct RecursivePositionException -{ -}; - -double Coordinate::resolve (MarkerResolver& markerResolver, int recursionCounter) const -{ - if (recursionCounter > 100) - { - jassertfalse - throw RecursivePositionException(); - } - - const double pos1 = getPosition (anchor1, markerResolver, recursionCounter); - - return isProportion ? pos1 + (getPosition (anchor2, markerResolver, recursionCounter) - pos1) * value - : pos1 + value; -} - -double Coordinate::resolve (MarkerResolver& markerResolver) const -{ - try - { - return resolve (markerResolver, 0); - } - catch (RecursivePositionException&) - {} - - return 0.0; -} - -void Coordinate::moveToAbsolute (double newPos, MarkerResolver& markerResolver) -{ - try - { - const double pos1 = getPosition (anchor1, markerResolver, 0); - - if (isProportion) - { - const double size = getPosition (anchor2, markerResolver, 0) - pos1; - - if (size != 0) - value = (newPos - pos1) / size; - } - else - { - value = newPos - pos1; - } - } - catch (RecursivePositionException&) - {} -} - -bool Coordinate::isRecursive (MarkerResolver& markerResolver) const -{ - try - { - resolve (markerResolver, 0); - } - catch (RecursivePositionException&) - { - return true; - } - - return false; -} - -void Coordinate::skipWhitespace (const String& s, int& i) -{ - while (CharacterFunctions::isWhitespace (s[i])) - ++i; -} - -const String Coordinate::readMarkerName (const String& s, int& i) -{ - skipWhitespace (s, i); - - if (CharacterFunctions::isLetter (s[i]) || s[i] == '_') - { - int start = i; - - while (CharacterFunctions::isLetterOrDigit (s[i]) || s[i] == '_' || s[i] == '.') - ++i; - - return s.substring (start, i); - } - - return String::empty; -} - -double Coordinate::readNumber (const String& s, int& i) -{ - skipWhitespace (s, i); - - int start = i; - - if (CharacterFunctions::isDigit (s[i]) || s[i] == '.' || s[i] == '-') - ++i; - - while (CharacterFunctions::isDigit (s[i]) || s[i] == '.') - ++i; - - if ((s[i] == 'e' || s[i] == 'E') - && (CharacterFunctions::isDigit (s[i + 1]) - || s[i + 1] == '-' - || s[i + 1] == '+')) - { - i += 2; - - while (CharacterFunctions::isDigit (s[i])) - ++i; - } - - const double value = s.substring (start, i).getDoubleValue(); - - while (CharacterFunctions::isWhitespace (s[i]) || s[i] == ',') - ++i; - - return value; -} - -Coordinate::Coordinate (const String& s, bool isHorizontal_) - : value (0), isProportion (false), isHorizontal (isHorizontal_) -{ - int i = 0; - - anchor1 = readMarkerName (s, i); - - if (anchor1.isNotEmpty()) - { - skipWhitespace (s, i); - - if (s[i] == '+') - value = readNumber (s, ++i); - else if (s[i] == '-') - value = -readNumber (s, ++i); - } - else - { - value = readNumber (s, i); - skipWhitespace (s, i); - - if (s[i] == '%') - { - isProportion = true; - value /= 100.0; - skipWhitespace (s, ++i); - - if (s[i] == '*') - { - anchor1 = readMarkerName (s, ++i); - skipWhitespace (s, i); - - if (s[i] == '-' && s[i + 1] == '>') - { - i += 2; - anchor2 = readMarkerName (s, i); - } - else - { - anchor2 = anchor1; - anchor1 = getOriginMarkerName(); - } - } - else - { - anchor1 = getOriginMarkerName(); - anchor2 = getExtentMarkerName(); - } - } - } -} - -const String Coordinate::toString() const -{ - if (isProportion) - { - const String percent (value * 100.0); - - if (isOrigin (anchor1)) - { - if (anchor2 == parentRightMarkerName || anchor2 == parentBottomMarkerName) - return percent + "%"; - else - return percent + "% * " + checkName (anchor2); - } - else - return percent + "% * " + checkName (anchor1) + " -> " + checkName (anchor2); - } - else - { - if (isOrigin (anchor1)) - return String (value); - else if (value > 0) - return checkName (anchor1) + " + " + String (value); - else if (value < 0) - return checkName (anchor1) + " - " + String (-value); - else - return checkName (anchor1); - } -} - -const double Coordinate::getEditableValue() const -{ - return isProportion ? value * 100.0 : value; -} - -void Coordinate::setEditableValue (const double newValue) -{ - value = isProportion ? newValue / 100.0 : newValue; -} - -void Coordinate::toggleProportionality (MarkerResolver& markerResolver) -{ - const double oldValue = resolve (markerResolver); - - isProportion = ! isProportion; - anchor1 = getOriginMarkerName(); - anchor2 = getExtentMarkerName(); - - moveToAbsolute (oldValue, markerResolver); -} - -void Coordinate::changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver) -{ - const double oldValue = resolve (markerResolver); - anchor1 = newMarkerName; - moveToAbsolute (oldValue, markerResolver); -} - -void Coordinate::changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver) -{ - const double oldValue = resolve (markerResolver); - anchor2 = newMarkerName; - moveToAbsolute (oldValue, markerResolver); -} - -//============================================================================== -RectangleCoordinates::RectangleCoordinates() - : left (true), right (true), top (false), bottom (false) -{ -} - -RectangleCoordinates::RectangleCoordinates (const Rectangle& rect) - : left (rect.getX(), true), - right (rect.getWidth(), "left", true), - top (rect.getY(), false), - bottom (rect.getHeight(), "top", false) -{ -} - -RectangleCoordinates::RectangleCoordinates (const String& stringVersion) - : left (true), right (true), top (false), bottom (false) -{ - StringArray tokens; - tokens.addTokens (stringVersion, ",", String::empty); - - left = Coordinate (tokens [0], true); - top = Coordinate (tokens [1], false); - right = Coordinate (tokens [2], true); - 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 RectangleCoordinates::resolve (Coordinate::MarkerResolver& markerResolver) const -{ - const int l = roundToInt (left.resolve (markerResolver)); - const int r = roundToInt (right.resolve (markerResolver)); - const int t = roundToInt (top.resolve (markerResolver)); - const int b = roundToInt (bottom.resolve (markerResolver)); - - return Rectangle (l, t, r - l, b - t); -} - -void RectangleCoordinates::moveToAbsolute (const Rectangle& newPos, Coordinate::MarkerResolver& markerResolver) -{ - left.moveToAbsolute (newPos.getX(), markerResolver); - right.moveToAbsolute (newPos.getRight(), markerResolver); - top.moveToAbsolute (newPos.getY(), markerResolver); - bottom.moveToAbsolute (newPos.getBottom(), markerResolver); -} - -const String RectangleCoordinates::toString() const -{ - return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); -} diff --git a/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.h b/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.h index b5c048bbe8..80bb638666 100644 --- a/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.h +++ b/extras/Jucer (experimental)/Source/utility/jucer_UtilityFunctions.h @@ -109,127 +109,107 @@ private: int64 fileHashCode, fileSize; }; - //============================================================================== -/** - Holds a co-ordinate along the x or y axis, expressed either as an absolute - position, or relative to other named marker positions. -*/ -class Coordinate +static const double tickSizes[] = { 1.0, 2.0, 5.0, + 10.0, 20.0, 50.0, + 100.0, 200.0, 500.0, 1000.0 }; + +class TickIterator { public: - //============================================================================== - /** Creates a zero coordinate. */ - explicit Coordinate (bool isHorizontal); + TickIterator (const double startValue_, const double endValue_, const double valuePerPixel_, + int minPixelsPerTick, int minWidthForLabels) + : startValue (startValue_), + endValue (endValue_), + valuePerPixel (valuePerPixel_) + { + tickLevelIndex = findLevelIndexForValue (valuePerPixel * minPixelsPerTick); + labelLevelIndex = findLevelIndexForValue (valuePerPixel * minWidthForLabels); + + tickPosition = pixelsToValue (-minWidthForLabels); + tickPosition = snapValueDown (tickPosition, tickLevelIndex); + } - /** Recreates a coordinate from its stringified version. */ - Coordinate (const String& stringVersion, bool isHorizontal); + bool getNextTick (float& pixelX, float& tickLength, String& label) + { + const double tickUnits = tickSizes [tickLevelIndex]; + tickPosition += tickUnits; - /** Creates an absolute position from the parent origin. */ - Coordinate (double absoluteDistanceFromOrigin, bool isHorizontal); + const int totalLevels = sizeof (tickSizes) / sizeof (*tickSizes); + int highestIndex = tickLevelIndex; - /** Creates an absolute position relative to a named marker. */ - Coordinate (double absolutePosition, const String& relativeToMarker, bool isHorizontal); + while (++highestIndex < totalLevels) + { + const double ticksAtThisLevel = tickPosition / tickSizes [highestIndex]; - /** Creates a relative position between two named markers. */ - Coordinate (double relativePosition, const String& marker1, const String& marker2, bool isHorizontal); + if (fabs (ticksAtThisLevel - floor (ticksAtThisLevel + 0.5)) > 0.000001) + break; + } - /** Destructor. */ - ~Coordinate(); + --highestIndex; - //============================================================================== - /** - Provides an interface for looking up the position of a named marker. - */ - class MarkerResolver - { - public: - virtual ~MarkerResolver() {} - virtual const Coordinate findMarker (const String& name, bool isHorizontal) = 0; - }; - - /** Calculates the absolute position of this co-ordinate. */ - double resolve (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; - - /** Changes the value of this marker to make it resolve to the specified position. */ - void moveToAbsolute (double newPos, MarkerResolver& markerResolver); - - const Coordinate getAnchorPoint1() const; - const Coordinate getAnchorPoint2() const; - - const double getEditableValue() const; - void setEditableValue (const double newValue); - - bool isProportional() const throw() { return isProportion; } - void toggleProportionality (MarkerResolver& markerResolver); - - const String getAnchor1() const { return anchor1; } - void changeAnchor1 (const String& newMarkerName, MarkerResolver& markerResolver); - - const String getAnchor2() const { return anchor2; } - void changeAnchor2 (const String& newMarkerName, MarkerResolver& markerResolver); - - //============================================================================== - /* - Position string formats: - 123 = absolute pixels from parent origin - marker - marker + 123 - marker - 123 - 50% = percentage between parent origin and parent extent - 50% * marker = percentage between parent origin and marker - 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. - */ - const String toString() const; - - //============================================================================== - static const char* parentLeftMarkerName; - static const char* parentRightMarkerName; - static const char* parentTopMarkerName; - static const char* parentBottomMarkerName; + if (highestIndex >= labelLevelIndex) + label = getDescriptionOfValue (tickPosition, labelLevelIndex); + else + label = String::empty; + + tickLength = (highestIndex + 1 - tickLevelIndex) / (float) (totalLevels + 1 - tickLevelIndex); + pixelX = valueToPixels (tickPosition); + + return tickPosition < endValue; + } private: - //============================================================================== - String anchor1, anchor2; - double value; - bool isProportion, isHorizontal; - - double resolve (MarkerResolver& markerResolver, int recursionCounter) const; - double getPosition (const String& name, MarkerResolver& markerResolver, int recursionCounter) const; - const String checkName (const String& name) const; - const String getOriginMarkerName() const; - const String getExtentMarkerName() const; - static bool isOrigin (const String& name); - static void skipWhitespace (const String& s, int& i); - static const String readMarkerName (const String& s, int& i); - static double readNumber (const String& s, int& i); -}; + double tickPosition; + int tickLevelIndex, labelLevelIndex; + const double startValue, endValue, valuePerPixel; -//============================================================================== -/** - Describes a rectangle as a set of Coordinate values. -*/ -class RectangleCoordinates -{ -public: - //============================================================================== - RectangleCoordinates(); - explicit RectangleCoordinates (const Rectangle& rect); - explicit RectangleCoordinates (const String& stringVersion); - - //============================================================================== - const Rectangle resolve (Coordinate::MarkerResolver& markerResolver) const; - bool isRecursive (Coordinate::MarkerResolver& markerResolver) const; - void moveToAbsolute (const Rectangle& newPos, Coordinate::MarkerResolver& markerResolver); - const String toString() const; - - Coordinate left, right, top, bottom; + int findLevelIndexForValue (const double value) const + { + int i; + for (i = 0; i < sizeof (tickSizes) / sizeof (*tickSizes); ++i) + if (tickSizes [i] >= value) + break; + + return i; + } + + double pixelsToValue (int pixels) const + { + return startValue + pixels * valuePerPixel; + } + + float valueToPixels (double value) const + { + return (float) ((value - startValue) / valuePerPixel); + } + + static double snapValueToNearest (const double t, const int valueLevelIndex) + { + const double unitsPerInterval = tickSizes [valueLevelIndex]; + return unitsPerInterval * floor (t / unitsPerInterval + 0.5); + } + + static double snapValueDown (const double t, const int valueLevelIndex) + { + const double unitsPerInterval = tickSizes [valueLevelIndex]; + return unitsPerInterval * floor (t / unitsPerInterval); + } + + static inline int roundDoubleToInt (const double value) + { + union { int asInt[2]; double asDouble; } n; + n.asDouble = value + 6755399441055744.0; + + #if TARGET_RT_BIG_ENDIAN + return n.asInt [1]; + #else + return n.asInt [0]; + #endif + } + + static const String getDescriptionOfValue (const double value, const int valueLevelIndex) + { + return String (roundToInt (value)); + } }; diff --git a/extras/amalgamator/Builds/Linux/Makefile b/extras/amalgamator/Builds/Linux/Makefile index eb3ea87325..96818919aa 100644 --- a/extras/amalgamator/Builds/Linux/Makefile +++ b/extras/amalgamator/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := amalgamator @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -Os - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := amalgamator diff --git a/extras/audio plugin host/Builds/Linux/Makefile b/extras/audio plugin host/Builds/Linux/Makefile index f3921c8f2c..3a1e6599b5 100644 --- a/extras/audio plugin host/Builds/Linux/Makefile +++ b/extras/audio plugin host/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := Plugin\ Host @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -Os - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := Plugin\ Host diff --git a/extras/binarybuilder/Builds/Linux/Makefile b/extras/binarybuilder/Builds/Linux/Makefile index 4ad1fa9c6e..695bce9910 100644 --- a/extras/binarybuilder/Builds/Linux/Makefile +++ b/extras/binarybuilder/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := BinaryBuilder @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -Os - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := BinaryBuilder diff --git a/extras/example projects/Builds/Linux/Makefile b/extras/example projects/Builds/Linux/Makefile index 6b44bc3007..eeb3858c24 100644 --- a/extras/example projects/Builds/Linux/Makefile +++ b/extras/example projects/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := HelloWorld @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -Os - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := HelloWorld diff --git a/extras/juce demo/Builds/Linux/Makefile b/extras/juce demo/Builds/Linux/Makefile index 47f278be74..131093a021 100644 --- a/extras/juce demo/Builds/Linux/Makefile +++ b/extras/juce demo/Builds/Linux/Makefile @@ -19,8 +19,8 @@ ifeq ($(CONFIG),Debug) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := JuceDemo @@ -34,8 +34,8 @@ ifeq ($(CONFIG),Release) OUTDIR := build CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -Os - CXXFLAGS += $(CFLAGS) - LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -mwindows -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound + CXXFLAGS += $(CFLAGS) + LDFLAGS += -L$(BINDIR) -L$(LIBDIR) -L"/usr/X11R6/lib/" -L"../../../../../juce/bin" -lfreetype -lpthread -lrt -lX11 -lGL -lGLU -lXinerama -lasound LDDEPS := RESFLAGS := -D "LINUX=1" -D "NDEBUG=1" -I "/usr/include" -I "/usr/include/freetype2" TARGET := JuceDemo diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 6e17a629d2..559ed8fc31 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -10189,7 +10189,8 @@ public: static juce_wchar* createCopy (const char* const src, const size_t numChars) { juce_wchar* const dest = createUninitialised (numChars); - CharacterFunctions::copy (dest, src, numChars + 1); + CharacterFunctions::copy (dest, src, numChars); + dest [numChars] = 0; return dest; } @@ -17924,7 +17925,11 @@ FileBasedDocument::~FileBasedDocument() void FileBasedDocument::setChangedFlag (const bool hasChanged) { - changedSinceSave = hasChanged; + if (changedSinceSave != hasChanged) + { + changedSinceSave = hasChanged; + sendChangeMessage (this); + } } void FileBasedDocument::changed() @@ -17938,7 +17943,7 @@ void FileBasedDocument::setFile (const File& newFile) if (documentFile != newFile) { documentFile = newFile; - changedSinceSave = true; + changed(); } } @@ -48452,12 +48457,17 @@ void Slider::setTextValueSuffix (const String& suffix) } } +const String Slider::getTextValueSuffix() const +{ + return textSuffix; +} + const String Slider::getTextFromValue (double v) { - if (numDecimalPlaces > 0) - return String (v, numDecimalPlaces) + textSuffix; + if (getNumDecimalPlacesToDisplay() > 0) + return String (v, getNumDecimalPlacesToDisplay()) + getTextValueSuffix(); else - return String (roundToInt (v)) + textSuffix; + return String (roundToInt (v)) + getTextValueSuffix(); } double Slider::getValueFromText (const String& text) diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 1dabc5fb65..7d2bf5fefa 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -43,7 +43,7 @@ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 51 -#define JUCE_BUILDNUMBER 14 +#define JUCE_BUILDNUMBER 15 #define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER) @@ -21367,6 +21367,8 @@ public: void setTextValueSuffix (const String& suffix); + const String getTextValueSuffix() const; + virtual double proportionOfLengthToValue (double proportion); virtual double valueToProportionOfLength (double value); @@ -21415,6 +21417,8 @@ protected: void colourChanged(); void valueChanged (Value& value); + int getNumDecimalPlacesToDisplay() const throw() { return numDecimalPlaces; } + private: ListenerList listeners; Value currentValue, valueMin, valueMax; diff --git a/src/core/juce_Atomic.h b/src/core/juce_Atomic.h index 6af1e8f7f0..1ddd81eb7d 100644 --- a/src/core/juce_Atomic.h +++ b/src/core/juce_Atomic.h @@ -47,7 +47,7 @@ public: /** If the current value of destination is equal to requiredCurrentValue, this will set it to newValue; otherwise, it will leave it unchanged. - @returns the new value of destination + @returns the original value of destination */ static int32 compareAndExchange (int32& destination, int32 newValue, int32 requiredCurrentValue); diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h index 2f07f90544..d80584bdc4 100644 --- a/src/core/juce_StandardHeader.h +++ b/src/core/juce_StandardHeader.h @@ -33,7 +33,7 @@ */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 51 -#define JUCE_BUILDNUMBER 14 +#define JUCE_BUILDNUMBER 15 /** Current Juce version number. diff --git a/src/gui/components/controls/juce_Slider.cpp b/src/gui/components/controls/juce_Slider.cpp index 73c4e41707..406d4e1aa9 100644 --- a/src/gui/components/controls/juce_Slider.cpp +++ b/src/gui/components/controls/juce_Slider.cpp @@ -632,12 +632,17 @@ void Slider::setTextValueSuffix (const String& suffix) } } +const String Slider::getTextValueSuffix() const +{ + return textSuffix; +} + const String Slider::getTextFromValue (double v) { - if (numDecimalPlaces > 0) - return String (v, numDecimalPlaces) + textSuffix; + if (getNumDecimalPlacesToDisplay() > 0) + return String (v, getNumDecimalPlacesToDisplay()) + getTextValueSuffix(); else - return String (roundToInt (v)) + textSuffix; + return String (roundToInt (v)) + getTextValueSuffix(); } double Slider::getValueFromText (const String& text) diff --git a/src/gui/components/controls/juce_Slider.h b/src/gui/components/controls/juce_Slider.h index a3f4bad8a4..bbd51cec5b 100644 --- a/src/gui/components/controls/juce_Slider.h +++ b/src/gui/components/controls/juce_Slider.h @@ -620,6 +620,9 @@ public: */ void setTextValueSuffix (const String& suffix); + /** Returns the suffix that was set by setTextValueSuffix(). */ + const String getTextValueSuffix() const; + //============================================================================== /** Allows a user-defined mapping of distance along the slider to its value. @@ -748,6 +751,11 @@ protected: /** @internal */ void valueChanged (Value& value); + /** Returns the best number of decimal places to use when displaying numbers. + This is calculated from the slider's interval setting. + */ + int getNumDecimalPlacesToDisplay() const throw() { return numDecimalPlaces; } + private: ListenerList listeners; Value currentValue, valueMin, valueMax; diff --git a/src/text/juce_String.cpp b/src/text/juce_String.cpp index cf89a4b537..79376ce67c 100644 --- a/src/text/juce_String.cpp +++ b/src/text/juce_String.cpp @@ -78,7 +78,8 @@ public: static juce_wchar* createCopy (const char* const src, const size_t numChars) { juce_wchar* const dest = createUninitialised (numChars); - CharacterFunctions::copy (dest, src, numChars + 1); + CharacterFunctions::copy (dest, src, numChars); + dest [numChars] = 0; return dest; } diff --git a/src/text/juce_String.h b/src/text/juce_String.h index cca90ae41e..b17608c43d 100644 --- a/src/text/juce_String.h +++ b/src/text/juce_String.h @@ -565,7 +565,7 @@ public: /** Returns a copy of this string, having removed a specified set of characters from its start. Characters are removed from the start of the string until it finds one that is not in the specified set, and then it stops. - @param charactersToTrim the set of characters to remove. This must not be null. + @param charactersToTrim the set of characters to remove. @see trim, trimStart, trimCharactersAtEnd */ const String trimCharactersAtStart (const String& charactersToTrim) const; @@ -573,7 +573,7 @@ public: /** Returns a copy of this string, having removed a specified set of characters from its end. Characters are removed from the end of the string until it finds one that is not in the specified set, and then it stops. - @param charactersToTrim the set of characters to remove. This must not be null. + @param charactersToTrim the set of characters to remove. @see trim, trimEnd, trimCharactersAtStart */ const String trimCharactersAtEnd (const String& charactersToTrim) const; diff --git a/src/utilities/juce_FileBasedDocument.cpp b/src/utilities/juce_FileBasedDocument.cpp index 961c349bf1..d1c6ceab7f 100644 --- a/src/utilities/juce_FileBasedDocument.cpp +++ b/src/utilities/juce_FileBasedDocument.cpp @@ -54,7 +54,11 @@ FileBasedDocument::~FileBasedDocument() //============================================================================== void FileBasedDocument::setChangedFlag (const bool hasChanged) { - changedSinceSave = hasChanged; + if (changedSinceSave != hasChanged) + { + changedSinceSave = hasChanged; + sendChangeMessage (this); + } } void FileBasedDocument::changed() @@ -69,7 +73,7 @@ void FileBasedDocument::setFile (const File& newFile) if (documentFile != newFile) { documentFile = newFile; - changedSinceSave = true; + changed(); } }