Browse Source

Fix for listbox and table multi-selection. Internal updates for relative positioning. Additions to Typeface class to allow hinted subclasses.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
2c669674ad
24 changed files with 1536 additions and 760 deletions
  1. +0
    -140
      extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.cpp
  2. +0
    -70
      extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h
  3. +546
    -145
      juce_amalgamated.cpp
  4. +110
    -21
      juce_amalgamated.h
  5. +5
    -0
      src/audio/audio_file_formats/juce_AudioThumbnail.h
  6. +216
    -216
      src/containers/juce_NamedValueSet.cpp
  7. +1
    -1
      src/core/juce_StandardHeader.h
  8. +5
    -4
      src/gui/components/controls/juce_ListBox.cpp
  9. +2
    -1
      src/gui/components/controls/juce_ListBox.h
  10. +2
    -2
      src/gui/components/controls/juce_TableListBox.cpp
  11. +1
    -1
      src/gui/components/filebrowser/juce_FileListComponent.cpp
  12. +18
    -0
      src/gui/components/juce_Component.cpp
  13. +44
    -9
      src/gui/components/juce_Component.h
  14. +7
    -11
      src/gui/components/layout/juce_ComponentBuilder.cpp
  15. +16
    -1
      src/gui/components/layout/juce_MarkerList.cpp
  16. +33
    -5
      src/gui/components/layout/juce_MarkerList.h
  17. +15
    -9
      src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp
  18. +130
    -108
      src/gui/graphics/fonts/juce_Font.cpp
  19. +4
    -3
      src/gui/graphics/fonts/juce_Font.h
  20. +8
    -0
      src/gui/graphics/fonts/juce_Typeface.h
  21. +340
    -1
      src/gui/graphics/geometry/juce_RelativeCoordinate.cpp
  22. +8
    -0
      src/gui/graphics/geometry/juce_RelativeCoordinate.h
  23. +20
    -10
      src/maths/juce_Expression.cpp
  24. +5
    -2
      src/maths/juce_Expression.h

+ 0
- 140
extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.cpp View File

@@ -336,143 +336,3 @@ void FloatingLabelComponent::paint (Graphics& g)
g.setColour (colour);
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_)
{
}

+ 0
- 70
extras/Jucer (experimental)/Source/Utility/jucer_MiscUtilities.h View File

@@ -96,10 +96,6 @@ public:
setClickingTogglesState (false);
}
~JucerToolbarButton()
{
}
//==============================================================================
bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize, int& minSize, int& maxSize)
{
@@ -137,69 +133,3 @@ public:
private:
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);
};

+ 546
- 145
juce_amalgamated.cpp View File

@@ -4719,13 +4719,14 @@ public:
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
: mainSymbol + "." + member;
@@ -5501,6 +5502,9 @@ const Expression Expression::withRenamedSymbol (const String& oldSymbol, const S
{
jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));

if (oldSymbol == newSymbol)
return *this;

Expression newExpression (term->clone());
Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol);
return newExpression;
@@ -5523,7 +5527,14 @@ Expression::Type Expression::getType() const throw()

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
@@ -5572,10 +5583,9 @@ const ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
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!
return String::empty;
}

const String Expression::Term::getFunctionName() const
@@ -41530,6 +41540,23 @@ MarkerList* Component::getMarkers (bool /*xAxis*/)
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()
{
return Rectangle<int> (getWidth(), getHeight());
@@ -48343,7 +48370,7 @@ public:
{
if (! selected)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, false);

if (owner.getModel() != 0)
owner.getModel()->listBoxItemClicked (row, e);
@@ -48359,7 +48386,7 @@ public:
{
if (isEnabled() && selectRowOnMouseUp && ! isDragging)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, true);

if (owner.getModel() != 0)
owner.getModel()->listBoxItemClicked (row, e);
@@ -48827,7 +48854,8 @@ void ListBox::deselectAllRows()
}

void ListBox::selectRowsBasedOnModifierKeys (const int row,
const ModifierKeys& mods)
const ModifierKeys& mods,
const bool isMouseUpEvent)
{
if (multipleSelection && mods.isCommandDown())
{
@@ -48839,7 +48867,7 @@ void ListBox::selectRowsBasedOnModifierKeys (const int 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)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, false);

const int columnId = owner.getHeader().getColumnIdAtX (e.x);

@@ -51729,7 +51757,7 @@ public:
{
if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled())
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, true);

const int columnId = owner.getHeader().getColumnIdAtX (e.x);

