| @@ -40,7 +40,7 @@ public: | |||
| { | |||
| hash = in.readInt64(); | |||
| const int64 len = in.readInt64(); | |||
| in.readIntoMemoryBlock (data, len); | |||
| in.readIntoMemoryBlock (data, (ssize_t) len); | |||
| } | |||
| void write (OutputStream& out) | |||
| @@ -91,6 +91,10 @@ typedef unsigned int uint32; | |||
| typedef unsigned int pointer_sized_uint; | |||
| #endif | |||
| #if JUCE_MSVC | |||
| typedef pointer_sized_int ssize_t; | |||
| #endif | |||
| //============================================================================== | |||
| // 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. | |||
| 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 | |||
| } | |||
| #if JUCE_MSVC | |||
| #pragma optimize ("", on) // resets optimisations to the project defaults | |||
| #endif | |||
| /** Fast floating-point-to-integer conversion. | |||
| 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; | |||
| } | |||
| /** 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. | |||
| The divisor must be greater than zero. | |||
| */ | |||
| @@ -199,7 +199,7 @@ String InputStream::readNextLine() | |||
| 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); | |||
| return mo.writeFromInputStream (*this, numBytes); | |||
| @@ -245,7 +245,7 @@ public: | |||
| @returns the number of bytes that were added to the memory block | |||
| */ | |||
| 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. | |||
| @@ -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() | |||
| && startX < context->getClipBounds().getRight()) | |||
| { | |||
| GlyphArrangement arr; | |||
| 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 | |||
| 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 | |||
| */ | |||
| 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. | |||
| @@ -1012,7 +1012,7 @@ public: | |||
| virtual Ptr clipToPath (const Path& p, const AffineTransform& transform) = 0; | |||
| virtual Ptr clipToEdgeTable (const EdgeTable& et) = 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 Rectangle<int> getClipBounds() const = 0; | |||
| @@ -1294,10 +1294,9 @@ public: | |||
| return edgeTable.isEmpty() ? nullptr : this; | |||
| } | |||
| Ptr translated (const Point<int>& delta) | |||
| void translate (const Point<int>& delta) | |||
| { | |||
| edgeTable.translate ((float) delta.getX(), delta.getY()); | |||
| return edgeTable.isEmpty() ? nullptr : this; | |||
| } | |||
| bool clipRegionIntersects (const Rectangle<int>& r) const | |||
| @@ -1451,10 +1450,9 @@ public: | |||
| return toEdgeTable()->clipToImageAlpha (image, transform, betterQuality); | |||
| } | |||
| Ptr translated (const Point<int>& delta) | |||
| void translate (const Point<int>& delta) | |||
| { | |||
| clip.offsetAll (delta.getX(), delta.getY()); | |||
| return clip.isEmpty() ? nullptr : this; | |||
| } | |||
| bool clipRegionIntersects (const Rectangle<int>& r) const | |||
| @@ -1821,12 +1819,6 @@ public: | |||
| return false; | |||
| } | |||
| Rectangle<int> getUntransformedClipBounds() const | |||
| { | |||
| return clip != nullptr ? clip->getClipBounds() | |||
| : Rectangle<int>(); | |||
| } | |||
| Rectangle<int> getClipBounds() const | |||
| { | |||
| return clip != nullptr ? transform.deviceSpaceToUserSpace (clip->getClipBounds()) | |||
| @@ -1835,26 +1827,34 @@ public: | |||
| SavedState* beginTransparencyLayer (float opacity) | |||
| { | |||
| const Rectangle<int> layerBounds (getUntransformedClipBounds()); | |||
| 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; | |||
| } | |||
| 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); | |||
| /** 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. */ | |||
| EdgeTable (const RectangleList& rectanglesToAdd); | |||
| explicit EdgeTable (const RectangleList& rectanglesToAdd); | |||
| /** 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. */ | |||
| EdgeTable (const EdgeTable& other); | |||
| @@ -1162,7 +1162,7 @@ void Component::setBoundsToFit (int x, int y, int width, int height, | |||
| } | |||
| 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))); | |||
| } | |||
| } | |||
| @@ -104,6 +104,30 @@ public: | |||
| void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy, | |||
| 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 | |||
| // 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.. | |||
| @@ -610,7 +610,7 @@ public: | |||
| Graphics::ScopedSaveState state (g); | |||
| 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, | |||
| @@ -87,7 +87,7 @@ public: | |||
| Rectangle<int> getViewBounds() const | |||
| { | |||
| 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; | |||
| @@ -99,7 +99,7 @@ public: | |||
| Rectangle<int> getViewBounds() const | |||
| { | |||
| 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; | |||