From ded840d4560f99600a01a278af80d0b2c5affbd0 Mon Sep 17 00:00:00 2001 From: Julian Storer Date: Tue, 1 Dec 2009 22:25:38 +0000 Subject: [PATCH] Updated the demo to have a new graphics rendering test page - this tests a lot of the new graphics features and lets you swap between software/OS rendering engines. Also fixed a mac menu bug, and mac mouse event timestamps. --- extras/juce demo/build/linux/JuceDemo.make | 28 +- .../macosx/jucedemo.xcodeproj/project.pbxproj | 10 +- .../juce demo/build/win32_vc8/jucedemo.vcproj | 26 +- extras/juce demo/src/MainDemoWindow.cpp | 37 ++- extras/juce demo/src/jucedemo_headers.h | 2 +- juce_amalgamated.cpp | 257 +++++++++++++----- juce_amalgamated.h | 28 +- .../components/windows/juce_ComponentPeer.cpp | 16 ++ .../components/windows/juce_ComponentPeer.h | 5 + src/gui/graphics/contexts/juce_FillType.cpp | 7 + src/gui/graphics/contexts/juce_FillType.h | 21 +- .../contexts/juce_LowLevelGraphicsContext.h | 3 +- .../juce_LowLevelGraphicsSoftwareRenderer.cpp | 25 +- .../mac/juce_iphone_UIViewComponentPeer.mm | 6 +- .../mac/juce_mac_CoreGraphicsContext.mm | 22 +- src/native/mac/juce_mac_MainMenu.mm | 22 ++ .../mac/juce_mac_NSViewComponentPeer.mm | 115 +++++--- src/text/juce_XmlElement.cpp | 22 +- 18 files changed, 464 insertions(+), 188 deletions(-) diff --git a/extras/juce demo/build/linux/JuceDemo.make b/extras/juce demo/build/linux/JuceDemo.make index ebb2ea0774..5362e13646 100644 --- a/extras/juce demo/build/linux/JuceDemo.make +++ b/extras/juce demo/build/linux/JuceDemo.make @@ -39,10 +39,10 @@ ifeq ($(CONFIG),Release) endif OBJECTS := \ + $(OBJDIR)/MainDemoWindow.o \ $(OBJDIR)/BinaryData.o \ $(OBJDIR)/ApplicationStartup.o \ $(OBJDIR)/juce_LibrarySource.o \ - $(OBJDIR)/MainDemoWindow.o \ $(OBJDIR)/AudioDemoLatencyPage.o \ $(OBJDIR)/AudioDemoPlaybackPage.o \ $(OBJDIR)/AudioDemoRecordPage.o \ @@ -51,17 +51,17 @@ OBJECTS := \ $(OBJDIR)/AudioDemoTabComponent.o \ $(OBJDIR)/CameraDemo.o \ $(OBJDIR)/DragAndDropDemo.o \ - $(OBJDIR)/FontsAndTextDemo.o \ $(OBJDIR)/InterprocessCommsDemo.o \ $(OBJDIR)/OpenGLDemo.o \ + $(OBJDIR)/RenderingTestComponent.o \ $(OBJDIR)/QuickTimeDemo.o \ $(OBJDIR)/TableDemo.o \ $(OBJDIR)/ThreadingDemo.o \ $(OBJDIR)/TreeViewDemo.o \ $(OBJDIR)/WebBrowserDemo.o \ - $(OBJDIR)/WidgetsDemo.o \ $(OBJDIR)/CodeEditorDemo.o \ - $(OBJDIR)/PathsAndTransformsDemo.o \ + $(OBJDIR)/FontsAndTextDemo.o \ + $(OBJDIR)/WidgetsDemo.o \ MKDIR_TYPE := msdos CMD := $(subst \,\\,$(ComSpec)$(COMSPEC)) @@ -103,22 +103,22 @@ else -@if exist $(subst /,\,$(OBJDIR)) rmdir /s /q $(subst /,\,$(OBJDIR)) endif -$(OBJDIR)/BinaryData.o: ../../src/BinaryData.cpp +$(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp +$(OBJDIR)/BinaryData.o: ../../src/BinaryData.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp +$(OBJDIR)/ApplicationStartup.o: ../../src/ApplicationStartup.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/MainDemoWindow.o: ../../src/MainDemoWindow.cpp +$(OBJDIR)/juce_LibrarySource.o: ../../src/juce_LibrarySource.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" @@ -163,17 +163,17 @@ $(OBJDIR)/DragAndDropDemo.o: ../../src/demos/DragAndDropDemo.cpp @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp +$(OBJDIR)/InterprocessCommsDemo.o: ../../src/demos/InterprocessCommsDemo.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/InterprocessCommsDemo.o: ../../src/demos/InterprocessCommsDemo.cpp +$(OBJDIR)/OpenGLDemo.o: ../../src/demos/OpenGLDemo.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/OpenGLDemo.o: ../../src/demos/OpenGLDemo.cpp +$(OBJDIR)/RenderingTestComponent.o: ../../src/demos/RenderingTestComponent.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" @@ -203,17 +203,17 @@ $(OBJDIR)/WebBrowserDemo.o: ../../src/demos/WebBrowserDemo.cpp @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/WidgetsDemo.o: ../../src/demos/WidgetsDemo.cpp +$(OBJDIR)/CodeEditorDemo.o: ../../src/demos/CodeEditorDemo.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/CodeEditorDemo.o: ../../src/demos/CodeEditorDemo.cpp +$(OBJDIR)/FontsAndTextDemo.o: ../../src/demos/FontsAndTextDemo.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" -$(OBJDIR)/PathsAndTransformsDemo.o: ../../src/demos/PathsAndTransformsDemo.cpp +$(OBJDIR)/WidgetsDemo.o: ../../src/demos/WidgetsDemo.cpp -@$(CMD_MKOBJDIR) @echo $(notdir $<) @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" diff --git a/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj b/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj index 92e5467b2a..3771f3fe5d 100644 --- a/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj +++ b/extras/juce demo/build/macosx/jucedemo.xcodeproj/project.pbxproj @@ -12,13 +12,13 @@ 841FE43F0E8ABDD4003C3263 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841FE4390E8ABDD4003C3263 /* IOKit.framework */; }; 841FE4400E8ABDD4003C3263 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841FE43A0E8ABDD4003C3263 /* OpenGL.framework */; }; 841FE4410E8ABDD4003C3263 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 841FE43B0E8ABDD4003C3263 /* WebKit.framework */; }; + 8429581F10BDF8AA0029323B /* RenderingTestComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8429581D10BDF8AA0029323B /* RenderingTestComponent.cpp */; }; 8450577A0EB52CE500029DFF /* QuickTime.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 845057790EB52CE500029DFF /* QuickTime.framework */; }; 847F4D900E8AC35C00F64426 /* QTKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 847F4D8F0E8AC35C00F64426 /* QTKit.framework */; }; 847F4EA60E8BA9C300F64426 /* DragAndDropDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4E9B0E8BA9C300F64426 /* DragAndDropDemo.cpp */; }; 847F4EA70E8BA9C300F64426 /* FontsAndTextDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4E9C0E8BA9C300F64426 /* FontsAndTextDemo.cpp */; }; 847F4EA80E8BA9C300F64426 /* InterprocessCommsDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4E9D0E8BA9C300F64426 /* InterprocessCommsDemo.cpp */; }; 847F4EA90E8BA9C300F64426 /* OpenGLDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4E9E0E8BA9C300F64426 /* OpenGLDemo.cpp */; }; - 847F4EAA0E8BA9C300F64426 /* PathsAndTransformsDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4E9F0E8BA9C300F64426 /* PathsAndTransformsDemo.cpp */; }; 847F4EAB0E8BA9C300F64426 /* QuickTimeDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EA00E8BA9C300F64426 /* QuickTimeDemo.cpp */; }; 847F4EAC0E8BA9C300F64426 /* TableDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EA10E8BA9C300F64426 /* TableDemo.cpp */; }; 847F4EAD0E8BA9C300F64426 /* ThreadingDemo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 847F4EA20E8BA9C300F64426 /* ThreadingDemo.cpp */; }; @@ -50,13 +50,14 @@ 841FE4390E8ABDD4003C3263 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; 841FE43A0E8ABDD4003C3263 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; 841FE43B0E8ABDD4003C3263 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = /System/Library/Frameworks/WebKit.framework; sourceTree = ""; }; + 8429581D10BDF8AA0029323B /* RenderingTestComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RenderingTestComponent.cpp; path = ../../src/demos/RenderingTestComponent.cpp; sourceTree = SOURCE_ROOT; }; + 8429581E10BDF8AA0029323B /* RenderingTestComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RenderingTestComponent.h; path = ../../src/demos/RenderingTestComponent.h; sourceTree = SOURCE_ROOT; }; 845057790EB52CE500029DFF /* QuickTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickTime.framework; path = /System/Library/Frameworks/QuickTime.framework; sourceTree = ""; }; 847F4D8F0E8AC35C00F64426 /* QTKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QTKit.framework; path = /System/Library/Frameworks/QTKit.framework; sourceTree = ""; }; 847F4E9B0E8BA9C300F64426 /* DragAndDropDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DragAndDropDemo.cpp; path = ../../src/demos/DragAndDropDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4E9C0E8BA9C300F64426 /* FontsAndTextDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FontsAndTextDemo.cpp; path = ../../src/demos/FontsAndTextDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4E9D0E8BA9C300F64426 /* InterprocessCommsDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InterprocessCommsDemo.cpp; path = ../../src/demos/InterprocessCommsDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4E9E0E8BA9C300F64426 /* OpenGLDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = OpenGLDemo.cpp; path = ../../src/demos/OpenGLDemo.cpp; sourceTree = SOURCE_ROOT; }; - 847F4E9F0E8BA9C300F64426 /* PathsAndTransformsDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 2; name = PathsAndTransformsDemo.cpp; path = ../../src/demos/PathsAndTransformsDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4EA00E8BA9C300F64426 /* QuickTimeDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QuickTimeDemo.cpp; path = ../../src/demos/QuickTimeDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4EA10E8BA9C300F64426 /* TableDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TableDemo.cpp; path = ../../src/demos/TableDemo.cpp; sourceTree = SOURCE_ROOT; }; 847F4EA20E8BA9C300F64426 /* ThreadingDemo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadingDemo.cpp; path = ../../src/demos/ThreadingDemo.cpp; sourceTree = SOURCE_ROOT; }; @@ -196,7 +197,8 @@ 847F4E9C0E8BA9C300F64426 /* FontsAndTextDemo.cpp */, 847F4E9D0E8BA9C300F64426 /* InterprocessCommsDemo.cpp */, 847F4E9E0E8BA9C300F64426 /* OpenGLDemo.cpp */, - 847F4E9F0E8BA9C300F64426 /* PathsAndTransformsDemo.cpp */, + 8429581D10BDF8AA0029323B /* RenderingTestComponent.cpp */, + 8429581E10BDF8AA0029323B /* RenderingTestComponent.h */, 847F4EA00E8BA9C300F64426 /* QuickTimeDemo.cpp */, 847F4EA10E8BA9C300F64426 /* TableDemo.cpp */, 847F4EA20E8BA9C300F64426 /* ThreadingDemo.cpp */, @@ -264,7 +266,6 @@ 847F4EA70E8BA9C300F64426 /* FontsAndTextDemo.cpp in Sources */, 847F4EA80E8BA9C300F64426 /* InterprocessCommsDemo.cpp in Sources */, 847F4EA90E8BA9C300F64426 /* OpenGLDemo.cpp in Sources */, - 847F4EAA0E8BA9C300F64426 /* PathsAndTransformsDemo.cpp in Sources */, 847F4EAB0E8BA9C300F64426 /* QuickTimeDemo.cpp in Sources */, 847F4EAC0E8BA9C300F64426 /* TableDemo.cpp in Sources */, 847F4EAD0E8BA9C300F64426 /* ThreadingDemo.cpp in Sources */, @@ -283,6 +284,7 @@ 84913FE21063947900456AFC /* AudioDemoTabComponent.cpp in Sources */, 849144091064E54800456AFC /* AudioDemoRecordPage.cpp in Sources */, 84EDCA1F10A19E730079DB17 /* CodeEditorDemo.cpp in Sources */, + 8429581F10BDF8AA0029323B /* RenderingTestComponent.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/extras/juce demo/build/win32_vc8/jucedemo.vcproj b/extras/juce demo/build/win32_vc8/jucedemo.vcproj index 8c0649694b..a36493bcaa 100644 --- a/extras/juce demo/build/win32_vc8/jucedemo.vcproj +++ b/extras/juce demo/build/win32_vc8/jucedemo.vcproj @@ -393,29 +393,15 @@ > - - - - - - + + getAvailableRenderingEngines()); + if (renderingEngines.size() > 1) + { + menu.addSeparator(); + + for (int i = 0; i < renderingEngines.size(); ++i) + menu.addItem (5001 + i, "Use " + renderingEngines[i], true, + i == getPeer()->getCurrentRenderingEngine()); + } } return menu; @@ -161,8 +171,11 @@ public: void menuItemSelected (int menuItemID, int topLevelMenuIndex) { - // all our menu items are invoked automatically as commands, so no need to do - // anything in this callback + // most of our menu items are invoked automatically as commands, but we can handle the + // other special cases here.. + + if (menuItemID >= 5001 && menuItemID < 5010) + getPeer()->setCurrentRenderingEngine (menuItemID - 5001); } //============================================================================== @@ -180,7 +193,7 @@ public: void getAllCommands (Array & commands) { // this returns the set of all commands that this target can perform.. - const CommandID ids[] = { showPathsAndTransforms, + const CommandID ids[] = { showRendering, showFontsAndText, showWidgets, showThreading, @@ -218,9 +231,9 @@ public: switch (commandID) { - case showPathsAndTransforms: - result.setInfo (T("Paths and Transforms"), T("Shows the paths & transforms demo"), demosCategory, 0); - result.setTicked (currentDemoId == showPathsAndTransforms); + case showRendering: + result.setInfo (T("Graphics Rendering"), T("Shows the graphics demo"), demosCategory, 0); + result.setTicked (currentDemoId == showRendering); result.addDefaultKeypress (T('1'), ModifierKeys::commandModifier); break; @@ -353,9 +366,9 @@ public: { switch (info.commandID) { - case showPathsAndTransforms: - showDemo (createPathsAndTransformsDemo()); - currentDemoId = showPathsAndTransforms; + case showRendering: + showDemo (createRenderingDemo()); + currentDemoId = showRendering; break; case showFontsAndText: diff --git a/extras/juce demo/src/jucedemo_headers.h b/extras/juce demo/src/jucedemo_headers.h index 890af0ab51..2c6b91b9b0 100644 --- a/extras/juce demo/src/jucedemo_headers.h +++ b/extras/juce demo/src/jucedemo_headers.h @@ -42,7 +42,7 @@ // Pre-declare the functions that create each of the demo components.. Component* createFontsAndTextDemo(); -Component* createPathsAndTransformsDemo(); +Component* createRenderingDemo(); Component* createWidgetsDemo (ApplicationCommandManager* commandManager); Component* createThreadingDemo(); Component* createTreeViewDemo(); diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 06efc1ff6e..8268fbc44b 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -14639,13 +14639,27 @@ bool XmlElement::writeToFile (const File& f, << dtd << "\r\n"; writeElementAsText (*out, 0, lineWrapLength); - delete out; - if (tempFile.moveFileTo (f)) - return true; + if (! tempFile.exists()) + return false; - tempFile.deleteFile(); + int i; + for (i = 5; --i >= 0;) + { + if (tempFile.moveFileTo (f)) + return true; + + Thread::sleep (100); + } + + for (i = 5; --i >= 0;) + { + if (tempFile.deleteFile()) + break; + + Thread::sleep (100); + } } } @@ -75911,6 +75925,22 @@ void ComponentPeer::addMaskedRegion (int x, int y, int w, int h) throw() maskedRegion.add (x, y, w, h); } +const StringArray ComponentPeer::getAvailableRenderingEngines() throw() +{ + StringArray s; + s.add ("Software Renderer"); + return s; +} + +int ComponentPeer::getCurrentRenderingEngine() throw() +{ + return 0; +} + +void ComponentPeer::setCurrentRenderingEngine (int /*index*/) throw() +{ +} + END_JUCE_NAMESPACE /********* End of inlined file: juce_ComponentPeer.cpp *********/ @@ -79228,6 +79258,7 @@ void FillType::setGradient (const ColourGradient& newGradient) throw() { image = 0; gradient = new ColourGradient (newGradient); + colour = Colours::black; } } @@ -79236,6 +79267,12 @@ void FillType::setTiledImage (const Image& image_, const AffineTransform& transf deleteAndZero (gradient); image = &image_; transform = transform_; + colour = Colours::black; +} + +void FillType::setOpacity (const float newOpacity) throw() +{ + colour = colour.withAlpha (newOpacity); } END_JUCE_NAMESPACE @@ -81459,6 +81496,7 @@ public: jassert (! replaceContents); // that option is just for solid colours ColourGradient g2 (*(fillType.gradient)); + g2.multiplyOpacity (fillType.getOpacity()); AffineTransform transform (fillType.transform.translated ((float) xOffset, (float) yOffset)); const bool isIdentity = transform.isOnlyTranslation(); @@ -81863,9 +81901,9 @@ void LowLevelGraphicsSoftwareRenderer::setFill (const FillType& fillType) currentState->fillType = fillType; } -void LowLevelGraphicsSoftwareRenderer::setOpacity (float opacity) +void LowLevelGraphicsSoftwareRenderer::setOpacity (float newOpacity) { - currentState->fillType.colour = currentState->fillType.colour.withAlpha (opacity); + currentState->fillType.setOpacity (newOpacity); } void LowLevelGraphicsSoftwareRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) @@ -81910,15 +81948,21 @@ void LowLevelGraphicsSoftwareRenderer::drawLine (double x1, double y1, double x2 void LowLevelGraphicsSoftwareRenderer::drawVerticalLine (const int x, double top, double bottom) { - EdgeTable et ((float) (x + currentState->xOffset), (float) (top + currentState->yOffset), 1.0f, (float) (bottom - top)); - currentState->fillEdgeTable (image, et); + if (bottom > top) + { + EdgeTable et ((float) (x + currentState->xOffset), (float) (top + currentState->yOffset), 1.0f, (float) (bottom - top)); + currentState->fillEdgeTable (image, et); + } } void LowLevelGraphicsSoftwareRenderer::drawHorizontalLine (const int y, double left, double right) { - EdgeTable et ((float) (left + currentState->xOffset), (float) (y + currentState->yOffset), - (float) (right - left), 1.0f); - currentState->fillEdgeTable (image, et); + if (right > left) + { + EdgeTable et ((float) (left + currentState->xOffset), (float) (y + currentState->yOffset), + (float) (right - left), 1.0f); + currentState->fillEdgeTable (image, et); + } } class GlyphCache : private DeletedAtShutdown @@ -82012,7 +82056,7 @@ public: const AffineTransform transform (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)); float px, py, pw, ph; - glyphPath.getBoundsTransformed (transform, px, py, pw, ph); + glyphPath.getBoundsTransformed (transform.translated (0.0f, -0.5f), px, py, pw, ph); Rectangle clip ((int) floorf (px), (int) floorf (py), roundFloatToInt (pw) + 2, roundFloatToInt (ph) + 2); @@ -82063,7 +82107,7 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT { GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber, transform.getTranslationX() + (float) currentState->xOffset, - roundFloatToInt (transform.getTranslationY() + (float) currentState->yOffset)); + transform.getTranslationY() + (float) currentState->yOffset); } else { @@ -261555,9 +261599,9 @@ public: } } - void setOpacity (float opacity) + void setOpacity (float newOpacity) { - state->fillType.colour = state->fillType.colour.withAlpha (opacity); + state->fillType.setOpacity (newOpacity); setFill (state->fillType); } @@ -261655,7 +261699,7 @@ public: CGImageRelease (fullImage); CGContextSaveGState (context); - CGContextSetAlpha (context, state->fillType.colour.getFloatAlpha()); + CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -261840,26 +261884,27 @@ private: outData[3] = colour.getAlpha() / 255.0f; } - CGShadingRef createGradient (const AffineTransform& transform, const ColourGradient* const gradient) throw() + CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { +// gradient.multiplyOpacity (state->fillType.getOpacity()); delete gradientLookupTable; - gradientLookupTable = gradient->createLookupTable (transform, numGradientLookupEntries); + gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); --numGradientLookupEntries; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate ((void*) this, 1, 0, 4, 0, &gradientCallbacks); - CGPoint p1 (CGPointMake (gradient->x1, gradient->y1)); + CGPoint p1 (CGPointMake (gradient.x1, gradient.y1)); - if (gradient->isRadial) + if (gradient.isRadial) { result = CGShadingCreateRadial (rgbColourSpace, p1, 0, - p1, hypotf (gradient->x1 - gradient->x2, gradient->y1 - gradient->y2), + p1, hypotf (gradient.x1 - gradient.x2, gradient.y1 - gradient.y2), function, true, true); } else { result = CGShadingCreateAxial (rgbColourSpace, p1, - CGPointMake (gradient->x2, gradient->y2), + CGPointMake (gradient.x2, gradient.y2), function, true, true); } @@ -261872,10 +261917,9 @@ private: flip(); applyTransform (state->fillType.transform); - CGContextSetAlpha (context, 1.0f); CGContextSetInterpolationQuality (context, kCGInterpolationDefault); // (This is required for 10.4, where there's a crash if // you draw a gradient with high quality interp enabled). - CGShadingRef shading = createGradient (state->fillType.transform, state->fillType.gradient); + CGShadingRef shading = createGradient (state->fillType.transform, *(state->fillType.gradient)); CGContextDrawShading (context, shading); CGShadingRelease (shading); } @@ -262146,7 +262190,11 @@ static int getModifierForButtonNumber (const int num) throw() : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); } -static int64 getMouseTime (UIEvent* e) { return (int64) ([e timestamp] * 1000.0); } +static int64 getMouseTime (UIEvent* e) throw() +{ + return (Time::currentTimeMillis() - Time::getMillisecondCounter()) + + (int64) ([e timestamp] * 1000.0); +} int juce_lastMouseX = 0, juce_lastMouseY = 0; @@ -266003,9 +266051,9 @@ public: } } - void setOpacity (float opacity) + void setOpacity (float newOpacity) { - state->fillType.colour = state->fillType.colour.withAlpha (opacity); + state->fillType.setOpacity (newOpacity); setFill (state->fillType); } @@ -266103,7 +266151,7 @@ public: CGImageRelease (fullImage); CGContextSaveGState (context); - CGContextSetAlpha (context, state->fillType.colour.getFloatAlpha()); + CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -266288,26 +266336,27 @@ private: outData[3] = colour.getAlpha() / 255.0f; } - CGShadingRef createGradient (const AffineTransform& transform, const ColourGradient* const gradient) throw() + CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { +// gradient.multiplyOpacity (state->fillType.getOpacity()); delete gradientLookupTable; - gradientLookupTable = gradient->createLookupTable (transform, numGradientLookupEntries); + gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); --numGradientLookupEntries; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate ((void*) this, 1, 0, 4, 0, &gradientCallbacks); - CGPoint p1 (CGPointMake (gradient->x1, gradient->y1)); + CGPoint p1 (CGPointMake (gradient.x1, gradient.y1)); - if (gradient->isRadial) + if (gradient.isRadial) { result = CGShadingCreateRadial (rgbColourSpace, p1, 0, - p1, hypotf (gradient->x1 - gradient->x2, gradient->y1 - gradient->y2), + p1, hypotf (gradient.x1 - gradient.x2, gradient.y1 - gradient.y2), function, true, true); } else { result = CGShadingCreateAxial (rgbColourSpace, p1, - CGPointMake (gradient->x2, gradient->y2), + CGPointMake (gradient.x2, gradient.y2), function, true, true); } @@ -266320,10 +266369,9 @@ private: flip(); applyTransform (state->fillType.transform); - CGContextSetAlpha (context, 1.0f); CGContextSetInterpolationQuality (context, kCGInterpolationDefault); // (This is required for 10.4, where there's a crash if // you draw a gradient with high quality interp enabled). - CGShadingRef shading = createGradient (state->fillType.transform, state->fillType.gradient); + CGShadingRef shading = createGradient (state->fillType.transform, *(state->fillType.gradient)); CGContextDrawShading (context, shading); CGShadingRelease (shading); } @@ -266563,6 +266611,9 @@ public: void toFront (bool makeActiveWindow); void toBehind (ComponentPeer* other); void setIcon (const Image& newIcon); + const StringArray getAvailableRenderingEngines() throw(); + int getCurrentRenderingEngine() throw(); + void setCurrentRenderingEngine (int index) throw(); /* When you use multiple DLLs which share similarly-named obj-c classes - like for example having more than one juce plugin loaded into a host, then when a @@ -266618,7 +266669,7 @@ public: NSWindow* window; JuceNSView* view; - bool isSharedWindow, fullScreen, insideDrawRect; + bool isSharedWindow, fullScreen, insideDrawRect, usingCoreGraphics; }; END_JUCE_NAMESPACE @@ -267036,7 +267087,11 @@ void ModifierKeys::updateCurrentModifiers() throw() currentModifierFlags = currentModifiers; } -static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } +static int64 getMouseTime (NSEvent* e) throw() +{ + return (Time::currentTimeMillis() - Time::getMillisecondCounter()) + + (int64) ([e timestamp] * 1000.0); +} static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) { @@ -267060,7 +267115,12 @@ NSViewComponentPeer::NSViewComponentPeer (Component* const component, view (0), isSharedWindow (viewToAttachTo != 0), fullScreen (false), - insideDrawRect (false) + insideDrawRect (false), +#if USE_COREGRAPHICS_RENDERING + usingCoreGraphics (true) +#else + usingCoreGraphics (false) +#endif { NSRect r; r.origin.x = 0; @@ -267721,45 +267781,78 @@ void NSViewComponentPeer::drawRect (NSRect r) CGContextClearRect (cg, CGContextGetClipBoundingBox (cg)); #if USE_COREGRAPHICS_RENDERING - CoreGraphicsContext context (cg, [view frame].size.height); + if (usingCoreGraphics) + { + CoreGraphicsContext context (cg, [view frame].size.height); - insideDrawRect = true; - handlePaint (context); - insideDrawRect = false; -#else - Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, - (int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! getComponent()->isOpaque()); + insideDrawRect = true; + handlePaint (context); + insideDrawRect = false; + } + else +#endif + { + Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, + (int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); - LowLevelGraphicsSoftwareRenderer context (temp); - context.setOrigin (-roundFloatToInt (r.origin.x), - -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); + LowLevelGraphicsSoftwareRenderer context (temp); + context.setOrigin (-roundFloatToInt (r.origin.x), + -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); - const NSRect* rects = 0; - NSInteger numRects = 0; - [view getRectsBeingDrawn: &rects count: &numRects]; + const NSRect* rects = 0; + NSInteger numRects = 0; + [view getRectsBeingDrawn: &rects count: &numRects]; - RectangleList clip; - for (int i = 0; i < numRects; ++i) - { - clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), - roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), - roundFloatToInt (rects[i].size.width), - roundFloatToInt (rects[i].size.height))); + RectangleList clip; + for (int i = 0; i < numRects; ++i) + { + clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), + roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), + roundFloatToInt (rects[i].size.width), + roundFloatToInt (rects[i].size.height))); + } + + if (context.clipToRectangleList (clip)) + { + insideDrawRect = true; + handlePaint (context); + insideDrawRect = false; + + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); + CGColorSpaceRelease (colourSpace); + CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); + CGImageRelease (image); + } } +} - if (context.clipToRectangleList (clip)) - { - insideDrawRect = true; - handlePaint (context); - insideDrawRect = false; +const StringArray NSViewComponentPeer::getAvailableRenderingEngines() throw() +{ + StringArray s; + s.add ("Software Renderer"); - CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); - CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); - CGColorSpaceRelease (colourSpace); - CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); - CGImageRelease (image); +#if USE_COREGRAPHICS_RENDERING + s.add ("CoreGraphics Renderer"); +#endif + + return s; +} + +int NSViewComponentPeer::getCurrentRenderingEngine() throw() +{ + return usingCoreGraphics ? 1 : 0; +} + +void NSViewComponentPeer::setCurrentRenderingEngine (int index) throw() +{ +#if USE_COREGRAPHICS_RENDERING + if (usingCoreGraphics != (index > 0)) + { + usingCoreGraphics = index > 0; + [view setNeedsDisplay: true]; } #endif } @@ -269089,6 +269182,28 @@ END_JUCE_NAMESPACE if ([[item representedObject] isKindOfClass: [NSArray class]]) { + // If the menu is being triggered by a keypress, the OS will have picked it up before we had a chance to offer it to + // our own components, which may have wanted to intercept it. So, rather than dispatching directly, we'll feed it back + // into the focused component and let it trigger the menu item indirectly. + NSEvent* e = [NSApp currentEvent]; + if ([e type] == NSKeyDown || [e type] == NSKeyUp) + { + if (JUCE_NAMESPACE::Component::getCurrentlyFocusedComponent()->isValidComponent()) + { + JUCE_NAMESPACE::NSViewComponentPeer* peer = dynamic_cast (JUCE_NAMESPACE::Component::getCurrentlyFocusedComponent()->getPeer()); + + if (peer != 0) + { + if ([e type] == NSKeyDown) + peer->redirectKeyDown (e); + else + peer->redirectKeyUp (e); + + return; + } + } + } + NSArray* info = (NSArray*) [item representedObject]; owner->invoke ([item tag], diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 7089ea8ae2..4af4b1ea49 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -19894,17 +19894,36 @@ public: */ void setTiledImage (const Image& image, const AffineTransform& transform) throw(); - /** Returns the solid colour being used. */ + /** Changes the opacity that should be used. + If the fill is a solid colour, this just changes the opacity of that colour. For + gradients and image tiles, it changes the opacity that will be used for them. + */ + void setOpacity (const float newOpacity) throw(); + + /** Returns the current opacity to be applied to the colour, gradient, or image. + @see setOpacity + */ + float getOpacity() const throw() { return colour.getFloatAlpha(); } + + /** The solid colour being used. + + If the fill type is not a solid colour, the alpha channel of this colour indicates + the opacity that should be used for the fill, and the RGB channels are ignored. + */ Colour colour; /** Returns the gradient that should be used for filling. This will be zero if the object is some other type of fill. + If a gradient is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ ColourGradient* gradient; /** Returns the image that should be used for tiling. The FillType object just keeps a pointer to this image, it doesn't own it, so you have to be careful to make sure the image doesn't get deleted while it's being used. + If an image fill is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ const Image* image; @@ -21503,6 +21522,10 @@ public: static void bringModalComponentToFront(); + virtual const StringArray getAvailableRenderingEngines() throw(); + virtual int getCurrentRenderingEngine() throw(); + virtual void setCurrentRenderingEngine (int index) throw(); + juce_UseDebuggingNewOperator protected: @@ -39807,8 +39830,7 @@ public: virtual void restoreState() = 0; virtual void setFill (const FillType& fillType) = 0; - - virtual void setOpacity (float opacity) = 0; + virtual void setOpacity (float newOpacity) = 0; virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0; virtual void fillRect (const Rectangle& r, const bool replaceExistingContents) = 0; diff --git a/src/gui/components/windows/juce_ComponentPeer.cpp b/src/gui/components/windows/juce_ComponentPeer.cpp index 6b99c5efda..9e2bd7d5f9 100644 --- a/src/gui/components/windows/juce_ComponentPeer.cpp +++ b/src/gui/components/windows/juce_ComponentPeer.cpp @@ -776,5 +776,21 @@ void ComponentPeer::addMaskedRegion (int x, int y, int w, int h) throw() maskedRegion.add (x, y, w, h); } +//============================================================================== +const StringArray ComponentPeer::getAvailableRenderingEngines() throw() +{ + StringArray s; + s.add ("Software Renderer"); + return s; +} + +int ComponentPeer::getCurrentRenderingEngine() throw() +{ + return 0; +} + +void ComponentPeer::setCurrentRenderingEngine (int /*index*/) throw() +{ +} END_JUCE_NAMESPACE diff --git a/src/gui/components/windows/juce_ComponentPeer.h b/src/gui/components/windows/juce_ComponentPeer.h index d74e677809..3cbef21315 100644 --- a/src/gui/components/windows/juce_ComponentPeer.h +++ b/src/gui/components/windows/juce_ComponentPeer.h @@ -353,6 +353,11 @@ public: //============================================================================== static void bringModalComponentToFront(); + //============================================================================== + virtual const StringArray getAvailableRenderingEngines() throw(); + virtual int getCurrentRenderingEngine() throw(); + virtual void setCurrentRenderingEngine (int index) throw(); + //============================================================================== juce_UseDebuggingNewOperator diff --git a/src/gui/graphics/contexts/juce_FillType.cpp b/src/gui/graphics/contexts/juce_FillType.cpp index 506ffcf666..dbbd457146 100644 --- a/src/gui/graphics/contexts/juce_FillType.cpp +++ b/src/gui/graphics/contexts/juce_FillType.cpp @@ -28,6 +28,7 @@ BEGIN_JUCE_NAMESPACE #include "juce_FillType.h" +#include "../colour/juce_Colours.h" //============================================================================== @@ -95,6 +96,7 @@ void FillType::setGradient (const ColourGradient& newGradient) throw() { image = 0; gradient = new ColourGradient (newGradient); + colour = Colours::black; } } @@ -103,7 +105,12 @@ void FillType::setTiledImage (const Image& image_, const AffineTransform& transf deleteAndZero (gradient); image = &image_; transform = transform_; + colour = Colours::black; } +void FillType::setOpacity (const float newOpacity) throw() +{ + colour = colour.withAlpha (newOpacity); +} END_JUCE_NAMESPACE diff --git a/src/gui/graphics/contexts/juce_FillType.h b/src/gui/graphics/contexts/juce_FillType.h index c22adbe53b..6f82fd0ade 100644 --- a/src/gui/graphics/contexts/juce_FillType.h +++ b/src/gui/graphics/contexts/juce_FillType.h @@ -91,17 +91,36 @@ public: */ void setTiledImage (const Image& image, const AffineTransform& transform) throw(); - /** Returns the solid colour being used. */ + /** Changes the opacity that should be used. + If the fill is a solid colour, this just changes the opacity of that colour. For + gradients and image tiles, it changes the opacity that will be used for them. + */ + void setOpacity (const float newOpacity) throw(); + + /** Returns the current opacity to be applied to the colour, gradient, or image. + @see setOpacity + */ + float getOpacity() const throw() { return colour.getFloatAlpha(); } + + /** The solid colour being used. + + If the fill type is not a solid colour, the alpha channel of this colour indicates + the opacity that should be used for the fill, and the RGB channels are ignored. + */ Colour colour; /** Returns the gradient that should be used for filling. This will be zero if the object is some other type of fill. + If a gradient is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ ColourGradient* gradient; /** Returns the image that should be used for tiling. The FillType object just keeps a pointer to this image, it doesn't own it, so you have to be careful to make sure the image doesn't get deleted while it's being used. + If an image fill is active, the overall opacity with which it should be applied + is indicated by the alpha channel of the colour variable. */ const Image* image; diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h b/src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h index ea9431e681..2464971ed7 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsContext.h @@ -81,8 +81,7 @@ public: //============================================================================== virtual void setFill (const FillType& fillType) = 0; - - virtual void setOpacity (float opacity) = 0; + virtual void setOpacity (float newOpacity) = 0; virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0; //============================================================================== diff --git a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp index e2e8faf274..b5c1b8885e 100644 --- a/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp +++ b/src/gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.cpp @@ -949,6 +949,7 @@ public: jassert (! replaceContents); // that option is just for solid colours ColourGradient g2 (*(fillType.gradient)); + g2.multiplyOpacity (fillType.getOpacity()); AffineTransform transform (fillType.transform.translated ((float) xOffset, (float) yOffset)); const bool isIdentity = transform.isOnlyTranslation(); @@ -1365,9 +1366,9 @@ void LowLevelGraphicsSoftwareRenderer::setFill (const FillType& fillType) currentState->fillType = fillType; } -void LowLevelGraphicsSoftwareRenderer::setOpacity (float opacity) +void LowLevelGraphicsSoftwareRenderer::setOpacity (float newOpacity) { - currentState->fillType.colour = currentState->fillType.colour.withAlpha (opacity); + currentState->fillType.setOpacity (newOpacity); } void LowLevelGraphicsSoftwareRenderer::setInterpolationQuality (Graphics::ResamplingQuality quality) @@ -1414,15 +1415,21 @@ void LowLevelGraphicsSoftwareRenderer::drawLine (double x1, double y1, double x2 void LowLevelGraphicsSoftwareRenderer::drawVerticalLine (const int x, double top, double bottom) { - EdgeTable et ((float) (x + currentState->xOffset), (float) (top + currentState->yOffset), 1.0f, (float) (bottom - top)); - currentState->fillEdgeTable (image, et); + if (bottom > top) + { + EdgeTable et ((float) (x + currentState->xOffset), (float) (top + currentState->yOffset), 1.0f, (float) (bottom - top)); + currentState->fillEdgeTable (image, et); + } } void LowLevelGraphicsSoftwareRenderer::drawHorizontalLine (const int y, double left, double right) { - EdgeTable et ((float) (left + currentState->xOffset), (float) (y + currentState->yOffset), - (float) (right - left), 1.0f); - currentState->fillEdgeTable (image, et); + if (right > left) + { + EdgeTable et ((float) (left + currentState->xOffset), (float) (y + currentState->yOffset), + (float) (right - left), 1.0f); + currentState->fillEdgeTable (image, et); + } } //============================================================================== @@ -1519,7 +1526,7 @@ public: const AffineTransform transform (AffineTransform::scale (fontHeight * font.getHorizontalScale(), fontHeight)); float px, py, pw, ph; - glyphPath.getBoundsTransformed (transform, px, py, pw, ph); + glyphPath.getBoundsTransformed (transform.translated (0.0f, -0.5f), px, py, pw, ph); Rectangle clip ((int) floorf (px), (int) floorf (py), roundFloatToInt (pw) + 2, roundFloatToInt (ph) + 2); @@ -1573,7 +1580,7 @@ void LowLevelGraphicsSoftwareRenderer::drawGlyph (int glyphNumber, const AffineT { GlyphCache::getInstance()->drawGlyph (*currentState, image, f, glyphNumber, transform.getTranslationX() + (float) currentState->xOffset, - roundFloatToInt (transform.getTranslationY() + (float) currentState->yOffset)); + transform.getTranslationY() + (float) currentState->yOffset); } else { diff --git a/src/native/mac/juce_iphone_UIViewComponentPeer.mm b/src/native/mac/juce_iphone_UIViewComponentPeer.mm index cd3129cb3f..d7aa7d3749 100644 --- a/src/native/mac/juce_iphone_UIViewComponentPeer.mm +++ b/src/native/mac/juce_iphone_UIViewComponentPeer.mm @@ -186,7 +186,11 @@ static int getModifierForButtonNumber (const int num) throw() : (num == 2 ? ModifierKeys::middleButtonModifier : 0)); } -static int64 getMouseTime (UIEvent* e) { return (int64) ([e timestamp] * 1000.0); } +static int64 getMouseTime (UIEvent* e) throw() +{ + return (Time::currentTimeMillis() - Time::getMillisecondCounter()) + + (int64) ([e timestamp] * 1000.0); +} int juce_lastMouseX = 0, juce_lastMouseY = 0; diff --git a/src/native/mac/juce_mac_CoreGraphicsContext.mm b/src/native/mac/juce_mac_CoreGraphicsContext.mm index ccdac62164..856d528665 100644 --- a/src/native/mac/juce_mac_CoreGraphicsContext.mm +++ b/src/native/mac/juce_mac_CoreGraphicsContext.mm @@ -279,9 +279,9 @@ public: } } - void setOpacity (float opacity) + void setOpacity (float newOpacity) { - state->fillType.colour = state->fillType.colour.withAlpha (opacity); + state->fillType.setOpacity (newOpacity); setFill (state->fillType); } @@ -380,7 +380,7 @@ public: CGImageRelease (fullImage); CGContextSaveGState (context); - CGContextSetAlpha (context, state->fillType.colour.getFloatAlpha()); + CGContextSetAlpha (context, state->fillType.getOpacity()); flip(); applyTransform (AffineTransform::scale (1.0f, -1.0f).translated (0, sourceImage.getHeight()).followedBy (transform)); @@ -566,26 +566,27 @@ private: outData[3] = colour.getAlpha() / 255.0f; } - CGShadingRef createGradient (const AffineTransform& transform, const ColourGradient* const gradient) throw() + CGShadingRef createGradient (const AffineTransform& transform, ColourGradient gradient) throw() { +// gradient.multiplyOpacity (state->fillType.getOpacity()); delete gradientLookupTable; - gradientLookupTable = gradient->createLookupTable (transform, numGradientLookupEntries); + gradientLookupTable = gradient.createLookupTable (transform, numGradientLookupEntries); --numGradientLookupEntries; CGShadingRef result = 0; CGFunctionRef function = CGFunctionCreate ((void*) this, 1, 0, 4, 0, &gradientCallbacks); - CGPoint p1 (CGPointMake (gradient->x1, gradient->y1)); + CGPoint p1 (CGPointMake (gradient.x1, gradient.y1)); - if (gradient->isRadial) + if (gradient.isRadial) { result = CGShadingCreateRadial (rgbColourSpace, p1, 0, - p1, hypotf (gradient->x1 - gradient->x2, gradient->y1 - gradient->y2), + p1, hypotf (gradient.x1 - gradient.x2, gradient.y1 - gradient.y2), function, true, true); } else { result = CGShadingCreateAxial (rgbColourSpace, p1, - CGPointMake (gradient->x2, gradient->y2), + CGPointMake (gradient.x2, gradient.y2), function, true, true); } @@ -598,10 +599,9 @@ private: flip(); applyTransform (state->fillType.transform); - CGContextSetAlpha (context, 1.0f); CGContextSetInterpolationQuality (context, kCGInterpolationDefault); // (This is required for 10.4, where there's a crash if // you draw a gradient with high quality interp enabled). - CGShadingRef shading = createGradient (state->fillType.transform, state->fillType.gradient); + CGShadingRef shading = createGradient (state->fillType.transform, *(state->fillType.gradient)); CGContextDrawShading (context, shading); CGShadingRelease (shading); } diff --git a/src/native/mac/juce_mac_MainMenu.mm b/src/native/mac/juce_mac_MainMenu.mm index 7643f7dc9a..a9fd691e49 100644 --- a/src/native/mac/juce_mac_MainMenu.mm +++ b/src/native/mac/juce_mac_MainMenu.mm @@ -361,6 +361,28 @@ END_JUCE_NAMESPACE if ([[item representedObject] isKindOfClass: [NSArray class]]) { + // If the menu is being triggered by a keypress, the OS will have picked it up before we had a chance to offer it to + // our own components, which may have wanted to intercept it. So, rather than dispatching directly, we'll feed it back + // into the focused component and let it trigger the menu item indirectly. + NSEvent* e = [NSApp currentEvent]; + if ([e type] == NSKeyDown || [e type] == NSKeyUp) + { + if (JUCE_NAMESPACE::Component::getCurrentlyFocusedComponent()->isValidComponent()) + { + JUCE_NAMESPACE::NSViewComponentPeer* peer = dynamic_cast (JUCE_NAMESPACE::Component::getCurrentlyFocusedComponent()->getPeer()); + + if (peer != 0) + { + if ([e type] == NSKeyDown) + peer->redirectKeyDown (e); + else + peer->redirectKeyUp (e); + + return; + } + } + } + NSArray* info = (NSArray*) [item representedObject]; owner->invoke ([item tag], diff --git a/src/native/mac/juce_mac_NSViewComponentPeer.mm b/src/native/mac/juce_mac_NSViewComponentPeer.mm index 1c0a684a05..126fff45f1 100644 --- a/src/native/mac/juce_mac_NSViewComponentPeer.mm +++ b/src/native/mac/juce_mac_NSViewComponentPeer.mm @@ -149,6 +149,9 @@ public: void toFront (bool makeActiveWindow); void toBehind (ComponentPeer* other); void setIcon (const Image& newIcon); + const StringArray getAvailableRenderingEngines() throw(); + int getCurrentRenderingEngine() throw(); + void setCurrentRenderingEngine (int index) throw(); /* When you use multiple DLLs which share similarly-named obj-c classes - like for example having more than one juce plugin loaded into a host, then when a @@ -207,7 +210,7 @@ public: NSWindow* window; JuceNSView* view; - bool isSharedWindow, fullScreen, insideDrawRect; + bool isSharedWindow, fullScreen, insideDrawRect, usingCoreGraphics; }; //============================================================================== @@ -634,7 +637,11 @@ void ModifierKeys::updateCurrentModifiers() throw() currentModifierFlags = currentModifiers; } -static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; } +static int64 getMouseTime (NSEvent* e) throw() +{ + return (Time::currentTimeMillis() - Time::getMillisecondCounter()) + + (int64) ([e timestamp] * 1000.0); +} static void getMousePos (NSEvent* e, NSView* view, int& x, int& y) { @@ -659,7 +666,12 @@ NSViewComponentPeer::NSViewComponentPeer (Component* const component, view (0), isSharedWindow (viewToAttachTo != 0), fullScreen (false), - insideDrawRect (false) + insideDrawRect (false), +#if USE_COREGRAPHICS_RENDERING + usingCoreGraphics (true) +#else + usingCoreGraphics (false) +#endif { NSRect r; r.origin.x = 0; @@ -1324,45 +1336,78 @@ void NSViewComponentPeer::drawRect (NSRect r) CGContextClearRect (cg, CGContextGetClipBoundingBox (cg)); #if USE_COREGRAPHICS_RENDERING - CoreGraphicsContext context (cg, [view frame].size.height); + if (usingCoreGraphics) + { + CoreGraphicsContext context (cg, [view frame].size.height); - insideDrawRect = true; - handlePaint (context); - insideDrawRect = false; -#else - Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, - (int) (r.size.width + 0.5f), - (int) (r.size.height + 0.5f), - ! getComponent()->isOpaque()); + insideDrawRect = true; + handlePaint (context); + insideDrawRect = false; + } + else +#endif + { + Image temp (getComponent()->isOpaque() ? Image::RGB : Image::ARGB, + (int) (r.size.width + 0.5f), + (int) (r.size.height + 0.5f), + ! getComponent()->isOpaque()); - LowLevelGraphicsSoftwareRenderer context (temp); - context.setOrigin (-roundFloatToInt (r.origin.x), - -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); + LowLevelGraphicsSoftwareRenderer context (temp); + context.setOrigin (-roundFloatToInt (r.origin.x), + -roundFloatToInt ([view frame].size.height - (r.origin.y + r.size.height))); - const NSRect* rects = 0; - NSInteger numRects = 0; - [view getRectsBeingDrawn: &rects count: &numRects]; + const NSRect* rects = 0; + NSInteger numRects = 0; + [view getRectsBeingDrawn: &rects count: &numRects]; - RectangleList clip; - for (int i = 0; i < numRects; ++i) - { - clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), - roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), - roundFloatToInt (rects[i].size.width), - roundFloatToInt (rects[i].size.height))); + RectangleList clip; + for (int i = 0; i < numRects; ++i) + { + clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x), + roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)), + roundFloatToInt (rects[i].size.width), + roundFloatToInt (rects[i].size.height))); + } + + if (context.clipToRectangleList (clip)) + { + insideDrawRect = true; + handlePaint (context); + insideDrawRect = false; + + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); + CGColorSpaceRelease (colourSpace); + CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); + CGImageRelease (image); + } } +} - if (context.clipToRectangleList (clip)) - { - insideDrawRect = true; - handlePaint (context); - insideDrawRect = false; +const StringArray NSViewComponentPeer::getAvailableRenderingEngines() throw() +{ + StringArray s; + s.add ("Software Renderer"); + +#if USE_COREGRAPHICS_RENDERING + s.add ("CoreGraphics Renderer"); +#endif + + return s; +} - CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); - CGImageRef image = CoreGraphicsImage::createImage (temp, false, colourSpace); - CGColorSpaceRelease (colourSpace); - CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, temp.getWidth(), temp.getHeight()), image); - CGImageRelease (image); +int NSViewComponentPeer::getCurrentRenderingEngine() throw() +{ + return usingCoreGraphics ? 1 : 0; +} + +void NSViewComponentPeer::setCurrentRenderingEngine (int index) throw() +{ +#if USE_COREGRAPHICS_RENDERING + if (usingCoreGraphics != (index > 0)) + { + usingCoreGraphics = index > 0; + [view setNeedsDisplay: true]; } #endif } diff --git a/src/text/juce_XmlElement.cpp b/src/text/juce_XmlElement.cpp index 5f17fd3872..a4705f106b 100644 --- a/src/text/juce_XmlElement.cpp +++ b/src/text/juce_XmlElement.cpp @@ -430,13 +430,27 @@ bool XmlElement::writeToFile (const File& f, << dtd << "\r\n"; writeElementAsText (*out, 0, lineWrapLength); - delete out; - if (tempFile.moveFileTo (f)) - return true; + if (! tempFile.exists()) + return false; - tempFile.deleteFile(); + int i; + for (i = 5; --i >= 0;) + { + if (tempFile.moveFileTo (f)) + return true; + + Thread::sleep (100); + } + + for (i = 5; --i >= 0;) + { + if (tempFile.deleteFile()) + break; + + Thread::sleep (100); + } } }