Browse Source

Added ListenerList class and changed some components to use it for their listener dispatching. Sorted out bug in popup menus and win32 mouse wheel.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
2676bb02f2
42 changed files with 1798 additions and 1850 deletions
  1. +4
    -0
      build/macosx/Juce.xcodeproj/project.pbxproj
  2. +4
    -0
      build/win32/vc8/JUCE.vcproj
  3. +509
    -834
      juce_amalgamated.cpp
  4. +357
    -129
      juce_amalgamated.h
  5. +5
    -15
      src/application/juce_ApplicationCommandManager.cpp
  6. +2
    -2
      src/application/juce_ApplicationCommandManager.h
  7. +4
    -10
      src/containers/juce_Value.cpp
  8. +2
    -1
      src/containers/juce_Value.h
  9. +4
    -34
      src/containers/juce_ValueTree.cpp
  10. +2
    -5
      src/containers/juce_ValueTree.h
  11. +156
    -156
      src/core/juce_StandardHeader.h
  12. +315
    -0
      src/events/juce_ListenerList.h
  13. +10
    -43
      src/gui/components/buttons/juce_Button.cpp
  14. +2
    -2
      src/gui/components/buttons/juce_Button.h
  15. +4
    -9
      src/gui/components/controls/juce_ComboBox.cpp
  16. +1
    -1
      src/gui/components/controls/juce_ComboBox.h
  17. +12
    -13
      src/gui/components/controls/juce_Label.cpp
  18. +1
    -1
      src/gui/components/controls/juce_Label.h
  19. +8
    -19
      src/gui/components/controls/juce_Slider.cpp
  20. +1
    -2
      src/gui/components/controls/juce_Slider.h
  21. +21
    -35
      src/gui/components/controls/juce_TextEditor.cpp
  22. +1
    -1
      src/gui/components/controls/juce_TextEditor.h
  23. +8
    -38
      src/gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.cpp
  24. +1
    -1
      src/gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.h
  25. +9
    -38
      src/gui/components/filebrowser/juce_FileBrowserComponent.cpp
  26. +1
    -1
      src/gui/components/filebrowser/juce_FileBrowserComponent.h
  27. +4
    -10
      src/gui/components/filebrowser/juce_FilenameComponent.cpp
  28. +1
    -1
      src/gui/components/filebrowser/juce_FilenameComponent.h
  29. +234
    -329
      src/gui/components/juce_Component.cpp
  30. +32
    -5
      src/gui/components/juce_Component.h
  31. +1
    -1
      src/gui/components/juce_ComponentListener.cpp
  32. +31
    -51
      src/gui/components/juce_Desktop.cpp
  33. +25
    -25
      src/gui/components/juce_Desktop.h
  34. +3
    -11
      src/gui/components/layout/juce_ScrollBar.cpp
  35. +1
    -1
      src/gui/components/layout/juce_ScrollBar.h
  36. +5
    -17
      src/gui/components/menus/juce_MenuBarModel.cpp
  37. +1
    -1
      src/gui/components/menus/juce_MenuBarModel.h
  38. +7
    -7
      src/gui/components/menus/juce_PopupMenu.cpp
  39. +6
    -0
      src/juce_app_includes.h
  40. +1
    -0
      src/native/juce_linux_NativeCode.cpp
  41. +1
    -0
      src/native/juce_win32_NativeCode.cpp
  42. +1
    -1
      src/native/windows/juce_win32_Windowing.cpp

+ 4
- 0
build/macosx/Juce.xcodeproj/project.pbxproj View File

@@ -30,6 +30,7 @@
844BB95D10C5579B00DF5536 /* juce_FillType.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F29A9E10C2EFA5005014DF /* juce_FillType.h */; };
844BB95E10C557A600DF5536 /* juce_mac_CoreGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = 84D0F00B109B1546007F73A3 /* juce_mac_CoreGraphicsContext.mm */; };
844BB95F10C557A800DF5536 /* juce_Config.h in Headers */ = {isa = PBXBuildFile; fileRef = 8456EC6508A2A6C80087C412 /* juce_Config.h */; };
8458B536113ECFCF0044DA09 /* juce_ListenerList.h in Headers */ = {isa = PBXBuildFile; fileRef = 8458B535113ECFCF0044DA09 /* juce_ListenerList.h */; };
8473E64A11249FD800D74E02 /* juce_TextInputTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 8473E64911249FD800D74E02 /* juce_TextInputTarget.h */; };
8473E64B11249FD800D74E02 /* juce_TextInputTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 8473E64911249FD800D74E02 /* juce_TextInputTarget.h */; };
8473E6531125974600D74E02 /* juce_Range.h in Headers */ = {isa = PBXBuildFile; fileRef = 8473E6521125974600D74E02 /* juce_Range.h */; };
@@ -1245,6 +1246,7 @@
843D4A3A10D3C54500624BA6 /* juce_ValueTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_ValueTree.h; sourceTree = "<group>"; };
8456EC6508A2A6C80087C412 /* juce_Config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = juce_Config.h; path = ../../juce_Config.h; sourceTree = SOURCE_ROOT; };
8456EC6908A2A6F00087C412 /* JUCE changelist.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = "JUCE changelist.txt"; path = "../../docs/JUCE changelist.txt"; sourceTree = SOURCE_ROOT; };
8458B535113ECFCF0044DA09 /* juce_ListenerList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_ListenerList.h; sourceTree = "<group>"; };
8473E64911249FD800D74E02 /* juce_TextInputTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_TextInputTarget.h; sourceTree = "<group>"; };
8473E6521125974600D74E02 /* juce_Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = juce_Range.h; sourceTree = "<group>"; };
84751E591132EE9E00640F9A /* juce_MouseInputSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = juce_MouseInputSource.cpp; sourceTree = "<group>"; };
@@ -2313,6 +2315,7 @@
84F1E958104036B3006A1807 /* juce_InterprocessConnection.h */,
84F1E959104036B3006A1807 /* juce_InterprocessConnectionServer.cpp */,
84F1E95A104036B3006A1807 /* juce_InterprocessConnectionServer.h */,
8458B535113ECFCF0044DA09 /* juce_ListenerList.h */,
84F1E95B104036B3006A1807 /* juce_Message.cpp */,
84F1E95C104036B3006A1807 /* juce_Message.h */,
84F1E95D104036B3006A1807 /* juce_MessageListener.cpp */,
@@ -3594,6 +3597,7 @@
8473E64A11249FD800D74E02 /* juce_TextInputTarget.h in Headers */,
8473E6531125974600D74E02 /* juce_Range.h in Headers */,
84751E5C1132EE9E00640F9A /* juce_MouseInputSource.h in Headers */,
8458B536113ECFCF0044DA09 /* juce_ListenerList.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};


+ 4
- 0
build/win32/vc8/JUCE.vcproj View File

@@ -1285,6 +1285,10 @@
RelativePath="..\..\..\src\events\juce_InterprocessConnectionServer.h"
>
</File>
<File
RelativePath="..\..\..\src\events\juce_ListenerList.h"
>
</File>
<File
RelativePath="..\..\..\src\events\juce_Message.cpp"
>


+ 509
- 834
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 357
- 129
juce_amalgamated.h View File

@@ -43,7 +43,7 @@

#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 51
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7

#define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER)

@@ -1278,7 +1278,11 @@ public:
void vprintf (const tchar* const format, va_list& args) throw();

static const String repeatedString (const tchar* const stringToRepeat,
int numberOfTimesToRepeat) throw();
int numberOfTimesToRepeat);

const String paddedLeft (const juce_wchar padCharacter, int minimumLength) const;

const String paddedRight (const juce_wchar padCharacter, int minimumLength) const;

static const String createStringFromData (const void* const data,
const int size) throw();
@@ -6013,6 +6017,211 @@ private:
#endif // __JUCE_ASYNCUPDATER_JUCEHEADER__
/*** End of inlined file: juce_AsyncUpdater.h ***/


/*** Start of inlined file: juce_ListenerList.h ***/
#ifndef __JUCE_LISTENERLIST_JUCEHEADER__
#define __JUCE_LISTENERLIST_JUCEHEADER__

template <class ListenerClass,
class ArrayType = Array <ListenerClass*> >
class ListenerList
{
public:

ListenerList()
{
}

~ListenerList()
{
}

void add (ListenerClass* const listenerToAdd)
{
// Listeners can't be null pointers!
jassert (listenerToAdd != 0);

if (listenerToAdd != 0)
listeners.add (listenerToAdd);
}

void remove (ListenerClass* const listenerToRemove)
{
// Listeners can't be null pointers!
jassert (listenerToRemove != 0);

listeners.removeValue (listenerToRemove);
}

int size() const throw()
{
return listeners.size();
}

bool isEmpty() const throw()
{
return listeners.size() == 0;
}

bool contains (ListenerClass* const listener) const throw()
{
return listeners.contains (listener);
}

void call (void (ListenerClass::*callbackFunction) ())
{
callChecked (DummyBailOutChecker(), callbackFunction);
}

template <class BailOutCheckerType>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) ())
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) ();
}

template <typename P1, typename P2>
void call (void (ListenerClass::*callbackFunction) (P1),
P2& param1)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1);
}

template <class BailOutCheckerType, typename P1, typename P2>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1),
P2& param1)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1);
}

template <typename P1, typename P2, typename P3, typename P4>
void call (void (ListenerClass::*callbackFunction) (P1, P2),
P3& param1, P4& param2)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2);
}

template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2),
P3& param1, P4& param2)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2);
}

template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3),
P4& param1, P5& param2, P6& param3)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3);
}

template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3),
P4& param1, P5& param2, P6& param3)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3);
}

template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
P5& param1, P6& param2, P7& param3, P8& param4)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
}

template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
P5& param1, P6& param2, P7& param3, P8& param4)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
}

template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
P6& param1, P7& param2, P8& param3, P9& param4, P10& param5)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
}

template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
P6& param1, P7& param2, P8& param3, P9& param4, P10& param5)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
}

class DummyBailOutChecker
{
public:
inline bool shouldBailOut() const throw() { return false; }
};

