Browse Source

Big rewrite to the internals of modal components, with a new class ModalComponentManager. This now lets you use modal components asynchronously, providing an object which will receive a callback when they are dismissed, rather than using a blocking event loop. ComboBoxes and some other components now show their popups asynchronously.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
b2e0b43960
34 changed files with 1511 additions and 780 deletions
  1. +6
    -0
      Builds/Linux/Makefile
  2. +6
    -0
      Builds/MacOSX/Juce.xcodeproj/project.pbxproj
  3. +2
    -0
      Builds/VisualStudio2005/Juce.vcproj
  4. +2
    -0
      Builds/VisualStudio2008/Juce.vcproj
  5. +2
    -0
      Builds/VisualStudio2008_DLL/Juce.vcproj
  6. +2
    -0
      Builds/VisualStudio2010/Juce.vcxproj
  7. +6
    -0
      Builds/VisualStudio2010/Juce.vcxproj.filters
  8. +6
    -0
      Builds/iPhone/Juce.xcodeproj/project.pbxproj
  9. +4
    -0
      Juce.jucer
  10. +1
    -0
      amalgamation/juce_amalgamated_template.cpp
  11. +1
    -1
      extras/Jucer (experimental)/Source/model/Project/jucer_ProjectExport_MSVC.h
  12. +4
    -4
      extras/audio plugin host/Plugin Host.jucer
  13. +3
    -3
      extras/audio plugins/demo/JuceDemoPlugin.jucer
  14. +5
    -5
      extras/example projects/HelloWorld.jucer
  15. +505
    -335
      juce_amalgamated.cpp
  16. +221
    -72
      juce_amalgamated.h
  17. +3
    -3
      src/core/juce_Singleton.h
  18. +1
    -1
      src/core/juce_StandardHeader.h
  19. +29
    -14
      src/gui/components/controls/juce_ComboBox.cpp
  20. +3
    -0
      src/gui/components/controls/juce_ComboBox.h
  21. +24
    -7
      src/gui/components/controls/juce_TextEditor.cpp
  22. +4
    -3
      src/gui/components/controls/juce_TextEditor.h
  23. +9
    -1
      src/gui/components/filebrowser/juce_FileChooserDialogBox.cpp
  24. +9
    -1
      src/gui/components/filebrowser/juce_FileChooserDialogBox.h
  25. +12
    -79
      src/gui/components/juce_Component.cpp
  26. +11
    -3
      src/gui/components/juce_Component.h
  27. +267
    -0
      src/gui/components/juce_ModalComponentManager.cpp
  28. +144
    -0
      src/gui/components/juce_ModalComponentManager.h
  29. +82
    -144
      src/gui/components/menus/juce_MenuBarComponent.cpp
  30. +10
    -6
      src/gui/components/menus/juce_MenuBarComponent.h
  31. +106
    -90
      src/gui/components/menus/juce_PopupMenu.cpp
  32. +17
    -7
      src/gui/components/menus/juce_PopupMenu.h
  33. +1
    -1
      src/gui/graphics/geometry/juce_Path.cpp
  34. +3
    -0
      src/juce_app_includes.h

+ 6
- 0
Builds/Linux/Makefile View File

@@ -127,6 +127,7 @@ OBJECTS := \
$(OBJDIR)/juce_Component_49f01dfa.o \
$(OBJDIR)/juce_ComponentListener_e0eda7ce.o \
$(OBJDIR)/juce_Desktop_e3b47b99.o \
$(OBJDIR)/juce_ModalComponentManager_b87bddba.o \
$(OBJDIR)/juce_ArrowButton_ebac7066.o \
$(OBJDIR)/juce_Button_886d3491.o \
$(OBJDIR)/juce_DrawableButton_e03899cf.o \
@@ -793,6 +794,11 @@ $(OBJDIR)/juce_Desktop_e3b47b99.o: ../../src/gui/components/juce_Desktop.cpp
@echo "Compiling juce_Desktop.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
$(OBJDIR)/juce_ModalComponentManager_b87bddba.o: ../../src/gui/components/juce_ModalComponentManager.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling juce_ModalComponentManager.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
$(OBJDIR)/juce_ArrowButton_ebac7066.o: ../../src/gui/components/buttons/juce_ArrowButton.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling juce_ArrowButton.cpp"


+ 6
- 0
Builds/MacOSX/Juce.xcodeproj/project.pbxproj View File

@@ -96,6 +96,7 @@
621B7B0B518E63E69122C13E = { isa = PBXBuildFile; fileRef = D0D9267E200BD462361810F7; };
97982824572C18827047D92A = { isa = PBXBuildFile; fileRef = E13F33E386E1A0D5FC546521; };
927E7250FCE62E838599DF83 = { isa = PBXBuildFile; fileRef = 621B3A4B154182F69DDE2989; };
9AE6891C35CE161CB1707B4B = { isa = PBXBuildFile; fileRef = 2FFF9AFE4BD9437CE096E52B; };
06994A713C38F415C4E8A009 = { isa = PBXBuildFile; fileRef = 18EE6576A9ED098632CE5155; };
98F737B7459895BFCDC7965E = { isa = PBXBuildFile; fileRef = 8B1C747E63EEF036AD9AF3D8; };
7033A0968B1C81A821CCC296 = { isa = PBXBuildFile; fileRef = 1C3D15546065C1A9AA5AA0C6; };
@@ -550,6 +551,8 @@
A0D6308567AAA50D1163D9D3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentListener.h; path = ../../src/gui/components/juce_ComponentListener.h; sourceTree = SOURCE_ROOT; };
621B3A4B154182F69DDE2989 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Desktop.cpp; path = ../../src/gui/components/juce_Desktop.cpp; sourceTree = SOURCE_ROOT; };
A1F58C1A972425C2B43DD1B3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Desktop.h; path = ../../src/gui/components/juce_Desktop.h; sourceTree = SOURCE_ROOT; };
2FFF9AFE4BD9437CE096E52B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModalComponentManager.cpp; path = ../../src/gui/components/juce_ModalComponentManager.cpp; sourceTree = SOURCE_ROOT; };
41C8C324F13ADA3423FC3B0F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModalComponentManager.h; path = ../../src/gui/components/juce_ModalComponentManager.h; sourceTree = SOURCE_ROOT; };
18EE6576A9ED098632CE5155 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ArrowButton.cpp; path = ../../src/gui/components/buttons/juce_ArrowButton.cpp; sourceTree = SOURCE_ROOT; };
EB182DC4124FEFFFC87D12C4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrowButton.h; path = ../../src/gui/components/buttons/juce_ArrowButton.h; sourceTree = SOURCE_ROOT; };
8B1C747E63EEF036AD9AF3D8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Button.cpp; path = ../../src/gui/components/buttons/juce_Button.cpp; sourceTree = SOURCE_ROOT; };
@@ -1455,6 +1458,8 @@
A0D6308567AAA50D1163D9D3,
621B3A4B154182F69DDE2989,
A1F58C1A972425C2B43DD1B3,
2FFF9AFE4BD9437CE096E52B,
41C8C324F13ADA3423FC3B0F,
2DB55F83F4310F0C4E4E03AA,
17B11D96CDB313ED60D8CFE0,
BCB2FFE7C2A4084A267F57F2,
@@ -1930,6 +1935,7 @@
621B7B0B518E63E69122C13E,
97982824572C18827047D92A,
927E7250FCE62E838599DF83,
9AE6891C35CE161CB1707B4B,
06994A713C38F415C4E8A009,
98F737B7459895BFCDC7965E,
7033A0968B1C81A821CCC296,


+ 2
- 0
Builds/VisualStudio2005/Juce.vcproj View File

@@ -349,6 +349,8 @@
<File RelativePath="..\..\src\gui\components\juce_ComponentListener.h"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.h"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.h"/>
<Filter Name="buttons">
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.cpp"/>
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.h"/>


+ 2
- 0
Builds/VisualStudio2008/Juce.vcproj View File

@@ -349,6 +349,8 @@
<File RelativePath="..\..\src\gui\components\juce_ComponentListener.h"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.h"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.h"/>
<Filter Name="buttons">
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.cpp"/>
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.h"/>


+ 2
- 0
Builds/VisualStudio2008_DLL/Juce.vcproj View File

@@ -351,6 +351,8 @@
<File RelativePath="..\..\src\gui\components\juce_ComponentListener.h"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_Desktop.h"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.cpp"/>
<File RelativePath="..\..\src\gui\components\juce_ModalComponentManager.h"/>
<Filter Name="buttons">
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.cpp"/>
<File RelativePath="..\..\src\gui\components\buttons\juce_ArrowButton.h"/>


+ 2
- 0
Builds/VisualStudio2010/Juce.vcxproj View File

@@ -210,6 +210,7 @@
<ClCompile Include="..\..\src\gui\components\juce_Component.cpp"/>
<ClCompile Include="..\..\src\gui\components\juce_ComponentListener.cpp"/>
<ClCompile Include="..\..\src\gui\components\juce_Desktop.cpp"/>
<ClCompile Include="..\..\src\gui\components\juce_ModalComponentManager.cpp"/>
<ClCompile Include="..\..\src\gui\components\buttons\juce_ArrowButton.cpp"/>
<ClCompile Include="..\..\src\gui\components\buttons\juce_Button.cpp"/>
<ClCompile Include="..\..\src\gui\components\buttons\juce_DrawableButton.cpp"/>
@@ -549,6 +550,7 @@
<ClInclude Include="..\..\src\gui\components\juce_Component.h"/>
<ClInclude Include="..\..\src\gui\components\juce_ComponentListener.h"/>
<ClInclude Include="..\..\src\gui\components\juce_Desktop.h"/>
<ClInclude Include="..\..\src\gui\components\juce_ModalComponentManager.h"/>
<ClInclude Include="..\..\src\gui\components\buttons\juce_ArrowButton.h"/>
<ClInclude Include="..\..\src\gui\components\buttons\juce_Button.h"/>
<ClInclude Include="..\..\src\gui\components\buttons\juce_DrawableButton.h"/>


