Browse Source

Added some cunning hacks that should make modal dialogs in plugins block mouse events in the host app. Also added a fix for thread-safety in ReferenceCountedArrays, and tweaked the new variant classes.

tags/2021-05-28
jules 16 years ago
parent
commit
ef6ab9ed6a
12 changed files with 950 additions and 478 deletions
  1. +42
    -3
      build/macosx/platform_specific_code/juce_mac_MessageManager.mm
  2. +28
    -0
      build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm
  3. +54
    -1
      build/win32/platform_specific_code/juce_win32_Messaging.cpp
  4. +2
    -2
      extras/audio plugins/wrapper/Standalone/juce_AudioFilterStreamer.cpp
  5. +247
    -47
      juce_amalgamated.cpp
  6. +65
    -31
      juce_amalgamated.h
  7. +1
    -1
      src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp
  8. +25
    -0
      src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp
  9. +6
    -0
      src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h
  10. +12
    -12
      src/juce_core/containers/juce_ReferenceCountedArray.h
  11. +416
    -361
      src/juce_core/containers/juce_Variant.cpp
  12. +52
    -20
      src/juce_core/containers/juce_Variant.h

+ 42
- 3
build/macosx/platform_specific_code/juce_mac_MessageManager.mm View File

@@ -271,6 +271,45 @@ void MessageManager::stopDispatchLoop()
[NSApp stop: nil]; [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) bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
{ {
const ScopedAutoReleasePool pool; const ScopedAutoReleasePool pool;
@@ -290,7 +329,9 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
untilDate: endDate untilDate: endDate
inMode: NSDefaultRunLoopMode inMode: NSDefaultRunLoopMode
dequeue: YES]; dequeue: YES];
[NSApp sendEvent: e];
if (! isEventBlockedByModalComps (e))
[NSApp sendEvent: e];
} }
return ! quitMessagePosted; return ! quitMessagePosted;
@@ -325,8 +366,6 @@ void MessageManager::doPlatformSpecificShutdown()
getInstance()->runDispatchLoopUntil (10); getInstance()->runDispatchLoopUntil (10);
} }
jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting..
[juceAppDelegate release]; [juceAppDelegate release];
juceAppDelegate = 0; juceAppDelegate = 0;
} }


+ 28
- 0
build/macosx/platform_specific_code/juce_mac_NSViewComponentPeer.mm View File

@@ -54,7 +54,9 @@ END_JUCE_NAMESPACE
- (void) drawRect: (NSRect) r; - (void) drawRect: (NSRect) r;
- (void) mouseDown: (NSEvent*) ev; - (void) mouseDown: (NSEvent*) ev;
- (void) asyncMouseDown: (NSEvent*) ev;
- (void) mouseUp: (NSEvent*) ev; - (void) mouseUp: (NSEvent*) ev;
- (void) asyncMouseUp: (NSEvent*) ev;
- (void) mouseDragged: (NSEvent*) ev; - (void) mouseDragged: (NSEvent*) ev;
- (void) mouseMoved: (NSEvent*) ev; - (void) mouseMoved: (NSEvent*) ev;
- (void) mouseEntered: (NSEvent*) ev; - (void) mouseEntered: (NSEvent*) ev;
@@ -252,12 +254,38 @@ END_JUCE_NAMESPACE
//============================================================================== //==============================================================================
- (void) mouseDown: (NSEvent*) ev - (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) if (owner != 0)
owner->redirectMouseDown (ev); owner->redirectMouseDown (ev);
} }
- (void) mouseUp: (NSEvent*) 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) if (owner != 0)
owner->redirectMouseUp (ev); owner->redirectMouseUp (ev);


+ 54
- 1
build/win32/platform_specific_code/juce_win32_Messaging.cpp View File

