| @@ -40,7 +40,7 @@ public: | |||||
| { | { | ||||
| hash = in.readInt64(); | hash = in.readInt64(); | ||||
| const int64 len = in.readInt64(); | const int64 len = in.readInt64(); | ||||
| in.readIntoMemoryBlock (data, len); | |||||
| in.readIntoMemoryBlock (data, (ssize_t) len); | |||||
| } | } | ||||
| void write (OutputStream& out) | void write (OutputStream& out) | ||||
| @@ -91,6 +91,10 @@ typedef unsigned int uint32; | |||||
| typedef unsigned int pointer_sized_uint; | typedef unsigned int pointer_sized_uint; | ||||
| #endif | #endif | ||||
| #if JUCE_MSVC | |||||
| typedef pointer_sized_int ssize_t; | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| // Some indispensible min/max functions | // Some indispensible min/max functions | ||||
| @@ -351,6 +355,10 @@ inline bool juce_isfinite (FloatingPointType value) | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| #if JUCE_MSVC | |||||
| #pragma optimize ("t", off) | |||||
| #endif | |||||
| /** Fast floating-point-to-integer conversion. | /** Fast floating-point-to-integer conversion. | ||||
| This is faster than using the normal c++ cast to convert a float to an int, and | This is faster than using the normal c++ cast to convert a float to an int, and | ||||
| @@ -374,6 +382,10 @@ inline int roundToInt (const FloatType value) noexcept | |||||
| #endif | #endif | ||||
| } | } | ||||
| #if JUCE_MSVC | |||||
| #pragma optimize ("", on) // resets optimisations to the project defaults | |||||
| #endif | |||||
| /** Fast floating-point-to-integer conversion. | /** Fast floating-point-to-integer conversion. | ||||
| This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works | This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works | ||||
| @@ -424,6 +436,19 @@ bool isPowerOfTwo (IntegerType value) | |||||
| return (value & (value - 1)) == 0; | return (value & (value - 1)) == 0; | ||||
| } | } | ||||
| /** Returns the next power-of-two which is equal to or greater than the given integer. | |||||
| */ | |||||
| inline int nextPowerOfTwo (int n) | |||||
| { | |||||
| --n; | |||||
| n |= (n >> 1); | |||||
| n |= (n >> 2); | |||||
| n |= (n >> 4); | |||||
| n |= (n >> 8); | |||||
| n |= (n >> 16); | |||||
| return n + 1; | |||||
| } | |||||
| /** Performs a modulo operation, but can cope with the dividend being negative. | /** Performs a modulo operation, but can cope with the dividend being negative. | ||||
| The divisor must be greater than zero. | The divisor must be greater than zero. | ||||
| */ | */ | ||||
| @@ -199,7 +199,7 @@ String InputStream::readNextLine() | |||||
| return String::fromUTF8 (data, (int) i); | return String::fromUTF8 (data, (int) i); | ||||
| } | } | ||||
| int InputStream::readIntoMemoryBlock (MemoryBlock& block, int numBytes) | |||||
| int InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes) | |||||
| { | { | ||||
| MemoryOutputStream mo (block, true); | MemoryOutputStream mo (block, true); | ||||
| return mo.writeFromInputStream (*this, numBytes); | return mo.writeFromInputStream (*this, numBytes); | ||||
| @@ -245,7 +245,7 @@ public: | |||||
| @returns the number of bytes that were added to the memory block | @returns the number of bytes that were added to the memory block | ||||
| */ | */ | ||||
| virtual int readIntoMemoryBlock (MemoryBlock& destBlock, | virtual int readIntoMemoryBlock (MemoryBlock& destBlock, | ||||
| int maxNumBytesToRead = -1); | |||||
| ssize_t maxNumBytesToRead = -1); | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns the offset of the next byte that will be read from the stream. | /** Returns the offset of the next byte that will be read from the stream. | ||||
| @@ -231,14 +231,33 @@ Font Graphics::getCurrentFont() const | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| void Graphics::drawSingleLineText (const String& text, const int startX, const int baselineY) const | |||||
| void Graphics::drawSingleLineText (const String& text, const int startX, const int baselineY, | |||||
| const Justification& justification) const | |||||
| { | { | ||||
| if (text.isNotEmpty() | if (text.isNotEmpty() | ||||
| && startX < context->getClipBounds().getRight()) | && startX < context->getClipBounds().getRight()) | ||||
| { | { | ||||
| GlyphArrangement arr; | GlyphArrangement arr; | ||||
| arr.addLineOfText (context->getFont(), text, (float) startX, (float) baselineY); | arr.addLineOfText (context->getFont(), text, (float) startX, (float) baselineY); | ||||
| arr.draw (*this); | |||||
| // Don't pass any vertical placement flags to this method - they'll be ignored. | |||||
| jassert (justification.getOnlyVerticalFlags() == 0); | |||||
| const int flags = justification.getOnlyHorizontalFlags(); | |||||
| if (flags != Justification::left) | |||||
| { | |||||
| float w = arr.getBoundingBox (0, -1, true).getWidth(); | |||||
| if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0) | |||||
| w /= 2.0f; | |||||
| arr.draw (*this, AffineTransform::translation (-w, 0)); | |||||
| } | |||||
| else | |||||
| { | |||||
| arr.draw (*this); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -138,13 +138,16 @@ public: | |||||
| This will use the current colour (or brush) to fill the text. The font is the last | This will use the current colour (or brush) to fill the text. The font is the last | ||||
| one specified by setFont(). | one specified by setFont(). | ||||
| @param text the string to draw | |||||
| @param startX the position to draw the left-hand edge of the text | |||||
| @param baselineY the position of the text's baseline | |||||
| @param text the string to draw | |||||
| @param startX the position to draw the left-hand edge of the text | |||||
| @param baselineY the position of the text's baseline | |||||
| @param justification the horizontal flags indicate which end of the text string is | |||||
| anchored at the specified point. | |||||
| @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText | @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText | ||||
| */ | */ | ||||
| void drawSingleLineText (const String& text, | void drawSingleLineText (const String& text, | ||||
| int startX, int baselineY) const; | |||||
| int startX, int baselineY, | |||||
| const Justification& justification = Justification::left) const; | |||||
| /** Draws text across multiple lines. | /** Draws text across multiple lines. | ||||
| @@ -1012,7 +1012,7 @@ public: | |||||
| virtual Ptr clipToPath (const Path& p, const AffineTransform& transform) = 0; | virtual Ptr clipToPath (const Path& p, const AffineTransform& transform) = 0; | ||||
| virtual Ptr clipToEdgeTable (const EdgeTable& et) = 0; | virtual Ptr clipToEdgeTable (const EdgeTable& et) = 0; | ||||
| virtual Ptr clipToImageAlpha (const Image& image, const AffineTransform& t, const bool betterQuality) = 0; | virtual Ptr clipToImageAlpha (const Image& image, const AffineTransform& t, const bool betterQuality) = 0; | ||||
| virtual Ptr translated (const Point<int>& delta) = 0; | |||||
| virtual void translate (const Point<int>& delta) = 0; | |||||
| virtual bool clipRegionIntersects (const Rectangle<int>& r) const = 0; | virtual bool clipRegionIntersects (const Rectangle<int>& r) const = 0; | ||||
| virtual Rectangle<int> getClipBounds() const = 0; | virtual Rectangle<int> getClipBounds() const = 0; | ||||
| @@ -1294,10 +1294,9 @@ public: | |||||
| return edgeTable.isEmpty() ? nullptr : this; | return edgeTable.isEmpty() ? nullptr : this; | ||||
| } | } | ||||
| Ptr translated (const Point<int>& delta) | |||||
| void translate (const Point<int>& delta) | |||||
| { | { | ||||
| edgeTable.translate ((float) delta.getX(), delta.getY()); | edgeTable.translate ((float) delta.getX(), delta.getY()); | ||||
| return edgeTable.isEmpty() ? nullptr : this; | |||||
| } | } | ||||
| bool clipRegionIntersects (const Rectangle<int>& r) const | bool clipRegionIntersects (const Rectangle<int>& r) const | ||||
| @@ -1451,10 +1450,9 @@ public: | |||||
| return toEdgeTable()->clipToImageAlpha (image, transform, betterQuality); | return toEdgeTable()->clipToImageAlpha (image, transform, betterQuality); | ||||
| } | } | ||||
| Ptr translated (const Point<int>& delta) | |||||
| void translate (const Point<int>& delta) | |||||
| { | { | ||||
| clip.offsetAll (delta.getX(), delta.getY()); | clip.offsetAll (delta.getX(), delta.getY()); | ||||
| return clip.isEmpty() ? nullptr : this; | |||||
| } | } | ||||
| bool clipRegionIntersects (const Rectangle<int>& r) const | bool clipRegionIntersects (const Rectangle<int>& r) const | ||||
| @@ -1821,12 +1819,6 @@ public: | |||||
| return false; | return false; | ||||
| } | } | ||||
| Rectangle<int> getUntransformedClipBounds() const | |||||
| { | |||||
| return clip != nullptr ? clip->getClipBounds() | |||||
| : Rectangle<int>(); | |||||
| } | |||||
| Rectangle<int> getClipBounds() const | Rectangle<int> getClipBounds() const | ||||
| { | { | ||||
| return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds()) | return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds()) | ||||
| @@ -1835,26 +1827,34 @@ public: | |||||
| SavedState* beginTransparencyLayer (float opacity) | SavedState* beginTransparencyLayer (float opacity) | ||||
| { | { | ||||
| const Rectangle<int> layerBounds (getUntransformedClipBounds()); | |||||
| SavedState* s = new SavedState (*this); | SavedState* s = new SavedState (*this); | ||||
| s->image = Image (Image::ARGB, layerBounds.getWidth(), layerBounds.getHeight(), true); | |||||
| s->transparencyLayerAlpha = opacity; | |||||
| s->transform.moveOriginInDeviceSpace (-layerBounds.getX(), -layerBounds.getY()); | |||||
| s->cloneClipIfMultiplyReferenced(); | |||||
| s->clip = s->clip->translated (-layerBounds.getPosition()); | |||||
| if (clip != nullptr) | |||||
| { | |||||
| const Rectangle<int> layerBounds (clip->getClipBounds()); | |||||
| s->image = Image (Image::ARGB, layerBounds.getWidth(), layerBounds.getHeight(), true); | |||||
| s->transparencyLayerAlpha = opacity; | |||||
| s->transform.moveOriginInDeviceSpace (-layerBounds.getX(), -layerBounds.getY()); | |||||
| s->cloneClipIfMultiplyReferenced(); | |||||
| s->clip->translate (-layerBounds.getPosition()); | |||||
| } | |||||
| return s; | return s; | ||||
| } | } | ||||
| void endTransparencyLayer (SavedState& finishedLayerState) | void endTransparencyLayer (SavedState& finishedLayerState) | ||||
| { | { | ||||
| const Rectangle<int> layerBounds (getUntransformedClipBounds()); | |||||
| if (clip != nullptr) | |||||
| { | |||||
| const Rectangle<int> layerBounds (clip->getClipBounds()); | |||||
| const ScopedPointer<LowLevelGraphicsContext> g (image.createLowLevelContext()); | |||||
| g->setOpacity (finishedLayerState.transparencyLayerAlpha); | |||||
| g->drawImage (finishedLayerState.image, AffineTransform::translation ((float) layerBounds.getX(), | |||||
| (float) layerBounds.getY())); | |||||
| const ScopedPointer<LowLevelGraphicsContext> g (image.createLowLevelContext()); | |||||
| g->setOpacity (finishedLayerState.transparencyLayerAlpha); | |||||
| g->drawImage (finishedLayerState.image, AffineTransform::translation ((float) layerBounds.getX(), | |||||
| (float) layerBounds.getY())); | |||||
| } | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -57,13 +57,13 @@ public: | |||||
| const AffineTransform& transform); | const AffineTransform& transform); | ||||
| /** Creates an edge table containing a rectangle. */ | /** Creates an edge table containing a rectangle. */ | ||||
| EdgeTable (const Rectangle<int>& rectangleToAdd); | |||||
| explicit EdgeTable (const Rectangle<int>& rectangleToAdd); | |||||
| /** Creates an edge table containing a rectangle list. */ | /** Creates an edge table containing a rectangle list. */ | ||||
| EdgeTable (const RectangleList& rectanglesToAdd); | |||||
| explicit EdgeTable (const RectangleList& rectanglesToAdd); | |||||
| /** Creates an edge table containing a rectangle. */ | /** Creates an edge table containing a rectangle. */ | ||||
| EdgeTable (const Rectangle<float>& rectangleToAdd); | |||||
| explicit EdgeTable (const Rectangle<float>& rectangleToAdd); | |||||
| /** Creates a copy of another edge table. */ | /** Creates a copy of another edge table. */ | ||||
| EdgeTable (const EdgeTable& other); | EdgeTable (const EdgeTable& other); | ||||
| @@ -1162,7 +1162,7 @@ void Component::setBoundsToFit (int x, int y, int width, int height, | |||||
| } | } | ||||
| if (newW > 0 && newH > 0) | if (newW > 0 && newH > 0) | ||||
| setBounds (justification.appliedToRectangle (Rectangle<int> (0, 0, newW, newH), | |||||
| setBounds (justification.appliedToRectangle (Rectangle<int> (newW, newH), | |||||
| Rectangle<int> (x, y, width, height))); | Rectangle<int> (x, y, width, height))); | ||||
| } | } | ||||
| } | } | ||||
| @@ -104,6 +104,30 @@ public: | |||||
| void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy, | void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy, | ||||
| const String& name, const int menuId, const int tag) | const String& name, const int menuId, const int tag) | ||||
| { | { | ||||
| #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 | |||||
| static bool is10_4 = (SystemStats::getOSXMinorVersionNumber() <= 4); | |||||
| if (is10_4) | |||||
| { | |||||
| [parentItem setTag: tag]; | |||||
| NSMenu* menu = [parentItem submenu]; | |||||
| [menu setTitle: juceStringToNS (name)]; | |||||
| while ([menu numberOfItems] > 0) | |||||
| [menu removeItemAtIndex: 0]; | |||||
| PopupMenu::MenuItemIterator iter (menuToCopy); | |||||
| while (iter.next()) | |||||
| addMenuItem (iter, menu, menuId, tag); | |||||
| [menu setAutoenablesItems: false]; | |||||
| [menu update]; | |||||
| return; | |||||
| } | |||||
| #endif | |||||
| // Note: This method used to update the contents of the existing menu in-place, but that caused | // Note: This method used to update the contents of the existing menu in-place, but that caused | ||||
| // weird side-effects which messed-up keyboard focus when switching between windows. By creating | // weird side-effects which messed-up keyboard focus when switching between windows. By creating | ||||
| // a new menu and replacing the old one with it, that problem seems to be avoided.. | // a new menu and replacing the old one with it, that problem seems to be avoided.. | ||||
| @@ -610,7 +610,7 @@ public: | |||||
| Graphics::ScopedSaveState state (g); | Graphics::ScopedSaveState state (g); | ||||
| g.reduceClipRegion (Rectangle<int> (startX, baselineY, endX - startX, 1)); | g.reduceClipRegion (Rectangle<int> (startX, baselineY, endX - startX, 1)); | ||||
| g.fillCheckerBoard (Rectangle<int> (0, 0, endX, baselineY + 1), 3, 1, colour, Colours::transparentBlack); | |||||
| g.fillCheckerBoard (Rectangle<int> (endX, baselineY + 1), 3, 1, colour, Colours::transparentBlack); | |||||
| } | } | ||||
| void drawSelectedText (Graphics& g, | void drawSelectedText (Graphics& g, | ||||
| @@ -87,7 +87,7 @@ public: | |||||
| Rectangle<int> getViewBounds() const | Rectangle<int> getViewBounds() const | ||||
| { | { | ||||
| CGRect r = [view frame]; | CGRect r = [view frame]; | ||||
| return Rectangle<int> (0, 0, (int) r.size.width, (int) r.size.height); | |||||
| return Rectangle<int> ((int) r.size.width, (int) r.size.height); | |||||
| } | } | ||||
| UIView* const view; | UIView* const view; | ||||
| @@ -99,7 +99,7 @@ public: | |||||
| Rectangle<int> getViewBounds() const | Rectangle<int> getViewBounds() const | ||||
| { | { | ||||
| NSRect r = [view frame]; | NSRect r = [view frame]; | ||||
| return Rectangle<int> (0, 0, (int) r.size.width, (int) r.size.height); | |||||
| return Rectangle<int> ((int) r.size.width, (int) r.size.height); | |||||
| } | } | ||||
| NSView* const view; | NSView* const view; | ||||