1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-05 03:50:07 +00:00

Updated the path flattening code to correctly observe tolerance values, and made the tolerances adapt to the scaling being used when drawing to a transformed graphics context. Fixed a small issue with focus listeners, and a mac menu dismissal problem.

This commit is contained in:
Julian Storer 2010-12-15 17:20:26 +00:00
parent f402ce803b
commit 5f347bc999
29 changed files with 432 additions and 311 deletions

View file

@ -40,9 +40,9 @@
#include <exdisp.h>
#pragma warning (disable:4584)
#include "juce_IncludeBrowserPluginInfo.h"
#include "../../../juce_amalgamated.h"
#include "juce_BrowserPluginComponent.h"
#include "juce_IncludeBrowserPluginInfo.h"
#ifndef JuceBrowserPlugin_ActiveXCLSID
#error "For an activeX plugin, you need to define JuceBrowserPlugin_ActiveXCLSID in your BrowserPluginCharacteristics.h file!"

View file

@ -66,9 +66,9 @@
#endif
//==============================================================================
#include "juce_IncludeBrowserPluginInfo.h"
#include "../../../juce_amalgamated.h"
#include "juce_BrowserPluginComponent.h"
#include "juce_IncludeBrowserPluginInfo.h"
#if JUCE_MAC && JUCE_DEBUG && 0
#include <fstream>

View file