@@ -92,6 +92,59 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h,
return DefWindowProc (h, message, wParam, lParam); 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) bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages)
{ {
MSG m; MSG m;
@@ -106,7 +159,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
{ {
MessageManager::getInstance()->deliverMessage ((void*) m.lParam); MessageManager::getInstance()->deliverMessage ((void*) m.lParam);
} }
else
else if (! isEventBlockedByModalComps (m))
{ {
if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber
&& (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)) && (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN))


+ 2
- 2
extras/audio plugins/wrapper/Standalone/juce_AudioFilterStreamer.cpp View File

@@ -155,7 +155,7 @@ void AudioFilterStreamingDeviceManager::setFilter (AudioProcessor* filterToStrea
if (streamer != 0) if (streamer != 0)
{ {
removeMidiInputCallback (String::empty, streamer); removeMidiInputCallback (String::empty, streamer);
setAudioCallback (0);
removeAudioCallback (streamer);
delete streamer; delete streamer;
streamer = 0; streamer = 0;
@@ -165,7 +165,7 @@ void AudioFilterStreamingDeviceManager::setFilter (AudioProcessor* filterToStrea
{ {
streamer = new AudioFilterStreamer (*filterToStream); streamer = new AudioFilterStreamer (*filterToStream);
setAudioCallback (streamer);
addAudioCallback (streamer);
addMidiInputCallback (String::empty, streamer); addMidiInputCallback (String::empty, streamer);
} }
} }


+ 247
- 47
juce_amalgamated.cpp View File

@@ -3562,6 +3562,12 @@ var::var (DynamicObject* const object) throw()
object->incReferenceCount(); object->incReferenceCount();
} }


var::var (MethodFunction method_) throw()
: type (methodType)
{
value.methodValue = method_;
}

const var& var::operator= (const var& valueToCopy) throw() const var& var::operator= (const var& valueToCopy) throw()
{ {
if (this != &valueToCopy) if (this != &valueToCopy)
@@ -3643,6 +3649,14 @@ const var& var::operator= (DynamicObject* const value_) throw()
return *this; return *this;
} }


const var& var::operator= (MethodFunction method_) throw()
{
releaseValue();
type = doubleType;
value.methodValue = method_;
return *this;
}

var::operator int() const throw() var::operator int() const throw()
{ {
switch (type) switch (type)
@@ -3714,6 +3728,74 @@ DynamicObject* var::getObject() const throw()
return type == objectType ? value.objectValue : 0; 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()
{ {
} }
@@ -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) if (index >= 0)
return *propertyValues.getUnchecked (index); return *propertyValues.getUnchecked (index);


return var(); 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) if (index >= 0)
{ {
@@ -3746,60 +3829,32 @@ void DynamicObject::setProperty (const String& propertyName, const var& newValue
} }
else else
{ {
propertyNames.add (propertyName);
propertyIds.add (propertyName.hashCode);
propertyValues.add (new var (newValue)); 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) if (index >= 0)
{ {
propertyNames.remove (index);
propertyIds.remove (index);
propertyValues.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, const var* parameters,
int numParameters) 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 END_JUCE_NAMESPACE
@@ -23037,7 +23092,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
{ {
const double callbackStartTime = Time::getMillisecondCounterHiRes(); 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, callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples); 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, void LookAndFeel::drawScrollbarButton (Graphics& g,
ScrollBar& scrollbar, ScrollBar& scrollbar,
int width, int height, int width, int height,
@@ -242763,6 +242843,59 @@ static LRESULT CALLBACK juce_MessageWndProc (HWND h,
return DefWindowProc (h, message, wParam, lParam); 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) bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages)
{ {
MSG m; MSG m;
@@ -242777,7 +242910,7 @@ bool juce_dispatchNextMessageOnSystemQueue (const bool returnIfNoPendingMessages
{ {
MessageManager::getInstance()->deliverMessage ((void*) m.lParam); MessageManager::getInstance()->deliverMessage ((void*) m.lParam);
} }
else
else if (! isEventBlockedByModalComps (m))
{ {
if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber if (GetWindowLong (m.hwnd, GWLP_USERDATA) != improbableWindowNumber
&& (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN)) && (m.message == WM_LBUTTONDOWN || m.message == WM_RBUTTONDOWN))
@@ -266715,7 +266848,9 @@ END_JUCE_NAMESPACE
- (void) drawRect: (NSRect) r; - (void) drawRect: (NSRect) r;


- (void) mouseDown: (NSEvent*) ev; - (void) mouseDown: (NSEvent*) ev;
- (void) asyncMouseDown: (NSEvent*) ev;
- (void) mouseUp: (NSEvent*) ev; - (void) mouseUp: (NSEvent*) ev;
- (void) asyncMouseUp: (NSEvent*) ev;
- (void) mouseDragged: (NSEvent*) ev; - (void) mouseDragged: (NSEvent*) ev;
- (void) mouseMoved: (NSEvent*) ev; - (void) mouseMoved: (NSEvent*) ev;
- (void) mouseEntered: (NSEvent*) ev; - (void) mouseEntered: (NSEvent*) ev;
@@ -266904,12 +267039,38 @@ END_JUCE_NAMESPACE
} }


- (void) mouseDown: (NSEvent*) ev - (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) if (owner != 0)
owner->redirectMouseDown (ev); owner->redirectMouseDown (ev);
} }


- (void) mouseUp: (NSEvent*) 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) if (owner != 0)
owner->redirectMouseUp (ev); owner->redirectMouseUp (ev);
@@ -270811,6 +270972,45 @@ void MessageManager::stopDispatchLoop()
[NSApp stop: nil]; [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) bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
{ {
const ScopedAutoReleasePool pool; const ScopedAutoReleasePool pool;
@@ -270830,7 +271030,9 @@ bool MessageManager::runDispatchLoopUntil (int millisecondsToRunFor)
untilDate: endDate untilDate: endDate
inMode: NSDefaultRunLoopMode inMode: NSDefaultRunLoopMode
dequeue: YES]; dequeue: YES];
[NSApp sendEvent: e];

if (! isEventBlockedByModalComps (e))
[NSApp sendEvent: e];
} }


return ! quitMessagePosted; return ! quitMessagePosted;
@@ -270864,8 +271066,6 @@ void MessageManager::doPlatformSpecificShutdown()
getInstance()->runDispatchLoopUntil (10); getInstance()->runDispatchLoopUntil (10);
} }


jassert (numPendingMessages == 0); // failed to get all the pending messages cleared before quitting..

[juceAppDelegate release]; [juceAppDelegate release];
juceAppDelegate = 0; juceAppDelegate = 0;
} }