+ 6
- 0
Builds/VisualStudio2010/Juce.vcxproj.filters View File

@@ -430,6 +430,9 @@
<ClCompile Include="..\..\src\gui\components\juce_Desktop.cpp">
<Filter>Juce\Source\gui\components</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gui\components\juce_ModalComponentManager.cpp">
<Filter>Juce\Source\gui\components</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gui\components\buttons\juce_ArrowButton.cpp">
<Filter>Juce\Source\gui\components\buttons</Filter>
</ClCompile>
@@ -1521,6 +1524,9 @@
<ClInclude Include="..\..\src\gui\components\juce_Desktop.h">
<Filter>Juce\Source\gui\components</Filter>
</ClInclude>
<ClInclude Include="..\..\src\gui\components\juce_ModalComponentManager.h">
<Filter>Juce\Source\gui\components</Filter>
</ClInclude>
<ClInclude Include="..\..\src\gui\components\buttons\juce_ArrowButton.h">
<Filter>Juce\Source\gui\components\buttons</Filter>
</ClInclude>


+ 6
- 0
Builds/iPhone/Juce.xcodeproj/project.pbxproj View File

@@ -96,6 +96,7 @@
621B7B0B518E63E69122C13E = { isa = PBXBuildFile; fileRef = D0D9267E200BD462361810F7; };
97982824572C18827047D92A = { isa = PBXBuildFile; fileRef = E13F33E386E1A0D5FC546521; };
927E7250FCE62E838599DF83 = { isa = PBXBuildFile; fileRef = 621B3A4B154182F69DDE2989; };
9AE6891C35CE161CB1707B4B = { isa = PBXBuildFile; fileRef = 2FFF9AFE4BD9437CE096E52B; };
06994A713C38F415C4E8A009 = { isa = PBXBuildFile; fileRef = 18EE6576A9ED098632CE5155; };
98F737B7459895BFCDC7965E = { isa = PBXBuildFile; fileRef = 8B1C747E63EEF036AD9AF3D8; };
7033A0968B1C81A821CCC296 = { isa = PBXBuildFile; fileRef = 1C3D15546065C1A9AA5AA0C6; };
@@ -550,6 +551,8 @@
A0D6308567AAA50D1163D9D3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ComponentListener.h; path = ../../src/gui/components/juce_ComponentListener.h; sourceTree = SOURCE_ROOT; };
621B3A4B154182F69DDE2989 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Desktop.cpp; path = ../../src/gui/components/juce_Desktop.cpp; sourceTree = SOURCE_ROOT; };
A1F58C1A972425C2B43DD1B3 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_Desktop.h; path = ../../src/gui/components/juce_Desktop.h; sourceTree = SOURCE_ROOT; };
2FFF9AFE4BD9437CE096E52B = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ModalComponentManager.cpp; path = ../../src/gui/components/juce_ModalComponentManager.cpp; sourceTree = SOURCE_ROOT; };
41C8C324F13ADA3423FC3B0F = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ModalComponentManager.h; path = ../../src/gui/components/juce_ModalComponentManager.h; sourceTree = SOURCE_ROOT; };
18EE6576A9ED098632CE5155 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ArrowButton.cpp; path = ../../src/gui/components/buttons/juce_ArrowButton.cpp; sourceTree = SOURCE_ROOT; };
EB182DC4124FEFFFC87D12C4 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ArrowButton.h; path = ../../src/gui/components/buttons/juce_ArrowButton.h; sourceTree = SOURCE_ROOT; };
8B1C747E63EEF036AD9AF3D8 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_Button.cpp; path = ../../src/gui/components/buttons/juce_Button.cpp; sourceTree = SOURCE_ROOT; };
@@ -1455,6 +1458,8 @@
A0D6308567AAA50D1163D9D3,
621B3A4B154182F69DDE2989,
A1F58C1A972425C2B43DD1B3,
2FFF9AFE4BD9437CE096E52B,
41C8C324F13ADA3423FC3B0F,
2DB55F83F4310F0C4E4E03AA,
17B11D96CDB313ED60D8CFE0,
BCB2FFE7C2A4084A267F57F2,
@@ -1930,6 +1935,7 @@
621B7B0B518E63E69122C13E,
97982824572C18827047D92A,
927E7250FCE62E838599DF83,
9AE6891C35CE161CB1707B4B,
06994A713C38F415C4E8A009,
98F737B7459895BFCDC7965E,
7033A0968B1C81A821CCC296,


+ 4
- 0
Juce.jucer View File

@@ -495,6 +495,10 @@
file="src/gui/components/juce_Desktop.cpp"/>
<FILE id="kteq7JUyy" name="juce_Desktop.h" compile="0" resource="0"
file="src/gui/components/juce_Desktop.h"/>
<FILE id="OSpcyIq" name="juce_ModalComponentManager.cpp" compile="1"
resource="0" file="src/gui/components/juce_ModalComponentManager.cpp"/>
<FILE id="hHLSn88" name="juce_ModalComponentManager.h" compile="0"
resource="0" file="src/gui/components/juce_ModalComponentManager.h"/>
<GROUP id="bZKiEBSYn" name="buttons">
<FILE id="XWJvOnuh3" name="juce_ArrowButton.cpp" compile="1" resource="0"
file="src/gui/components/buttons/juce_ArrowButton.cpp"/>


+ 1
- 0
amalgamation/juce_amalgamated_template.cpp View File

@@ -223,6 +223,7 @@
#include "../src/gui/components/juce_Component.cpp"
#include "../src/gui/components/juce_ComponentListener.cpp"
#include "../src/gui/components/juce_Desktop.cpp"
#include "../src/gui/components/juce_ModalComponentManager.cpp"
#include "../src/gui/components/buttons/juce_ArrowButton.cpp"
#include "../src/gui/components/buttons/juce_Button.cpp"
#include "../src/gui/components/buttons/juce_DrawableButton.cpp"


+ 1
- 1
extras/Jucer (experimental)/Source/model/Project/jucer_ProjectExport_MSVC.h View File