template <class BailOutCheckerType>
class Iterator
{
public:

Iterator (const ListenerList& list_, const BailOutCheckerType& bailOutChecker_)
: list (list_), bailOutChecker (bailOutChecker_), index (list_.size())
{}

~Iterator() {}

bool next()
{
if (index <= 0 || bailOutChecker.shouldBailOut())
return false;

const int listSize = list.size();

if (--index < listSize)
return true;

index = listSize - 1;
return index >= 0;
}

ListenerClass* getListener() const throw()
{
return list.listeners.getUnchecked (index);
}

private:
const ListenerList& list;
const BailOutCheckerType& bailOutChecker;
int index;

Iterator (const Iterator&);
Iterator& operator= (const Iterator&);
};

private:

ArrayType listeners;

ListenerList (const ListenerList&);
ListenerList& operator= (const ListenerList&);
};

#endif // __JUCE_LISTENERLIST_JUCEHEADER__
/*** End of inlined file: juce_ListenerList.h ***/

class JUCE_API Value
{
public:
@@ -6088,7 +6297,7 @@ public:
private:
friend class ValueSource;
ReferenceCountedObjectPtr <ValueSource> value;
SortedSet <Listener*> listeners;
ListenerList <Listener> listeners;

void callListeners();

@@ -6490,11 +6699,7 @@ private:
typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr;

ReferenceCountedObjectPtr <SharedObject> object;
SortedSet <Listener*> listeners;

void deliverPropertyChangeMessage (ValueTree& tree, const var::identifier& property);
void deliverChildChangeMessage (ValueTree& tree);
void deliverParentChangeMessage (ValueTree& tree);
ListenerList <Listener> listeners;

ValueTree (SharedObject* const object_);
};
@@ -9261,6 +9466,8 @@ public:

int getDistanceFromDragStartY() const throw();

const Point<int> getOffsetFromDragStart() const throw();

bool mouseWasClicked() const throw();

int getNumberOfClicks() const throw() { return numberOfClicks; }
@@ -12379,9 +12586,7 @@ public:
return *this;
}

operator ComponentType*() throw() { return comp; }

operator const ComponentType*() const throw() { return comp; }
operator ComponentType*() const throw() { return comp; }

/** Returns the component that this pointer refers to, or null if the component no longer exists. */
ComponentType* operator->() throw() { jassert (comp != 0); return comp; }
@@ -12399,6 +12604,22 @@ public:
void componentBeingDeleted (Component&) { comp = 0; }
};

class BailOutChecker
{
public:
BailOutChecker (Component* const component1,
Component* const component2 = 0);

bool shouldBailOut() const throw();

private:
Component::SafePointer<Component> safePointer1, safePointer2;
Component* const component2;

BailOutChecker (const BailOutChecker&);
BailOutChecker& operator= (const BailOutChecker&);
};

juce_UseDebuggingNewOperator

private:
@@ -12422,7 +12643,7 @@ private:
Image* bufferedImage_;
VoidArray* mouseListeners_;
VoidArray* keyListeners_;
VoidArray* componentListeners_;
ListenerList <ComponentListener> componentListeners;
NamedValueSet properties;

struct ComponentFlags
@@ -12876,13 +13097,13 @@ class JUCE_API Desktop : private DeletedAtShutdown,
{
public:

static Desktop& JUCE_CALLTYPE getInstance() throw();
static Desktop& JUCE_CALLTYPE getInstance();

const RectangleList getAllMonitorDisplayAreas (const bool clippedToWorkArea = true) const throw();

const Rectangle<int> getMainMonitorArea (const bool clippedToWorkArea = true) const throw();

const Rectangle<int> getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea = true) const throw();
const Rectangle<int> getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea = true) const;

static const Point<int> getMousePosition();

@@ -12896,18 +13117,18 @@ public:

static bool isScreenSaverEnabled() throw();

void addGlobalMouseListener (MouseListener* const listener) throw();
void addGlobalMouseListener (MouseListener* const listener);

void removeGlobalMouseListener (MouseListener* const listener) throw();
void removeGlobalMouseListener (MouseListener* const listener);

void addFocusChangeListener (FocusChangeListener* const listener) throw();
void addFocusChangeListener (FocusChangeListener* const listener);

void removeFocusChangeListener (FocusChangeListener* const listener) throw();
void removeFocusChangeListener (FocusChangeListener* const listener);

void setKioskModeComponent (Component* componentToUse,
const bool allowMenusAndBars = true);

Component* getKioskModeComponent() const { return kioskModeComponent; }
Component* getKioskModeComponent() const throw() { return kioskModeComponent; }

int getNumComponents() const throw();

@@ -12927,7 +13148,7 @@ public:

juce_UseDebuggingNewOperator

void refreshMonitorSizes() throw();
void refreshMonitorSizes();

static bool canUseSemiTransparentWindows() throw();

@@ -12939,42 +13160,43 @@ private:
friend class ComponentPeer;
friend class MouseInputSource;
friend class MouseInputSourceInternal;
SortedSet <void*> mouseListeners, focusListeners;
Array <Component*> desktopComponents;

friend class DeletedAtShutdown;
friend class TopLevelWindowManager;
Desktop() throw();
~Desktop() throw();

Array <Rectangle<int> > monitorCoordsClipped, monitorCoordsUnclipped;

OwnedArray <MouseInputSource> mouseSources;
void createMouseInputSources();

ListenerList <MouseListener> mouseListeners;
ListenerList <FocusChangeListener> focusListeners;

Array <Component*> desktopComponents;
Array <Rectangle<int> > monitorCoordsClipped, monitorCoordsUnclipped;

Point<int> lastFakeMouseMove;
int mouseClickCounter;
void sendMouseMove();

int mouseClickCounter;
void incrementMouseClickCounter() throw();

Component* kioskModeComponent;
Rectangle<int> kioskComponentOriginalBounds;

void createMouseInputSources();

void timerCallback();
void sendMouseMove();
void resetTimer() throw();
void resetTimer();

int getNumDisplayMonitors() const throw();
const Rectangle<int> getDisplayMonitorCoordinates (const int index, const bool clippedToWorkArea) const throw();

void addDesktopComponent (Component* const c) throw();
void removeDesktopComponent (Component* const c) throw();
void componentBroughtToFront (Component* const c) throw();
void addDesktopComponent (Component* const c);
void removeDesktopComponent (Component* const c);
void componentBroughtToFront (Component* const c);

void triggerFocusCallback() throw();
void triggerFocusCallback();
void handleAsyncUpdate();

Desktop();
~Desktop();

Desktop (const Desktop&);
Desktop& operator= (const Desktop&);
};
@@ -13046,11 +13268,11 @@ public:
private:

OwnedArray <ApplicationCommandInfo> commands;
SortedSet <void*> listeners;
ListenerList <ApplicationCommandManagerListener> listeners;
ScopedPointer <KeyPressMappingSet> keyMappings;
ApplicationCommandTarget* firstTarget;

void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) const;
void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info);
void handleAsyncUpdate();
void globalFocusChanged (Component*);

@@ -15708,9 +15930,9 @@ protected:
private:

Array <KeyPress> shortcuts;
Component* keySource;
Component::SafePointer<Component> keySource;
String text;
SortedSet <void*> buttonListeners;
ListenerList <ButtonListener> buttonListeners;

class RepeatTimer;
friend class RepeatTimer;
@@ -15843,7 +16065,7 @@ private:
bool vertical, isDraggingThumb, alwaysVisible;
Button* upButton;
Button* downButton;
SortedSet <void*> listeners;
ListenerList <ScrollBarListener> listeners;

void updateThumbPosition() throw();
void timerCallback();
@@ -15921,7 +16143,7 @@ public:
bool useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);

private:
Component* contentComp;
Component::SafePointer<Component> contentComp;
int lastVX, lastVY, lastVW, lastVH;
int scrollBarThickness;
int singleStepX, singleStepY;
@@ -16385,7 +16607,7 @@ private:
} dragType;

String allowedCharacters;
SortedSet <void*> listeners;
ListenerList <TextEditorListener> listeners;

friend class TextEditorInsertAction;
friend class TextEditorRemoveAction;
@@ -16562,7 +16784,7 @@ private:
Font font;
Justification justification;
ScopedPointer <TextEditor> editor;
SortedSet <void*> listeners;
ListenerList <LabelListener> listeners;
Component::SafePointer<Component> ownerComponent;
int horizontalBorderSize, verticalBorderSize;
float minimumHorizontalScale;
@@ -16710,7 +16932,7 @@ private:
Value currentId;
int lastCurrentId;
bool isButtonDown, separatorPending, menuActive, textIsCustom;
SortedSet <void*> listeners;
ListenerList <ComboBoxListener> listeners;
ScopedPointer<Label> label;
String textWhenNothingSelected, noChoicesMessage;

@@ -19335,6 +19557,9 @@ private:
/*** End of inlined file: juce_InterprocessConnectionServer.h ***/


#endif
#ifndef __JUCE_LISTENERLIST_JUCEHEADER__

#endif
#ifndef __JUCE_MESSAGE_JUCEHEADER__

@@ -21063,7 +21288,7 @@ protected:
void valueChanged (Value& value);

private:
SortedSet <void*> listeners;
ListenerList <SliderListener> listeners;
Value currentValue, valueMin, valueMax;
double lastCurrentValue, lastValueMin, lastValueMax;
double minimum, maximum, interval, doubleClickReturnValue;
@@ -22067,7 +22292,7 @@ public:

protected:
DirectoryContentsList& fileList;
SortedSet <void*> listeners;
ListenerList <FileBrowserListener> listeners;

DirectoryContentsDisplayComponent (const DirectoryContentsDisplayComponent&);
DirectoryContentsDisplayComponent& operator= (const DirectoryContentsDisplayComponent&);
@@ -22197,7 +22422,7 @@ private:
int flags;
File currentRoot;
Array<File> chosenFiles;
SortedSet <void*> listeners;
ListenerList <FileBrowserListener> listeners;

DirectoryContentsDisplayComponent* fileListComponent;
FilePreviewComponent* previewComp;
@@ -22537,9 +22762,9 @@ public:

~ResizableBorderComponent();

void setBorderThickness (const BorderSize& newBorderSize) throw();
void setBorderThickness (const BorderSize& newBorderSize);

const BorderSize getBorderThickness() const throw();
const BorderSize getBorderThickness() const;

juce_UseDebuggingNewOperator

@@ -22553,13 +22778,13 @@ protected:
bool hitTest (int x, int y);

