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];
}
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;
}


+ 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) 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);


+ 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);
}
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))


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

@@ -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);
}
}


+ 247
- 47
juce_amalgamated.cpp View File

@@ -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;
}


+ 65
- 31
juce_amalgamated.h View File

@@ -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


+ 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();
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);


+ 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,
ScrollBar& scrollbar,
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,
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.


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

@@ -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;


+ 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
{
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;
};


Loading…
Cancel
Save