@@ -58728,7 +58756,7 @@ public:

void mouseDown (const MouseEvent& e)
{
owner.selectRowsBasedOnModifierKeys (index, e.mods);
owner.selectRowsBasedOnModifierKeys (index, e.mods, false);
owner.sendMouseClickMessage (file, e);
}

@@ -61350,24 +61378,20 @@ namespace ComponentBuilderHelpers

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.
updateComponent (builder, state.getParent());
if (state.getParent().isValid())
updateComponent (builder, state.getParent());
}
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()
{
listeners.call (&MarkerList::Listener::markerListBeingDeleted, this);
}

bool MarkerList::operator== (const MarkerList& other) const throw()
@@ -62129,7 +62154,21 @@ void MarkerList::removeMarker (const String& name)

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)
@@ -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::this_ ("this");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
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 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)
@@ -79909,6 +80212,11 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex
bottom.moveToAbsolute (newPos.getBottom(), context);
}

bool RelativeRectangle::isDynamic() const
{
return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic();
}

const String RelativeRectangle::toString() const
{
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);
}

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()
: usesNonZeroWinding (true),
containsDynamicPoints (false)
@@ -85678,10 +86051,12 @@ class LowLevelGraphicsSoftwareRenderer::CachedGlyph
{
public:
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)
state.fillEdgeTable (*edgeTable, x, roundToInt (y));
}
@@ -85689,6 +86064,7 @@ public:
void generate (const Font& newFont, const int glyphNumber)
{
font = newFont;
snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
glyph = glyphNumber;
edgeTable = 0;

@@ -85709,8 +86085,9 @@ public:
}
}

int glyph, lastAccessCount;
Font font;
int glyph, lastAccessCount;
bool snapToIntegerCoordinate;

private:
ScopedPointer <EdgeTable> edgeTable;
@@ -85724,8 +86101,7 @@ public:
GlyphCache()
: accessCounter (0), hits (0), misses (0)
{
for (int i = 120; --i >= 0;)
glyphs.add (new CachedGlyph());
addNewGlyphSlots (120);
}

~GlyphCache()
@@ -85763,10 +86139,7 @@ public:
if (hits + ++misses > (glyphs.size() << 4))
{
if (misses * 2 > hits)
{
for (int i = 32; --i >= 0;)
glyphs.add (new CachedGlyph());
}
addNewGlyphSlots (32);

hits = misses = 0;
oldest = glyphs.getLast();
@@ -85783,6 +86156,12 @@ private:
OwnedArray <CachedGlyph> glyphs;
int accessCounter, hits, misses;

void addNewGlyphSlots (int num)
{
while (--num >= 0)
glyphs.add (new CachedGlyph());
}

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache);
};