@ -42956,7 +42956,9 @@ void Desktop::triggerFocusCallback()
void Desktop::handleAsyncUpdate()
{
Component* currentFocus = Component::getCurrentlyFocusedComponent();
// The component may be deleted during this operation, but we'll use a SafePointer rather than a
// BailOutChecker so that any remaining listeners will still get a callback (with a null pointer).
Component::SafePointer<Component> currentFocus (Component::getCurrentlyFocusedComponent());
focusListeners.call (&FocusChangeListener::globalFocusChanged, currentFocus);
}
@ -70204,15 +70206,18 @@ int PopupMenu::showAt (Component* componentToAttachTo,
}
}
void JUCE_CALLTYPE PopupMenu::dismissAllActiveMenus()
bool JUCE_CALLTYPE PopupMenu::dismissAllActiveMenus()
{
for (int i = Window::getActiveWindows().size(); --i >= 0;)
const int numWindows = Window::getActiveWindows().size();
for (int i = numWindows; --i >= 0;)
{
Window* const pmw = Window::getActiveWindows()[i];
if (pmw != 0)
pmw->dismissMenu (0);
}
return numWindows > 0;
}
int PopupMenu::getNumItems() const throw()
@ -82175,7 +82180,7 @@ void Graphics::strokePath (const Path& path,
const AffineTransform& transform) const
{
Path stroke;
strokeType.createStrokedPath (stroke, path, transform);
strokeType.createStrokedPath (stroke, path, transform, context->getScaleFactor());
fillPath (stroke);
}
@ -82660,6 +82665,12 @@ void LowLevelGraphicsPostScriptRenderer::addTransform (const AffineTransform& /*
jassertfalse;
}
float LowLevelGraphicsPostScriptRenderer::getScaleFactor()
{
jassertfalse; //xxx
return 1.0f;
}
bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle<int>& r)
{
needToClip = true;
@ -84873,6 +84884,11 @@ public:
}
}
float getScaleFactor() const
{
return isOnlyTranslated ? 1.0f : complexTransform.getScaleFactor();
}
bool clipToRectangle (const Rectangle<int>& r)
{
if (clip != 0)
@ -85278,6 +85294,11 @@ void LowLevelGraphicsSoftwareRenderer::addTransform (const AffineTransform& tran
currentState->addTransform (transform);
}
float LowLevelGraphicsSoftwareRenderer::getScaleFactor()
{
return currentState->getScaleFactor();
}
bool LowLevelGraphicsSoftwareRenderer::clipToRectangle (const Rectangle<int>& r)
{
return currentState->clipToRectangle (r);
@ -88682,7 +88703,7 @@ private:
float x = getCoordLength (strokeWidth, viewBoxW), y = 0.0f;
transform.transformPoints (ox, oy, x, y);
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypotf (x - ox, y - oy) : 1.0f,
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypot (x - ox, y - oy) : 1.0f,
joinStyle, capStyle);
}
@ -91443,6 +91464,11 @@ bool AffineTransform::isOnlyTranslation() const throw()
&& (mat11 == 1.0f);
}
float AffineTransform::getScaleFactor() const throw()
{
return juce_hypot (mat00 + mat01, mat10 + mat11);
}
END_JUCE_NAMESPACE
/*** End of inlined file: juce_AffineTransform.cpp ***/
@ -91581,6 +91607,11 @@ namespace PathHelpers
return String (start, (int) (t - start));
}
inline double lengthOf (float x1, float y1, float x2, float y2) throw()
{
return juce_hypot ((double) (x1 - x2), (double) (y1 - y2));
}
}
const float Path::lineMarker = 100001.0f;
@ -92481,13 +92512,13 @@ const AffineTransform Path::getTransformToScaleToFit (const float x, const float
}
}
bool Path::contains (const float x, const float y, const float tolerence) const
bool Path::contains (const float x, const float y, const float tolerance) const
{
if (x <= pathXMin || x >= pathXMax
|| y <= pathYMin || y >= pathYMax)
return false;
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
PathFlatteningIterator i (*this, AffineTransform::identity, tolerance);
int positiveCrossings = 0;
int negativeCrossings = 0;
@ -92512,14 +92543,14 @@ bool Path::contains (const float x, const float y, const float tolerence) const
: ((negativeCrossings + positiveCrossings) & 1) != 0;
}
bool Path::contains (const Point<float>& point, const float tolerence) const
bool Path::contains (const Point<float>& point, const float tolerance) const
{
return contains (point.getX(), point.getY(), tolerence);
return contains (point.getX(), point.getY(), tolerance);
}
bool Path::intersectsLine (const Line<float>& line, const float tolerence)
bool Path::intersectsLine (const Line<float>& line, const float tolerance)
{
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
PathFlatteningIterator i (*this, AffineTransform::identity, tolerance);
Point<float> intersection;
while (i.next())
@ -92672,8 +92703,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
if (lastWasLine)
{
const double len1 = juce_hypot (startX - joinX,
startY - joinY);
const double len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
if (len1 > 0)
{
@ -92683,8 +92713,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
p.data.elements [p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
}
const double len2 = juce_hypot (endX - joinX,
endY - joinY);
const double len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
if (len2 > 0)
{
@ -92714,8 +92743,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
endX = data.elements [indexOfPathStartThis + 4];
endY = data.elements [indexOfPathStartThis + 5];
const double len1 = juce_hypot (startX - joinX,
startY - joinY);
const double len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
if (len1 > 0)
{
@ -92725,8 +92753,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
p.data.elements [p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
}
const double len2 = juce_hypot (endX - joinX,
endY - joinY);
const double len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
if (len2 > 0)
{
@ -93095,9 +93122,11 @@ BEGIN_JUCE_NAMESPACE
#pragma optimize ("t", on)
#endif
const float PathFlatteningIterator::defaultTolerance = 0.6f;
PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
const AffineTransform& transform_,
float tolerence_)
const float tolerance)
: x2 (0),
y2 (0),
closesSubPath (false),
@ -93105,7 +93134,7 @@ PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
path (path_),
transform (transform_),
points (path_.data.elements),
tolerence (tolerence_ * tolerence_),
toleranceSquared (tolerance * tolerance),
subPathCloseX (0),
subPathCloseY (0),
isIdentityTransform (transform_.isIdentity()),
@ -93221,11 +93250,6 @@ bool PathFlatteningIterator::next()
stackPos = stackBase + offset;
}
const float dx1 = x1 - x2;
const float dy1 = y1 - y2;
const float dx2 = x2 - x3;
const float dy2 = y2 - y3;
const float m1x = (x1 + x2) * 0.5f;
const float m1y = (y1 + y2) * 0.5f;
const float m2x = (x2 + x3) * 0.5f;
@ -93233,7 +93257,10 @@ bool PathFlatteningIterator::next()
const float m3x = (m1x + m2x) * 0.5f;
const float m3y = (m1y + m2y) * 0.5f;
if (dx1*dx1 + dy1*dy1 + dx2*dx2 + dy2*dy2 > tolerence)
const float errorX = m3x - x2;
const float errorY = m3y - y2;
if (errorX * errorX + errorY * errorY > toleranceSquared)
{
*stackPos++ = y3;
*stackPos++ = x3;
@ -93271,13 +93298,6 @@ bool PathFlatteningIterator::next()
stackPos = stackBase + offset;
}
const float dx1 = x1 - x2;
const float dy1 = y1 - y2;
const float dx2 = x2 - x3;
const float dy2 = y2 - y3;
const float dx3 = x3 - x4;
const float dy3 = y3 - y4;
const float m1x = (x1 + x2) * 0.5f;
const float m1y = (y1 + y2) * 0.5f;
const float m2x = (x3 + x2) * 0.5f;
@ -93289,8 +93309,13 @@ bool PathFlatteningIterator::next()
const float m5x = (m3x + m2x) * 0.5f;
const float m5y = (m3y + m2y) * 0.5f;
if (dx1*dx1 + dy1*dy1 + dx2*dx2
+ dy2*dy2 + dx3*dx3 + dy3*dy3 > tolerence)
const float error1X = m4x - x2;
const float error1Y = m4y - y2;
const float error2X = m5x - x3;
const float error2Y = m5y - y3;
if (error1X * error1X + error1Y * error1Y > toleranceSquared
|| error2X * error2X + error2Y * error2Y > toleranceSquared)
{
*stackPos++ = y4;
*stackPos++ = x4;
@ -93628,7 +93653,7 @@ namespace PathStrokeHelpers
float dx = x2 - x1;
float dy = y2 - y1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len == 0)
{
@ -93705,7 +93730,7 @@ namespace PathStrokeHelpers
LineSection& l = subPath.getReference (subPath.size() - 1);
float dx = l.rx2 - l.rx1;
float dy = l.ry2 - l.ry1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len <= amountAtEnd && subPath.size() > 1)
{
@ -93733,7 +93758,7 @@ namespace PathStrokeHelpers
LineSection& l = subPath.getReference (0);
float dx = l.rx2 - l.rx1;
float dy = l.ry2 - l.ry1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len <= amountAtStart && subPath.size() > 1)
{
@ -93876,6 +93901,8 @@ namespace PathStrokeHelpers
const AffineTransform& transform,
const float extraAccuracy, const Arrowhead* const arrowhead)
{
jassert (extraAccuracy > 0);
if (thickness <= 0)
{
destPath.clear();
@ -93902,7 +93929,7 @@ namespace PathStrokeHelpers
// Iterate the path, creating a list of the
// left/right-hand lines along either side of it...
PathFlatteningIterator it (*sourcePath, transform, 9.0f / extraAccuracy);
PathFlatteningIterator it (*sourcePath, transform, PathFlatteningIterator::defaultTolerance / extraAccuracy);
Array <LineSection> subPath;
subPath.ensureStorageAllocated (512);
@ -93910,7 +93937,7 @@ namespace PathStrokeHelpers
l.x1 = 0;
l.y1 = 0;
const float minSegmentLength = 2.0f / (extraAccuracy * extraAccuracy);
const float minSegmentLength = 0.0001f;
while (it.next())
{
@ -93994,6 +94021,8 @@ void PathStrokeType::createDashedStroke (Path& destPath,
const AffineTransform& transform,
const float extraAccuracy) const
{
jassert (extraAccuracy > 0);
if (thickness <= 0)
return;
@ -94001,7 +94030,7 @@ void PathStrokeType::createDashedStroke (Path& destPath,
jassert ((numDashLengths & 1) == 0);
Path newDestPath;
PathFlatteningIterator it (sourcePath, transform, 9.0f / extraAccuracy);
PathFlatteningIterator it (sourcePath, transform, PathFlatteningIterator::defaultTolerance / extraAccuracy);
bool first = true;
int dashNum = 0;
@ -94037,7 +94066,7 @@ void PathStrokeType::createDashedStroke (Path& destPath,
dx = it.x2 - it.x1;
dy = it.y2 - it.y1;
lineLen = juce_hypotf (dx, dy);
lineLen = juce_hypot (dx, dy);
lineEndPos += lineLen;
first = it.closesSubPath;
}
@ -240547,6 +240576,12 @@ public:
jassertfalse;
}
float getScaleFactor()
{
jassertfalse; //xxx
return 1.0f;
}
bool clipToRectangle (const Rectangle<int>& r)
{
currentState->clipToRectangle (r);
@ -265647,6 +265682,12 @@ public:
lastClipRectIsValid = false;
}
float getScaleFactor()
{
CGAffineTransform t = CGContextGetCTM (context);
return (float) juce_hypot (t.a + t.c, t.b + t.d);
}
bool clipToRectangle (const Rectangle<int>& r)
{
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()));
@ -270377,6 +270418,12 @@ public:
lastClipRectIsValid = false;
}
float getScaleFactor()
{
CGAffineTransform t = CGContextGetCTM (context);
return (float) juce_hypot (t.a + t.c, t.b + t.d);
}
bool clipToRectangle (const Rectangle<int>& r)
{
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()));
@ -273823,7 +273870,6 @@ class JuceMainMenuHandler : private MenuBarModel::Listener,
private DeletedAtShutdown
{
public:
static JuceMainMenuHandler* instance;
JuceMainMenuHandler()
: currentModel (0),
@ -273918,64 +273964,6 @@ public:
}
}
static void flashMenuBar (NSMenu* menu)
{
if ([[menu title] isEqualToString: @"Apple"])
return;
[menu retain];
const unichar f35Key = NSF35FunctionKey;
NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1];
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x"
action: nil
keyEquivalent: f35String];
[item setTarget: nil];
[menu insertItem: item atIndex: [menu numberOfItems]];
[item release];
if ([menu indexOfItem: item] >= 0)
{
NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown
location: NSZeroPoint
modifierFlags: NSCommandKeyMask
timestamp: 0
windowNumber: 0
context: [NSGraphicsContext currentContext]
characters: f35String
charactersIgnoringModifiers: f35String
isARepeat: NO
keyCode: 0];
[menu performKeyEquivalent: f35Event];
if ([menu indexOfItem: item] >= 0)
[menu removeItem: item]; // (this throws if the item isn't actually in the menu)
}
[menu release];
}
static NSMenuItem* findMenuItem (NSMenu* const menu, const ApplicationCommandTarget::InvocationInfo& info)
{
for (NSInteger i = [menu numberOfItems]; --i >= 0;)
{
NSMenuItem* m = [menu itemAtIndex: i];
if ([m tag] == info.commandID)
return m;
if ([m submenu] != 0)
{
NSMenuItem* found = findMenuItem ([m submenu], info);
if (found != 0)
return found;
}
}
return 0;
}
void menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo& info)
{
NSMenuItem* item = findMenuItem ([NSApp mainMenu], info);
@ -273984,8 +273972,16 @@ public:
flashMenuBar ([item menu]);
}
void updateMenus()
void updateMenus (NSMenu* menu)
{
if (PopupMenu::dismissAllActiveMenus())
{
// If we were running a juce menu, then we should let that modal loop finish before allowing
// the OS menus to start their own modal loop - so cancel the menu that was being opened..
if ([menu respondsToSelector: @selector (cancelTracking)])
[menu performSelector: @selector (cancelTracking)];
}
if (Time::getMillisecondCounter() > lastUpdateTime + 500)
menuBarItemsChanged (0);
}
@ -274006,9 +274002,6 @@ public:
}
}
MenuBarModel* currentModel;
uint32 lastUpdateTime;
void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo,
const int topLevelMenuId, const int topLevelIndex)
{
@ -274098,7 +274091,12 @@ public:
}
}
static JuceMainMenuHandler* instance;
MenuBarModel* currentModel;
uint32 lastUpdateTime;
JuceMenuCallback* callback;
private:
NSMenu* createMenu (const PopupMenu menu,
@ -274119,11 +274117,70 @@ private:
[m update];
return m;
}
static NSMenuItem* findMenuItem (NSMenu* const menu, const ApplicationCommandTarget::InvocationInfo& info)
{
for (NSInteger i = [menu numberOfItems]; --i >= 0;)
{
NSMenuItem* m = [menu itemAtIndex: i];
if ([m tag] == info.commandID)
return m;
if ([m submenu] != 0)
{
NSMenuItem* found = findMenuItem ([m submenu], info);
if (found != 0)
return found;
}
}
return 0;
}
static void flashMenuBar (NSMenu* menu)
{
if ([[menu title] isEqualToString: @"Apple"])
return;
[menu retain];
const unichar f35Key = NSF35FunctionKey;
NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1];
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x"
action: nil
keyEquivalent: f35String];
[item setTarget: nil];
[menu insertItem: item atIndex: [menu numberOfItems]];
[item release];
if ([menu indexOfItem: item] >= 0)
{
NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown
location: NSZeroPoint
modifierFlags: NSCommandKeyMask
timestamp: 0
windowNumber: 0
context: [NSGraphicsContext currentContext]
characters: f35String
charactersIgnoringModifiers: f35String
isARepeat: NO
keyCode: 0];
[menu performKeyEquivalent: f35Event];
if ([menu indexOfItem: item] >= 0)
[menu removeItem: item]; // (this throws if the item isn't actually in the menu)
}
[menu release];
}
};
JuceMainMenuHandler* JuceMainMenuHandler::instance = 0;
END_JUCE_NAMESPACE
@implementation JuceMenuCallback
- (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_
@ -274177,10 +274234,8 @@ END_JUCE_NAMESPACE
- (void) menuNeedsUpdate: (NSMenu*) menu;
{
(void) menu;
if (JuceMainMenuHandler::instance != 0)
JuceMainMenuHandler::instance->updateMenus();
JuceMainMenuHandler::instance->updateMenus (menu);
}
@end

View file

@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 103
#define JUCE_BUILDNUMBER 104
/** Current Juce version number.
@ -1261,25 +1261,15 @@ inline void swapVariables (Type& variable1, Type& variable2)
// Some useful maths functions that aren't always present with all compilers and build settings.
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
versions of these functions of various platforms and compilers. */
inline double juce_hypot (double a, double b) throw()
/** Using juce_hypot is easier than dealing with the different types of hypot function
that are provided by the various platforms and compilers. */
template <typename Type>
inline Type juce_hypot (Type a, Type b) throw()
{
#if JUCE_WINDOWS
return _hypot (a, b);
return static_cast <Type> (_hypot (a, b));
#else
return hypot (a, b);
#endif
}
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
versions of these functions of various platforms and compilers. */
inline float juce_hypotf (float a, float b) throw()
{
#if JUCE_WINDOWS
return (float) _hypot (a, b);
#else
return hypotf (a, b);
return static_cast <Type> (hypot (a, b));
#endif
}
@ -19796,6 +19786,12 @@ public:
*/
float getTranslationY() const throw() { return mat12; }
/** Returns the approximate scale factor by which lengths will be transformed.
Obviously a length may be scaled by entirely different amounts depending on its
direction, so this is only appropriate as a rough guide.
*/
float getScaleFactor() const throw();
/* The transform matrix is:
(mat00 mat01 mat02)
@ -19902,10 +19898,10 @@ public:
const Point operator-() const throw() { return Point (-x, -y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFromOrigin() const throw() { return (ValueType) juce_hypot (x, y); }
ValueType getDistanceFromOrigin() const throw() { return juce_hypot (x, y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFrom (const Point& other) const throw() { return (ValueType) juce_hypot (x - other.x, y - other.y); }
ValueType getDistanceFrom (const Point& other) const throw() { return juce_hypot (x - other.x, y - other.y); }
/** Returns the angle from this point to another one.
@ -20872,7 +20868,8 @@ public:
ValueType perpendicularDistance) const throw()
{
const Point<ValueType> delta (end - start);
const double length = juce_hypot (delta.getX(), delta.getY());
const double length = juce_hypot ((double) delta.getX(),
(double) delta.getY());
if (length == 0)
return start;
@ -21985,14 +21982,14 @@ public:
The path's winding rule is taken into account by this method.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
@see closeSubPath, setUsingNonZeroWinding
*/
bool contains (float x, float y,
float tolerence = 10.0f) const;
float tolerance = 1.0f) const;
/** Checks whether a point lies within the path.
@ -22001,14 +21998,14 @@ public:
The path's winding rule is taken into account by this method.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
@see closeSubPath, setUsingNonZeroWinding
*/
bool contains (const Point<float>& point,
float tolerence = 10.0f) const;
float tolerance = 1.0f) const;
/** Checks whether a line crosses the path.
@ -22016,12 +22013,12 @@ public:
lines or curves. It doesn't take into account whether the line is inside
or outside the path, or whether the path is open or closed.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
*/
bool intersectsLine (const Line<float>& line,
float tolerence = 10.0f);
float tolerance = 1.0f);
/** Cuts off parts of a line to keep the parts that are either inside or
outside this path.
@ -23214,8 +23211,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
@see createDashedStroke
*/
@ -23243,8 +23241,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
*/
void createDashedStroke (Path& destPath,
const Path& sourcePath,
@ -23267,8 +23266,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
@see createDashedStroke
*/
void createStrokeWithArrowheads (Path& destPath,
@ -37307,7 +37307,7 @@ public:
by some means other than a user action, and you'd like to make sure that menus
aren't left hanging around.
*/
static void JUCE_CALLTYPE dismissAllActiveMenus();
static bool JUCE_CALLTYPE dismissAllActiveMenus();
/** Specifies a look-and-feel for the menu and any sub-menus that it has.
@ -60277,6 +60277,7 @@ public:
*/
virtual void setOrigin (int x, int y) = 0;
virtual void addTransform (const AffineTransform& transform) = 0;
virtual float getScaleFactor() = 0;
virtual bool clipToRectangle (const Rectangle<int>& r) = 0;
virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0;
@ -60342,6 +60343,7 @@ public:
bool isVectorDevice() const;
void setOrigin (int x, int y);
void addTransform (const AffineTransform& transform);
float getScaleFactor();
bool clipToRectangle (const Rectangle<int>& r);
bool clipToRectangleList (const RectangleList& clipRegion);
@ -60440,6 +60442,7 @@ public:
void setOrigin (int x, int y);
void addTransform (const AffineTransform& transform);
float getScaleFactor();
bool clipToRectangle (const Rectangle<int>& r);
bool clipToRectangleList (const RectangleList& clipRegion);
@ -61417,13 +61420,13 @@ public:
@param path the path to iterate along
@param transform a transform to apply to each point in the path being iterated
@param tolerence the amount by which the curves are allowed to deviate from the
lines into which they are being broken down - a higher tolerence
is a bit faster, but less smooth.
@param tolerance the amount by which the curves are allowed to deviate from the lines
into which they are being broken down - a higher tolerance contains
less lines, so can be generated faster, but will be less smooth.
*/
PathFlatteningIterator (const Path& path,
const AffineTransform& transform = AffineTransform::identity,
float tolerence = 6.0f);
float tolerance = defaultTolerance);
/** Destructor. */
~PathFlatteningIterator();
@ -61460,12 +61463,16 @@ public:
bool isLastInSubpath() const throw() { return stackPos == stackBase.getData()
&& (index >= path.numElements || points [index] == Path::moveMarker); }
/** This is the default value that should be used for the tolerance value (see the constructor parameters). */
static const float defaultTolerance;
private:
const Path& path;
const AffineTransform transform;
float* points;
float tolerence, subPathCloseX, subPathCloseY;
const float toleranceSquared;
float subPathCloseX, subPathCloseY;
const bool isIdentityTransform;
HeapBlock <float> stackBase;

View file

@ -292,25 +292,15 @@ inline void swapVariables (Type& variable1, Type& variable2)
//==============================================================================
// Some useful maths functions that aren't always present with all compilers and build settings.
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
versions of these functions of various platforms and compilers. */
inline double juce_hypot (double a, double b) throw()
/** Using juce_hypot is easier than dealing with the different types of hypot function
that are provided by the various platforms and compilers. */
template <typename Type>
inline Type juce_hypot (Type a, Type b) throw()
{
#if JUCE_WINDOWS
return _hypot (a, b);
return static_cast <Type> (_hypot (a, b));
#else
return hypot (a, b);
#endif
}
/** Using juce_hypot and juce_hypotf is easier than dealing with all the different
versions of these functions of various platforms and compilers. */
inline float juce_hypotf (float a, float b) throw()
{
#if JUCE_WINDOWS
return (float) _hypot (a, b);
#else
return hypotf (a, b);
return static_cast <Type> (hypot (a, b));
#endif
}

View file

@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 103
#define JUCE_BUILDNUMBER 104
/** Current Juce version number.

View file

@ -274,7 +274,9 @@ void Desktop::triggerFocusCallback()
void Desktop::handleAsyncUpdate()
{
Component* currentFocus = Component::getCurrentlyFocusedComponent();
// The component may be deleted during this operation, but we'll use a SafePointer rather than a
// BailOutChecker so that any remaining listeners will still get a callback (with a null pointer).
Component::SafePointer<Component> currentFocus (Component::getCurrentlyFocusedComponent());
focusListeners.call (&FocusChangeListener::globalFocusChanged, currentFocus);
}

View file

@ -1528,15 +1528,18 @@ int PopupMenu::showAt (Component* componentToAttachTo,
}
}
void JUCE_CALLTYPE PopupMenu::dismissAllActiveMenus()
bool JUCE_CALLTYPE PopupMenu::dismissAllActiveMenus()
{
for (int i = Window::getActiveWindows().size(); --i >= 0;)
const int numWindows = Window::getActiveWindows().size();
for (int i = numWindows; --i >= 0;)
{
Window* const pmw = Window::getActiveWindows()[i];
if (pmw != 0)
pmw->dismissMenu (0);
}
return numWindows > 0;
}
//==============================================================================

View file

@ -295,7 +295,7 @@ public:
by some means other than a user action, and you'd like to make sure that menus
aren't left hanging around.
*/
static void JUCE_CALLTYPE dismissAllActiveMenus();
static bool JUCE_CALLTYPE dismissAllActiveMenus();
//==============================================================================

View file

@ -375,7 +375,7 @@ void Graphics::strokePath (const Path& path,
const AffineTransform& transform) const
{
Path stroke;
strokeType.createStrokedPath (stroke, path, transform);
strokeType.createStrokedPath (stroke, path, transform, context->getScaleFactor());
fillPath (stroke);
}

View file

@ -67,6 +67,7 @@ public:
*/
virtual void setOrigin (int x, int y) = 0;
virtual void addTransform (const AffineTransform& transform) = 0;
virtual float getScaleFactor() = 0;
virtual bool clipToRectangle (const Rectangle<int>& r) = 0;
virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0;

View file

@ -118,6 +118,12 @@ void LowLevelGraphicsPostScriptRenderer::addTransform (const AffineTransform& /*
jassertfalse;
}
float LowLevelGraphicsPostScriptRenderer::getScaleFactor()
{
jassertfalse; //xxx
return 1.0f;
}
bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (const Rectangle<int>& r)
{
needToClip = true;

View file

@ -50,6 +50,7 @@ public:
bool isVectorDevice() const;
void setOrigin (int x, int y);
void addTransform (const AffineTransform& transform);
float getScaleFactor();
bool clipToRectangle (const Rectangle<int>& r);
bool clipToRectangleList (const RectangleList& clipRegion);

View file

@ -1843,6 +1843,11 @@ public:
}
}
float getScaleFactor() const
{
return isOnlyTranslated ? 1.0f : complexTransform.getScaleFactor();
}
bool clipToRectangle (const Rectangle<int>& r)
{
if (clip != 0)
@ -2254,6 +2259,11 @@ void LowLevelGraphicsSoftwareRenderer::addTransform (const AffineTransform& tran
currentState->addTransform (transform);
}
float LowLevelGraphicsSoftwareRenderer::getScaleFactor()
{
return currentState->getScaleFactor();
}
bool LowLevelGraphicsSoftwareRenderer::clipToRectangle (const Rectangle<int>& r)
{
return currentState->clipToRectangle (r);

View file

@ -50,6 +50,7 @@ public:
//==============================================================================
void setOrigin (int x, int y);
void addTransform (const AffineTransform& transform);
float getScaleFactor();
bool clipToRectangle (const Rectangle<int>& r);
bool clipToRectangleList (const RectangleList& clipRegion);

View file

@ -819,7 +819,7 @@ private:
float x = getCoordLength (strokeWidth, viewBoxW), y = 0.0f;
transform.transformPoints (ox, oy, x, y);
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypotf (x - ox, y - oy) : 1.0f,
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypot (x - ox, y - oy) : 1.0f,
joinStyle, capStyle);
}

View file

@ -244,5 +244,10 @@ bool AffineTransform::isOnlyTranslation() const throw()
&& (mat11 == 1.0f);
}
float AffineTransform::getScaleFactor() const throw()
{
return juce_hypot (mat00 + mat01, mat10 + mat11);
}
END_JUCE_NAMESPACE

View file

@ -232,6 +232,12 @@ public:
*/
float getTranslationY() const throw() { return mat12; }
/** Returns the approximate scale factor by which lengths will be transformed.
Obviously a length may be scaled by entirely different amounts depending on its
direction, so this is only appropriate as a rough guide.
*/
float getScaleFactor() const throw();
//==============================================================================
/* The transform matrix is:

View file

@ -209,7 +209,8 @@ public:
ValueType perpendicularDistance) const throw()
{
const Point<ValueType> delta (end - start);
const double length = juce_hypot (delta.getX(), delta.getY());
const double length = juce_hypot ((double) delta.getX(),
(double) delta.getY());
if (length == 0)
return start;

View file

@ -55,6 +55,11 @@ namespace PathHelpers
return String (start, (int) (t - start));
}
inline double lengthOf (float x1, float y1, float x2, float y2) throw()
{
return juce_hypot ((double) (x1 - x2), (double) (y1 - y2));
}
}
//==============================================================================
@ -966,13 +971,13 @@ const AffineTransform Path::getTransformToScaleToFit (const float x, const float
}
//==============================================================================
bool Path::contains (const float x, const float y, const float tolerence) const
bool Path::contains (const float x, const float y, const float tolerance) const
{
if (x <= pathXMin || x >= pathXMax
|| y <= pathYMin || y >= pathYMax)
return false;
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
PathFlatteningIterator i (*this, AffineTransform::identity, tolerance);
int positiveCrossings = 0;
int negativeCrossings = 0;
@ -997,14 +1002,14 @@ bool Path::contains (const float x, const float y, const float tolerence) const
: ((negativeCrossings + positiveCrossings) & 1) != 0;
}
bool Path::contains (const Point<float>& point, const float tolerence) const
bool Path::contains (const Point<float>& point, const float tolerance) const
{
return contains (point.getX(), point.getY(), tolerence);
return contains (point.getX(), point.getY(), tolerance);
}
bool Path::intersectsLine (const Line<float>& line, const float tolerence)
bool Path::intersectsLine (const Line<float>& line, const float tolerance)
{
PathFlatteningIterator i (*this, AffineTransform::identity, tolerence);
PathFlatteningIterator i (*this, AffineTransform::identity, tolerance);
Point<float> intersection;
while (i.next())
@ -1158,8 +1163,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
if (lastWasLine)
{
const double len1 = juce_hypot (startX - joinX,
startY - joinY);
const double len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
if (len1 > 0)
{
@ -1169,8 +1173,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
p.data.elements [p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
}
const double len2 = juce_hypot (endX - joinX,
endY - joinY);
const double len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
if (len2 > 0)
{
@ -1200,8 +1203,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
endX = data.elements [indexOfPathStartThis + 4];
endY = data.elements [indexOfPathStartThis + 5];
const double len1 = juce_hypot (startX - joinX,
startY - joinY);
const double len1 = PathHelpers::lengthOf (startX, startY, joinX, joinY);
if (len1 > 0)
{
@ -1211,8 +1213,7 @@ const Path Path::createPathWithRoundedCorners (const float cornerRadius) const
p.data.elements [p.numElements - 1] = (float) (joinY - (joinY - startY) * propNeeded);
}
const double len2 = juce_hypot (endX - joinX,
endY - joinY);
const double len2 = PathHelpers::lengthOf (endX, endY, joinX, joinY);
if (len2 > 0)
{

View file

@ -107,14 +107,14 @@ public:
The path's winding rule is taken into account by this method.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
@see closeSubPath, setUsingNonZeroWinding
*/
bool contains (float x, float y,
float tolerence = 10.0f) const;
float tolerance = 1.0f) const;
/** Checks whether a point lies within the path.
@ -123,14 +123,14 @@ public:
The path's winding rule is taken into account by this method.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
@see closeSubPath, setUsingNonZeroWinding
*/
bool contains (const Point<float>& point,
float tolerence = 10.0f) const;
float tolerance = 1.0f) const;
/** Checks whether a line crosses the path.
@ -138,12 +138,12 @@ public:
lines or curves. It doesn't take into account whether the line is inside
or outside the path, or whether the path is open or closed.
The tolerence parameter is passed to the PathFlatteningIterator that
is used to trace the path - for more info about it, see the notes for
the PathFlatteningIterator constructor.
The tolerance parameter is the maximum error allowed when flattening the path,
so this method could return a false positive when your point is up to this distance
outside the path's boundary.
*/
bool intersectsLine (const Line<float>& line,
float tolerence = 10.0f);
float tolerance = 1.0f);
/** Cuts off parts of a line to keep the parts that are either inside or
outside this path.

View file

@ -33,10 +33,14 @@ BEGIN_JUCE_NAMESPACE
#pragma optimize ("t", on)
#endif
//==============================================================================
const float PathFlatteningIterator::defaultTolerance = 0.6f;
//==============================================================================
PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
const AffineTransform& transform_,
float tolerence_)
const float tolerance)
: x2 (0),
y2 (0),
closesSubPath (false),
@ -44,7 +48,7 @@ PathFlatteningIterator::PathFlatteningIterator (const Path& path_,
path (path_),
transform (transform_),
points (path_.data.elements),
tolerence (tolerence_ * tolerence_),
toleranceSquared (tolerance * tolerance),
subPathCloseX (0),
subPathCloseY (0),
isIdentityTransform (transform_.isIdentity()),
@ -160,11 +164,6 @@ bool PathFlatteningIterator::next()
stackPos = stackBase + offset;
}
const float dx1 = x1 - x2;
const float dy1 = y1 - y2;
const float dx2 = x2 - x3;
const float dy2 = y2 - y3;
const float m1x = (x1 + x2) * 0.5f;
const float m1y = (y1 + y2) * 0.5f;
const float m2x = (x2 + x3) * 0.5f;
@ -172,7 +171,10 @@ bool PathFlatteningIterator::next()
const float m3x = (m1x + m2x) * 0.5f;
const float m3y = (m1y + m2y) * 0.5f;
if (dx1*dx1 + dy1*dy1 + dx2*dx2 + dy2*dy2 > tolerence)
const float errorX = m3x - x2;
const float errorY = m3y - y2;
if (errorX * errorX + errorY * errorY > toleranceSquared)
{
*stackPos++ = y3;
*stackPos++ = x3;
@ -210,13 +212,6 @@ bool PathFlatteningIterator::next()
stackPos = stackBase + offset;
}
const float dx1 = x1 - x2;
const float dy1 = y1 - y2;
const float dx2 = x2 - x3;
const float dy2 = y2 - y3;
const float dx3 = x3 - x4;
const float dy3 = y3 - y4;
const float m1x = (x1 + x2) * 0.5f;
const float m1y = (y1 + y2) * 0.5f;
const float m2x = (x3 + x2) * 0.5f;
@ -228,8 +223,13 @@ bool PathFlatteningIterator::next()
const float m5x = (m3x + m2x) * 0.5f;
const float m5y = (m3y + m2y) * 0.5f;
if (dx1*dx1 + dy1*dy1 + dx2*dx2
+ dy2*dy2 + dx3*dx3 + dy3*dy3 > tolerence)
const float error1X = m4x - x2;
const float error1Y = m4y - y2;
const float error2X = m5x - x3;
const float error2Y = m5y - y3;
if (error1X * error1X + error1Y * error1Y > toleranceSquared
|| error2X * error2X + error2Y * error2Y > toleranceSquared)
{
*stackPos++ = y4;
*stackPos++ = x4;

View file

@ -50,13 +50,13 @@ public:
@param path the path to iterate along
@param transform a transform to apply to each point in the path being iterated
@param tolerence the amount by which the curves are allowed to deviate from the
lines into which they are being broken down - a higher tolerence
is a bit faster, but less smooth.
@param tolerance the amount by which the curves are allowed to deviate from the lines
into which they are being broken down - a higher tolerance contains
less lines, so can be generated faster, but will be less smooth.
*/
PathFlatteningIterator (const Path& path,
const AffineTransform& transform = AffineTransform::identity,
float tolerence = 6.0f);
float tolerance = defaultTolerance);
/** Destructor. */
~PathFlatteningIterator();
@ -94,12 +94,17 @@ public:
bool isLastInSubpath() const throw() { return stackPos == stackBase.getData()
&& (index >= path.numElements || points [index] == Path::moveMarker); }
/** This is the default value that should be used for the tolerance value (see the constructor parameters). */
static const float defaultTolerance;
private:
//==============================================================================
const Path& path;
const AffineTransform transform;
float* points;
float tolerence, subPathCloseX, subPathCloseY;
const float toleranceSquared;
float subPathCloseX, subPathCloseY;
const bool isIdentityTransform;
HeapBlock <float> stackBase;

