diff --git a/extras/Demo/Builds/Android/jni/Android.mk b/extras/Demo/Builds/Android/jni/Android.mk
index bf2e9e7176..4677c306d3 100644
--- a/extras/Demo/Builds/Android/jni/Android.mk
+++ b/extras/Demo/Builds/Android/jni/Android.mk
@@ -30,6 +30,7 @@ LOCAL_SRC_FILES := \
../../../Source/Demos/JavaScript.cpp\
../../../Source/Demos/KeyMappingsDemo.cpp\
../../../Source/Demos/LiveConstantDemo.cpp\
+ ../../../Source/Demos/LookAndFeelDemo.cpp\
../../../Source/Demos/MDIDemo.cpp\
../../../Source/Demos/MidiDemo.cpp\
../../../Source/Demos/MultithreadingDemo.cpp\
diff --git a/extras/Demo/Builds/Linux/Makefile b/extras/Demo/Builds/Linux/Makefile
index 0be879a43a..ab2b8f594a 100644
--- a/extras/Demo/Builds/Linux/Makefile
+++ b/extras/Demo/Builds/Linux/Makefile
@@ -73,6 +73,7 @@ OBJECTS := \
$(OBJDIR)/JavaScript_d6e42eb5.o \
$(OBJDIR)/KeyMappingsDemo_cf05c709.o \
$(OBJDIR)/LiveConstantDemo_e3b18a9b.o \
+ $(OBJDIR)/LookAndFeelDemo_25c558a3.o \
$(OBJDIR)/MDIDemo_c476c2d7.o \
$(OBJDIR)/MidiDemo_75ebc30c.o \
$(OBJDIR)/MultithreadingDemo_ff566eaa.o \
@@ -234,6 +235,11 @@ $(OBJDIR)/LiveConstantDemo_e3b18a9b.o: ../../Source/Demos/LiveConstantDemo.cpp
@echo "Compiling LiveConstantDemo.cpp"
@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+$(OBJDIR)/LookAndFeelDemo_25c558a3.o: ../../Source/Demos/LookAndFeelDemo.cpp
+ -@mkdir -p $(OBJDIR)
+ @echo "Compiling LookAndFeelDemo.cpp"
+ @$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
$(OBJDIR)/MDIDemo_c476c2d7.o: ../../Source/Demos/MDIDemo.cpp
-@mkdir -p $(OBJDIR)
@echo "Compiling MDIDemo.cpp"
diff --git a/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj b/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
index dd64b9ace6..9fc0f30704 100644
--- a/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
+++ b/extras/Demo/Builds/MacOSX/JuceDemo.xcodeproj/project.pbxproj
@@ -43,6 +43,7 @@
B810E94ECBCA231F60EBEA5F = {isa = PBXBuildFile; fileRef = CCEC8F9385AE939B24D27954; };
15B2A7314D1E347D65EC664D = {isa = PBXBuildFile; fileRef = F1E995A1E00C6545A4C3297B; };
7F933AA1FB06796E6D67C6E2 = {isa = PBXBuildFile; fileRef = 92D3CD3845968E4FAB93576D; };
+ 251D94E4E171A4A2B67104E6 = {isa = PBXBuildFile; fileRef = DEE5EFE8148FD2DC743A7DD7; };
52B925A3C2C3D9B8CB7E42C0 = {isa = PBXBuildFile; fileRef = 52E4BE1BCD56D3676C84BEB0; };
B65EF8DC596033D841E653C4 = {isa = PBXBuildFile; fileRef = 28CB3F1A8BFCE1F01FD630A6; };
B402A461C4EE2203251F9BF1 = {isa = PBXBuildFile; fileRef = 9F75FFB61C74FEECE61A7138; };
@@ -893,6 +894,7 @@
DB8FAF091C9E78AE5F64701F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Timer.cpp"; path = "../../../../modules/juce_events/timers/juce_Timer.cpp"; sourceTree = "SOURCE_ROOT"; };
DC0AE99EFE4F88987CA2F705 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SubregionStream.cpp"; path = "../../../../modules/juce_core/streams/juce_SubregionStream.cpp"; sourceTree = "SOURCE_ROOT"; };
DC6930EE56EEA5221CFECAB7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioFormatManager.h"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatManager.h"; sourceTree = "SOURCE_ROOT"; };
+ DD24BAA1E8104B6D3554A222 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMLandJSONDemo.cpp; path = ../../Source/Demos/XMLandJSONDemo.cpp; sourceTree = "SOURCE_ROOT"; };
DD4A812225F47E590FCF2E29 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Logger.cpp"; path = "../../../../modules/juce_core/logging/juce_Logger.cpp"; sourceTree = "SOURCE_ROOT"; };
DD5F4BFEA497212883A869A9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Windowing.cpp"; path = "../../../../modules/juce_gui_basics/native/juce_android_Windowing.cpp"; sourceTree = "SOURCE_ROOT"; };
DDDB707A59DB489D195BF99D = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioTransportSource.cpp"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioTransportSource.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -924,23 +926,23 @@
E4BD5632ADD38CF8BAD38A76 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_CallOutBox.cpp"; path = "../../../../modules/juce_gui_basics/windows/juce_CallOutBox.cpp"; sourceTree = "SOURCE_ROOT"; };
E5058DD199CEC42ECE922239 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Justification.h"; path = "../../../../modules/juce_graphics/placement/juce_Justification.h"; sourceTree = "SOURCE_ROOT"; };
E52756E1DB553ED02D829F61 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_cryptography/juce_module_info"; sourceTree = "SOURCE_ROOT"; };
- E5E02A3C4E942105FEDCA885 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChannelRemappingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
E6333272C33612B6A7D6073E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_AudioCDBurner.cpp"; path = "../../../../modules/juce_audio_devices/native/juce_win32_AudioCDBurner.cpp"; sourceTree = "SOURCE_ROOT"; };
+ E682A3A52BD15D5CA4933C12 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeParallelogram.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h"; sourceTree = "SOURCE_ROOT"; };
E6E0ADA4E3632540A8ADC7D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ConnectedChildProcess.cpp"; path = "../../../../modules/juce_events/interprocess/juce_ConnectedChildProcess.cpp"; sourceTree = "SOURCE_ROOT"; };
E6E0FE3CBDBE2554B527CF60 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSourcePlayer.cpp"; path = "../../../../modules/juce_audio_devices/sources/juce_AudioSourcePlayer.cpp"; sourceTree = "SOURCE_ROOT"; };
E70A283A87989F5A1CEDE6A4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ResamplingAudioSource.cpp"; path = "../../../../modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp"; sourceTree = "SOURCE_ROOT"; };
E7113B21A18CD89165BAFD4B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_android_Messaging.cpp"; path = "../../../../modules/juce_events/native/juce_android_Messaging.cpp"; sourceTree = "SOURCE_ROOT"; };
- E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E7EA99CD84E1EC598F4984DD = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Array.h"; path = "../../../../modules/juce_core/containers/juce_Array.h"; sourceTree = "SOURCE_ROOT"; };
+ E7EE6BDC0E3A0739529AED91 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSubsectionReader.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"; sourceTree = "SOURCE_ROOT"; };
E80CA3836329ED0EEC74BAE6 = {isa = PBXFileReference; lastKnownFileType = file.nib; name = RecentFilesMenuTemplate.nib; path = RecentFilesMenuTemplate.nib; sourceTree = "SOURCE_ROOT"; };
E8B785D8DD9C49BC7FF5EA75 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_OpenGL_linux.h"; path = "../../../../modules/juce_opengl/native/juce_OpenGL_linux.h"; sourceTree = "SOURCE_ROOT"; };
EA7D346CAE6A07C0B395816B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../../../modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; };
EACCBFA17F4D07ECE058EEBB = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
229D2DAADACF15540C3BBD15 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JuceDemo.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
- DD24BAA1E8104B6D3554A222 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = XMLandJSONDemo.cpp; path = ../../Source/Demos/XMLandJSONDemo.cpp; sourceTree = "SOURCE_ROOT"; };
- E682A3A52BD15D5CA4933C12 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RelativeParallelogram.h"; path = "../../../../modules/juce_gui_basics/positioning/juce_RelativeParallelogram.h"; sourceTree = "SOURCE_ROOT"; };
+ DEE5EFE8148FD2DC743A7DD7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LookAndFeelDemo.cpp; path = ../../Source/Demos/LookAndFeelDemo.cpp; sourceTree = "SOURCE_ROOT"; };
+ E5E02A3C4E942105FEDCA885 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ChannelRemappingAudioSource.h"; path = "../../../../modules/juce_audio_basics/sources/juce_ChannelRemappingAudioSource.h"; sourceTree = "SOURCE_ROOT"; };
+ E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E7B21011F93915ADD2CC5DD9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_GlyphArrangement.cpp"; path = "../../../../modules/juce_graphics/fonts/juce_GlyphArrangement.cpp"; sourceTree = "SOURCE_ROOT"; };
- E7EE6BDC0E3A0739529AED91 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioSubsectionReader.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioSubsectionReader.cpp"; sourceTree = "SOURCE_ROOT"; };
E8128A35828C860977FEC54C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatWriter.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
E98EA1189613978EA4E78D85 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentListener.h"; path = "../../../../modules/juce_gui_basics/components/juce_ComponentListener.h"; sourceTree = "SOURCE_ROOT"; };
E9A3E96E32C301EE817059C1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -1038,6 +1040,7 @@
CCEC8F9385AE939B24D27954,
F1E995A1E00C6545A4C3297B,
92D3CD3845968E4FAB93576D,
+ DEE5EFE8148FD2DC743A7DD7,
52E4BE1BCD56D3676C84BEB0,
28CB3F1A8BFCE1F01FD630A6,
9F75FFB61C74FEECE61A7138,
@@ -2285,6 +2288,7 @@
B810E94ECBCA231F60EBEA5F,
15B2A7314D1E347D65EC664D,
7F933AA1FB06796E6D67C6E2,
+ 251D94E4E171A4A2B67104E6,
52B925A3C2C3D9B8CB7E42C0,
B65EF8DC596033D841E653C4,
B402A461C4EE2203251F9BF1,
diff --git a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
index d41753724a..2bdf20f6bf 100644
--- a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj
@@ -147,6 +147,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
index 836736c893..7151b7541f 100644
--- a/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2010/JuceDemo.vcxproj.filters
@@ -385,6 +385,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
index 29704ad07e..37734d83e0 100644
--- a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj
@@ -153,6 +153,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
index 836736c893..7151b7541f 100644
--- a/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2012/JuceDemo.vcxproj.filters
@@ -385,6 +385,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
index 1683e1352e..d2885eac7d 100644
--- a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
+++ b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj
@@ -153,6 +153,7 @@
+
diff --git a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
index 38b296356f..44d7b549dd 100644
--- a/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
+++ b/extras/Demo/Builds/VisualStudio2013/JuceDemo.vcxproj.filters
@@ -385,6 +385,9 @@
JuceDemo\Source\Demos
+
+ JuceDemo\Source\Demos
+
JuceDemo\Source\Demos
diff --git a/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj b/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
index 40cd5f7211..ea1940489b 100644
--- a/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
+++ b/extras/Demo/Builds/iOS/JuceDemo.xcodeproj/project.pbxproj
@@ -38,6 +38,7 @@
B810E94ECBCA231F60EBEA5F = {isa = PBXBuildFile; fileRef = CCEC8F9385AE939B24D27954; };
15B2A7314D1E347D65EC664D = {isa = PBXBuildFile; fileRef = F1E995A1E00C6545A4C3297B; };
7F933AA1FB06796E6D67C6E2 = {isa = PBXBuildFile; fileRef = 92D3CD3845968E4FAB93576D; };
+ 251D94E4E171A4A2B67104E6 = {isa = PBXBuildFile; fileRef = DEE5EFE8148FD2DC743A7DD7; };
52B925A3C2C3D9B8CB7E42C0 = {isa = PBXBuildFile; fileRef = 52E4BE1BCD56D3676C84BEB0; };
B65EF8DC596033D841E653C4 = {isa = PBXBuildFile; fileRef = 28CB3F1A8BFCE1F01FD630A6; };
B402A461C4EE2203251F9BF1 = {isa = PBXBuildFile; fileRef = 9F75FFB61C74FEECE61A7138; };
@@ -890,6 +891,7 @@
DE3BEA732CBC57AE71E94159 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ContainerDeletePolicy.h"; path = "../../../../modules/juce_core/memory/juce_ContainerDeletePolicy.h"; sourceTree = "SOURCE_ROOT"; };
DE534A5A2D3B48BFBCE598B4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Fonts.cpp"; path = "../../../../modules/juce_graphics/native/juce_linux_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; };
DEB0E2F28130100B1EFD250E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_ios_Windowing.mm"; path = "../../../../modules/juce_gui_basics/native/juce_ios_Windowing.mm"; sourceTree = "SOURCE_ROOT"; };
+ DEE5EFE8148FD2DC743A7DD7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = LookAndFeelDemo.cpp; path = ../../Source/Demos/LookAndFeelDemo.cpp; sourceTree = "SOURCE_ROOT"; };
DEFD6AD8B2BBA57017DB4A13 = {isa = PBXFileReference; lastKnownFileType = file; name = "juce_module_info"; path = "../../../../modules/juce_box2d/juce_module_info"; sourceTree = "SOURCE_ROOT"; };
DF9B26660FAF5ECF2EF620B8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MemoryBlock.h"; path = "../../../../modules/juce_core/memory/juce_MemoryBlock.h"; sourceTree = "SOURCE_ROOT"; };
E04EC9F05219CEEB4469A437 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MidiOutput.h"; path = "../../../../modules/juce_audio_devices/midi_io/juce_MidiOutput.h"; sourceTree = "SOURCE_ROOT"; };
@@ -929,10 +931,13 @@
E9A3E96E32C301EE817059C1 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_SliderPropertyComponent.cpp"; path = "../../../../modules/juce_gui_basics/properties/juce_SliderPropertyComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E9BBEE1B3986E0829AA44133 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ImagePreviewComponent.h"; path = "../../../../modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.h"; sourceTree = "SOURCE_ROOT"; };
EA082125C757D1FD63BA38C5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentAnimator.h"; path = "../../../../modules/juce_gui_basics/layout/juce_ComponentAnimator.h"; sourceTree = "SOURCE_ROOT"; };
+ EA3436079F0D78BB76CD15F7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseInactivityDetector.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h"; sourceTree = "SOURCE_ROOT"; };
+ EA9FE6D1E0A072E73312916C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentDragger.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_ComponentDragger.h"; sourceTree = "SOURCE_ROOT"; };
EACCBFA17F4D07ECE058EEBB = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMIDI.framework; path = System/Library/Frameworks/CoreMIDI.framework; sourceTree = SDKROOT; };
+ EB369EA30D31CD710A09B7FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_ios_MessageManager.mm"; path = "../../../../modules/juce_events/native/juce_ios_MessageManager.mm"; sourceTree = "SOURCE_ROOT"; };
EB6F5F8F57F0117C10735583 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioIODevice.h"; path = "../../../../modules/juce_audio_devices/audio_io/juce_AudioIODevice.h"; sourceTree = "SOURCE_ROOT"; };
- ED3DE86815324354C48631D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_XMLCodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
- ED6224ABC715AAB68661F4D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_box2d.cpp"; path = "../../../../modules/juce_box2d/juce_box2d.cpp"; sourceTree = "SOURCE_ROOT"; };
+ EC8A992EA9CFA558DB9F950E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharacterFunctions.h"; path = "../../../../modules/juce_core/text/juce_CharacterFunctions.h"; sourceTree = "SOURCE_ROOT"; };
+ ECAB8BD2816B0BEFCD9F6961 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AsyncUpdater.h"; path = "../../../../modules/juce_events/broadcasters/juce_AsyncUpdater.h"; sourceTree = "SOURCE_ROOT"; };
F1E995A1E00C6545A4C3297B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = KeyMappingsDemo.cpp; path = ../../Source/Demos/KeyMappingsDemo.cpp; sourceTree = "SOURCE_ROOT"; };
FBCD860CD7113A3136B127C8 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
229D2DAADACF15540C3BBD15 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JuceDemo.app; sourceTree = "BUILT_PRODUCTS_DIR"; };
@@ -940,12 +945,9 @@
E7A5AF3EBCFEEF8787F2D14F = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_MidiKeyboardComponent.cpp"; path = "../../../../modules/juce_audio_utils/gui/juce_MidiKeyboardComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
E8128A35828C860977FEC54C = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioFormatWriter.cpp"; path = "../../../../modules/juce_audio_formats/format/juce_AudioFormatWriter.cpp"; sourceTree = "SOURCE_ROOT"; };
E9B8B3FAECC80B66257B14F9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BlowFish.h"; path = "../../../../modules/juce_cryptography/encryption/juce_BlowFish.h"; sourceTree = "SOURCE_ROOT"; };
- EA3436079F0D78BB76CD15F7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_MouseInactivityDetector.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h"; sourceTree = "SOURCE_ROOT"; };
EA7D346CAE6A07C0B395816B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Decibels.h"; path = "../../../../modules/juce_audio_basics/effects/juce_Decibels.h"; sourceTree = "SOURCE_ROOT"; };
- EA9FE6D1E0A072E73312916C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ComponentDragger.h"; path = "../../../../modules/juce_gui_basics/mouse/juce_ComponentDragger.h"; sourceTree = "SOURCE_ROOT"; };
- EB369EA30D31CD710A09B7FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_ios_MessageManager.mm"; path = "../../../../modules/juce_events/native/juce_ios_MessageManager.mm"; sourceTree = "SOURCE_ROOT"; };
- EC8A992EA9CFA558DB9F950E = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_CharacterFunctions.h"; path = "../../../../modules/juce_core/text/juce_CharacterFunctions.h"; sourceTree = "SOURCE_ROOT"; };
- ECAB8BD2816B0BEFCD9F6961 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AsyncUpdater.h"; path = "../../../../modules/juce_events/broadcasters/juce_AsyncUpdater.h"; sourceTree = "SOURCE_ROOT"; };
+ ED3DE86815324354C48631D0 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_XMLCodeTokeniser.h"; path = "../../../../modules/juce_gui_extra/code_editor/juce_XMLCodeTokeniser.h"; sourceTree = "SOURCE_ROOT"; };
+ ED6224ABC715AAB68661F4D4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_box2d.cpp"; path = "../../../../modules/juce_box2d/juce_box2d.cpp"; sourceTree = "SOURCE_ROOT"; };
ED80E9909586DD64BDE03A70 = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = portmeirion.jpg; path = ../../Resources/portmeirion.jpg; sourceTree = "SOURCE_ROOT"; };
EE7001BD5206A8D8EA2D125B = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_RectangleList.h"; path = "../../../../modules/juce_graphics/geometry/juce_RectangleList.h"; sourceTree = "SOURCE_ROOT"; };
EEA020419EF58E90C10AAE26 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_ResizableWindow.h"; path = "../../../../modules/juce_gui_basics/windows/juce_ResizableWindow.h"; sourceTree = "SOURCE_ROOT"; };
@@ -1028,6 +1030,7 @@
CCEC8F9385AE939B24D27954,
F1E995A1E00C6545A4C3297B,
92D3CD3845968E4FAB93576D,
+ DEE5EFE8148FD2DC743A7DD7,
52E4BE1BCD56D3676C84BEB0,
28CB3F1A8BFCE1F01FD630A6,
9F75FFB61C74FEECE61A7138,
@@ -2267,6 +2270,7 @@
B810E94ECBCA231F60EBEA5F,
15B2A7314D1E347D65EC664D,
7F933AA1FB06796E6D67C6E2,
+ 251D94E4E171A4A2B67104E6,
52B925A3C2C3D9B8CB7E42C0,
B65EF8DC596033D841E653C4,
B402A461C4EE2203251F9BF1,
diff --git a/extras/Demo/JuceDemo.jucer b/extras/Demo/JuceDemo.jucer
index c15855472f..438000723d 100644
--- a/extras/Demo/JuceDemo.jucer
+++ b/extras/Demo/JuceDemo.jucer
@@ -242,6 +242,8 @@
file="Source/Demos/KeyMappingsDemo.cpp"/>
+
a (x, y, diameter, diameter);
+ const float halfThickness = outlineThickness * 0.5f;
+
+ Path p;
+ p.addEllipse (x + halfThickness, y + halfThickness, diameter - outlineThickness, diameter - outlineThickness);
+
+ const DropShadow ds (Colours::black, 1, Point (0, 0));
+ ds.drawForPath (g, p);
+
+ g.setColour (colour);
+ g.fillPath (p);
+
+ g.setColour (colour.brighter());
+ g.strokePath (p, PathStrokeType (outlineThickness));
+ }
+
+ void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
+ bool isMouseOverButton, bool isButtonDown) override
+ {
+ Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
+
+ if (isButtonDown || isMouseOverButton)
+ baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f);
+
+ const bool flatOnLeft = button.isConnectedOnLeft();
+ const bool flatOnRight = button.isConnectedOnRight();
+ const bool flatOnTop = button.isConnectedOnTop();
+ const bool flatOnBottom = button.isConnectedOnBottom();
+
+ const float width = button.getWidth() - 1.0f;
+ const float height = button.getHeight() - 1.0f;
+
+ if (width > 0 && height > 0)
+ {
+ const float cornerSize = jmin (15.0f, jmin (width, height) * 0.45f);
+ const float lineThickness = cornerSize * 0.1f;
+ const float halfThickness = lineThickness * 0.5f;
+
+ Path outline;
+ outline.addRoundedRectangle (0.5f + halfThickness, 0.5f + halfThickness, width - lineThickness, height - lineThickness,
+ cornerSize, cornerSize,
+ ! (flatOnLeft || flatOnTop),
+ ! (flatOnRight || flatOnTop),
+ ! (flatOnLeft || flatOnBottom),
+ ! (flatOnRight || flatOnBottom));
+
+ const Colour outlineColour (button.findColour (button.getToggleState() ? TextButton::textColourOnId
+ : TextButton::textColourOffId));
+
+ g.setColour (baseColour);
+ g.fillPath (outline);
+
+ if (! button.getToggleState())
+ {
+ g.setColour (outlineColour);
+ g.strokePath (outline, PathStrokeType (lineThickness));
+ }
+ }
+ }
+
+ void drawTickBox (Graphics& g, Component& component,
+ float x, float y, float w, float h,
+ bool ticked,
+ bool isEnabled,
+ bool isMouseOverButton,
+ bool isButtonDown) override
+ {
+ const float boxSize = w * 0.7f;
+
+ bool isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown());
+ const Colour colour (component.findColour (TextButton::buttonColourId).withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f));
+
+ drawRoundThumb (g, x, y + (h - boxSize) * 0.5f, boxSize, colour,
+ isEnabled ? ((isButtonDown || isMouseOverButton) ? 1.1f : 0.5f) : 0.3f);
+
+ if (ticked)
+ {
+ const Path tick (LookAndFeel_V2::getTickShape (6.0f));
+ g.setColour (isEnabled ? findColour (TextButton::buttonOnColourId) : Colours::grey);
+
+ const float scale = 9.0f;
+ const AffineTransform trans (AffineTransform::scale (w / scale, h / scale)
+ .translated (x - 2.5f, y + 1.0f));
+ g.fillPath (tick, trans);
+ }
+ }
+
+ void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height,
+ float sliderPos, float minSliderPos, float maxSliderPos,
+ const Slider::SliderStyle style, Slider& slider) override
+ {
+ const float sliderRadius = (float) (getSliderThumbRadius (slider) - 2);
+
+ bool isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown());
+ Colour knobColour (slider.findColour (Slider::thumbColourId).withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f));
+
+ if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
+ {
+ float kx, ky;
+
+ if (style == Slider::LinearVertical)
+ {
+ kx = x + width * 0.5f;
+ ky = sliderPos;
+ }
+ else
+ {
+ kx = sliderPos;
+ ky = y + height * 0.5f;
+ }
+
+ const float outlineThickness = slider.isEnabled() ? 0.8f : 0.3f;
+
+ drawRoundThumb (g,
+ kx - sliderRadius,
+ ky - sliderRadius,
+ sliderRadius * 2.0f,
+ knobColour, outlineThickness);
+ }
+ else
+ {
+ // Just call the base class for the demo
+ LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
+ }
+ }
+
+ void drawLinearSlider (Graphics& g, int x, int y, int width, int height,
+ float sliderPos, float minSliderPos, float maxSliderPos,
+ const Slider::SliderStyle style, Slider& slider) override
+ {
+ g.fillAll (slider.findColour (Slider::backgroundColourId));
+
+ if (style == Slider::LinearBar || style == Slider::LinearBarVertical)
+ {
+ const float fx = (float) x, fy = (float) y, fw = (float) width, fh = (float) height;
+
+ Path p;
+
+ if (style == Slider::LinearBarVertical)
+ p.addRectangle (fx, sliderPos, fw, 1.0f + fh - sliderPos);
+ else
+ p.addRectangle (fx, fy, sliderPos - fx, fh);
+
+
+ Colour baseColour (slider.findColour (Slider::rotarySliderFillColourId)
+ .withMultipliedSaturation (slider.isEnabled() ? 1.0f : 0.5f)
+ .withMultipliedAlpha (0.8f));
+
+ g.setColour (baseColour);
+ g.fillPath (p);
+
+ const float lineThickness = jmin (15.0f, jmin (width, height) * 0.45f) * 0.1f;
+ g.drawRect (slider.getLocalBounds().toFloat(), lineThickness);
+ }
+ else
+ {
+ drawLinearSliderBackground (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
+ drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
+ }
+ }
+
+ void drawLinearSliderBackground (Graphics& g, int x, int y, int width, int height,
+ float /*sliderPos*/,
+ float /*minSliderPos*/,
+ float /*maxSliderPos*/,
+ const Slider::SliderStyle /*style*/, Slider& slider) override
+ {
+ const float sliderRadius = getSliderThumbRadius (slider) - 5.0f;
+ Path on, off;
+
+ if (slider.isHorizontal())
+ {
+ const float iy = x + width * 0.5f - sliderRadius * 0.5f;
+ Rectangle r (x - sliderRadius * 0.5f, iy, width + sliderRadius, sliderRadius);
+ const float onW = r.getWidth() * ((float) slider.valueToProportionOfLength (slider.getValue()));
+
+ on.addRectangle (r.removeFromLeft (onW));
+ off.addRectangle (r);
+ }
+ else
+ {
+ const float ix = x + width * 0.5f - sliderRadius * 0.5f;
+ Rectangle r (ix, y - sliderRadius * 0.5f, sliderRadius, height + sliderRadius);
+ const float onH = r.getHeight() * ((float) slider.valueToProportionOfLength (slider.getValue()));
+
+ on.addRectangle (r.removeFromBottom (onH));
+ off.addRectangle (r);
+ }
+
+ g.setColour (slider.findColour (Slider::rotarySliderFillColourId));
+ g.fillPath (on);
+
+ g.setColour (slider.findColour (Slider::trackColourId));
+ g.fillPath (off);
+ }
+
+ void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
+ float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override
+ {
+ const float radius = jmin (width / 2, height / 2) - 2.0f;
+ const float centreX = x + width * 0.5f;
+ const float centreY = y + height * 0.5f;
+ const float rx = centreX - radius;
+ const float ry = centreY - radius;
+ const float rw = radius * 2.0f;
+ const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
+ const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
+
+ if (slider.isEnabled())
+ g.setColour (slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 1.0f : 0.7f));
+ else
+ g.setColour (Colour (0x80808080));
+
+ {
+ Path filledArc;
+ filledArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, angle, 0.0);
+ g.fillPath (filledArc);
+ }
+
+ {
+ const float lineThickness = jmin (15.0f, jmin (width, height) * 0.45f) * 0.1f;
+ Path outlineArc;
+ outlineArc.addPieSegment (rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, 0.0);
+ g.strokePath (outlineArc, PathStrokeType (lineThickness));
+ }
+ }
+};
+
+//==============================================================================
+/** Another really simple look and feel that is very flat and square.
+ This inherits from CustomLookAndFeel above for the linear bar and slider backgrounds.
+ */
+struct SquareLookAndFeel : public CustomLookAndFeel
+{
+ void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour,
+ bool isMouseOverButton, bool isButtonDown) override
+ {
+ Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f));
+
+ if (isButtonDown || isMouseOverButton)
+ baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f);
+
+ const float width = button.getWidth() - 1.0f;
+ const float height = button.getHeight() - 1.0f;
+
+ if (width > 0 && height > 0)
+ {
+ g.setGradientFill (ColourGradient (baseColour, 0.0f, 0.0f,
+ baseColour.darker (0.1f), 0.0f, height,
+ false));
+
+ g.fillRect (button.getLocalBounds());
+ }
+ }
+
+ void drawTickBox (Graphics& g, Component& component,
+ float x, float y, float w, float h,
+ bool ticked,
+ bool isEnabled,
+ bool /*isMouseOverButton*/,
+ bool /*isButtonDown*/) override
+ {
+ const float boxSize = w * 0.7f;
+
+ bool isDownOrDragging = component.isEnabled() && (component.isMouseOverOrDragging() || component.isMouseButtonDown());
+ const Colour colour (component.findColour (TextButton::buttonOnColourId).withMultipliedSaturation ((component.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (component.isEnabled() ? 1.0f : 0.7f));
+ g.setColour (colour);
+
+ Rectangle r (x, y + (h - boxSize) * 0.5f, boxSize, boxSize);
+ g.fillRect (r);
+
+ if (ticked)
+ {
+ const Path tick (LookAndFeel_V3::getTickShape (6.0f));
+ g.setColour (isEnabled ? findColour (TextButton::buttonColourId) : Colours::grey);
+
+ const AffineTransform trans (RectanglePlacement (RectanglePlacement::centred)
+ .getTransformToFit (tick.getBounds(), r.reduced (r.getHeight() * 0.05f)));
+ g.fillPath (tick, trans);
+ }
+ }
+
+ void drawLinearSliderThumb (Graphics& g, int x, int y, int width, int height,
+ float sliderPos, float minSliderPos, float maxSliderPos,
+ const Slider::SliderStyle style, Slider& slider) override
+ {
+ const float sliderRadius = (float) getSliderThumbRadius (slider);
+
+ bool isDownOrDragging = slider.isEnabled() && (slider.isMouseOverOrDragging() || slider.isMouseButtonDown());
+ Colour knobColour (slider.findColour (Slider::rotarySliderFillColourId).withMultipliedSaturation ((slider.hasKeyboardFocus (false) || isDownOrDragging) ? 1.3f : 0.9f)
+ .withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.7f));
+ g.setColour (knobColour);
+
+ if (style == Slider::LinearHorizontal || style == Slider::LinearVertical)
+ {
+ float kx, ky;
+
+ if (style == Slider::LinearVertical)
+ {
+ kx = x + width * 0.5f;
+ ky = sliderPos;
+ g.fillRect (Rectangle (kx - sliderRadius, ky - 2.5f, sliderRadius * 2.0f, 5.0f));
+ }
+ else
+ {
+ kx = sliderPos;
+ ky = y + height * 0.5f;
+ g.fillRect (Rectangle (kx - 2.5f, ky - sliderRadius, 5.0f, sliderRadius * 2.0f));
+ }
+ }
+ else
+ {
+ // Just call the base class for the demo
+ LookAndFeel_V2::drawLinearSliderThumb (g, x, y, width, height, sliderPos, minSliderPos, maxSliderPos, style, slider);
+ }
+ }
+
+ void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
+ float rotaryStartAngle, float rotaryEndAngle, Slider& slider) override
+ {
+ const float diameter = jmin (width, height) - 4.0f;
+ const float radius = (diameter / 2.0f) * std::cos (float_Pi / 4.0f);
+ const float centreX = x + width * 0.5f;
+ const float centreY = y + height * 0.5f;
+ const float rx = centreX - radius;
+ const float ry = centreY - radius;
+ const float rw = radius * 2.0f;
+ const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
+ const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
+
+ const Colour baseColour (slider.isEnabled() ? slider.findColour (Slider::rotarySliderFillColourId).withAlpha (isMouseOver ? 0.8f : 1.0f)
+ : Colour (0x80808080));
+
+ Rectangle r (rx, ry, rw, rw);
+ AffineTransform t (AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY()));
+
+ float x1 = r.getTopLeft().getX(), y1 = r.getTopLeft().getY(), x2 = r.getBottomLeft().getX(), y2 = r.getBottomLeft().getY();
+ t.transformPoints (x1, y1, x2, y2);
+
+ g.setGradientFill (ColourGradient (baseColour, x1, y1,
+ baseColour.darker (0.1f), x2, y2,
+ false));
+
+ Path knob;
+ knob.addRectangle (r);
+ g.fillPath (knob, t);
+
+ Path needle;
+ Rectangle r2 (r * 0.1f);
+ needle.addRectangle (r2.withPosition (Point (r.getCentreX() - (r2.getWidth() / 2.0f), r.getY())));
+
+ g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId));
+ g.fillPath (needle, AffineTransform::rotation (angle, r.getCentreX(), r.getCentreY()));
+ }
+};
+
+//==============================================================================
+struct LookAndFeelDemoComponent : public Component
+{
+ LookAndFeelDemoComponent()
+ {
+ addAndMakeVisible (rotarySlider);
+ rotarySlider.setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
+ rotarySlider.setTextBoxStyle (Slider::NoTextBox, false, 0, 0);
+ rotarySlider.setValue (2.5);
+
+ addAndMakeVisible (verticalSlider);
+ verticalSlider.setSliderStyle (Slider::LinearVertical);
+ verticalSlider.setTextBoxStyle (Slider::NoTextBox, false, 90, 20);
+ verticalSlider.setValue (6.2);
+
+ addAndMakeVisible (barSlider);
+ barSlider.setSliderStyle (Slider::LinearBar);
+ barSlider.setValue (4.5);
+
+ addAndMakeVisible (incDecSlider);
+ incDecSlider.setSliderStyle (Slider::IncDecButtons);
+ incDecSlider.setRange (0.0, 10.0, 1.0);
+ incDecSlider.setIncDecButtonsMode (Slider::incDecButtonsDraggable_Horizontal);
+ incDecSlider.setTextBoxStyle (Slider::TextBoxBelow, false, 90, 20);
+
+ addAndMakeVisible (button1);
+ button1.setButtonText ("Hello World!");
+
+ addAndMakeVisible (button2);
+ button2.setButtonText ("Hello World!");
+ button2.setClickingTogglesState (true);
+ button2.setToggleState (true, dontSendNotification);
+
+ addAndMakeVisible (button3);
+ button3.setButtonText ("Hello World!");
+
+ addAndMakeVisible (button4);
+ button4.setButtonText ("Toggle Me");
+ button4.setToggleState (true, dontSendNotification);
+
+ for (int i = 0; i < 3; ++i)
+ {
+ TextButton* b = radioButtons.add (new TextButton());
+ addAndMakeVisible (b);
+ b->setRadioGroupId (42);
+ b->setClickingTogglesState (true);
+ b->setButtonText ("Button " + String (i + 1));
+
+ switch (i)
+ {
+ case 0: b->setConnectedEdges (Button::ConnectedOnRight); break;
+ case 1: b->setConnectedEdges (Button::ConnectedOnRight + Button::ConnectedOnLeft); break;
+ case 2: b->setConnectedEdges (Button::ConnectedOnLeft); break;
+ default: break;
+ }
+ }
+
+ radioButtons.getUnchecked (2)->setToggleState (true, dontSendNotification);
+ }
+
+ void resized() override
+ {
+ Rectangle area (getLocalBounds().reduced (10));
+ Rectangle row (area.removeFromTop (100));
+
+ rotarySlider.setBounds (row.removeFromLeft (100).reduced (5));
+ verticalSlider.setBounds (row.removeFromLeft (100).reduced (5));
+ barSlider.setBounds (row.removeFromLeft (100).reduced (5, 25));
+ incDecSlider.setBounds (row.removeFromLeft (100).reduced (5, 28));
+
+ row = area.removeFromTop (100);
+ button1.setBounds (row.removeFromLeft (100).reduced (5));
+
+ Rectangle row2 (row.removeFromTop (row.getHeight() / 2).reduced (0, 10));
+ button2.setBounds (row2.removeFromLeft (100).reduced (5, 0));
+ button3.setBounds (row2.removeFromLeft (100).reduced (5, 0));
+ button4.setBounds (row2.removeFromLeft (100).reduced (5, 0));
+
+ row2 = (row.removeFromTop (row2.getHeight() + 20).reduced (5, 10));
+
+ for (int i = 0; i < radioButtons.size(); ++i)
+ radioButtons.getUnchecked (i)->setBounds (row2.removeFromLeft (100));
+ }
+
+ Slider rotarySlider, verticalSlider, barSlider, incDecSlider;
+ TextButton button1, button2, button3;
+ ToggleButton button4;
+ OwnedArray radioButtons;
+};
+
+//==============================================================================
+class LookAndFeelDemo : public Component,
+ private ComboBox::Listener,
+ private Button::Listener
+{
+public:
+ LookAndFeelDemo()
+ {
+ descriptionLabel.setMinimumHorizontalScale (1.0f);
+ descriptionLabel.setText ("This demonstrates how to create a custom look and feel by overriding only the desired methods.\n\n"
+ "Components can have their look and feel individually assigned or they will inherit it from their parent. "
+ "Colours work in a similar way, they can be set for individual components or a look and feel as a whole.",
+ dontSendNotification);
+
+ addAndMakeVisible (descriptionLabel);
+ addAndMakeVisible (lafBox);
+ addAndMakeVisible (demoComp);
+
+ addLookAndFeel (new LookAndFeel_V1(), "LookAndFeel_V1");
+ addLookAndFeel (new LookAndFeel_V2(), "LookAndFeel_V2");
+ addLookAndFeel (new LookAndFeel_V3(), "LookAndFeel_V3");
+
+ CustomLookAndFeel* claf = new CustomLookAndFeel();
+ addLookAndFeel (claf, "Custom Look And Feel");
+ setupCustomLookAndFeelColours (*claf);
+
+ SquareLookAndFeel* slaf = new SquareLookAndFeel();
+ addLookAndFeel (slaf, "Square Look And Feel");
+ setupSquareLookAndFeelColours (*slaf);
+
+ lafBox.addListener (this);
+ lafBox.setSelectedItemIndex (3);
+
+ addAndMakeVisible (randomButton);
+ randomButton.setButtonText ("Assign Randomly");
+ randomButton.addListener (this);
+ }
+
+ void paint (Graphics& g) override
+ {
+ g.fillAll (Colour::greyLevel (0.85f));
+ }
+
+ void resized() override
+ {
+ Rectangle r (getLocalBounds().reduced (10));
+
+ demoComp.setBounds (r);
+
+ descriptionLabel.setBounds (r.removeFromTop (200));
+ lafBox.setBounds (r.removeFromTop (22).removeFromLeft (250));
+ randomButton.setBounds (lafBox.getBounds().withX (lafBox.getRight() + 20).withWidth (140));
+
+ demoComp.setBounds (r.withTrimmedTop (10));
+ }
+
+private:
+ Label descriptionLabel;
+ ComboBox lafBox;
+ TextButton randomButton;
+ OwnedArray lookAndFeels;
+ LookAndFeelDemoComponent demoComp;
+
+ void addLookAndFeel (LookAndFeel* laf, const String& name)
+ {
+ lookAndFeels.add (laf);
+ lafBox.addItem (name, lafBox.getNumItems() + 1);
+ }
+
+ void setupCustomLookAndFeelColours (LookAndFeel& laf)
+ {
+ laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f));
+ laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite);
+ laf.setColour (Slider::rotarySliderFillColourId, Colour (0xff00b5f6));
+ laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white);
+
+ laf.setColour (TextButton::buttonColourId, Colours::white);
+ laf.setColour (TextButton::textColourOffId, Colour (0xff00b5f6));
+
+ laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId));
+ laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId));
+ }
+
+ void setupSquareLookAndFeelColours (LookAndFeel& laf)
+ {
+ const Colour baseColour (Colours::red);
+ laf.setColour (Slider::thumbColourId, Colour::greyLevel (0.95f));
+ laf.setColour (Slider::textBoxOutlineColourId, Colours::transparentWhite);
+ laf.setColour (Slider::rotarySliderFillColourId, baseColour);
+ laf.setColour (Slider::rotarySliderOutlineColourId, Colours::white);
+ laf.setColour (Slider::trackColourId, Colours::black);
+
+ laf.setColour (TextButton::buttonColourId, Colours::white);
+ laf.setColour (TextButton::textColourOffId, baseColour);
+
+ laf.setColour (TextButton::buttonOnColourId, laf.findColour (TextButton::textColourOffId));
+ laf.setColour (TextButton::textColourOnId, laf.findColour (TextButton::buttonColourId));
+ }
+
+ void setAllLookAndFeels (LookAndFeel* laf)
+ {
+ for (int i = 0; i < demoComp.getNumChildComponents(); ++i)
+ if (Component* c = demoComp.getChildComponent (i))
+ c->setLookAndFeel (laf);
+ }
+
+ void comboBoxChanged (ComboBox* comboBoxThatHasChanged) override
+ {
+ if (comboBoxThatHasChanged == &lafBox)
+ setAllLookAndFeels (lookAndFeels[lafBox.getSelectedItemIndex()]);
+ }
+
+ void buttonClicked (Button* b) override
+ {
+ if (b == &randomButton)
+ lafBox.setSelectedItemIndex (Random::getSystemRandom().nextInt (lafBox.getNumItems()));
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeelDemo);
+};
+
+
+// This static object will register this demo type in a global list of demos..
+static JuceDemoType demo ("10 Components: Look And Feel");