@@ -1184,7 +1184,7 @@ protected:
const String getProjectType() const
{
if (project.isGUIApplication())
if (project.isGUIApplication() || project.isCommandLineApp())
return "Application";
else if (project.isAudioPlugin() || project.isBrowserPlugin())
return "DynamicLibrary";


+ 4
- 4
extras/audio plugin host/Plugin Host.jucer View File

@@ -13,12 +13,12 @@
jucerVersion="3.0.0">
<EXPORTFORMATS>
<XCODE_MAC targetFolder="Builds/MacOSX" vstFolder="~/SDKs/vstsdk2.4" rtasFolder="~/SDKs/PT_80_SDK"
juceFolder="../../../juce"/>
juceFolder="../.."/>
<VS2005 targetFolder="Builds/VisualStudio2005" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../.." libraryType="1"/>
<VS2008 targetFolder="Builds/VisualStudio2008" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../juce"/>
<LINUX_MAKE targetFolder="Builds/Linux" vstFolder="~/SDKs/vstsdk2.4" juceFolder="../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../.." libraryType="1"/>
<LINUX_MAKE targetFolder="Builds/Linux" vstFolder="~/SDKs/vstsdk2.4" juceFolder="../.."/>
</EXPORTFORMATS>
<CONFIGURATIONS>
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="Plugin Host"


+ 3
- 3
extras/audio plugins/demo/JuceDemoPlugin.jucer View File

@@ -11,11 +11,11 @@
bundleIdentifier="com.rawmaterialsoftware.JuceDemoPlugin" jucerVersion="3.0.0">
<EXPORTFORMATS>
<XCODE_MAC targetFolder="Builds/MacOSX" vstFolder="~/SDKs/vstsdk2.4" rtasFolder="~/SDKs/PT_80_SDK"
juceFolder="../../../../juce" objCExtraSuffix="JuceDemo"/>
juceFolder="../../.." objCExtraSuffix="JuceDemo"/>
<VS2005 targetFolder="Builds/VisualStudio2005" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../.." libraryType="1"/>
<VS2008 targetFolder="Builds/VisualStudio2008" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../.." libraryType="1"/>
</EXPORTFORMATS>
<CONFIGURATIONS>
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="JuceDemoPlugin"


+ 5
- 5
extras/example projects/HelloWorld.jucer View File

@@ -12,14 +12,14 @@
pluginAUViewClass="HelloWorldAU_V1" pluginRTASCategory="" bundleIdentifier="com.rawmaterialsoftware.jucehelloworld">
<EXPORTFORMATS>
<XCODE_MAC targetFolder="Builds/MacOSX" vstFolder="~/SDKs/vstsdk2.4" rtasFolder="~/SDKs/PT_80_SDK"
juceFolder="../../../juce"/>
juceFolder="../.."/>
<XCODE_IPHONE targetFolder="Builds/iPhone" vstFolder="~/SDKs/vstsdk2.4" rtasFolder="~/SDKs/PT_80_SDK"
juceFolder="../../../juce"/>
juceFolder="../.."/>
<VS2005 targetFolder="Builds/VisualStudio2005" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../.." libraryType="1"/>
<VS2008 targetFolder="Builds/VisualStudio2008" vstFolder="c:\SDKs\vstsdk2.4"
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../../../juce"/>
<LINUX_MAKE targetFolder="Builds/Linux" vstFolder="~/SDKs/vstsdk2.4" juceFolder="../../../juce"/>
rtasFolder="c:\SDKs\PT_80_SDK" juceFolder="../.." libraryType="1"/>
<LINUX_MAKE targetFolder="Builds/Linux" vstFolder="~/SDKs/vstsdk2.4" juceFolder="../.."/>
</EXPORTFORMATS>
<CONFIGURATIONS>
<CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="HelloWorld"


+ 505
- 335
juce_amalgamated.cpp
File diff suppressed because it is too large
View File


+ 221
- 72
juce_amalgamated.h View File

@@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 19
#define JUCE_BUILDNUMBER 20

/** Current Juce version number.

@@ -14254,7 +14254,7 @@ private:
static classname* _singletonInstance; \
static JUCE_NAMESPACE::CriticalSection _singletonLock; \
\
static classname* getInstance() \
static classname* JUCE_CALLTYPE getInstance() \
{ \
if (_singletonInstance == 0) \
{\
@@ -14282,12 +14282,12 @@ private:
return _singletonInstance; \
} \
\
static inline classname* getInstanceWithoutCreating() throw() \
static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() throw() \
{ \
return _singletonInstance; \
} \
\
static void deleteInstance() \
static void JUCE_CALLTYPE deleteInstance() \
{ \
const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \
if (_singletonInstance != 0) \
@@ -24927,6 +24927,167 @@ private:
#endif // __JUCE_BORDERSIZE_JUCEHEADER__
/*** End of inlined file: juce_BorderSize.h ***/


/*** Start of inlined file: juce_ModalComponentManager.h ***/
#ifndef __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__
#define __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__


/*** Start of inlined file: juce_DeletedAtShutdown.h ***/
#ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__
#define __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__

/**
Classes derived from this will be automatically deleted when the application exits.

After JUCEApplication::shutdown() has been called, any objects derived from
DeletedAtShutdown which are still in existence will be deleted in the reverse
order to that in which they were created.

So if you've got a singleton and don't want to have to explicitly delete it, just
inherit from this and it'll be taken care of.
*/
class JUCE_API DeletedAtShutdown
{
protected:
/** Creates a DeletedAtShutdown object. */
DeletedAtShutdown();

/** Destructor.

It's ok to delete these objects explicitly - it's only the ones left
dangling at the end that will be deleted automatically.
*/
virtual ~DeletedAtShutdown();

public:
/** Deletes all extant objects.

This shouldn't be used by applications, as it's called automatically
in the shutdown code of the JUCEApplication class.
*/
static void deleteAll();

private:
DeletedAtShutdown (const DeletedAtShutdown&);
DeletedAtShutdown& operator= (const DeletedAtShutdown&);

static CriticalSection& getLock();
static Array <DeletedAtShutdown*>& getObjects();
};

#endif // __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__
/*** End of inlined file: juce_DeletedAtShutdown.h ***/

/**
Manages the system's stack of modal components.

Normally you'll just use the Component methods to invoke modal states in components,
and won't have to deal with this class directly, but this is the singleton object that's
used internally to manage the stack.

@see Component::enterModalState, Component::exitModalState, Component::isCurrentlyModal,
Component::getCurrentlyModalComponent, Component::isCurrentlyBlockedByAnotherModalComponent
*/
class JUCE_API ModalComponentManager : public AsyncUpdater,
public DeletedAtShutdown
{
public:

/** Receives callbacks when a modal component is dismissed.

You can register a callback using Component::enterModalState() or
ModalComponentManager::attachCallback().
*/
class Callback
{
public:
/** */
Callback() {}

/** Destructor. */
virtual ~Callback() {}

/** Called to indicate that a modal component has been dismissed.

You can register a callback using Component::enterModalState() or
ModalComponentManager::attachCallback().

The returnValue parameter is the value that was passed to Component::exitModalState()
when the component was dismissed.

The callback object will be deleted shortly after this method is called.
*/
virtual void modalStateFinished (int returnValue) = 0;
};

/** Returns the number of components currently being shown modally.
@see getModalComponent
*/
int getNumModalComponents() const;

/** Returns one of the components being shown modally.
An index of 0 is the most recently-shown, topmost component.
*/
Component* getModalComponent (int index) const;

/** Returns true if the specified component is in a modal state. */
bool isModal (Component* component) const;

/** Returns true if the specified component is currently the topmost modal component. */
bool isFrontModalComponent (Component* component) const;

/** Adds a new callback that will be called when the specified modal component is dismissed.

If the component is modal, then when it is dismissed, either by being hidden, or by calling
Component::exitModalState(), then the Callback::modalStateFinished() method will be
called.

Each component can have any number of callbacks associated with it, and this one is added
to that list.

The object that is passed in will be deleted by the manager when it's no longer needed. If
the given component is not currently modal, the callback object is deleted immediately and
no action is taken.
*/
void attachCallback (Component* component, Callback* callback);

/** Runs the event loop until the currently topmost modal component is dismissed, and
returns the exit code for that component.
*/
int runEventLoopForCurrentComponent();

juce_DeclareSingleton_SingleThreaded_Minimal (ModalComponentManager);

protected:
/** Creates a ModalComponentManager.
You shouldn't ever call the constructor - it's a singleton, so use ModalComponentManager::getInstance()
*/
ModalComponentManager();

/** Destructor. */
~ModalComponentManager();

/** @internal */
void handleAsyncUpdate();

private:
class ModalItem;
class ReturnValueRetriever;

friend class Component;
friend class OwnedArray <ModalItem>;
OwnedArray <ModalItem> stack;

void startModal (Component* component, Callback* callback);
void endModal (Component* component, int returnValue);
void endModal (Component* component);

};

#endif // __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__
/*** End of inlined file: juce_ModalComponentManager.h ***/

class LookAndFeel;
class MouseInputSource;
class MouseInputSourceInternal;
@@ -26576,7 +26737,7 @@ public:
passed into exitModalState().

@see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent,
isCurrentlyBlockedByAnotherModalComponent, MessageManager::dispatchNextMessage
isCurrentlyBlockedByAnotherModalComponent, ModalComponentManager
*/
int runModalLoop();

@@ -26590,9 +26751,15 @@ public:
get the focus, which is usually what you'll want it to do. If not, it will leave
the focus unchanged.

@see exitModalState, runModalLoop
The callback is an optional object which will receive a callback when the modal
component loses its modal status, either by being hidden or when exitModalState()
is called. If you pass an object in here, the system will take care of deleting it
later, after making the callback

@see exitModalState, runModalLoop, ModalComponentManager::attachCallback
*/
void enterModalState (bool takeKeyboardFocus = true);
void enterModalState (bool takeKeyboardFocus = true,
ModalComponentManager::Callback* callback = 0);

/** Ends a component's modal state.

@@ -27717,53 +27884,6 @@ public:
#define __JUCE_DESKTOP_JUCEHEADER__


/*** Start of inlined file: juce_DeletedAtShutdown.h ***/
#ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__
#define __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__

/**
Classes derived from this will be automatically deleted when the application exits.

After JUCEApplication::shutdown() has been called, any objects derived from
DeletedAtShutdown which are still in existence will be deleted in the reverse
order to that in which they were created.

So if you've got a singleton and don't want to have to explicitly delete it, just
inherit from this and it'll be taken care of.
*/
class JUCE_API DeletedAtShutdown
{
protected:
/** Creates a DeletedAtShutdown object. */
DeletedAtShutdown();

/** Destructor.

It's ok to delete these objects explicitly - it's only the ones left
dangling at the end that will be deleted automatically.
*/
virtual ~DeletedAtShutdown();

public:
/** Deletes all extant objects.

This shouldn't be used by applications, as it's called automatically
in the shutdown code of the JUCEApplication class.
*/
static void deleteAll();

private:
DeletedAtShutdown (const DeletedAtShutdown&);
DeletedAtShutdown& operator= (const DeletedAtShutdown&);

static CriticalSection& getLock();
static Array <DeletedAtShutdown*>& getObjects();
};

#endif // __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__
/*** End of inlined file: juce_DeletedAtShutdown.h ***/


/*** Start of inlined file: juce_Timer.h ***/
#ifndef __JUCE_TIMER_JUCEHEADER__
#define __JUCE_TIMER_JUCEHEADER__
@@ -34964,12 +35084,19 @@ public:
in zero.
@param standardItemHeight if this is non-zero, it will be used as the standard
height for menu items (apart from custom items)
@param callback if this is non-zero, the menu will be launched asynchronously,
returning immediately, and the callback will receive a
call when the menu is either dismissed or has an item
selected. This object will be owned and deleted by the
system, so make sure that it works safely and that any
pointers that it uses are safely within scope.
@see showAt
*/
int show (int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);

/** Displays the menu at a specific location.

@@ -34987,7 +35114,8 @@ public:
int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);

/** Displays the menu as if it's attached to a component such as a button.

@@ -34999,7 +35127,8 @@ public:
int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);

/** Closes any menus that are currently open.

@@ -35098,6 +35227,7 @@ private:
friend class ItemComponent;
friend class Window;
friend class PopupMenuCustomComponent;
friend class MenuBarComponent;
friend class OwnedArray <Item>;
friend class ScopedPointer <Window>;

@@ -35107,16 +35237,16 @@ private:

void addSeparatorIfPending();

int showMenu (int x, int y, int w, int h,
int showMenu (const Rectangle<int>& target,
int itemIdThatMustBeVisible,
int minimumWidth,
int maximumNumColumns,
int standardItemHeight,
bool alignToRectangle,
Component* componentAttachedTo);
Component* componentAttachedTo,
ModalComponentManager::Callback* callback);

friend class MenuBarComponent;
Component* createMenuComponent (int x, int y, int w, int h,
Component* createMenuComponent (const Rectangle<int>& target,
int itemIdThatMustBeVisible,
int minimumWidth,
int maximumNumColumns,
@@ -35660,10 +35790,6 @@ public:
/** @internal */
bool isTextInputActive() const;

juce_UseDebuggingNewOperator

protected:

/** This adds the items to the popup menu.

By default it adds the cut/copy/paste items, but you can override this if
@@ -35701,6 +35827,10 @@ protected:
*/
virtual void performPopupMenuAction (int menuItemID);

juce_UseDebuggingNewOperator

protected:

/** Scrolls the minimum distance needed to get the caret into view. */
void scrollToMakeSureCursorIsVisible();

@@ -36462,6 +36592,9 @@ private:
bool isRealItem() const throw();
};