@@ -89314,15 +89693,119 @@ namespace FontValues
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_),
height (height_),
horizontalScale (horizontalScale_),
kerning (kerning_),
ascent (ascent_),
horizontalScale (1.0f),
kerning (0),
ascent (0),
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_)
{
}
@@ -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 (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 (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()
{
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()
@@ -89659,87 +90141,6 @@ const Font Font::fromString (const String& fontDescription)
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
{
if (font->typeface == 0)


+ 110
- 21
juce_amalgamated.h View File

@@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 3
#define JUCE_BUILDNUMBER 4

/** Current Juce version number.

@@ -17892,9 +17892,12 @@ public:
/** Returns the type of this expression. */
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;

/** 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. */
const String getFunction() const;

@@ -17936,7 +17939,7 @@ private:
double overallTarget, Term* topLevelTerm) const;
virtual const ReferenceCountedObjectPtr<Term> negated();
virtual Type getType() const throw() = 0;
virtual const String getSymbolName() const;
virtual void getSymbolParts (String& objectName, String& memberName) const;
virtual const String getFunctionName() const;

private:
@@ -23409,6 +23412,12 @@ public:
/** Destructor. */
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.
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
@@ -23445,6 +23454,9 @@ public:
*/
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;

/** Returns true if the typeface uses hinting. */
virtual bool isHinted() const { return false; }

protected:

String name;
@@ -23887,11 +23899,12 @@ private:
class SharedFontInternal : public ReferenceCountedObject
{
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();

bool operator== (const SharedFontInternal&) const throw();

String typefaceName;
float height, horizontalScale, kerning, ascent;
int styleFlags;
@@ -28878,7 +28891,7 @@ public:
the list iterator to stop cleanly if the component is deleted by a listener callback
while the list is still being iterated.
*/
class BailOutChecker
class JUCE_API BailOutChecker
{
public:
/** Creates a checker that watches one component. */
@@ -28893,16 +28906,49 @@ public:
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

private:
@@ -28917,6 +28963,7 @@ private:
String componentName, componentID;
Component* parentComponent;
Rectangle<int> bounds;
ScopedPointer <Positioner> positioner;
ScopedPointer <AffineTransform> affineTransform;
Array <Component*> childComponentList;
LookAndFeel* lookAndFeel;
@@ -33468,6 +33515,9 @@ public:
/** Returns true if the low res preview is fully generated. */
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.
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.
@@ -33477,8 +33527,10 @@ public:
/** Returns the hash code that was set by setSource() or setReader(). */
int64 getHashCode() const;

#ifndef DOXYGEN
// (this is only public to avoid a VC6 bug)
class LevelDataSource;
#endif

private:

@@ -42737,7 +42789,8 @@ public:
@see selectRow
*/
void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn,
const ModifierKeys& modifiers);
const ModifierKeys& modifiers,
bool isMouseUpEvent);

/** Scrolls the list to a particular position.

@@ -45291,6 +45344,8 @@ private:
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__
#define __JUCE_RELATIVECOORDINATE_JUCEHEADER__

class Component;

/**
Expresses a coordinate as a dynamically evaluated expression.

@@ -45372,6 +45427,7 @@ public:
struct Strings
{
static const String parent; /**< "parent" */
static const String this_; /**< "this" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
@@ -45498,6 +45554,9 @@ public:
*/
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.
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.
@@ -45510,6 +45569,9 @@ public:
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);

/** */
void applyToComponent (Component& component) const;

// The actual rectangle coords...
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.
@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:

@@ -54038,6 +54097,36 @@ public:
/** Returns true if not all the markers in these two lists match exactly. */
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. */
class ValueTreeWrapper
{
@@ -54065,7 +54154,7 @@ public:
private:

OwnedArray<Marker> markers;
void markersHaveChanged();
ListenerList <Listener> listeners;

JUCE_LEAK_DETECTOR (MarkerList);
};


+ 5
- 0
src/audio/audio_file_formats/juce_AudioThumbnail.h View File

@@ -177,6 +177,9 @@ public:
/** Returns true if the low res preview is fully generated. */
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.
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.
@@ -186,8 +189,10 @@ public:
/** Returns the hash code that was set by setSource() or setReader(). */
int64 getHashCode() const;
#ifndef DOXYGEN
// (this is only public to avoid a VC6 bug)
class LevelDataSource;
#endif
private:
//==============================================================================


+ 216
- 216
src/containers/juce_NamedValueSet.cpp View File

@@ -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

+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 3
#define JUCE_BUILDNUMBER 4
/** Current Juce version number.


+ 5
- 4
src/gui/components/controls/juce_ListBox.cpp View File

@@ -80,7 +80,7 @@ public:
{
if (! selected)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, false);
if (owner.getModel() != 0)
owner.getModel()->listBoxItemClicked (row, e);
@@ -96,7 +96,7 @@ public:
{
if (isEnabled() && selectRowOnMouseUp && ! isDragging)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, true);
if (owner.getModel() != 0)
owner.getModel()->listBoxItemClicked (row, e);
@@ -571,7 +571,8 @@ void ListBox::deselectAllRows()
}
void ListBox::selectRowsBasedOnModifierKeys (const int row,
const ModifierKeys& mods)
const ModifierKeys& mods,
const bool isMouseUpEvent)
{
if (multipleSelection && mods.isCommandDown())
{
@@ -583,7 +584,7 @@ void ListBox::selectRowsBasedOnModifierKeys (const int row,
}
else if ((! mods.isPopupMenu()) || ! isRowSelected (row))
{
selectRowInternal (row, false, ! (multipleSelection && isRowSelected (row)), true);
selectRowInternal (row, false, ! (multipleSelection && (! isMouseUpEvent) && isRowSelected (row)), true);
}
}


+ 2
- 1
src/gui/components/controls/juce_ListBox.h View File

@@ -330,7 +330,8 @@ public:
@see selectRow
*/
void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn,
const ModifierKeys& modifiers);
const ModifierKeys& modifiers,
bool isMouseUpEvent);
//==============================================================================
/** Scrolls the list to a particular position.


+ 2
- 2
src/gui/components/controls/juce_TableListBox.cpp View File

@@ -146,7 +146,7 @@ public:
{
if (! isSelected)
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, false);
const int columnId = owner.getHeader().getColumnIdAtX (e.x);
@@ -183,7 +183,7 @@ public:
{
if (selectRowOnMouseUp && e.mouseWasClicked() && isEnabled())
{
owner.selectRowsBasedOnModifierKeys (row, e.mods);
owner.selectRowsBasedOnModifierKeys (row, e.mods, true);
const int columnId = owner.getHeader().getColumnIdAtX (e.x);


+ 1
- 1
src/gui/components/filebrowser/juce_FileListComponent.cpp View File

@@ -110,7 +110,7 @@ public:
void mouseDown (const MouseEvent& e)
{
owner.selectRowsBasedOnModifierKeys (index, e.mods);
owner.selectRowsBasedOnModifierKeys (index, e.mods, false);
owner.sendMouseClickMessage (file, e);
}


+ 18
- 0
src/gui/components/juce_Component.cpp View File

@@ -2055,6 +2055,24 @@ MarkerList* Component::getMarkers (bool /*xAxis*/)
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()
{


+ 44
- 9
src/gui/components/juce_Component.h View File

@@ -2093,7 +2093,7 @@ public:
the list iterator to stop cleanly if the component is deleted by a listener callback
while the list is still being iterated.
*/
class BailOutChecker
class JUCE_API BailOutChecker
{
public:
/** 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
private:
@@ -2134,6 +2168,7 @@ private:
String componentName, componentID;
Component* parentComponent;
Rectangle<int> bounds;
ScopedPointer <Positioner> positioner;
ScopedPointer <AffineTransform> affineTransform;
Array <Component*> childComponentList;
LookAndFeel* lookAndFeel;


+ 7
- 11
src/gui/components/layout/juce_ComponentBuilder.cpp View File

@@ -85,24 +85,20 @@ namespace ComponentBuilderHelpers
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.
updateComponent (builder, state.getParent());
if (state.getParent().isValid())
updateComponent (builder, state.getParent());
}
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);
}
}
}


+ 16
- 1
src/gui/components/layout/juce_MarkerList.cpp View File

@@ -54,6 +54,7 @@ MarkerList& MarkerList::operator= (const MarkerList& other)
MarkerList::~MarkerList()
{
listeners.call (&MarkerList::Listener::markerListBeingDeleted, this);
}
bool MarkerList::operator== (const MarkerList& other) const throw()
@@ -148,7 +149,21 @@ void MarkerList::removeMarker (const String& name)
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);
}
//==============================================================================


+ 33
- 5
src/gui/components/layout/juce_MarkerList.h View File

@@ -36,11 +36,8 @@
This class is used to store sets of X and Y marker points in components.
@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:
//==============================================================================
@@ -105,6 +102,37 @@ public:
/** Returns true if not all the markers in these two lists match exactly. */
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. */
class ValueTreeWrapper
@@ -133,7 +161,7 @@ public:
private:
//==============================================================================
OwnedArray<Marker> markers;
void markersHaveChanged();
ListenerList <Listener> listeners;
JUCE_LEAK_DETECTOR (MarkerList);
};


+ 15
- 9
src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp View File

@@ -2394,10 +2394,12 @@ class LowLevelGraphicsSoftwareRenderer::CachedGlyph
{
public:
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)
state.fillEdgeTable (*edgeTable, x, roundToInt (y));
}
@@ -2405,6 +2407,7 @@ public:
void generate (const Font& newFont, const int glyphNumber)
{
font = newFont;
snapToIntegerCoordinate = newFont.getTypeface()->isHinted();
glyph = glyphNumber;
edgeTable = 0;
@@ -2425,8 +2428,9 @@ public:
}
}
int glyph, lastAccessCount;
Font font;
int glyph, lastAccessCount;
bool snapToIntegerCoordinate;
private:
ScopedPointer <EdgeTable> edgeTable;
@@ -2441,8 +2445,7 @@ public:
GlyphCache()
: accessCounter (0), hits (0), misses (0)
{
for (int i = 120; --i >= 0;)
glyphs.add (new CachedGlyph());
addNewGlyphSlots (120);
}
~GlyphCache()
@@ -2481,10 +2484,7 @@ public:
if (hits + ++misses > (glyphs.size() << 4))
{
if (misses * 2 > hits)
{
for (int i = 32; --i >= 0;)
glyphs.add (new CachedGlyph());
}
addNewGlyphSlots (32);
hits = misses = 0;
oldest = glyphs.getLast();
@@ -2501,6 +2501,12 @@ private:
OwnedArray <CachedGlyph> glyphs;
int accessCounter, hits, misses;
void addNewGlyphSlots (int num)
{
while (--num >= 0)
glyphs.add (new CachedGlyph());
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GlyphCache);
};