private:
Component* const component;
Component::SafePointer<Component> component;
ComponentBoundsConstrainer* constrainer;
BorderSize borderSize;
int originalX, originalY, originalW, originalH;
Rectangle<int> originalBounds;
int mouseZone;

void updateMouseZone (const MouseEvent& e) throw();
void updateMouseZone (const MouseEvent& e);

ResizableBorderComponent (const ResizableBorderComponent&);
ResizableBorderComponent& operator= (const ResizableBorderComponent&);
@@ -22593,9 +22818,9 @@ protected:

private:

Component* const component;
Component::SafePointer<Component> component;
ComponentBoundsConstrainer* constrainer;
int originalX, originalY, originalW, originalH;
Rectangle<int> originalBounds;

ResizableCornerComponent (const ResizableCornerComponent&);
ResizableCornerComponent& operator= (const ResizableCornerComponent&);
@@ -23038,7 +23263,7 @@ private:
int maxRecentFiles;
bool isDir, isSaving, isFileDragOver;
String wildcard, enforcedSuffix, browseButtonText;
SortedSet <void*> listeners;
ListenerList <FilenameComponentListener> listeners;
File defaultBrowseFile;

void comboBoxChanged (ComboBox*);
@@ -23853,7 +24078,7 @@ public:

private:
ApplicationCommandManager* manager;
SortedSet <void*> listeners;
ListenerList <MenuBarModelListener> listeners;

MenuBarModel (const MenuBarModel&);
MenuBarModel& operator= (const MenuBarModel&);
@@ -25516,6 +25741,81 @@ private:
/*** End of inlined file: juce_MouseHoverDetector.h ***/


#endif
#ifndef __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__

/*** Start of inlined file: juce_MouseInputSource.h ***/
#ifndef __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
#define __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__

class Component;
class ComponentPeer;
class MouseInputSourceInternal;

class JUCE_API MouseInputSource
{
public:

MouseInputSource (int index, bool isMouseDevice);

~MouseInputSource();

bool isMouse() const;

bool isTouch() const;

bool canHover() const;

bool hasMouseWheel() const;

int getIndex() const;

bool isDragging() const;

const Point<int> getScreenPosition() const;

const ModifierKeys getCurrentModifiers() const;

Component* getComponentUnderMouse() const;

void triggerFakeMove() const;

int getNumberOfMultipleClicks() const throw();

const Time getLastMouseDownTime() const throw();

const Point<int> getLastMouseDownPosition() const throw();

bool hasMouseMovedSignificantlySincePressed() const throw();

bool hasMouseCursor() const throw();
void showMouseCursor (const MouseCursor& cursor);
void hideCursor();
void revealCursor();

bool canDoUnboundedMovement() const throw();

void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false);

juce_UseDebuggingNewOperator

void handleEvent (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, const ModifierKeys& mods);
void handleWheel (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, float x, float y);

private:
friend class Desktop;
friend class ComponentPeer;
friend class MouseInputSourceInternal;
ScopedPointer<MouseInputSourceInternal> pimpl;

MouseInputSource (const MouseInputSource&);
MouseInputSource& operator= (const MouseInputSource&);
};

#endif // __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
/*** End of inlined file: juce_MouseInputSource.h ***/


#endif
#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__

@@ -26069,78 +26369,6 @@ private:
#ifndef __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__
#define __JUCE_MAGNIFIERCOMPONENT_JUCEHEADER__


/*** Start of inlined file: juce_MouseInputSource.h ***/
#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__x
#define __JUCE_MOUSEEVENT_JUCEHEADER__x

class Component;
class ComponentPeer;
class MouseInputSourceInternal;

class JUCE_API MouseInputSource
{
public:

MouseInputSource (int index, bool isMouseDevice);

~MouseInputSource();

bool isMouse() const;

bool isTouch() const;

bool canHover() const;

bool hasMouseWheel() const;

int getIndex() const;

bool isDragging() const;

const Point<int> getScreenPosition() const;

const ModifierKeys getCurrentModifiers() const;

Component* getComponentUnderMouse() const;

void triggerFakeMove() const;

int getNumberOfMultipleClicks() const throw();

const Time getLastMouseDownTime() const throw();

const Point<int> getLastMouseDownPosition() const throw();

bool hasMouseMovedSignificantlySincePressed() const throw();

bool hasMouseCursor() const throw();
void showMouseCursor (const MouseCursor& cursor);
void hideCursor();
void revealCursor();

bool canDoUnboundedMovement() const throw();

void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false);

juce_UseDebuggingNewOperator

void handleEvent (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, const ModifierKeys& mods);
void handleWheel (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, float x, float y);

private:
friend class Desktop;
friend class ComponentPeer;
friend class MouseInputSourceInternal;
ScopedPointer<MouseInputSourceInternal> pimpl;

MouseInputSource (const MouseInputSource&);
MouseInputSource& operator= (const MouseInputSource&);
};

#endif // __JUCE_MOUSEEVENT_JUCEHEADER__
/*** End of inlined file: juce_MouseInputSource.h ***/

class JUCE_API MagnifierComponent : public Component
{
public:


+ 5
- 15
src/application/juce_ApplicationCommandManager.cpp View File

@@ -305,32 +305,22 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget(
//==============================================================================
void ApplicationCommandManager::addListener (ApplicationCommandManagerListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void ApplicationCommandManager::removeListener (ApplicationCommandManagerListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void ApplicationCommandManager::sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) const
void ApplicationCommandManager::sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info)
{
for (int i = listeners.size(); --i >= 0;)
{
((ApplicationCommandManagerListener*) listeners.getUnchecked (i))->applicationCommandInvoked (info);
i = jmin (i, listeners.size());
}
listeners.call (&ApplicationCommandManagerListener::applicationCommandInvoked, info);
}
void ApplicationCommandManager::handleAsyncUpdate()
{
for (int i = listeners.size(); --i >= 0;)
{
((ApplicationCommandManagerListener*) listeners.getUnchecked (i))->applicationCommandListChanged();
i = jmin (i, listeners.size());
}
listeners.call (&ApplicationCommandManagerListener::applicationCommandListChanged);
}
void ApplicationCommandManager::globalFocusChanged (Component*)


+ 2
- 2
src/application/juce_ApplicationCommandManager.h View File

@@ -320,11 +320,11 @@ public:
private:
//==============================================================================
OwnedArray <ApplicationCommandInfo> commands;
SortedSet <void*> listeners;
ListenerList <ApplicationCommandManagerListener> listeners;
ScopedPointer <KeyPressMappingSet> keyMappings;
ApplicationCommandTarget* firstTarget;
void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info) const;
void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info);
void handleAsyncUpdate();
void globalFocusChanged (Component*);


+ 4
- 10
src/containers/juce_Value.cpp View File

@@ -200,7 +200,7 @@ void Value::addListener (Listener* const listener)
void Value::removeListener (Listener* const listener)
{
listeners.removeValue (listener);
listeners.remove (listener);
if (listeners.size() == 0)
value->valuesWithListeners.removeValue (this);
@@ -208,15 +208,9 @@ void Value::removeListener (Listener* const listener)
void Value::callListeners()
{
Value valueCopy (*this); // Use a copy in case this object gets deleted by a callback
for (int i = listeners.size(); --i >= 0;)
{
Listener* const l = listeners[i];
if (l != 0)
l->valueChanged (valueCopy);
}
Value v (*this); // (create a copy in case this gets deleted by a callback)
listeners.call (&Listener::valueChanged, v);
}
END_JUCE_NAMESPACE

+ 2
- 1
src/containers/juce_Value.h View File

@@ -28,6 +28,7 @@
#include "juce_Variant.h"
#include "../events/juce_AsyncUpdater.h"
#include "../events/juce_ListenerList.h"
#include "juce_ReferenceCountedObject.h"
#include "juce_SortedSet.h"
@@ -217,7 +218,7 @@ public:
private:
friend class ValueSource;
ReferenceCountedObjectPtr <ValueSource> value;
SortedSet <Listener*> listeners;
ListenerList <Listener> listeners;
void callListeners();


+ 4
- 34
src/containers/juce_ValueTree.cpp View File

@@ -162,23 +162,13 @@ ValueTree::SharedObject::~SharedObject()
}
//==============================================================================
void ValueTree::deliverPropertyChangeMessage (ValueTree& tree, const var::identifier& property)
{
for (int i = listeners.size(); --i >= 0;)
{
ValueTree::Listener* const l = listeners[i];
if (l != 0)
l->valueTreePropertyChanged (tree, property);
}
}
void ValueTree::SharedObject::sendPropertyChangeMessage (ValueTree& tree, const var::identifier& property)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != 0)
v->deliverPropertyChangeMessage (tree, property);
v->listeners.call (&ValueTree::Listener::valueTreePropertyChanged, tree, property);
}
}
@@ -194,23 +184,13 @@ void ValueTree::SharedObject::sendPropertyChangeMessage (const var::identifier&
}
}
void ValueTree::deliverChildChangeMessage (ValueTree& tree)
{
for (int i = listeners.size(); --i >= 0;)
{
ValueTree::Listener* const l = listeners[i];
if (l != 0)
l->valueTreeChildrenChanged (tree);
}
}
void ValueTree::SharedObject::sendChildChangeMessage (ValueTree& tree)
{
for (int i = valueTreesWithListeners.size(); --i >= 0;)
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != 0)
v->deliverChildChangeMessage (tree);
v->listeners.call (&ValueTree::Listener::valueTreeChildrenChanged, tree);
}
}
@@ -226,16 +206,6 @@ void ValueTree::SharedObject::sendChildChangeMessage()
}
}
void ValueTree::deliverParentChangeMessage (ValueTree& tree)
{
for (int i = listeners.size(); --i >= 0;)
{
ValueTree::Listener* const l = listeners[i];
if (l != 0)
l->valueTreeParentChanged (tree);
}
}
void ValueTree::SharedObject::sendParentChangeMessage()
{
ValueTree tree (this);
@@ -252,7 +222,7 @@ void ValueTree::SharedObject::sendParentChangeMessage()
{
ValueTree* const v = valueTreesWithListeners[i];
if (v != 0)
v->deliverParentChangeMessage (tree);
v->listeners.call (&ValueTree::Listener::valueTreeParentChanged, tree);
}
}
@@ -651,7 +621,7 @@ void ValueTree::addListener (Listener* listener)
void ValueTree::removeListener (Listener* listener)
{
listeners.removeValue (listener);
listeners.remove (listener);
if (listeners.size() == 0 && object != 0)
object->valueTreesWithListeners.removeValue (this);


+ 2
- 5
src/containers/juce_ValueTree.h View File

@@ -30,6 +30,7 @@
#include "juce_Value.h"
#include "../utilities/juce_UndoManager.h"
#include "../text/juce_XmlElement.h"
#include "../events/juce_ListenerList.h"
#include "juce_ReferenceCountedArray.h"
@@ -440,11 +441,7 @@ private:
typedef ReferenceCountedObjectPtr <SharedObject> SharedObjectPtr;
ReferenceCountedObjectPtr <SharedObject> object;
SortedSet <Listener*> listeners;
void deliverPropertyChangeMessage (ValueTree& tree, const var::identifier& property);
void deliverChildChangeMessage (ValueTree& tree);
void deliverParentChangeMessage (ValueTree& tree);
ListenerList <Listener> listeners;
ValueTree (SharedObject* const object_);
};