+ 65
- 31
juce_amalgamated.h View File

@@ -9812,12 +9812,12 @@ public:


@see getUnchecked @see getUnchecked
*/ */
inline ObjectClass* operator[] (const int index) const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw()
{ {
lock.enter(); 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(); lock.exit();
return result; 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 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. 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(); lock.enter();
jassert (((unsigned int) index) < (unsigned int) numUsed); jassert (((unsigned int) index) < (unsigned int) numUsed);
ObjectClass* const result = this->elements [index];
const ReferenceCountedObjectPtr<ObjectClass> result (this->elements [index]);
lock.exit(); lock.exit();
return result; return result;
} }
@@ -9841,11 +9841,11 @@ public:
This will return a null pointer if the array's empty. This will return a null pointer if the array's empty.
@see getLast @see getLast
*/ */
inline ObjectClass* getFirst() const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw()
{ {
lock.enter(); 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(); lock.exit();


return result; return result;
@@ -9856,11 +9856,11 @@ public:
This will return a null pointer if the array's empty. This will return a null pointer if the array's empty.
@see getFirst @see getFirst
*/ */
inline ObjectClass* getLast() const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw()
{ {
lock.enter(); 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(); lock.exit();


return result; return result;
@@ -11384,6 +11384,8 @@ class JUCE_API var
{ {
public: public:


typedef const var (MethodFunction) (const var& thisObject, const var* arguments, int numArguments);

/** Creates a void variant. */ /** Creates a void variant. */
var() throw(); var() throw();


@@ -11398,6 +11400,7 @@ public:
var (const juce_wchar* const value) throw(); var (const juce_wchar* const value) throw();
var (const String& value) throw(); var (const String& value) throw();
var (DynamicObject* const object) throw(); var (DynamicObject* const object) throw();
var (MethodFunction method) throw();


const var& operator= (const var& valueToCopy) throw(); const var& operator= (const var& valueToCopy) throw();
const var& operator= (const int value) 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 juce_wchar* const value) throw();
const var& operator= (const String& value) throw(); const var& operator= (const String& value) throw();
const var& operator= (DynamicObject* const object) throw(); const var& operator= (DynamicObject* const object) throw();
const var& operator= (MethodFunction method) throw();


operator int() const throw(); operator int() const throw();
operator bool() const throw(); operator bool() const throw();
@@ -11420,6 +11424,40 @@ public:
bool isDouble() const throw() { return type == doubleType; } bool isDouble() const throw() { return type == doubleType; }
bool isString() const throw() { return type == stringType; } bool isString() const throw() { return type == stringType; }
bool isObject() const throw() { return type == objectType; } 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 juce_UseDebuggingNewOperator


@@ -11431,7 +11469,8 @@ private:
boolType, boolType,
doubleType, doubleType,
stringType, stringType,
objectType
objectType,
methodType
}; };


Type type; Type type;
@@ -11443,6 +11482,7 @@ private:
double doubleValue; double doubleValue;
String* stringValue; String* stringValue;
DynamicObject* objectValue; DynamicObject* objectValue;
MethodFunction* methodValue;
} value; } value;


void releaseValue() throw(); void releaseValue() throw();
@@ -11466,32 +11506,21 @@ public:
/** Destructor. */ /** Destructor. */
virtual ~DynamicObject(); 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, const var* parameters,
int numParameters); 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 juce_UseDebuggingNewOperator


private: private:
StringArray propertyNames;
Array <int> propertyIds;
OwnedArray <var> propertyValues; OwnedArray <var> propertyValues;
}; };