class Callback;
friend class Callback;

OwnedArray <ItemInfo> items;
Value currentId;
int lastCurrentId;
@@ -50012,7 +50145,16 @@ public:

Leave the width or height as 0 to use the default size
*/
bool show (int width = 0,int height = 0);
bool show (int width = 0, int height = 0);

/** Displays and runs the dialog box modally.

This will show the box with the specified size at the specified location,
returning true if the user pressed 'ok', or false if they cancelled.

Leave the width or height as 0 to use the default size.
*/
bool showAt (int x, int y, int width, int height);

/** A set of colour IDs to use to change the colour of various aspects of the box.

@@ -50628,6 +50770,9 @@ private:
#endif
#ifndef __JUCE_DESKTOP_JUCEHEADER__

#endif
#ifndef __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__

#endif
#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__

@@ -51809,6 +51954,10 @@ public:
*/
void setModel (MenuBarModel* newModel);

/** Returns the current menu bar model being used.
*/
MenuBarModel* getModel() const throw();

/** Pops up one of the menu items.

This lets you manually open one of the menus - it could be triggered by a
@@ -51833,8 +51982,6 @@ public:
/** @internal */
void mouseMove (const MouseEvent& e);
/** @internal */
void inputAttemptWhenModal();
/** @internal */
void handleCommandMessage (int commandId);
/** @internal */
bool keyPressed (const KeyPress& key);
@@ -51847,20 +51994,22 @@ public:
juce_UseDebuggingNewOperator

private:
class AsyncCallback;
friend class AsyncCallback;
MenuBarModel* model;

StringArray menuNames;
Array <int> xPositions;
int itemUnderMouse, currentPopupIndex, topLevelIndexClicked, indexToShowAgain;
int itemUnderMouse, currentPopupIndex, topLevelIndexClicked;
int lastMouseX, lastMouseY;
bool inModalState;
ScopedPointer <Component> currentPopup;

int getItemAt (int x, int y);
void setItemUnderMouse (int index);
void setOpenItem (int index);
void updateItemUnderMouse (int x, int y);
void hideCurrentMenu();
void timerCallback();
void repaintMenuItem (int index);
void menuDismissed (int topLevelIndex, int itemId);

MenuBarComponent (const MenuBarComponent&);
MenuBarComponent& operator= (const MenuBarComponent&);


+ 3
- 3
src/core/juce_Singleton.h View File