+ 156
- 156
src/core/juce_StandardHeader.h View File

@@ -1,156 +1,156 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCE_STANDARDHEADER_JUCEHEADER__
#define __JUCE_STANDARDHEADER_JUCEHEADER__
//==============================================================================
/** Current Juce version number.
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 51
#define JUCE_BUILDNUMBER 7
/** Current Juce version number.
Bits 16 to 32 = major version.
Bits 8 to 16 = minor version.
Bits 0 to 8 = point release (not currently used).
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER)
//==============================================================================
#include "juce_TargetPlatform.h" // (sets up the various JUCE_WINDOWS, JUCE_MAC, etc flags)
#include "../../juce_Config.h"
//==============================================================================
#ifdef JUCE_NAMESPACE
#define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE {
#define END_JUCE_NAMESPACE }
#else
#define BEGIN_JUCE_NAMESPACE
#define END_JUCE_NAMESPACE
#endif
//==============================================================================
#include "juce_PlatformDefs.h"
// Now we'll include any OS headers we need.. (at this point we are outside the Juce namespace).
#if JUCE_MSVC
#if (defined(_MSC_VER) && (_MSC_VER <= 1200))
#pragma warning (disable: 4284) // (spurious VC6 warning)
#endif
#pragma warning (push)
#pragma warning (disable: 4514 4245 4100)
#endif
#include <cstdlib>
#include <cstdarg>
#include <climits>
#include <limits>
#include <cmath>
#include <cwchar>
#include <stdexcept>
#include <typeinfo>
#include <cstring>
#include <cstdio>
#include <iostream>
#if JUCE_USE_INTRINSICS
#include <intrin.h>
#endif
#if JUCE_MAC || JUCE_IPHONE
#include <libkern/OSAtomic.h>
#endif
#if JUCE_LINUX
#include <signal.h>
#endif
#if JUCE_MSVC && JUCE_DEBUG
#include <crtdbg.h>
#endif
#if JUCE_MSVC
#include <malloc.h>
#pragma warning (pop)
#if ! JUCE_PUBLIC_INCLUDES
#pragma warning (4: 4511 4512 4100) // (enable some warnings that are turned off in VC8)
#endif
#endif
//==============================================================================
// DLL building settings on Win32
#if JUCE_MSVC
#ifdef JUCE_DLL_BUILD
#define JUCE_API __declspec (dllexport)
#pragma warning (disable: 4251)
#elif defined (JUCE_DLL)
#define JUCE_API __declspec (dllimport)
#pragma warning (disable: 4251)
#endif
#elif defined (__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
#ifdef JUCE_DLL_BUILD
#define JUCE_API __attribute__ ((visibility("default")))
#endif
#endif
#ifndef JUCE_API
/** This macro is added to all juce public class declarations. */
#define JUCE_API
#endif
/** This macro is added to all juce public function declarations. */
#define JUCE_PUBLIC_FUNCTION JUCE_API JUCE_CALLTYPE
//==============================================================================
// Now include some basics that are needed by most of the Juce classes...
BEGIN_JUCE_NAMESPACE
extern bool JUCE_PUBLIC_FUNCTION juce_isRunningUnderDebugger();
#if JUCE_LOG_ASSERTIONS
extern void JUCE_API juce_LogAssertion (const char* filename, const int lineNum) throw();
#endif
#include "juce_Memory.h"
#include "juce_MathsFunctions.h"
#include "juce_ByteOrder.h"
#include "juce_Logger.h"
END_JUCE_NAMESPACE
#endif // __JUCE_STANDARDHEADER_JUCEHEADER__
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCE_STANDARDHEADER_JUCEHEADER__
#define __JUCE_STANDARDHEADER_JUCEHEADER__
//==============================================================================
/** Current Juce version number.
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 51
#define JUCE_BUILDNUMBER 7
/** Current Juce version number.
Bits 16 to 32 = major version.
Bits 8 to 16 = minor version.
Bits 0 to 8 = point release (not currently used).
See also SystemStats::getJUCEVersion() for a string version.
*/
#define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER)
//==============================================================================
#include "juce_TargetPlatform.h" // (sets up the various JUCE_WINDOWS, JUCE_MAC, etc flags)
#include "../../juce_Config.h"
//==============================================================================
#ifdef JUCE_NAMESPACE
#define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE {
#define END_JUCE_NAMESPACE }
#else
#define BEGIN_JUCE_NAMESPACE
#define END_JUCE_NAMESPACE
#endif
//==============================================================================
#include "juce_PlatformDefs.h"
// Now we'll include any OS headers we need.. (at this point we are outside the Juce namespace).
#if JUCE_MSVC
#if (defined(_MSC_VER) && (_MSC_VER <= 1200))
#pragma warning (disable: 4284) // (spurious VC6 warning)
#endif
#pragma warning (push)
#pragma warning (disable: 4514 4245 4100)
#endif
#include <cstdlib>
#include <cstdarg>
#include <climits>
#include <limits>
#include <cmath>
#include <cwchar>
#include <stdexcept>
#include <typeinfo>
#include <cstring>
#include <cstdio>
#include <iostream>
#if JUCE_USE_INTRINSICS
#include <intrin.h>
#endif
#if JUCE_MAC || JUCE_IPHONE
#include <libkern/OSAtomic.h>
#endif
#if JUCE_LINUX
#include <signal.h>
#endif
#if JUCE_MSVC && JUCE_DEBUG
#include <crtdbg.h>
#endif
#if JUCE_MSVC
#include <malloc.h>
#pragma warning (pop)
#if ! JUCE_PUBLIC_INCLUDES
#pragma warning (4: 4511 4512 4100) // (enable some warnings that are turned off in VC8)
#endif
#endif
//==============================================================================
// DLL building settings on Win32
#if JUCE_MSVC
#ifdef JUCE_DLL_BUILD
#define JUCE_API __declspec (dllexport)
#pragma warning (disable: 4251)
#elif defined (JUCE_DLL)
#define JUCE_API __declspec (dllimport)
#pragma warning (disable: 4251)
#endif
#elif defined (__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
#ifdef JUCE_DLL_BUILD
#define JUCE_API __attribute__ ((visibility("default")))
#endif
#endif
#ifndef JUCE_API
/** This macro is added to all juce public class declarations. */
#define JUCE_API
#endif
/** This macro is added to all juce public function declarations. */
#define JUCE_PUBLIC_FUNCTION JUCE_API JUCE_CALLTYPE
//==============================================================================
// Now include some basics that are needed by most of the Juce classes...
BEGIN_JUCE_NAMESPACE
extern bool JUCE_PUBLIC_FUNCTION juce_isRunningUnderDebugger();
#if JUCE_LOG_ASSERTIONS
extern void JUCE_API juce_LogAssertion (const char* filename, const int lineNum) throw();
#endif
#include "juce_Memory.h"
#include "juce_MathsFunctions.h"
#include "juce_ByteOrder.h"
#include "juce_Logger.h"
END_JUCE_NAMESPACE
#endif // __JUCE_STANDARDHEADER_JUCEHEADER__

+ 315
- 0
src/events/juce_ListenerList.h View File