@@ -53529,6 +53558,11 @@ public:
int width, int height, int width, int height,
double progress, const String& textToShow); 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. /** Draws one of the buttons on a scrollbar.


@param g the context to draw into @param g the context to draw into


+ 1
- 1
src/juce_appframework/audio/devices/juce_AudioDeviceManager.cpp View File

@@ -663,7 +663,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat
{ {
const double callbackStartTime = Time::getMillisecondCounterHiRes(); 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, callbacks.getUnchecked(0)->audioDeviceIOCallback (inputChannelData, numInputChannels,
outputChannelData, numOutputChannels, numSamples); outputChannelData, numOutputChannels, numSamples);


+ 25
- 0
src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.cpp View File

@@ -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, void LookAndFeel::drawScrollbarButton (Graphics& g,
ScrollBar& scrollbar, ScrollBar& scrollbar,
int width, int height, int width, int height,


+ 6
- 0
src/juce_appframework/gui/components/lookandfeel/juce_LookAndFeel.h View File

@@ -210,6 +210,12 @@ public:
int width, int height, int width, int height,
double progress, const String& textToShow); 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. /** Draws one of the buttons on a scrollbar.


+ 12
- 12
src/juce_core/containers/juce_ReferenceCountedArray.h View File

@@ -158,12 +158,12 @@ public:
@see getUnchecked @see getUnchecked
*/ */
inline ObjectClass* operator[] (const int index) const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> operator[] (const int index) const throw()
{ {
lock.enter(); 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(); lock.exit();
return result; 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 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. 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(); lock.enter();
jassert (((unsigned int) index) < (unsigned int) numUsed); jassert (((unsigned int) index) < (unsigned int) numUsed);
ObjectClass* const result = this->elements [index];
const ReferenceCountedObjectPtr<ObjectClass> result (this->elements [index]);
lock.exit(); lock.exit();
return result; return result;
} }
@@ -187,11 +187,11 @@ public:
This will return a null pointer if the array's empty. This will return a null pointer if the array's empty.
@see getLast @see getLast
*/ */
inline ObjectClass* getFirst() const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> getFirst() const throw()
{ {
lock.enter(); 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(); lock.exit();
return result; return result;
@@ -202,11 +202,11 @@ public:
This will return a null pointer if the array's empty. This will return a null pointer if the array's empty.
@see getFirst @see getFirst
*/ */
inline ObjectClass* getLast() const throw()
inline const ReferenceCountedObjectPtr<ObjectClass> getLast() const throw()
{ {
lock.enter(); 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(); lock.exit();
return result; return result;


+ 416
- 361
src/juce_core/containers/juce_Variant.cpp View File

@@ -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
- 20
src/juce_core/containers/juce_Variant.h View File

@@ -52,6 +52,9 @@ class JUCE_API DynamicObject;
class JUCE_API var class JUCE_API var
{ {
public: public:
//==============================================================================
typedef const var (MethodFunction) (const var& thisObject, const var* arguments, int numArguments);
//============================================================================== //==============================================================================
/** Creates a void variant. */ /** Creates a void variant. */
var() throw(); var() throw();
@@ -67,6 +70,7 @@ public:
var (const juce_wchar* const value) throw(); var (const juce_wchar* const value) throw();
var (const String& value) throw(); var (const String& value) throw();
var (DynamicObject* const object) throw(); var (DynamicObject* const object) throw();
var (MethodFunction method) throw();
const var& operator= (const var& valueToCopy) throw(); const var& operator= (const var& valueToCopy) throw();
const var& operator= (const int value) 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 juce_wchar* const value) throw();
const var& operator= (const String& value) throw(); const var& operator= (const String& value) throw();
const var& operator= (DynamicObject* const object) throw(); const var& operator= (DynamicObject* const object) throw();
const var& operator= (MethodFunction method) throw();
operator int() const throw(); operator int() const throw();
operator bool() const throw(); operator bool() const throw();
@@ -89,6 +94,43 @@ public:
bool isDouble() const throw() { return type == doubleType; } bool isDouble() const throw() { return type == doubleType; }
bool isString() const throw() { return type == stringType; } bool isString() const throw() { return type == stringType; }
bool isObject() const throw() { return type == objectType; } 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 juce_UseDebuggingNewOperator
@@ -101,7 +143,8 @@ private:
boolType, boolType,
doubleType, doubleType,
stringType, stringType,
objectType
objectType,
methodType
}; };
Type type; Type type;
@@ -113,6 +156,7 @@ private:
double doubleValue; double doubleValue;
String* stringValue; String* stringValue;
DynamicObject* objectValue; DynamicObject* objectValue;
MethodFunction* methodValue;
} value; } value;
void releaseValue() throw(); void releaseValue() throw();
@@ -138,35 +182,23 @@ public:
virtual ~DynamicObject(); 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, const var* parameters,
int numParameters); 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 juce_UseDebuggingNewOperator
private: private:
StringArray propertyNames;
Array <int> propertyIds;
OwnedArray <var> propertyValues; OwnedArray <var> propertyValues;
}; };


Loading…
Cancel
Save