| @@ -336,143 +336,3 @@ void FloatingLabelComponent::paint (Graphics& g) | |||||
| g.setColour (colour); | g.setColour (colour); | ||||
| glyphs.draw (g, AffineTransform::translation (1.0f, 1.0f)); | glyphs.draw (g, AffineTransform::translation (1.0f, 1.0f)); | ||||
| } | } | ||||
| //============================================================================== | |||||
| RelativeRectangleLayoutManager::RelativeRectangleLayoutManager (Component* parentComponent) | |||||
| : parent (parentComponent) | |||||
| { | |||||
| parent->addComponentListener (this); | |||||
| } | |||||
| RelativeRectangleLayoutManager::~RelativeRectangleLayoutManager() | |||||
| { | |||||
| parent->removeComponentListener (this); | |||||
| for (int i = components.size(); --i >= 0;) | |||||
| components.getUnchecked(i)->component->removeComponentListener (this); | |||||
| } | |||||
| void RelativeRectangleLayoutManager::setMarker (const String& name, const RelativeCoordinate& coord) | |||||
| { | |||||
| for (int i = markers.size(); --i >= 0;) | |||||
| { | |||||
| MarkerPosition* m = markers.getUnchecked(i); | |||||
| if (m->markerName == name) | |||||
| { | |||||
| m->position = coord; | |||||
| applyLayout(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| markers.add (new MarkerPosition (name, coord)); | |||||
| applyLayout(); | |||||
| } | |||||
| void RelativeRectangleLayoutManager::setComponentBounds (Component* comp, const String& name, const RelativeRectangle& coords) | |||||
| { | |||||
| jassert (comp != 0); | |||||
| // All the components that this layout manages must be inside the parent component.. | |||||
| jassert (parent->isParentOf (comp)); | |||||
| for (int i = components.size(); --i >= 0;) | |||||
| { | |||||
| ComponentPosition* c = components.getUnchecked(i); | |||||
| if (c->component == comp) | |||||
| { | |||||
| c->name = name; | |||||
| c->coords = coords; | |||||
| triggerAsyncUpdate(); | |||||
| return; | |||||
| } | |||||
| } | |||||
| components.add (new ComponentPosition (comp, name, coords)); | |||||
| comp->addComponentListener (this); | |||||
| triggerAsyncUpdate(); | |||||
| } | |||||
| void RelativeRectangleLayoutManager::applyLayout() | |||||
| { | |||||
| for (int i = components.size(); --i >= 0;) | |||||
| { | |||||
| ComponentPosition* c = components.getUnchecked(i); | |||||
| // All the components that this layout manages must be inside the parent component.. | |||||
| jassert (parent->isParentOf (c->component)); | |||||
| c->component->setBounds (c->coords.resolve (this).getSmallestIntegerContainer()); | |||||
| } | |||||
| } | |||||
| const Expression RelativeRectangleLayoutManager::getSymbolValue (const String& objectName, const String& edge) const | |||||
| { | |||||
| if (objectName == RelativeCoordinate::Strings::parent) | |||||
| { | |||||
| if (edge == RelativeCoordinate::Strings::right) return Expression ((double) parent->getWidth()); | |||||
| if (edge == RelativeCoordinate::Strings::bottom) return Expression ((double) parent->getHeight()); | |||||
| } | |||||
| if (objectName.isNotEmpty() && edge.isNotEmpty()) | |||||
| { | |||||
| for (int i = components.size(); --i >= 0;) | |||||
| { | |||||
| ComponentPosition* c = components.getUnchecked(i); | |||||
| if (c->name == objectName) | |||||
| { | |||||
| if (edge == RelativeCoordinate::Strings::left) return c->coords.left.getExpression(); | |||||
| if (edge == RelativeCoordinate::Strings::right) return c->coords.right.getExpression(); | |||||
| if (edge == RelativeCoordinate::Strings::top) return c->coords.top.getExpression(); | |||||
| if (edge == RelativeCoordinate::Strings::bottom) return c->coords.bottom.getExpression(); | |||||
| } | |||||
| } | |||||
| } | |||||
| for (int i = markers.size(); --i >= 0;) | |||||
| { | |||||
| MarkerPosition* m = markers.getUnchecked(i); | |||||
| if (m->markerName == objectName) | |||||
| return m->position.getExpression(); | |||||
| } | |||||
| return Expression(); | |||||
| } | |||||
| void RelativeRectangleLayoutManager::componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||||
| { | |||||
| triggerAsyncUpdate(); | |||||
| if (parent == &component) | |||||
| handleUpdateNowIfNeeded(); | |||||
| } | |||||
| void RelativeRectangleLayoutManager::componentBeingDeleted (Component& component) | |||||
| { | |||||
| for (int i = components.size(); --i >= 0;) | |||||
| { | |||||
| ComponentPosition* c = components.getUnchecked(i); | |||||
| if (c->component == &component) | |||||
| { | |||||
| components.remove (i); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| void RelativeRectangleLayoutManager::handleAsyncUpdate() | |||||
| { | |||||
| applyLayout(); | |||||
| } | |||||
| RelativeRectangleLayoutManager::MarkerPosition::MarkerPosition (const String& name, const RelativeCoordinate& coord) | |||||
| : markerName (name), position (coord) | |||||
| { | |||||
| } | |||||
| RelativeRectangleLayoutManager::ComponentPosition::ComponentPosition (Component* component_, const String& name_, const RelativeRectangle& coords_) | |||||
| : component (component_), name (name_), coords (coords_) | |||||
| { | |||||
| } | |||||
| @@ -96,10 +96,6 @@ public: | |||||
| setClickingTogglesState (false); | setClickingTogglesState (false); | ||||
| } | } | ||||
| ~JucerToolbarButton() | |||||
| { | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, int& minSize, int& maxSize) | bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, int& minSize, int& maxSize) | ||||
| { | { | ||||
| @@ -137,69 +133,3 @@ public: | |||||
| private: | private: | ||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JucerToolbarButton); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JucerToolbarButton); | ||||
| }; | }; | ||||
| //============================================================================== | |||||
| /** | |||||
| */ | |||||
| class RelativeRectangleLayoutManager : public ComponentListener, | |||||
| public Expression::EvaluationContext, | |||||
| public AsyncUpdater | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** | |||||
| */ | |||||
| RelativeRectangleLayoutManager (Component* parentComponent); | |||||
| /** Destructor. */ | |||||
| ~RelativeRectangleLayoutManager(); | |||||
| //============================================================================== | |||||
| /** | |||||
| */ | |||||
| void setMarker (const String& name, const RelativeCoordinate& coord); | |||||
| /** | |||||
| */ | |||||
| void setComponentBounds (Component* component, const String& componentName, const RelativeRectangle& bounds); | |||||
| /** | |||||
| */ | |||||
| void applyLayout(); | |||||
| //============================================================================== | |||||
| /** @internal */ | |||||
| const Expression getSymbolValue (const String& symbol, const String& member) const; | |||||
| /** @internal */ | |||||
| void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); | |||||
| /** @internal */ | |||||
| void componentBeingDeleted (Component& component); | |||||
| /** @internal */ | |||||
| void handleAsyncUpdate(); | |||||
| private: | |||||
| //============================================================================== | |||||
| struct ComponentPosition | |||||
| { | |||||
| ComponentPosition (Component* component, const String& name, const RelativeRectangle& coords); | |||||
| Component* component; | |||||
| String name; | |||||
| RelativeRectangle coords; | |||||
| }; | |||||
| struct MarkerPosition | |||||
| { | |||||
| MarkerPosition (const String& name, const RelativeCoordinate& coord); | |||||
| String markerName; | |||||
| RelativeCoordinate position; | |||||
| }; | |||||
| Component* parent; | |||||
| OwnedArray <ComponentPosition> components; | |||||
| OwnedArray <MarkerPosition> markers; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleLayoutManager); | |||||
| }; | |||||
| @@ -4719,13 +4719,14 @@ public: | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| Type getType() const throw() { return symbolType; } | |||||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||||
| int getNumInputs() const { return 0; } | |||||
| Term* getInput (int) const { return 0; } | |||||
| const String getSymbolName() const { return toString(); } | |||||
| Type getType() const throw() { return symbolType; } | |||||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||||
| int getNumInputs() const { return 0; } | |||||
| Term* getInput (int) const { return 0; } | |||||
| const String toString() const { return joinParts (mainSymbol, member); } | |||||
| void getSymbolParts (String& objectName, String& memberName) const { objectName = mainSymbol; memberName = member; } | |||||
| const String toString() const | |||||
| static const String joinParts (const String& mainSymbol, const String& member) | |||||
| { | { | ||||
| return member.isEmpty() ? mainSymbol | return member.isEmpty() ? mainSymbol | ||||
| : mainSymbol + "." + member; | : mainSymbol + "." + member; | ||||
| @@ -5501,6 +5502,9 @@ const Expression Expression::withRenamedSymbol (const String& oldSymbol, const S | |||||
| { | { | ||||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | ||||
| if (oldSymbol == newSymbol) | |||||
| return *this; | |||||
| Expression newExpression (term->clone()); | Expression newExpression (term->clone()); | ||||
| Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | ||||
| return newExpression; | return newExpression; | ||||
| @@ -5523,7 +5527,14 @@ Expression::Type Expression::getType() const throw() | |||||
| const String Expression::getSymbol() const | const String Expression::getSymbol() const | ||||
| { | { | ||||
| return term->getSymbolName(); | |||||
| String objectName, memberName; | |||||
| term->getSymbolParts (objectName, memberName); | |||||
| return Expression::Helpers::Symbol::joinParts (objectName, memberName); | |||||
| } | |||||
| void Expression::getSymbolParts (String& objectName, String& memberName) const | |||||
| { | |||||
| term->getSymbolParts (objectName, memberName); | |||||
| } | } | ||||
| const String Expression::getFunction() const | const String Expression::getFunction() const | ||||
| @@ -5572,10 +5583,9 @@ const ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated() | |||||
| return new Helpers::Negate (this); | return new Helpers::Negate (this); | ||||
| } | } | ||||
| const String Expression::Term::getSymbolName() const | |||||
| void Expression::Term::getSymbolParts (String&, String&) const | |||||
| { | { | ||||
| jassertfalse; // You should only call getSymbol() on an expression that's actually a symbol! | jassertfalse; // You should only call getSymbol() on an expression that's actually a symbol! | ||||
| return String::empty; | |||||
| } | } | ||||
| const String Expression::Term::getFunctionName() const | const String Expression::Term::getFunctionName() const | ||||
| @@ -41530,6 +41540,23 @@ MarkerList* Component::getMarkers (bool /*xAxis*/) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| Component::Positioner::Positioner (Component& component_) throw() | |||||
| : component (component_) | |||||
| { | |||||
| } | |||||
| Component::Positioner* Component::getPositioner() const throw() | |||||
| { | |||||
| return positioner; | |||||
| } | |||||
| void Component::setPositioner (Positioner* newPositioner) | |||||
| { | |||||
| // You can only assign a positioner to the component that it was created for! | |||||
| jassert (newPositioner == 0 || this == &(newPositioner->getComponent())); | |||||
| positioner = newPositioner; | |||||
| } | |||||
| const Rectangle<int> Component::getLocalBounds() const throw() | const Rectangle<int> Component::getLocalBounds() const throw() | ||||
| { | { | ||||
| return Rectangle<int> (getWidth(), getHeight()); | return Rectangle<int> (getWidth(), getHeight()); | ||||
| @@ -48343,7 +48370,7 @@ public: | |||||
| { | { | ||||
| if (! selected) | if (! selected) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, false); | |||||
| if (owner.getModel() != 0) | if (owner.getModel() != 0) | ||||
| owner.getModel()->listBoxItemClicked (row, e); | owner.getModel()->listBoxItemClicked (row, e); | ||||
| @@ -48359,7 +48386,7 @@ public: | |||||
| { | { | ||||
| if (isEnabled() && selectRowOnMouseUp && ! isDragging) | if (isEnabled() && selectRowOnMouseUp && ! isDragging) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, true); | |||||
| if (owner.getModel() != 0) | if (owner.getModel() != 0) | ||||
| owner.getModel()->listBoxItemClicked (row, e); | owner.getModel()->listBoxItemClicked (row, e); | ||||
| @@ -48827,7 +48854,8 @@ void ListBox::deselectAllRows() | |||||
| } | } | ||||
| void ListBox::selectRowsBasedOnModifierKeys (const int row, | void ListBox::selectRowsBasedOnModifierKeys (const int row, | ||||
| const ModifierKeys& mods) | |||||
| const ModifierKeys& mods, | |||||
| const bool isMouseUpEvent) | |||||
| { | { | ||||
| if (multipleSelection && mods.isCommandDown()) | if (multipleSelection && mods.isCommandDown()) | ||||
| { | { | ||||
| @@ -48839,7 +48867,7 @@ void ListBox::selectRowsBasedOnModifierKeys (const int row, | |||||
| } | } | ||||
| else if ((! mods.isPopupMenu()) || ! isRowSelected (row)) | else if ((! mods.isPopupMenu()) || ! isRowSelected (row)) | ||||
| { | { | ||||
| selectRowInternal (row, false, ! (multipleSelection && isRowSelected (row)), true); | |||||
| selectRowInternal (row, false, ! (multipleSelection && (! isMouseUpEvent) && isRowSelected (row)), true); | |||||
| } | } | ||||
| } | } | ||||
| @@ -51692,7 +51720,7 @@ public: | |||||
| { | { | ||||
| if (! isSelected) | if (! isSelected) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, false); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | const int columnId = owner.getHeader().getColumnIdAtX (e.x); | ||||
| @@ -51729,7 +51757,7 @@ public: | |||||
| { | { | ||||
| if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled()) | if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled()) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, true); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | const int columnId = owner.getHeader().getColumnIdAtX (e.x); | ||||
| @@ -58728,7 +58756,7 @@ public: | |||||
| void mouseDown (const MouseEvent& e) | void mouseDown (const MouseEvent& e) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (index, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (index, e.mods, false); | |||||
| owner.sendMouseClickMessage (file, e); | owner.sendMouseClickMessage (file, e); | ||||
| } | } | ||||
| @@ -61350,24 +61378,20 @@ namespace ComponentBuilderHelpers | |||||
| if (topLevelComp != 0) | if (topLevelComp != 0) | ||||
| { | { | ||||
| const String compId (getStateId (state)); | |||||
| ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); | |||||
| if (compId.isEmpty() && state.getParent().isValid()) | |||||
| if (type == 0) | |||||
| { | { | ||||
| // ..handle the case where a child of the actual state node has changed. | // ..handle the case where a child of the actual state node has changed. | ||||
| updateComponent (builder, state.getParent()); | |||||
| if (state.getParent().isValid()) | |||||
| updateComponent (builder, state.getParent()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); | |||||
| Component* const changedComp = findComponentWithID (topLevelComp, getStateId (state)); | |||||
| if (type != 0) | |||||
| { | |||||
| Component* const changedComp = findComponentWithID (topLevelComp, compId); | |||||
| if (changedComp != 0) | |||||
| type->updateComponentFromState (changedComp, state); | |||||
| } | |||||
| if (changedComp != 0) | |||||
| type->updateComponentFromState (changedComp, state); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -62036,6 +62060,7 @@ MarkerList& MarkerList::operator= (const MarkerList& other) | |||||
| MarkerList::~MarkerList() | MarkerList::~MarkerList() | ||||
| { | { | ||||
| listeners.call (&MarkerList::Listener::markerListBeingDeleted, this); | |||||
| } | } | ||||
| bool MarkerList::operator== (const MarkerList& other) const throw() | bool MarkerList::operator== (const MarkerList& other) const throw() | ||||
| @@ -62129,7 +62154,21 @@ void MarkerList::removeMarker (const String& name) | |||||
| void MarkerList::markersHaveChanged() | void MarkerList::markersHaveChanged() | ||||
| { | { | ||||
| sendChangeMessage(); | |||||
| listeners.call (&MarkerList::Listener::markersChanged, this); | |||||
| } | |||||
| void MarkerList::Listener::markerListBeingDeleted (MarkerList* markerList) | |||||
| { | |||||
| } | |||||
| void MarkerList::addListener (Listener* listener) | |||||
| { | |||||
| listeners.add (listener); | |||||
| } | |||||
| void MarkerList::removeListener (Listener* listener) | |||||
| { | |||||
| listeners.remove (listener); | |||||
| } | } | ||||
| MarkerList::Marker::Marker (const Marker& other) | MarkerList::Marker::Marker (const Marker& other) | ||||
| @@ -79647,7 +79686,271 @@ namespace RelativeCoordinateHelpers | |||||
| } | } | ||||
| } | } | ||||
| class RelativeComponentPositioner : public Component::Positioner, | |||||
| public ComponentListener, | |||||
| public MarkerList::Listener, | |||||
| public Expression::EvaluationContext | |||||
| { | |||||
| public: | |||||
| RelativeComponentPositioner (Component& component_) | |||||
| : Component::Positioner (component_), registeredOk (false) | |||||
| { | |||||
| } | |||||
| ~RelativeComponentPositioner() | |||||
| { | |||||
| unregisterListeners(); | |||||
| } | |||||
| const Expression getSymbolValue (const String& objectName, const String& member) const | |||||
| { | |||||
| jassert (objectName.isNotEmpty()); | |||||
| if (member.isNotEmpty()) | |||||
| { | |||||
| const Component* comp = getSourceComponent (objectName); | |||||
| if (comp == 0) | |||||
| { | |||||
| if (objectName == RelativeCoordinate::Strings::parent) | |||||
| comp = getComponent().getParentComponent(); | |||||
| else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID()) | |||||
| comp = &getComponent(); | |||||
| } | |||||
| if (comp != 0) | |||||
| { | |||||
| if (member == RelativeCoordinate::Strings::left) return xToExpression (comp, 0); | |||||
| if (member == RelativeCoordinate::Strings::right) return xToExpression (comp, comp->getWidth()); | |||||
| if (member == RelativeCoordinate::Strings::top) return yToExpression (comp, 0); | |||||
| if (member == RelativeCoordinate::Strings::bottom) return yToExpression (comp, comp->getHeight()); | |||||
| } | |||||
| } | |||||
| for (int i = sourceMarkerLists.size(); --i >= 0;) | |||||
| { | |||||
| MarkerList* const markerList = sourceMarkerLists.getUnchecked(i); | |||||
| const MarkerList::Marker* const marker = markerList->getMarker (objectName); | |||||
| if (marker != 0) | |||||
| return marker->position.getExpression(); | |||||
| } | |||||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||||
| } | |||||
| void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void componentParentHierarchyChanged (Component& component) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void componentBeingDeleted (Component& component) | |||||
| { | |||||
| jassert (sourceComponents.contains (&component)); | |||||
| sourceComponents.removeValue (&component); | |||||
| } | |||||
| void markersChanged (MarkerList* markerList) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void markerListBeingDeleted (MarkerList* markerList) | |||||
| { | |||||
| jassert (sourceMarkerLists.contains (markerList)); | |||||
| sourceMarkerLists.removeValue (markerList); | |||||
| } | |||||
| void apply() | |||||
| { | |||||
| if (! registeredOk) | |||||
| { | |||||
| unregisterListeners(); | |||||
| registeredOk = registerCoordinates(); | |||||
| } | |||||
| applyToComponentBounds(); | |||||
| } | |||||
| protected: | |||||
| bool addCoordinate (const RelativeCoordinate& coord) | |||||
| { | |||||
| return registerListeners (coord.getExpression()); | |||||
| } | |||||
| virtual bool registerCoordinates() = 0; | |||||
| virtual void applyToComponentBounds() = 0; | |||||
| private: | |||||
| Array <Component*> sourceComponents; | |||||
| Array <MarkerList*> sourceMarkerLists; | |||||
| bool registeredOk; | |||||
| bool registerListeners (const Expression& e) | |||||
| { | |||||
| bool ok = true; | |||||
| if (e.getType() == Expression::symbolType) | |||||
| { | |||||
| String objectName, memberName; | |||||
| e.getSymbolParts (objectName, memberName); | |||||
| if (memberName.isNotEmpty()) | |||||
| ok = registerComponentEdge (objectName, memberName) && ok; | |||||
| else | |||||
| ok = registerMarker (objectName) && ok; | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = e.getNumInputs(); --i >= 0;) | |||||
| ok = registerListeners (e.getInput (i)) && ok; | |||||
| } | |||||
| return ok; | |||||
| } | |||||
| bool registerComponentEdge (const String& objectName, const String memberName) | |||||
| { | |||||
| Component* comp = findComponent (objectName); | |||||
| if (comp == 0) | |||||
| { | |||||
| if (objectName == RelativeCoordinate::Strings::parent) | |||||
| comp = getComponent().getParentComponent(); | |||||
| else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID()) | |||||
| comp = &getComponent(); | |||||
| } | |||||
| if (comp != 0) | |||||
| { | |||||
| if (comp != &getComponent()) | |||||
| registerComponentListener (comp); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| // The component we want doesn't exist, so watch the parent in case the hierarchy changes and it appears later.. | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| registerComponentListener (parent); | |||||
| else | |||||
| registerComponentListener (&getComponent()); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| bool registerMarker (const String markerName) | |||||
| { | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| { | |||||
| MarkerList* list = parent->getMarkers (true); | |||||
| if (list == 0 || list->getMarker (markerName) == 0) | |||||
| list = parent->getMarkers (false); | |||||
| if (list != 0 && list->getMarker (markerName) != 0) | |||||
| { | |||||
| registerMarkerListListener (list); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later.. | |||||
| registerMarkerListListener (parent->getMarkers (true)); | |||||
| registerMarkerListListener (parent->getMarkers (false)); | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void registerComponentListener (Component* const comp) | |||||
| { | |||||
| if (comp != 0 && ! sourceComponents.contains (comp)) | |||||
| { | |||||
| comp->addComponentListener (this); | |||||
| sourceComponents.add (comp); | |||||
| } | |||||
| } | |||||
| void registerMarkerListListener (MarkerList* const list) | |||||
| { | |||||
| if (list != 0 && ! sourceMarkerLists.contains (list)) | |||||
| { | |||||
| list->addListener (this); | |||||
| sourceMarkerLists.add (list); | |||||
| } | |||||
| } | |||||
| void unregisterListeners() | |||||
| { | |||||
| int i; | |||||
| for (i = sourceComponents.size(); --i >= 0;) | |||||
| sourceComponents.getUnchecked(i)->removeComponentListener (this); | |||||
| for (i = sourceMarkerLists.size(); --i >= 0;) | |||||
| sourceMarkerLists.getUnchecked(i)->removeListener (this); | |||||
| sourceComponents.clear(); | |||||
| sourceMarkerLists.clear(); | |||||
| } | |||||
| Component* findComponent (const String& componentID) const | |||||
| { | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| { | |||||
| for (int i = parent->getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = parent->getChildComponent(i); | |||||
| if (c->getComponentID() == componentID) | |||||
| return c; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| Component* getSourceComponent (const String& objectName) const | |||||
| { | |||||
| for (int i = sourceComponents.size(); --i >= 0;) | |||||
| { | |||||
| Component* const comp = sourceComponents.getUnchecked(i); | |||||
| if (comp->getComponentID() == objectName) | |||||
| return comp; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| const Expression xToExpression (const Component* const source, const int x) const | |||||
| { | |||||
| return Expression ((double) (getComponent().getLocalPoint (source, Point<int> (x, 0)).getX() + getComponent().getX())); | |||||
| } | |||||
| const Expression yToExpression (const Component* const source, const int y) const | |||||
| { | |||||
| return Expression ((double) (getComponent().getLocalPoint (source, Point<int> (0, y)).getY() + getComponent().getY())); | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeComponentPositioner); | |||||
| }; | |||||
| const String RelativeCoordinate::Strings::parent ("parent"); | const String RelativeCoordinate::Strings::parent ("parent"); | ||||
| const String RelativeCoordinate::Strings::this_ ("this"); | |||||
| const String RelativeCoordinate::Strings::left ("left"); | const String RelativeCoordinate::Strings::left ("left"); | ||||
| const String RelativeCoordinate::Strings::right ("right"); | const String RelativeCoordinate::Strings::right ("right"); | ||||
| const String RelativeCoordinate::Strings::top ("top"); | const String RelativeCoordinate::Strings::top ("top"); | ||||
| @@ -79898,7 +80201,7 @@ const Rectangle<float> RelativeRectangle::resolve (const Expression::EvaluationC | |||||
| const double t = top.resolve (context); | const double t = top.resolve (context); | ||||
| const double b = bottom.resolve (context); | const double b = bottom.resolve (context); | ||||
| return Rectangle<float> ((float) l, (float) t, (float) (r - l), (float) (b - t)); | |||||
| return Rectangle<float> ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t)); | |||||
| } | } | ||||
| void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* context) | void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* context) | ||||
| @@ -79909,6 +80212,11 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex | |||||
| bottom.moveToAbsolute (newPos.getBottom(), context); | bottom.moveToAbsolute (newPos.getBottom(), context); | ||||
| } | } | ||||
| bool RelativeRectangle::isDynamic() const | |||||
| { | |||||
| return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic(); | |||||
| } | |||||
| const String RelativeRectangle::toString() const | const String RelativeRectangle::toString() const | ||||
| { | { | ||||
| return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); | return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); | ||||
| @@ -79922,6 +80230,71 @@ void RelativeRectangle::renameSymbolIfUsed (const String& oldName, const String& | |||||
| bottom.renameSymbolIfUsed (oldName, newName); | bottom.renameSymbolIfUsed (oldName, newName); | ||||
| } | } | ||||
| class RelativeRectangleComponentPositioner : public RelativeComponentPositioner | |||||
| { | |||||
| public: | |||||
| RelativeRectangleComponentPositioner (Component& component_, const RelativeRectangle& rectangle_) | |||||
| : RelativeComponentPositioner (component_), | |||||
| rectangle (rectangle_) | |||||
| { | |||||
| } | |||||
| bool registerCoordinates() | |||||
| { | |||||
| bool ok = addCoordinate (rectangle.left); | |||||
| ok = addCoordinate (rectangle.right) && ok; | |||||
| ok = addCoordinate (rectangle.top) && ok; | |||||
| ok = addCoordinate (rectangle.bottom) && ok; | |||||
| return ok; | |||||
| } | |||||
| bool isUsingRectangle (const RelativeRectangle& other) const throw() | |||||
| { | |||||
| return rectangle == other; | |||||
| } | |||||
| void applyToComponentBounds() | |||||
| { | |||||
| for (int i = 4; --i >= 0;) | |||||
| { | |||||
| const Rectangle<int> newBounds (rectangle.resolve (this).getSmallestIntegerContainer()); | |||||
| if (newBounds == getComponent().getBounds()) | |||||
| return; | |||||
| getComponent().setBounds (newBounds); | |||||
| } | |||||
| jassertfalse; // must be a recursive reference! | |||||
| } | |||||
| private: | |||||
| const RelativeRectangle rectangle; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner); | |||||
| }; | |||||
| void RelativeRectangle::applyToComponent (Component& component) const | |||||
| { | |||||
| if (isDynamic()) | |||||
| { | |||||
| RelativeRectangleComponentPositioner* current = dynamic_cast <RelativeRectangleComponentPositioner*> (component.getPositioner()); | |||||
| if (current == 0 || ! current->isUsingRectangle (*this)) | |||||
| { | |||||
| RelativeRectangleComponentPositioner* p = new RelativeRectangleComponentPositioner (component, *this); | |||||
| component.setPositioner (p); | |||||
| p->apply(); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| component.setPositioner (0); | |||||
| component.setBounds (resolve (0).getSmallestIntegerContainer()); | |||||
| } | |||||
| } | |||||
| RelativePointPath::RelativePointPath() | RelativePointPath::RelativePointPath() | ||||
| : usesNonZeroWinding (true), | : usesNonZeroWinding (true), | ||||
| containsDynamicPoints (false) | containsDynamicPoints (false) | ||||
| @@ -85678,10 +86051,12 @@ class LowLevelGraphicsSoftwareRenderer::CachedGlyph | |||||
| { | { | ||||
| public: | public: | ||||
| CachedGlyph() : glyph (0), lastAccessCount (0) {} | CachedGlyph() : glyph (0), lastAccessCount (0) {} | ||||
| ~CachedGlyph() {} | |||||
| void draw (SavedState& state, const float x, const float y) const | |||||
| void draw (SavedState& state, float x, const float y) const | |||||
| { | { | ||||
| if (snapToIntegerCoordinate) | |||||
| x = std::floor (x + 0.5f); | |||||
| if (edgeTable != 0) | if (edgeTable != 0) | ||||
| state.fillEdgeTable (*edgeTable, x, roundToInt (y)); | state.fillEdgeTable (*edgeTable, x, roundToInt (y)); | ||||
| } | } | ||||
| @@ -85689,6 +86064,7 @@ public: | |||||
| void generate (const Font& newFont, const int glyphNumber) | void generate (const Font& newFont, const int glyphNumber) | ||||
| { | { | ||||
| font = newFont; | font = newFont; | ||||
| snapToIntegerCoordinate = newFont.getTypeface()->isHinted(); | |||||
| glyph = glyphNumber; | glyph = glyphNumber; | ||||
| edgeTable = 0; | edgeTable = 0; | ||||
| @@ -85709,8 +86085,9 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| int glyph, lastAccessCount; | |||||
| Font font; | Font font; | ||||
| int glyph, lastAccessCount; | |||||
| bool snapToIntegerCoordinate; | |||||
| private: | private: | ||||
| ScopedPointer <EdgeTable> edgeTable; | ScopedPointer <EdgeTable> edgeTable; | ||||
| @@ -85724,8 +86101,7 @@ public: | |||||
| GlyphCache() | GlyphCache() | ||||
| : accessCounter (0), hits (0), misses (0) | : accessCounter (0), hits (0), misses (0) | ||||
| { | { | ||||
| for (int i = 120; --i >= 0;) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| addNewGlyphSlots (120); | |||||
| } | } | ||||
| ~GlyphCache() | ~GlyphCache() | ||||
| @@ -85763,10 +86139,7 @@ public: | |||||
| if (hits + ++misses > (glyphs.size() << 4)) | if (hits + ++misses > (glyphs.size() << 4)) | ||||
| { | { | ||||
| if (misses * 2 > hits) | if (misses * 2 > hits) | ||||
| { | |||||
| for (int i = 32; --i >= 0;) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| } | |||||
| addNewGlyphSlots (32); | |||||
| hits = misses = 0; | hits = misses = 0; | ||||
| oldest = glyphs.getLast(); | oldest = glyphs.getLast(); | ||||
| @@ -85783,6 +86156,12 @@ private: | |||||
| OwnedArray <CachedGlyph> glyphs; | OwnedArray <CachedGlyph> glyphs; | ||||
| int accessCounter, hits, misses; | int accessCounter, hits, misses; | ||||
| void addNewGlyphSlots (int num) | |||||
| { | |||||
| while (--num >= 0) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache); | ||||
| }; | }; | ||||
| @@ -89314,15 +89693,119 @@ namespace FontValues | |||||
| String fallbackFont; | String fallbackFont; | ||||
| } | } | ||||
| Font::SharedFontInternal::SharedFontInternal (const String& typefaceName_, const float height_, const float horizontalScale_, | |||||
| const float kerning_, const float ascent_, const int styleFlags_, | |||||
| Typeface* const typeface_) throw() | |||||
| class TypefaceCache : public DeletedAtShutdown | |||||
| { | |||||
| public: | |||||
| TypefaceCache (int numToCache = 10) | |||||
| : counter (1) | |||||
| { | |||||
| while (--numToCache >= 0) | |||||
| faces.add (CachedFace()); | |||||
| } | |||||
| ~TypefaceCache() | |||||
| { | |||||
| clearSingletonInstance(); | |||||
| } | |||||
| juce_DeclareSingleton_SingleThreaded_Minimal (TypefaceCache) | |||||
| const Typeface::Ptr findTypefaceFor (const Font& font) | |||||
| { | |||||
| // (can't initialise defaultFace in the constructor or in getDefaultTypeface() because of recursion). | |||||
| if (defaultFace == 0) | |||||
| defaultFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (Font()); | |||||
| const int flags = font.getStyleFlags() & (Font::bold | Font::italic); | |||||
| const String faceName (font.getTypefaceName()); | |||||
| int i; | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| CachedFace& face = faces.getReference(i); | |||||
| if (face.flags == flags | |||||
| && face.typefaceName == faceName | |||||
| && face.typeface->isSuitableForFont (font)) | |||||
| { | |||||
| face.lastUsageCount = ++counter; | |||||
| return face.typeface; | |||||
| } | |||||
| } | |||||
| int replaceIndex = 0; | |||||
| int bestLastUsageCount = std::numeric_limits<int>::max(); | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| const int lu = faces.getReference(i).lastUsageCount; | |||||
| if (bestLastUsageCount > lu) | |||||
| { | |||||
| bestLastUsageCount = lu; | |||||
| replaceIndex = i; | |||||
| } | |||||
| } | |||||
| CachedFace& face = faces.getReference (replaceIndex); | |||||
| face.typefaceName = faceName; | |||||
| face.flags = flags; | |||||
| face.lastUsageCount = ++counter; | |||||
| face.typeface = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); | |||||
| jassert (face.typeface != 0); // the look and feel must return a typeface! | |||||
| return face.typeface; | |||||
| } | |||||
| const Typeface::Ptr getDefaultTypeface() const throw() | |||||
| { | |||||
| return defaultFace; | |||||
| } | |||||
| private: | |||||
| struct CachedFace | |||||
| { | |||||
| CachedFace() throw() | |||||
| : lastUsageCount (0), flags (-1) | |||||
| { | |||||
| } | |||||
| // Although it seems a bit wacky to store the name here, it's because it may be a | |||||
| // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name. | |||||
| // Since the typeface itself doesn't know that it may have this alias, the name under | |||||
| // which it was fetched needs to be stored separately. | |||||
| String typefaceName; | |||||
| int lastUsageCount, flags; | |||||
| Typeface::Ptr typeface; | |||||
| }; | |||||
| Array <CachedFace> faces; | |||||
| Typeface::Ptr defaultFace; | |||||
| int counter; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache); | |||||
| }; | |||||
| juce_ImplementSingleton_SingleThreaded (TypefaceCache) | |||||
| Font::SharedFontInternal::SharedFontInternal (const String& typefaceName_, const float height_, const int styleFlags_) throw() | |||||
| : typefaceName (typefaceName_), | : typefaceName (typefaceName_), | ||||
| height (height_), | height (height_), | ||||
| horizontalScale (horizontalScale_), | |||||
| kerning (kerning_), | |||||
| ascent (ascent_), | |||||
| horizontalScale (1.0f), | |||||
| kerning (0), | |||||
| ascent (0), | |||||
| styleFlags (styleFlags_), | styleFlags (styleFlags_), | ||||
| typeface (TypefaceCache::getInstance()->getDefaultTypeface()) | |||||
| { | |||||
| } | |||||
| Font::SharedFontInternal::SharedFontInternal (const Typeface::Ptr& typeface_) throw() | |||||
| : typefaceName (typeface_->getName()), | |||||
| height (FontValues::defaultFontHeight), | |||||
| horizontalScale (1.0f), | |||||
| kerning (0), | |||||
| ascent (0), | |||||
| styleFlags (Font::plain), | |||||
| typeface (typeface_) | typeface (typeface_) | ||||
| { | { | ||||
| } | } | ||||
| @@ -89338,23 +89821,32 @@ Font::SharedFontInternal::SharedFontInternal (const SharedFontInternal& other) t | |||||
| { | { | ||||
| } | } | ||||
| bool Font::SharedFontInternal::operator== (const SharedFontInternal& other) const throw() | |||||
| { | |||||
| return height == other.height | |||||
| && styleFlags == other.styleFlags | |||||
| && horizontalScale == other.horizontalScale | |||||
| && kerning == other.kerning | |||||
| && typefaceName == other.typefaceName; | |||||
| } | |||||
| Font::Font() | Font::Font() | ||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::defaultFontHeight, | |||||
| 1.0f, 0, 0, Font::plain, 0)) | |||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::defaultFontHeight, Font::plain)) | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const float fontHeight, const int styleFlags_) | Font::Font (const float fontHeight, const int styleFlags_) | ||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::limitFontHeight (fontHeight), | |||||
| 1.0f, 0, 0, styleFlags_, 0)) | |||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::limitFontHeight (fontHeight), styleFlags_)) | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const String& typefaceName_, | |||||
| const float fontHeight, | |||||
| const int styleFlags_) | |||||
| : font (new SharedFontInternal (typefaceName_, FontValues::limitFontHeight (fontHeight), | |||||
| 1.0f, 0, 0, styleFlags_, 0)) | |||||
| Font::Font (const String& typefaceName_, const float fontHeight, const int styleFlags_) | |||||
| : font (new SharedFontInternal (typefaceName_, FontValues::limitFontHeight (fontHeight), styleFlags_)) | |||||
| { | |||||
| } | |||||
| Font::Font (const Typeface::Ptr& typeface) | |||||
| : font (new SharedFontInternal (typeface)) | |||||
| { | { | ||||
| } | } | ||||
| @@ -89373,20 +89865,10 @@ Font::~Font() throw() | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const Typeface::Ptr& typeface) | |||||
| : font (new SharedFontInternal (typeface->getName(), FontValues::defaultFontHeight, | |||||
| 1.0f, 0, 0, Font::plain, typeface)) | |||||
| { | |||||
| } | |||||
| bool Font::operator== (const Font& other) const throw() | bool Font::operator== (const Font& other) const throw() | ||||
| { | { | ||||
| return font == other.font | return font == other.font | ||||
| || (font->height == other.font->height | |||||
| && font->styleFlags == other.font->styleFlags | |||||
| && font->horizontalScale == other.font->horizontalScale | |||||
| && font->kerning == other.font->kerning | |||||
| && font->typefaceName == other.font->typefaceName); | |||||
| || *font == *other.font; | |||||
| } | } | ||||
| bool Font::operator!= (const Font& other) const throw() | bool Font::operator!= (const Font& other) const throw() | ||||
| @@ -89659,87 +90141,6 @@ const Font Font::fromString (const String& fontDescription) | |||||
| return Font (name, height, flags); | return Font (name, height, flags); | ||||
| } | } | ||||
| class TypefaceCache : public DeletedAtShutdown | |||||
| { | |||||
| public: | |||||
| TypefaceCache (int numToCache = 10) | |||||
| : counter (1) | |||||
| { | |||||
| while (--numToCache >= 0) | |||||
| faces.add (new CachedFace()); | |||||
| } | |||||
| ~TypefaceCache() | |||||
| { | |||||
| clearSingletonInstance(); | |||||
| } | |||||
| juce_DeclareSingleton_SingleThreaded_Minimal (TypefaceCache) | |||||
| const Typeface::Ptr findTypefaceFor (const Font& font) | |||||
| { | |||||
| const int flags = font.getStyleFlags() & (Font::bold | Font::italic); | |||||
| const String faceName (font.getTypefaceName()); | |||||
| int i; | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| CachedFace* const face = faces.getUnchecked(i); | |||||
| if (face->flags == flags | |||||
| && face->typefaceName == faceName) | |||||
| { | |||||
| face->lastUsageCount = ++counter; | |||||
| return face->typeFace; | |||||
| } | |||||
| } | |||||
| int replaceIndex = 0; | |||||
| int bestLastUsageCount = std::numeric_limits<int>::max(); | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| const int lu = faces.getUnchecked(i)->lastUsageCount; | |||||
| if (bestLastUsageCount > lu) | |||||
| { | |||||
| bestLastUsageCount = lu; | |||||
| replaceIndex = i; | |||||
| } | |||||
| } | |||||
| CachedFace* const face = faces.getUnchecked (replaceIndex); | |||||
| face->typefaceName = faceName; | |||||
| face->flags = flags; | |||||
| face->lastUsageCount = ++counter; | |||||
| face->typeFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); | |||||
| jassert (face->typeFace != 0); // the look and feel must return a typeface! | |||||
| return face->typeFace; | |||||
| } | |||||
| private: | |||||
| struct CachedFace | |||||
| { | |||||
| CachedFace() throw() | |||||
| : lastUsageCount (0), flags (-1) | |||||
| { | |||||
| } | |||||
| String typefaceName; | |||||
| int lastUsageCount; | |||||
| int flags; | |||||
| Typeface::Ptr typeFace; | |||||
| }; | |||||
| int counter; | |||||
| OwnedArray <CachedFace> faces; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache); | |||||
| }; | |||||
| juce_ImplementSingleton_SingleThreaded (TypefaceCache) | |||||
| Typeface* Font::getTypeface() const | Typeface* Font::getTypeface() const | ||||
| { | { | ||||
| if (font->typeface == 0) | if (font->typeface == 0) | ||||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 3 | |||||
| #define JUCE_BUILDNUMBER 4 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -17892,9 +17892,12 @@ public: | |||||
| /** Returns the type of this expression. */ | /** Returns the type of this expression. */ | ||||
| Type getType() const throw(); | Type getType() const throw(); | ||||
| /** If this expression is a symbol, this returns its name. */ | |||||
| /** If this expression is a symbol, this returns its full name. */ | |||||
| const String getSymbol() const; | const String getSymbol() const; | ||||
| /** For a symbol that contains a dot, this returns the two */ | |||||
| void getSymbolParts (String& objectName, String& memberName) const; | |||||
| /** If this expression is a function, this returns its name. */ | /** If this expression is a function, this returns its name. */ | ||||
| const String getFunction() const; | const String getFunction() const; | ||||
| @@ -17936,7 +17939,7 @@ private: | |||||
| double overallTarget, Term* topLevelTerm) const; | double overallTarget, Term* topLevelTerm) const; | ||||
| virtual const ReferenceCountedObjectPtr<Term> negated(); | virtual const ReferenceCountedObjectPtr<Term> negated(); | ||||
| virtual Type getType() const throw() = 0; | virtual Type getType() const throw() = 0; | ||||
| virtual const String getSymbolName() const; | |||||
| virtual void getSymbolParts (String& objectName, String& memberName) const; | |||||
| virtual const String getFunctionName() const; | virtual const String getFunctionName() const; | ||||
| private: | private: | ||||
| @@ -23409,6 +23412,12 @@ public: | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| virtual ~Typeface(); | virtual ~Typeface(); | ||||
| /** Returns true if this typeface can be used to render the specified font. | |||||
| When called, the font will already have been checked to make sure that its name and | |||||
| style flags match the typeface. | |||||
| */ | |||||
| virtual bool isSuitableForFont (const Font&) const { return true; } | |||||
| /** Returns the ascent of the font, as a proportion of its height. | /** Returns the ascent of the font, as a proportion of its height. | ||||
| The height is considered to always be normalised as 1.0, so this will be a | The height is considered to always be normalised as 1.0, so this will be a | ||||
| value less that 1.0, indicating the proportion of the font that lies above | value less that 1.0, indicating the proportion of the font that lies above | ||||
| @@ -23445,6 +23454,9 @@ public: | |||||
| */ | */ | ||||
| virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; | virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; | ||||
| /** Returns true if the typeface uses hinting. */ | |||||
| virtual bool isHinted() const { return false; } | |||||
| protected: | protected: | ||||
| String name; | String name; | ||||
| @@ -23887,11 +23899,12 @@ private: | |||||
| class SharedFontInternal : public ReferenceCountedObject | class SharedFontInternal : public ReferenceCountedObject | ||||
| { | { | ||||
| public: | public: | ||||
| SharedFontInternal (const String& typefaceName, float height, float horizontalScale, | |||||
| float kerning, float ascent, int styleFlags, | |||||
| Typeface* typeface) throw(); | |||||
| SharedFontInternal (const String& typefaceName, float height, int styleFlags) throw(); | |||||
| SharedFontInternal (const Typeface::Ptr& typeface) throw(); | |||||
| SharedFontInternal (const SharedFontInternal& other) throw(); | SharedFontInternal (const SharedFontInternal& other) throw(); | ||||
| bool operator== (const SharedFontInternal&) const throw(); | |||||
| String typefaceName; | String typefaceName; | ||||
| float height, horizontalScale, kerning, ascent; | float height, horizontalScale, kerning, ascent; | ||||
| int styleFlags; | int styleFlags; | ||||
| @@ -28878,7 +28891,7 @@ public: | |||||
| the list iterator to stop cleanly if the component is deleted by a listener callback | the list iterator to stop cleanly if the component is deleted by a listener callback | ||||
| while the list is still being iterated. | while the list is still being iterated. | ||||
| */ | */ | ||||
| class BailOutChecker | |||||
| class JUCE_API BailOutChecker | |||||
| { | { | ||||
| public: | public: | ||||
| /** Creates a checker that watches one component. */ | /** Creates a checker that watches one component. */ | ||||
| @@ -28893,16 +28906,49 @@ public: | |||||
| JUCE_DECLARE_NON_COPYABLE (BailOutChecker); | JUCE_DECLARE_NON_COPYABLE (BailOutChecker); | ||||
| }; | }; | ||||
| #ifndef DOXYGEN | |||||
| /** This method is deprecated - use localPointToGlobal instead. */ | |||||
| const Point<int> relativePositionToGlobal (const Point<int>& relativePosition) const; | |||||
| /** | |||||
| Base class for objects that can be used to automatically position a component according to | |||||
| some kind of algorithm. | |||||
| /** This method is deprecated - use getLocalPoint instead. */ | |||||
| const Point<int> globalPositionToRelative (const Point<int>& screenPosition) const; | |||||
| The component class simply holds onto a reference to a Positioner, but doesn't actually do | |||||
| anything with it - all the functionality must be implemented by the positioner itself (e.g. | |||||
| it might choose to watch some kind of value and move the component when the value changes). | |||||
| */ | |||||
| class JUCE_API Positioner | |||||
| { | |||||
| public: | |||||
| /** Creates a Positioner which can control the specified component. */ | |||||
| explicit Positioner (Component& component) throw(); | |||||
| /** Destructor. */ | |||||
| virtual ~Positioner() {} | |||||
| /** Returns the component that this positioner controls. */ | |||||
| Component& getComponent() const throw() { return component; } | |||||
| private: | |||||
| Component& component; | |||||
| /** This method is deprecated - use getLocalPoint instead. */ | |||||
| const Point<int> relativePositionToOtherComponent (const Component* targetComponent, | |||||
| const Point<int>& positionRelativeToThis) const; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner); | |||||
| }; | |||||
| /** Returns the Positioner object that has been set for this component. | |||||
| @see setPositioner() | |||||
| */ | |||||
| Positioner* getPositioner() const throw(); | |||||
| /** Sets a new Positioner object for this component. | |||||
| If there's currently another positioner set, it will be deleted. The object that is passed in | |||||
| will be deleted automatically by this component when it's no longer required. Pass a null pointer | |||||
| to clear the current positioner. | |||||
| @see getPositioner() | |||||
| */ | |||||
| void setPositioner (Positioner* newPositioner); | |||||
| #ifndef DOXYGEN | |||||
| // These methods are deprecated - use localPointToGlobal, getLocalPoint, getLocalPoint, etc instead. | |||||
| JUCE_DEPRECATED (const Point<int> relativePositionToGlobal (const Point<int>&) const); | |||||
| JUCE_DEPRECATED (const Point<int> globalPositionToRelative (const Point<int>&) const); | |||||
| JUCE_DEPRECATED (const Point<int> relativePositionToOtherComponent (const Component*, const Point<int>&) const); | |||||
| #endif | #endif | ||||
| private: | private: | ||||
| @@ -28917,6 +28963,7 @@ private: | |||||
| String componentName, componentID; | String componentName, componentID; | ||||
| Component* parentComponent; | Component* parentComponent; | ||||
| Rectangle<int> bounds; | Rectangle<int> bounds; | ||||
| ScopedPointer <Positioner> positioner; | |||||
| ScopedPointer <AffineTransform> affineTransform; | ScopedPointer <AffineTransform> affineTransform; | ||||
| Array <Component*> childComponentList; | Array <Component*> childComponentList; | ||||
| LookAndFeel* lookAndFeel; | LookAndFeel* lookAndFeel; | ||||
| @@ -33468,6 +33515,9 @@ public: | |||||
| /** Returns true if the low res preview is fully generated. */ | /** Returns true if the low res preview is fully generated. */ | ||||
| bool isFullyLoaded() const throw(); | bool isFullyLoaded() const throw(); | ||||
| /** Returns the number of samples that have been set in the thumbnail. */ | |||||
| int64 getNumSamplesFinished() const throw(); | |||||
| /** Returns the highest level in the thumbnail. | /** Returns the highest level in the thumbnail. | ||||
| Note that because the thumb only stores low-resolution data, this isn't | Note that because the thumb only stores low-resolution data, this isn't | ||||
| an accurate representation of the highest value, it's only a rough approximation. | an accurate representation of the highest value, it's only a rough approximation. | ||||
| @@ -33477,8 +33527,10 @@ public: | |||||
| /** Returns the hash code that was set by setSource() or setReader(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| #ifndef DOXYGEN | |||||
| // (this is only public to avoid a VC6 bug) | // (this is only public to avoid a VC6 bug) | ||||
| class LevelDataSource; | class LevelDataSource; | ||||
| #endif | |||||
| private: | private: | ||||
| @@ -42737,7 +42789,8 @@ public: | |||||
| @see selectRow | @see selectRow | ||||
| */ | */ | ||||
| void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn, | void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn, | ||||
| const ModifierKeys& modifiers); | |||||
| const ModifierKeys& modifiers, | |||||
| bool isMouseUpEvent); | |||||
| /** Scrolls the list to a particular position. | /** Scrolls the list to a particular position. | ||||
| @@ -45291,6 +45344,8 @@ private: | |||||
| #ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | #ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | ||||
| #define __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | #define __JUCE_RELATIVECOORDINATE_JUCEHEADER__ | ||||
| class Component; | |||||
| /** | /** | ||||
| Expresses a coordinate as a dynamically evaluated expression. | Expresses a coordinate as a dynamically evaluated expression. | ||||
| @@ -45372,6 +45427,7 @@ public: | |||||
| struct Strings | struct Strings | ||||
| { | { | ||||
| static const String parent; /**< "parent" */ | static const String parent; /**< "parent" */ | ||||
| static const String this_; /**< "this" */ | |||||
| static const String left; /**< "left" */ | static const String left; /**< "left" */ | ||||
| static const String right; /**< "right" */ | static const String right; /**< "right" */ | ||||
| static const String top; /**< "top" */ | static const String top; /**< "top" */ | ||||
| @@ -45498,6 +45554,9 @@ public: | |||||
| */ | */ | ||||
| void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | ||||
| /** Returns true if this rectangle depends on any other coordinates for its position. */ | |||||
| bool isDynamic() const; | |||||
| /** Returns a string which represents this point. | /** Returns a string which represents this point. | ||||
| This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | ||||
| the string syntax used by the coordinates, see the RelativeCoordinate constructor notes. | the string syntax used by the coordinates, see the RelativeCoordinate constructor notes. | ||||
| @@ -45510,6 +45569,9 @@ public: | |||||
| */ | */ | ||||
| void renameSymbolIfUsed (const String& oldName, const String& newName); | void renameSymbolIfUsed (const String& oldName, const String& newName); | ||||
| /** */ | |||||
| void applyToComponent (Component& component) const; | |||||
| // The actual rectangle coords... | // The actual rectangle coords... | ||||
| RelativeCoordinate left, right, top, bottom; | RelativeCoordinate left, right, top, bottom; | ||||
| }; | }; | ||||
| @@ -53971,11 +54033,8 @@ private: | |||||
| This class is used to store sets of X and Y marker points in components. | This class is used to store sets of X and Y marker points in components. | ||||
| @see Component::getMarkers(). | @see Component::getMarkers(). | ||||
| The MarkerList is also a ChangeBroadcaster, so that listeners can register to receive | |||||
| a callback when a marker is moved, | |||||
| */ | */ | ||||
| class JUCE_API MarkerList : public ChangeBroadcaster | |||||
| class JUCE_API MarkerList | |||||
| { | { | ||||
| public: | public: | ||||
| @@ -54038,6 +54097,36 @@ public: | |||||
| /** Returns true if not all the markers in these two lists match exactly. */ | /** Returns true if not all the markers in these two lists match exactly. */ | ||||
| bool operator!= (const MarkerList& other) const throw(); | bool operator!= (const MarkerList& other) const throw(); | ||||
| /** | |||||
| A class for receiving events when changes are made to a MarkerList. | |||||
| You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener() | |||||
| method, and it will be called when markers are moved, added, or deleted. | |||||
| @see MarkerList::addListener, MarkerList::removeListener | |||||
| */ | |||||
| class JUCE_API Listener | |||||
| { | |||||
| public: | |||||
| /** Destructor. */ | |||||
| virtual ~Listener() {} | |||||
| /** Called when something in the given marker list changes. */ | |||||
| virtual void markersChanged (MarkerList* markerList) = 0; | |||||
| /** Called when the given marker list is being deleted. */ | |||||
| virtual void markerListBeingDeleted (MarkerList* markerList); | |||||
| }; | |||||
| /** Registers a listener that will be called when the markers are changed. */ | |||||
| void addListener (Listener* listener); | |||||
| /** Deregisters a previously-registered listener. */ | |||||
| void removeListener (Listener* listener); | |||||
| /** Synchronously calls markersChanged() on all the registered listeners. */ | |||||
| void markersHaveChanged(); | |||||
| /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ | /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ | ||||
| class ValueTreeWrapper | class ValueTreeWrapper | ||||
| { | { | ||||
| @@ -54065,7 +54154,7 @@ public: | |||||
| private: | private: | ||||
| OwnedArray<Marker> markers; | OwnedArray<Marker> markers; | ||||
| void markersHaveChanged(); | |||||
| ListenerList <Listener> listeners; | |||||
| JUCE_LEAK_DETECTOR (MarkerList); | JUCE_LEAK_DETECTOR (MarkerList); | ||||
| }; | }; | ||||
| @@ -177,6 +177,9 @@ public: | |||||
| /** Returns true if the low res preview is fully generated. */ | /** Returns true if the low res preview is fully generated. */ | ||||
| bool isFullyLoaded() const throw(); | bool isFullyLoaded() const throw(); | ||||
| /** Returns the number of samples that have been set in the thumbnail. */ | |||||
| int64 getNumSamplesFinished() const throw(); | |||||
| /** Returns the highest level in the thumbnail. | /** Returns the highest level in the thumbnail. | ||||
| Note that because the thumb only stores low-resolution data, this isn't | Note that because the thumb only stores low-resolution data, this isn't | ||||
| an accurate representation of the highest value, it's only a rough approximation. | an accurate representation of the highest value, it's only a rough approximation. | ||||
| @@ -186,8 +189,10 @@ public: | |||||
| /** Returns the hash code that was set by setSource() or setReader(). */ | /** Returns the hash code that was set by setSource() or setReader(). */ | ||||
| int64 getHashCode() const; | int64 getHashCode() const; | ||||
| #ifndef DOXYGEN | |||||
| // (this is only public to avoid a VC6 bug) | // (this is only public to avoid a VC6 bug) | ||||
| class LevelDataSource; | class LevelDataSource; | ||||
| #endif | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1,216 +1,216 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-10 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 "../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_NamedValueSet.h" | |||||
| #include "../text/juce_XmlElement.h" | |||||
| //============================================================================== | |||||
| NamedValueSet::NamedValue::NamedValue() throw() | |||||
| { | |||||
| } | |||||
| inline NamedValueSet::NamedValue::NamedValue (const Identifier& name_, const var& value_) | |||||
| : name (name_), value (value_) | |||||
| { | |||||
| } | |||||
| bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const throw() | |||||
| { | |||||
| return name == other.name && value == other.value; | |||||
| } | |||||
| //============================================================================== | |||||
| NamedValueSet::NamedValueSet() throw() | |||||
| { | |||||
| } | |||||
| NamedValueSet::NamedValueSet (const NamedValueSet& other) | |||||
| { | |||||
| values.addCopyOfList (other.values); | |||||
| } | |||||
| NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other) | |||||
| { | |||||
| clear(); | |||||
| values.addCopyOfList (other.values); | |||||
| return *this; | |||||
| } | |||||
| NamedValueSet::~NamedValueSet() | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| void NamedValueSet::clear() | |||||
| { | |||||
| values.deleteAll(); | |||||
| } | |||||
| bool NamedValueSet::operator== (const NamedValueSet& other) const | |||||
| { | |||||
| const NamedValue* i1 = values; | |||||
| const NamedValue* i2 = other.values; | |||||
| while (i1 != 0 && i2 != 0) | |||||
| { | |||||
| if (! (*i1 == *i2)) | |||||
| return false; | |||||
| i1 = i1->nextListItem; | |||||
| i2 = i2->nextListItem; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| bool NamedValueSet::operator!= (const NamedValueSet& other) const | |||||
| { | |||||
| return ! operator== (other); | |||||
| } | |||||
| int NamedValueSet::size() const throw() | |||||
| { | |||||
| return values.size(); | |||||
| } | |||||
| const var& NamedValueSet::operator[] (const Identifier& name) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| if (i->name == name) | |||||
| return i->value; | |||||
| return var::null; | |||||
| } | |||||
| const var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const | |||||
| { | |||||
| const var* v = getVarPointer (name); | |||||
| return v != 0 ? *v : defaultReturnValue; | |||||
| } | |||||
| var* NamedValueSet::getVarPointer (const Identifier& name) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| if (i->name == name) | |||||
| return &(i->value); | |||||
| return 0; | |||||
| } | |||||
| bool NamedValueSet::set (const Identifier& name, const var& newValue) | |||||
| { | |||||
| LinkedListPointer<NamedValue>* i = &values; | |||||
| while (i->get() != 0) | |||||
| { | |||||
| NamedValue* const v = i->get(); | |||||
| if (v->name == name) | |||||
| { | |||||
| if (v->value == newValue) | |||||
| return false; | |||||
| v->value = newValue; | |||||
| return true; | |||||
| } | |||||
| i = &(v->nextListItem); | |||||
| } | |||||
| i->insertNext (new NamedValue (name, newValue)); | |||||
| return true; | |||||
| } | |||||
| bool NamedValueSet::contains (const Identifier& name) const | |||||
| { | |||||
| return getVarPointer (name) != 0; | |||||
| } | |||||
| bool NamedValueSet::remove (const Identifier& name) | |||||
| { | |||||
| LinkedListPointer<NamedValue>* i = &values; | |||||
| for (;;) | |||||
| { | |||||
| NamedValue* const v = i->get(); | |||||
| if (v == 0) | |||||
| break; | |||||
| if (v->name == name) | |||||
| { | |||||
| delete i->removeNext(); | |||||
| return true; | |||||
| } | |||||
| i = &(v->nextListItem); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| const Identifier NamedValueSet::getName (const int index) const | |||||
| { | |||||
| const NamedValue* const v = values[index]; | |||||
| jassert (v != 0); | |||||
| return v->name; | |||||
| } | |||||
| const var NamedValueSet::getValueAt (const int index) const | |||||
| { | |||||
| const NamedValue* const v = values[index]; | |||||
| jassert (v != 0); | |||||
| return v->value; | |||||
| } | |||||
| void NamedValueSet::setFromXmlAttributes (const XmlElement& xml) | |||||
| { | |||||
| clear(); | |||||
| LinkedListPointer<NamedValue>::Appender appender (values); | |||||
| const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator.. | |||||
| for (int i = 0; i < numAtts; ++i) | |||||
| appender.append (new NamedValue (xml.getAttributeName (i), var (xml.getAttributeValue (i)))); | |||||
| } | |||||
| void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| { | |||||
| jassert (! i->value.isObject()); // DynamicObjects can't be stored as XML! | |||||
| xml.setAttribute (i->name.toString(), | |||||
| i->value.toString()); | |||||
| } | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-10 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 "../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_NamedValueSet.h" | |||||
| #include "../text/juce_XmlElement.h" | |||||
| //============================================================================== | |||||
| NamedValueSet::NamedValue::NamedValue() throw() | |||||
| { | |||||
| } | |||||
| inline NamedValueSet::NamedValue::NamedValue (const Identifier& name_, const var& value_) | |||||
| : name (name_), value (value_) | |||||
| { | |||||
| } | |||||
| bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const throw() | |||||
| { | |||||
| return name == other.name && value == other.value; | |||||
| } | |||||
| //============================================================================== | |||||
| NamedValueSet::NamedValueSet() throw() | |||||
| { | |||||
| } | |||||
| NamedValueSet::NamedValueSet (const NamedValueSet& other) | |||||
| { | |||||
| values.addCopyOfList (other.values); | |||||
| } | |||||
| NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other) | |||||
| { | |||||
| clear(); | |||||
| values.addCopyOfList (other.values); | |||||
| return *this; | |||||
| } | |||||
| NamedValueSet::~NamedValueSet() | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| void NamedValueSet::clear() | |||||
| { | |||||
| values.deleteAll(); | |||||
| } | |||||
| bool NamedValueSet::operator== (const NamedValueSet& other) const | |||||
| { | |||||
| const NamedValue* i1 = values; | |||||
| const NamedValue* i2 = other.values; | |||||
| while (i1 != 0 && i2 != 0) | |||||
| { | |||||
| if (! (*i1 == *i2)) | |||||
| return false; | |||||
| i1 = i1->nextListItem; | |||||
| i2 = i2->nextListItem; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| bool NamedValueSet::operator!= (const NamedValueSet& other) const | |||||
| { | |||||
| return ! operator== (other); | |||||
| } | |||||
| int NamedValueSet::size() const throw() | |||||
| { | |||||
| return values.size(); | |||||
| } | |||||
| const var& NamedValueSet::operator[] (const Identifier& name) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| if (i->name == name) | |||||
| return i->value; | |||||
| return var::null; | |||||
| } | |||||
| const var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const | |||||
| { | |||||
| const var* v = getVarPointer (name); | |||||
| return v != 0 ? *v : defaultReturnValue; | |||||
| } | |||||
| var* NamedValueSet::getVarPointer (const Identifier& name) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| if (i->name == name) | |||||
| return &(i->value); | |||||
| return 0; | |||||
| } | |||||
| bool NamedValueSet::set (const Identifier& name, const var& newValue) | |||||
| { | |||||
| LinkedListPointer<NamedValue>* i = &values; | |||||
| while (i->get() != 0) | |||||
| { | |||||
| NamedValue* const v = i->get(); | |||||
| if (v->name == name) | |||||
| { | |||||
| if (v->value == newValue) | |||||
| return false; | |||||
| v->value = newValue; | |||||
| return true; | |||||
| } | |||||
| i = &(v->nextListItem); | |||||
| } | |||||
| i->insertNext (new NamedValue (name, newValue)); | |||||
| return true; | |||||
| } | |||||
| bool NamedValueSet::contains (const Identifier& name) const | |||||
| { | |||||
| return getVarPointer (name) != 0; | |||||
| } | |||||
| bool NamedValueSet::remove (const Identifier& name) | |||||
| { | |||||
| LinkedListPointer<NamedValue>* i = &values; | |||||
| for (;;) | |||||
| { | |||||
| NamedValue* const v = i->get(); | |||||
| if (v == 0) | |||||
| break; | |||||
| if (v->name == name) | |||||
| { | |||||
| delete i->removeNext(); | |||||
| return true; | |||||
| } | |||||
| i = &(v->nextListItem); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| const Identifier NamedValueSet::getName (const int index) const | |||||
| { | |||||
| const NamedValue* const v = values[index]; | |||||
| jassert (v != 0); | |||||
| return v->name; | |||||
| } | |||||
| const var NamedValueSet::getValueAt (const int index) const | |||||
| { | |||||
| const NamedValue* const v = values[index]; | |||||
| jassert (v != 0); | |||||
| return v->value; | |||||
| } | |||||
| void NamedValueSet::setFromXmlAttributes (const XmlElement& xml) | |||||
| { | |||||
| clear(); | |||||
| LinkedListPointer<NamedValue>::Appender appender (values); | |||||
| const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator.. | |||||
| for (int i = 0; i < numAtts; ++i) | |||||
| appender.append (new NamedValue (xml.getAttributeName (i), var (xml.getAttributeValue (i)))); | |||||
| } | |||||
| void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const | |||||
| { | |||||
| for (NamedValue* i = values; i != 0; i = i->nextListItem) | |||||
| { | |||||
| jassert (! i->value.isObject()); // DynamicObjects can't be stored as XML! | |||||
| xml.setAttribute (i->name.toString(), | |||||
| i->value.toString()); | |||||
| } | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 3 | |||||
| #define JUCE_BUILDNUMBER 4 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -80,7 +80,7 @@ public: | |||||
| { | { | ||||
| if (! selected) | if (! selected) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, false); | |||||
| if (owner.getModel() != 0) | if (owner.getModel() != 0) | ||||
| owner.getModel()->listBoxItemClicked (row, e); | owner.getModel()->listBoxItemClicked (row, e); | ||||
| @@ -96,7 +96,7 @@ public: | |||||
| { | { | ||||
| if (isEnabled() && selectRowOnMouseUp && ! isDragging) | if (isEnabled() && selectRowOnMouseUp && ! isDragging) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, true); | |||||
| if (owner.getModel() != 0) | if (owner.getModel() != 0) | ||||
| owner.getModel()->listBoxItemClicked (row, e); | owner.getModel()->listBoxItemClicked (row, e); | ||||
| @@ -571,7 +571,8 @@ void ListBox::deselectAllRows() | |||||
| } | } | ||||
| void ListBox::selectRowsBasedOnModifierKeys (const int row, | void ListBox::selectRowsBasedOnModifierKeys (const int row, | ||||
| const ModifierKeys& mods) | |||||
| const ModifierKeys& mods, | |||||
| const bool isMouseUpEvent) | |||||
| { | { | ||||
| if (multipleSelection && mods.isCommandDown()) | if (multipleSelection && mods.isCommandDown()) | ||||
| { | { | ||||
| @@ -583,7 +584,7 @@ void ListBox::selectRowsBasedOnModifierKeys (const int row, | |||||
| } | } | ||||
| else if ((! mods.isPopupMenu()) || ! isRowSelected (row)) | else if ((! mods.isPopupMenu()) || ! isRowSelected (row)) | ||||
| { | { | ||||
| selectRowInternal (row, false, ! (multipleSelection && isRowSelected (row)), true); | |||||
| selectRowInternal (row, false, ! (multipleSelection && (! isMouseUpEvent) && isRowSelected (row)), true); | |||||
| } | } | ||||
| } | } | ||||
| @@ -330,7 +330,8 @@ public: | |||||
| @see selectRow | @see selectRow | ||||
| */ | */ | ||||
| void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn, | void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn, | ||||
| const ModifierKeys& modifiers); | |||||
| const ModifierKeys& modifiers, | |||||
| bool isMouseUpEvent); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Scrolls the list to a particular position. | /** Scrolls the list to a particular position. | ||||
| @@ -146,7 +146,7 @@ public: | |||||
| { | { | ||||
| if (! isSelected) | if (! isSelected) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, false); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | const int columnId = owner.getHeader().getColumnIdAtX (e.x); | ||||
| @@ -183,7 +183,7 @@ public: | |||||
| { | { | ||||
| if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled()) | if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled()) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (row, e.mods, true); | |||||
| const int columnId = owner.getHeader().getColumnIdAtX (e.x); | const int columnId = owner.getHeader().getColumnIdAtX (e.x); | ||||
| @@ -110,7 +110,7 @@ public: | |||||
| void mouseDown (const MouseEvent& e) | void mouseDown (const MouseEvent& e) | ||||
| { | { | ||||
| owner.selectRowsBasedOnModifierKeys (index, e.mods); | |||||
| owner.selectRowsBasedOnModifierKeys (index, e.mods, false); | |||||
| owner.sendMouseClickMessage (file, e); | owner.sendMouseClickMessage (file, e); | ||||
| } | } | ||||
| @@ -2055,6 +2055,24 @@ MarkerList* Component::getMarkers (bool /*xAxis*/) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| //============================================================================== | |||||
| Component::Positioner::Positioner (Component& component_) throw() | |||||
| : component (component_) | |||||
| { | |||||
| } | |||||
| Component::Positioner* Component::getPositioner() const throw() | |||||
| { | |||||
| return positioner; | |||||
| } | |||||
| void Component::setPositioner (Positioner* newPositioner) | |||||
| { | |||||
| // You can only assign a positioner to the component that it was created for! | |||||
| jassert (newPositioner == 0 || this == &(newPositioner->getComponent())); | |||||
| positioner = newPositioner; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| const Rectangle<int> Component::getLocalBounds() const throw() | const Rectangle<int> Component::getLocalBounds() const throw() | ||||
| { | { | ||||
| @@ -2093,7 +2093,7 @@ public: | |||||
| the list iterator to stop cleanly if the component is deleted by a listener callback | the list iterator to stop cleanly if the component is deleted by a listener callback | ||||
| while the list is still being iterated. | while the list is still being iterated. | ||||
| */ | */ | ||||
| class BailOutChecker | |||||
| class JUCE_API BailOutChecker | |||||
| { | { | ||||
| public: | public: | ||||
| /** Creates a checker that watches one component. */ | /** Creates a checker that watches one component. */ | ||||
| @@ -2109,16 +2109,50 @@ public: | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| #ifndef DOXYGEN | |||||
| /** This method is deprecated - use localPointToGlobal instead. */ | |||||
| const Point<int> relativePositionToGlobal (const Point<int>& relativePosition) const; | |||||
| /** | |||||
| Base class for objects that can be used to automatically position a component according to | |||||
| some kind of algorithm. | |||||
| The component class simply holds onto a reference to a Positioner, but doesn't actually do | |||||
| anything with it - all the functionality must be implemented by the positioner itself (e.g. | |||||
| it might choose to watch some kind of value and move the component when the value changes). | |||||
| */ | |||||
| class JUCE_API Positioner | |||||
| { | |||||
| public: | |||||
| /** Creates a Positioner which can control the specified component. */ | |||||
| explicit Positioner (Component& component) throw(); | |||||
| /** Destructor. */ | |||||
| virtual ~Positioner() {} | |||||
| /** Returns the component that this positioner controls. */ | |||||
| Component& getComponent() const throw() { return component; } | |||||
| /** This method is deprecated - use getLocalPoint instead. */ | |||||
| const Point<int> globalPositionToRelative (const Point<int>& screenPosition) const; | |||||
| private: | |||||
| Component& component; | |||||
| /** This method is deprecated - use getLocalPoint instead. */ | |||||
| const Point<int> relativePositionToOtherComponent (const Component* targetComponent, | |||||
| const Point<int>& positionRelativeToThis) const; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner); | |||||
| }; | |||||
| /** Returns the Positioner object that has been set for this component. | |||||
| @see setPositioner() | |||||
| */ | |||||
| Positioner* getPositioner() const throw(); | |||||
| /** Sets a new Positioner object for this component. | |||||
| If there's currently another positioner set, it will be deleted. The object that is passed in | |||||
| will be deleted automatically by this component when it's no longer required. Pass a null pointer | |||||
| to clear the current positioner. | |||||
| @see getPositioner() | |||||
| */ | |||||
| void setPositioner (Positioner* newPositioner); | |||||
| //============================================================================== | |||||
| #ifndef DOXYGEN | |||||
| // These methods are deprecated - use localPointToGlobal, getLocalPoint, getLocalPoint, etc instead. | |||||
| JUCE_DEPRECATED (const Point<int> relativePositionToGlobal (const Point<int>&) const); | |||||
| JUCE_DEPRECATED (const Point<int> globalPositionToRelative (const Point<int>&) const); | |||||
| JUCE_DEPRECATED (const Point<int> relativePositionToOtherComponent (const Component*, const Point<int>&) const); | |||||
| #endif | #endif | ||||
| private: | private: | ||||
| @@ -2134,6 +2168,7 @@ private: | |||||
| String componentName, componentID; | String componentName, componentID; | ||||
| Component* parentComponent; | Component* parentComponent; | ||||
| Rectangle<int> bounds; | Rectangle<int> bounds; | ||||
| ScopedPointer <Positioner> positioner; | |||||
| ScopedPointer <AffineTransform> affineTransform; | ScopedPointer <AffineTransform> affineTransform; | ||||
| Array <Component*> childComponentList; | Array <Component*> childComponentList; | ||||
| LookAndFeel* lookAndFeel; | LookAndFeel* lookAndFeel; | ||||
| @@ -85,24 +85,20 @@ namespace ComponentBuilderHelpers | |||||
| if (topLevelComp != 0) | if (topLevelComp != 0) | ||||
| { | { | ||||
| const String compId (getStateId (state)); | |||||
| ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); | |||||
| if (compId.isEmpty() && state.getParent().isValid()) | |||||
| if (type == 0) | |||||
| { | { | ||||
| // ..handle the case where a child of the actual state node has changed. | // ..handle the case where a child of the actual state node has changed. | ||||
| updateComponent (builder, state.getParent()); | |||||
| if (state.getParent().isValid()) | |||||
| updateComponent (builder, state.getParent()); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| ComponentBuilder::TypeHandler* const type = builder.getHandlerForState (state); | |||||
| Component* const changedComp = findComponentWithID (topLevelComp, getStateId (state)); | |||||
| if (type != 0) | |||||
| { | |||||
| Component* const changedComp = findComponentWithID (topLevelComp, compId); | |||||
| if (changedComp != 0) | |||||
| type->updateComponentFromState (changedComp, state); | |||||
| } | |||||
| if (changedComp != 0) | |||||
| type->updateComponentFromState (changedComp, state); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -54,6 +54,7 @@ MarkerList& MarkerList::operator= (const MarkerList& other) | |||||
| MarkerList::~MarkerList() | MarkerList::~MarkerList() | ||||
| { | { | ||||
| listeners.call (&MarkerList::Listener::markerListBeingDeleted, this); | |||||
| } | } | ||||
| bool MarkerList::operator== (const MarkerList& other) const throw() | bool MarkerList::operator== (const MarkerList& other) const throw() | ||||
| @@ -148,7 +149,21 @@ void MarkerList::removeMarker (const String& name) | |||||
| void MarkerList::markersHaveChanged() | void MarkerList::markersHaveChanged() | ||||
| { | { | ||||
| sendChangeMessage(); | |||||
| listeners.call (&MarkerList::Listener::markersChanged, this); | |||||
| } | |||||
| void MarkerList::Listener::markerListBeingDeleted (MarkerList* markerList) | |||||
| { | |||||
| } | |||||
| void MarkerList::addListener (Listener* listener) | |||||
| { | |||||
| listeners.add (listener); | |||||
| } | |||||
| void MarkerList::removeListener (Listener* listener) | |||||
| { | |||||
| listeners.remove (listener); | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -36,11 +36,8 @@ | |||||
| This class is used to store sets of X and Y marker points in components. | This class is used to store sets of X and Y marker points in components. | ||||
| @see Component::getMarkers(). | @see Component::getMarkers(). | ||||
| The MarkerList is also a ChangeBroadcaster, so that listeners can register to receive | |||||
| a callback when a marker is moved, | |||||
| */ | */ | ||||
| class JUCE_API MarkerList : public ChangeBroadcaster | |||||
| class JUCE_API MarkerList | |||||
| { | { | ||||
| public: | public: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -105,6 +102,37 @@ public: | |||||
| /** Returns true if not all the markers in these two lists match exactly. */ | /** Returns true if not all the markers in these two lists match exactly. */ | ||||
| bool operator!= (const MarkerList& other) const throw(); | bool operator!= (const MarkerList& other) const throw(); | ||||
| //============================================================================== | |||||
| /** | |||||
| A class for receiving events when changes are made to a MarkerList. | |||||
| You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener() | |||||
| method, and it will be called when markers are moved, added, or deleted. | |||||
| @see MarkerList::addListener, MarkerList::removeListener | |||||
| */ | |||||
| class JUCE_API Listener | |||||
| { | |||||
| public: | |||||
| /** Destructor. */ | |||||
| virtual ~Listener() {} | |||||
| /** Called when something in the given marker list changes. */ | |||||
| virtual void markersChanged (MarkerList* markerList) = 0; | |||||
| /** Called when the given marker list is being deleted. */ | |||||
| virtual void markerListBeingDeleted (MarkerList* markerList); | |||||
| }; | |||||
| /** Registers a listener that will be called when the markers are changed. */ | |||||
| void addListener (Listener* listener); | |||||
| /** Deregisters a previously-registered listener. */ | |||||
| void removeListener (Listener* listener); | |||||
| /** Synchronously calls markersChanged() on all the registered listeners. */ | |||||
| void markersHaveChanged(); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ | /** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */ | ||||
| class ValueTreeWrapper | class ValueTreeWrapper | ||||
| @@ -133,7 +161,7 @@ public: | |||||
| private: | private: | ||||
| //============================================================================== | //============================================================================== | ||||
| OwnedArray<Marker> markers; | OwnedArray<Marker> markers; | ||||
| void markersHaveChanged(); | |||||
| ListenerList <Listener> listeners; | |||||
| JUCE_LEAK_DETECTOR (MarkerList); | JUCE_LEAK_DETECTOR (MarkerList); | ||||
| }; | }; | ||||
| @@ -2394,10 +2394,12 @@ class LowLevelGraphicsSoftwareRenderer::CachedGlyph | |||||
| { | { | ||||
| public: | public: | ||||
| CachedGlyph() : glyph (0), lastAccessCount (0) {} | CachedGlyph() : glyph (0), lastAccessCount (0) {} | ||||
| ~CachedGlyph() {} | |||||
| void draw (SavedState& state, const float x, const float y) const | |||||
| void draw (SavedState& state, float x, const float y) const | |||||
| { | { | ||||
| if (snapToIntegerCoordinate) | |||||
| x = std::floor (x + 0.5f); | |||||
| if (edgeTable != 0) | if (edgeTable != 0) | ||||
| state.fillEdgeTable (*edgeTable, x, roundToInt (y)); | state.fillEdgeTable (*edgeTable, x, roundToInt (y)); | ||||
| } | } | ||||
| @@ -2405,6 +2407,7 @@ public: | |||||
| void generate (const Font& newFont, const int glyphNumber) | void generate (const Font& newFont, const int glyphNumber) | ||||
| { | { | ||||
| font = newFont; | font = newFont; | ||||
| snapToIntegerCoordinate = newFont.getTypeface()->isHinted(); | |||||
| glyph = glyphNumber; | glyph = glyphNumber; | ||||
| edgeTable = 0; | edgeTable = 0; | ||||
| @@ -2425,8 +2428,9 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| int glyph, lastAccessCount; | |||||
| Font font; | Font font; | ||||
| int glyph, lastAccessCount; | |||||
| bool snapToIntegerCoordinate; | |||||
| private: | private: | ||||
| ScopedPointer <EdgeTable> edgeTable; | ScopedPointer <EdgeTable> edgeTable; | ||||
| @@ -2441,8 +2445,7 @@ public: | |||||
| GlyphCache() | GlyphCache() | ||||
| : accessCounter (0), hits (0), misses (0) | : accessCounter (0), hits (0), misses (0) | ||||
| { | { | ||||
| for (int i = 120; --i >= 0;) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| addNewGlyphSlots (120); | |||||
| } | } | ||||
| ~GlyphCache() | ~GlyphCache() | ||||
| @@ -2481,10 +2484,7 @@ public: | |||||
| if (hits + ++misses > (glyphs.size() << 4)) | if (hits + ++misses > (glyphs.size() << 4)) | ||||
| { | { | ||||
| if (misses * 2 > hits) | if (misses * 2 > hits) | ||||
| { | |||||
| for (int i = 32; --i >= 0;) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| } | |||||
| addNewGlyphSlots (32); | |||||
| hits = misses = 0; | hits = misses = 0; | ||||
| oldest = glyphs.getLast(); | oldest = glyphs.getLast(); | ||||
| @@ -2501,6 +2501,12 @@ private: | |||||
| OwnedArray <CachedGlyph> glyphs; | OwnedArray <CachedGlyph> glyphs; | ||||
| int accessCounter, hits, misses; | int accessCounter, hits, misses; | ||||
| void addNewGlyphSlots (int num) | |||||
| { | |||||
| while (--num >= 0) | |||||
| glyphs.add (new CachedGlyph()); | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache); | ||||
| }; | }; | ||||
| @@ -48,15 +48,121 @@ namespace FontValues | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| Font::SharedFontInternal::SharedFontInternal (const String& typefaceName_, const float height_, const float horizontalScale_, | |||||
| const float kerning_, const float ascent_, const int styleFlags_, | |||||
| Typeface* const typeface_) throw() | |||||
| class TypefaceCache : public DeletedAtShutdown | |||||
| { | |||||
| public: | |||||
| TypefaceCache (int numToCache = 10) | |||||
| : counter (1) | |||||
| { | |||||
| while (--numToCache >= 0) | |||||
| faces.add (CachedFace()); | |||||
| } | |||||
| ~TypefaceCache() | |||||
| { | |||||
| clearSingletonInstance(); | |||||
| } | |||||
| juce_DeclareSingleton_SingleThreaded_Minimal (TypefaceCache) | |||||
| const Typeface::Ptr findTypefaceFor (const Font& font) | |||||
| { | |||||
| // (can't initialise defaultFace in the constructor or in getDefaultTypeface() because of recursion). | |||||
| if (defaultFace == 0) | |||||
| defaultFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (Font()); | |||||
| const int flags = font.getStyleFlags() & (Font::bold | Font::italic); | |||||
| const String faceName (font.getTypefaceName()); | |||||
| int i; | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| CachedFace& face = faces.getReference(i); | |||||
| if (face.flags == flags | |||||
| && face.typefaceName == faceName | |||||
| && face.typeface->isSuitableForFont (font)) | |||||
| { | |||||
| face.lastUsageCount = ++counter; | |||||
| return face.typeface; | |||||
| } | |||||
| } | |||||
| int replaceIndex = 0; | |||||
| int bestLastUsageCount = std::numeric_limits<int>::max(); | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| const int lu = faces.getReference(i).lastUsageCount; | |||||
| if (bestLastUsageCount > lu) | |||||
| { | |||||
| bestLastUsageCount = lu; | |||||
| replaceIndex = i; | |||||
| } | |||||
| } | |||||
| CachedFace& face = faces.getReference (replaceIndex); | |||||
| face.typefaceName = faceName; | |||||
| face.flags = flags; | |||||
| face.lastUsageCount = ++counter; | |||||
| face.typeface = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); | |||||
| jassert (face.typeface != 0); // the look and feel must return a typeface! | |||||
| return face.typeface; | |||||
| } | |||||
| const Typeface::Ptr getDefaultTypeface() const throw() | |||||
| { | |||||
| return defaultFace; | |||||
| } | |||||
| private: | |||||
| struct CachedFace | |||||
| { | |||||
| CachedFace() throw() | |||||
| : lastUsageCount (0), flags (-1) | |||||
| { | |||||
| } | |||||
| // Although it seems a bit wacky to store the name here, it's because it may be a | |||||
| // placeholder rather than a real one, e.g. "<Sans-Serif>" vs the actual typeface name. | |||||
| // Since the typeface itself doesn't know that it may have this alias, the name under | |||||
| // which it was fetched needs to be stored separately. | |||||
| String typefaceName; | |||||
| int lastUsageCount, flags; | |||||
| Typeface::Ptr typeface; | |||||
| }; | |||||
| Array <CachedFace> faces; | |||||
| Typeface::Ptr defaultFace; | |||||
| int counter; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache); | |||||
| }; | |||||
| juce_ImplementSingleton_SingleThreaded (TypefaceCache) | |||||
| //============================================================================== | |||||
| Font::SharedFontInternal::SharedFontInternal (const String& typefaceName_, const float height_, const int styleFlags_) throw() | |||||
| : typefaceName (typefaceName_), | : typefaceName (typefaceName_), | ||||
| height (height_), | height (height_), | ||||
| horizontalScale (horizontalScale_), | |||||
| kerning (kerning_), | |||||
| ascent (ascent_), | |||||
| horizontalScale (1.0f), | |||||
| kerning (0), | |||||
| ascent (0), | |||||
| styleFlags (styleFlags_), | styleFlags (styleFlags_), | ||||
| typeface (TypefaceCache::getInstance()->getDefaultTypeface()) | |||||
| { | |||||
| } | |||||
| Font::SharedFontInternal::SharedFontInternal (const Typeface::Ptr& typeface_) throw() | |||||
| : typefaceName (typeface_->getName()), | |||||
| height (FontValues::defaultFontHeight), | |||||
| horizontalScale (1.0f), | |||||
| kerning (0), | |||||
| ascent (0), | |||||
| styleFlags (Font::plain), | |||||
| typeface (typeface_) | typeface (typeface_) | ||||
| { | { | ||||
| } | } | ||||
| @@ -72,25 +178,33 @@ Font::SharedFontInternal::SharedFontInternal (const SharedFontInternal& other) t | |||||
| { | { | ||||
| } | } | ||||
| bool Font::SharedFontInternal::operator== (const SharedFontInternal& other) const throw() | |||||
| { | |||||
| return height == other.height | |||||
| && styleFlags == other.styleFlags | |||||
| && horizontalScale == other.horizontalScale | |||||
| && kerning == other.kerning | |||||
| && typefaceName == other.typefaceName; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| Font::Font() | Font::Font() | ||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::defaultFontHeight, | |||||
| 1.0f, 0, 0, Font::plain, 0)) | |||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::defaultFontHeight, Font::plain)) | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const float fontHeight, const int styleFlags_) | Font::Font (const float fontHeight, const int styleFlags_) | ||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::limitFontHeight (fontHeight), | |||||
| 1.0f, 0, 0, styleFlags_, 0)) | |||||
| : font (new SharedFontInternal (getDefaultSansSerifFontName(), FontValues::limitFontHeight (fontHeight), styleFlags_)) | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const String& typefaceName_, | |||||
| const float fontHeight, | |||||
| const int styleFlags_) | |||||
| : font (new SharedFontInternal (typefaceName_, FontValues::limitFontHeight (fontHeight), | |||||
| 1.0f, 0, 0, styleFlags_, 0)) | |||||
| Font::Font (const String& typefaceName_, const float fontHeight, const int styleFlags_) | |||||
| : font (new SharedFontInternal (typefaceName_, FontValues::limitFontHeight (fontHeight), styleFlags_)) | |||||
| { | |||||
| } | |||||
| Font::Font (const Typeface::Ptr& typeface) | |||||
| : font (new SharedFontInternal (typeface)) | |||||
| { | { | ||||
| } | } | ||||
| @@ -109,20 +223,10 @@ Font::~Font() throw() | |||||
| { | { | ||||
| } | } | ||||
| Font::Font (const Typeface::Ptr& typeface) | |||||
| : font (new SharedFontInternal (typeface->getName(), FontValues::defaultFontHeight, | |||||
| 1.0f, 0, 0, Font::plain, typeface)) | |||||
| { | |||||
| } | |||||
| bool Font::operator== (const Font& other) const throw() | bool Font::operator== (const Font& other) const throw() | ||||
| { | { | ||||
| return font == other.font | return font == other.font | ||||
| || (font->height == other.font->height | |||||
| && font->styleFlags == other.font->styleFlags | |||||
| && font->horizontalScale == other.font->horizontalScale | |||||
| && font->kerning == other.font->kerning | |||||
| && font->typefaceName == other.font->typefaceName); | |||||
| || *font == *other.font; | |||||
| } | } | ||||
| bool Font::operator!= (const Font& other) const throw() | bool Font::operator!= (const Font& other) const throw() | ||||
| @@ -400,88 +504,6 @@ const Font Font::fromString (const String& fontDescription) | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| class TypefaceCache : public DeletedAtShutdown | |||||
| { | |||||
| public: | |||||
| TypefaceCache (int numToCache = 10) | |||||
| : counter (1) | |||||
| { | |||||
| while (--numToCache >= 0) | |||||
| faces.add (new CachedFace()); | |||||
| } | |||||
| ~TypefaceCache() | |||||
| { | |||||
| clearSingletonInstance(); | |||||
| } | |||||
| juce_DeclareSingleton_SingleThreaded_Minimal (TypefaceCache) | |||||
| const Typeface::Ptr findTypefaceFor (const Font& font) | |||||
| { | |||||
| const int flags = font.getStyleFlags() & (Font::bold | Font::italic); | |||||
| const String faceName (font.getTypefaceName()); | |||||
| int i; | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| CachedFace* const face = faces.getUnchecked(i); | |||||
| if (face->flags == flags | |||||
| && face->typefaceName == faceName) | |||||
| { | |||||
| face->lastUsageCount = ++counter; | |||||
| return face->typeFace; | |||||
| } | |||||
| } | |||||
| int replaceIndex = 0; | |||||
| int bestLastUsageCount = std::numeric_limits<int>::max(); | |||||
| for (i = faces.size(); --i >= 0;) | |||||
| { | |||||
| const int lu = faces.getUnchecked(i)->lastUsageCount; | |||||
| if (bestLastUsageCount > lu) | |||||
| { | |||||
| bestLastUsageCount = lu; | |||||
| replaceIndex = i; | |||||
| } | |||||
| } | |||||
| CachedFace* const face = faces.getUnchecked (replaceIndex); | |||||
| face->typefaceName = faceName; | |||||
| face->flags = flags; | |||||
| face->lastUsageCount = ++counter; | |||||
| face->typeFace = LookAndFeel::getDefaultLookAndFeel().getTypefaceForFont (font); | |||||
| jassert (face->typeFace != 0); // the look and feel must return a typeface! | |||||
| return face->typeFace; | |||||
| } | |||||
| private: | |||||
| struct CachedFace | |||||
| { | |||||
| CachedFace() throw() | |||||
| : lastUsageCount (0), flags (-1) | |||||
| { | |||||
| } | |||||
| String typefaceName; | |||||
| int lastUsageCount; | |||||
| int flags; | |||||
| Typeface::Ptr typeFace; | |||||
| }; | |||||
| int counter; | |||||
| OwnedArray <CachedFace> faces; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypefaceCache); | |||||
| }; | |||||
| juce_ImplementSingleton_SingleThreaded (TypefaceCache) | |||||
| Typeface* Font::getTypeface() const | Typeface* Font::getTypeface() const | ||||
| { | { | ||||
| if (font->typeface == 0) | if (font->typeface == 0) | ||||
| @@ -367,11 +367,12 @@ private: | |||||
| class SharedFontInternal : public ReferenceCountedObject | class SharedFontInternal : public ReferenceCountedObject | ||||
| { | { | ||||
| public: | public: | ||||
| SharedFontInternal (const String& typefaceName, float height, float horizontalScale, | |||||
| float kerning, float ascent, int styleFlags, | |||||
| Typeface* typeface) throw(); | |||||
| SharedFontInternal (const String& typefaceName, float height, int styleFlags) throw(); | |||||
| SharedFontInternal (const Typeface::Ptr& typeface) throw(); | |||||
| SharedFontInternal (const SharedFontInternal& other) throw(); | SharedFontInternal (const SharedFontInternal& other) throw(); | ||||
| bool operator== (const SharedFontInternal&) const throw(); | |||||
| String typefaceName; | String typefaceName; | ||||
| float height, horizontalScale, kerning, ascent; | float height, horizontalScale, kerning, ascent; | ||||
| int styleFlags; | int styleFlags; | ||||
| @@ -69,6 +69,12 @@ public: | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| virtual ~Typeface(); | virtual ~Typeface(); | ||||
| /** Returns true if this typeface can be used to render the specified font. | |||||
| When called, the font will already have been checked to make sure that its name and | |||||
| style flags match the typeface. | |||||
| */ | |||||
| virtual bool isSuitableForFont (const Font&) const { return true; } | |||||
| /** Returns the ascent of the font, as a proportion of its height. | /** Returns the ascent of the font, as a proportion of its height. | ||||
| The height is considered to always be normalised as 1.0, so this will be a | The height is considered to always be normalised as 1.0, so this will be a | ||||
| value less that 1.0, indicating the proportion of the font that lies above | value less that 1.0, indicating the proportion of the font that lies above | ||||
| @@ -105,6 +111,8 @@ public: | |||||
| */ | */ | ||||
| virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; | virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; | ||||
| /** Returns true if the typeface uses hinting. */ | |||||
| virtual bool isHinted() const { return false; } | |||||
| protected: | protected: | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_RelativeCoordinate.h" | #include "juce_RelativeCoordinate.h" | ||||
| #include "../drawables/juce_DrawablePath.h" | #include "../drawables/juce_DrawablePath.h" | ||||
| #include "../../components/layout/juce_MarkerList.h" | |||||
| #include "../../../io/streams/juce_MemoryOutputStream.h" | #include "../../../io/streams/juce_MemoryOutputStream.h" | ||||
| @@ -45,8 +46,274 @@ namespace RelativeCoordinateHelpers | |||||
| } | } | ||||
| } | } | ||||
| //============================================================================== | |||||
| class RelativeComponentPositioner : public Component::Positioner, | |||||
| public ComponentListener, | |||||
| public MarkerList::Listener, | |||||
| public Expression::EvaluationContext | |||||
| { | |||||
| public: | |||||
| RelativeComponentPositioner (Component& component_) | |||||
| : Component::Positioner (component_), registeredOk (false) | |||||
| { | |||||
| } | |||||
| ~RelativeComponentPositioner() | |||||
| { | |||||
| unregisterListeners(); | |||||
| } | |||||
| const Expression getSymbolValue (const String& objectName, const String& member) const | |||||
| { | |||||
| jassert (objectName.isNotEmpty()); | |||||
| if (member.isNotEmpty()) | |||||
| { | |||||
| const Component* comp = getSourceComponent (objectName); | |||||
| if (comp == 0) | |||||
| { | |||||
| if (objectName == RelativeCoordinate::Strings::parent) | |||||
| comp = getComponent().getParentComponent(); | |||||
| else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID()) | |||||
| comp = &getComponent(); | |||||
| } | |||||
| if (comp != 0) | |||||
| { | |||||
| if (member == RelativeCoordinate::Strings::left) return xToExpression (comp, 0); | |||||
| if (member == RelativeCoordinate::Strings::right) return xToExpression (comp, comp->getWidth()); | |||||
| if (member == RelativeCoordinate::Strings::top) return yToExpression (comp, 0); | |||||
| if (member == RelativeCoordinate::Strings::bottom) return yToExpression (comp, comp->getHeight()); | |||||
| } | |||||
| } | |||||
| for (int i = sourceMarkerLists.size(); --i >= 0;) | |||||
| { | |||||
| MarkerList* const markerList = sourceMarkerLists.getUnchecked(i); | |||||
| const MarkerList::Marker* const marker = markerList->getMarker (objectName); | |||||
| if (marker != 0) | |||||
| return marker->position.getExpression(); | |||||
| } | |||||
| return Expression::EvaluationContext::getSymbolValue (objectName, member); | |||||
| } | |||||
| void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void componentParentHierarchyChanged (Component& component) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void componentBeingDeleted (Component& component) | |||||
| { | |||||
| jassert (sourceComponents.contains (&component)); | |||||
| sourceComponents.removeValue (&component); | |||||
| } | |||||
| void markersChanged (MarkerList* markerList) | |||||
| { | |||||
| apply(); | |||||
| } | |||||
| void markerListBeingDeleted (MarkerList* markerList) | |||||
| { | |||||
| jassert (sourceMarkerLists.contains (markerList)); | |||||
| sourceMarkerLists.removeValue (markerList); | |||||
| } | |||||
| void apply() | |||||
| { | |||||
| if (! registeredOk) | |||||
| { | |||||
| unregisterListeners(); | |||||
| registeredOk = registerCoordinates(); | |||||
| } | |||||
| applyToComponentBounds(); | |||||
| } | |||||
| protected: | |||||
| bool addCoordinate (const RelativeCoordinate& coord) | |||||
| { | |||||
| return registerListeners (coord.getExpression()); | |||||
| } | |||||
| virtual bool registerCoordinates() = 0; | |||||
| virtual void applyToComponentBounds() = 0; | |||||
| private: | |||||
| Array <Component*> sourceComponents; | |||||
| Array <MarkerList*> sourceMarkerLists; | |||||
| bool registeredOk; | |||||
| bool registerListeners (const Expression& e) | |||||
| { | |||||
| bool ok = true; | |||||
| if (e.getType() == Expression::symbolType) | |||||
| { | |||||
| String objectName, memberName; | |||||
| e.getSymbolParts (objectName, memberName); | |||||
| if (memberName.isNotEmpty()) | |||||
| ok = registerComponentEdge (objectName, memberName) && ok; | |||||
| else | |||||
| ok = registerMarker (objectName) && ok; | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = e.getNumInputs(); --i >= 0;) | |||||
| ok = registerListeners (e.getInput (i)) && ok; | |||||
| } | |||||
| return ok; | |||||
| } | |||||
| bool registerComponentEdge (const String& objectName, const String memberName) | |||||
| { | |||||
| Component* comp = findComponent (objectName); | |||||
| if (comp == 0) | |||||
| { | |||||
| if (objectName == RelativeCoordinate::Strings::parent) | |||||
| comp = getComponent().getParentComponent(); | |||||
| else if (objectName == RelativeCoordinate::Strings::this_ || objectName == getComponent().getComponentID()) | |||||
| comp = &getComponent(); | |||||
| } | |||||
| if (comp != 0) | |||||
| { | |||||
| if (comp != &getComponent()) | |||||
| registerComponentListener (comp); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| // The component we want doesn't exist, so watch the parent in case the hierarchy changes and it appears later.. | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| registerComponentListener (parent); | |||||
| else | |||||
| registerComponentListener (&getComponent()); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| bool registerMarker (const String markerName) | |||||
| { | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| { | |||||
| MarkerList* list = parent->getMarkers (true); | |||||
| if (list == 0 || list->getMarker (markerName) == 0) | |||||
| list = parent->getMarkers (false); | |||||
| if (list != 0 && list->getMarker (markerName) != 0) | |||||
| { | |||||
| registerMarkerListListener (list); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| // The marker we want doesn't exist, so watch all lists in case they change and the marker appears later.. | |||||
| registerMarkerListListener (parent->getMarkers (true)); | |||||
| registerMarkerListListener (parent->getMarkers (false)); | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void registerComponentListener (Component* const comp) | |||||
| { | |||||
| if (comp != 0 && ! sourceComponents.contains (comp)) | |||||
| { | |||||
| comp->addComponentListener (this); | |||||
| sourceComponents.add (comp); | |||||
| } | |||||
| } | |||||
| void registerMarkerListListener (MarkerList* const list) | |||||
| { | |||||
| if (list != 0 && ! sourceMarkerLists.contains (list)) | |||||
| { | |||||
| list->addListener (this); | |||||
| sourceMarkerLists.add (list); | |||||
| } | |||||
| } | |||||
| void unregisterListeners() | |||||
| { | |||||
| int i; | |||||
| for (i = sourceComponents.size(); --i >= 0;) | |||||
| sourceComponents.getUnchecked(i)->removeComponentListener (this); | |||||
| for (i = sourceMarkerLists.size(); --i >= 0;) | |||||
| sourceMarkerLists.getUnchecked(i)->removeListener (this); | |||||
| sourceComponents.clear(); | |||||
| sourceMarkerLists.clear(); | |||||
| } | |||||
| Component* findComponent (const String& componentID) const | |||||
| { | |||||
| Component* const parent = getComponent().getParentComponent(); | |||||
| if (parent != 0) | |||||
| { | |||||
| for (int i = parent->getNumChildComponents(); --i >= 0;) | |||||
| { | |||||
| Component* const c = parent->getChildComponent(i); | |||||
| if (c->getComponentID() == componentID) | |||||
| return c; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| Component* getSourceComponent (const String& objectName) const | |||||
| { | |||||
| for (int i = sourceComponents.size(); --i >= 0;) | |||||
| { | |||||
| Component* const comp = sourceComponents.getUnchecked(i); | |||||
| if (comp->getComponentID() == objectName) | |||||
| return comp; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| const Expression xToExpression (const Component* const source, const int x) const | |||||
| { | |||||
| return Expression ((double) (getComponent().getLocalPoint (source, Point<int> (x, 0)).getX() + getComponent().getX())); | |||||
| } | |||||
| const Expression yToExpression (const Component* const source, const int y) const | |||||
| { | |||||
| return Expression ((double) (getComponent().getLocalPoint (source, Point<int> (0, y)).getY() + getComponent().getY())); | |||||
| } | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeComponentPositioner); | |||||
| }; | |||||
| //============================================================================== | //============================================================================== | ||||
| const String RelativeCoordinate::Strings::parent ("parent"); | const String RelativeCoordinate::Strings::parent ("parent"); | ||||
| const String RelativeCoordinate::Strings::this_ ("this"); | |||||
| const String RelativeCoordinate::Strings::left ("left"); | const String RelativeCoordinate::Strings::left ("left"); | ||||
| const String RelativeCoordinate::Strings::right ("right"); | const String RelativeCoordinate::Strings::right ("right"); | ||||
| const String RelativeCoordinate::Strings::top ("top"); | const String RelativeCoordinate::Strings::top ("top"); | ||||
| @@ -301,7 +568,7 @@ const Rectangle<float> RelativeRectangle::resolve (const Expression::EvaluationC | |||||
| const double t = top.resolve (context); | const double t = top.resolve (context); | ||||
| const double b = bottom.resolve (context); | const double b = bottom.resolve (context); | ||||
| return Rectangle<float> ((float) l, (float) t, (float) (r - l), (float) (b - t)); | |||||
| return Rectangle<float> ((float) l, (float) t, (float) jmax (0.0, r - l), (float) jmax (0.0, b - t)); | |||||
| } | } | ||||
| void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* context) | void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* context) | ||||
| @@ -312,6 +579,11 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex | |||||
| bottom.moveToAbsolute (newPos.getBottom(), context); | bottom.moveToAbsolute (newPos.getBottom(), context); | ||||
| } | } | ||||
| bool RelativeRectangle::isDynamic() const | |||||
| { | |||||
| return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic(); | |||||
| } | |||||
| const String RelativeRectangle::toString() const | const String RelativeRectangle::toString() const | ||||
| { | { | ||||
| return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); | return left.toString() + ", " + top.toString() + ", " + right.toString() + ", " + bottom.toString(); | ||||
| @@ -326,6 +598,73 @@ void RelativeRectangle::renameSymbolIfUsed (const String& oldName, const String& | |||||
| } | } | ||||
| //============================================================================== | |||||
| class RelativeRectangleComponentPositioner : public RelativeComponentPositioner | |||||
| { | |||||
| public: | |||||
| RelativeRectangleComponentPositioner (Component& component_, const RelativeRectangle& rectangle_) | |||||
| : RelativeComponentPositioner (component_), | |||||
| rectangle (rectangle_) | |||||
| { | |||||
| } | |||||
| bool registerCoordinates() | |||||
| { | |||||
| bool ok = addCoordinate (rectangle.left); | |||||
| ok = addCoordinate (rectangle.right) && ok; | |||||
| ok = addCoordinate (rectangle.top) && ok; | |||||
| ok = addCoordinate (rectangle.bottom) && ok; | |||||
| return ok; | |||||
| } | |||||
| bool isUsingRectangle (const RelativeRectangle& other) const throw() | |||||
| { | |||||
| return rectangle == other; | |||||
| } | |||||
| void applyToComponentBounds() | |||||
| { | |||||
| for (int i = 4; --i >= 0;) | |||||
| { | |||||
| const Rectangle<int> newBounds (rectangle.resolve (this).getSmallestIntegerContainer()); | |||||
| if (newBounds == getComponent().getBounds()) | |||||
| return; | |||||
| getComponent().setBounds (newBounds); | |||||
| } | |||||
| jassertfalse; // must be a recursive reference! | |||||
| } | |||||
| private: | |||||
| const RelativeRectangle rectangle; | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeRectangleComponentPositioner); | |||||
| }; | |||||
| void RelativeRectangle::applyToComponent (Component& component) const | |||||
| { | |||||
| if (isDynamic()) | |||||
| { | |||||
| RelativeRectangleComponentPositioner* current = dynamic_cast <RelativeRectangleComponentPositioner*> (component.getPositioner()); | |||||
| if (current == 0 || ! current->isUsingRectangle (*this)) | |||||
| { | |||||
| RelativeRectangleComponentPositioner* p = new RelativeRectangleComponentPositioner (component, *this); | |||||
| component.setPositioner (p); | |||||
| p->apply(); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| component.setPositioner (0); | |||||
| component.setBounds (resolve (0).getSmallestIntegerContainer()); | |||||
| } | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| RelativePointPath::RelativePointPath() | RelativePointPath::RelativePointPath() | ||||
| : usesNonZeroWinding (true), | : usesNonZeroWinding (true), | ||||
| @@ -31,6 +31,7 @@ | |||||
| #include "../../../maths/juce_Expression.h" | #include "../../../maths/juce_Expression.h" | ||||
| #include "../../../containers/juce_OwnedArray.h" | #include "../../../containers/juce_OwnedArray.h" | ||||
| #include "../../../containers/juce_ValueTree.h" | #include "../../../containers/juce_ValueTree.h" | ||||
| class Component; | |||||
| //============================================================================== | //============================================================================== | ||||
| @@ -120,6 +121,7 @@ public: | |||||
| struct Strings | struct Strings | ||||
| { | { | ||||
| static const String parent; /**< "parent" */ | static const String parent; /**< "parent" */ | ||||
| static const String this_; /**< "this" */ | |||||
| static const String left; /**< "left" */ | static const String left; /**< "left" */ | ||||
| static const String right; /**< "right" */ | static const String right; /**< "right" */ | ||||
| static const String top; /**< "top" */ | static const String top; /**< "top" */ | ||||
| @@ -251,6 +253,9 @@ public: | |||||
| */ | */ | ||||
| void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | void moveToAbsolute (const Rectangle<float>& newPos, const Expression::EvaluationContext* evaluationContext); | ||||
| /** Returns true if this rectangle depends on any other coordinates for its position. */ | |||||
| bool isDynamic() const; | |||||
| /** Returns a string which represents this point. | /** Returns a string which represents this point. | ||||
| This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of | ||||
| the string syntax used by the coordinates, see the RelativeCoordinate constructor notes. | the string syntax used by the coordinates, see the RelativeCoordinate constructor notes. | ||||
| @@ -263,6 +268,9 @@ public: | |||||
| */ | */ | ||||
| void renameSymbolIfUsed (const String& oldName, const String& newName); | void renameSymbolIfUsed (const String& oldName, const String& newName); | ||||
| /** */ | |||||
| void applyToComponent (Component& component) const; | |||||
| // The actual rectangle coords... | // The actual rectangle coords... | ||||
| RelativeCoordinate left, right, top, bottom; | RelativeCoordinate left, right, top, bottom; | ||||
| }; | }; | ||||
| @@ -101,13 +101,14 @@ public: | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| Type getType() const throw() { return symbolType; } | |||||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||||
| int getNumInputs() const { return 0; } | |||||
| Term* getInput (int) const { return 0; } | |||||
| const String getSymbolName() const { return toString(); } | |||||
| const String toString() const | |||||
| Type getType() const throw() { return symbolType; } | |||||
| Term* clone() const { return new Symbol (mainSymbol, member); } | |||||
| int getNumInputs() const { return 0; } | |||||
| Term* getInput (int) const { return 0; } | |||||
| const String toString() const { return joinParts (mainSymbol, member); } | |||||
| void getSymbolParts (String& objectName, String& memberName) const { objectName = mainSymbol; memberName = member; } | |||||
| static const String joinParts (const String& mainSymbol, const String& member) | |||||
| { | { | ||||
| return member.isEmpty() ? mainSymbol | return member.isEmpty() ? mainSymbol | ||||
| : mainSymbol + "." + member; | : mainSymbol + "." + member; | ||||
| @@ -894,6 +895,9 @@ const Expression Expression::withRenamedSymbol (const String& oldSymbol, const S | |||||
| { | { | ||||
| jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_")); | ||||
| if (oldSymbol == newSymbol) | |||||
| return *this; | |||||
| Expression newExpression (term->clone()); | Expression newExpression (term->clone()); | ||||
| Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol); | ||||
| return newExpression; | return newExpression; | ||||
| @@ -916,7 +920,14 @@ Expression::Type Expression::getType() const throw() | |||||
| const String Expression::getSymbol() const | const String Expression::getSymbol() const | ||||
| { | { | ||||
| return term->getSymbolName(); | |||||
| String objectName, memberName; | |||||
| term->getSymbolParts (objectName, memberName); | |||||
| return Expression::Helpers::Symbol::joinParts (objectName, memberName); | |||||
| } | |||||
| void Expression::getSymbolParts (String& objectName, String& memberName) const | |||||
| { | |||||
| term->getSymbolParts (objectName, memberName); | |||||
| } | } | ||||
| const String Expression::getFunction() const | const String Expression::getFunction() const | ||||
| @@ -966,10 +977,9 @@ const ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated() | |||||
| return new Helpers::Negate (this); | return new Helpers::Negate (this); | ||||
| } | } | ||||
| const String Expression::Term::getSymbolName() const | |||||
| void Expression::Term::getSymbolParts (String&, String&) const | |||||
| { | { | ||||
| jassertfalse; // You should only call getSymbol() on an expression that's actually a symbol! | jassertfalse; // You should only call getSymbol() on an expression that's actually a symbol! | ||||
| return String::empty; | |||||
| } | } | ||||
| const String Expression::Term::getFunctionName() const | const String Expression::Term::getFunctionName() const | ||||
| @@ -202,9 +202,12 @@ public: | |||||
| /** Returns the type of this expression. */ | /** Returns the type of this expression. */ | ||||
| Type getType() const throw(); | Type getType() const throw(); | ||||
| /** If this expression is a symbol, this returns its name. */ | |||||
| /** If this expression is a symbol, this returns its full name. */ | |||||
| const String getSymbol() const; | const String getSymbol() const; | ||||
| /** For a symbol that contains a dot, this returns the two */ | |||||
| void getSymbolParts (String& objectName, String& memberName) const; | |||||
| /** If this expression is a function, this returns its name. */ | /** If this expression is a function, this returns its name. */ | ||||
| const String getFunction() const; | const String getFunction() const; | ||||
| @@ -246,7 +249,7 @@ private: | |||||
| double overallTarget, Term* topLevelTerm) const; | double overallTarget, Term* topLevelTerm) const; | ||||
| virtual const ReferenceCountedObjectPtr<Term> negated(); | virtual const ReferenceCountedObjectPtr<Term> negated(); | ||||
| virtual Type getType() const throw() = 0; | virtual Type getType() const throw() = 0; | ||||
| virtual const String getSymbolName() const; | |||||
| virtual void getSymbolParts (String& objectName, String& memberName) const; | |||||
| virtual const String getFunctionName() const; | virtual const String getFunctionName() const; | ||||
| private: | private: | ||||