@@ -0,0 +1,315 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
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.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
#ifndef __JUCE_LISTENERLIST_JUCEHEADER__
#define __JUCE_LISTENERLIST_JUCEHEADER__
#include "../containers/juce_Array.h"
//==============================================================================
/**
Holds a set of objects and can invoke a member function callback on each object
in the set with a single call.
Use a ListenerList to manage a set of objects which need a callback, and you
can invoke a member function by simply calling call() or callChecked().
E.g.
@code
class MyListenerType
{
public:
void myCallbackMethod (int foo, bool bar);
};
ListenerList <MyListenerType> listeners;
listeners.add (someCallbackObjects...);
// This will invoke myCallbackMethod (1234, true) on each of the objects
// in the list...
listeners.call (&MyListenerType::myCallbackMethod, 1234, true);
@endcode
If you add or remove listeners from the list during one of the callbacks - i.e. while
it's in the middle of iterating the listeners, then it's guaranteed that no listeners
will be mistakenly called after they've been removed, but it may mean that some of the
listeners could be called more than once, or not at all, depending on the list's order.
Sometimes, there's a chance that invoking one of the callbacks might result in the
list itself being deleted while it's still iterating - to survive this situation, you can
use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker".
The BailOutChecker must implement a method of the form "bool shouldBailOut()", and
the list will check this after each callback to determine whether it should abort the
operation. For an example of a bail-out checker, see the Component::BailOutChecker class,
which can be used to check when a Component has been deleted. See also
ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false.
*/
template <class ListenerClass,
class ArrayType = Array <ListenerClass*> >
class ListenerList
{
public:
//==============================================================================
/** Creates an empty list. */
ListenerList()
{
}
/** Destructor. */
~ListenerList()
{
}
//==============================================================================
/** Adds a listener to the list.
A listener can only be added once, so if the listener is already in the list,
this method has no effect.
@see remove
*/
void add (ListenerClass* const listenerToAdd)
{
// Listeners can't be null pointers!
jassert (listenerToAdd != 0);
if (listenerToAdd != 0)
listeners.add (listenerToAdd);
}
/** Removes a listener from the list.
If the listener wasn't in the list, this has no effect.
*/
void remove (ListenerClass* const listenerToRemove)
{
// Listeners can't be null pointers!
jassert (listenerToRemove != 0);
listeners.removeValue (listenerToRemove);
}
/** Returns the number of registered listeners. */
int size() const throw()
{
return listeners.size();
}
/** Returns true if any listeners are registered. */
bool isEmpty() const throw()
{
return listeners.size() == 0;
}
/** Returns true if the specified listener has been added to the list. */
bool contains (ListenerClass* const listener) const throw()
{
return listeners.contains (listener);
}
//==============================================================================
/** Calls a member function on each listener in the list, with no parameters. */
void call (void (ListenerClass::*callbackFunction) ())
{
callChecked (DummyBailOutChecker(), callbackFunction);
}
/** Calls a member function on each listener in the list, with no parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) ())
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) ();
}
//==============================================================================
/** Calls a member function on each listener in the list, with 1 parameter. */
template <typename P1, typename P2>
void call (void (ListenerClass::*callbackFunction) (P1),
P2& param1)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1);
}
/** Calls a member function on each listener in the list, with one parameter and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType, typename P1, typename P2>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1),
P2& param1)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1);
}
//==============================================================================
/** Calls a member function on each listener in the list, with 2 parameters. */
template <typename P1, typename P2, typename P3, typename P4>
void call (void (ListenerClass::*callbackFunction) (P1, P2),
P3& param1, P4& param2)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2);
}
/** Calls a member function on each listener in the list, with 2 parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2),
P3& param1, P4& param2)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2);
}
//==============================================================================
/** Calls a member function on each listener in the list, with 3 parameters. */
template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3),
P4& param1, P5& param2, P6& param3)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3);
}
/** Calls a member function on each listener in the list, with 3 parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3),
P4& param1, P5& param2, P6& param3)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3);
}
//==============================================================================
/** Calls a member function on each listener in the list, with 4 parameters. */
template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
P5& param1, P6& param2, P7& param3, P8& param4)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
}
/** Calls a member function on each listener in the list, with 4 parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
P5& param1, P6& param2, P7& param3, P8& param4)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4);
}
//==============================================================================
/** Calls a member function on each listener in the list, with 5 parameters. */
template <typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
P6& param1, P7& param2, P8& param3, P9& param4, P10& param5)
{
for (Iterator<DummyBailOutChecker> iter (*this, DummyBailOutChecker()); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
}
/** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker.
See the class description for info about writing a bail-out checker. */
template <class BailOutCheckerType, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9, typename P10>
void callChecked (const BailOutCheckerType& bailOutChecker,
void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5),
P6& param1, P7& param2, P8& param3, P9& param4, P10& param5)
{
for (Iterator<BailOutCheckerType> iter (*this, bailOutChecker); iter.next();)
(iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5);
}
//==============================================================================
/** A dummy bail-out checker that always returns false.
See the ListenerList notes for more info about bail-out checkers.
*/
class DummyBailOutChecker
{
public:
inline bool shouldBailOut() const throw() { return false; }
};
//==============================================================================
/** Iterates the listeners in a ListenerList. */
template <class BailOutCheckerType>
class Iterator
{
public:
//==============================================================================
Iterator (const ListenerList& list_, const BailOutCheckerType& bailOutChecker_)
: list (list_), bailOutChecker (bailOutChecker_), index (list_.size())
{}
~Iterator() {}
//==============================================================================
bool next()
{
if (index <= 0 || bailOutChecker.shouldBailOut())
return false;
const int listSize = list.size();
if (--index < listSize)
return true;
index = listSize - 1;
return index >= 0;
}
ListenerClass* getListener() const throw()
{
return list.listeners.getUnchecked (index);
}
//==============================================================================
private:
const ListenerList& list;
const BailOutCheckerType& bailOutChecker;
int index;
Iterator (const Iterator&);
Iterator& operator= (const Iterator&);
};
private:
//==============================================================================
ArrayType listeners;
ListenerList (const ListenerList&);
ListenerList& operator= (const ListenerList&);
};
#endif // __JUCE_LISTENERLIST_JUCEHEADER__

+ 10
- 43
src/gui/components/buttons/juce_Button.cpp View File

@@ -52,7 +52,6 @@ private:
//==============================================================================
Button::Button (const String& name)
: Component (name),
keySource (0),
text (name),
buttonPressTime (0),
lastTimeCallbackTime (0),
@@ -352,23 +351,17 @@ void Button::handleCommandMessage (int commandId)
//==============================================================================
void Button::addButtonListener (ButtonListener* const newListener)
{
jassert (newListener != 0);
jassert (! buttonListeners.contains (newListener)); // trying to add a listener to the list twice!
if (newListener != 0)
buttonListeners.add (newListener);
buttonListeners.add (newListener);
}
void Button::removeButtonListener (ButtonListener* const listener)
{
jassert (buttonListeners.contains (listener)); // trying to remove a listener that isn't on the list!
buttonListeners.removeValue (listener);
buttonListeners.remove (listener);
}
void Button::sendClickMessage (const ModifierKeys& modifiers)
{
Component::SafePointer<Component> deletionWatcher (this);
Component::BailOutChecker checker (this);
if (commandManagerToUse != 0 && commandID != 0)
{
@@ -381,44 +374,18 @@ void Button::sendClickMessage (const ModifierKeys& modifiers)
clicked (modifiers);
if (deletionWatcher != 0)
{
for (int i = buttonListeners.size(); --i >= 0;)
{
ButtonListener* const bl = (ButtonListener*) buttonListeners[i];
if (bl != 0)
{
bl->buttonClicked (this);
if (deletionWatcher == 0)
return;
}
}
}
if (! checker.shouldBailOut())
buttonListeners.callChecked (checker, &ButtonListener::buttonClicked, this);
}
void Button::sendStateMessage()
{
Component::SafePointer<Component> deletionWatcher (this);
Component::BailOutChecker checker (this);
buttonStateChanged();
if (deletionWatcher == 0)
return;
for (int i = buttonListeners.size(); --i >= 0;)
{
ButtonListener* const bl = (ButtonListener*) buttonListeners[i];
if (bl != 0)
{
bl->buttonStateChanged (this);
if (deletionWatcher == 0)
return;
}
}
if (! checker.shouldBailOut())
buttonListeners.callChecked (checker, &ButtonListener::buttonStateChanged, this);
}
//==============================================================================
@@ -512,12 +479,12 @@ void Button::parentHierarchyChanged()
if (newKeySource != keySource)
{
if (keySource->isValidComponent())
if (keySource != 0)
keySource->removeKeyListener (this);
keySource = newKeySource;
if (keySource->isValidComponent())
if (keySource != 0)
keySource->addKeyListener (this);
}
}


+ 2
- 2
src/gui/components/buttons/juce_Button.h View File

@@ -469,9 +469,9 @@ protected:
private:
//==============================================================================
Array <KeyPress> shortcuts;
Component* keySource;
Component::SafePointer<Component> keySource;
String text;
SortedSet <void*> buttonListeners;
ListenerList <ButtonListener> buttonListeners;
class RepeatTimer;
friend class RepeatTimer;


+ 4
- 9
src/gui/components/controls/juce_ComboBox.cpp View File

