| @@ -271,6 +271,45 @@ void MessageManager::stopDispatchLoop() | |||
| [NSApp stop: nil]; | |||
| } | |||
| static bool isEventBlockedByModalComps (NSEvent* e) | |||
| { | |||
| if (Component::getNumCurrentlyModalComponents() == 0) | |||
| return false; | |||
| [[NSApp mainMenu] update]; | |||
| NSWindow* const w = [e window]; | |||
| if (w == 0 || [w worksWhenModal]) | |||
| return false; | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| { | |||
| ComponentPeer* const peer = ComponentPeer::getPeer (i); | |||
| NSView* const compView = (NSView*) peer->getNativeHandle(); | |||
| if ([compView window] == w | |||
| && (NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], | |||
| [compView bounds]) | |||
| || peer->getComponent()->isMouseButtonDown())) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| if ([e type] == NSLeftMouseDown | |||
| || [e type] == NSRightMouseDown | |||
| || [e type] == NSOtherMouseDown) | |||
| { | |||
| if (! [NSApp isActive]) | |||
| [NSApp activateIgnoringOtherApps: YES]; | |||
| Component* const modal = Component::getCurrentlyModalComponent (0); | |||
| if (modal != 0) | |||
| modal->inputAttemptWhenModal(); | |||
| } | |||
| return true; | |||
| } | |||
| bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| @@ -290,7 +329,9 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| untilDate: endDate | |||
| inMode: NSDefaultRunLoopMode | |||
| dequeue: YES]; | |||
| [NSApp sendEvent: e]; | |||
| if (! isEventBlockedByModalComps (e)) | |||
| [NSApp sendEvent: e]; | |||
| } | |||
| return ! quitMessagePosted; | |||
| @@ -325,8 +366,6 @@ void MessageManager::doPlatformSpecificShutdown() | |||
| getInstance()->runDispatchLoopUntil (10); | |||
| } | |||
| jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting.. | |||
| [juceAppDelegate release]; | |||
| juceAppDelegate = 0; | |||
| } | |||
| @@ -54,7 +54,9 @@ END_JUCE_NAMESPACE | |||
| - (void) drawRect: (NSRect) r; | |||
| - (void) mouseDown: (NSEvent*) ev; | |||
| - (void) asyncMouseDown: (NSEvent*) ev; | |||
| - (void) mouseUp: (NSEvent*) ev; | |||
| - (void) asyncMouseUp: (NSEvent*) ev; | |||
| - (void) mouseDragged: (NSEvent*) ev; | |||
| - (void) mouseMoved: (NSEvent*) ev; | |||
| - (void) mouseEntered: (NSEvent*) ev; | |||
| @@ -252,12 +254,38 @@ END_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| - (void) mouseDown: (NSEvent*) ev | |||
| { | |||
| // In some host situations, the host will stop modal loops from working | |||
| // correctly if they're called from a mouse event, so we'll trigger | |||
| // the event asynchronously.. | |||
| if (JUCEApplication::getInstance() == 0) | |||
| [self performSelectorOnMainThread: @selector (asyncMouseDown:) | |||
| withObject: ev | |||
| waitUntilDone: NO]; | |||
| else | |||
| [self asyncMouseDown: ev]; | |||
| } | |||
| - (void) asyncMouseDown: (NSEvent*) ev | |||
| { | |||
| if (owner != 0) | |||
| owner->redirectMouseDown (ev); | |||
| } | |||
| - (void) mouseUp: (NSEvent*) ev | |||
| { | |||
| // In some host situations, the host will stop modal loops from working | |||
| // correctly if they're called from a mouse event, so we'll trigger | |||
| // the event asynchronously.. | |||
| if (JUCEApplication::getInstance() == 0) | |||
| [self performSelectorOnMainThread: @selector (asyncMouseUp:) | |||
| withObject: ev | |||
| waitUntilDone: NO]; | |||
| else | |||
| [self asyncMouseUp: ev]; | |||
| } | |||
| - (void) asyncMouseUp: (NSEvent*) ev | |||
| { | |||
| if (owner != 0) | |||
| owner->redirectMouseUp (ev); | |||
| @@ -92,6 +92,59 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h, | |||
| return DefWindowProc (h, message, wParam, lParam); | |||
| } | |||
| static bool isEventBlockedByModalComps (MSG& m) | |||
| { | |||
| if (Component::getNumCurrentlyModalComponents() == 0 | |||
| || GetWindowLong (m.hwnd, GWLP_USERDATA) == improbableWindowNumber) | |||
| return false; | |||
| switch (m.message) | |||
| { | |||
| case WM_MOUSEMOVE: | |||
| case WM_NCMOUSEMOVE: | |||
| case 0x020A: /* WM_MOUSEWHEEL */ | |||
| case 0x020E: /* WM_MOUSEHWHEEL */ | |||
| case WM_KEYUP: | |||
| case WM_SYSKEYUP: | |||
| case WM_CHAR: | |||
| case WM_APPCOMMAND: | |||
| case WM_LBUTTONUP: | |||
| case WM_MBUTTONUP: | |||
| case WM_RBUTTONUP: | |||
| case WM_MOUSEACTIVATE: | |||
| case WM_NCMOUSEHOVER: | |||
| case WM_MOUSEHOVER: | |||
| return true; | |||
| case WM_NCLBUTTONDOWN: | |||
| case WM_NCLBUTTONDBLCLK: | |||
| case WM_NCRBUTTONDOWN: | |||
| case WM_NCRBUTTONDBLCLK: | |||
| case WM_NCMBUTTONDOWN: | |||
| case WM_NCMBUTTONDBLCLK: | |||
| case WM_LBUTTONDOWN: | |||
| case WM_LBUTTONDBLCLK: | |||
| case WM_MBUTTONDOWN: | |||
| case WM_MBUTTONDBLCLK: | |||
| case WM_RBUTTONDOWN: | |||
| case WM_RBUTTONDBLCLK: | |||
| case WM_KEYDOWN: | |||
| case WM_SYSKEYDOWN: | |||
| { | |||
| Component* const modal = Component::getCurrentlyModalComponent (0); | |||
| if (modal != 0) | |||
| modal->inputAttemptWhenModal(); | |||
| return true; | |||
| } | |||
| default: | |||
| break; | |||
| } | |||
| return false; | |||
| } | |||
| bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) | |||
| { | |||
| MSG m; | |||
| @@ -106,7 +159,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||
| { | |||
| MessageManager::getInstance()->deliverMessage ((void*) m.lParam); | |||
| } | |||
| else | |||
| else if (! isEventBlockedByModalComps (m)) | |||
| { | |||
| if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber | |||
| && (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)) | |||
| @@ -155,7 +155,7 @@ void AudioFilterStreamingDeviceManager::setFilter (AudioProcessor* filterToStrea | |||
| if (streamer != 0) | |||
| { | |||
| removeMidiInputCallback (String::empty, streamer); | |||
| setAudioCallback (0); | |||
| removeAudioCallback (streamer); | |||
| delete streamer; | |||
| streamer = 0; | |||
| @@ -165,7 +165,7 @@ void AudioFilterStreamingDeviceManager::setFilter (AudioProcessor* filterToStrea | |||
| { | |||
| streamer = new AudioFilterStreamer (*filterToStream); | |||
| setAudioCallback (streamer); | |||
| addAudioCallback (streamer); | |||
| addMidiInputCallback (String::empty, streamer); | |||
| } | |||
| } | |||
| @@ -3562,6 +3562,12 @@ var::var (DynamicObject* const object) throw() | |||
| object->incReferenceCount(); | |||
| } | |||
| var::var (MethodFunction method_) throw() | |||
| : type (methodType) | |||
| { | |||
| value.methodValue = method_; | |||
| } | |||
| const var& var::operator= (const var& valueToCopy) throw() | |||
| { | |||
| if (this != &valueToCopy) | |||
| @@ -3643,6 +3649,14 @@ const var& var::operator= (DynamicObject* const value_) throw() | |||
| return *this; | |||
| } | |||
| const var& var::operator= (MethodFunction method_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = doubleType; | |||
| value.methodValue = method_; | |||
| return *this; | |||
| } | |||
| var::operator int() const throw() | |||
| { | |||
| switch (type) | |||
| @@ -3714,6 +3728,74 @@ DynamicObject* var::getObject() const throw() | |||
| return type == objectType ? value.objectValue : 0; | |||
| } | |||
| const var var::operator[] (const var::identifier& propertyName) const throw() | |||
| { | |||
| if (type == objectType && value.objectValue != 0) | |||
| return value.objectValue->getProperty (propertyName); | |||
| return var(); | |||
| } | |||
| const var var::invoke (const var::identifier& method, const var* arguments, int numArguments) const | |||
| { | |||
| if (type == objectType && value.objectValue != 0) | |||
| return value.objectValue->invokeMethod (method, arguments, numArguments); | |||
| return var(); | |||
| } | |||
| const var var::invoke (const var& targetObject, const var* arguments, int numArguments) const | |||
| { | |||
| if (isMethod()) | |||
| return value.methodValue (targetObject, arguments, numArguments); | |||
| return var(); | |||
| } | |||
| const var var::call (const var::identifier& method) const | |||
| { | |||
| return invoke (method, 0, 0); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1) const | |||
| { | |||
| return invoke (method, &arg1, 1); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2) const | |||
| { | |||
| var args[] = { arg1, arg2 }; | |||
| return invoke (method, args, 2); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2, const var& arg3) | |||
| { | |||
| var args[] = { arg1, arg2, arg3 }; | |||
| return invoke (method, args, 3); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const | |||
| { | |||
| var args[] = { arg1, arg2, arg3, arg4 }; | |||
| return invoke (method, args, 4); | |||
| } | |||
| var::identifier::identifier (const String& name_) throw() | |||
| : name (name_), | |||
| hashCode (name_.hashCode()) | |||
| { | |||
| } | |||
| var::identifier::identifier (const char* const name_) throw() | |||
| : name (name_), | |||
| hashCode (name.hashCode()) | |||
| { | |||
| } | |||
| var::identifier::~identifier() throw() | |||
| { | |||
| } | |||
| DynamicObject::DynamicObject() | |||
| { | |||
| } | |||
| @@ -3722,23 +3804,24 @@ DynamicObject::~DynamicObject() | |||
| { | |||
| } | |||
| bool DynamicObject::hasProperty (const String& propertyName) const | |||
| bool DynamicObject::hasProperty (const var::identifier& propertyName) const | |||
| { | |||
| return propertyNames.contains (propertyName, false); | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| return index >= 0 && ! propertyValues.getUnchecked (index)->isMethod(); | |||
| } | |||
| const var DynamicObject::getProperty (const String& propertyName) const | |||
| const var DynamicObject::getProperty (const var::identifier& propertyName) const | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| return *propertyValues.getUnchecked (index); | |||
| return var(); | |||
| } | |||
| void DynamicObject::setProperty (const String& propertyName, const var& newValue) | |||
| void DynamicObject::setProperty (const var::identifier& propertyName, const var& newValue) | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| { | |||
| @@ -3746,60 +3829,32 @@ void DynamicObject::setProperty (const String& propertyName, const var& newValue | |||
| } | |||
| else | |||
| { | |||
| propertyNames.add (propertyName); | |||
| propertyIds.add (propertyName.hashCode); | |||
| propertyValues.add (new var (newValue)); | |||
| } | |||
| } | |||
| void DynamicObject::removeProperty (const String& propertyName) | |||
| void DynamicObject::removeProperty (const var::identifier& propertyName) | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| { | |||
| propertyNames.remove (index); | |||
| propertyIds.remove (index); | |||
| propertyValues.remove (index); | |||
| } | |||
| } | |||
| bool DynamicObject::hasMethod (const String& methodName) const | |||
| bool DynamicObject::hasMethod (const var::identifier& methodName) const | |||
| { | |||
| return false; | |||
| return getProperty (methodName).isMethod(); | |||
| } | |||
| const var DynamicObject::invokeMethod (const String& methodName, | |||
| const var DynamicObject::invokeMethod (const var::identifier& methodName, | |||
| const var* parameters, | |||
| int numParameters) | |||
| { | |||
| return var(); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName) | |||
| { | |||
| return invokeMethod (methodName, 0, 0); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1) | |||
| { | |||
| return invokeMethod (methodName, &arg1, 1); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2) | |||
| { | |||
| var params[] = { arg1, arg2 }; | |||
| return invokeMethod (methodName, params, 2); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3) | |||
| { | |||
| var params[] = { arg1, arg2, arg3 }; | |||
| return invokeMethod (methodName, params, 3); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3, const var& arg4) | |||
| { | |||
| var params[] = { arg1, arg2, arg3, arg4 }; | |||
| return invokeMethod (methodName, params, 4); | |||
| return getProperty (methodName).invoke (this, parameters, numParameters); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -23037,7 +23092,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| { | |||
| const double callbackStartTime = Time::getMillisecondCounterHiRes(); | |||
| tempBuffer.setSize (numOutputChannels, numSamples, false, false, true); | |||
| tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true); | |||
| callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels, | |||
| outputChannelData, numOutputChannels, numSamples); | |||
| @@ -61038,6 +61093,31 @@ void LookAndFeel::drawProgressBar (Graphics& g, ProgressBar& progressBar, | |||
| } | |||
| } | |||
| void LookAndFeel::drawSpinningWaitAnimation (Graphics& g, int x, int y, int w, int h) | |||
| { | |||
| const float radius = jmin (w, h) * 0.4f; | |||
| const float thickness = radius * 0.15f; | |||
| Path p; | |||
| p.addRoundedRectangle (radius * 0.4f, thickness * -0.5f, | |||
| radius * 0.6f, thickness, | |||
| thickness * 0.5f); | |||
| const float cx = x + w * 0.5f; | |||
| const float cy = y + h * 0.5f; | |||
| const uint32 animationIndex = (Time::getMillisecondCounter() / (1000 / 10)) % 12; | |||
| const Colour col (g.getCurrentColour()); | |||
| for (int i = 0; i < 12; ++i) | |||
| { | |||
| const int n = (i + 12 - animationIndex) % 12; | |||
| g.setColour (col.withMultipliedAlpha ((n + 1) / 12.0f)); | |||
| g.fillPath (p, AffineTransform::rotation (i * (float_Pi / 6.0f)) | |||
| .translated (cx, cy)); | |||
| } | |||
| } | |||
| void LookAndFeel::drawScrollbarButton (Graphics& g, | |||
| ScrollBar& scrollbar, | |||
| int width, int height, | |||
| @@ -242763,6 +242843,59 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h, | |||
| return DefWindowProc (h, message, wParam, lParam); | |||
| } | |||
| static bool isEventBlockedByModalComps (MSG& m) | |||
| { | |||
| if (Component::getNumCurrentlyModalComponents() == 0 | |||
| || GetWindowLong (m.hwnd, GWLP_USERDATA) == improbableWindowNumber) | |||
| return false; | |||
| switch (m.message) | |||
| { | |||
| case WM_MOUSEMOVE: | |||
| case WM_NCMOUSEMOVE: | |||
| case 0x020A: /* WM_MOUSEWHEEL */ | |||
| case 0x020E: /* WM_MOUSEHWHEEL */ | |||
| case WM_KEYUP: | |||
| case WM_SYSKEYUP: | |||
| case WM_CHAR: | |||
| case WM_APPCOMMAND: | |||
| case WM_LBUTTONUP: | |||
| case WM_MBUTTONUP: | |||
| case WM_RBUTTONUP: | |||
| case WM_MOUSEACTIVATE: | |||
| case WM_NCMOUSEHOVER: | |||
| case WM_MOUSEHOVER: | |||
| return true; | |||
| case WM_NCLBUTTONDOWN: | |||
| case WM_NCLBUTTONDBLCLK: | |||
| case WM_NCRBUTTONDOWN: | |||
| case WM_NCRBUTTONDBLCLK: | |||
| case WM_NCMBUTTONDOWN: | |||
| case WM_NCMBUTTONDBLCLK: | |||
| case WM_LBUTTONDOWN: | |||
| case WM_LBUTTONDBLCLK: | |||
| case WM_MBUTTONDOWN: | |||
| case WM_MBUTTONDBLCLK: | |||
| case WM_RBUTTONDOWN: | |||
| case WM_RBUTTONDBLCLK: | |||
| case WM_KEYDOWN: | |||
| case WM_SYSKEYDOWN: | |||
| { | |||
| Component* const modal = Component::getCurrentlyModalComponent (0); | |||
| if (modal != 0) | |||
| modal->inputAttemptWhenModal(); | |||
| return true; | |||
| } | |||
| default: | |||
| break; | |||
| } | |||
| return false; | |||
| } | |||
| bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages) | |||
| { | |||
| MSG m; | |||
| @@ -242777,7 +242910,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages | |||
| { | |||
| MessageManager::getInstance()->deliverMessage ((void*) m.lParam); | |||
| } | |||
| else | |||
| else if (! isEventBlockedByModalComps (m)) | |||
| { | |||
| if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber | |||
| && (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)) | |||
| @@ -266715,7 +266848,9 @@ END_JUCE_NAMESPACE | |||
| - (void) drawRect: (NSRect) r; | |||
| - (void) mouseDown: (NSEvent*) ev; | |||
| - (void) asyncMouseDown: (NSEvent*) ev; | |||
| - (void) mouseUp: (NSEvent*) ev; | |||
| - (void) asyncMouseUp: (NSEvent*) ev; | |||
| - (void) mouseDragged: (NSEvent*) ev; | |||
| - (void) mouseMoved: (NSEvent*) ev; | |||
| - (void) mouseEntered: (NSEvent*) ev; | |||
| @@ -266904,12 +267039,38 @@ END_JUCE_NAMESPACE | |||
| } | |||
| - (void) mouseDown: (NSEvent*) ev | |||
| { | |||
| // In some host situations, the host will stop modal loops from working | |||
| // correctly if they're called from a mouse event, so we'll trigger | |||
| // the event asynchronously.. | |||
| if (JUCEApplication::getInstance() == 0) | |||
| [self performSelectorOnMainThread: @selector (asyncMouseDown:) | |||
| withObject: ev | |||
| waitUntilDone: NO]; | |||
| else | |||
| [self asyncMouseDown: ev]; | |||
| } | |||
| - (void) asyncMouseDown: (NSEvent*) ev | |||
| { | |||
| if (owner != 0) | |||
| owner->redirectMouseDown (ev); | |||
| } | |||
| - (void) mouseUp: (NSEvent*) ev | |||
| { | |||
| // In some host situations, the host will stop modal loops from working | |||
| // correctly if they're called from a mouse event, so we'll trigger | |||
| // the event asynchronously.. | |||
| if (JUCEApplication::getInstance() == 0) | |||
| [self performSelectorOnMainThread: @selector (asyncMouseUp:) | |||
| withObject: ev | |||
| waitUntilDone: NO]; | |||
| else | |||
| [self asyncMouseUp: ev]; | |||
| } | |||
| - (void) asyncMouseUp: (NSEvent*) ev | |||
| { | |||
| if (owner != 0) | |||
| owner->redirectMouseUp (ev); | |||
| @@ -270811,6 +270972,45 @@ void MessageManager::stopDispatchLoop() | |||
| [NSApp stop: nil]; | |||
| } | |||
| static bool isEventBlockedByModalComps (NSEvent* e) | |||
| { | |||
| if (Component::getNumCurrentlyModalComponents() == 0) | |||
| return false; | |||
| [[NSApp mainMenu] update]; | |||
| NSWindow* const w = [e window]; | |||
| if (w == 0 || [w worksWhenModal]) | |||
| return false; | |||
| for (int i = ComponentPeer::getNumPeers(); --i >= 0;) | |||
| { | |||
| ComponentPeer* const peer = ComponentPeer::getPeer (i); | |||
| NSView* const compView = (NSView*) peer->getNativeHandle(); | |||
| if ([compView window] == w | |||
| && (NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], | |||
| [compView bounds]) | |||
| || peer->getComponent()->isMouseButtonDown())) | |||
| { | |||
| return false; | |||
| } | |||
| } | |||
| if ([e type] == NSLeftMouseDown | |||
| || [e type] == NSRightMouseDown | |||
| || [e type] == NSOtherMouseDown) | |||
| { | |||
| if (! [NSApp isActive]) | |||
| [NSApp activateIgnoringOtherApps: YES]; | |||
| Component* const modal = Component::getCurrentlyModalComponent (0); | |||
| if (modal != 0) | |||
| modal->inputAttemptWhenModal(); | |||
| } | |||
| return true; | |||
| } | |||
| bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| @@ -270830,7 +271030,9 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor) | |||
| untilDate: endDate | |||
| inMode: NSDefaultRunLoopMode | |||
| dequeue: YES]; | |||
| [NSApp sendEvent: e]; | |||
| if (! isEventBlockedByModalComps (e)) | |||
| [NSApp sendEvent: e]; | |||
| } | |||
| return ! quitMessagePosted; | |||
| @@ -270864,8 +271066,6 @@ void MessageManager::doPlatformSpecificShutdown() | |||
| getInstance()->runDispatchLoopUntil (10); | |||
| } | |||
| jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting.. | |||
| [juceAppDelegate release]; | |||
| juceAppDelegate = 0; | |||
| } | |||
| @@ -9812,12 +9812,12 @@ public: | |||
| @see getUnchecked | |||
| */ | |||
| inline ObjectClass* operator[] (const int index) const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (((unsigned int) index) < (unsigned int) numUsed) | |||
| ? this->elements [index] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((((unsigned int) index) < (unsigned int) numUsed) | |||
| ? this->elements [index] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| @@ -9827,11 +9827,11 @@ public: | |||
| This is a faster and less safe version of operator[] which doesn't check the index passed in, so | |||
| it can be used when you're sure the index if always going to be legal. | |||
| */ | |||
| inline ObjectClass* getUnchecked (const int index) const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getUnchecked (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| ObjectClass* const result = this->elements [index]; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result (this->elements [index]); | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| @@ -9841,11 +9841,11 @@ public: | |||
| This will return a null pointer if the array's empty. | |||
| @see getLast | |||
| */ | |||
| inline ObjectClass* getFirst() const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| @@ -9856,11 +9856,11 @@ public: | |||
| This will return a null pointer if the array's empty. | |||
| @see getFirst | |||
| */ | |||
| inline ObjectClass* getLast() const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| @@ -11384,6 +11384,8 @@ class JUCE_API var | |||
| { | |||
| public: | |||
| typedef const var (MethodFunction) (const var& thisObject, const var* arguments, int numArguments); | |||
| /** Creates a void variant. */ | |||
| var() throw(); | |||
| @@ -11398,6 +11400,7 @@ public: | |||
| var (const juce_wchar* const value) throw(); | |||
| var (const String& value) throw(); | |||
| var (DynamicObject* const object) throw(); | |||
| var (MethodFunction method) throw(); | |||
| const var& operator= (const var& valueToCopy) throw(); | |||
| const var& operator= (const int value) throw(); | |||
| @@ -11407,6 +11410,7 @@ public: | |||
| const var& operator= (const juce_wchar* const value) throw(); | |||
| const var& operator= (const String& value) throw(); | |||
| const var& operator= (DynamicObject* const object) throw(); | |||
| const var& operator= (MethodFunction method) throw(); | |||
| operator int() const throw(); | |||
| operator bool() const throw(); | |||
| @@ -11420,6 +11424,40 @@ public: | |||
| bool isDouble() const throw() { return type == doubleType; } | |||
| bool isString() const throw() { return type == stringType; } | |||
| bool isObject() const throw() { return type == objectType; } | |||
| bool isMethod() const throw() { return type == methodType; } | |||
| class identifier | |||
| { | |||
| public: | |||
| identifier (const char* const name) throw(); | |||
| identifier (const String& name) throw(); | |||
| ~identifier() throw(); | |||
| bool operator== (const identifier& other) const throw() { return hashCode == other.hashCode; } | |||
| String name; | |||
| int hashCode; | |||
| }; | |||
| /** If this variant is an object, this returns one of its properties. */ | |||
| const var operator[] (const identifier& propertyName) const throw(); | |||
| /** If this variant is an object, this invokes one of its methods with no arguments. */ | |||
| const var call (const identifier& method) const; | |||
| /** If this variant is an object, this invokes one of its methods with one argument. */ | |||
| const var call (const identifier& method, const var& arg1) const; | |||
| /** If this variant is an object, this invokes one of its methods with 2 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2) const; | |||
| /** If this variant is an object, this invokes one of its methods with 3 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3); | |||
| /** If this variant is an object, this invokes one of its methods with 4 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; | |||
| /** If this variant is an object, this invokes one of its methods with a list of arguments. */ | |||
| const var invoke (const identifier& method, const var* arguments, int numArguments) const; | |||
| /** If this variant is a method pointer, this invokes it on a target object. */ | |||
| const var invoke (const var& targetObject, const var* arguments, int numArguments) const; | |||
| juce_UseDebuggingNewOperator | |||
| @@ -11431,7 +11469,8 @@ private: | |||
| boolType, | |||
| doubleType, | |||
| stringType, | |||
| objectType | |||
| objectType, | |||
| methodType | |||
| }; | |||
| Type type; | |||
| @@ -11443,6 +11482,7 @@ private: | |||
| double doubleValue; | |||
| String* stringValue; | |||
| DynamicObject* objectValue; | |||
| MethodFunction* methodValue; | |||
| } value; | |||
| void releaseValue() throw(); | |||
| @@ -11466,32 +11506,21 @@ public: | |||
| /** Destructor. */ | |||
| virtual ~DynamicObject(); | |||
| virtual bool hasProperty (const String& propertyName) const; | |||
| virtual const var getProperty (const String& propertyName) const; | |||
| virtual void setProperty (const String& propertyName, const var& newValue); | |||
| virtual void removeProperty (const String& propertyName); | |||
| virtual bool hasProperty (const var::identifier& propertyName) const; | |||
| virtual const var getProperty (const var::identifier& propertyName) const; | |||
| virtual void setProperty (const var::identifier& propertyName, const var& newValue); | |||
| virtual void removeProperty (const var::identifier& propertyName); | |||
| virtual bool hasMethod (const String& methodName) const; | |||
| virtual bool hasMethod (const var::identifier& methodName) const; | |||
| virtual const var invokeMethod (const String& methodName, | |||
| virtual const var invokeMethod (const var::identifier& methodName, | |||
| const var* parameters, | |||
| int numParameters); | |||
| /** Shortcut method for invoking a method with no arguments. */ | |||
| const var invoke (const String& methodName); | |||
| /** Shortcut method for invoking a method with one argument. */ | |||
| const var invoke (const String& methodName, const var& arg1); | |||
| /** Shortcut method for invoking a method with 2 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2); | |||
| /** Shortcut method for invoking a method with 3 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3); | |||
| /** Shortcut method for invoking a method with 4 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3, const var& arg4); | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| StringArray propertyNames; | |||
| Array <int> propertyIds; | |||
| OwnedArray <var> propertyValues; | |||
| }; | |||
| @@ -53529,6 +53558,11 @@ public: | |||
| int width, int height, | |||
| double progress, const String& textToShow); | |||
| // Draws a small image that spins to indicate that something's happening.. | |||
| // This method should use the current time to animate itself, so just keep | |||
| // repainting it every so often. | |||
| virtual void drawSpinningWaitAnimation (Graphics& g, int x, int y, int w, int h); | |||
| /** Draws one of the buttons on a scrollbar. | |||
| @param g the context to draw into | |||
| @@ -663,7 +663,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| { | |||
| const double callbackStartTime = Time::getMillisecondCounterHiRes(); | |||
| tempBuffer.setSize (numOutputChannels, numSamples, false, false, true); | |||
| tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true); | |||
| callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels, | |||
| outputChannelData, numOutputChannels, numSamples); | |||
| @@ -656,6 +656,31 @@ void LookAndFeel::drawProgressBar (Graphics& g, ProgressBar& progressBar, | |||
| } | |||
| } | |||
| void LookAndFeel::drawSpinningWaitAnimation (Graphics& g, int x, int y, int w, int h) | |||
| { | |||
| const float radius = jmin (w, h) * 0.4f; | |||
| const float thickness = radius * 0.15f; | |||
| Path p; | |||
| p.addRoundedRectangle (radius * 0.4f, thickness * -0.5f, | |||
| radius * 0.6f, thickness, | |||
| thickness * 0.5f); | |||
| const float cx = x + w * 0.5f; | |||
| const float cy = y + h * 0.5f; | |||
| const uint32 animationIndex = (Time::getMillisecondCounter() / (1000 / 10)) % 12; | |||
| const Colour col (g.getCurrentColour()); | |||
| for (int i = 0; i < 12; ++i) | |||
| { | |||
| const int n = (i + 12 - animationIndex) % 12; | |||
| g.setColour (col.withMultipliedAlpha ((n + 1) / 12.0f)); | |||
| g.fillPath (p, AffineTransform::rotation (i * (float_Pi / 6.0f)) | |||
| .translated (cx, cy)); | |||
| } | |||
| } | |||
| void LookAndFeel::drawScrollbarButton (Graphics& g, | |||
| ScrollBar& scrollbar, | |||
| int width, int height, | |||
| @@ -210,6 +210,12 @@ public: | |||
| int width, int height, | |||
| double progress, const String& textToShow); | |||
| //============================================================================== | |||
| // Draws a small image that spins to indicate that something's happening.. | |||
| // This method should use the current time to animate itself, so just keep | |||
| // repainting it every so often. | |||
| virtual void drawSpinningWaitAnimation (Graphics& g, int x, int y, int w, int h); | |||
| //============================================================================== | |||
| /** Draws one of the buttons on a scrollbar. | |||
| @@ -158,12 +158,12 @@ public: | |||
| @see getUnchecked | |||
| */ | |||
| inline ObjectClass* operator[] (const int index) const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (((unsigned int) index) < (unsigned int) numUsed) | |||
| ? this->elements [index] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((((unsigned int) index) < (unsigned int) numUsed) | |||
| ? this->elements [index] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| @@ -173,11 +173,11 @@ public: | |||
| This is a faster and less safe version of operator[] which doesn't check the index passed in, so | |||
| it can be used when you're sure the index if always going to be legal. | |||
| */ | |||
| inline ObjectClass* getUnchecked (const int index) const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getUnchecked (const int index) const throw() | |||
| { | |||
| lock.enter(); | |||
| jassert (((unsigned int) index) < (unsigned int) numUsed); | |||
| ObjectClass* const result = this->elements [index]; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result (this->elements [index]); | |||
| lock.exit(); | |||
| return result; | |||
| } | |||
| @@ -187,11 +187,11 @@ public: | |||
| This will return a null pointer if the array's empty. | |||
| @see getLast | |||
| */ | |||
| inline ObjectClass* getFirst() const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? this->elements [0] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| @@ -202,11 +202,11 @@ public: | |||
| This will return a null pointer if the array's empty. | |||
| @see getFirst | |||
| */ | |||
| inline ObjectClass* getLast() const throw() | |||
| inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw() | |||
| { | |||
| lock.enter(); | |||
| ObjectClass* const result = (numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0; | |||
| const ReferenceCountedObjectPtr<ObjectClass> result ((numUsed > 0) ? this->elements [numUsed - 1] | |||
| : (ObjectClass*) 0); | |||
| lock.exit(); | |||
| return result; | |||
| @@ -1,361 +1,416 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_Variant.h" | |||
| //============================================================================== | |||
| var::var() throw() | |||
| : type (voidType) | |||
| { | |||
| value.doubleValue = 0; | |||
| } | |||
| void var::releaseValue() throw() | |||
| { | |||
| if (type == stringType) | |||
| delete value.stringValue; | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->decReferenceCount(); | |||
| } | |||
| var::~var() | |||
| { | |||
| releaseValue(); | |||
| } | |||
| //============================================================================== | |||
| var::var (const var& valueToCopy) throw() | |||
| : type (valueToCopy.type), | |||
| value (valueToCopy.value) | |||
| { | |||
| if (type == stringType) | |||
| value.stringValue = new String (*(value.stringValue)); | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->incReferenceCount(); | |||
| } | |||
| var::var (const int value_) throw() | |||
| : type (intType) | |||
| { | |||
| value.intValue = value_; | |||
| } | |||
| var::var (const bool value_) throw() | |||
| : type (boolType) | |||
| { | |||
| value.boolValue = value_; | |||
| } | |||
| var::var (const double value_) throw() | |||
| : type (doubleType) | |||
| { | |||
| value.doubleValue = value_; | |||
| } | |||
| var::var (const String& value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (const char* const value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (const juce_wchar* const value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (DynamicObject* const object) throw() | |||
| : type (objectType) | |||
| { | |||
| value.objectValue = object; | |||
| if (object != 0) | |||
| object->incReferenceCount(); | |||
| } | |||
| //============================================================================== | |||
| const var& var::operator= (const var& valueToCopy) throw() | |||
| { | |||
| if (this != &valueToCopy) | |||
| { | |||
| if (type == stringType) | |||
| delete value.stringValue; | |||
| DynamicObject* const oldObject = getObject(); | |||
| type = valueToCopy.type; | |||
| value = valueToCopy.value; | |||
| if (type == stringType) | |||
| value.stringValue = new String (*(value.stringValue)); | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->incReferenceCount(); | |||
| if (oldObject != 0) | |||
| oldObject->decReferenceCount(); | |||
| } | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const int value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = intType; | |||
| value.intValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const bool value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = boolType; | |||
| value.boolValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const double value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = doubleType; | |||
| value.doubleValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const char* const value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const juce_wchar* const value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const String& value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (DynamicObject* const value_) throw() | |||
| { | |||
| value_->incReferenceCount(); | |||
| releaseValue(); | |||
| type = objectType; | |||
| value.objectValue = value_; | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| var::operator int() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: break; | |||
| case intType: return value.intValue; | |||
| case boolType: return value.boolValue ? 1 : 0; | |||
| case doubleType: return (int) value.doubleValue; | |||
| case stringType: return value.stringValue->getIntValue(); | |||
| default: jassertfalse; break; | |||
| } | |||
| return 0; | |||
| } | |||
| var::operator bool() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: break; | |||
| case objectType: return value.objectValue != 0; | |||
| case intType: return value.intValue != 0; | |||
| case boolType: return value.boolValue; | |||
| case doubleType: return value.doubleValue != 0; | |||
| case stringType: return value.stringValue->getIntValue() != 0 | |||
| || value.stringValue->trim().equalsIgnoreCase (T("true")) | |||
| || value.stringValue->trim().equalsIgnoreCase (T("yes")); | |||
| default: jassertfalse; break; | |||
| } | |||
| return false; | |||
| } | |||
| var::operator double() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: break; | |||
| case intType: return value.intValue; | |||
| case boolType: return value.boolValue ? 1.0 : 0.0; | |||
| case doubleType: return value.doubleValue; | |||
| case stringType: return value.stringValue->getDoubleValue(); | |||
| default: jassertfalse; break; | |||
| } | |||
| return 0; | |||
| } | |||
| const String var::toString() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: return "Object 0x" + String::toHexString ((pointer_sized_int) value.objectValue); | |||
| case intType: return String (value.intValue); | |||
| case boolType: return value.boolValue ? T("1") : T("0"); | |||
| case doubleType: return String (value.doubleValue); | |||
| case stringType: return *(value.stringValue); | |||
| default: jassertfalse; break; | |||
| } | |||
| return String::empty; | |||
| } | |||
| DynamicObject* var::getObject() const throw() | |||
| { | |||
| return type == objectType ? value.objectValue : 0; | |||
| } | |||
| //============================================================================== | |||
| //============================================================================== | |||
| DynamicObject::DynamicObject() | |||
| { | |||
| } | |||
| DynamicObject::~DynamicObject() | |||
| { | |||
| } | |||
| bool DynamicObject::hasProperty (const String& propertyName) const | |||
| { | |||
| return propertyNames.contains (propertyName, false); | |||
| } | |||
| const var DynamicObject::getProperty (const String& propertyName) const | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| if (index >= 0) | |||
| return *propertyValues.getUnchecked (index); | |||
| return var(); | |||
| } | |||
| void DynamicObject::setProperty (const String& propertyName, const var& newValue) | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| if (index >= 0) | |||
| { | |||
| propertyValues.set (index, new var (newValue)); | |||
| } | |||
| else | |||
| { | |||
| propertyNames.add (propertyName); | |||
| propertyValues.add (new var (newValue)); | |||
| } | |||
| } | |||
| void DynamicObject::removeProperty (const String& propertyName) | |||
| { | |||
| const int index = propertyNames.indexOf (propertyName, false); | |||
| if (index >= 0) | |||
| { | |||
| propertyNames.remove (index); | |||
| propertyValues.remove (index); | |||
| } | |||
| } | |||
| bool DynamicObject::hasMethod (const String& methodName) const | |||
| { | |||
| return false; | |||
| } | |||
| const var DynamicObject::invokeMethod (const String& methodName, | |||
| const var* parameters, | |||
| int numParameters) | |||
| { | |||
| return var(); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName) | |||
| { | |||
| return invokeMethod (methodName, 0, 0); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1) | |||
| { | |||
| return invokeMethod (methodName, &arg1, 1); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2) | |||
| { | |||
| var params[] = { arg1, arg2 }; | |||
| return invokeMethod (methodName, params, 2); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3) | |||
| { | |||
| var params[] = { arg1, arg2, arg3 }; | |||
| return invokeMethod (methodName, params, 3); | |||
| } | |||
| const var DynamicObject::invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3, const var& arg4) | |||
| { | |||
| var params[] = { arg1, arg2, arg3, arg4 }; | |||
| return invokeMethod (methodName, params, 4); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||
| Copyright 2004-7 by Raw Material Software ltd. | |||
| ------------------------------------------------------------------------------ | |||
| JUCE can be redistributed and/or modified under the terms of the | |||
| GNU General Public License, as published by the Free Software Foundation; | |||
| either version 2 of the License, or (at your option) any later version. | |||
| JUCE is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU General Public License for more details. | |||
| You should have received a copy of the GNU General Public License | |||
| along with JUCE; if not, visit www.gnu.org/licenses or write to the | |||
| Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |||
| Boston, MA 02111-1307 USA | |||
| ------------------------------------------------------------------------------ | |||
| If you'd like to release a closed-source product which uses JUCE, commercial | |||
| licenses are also available: visit www.rawmaterialsoftware.com/juce for | |||
| more information. | |||
| ============================================================================== | |||
| */ | |||
| #include "../basics/juce_StandardHeader.h" | |||
| BEGIN_JUCE_NAMESPACE | |||
| #include "juce_Variant.h" | |||
| //============================================================================== | |||
| var::var() throw() | |||
| : type (voidType) | |||
| { | |||
| value.doubleValue = 0; | |||
| } | |||
| void var::releaseValue() throw() | |||
| { | |||
| if (type == stringType) | |||
| delete value.stringValue; | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->decReferenceCount(); | |||
| } | |||
| var::~var() | |||
| { | |||
| releaseValue(); | |||
| } | |||
| //============================================================================== | |||
| var::var (const var& valueToCopy) throw() | |||
| : type (valueToCopy.type), | |||
| value (valueToCopy.value) | |||
| { | |||
| if (type == stringType) | |||
| value.stringValue = new String (*(value.stringValue)); | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->incReferenceCount(); | |||
| } | |||
| var::var (const int value_) throw() | |||
| : type (intType) | |||
| { | |||
| value.intValue = value_; | |||
| } | |||
| var::var (const bool value_) throw() | |||
| : type (boolType) | |||
| { | |||
| value.boolValue = value_; | |||
| } | |||
| var::var (const double value_) throw() | |||
| : type (doubleType) | |||
| { | |||
| value.doubleValue = value_; | |||
| } | |||
| var::var (const String& value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (const char* const value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (const juce_wchar* const value_) throw() | |||
| : type (stringType) | |||
| { | |||
| value.stringValue = new String (value_); | |||
| } | |||
| var::var (DynamicObject* const object) throw() | |||
| : type (objectType) | |||
| { | |||
| value.objectValue = object; | |||
| if (object != 0) | |||
| object->incReferenceCount(); | |||
| } | |||
| var::var (MethodFunction method_) throw() | |||
| : type (methodType) | |||
| { | |||
| value.methodValue = method_; | |||
| } | |||
| //============================================================================== | |||
| const var& var::operator= (const var& valueToCopy) throw() | |||
| { | |||
| if (this != &valueToCopy) | |||
| { | |||
| if (type == stringType) | |||
| delete value.stringValue; | |||
| DynamicObject* const oldObject = getObject(); | |||
| type = valueToCopy.type; | |||
| value = valueToCopy.value; | |||
| if (type == stringType) | |||
| value.stringValue = new String (*(value.stringValue)); | |||
| else if (type == objectType && value.objectValue != 0) | |||
| value.objectValue->incReferenceCount(); | |||
| if (oldObject != 0) | |||
| oldObject->decReferenceCount(); | |||
| } | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const int value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = intType; | |||
| value.intValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const bool value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = boolType; | |||
| value.boolValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const double value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = doubleType; | |||
| value.doubleValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const char* const value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const juce_wchar* const value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (const String& value_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = stringType; | |||
| value.stringValue = new String (value_); | |||
| return *this; | |||
| } | |||
| const var& var::operator= (DynamicObject* const value_) throw() | |||
| { | |||
| value_->incReferenceCount(); | |||
| releaseValue(); | |||
| type = objectType; | |||
| value.objectValue = value_; | |||
| return *this; | |||
| } | |||
| const var& var::operator= (MethodFunction method_) throw() | |||
| { | |||
| releaseValue(); | |||
| type = doubleType; | |||
| value.methodValue = method_; | |||
| return *this; | |||
| } | |||
| //============================================================================== | |||
| var::operator int() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: break; | |||
| case intType: return value.intValue; | |||
| case boolType: return value.boolValue ? 1 : 0; | |||
| case doubleType: return (int) value.doubleValue; | |||
| case stringType: return value.stringValue->getIntValue(); | |||
| default: jassertfalse; break; | |||
| } | |||
| return 0; | |||
| } | |||
| var::operator bool() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: break; | |||
| case objectType: return value.objectValue != 0; | |||
| case intType: return value.intValue != 0; | |||
| case boolType: return value.boolValue; | |||
| case doubleType: return value.doubleValue != 0; | |||
| case stringType: return value.stringValue->getIntValue() != 0 | |||
| || value.stringValue->trim().equalsIgnoreCase (T("true")) | |||
| || value.stringValue->trim().equalsIgnoreCase (T("yes")); | |||
| default: jassertfalse; break; | |||
| } | |||
| return false; | |||
| } | |||
| var::operator double() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: break; | |||
| case intType: return value.intValue; | |||
| case boolType: return value.boolValue ? 1.0 : 0.0; | |||
| case doubleType: return value.doubleValue; | |||
| case stringType: return value.stringValue->getDoubleValue(); | |||
| default: jassertfalse; break; | |||
| } | |||
| return 0; | |||
| } | |||
| const String var::toString() const throw() | |||
| { | |||
| switch (type) | |||
| { | |||
| case voidType: | |||
| case objectType: return "Object 0x" + String::toHexString ((pointer_sized_int) value.objectValue); | |||
| case intType: return String (value.intValue); | |||
| case boolType: return value.boolValue ? T("1") : T("0"); | |||
| case doubleType: return String (value.doubleValue); | |||
| case stringType: return *(value.stringValue); | |||
| default: jassertfalse; break; | |||
| } | |||
| return String::empty; | |||
| } | |||
| DynamicObject* var::getObject() const throw() | |||
| { | |||
| return type == objectType ? value.objectValue : 0; | |||
| } | |||
| const var var::operator[] (const var::identifier& propertyName) const throw() | |||
| { | |||
| if (type == objectType && value.objectValue != 0) | |||
| return value.objectValue->getProperty (propertyName); | |||
| return var(); | |||
| } | |||
| const var var::invoke (const var::identifier& method, const var* arguments, int numArguments) const | |||
| { | |||
| if (type == objectType && value.objectValue != 0) | |||
| return value.objectValue->invokeMethod (method, arguments, numArguments); | |||
| return var(); | |||
| } | |||
| const var var::invoke (const var& targetObject, const var* arguments, int numArguments) const | |||
| { | |||
| if (isMethod()) | |||
| return value.methodValue (targetObject, arguments, numArguments); | |||
| return var(); | |||
| } | |||
| const var var::call (const var::identifier& method) const | |||
| { | |||
| return invoke (method, 0, 0); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1) const | |||
| { | |||
| return invoke (method, &arg1, 1); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2) const | |||
| { | |||
| var args[] = { arg1, arg2 }; | |||
| return invoke (method, args, 2); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2, const var& arg3) | |||
| { | |||
| var args[] = { arg1, arg2, arg3 }; | |||
| return invoke (method, args, 3); | |||
| } | |||
| const var var::call (const var::identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const | |||
| { | |||
| var args[] = { arg1, arg2, arg3, arg4 }; | |||
| return invoke (method, args, 4); | |||
| } | |||
| //============================================================================== | |||
| var::identifier::identifier (const String& name_) throw() | |||
| : name (name_), | |||
| hashCode (name_.hashCode()) | |||
| { | |||
| } | |||
| var::identifier::identifier (const char* const name_) throw() | |||
| : name (name_), | |||
| hashCode (name.hashCode()) | |||
| { | |||
| } | |||
| var::identifier::~identifier() throw() | |||
| { | |||
| } | |||
| //============================================================================== | |||
| //============================================================================== | |||
| DynamicObject::DynamicObject() | |||
| { | |||
| } | |||
| DynamicObject::~DynamicObject() | |||
| { | |||
| } | |||
| bool DynamicObject::hasProperty (const var::identifier& propertyName) const | |||
| { | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| return index >= 0 && ! propertyValues.getUnchecked (index)->isMethod(); | |||
| } | |||
| const var DynamicObject::getProperty (const var::identifier& propertyName) const | |||
| { | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| return *propertyValues.getUnchecked (index); | |||
| return var(); | |||
| } | |||
| void DynamicObject::setProperty (const var::identifier& propertyName, const var& newValue) | |||
| { | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| { | |||
| propertyValues.set (index, new var (newValue)); | |||
| } | |||
| else | |||
| { | |||
| propertyIds.add (propertyName.hashCode); | |||
| propertyValues.add (new var (newValue)); | |||
| } | |||
| } | |||
| void DynamicObject::removeProperty (const var::identifier& propertyName) | |||
| { | |||
| const int index = propertyIds.indexOf (propertyName.hashCode); | |||
| if (index >= 0) | |||
| { | |||
| propertyIds.remove (index); | |||
| propertyValues.remove (index); | |||
| } | |||
| } | |||
| bool DynamicObject::hasMethod (const var::identifier& methodName) const | |||
| { | |||
| return getProperty (methodName).isMethod(); | |||
| } | |||
| const var DynamicObject::invokeMethod (const var::identifier& methodName, | |||
| const var* parameters, | |||
| int numParameters) | |||
| { | |||
| return getProperty (methodName).invoke (this, parameters, numParameters); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -52,6 +52,9 @@ class JUCE_API DynamicObject; | |||
| class JUCE_API var | |||
| { | |||
| public: | |||
| //============================================================================== | |||
| typedef const var (MethodFunction) (const var& thisObject, const var* arguments, int numArguments); | |||
| //============================================================================== | |||
| /** Creates a void variant. */ | |||
| var() throw(); | |||
| @@ -67,6 +70,7 @@ public: | |||
| var (const juce_wchar* const value) throw(); | |||
| var (const String& value) throw(); | |||
| var (DynamicObject* const object) throw(); | |||
| var (MethodFunction method) throw(); | |||
| const var& operator= (const var& valueToCopy) throw(); | |||
| const var& operator= (const int value) throw(); | |||
| @@ -76,6 +80,7 @@ public: | |||
| const var& operator= (const juce_wchar* const value) throw(); | |||
| const var& operator= (const String& value) throw(); | |||
| const var& operator= (DynamicObject* const object) throw(); | |||
| const var& operator= (MethodFunction method) throw(); | |||
| operator int() const throw(); | |||
| operator bool() const throw(); | |||
| @@ -89,6 +94,43 @@ public: | |||
| bool isDouble() const throw() { return type == doubleType; } | |||
| bool isString() const throw() { return type == stringType; } | |||
| bool isObject() const throw() { return type == objectType; } | |||
| bool isMethod() const throw() { return type == methodType; } | |||
| //============================================================================== | |||
| class identifier | |||
| { | |||
| public: | |||
| identifier (const char* const name) throw(); | |||
| identifier (const String& name) throw(); | |||
| ~identifier() throw(); | |||
| bool operator== (const identifier& other) const throw() { return hashCode == other.hashCode; } | |||
| String name; | |||
| int hashCode; | |||
| }; | |||
| /** If this variant is an object, this returns one of its properties. */ | |||
| const var operator[] (const identifier& propertyName) const throw(); | |||
| //============================================================================== | |||
| /** If this variant is an object, this invokes one of its methods with no arguments. */ | |||
| const var call (const identifier& method) const; | |||
| /** If this variant is an object, this invokes one of its methods with one argument. */ | |||
| const var call (const identifier& method, const var& arg1) const; | |||
| /** If this variant is an object, this invokes one of its methods with 2 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2) const; | |||
| /** If this variant is an object, this invokes one of its methods with 3 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3); | |||
| /** If this variant is an object, this invokes one of its methods with 4 arguments. */ | |||
| const var call (const identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; | |||
| /** If this variant is an object, this invokes one of its methods with a list of arguments. */ | |||
| const var invoke (const identifier& method, const var* arguments, int numArguments) const; | |||
| //============================================================================== | |||
| /** If this variant is a method pointer, this invokes it on a target object. */ | |||
| const var invoke (const var& targetObject, const var* arguments, int numArguments) const; | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -101,7 +143,8 @@ private: | |||
| boolType, | |||
| doubleType, | |||
| stringType, | |||
| objectType | |||
| objectType, | |||
| methodType | |||
| }; | |||
| Type type; | |||
| @@ -113,6 +156,7 @@ private: | |||
| double doubleValue; | |||
| String* stringValue; | |||
| DynamicObject* objectValue; | |||
| MethodFunction* methodValue; | |||
| } value; | |||
| void releaseValue() throw(); | |||
| @@ -138,35 +182,23 @@ public: | |||
| virtual ~DynamicObject(); | |||
| //============================================================================== | |||
| virtual bool hasProperty (const String& propertyName) const; | |||
| virtual const var getProperty (const String& propertyName) const; | |||
| virtual void setProperty (const String& propertyName, const var& newValue); | |||
| virtual void removeProperty (const String& propertyName); | |||
| virtual bool hasProperty (const var::identifier& propertyName) const; | |||
| virtual const var getProperty (const var::identifier& propertyName) const; | |||
| virtual void setProperty (const var::identifier& propertyName, const var& newValue); | |||
| virtual void removeProperty (const var::identifier& propertyName); | |||
| //============================================================================== | |||
| virtual bool hasMethod (const String& methodName) const; | |||
| virtual bool hasMethod (const var::identifier& methodName) const; | |||
| virtual const var invokeMethod (const String& methodName, | |||
| virtual const var invokeMethod (const var::identifier& methodName, | |||
| const var* parameters, | |||
| int numParameters); | |||
| //============================================================================== | |||
| /** Shortcut method for invoking a method with no arguments. */ | |||
| const var invoke (const String& methodName); | |||
| /** Shortcut method for invoking a method with one argument. */ | |||
| const var invoke (const String& methodName, const var& arg1); | |||
| /** Shortcut method for invoking a method with 2 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2); | |||
| /** Shortcut method for invoking a method with 3 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3); | |||
| /** Shortcut method for invoking a method with 4 arguments. */ | |||
| const var invoke (const String& methodName, const var& arg1, const var& arg2, const var& arg3, const var& arg4); | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| StringArray propertyNames; | |||
| Array <int> propertyIds; | |||
| OwnedArray <var> propertyValues; | |||
| }; | |||