@@ -93,7 +93,7 @@
static classname* _singletonInstance; \
static JUCE_NAMESPACE::CriticalSection _singletonLock; \
\
static classname* getInstance() \
static classname* JUCE_CALLTYPE getInstance() \
{ \
if (_singletonInstance == 0) \
{\
@@ -121,12 +121,12 @@
return _singletonInstance; \
} \
\
static inline classname* getInstanceWithoutCreating() throw() \
static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() throw() \
{ \
return _singletonInstance; \
} \
\
static void deleteInstance() \
static void JUCE_CALLTYPE deleteInstance() \
{ \
const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \
if (_singletonInstance != 0) \


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

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 19
#define JUCE_BUILDNUMBER 20
/** Current Juce version number.


+ 29
- 14
src/gui/components/controls/juce_ComboBox.cpp View File

@@ -525,15 +525,40 @@ void ComboBox::labelTextChanged (Label*)
//==============================================================================
class ComboBox::Callback : public ModalComponentManager::Callback
{
public:
Callback (ComboBox* const box_)
: box (box_)
{
}
void modalStateFinished (int returnValue)
{
if (box != 0)
{
box->menuActive = false;
if (returnValue != 0)
box->setSelectedId (returnValue);
}
}
private:
Component::SafePointer<ComboBox> box;
Callback (const Callback&);
Callback& operator= (const Callback&);
};
void ComboBox::showPopup()
{
if (! menuActive)
{
const int selectedId = getSelectedId();
Component::SafePointer<Component> deletionWatcher (this);
PopupMenu menu;
menu.setLookAndFeel (&getLookAndFeel());
for (int i = 0; i < items.size(); ++i)
@@ -552,19 +577,9 @@ void ComboBox::showPopup()
if (items.size() == 0)
menu.addItem (1, noChoicesMessage, false);
const int itemHeight = jlimit (12, 24, getHeight());
menuActive = true;
const int resultId = menu.showAt (this, selectedId,
getWidth(), 1, itemHeight);
if (deletionWatcher == 0)
return;
menuActive = false;
if (resultId != 0)
setSelectedId (resultId);
menu.showAt (this, selectedId, getWidth(), 1, jlimit (12, 24, getHeight()),
new Callback (this));
}
}


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

@@ -388,6 +388,9 @@ private:
bool isRealItem() const throw();
};
class Callback;
friend class Callback;
OwnedArray <ItemInfo> items;
Value currentId;
int lastCurrentId;


+ 24
- 7
src/gui/components/controls/juce_TextEditor.cpp View File

@@ -1773,6 +1773,28 @@ void TextEditor::paintOverChildren (Graphics& g)
}
//==============================================================================
class TextEditorMenuPerformer : public ModalComponentManager::Callback
{
public:
TextEditorMenuPerformer (TextEditor* const editor_)
: editor (editor_)
{
}
void modalStateFinished (int returnValue)
{
if (editor != 0 && returnValue != 0)
editor->performPopupMenuAction (returnValue);
}
private:
Component::SafePointer<TextEditor> editor;
TextEditorMenuPerformer (const TextEditorMenuPerformer&);
TextEditorMenuPerformer& operator= (const TextEditorMenuPerformer&);
};
void TextEditor::mouseDown (const MouseEvent& e)
{
beginDragAutoRepeat (100);
@@ -1791,12 +1813,7 @@ void TextEditor::mouseDown (const MouseEvent& e)
m.setLookAndFeel (&getLookAndFeel());
addPopupMenuItems (m, &e);
menuActive = true;
const int result = m.show();
menuActive = false;
if (result != 0)
performPopupMenuAction (result);
m.show (0, 0, 0, 0, new TextEditorMenuPerformer (this));
}
}
}
@@ -2221,7 +2238,7 @@ void TextEditor::enablementChanged()
//==============================================================================
UndoManager* TextEditor::getUndoManager() throw()
{
return isReadOnly() ? &undoManager : 0;
return isReadOnly() ? 0 : &undoManager;
}
void TextEditor::clearInternal (UndoManager* const um)


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

@@ -538,9 +538,6 @@ public:
/** @internal */
bool isTextInputActive() const;
juce_UseDebuggingNewOperator
protected:
//==============================================================================
/** This adds the items to the popup menu.
@@ -579,6 +576,10 @@ protected:
*/
virtual void performPopupMenuAction (int menuItemID);
//==============================================================================
juce_UseDebuggingNewOperator
protected:
//==============================================================================
/** Scrolls the minimum distance needed to get the caret into view. */
void scrollToMakeSureCursorIsVisible();


+ 9
- 1
src/gui/components/filebrowser/juce_FileChooserDialogBox.cpp View File

@@ -75,6 +75,11 @@ FileChooserDialogBox::~FileChooserDialogBox()
//==============================================================================
bool FileChooserDialogBox::show (int w, int h)
{
return showAt (-1, -1, w, h);
}
bool FileChooserDialogBox::showAt (int x, int y, int w, int h)
{
if (w <= 0)
{
@@ -88,7 +93,10 @@ bool FileChooserDialogBox::show (int w, int h)
if (h <= 0)
h = 500;
centreWithSize (w, h);
if (x < 0 || y < 0)
centreWithSize (w, h);
else
setBounds (x, y, w, h);
const bool ok = (runModalLoop() != 0);
setVisible (false);


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

@@ -103,8 +103,16 @@ public:
Leave the width or height as 0 to use the default size
*/
bool show (int width = 0,int height = 0);
bool show (int width = 0, int height = 0);
/** Displays and runs the dialog box modally.
This will show the box with the specified size at the specified location,
returning true if the user pressed 'ok', or false if they cancelled.
Leave the width or height as 0 to use the default size.
*/
bool showAt (int x, int y, int width, int height);
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the box.


+ 12
- 79
src/gui/components/juce_Component.cpp View File

@@ -39,15 +39,12 @@ BEGIN_JUCE_NAMESPACE
#include "../../events/juce_MessageManager.h"
#include "../../events/juce_Timer.h"
#include "../../core/juce_Time.h"
#include "../../core/juce_Singleton.h"
#include "../../core/juce_PlatformUtilities.h"
#include "mouse/juce_MouseInputSource.h"
//==============================================================================
Component* Component::currentlyFocusedComponent = 0;
static Array <Component*> modalComponentStack, modalComponentReturnValueKeys;
static Array <int> modalReturnValues;
//==============================================================================
#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
enum ComponentMessageNumbers
{
@@ -55,10 +52,8 @@ enum ComponentMessageNumbers
exitModalStateMessage = 0x7fff0002
};
//==============================================================================
#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
static uint32 nextComponentUID = 0;
Component* Component::currentlyFocusedComponent = 0;
//==============================================================================
@@ -106,8 +101,6 @@ Component::~Component()
if (flags.hasHeavyweightPeerFlag)
removeFromDesktop();
modalComponentStack.removeValue (this);
for (int i = childComponentList_.size(); --i >= 0;)
childComponentList_.getUnchecked(i)->parentComponent_ = 0;
@@ -1330,59 +1323,17 @@ int Component::runModalLoop()
if (! MessageManager::getInstance()->isThisTheMessageThread())
{
// use a callback so this can be called from non-gui threads
return (int) (pointer_sized_int)
MessageManager::getInstance()
->callFunctionOnMessageThread (&runModalLoopCallback, this);
return (int) (pointer_sized_int) MessageManager::getInstance()
->callFunctionOnMessageThread (&runModalLoopCallback, this);
}
SafePointer<Component> prevFocused (getCurrentlyFocusedComponent());
if (! isCurrentlyModal())
enterModalState();
JUCE_TRY
{
while (flags.currentlyModalFlag && flags.visibleFlag)
{
if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
break;
enterModalState (true);
// check whether this component was deleted during the last message
if (! isValidMessageListener())
break;
}
}
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
catch (const std::exception& e)
{
JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__);
return 0;
}
catch (...)
{
JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__);
return 0;
}
#endif
const int modalIndex = modalComponentReturnValueKeys.indexOf (this);
int returnValue = 0;
if (modalIndex >= 0)
{
modalComponentReturnValueKeys.remove (modalIndex);
returnValue = modalReturnValues.remove (modalIndex);
}
modalComponentStack.removeValue (this);
if (prevFocused != 0)
prevFocused->grabKeyboardFocus();
return returnValue;
return ModalComponentManager::getInstance()->runEventLoopForCurrentComponent();
}
void Component::enterModalState (const bool takeKeyboardFocus_)
void Component::enterModalState (const bool takeKeyboardFocus_, ModalComponentManager::Callback* const callback)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
@@ -1394,10 +1345,7 @@ void Component::enterModalState (const bool takeKeyboardFocus_)
if (! isCurrentlyModal())
{
modalComponentStack.add (this);
modalComponentReturnValueKeys.add (this);
modalReturnValues.add (0);
ModalComponentManager::getInstance()->startModal (this, callback);
flags.currentlyModalFlag = true;
setVisible (true);
@@ -1412,20 +1360,7 @@ void Component::exitModalState (const int returnValue)
{
if (MessageManager::getInstance()->isThisTheMessageThread())
{
const int modalIndex = modalComponentReturnValueKeys.indexOf (this);
if (modalIndex >= 0)
{
modalReturnValues.set (modalIndex, returnValue);
}
else
{
modalComponentReturnValueKeys.add (this);
modalReturnValues.add (returnValue);
}
modalComponentStack.removeValue (this);
ModalComponentManager::getInstance()->endModal (this, returnValue);
flags.currentlyModalFlag = false;
bringModalComponentToFront();
@@ -1455,14 +1390,12 @@ bool Component::isCurrentlyBlockedByAnotherModalComponent() const
int JUCE_CALLTYPE Component::getNumCurrentlyModalComponents() throw()
{
return modalComponentStack.size();
return ModalComponentManager::getInstance()->getNumModalComponents();
}
Component* JUCE_CALLTYPE Component::getCurrentlyModalComponent (int index) throw()
{
Component* const c = static_cast <Component*> (modalComponentStack [modalComponentStack.size() - index - 1]);
return c->isValidComponent() ? c : 0;
return ModalComponentManager::getInstance()->getModalComponent (index);
}
void Component::bringModalComponentToFront()


+ 11
- 3
src/gui/components/juce_Component.h View File

@@ -41,6 +41,8 @@
#include "../../text/juce_StringArray.h"
#include "../../containers/juce_Array.h"
#include "../../containers/juce_NamedValueSet.h"
#include "juce_ModalComponentManager.h"
class LookAndFeel;
class MouseInputSource;
class MouseInputSourceInternal;
@@ -1728,7 +1730,7 @@ public:
passed into exitModalState().
@see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent,
isCurrentlyBlockedByAnotherModalComponent, MessageManager::dispatchNextMessage
isCurrentlyBlockedByAnotherModalComponent, ModalComponentManager
*/
int runModalLoop();
@@ -1742,9 +1744,15 @@ public:
get the focus, which is usually what you'll want it to do. If not, it will leave
the focus unchanged.
@see exitModalState, runModalLoop
The callback is an optional object which will receive a callback when the modal
component loses its modal status, either by being hidden or when exitModalState()
is called. If you pass an object in here, the system will take care of deleting it
later, after making the callback
@see exitModalState, runModalLoop, ModalComponentManager::attachCallback
*/
void enterModalState (bool takeKeyboardFocus = true);
void enterModalState (bool takeKeyboardFocus = true,
ModalComponentManager::Callback* callback = 0);
/** Ends a component's modal state.


+ 267
- 0
src/gui/components/juce_ModalComponentManager.cpp View File

@@ -0,0 +1,267 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 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.
==============================================================================
*/
#include "../../core/juce_StandardHeader.h"
BEGIN_JUCE_NAMESPACE
#include "juce_Component.h"
#include "juce_ModalComponentManager.h"
#include "../../events/juce_MessageManager.h"
#include "../../application/juce_Application.h"
//==============================================================================
class ModalComponentManager::ModalItem : public ComponentListener
{
public:
ModalItem (Component* const comp, Callback* const callback)
: component (comp), returnValue (0), isActive (true), isDeleted (false)
{
if (callback != 0)
callbacks.add (callback);
jassert (comp != 0);
component->addComponentListener (this);
}
~ModalItem()
{
if (! isDeleted)
component->removeComponentListener (this);
}
void componentBeingDeleted (Component&)
{
isDeleted = true;
cancel();
}
void componentVisibilityChanged (Component&)
{
if (! component->isShowing())
cancel();
}
void componentParentHierarchyChanged (Component&)
{
if (! component->isShowing())
cancel();
}
void cancel()
{
if (isActive)
{
isActive = false;
ModalComponentManager::getInstance()->triggerAsyncUpdate();
}
}
Component* component;
OwnedArray<Callback> callbacks;
int returnValue;
bool isActive, isDeleted;
private:
ModalItem (const ModalItem&);
ModalItem& operator= (const ModalItem&);
};
//==============================================================================
ModalComponentManager::ModalComponentManager()
{
}
ModalComponentManager::~ModalComponentManager()
{
clearSingletonInstance();
}
juce_ImplementSingleton_SingleThreaded (ModalComponentManager);
//==============================================================================
void ModalComponentManager::startModal (Component* component, Callback* callback)
{
if (component != 0)
stack.add (new ModalItem (component, callback));
}
void ModalComponentManager::attachCallback (Component* component, Callback* callback)
{
if (callback != 0)
{
ScopedPointer<Callback> callbackDeleter (callback);
for (int i = stack.size(); --i >= 0;)
{
ModalItem* const item = stack.getUnchecked(i);
if (item->component == component)
{
item->callbacks.add (callback);
callbackDeleter.release();
break;
}
}
}
}
void ModalComponentManager::endModal (Component* component)
{
for (int i = stack.size(); --i >= 0;)
{
ModalItem* const item = stack.getUnchecked(i);
if (item->component == component)
item->cancel();
}
}
void ModalComponentManager::endModal (Component* component, int returnValue)
{
for (int i = stack.size(); --i >= 0;)
{
ModalItem* const item = stack.getUnchecked(i);
if (item->component == component)
{
item->returnValue = returnValue;
item->cancel();
}
}
}
int ModalComponentManager::getNumModalComponents() const
{
int n = 0;
for (int i = 0; i < stack.size(); ++i)
if (stack.getUnchecked(i)->isActive)
++n;
return n;
}
Component* ModalComponentManager::getModalComponent (const int index) const
{
int n = 0;
for (int i = stack.size(); --i >= 0;)
{
const ModalItem* const item = stack.getUnchecked(i);
if (item->isActive)
if (n++ == index)
return item->component;
}
return 0;
}
bool ModalComponentManager::isModal (Component* const comp) const
{
for (int i = stack.size(); --i >= 0;)
{
const ModalItem* const item = stack.getUnchecked(i);
if (item->isActive && item->component == comp)
return true;
}
return false;
}
bool ModalComponentManager::isFrontModalComponent (Component* const comp) const
{
return comp == getModalComponent (0);
}
void ModalComponentManager::handleAsyncUpdate()
{
for (int i = stack.size(); --i >= 0;)
{
const ModalItem* const item = stack.getUnchecked(i);
if (! item->isActive)
{
for (int j = item->callbacks.size(); --j >= 0;)
item->callbacks.getUnchecked(j)->modalStateFinished (item->returnValue);
stack.remove (i);
}
}
}
class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
{
public:
ReturnValueRetriever (int& value_, bool& finished_) : value (value_), finished (finished_) {}
~ReturnValueRetriever() {}
void modalStateFinished (int returnValue)
{
finished = true;
value = returnValue;
}
private:
int& value;
bool& finished;
ReturnValueRetriever (const ReturnValueRetriever&);
ReturnValueRetriever& operator= (const ReturnValueRetriever&);
};
int ModalComponentManager::runEventLoopForCurrentComponent()
{
// This can only be run from the message thread!
jassert (MessageManager::getInstance()->isThisTheMessageThread());
Component* currentlyModal = getModalComponent (0);
if (currentlyModal == 0)
return 0;
Component::SafePointer<Component> prevFocused (Component::getCurrentlyFocusedComponent());
int returnValue = 0;
bool finished = false;
attachCallback (currentlyModal, new ReturnValueRetriever (returnValue, finished));
JUCE_TRY
{
while (! finished)
{
if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
break;
}
}
JUCE_CATCH_EXCEPTION
if (prevFocused != 0)
prevFocused->grabKeyboardFocus();
return returnValue;
}
END_JUCE_NAMESPACE

+ 144
- 0
src/gui/components/juce_ModalComponentManager.h View File

@@ -0,0 +1,144 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 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_MODALCOMPONENTMANAGER_JUCEHEADER__
#define __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__
#include "../../core/juce_Singleton.h"
#include "../../events/juce_AsyncUpdater.h"
#include "../../utilities/juce_DeletedAtShutdown.h"
//==============================================================================
/**
Manages the system's stack of modal components.
Normally you'll just use the Component methods to invoke modal states in components,
and won't have to deal with this class directly, but this is the singleton object that's
used internally to manage the stack.
@see Component::enterModalState, Component::exitModalState, Component::isCurrentlyModal,
Component::getCurrentlyModalComponent, Component::isCurrentlyBlockedByAnotherModalComponent
*/
class JUCE_API ModalComponentManager : public AsyncUpdater,
public DeletedAtShutdown
{
public:
//==============================================================================
/** Receives callbacks when a modal component is dismissed.
You can register a callback using Component::enterModalState() or
ModalComponentManager::attachCallback().
*/
class Callback
{
public:
/** */
Callback() {}
/** Destructor. */
virtual ~Callback() {}
/** Called to indicate that a modal component has been dismissed.
You can register a callback using Component::enterModalState() or
ModalComponentManager::attachCallback().
The returnValue parameter is the value that was passed to Component::exitModalState()
when the component was dismissed.
The callback object will be deleted shortly after this method is called.
*/
virtual void modalStateFinished (int returnValue) = 0;
};
//==============================================================================
/** Returns the number of components currently being shown modally.
@see getModalComponent
*/
int getNumModalComponents() const;
/** Returns one of the components being shown modally.
An index of 0 is the most recently-shown, topmost component.
*/
Component* getModalComponent (int index) const;
/** Returns true if the specified component is in a modal state. */
bool isModal (Component* component) const;
/** Returns true if the specified component is currently the topmost modal component. */
bool isFrontModalComponent (Component* component) const;
/** Adds a new callback that will be called when the specified modal component is dismissed.
If the component is modal, then when it is dismissed, either by being hidden, or by calling
Component::exitModalState(), then the Callback::modalStateFinished() method will be
called.
Each component can have any number of callbacks associated with it, and this one is added
to that list.
The object that is passed in will be deleted by the manager when it's no longer needed. If
the given component is not currently modal, the callback object is deleted immediately and
no action is taken.
*/
void attachCallback (Component* component, Callback* callback);
/** Runs the event loop until the currently topmost modal component is dismissed, and
returns the exit code for that component.
*/
int runEventLoopForCurrentComponent();
//==============================================================================
juce_DeclareSingleton_SingleThreaded_Minimal (ModalComponentManager);
protected:
/** Creates a ModalComponentManager.
You shouldn't ever call the constructor - it's a singleton, so use ModalComponentManager::getInstance()
*/
ModalComponentManager();
/** Destructor. */
~ModalComponentManager();
/** @internal */
void handleAsyncUpdate();
private:
class ModalItem;
class ReturnValueRetriever;
friend class Component;
friend class OwnedArray <ModalItem>;
OwnedArray <ModalItem> stack;
void startModal (Component* component, Callback* callback);
void endModal (Component* component, int returnValue);
void endModal (Component* component);
};
#endif // __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__

+ 82
- 144
src/gui/components/menus/juce_MenuBarComponent.cpp View File

@@ -32,31 +32,14 @@ BEGIN_JUCE_NAMESPACE
#include "../lookandfeel/juce_LookAndFeel.h"
//==============================================================================
class DummyMenuComponent : public Component
{
DummyMenuComponent (const DummyMenuComponent&);
DummyMenuComponent& operator= (const DummyMenuComponent&);
public:
DummyMenuComponent() {}
~DummyMenuComponent() {}
void inputAttemptWhenModal()
{
exitModalState (0);
}
};
//==============================================================================
MenuBarComponent::MenuBarComponent (MenuBarModel* model_)
: model (0),
itemUnderMouse (-1),
currentPopupIndex (-1),
indexToShowAgain (-1),
topLevelIndexClicked (0),
lastMouseX (0),
lastMouseY (0),
inModalState (false)
lastMouseY (0)
{
setRepaintsOnMouseActivity (true);
setWantsKeyboardFocus (false);
@@ -68,9 +51,12 @@ MenuBarComponent::MenuBarComponent (MenuBarModel* model_)
MenuBarComponent::~MenuBarComponent()
{
setModel (0);
Desktop::getInstance().removeGlobalMouseListener (this);
currentPopup = 0;
}
MenuBarModel* MenuBarComponent::getModel() const throw()
{
return model;
}
void MenuBarComponent::setModel (MenuBarModel* const newModel)
@@ -158,144 +144,102 @@ void MenuBarComponent::repaintMenuItem (int index)
}
}
void MenuBarComponent::updateItemUnderMouse (int x, int y)
void MenuBarComponent::setItemUnderMouse (const int index)
{
const int newItem = getItemAt (x, y);
if (itemUnderMouse != newItem)
if (itemUnderMouse != index)
{
repaintMenuItem (itemUnderMouse);
itemUnderMouse = newItem;
itemUnderMouse = index;
repaintMenuItem (itemUnderMouse);
}
}
void MenuBarComponent::hideCurrentMenu()
void MenuBarComponent::setOpenItem (int index)
{
currentPopup = 0;
repaint();
}
void MenuBarComponent::showMenu (int index)
{
if (index != currentPopupIndex)
if (currentPopupIndex != index)
{
if (inModalState)
{
hideCurrentMenu();
indexToShowAgain = index;
return;
}
repaintMenuItem (currentPopupIndex);
currentPopupIndex = index;
repaintMenuItem (currentPopupIndex);
indexToShowAgain = -1;
currentPopupIndex = -1;
itemUnderMouse = index;
currentPopup = 0;
menuBarItemsChanged (0);
if (index >= 0)
Desktop::getInstance().addGlobalMouseListener (this);
else
Desktop::getInstance().removeGlobalMouseListener (this);
}
}
Component::SafePointer<Component> prevFocused (getCurrentlyFocusedComponent());
Component::SafePointer<Component> deletionChecker (this);
void MenuBarComponent::updateItemUnderMouse (int x, int y)
{
setItemUnderMouse (getItemAt (x, y));
}
enterModalState (false);
inModalState = true;
int result = 0;
ApplicationCommandManager* managerOfChosenCommand = 0;
class MenuBarComponent::AsyncCallback : public ModalComponentManager::Callback
{
public:
AsyncCallback (MenuBarComponent* const bar_, const int topLevelIndex_)
: bar (bar_), topLevelIndex (topLevelIndex_)
{
}
Desktop::getInstance().addGlobalMouseListener (this);
~AsyncCallback() {}
for (;;)
{
const int x = getScreenX() + xPositions [itemUnderMouse];
const int w = xPositions [itemUnderMouse + 1] - xPositions [itemUnderMouse];
currentPopupIndex = itemUnderMouse;
indexToShowAgain = -1;
repaint();
if (((unsigned int) itemUnderMouse) < (unsigned int) menuNames.size())
{
PopupMenu m (model->getMenuForIndex (itemUnderMouse,
menuNames [itemUnderMouse]));
if (m.lookAndFeel == 0)
m.setLookAndFeel (&getLookAndFeel());
currentPopup = m.createMenuComponent (x, getScreenY(),
w, getHeight(),
0, w, 0, 0,
true, this,
&managerOfChosenCommand,
this);
}
if (currentPopup == 0)
{
currentPopup = new DummyMenuComponent();
addAndMakeVisible (currentPopup);
}
currentPopup->enterModalState (false);
currentPopup->toFront (false); // need to do this after making it modal, or it could
// be stuck behind other comps that are already modal..
result = currentPopup->runModalLoop();
if (deletionChecker == 0)
return;
const int lastPopupIndex = currentPopupIndex;
currentPopup = 0;
currentPopupIndex = -1;
if (result != 0)
{
topLevelIndexClicked = lastPopupIndex;
break;
}
else if (indexToShowAgain >= 0)
{
menuBarItemsChanged (0);
repaint();
itemUnderMouse = indexToShowAgain;
if (((unsigned int) itemUnderMouse) >= (unsigned int) menuNames.size())
break;
}
else
{
break;
}
}
void modalStateFinished (int returnValue)
{
if (bar != 0)
bar->menuDismissed (topLevelIndex, returnValue);
}
Desktop::getInstance().removeGlobalMouseListener (this);
private:
Component::SafePointer<MenuBarComponent> bar;
const int topLevelIndex;
inModalState = false;
exitModalState (0);
AsyncCallback (const AsyncCallback&);
AsyncCallback& operator= (const AsyncCallback&);
};
if (prevFocused != 0)
prevFocused->grabKeyboardFocus();
void MenuBarComponent::showMenu (int index)
{
if (index != currentPopupIndex)
{
PopupMenu::dismissAllActiveMenus();
menuBarItemsChanged (0);
const Point<int> mousePos (getMouseXYRelative());
updateItemUnderMouse (mousePos.getX(), mousePos.getY());
repaint();
setOpenItem (index);
setItemUnderMouse (index);
if (result != 0)
if (index >= 0)
{
if (managerOfChosenCommand != 0)
{
ApplicationCommandTarget::InvocationInfo info (result);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu;
PopupMenu m (model->getMenuForIndex (itemUnderMouse,
menuNames [itemUnderMouse]));
if (m.lookAndFeel == 0)
m.setLookAndFeel (&getLookAndFeel());
managerOfChosenCommand->invoke (info, true);
}
const Rectangle<int> itemPos (xPositions [index], 0, xPositions [index + 1] - xPositions [index], getHeight());
postCommandMessage (result);
m.showMenu (itemPos + getScreenPosition(),
0, itemPos.getWidth(), 0, 0, true, this,
new AsyncCallback (this, index));
}
}
}
void MenuBarComponent::menuDismissed (int topLevelIndex, int itemId)
{
topLevelIndexClicked = topLevelIndex;
postCommandMessage (itemId);
}
void MenuBarComponent::handleCommandMessage (int commandId)
{
if (model != 0)
const Point<int> mousePos (getMouseXYRelative());
updateItemUnderMouse (mousePos.getX(), mousePos.getY());
if (! isCurrentlyBlockedByAnotherModalComponent())
setOpenItem (-1);
if (commandId != 0 && model != 0)
model->menuItemSelected (commandId, topLevelIndexClicked);
}
@@ -327,7 +271,6 @@ void MenuBarComponent::mouseDown (const MouseEvent& e)
void MenuBarComponent::mouseDrag (const MouseEvent& e)
{
const MouseEvent e2 (e.getEventRelativeTo (this));
const int item = getItemAt (e2.x, e2.y);
if (item >= 0)
@@ -340,8 +283,11 @@ void MenuBarComponent::mouseUp (const MouseEvent& e)
updateItemUnderMouse (e2.x, e2.y);
if (itemUnderMouse < 0 && dynamic_cast <DummyMenuComponent*> (static_cast <Component*> (currentPopup)) != 0)
hideCurrentMenu();
if (itemUnderMouse < 0 && getLocalBounds().contains (e2.x, e2.y))
{
setOpenItem (-1);
PopupMenu::dismissAllActiveMenus();
}
}
void MenuBarComponent::mouseMove (const MouseEvent& e)
@@ -387,11 +333,6 @@ bool MenuBarComponent::keyPressed (const KeyPress& key)
return used;
}
void MenuBarComponent::inputAttemptWhenModal()
{
hideCurrentMenu();
}
void MenuBarComponent::menuBarItemsChanged (MenuBarModel* /*menuBarModel*/)
{
StringArray newNames;
@@ -410,8 +351,7 @@ void MenuBarComponent::menuBarItemsChanged (MenuBarModel* /*menuBarModel*/)
void MenuBarComponent::menuCommandInvoked (MenuBarModel* /*menuBarModel*/,
const ApplicationCommandTarget::InvocationInfo& info)
{
if (model == 0
|| (info.commandFlags & ApplicationCommandInfo::dontTriggerVisualFeedback) != 0)
if (model == 0 || (info.commandFlags & ApplicationCommandInfo::dontTriggerVisualFeedback) != 0)
return;
for (int i = 0; i < menuNames.size(); ++i)
@@ -420,10 +360,8 @@ void MenuBarComponent::menuCommandInvoked (MenuBarModel* /*menuBarModel*/,
if (menu.containsCommandItem (info.commandID))
{
itemUnderMouse = i;
repaintMenuItem (i);
setItemUnderMouse (i);
startTimer (200);
break;
}
}


+ 10
- 6
src/gui/components/menus/juce_MenuBarComponent.h View File

@@ -60,6 +60,10 @@ public:
*/
void setModel (MenuBarModel* newModel);
/** Returns the current menu bar model being used.
*/
MenuBarModel* getModel() const throw();
//==============================================================================
/** Pops up one of the menu items.
@@ -86,8 +90,6 @@ public:
/** @internal */
void mouseMove (const MouseEvent& e);
/** @internal */
void inputAttemptWhenModal();
/** @internal */
void handleCommandMessage (int commandId);
/** @internal */
bool keyPressed (const KeyPress& key);
@@ -102,20 +104,22 @@ public:
juce_UseDebuggingNewOperator
private:
class AsyncCallback;
friend class AsyncCallback;
MenuBarModel* model;
StringArray menuNames;
Array <int> xPositions;
int itemUnderMouse, currentPopupIndex, topLevelIndexClicked, indexToShowAgain;
int itemUnderMouse, currentPopupIndex, topLevelIndexClicked;
int lastMouseX, lastMouseY;
bool inModalState;
ScopedPointer <Component> currentPopup;
int getItemAt (int x, int y);
void setItemUnderMouse (int index);
void setOpenItem (int index);
void updateItemUnderMouse (int x, int y);
void hideCurrentMenu();
void timerCallback();
void repaintMenuItem (int index);
void menuDismissed (int topLevelIndex, int itemId);
MenuBarComponent (const MenuBarComponent&);
MenuBarComponent& operator= (const MenuBarComponent&);


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

@@ -309,8 +309,7 @@ public:
static Window* create (const PopupMenu& menu,
const bool dismissOnMouseUp,
Window* const owner_,
const int minX, const int maxX,
const int minY, const int maxY,
const Rectangle<int>& target,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight,
@@ -348,14 +347,14 @@ public:
mw->componentAttachedTo = componentAttachedTo;
mw->componentAttachedToOriginal = componentAttachedTo;
mw->calculateWindowPos (minX, maxX, minY, maxY, alignToRectangle);
mw->calculateWindowPos (target, alignToRectangle);
mw->setTopLeftPosition (mw->windowPos.getX(),
mw->windowPos.getY());
mw->updateYPositions();
if (itemIdThatMustBeVisible != 0)
{
const int y = minY - mw->windowPos.getY();
const int y = target.getY() - mw->windowPos.getY();
mw->ensureItemIsVisible (itemIdThatMustBeVisible,
(((unsigned int) y) < (unsigned int) mw->windowPos.getHeight()) ? y : -1);
}
@@ -804,13 +803,10 @@ private:
}
//==============================================================================
void calculateWindowPos (const int minX, const int maxX,
const int minY, const int maxY,
const bool alignToRectangle)
void calculateWindowPos (const Rectangle<int>& target, const bool alignToRectangle)
{
const Rectangle<int> mon (Desktop::getInstance()
.getMonitorAreaContaining (Point<int> ((minX + maxX) / 2,
(minY + maxY) / 2),
.getMonitorAreaContaining (target.getCentre(),
#if JUCE_MAC
true));
#else
@@ -822,19 +818,19 @@ private:
if (alignToRectangle)
{
x = minX;
x = target.getX();
const int spaceUnder = mon.getHeight() - (maxY - mon.getY());
const int spaceOver = minY - mon.getY();
const int spaceUnder = mon.getHeight() - (target.getBottom() - mon.getY());
const int spaceOver = target.getY() - mon.getY();
if (heightToUse < spaceUnder - 30 || spaceUnder >= spaceOver)
y = maxY;
y = target.getBottom();
else
y = minY - heightToUse;
y = target.getY() - heightToUse;
}
else
{
bool tendTowardsRight = (minX + maxX) / 2 < mon.getCentreX();
bool tendTowardsRight = target.getCentreX() < mon.getCentreX();
if (owner != 0)
{
@@ -843,38 +839,38 @@ private:
const bool ownerGoingRight = (owner->getX() + owner->getWidth() / 2
> owner->owner->getX() + owner->owner->getWidth() / 2);
if (ownerGoingRight && maxX + widthToUse < mon.getRight() - 4)
if (ownerGoingRight && target.getRight() + widthToUse < mon.getRight() - 4)
tendTowardsRight = true;
else if ((! ownerGoingRight) && minX > widthToUse + 4)
else if ((! ownerGoingRight) && target.getX() > widthToUse + 4)
tendTowardsRight = false;
}
else if (maxX + widthToUse < mon.getRight() - 32)
else if (target.getRight() + widthToUse < mon.getRight() - 32)
{
tendTowardsRight = true;
}
}
const int biggestSpace = jmax (mon.getRight() - maxX,
minX - mon.getX()) - 32;
const int biggestSpace = jmax (mon.getRight() - target.getRight(),
target.getX() - mon.getX()) - 32;
if (biggestSpace < widthToUse)
{
layoutMenuItems (biggestSpace + (maxX - minX) / 3, widthToUse, heightToUse);
layoutMenuItems (biggestSpace + target.getWidth() / 3, widthToUse, heightToUse);
if (numColumns > 1)
layoutMenuItems (biggestSpace - 4, widthToUse, heightToUse);
tendTowardsRight = (mon.getRight() - maxX) >= (minX - mon.getX());
tendTowardsRight = (mon.getRight() - target.getRight()) >= (target.getX() - mon.getX());
}
if (tendTowardsRight)
x = jmin (mon.getRight() - widthToUse - 4, maxX);
x = jmin (mon.getRight() - widthToUse - 4, target.getRight());
else
x = jmax (mon.getX() + 4, minX - widthToUse);
x = jmax (mon.getX() + 4, target.getX() - widthToUse);
y = minY;
if ((minY + maxY) / 2 > mon.getCentreY())
y = jmax (mon.getY(), maxY - heightToUse);
y = target.getY();
if (target.getCentreY() > mon.getCentreY())
y = jmax (mon.getY(), target.getBottom() - heightToUse);
}
x = jmax (mon.getX() + 1, jmin (mon.getRight() - (widthToUse + 6), x));
@@ -1107,13 +1103,10 @@ private:
if (childComp->isValidComponent() && childComp->itemInfo.hasActiveSubMenu())
{
const Point<int> topLeft (childComp->relativePositionToGlobal (Point<int>()));
const Point<int> bottomRight (childComp->relativePositionToGlobal (Point<int> (childComp->getWidth(), childComp->getHeight())));
activeSubMenu = Window::create (*(childComp->itemInfo.subMenu),
dismissOnMouseUp,
this,
topLeft.getX(), bottomRight.getX(), topLeft.getY(), bottomRight.getY(),
childComp->getScreenBounds(),
0, maximumNumColumns,
standardItemHeight,
false, 0, menuBarComponent,
@@ -1494,7 +1487,7 @@ void PopupMenu::addSectionHeader (const String& title)
}
//==============================================================================
Component* PopupMenu::createMenuComponent (const int x, const int y, const int w, const int h,
Component* PopupMenu::createMenuComponent (const Rectangle<int>& target,
const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
@@ -1504,20 +1497,10 @@ Component* PopupMenu::createMenuComponent (const int x, const int y, const int w
ApplicationCommandManager** managerOfChosenCommand,
Component* const componentAttachedTo)
{
Window* const pw
= Window::create (*this,
ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(),
0,
x, x + w,
y, y + h,
minimumWidth,
maximumNumColumns,
standardItemHeight,
alignToRectangle,
itemIdThatMustBeVisible,
menuBarComponent,
managerOfChosenCommand,
componentAttachedTo);
Window* const pw = Window::create (*this, ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(),
0, target, minimumWidth, maximumNumColumns, standardItemHeight,
alignToRectangle, itemIdThatMustBeVisible, menuBarComponent,
managerOfChosenCommand, componentAttachedTo);
if (pw != 0)
pw->setVisible (true);
@@ -1525,56 +1508,87 @@ Component* PopupMenu::createMenuComponent (const int x, const int y, const int w
return pw;
}
int PopupMenu::showMenu (const int x, const int y, const int w, const int h,
// This invokes any command manager commands and deletes the menu window when it is dismissed
class PopupMenuCompletionCallback : public ModalComponentManager::Callback
{
public:
PopupMenuCompletionCallback()
: managerOfChosenCommand (0)
{
}
~PopupMenuCompletionCallback() {}
void modalStateFinished (int result)
{
if (managerOfChosenCommand != 0 && result != 0)
{
ApplicationCommandTarget::InvocationInfo info (result);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu;
managerOfChosenCommand->invoke (info, true);
}
}
ApplicationCommandManager* managerOfChosenCommand;
ScopedPointer<Component> component;
private:
PopupMenuCompletionCallback (const PopupMenuCompletionCallback&);
PopupMenuCompletionCallback& operator= (const PopupMenuCompletionCallback&);
};
int PopupMenu::showMenu (const Rectangle<int>& target,
const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight,
const bool alignToRectangle,
Component* const componentAttachedTo)
Component* const componentAttachedTo,
ModalComponentManager::Callback* userCallback)
{
ScopedPointer<ModalComponentManager::Callback> userCallbackDeleter (userCallback);
Component::SafePointer<Component> prevFocused (Component::getCurrentlyFocusedComponent());
Component::SafePointer<Component> prevTopLevel ((prevFocused != 0) ? prevFocused->getTopLevelComponent() : 0);
Window::wasHiddenBecauseOfAppChange() = false;
int result = 0;
ApplicationCommandManager* managerOfChosenCommand = 0;
PopupMenuCompletionCallback* callback = new PopupMenuCompletionCallback();
ScopedPointer<PopupMenuCompletionCallback> callbackDeleter (callback);
ScopedPointer <Component> popupComp (createMenuComponent (x, y, w, h,
itemIdThatMustBeVisible,
minimumWidth,
maximumNumColumns > 0 ? maximumNumColumns : 7,
standardItemHeight,
alignToRectangle, 0,
&managerOfChosenCommand,
componentAttachedTo));
callback->component = createMenuComponent (target,
itemIdThatMustBeVisible,
minimumWidth,
maximumNumColumns > 0 ? maximumNumColumns : 7,
standardItemHeight,
alignToRectangle, 0,
&callback->managerOfChosenCommand,
componentAttachedTo);
if (popupComp != 0)
{
popupComp->enterModalState (false);
popupComp->toFront (false); // need to do this after making it modal, or it could
// be stuck behind other comps that are already modal..
if (callback->component == 0)
return 0;
result = popupComp->runModalLoop();
popupComp = 0;
callbackDeleter.release();
if (! Window::wasHiddenBecauseOfAppChange())
{
if (prevTopLevel != 0)
prevTopLevel->toFront (true);
callback->component->enterModalState (false, userCallbackDeleter.release());
callback->component->toFront (false); // need to do this after making it modal, or it could
// be stuck behind other comps that are already modal..
if (prevFocused != 0)
prevFocused->grabKeyboardFocus();
}
}
ModalComponentManager::getInstance()->attachCallback (callback->component, callback);
if (userCallback != 0)
return 0;
const int result = callback->component->runModalLoop();
if (managerOfChosenCommand != 0 && result != 0)
if (! Window::wasHiddenBecauseOfAppChange())
{
ApplicationCommandTarget::InvocationInfo info (result);
info.invocationMethod = ApplicationCommandTarget::InvocationInfo::fromMenu;
if (prevTopLevel != 0)
prevTopLevel->toFront (true);
managerOfChosenCommand->invoke (info, true);
if (prevFocused != 0)
prevFocused->grabKeyboardFocus();
}
return result;
@@ -1583,7 +1597,8 @@ int PopupMenu::showMenu (const int x, const int y, const int w, const int h,
int PopupMenu::show (const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight)
const int standardItemHeight,
ModalComponentManager::Callback* callback)
{
const Point<int> mousePos (Desktop::getMousePosition());
@@ -1591,7 +1606,8 @@ int PopupMenu::show (const int itemIdThatMustBeVisible,
itemIdThatMustBeVisible,
minimumWidth,
maximumNumColumns,
standardItemHeight);
standardItemHeight,
callback);
}
int PopupMenu::showAt (const int screenX,
@@ -1599,39 +1615,39 @@ int PopupMenu::showAt (const int screenX,
const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight)
const int standardItemHeight,
ModalComponentManager::Callback* callback)
{
return showMenu (screenX, screenY, 1, 1,
return showMenu (Rectangle<int> (screenX, screenY, 1, 1),
itemIdThatMustBeVisible,
minimumWidth, maximumNumColumns,
standardItemHeight,
false, 0);
false, 0, callback);
}
int PopupMenu::showAt (Component* componentToAttachTo,
const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight)
const int standardItemHeight,
ModalComponentManager::Callback* callback)
{
if (componentToAttachTo != 0)
{
return showMenu (componentToAttachTo->getScreenX(),
componentToAttachTo->getScreenY(),
componentToAttachTo->getWidth(),
componentToAttachTo->getHeight(),
return showMenu (componentToAttachTo->getScreenBounds(),
itemIdThatMustBeVisible,
minimumWidth,
maximumNumColumns,
standardItemHeight,
true, componentToAttachTo);
true, componentToAttachTo, callback);
}
else
{
return show (itemIdThatMustBeVisible,
minimumWidth,
maximumNumColumns,
standardItemHeight);
standardItemHeight,
callback);
}
}


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

@@ -240,12 +240,19 @@ public:
in zero.
@param standardItemHeight if this is non-zero, it will be used as the standard
height for menu items (apart from custom items)
@param callback if this is non-zero, the menu will be launched asynchronously,
returning immediately, and the callback will receive a
call when the menu is either dismissed or has an item
selected. This object will be owned and deleted by the
system, so make sure that it works safely and that any
pointers that it uses are safely within scope.
@see showAt
*/
int show (int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);
/** Displays the menu at a specific location.
@@ -264,7 +271,8 @@ public:
int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);
/** Displays the menu as if it's attached to a component such as a button.
@@ -276,7 +284,8 @@ public:
int itemIdThatMustBeVisible = 0,
int minimumWidth = 0,
int maximumNumColumns = 0,
int standardItemHeight = 0);
int standardItemHeight = 0,
ModalComponentManager::Callback* callback = 0);
//==============================================================================
/** Closes any menus that are currently open.
@@ -383,6 +392,7 @@ private:
friend class ItemComponent;
friend class Window;
friend class PopupMenuCustomComponent;
friend class MenuBarComponent;
friend class OwnedArray <Item>;
friend class ScopedPointer <Window>;
@@ -392,16 +402,16 @@ private:
void addSeparatorIfPending();
int showMenu (int x, int y, int w, int h,
int showMenu (const Rectangle<int>& target,
int itemIdThatMustBeVisible,
int minimumWidth,
int maximumNumColumns,
int standardItemHeight,
bool alignToRectangle,
Component* componentAttachedTo);
Component* componentAttachedTo,
ModalComponentManager::Callback* callback);
friend class MenuBarComponent;
Component* createMenuComponent (int x, int y, int w, int h,
Component* createMenuComponent (const Rectangle<int>& target,
int itemIdThatMustBeVisible,
int minimumWidth,
int maximumNumColumns,


+ 1
- 1
src/gui/graphics/geometry/juce_Path.cpp View File

@@ -601,7 +601,7 @@ void Path::addArrow (const Line<float>& line, float lineThickness,
startNewSubPath (line.getPointAlongLine (0, lineThickness));
lineTo (line.getPointAlongLine (0, -lineThickness));
lineTo (reversed.getPointAlongLine (0, lineThickness));
lineTo (reversed.getPointAlongLine (arrowheadLength, lineThickness));
lineTo (reversed.getPointAlongLine (arrowheadLength, arrowheadWidth));
lineTo (line.getEnd());
lineTo (reversed.getPointAlongLine (arrowheadLength, -arrowheadWidth));


+ 3
- 0
src/juce_app_includes.h View File

@@ -404,6 +404,9 @@
#ifndef __JUCE_DESKTOP_JUCEHEADER__
#include "gui/components/juce_Desktop.h"
#endif
#ifndef __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__
#include "gui/components/juce_ModalComponentManager.h"
#endif
#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__
#include "gui/components/keyboard/juce_KeyboardFocusTraverser.h"
#endif


Loading…
Cancel
Save