@@ -605,23 +605,18 @@ void ComboBox::mouseUp (const MouseEvent& e2)
//==============================================================================
void ComboBox::addListener (ComboBoxListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void ComboBox::removeListener (ComboBoxListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void ComboBox::handleAsyncUpdate()
{
for (int i = listeners.size(); --i >= 0;)
{
((ComboBoxListener*) listeners.getUnchecked (i))->comboBoxChanged (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &ComboBoxListener::comboBoxChanged, this);
}


+ 1
- 1
src/gui/components/controls/juce_ComboBox.h View File

@@ -392,7 +392,7 @@ private:
Value currentId;
int lastCurrentId;
bool isButtonDown, separatorPending, menuActive, textIsCustom;
SortedSet <void*> listeners;
ListenerList <ComboBoxListener> listeners;
ScopedPointer<Label> label;
String textWhenNothingSelected, noChoicesMessage;


+ 12
- 13
src/gui/components/controls/juce_Label.cpp View File

@@ -140,7 +140,7 @@ void Label::setBorderSize (int h, int v)
//==============================================================================
Component* Label::getAttachedComponent() const
{
return const_cast <Component*> (static_cast <const Component*> (ownerComponent));
return static_cast<Component*> (ownerComponent);
}
void Label::attachToComponent (Component* owner,
@@ -257,6 +257,8 @@ void Label::hideEditor (const bool discardCurrentEditorContents)
{
if (editor != 0)
{
Component::SafePointer<Component> deletionChecker (this);
editorAboutToBeHidden (editor);
const bool changed = (! discardCurrentEditorContents)
@@ -268,9 +270,10 @@ void Label::hideEditor (const bool discardCurrentEditorContents)
if (changed)
textWasEdited();
exitModalState (0);
if (deletionChecker != 0)
exitModalState (0);
if (changed && isValidComponent())
if (changed && deletionChecker != 0)
callChangeListeners();
}
}
@@ -395,23 +398,18 @@ KeyboardFocusTraverser* Label::createFocusTraverser()
//==============================================================================
void Label::addListener (LabelListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void Label::removeListener (LabelListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void Label::callChangeListeners()
{
for (int i = listeners.size(); --i >= 0;)
{
((LabelListener*) listeners.getUnchecked (i))->labelTextChanged (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &LabelListener::labelTextChanged, this);
}
//==============================================================================
@@ -443,9 +441,10 @@ void Label::textEditorReturnKeyPressed (TextEditor& ed)
if (changed)
{
Component::SafePointer<Component> deletionChecker (this);
textWasEdited();
if (isValidComponent())
if (deletionChecker != 0)
callChangeListeners();
}
}


+ 1
- 1
src/gui/components/controls/juce_Label.h View File

@@ -327,7 +327,7 @@ private:
Font font;
Justification justification;
ScopedPointer <TextEditor> editor;
SortedSet <void*> listeners;
ListenerList <LabelListener> listeners;
Component::SafePointer<Component> ownerComponent;
int horizontalBorderSize, verticalBorderSize;
float minimumHorizontalScale;


+ 8
- 19
src/gui/components/controls/juce_Slider.cpp View File

@@ -158,22 +158,16 @@ void Slider::handleAsyncUpdate()
{
cancelPendingUpdate();
for (int i = listeners.size(); --i >= 0;)
{
((SliderListener*) listeners.getUnchecked (i))->sliderValueChanged (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &SliderListener::sliderValueChanged, this);
}
void Slider::sendDragStart()
{
startedDragging();
for (int i = listeners.size(); --i >= 0;)
{
((SliderListener*) listeners.getUnchecked (i))->sliderDragStarted (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &SliderListener::sliderDragStarted, this);
}
void Slider::sendDragEnd()
@@ -182,23 +176,18 @@ void Slider::sendDragEnd()
sliderBeingDragged = -1;
for (int i = listeners.size(); --i >= 0;)
{
((SliderListener*) listeners.getUnchecked (i))->sliderDragEnded (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &SliderListener::sliderDragEnded, this);
}
void Slider::addListener (SliderListener* const listener)
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void Slider::removeListener (SliderListener* const listener)
{
listeners.removeValue (listener);
listeners.remove (listener);
}
//==============================================================================


+ 1
- 2
src/gui/components/controls/juce_Slider.h View File

@@ -30,7 +30,6 @@
#include "juce_Label.h"
#include "../buttons/juce_Button.h"
#include "../../../events/juce_AsyncUpdater.h"
#include "../../../containers/juce_SortedSet.h"
#include "../../../containers/juce_Value.h"
@@ -750,7 +749,7 @@ protected:
void valueChanged (Value& value);
private:
SortedSet <void*> listeners;
ListenerList <SliderListener> listeners;
Value currentValue, valueMin, valueMax;
double lastCurrentValue, lastValueMin, lastValueMax;
double minimum, maximum, interval, doubleClickReturnValue;


+ 21
- 35
src/gui/components/controls/juce_TextEditor.cpp View File

@@ -1258,15 +1258,12 @@ void TextEditor::escapePressed()
void TextEditor::addListener (TextEditorListener* const newListener)
{
jassert (newListener != 0)
if (newListener != 0)
listeners.add (newListener);
listeners.add (newListener);
}
void TextEditor::removeListener (TextEditorListener* const listenerToRemove)
{
listeners.removeValue (listenerToRemove);
listeners.remove (listenerToRemove);
}
//==============================================================================
@@ -2166,47 +2163,36 @@ void TextEditor::resized()
void TextEditor::handleCommandMessage (const int commandId)
{
Component::SafePointer<Component> deletionChecker (this);
Component::BailOutChecker checker (this);
for (int i = listeners.size(); --i >= 0;)
switch (commandId)
{
TextEditorListener* const tl = (TextEditorListener*) listeners [i];
if (tl != 0)
{
switch (commandId)
{
case TextEditorDefs::textChangeMessageId:
tl->textEditorTextChanged (*this);
break;
case TextEditorDefs::returnKeyMessageId:
tl->textEditorReturnKeyPressed (*this);
break;
case TextEditorDefs::textChangeMessageId:
listeners.callChecked (checker, &TextEditorListener::textEditorTextChanged, (TextEditor&) *this);
break;
case TextEditorDefs::escapeKeyMessageId:
tl->textEditorEscapeKeyPressed (*this);
break;
case TextEditorDefs::returnKeyMessageId:
listeners.callChecked (checker, &TextEditorListener::textEditorReturnKeyPressed, (TextEditor&) *this);
break;
case TextEditorDefs::focusLossMessageId:
tl->textEditorFocusLost (*this);
break;
case TextEditorDefs::escapeKeyMessageId:
listeners.callChecked (checker, &TextEditorListener::textEditorEscapeKeyPressed, (TextEditor&) *this);
break;
default:
jassertfalse
break;
}
case TextEditorDefs::focusLossMessageId:
listeners.callChecked (checker, &TextEditorListener::textEditorFocusLost, (TextEditor&) *this);
break;
if (deletionChecker == 0)
return;
}
default:
jassertfalse
break;
}
}
void TextEditor::enablementChanged()
{
setMouseCursor (MouseCursor (isReadOnly() ? MouseCursor::NormalCursor
: MouseCursor::IBeamCursor));
setMouseCursor (isReadOnly() ? MouseCursor::NormalCursor
: MouseCursor::IBeamCursor);
repaint();
}


+ 1
- 1
src/gui/components/controls/juce_TextEditor.h View File

@@ -652,7 +652,7 @@ private:
} dragType;
String allowedCharacters;
SortedSet <void*> listeners;
ListenerList <TextEditorListener> listeners;
friend class TextEditorInsertAction;
friend class TextEditorRemoveAction;


+ 8
- 38
src/gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.cpp View File

@@ -47,47 +47,26 @@ FileBrowserListener::~FileBrowserListener()
void DirectoryContentsDisplayComponent::addListener (FileBrowserListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void DirectoryContentsDisplayComponent::removeListener (FileBrowserListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void DirectoryContentsDisplayComponent::sendSelectionChangeMessage()
{
Component::SafePointer<Component> deletionWatcher (dynamic_cast <Component*> (this));
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->selectionChanged();
if (deletionWatcher == 0)
return;
i = jmin (i, listeners.size() - 1);
}
Component::BailOutChecker checker (dynamic_cast <Component*> (this));
listeners.callChecked (checker, &FileBrowserListener::selectionChanged);
}
void DirectoryContentsDisplayComponent::sendMouseClickMessage (const File& file, const MouseEvent& e)
{
if (fileList.getDirectory().exists())
{
Component::SafePointer<Component> deletionWatcher (dynamic_cast <Component*> (this));
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->fileClicked (file, e);
if (deletionWatcher == 0)
return;
i = jmin (i, listeners.size() - 1);
}
Component::BailOutChecker checker (dynamic_cast <Component*> (this));
listeners.callChecked (checker, &FileBrowserListener::fileClicked, file, e);
}
}
@@ -95,17 +74,8 @@ void DirectoryContentsDisplayComponent::sendDoubleClickMessage (const File& file
{
if (fileList.getDirectory().exists())
{
Component::SafePointer<Component> deletionWatcher (dynamic_cast <Component*> (this));
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->fileDoubleClicked (file);
if (deletionWatcher == 0)
return;
i = jmin (i, listeners.size() - 1);
}
Component::BailOutChecker checker (dynamic_cast <Component*> (this));
listeners.callChecked (checker, &FileBrowserListener::fileDoubleClicked, file);
}
}


+ 1
- 1
src/gui/components/filebrowser/juce_DirectoryContentsDisplayComponent.h View File

@@ -104,7 +104,7 @@ public:
protected:
DirectoryContentsList& fileList;
SortedSet <void*> listeners;
ListenerList <FileBrowserListener> listeners;
DirectoryContentsDisplayComponent (const DirectoryContentsDisplayComponent&);
DirectoryContentsDisplayComponent& operator= (const DirectoryContentsDisplayComponent&);


+ 9
- 38
src/gui/components/filebrowser/juce_FileBrowserComponent.cpp View File

@@ -152,15 +152,12 @@ FileBrowserComponent::~FileBrowserComponent()
//==============================================================================
void FileBrowserComponent::addListener (FileBrowserListener* const newListener) throw()
{
jassert (newListener != 0)
if (newListener != 0)
listeners.add (newListener);
listeners.add (newListener);
}
void FileBrowserComponent::removeListener (FileBrowserListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
//==============================================================================
@@ -302,23 +299,15 @@ void FileBrowserComponent::resized()
//==============================================================================
void FileBrowserComponent::sendListenerChangeMessage()
{
Component::SafePointer<Component> deletionWatcher (this);
Component::BailOutChecker checker (this);
if (previewComp != 0)
previewComp->selectedFileChanged (getSelectedFile (0));
// You shouldn't delete the browser when the file gets changed!
jassert (deletionWatcher != 0);
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->selectionChanged();
if (deletionWatcher == 0)
return;
jassert (! checker.shouldBailOut());
i = jmin (i, listeners.size() - 1);
}
listeners.callChecked (checker, &FileBrowserListener::selectionChanged);
}
void FileBrowserComponent::selectionChanged()
@@ -351,17 +340,8 @@ void FileBrowserComponent::selectionChanged()
void FileBrowserComponent::fileClicked (const File& f, const MouseEvent& e)
{
Component::SafePointer<Component> deletionWatcher (this);
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->fileClicked (f, e);
if (deletionWatcher == 0)
return;
i = jmin (i, listeners.size() - 1);
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &FileBrowserListener::fileClicked, f, e);
}
void FileBrowserComponent::fileDoubleClicked (const File& f)
@@ -372,17 +352,8 @@ void FileBrowserComponent::fileDoubleClicked (const File& f)
}
else
{
Component::SafePointer<Component> deletionWatcher (this);
for (int i = listeners.size(); --i >= 0;)
{
((FileBrowserListener*) listeners.getUnchecked (i))->fileDoubleClicked (f);
if (deletionWatcher == 0)
return;
i = jmin (i, listeners.size() - 1);
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &FileBrowserListener::fileDoubleClicked, f);
}
}


+ 1
- 1
src/gui/components/filebrowser/juce_FileBrowserComponent.h View File

@@ -213,7 +213,7 @@ private:
int flags;
File currentRoot;
Array<File> chosenFiles;
SortedSet <void*> listeners;
ListenerList <FileBrowserListener> listeners;
DirectoryContentsDisplayComponent* fileListComponent;
FilePreviewComponent* previewComp;


+ 4
- 10
src/gui/components/filebrowser/juce_FilenameComponent.cpp View File

@@ -239,24 +239,18 @@ void FilenameComponent::addRecentlyUsedFile (const File& file)
//==============================================================================
void FilenameComponent::addListener (FilenameComponentListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void FilenameComponent::removeListener (FilenameComponentListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void FilenameComponent::handleAsyncUpdate()
{
for (int i = listeners.size(); --i >= 0;)
{
((FilenameComponentListener*) listeners.getUnchecked (i))->filenameComponentChanged (this);
i = jmin (i, listeners.size());
}
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &FilenameComponentListener::filenameComponentChanged, this);
}
END_JUCE_NAMESPACE

+ 1
- 1
src/gui/components/filebrowser/juce_FilenameComponent.h View File

@@ -209,7 +209,7 @@ private:
int maxRecentFiles;
bool isDir, isSaving, isFileDragOver;
String wildcard, enforcedSuffix, browseButtonText;
SortedSet <void*> listeners;
ListenerList <FilenameComponentListener> listeners;
File defaultBrowseFile;
void comboBoxChanged (ComboBox*);


+ 234
- 329
src/gui/components/juce_Component.cpp
File diff suppressed because it is too large
View File


+ 32
- 5
src/gui/components/juce_Component.h View File

@@ -36,6 +36,7 @@
#include "../graphics/geometry/juce_RectangleList.h"
#include "../graphics/geometry/juce_BorderSize.h"
#include "../../events/juce_MessageListener.h"
#include "../../events/juce_ListenerList.h"
#include "../../text/juce_StringArray.h"
#include "../../containers/juce_VoidArray.h"
#include "../../containers/juce_NamedValueSet.h"
@@ -1931,10 +1932,7 @@ public:
}
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
operator ComponentType*() throw() { return comp; }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
operator const ComponentType*() const throw() { return comp; }
operator ComponentType*() const throw() { return comp; }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
ComponentType* operator->() throw() { jassert (comp != 0); return comp; }
@@ -1953,6 +1951,35 @@ public:
void componentBeingDeleted (Component&) { comp = 0; }
};
//==============================================================================
/** A class to keep an eye on one or two components and check for them being deleted.
This is designed for use with the ListenerList::callChecked() methods, to allow
the list iterator to stop cleanly if the component is deleted by a listener callback
while the list is still being iterated.
*/
class BailOutChecker
{
public:
/** Creates a checker that watches either one or two components.
component1 must be a valid component; component2 can be null if you only need
to check on one component.
*/
BailOutChecker (Component* const component1,
Component* const component2 = 0);
/** Returns true if either of the two components have been deleted since this
object was created. */
bool shouldBailOut() const throw();
private:
Component::SafePointer<Component> safePointer1, safePointer2;
Component* const component2;
BailOutChecker (const BailOutChecker&);
BailOutChecker& operator= (const BailOutChecker&);
};
//==============================================================================
juce_UseDebuggingNewOperator
@@ -1978,7 +2005,7 @@ private:
Image* bufferedImage_;
VoidArray* mouseListeners_;
VoidArray* keyListeners_;
VoidArray* componentListeners_;
ListenerList <ComponentListener> componentListeners;
NamedValueSet properties;
struct ComponentFlags


+ 1
- 1
src/gui/components/juce_ComponentListener.cpp View File

@@ -36,6 +36,6 @@ void ComponentListener::componentVisibilityChanged (Component&) {}
void ComponentListener::componentChildrenChanged (Component&) {}
void ComponentListener::componentParentHierarchyChanged (Component&) {}
void ComponentListener::componentNameChanged (Component&) {}
void ComponentListener::componentBeingDeleted (Component& component) {}
void ComponentListener::componentBeingDeleted (Component&) {}
END_JUCE_NAMESPACE

+ 31
- 51
src/gui/components/juce_Desktop.cpp View File

@@ -36,7 +36,7 @@ BEGIN_JUCE_NAMESPACE
//==============================================================================
Desktop::Desktop() throw()
Desktop::Desktop()
: mouseClickCounter (0),
kioskModeComponent (0)
{
@@ -44,7 +44,7 @@ Desktop::Desktop() throw()
refreshMonitorSizes();
}
Desktop::~Desktop() throw()
Desktop::~Desktop()
{
jassert (instance == this);
instance = 0;
@@ -54,7 +54,7 @@ Desktop::~Desktop() throw()
jassert (desktopComponents.size() == 0);
}
Desktop& JUCE_CALLTYPE Desktop::getInstance() throw()
Desktop& JUCE_CALLTYPE Desktop::getInstance()
{
if (instance == 0)
instance = new Desktop();
@@ -68,7 +68,7 @@ Desktop* Desktop::instance = 0;
extern void juce_updateMultiMonitorInfo (Array <Rectangle<int> >& monitorCoords,
const bool clipToWorkArea);
void Desktop::refreshMonitorSizes() throw()
void Desktop::refreshMonitorSizes()
{
const Array <Rectangle<int> > oldClipped (monitorCoordsClipped);
const Array <Rectangle<int> > oldUnclipped (monitorCoordsUnclipped);
@@ -118,7 +118,7 @@ const Rectangle<int> Desktop::getMainMonitorArea (const bool clippedToWorkArea)
return getDisplayMonitorCoordinates (0, clippedToWorkArea);
}
const Rectangle<int> Desktop::getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea) const throw()
const Rectangle<int> Desktop::getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea) const
{
Rectangle<int> best (getMainMonitorArea (clippedToWorkArea));
double bestDistance = 1.0e10;
@@ -168,19 +168,19 @@ Component* Desktop::findComponentAt (const Point<int>& screenPosition) const
}
//==============================================================================
void Desktop::addDesktopComponent (Component* const c) throw()
void Desktop::addDesktopComponent (Component* const c)
{
jassert (c != 0);
jassert (! desktopComponents.contains (c));
desktopComponents.addIfNotAlreadyThere (c);
}
void Desktop::removeDesktopComponent (Component* const c) throw()
void Desktop::removeDesktopComponent (Component* const c)
{
desktopComponents.removeValue (c);
}
void Desktop::componentBroughtToFront (Component* const c) throw()
void Desktop::componentBroughtToFront (Component* const c)
{
const int index = desktopComponents.indexOf (c);
jassert (index >= 0);
@@ -249,52 +249,40 @@ MouseInputSource* Desktop::getDraggingMouseSource (int index) const throw()
}
//==============================================================================
void Desktop::addGlobalMouseListener (MouseListener* const listener) throw()
void Desktop::addFocusChangeListener (FocusChangeListener* const listener)
{
jassert (listener != 0);
if (listener != 0)
{
mouseListeners.add (listener);
resetTimer();
}
focusListeners.add (listener);
}
void Desktop::removeGlobalMouseListener (MouseListener* const listener) throw()
void Desktop::removeFocusChangeListener (FocusChangeListener* const listener)
{
mouseListeners.removeValue (listener);
resetTimer();
focusListeners.remove (listener);
}
//==============================================================================
void Desktop::addFocusChangeListener (FocusChangeListener* const listener) throw()
void Desktop::triggerFocusCallback()
{
jassert (listener != 0);
if (listener != 0)
focusListeners.add (listener);
triggerAsyncUpdate();
}
void Desktop::removeFocusChangeListener (FocusChangeListener* const listener) throw()
void Desktop::handleAsyncUpdate()
{
focusListeners.removeValue (listener);
Component* currentFocus = Component::getCurrentlyFocusedComponent();
focusListeners.call (&FocusChangeListener::globalFocusChanged, currentFocus);
}
void Desktop::triggerFocusCallback() throw()
//==============================================================================
void Desktop::addGlobalMouseListener (MouseListener* const listener)
{
triggerAsyncUpdate();
mouseListeners.add (listener);
resetTimer();
}
void Desktop::handleAsyncUpdate()
void Desktop::removeGlobalMouseListener (MouseListener* const listener)
{
for (int i = focusListeners.size(); --i >= 0;)
{
((FocusChangeListener*) focusListeners.getUnchecked (i))->globalFocusChanged (Component::getCurrentlyFocusedComponent());
i = jmin (i, focusListeners.size());
}
mouseListeners.remove (listener);
resetTimer();
}
//==============================================================================
void Desktop::timerCallback()
{
if (lastFakeMouseMove != getMousePosition())
@@ -303,7 +291,7 @@ void Desktop::timerCallback()
void Desktop::sendMouseMove()
{
if (mouseListeners.size() > 0)
if (! mouseListeners.isEmpty())
{
startTimer (20);
@@ -313,30 +301,22 @@ void Desktop::sendMouseMove()
if (target != 0)
{
Component::SafePointer<Component> deletionChecker (target);
Component::BailOutChecker checker (target);
const Point<int> pos (target->globalPositionToRelative (lastFakeMouseMove));
const Time now (Time::getCurrentTime());
const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(),
target, now, pos, now, 0, false);
for (int i = mouseListeners.size(); --i >= 0;)
{
if (ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown())
((MouseListener*) mouseListeners[i])->mouseDrag (me);
else
((MouseListener*) mouseListeners[i])->mouseMove (me);
if (deletionChecker == 0)
return;
i = jmin (i, mouseListeners.size());
}
if (me.mods.isAnyMouseButtonDown())
mouseListeners.callChecked (checker, &MouseListener::mouseDrag, me);
else
mouseListeners.callChecked (checker, &MouseListener::mouseMove, me);
}
}
}
void Desktop::resetTimer() throw()
void Desktop::resetTimer()
{
if (mouseListeners.size() == 0)
stopTimer();


+ 25
- 25
src/gui/components/juce_Desktop.h View File

@@ -31,7 +31,6 @@
#include "../../utilities/juce_DeletedAtShutdown.h"
#include "../../events/juce_Timer.h"
#include "../../events/juce_AsyncUpdater.h"
#include "../../containers/juce_SortedSet.h"
#include "../../containers/juce_OwnedArray.h"
#include "../graphics/geometry/juce_RectangleList.h"
class MouseInputSource;
@@ -70,7 +69,7 @@ public:
//==============================================================================
/** There's only one dektop object, and this method will return it.
*/
static Desktop& JUCE_CALLTYPE getInstance() throw();
static Desktop& JUCE_CALLTYPE getInstance();
//==============================================================================
/** Returns a list of the positions of all the monitors available.
@@ -97,7 +96,7 @@ public:
If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows,
or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned.
*/
const Rectangle<int> getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea = true) const throw();
const Rectangle<int> getMonitorAreaContaining (const Point<int>& position, const bool clippedToWorkArea = true) const;
//==============================================================================
@@ -157,23 +156,23 @@ public:
@see removeGlobalMouseListener
*/
void addGlobalMouseListener (MouseListener* const listener) throw();
void addGlobalMouseListener (MouseListener* const listener);
/** Unregisters a MouseListener that was added with the addGlobalMouseListener()
method.
@see addGlobalMouseListener
*/
void removeGlobalMouseListener (MouseListener* const listener) throw();
void removeGlobalMouseListener (MouseListener* const listener);
//==============================================================================
/** Registers a MouseListener that will receive a callback whenever the focused
component changes.
*/
void addFocusChangeListener (FocusChangeListener* const listener) throw();
void addFocusChangeListener (FocusChangeListener* const listener);
/** Unregisters a listener that was added with addFocusChangeListener(). */
void removeFocusChangeListener (FocusChangeListener* const listener) throw();
void removeFocusChangeListener (FocusChangeListener* const listener);
//==============================================================================
/** Takes a component and makes it full-screen, removing the taskbar, dock, etc.
@@ -198,7 +197,7 @@ public:
This is the component that was last set by setKioskModeComponent(). If none
has been set, this returns 0.
*/
Component* getKioskModeComponent() const { return kioskModeComponent; }
Component* getKioskModeComponent() const throw() { return kioskModeComponent; }
//==============================================================================
/** Returns the number of components that are currently active as top-level
@@ -269,7 +268,7 @@ public:
(Called internally by the native code).
*/
void refreshMonitorSizes() throw();
void refreshMonitorSizes();
/** True if the OS supports semitransparent windows */
static bool canUseSemiTransparentWindows() throw();
@@ -282,42 +281,43 @@ private:
friend class ComponentPeer;
friend class MouseInputSource;
friend class MouseInputSourceInternal;
SortedSet <void*> mouseListeners, focusListeners;
Array <Component*> desktopComponents;
friend class DeletedAtShutdown;
friend class TopLevelWindowManager;
Desktop() throw();
~Desktop() throw();
Array <Rectangle<int> > monitorCoordsClipped, monitorCoordsUnclipped;
OwnedArray <MouseInputSource> mouseSources;
void createMouseInputSources();
ListenerList <MouseListener> mouseListeners;
ListenerList <FocusChangeListener> focusListeners;
Array <Component*> desktopComponents;
Array <Rectangle<int> > monitorCoordsClipped, monitorCoordsUnclipped;
Point<int> lastFakeMouseMove;
int mouseClickCounter;
void sendMouseMove();
int mouseClickCounter;
void incrementMouseClickCounter() throw();
Component* kioskModeComponent;
Rectangle<int> kioskComponentOriginalBounds;
void createMouseInputSources();
void timerCallback();
void sendMouseMove();
void resetTimer() throw();
void resetTimer();
int getNumDisplayMonitors() const throw();
const Rectangle<int> getDisplayMonitorCoordinates (const int index, const bool clippedToWorkArea) const throw();
void addDesktopComponent (Component* const c) throw();
void removeDesktopComponent (Component* const c) throw();
void componentBroughtToFront (Component* const c) throw();
void addDesktopComponent (Component* const c);
void removeDesktopComponent (Component* const c);
void componentBroughtToFront (Component* const c);
void triggerFocusCallback() throw();
void triggerFocusCallback();
void handleAsyncUpdate();
Desktop();
~Desktop();
Desktop (const Desktop&);
Desktop& operator= (const Desktop&);
};


+ 3
- 11
src/gui/components/layout/juce_ScrollBar.cpp View File

@@ -189,25 +189,17 @@ void ScrollBar::setButtonRepeatSpeed (const int initialDelayInMillisecs_,
//==============================================================================
void ScrollBar::addListener (ScrollBarListener* const listener) throw()
{
jassert (listener != 0);
if (listener != 0)
listeners.add (listener);
listeners.add (listener);
}
void ScrollBar::removeListener (ScrollBarListener* const listener) throw()
{
listeners.removeValue (listener);
listeners.remove (listener);
}
void ScrollBar::handleAsyncUpdate()
{
const double value = getCurrentRangeStart();
for (int i = listeners.size(); --i >= 0;)
{
((ScrollBarListener*) listeners.getUnchecked (i))->scrollBarMoved (this, value);
i = jmin (i, listeners.size());
}
listeners.call (&ScrollBarListener::scrollBarMoved, this, rangeStart);
}
//==============================================================================


+ 1
- 1
src/gui/components/layout/juce_ScrollBar.h View File

@@ -293,7 +293,7 @@ private:
bool vertical, isDraggingThumb, alwaysVisible;
Button* upButton;
Button* downButton;
SortedSet <void*> listeners;
ListenerList <ScrollBarListener> listeners;
void updateThumbPosition() throw();
void timerCallback();


+ 5
- 17
src/gui/components/menus/juce_MenuBarModel.cpp View File

@@ -63,11 +63,7 @@ void MenuBarModel::setApplicationCommandManagerToWatch (ApplicationCommandManage
void MenuBarModel::addListener (MenuBarModelListener* const newListener) throw()
{
jassert (newListener != 0);
jassert (! listeners.contains (newListener)); // trying to add a listener to the list twice!
if (newListener != 0)
listeners.add (newListener);
listeners.add (newListener);
}
void MenuBarModel::removeListener (MenuBarModelListener* const listenerToRemove) throw()
@@ -77,26 +73,18 @@ void MenuBarModel::removeListener (MenuBarModelListener* const listenerToRemove)
// deleted this menu model while it's still being used by something (e.g. by a MenuBarComponent)
jassert (listeners.contains (listenerToRemove));
listeners.removeValue (listenerToRemove);
listeners.remove (listenerToRemove);
}
//==============================================================================
void MenuBarModel::handleAsyncUpdate()
{
for (int i = listeners.size(); --i >= 0;)
{
((MenuBarModelListener*) listeners.getUnchecked (i))->menuBarItemsChanged (this);
i = jmin (i, listeners.size());
}
listeners.call (&MenuBarModelListener::menuBarItemsChanged, this);
}
//==============================================================================
void MenuBarModel::applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info)
{
for (int i = listeners.size(); --i >= 0;)
{
((MenuBarModelListener*) listeners.getUnchecked (i))->menuCommandInvoked (this, info);
i = jmin (i, listeners.size());
}
listeners.call (&MenuBarModelListener::menuCommandInvoked, this, info);
}
void MenuBarModel::applicationCommandListChanged()


+ 1
- 1
src/gui/components/menus/juce_MenuBarModel.h View File

@@ -172,7 +172,7 @@ public:
private:
ApplicationCommandManager* manager;
SortedSet <void*> listeners;
ListenerList <MenuBarModelListener> listeners;
MenuBarModel (const MenuBarModel&);
MenuBarModel& operator= (const MenuBarModel&);


+ 7
- 7
src/gui/components/menus/juce_PopupMenu.cpp View File

@@ -351,6 +351,7 @@ public:
mw->menuBarComponent = menuBarComponent;
mw->managerOfChosenCommand = managerOfChosenCommand;
mw->componentAttachedTo = componentAttachedTo;
mw->componentAttachedToOriginal = componentAttachedTo;
mw->calculateWindowPos (minX, maxX, minY, maxY, alignToRectangle);
mw->setTopLeftPosition (mw->windowPos.getX(),
@@ -502,16 +503,14 @@ public:
}
else if (key.isKeyCode (KeyPress::leftKey))
{
Window* parentWindow = owner;
if (parentWindow != 0)
if (owner != 0)
{
PopupMenu::ItemComponent* currentChildOfParent
= (parentWindow != 0) ? parentWindow->currentChild : 0;
Component::SafePointer<Window> parentWindow (owner);
PopupMenu::ItemComponent* currentChildOfParent = parentWindow->currentChild;
hide (0);
if (parentWindow->isValidComponent())
if (parentWindow != 0)
parentWindow->setCurrentlyHighlightedChild (currentChildOfParent);
disableTimerUntilMouseMoves();
@@ -594,7 +593,7 @@ public:
if (! isVisible())
return;
if (componentAttachedTo == 0)
if (componentAttachedTo != componentAttachedToOriginal)
{
dismissMenu (0);
return;
@@ -748,6 +747,7 @@ private:
Component* menuBarComponent;
ApplicationCommandManager** managerOfChosenCommand;
Component::SafePointer<Component> componentAttachedTo;
Component* componentAttachedToOriginal;
Rectangle<int> windowPos;
Point<int> lastMouse;
int minimumWidth, maximumNumColumns, standardItemHeight;


+ 6
- 0
src/juce_app_includes.h View File

@@ -254,6 +254,9 @@
#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__
#include "events/juce_InterprocessConnectionServer.h"
#endif
#ifndef __JUCE_LISTENERLIST_JUCEHEADER__
#include "events/juce_ListenerList.h"
#endif
#ifndef __JUCE_MESSAGE_JUCEHEADER__
#include "events/juce_Message.h"
#endif
@@ -509,6 +512,9 @@
#ifndef __JUCE_MOUSEHOVERDETECTOR_JUCEHEADER__
#include "gui/components/mouse/juce_MouseHoverDetector.h"
#endif
#ifndef __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
#include "gui/components/mouse/juce_MouseInputSource.h"
#endif
#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__
#include "gui/components/mouse/juce_MouseListener.h"
#endif


+ 1
- 0
src/native/juce_linux_NativeCode.cpp View File

@@ -73,6 +73,7 @@ BEGIN_JUCE_NAMESPACE
#include "../gui/components/windows/juce_AlertWindow.h"
#include "../gui/components/special/juce_OpenGLComponent.h"
#include "../gui/components/juce_Desktop.h"
#include "../gui/components/mouse/juce_MouseInputSource.h"
#include "../gui/graphics/geometry/juce_RectangleList.h"
#include "../gui/graphics/imaging/juce_ImageFileFormat.h"
#include "../gui/graphics/contexts/juce_LowLevelGraphicsSoftwareRenderer.h"


+ 1
- 0
src/native/juce_win32_NativeCode.cpp View File

@@ -64,6 +64,7 @@ BEGIN_JUCE_NAMESPACE
#include "../gui/components/special/juce_OpenGLComponent.h"
#include "../gui/components/special/juce_QuickTimeMovieComponent.h"
#include "../gui/components/mouse/juce_DragAndDropContainer.h"
#include "../gui/components/mouse/juce_MouseInputSource.h"
#include "../gui/components/keyboard/juce_KeyPressMappingSet.h"
#include "../gui/components/layout/juce_ComponentMovementWatcher.h"
#include "../gui/components/special/juce_ActiveXControlComponent.h"


+ 1
- 1
src/native/windows/juce_win32_Windowing.cpp View File

@@ -1312,7 +1312,7 @@ private:
{
updateKeyModifiers();
const float amount = jlimit (-1000.0f, 1000.0f, 0.75f * HIWORD (wParam));
const float amount = jlimit (-1000.0f, 1000.0f, 0.75f * (short) HIWORD (wParam));
handleMouseWheel (0, position, getMouseEventTime(),
isVertical ? 0.0f : amount,


Loading…
Cancel
Save