View file

@ -303,7 +303,7 @@ namespace PathStrokeHelpers
float dx = x2 - x1;
float dy = y2 - y1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len == 0)
{
@ -380,7 +380,7 @@ namespace PathStrokeHelpers
LineSection& l = subPath.getReference (subPath.size() - 1);
float dx = l.rx2 - l.rx1;
float dy = l.ry2 - l.ry1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len <= amountAtEnd && subPath.size() > 1)
{
@ -408,7 +408,7 @@ namespace PathStrokeHelpers
LineSection& l = subPath.getReference (0);
float dx = l.rx2 - l.rx1;
float dy = l.ry2 - l.ry1;
const float len = juce_hypotf (dx, dy);
const float len = juce_hypot (dx, dy);
if (len <= amountAtStart && subPath.size() > 1)
{
@ -551,6 +551,8 @@ namespace PathStrokeHelpers
const AffineTransform& transform,
const float extraAccuracy, const Arrowhead* const arrowhead)
{
jassert (extraAccuracy > 0);
if (thickness <= 0)
{
destPath.clear();
@ -577,7 +579,7 @@ namespace PathStrokeHelpers
// Iterate the path, creating a list of the
// left/right-hand lines along either side of it...
PathFlatteningIterator it (*sourcePath, transform, 9.0f / extraAccuracy);
PathFlatteningIterator it (*sourcePath, transform, PathFlatteningIterator::defaultTolerance / extraAccuracy);
Array <LineSection> subPath;
subPath.ensureStorageAllocated (512);
@ -585,7 +587,7 @@ namespace PathStrokeHelpers
l.x1 = 0;
l.y1 = 0;
const float minSegmentLength = 2.0f / (extraAccuracy * extraAccuracy);
const float minSegmentLength = 0.0001f;
while (it.next())
{
@ -669,6 +671,8 @@ void PathStrokeType::createDashedStroke (Path& destPath,
const AffineTransform& transform,
const float extraAccuracy) const
{
jassert (extraAccuracy > 0);
if (thickness <= 0)
return;
@ -676,7 +680,7 @@ void PathStrokeType::createDashedStroke (Path& destPath,
jassert ((numDashLengths & 1) == 0);
Path newDestPath;
PathFlatteningIterator it (sourcePath, transform, 9.0f / extraAccuracy);
PathFlatteningIterator it (sourcePath, transform, PathFlatteningIterator::defaultTolerance / extraAccuracy);
bool first = true;
int dashNum = 0;
@ -712,7 +716,7 @@ void PathStrokeType::createDashedStroke (Path& destPath,
dx = it.x2 - it.x1;
dy = it.y2 - it.y1;
lineLen = juce_hypotf (dx, dy);
lineLen = juce_hypot (dx, dy);
lineEndPos += lineLen;
first = it.closesSubPath;
}

View file

@ -96,8 +96,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
@see createDashedStroke
*/
@ -127,8 +128,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
*/
void createDashedStroke (Path& destPath,
const Path& sourcePath,
@ -152,8 +154,9 @@ public:
@param transform an optional transform to apply to the points from the source path
as they are being used
@param extraAccuracy if this is greater than 1.0, it will subdivide the path to
a higher resolution, which improved the quality if you'll later want
to enlarge the stroked path
a higher resolution, which improves the quality if you'll later want
to enlarge the stroked path. So for example, if you're planning on drawing
the stroke at 3x the size that you're creating it, you should set this to 3.
@see createDashedStroke
*/
void createStrokeWithArrowheads (Path& destPath,

View file

@ -120,10 +120,10 @@ public:
const Point operator-() const throw() { return Point (-x, -y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFromOrigin() const throw() { return (ValueType) juce_hypot (x, y); }
ValueType getDistanceFromOrigin() const throw() { return juce_hypot (x, y); }
/** Returns the straight-line distance between this point and another one. */
ValueType getDistanceFrom (const Point& other) const throw() { return (ValueType) juce_hypot (x - other.x, y - other.y); }
ValueType getDistanceFrom (const Point& other) const throw() { return juce_hypot (x - other.x, y - other.y); }
/** Returns the angle from this point to another one.

View file

@ -192,6 +192,12 @@ public:
lastClipRectIsValid = false;
}
float getScaleFactor()
{
CGAffineTransform t = CGContextGetCTM (context);
return (float) juce_hypot (t.a + t.c, t.b + t.d);
}
bool clipToRectangle (const Rectangle<int>& r)
{
CGContextClipToRect (context, CGRectMake (r.getX(), flipHeight - r.getBottom(), r.getWidth(), r.getHeight()));

View file

@ -57,8 +57,6 @@ class JuceMainMenuHandler : private MenuBarModel::Listener,
private DeletedAtShutdown
{
public:
static JuceMainMenuHandler* instance;
//==============================================================================
JuceMainMenuHandler()
: currentModel (0),
@ -153,64 +151,6 @@ public:
}
}
static void flashMenuBar (NSMenu* menu)
{
if ([[menu title] isEqualToString: @"Apple"])
return;
[menu retain];
const unichar f35Key = NSF35FunctionKey;
NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1];
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x"
action: nil
keyEquivalent: f35String];
[item setTarget: nil];
[menu insertItem: item atIndex: [menu numberOfItems]];
[item release];
if ([menu indexOfItem: item] >= 0)
{
NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown
location: NSZeroPoint
modifierFlags: NSCommandKeyMask
timestamp: 0
windowNumber: 0
context: [NSGraphicsContext currentContext]
characters: f35String
charactersIgnoringModifiers: f35String
isARepeat: NO
keyCode: 0];
[menu performKeyEquivalent: f35Event];
if ([menu indexOfItem: item] >= 0)
[menu removeItem: item]; // (this throws if the item isn't actually in the menu)
}
[menu release];
}
static NSMenuItem* findMenuItem (NSMenu* const menu, const ApplicationCommandTarget::InvocationInfo& info)
{
for (NSInteger i = [menu numberOfItems]; --i >= 0;)
{
NSMenuItem* m = [menu itemAtIndex: i];
if ([m tag] == info.commandID)
return m;
if ([m submenu] != 0)
{
NSMenuItem* found = findMenuItem ([m submenu], info);
if (found != 0)
return found;
}
}
return 0;
}
void menuCommandInvoked (MenuBarModel*, const ApplicationCommandTarget::InvocationInfo& info)
{
NSMenuItem* item = findMenuItem ([NSApp mainMenu], info);
@ -219,8 +159,16 @@ public:
flashMenuBar ([item menu]);
}
void updateMenus()
void updateMenus (NSMenu* menu)
{
if (PopupMenu::dismissAllActiveMenus())
{
// If we were running a juce menu, then we should let that modal loop finish before allowing
// the OS menus to start their own modal loop - so cancel the menu that was being opened..
if ([menu respondsToSelector: @selector (cancelTracking)])
[menu performSelector: @selector (cancelTracking)];
}
if (Time::getMillisecondCounter() > lastUpdateTime + 500)
menuBarItemsChanged (0);
}
@ -241,9 +189,6 @@ public:
}
}
MenuBarModel* currentModel;
uint32 lastUpdateTime;
void addMenuItem (PopupMenu::MenuItemIterator& iter, NSMenu* menuToAddTo,
const int topLevelMenuId, const int topLevelIndex)
{
@ -333,9 +278,14 @@ public:
}
}
JuceMenuCallback* callback;
private:
static JuceMainMenuHandler* instance;
MenuBarModel* currentModel;
uint32 lastUpdateTime;
JuceMenuCallback* callback;
private:
//==============================================================================
NSMenu* createMenu (const PopupMenu menu,
const String& menuName,
const int topLevelMenuId,
@ -354,11 +304,71 @@ private:
[m update];
return m;
}
static NSMenuItem* findMenuItem (NSMenu* const menu, const ApplicationCommandTarget::InvocationInfo& info)
{
for (NSInteger i = [menu numberOfItems]; --i >= 0;)
{
NSMenuItem* m = [menu itemAtIndex: i];
if ([m tag] == info.commandID)
return m;
if ([m submenu] != 0)
{
NSMenuItem* found = findMenuItem ([m submenu], info);
if (found != 0)
return found;
}
}
return 0;
}
static void flashMenuBar (NSMenu* menu)
{
if ([[menu title] isEqualToString: @"Apple"])
return;
[menu retain];
const unichar f35Key = NSF35FunctionKey;
NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1];
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: @"x"
action: nil
keyEquivalent: f35String];
[item setTarget: nil];
[menu insertItem: item atIndex: [menu numberOfItems]];
[item release];
if ([menu indexOfItem: item] >= 0)
{
NSEvent* f35Event = [NSEvent keyEventWithType: NSKeyDown
location: NSZeroPoint
modifierFlags: NSCommandKeyMask
timestamp: 0
windowNumber: 0
context: [NSGraphicsContext currentContext]
characters: f35String
charactersIgnoringModifiers: f35String
isARepeat: NO
keyCode: 0];
[menu performKeyEquivalent: f35Event];
if ([menu indexOfItem: item] >= 0)
[menu removeItem: item]; // (this throws if the item isn't actually in the menu)
}
[menu release];
}
};
JuceMainMenuHandler* JuceMainMenuHandler::instance = 0;
END_JUCE_NAMESPACE
//==============================================================================
@implementation JuceMenuCallback
- (JuceMenuCallback*) initWithOwner: (JuceMainMenuHandler*) owner_
@ -412,10 +422,8 @@ END_JUCE_NAMESPACE
- (void) menuNeedsUpdate: (NSMenu*) menu;
{
(void) menu;
if (JuceMainMenuHandler::instance != 0)
JuceMainMenuHandler::instance->updateMenus();
JuceMainMenuHandler::instance->updateMenus (menu);
}
@end

View file

@ -125,6 +125,12 @@ public:
jassertfalse;
}
float getScaleFactor()
{
jassertfalse; //xxx
return 1.0f;
}
bool clipToRectangle (const Rectangle<int>& r)
{
currentState->clipToRectangle (r);