| @@ -40,7 +40,7 @@ static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe, | |||||
| int type, | int type, | ||||
| LPARAM lParam) | LPARAM lParam) | ||||
| { | { | ||||
| if (lpelfe != 0 && type == TRUETYPE_FONTTYPE) | |||||
| if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0) | |||||
| { | { | ||||
| const String fontName (lpelfe->elfLogFont.lfFaceName); | const String fontName (lpelfe->elfLogFont.lfFaceName); | ||||
| @@ -55,8 +55,7 @@ static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, | |||||
| int type, | int type, | ||||
| LPARAM lParam) | LPARAM lParam) | ||||
| { | { | ||||
| if (lpelfe != 0 | |||||
| && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0)) | |||||
| if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0) | |||||
| { | { | ||||
| LOGFONTW lf; | LOGFONTW lf; | ||||
| zerostruct (lf); | zerostruct (lf); | ||||
| @@ -55,7 +55,7 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| #define juceFilterObjectPropertyID 0x1a45ffe9 | #define juceFilterObjectPropertyID 0x1a45ffe9 | ||||
| static VoidArray activePlugins; | |||||
| static VoidArray activePlugins, activeUIs; | |||||
| static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; | static const short channelConfigs[][2] = { JucePlugin_PreferredChannelConfigurations }; | ||||
| static const int numChannelConfigs = numElementsInArray (channelConfigs); | static const int numChannelConfigs = numElementsInArray (channelConfigs); | ||||
| @@ -108,7 +108,7 @@ public: | |||||
| channels (0), | channels (0), | ||||
| prepared (false) | prepared (false) | ||||
| { | { | ||||
| if (activePlugins.size() == 0) | |||||
| if (activePlugins.size() + activeUIs.size() == 0) | |||||
| { | { | ||||
| #if BUILD_AU_CARBON_UI | #if BUILD_AU_CARBON_UI | ||||
| NSApplicationLoad(); | NSApplicationLoad(); | ||||
| @@ -143,7 +143,7 @@ public: | |||||
| jassert (activePlugins.contains (this)); | jassert (activePlugins.contains (this)); | ||||
| activePlugins.removeValue (this); | activePlugins.removeValue (this); | ||||
| if (activePlugins.size() == 0) | |||||
| if (activePlugins.size() + activeUIs.size() == 0) | |||||
| shutdownJuce_GUI(); | shutdownJuce_GUI(); | ||||
| } | } | ||||
| @@ -993,6 +993,8 @@ public: | |||||
| [self setHidden: NO]; | [self setHidden: NO]; | ||||
| [self setPostsFrameChangedNotifications: YES]; | [self setPostsFrameChangedNotifications: YES]; | ||||
| activeUIs.add (self); | |||||
| editorComp->addToDesktop (0, (void*) self); | editorComp->addToDesktop (0, (void*) self); | ||||
| editorComp->setVisible (true); | editorComp->setVisible (true); | ||||
| @@ -1005,10 +1007,19 @@ public: | |||||
| // is trying to delete our plugin.. | // is trying to delete our plugin.. | ||||
| jassert (Component::getCurrentlyModalComponent() == 0); | jassert (Component::getCurrentlyModalComponent() == 0); | ||||
| if (editorComp != 0 && editorComp->getChildComponent(0) != 0) | |||||
| filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0)); | |||||
| if (editorComp != 0 && editorComp->isValidComponent()) | |||||
| { | |||||
| if (editorComp->getChildComponent(0) != 0) | |||||
| if (activePlugins.contains ((void*) filter)) // plugin may have been deleted before the UI | |||||
| filter->editorBeingDeleted ((AudioProcessorEditor*) editorComp->getChildComponent(0)); | |||||
| deleteAndZero (editorComp); | |||||
| } | |||||
| deleteAndZero (editorComp); | |||||
| jassert (activeUIs.contains (self)); | |||||
| activeUIs.removeValue (self); | |||||
| if (activePlugins.size() + activeUIs.size() == 0) | |||||
| shutdownJuce_GUI(); | |||||
| [super dealloc]; | [super dealloc]; | ||||
| } | } | ||||
| @@ -221,9 +221,13 @@ class SharedMessageThread : public Thread | |||||
| { | { | ||||
| public: | public: | ||||
| SharedMessageThread() | SharedMessageThread() | ||||
| : Thread (T("VstMessageThread")) | |||||
| : Thread (T("VstMessageThread")), | |||||
| initialised (false) | |||||
| { | { | ||||
| startThread (7); | startThread (7); | ||||
| while (! initialised) | |||||
| sleep (1); | |||||
| } | } | ||||
| ~SharedMessageThread() | ~SharedMessageThread() | ||||
| @@ -241,6 +245,9 @@ public: | |||||
| const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); | const Thread::ThreadID originalThreadId = messageManager->getCurrentMessageThread(); | ||||
| messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); | messageManager->setCurrentMessageThread (Thread::getCurrentThreadId()); | ||||
| initialiseJuce_GUI(); | |||||
| initialised = true; | |||||
| while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) | while ((! threadShouldExit()) && messageManager->runDispatchLoopUntil (250)) | ||||
| { | { | ||||
| } | } | ||||
| @@ -249,8 +256,12 @@ public: | |||||
| } | } | ||||
| juce_DeclareSingleton (SharedMessageThread, false) | juce_DeclareSingleton (SharedMessageThread, false) | ||||
| private: | |||||
| bool initialised; | |||||
| }; | }; | ||||
| juce_ImplementSingleton (SharedMessageThread) | |||||
| #endif | #endif | ||||
| @@ -446,6 +457,7 @@ public: | |||||
| { | { | ||||
| if (editorComp == 0) | if (editorComp == 0) | ||||
| { | { | ||||
| const MessageManagerLock mmLock; | |||||
| AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); | AudioProcessorEditor* const ed = filter->createEditorIfNeeded(); | ||||
| if (ed != 0) | if (ed != 0) | ||||
| @@ -462,6 +474,7 @@ public: | |||||
| void close() | void close() | ||||
| { | { | ||||
| const MessageManagerLock mmLock; | |||||
| jassert (! recursionCheck); | jassert (! recursionCheck); | ||||
| stopTimer(); | stopTimer(); | ||||
| @@ -1179,6 +1192,7 @@ public: | |||||
| if (canDeleteLaterIfModal) | if (canDeleteLaterIfModal) | ||||
| { | { | ||||
| shouldDeleteEditor = true; | shouldDeleteEditor = true; | ||||
| recursionCheck = false; | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1219,6 +1233,7 @@ public: | |||||
| } | } | ||||
| else if (opCode == effEditOpen) | else if (opCode == effEditOpen) | ||||
| { | { | ||||
| const MessageManagerLock mmLock; | |||||
| jassert (! recursionCheck); | jassert (! recursionCheck); | ||||
| deleteEditor (true); | deleteEditor (true); | ||||
| @@ -1253,11 +1268,13 @@ public: | |||||
| } | } | ||||
| else if (opCode == effEditClose) | else if (opCode == effEditClose) | ||||
| { | { | ||||
| const MessageManagerLock mmLock; | |||||
| deleteEditor (true); | deleteEditor (true); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| else if (opCode == effEditGetRect) | else if (opCode == effEditGetRect) | ||||
| { | { | ||||
| const MessageManagerLock mmLock; | |||||
| createEditorComp(); | createEditorComp(); | ||||
| if (editorComp != 0) | if (editorComp != 0) | ||||
| @@ -1490,7 +1507,6 @@ extern "C" __attribute__ ((visibility("default"))) AEffect* main_macho (audioMas | |||||
| extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) | extern "C" AEffect* VSTPluginMain (audioMasterCallback audioMaster) | ||||
| { | { | ||||
| initialiseJuce_GUI(); | |||||
| SharedMessageThread::getInstance(); | SharedMessageThread::getInstance(); | ||||
| return pluginEntryPoint (audioMaster); | return pluginEntryPoint (audioMaster); | ||||
| @@ -447,7 +447,7 @@ public: | |||||
| { | { | ||||
| return [[v className] isEqualToString: @"WebNetscapePluginDocumentView"] | return [[v className] isEqualToString: @"WebNetscapePluginDocumentView"] | ||||
| || [[v className] isEqualToString: @"WebPluginDocumentView"] | || [[v className] isEqualToString: @"WebPluginDocumentView"] | ||||
| || [[v className] isEqualToString: @"ChildView"]; | |||||
| || ([[v className] isEqualToString: @"ChildView"] && ([v frame].origin.x != 0 && [v frame].origin.y != 0)); | |||||
| } | } | ||||
| void setWindow (NPWindow* window) | void setWindow (NPWindow* window) | ||||
| @@ -7965,6 +7965,73 @@ bool URL::isWellFormed() const | |||||
| return url.isNotEmpty(); | return url.isNotEmpty(); | ||||
| } | } | ||||
| static int findStartOfDomain (const String& url) | |||||
| { | |||||
| int i = 0; | |||||
| while (CharacterFunctions::isLetterOrDigit (url[i]) | |||||
| || CharacterFunctions::indexOfChar (T("+-."), url[i], false) >= 0) | |||||
| ++i; | |||||
| return url[i] == T(':') ? i + 1 : 0; | |||||
| } | |||||
| const String URL::getDomain() const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int end1 = url.indexOfChar (start, T('/')); | |||||
| const int end2 = url.indexOfChar (start, T(':')); | |||||
| const int end = (end1 < 0 || end2 < 0) ? jmax (end1, end2) | |||||
| : jmin (end1, end2); | |||||
| return url.substring (start, end); | |||||
| } | |||||
| const String URL::getSubPath() const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int startOfPath = url.indexOfChar (start, T('/')) + 1; | |||||
| return startOfPath <= 0 ? String::empty | |||||
| : url.substring (startOfPath); | |||||
| } | |||||
| const String URL::getScheme() const | |||||
| { | |||||
| return url.substring (0, findStartOfDomain (url) - 1); | |||||
| } | |||||
| const URL URL::withNewSubPath (const String& newPath) const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int startOfPath = url.indexOfChar (start, T('/')) + 1; | |||||
| URL u (*this); | |||||
| if (startOfPath > 0) | |||||
| u.url = url.substring (0, startOfPath); | |||||
| if (! u.url.endsWithChar (T('/'))) | |||||
| u.url << '/'; | |||||
| if (newPath.startsWithChar (T('/'))) | |||||
| u.url << newPath.substring (1); | |||||
| else | |||||
| u.url << newPath; | |||||
| return u; | |||||
| } | |||||
| bool URL::isProbablyAWebsiteURL (const String& possibleURL) | bool URL::isProbablyAWebsiteURL (const String& possibleURL) | ||||
| { | { | ||||
| if (possibleURL.startsWithIgnoreCase (T("http:")) | if (possibleURL.startsWithIgnoreCase (T("http:")) | ||||
| @@ -52504,7 +52571,7 @@ public: | |||||
| if (buttonUnderMouse != newItem) | if (buttonUnderMouse != newItem) | ||||
| { | { | ||||
| if (buttonUnderMouse != 0) | |||||
| if (buttonUnderMouse != 0 && containsItem (buttonUnderMouse)) | |||||
| { | { | ||||
| const Rectangle r (buttonUnderMouse->getItemPosition (false)); | const Rectangle r (buttonUnderMouse->getItemPosition (false)); | ||||
| repaint (0, r.getY(), r.getX(), buttonUnderMouse->getItemHeight()); | repaint (0, r.getY(), r.getX(), buttonUnderMouse->getItemHeight()); | ||||
| @@ -52588,6 +52655,15 @@ private: | |||||
| item->setSelected ((! cmd) || (! item->isSelected()), ! cmd); | item->setSelected ((! cmd) || (! item->isSelected()), ! cmd); | ||||
| } | } | ||||
| } | } | ||||
| bool containsItem (TreeViewItem* const item) const | |||||
| { | |||||
| for (int i = rowComponentItems.size(); --i >= 0;) | |||||
| if ((TreeViewItem*) rowComponentItems.getUnchecked (i) == item) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| }; | }; | ||||
| class TreeViewport : public Viewport | class TreeViewport : public Viewport | ||||
| @@ -61074,10 +61150,15 @@ void LookAndFeel::drawButtonBackground (Graphics& g, | |||||
| button.isConnectedOnBottom()); | button.isConnectedOnBottom()); | ||||
| } | } | ||||
| const Font LookAndFeel::getFontForTextButton (TextButton& button) | |||||
| { | |||||
| return button.getFont(); | |||||
| } | |||||
| void LookAndFeel::drawButtonText (Graphics& g, TextButton& button, | void LookAndFeel::drawButtonText (Graphics& g, TextButton& button, | ||||
| bool /*isMouseOverButton*/, bool /*isButtonDown*/) | bool /*isMouseOverButton*/, bool /*isButtonDown*/) | ||||
| { | { | ||||
| g.setFont (button.getFont()); | |||||
| g.setFont (getFontForTextButton (button)); | |||||
| g.setColour (button.findColour (TextButton::textColourId) | g.setColour (button.findColour (TextButton::textColourId) | ||||
| .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f)); | .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f)); | ||||
| @@ -70772,7 +70853,8 @@ MagnifierComponent::MagnifierComponent (Component* const content_, | |||||
| : content (content_), | : content (content_), | ||||
| scaleFactor (0.0), | scaleFactor (0.0), | ||||
| peer (0), | peer (0), | ||||
| deleteContent (deleteContentCompWhenNoLongerNeeded) | |||||
| deleteContent (deleteContentCompWhenNoLongerNeeded), | |||||
| quality (Graphics::lowResamplingQuality) | |||||
| { | { | ||||
| holderComp = new PeerHolderComp (this); | holderComp = new PeerHolderComp (this); | ||||
| setScaleFactor (1.0); | setScaleFactor (1.0); | ||||
| @@ -70844,7 +70926,7 @@ void MagnifierComponent::paint (Graphics& g) | |||||
| g2.reduceClipRegion (srcX, srcY, srcW, srcH); | g2.reduceClipRegion (srcX, srcY, srcW, srcH); | ||||
| holderComp->paintEntireComponent (g2); | holderComp->paintEntireComponent (g2); | ||||
| g.setImageResamplingQuality (Graphics::lowResamplingQuality); | |||||
| g.setImageResamplingQuality (quality); | |||||
| g.drawImage (&temp, | g.drawImage (&temp, | ||||
| 0, 0, (int) (w * scaleFactor), (int) (h * scaleFactor), | 0, 0, (int) (w * scaleFactor), (int) (h * scaleFactor), | ||||
| 0, 0, w, h, | 0, 0, w, h, | ||||
| @@ -72256,6 +72338,9 @@ AlertWindow::AlertWindow (const String& title, | |||||
| } | } | ||||
| } | } | ||||
| if (JUCEApplication::getInstance() == 0) | |||||
| setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level | |||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | ||||
| @@ -76602,6 +76687,7 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw | |||||
| if (n >= maxEdgesPerLine) | if (n >= maxEdgesPerLine) | ||||
| { | { | ||||
| remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); | remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); | ||||
| jassert (n < maxEdgesPerLine); | |||||
| lineStart = table + lineStrideElements * y; | lineStart = table + lineStrideElements * y; | ||||
| } | } | ||||
| @@ -80551,11 +80637,9 @@ const AffineTransform RectanglePlacement::getTransformToFit (float x, float y, | |||||
| const float scaleY = dh / h; | const float scaleY = dh / h; | ||||
| if ((flags & stretchToFit) != 0) | if ((flags & stretchToFit) != 0) | ||||
| { | |||||
| return AffineTransform::translation (-x, -y) | return AffineTransform::translation (-x, -y) | ||||
| .scaled (scaleX, scaleY) | .scaled (scaleX, scaleY) | ||||
| .translated (dx - x, dy - y); | |||||
| } | |||||
| .translated (dx, dy); | |||||
| float scale = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY) | float scale = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY) | ||||
| : jmin (scaleX, scaleY); | : jmin (scaleX, scaleY); | ||||
| @@ -246621,7 +246705,7 @@ static int CALLBACK wfontEnum2 (ENUMLOGFONTEXW* lpelfe, | |||||
| int type, | int type, | ||||
| LPARAM lParam) | LPARAM lParam) | ||||
| { | { | ||||
| if (lpelfe != 0 && type == TRUETYPE_FONTTYPE) | |||||
| if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0) | |||||
| { | { | ||||
| const String fontName (lpelfe->elfLogFont.lfFaceName); | const String fontName (lpelfe->elfLogFont.lfFaceName); | ||||
| @@ -246636,8 +246720,7 @@ static int CALLBACK wfontEnum1 (ENUMLOGFONTEXW* lpelfe, | |||||
| int type, | int type, | ||||
| LPARAM lParam) | LPARAM lParam) | ||||
| { | { | ||||
| if (lpelfe != 0 | |||||
| && ((type & (DEVICE_FONTTYPE | RASTER_FONTTYPE)) == 0)) | |||||
| if (lpelfe != 0 && (type & RASTER_FONTTYPE) == 0) | |||||
| { | { | ||||
| LOGFONTW lf; | LOGFONTW lf; | ||||
| zerostruct (lf); | zerostruct (lf); | ||||
| @@ -12593,6 +12593,32 @@ public: | |||||
| /** True if it seems to be valid. */ | /** True if it seems to be valid. */ | ||||
| bool isWellFormed() const; | bool isWellFormed() const; | ||||
| /** Returns just the domain part of the URL. | |||||
| E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". | |||||
| */ | |||||
| const String getDomain() const; | |||||
| /** Returns the path part of the URL. | |||||
| E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". | |||||
| */ | |||||
| const String getSubPath() const; | |||||
| /** Returns the scheme of the URL. | |||||
| E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't | |||||
| include the colon). | |||||
| */ | |||||
| const String getScheme() const; | |||||
| /** Returns a new version of this URL that uses a different sub-path. | |||||
| E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with | |||||
| "bar", it'll return "http://www.xyz.com/bar?x=1". | |||||
| */ | |||||
| const URL withNewSubPath (const String& newPath) const; | |||||
| /** Returns a copy of this URL, with a GET parameter added to the end. | /** Returns a copy of this URL, with a GET parameter added to the end. | ||||
| Any control characters in the value will be encoded. | Any control characters in the value will be encoded. | ||||
| @@ -52446,6 +52472,10 @@ public: | |||||
| /** Returns the current zoom factor. */ | /** Returns the current zoom factor. */ | ||||
| double getScaleFactor() const throw() { return scaleFactor; } | double getScaleFactor() const throw() { return scaleFactor; } | ||||
| /** Changes the quality setting used to rescale the graphics. | |||||
| */ | |||||
| void setResamplingQuality (Graphics::ResamplingQuality newQuality); | |||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| /** @internal */ | /** @internal */ | ||||
| @@ -52457,6 +52487,7 @@ private: | |||||
| double scaleFactor; | double scaleFactor; | ||||
| ComponentPeer* peer; | ComponentPeer* peer; | ||||
| bool deleteContent; | bool deleteContent; | ||||
| Graphics::ResamplingQuality quality; | |||||
| void paint (Graphics& g); | void paint (Graphics& g); | ||||
| void mouseDown (const MouseEvent& e); | void mouseDown (const MouseEvent& e); | ||||
| @@ -53803,6 +53834,8 @@ public: | |||||
| bool isMouseOverButton, | bool isMouseOverButton, | ||||
| bool isButtonDown); | bool isButtonDown); | ||||
| virtual const Font getFontForTextButton (TextButton& button); | |||||
| /** Draws the text for a TextButton. */ | /** Draws the text for a TextButton. */ | ||||
| virtual void drawButtonText (Graphics& g, | virtual void drawButtonText (Graphics& g, | ||||
| TextButton& button, | TextButton& button, | ||||
| @@ -278,7 +278,7 @@ public: | |||||
| if (buttonUnderMouse != newItem) | if (buttonUnderMouse != newItem) | ||||
| { | { | ||||
| if (buttonUnderMouse != 0) | |||||
| if (buttonUnderMouse != 0 && containsItem (buttonUnderMouse)) | |||||
| { | { | ||||
| const Rectangle r (buttonUnderMouse->getItemPosition (false)); | const Rectangle r (buttonUnderMouse->getItemPosition (false)); | ||||
| repaint (0, r.getY(), r.getX(), buttonUnderMouse->getItemHeight()); | repaint (0, r.getY(), r.getX(), buttonUnderMouse->getItemHeight()); | ||||
| @@ -363,6 +363,15 @@ private: | |||||
| item->setSelected ((! cmd) || (! item->isSelected()), ! cmd); | item->setSelected ((! cmd) || (! item->isSelected()), ! cmd); | ||||
| } | } | ||||
| } | } | ||||
| bool containsItem (TreeViewItem* const item) const | |||||
| { | |||||
| for (int i = rowComponentItems.size(); --i >= 0;) | |||||
| if ((TreeViewItem*) rowComponentItems.getUnchecked (i) == item) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| }; | }; | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -365,10 +365,15 @@ void LookAndFeel::drawButtonBackground (Graphics& g, | |||||
| button.isConnectedOnBottom()); | button.isConnectedOnBottom()); | ||||
| } | } | ||||
| const Font LookAndFeel::getFontForTextButton (TextButton& button) | |||||
| { | |||||
| return button.getFont(); | |||||
| } | |||||
| void LookAndFeel::drawButtonText (Graphics& g, TextButton& button, | void LookAndFeel::drawButtonText (Graphics& g, TextButton& button, | ||||
| bool /*isMouseOverButton*/, bool /*isButtonDown*/) | bool /*isMouseOverButton*/, bool /*isButtonDown*/) | ||||
| { | { | ||||
| g.setFont (button.getFont()); | |||||
| g.setFont (getFontForTextButton (button)); | |||||
| g.setColour (button.findColour (TextButton::textColourId) | g.setColour (button.findColour (TextButton::textColourId) | ||||
| .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f)); | .withMultipliedAlpha (button.isEnabled() ? 1.0f : 0.5f)); | ||||
| @@ -153,6 +153,8 @@ public: | |||||
| bool isMouseOverButton, | bool isMouseOverButton, | ||||
| bool isButtonDown); | bool isButtonDown); | ||||
| virtual const Font getFontForTextButton (TextButton& button); | |||||
| /** Draws the text for a TextButton. */ | /** Draws the text for a TextButton. */ | ||||
| virtual void drawButtonText (Graphics& g, | virtual void drawButtonText (Graphics& g, | ||||
| TextButton& button, | TextButton& button, | ||||
| @@ -200,7 +200,8 @@ MagnifierComponent::MagnifierComponent (Component* const content_, | |||||
| : content (content_), | : content (content_), | ||||
| scaleFactor (0.0), | scaleFactor (0.0), | ||||
| peer (0), | peer (0), | ||||
| deleteContent (deleteContentCompWhenNoLongerNeeded) | |||||
| deleteContent (deleteContentCompWhenNoLongerNeeded), | |||||
| quality (Graphics::lowResamplingQuality) | |||||
| { | { | ||||
| holderComp = new PeerHolderComp (this); | holderComp = new PeerHolderComp (this); | ||||
| setScaleFactor (1.0); | setScaleFactor (1.0); | ||||
| @@ -272,7 +273,7 @@ void MagnifierComponent::paint (Graphics& g) | |||||
| g2.reduceClipRegion (srcX, srcY, srcW, srcH); | g2.reduceClipRegion (srcX, srcY, srcW, srcH); | ||||
| holderComp->paintEntireComponent (g2); | holderComp->paintEntireComponent (g2); | ||||
| g.setImageResamplingQuality (Graphics::lowResamplingQuality); | |||||
| g.setImageResamplingQuality (quality); | |||||
| g.drawImage (&temp, | g.drawImage (&temp, | ||||
| 0, 0, (int) (w * scaleFactor), (int) (h * scaleFactor), | 0, 0, (int) (w * scaleFactor), (int) (h * scaleFactor), | ||||
| 0, 0, w, h, | 0, 0, w, h, | ||||
| @@ -89,6 +89,9 @@ public: | |||||
| /** Returns the current zoom factor. */ | /** Returns the current zoom factor. */ | ||||
| double getScaleFactor() const throw() { return scaleFactor; } | double getScaleFactor() const throw() { return scaleFactor; } | ||||
| /** Changes the quality setting used to rescale the graphics. | |||||
| */ | |||||
| void setResamplingQuality (Graphics::ResamplingQuality newQuality); | |||||
| //============================================================================== | //============================================================================== | ||||
| juce_UseDebuggingNewOperator | juce_UseDebuggingNewOperator | ||||
| @@ -102,6 +105,7 @@ private: | |||||
| double scaleFactor; | double scaleFactor; | ||||
| ComponentPeer* peer; | ComponentPeer* peer; | ||||
| bool deleteContent; | bool deleteContent; | ||||
| Graphics::ResamplingQuality quality; | |||||
| //============================================================================== | //============================================================================== | ||||
| void paint (Graphics& g); | void paint (Graphics& g); | ||||
| @@ -41,6 +41,7 @@ BEGIN_JUCE_NAMESPACE | |||||
| #include "../juce_Desktop.h" | #include "../juce_Desktop.h" | ||||
| #include "../../../../juce_core/text/juce_LocalisedStrings.h" | #include "../../../../juce_core/text/juce_LocalisedStrings.h" | ||||
| #include "../../../events/juce_MessageManager.h" | #include "../../../events/juce_MessageManager.h" | ||||
| #include "../../../application/juce_Application.h" | |||||
| static const int titleH = 24; | static const int titleH = 24; | ||||
| static const int iconWidth = 80; | static const int iconWidth = 80; | ||||
| @@ -112,6 +113,9 @@ AlertWindow::AlertWindow (const String& title, | |||||
| } | } | ||||
| } | } | ||||
| if (JUCEApplication::getInstance() == 0) | |||||
| setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level | |||||
| lookAndFeelChanged(); | lookAndFeelChanged(); | ||||
| constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | constrainer.setMinimumOnscreenAmounts (0x10000, 0x10000, 0x10000, 0x10000); | ||||
| @@ -135,6 +135,7 @@ void EdgeTable::addEdgePoint (const int x, const int y, const int winding) throw | |||||
| if (n >= maxEdgesPerLine) | if (n >= maxEdgesPerLine) | ||||
| { | { | ||||
| remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); | remapTableForNumEdges (maxEdgesPerLine + juce_edgeTableDefaultEdgesPerLine); | ||||
| jassert (n < maxEdgesPerLine); | |||||
| lineStart = table + lineStrideElements * y; | lineStart = table + lineStrideElements * y; | ||||
| } | } | ||||
| @@ -105,11 +105,9 @@ const AffineTransform RectanglePlacement::getTransformToFit (float x, float y, | |||||
| const float scaleY = dh / h; | const float scaleY = dh / h; | ||||
| if ((flags & stretchToFit) != 0) | if ((flags & stretchToFit) != 0) | ||||
| { | |||||
| return AffineTransform::translation (-x, -y) | return AffineTransform::translation (-x, -y) | ||||
| .scaled (scaleX, scaleY) | .scaled (scaleX, scaleY) | ||||
| .translated (dx - x, dy - y); | |||||
| } | |||||
| .translated (dx, dy); | |||||
| float scale = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY) | float scale = (flags & fillDestination) != 0 ? jmax (scaleX, scaleY) | ||||
| : jmin (scaleX, scaleY); | : jmin (scaleX, scaleY); | ||||
| @@ -133,6 +133,73 @@ bool URL::isWellFormed() const | |||||
| return url.isNotEmpty(); | return url.isNotEmpty(); | ||||
| } | } | ||||
| static int findStartOfDomain (const String& url) | |||||
| { | |||||
| int i = 0; | |||||
| while (CharacterFunctions::isLetterOrDigit (url[i]) | |||||
| || CharacterFunctions::indexOfChar (T("+-."), url[i], false) >= 0) | |||||
| ++i; | |||||
| return url[i] == T(':') ? i + 1 : 0; | |||||
| } | |||||
| const String URL::getDomain() const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int end1 = url.indexOfChar (start, T('/')); | |||||
| const int end2 = url.indexOfChar (start, T(':')); | |||||
| const int end = (end1 < 0 || end2 < 0) ? jmax (end1, end2) | |||||
| : jmin (end1, end2); | |||||
| return url.substring (start, end); | |||||
| } | |||||
| const String URL::getSubPath() const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int startOfPath = url.indexOfChar (start, T('/')) + 1; | |||||
| return startOfPath <= 0 ? String::empty | |||||
| : url.substring (startOfPath); | |||||
| } | |||||
| const String URL::getScheme() const | |||||
| { | |||||
| return url.substring (0, findStartOfDomain (url) - 1); | |||||
| } | |||||
| const URL URL::withNewSubPath (const String& newPath) const | |||||
| { | |||||
| int start = findStartOfDomain (url); | |||||
| while (url[start] == T('/')) | |||||
| ++start; | |||||
| const int startOfPath = url.indexOfChar (start, T('/')) + 1; | |||||
| URL u (*this); | |||||
| if (startOfPath > 0) | |||||
| u.url = url.substring (0, startOfPath); | |||||
| if (! u.url.endsWithChar (T('/'))) | |||||
| u.url << '/'; | |||||
| if (newPath.startsWithChar (T('/'))) | |||||
| u.url << newPath.substring (1); | |||||
| else | |||||
| u.url << newPath; | |||||
| return u; | |||||
| } | |||||
| //============================================================================== | //============================================================================== | ||||
| bool URL::isProbablyAWebsiteURL (const String& possibleURL) | bool URL::isProbablyAWebsiteURL (const String& possibleURL) | ||||
| { | { | ||||
| @@ -75,6 +75,32 @@ public: | |||||
| /** True if it seems to be valid. */ | /** True if it seems to be valid. */ | ||||
| bool isWellFormed() const; | bool isWellFormed() const; | ||||
| /** Returns just the domain part of the URL. | |||||
| E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". | |||||
| */ | |||||
| const String getDomain() const; | |||||
| /** Returns the path part of the URL. | |||||
| E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". | |||||
| */ | |||||
| const String getSubPath() const; | |||||
| /** Returns the scheme of the URL. | |||||
| E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't | |||||
| include the colon). | |||||
| */ | |||||
| const String getScheme() const; | |||||
| /** Returns a new version of this URL that uses a different sub-path. | |||||
| E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with | |||||
| "bar", it'll return "http://www.xyz.com/bar?x=1". | |||||
| */ | |||||
| const URL withNewSubPath (const String& newPath) const; | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Returns a copy of this URL, with a GET parameter added to the end. | /** Returns a copy of this URL, with a GET parameter added to the end. | ||||