+ 130
- 108
src/gui/graphics/fonts/juce_Font.cpp View File

@@ -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_),
height (height_),
horizontalScale (horizontalScale_),
kerning (kerning_),
ascent (ascent_),
horizontalScale (1.0f),
kerning (0),
ascent (0),
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_)
{
}
@@ -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 (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 (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()
{
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()
@@ -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
{
if (font->typeface == 0)


+ 4
- 3
src/gui/graphics/fonts/juce_Font.h View File

@@ -367,11 +367,12 @@ private:
class SharedFontInternal : public ReferenceCountedObject
{
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();
bool operator== (const SharedFontInternal&) const throw();
String typefaceName;
float height, horizontalScale, kerning, ascent;
int styleFlags;


+ 8
- 0
src/gui/graphics/fonts/juce_Typeface.h View File

@@ -69,6 +69,12 @@ public:
/** Destructor. */
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.
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
@@ -105,6 +111,8 @@ public:
*/
virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0;
/** Returns true if the typeface uses hinting. */
virtual bool isHinted() const { return false; }
protected:
//==============================================================================


+ 340
- 1
src/gui/graphics/geometry/juce_RelativeCoordinate.cpp View File

@@ -29,6 +29,7 @@ BEGIN_JUCE_NAMESPACE
#include "juce_RelativeCoordinate.h"
#include "../drawables/juce_DrawablePath.h"
#include "../../components/layout/juce_MarkerList.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::this_ ("this");
const String RelativeCoordinate::Strings::left ("left");
const String RelativeCoordinate::Strings::right ("right");
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 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)
@@ -312,6 +579,11 @@ void RelativeRectangle::moveToAbsolute (const Rectangle<float>& newPos, const Ex
bottom.moveToAbsolute (newPos.getBottom(), context);
}
bool RelativeRectangle::isDynamic() const
{
return left.isDynamic() || right.isDynamic() || top.isDynamic() || bottom.isDynamic();
}
const String RelativeRectangle::toString() const
{
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()
: usesNonZeroWinding (true),


+ 8
- 0
src/gui/graphics/geometry/juce_RelativeCoordinate.h View File

@@ -31,6 +31,7 @@
#include "../../../maths/juce_Expression.h"
#include "../../../containers/juce_OwnedArray.h"
#include "../../../containers/juce_ValueTree.h"
class Component;
//==============================================================================
@@ -120,6 +121,7 @@ public:
struct Strings
{
static const String parent; /**< "parent" */
static const String this_; /**< "this" */
static const String left; /**< "left" */
static const String right; /**< "right" */
static const String top; /**< "top" */
@@ -251,6 +253,9 @@ public:
*/
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.
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.
@@ -263,6 +268,9 @@ public:
*/
void renameSymbolIfUsed (const String& oldName, const String& newName);
/** */
void applyToComponent (Component& component) const;
// The actual rectangle coords...
RelativeCoordinate left, right, top, bottom;
};


+ 20
- 10
src/maths/juce_Expression.cpp View File

@@ -101,13 +101,14 @@ public:
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
: mainSymbol + "." + member;
@@ -894,6 +895,9 @@ const Expression Expression::withRenamedSymbol (const String& oldSymbol, const S
{
jassert (newSymbol.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));
if (oldSymbol == newSymbol)
return *this;
Expression newExpression (term->clone());
Helpers::renameSymbol (newExpression.term, oldSymbol, newSymbol);
return newExpression;
@@ -916,7 +920,14 @@ Expression::Type Expression::getType() const throw()
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
@@ -966,10 +977,9 @@ const ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
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!
return String::empty;
}
const String Expression::Term::getFunctionName() const


+ 5
- 2
src/maths/juce_Expression.h View File

@@ -202,9 +202,12 @@ public:
/** Returns the type of this expression. */
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;
/** 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. */
const String getFunction() const;
@@ -246,7 +249,7 @@ private:
double overallTarget, Term* topLevelTerm) const;
virtual const ReferenceCountedObjectPtr<Term> negated();
virtual Type getType() const throw() = 0;
virtual const String getSymbolName() const;
virtual void getSymbolParts (String& objectName, String& memberName) const;
virtual const String getFunctionName() const;
private:


Loading…
Cancel
Save