Browse Source

Update juce

tags/2018-04-16
falkTX 7 years ago
parent
commit
af87c602a1
100 changed files with 4669 additions and 931 deletions
  1. +1
    -1
      libs/juce/source/doxygen/Doxyfile
  2. +1
    -1
      libs/juce/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  3. +22
    -23
      libs/juce/source/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h
  4. +34
    -121
      libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  5. +16
    -9
      libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  6. +5
    -0
      libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp
  7. +7
    -1
      libs/juce/source/modules/juce_audio_devices/native/juce_ios_Audio.cpp
  8. +41
    -13
      libs/juce/source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp
  9. +6
    -15
      libs/juce/source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp
  10. +7
    -0
      libs/juce/source/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  11. +23
    -7
      libs/juce/source/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  12. +301
    -141
      libs/juce/source/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm
  13. +1
    -11
      libs/juce/source/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h
  14. +3
    -1
      libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp
  15. +38
    -0
      libs/juce/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  16. +11
    -7
      libs/juce/source/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm
  17. +20
    -7
      libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  18. +3
    -0
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3Headers.h
  19. +64
    -0
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  20. +2
    -2
      libs/juce/source/modules/juce_audio_processors/format_types/juce_VSTCommon.h
  21. +3
    -0
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  22. +26
    -0
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h
  23. +4
    -1
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp
  24. +22
    -0
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h
  25. +22
    -2
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp
  26. +3
    -0
      libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h
  27. +1
    -1
      libs/juce/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h
  28. +2
    -2
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp
  29. +1
    -1
      libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h
  30. +6
    -6
      libs/juce/source/modules/juce_audio_utils/players/juce_SoundPlayer.cpp
  31. +5
    -1
      libs/juce/source/modules/juce_audio_utils/players/juce_SoundPlayer.h
  32. +2
    -2
      libs/juce/source/modules/juce_core/containers/juce_DynamicObject.cpp
  33. +2
    -2
      libs/juce/source/modules/juce_core/containers/juce_DynamicObject.h
  34. +9
    -5
      libs/juce/source/modules/juce_core/containers/juce_HashMap.h
  35. +31
    -42
      libs/juce/source/modules/juce_core/containers/juce_SortedSet.h
  36. +15
    -9
      libs/juce/source/modules/juce_core/javascript/juce_JSON.cpp
  37. +6
    -2
      libs/juce/source/modules/juce_core/javascript/juce_JSON.h
  38. +1
    -1
      libs/juce/source/modules/juce_core/javascript/juce_Javascript.cpp
  39. +7
    -0
      libs/juce/source/modules/juce_core/memory/juce_HeapBlock.h
  40. +971
    -0
      libs/juce/source/modules/juce_core/native/java/IInAppBillingService.java
  41. +38
    -47
      libs/juce/source/modules/juce_core/native/java/JuceAppActivity.java
  42. +86
    -0
      libs/juce/source/modules/juce_core/native/juce_android_Files.cpp
  43. +125
    -28
      libs/juce/source/modules/juce_core/native/juce_android_JNIHelpers.h
  44. +93
    -0
      libs/juce/source/modules/juce_core/native/juce_android_SystemStats.cpp
  45. +5
    -0
      libs/juce/source/modules/juce_core/native/juce_mac_ClangBugWorkaround.h
  46. +5
    -0
      libs/juce/source/modules/juce_core/native/juce_mac_Files.mm
  47. +2
    -0
      libs/juce/source/modules/juce_core/native/juce_mac_Network.mm
  48. +10
    -0
      libs/juce/source/modules/juce_core/native/juce_osx_ObjCHelpers.h
  49. +8
    -14
      libs/juce/source/modules/juce_core/native/juce_posix_SharedCode.h
  50. +13
    -1
      libs/juce/source/modules/juce_core/native/juce_win32_SystemStats.cpp
  51. +18
    -0
      libs/juce/source/modules/juce_core/system/juce_CompilerSupport.h
  52. +5
    -5
      libs/juce/source/modules/juce_core/text/juce_String.cpp
  53. +16
    -8
      libs/juce/source/modules/juce_core/text/juce_String.h
  54. +31
    -2
      libs/juce/source/modules/juce_core/threads/juce_Thread.cpp
  55. +15
    -9
      libs/juce/source/modules/juce_core/threads/juce_Thread.h
  56. +79
    -44
      libs/juce/source/modules/juce_core/threads/juce_ThreadPool.cpp
  57. +24
    -11
      libs/juce/source/modules/juce_core/threads/juce_ThreadPool.h
  58. +3
    -1
      libs/juce/source/modules/juce_core/time/juce_PerformanceCounter.h
  59. +9
    -6
      libs/juce/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h
  60. +80
    -16
      libs/juce/source/modules/juce_events/native/juce_android_Messaging.cpp
  61. +19
    -29
      libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp
  62. +6
    -12
      libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.h
  63. +19
    -20
      libs/juce/source/modules/juce_graphics/geometry/juce_Path.cpp
  64. +18
    -18
      libs/juce/source/modules/juce_graphics/geometry/juce_Path.h
  65. +30
    -30
      libs/juce/source/modules/juce_graphics/geometry/juce_Point.h
  66. +6
    -3
      libs/juce/source/modules/juce_graphics/images/juce_Image.cpp
  67. +9
    -10
      libs/juce/source/modules/juce_graphics/native/juce_RenderingHelpers.h
  68. +5
    -12
      libs/juce/source/modules/juce_gui_basics/buttons/juce_Button.cpp
  69. +1
    -1
      libs/juce/source/modules/juce_gui_basics/buttons/juce_Button.h
  70. +6
    -9
      libs/juce/source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp
  71. +5
    -2
      libs/juce/source/modules/juce_gui_basics/buttons/juce_DrawableButton.h
  72. +50
    -54
      libs/juce/source/modules/juce_gui_basics/components/juce_Component.cpp
  73. +2
    -2
      libs/juce/source/modules/juce_gui_basics/components/juce_Component.h
  74. +5
    -5
      libs/juce/source/modules/juce_gui_basics/components/juce_Desktop.h
  75. +1
    -34
      libs/juce/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp
  76. +3
    -3
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h
  77. +1
    -1
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h
  78. +1
    -1
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.h
  79. +2
    -2
      libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h
  80. +8
    -0
      libs/juce/source/modules/juce_gui_basics/juce_gui_basics.cpp
  81. +9
    -0
      libs/juce/source/modules/juce_gui_basics/juce_gui_basics.h
  82. +1025
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_Grid.cpp
  83. +174
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_Grid.h
  84. +182
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_GridItem.cpp
  85. +223
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_GridItem.h
  86. +257
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_GridUnitTests.cpp
  87. +1
    -1
      libs/juce/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp
  88. +1
    -0
      libs/juce/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h
  89. +35
    -18
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  90. +6
    -3
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h
  91. +6
    -3
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp
  92. +2
    -4
      libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp
  93. +11
    -8
      libs/juce/source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp
  94. +6
    -0
      libs/juce/source/modules/juce_gui_basics/menus/juce_PopupMenu.h
  95. +10
    -5
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
  96. +3
    -0
      libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.h
  97. +68
    -9
      libs/juce/source/modules/juce_gui_basics/native/juce_android_Windowing.cpp
  98. +2
    -2
      libs/juce/source/modules/juce_gui_basics/native/juce_mac_MainMenu.mm
  99. +40
    -0
      libs/juce/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  100. +1
    -1
      libs/juce/source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h

+ 1
- 1
libs/juce/source/doxygen/Doxyfile View File

@@ -397,7 +397,7 @@ SUBGROUPING = YES
# SEPARATE_MEMBER_PAGES. # SEPARATE_MEMBER_PAGES.
# The default value is: NO. # The default value is: NO.


INLINE_GROUPED_CLASSES = YES
INLINE_GROUPED_CLASSES = NO


# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in # with only public data fields or simple typedef fields will be shown inline in


+ 1
- 1
libs/juce/source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -25,7 +25,7 @@
#if JUCE_INTEL #if JUCE_INTEL
#define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0; #define JUCE_SNAP_TO_ZERO(n) if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0;
#else #else
#define JUCE_SNAP_TO_ZERO(n)
#define JUCE_SNAP_TO_ZERO(n) ignoreUnused (n)
#endif #endif
//============================================================================== //==============================================================================


+ 22
- 23
libs/juce/source/modules/juce_audio_basics/native/juce_mac_CoreAudioLayouts.h View File

@@ -36,6 +36,15 @@ struct CoreAudioLayouts
return AudioChannelSet::channelSetWithChannels (getCoreAudioLayoutChannels (layout)); return AudioChannelSet::channelSetWithChannels (getCoreAudioLayoutChannels (layout));
} }
/** Convert CoreAudio's native AudioChannelLayoutTag to JUCE's AudioChannelSet.
Note that this method cannot preserve the order of channels.
*/
static AudioChannelSet fromCoreAudio (AudioChannelLayoutTag layoutTag)
{
return AudioChannelSet::channelSetWithChannels (getSpeakerLayoutForCoreAudioTag (layoutTag));
}
/** Convert JUCE's AudioChannelSet to CoreAudio's AudioChannelLayoutTag. /** Convert JUCE's AudioChannelSet to CoreAudio's AudioChannelLayoutTag.
Note that this method cannot preserve the order of channels. Note that this method cannot preserve the order of channels.
@@ -67,7 +76,7 @@ struct CoreAudioLayouts
/** Convert CoreAudio's native AudioChannelLayout to an array of JUCE ChannelTypes. */ /** Convert CoreAudio's native AudioChannelLayout to an array of JUCE ChannelTypes. */
static Array<AudioChannelSet::ChannelType> getCoreAudioLayoutChannels (const AudioChannelLayout& layout) static Array<AudioChannelSet::ChannelType> getCoreAudioLayoutChannels (const AudioChannelLayout& layout)
{ {
switch (layout.mChannelLayoutTag)
switch (layout.mChannelLayoutTag & 0xffff0000)
{ {
case kAudioChannelLayoutTag_UseChannelBitmap: case kAudioChannelLayoutTag_UseChannelBitmap:
return AudioChannelSet::fromWaveChannelMask (static_cast<int> (layout.mChannelBitmap)).getChannelTypes(); return AudioChannelSet::fromWaveChannelMask (static_cast<int> (layout.mChannelBitmap)).getChannelTypes();
@@ -94,30 +103,12 @@ struct CoreAudioLayouts
return getSpeakerLayoutForCoreAudioTag (layout.mChannelLayoutTag); return getSpeakerLayoutForCoreAudioTag (layout.mChannelLayoutTag);
} }
//==============================================================================
/* Convert between a CoreAudio and JUCE channel indices - and vice versa. */
// TODO: Fabian remove this
// static int convertChannelIndex (const AudioChannelLayout& caLayout, const AudioChannelSet& juceLayout, int index, bool fromJUCE)
// {
// auto coreAudioChannels = getCoreAudioLayoutChannels (caLayout);
//
// jassert (juceLayout.size() == coreAudioChannels.size());
// jassert (index >= 0 && index < juceLayout.size());
//
// return (fromJUCE ? coreAudioChannels.indexOf (juceLayout.getTypeOfChannel (index))
// : juceLayout.getChannelIndexForType (coreAudioChannels.getReference (index)));
// }
private:
//==============================================================================
struct LayoutTagSpeakerList
{
AudioChannelLayoutTag tag;
AudioChannelSet::ChannelType channelTypes[16];
};
static Array<AudioChannelSet::ChannelType> getSpeakerLayoutForCoreAudioTag (AudioChannelLayoutTag tag) static Array<AudioChannelSet::ChannelType> getSpeakerLayoutForCoreAudioTag (AudioChannelLayoutTag tag)
{ {
// You need to specify the full AudioChannelLayout when using
// the UseChannelBitmap and UseChannelDescriptions layout tag
jassert (tag != kAudioChannelLayoutTag_UseChannelBitmap && tag != kAudioChannelLayoutTag_UseChannelDescriptions);
Array<AudioChannelSet::ChannelType> speakers; Array<AudioChannelSet::ChannelType> speakers;
for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl) for (auto* tbl = SpeakerLayoutTable::get(); tbl->tag != 0; ++tbl)
@@ -139,6 +130,14 @@ private:
return speakers; return speakers;
} }
private:
//==============================================================================
struct LayoutTagSpeakerList
{
AudioChannelLayoutTag tag;
AudioChannelSet::ChannelType channelTypes[16];
};
static Array<AudioChannelLayoutTag> createKnownCoreAudioTags() static Array<AudioChannelLayoutTag> createKnownCoreAudioTags()
{ {
Array<AudioChannelLayoutTag> tags; Array<AudioChannelLayoutTag> tags;


+ 34
- 121
libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -24,20 +24,8 @@ SynthesiserSound::SynthesiserSound() {}
SynthesiserSound::~SynthesiserSound() {} SynthesiserSound::~SynthesiserSound() {}
//============================================================================== //==============================================================================
SynthesiserVoice::SynthesiserVoice()
: currentSampleRate (44100.0),
currentlyPlayingNote (-1),
currentPlayingMidiChannel (0),
noteOnTime (0),
keyIsDown (false),
sustainPedalDown (false),
sostenutoPedalDown (false)
{
}
SynthesiserVoice::~SynthesiserVoice()
{
}
SynthesiserVoice::SynthesiserVoice() {}
SynthesiserVoice::~SynthesiserVoice() {}
bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const bool SynthesiserVoice::isPlayingChannel (const int midiChannel) const
{ {
@@ -83,11 +71,6 @@ void SynthesiserVoice::renderNextBlock (AudioBuffer<double>& outputBuffer,
//============================================================================== //==============================================================================
Synthesiser::Synthesiser() Synthesiser::Synthesiser()
: sampleRate (0),
lastNoteOnCounter (0),
minimumSubBlockSize (32),
subBlockSubdivisionIsStrict (false),
shouldStealNotes (true)
{ {
for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i) for (int i = 0; i < numElementsInArray (lastPitchWheelValues); ++i)
lastPitchWheelValues[i] = 0x2000; lastPitchWheelValues[i] = 0x2000;
@@ -159,13 +142,11 @@ void Synthesiser::setCurrentPlaybackSampleRate (const double newRate)
if (sampleRate != newRate) if (sampleRate != newRate)
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
allNotesOff (0, false); allNotesOff (0, false);
sampleRate = newRate; sampleRate = newRate;
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->setCurrentPlaybackSampleRate (newRate);
for (auto* voice : voices)
voice->setCurrentPlaybackSampleRate (newRate);
} }
} }
@@ -230,25 +211,19 @@ void Synthesiser::processNextBlock (AudioBuffer<floatType>& outputAudio,
} }
// explicit template instantiation // explicit template instantiation
template void Synthesiser::processNextBlock<float> (AudioBuffer<float>& outputAudio,
const MidiBuffer& midiData,
int startSample,
int numSamples);
template void Synthesiser::processNextBlock<double> (AudioBuffer<double>& outputAudio,
const MidiBuffer& midiData,
int startSample,
int numSamples);
template void Synthesiser::processNextBlock<float> (AudioBuffer<float>&, const MidiBuffer&, int, int);
template void Synthesiser::processNextBlock<double> (AudioBuffer<double>&, const MidiBuffer&, int, int);
void Synthesiser::renderVoices (AudioBuffer<float>& buffer, int startSample, int numSamples) void Synthesiser::renderVoices (AudioBuffer<float>& buffer, int startSample, int numSamples)
{ {
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
for (auto* voice : voices)
voice->renderNextBlock (buffer, startSample, numSamples);
} }
void Synthesiser::renderVoices (AudioBuffer<double>& buffer, int startSample, int numSamples) void Synthesiser::renderVoices (AudioBuffer<double>& buffer, int startSample, int numSamples)
{ {
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
for (auto* voice : voices)
voice->renderNextBlock (buffer, startSample, numSamples);
} }
void Synthesiser::handleMidiEvent (const MidiMessage& m) void Synthesiser::handleMidiEvent (const MidiMessage& m)
@@ -298,23 +273,15 @@ void Synthesiser::noteOn (const int midiChannel,
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = sounds.size(); --i >= 0;)
for (auto* sound : sounds)
{ {
SynthesiserSound* const sound = sounds.getUnchecked(i);
if (sound->appliesToNote (midiNoteNumber)
&& sound->appliesToChannel (midiChannel))
if (sound->appliesToNote (midiNoteNumber) && sound->appliesToChannel (midiChannel))
{ {
// If hitting a note that's still ringing, stop it first (it could be // If hitting a note that's still ringing, stop it first (it could be
// still playing because of the sustain or sostenuto pedal). // still playing because of the sustain or sostenuto pedal).
for (int j = voices.size(); --j >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (j);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& voice->isPlayingChannel (midiChannel))
for (auto* voice : voices)
if (voice->getCurrentlyPlayingNote() == midiNoteNumber && voice->isPlayingChannel (midiChannel))
stopVoice (voice, 1.0f, true); stopVoice (voice, 1.0f, true);
}
startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes), startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
sound, midiChannel, midiNoteNumber, velocity); sound, midiChannel, midiNoteNumber, velocity);
@@ -337,7 +304,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
voice->currentPlayingMidiChannel = midiChannel; voice->currentPlayingMidiChannel = midiChannel;
voice->noteOnTime = ++lastNoteOnCounter; voice->noteOnTime = ++lastNoteOnCounter;
voice->currentlyPlayingSound = sound; voice->currentlyPlayingSound = sound;
voice->keyIsDown = true;
voice->setKeyDown (true);
voice->sostenutoPedalDown = false; voice->sostenutoPedalDown = false;
voice->sustainPedalDown = sustainPedalsDown[midiChannel]; voice->sustainPedalDown = sustainPedalsDown[midiChannel];
@@ -363,10 +330,8 @@ void Synthesiser::noteOff (const int midiChannel,
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
for (auto* voice : voices)
{ {
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& voice->isPlayingChannel (midiChannel)) && voice->isPlayingChannel (midiChannel))
{ {
@@ -377,7 +342,7 @@ void Synthesiser::noteOff (const int midiChannel,
{ {
jassert (! voice->keyIsDown || voice->sustainPedalDown == sustainPedalsDown [midiChannel]); jassert (! voice->keyIsDown || voice->sustainPedalDown == sustainPedalsDown [midiChannel]);
voice->keyIsDown = false;
voice->setKeyDown (false);
if (! (voice->sustainPedalDown || voice->sostenutoPedalDown)) if (! (voice->sustainPedalDown || voice->sostenutoPedalDown))
stopVoice (voice, velocity, allowTailOff); stopVoice (voice, velocity, allowTailOff);
@@ -391,13 +356,9 @@ void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->stopNote (1.0f, allowTailOff); voice->stopNote (1.0f, allowTailOff);
}
sustainPedalsDown.clear(); sustainPedalsDown.clear();
} }
@@ -406,13 +367,9 @@ void Synthesiser::handlePitchWheel (const int midiChannel, const int wheelValue)
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->pitchWheelMoved (wheelValue); voice->pitchWheelMoved (wheelValue);
}
} }
void Synthesiser::handleController (const int midiChannel, void Synthesiser::handleController (const int midiChannel,
@@ -429,40 +386,28 @@ void Synthesiser::handleController (const int midiChannel,
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->controllerMoved (controllerNumber, controllerValue); voice->controllerMoved (controllerNumber, controllerValue);
}
} }
void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue) void Synthesiser::handleAftertouch (int midiChannel, int midiNoteNumber, int aftertouchValue)
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (voice->getCurrentlyPlayingNote() == midiNoteNumber if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))) && (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)))
voice->aftertouchChanged (aftertouchValue); voice->aftertouchChanged (aftertouchValue);
}
} }
void Synthesiser::handleChannelPressure (int midiChannel, int channelPressureValue) void Synthesiser::handleChannelPressure (int midiChannel, int channelPressureValue)
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->channelPressureChanged (channelPressureValue); voice->channelPressureChanged (channelPressureValue);
}
} }
void Synthesiser::handleSustainPedal (int midiChannel, bool isDown) void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
@@ -474,25 +419,19 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
{ {
sustainPedalsDown.setBit (midiChannel); sustainPedalsDown.setBit (midiChannel);
for (int i = voices.size(); --i >= 0;)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown()) if (voice->isPlayingChannel (midiChannel) && voice->isKeyDown())
voice->sustainPedalDown = true; voice->sustainPedalDown = true;
}
} }
else else
{ {
for (int i = voices.size(); --i >= 0;)
for (auto* voice : voices)
{ {
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel)) if (voice->isPlayingChannel (midiChannel))
{ {
voice->sustainPedalDown = false; voice->sustainPedalDown = false;
if (! voice->isKeyDown())
if (! (voice->isKeyDown() || voice->isSostenutoPedalDown()))
stopVoice (voice, 1.0f, true); stopVoice (voice, 1.0f, true);
} }
} }
@@ -506,10 +445,8 @@ void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
jassert (midiChannel > 0 && midiChannel <= 16); jassert (midiChannel > 0 && midiChannel <= 16);
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = voices.size(); --i >= 0;)
for (auto* voice : voices)
{ {
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel)) if (voice->isPlayingChannel (midiChannel))
{ {
if (isDown) if (isDown)
@@ -539,13 +476,9 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = 0; i < voices.size(); ++i)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
for (auto* voice : voices)
if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay)) if ((! voice->isVoiceActive()) && voice->canPlaySound (soundToPlay))
return voice; return voice;
}
if (stealIfNoneAvailable) if (stealIfNoneAvailable)
return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber); return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
@@ -569,7 +502,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
// - Protect the lowest & topmost notes, even if sustained, but not if they've been released. // - Protect the lowest & topmost notes, even if sustained, but not if they've been released.
// apparently you are trying to render audio without having any voices... // apparently you are trying to render audio without having any voices...
jassert (voices.size() > 0);
jassert (! voices.isEmpty());
// These are the voices we want to protect (ie: only steal if unavoidable) // These are the voices we want to protect (ie: only steal if unavoidable)
SynthesiserVoice* low = nullptr; // Lowest sounding note, might be sustained, but NOT in release phase SynthesiserVoice* low = nullptr; // Lowest sounding note, might be sustained, but NOT in release phase
@@ -579,10 +512,8 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
Array<SynthesiserVoice*> usableVoices; Array<SynthesiserVoice*> usableVoices;
usableVoices.ensureStorageAllocated (voices.size()); usableVoices.ensureStorageAllocated (voices.size());
for (int i = 0; i < voices.size(); ++i)
for (auto* voice : voices)
{ {
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->canPlaySound (soundToPlay)) if (voice->canPlaySound (soundToPlay))
{ {
jassert (voice->isVoiceActive()); // We wouldn't be here otherwise jassert (voice->isVoiceActive()); // We wouldn't be here otherwise
@@ -592,7 +523,7 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
if (! voice->isPlayingButReleased()) // Don't protect released notes if (! voice->isPlayingButReleased()) // Don't protect released notes
{ {
const int note = voice->getCurrentlyPlayingNote();
auto note = voice->getCurrentlyPlayingNote();
if (low == nullptr || note < low->getCurrentlyPlayingNote()) if (low == nullptr || note < low->getCurrentlyPlayingNote())
low = voice; low = voice;
@@ -607,43 +538,25 @@ SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
if (top == low) if (top == low)
top = nullptr; top = nullptr;
const int numUsableVoices = usableVoices.size();
// The oldest note that's playing with the target pitch is ideal.. // The oldest note that's playing with the target pitch is ideal..
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
for (auto* voice : usableVoices)
if (voice->getCurrentlyPlayingNote() == midiNoteNumber) if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
return voice; return voice;
}
// Oldest voice that has been released (no finger on it and not held by sustain pedal) // Oldest voice that has been released (no finger on it and not held by sustain pedal)
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
for (auto* voice : usableVoices)
if (voice != low && voice != top && voice->isPlayingButReleased()) if (voice != low && voice != top && voice->isPlayingButReleased())
return voice; return voice;
}
// Oldest voice that doesn't have a finger on it: // Oldest voice that doesn't have a finger on it:
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
for (auto* voice : usableVoices)
if (voice != low && voice != top && ! voice->isKeyDown()) if (voice != low && voice != top && ! voice->isKeyDown())
return voice; return voice;
}
// Oldest voice that isn't protected // Oldest voice that isn't protected
for (int i = 0; i < numUsableVoices; ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
for (auto* voice : usableVoices)
if (voice != low && voice != top) if (voice != low && voice != top)
return voice; return voice;
}
// We've only got "protected" voices now: lowest note takes priority // We've only got "protected" voices now: lowest note takes priority
jassert (low != nullptr); jassert (low != nullptr);


+ 16
- 9
libs/juce/source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -182,6 +182,8 @@ public:
virtual void renderNextBlock (AudioBuffer<float>& outputBuffer, virtual void renderNextBlock (AudioBuffer<float>& outputBuffer,
int startSample, int startSample,
int numSamples) = 0; int numSamples) = 0;
/** A double-precision version of renderNextBlock() */
virtual void renderNextBlock (AudioBuffer<double>& outputBuffer, virtual void renderNextBlock (AudioBuffer<double>& outputBuffer,
int startSample, int startSample,
int numSamples); int numSamples);
@@ -214,6 +216,11 @@ public:
*/ */
bool isKeyDown() const noexcept { return keyIsDown; } bool isKeyDown() const noexcept { return keyIsDown; }
/** Allows you to modify the flag indicating that the key that triggered this voice is still held down.
@see isKeyDown
*/
void setKeyDown (bool isNowDown) noexcept { keyIsDown = isNowDown; }
/** Returns true if the sustain pedal is currently active for this voice. */ /** Returns true if the sustain pedal is currently active for this voice. */
bool isSustainPedalDown() const noexcept { return sustainPedalDown; } bool isSustainPedalDown() const noexcept { return sustainPedalDown; }
@@ -249,11 +256,11 @@ private:
//============================================================================== //==============================================================================
friend class Synthesiser; friend class Synthesiser;
double currentSampleRate;
int currentlyPlayingNote, currentPlayingMidiChannel;
uint32 noteOnTime;
double currentSampleRate = 44100.0;
int currentlyPlayingNote = -1, currentPlayingMidiChannel = 0;
uint32 noteOnTime = 0;
SynthesiserSound::Ptr currentlyPlayingSound; SynthesiserSound::Ptr currentlyPlayingSound;
bool keyIsDown, sustainPedalDown, sostenutoPedalDown;
bool keyIsDown = false, sustainPedalDown = false, sostenutoPedalDown = false;
AudioBuffer<float> tempBuffer; AudioBuffer<float> tempBuffer;
@@ -615,11 +622,11 @@ private:
int startSample, int startSample,
int numSamples); int numSamples);
//============================================================================== //==============================================================================
double sampleRate;
uint32 lastNoteOnCounter;
int minimumSubBlockSize;
bool subBlockSubdivisionIsStrict;
bool shouldStealNotes;
double sampleRate = 0;
uint32 lastNoteOnCounter = 0;
int minimumSubBlockSize = 32;
bool subBlockSubdivisionIsStrict = false;
bool shouldStealNotes = true;
BigInteger sustainPedalsDown; BigInteger sustainPedalsDown;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE #if JUCE_CATCH_DEPRECATED_CODE_MISUSE


+ 5
- 0
libs/juce/source/modules/juce_audio_devices/native/juce_android_OpenSL.cpp View File

@@ -651,11 +651,16 @@ public:
{ {
OpenSLSession::stop(); OpenSLSession::stop();
while (! guard.compareAndSetBool (1, 0))
Thread::sleep (1);
if (inputChannels > 0) if (inputChannels > 0)
recorder->setState (false); recorder->setState (false);
if (outputChannels > 0) if (outputChannels > 0)
player->setState (false); player->setState (false);
guard.set (0);
} }
bool setAudioPreprocessingEnabled (bool shouldEnable) override bool setAudioPreprocessingEnabled (bool shouldEnable) override


+ 7
- 1
libs/juce/source/modules/juce_audio_devices/native/juce_ios_Audio.cpp View File

@@ -576,7 +576,13 @@ struct iOSAudioIODevice::Pimpl : public AudioPlayHead,
&hostUrl, &hostUrl,
&dataSize); &dataSize);
if (err == noErr) if (err == noErr)
[[UIApplication sharedApplication] openURL:(NSURL*)hostUrl];
{
#if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
[[UIApplication sharedApplication] openURL: (NSURL*)hostUrl];
#else
[[UIApplication sharedApplication] openURL: (NSURL*)hostUrl options: @{} completionHandler: nil];
#endif
}
} }
//============================================================================== //==============================================================================


+ 41
- 13
libs/juce/source/modules/juce_audio_devices/native/juce_win32_WASAPI.cpp View File

@@ -357,7 +357,8 @@ public:
actualBufferSize (0), actualBufferSize (0),
bytesPerSample (0), bytesPerSample (0),
bytesPerFrame (0), bytesPerFrame (0),
sampleRateHasChanged (false)
sampleRateHasChanged (false),
shouldClose (false)
{ {
clientEvent = CreateEvent (nullptr, false, false, nullptr); clientEvent = CreateEvent (nullptr, false, false, nullptr);
@@ -468,6 +469,11 @@ public:
sampleRateHasChanged = true; sampleRateHasChanged = true;
} }
void deviceBecameInactive()
{
shouldClose = true;
}
//============================================================================== //==============================================================================
ComSmartPtr<IMMDevice> device; ComSmartPtr<IMMDevice> device;
ComSmartPtr<IAudioClient> client; ComSmartPtr<IAudioClient> client;
@@ -482,7 +488,7 @@ public:
Array<int> channelMaps; Array<int> channelMaps;
UINT32 actualBufferSize; UINT32 actualBufferSize;
int bytesPerSample, bytesPerFrame; int bytesPerSample, bytesPerFrame;
bool sampleRateHasChanged;
bool sampleRateHasChanged, shouldClose;
virtual void updateFormat (bool isFloat) = 0; virtual void updateFormat (bool isFloat) = 0;
@@ -498,10 +504,17 @@ private:
JUCE_COMRESULT OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; } JUCE_COMRESULT OnSimpleVolumeChanged (float, BOOL, LPCGUID) { return S_OK; }
JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; } JUCE_COMRESULT OnChannelVolumeChanged (DWORD, float*, DWORD, LPCGUID) { return S_OK; }
JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; } JUCE_COMRESULT OnGroupingParamChanged (LPCGUID, LPCGUID) { return S_OK; }
JUCE_COMRESULT OnStateChanged (AudioSessionState) { return S_OK; }
JUCE_COMRESULT OnStateChanged(AudioSessionState state)
{
if (state == AudioSessionStateInactive || state == AudioSessionStateExpired)
owner.deviceBecameInactive();
return S_OK;
}
JUCE_COMRESULT OnSessionDisconnected (AudioSessionDisconnectReason reason) JUCE_COMRESULT OnSessionDisconnected (AudioSessionDisconnectReason reason)
{ {
Logger::writeToLog("OnSessionDisconnected");
if (reason == DisconnectReasonFormatChanged) if (reason == DisconnectReasonFormatChanged)
owner.deviceSampleRateChanged(); owner.deviceSampleRateChanged();
@@ -969,7 +982,8 @@ public:
isStarted (false), isStarted (false),
currentBufferSizeSamples (0), currentBufferSizeSamples (0),
currentSampleRate (0), currentSampleRate (0),
callback (nullptr)
callback (nullptr),
deviceBecameInactive (false)
{ {
} }
@@ -1107,6 +1121,8 @@ public:
if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent); if (inputDevice != nullptr) ResetEvent (inputDevice->clientEvent);
if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent); if (outputDevice != nullptr) ResetEvent (outputDevice->clientEvent);
deviceBecameInactive = false;
startThread (8); startThread (8);
Thread::sleep (5); Thread::sleep (5);
@@ -1226,8 +1242,14 @@ public:
while (! threadShouldExit()) while (! threadShouldExit())
{ {
if (inputDevice != nullptr)
if (outputDevice != nullptr && outputDevice->shouldClose)
deviceBecameInactive = true;
if (inputDevice != nullptr && ! deviceBecameInactive)
{ {
if (inputDevice->shouldClose)
deviceBecameInactive = true;
if (outputDevice == nullptr) if (outputDevice == nullptr)
{ {
if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT) if (WaitForSingleObject (inputDevice->clientEvent, 1000) == WAIT_TIMEOUT)
@@ -1253,6 +1275,7 @@ public:
} }
} }
if (! deviceBecameInactive)
{ {
const ScopedTryLock sl (startStopLock); const ScopedTryLock sl (startStopLock);
@@ -1263,7 +1286,7 @@ public:
outs.clear(); outs.clear();
} }
if (outputDevice != nullptr)
if (outputDevice != nullptr && !deviceBecameInactive)
{ {
// Note that this function is handed the input device so it can check for the event and make sure // Note that this function is handed the input device so it can check for the event and make sure
// the input reservoir is filled up correctly even when bufferSize > device actualBufferSize // the input reservoir is filled up correctly even when bufferSize > device actualBufferSize
@@ -1276,7 +1299,7 @@ public:
} }
} }
if (sampleRateHasChanged)
if (sampleRateHasChanged || deviceBecameInactive)
{ {
triggerAsyncUpdate(); triggerAsyncUpdate();
break; // Quit the thread... will restart it later! break; // Quit the thread... will restart it later!
@@ -1303,7 +1326,7 @@ private:
bool isOpen_, isStarted; bool isOpen_, isStarted;
int currentBufferSizeSamples; int currentBufferSizeSamples;
double currentSampleRate; double currentSampleRate;
bool sampleRateChangedByOutput;
bool sampleRateChangedByOutput, deviceBecameInactive;
AudioIODeviceCallback* callback; AudioIODeviceCallback* callback;
CriticalSection startStopLock; CriticalSection startStopLock;
@@ -1354,12 +1377,17 @@ private:
outputDevice = nullptr; outputDevice = nullptr;
inputDevice = nullptr; inputDevice = nullptr;
initialise();
open (lastKnownInputChannels, lastKnownOutputChannels,
getChangedSampleRate(), currentBufferSizeSamples);
// sample rate change
if (! deviceBecameInactive)
{
initialise();
open (lastKnownInputChannels, lastKnownOutputChannels,
getChangedSampleRate(), currentBufferSizeSamples);
start (callback);
start (callback);
}
} }
double getChangedSampleRate() const double getChangedSampleRate() const
@@ -1481,7 +1509,7 @@ private:
HRESULT STDMETHODCALLTYPE OnDeviceAdded (LPCWSTR) { return notify(); } HRESULT STDMETHODCALLTYPE OnDeviceAdded (LPCWSTR) { return notify(); }
HRESULT STDMETHODCALLTYPE OnDeviceRemoved (LPCWSTR) { return notify(); } HRESULT STDMETHODCALLTYPE OnDeviceRemoved (LPCWSTR) { return notify(); }
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged (LPCWSTR, DWORD) { return notify(); }
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR, DWORD) { return notify(); }
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged (EDataFlow, ERole, LPCWSTR) { return notify(); } HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged (EDataFlow, ERole, LPCWSTR) { return notify(); }
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged (LPCWSTR, const PROPERTYKEY) { return notify(); } HRESULT STDMETHODCALLTYPE OnPropertyValueChanged (LPCWSTR, const PROPERTYKEY) { return notify(); }


+ 6
- 15
libs/juce/source/modules/juce_audio_formats/codecs/juce_CoreAudioFormat.cpp View File

@@ -619,8 +619,7 @@ public:
for (auto tagEntry : knownTags) for (auto tagEntry : knownTags)
{ {
AudioChannelLayout layout { tagEntry.tag };
auto labels = CoreAudioLayouts::fromCoreAudio (layout);
auto labels = CoreAudioLayouts::fromCoreAudio (tagEntry.tag);
expect (! labels.isDiscreteLayout(), String ("Tag \"") + String (tagEntry.name) + "\" is not handled by JUCE"); expect (! labels.isDiscreteLayout(), String ("Tag \"") + String (tagEntry.name) + "\" is not handled by JUCE");
} }
@@ -631,8 +630,7 @@ public:
for (auto tagEntry : knownTags) for (auto tagEntry : knownTags)
{ {
AudioChannelLayout layout { tagEntry.tag };
auto labels = CoreAudioLayouts::getCoreAudioLayoutChannels (layout);
auto labels = CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag);
expect (labels.size() == (tagEntry.tag & 0xffff), String ("Tag \"") + String (tagEntry.name) + "\" has incorrect channel count"); expect (labels.size() == (tagEntry.tag & 0xffff), String ("Tag \"") + String (tagEntry.name) + "\" has incorrect channel count");
} }
@@ -643,8 +641,7 @@ public:
for (auto tagEntry : knownTags) for (auto tagEntry : knownTags)
{ {
AudioChannelLayout layout { tagEntry.tag };
auto labels = CoreAudioLayouts::getCoreAudioLayoutChannels (layout);
auto labels = CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag);
labels.sort(); labels.sort();
for (int i = 0; i < (labels.size() - 1); ++i) for (int i = 0; i < (labels.size() - 1); ++i)
@@ -657,13 +654,9 @@ public:
beginTest ("CA speaker list and juce layouts are consistent"); beginTest ("CA speaker list and juce layouts are consistent");
for (auto tagEntry : knownTags) for (auto tagEntry : knownTags)
{
AudioChannelLayout layout { tagEntry.tag };
expect (AudioChannelSet::channelSetWithChannels (CoreAudioLayouts::getCoreAudioLayoutChannels (layout))
== CoreAudioLayouts::fromCoreAudio (layout),
expect (AudioChannelSet::channelSetWithChannels (CoreAudioLayouts::getSpeakerLayoutForCoreAudioTag (tagEntry.tag))
== CoreAudioLayouts::fromCoreAudio (tagEntry.tag),
String ("Tag \"") + String (tagEntry.name) + "\" is not converted consistantly by JUCE"); String ("Tag \"") + String (tagEntry.name) + "\" is not converted consistantly by JUCE");
}
} }
{ {
@@ -674,9 +667,7 @@ public:
if (tagEntry.equivalentChannelSet.isDisabled()) if (tagEntry.equivalentChannelSet.isDisabled())
continue; continue;
AudioChannelLayout layout { tagEntry.tag };
expect (CoreAudioLayouts::fromCoreAudio (layout) == tagEntry.equivalentChannelSet,
expect (CoreAudioLayouts::fromCoreAudio (tagEntry.tag) == tagEntry.equivalentChannelSet,
String ("Documentation for tag \"") + String (tagEntry.name) + "\" is incorrect"); String ("Documentation for tag \"") + String (tagEntry.name) + "\" is incorrect");
} }
} }


+ 7
- 0
libs/juce/source/modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -942,6 +942,13 @@ namespace AAXClasses
{ {
if (type == AAX_eNotificationEvent_EnteringOfflineMode) pluginInstance->setNonRealtime (true); if (type == AAX_eNotificationEvent_EnteringOfflineMode) pluginInstance->setNonRealtime (true);
if (type == AAX_eNotificationEvent_ExitingOfflineMode) pluginInstance->setNonRealtime (false); if (type == AAX_eNotificationEvent_ExitingOfflineMode) pluginInstance->setNonRealtime (false);
if (type == AAX_eNotificationEvent_TrackNameChanged && data != nullptr)
{
AudioProcessor::TrackProperties props;
props.name = static_cast<const AAX_IString*> (data)->Get();
pluginInstance->updateTrackProperties (props);
}
return AAX_CEffectParameters::NotificationReceived (type, data, size); return AAX_CEffectParameters::NotificationReceived (type, data, size);
} }


+ 23
- 7
libs/juce/source/modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -147,6 +147,8 @@ public:
channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter); channelInfo = AudioUnitHelpers::getAUChannelInfo (*juceFilter);
#endif #endif
AddPropertyListener (kAudioUnitProperty_ContextName, auPropertyListenerDispatcher, this);
totalInChannels = juceFilter->getTotalNumInputChannels(); totalInChannels = juceFilter->getTotalNumInputChannels();
totalOutChannels = juceFilter->getTotalNumOutputChannels(); totalOutChannels = juceFilter->getTotalNumOutputChannels();
@@ -1818,12 +1820,7 @@ private:
if (numChannels != tagNumChannels) if (numChannels != tagNumChannels)
return kAudioUnitErr_FormatNotSupported; return kAudioUnitErr_FormatNotSupported;
AudioChannelLayout layout;
zerostruct (layout);
layout.mChannelLayoutTag = currentLayoutTag;
requestedBuses.add (CoreAudioLayouts::fromCoreAudio (layout));
requestedBuses.add (CoreAudioLayouts::fromCoreAudio (currentLayoutTag));
} }
} }
@@ -1909,7 +1906,7 @@ private:
auto& knownTags = CoreAudioLayouts::getKnownCoreAudioTags(); auto& knownTags = CoreAudioLayouts::getKnownCoreAudioTags();
for (auto tag : knownTags) for (auto tag : knownTags)
if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (AudioChannelLayout {tag})))
if (bus->isLayoutSupported (CoreAudioLayouts::fromCoreAudio (tag)))
tags.addIfNotAlreadyThere (tag); tags.addIfNotAlreadyThere (tag);
#endif #endif
@@ -1961,6 +1958,25 @@ private:
return (getHostType().isLogic() ? 8 : 64); return (getHostType().isLogic() ? 8 : 64);
} }
//==============================================================================
void auPropertyListener (AudioUnitPropertyID propId, AudioUnitScope scope, AudioUnitElement)
{
if (scope == kAudioUnitScope_Global && propId == kAudioUnitProperty_ContextName
&& juceFilter != nullptr && mContextName != nullptr)
{
AudioProcessor::TrackProperties props;
props.name = String::fromCFString (mContextName);
juceFilter->updateTrackProperties (props);
}
}
static void auPropertyListenerDispatcher (void* inRefCon, AudioUnit, AudioUnitPropertyID propId,
AudioUnitScope scope, AudioUnitElement element)
{
static_cast<JuceAU*> (inRefCon)->auPropertyListener (propId, scope, element);
}
JUCE_DECLARE_NON_COPYABLE (JuceAU) JUCE_DECLARE_NON_COPYABLE (JuceAU)
}; };


+ 301
- 141
libs/juce/source/modules/juce_audio_plugin_client/AU/juce_AUv3_Wrapper.mm View File

@@ -37,12 +37,20 @@
#if (! defined MAC_OS_X_VERSION_MIN_REQUIRED) || (! defined MAC_OS_X_VERSION_10_11) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11) #if (! defined MAC_OS_X_VERSION_MIN_REQUIRED) || (! defined MAC_OS_X_VERSION_10_11) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11)
#error AUv3 needs Deployment Target OS X 10.11 or higher to compile #error AUv3 needs Deployment Target OS X 10.11 or higher to compile
#endif #endif
#if (defined MAC_OS_X_VERSION_10_13) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_13)
#define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
#define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
#endif
#endif #endif
#if JUCE_IOS #if JUCE_IOS
#if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_9_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) #if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_9_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#error AUv3 needs Deployment Target iOS 9.0 or higher to compile #error AUv3 needs Deployment Target iOS 9.0 or higher to compile
#endif #endif
#if (defined __IPHONE_11_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
#define JUCE_AUV3_MIDI_OUTPUT_SUPPORTED 1
#define JUCE_AUV3_VIEW_CONFIG_SUPPORTED 1
#endif
#endif #endif
#ifndef __OBJC2__ #ifndef __OBJC2__
@@ -97,6 +105,15 @@ struct AudioProcessorHolder : public ReferenceCountedObject
AudioProcessor* operator->() noexcept { return processor; } AudioProcessor* operator->() noexcept { return processor; }
AudioProcessor* get() noexcept { return processor; } AudioProcessor* get() noexcept { return processor; }
struct ViewConfig
{
double width;
double height;
bool hostHasMIDIController;
};
ScopedPointer<ViewConfig> viewConfiguration;
typedef ReferenceCountedObjectPtr<AudioProcessorHolder> Ptr; typedef ReferenceCountedObjectPtr<AudioProcessorHolder> Ptr;
private: private:
@@ -121,8 +138,7 @@ public:
error: error error: error
juceClass: this]) juceClass: this])
#pragma clang diagnostic pop #pragma clang diagnostic pop
{
}
{}
JuceAudioUnitv3Base (AUAudioUnit* audioUnit) : au (audioUnit) JuceAudioUnitv3Base (AUAudioUnit* audioUnit) : au (audioUnit)
{ {
@@ -134,39 +150,14 @@ public:
//============================================================================== //==============================================================================
AUAudioUnit* getAudioUnit() noexcept { return au; } AUAudioUnit* getAudioUnit() noexcept { return au; }
virtual int getVirtualMIDICableCount() { return 0; }
virtual void reset() {}
virtual bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* bus)
{
objc_super s = { getAudioUnit(), [AUAudioUnit class] };
return (ObjCMsgSendSuper<BOOL, AVAudioFormat*,AUAudioUnitBus* > (&s, @selector (shouldChangeToFormat:forBus:), format, bus) == YES);
}
virtual AUAudioUnitPreset* getCurrentPreset() { return nullptr; }
virtual void setCurrentPreset(AUAudioUnitPreset*) {}
virtual NSTimeInterval getLatency() { return 0.0; }
virtual NSTimeInterval getTailTime() { return 0.0; }
virtual bool getCanProcessInPlace() { return false; }
virtual bool getRenderingOffline() { return false; }
//============================================================================== //==============================================================================
virtual AUAudioUnitBusArray* getInputBusses() = 0;
virtual AUAudioUnitBusArray* getOutputBusses() = 0;
virtual AUParameterTree* getParameterTree() = 0;
virtual AUInternalRenderBlock getInternalRenderBlock() = 0;
virtual void setRenderingOffline (bool offline) = 0;
virtual NSArray<NSNumber*> *getChannelCapabilities() = 0;
virtual void reset() = 0;
//============================================================================== //==============================================================================
virtual NSArray<NSNumber*>* parametersForOverviewWithCount (int)
{
return [NSArray<NSNumber*> array];
}
virtual NSArray<AUAudioUnitPreset*>* getFactoryPresets()
{
return [NSArray<AUAudioUnitPreset*> array];
}
virtual AUAudioUnitPreset* getCurrentPreset() = 0;
virtual void setCurrentPreset(AUAudioUnitPreset*) = 0;
virtual NSArray<AUAudioUnitPreset*>* getFactoryPresets() = 0;
virtual NSDictionary<NSString*, id>* getFullState() virtual NSDictionary<NSString*, id>* getFullState()
{ {
@@ -180,6 +171,34 @@ public:
ObjCMsgSendSuper<void, NSDictionary<NSString*, id>*> (&s, @selector (setFullState:), state); ObjCMsgSendSuper<void, NSDictionary<NSString*, id>*> (&s, @selector (setFullState:), state);
} }
virtual AUParameterTree* getParameterTree() = 0;
virtual NSArray<NSNumber*>* parametersForOverviewWithCount (int) = 0;
//==============================================================================
virtual NSTimeInterval getLatency() = 0;
virtual NSTimeInterval getTailTime() = 0;
//==============================================================================
virtual AUAudioUnitBusArray* getInputBusses() = 0;
virtual AUAudioUnitBusArray* getOutputBusses() = 0;
virtual NSArray<NSNumber*>* getChannelCapabilities() = 0;
virtual bool shouldChangeToFormat (AVAudioFormat*, AUAudioUnitBus*) = 0;
//==============================================================================
virtual int getVirtualMIDICableCount() = 0;
virtual bool getSupportsMPE() = 0;
virtual NSArray<NSString*>* getMIDIOutputNames() = 0;
//==============================================================================
virtual AUInternalRenderBlock getInternalRenderBlock() = 0;
virtual bool getCanProcessInPlace() { return false; }
virtual bool getRenderingOffline() = 0;
virtual void setRenderingOffline (bool offline) = 0;
//==============================================================================
virtual NSString* getContextName() const = 0;
virtual void setContextName (NSString*) = 0;
virtual bool allocateRenderResourcesAndReturnError (NSError **outError) virtual bool allocateRenderResourcesAndReturnError (NSError **outError)
{ {
objc_super s = { getAudioUnit(), [AUAudioUnit class] }; objc_super s = { getAudioUnit(), [AUAudioUnit class] };
@@ -192,6 +211,12 @@ public:
ObjCMsgSendSuper<void> (&s, @selector (deallocateRenderResources)); ObjCMsgSendSuper<void> (&s, @selector (deallocateRenderResources));
} }
//==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
virtual NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>*) = 0;
virtual void selectViewConfiguration (AUAudioUnitViewConfiguration*) = 0;
#endif
private: private:
struct Class : public ObjCClass<AUAudioUnit> struct Class : public ObjCClass<AUAudioUnit>
{ {
@@ -212,31 +237,55 @@ private:
@encode (AudioComponentDescription), @encode (AudioComponentDescription),
@encode (AudioComponentInstantiationOptions), "^@"); @encode (AudioComponentInstantiationOptions), "^@");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (inputBusses), getInputBusses, "@@:");
addMethod (@selector (outputBusses), getOutputBusses, "@@:");
addMethod (@selector (parameterTree), getParameterTree, "@@:");
addMethod (@selector (deallocateRenderResources), deallocateRenderResources, "v@:");
addMethod (@selector (reset), reset, "v@:");
addMethod (@selector (shouldChangeToFormat:forBus:), shouldChangeToFormat, "B@:@@");
addMethod (@selector (factoryPresets), getFactoryPresets, "@@:");
addMethod (@selector (currentPreset), getCurrentPreset, "@@:");
addMethod (@selector (setCurrentPreset:), setCurrentPreset, "v@:@");
addMethod (@selector (fullState), getFullState, "@@:");
addMethod (@selector (setFullState:), setFullState, "v@:@");
addMethod (@selector (channelCapabilities), getChannelCapabilities, "@@:");
addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "B@:^@");
addMethod (@selector (dealloc), dealloc, "v@:");
//==============================================================================
addMethod (@selector (reset), reset, "v@:");
//==============================================================================
addMethod (@selector (currentPreset), getCurrentPreset, "@@:");
addMethod (@selector (setCurrentPreset:), setCurrentPreset, "v@:@");
addMethod (@selector (factoryPresets), getFactoryPresets, "@@:");
addMethod (@selector (fullState), getFullState, "@@:");
addMethod (@selector (setFullState:), setFullState, "v@:@");
addMethod (@selector (parameterTree), getParameterTree, "@@:");
addMethod (@selector (parametersForOverviewWithCount:), parametersForOverviewWithCount, "@@:", @encode (NSInteger)); addMethod (@selector (parametersForOverviewWithCount:), parametersForOverviewWithCount, "@@:", @encode (NSInteger));
//==============================================================================
addMethod (@selector (latency), getLatency, @encode (NSTimeInterval), "@:");
addMethod (@selector (tailTime), getTailTime, @encode (NSTimeInterval), "@:");
//==============================================================================
addMethod (@selector (inputBusses), getInputBusses, "@@:");
addMethod (@selector (outputBusses), getOutputBusses, "@@:");
addMethod (@selector (channelCapabilities), getChannelCapabilities, "@@:");
addMethod (@selector (shouldChangeToFormat:forBus:), shouldChangeToFormat, "B@:@@");
//==============================================================================
addMethod (@selector (virtualMIDICableCount), getVirtualMIDICableCount, @encode (NSInteger), "@:");
addMethod (@selector (supportsMPE), getSupportsMPE, @encode (BOOL), "@:");
#if JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
addMethod (@selector (MIDIOutputNames), getMIDIOutputNames, "@@:");
#endif
//==============================================================================
addMethod (@selector (internalRenderBlock), getInternalRenderBlock, @encode (AUInternalRenderBlock), "@:");
addMethod (@selector (canProcessInPlace), getCanProcessInPlace, @encode (BOOL), "@:");
addMethod (@selector (isRenderingOffline), getRenderingOffline, @encode (BOOL), "@:");
addMethod (@selector (setRenderingOffline:), setRenderingOffline, "v@:", @encode (BOOL)); addMethod (@selector (setRenderingOffline:), setRenderingOffline, "v@:", @encode (BOOL));
addMethod (@selector (allocateRenderResourcesAndReturnError:), allocateRenderResourcesAndReturnError, "B@:^@");
addMethod (@selector (deallocateRenderResources), deallocateRenderResources, "v@:");
//==============================================================================
addMethod (@selector (contextName), getContextName, "@@:");
addMethod (@selector (setContextName:), setContextName, "v@:@");
addMethod (@selector (internalRenderBlock), getInternalRenderBlock, @encode (AUInternalRenderBlock), "@:");
addMethod (@selector (virtualMIDICableCount), getVirtualMIDICableCount, @encode (NSInteger), "@:");
addMethod (@selector (latency), getLatency, @encode (NSTimeInterval), "@:");
addMethod (@selector (tailTime), getTailTime, @encode (NSTimeInterval), "@:");
addMethod (@selector (canProcessInPlace), getCanProcessInPlace, @encode (BOOL), "@:");
addMethod (@selector (isRenderingOffline), getRenderingOffline, @encode (BOOL), "@:");
//==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
addMethod (@selector (supportedViewConfigurations:), getSupportedViewConfigurations, "@@:@");
addMethod (@selector (selectViewConfiguration:), selectViewConfiguration, "v@:@");
#endif
registerClass(); registerClass();
} }
@@ -274,27 +323,51 @@ private:
} }
static void dealloc (id self, SEL) { delete _this (self); } static void dealloc (id self, SEL) { delete _this (self); }
static AUAudioUnitBusArray* getInputBusses (id self, SEL) { return _this (self)->getInputBusses(); }
static AUAudioUnitBusArray* getOutputBusses (id self, SEL) { return _this (self)->getOutputBusses(); }
static AUParameterTree* getParameterTree (id self, SEL) { return _this (self)->getParameterTree(); }
static AUInternalRenderBlock getInternalRenderBlock (id self, SEL) { return _this (self)->getInternalRenderBlock(); }
static BOOL allocateRenderResourcesAndReturnError (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }
static void deallocateRenderResources (id self, SEL) { _this (self)->deallocateRenderResources(); }
//==============================================================================
static void reset (id self, SEL) { _this (self)->reset(); } static void reset (id self, SEL) { _this (self)->reset(); }
static NSInteger getVirtualMIDICableCount (id self, SEL) { return _this (self)->getVirtualMIDICableCount(); }
static BOOL shouldChangeToFormat (id self, SEL, AVAudioFormat* format, AUAudioUnitBus* bus) { return _this (self)->shouldChangeToFormat (format, bus) ? YES : NO; }
static NSArray<NSNumber*>* parametersForOverviewWithCount (id self, SEL, NSInteger count) { return _this (self)->parametersForOverviewWithCount (static_cast<int> (count)); }
static NSArray<AUAudioUnitPreset*>* getFactoryPresets (id self, SEL) { return _this (self)->getFactoryPresets(); }
//==============================================================================
static AUAudioUnitPreset* getCurrentPreset (id self, SEL) { return _this (self)->getCurrentPreset(); } static AUAudioUnitPreset* getCurrentPreset (id self, SEL) { return _this (self)->getCurrentPreset(); }
static void setCurrentPreset (id self, SEL, AUAudioUnitPreset* preset) { return _this (self)->setCurrentPreset (preset); } static void setCurrentPreset (id self, SEL, AUAudioUnitPreset* preset) { return _this (self)->setCurrentPreset (preset); }
static NSArray<AUAudioUnitPreset*>* getFactoryPresets (id self, SEL) { return _this (self)->getFactoryPresets(); }
static NSDictionary<NSString*, id>* getFullState (id self, SEL) { return _this (self)->getFullState(); } static NSDictionary<NSString*, id>* getFullState (id self, SEL) { return _this (self)->getFullState(); }
static void setFullState (id self, SEL, NSDictionary<NSString *, id>* state) { return _this (self)->setFullState (state); } static void setFullState (id self, SEL, NSDictionary<NSString *, id>* state) { return _this (self)->setFullState (state); }
static AUParameterTree* getParameterTree (id self, SEL) { return _this (self)->getParameterTree(); }
static NSArray<NSNumber*>* parametersForOverviewWithCount (id self, SEL, NSInteger count) { return _this (self)->parametersForOverviewWithCount (static_cast<int> (count)); }
//==============================================================================
static NSTimeInterval getLatency (id self, SEL) { return _this (self)->getLatency(); } static NSTimeInterval getLatency (id self, SEL) { return _this (self)->getLatency(); }
static NSTimeInterval getTailTime (id self, SEL) { return _this (self)->getTailTime(); } static NSTimeInterval getTailTime (id self, SEL) { return _this (self)->getTailTime(); }
//==============================================================================
static AUAudioUnitBusArray* getInputBusses (id self, SEL) { return _this (self)->getInputBusses(); }
static AUAudioUnitBusArray* getOutputBusses (id self, SEL) { return _this (self)->getOutputBusses(); }
static NSArray<NSNumber*>* getChannelCapabilities (id self, SEL) { return _this (self)->getChannelCapabilities(); }
static BOOL shouldChangeToFormat (id self, SEL, AVAudioFormat* format, AUAudioUnitBus* bus) { return _this (self)->shouldChangeToFormat (format, bus) ? YES : NO; }
//==============================================================================
static NSInteger getVirtualMIDICableCount (id self, SEL) { return _this (self)->getVirtualMIDICableCount(); }
static BOOL getSupportsMPE (id self, SEL) { return _this (self)->getSupportsMPE() ? YES : NO; }
static NSArray<NSString*>* getMIDIOutputNames (id self, SEL) { return _this (self)->getMIDIOutputNames(); }
//==============================================================================
static AUInternalRenderBlock getInternalRenderBlock (id self, SEL) { return _this (self)->getInternalRenderBlock(); }
static BOOL getCanProcessInPlace (id self, SEL) { return _this (self)->getCanProcessInPlace() ? YES : NO; } static BOOL getCanProcessInPlace (id self, SEL) { return _this (self)->getCanProcessInPlace() ? YES : NO; }
static BOOL getRenderingOffline (id self, SEL) { return _this (self)->getRenderingOffline() ? YES : NO; } static BOOL getRenderingOffline (id self, SEL) { return _this (self)->getRenderingOffline() ? YES : NO; }
static void setRenderingOffline (id self, SEL, BOOL renderingOffline) { _this (self)->setRenderingOffline (renderingOffline); } static void setRenderingOffline (id self, SEL, BOOL renderingOffline) { _this (self)->setRenderingOffline (renderingOffline); }
static NSArray<NSNumber*>* getChannelCapabilities (id self, SEL) { return _this (self)->getChannelCapabilities(); }
static BOOL allocateRenderResourcesAndReturnError (id self, SEL, NSError** error) { return _this (self)->allocateRenderResourcesAndReturnError (error) ? YES : NO; }
static void deallocateRenderResources (id self, SEL) { _this (self)->deallocateRenderResources(); }
//==============================================================================
static NSString* getContextName (id self, SEL) { return _this (self)->getContextName(); }
static void setContextName (id self, SEL, NSString* str) { return _this (self)->setContextName (str); }
//==============================================================================
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
static NSIndexSet* getSupportedViewConfigurations (id self, SEL, NSArray<AUAudioUnitViewConfiguration*>* configs) { return _this (self)->getSupportedViewConfigurations (configs); }
static void selectViewConfiguration (id self, SEL, AUAudioUnitViewConfiguration* config) { _this (self)->selectViewConfiguration (config); }
#endif
}; };
static JuceAudioUnitv3Base* create (AUAudioUnit*, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**); static JuceAudioUnitv3Base* create (AUAudioUnit*, AudioComponentDescription, AudioComponentInstantiationOptions, NSError**);
@@ -410,16 +483,14 @@ public:
addAudioUnitBusses (false); addAudioUnitBusses (false);
} }
//==============================================================================
AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; } AudioProcessor& getAudioProcessor() const noexcept { return **processorHolder; }
AUAudioUnitBusArray* getInputBusses() override { return inputBusses; }
AUAudioUnitBusArray* getOutputBusses() override { return outputBusses; }
AUParameterTree* getParameterTree() override { return paramTree; }
AUInternalRenderBlock getInternalRenderBlock() override { return internalRenderBlock; }
NSArray<AUAudioUnitPreset*>* getFactoryPresets() override { return factoryPresets; }
bool getRenderingOffline() override { return getAudioProcessor().isNonRealtime(); }
void setRenderingOffline (bool offline) override { getAudioProcessor().setNonRealtime (offline); }
NSArray<NSNumber*>* getChannelCapabilities() override { return channelCapabilities; }
//==============================================================================
void reset() override
{
midiMessages.clear();
lastTimeStamp.mSampleTime = std::numeric_limits<Float64>::max();
}
//============================================================================== //==============================================================================
AUAudioUnitPreset* getCurrentPreset() override AUAudioUnitPreset* getCurrentPreset() override
@@ -442,7 +513,11 @@ public:
getAudioProcessor().setCurrentProgram (idx); getAudioProcessor().setCurrentProgram (idx);
} }
//==============================================================================
NSArray<AUAudioUnitPreset*>* getFactoryPresets() override
{
return factoryPresets;
}
NSDictionary<NSString*, id>* getFullState() override NSDictionary<NSString*, id>* getFullState() override
{ {
NSMutableDictionary<NSString*, id>* retval = [[NSMutableDictionary<NSString*, id> alloc] init]; NSMutableDictionary<NSString*, id>* retval = [[NSMutableDictionary<NSString*, id> alloc] init];
@@ -508,7 +583,11 @@ public:
[modifiedState release]; [modifiedState release];
} }
//==============================================================================
AUParameterTree* getParameterTree() override
{
return paramTree;
}
NSArray<NSNumber*>* parametersForOverviewWithCount (int count) override NSArray<NSNumber*>* parametersForOverviewWithCount (int count) override
{ {
const int n = static_cast<int> ([overviewParams count]); const int n = static_cast<int> ([overviewParams count]);
@@ -522,6 +601,68 @@ public:
return [retval autorelease]; return [retval autorelease];
} }
//==============================================================================
NSTimeInterval getLatency() override
{
auto& p = getAudioProcessor();
return p.getLatencySamples() / p.getSampleRate();
}
NSTimeInterval getTailTime() override
{
return getAudioProcessor().getTailLengthSeconds();
}
//==============================================================================
AUAudioUnitBusArray* getInputBusses() override { return inputBusses; }
AUAudioUnitBusArray* getOutputBusses() override { return outputBusses; }
NSArray<NSNumber*>* getChannelCapabilities() override { return channelCapabilities; }
bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* auBus) override
{
const bool isInput = ([auBus busType] == AUAudioUnitBusTypeInput);
const int busIdx = static_cast<int> ([auBus index]);
const int newNumChannels = static_cast<int> ([format channelCount]);
AudioProcessor& processor = getAudioProcessor();
if (AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx))
{
#ifdef JucePlugin_PreferredChannelConfigurations
ignoreUnused (bus);
short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
if (! AudioUnitHelpers::isLayoutSupported (processor, isInput, busIdx, newNumChannels, configs))
return false;
#else
const AVAudioChannelLayout* layout = [format channelLayout];
const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0);
if (layoutTag != 0)
{
AudioChannelSet newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag);
if (newLayout.size() != newNumChannels)
return false;
if (! bus->isLayoutSupported (newLayout))
return false;
}
else
{
if (! bus->isNumberOfChannelsSupported (newNumChannels))
return false;
}
#endif
return true;
}
return false;
}
//==============================================================================
int getVirtualMIDICableCount() override int getVirtualMIDICableCount() override
{ {
#if JucePlugin_WantsMidiInput #if JucePlugin_WantsMidiInput
@@ -531,6 +672,38 @@ public:
#endif #endif
} }
bool getSupportsMPE() override
{
return getAudioProcessor().supportsMPE();
}
NSArray<NSString*>* getMIDIOutputNames() override
{
#if JucePlugin_ProducesMidiOutput
return @[@"MIDI Out"];
#else
return @[];
#endif
}
//==============================================================================
AUInternalRenderBlock getInternalRenderBlock() override { return internalRenderBlock; }
bool getRenderingOffline() override { return getAudioProcessor().isNonRealtime(); }
void setRenderingOffline (bool offline) override { getAudioProcessor().setNonRealtime (offline); }
//==============================================================================
NSString* getContextName() const override { return juceStringToNS (contextName); }
void setContextName (NSString* str) override
{
if (str != nullptr)
{
AudioProcessor::TrackProperties props;
props.name = nsStringToJuce (str);
getAudioProcessor().updateTrackProperties (props);
}
}
//============================================================================== //==============================================================================
bool allocateRenderResourcesAndReturnError (NSError **outError) override bool allocateRenderResourcesAndReturnError (NSError **outError) override
{ {
@@ -563,13 +736,7 @@ public:
const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0); const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0);
if (layoutTag != 0) if (layoutTag != 0)
{
AudioChannelLayout caLayout;
zerostruct (caLayout);
caLayout.mChannelLayoutTag = layoutTag;
newLayout = CoreAudioLayouts::fromCoreAudio (caLayout);
}
newLayout = CoreAudioLayouts::fromCoreAudio (layoutTag);
else else
newLayout = bus->supportedLayoutWithChannels (static_cast<int> ([format channelCount])); newLayout = bus->supportedLayoutWithChannels (static_cast<int> ([format channelCount]));
@@ -641,60 +808,45 @@ public:
JuceAudioUnitv3Base::deallocateRenderResources(); JuceAudioUnitv3Base::deallocateRenderResources();
} }
void reset() override
{
midiMessages.clear();
lastTimeStamp.mSampleTime = std::numeric_limits<Float64>::max();
}
//============================================================================== //==============================================================================
bool shouldChangeToFormat (AVAudioFormat* format, AUAudioUnitBus* auBus) override
#if JUCE_AUV3_VIEW_CONFIG_SUPPORTED
NSIndexSet* getSupportedViewConfigurations (NSArray<AUAudioUnitViewConfiguration*>* configs) override
{ {
const bool isInput = ([auBus busType] == AUAudioUnitBusTypeInput);
const int busIdx = static_cast<int> ([auBus index]);
const int newNumChannels = static_cast<int> ([format channelCount]);
auto supportedViewIndecies = [[NSMutableIndexSet alloc] init];
auto n = [configs count];
AudioProcessor& processor = getAudioProcessor();
if (AudioProcessor::Bus* bus = processor.getBus (isInput, busIdx))
if (auto* editor = getAudioProcessor().createEditorIfNeeded())
{ {
#ifdef JucePlugin_PreferredChannelConfigurations
ignoreUnused (bus);
short configs[][2] = {JucePlugin_PreferredChannelConfigurations};
// If you hit this assertion then your plug-in's editor is reporting that it doesn't support
// any host MIDI controller configurations!
jassert (editor->supportsHostMIDIControllerPresence (true) || editor->supportsHostMIDIControllerPresence (false));
if (! AudioUnitHelpers::isLayoutSupported (processor, isInput, busIdx, newNumChannels, configs))
return false;
#else
const AVAudioChannelLayout* layout = [format channelLayout];
const AudioChannelLayoutTag layoutTag = (layout != nullptr ? [layout layoutTag] : 0);
if (layoutTag != 0)
{
AudioChannelLayout caLayout;
zerostruct (caLayout);
caLayout.mChannelLayoutTag = layoutTag;
AudioChannelSet newLayout = CoreAudioLayouts::fromCoreAudio (caLayout);
if (newLayout.size() != newNumChannels)
return false;
if (! bus->isLayoutSupported (newLayout))
return false;
}
else
for (auto i = 0u; i < n; ++i)
{ {
if (! bus->isNumberOfChannelsSupported (newNumChannels))
return false;
if (auto* viewConfiguration = [configs objectAtIndex:i])
{
if (editor->supportsHostMIDIControllerPresence ([viewConfiguration hostHasController] == YES))
{
auto* constrainer = editor->getConstrainer();
auto height = (int) [viewConfiguration height];
auto width = (int) [viewConfiguration width];
if (height <= constrainer->getMaximumHeight() && height >= constrainer->getMinimumHeight()
&& width <= constrainer->getMaximumWidth() && width >= constrainer->getMinimumWidth())
[supportedViewIndecies addIndex: i];
}
}
} }
#endif
return true;
} }
return false;
return [supportedViewIndecies autorelease];
}
void selectViewConfiguration (AUAudioUnitViewConfiguration* config) override
{
processorHolder->viewConfiguration = new AudioProcessorHolder::ViewConfig { [config width], [config height], [config hostHasController] == YES };
} }
#endif
//============================================================================== //==============================================================================
void audioProcessorChanged (AudioProcessor* processor) override void audioProcessorChanged (AudioProcessor* processor) override
@@ -720,15 +872,6 @@ public:
} }
} }
//==============================================================================
NSTimeInterval getLatency() override
{
auto& p = getAudioProcessor();
return p.getLatencySamples() / p.getSampleRate();
}
NSTimeInterval getTailTime() override { return getAudioProcessor().getTailLengthSeconds(); }
//============================================================================== //==============================================================================
bool getCurrentPosition (CurrentPositionInfo& info) override bool getCurrentPosition (CurrentPositionInfo& info) override
{ {
@@ -802,6 +945,7 @@ public:
return true; return true;
} }
//==============================================================================
static void removeEditor (AudioProcessor& processor) static void removeEditor (AudioProcessor& processor)
{ {
ScopedLock editorLock (processor.getCallbackLock()); ScopedLock editorLock (processor.getCallbackLock());
@@ -818,7 +962,7 @@ private:
struct BusBuffer struct BusBuffer
{ {
BusBuffer (AUAudioUnitBus* bus, int maxFramesPerBuffer) BusBuffer (AUAudioUnitBus* bus, int maxFramesPerBuffer)
: auBus (bus), bufferList (nullptr),
: auBus (bus),
maxFrames (maxFramesPerBuffer), maxFrames (maxFramesPerBuffer),
numberOfChannels (static_cast<int> ([[auBus format] channelCount])), numberOfChannels (static_cast<int> ([[auBus format] channelCount])),
isInterleaved ([[auBus format] isInterleaved]) isInterleaved ([[auBus format] isInterleaved])
@@ -893,7 +1037,7 @@ private:
private: private:
AUAudioUnitBus* auBus; AUAudioUnitBus* auBus;
HeapBlock<char> bufferListStorage; HeapBlock<char> bufferListStorage;
AudioBufferList* bufferList;
AudioBufferList* bufferList = nullptr;
int maxFrames, numberOfChannels; int maxFrames, numberOfChannels;
bool isInterleaved; bool isInterleaved;
AudioSampleBuffer scratchBuffer; AudioSampleBuffer scratchBuffer;
@@ -1048,6 +1192,7 @@ private:
static_cast<int> (maxFrames))); static_cast<int> (maxFrames)));
} }
//==============================================================================
void processEvents (const AURenderEvent *__nullable realtimeEventListHead, int numParams, AUEventSampleTime startTime) void processEvents (const AURenderEvent *__nullable realtimeEventListHead, int numParams, AUEventSampleTime startTime)
{ {
for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; event = event->head.next) for (const AURenderEvent* event = realtimeEventListHead; event != nullptr; event = event->head.next)
@@ -1175,6 +1320,17 @@ private:
// process audio // process audio
processBlock (audioBuffer.getBuffer (frameCount), midiMessages); processBlock (audioBuffer.getBuffer (frameCount), midiMessages);
// send MIDI
#if JucePlugin_ProducesMidiOutput && JUCE_AUV3_MIDI_OUTPUT_SUPPORTED
auto midiOut = [au MIDIOutputEventBlock];
MidiMessage msg;
int samplePosition;
for (MidiBuffer::Iterator it (midiMessages); it.getNextEvent (msg, samplePosition);)
midiOut (samplePosition, 0, msg.getRawDataSize(), msg.getRawData());
#endif
midiMessages.clear(); midiMessages.clear();
} }
@@ -1288,8 +1444,8 @@ private:
AUParameterObserverToken editorObserverToken; AUParameterObserverToken editorObserverToken;
ScopedPointer<AUParameterTree> paramTree; ScopedPointer<AUParameterTree> paramTree;
ScopedPointer<NSMutableArray<NSNumber*> > overviewParams;
ScopedPointer<NSMutableArray<NSNumber*> > channelCapabilities;
ScopedPointer<NSMutableArray<NSNumber*>> overviewParams;
ScopedPointer<NSMutableArray<NSNumber*>> channelCapabilities;
ScopedPointer<NSMutableArray<AUAudioUnitPreset*> > factoryPresets; ScopedPointer<NSMutableArray<AUAudioUnitPreset*> > factoryPresets;
@@ -1306,6 +1462,8 @@ private:
AudioTimeStamp lastTimeStamp; AudioTimeStamp lastTimeStamp;
CurrentPositionInfo lastAudioHead; CurrentPositionInfo lastAudioHead;
String contextName;
}; };
const double JuceAudioUnitv3::kDefaultSampleRate = 44100.0; const double JuceAudioUnitv3::kDefaultSampleRate = 44100.0;
@@ -1320,9 +1478,8 @@ JuceAudioUnitv3Base* JuceAudioUnitv3Base::create (AUAudioUnit* audioUnit, AudioC
class JuceAUViewController class JuceAUViewController
{ {
public: public:
JuceAUViewController (AUViewController<AUAudioUnitFactory>* p) JuceAUViewController (AUViewController<AUAudioUnitFactory>* p)
: myself (p), processorHolder (nullptr), preferredSize (1.0f, 1.0f)
: myself (p)
{ {
jassert (MessageManager::getInstance()->isThisTheMessageThread()); jassert (MessageManager::getInstance()->isThisTheMessageThread());
@@ -1370,6 +1527,9 @@ public:
{ {
if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor()) if (AudioProcessorEditor* editor = getAudioProcessor().getActiveEditor())
{ {
if (processorHolder->viewConfiguration != nullptr)
editor->hostMIDIControllerIsAvailable (processorHolder->viewConfiguration->hostHasMIDIController);
editor->setBounds (convertToRectInt ([[myself view] bounds])); editor->setBounds (convertToRectInt ([[myself view] bounds]));
if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0]) if (JUCE_IOS_MAC_VIEW* peerView = [[[myself view] subviews] objectAtIndex: 0])
@@ -1433,8 +1593,8 @@ public:
private: private:
//============================================================================== //==============================================================================
AUViewController<AUAudioUnitFactory>* myself; AUViewController<AUAudioUnitFactory>* myself;
AudioProcessorHolder::Ptr processorHolder;
Rectangle<int> preferredSize;
AudioProcessorHolder::Ptr processorHolder = nullptr;
Rectangle<int> preferredSize { 1, 1 };
//============================================================================== //==============================================================================
AUAudioUnit* createAudioUnitOnMessageThread (const AudioComponentDescription& descr, NSError** error) AUAudioUnit* createAudioUnitOnMessageThread (const AudioComponentDescription& descr, NSError** error)


+ 1
- 11
libs/juce/source/modules/juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h View File

@@ -520,22 +520,12 @@ private:
if (newMidiDevices != lastMidiDevices) if (newMidiDevices != lastMidiDevices)
{ {
for (auto& oldDevice : lastMidiDevices) for (auto& oldDevice : lastMidiDevices)
{
if (! newMidiDevices.contains (oldDevice)) if (! newMidiDevices.contains (oldDevice))
{
deviceManager.setMidiInputEnabled (oldDevice, false); deviceManager.setMidiInputEnabled (oldDevice, false);
deviceManager.removeMidiInputCallback (oldDevice, &player);
}
}
for (auto& newDevice : newMidiDevices) for (auto& newDevice : newMidiDevices)
{
if (! lastMidiDevices.contains (newDevice)) if (! lastMidiDevices.contains (newDevice))
{
deviceManager.addMidiInputCallback (newDevice, &player);
deviceManager.setMidiInputEnabled (newDevice, true); deviceManager.setMidiInputEnabled (newDevice, true);
}
}
} }
} }
#endif #endif
@@ -552,7 +542,7 @@ private:
that the other plugin wrappers use. that the other plugin wrappers use.
*/ */
class StandaloneFilterWindow : public DocumentWindow, class StandaloneFilterWindow : public DocumentWindow,
public ButtonListener // (can't use Button::Listener due to VC2005 bug)
public Button::Listener
{ {
public: public:
//============================================================================== //==============================================================================


+ 3
- 1
libs/juce/source/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp View File

@@ -1320,7 +1320,9 @@ public:
if (auto host = wrapper.hostCallback) if (auto host = wrapper.hostCallback)
{ {
if (host (wrapper.getVstEffectInterface(), hostOpcodeCanHostDo, 0, 0, const_cast<char*> ("sizeWindow"), 0) == (pointer_sized_int) 1)
auto status = host (wrapper.getVstEffectInterface(), hostOpcodeCanHostDo, 0, 0, const_cast<char*> ("sizeWindow"), 0);
if (status == (pointer_sized_int) 1 || getHostType().isAbletonLive())
{ {
isInSizeWindow = true; isInSizeWindow = true;
sizeWasSuccessful = (host (wrapper.getVstEffectInterface(), hostOpcodeWindowSize, newWidth, newHeight, 0, 0) != 0); sizeWasSuccessful = (host (wrapper.getVstEffectInterface(), hostOpcodeWindowSize, newWidth, newHeight, 0, 0) != 0);


+ 38
- 0
libs/juce/source/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -115,6 +115,7 @@ class JuceVST3Component;
//============================================================================== //==============================================================================
class JuceVST3EditController : public Vst::EditController, class JuceVST3EditController : public Vst::EditController,
public Vst::IMidiMapping, public Vst::IMidiMapping,
public Vst::ChannelContext::IInfoListener,
public AudioProcessorListener public AudioProcessorListener
{ {
public: public:
@@ -147,6 +148,7 @@ public:
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController2) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IEditController2)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IMidiMapping) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IMidiMapping)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IPluginBase, Vst::IEditController) TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IPluginBase, Vst::IEditController)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IDependent, Vst::IEditController) TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, IDependent, Vst::IEditController)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IEditController) TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IEditController)
@@ -429,6 +431,41 @@ public:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter)
}; };
//==============================================================================
tresult PLUGIN_API setChannelContextInfos (Vst::IAttributeList* list) override
{
if (auto* instance = getPluginInstance())
{
if (list != nullptr)
{
AudioProcessor::TrackProperties trackProperties;
{
Vst::String128 channelName;
if (list->getString (Vst::ChannelContext::kChannelNameKey, channelName, sizeof (channelName)) == kResultTrue)
trackProperties.name = toString (channelName);
}
{
int64 colour;
if (list->getInt (Vst::ChannelContext::kChannelColorKey, colour) == kResultTrue)
trackProperties.colour = Colour (Vst::ChannelContext::GetRed ((uint32) colour), Vst::ChannelContext::GetGreen ((uint32) colour),
Vst::ChannelContext::GetBlue ((uint32) colour), Vst::ChannelContext::GetAlpha ((uint32) colour));
}
if (MessageManager::getInstance()->isThisTheMessageThread())
instance->updateTrackProperties (trackProperties);
else
MessageManager::callAsync ([trackProperties, instance] ()
{ instance->updateTrackProperties (trackProperties); });
}
}
return kResultOk;
}
//============================================================================== //==============================================================================
tresult PLUGIN_API setComponentState (IBStream* stream) override tresult PLUGIN_API setComponentState (IBStream* stream) override
{ {
@@ -1120,6 +1157,7 @@ public:
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IAudioProcessor) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IAudioProcessor)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IUnitInfo) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IUnitInfo)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint) TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::IConnectionPoint)
TEST_FOR_AND_RETURN_IF_VALID (targetIID, Vst::ChannelContext::IInfoListener)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IComponent) TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (targetIID, FUnknown, Vst::IComponent)
if (doUIDsMatch (targetIID, JuceAudioProcessor::iid)) if (doUIDsMatch (targetIID, JuceAudioProcessor::iid))


+ 11
- 7
libs/juce/source/modules/juce_audio_plugin_client/juce_audio_plugin_client_AU_2.mm View File

@@ -35,9 +35,14 @@
#pragma clang diagnostic ignored "-Wextra-semi" #pragma clang diagnostic ignored "-Wextra-semi"
#endif #endif
#ifdef _MSC_VER
#pragma warning (push)
// #pragma warning (disable : 4127)
// From MacOS 10.13 and iOS 11 Apple has (sensibly!) stopped defining a whole
// set of functions with rather generic names. However, we still need a couple
// of them to compile the files below.
#ifndef verify
#define verify(assertion) __Verify(assertion)
#endif
#ifndef verify_noerr
#define verify_noerr(errorCode) __Verify_noErr(errorCode)
#endif #endif
#include "AU/CoreAudioUtilityClasses/AUBase.cpp" #include "AU/CoreAudioUtilityClasses/AUBase.cpp"
@@ -60,10 +65,9 @@
#include "AU/CoreAudioUtilityClasses/ComponentBase.cpp" #include "AU/CoreAudioUtilityClasses/ComponentBase.cpp"
#include "AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp" #include "AU/CoreAudioUtilityClasses/MusicDeviceBase.cpp"
#undef verify
#undef verify_noerr
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifdef _MSC_VER
#pragma warning (pop)
#endif

+ 20
- 7
libs/juce/source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -1065,6 +1065,19 @@ public:
jassertfalse; // xxx not implemented! jassertfalse; // xxx not implemented!
} }
//==============================================================================
void updateTrackProperties (const TrackProperties& properties) override
{
if (properties.name.isNotEmpty())
{
CFStringRef contextName = properties.name.toCFString();
AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ContextName, kAudioUnitScope_Global,
0, &contextName, sizeof (CFStringRef));
CFRelease (contextName);
}
}
//============================================================================== //==============================================================================
void getStateInformation (MemoryBlock& destData) override void getStateInformation (MemoryBlock& destData) override
{ {
@@ -1128,6 +1141,7 @@ public:
void refreshParameterList() override void refreshParameterList() override
{ {
parameters.clear(); parameters.clear();
paramIDToIndex.clear();
if (audioUnit != nullptr) if (audioUnit != nullptr)
{ {
@@ -1158,6 +1172,7 @@ public:
ParamInfo* const param = new ParamInfo(); ParamInfo* const param = new ParamInfo();
parameters.add (param); parameters.add (param);
param->paramID = ids[i]; param->paramID = ids[i];
paramIDToIndex[ids[i]] = i;
param->minValue = info.minValue; param->minValue = info.minValue;
param->maxValue = info.maxValue; param->maxValue = info.maxValue;
param->automatable = (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0; param->automatable = (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0;
@@ -1250,6 +1265,7 @@ private:
}; };
OwnedArray<ParamInfo> parameters; OwnedArray<ParamInfo> parameters;
std::unordered_map<AudioUnitParameterID, int> paramIDToIndex;
MidiDataConcatenator midiConcatenator; MidiDataConcatenator midiConcatenator;
CriticalSection midiInLock; CriticalSection midiInLock;
@@ -1335,13 +1351,10 @@ private:
|| event.mEventType == kAudioUnitEvent_BeginParameterChangeGesture || event.mEventType == kAudioUnitEvent_BeginParameterChangeGesture
|| event.mEventType == kAudioUnitEvent_EndParameterChangeGesture) || event.mEventType == kAudioUnitEvent_EndParameterChangeGesture)
{ {
for (paramIndex = 0; paramIndex < parameters.size(); ++paramIndex)
{
const ParamInfo& p = *parameters.getUnchecked(paramIndex);
auto it = paramIDToIndex.find (event.mArgument.mParameter.mParameterID)
if (p.paramID == event.mArgument.mParameter.mParameterID)
break;
}
if (it != paramIDToIndex.end())
paramIndex = it->second;
if (! isPositiveAndBelow (paramIndex, parameters.size())) if (! isPositiveAndBelow (paramIndex, parameters.size()))
return; return;
@@ -1351,7 +1364,7 @@ private:
{ {
case kAudioUnitEvent_ParameterValueChange: case kAudioUnitEvent_ParameterValueChange:
{ {
const ParamInfo& p = *parameters.getUnchecked(paramIndex);
auto& p = *parameters.getUnchecked (paramIndex);
sendParamChangeMessageToListeners (paramIndex, (newValue - p.minValue) / (p.maxValue - p.minValue)); sendParamChangeMessageToListeners (paramIndex, (newValue - p.minValue) / (p.maxValue - p.minValue));
} }
break; break;


+ 3
- 0
libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3Headers.h View File

@@ -68,6 +68,7 @@
#include <pluginterfaces/base/ipluginbase.h> #include <pluginterfaces/base/ipluginbase.h>
#include <pluginterfaces/base/ustring.h> #include <pluginterfaces/base/ustring.h>
#include <pluginterfaces/gui/iplugview.h> #include <pluginterfaces/gui/iplugview.h>
#include <pluginterfaces/gui/iplugviewcontentscalesupport.h>
#include <pluginterfaces/vst/ivstattributes.h> #include <pluginterfaces/vst/ivstattributes.h>
#include <pluginterfaces/vst/ivstaudioprocessor.h> #include <pluginterfaces/vst/ivstaudioprocessor.h>
#include <pluginterfaces/vst/ivstcomponent.h> #include <pluginterfaces/vst/ivstcomponent.h>
@@ -83,6 +84,7 @@
#include <pluginterfaces/vst/vsttypes.h> #include <pluginterfaces/vst/vsttypes.h>
#include <pluginterfaces/vst/ivstunits.h> #include <pluginterfaces/vst/ivstunits.h>
#include <pluginterfaces/vst/ivstmidicontrollers.h> #include <pluginterfaces/vst/ivstmidicontrollers.h>
#include <pluginterfaces/vst/ivstchannelcontextinfo.h>
#include <public.sdk/source/common/memorystream.h> #include <public.sdk/source/common/memorystream.h>
#include <public.sdk/source/vst/vsteditcontroller.h> #include <public.sdk/source/vst/vsteditcontroller.h>
#else #else
@@ -105,6 +107,7 @@
#include <pluginterfaces/gui/iplugview.h> #include <pluginterfaces/gui/iplugview.h>
#include <pluginterfaces/gui/iplugviewcontentscalesupport.h> #include <pluginterfaces/gui/iplugviewcontentscalesupport.h>
#include <pluginterfaces/vst/ivstmidicontrollers.h> #include <pluginterfaces/vst/ivstmidicontrollers.h>
#include <pluginterfaces/vst/ivstchannelcontextinfo.h>
#include <public.sdk/source/common/memorystream.cpp> #include <public.sdk/source/common/memorystream.cpp>
#include <public.sdk/source/common/pluginview.cpp> #include <public.sdk/source/common/pluginview.cpp>
#include <public.sdk/source/vst/vsteditcontroller.cpp> #include <public.sdk/source/vst/vsteditcontroller.cpp>


+ 64
- 0
libs/juce/source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -2101,6 +2101,67 @@ struct VST3PluginInstance : public AudioPluginInstance
return result; return result;
} }
//==============================================================================
void updateTrackProperties (const TrackProperties& properties) override
{
if (trackInfoListener != nullptr)
{
ComSmartPtr<Vst::IAttributeList> l (new TrackPropertiesAttributeList (properties));
trackInfoListener->setChannelContextInfos (l);
}
}
struct TrackPropertiesAttributeList : public Vst::IAttributeList
{
TrackPropertiesAttributeList (const TrackProperties& properties) : props (properties) {}
virtual ~TrackPropertiesAttributeList() {}
JUCE_DECLARE_VST3_COM_REF_METHODS
tresult PLUGIN_API queryInterface (const TUID queryIid, void** obj) override
{
TEST_FOR_AND_RETURN_IF_VALID (queryIid, Vst::IAttributeList)
TEST_FOR_COMMON_BASE_AND_RETURN_IF_VALID (queryIid, FUnknown, Vst::IAttributeList)
*obj = nullptr;
return kNotImplemented;
}
tresult PLUGIN_API setInt (AttrID, Steinberg::int64) override { return kOutOfMemory; }
tresult PLUGIN_API setFloat (AttrID, double) override { return kOutOfMemory; }
tresult PLUGIN_API setString (AttrID, const Vst::TChar*) override { return kOutOfMemory; }
tresult PLUGIN_API setBinary (AttrID, const void*, Steinberg::uint32) override { return kOutOfMemory; }
tresult PLUGIN_API getFloat (AttrID, double&) override { return kResultFalse; }
tresult PLUGIN_API getBinary (AttrID, const void*&, Steinberg::uint32&) override { return kResultFalse; }
tresult PLUGIN_API getString (AttrID id, Vst::TChar* string, Steinberg::uint32 size) override
{
if (! std::strcmp (id, Vst::ChannelContext::kChannelNameKey))
{
Steinberg::String str (props.name.toRawUTF8());
str.copyTo (string, 0, (Steinberg::int32) jmin (size, (Steinberg::uint32) std::numeric_limits<Steinberg::int32>::max()));
return kResultTrue;
}
return kResultFalse;
}
tresult PLUGIN_API getInt (AttrID id, Steinberg::int64& value) override
{
if (! std::strcmp (Vst::ChannelContext::kChannelNameLengthKey, id)) value = props.name.length();
else if (! std::strcmp (Vst::ChannelContext::kChannelColorKey, id)) value = static_cast<Steinberg::int64> (props.colour.getARGB());
else return kResultFalse;
return kResultTrue;
}
Atomic<int> refCount;
TrackProperties props;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TrackPropertiesAttributeList)
};
//============================================================================== //==============================================================================
String getChannelName (int channelIndex, bool forInput, bool forAudioChannel) const String getChannelName (int channelIndex, bool forInput, bool forAudioChannel) const
{ {
@@ -2450,6 +2511,7 @@ private:
ComSmartPtr<Vst::IUnitData> unitData; ComSmartPtr<Vst::IUnitData> unitData;
ComSmartPtr<Vst::IProgramListData> programListData; ComSmartPtr<Vst::IProgramListData> programListData;
ComSmartPtr<Vst::IConnectionPoint> componentConnection, editControllerConnection; ComSmartPtr<Vst::IConnectionPoint> componentConnection, editControllerConnection;
ComSmartPtr<Vst::ChannelContext::IInfoListener> trackInfoListener;
/** The number of IO buses MUST match that of the plugin, /** The number of IO buses MUST match that of the plugin,
even if there aren't enough channels to process, even if there aren't enough channels to process,
@@ -2534,6 +2596,7 @@ private:
editController2.loadFrom (holder->component); editController2.loadFrom (holder->component);
componentHandler.loadFrom (holder->component); componentHandler.loadFrom (holder->component);
componentHandler2.loadFrom (holder->component); componentHandler2.loadFrom (holder->component);
trackInfoListener.loadFrom (holder->component);
if (processor == nullptr) processor.loadFrom (editController); if (processor == nullptr) processor.loadFrom (editController);
if (unitInfo == nullptr) unitInfo.loadFrom (editController); if (unitInfo == nullptr) unitInfo.loadFrom (editController);
@@ -2542,6 +2605,7 @@ private:
if (editController2 == nullptr) editController2.loadFrom (editController); if (editController2 == nullptr) editController2.loadFrom (editController);
if (componentHandler == nullptr) componentHandler.loadFrom (editController); if (componentHandler == nullptr) componentHandler.loadFrom (editController);
if (componentHandler2 == nullptr) componentHandler2.loadFrom (editController); if (componentHandler2 == nullptr) componentHandler2.loadFrom (editController);
if (trackInfoListener == nullptr) trackInfoListener.loadFrom (editController);
} }
void setStateForAllMidiBuses (bool newState) void setStateForAllMidiBuses (bool newState)


+ 2
- 2
libs/juce/source/modules/juce_audio_processors/format_types/juce_VSTCommon.h View File

@@ -180,8 +180,8 @@ struct SpeakerMappings : private AudioChannelSet // (inheritance only to give e
VstSpeakerConfiguration* allocate (int numChannels) VstSpeakerConfiguration* allocate (int numChannels)
{ {
auto arrangementSize = (sizeof (VstSpeakerConfiguration) - (sizeof(VstIndividualSpeakerInfo) * 8))
+ (sizeof (VstIndividualSpeakerInfo) * static_cast<size_t> (numChannels));
auto arrangementSize = sizeof (VstSpeakerConfiguration)
+ sizeof (VstIndividualSpeakerInfo) * static_cast<size_t> (jmax (8, numChannels) - 8);
storage.malloc (1, arrangementSize); storage.malloc (1, arrangementSize);
return storage.getData(); return storage.getData();


+ 3
- 0
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -1029,6 +1029,9 @@ void AudioProcessor::setCurrentProgramStateInformation (const void* data, int si
setStateInformation (data, sizeInBytes); setStateInformation (data, sizeInBytes);
} }
//==============================================================================
void AudioProcessor::updateTrackProperties (const AudioProcessor::TrackProperties&) {}
//============================================================================== //==============================================================================
// magic number to identify memory blocks that we've stored as XML // magic number to identify memory blocks that we've stored as XML
const uint32 magicXmlNumber = 0x21324356; const uint32 magicXmlNumber = 0x21324356;


+ 26
- 0
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -1320,6 +1320,32 @@ public:
*/ */
WrapperType wrapperType; WrapperType wrapperType;
/** A struct containing information about the DAW track inside which your
AudioProcessor is loaded. */
struct TrackProperties
{
String name; // The name of the track - this will be empty if the track name is not known
Colour colour; // The colour of the track - this will be transparentBlack if the colour is not known
// other properties may be added in the future
};
/** Informs the AudioProcessor that track properties such as the track's name or
colour has been changed.
If you are hosting this AudioProcessor then use this method to inform the
AudioProcessor about which track the AudioProcessor is loaded on. This method
may only be called on the message thread.
If you are implemeting an AudioProcessor then you can override this callback
to do something useful with the track properties such as changing the colour
of your AudioProcessor's editor. It's entirely up to the host when and how
often this callback will be called.
The default implementation of this callback will do nothing.
*/
virtual void updateTrackProperties (const TrackProperties& properties);
//============================================================================== //==============================================================================
#ifndef DOXYGEN #ifndef DOXYGEN
/** Deprecated: use getTotalNumInputChannels instead. */ /** Deprecated: use getTotalNumInputChannels instead. */


+ 4
- 1
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.cpp View File

@@ -45,7 +45,10 @@ AudioProcessorEditor::~AudioProcessorEditor()
} }
void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {} void AudioProcessorEditor::setControlHighlight (ParameterControlHighlightInfo) {}
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
int AudioProcessorEditor::getControlParameterIndex (Component&) { return -1; }
bool AudioProcessorEditor::supportsHostMIDIControllerPresence (bool) { return true; }
void AudioProcessorEditor::hostMIDIControllerIsAvailable (bool) {}
void AudioProcessorEditor::initialise() void AudioProcessorEditor::initialise()
{ {


+ 22
- 0
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorEditor.h View File

@@ -85,6 +85,28 @@ public:
*/ */
virtual int getControlParameterIndex (Component&); virtual int getControlParameterIndex (Component&);
/** Override this method to indicate if your editor supports the presence or
absence of a host-provided MIDI controller.
Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later)
support this functionality, and even then the host may choose to ignore this
information.
The default behaviour is to report support for both cases.
*/
virtual bool supportsHostMIDIControllerPresence (bool hostMIDIControllerIsAvailable);
/** Called to indicate if a host is providing a MIDI controller when the host
reconfigures its layout.
Use this as an opportunity to hide or display your own onscreen keyboard or
other input component.
Currently only AUv3 plug-ins compiled for MacOS 10.13 or iOS 11.0 (or later)
support this functionality.
*/
virtual void hostMIDIControllerIsAvailable (bool controllerIsAvailable);
/** Can be called by a host to tell the editor that it should use a non-unity /** Can be called by a host to tell the editor that it should use a non-unity
GUI scale. GUI scale.
*/ */


+ 22
- 2
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.cpp View File

@@ -1466,6 +1466,7 @@ void AudioProcessorGraph::processAudio (AudioBuffer<FloatType>& buffer, MidiBuff
AudioBuffer<FloatType>& currentAudioOutputBuffer = audioBuffers->currentAudioOutputBuffer.get<FloatType>(); AudioBuffer<FloatType>& currentAudioOutputBuffer = audioBuffers->currentAudioOutputBuffer.get<FloatType>();
const int numSamples = buffer.getNumSamples(); const int numSamples = buffer.getNumSamples();
jassert (numSamples <= getBlockSize());
currentAudioInputBuffer = &buffer; currentAudioInputBuffer = &buffer;
currentAudioOutputBuffer.setSize (jmax (1, buffer.getNumChannels()), numSamples); currentAudioOutputBuffer.setSize (jmax (1, buffer.getNumChannels()), numSamples);
@@ -1488,6 +1489,25 @@ void AudioProcessorGraph::processAudio (AudioBuffer<FloatType>& buffer, MidiBuff
midiMessages.addEvents (currentMidiOutputBuffer, 0, buffer.getNumSamples(), 0); midiMessages.addEvents (currentMidiOutputBuffer, 0, buffer.getNumSamples(), 0);
} }
template <typename FloatType>
void AudioProcessorGraph::sliceAndProcess (AudioBuffer<FloatType>& buffer, MidiBuffer& midiMessages)
{
auto n = buffer.getNumSamples();
auto ch = buffer.getNumChannels();
auto max = 0;
for (auto pos = 0; pos < n; pos += max)
{
max = jmin (n - pos, getBlockSize());
AudioBuffer<FloatType> audioSlice (buffer.getArrayOfWritePointers(), ch, pos, max);
MidiBuffer midiSlice;
midiSlice.addEvents (midiMessages, pos, max, 0);
processAudio (audioSlice, midiSlice);
}
}
double AudioProcessorGraph::getTailLengthSeconds() const { return 0; } double AudioProcessorGraph::getTailLengthSeconds() const { return 0; }
bool AudioProcessorGraph::acceptsMidi() const { return true; } bool AudioProcessorGraph::acceptsMidi() const { return true; }
bool AudioProcessorGraph::producesMidi() const { return true; } bool AudioProcessorGraph::producesMidi() const { return true; }
@@ -1496,12 +1516,12 @@ void AudioProcessorGraph::setStateInformation (const void*, int) {}
void AudioProcessorGraph::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages) void AudioProcessorGraph::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{ {
processAudio (buffer, midiMessages);
sliceAndProcess (buffer, midiMessages);
} }
void AudioProcessorGraph::processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages) void AudioProcessorGraph::processBlock (AudioBuffer<double>& buffer, MidiBuffer& midiMessages)
{ {
processAudio (buffer, midiMessages);
sliceAndProcess (buffer, midiMessages);
} }
// explicit template instantiation // explicit template instantiation


+ 3
- 0
libs/juce/source/modules/juce_audio_processors/processors/juce_AudioProcessorGraph.h View File

@@ -380,6 +380,9 @@ private:
template <typename floatType> template <typename floatType>
void processAudio (AudioBuffer<floatType>& buffer, MidiBuffer& midiMessages); void processAudio (AudioBuffer<floatType>& buffer, MidiBuffer& midiMessages);
template <typename floatType>
void sliceAndProcess (AudioBuffer<floatType>& buffer, MidiBuffer& midiMessages);
//============================================================================== //==============================================================================
ReferenceCountedArray<Node> nodes; ReferenceCountedArray<Node> nodes;
OwnedArray<Connection> connections; OwnedArray<Connection> connections;


+ 1
- 1
libs/juce/source/modules/juce_audio_processors/scanning/juce_PluginListComponent.h View File

@@ -35,7 +35,7 @@
class JUCE_API PluginListComponent : public Component, class JUCE_API PluginListComponent : public Component,
public FileDragAndDropTarget, public FileDragAndDropTarget,
private ChangeListener, private ChangeListener,
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
private Button::Listener
{ {
public: public:
//============================================================================== //==============================================================================


+ 2
- 2
libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp View File

@@ -199,8 +199,8 @@ static String getNoDeviceString() { return "<< " + TRANS("none") + " >>"; }
//============================================================================== //==============================================================================
class AudioDeviceSettingsPanel : public Component, class AudioDeviceSettingsPanel : public Component,
private ChangeListener, private ChangeListener,
private ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug)
private ButtonListener
private ComboBox::Listener,
private Button::Listener
{ {
public: public:
AudioDeviceSettingsPanel (AudioIODeviceType& t, AudioDeviceSetupDetails& setupDetails, AudioDeviceSettingsPanel (AudioIODeviceType& t, AudioDeviceSetupDetails& setupDetails,


+ 1
- 1
libs/juce/source/modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.h View File

@@ -37,8 +37,8 @@
@see AudioDeviceManager @see AudioDeviceManager
*/ */
class JUCE_API AudioDeviceSelectorComponent : public Component, class JUCE_API AudioDeviceSelectorComponent : public Component,
private ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug)
private ChangeListener, private ChangeListener,
private ComboBox::Listener,
private Button::Listener, private Button::Listener,
private Timer private Timer
{ {


+ 6
- 6
libs/juce/source/modules/juce_audio_utils/players/juce_SoundPlayer.cpp View File

@@ -28,9 +28,9 @@
// This is an AudioTransportSource which will own it's assigned source // This is an AudioTransportSource which will own it's assigned source
struct AudioSourceOwningTransportSource : public AudioTransportSource struct AudioSourceOwningTransportSource : public AudioTransportSource
{ {
AudioSourceOwningTransportSource (PositionableAudioSource* s) : source (s)
AudioSourceOwningTransportSource (PositionableAudioSource* s, double sampleRate) : source (s)
{ {
AudioTransportSource::setSource (s);
AudioTransportSource::setSource (s, 0, nullptr, sampleRate);
} }
~AudioSourceOwningTransportSource() ~AudioSourceOwningTransportSource()
@@ -180,7 +180,7 @@ void SoundPlayer::play (const void* resourceData, size_t resourceSize)
void SoundPlayer::play (AudioFormatReader* reader, bool deleteWhenFinished) void SoundPlayer::play (AudioFormatReader* reader, bool deleteWhenFinished)
{ {
if (reader != nullptr) if (reader != nullptr)
play (new AudioFormatReaderSource (reader, deleteWhenFinished), true);
play (new AudioFormatReaderSource (reader, deleteWhenFinished), true, reader->sampleRate);
} }
void SoundPlayer::play (AudioSampleBuffer* buffer, bool deleteWhenFinished, bool playOnAllOutputChannels) void SoundPlayer::play (AudioSampleBuffer* buffer, bool deleteWhenFinished, bool playOnAllOutputChannels)
@@ -189,7 +189,7 @@ void SoundPlayer::play (AudioSampleBuffer* buffer, bool deleteWhenFinished, bool
play (new AudioSampleBufferSource (buffer, deleteWhenFinished, playOnAllOutputChannels), true); play (new AudioSampleBufferSource (buffer, deleteWhenFinished, playOnAllOutputChannels), true);
} }
void SoundPlayer::play (PositionableAudioSource* audioSource, bool deleteWhenFinished)
void SoundPlayer::play (PositionableAudioSource* audioSource, bool deleteWhenFinished, double fileSampleRate)
{ {
if (audioSource != nullptr) if (audioSource != nullptr)
{ {
@@ -199,12 +199,12 @@ void SoundPlayer::play (PositionableAudioSource* audioSource, bool deleteWhenFin
{ {
if (deleteWhenFinished) if (deleteWhenFinished)
{ {
transport = new AudioSourceOwningTransportSource (audioSource);
transport = new AudioSourceOwningTransportSource (audioSource, fileSampleRate);
} }
else else
{ {
transport = new AudioTransportSource(); transport = new AudioTransportSource();
transport->setSource (audioSource);
transport->setSource (audioSource, 0, nullptr, fileSampleRate);
deleteWhenFinished = true; deleteWhenFinished = true;
} }
} }


+ 5
- 1
libs/juce/source/modules/juce_audio_utils/players/juce_SoundPlayer.h View File

@@ -77,8 +77,12 @@ public:
@param deleteWhenFinished If this is true then the audio source will @param deleteWhenFinished If this is true then the audio source will
be deleted once the device manager has finished be deleted once the device manager has finished
playing. playing.
@param sampleRateOfSource The sample rate of the source. If this is zero, JUCE
will assume that the sample rate is the same as the
audio output device.
*/ */
void play (PositionableAudioSource* audioSource, bool deleteWhenFinished = false);
void play (PositionableAudioSource* audioSource, bool deleteWhenFinished = false,
double sampleRateOfSource = 0.0);
/** Plays the sound from an audio sample buffer. /** Plays the sound from an audio sample buffer.


+ 2
- 2
libs/juce/source/modules/juce_core/containers/juce_DynamicObject.cpp View File

@@ -91,7 +91,7 @@ DynamicObject::Ptr DynamicObject::clone()
return d; return d;
} }
void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine)
void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine, int maximumDecimalPlaces)
{ {
out << '{'; out << '{';
if (! allOnOneLine) if (! allOnOneLine)
@@ -107,7 +107,7 @@ void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const
out << '"'; out << '"';
JSONFormatter::writeString (out, properties.getName (i)); JSONFormatter::writeString (out, properties.getName (i));
out << "\": "; out << "\": ";
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine);
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine, maximumDecimalPlaces);
if (i < numValues - 1) if (i < numValues - 1)
{ {


+ 2
- 2
libs/juce/source/modules/juce_core/containers/juce_DynamicObject.h View File

@@ -113,14 +113,14 @@ public:
never need to call it directly, but it's virtual so that custom object types never need to call it directly, but it's virtual so that custom object types
can stringify themselves appropriately. can stringify themselves appropriately.
*/ */
virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine);
virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine, int maximumDecimalPlaces);
private: private:
//============================================================================== //==============================================================================
NamedValueSet properties; NamedValueSet properties;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// These methods have been deprecated - use var::invoke instead
// This method has been deprecated - use var::invoke instead
virtual void invokeMethod (const Identifier&, const var*, int) {} virtual void invokeMethod (const Identifier&, const var*, int) {}
#endif #endif


+ 9
- 5
libs/juce/source/modules/juce_core/containers/juce_HashMap.h View File

@@ -31,16 +31,20 @@
*/ */
struct DefaultHashFunctions struct DefaultHashFunctions
{ {
/** Generates a simple hash from an unsigned int. */
static int generateHash (uint32 key, int upperLimit) noexcept { return (int) (key % (uint32) upperLimit); }
/** Generates a simple hash from an integer. */ /** Generates a simple hash from an integer. */
int generateHash (const int key, const int upperLimit) const noexcept { return std::abs (key) % upperLimit; }
static int generateHash (int32 key, int upperLimit) noexcept { return generateHash ((uint32) key, upperLimit); }
/** Generates a simple hash from a uint64. */
static int generateHash (uint64 key, int upperLimit) noexcept { return (int) (key % (uint64) upperLimit); }
/** Generates a simple hash from an int64. */ /** Generates a simple hash from an int64. */
int generateHash (const int64 key, const int upperLimit) const noexcept { return std::abs ((int) key) % upperLimit; }
static int generateHash (int64 key, int upperLimit) noexcept { return generateHash ((uint64) key, upperLimit); }
/** Generates a simple hash from a string. */ /** Generates a simple hash from a string. */
int generateHash (const String& key, const int upperLimit) const noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
static int generateHash (const String& key, int upperLimit) noexcept { return generateHash ((uint32) key.hashCode(), upperLimit); }
/** Generates a simple hash from a variant. */ /** Generates a simple hash from a variant. */
int generateHash (const var& key, const int upperLimit) const noexcept { return generateHash (key.toString(), upperLimit); }
static int generateHash (const var& key, int upperLimit) noexcept { return generateHash (key.toString(), upperLimit); }
/** Generates a simple hash from a void ptr. */ /** Generates a simple hash from a void ptr. */
int generateHash (const void* key, const int upperLimit) const noexcept { return (int)(((pointer_sized_uint) key) % ((pointer_sized_uint) upperLimit)); }
static int generateHash (const void* key, int upperLimit) noexcept { return generateHash ((pointer_sized_uint) key, upperLimit); }
}; };


+ 31
- 42
libs/juce/source/modules/juce_core/containers/juce_SortedSet.h View File

@@ -55,31 +55,22 @@ class SortedSet
public: public:
//============================================================================== //==============================================================================
/** Creates an empty set. */ /** Creates an empty set. */
SortedSet() noexcept
{
}
SortedSet() noexcept = default;
/** Creates a copy of another set.
@param other the set to copy
*/
SortedSet (const SortedSet& other)
: data (other.data)
{
}
/** Creates a copy of another set. */
SortedSet (const SortedSet&) = default;
/** Destructor. */
~SortedSet() noexcept
{
}
/** Creates a copy of another set. */
SortedSet (SortedSet&&) noexcept = default;
/** Copies another set over this one.
@param other the set to copy
*/
SortedSet& operator= (const SortedSet& other) noexcept
{
data = other.data;
return *this;
}
/** Makes a copy of another set. */
SortedSet& operator= (const SortedSet&) = default;
/** Makes a copy of another set. */
SortedSet& operator= (SortedSet&&) noexcept = default;
/** Destructor. */
~SortedSet() noexcept {}
//============================================================================== //==============================================================================
/** Compares this set to another one. /** Compares this set to another one.
@@ -234,7 +225,7 @@ public:
if (elementToLookFor == data.getReference (s)) if (elementToLookFor == data.getReference (s))
return s; return s;
const int halfway = (s + e) / 2;
auto halfway = (s + e) / 2;
if (halfway == s) if (halfway == s)
return -1; return -1;
@@ -277,15 +268,16 @@ public:
while (s < e) while (s < e)
{ {
ElementType& elem = data.getReference (s);
auto& elem = data.getReference (s);
if (newElement == elem) if (newElement == elem)
{ {
elem = newElement; // force an update in case operator== permits differences. elem = newElement; // force an update in case operator== permits differences.
return false; return false;
} }
const int halfway = (s + e) / 2;
const bool isBeforeHalfway = (newElement < data.getReference (halfway));
auto halfway = (s + e) / 2;
bool isBeforeHalfway = (newElement < data.getReference (halfway));
if (halfway == s) if (halfway == s)
{ {
@@ -335,25 +327,22 @@ public:
int numElementsToAdd = -1) noexcept int numElementsToAdd = -1) noexcept
{ {
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock()); const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
const ScopedLockType lock2 (getLock());
jassert (this != &setToAddFrom);
if (this != &setToAddFrom)
{ {
const ScopedLockType lock2 (getLock());
jassert (this != &setToAddFrom);
if (this != &setToAddFrom)
if (startIndex < 0)
{ {
if (startIndex < 0)
{
jassertfalse;
startIndex = 0;
}
jassertfalse;
startIndex = 0;
}
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
numElementsToAdd = setToAddFrom.size() - startIndex;
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
numElementsToAdd = setToAddFrom.size() - startIndex;
if (numElementsToAdd > 0)
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
}
if (numElementsToAdd > 0)
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
} }
} }
@@ -400,7 +389,7 @@ public:
{ {
clear(); clear();
} }
else if (otherSet.size() > 0)
else if (! otherSet.isEmpty())
{ {
for (int i = data.size(); --i >= 0;) for (int i = data.size(); --i >= 0;)
if (otherSet.contains (data.getReference (i))) if (otherSet.contains (data.getReference (i)))
@@ -423,7 +412,7 @@ public:
if (this != &otherSet) if (this != &otherSet)
{ {
if (otherSet.size() <= 0)
if (otherSet.isEmpty())
{ {
clear(); clear();
} }


+ 15
- 9
libs/juce/source/modules/juce_core/javascript/juce_JSON.cpp View File

@@ -323,7 +323,8 @@ class JSONFormatter
{ {
public: public:
static void write (OutputStream& out, const var& v, static void write (OutputStream& out, const var& v,
const int indentLevel, const bool allOnOneLine)
const int indentLevel, const bool allOnOneLine,
int maximumDecimalPlaces)
{ {
if (v.isString()) if (v.isString())
{ {
@@ -343,14 +344,18 @@ public:
{ {
out << (static_cast<bool> (v) ? "true" : "false"); out << (static_cast<bool> (v) ? "true" : "false");
} }
else if (v.isDouble())
{
out << String (static_cast<double> (v), maximumDecimalPlaces);
}
else if (v.isArray()) else if (v.isArray())
{ {
writeArray (out, *v.getArray(), indentLevel, allOnOneLine);
writeArray (out, *v.getArray(), indentLevel, allOnOneLine, maximumDecimalPlaces);
} }
else if (v.isObject()) else if (v.isObject())
{ {
if (DynamicObject* object = v.getDynamicObject()) if (DynamicObject* object = v.getDynamicObject())
object->writeAsJSON (out, indentLevel, allOnOneLine);
object->writeAsJSON (out, indentLevel, allOnOneLine, maximumDecimalPlaces);
else else
jassertfalse; // Only DynamicObjects can be converted to JSON! jassertfalse; // Only DynamicObjects can be converted to JSON!
} }
@@ -420,7 +425,8 @@ public:
} }
static void writeArray (OutputStream& out, const Array<var>& array, static void writeArray (OutputStream& out, const Array<var>& array,
const int indentLevel, const bool allOnOneLine)
const int indentLevel, const bool allOnOneLine,
int maximumDecimalPlaces)
{ {
out << '['; out << '[';
@@ -434,7 +440,7 @@ public:
if (! allOnOneLine) if (! allOnOneLine)
writeSpaces (out, indentLevel + indentSize); writeSpaces (out, indentLevel + indentSize);
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine);
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine, maximumDecimalPlaces);
if (i < array.size() - 1) if (i < array.size() - 1)
{ {
@@ -493,16 +499,16 @@ Result JSON::parse (const String& text, var& result)
return JSONParser::parseObjectOrArray (text.getCharPointer(), result); return JSONParser::parseObjectOrArray (text.getCharPointer(), result);
} }
String JSON::toString (const var& data, const bool allOnOneLine)
String JSON::toString (const var& data, const bool allOnOneLine, int maximumDecimalPlaces)
{ {
MemoryOutputStream mo (1024); MemoryOutputStream mo (1024);
JSONFormatter::write (mo, data, 0, allOnOneLine);
JSONFormatter::write (mo, data, 0, allOnOneLine, maximumDecimalPlaces);
return mo.toUTF8(); return mo.toUTF8();
} }
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine)
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine, int maximumDecimalPlaces)
{ {
JSONFormatter::write (output, data, 0, allOnOneLine);
JSONFormatter::write (output, data, 0, allOnOneLine, maximumDecimalPlaces);
} }
String JSON::escapeString (StringRef s) String JSON::escapeString (StringRef s)


+ 6
- 2
libs/juce/source/modules/juce_core/javascript/juce_JSON.h View File

@@ -90,10 +90,12 @@ public:
/** Returns a string which contains a JSON-formatted representation of the var object. /** Returns a string which contains a JSON-formatted representation of the var object.
If allOnOneLine is true, the result will be compacted into a single line of text If allOnOneLine is true, the result will be compacted into a single line of text
with no carriage-returns. If false, it will be laid-out in a more human-readable format. with no carriage-returns. If false, it will be laid-out in a more human-readable format.
The maximumDecimalPlaces parameter determines the precision of floating point numbers.
@see writeToStream @see writeToStream
*/ */
static String toString (const var& objectToFormat, static String toString (const var& objectToFormat,
bool allOnOneLine = false);
bool allOnOneLine = false,
int maximumDecimalPlaces = 20);
/** Parses a string that was created with the toString() method. /** Parses a string that was created with the toString() method.
This is slightly different to the parse() methods because they will reject primitive This is slightly different to the parse() methods because they will reject primitive
@@ -105,11 +107,13 @@ public:
/** Writes a JSON-formatted representation of the var object to the given stream. /** Writes a JSON-formatted representation of the var object to the given stream.
If allOnOneLine is true, the result will be compacted into a single line of text If allOnOneLine is true, the result will be compacted into a single line of text
with no carriage-returns. If false, it will be laid-out in a more human-readable format. with no carriage-returns. If false, it will be laid-out in a more human-readable format.
The maximumDecimalPlaces parameter determines the precision of floating point numbers.
@see toString @see toString
*/ */
static void writeToStream (OutputStream& output, static void writeToStream (OutputStream& output,
const var& objectToFormat, const var& objectToFormat,
bool allOnOneLine = false);
bool allOnOneLine = false,
int maximumDecimalPlaces = 20);
/** Returns a version of a string with any extended characters escaped. */ /** Returns a version of a string with any extended characters escaped. */
static String escapeString (StringRef); static String escapeString (StringRef);


+ 1
- 1
libs/juce/source/modules/juce_core/javascript/juce_Javascript.cpp View File

@@ -827,7 +827,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
DynamicObject::Ptr clone() override { return new FunctionObject (*this); } DynamicObject::Ptr clone() override { return new FunctionObject (*this); }
void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/) override
void writeAsJSON (OutputStream& out, int /*indentLevel*/, bool /*allOnOneLine*/, int /*maximumDecimalPlaces*/) override
{ {
out << "function " << functionCode; out << "function " << functionCode;
} }


+ 7
- 0
libs/juce/source/modules/juce_core/memory/juce_HeapBlock.h View File

@@ -149,6 +149,13 @@ public:
*/ */
inline operator ElementType*() const noexcept { return data; } inline operator ElementType*() const noexcept { return data; }
/** Returns a raw pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method.
*/
inline ElementType* get() const noexcept { return data; }
/** Returns a raw pointer to the allocated data. /** Returns a raw pointer to the allocated data.
This may be a null pointer if the data hasn't yet been allocated, or if it has been This may be a null pointer if the data hasn't yet been allocated, or if it has been
freed by calling the free() method. freed by calling the free() method.


+ 971
- 0
libs/juce/source/modules/juce_core/native/java/IInAppBillingService.java View File

@@ -0,0 +1,971 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
package com.android.vending.billing;
/**
* InAppBillingService is the service that provides in-app billing version 3 and beyond.
* This service provides the following features:
* 1. Provides a new API to get details of in-app items published for the app including
* price, type, title and description.
* 2. The purchase flow is synchronous and purchase information is available immediately
* after it completes.
* 3. Purchase information of in-app purchases is maintained within the Google Play system
* till the purchase is consumed.
* 4. An API to consume a purchase of an inapp item. All purchases of one-time
* in-app items are consumable and thereafter can be purchased again.
* 5. An API to get current purchases of the user immediately. This will not contain any
* consumed purchases.
*
* All calls will give a response code with the following possible values
* RESULT_OK = 0 - success
* RESULT_USER_CANCELED = 1 - User pressed back or canceled a dialog
* RESULT_SERVICE_UNAVAILABLE = 2 - The network connection is down
* RESULT_BILLING_UNAVAILABLE = 3 - This billing API version is not supported for the type requested
* RESULT_ITEM_UNAVAILABLE = 4 - Requested SKU is not available for purchase
* RESULT_DEVELOPER_ERROR = 5 - Invalid arguments provided to the API
* RESULT_ERROR = 6 - Fatal error during the API action
* RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
* RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
*/
public interface IInAppBillingService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.android.vending.billing.IInAppBillingService
{
private static final java.lang.String DESCRIPTOR = "com.android.vending.billing.IInAppBillingService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.android.vending.billing.IInAppBillingService interface,
* generating a proxy if needed.
*/
public static com.android.vending.billing.IInAppBillingService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.android.vending.billing.IInAppBillingService))) {
return ((com.android.vending.billing.IInAppBillingService)iin);
}
return new com.android.vending.billing.IInAppBillingService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_isBillingSupported:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
int _result = this.isBillingSupported(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getSkuDetails:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
android.os.Bundle _arg3;
if ((0!=data.readInt())) {
_arg3 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg3 = null;
}
android.os.Bundle _result = this.getSkuDetails(_arg0, _arg1, _arg2, _arg3);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_getBuyIntent:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
java.lang.String _arg3;
_arg3 = data.readString();
java.lang.String _arg4;
_arg4 = data.readString();
android.os.Bundle _result = this.getBuyIntent(_arg0, _arg1, _arg2, _arg3, _arg4);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_getPurchases:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
java.lang.String _arg3;
_arg3 = data.readString();
android.os.Bundle _result = this.getPurchases(_arg0, _arg1, _arg2, _arg3);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_consumePurchase:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
int _result = this.consumePurchase(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_stub:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
int _result = this.stub(_arg0, _arg1, _arg2);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getBuyIntentToReplaceSkus:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.util.List<java.lang.String> _arg2;
_arg2 = data.createStringArrayList();
java.lang.String _arg3;
_arg3 = data.readString();
java.lang.String _arg4;
_arg4 = data.readString();
java.lang.String _arg5;
_arg5 = data.readString();
android.os.Bundle _result = this.getBuyIntentToReplaceSkus(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_getBuyIntentExtraParams:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
java.lang.String _arg3;
_arg3 = data.readString();
java.lang.String _arg4;
_arg4 = data.readString();
android.os.Bundle _arg5;
if ((0!=data.readInt())) {
_arg5 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg5 = null;
}
android.os.Bundle _result = this.getBuyIntentExtraParams(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_getPurchaseHistory:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
java.lang.String _arg3;
_arg3 = data.readString();
android.os.Bundle _arg4;
if ((0!=data.readInt())) {
_arg4 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg4 = null;
}
android.os.Bundle _result = this.getPurchaseHistory(_arg0, _arg1, _arg2, _arg3, _arg4);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_isBillingSupportedExtraParams:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _arg1;
_arg1 = data.readString();
java.lang.String _arg2;
_arg2 = data.readString();
android.os.Bundle _arg3;
if ((0!=data.readInt())) {
_arg3 = android.os.Bundle.CREATOR.createFromParcel(data);
}
else {
_arg3 = null;
}
int _result = this.isBillingSupportedExtraParams(_arg0, _arg1, _arg2, _arg3);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.android.vending.billing.IInAppBillingService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
mRemote.transact(Stub.TRANSACTION_isBillingSupported, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Provides details of a list of SKUs
* Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
* with a list JSON strings containing the productId, price, title and description.
* This API can be called with a maximum of 20 SKUs.
* @param apiVersion billing API version that the app is using
* @param packageName the package name of the calling app
* @param type of the in-app items ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "DETAILS_LIST" with a StringArrayList containing purchase information
* in JSON format similar to:
* '{ "productId" : "exampleSku",
* "type" : "inapp",
* "price" : "$5.00",
* "price_currency": "USD",
* "price_amount_micros": 5000000,
* "title : "Example Title",
* "description" : "This is an example description" }'
*/
@Override public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
if ((skusBundle!=null)) {
_data.writeInt(1);
skusBundle.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_getSkuDetails, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
* the type, a unique purchase token and an optional developer payload.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type of the in-app item being purchased ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
* codes on failures.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
*/
@Override public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(sku);
_data.writeString(type);
_data.writeString(developerPayload);
mRemote.transact(Stub.TRANSACTION_getBuyIntent, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Returns the current SKUs owned by the user of the type and package name specified along with
* purchase information and a signature of the data to be validated.
* This will return all SKUs that have been purchased in V3 and managed items purchased using
* V1 and V2 that have not been consumed.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param type of the in-app items being requested ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param continuationToken to be set as null for the first call, if the number of owned
* skus are too many, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
on failures.
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
@Override public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
_data.writeString(continuationToken);
mRemote.transact(Stub.TRANSACTION_getPurchases, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(purchaseToken);
mRemote.transact(Stub.TRANSACTION_consumePurchase, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
mRemote.transact(Stub.TRANSACTION_stub, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Returns a pending intent to launch the purchase flow for upgrading or downgrading a
* subscription. The existing owned SKU(s) should be provided along with the new SKU that
* the user is upgrading or downgrading to.
* @param apiVersion billing API version that the app is using, must be 5 or later
* @param packageName package name of the calling app
* @param oldSkus the SKU(s) that the user is upgrading or downgrading from,
* if null or empty this method will behave like {@link #getBuyIntent}
* @param newSku the SKU that the user is upgrading or downgrading to
* @param type of the item being purchased, currently must be "subs"
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
* codes on failures.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
*/
@Override public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeStringList(oldSkus);
_data.writeString(newSku);
_data.writeString(type);
_data.writeString(developerPayload);
mRemote.transact(Stub.TRANSACTION_getBuyIntentToReplaceSkus, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Returns a pending intent to launch the purchase flow for an in-app item. This method is
* a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}
* parameter. This parameter is a Bundle of optional keys and values that affect the
* operation of the method.
* @param apiVersion billing API version that the app is using, must be 6 or later
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type of the in-app item being purchased ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param developerPayload optional argument to be sent back with the purchase information
* @extraParams a Bundle with the following optional keys:
* "skusToReplace" - List<String> - an optional list of SKUs that the user is
* upgrading or downgrading from.
* Pass this field if the purchase is upgrading or downgrading
* existing subscriptions.
* The specified SKUs are replaced with the SKUs that the user is
* purchasing. Google Play replaces the specified SKUs at the start of
* the next billing cycle.
* "replaceSkusProration" - Boolean - whether the user should be credited for any unused
* subscription time on the SKUs they are upgrading or downgrading.
* If you set this field to true, Google Play swaps out the old SKUs
* and credits the user with the unused value of their subscription
* time on a pro-rated basis.
* Google Play applies this credit to the new subscription, and does
* not begin billing the user for the new subscription until after
* the credit is used up.
* If you set this field to false, the user does not receive credit for
* any unused subscription time and the recurrence date does not
* change.
* Default value is true. Ignored if you do not pass skusToReplace.
* "accountId" - String - an optional obfuscated string that is uniquely
* associated with the user's account in your app.
* If you pass this value, Google Play can use it to detect irregular
* activity, such as many devices making purchases on the same
* account in a short period of time.
* Do not use the developer ID or the user's Google ID for this field.
* In addition, this field should not contain the user's ID in
* cleartext.
* We recommend that you use a one-way hash to generate a string from
* the user's ID, and store the hashed string in this field.
* "vr" - Boolean - an optional flag indicating whether the returned intent
* should start a VR purchase flow. The apiVersion must also be 7 or
* later to use this flag.
*/
@Override public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(sku);
_data.writeString(type);
_data.writeString(developerPayload);
if ((extraParams!=null)) {
_data.writeInt(1);
extraParams.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_getBuyIntentExtraParams, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
/**
* Returns the most recent purchase made by the user for each SKU, even if that purchase is
* expired, canceled, or consumed.
* @param apiVersion billing API version that the app is using, must be 6 or later
* @param packageName package name of the calling app
* @param type of the in-app items being requested ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param continuationToken to be set as null for the first call, if the number of owned
* skus is too large, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @param extraParams a Bundle with extra params that would be appended into http request
* query string. Not used at this moment. Reserved for future functionality.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value: RESULT_OK(0) if success,
* {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.
*
* "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
@Override public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.os.Bundle _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
_data.writeString(continuationToken);
if ((extraParams!=null)) {
_data.writeInt(1);
extraParams.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_getPurchaseHistory, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.os.Bundle.CREATOR.createFromParcel(_reply);
}
else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(apiVersion);
_data.writeString(packageName);
_data.writeString(type);
if ((extraParams!=null)) {
_data.writeInt(1);
extraParams.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_isBillingSupportedExtraParams, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_isBillingSupported = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getSkuDetails = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_getBuyIntent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_getPurchases = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_consumePurchase = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_stub = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
static final int TRANSACTION_getBuyIntentToReplaceSkus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
static final int TRANSACTION_getBuyIntentExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
static final int TRANSACTION_getPurchaseHistory = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
static final int TRANSACTION_isBillingSupportedExtraParams = (android.os.IBinder.FIRST_CALL_TRANSACTION + 9);
}
public int isBillingSupported(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException;
/**
* Provides details of a list of SKUs
* Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
* with a list JSON strings containing the productId, price, title and description.
* This API can be called with a maximum of 20 SKUs.
* @param apiVersion billing API version that the app is using
* @param packageName the package name of the calling app
* @param type of the in-app items ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "DETAILS_LIST" with a StringArrayList containing purchase information
* in JSON format similar to:
* '{ "productId" : "exampleSku",
* "type" : "inapp",
* "price" : "$5.00",
* "price_currency": "USD",
* "price_amount_micros": 5000000,
* "title : "Example Title",
* "description" : "This is an example description" }'
*/
public android.os.Bundle getSkuDetails(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle skusBundle) throws android.os.RemoteException;
/**
* Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
* the type, a unique purchase token and an optional developer payload.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type of the in-app item being purchased ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
* codes on failures.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
*/
public android.os.Bundle getBuyIntent(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException;
/**
* Returns the current SKUs owned by the user of the type and package name specified along with
* purchase information and a signature of the data to be validated.
* This will return all SKUs that have been purchased in V3 and managed items purchased using
* V1 and V2 that have not been consumed.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param type of the in-app items being requested ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param continuationToken to be set as null for the first call, if the number of owned
* skus are too many, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
on failures.
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
public android.os.Bundle getPurchases(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken) throws android.os.RemoteException;
public int consumePurchase(int apiVersion, java.lang.String packageName, java.lang.String purchaseToken) throws android.os.RemoteException;
public int stub(int apiVersion, java.lang.String packageName, java.lang.String type) throws android.os.RemoteException;
/**
* Returns a pending intent to launch the purchase flow for upgrading or downgrading a
* subscription. The existing owned SKU(s) should be provided along with the new SKU that
* the user is upgrading or downgrading to.
* @param apiVersion billing API version that the app is using, must be 5 or later
* @param packageName package name of the calling app
* @param oldSkus the SKU(s) that the user is upgrading or downgrading from,
* if null or empty this method will behave like {@link #getBuyIntent}
* @param newSku the SKU that the user is upgrading or downgrading to
* @param type of the item being purchased, currently must be "subs"
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response codes
* on failures.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, appropriate response
* codes on failures.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
*/
public android.os.Bundle getBuyIntentToReplaceSkus(int apiVersion, java.lang.String packageName, java.util.List<java.lang.String> oldSkus, java.lang.String newSku, java.lang.String type, java.lang.String developerPayload) throws android.os.RemoteException;
/**
* Returns a pending intent to launch the purchase flow for an in-app item. This method is
* a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams}
* parameter. This parameter is a Bundle of optional keys and values that affect the
* operation of the method.
* @param apiVersion billing API version that the app is using, must be 6 or later
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type of the in-app item being purchased ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param developerPayload optional argument to be sent back with the purchase information
* @extraParams a Bundle with the following optional keys:
* "skusToReplace" - List<String> - an optional list of SKUs that the user is
* upgrading or downgrading from.
* Pass this field if the purchase is upgrading or downgrading
* existing subscriptions.
* The specified SKUs are replaced with the SKUs that the user is
* purchasing. Google Play replaces the specified SKUs at the start of
* the next billing cycle.
* "replaceSkusProration" - Boolean - whether the user should be credited for any unused
* subscription time on the SKUs they are upgrading or downgrading.
* If you set this field to true, Google Play swaps out the old SKUs
* and credits the user with the unused value of their subscription
* time on a pro-rated basis.
* Google Play applies this credit to the new subscription, and does
* not begin billing the user for the new subscription until after
* the credit is used up.
* If you set this field to false, the user does not receive credit for
* any unused subscription time and the recurrence date does not
* change.
* Default value is true. Ignored if you do not pass skusToReplace.
* "accountId" - String - an optional obfuscated string that is uniquely
* associated with the user's account in your app.
* If you pass this value, Google Play can use it to detect irregular
* activity, such as many devices making purchases on the same
* account in a short period of time.
* Do not use the developer ID or the user's Google ID for this field.
* In addition, this field should not contain the user's ID in
* cleartext.
* We recommend that you use a one-way hash to generate a string from
* the user's ID, and store the hashed string in this field.
* "vr" - Boolean - an optional flag indicating whether the returned intent
* should start a VR purchase flow. The apiVersion must also be 7 or
* later to use this flag.
*/
public android.os.Bundle getBuyIntentExtraParams(int apiVersion, java.lang.String packageName, java.lang.String sku, java.lang.String type, java.lang.String developerPayload, android.os.Bundle extraParams) throws android.os.RemoteException;
/**
* Returns the most recent purchase made by the user for each SKU, even if that purchase is
* expired, canceled, or consumed.
* @param apiVersion billing API version that the app is using, must be 6 or later
* @param packageName package name of the calling app
* @param type of the in-app items being requested ("inapp" for one-time purchases
* and "subs" for subscriptions)
* @param continuationToken to be set as null for the first call, if the number of owned
* skus is too large, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @param extraParams a Bundle with extra params that would be appended into http request
* query string. Not used at this moment. Reserved for future functionality.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value: RESULT_OK(0) if success,
* {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures.
*
* "INAPP_PURCHASE_ITEM_LIST" - ArrayList<String> containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - ArrayList<String> containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- ArrayList<String> containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
public android.os.Bundle getPurchaseHistory(int apiVersion, java.lang.String packageName, java.lang.String type, java.lang.String continuationToken, android.os.Bundle extraParams) throws android.os.RemoteException;
public int isBillingSupportedExtraParams(int apiVersion, java.lang.String packageName, java.lang.String type, android.os.Bundle extraParams) throws android.os.RemoteException;
}

+ 38
- 47
libs/juce/source/modules/juce_core/native/java/JuceAppActivity.java View File

@@ -55,8 +55,6 @@ import java.io.*;
import java.net.URL; import java.net.URL;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import android.media.AudioManager; import android.media.AudioManager;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.Manifest; import android.Manifest;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@@ -68,7 +66,7 @@ import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.*; import java.util.concurrent.atomic.*;
$$JuceAndroidMidiImports$$ // If you get an error here, you need to re-save your project with the Projucer!
$$JuceAndroidMidiImports$$ // If you get an error here, you need to re-save your project with the Projucer!
//============================================================================== //==============================================================================
@@ -301,23 +299,7 @@ public class JuceAppActivity extends Activity
private native void suspendApp(); private native void suspendApp();
private native void resumeApp(); private native void resumeApp();
private native void setScreenSize (int screenWidth, int screenHeight, int dpi); private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
//==============================================================================
public native void deliverMessage (long value);
private android.os.Handler messageHandler = new android.os.Handler();
public final void postMessage (long value)
{
messageHandler.post (new MessageCallback (value));
}
private final class MessageCallback implements Runnable
{
public MessageCallback (long value_) { value = value_; }
public final void run() { deliverMessage (value); }
private long value;
}
private native void appActivityResult (int requestCode, int resultCode, Intent data);
//============================================================================== //==============================================================================
private ViewHolder viewHolder; private ViewHolder viewHolder;
@@ -882,6 +864,38 @@ public class JuceAppActivity extends Activity
private int[] cachedRenderArray = new int [256]; private int[] cachedRenderArray = new int [256];
//==============================================================================
public static class NativeInvocationHandler implements InvocationHandler
{
public NativeInvocationHandler (long nativeContextRef)
{
nativeContext = nativeContextRef;
}
@Override
public void finalize()
{
dispatchFinalize (nativeContext);
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable
{
return dispatchInvoke (nativeContext, proxy, method, args);
}
//==============================================================================
private long nativeContext = 0;
private native void dispatchFinalize (long nativeContextRef);
private native Object dispatchInvoke (long nativeContextRef, Object proxy, Method method, Object[] args);
}
public static InvocationHandler createInvocationHandler (long nativeContextRef)
{
return new NativeInvocationHandler (nativeContextRef);
}
//============================================================================== //==============================================================================
public static class HTTPStream public static class HTTPStream
{ {
@@ -1185,36 +1199,13 @@ public class JuceAppActivity extends Activity
public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); } public static final String getDownloadsFolder() { return getFileLocation (Environment.DIRECTORY_DOWNLOADS); }
//============================================================================== //==============================================================================
private final class SingleMediaScanner implements MediaScannerConnectionClient
{
public SingleMediaScanner (Context context, String filename)
{
file = filename;
msc = new MediaScannerConnection (context, this);
msc.connect();
}
@Override
public void onMediaScannerConnected()
{
msc.scanFile (file, null);
}
@Override
public void onScanCompleted (String path, Uri uri)
{
msc.disconnect();
}
private MediaScannerConnection msc;
private String file;
}
public final void scanFile (String filename)
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data)
{ {
new SingleMediaScanner (this, filename);
appActivityResult (requestCode, resultCode, data);
} }
//==============================================================================
public final Typeface getTypeFaceFromAsset (String assetName) public final Typeface getTypeFaceFromAsset (String assetName)
{ {
try try


+ 86
- 0
libs/juce/source/modules/juce_core/native/juce_android_Files.cpp View File

@@ -20,6 +20,46 @@
============================================================================== ==============================================================================
*/ */
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "(Landroid/content/Context;Landroid/media/MediaScannerConnection$MediaScannerConnectionClient;)V") \
METHOD (connect, "connect", "()V") \
METHOD (disconnect, "disconnect", "()V") \
METHOD (scanFile, "scanFile", "(Ljava/lang/String;Ljava/lang/String;)V") \
DECLARE_JNI_CLASS (MediaScannerConnection, "android/media/MediaScannerConnection");
#undef JNI_CLASS_MEMBERS
//==============================================================================
class MediaScannerConnectionClient : public AndroidInterfaceImplementer
{
public:
virtual void onMediaScannerConnected() = 0;
virtual void onScanCompleted() = 0;
private:
jobject invoke (jobject proxy, jobject method, jobjectArray args) override
{
auto* env = getEnv();
auto methodName = juceString ((jstring) env->CallObjectMethod (method, Method.getName));
if (methodName == "onMediaScannerConnected")
{
onMediaScannerConnected();
return nullptr;
}
else if (methodName == "onScanCompleted")
{
onScanCompleted();
return nullptr;
}
return AndroidInterfaceImplementer::invoke (proxy, method, args);
}
};
//==============================================================================
bool File::isOnCDRomDrive() const bool File::isOnCDRomDrive() const
{ {
return false; return false;
@@ -100,3 +140,49 @@ JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const
void File::revealToUser() const void File::revealToUser() const
{ {
} }
//==============================================================================
class SingleMediaScanner : public MediaScannerConnectionClient
{
public:
SingleMediaScanner (const String& filename)
: msc (getEnv()->NewObject (MediaScannerConnection,
MediaScannerConnection.constructor,
android.activity.get(),
CreateJavaInterface (this, "android/media/MediaScannerConnection$MediaScannerConnectionClient").get())),
file (filename)
{
getEnv()->CallVoidMethod (msc.get(), MediaScannerConnection.connect);
}
void onMediaScannerConnected() override
{
auto* env = getEnv();
env->CallVoidMethod (msc.get(), MediaScannerConnection.scanFile, javaString (file).get(), 0);
}
void onScanCompleted() override
{
getEnv()->CallVoidMethod (msc.get(), MediaScannerConnection.disconnect);
}
private:
GlobalRef msc;
String file;
};
void FileOutputStream::flushInternal()
{
if (fileHandle != 0)
{
if (fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
new SingleMediaScanner (file.getFullPathName());
}
}

+ 125
- 28
libs/juce/source/modules/juce_core/native/juce_android_JNIHelpers.h View File

@@ -40,10 +40,11 @@ extern JNIEnv* attachAndroidJNI() noexcept;
class GlobalRef class GlobalRef
{ {
public: public:
inline GlobalRef() noexcept : obj (0) {}
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
~GlobalRef() { clear(); }
inline GlobalRef() noexcept : obj (0) {}
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
inline GlobalRef (GlobalRef && other) noexcept : obj (0) { std::swap (other.obj, obj); }
~GlobalRef() { clear(); }
inline void clear() inline void clear()
{ {
@@ -62,6 +63,14 @@ public:
return *this; return *this;
} }
inline GlobalRef& operator= (GlobalRef&& other)
{
clear();
std::swap (obj, other.obj);
return *this;
}
//============================================================================== //==============================================================================
inline operator jobject() const noexcept { return obj; } inline operator jobject() const noexcept { return obj; }
inline jobject get() const noexcept { return obj; } inline jobject get() const noexcept { return obj; }
@@ -98,7 +107,7 @@ public:
private: private:
//============================================================================== //==============================================================================
jobject obj;
jobject obj = 0;
static inline jobject retain (jobject obj) static inline jobject retain (jobject obj)
{ {
@@ -111,14 +120,19 @@ template <typename JavaType>
class LocalRef class LocalRef
{ {
public: public:
explicit inline LocalRef () noexcept : obj (0) {}
explicit inline LocalRef (JavaType o) noexcept : obj (o) {} explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {} inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
inline LocalRef (LocalRef&& other) noexcept : obj (0) { std::swap (obj, other.obj); }
~LocalRef() { clear(); } ~LocalRef() { clear(); }
void clear() void clear()
{ {
if (obj != 0) if (obj != 0)
{
getEnv()->DeleteLocalRef (obj); getEnv()->DeleteLocalRef (obj);
obj = 0;
}
} }
LocalRef& operator= (const LocalRef& other) LocalRef& operator= (const LocalRef& other)
@@ -129,6 +143,13 @@ public:
return *this; return *this;
} }
LocalRef& operator= (LocalRef&& other)
{
clear();
std::swap (other.obj, obj);
return *this;
}
inline operator JavaType() const noexcept { return obj; } inline operator JavaType() const noexcept { return obj; }
inline JavaType get() const noexcept { return obj; } inline JavaType get() const noexcept { return obj; }
@@ -258,29 +279,27 @@ extern AndroidSystem android;
//============================================================================== //==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
METHOD (deleteView, "deleteView", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
METHOD (deleteView, "deleteView", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
METHOD (createNativeSurfaceView, "createNativeSurfaceView", "(J)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$NativeSurfaceView;") \ METHOD (createNativeSurfaceView, "createNativeSurfaceView", "(J)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$NativeSurfaceView;") \
METHOD (postMessage, "postMessage", "(J)V") \
METHOD (finish, "finish", "()V") \
METHOD (finish, "finish", "()V") \
METHOD (setRequestedOrientation,"setRequestedOrientation", "(I)V") \ METHOD (setRequestedOrientation,"setRequestedOrientation", "(I)V") \
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
METHOD (renderGlyph, "renderGlyph", "(CCLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;ILjava/lang/String;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V") \
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
STATICMETHOD (getDocumentsFolder, "getDocumentsFolder", "()Ljava/lang/String;") \
STATICMETHOD (getPicturesFolder, "getPicturesFolder", "()Ljava/lang/String;") \
STATICMETHOD (getMusicFolder, "getMusicFolder", "()Ljava/lang/String;") \
STATICMETHOD (getDownloadsFolder, "getDownloadsFolder", "()Ljava/lang/String;") \
STATICMETHOD (getMoviesFolder, "getMoviesFolder", "()Ljava/lang/String;") \
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V") \
METHOD (getTypeFaceFromAsset, "getTypeFaceFromAsset", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
METHOD (renderGlyph, "renderGlyph", "(CCLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;ILjava/lang/String;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V") \
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
STATICMETHOD (getDocumentsFolder, "getDocumentsFolder", "()Ljava/lang/String;") \
STATICMETHOD (getPicturesFolder, "getPicturesFolder", "()Ljava/lang/String;") \
STATICMETHOD (getMusicFolder, "getMusicFolder", "()Ljava/lang/String;") \
STATICMETHOD (getDownloadsFolder, "getDownloadsFolder", "()Ljava/lang/String;") \
STATICMETHOD (getMoviesFolder, "getMoviesFolder", "()Ljava/lang/String;") \
METHOD (getTypeFaceFromAsset, "getTypeFaceFromAsset", "(Ljava/lang/String;)Landroid/graphics/Typeface;") \
METHOD (getTypeFaceFromByteArray,"getTypeFaceFromByteArray","([B)Landroid/graphics/Typeface;") \ METHOD (getTypeFaceFromByteArray,"getTypeFaceFromByteArray","([B)Landroid/graphics/Typeface;") \
METHOD (setScreenSaver, "setScreenSaver", "(Z)V") \ METHOD (setScreenSaver, "setScreenSaver", "(Z)V") \
METHOD (getScreenSaver, "getScreenSaver", "()Z") \ METHOD (getScreenSaver, "getScreenSaver", "()Z") \
@@ -288,11 +307,16 @@ extern AndroidSystem android;
METHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$BluetoothManager;") \ METHOD (getAndroidBluetoothManager, "getAndroidBluetoothManager", "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$BluetoothManager;") \
METHOD (getAndroidSDKVersion, "getAndroidSDKVersion", "()I") \ METHOD (getAndroidSDKVersion, "getAndroidSDKVersion", "()I") \
METHOD (audioManagerGetProperty, "audioManagerGetProperty", "(Ljava/lang/String;)Ljava/lang/String;") \ METHOD (audioManagerGetProperty, "audioManagerGetProperty", "(Ljava/lang/String;)Ljava/lang/String;") \
METHOD (hasSystemFeature, "hasSystemFeature", "(Ljava/lang/String;)Z" ) \
METHOD (hasSystemFeature, "hasSystemFeature", "(Ljava/lang/String;)Z" ) \
METHOD (requestRuntimePermission, "requestRuntimePermission", "(IJ)V" ) \ METHOD (requestRuntimePermission, "requestRuntimePermission", "(IJ)V" ) \
METHOD (isPermissionGranted, "isPermissionGranted", "(I)Z" ) \
METHOD (isPermissionGranted, "isPermissionGranted", "(I)Z" ) \
METHOD (isPermissionDeclaredInManifest, "isPermissionDeclaredInManifest", "(I)Z" ) \ METHOD (isPermissionDeclaredInManifest, "isPermissionDeclaredInManifest", "(I)Z" ) \
METHOD (getSystemService, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;") \ METHOD (getSystemService, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;") \
STATICMETHOD (createInvocationHandler, "createInvocationHandler", "(J)Ljava/lang/reflect/InvocationHandler;") \
METHOD (bindService, "bindService", "(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z") \
METHOD (unbindService, "unbindService", "(Landroid/content/ServiceConnection;)V") \
METHOD (startIntentSenderForResult, "startIntentSenderForResult", "(Landroid/content/IntentSender;ILandroid/content/Intent;III)V") \
METHOD (getPackageName, "getPackageName", "()Ljava/lang/String;") \
DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH); DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH);
#undef JNI_CLASS_MEMBERS #undef JNI_CLASS_MEMBERS
@@ -332,3 +356,76 @@ DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect"); DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
#undef JNI_CLASS_MEMBERS #undef JNI_CLASS_MEMBERS
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getName, "getName", "()Ljava/lang/String;") \
METHOD (getModifiers, "getModifiers", "()I") \
METHOD (getParameterTypes, "getParameterTypes", "()[Ljava/lang/Class;") \
METHOD (getReturnType, "getReturnType", "()Ljava/lang/Class;") \
METHOD (invoke, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;") \
METHOD (hashCode, "hashCode", "()I") \
METHOD (equals, "equals", "(Ljava/lang/Object;)Z") \
DECLARE_JNI_CLASS (Method, "java/lang/reflect/Method");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getName, "getName", "()Ljava/lang/String;") \
METHOD (getModifiers, "getModifiers", "()I") \
METHOD (isAnnotation, "isAnnotation", "()Z") \
METHOD (isAnonymousClass, "isAnonymousClass", "()Z") \
METHOD (isArray, "isArray", "()Z") \
METHOD (isEnum, "isEnum", "()Z") \
METHOD (isInterface, "isInterface", "()Z") \
METHOD (isLocalClass, "isLocalClass", "()Z") \
METHOD (isMemberClass, "isMemberClass", "()Z") \
METHOD (isPrimitive, "isPrimitive", "()Z") \
METHOD (isSynthetic, "isSynthetic", "()Z") \
METHOD (getComponentType, "getComponentType", "()Ljava/lang/Class;") \
METHOD (getSuperclass, "getSuperclass", "()Ljava/lang/Class;") \
METHOD (getClassLoader, "getClassLoader", "()Ljava/lang/ClassLoader;") \
DECLARE_JNI_CLASS (JavaClass, "java/lang/Class");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V") \
DECLARE_JNI_CLASS (JavaObject, "java/lang/Object");
#undef JNI_CLASS_MEMBERS
//==============================================================================
class AndroidInterfaceImplementer;
// This function takes ownership of the implementer. When the returned GlobalRef
// goes out of scope (and no other Java routine has a reference on the return-value)
// then the implementer will be deleted as well.
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames,
LocalRef<jobject> subclass);
//==============================================================================
jobject juce_invokeImplementer (JNIEnv*, jlong, jobject, jobject, jobjectArray);
void juce_dispatchDelete (JNIEnv*, jlong);
//==============================================================================
class AndroidInterfaceImplementer
{
protected:
virtual ~AndroidInterfaceImplementer() {}
virtual jobject invoke (jobject proxy, jobject method, jobjectArray args);
//==============================================================================
friend LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer*, const StringArray&, LocalRef<jobject>);
friend jobject juce_invokeImplementer (JNIEnv*, jlong, jobject, jobject, jobjectArray);
friend void juce_dispatchDelete (JNIEnv*, jlong);
private:
GlobalRef javaSubClass;
};
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames);
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const String& interfaceName);

+ 93
- 0
libs/juce/source/modules/juce_core/native/juce_android_SystemStats.cpp View File

@@ -20,6 +20,13 @@
============================================================================== ==============================================================================
*/ */
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
STATICMETHOD (newProxyInstance, "newProxyInstance", "(Ljava/lang/ClassLoader;[Ljava/lang/Class;Ljava/lang/reflect/InvocationHandler;)Ljava/lang/Object;") \
DECLARE_JNI_CLASS (JavaProxy, "java/lang/reflect/Proxy");
#undef JNI_CLASS_MEMBERS
JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0) JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0)
{ {
getClasses().add (this); getClasses().add (this);
@@ -91,6 +98,92 @@ jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, c
return f; return f;
} }
//==============================================================================
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames,
LocalRef<jobject> subclass)
{
auto* env = getEnv();
implementer->javaSubClass = GlobalRef (subclass);
// you need to override at least one interface
jassert (interfaceNames.size() > 0);
auto classArray = LocalRef<jobject> (env->NewObjectArray (interfaceNames.size(), JavaClass, nullptr));
LocalRef<jobject> classLoader;
for (auto i = 0; i < interfaceNames.size(); ++i)
{
auto aClass = LocalRef<jobject> (env->FindClass (interfaceNames[i].toRawUTF8()));
if (aClass != nullptr)
{
if (i == 0)
classLoader = LocalRef<jobject> (env->CallObjectMethod (aClass, JavaClass.getClassLoader));
env->SetObjectArrayElement ((jobjectArray) classArray.get(), i, aClass);
}
else
{
// interface class not found
jassertfalse;
}
}
auto invocationHandler = LocalRef<jobject> (env->CallStaticObjectMethod (JuceAppActivity,
JuceAppActivity.createInvocationHandler,
reinterpret_cast<jlong> (implementer)));
return LocalRef<jobject> (env->CallStaticObjectMethod (JavaProxy, JavaProxy.newProxyInstance,
classLoader.get(), classArray.get(),
invocationHandler.get()));
}
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const StringArray& interfaceNames)
{
return CreateJavaInterface (implementer, interfaceNames,
LocalRef<jobject> (getEnv()->NewObject (JavaObject,
JavaObject.constructor)));
}
LocalRef<jobject> CreateJavaInterface (AndroidInterfaceImplementer* implementer,
const String& interfaceName)
{
return CreateJavaInterface (implementer, StringArray (interfaceName));
}
jobject AndroidInterfaceImplementer::invoke (jobject /*proxy*/, jobject method, jobjectArray args)
{
auto* env = getEnv();
return env->CallObjectMethod (method, Method.invoke, javaSubClass.get(), args);
}
jobject juce_invokeImplementer (JNIEnv* env, jlong thisPtr, jobject proxy, jobject method, jobjectArray args)
{
setEnv (env);
return reinterpret_cast<AndroidInterfaceImplementer*> (thisPtr)->invoke (proxy, method, args);
}
void juce_dispatchDelete (JNIEnv* env, jlong thisPtr)
{
setEnv (env);
delete reinterpret_cast<AndroidInterfaceImplementer*> (thisPtr);
}
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeInvocationHandler), dispatchInvoke,
jobject, (JNIEnv* env, jobject /*object*/, jlong thisPtr, jobject proxy, jobject method, jobjectArray args))
{
return juce_invokeImplementer (env, thisPtr, proxy, method, args);
}
JUCE_JNI_CALLBACK (JUCE_JOIN_MACRO (JUCE_ANDROID_ACTIVITY_CLASSNAME, _00024NativeInvocationHandler), dispatchFinalize,
void, (JNIEnv* env, jobject /*object*/, jlong thisPtr))
{
juce_dispatchDelete (env, thisPtr);
}
//============================================================================== //==============================================================================
JavaVM* androidJNIJavaVM = nullptr; JavaVM* androidJNIJavaVM = nullptr;


+ 5
- 0
libs/juce/source/modules/juce_core/native/juce_mac_ClangBugWorkaround.h View File

@@ -27,4 +27,9 @@
#include <CoreFoundation/CFAvailability.h> #include <CoreFoundation/CFAvailability.h>
#undef CF_OPTIONS #undef CF_OPTIONS
#define CF_OPTIONS(_type, _name) _type _name; enum #define CF_OPTIONS(_type, _name) _type _name; enum
// This is a workaround for the XCode 9 version of NSUUID.h causing some errors
// in the live-build engine.
#define _Nullable
#define _Nonnull
#endif #endif

+ 5
- 0
libs/juce/source/modules/juce_core/native/juce_mac_Files.mm View File

@@ -401,7 +401,12 @@ bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String&
if (SystemStats::isRunningInAppExtensionSandbox()) if (SystemStats::isRunningInAppExtensionSandbox())
return false; return false;
#if (! defined __IPHONE_OS_VERSION_MIN_REQUIRED) || (! defined __IPHONE_10_0) || (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0)
return [[UIApplication sharedApplication] openURL: filenameAsURL]; return [[UIApplication sharedApplication] openURL: filenameAsURL];
#else
[[UIApplication sharedApplication] openURL: filenameAsURL options: @{} completionHandler: nil];
return true;
#endif
#else #else
NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; NSWorkspace* workspace = [NSWorkspace sharedWorkspace];


+ 2
- 0
libs/juce/source/modules/juce_core/native/juce_mac_Network.mm View File

@@ -137,6 +137,8 @@ public:
[task release]; [task release];
[request release]; [request release];
[headers release]; [headers release];
[session finishTasksAndInvalidate];
[session release]; [session release];
const ScopedLock sl (dataLock); const ScopedLock sl (dataLock);


+ 10
- 0
libs/juce/source/modules/juce_core/native/juce_osx_ObjCHelpers.h View File

@@ -59,6 +59,16 @@ namespace
return createNSURLFromFile (f.getFullPathName()); return createNSURLFromFile (f.getFullPathName());
} }
static inline NSArray* createNSArrayFromStringArray (const StringArray& strings)
{
auto* array = [[NSMutableArray alloc] init];
for (auto string: strings)
[array addObject:juceStringToNS (string)];
return [array autorelease];
}
#if JUCE_MAC #if JUCE_MAC
template <typename RectangleType> template <typename RectangleType>
static NSRect makeNSRect (const RectangleType& r) noexcept static NSRect makeNSRect (const RectangleType& r) noexcept


+ 8
- 14
libs/juce/source/modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -393,7 +393,11 @@ void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int
{ {
modificationTime = (int64) info.st_mtime * 1000; modificationTime = (int64) info.st_mtime * 1000;
accessTime = (int64) info.st_atime * 1000; accessTime = (int64) info.st_atime * 1000;
#if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS
creationTime = (int64) info.st_birthtime * 1000;
#else
creationTime = (int64) info.st_ctime * 1000; creationTime = (int64) info.st_ctime * 1000;
#endif
} }
} }
@@ -554,23 +558,13 @@ ssize_t FileOutputStream::writeInternal (const void* const data, const size_t nu
return result; return result;
} }
#ifndef JUCE_ANDROID
void FileOutputStream::flushInternal() void FileOutputStream::flushInternal()
{ {
if (fileHandle != 0)
{
if (fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
#if JUCE_ANDROID
// This stuff tells the OS to asynchronously update the metadata
// that the OS has cached aboud the file - this metadata is used
// when the device is acting as a USB drive, and unless it's explicitly
// refreshed, it'll get out of step with the real file.
const LocalRef<jstring> t (javaString (file.getFullPathName()));
android.activity.callVoidMethod (JuceAppActivity.scanFile, t.get());
#endif
}
if (fileHandle != 0 && fsync (getFD (fileHandle)) == -1)
status = getResultForErrno();
} }
#endif
Result FileOutputStream::truncate() Result FileOutputStream::truncate()
{ {


+ 13
- 1
libs/juce/source/modules/juce_core/native/juce_win32_SystemStats.cpp View File

@@ -227,7 +227,19 @@ String SystemStats::getOperatingSystemName()
String SystemStats::getDeviceDescription() String SystemStats::getDeviceDescription()
{ {
return {};
#if WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
return "Windows (Desktop)";
#elif WINAPI_FAMILY == WINAPI_FAMILY_PC_APP
return "Windows (Store)";
#elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
return "Windows (Phone)";
#elif WINAPI_FAMILY == WINAPI_FAMILY_SYSTEM
return "Windows (System)";
#elif WINAPI_FAMILY == WINAPI_FAMILY_SERVER
return "Windows (Server)";
#else
return "Windows";
#endif
} }
bool SystemStats::isOperatingSystem64Bit() bool SystemStats::isOperatingSystem64Bit()


+ 18
- 0
libs/juce/source/modules/juce_core/system/juce_CompilerSupport.h View File

@@ -47,6 +47,10 @@
#define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1 #define JUCE_COMPILER_SUPPORTS_THREAD_LOCAL 1
#endif #endif
#if __cpp_constexpr >= 201304
#define JUCE_HAS_CONSTEXPR 1
#endif
#ifndef JUCE_EXCEPTIONS_DISABLED #ifndef JUCE_EXCEPTIONS_DISABLED
#if ! __EXCEPTIONS #if ! __EXCEPTIONS
#define JUCE_EXCEPTIONS_DISABLED 1 #define JUCE_EXCEPTIONS_DISABLED 1
@@ -86,6 +90,10 @@
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1 #define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#endif #endif
#if __has_feature(cxx_relaxed_constexpr)
#define JUCE_HAS_CONSTEXPR 1
#endif
#ifndef JUCE_COMPILER_SUPPORTS_ARC #ifndef JUCE_COMPILER_SUPPORTS_ARC
#define JUCE_COMPILER_SUPPORTS_ARC 1 #define JUCE_COMPILER_SUPPORTS_ARC 1
#endif #endif
@@ -118,6 +126,10 @@
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
#endif #endif
#if _MSC_VER >= 1910
#define JUCE_HAS_CONSTEXPR 1
#endif
#ifndef JUCE_EXCEPTIONS_DISABLED #ifndef JUCE_EXCEPTIONS_DISABLED
#if ! _CPPUNWIND #if ! _CPPUNWIND
#define JUCE_EXCEPTIONS_DISABLED 1 #define JUCE_EXCEPTIONS_DISABLED 1
@@ -137,6 +149,12 @@
#define JUCE_DELETED_FUNCTION #define JUCE_DELETED_FUNCTION
#endif #endif
#if JUCE_HAS_CONSTEXPR
#define JUCE_CONSTEXPR constexpr
#else
#define JUCE_CONSTEXPR
#endif
#if ! DOXYGEN #if ! DOXYGEN
#if ! JUCE_COMPILER_SUPPORTS_NOEXCEPT #if ! JUCE_COMPILER_SUPPORTS_NOEXCEPT
#ifdef noexcept #ifdef noexcept


+ 5
- 5
libs/juce/source/modules/juce_core/text/juce_String.cpp View File

@@ -563,7 +563,7 @@ struct HashGenerator
template <typename CharPointer> template <typename CharPointer>
static Type calculate (CharPointer t) noexcept static Type calculate (CharPointer t) noexcept
{ {
Type result = Type();
Type result = {};
while (! t.isEmpty()) while (! t.isEmpty())
result = ((Type) multiplier) * result + (Type) t.getAndAdvance(); result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
@@ -574,9 +574,9 @@ struct HashGenerator
enum { multiplier = sizeof (Type) > 4 ? 101 : 31 }; enum { multiplier = sizeof (Type) > 4 ? 101 : 31 };
}; };
int String::hashCode() const noexcept { return HashGenerator<int> ::calculate (text); }
int64 String::hashCode64() const noexcept { return HashGenerator<int64> ::calculate (text); }
size_t String::hash() const noexcept { return HashGenerator<size_t> ::calculate (text); }
int String::hashCode() const noexcept { return (int) HashGenerator<uint32> ::calculate (text); }
int64 String::hashCode64() const noexcept { return (int64) HashGenerator<uint64> ::calculate (text); }
size_t String::hash() const noexcept { return HashGenerator<size_t> ::calculate (text); }
//============================================================================== //==============================================================================
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; } JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; }
@@ -1884,7 +1884,7 @@ String String::formattedRaw (const char* pf, ...)
va_end (args); va_end (args);
if (num > 0) if (num > 0)
return String (temp);
return String (temp.get());
bufferSize += 256; bufferSize += 256;


+ 16
- 8
libs/juce/source/modules/juce_core/text/juce_String.h View File

@@ -987,6 +987,10 @@ public:
*/ */
String (double doubleValue, int numberOfDecimalPlaces); String (double doubleValue, int numberOfDecimalPlaces);
// Automatically creating a String from a bool opens up lots of nasty type conversion edge cases.
// If you want a String representation of a bool you can cast the bool to an int first.
explicit String (bool) = delete;
/** Reads the value of the string as a decimal number (up to 32 bits in size). /** Reads the value of the string as a decimal number (up to 32 bits in size).
@returns the value of the string as a 32 bit signed base-10 integer. @returns the value of the string as a 32 bit signed base-10 integer.
@@ -1323,23 +1327,27 @@ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const String& string
/** Appends a string to the end of the first one. */ /** Appends a string to the end of the first one. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, StringRef string2); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, StringRef string2);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, short number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, short number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, unsigned long number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, unsigned long number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int64 number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int64 number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint64 number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, uint64 number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number);
/** Appends a decimal number at the end of a string. */
/** Appends a decimal number to the end of a string. */
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number); JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number);
// Automatically creating a String from a bool opens up lots of nasty type conversion edge cases.
// If you want a String representation of a bool you can cast the bool to an int first.
JUCE_API String& JUCE_CALLTYPE operator<< (String&, bool) = delete;
//============================================================================== //==============================================================================
/** Case-sensitive comparison of two strings. */ /** Case-sensitive comparison of two strings. */
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const String& string2) noexcept; JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const String& string2) noexcept;


+ 31
- 2
libs/juce/source/modules/juce_core/threads/juce_Thread.cpp View File

@@ -20,13 +20,16 @@
============================================================================== ==============================================================================
*/ */
Thread::Thread (const String& name, const size_t stackSize)
Thread::Thread (const String& name, size_t stackSize)
: threadName (name), threadStackSize (stackSize) : threadName (name), threadStackSize (stackSize)
{ {
} }
Thread::~Thread() Thread::~Thread()
{ {
if (deleteOnThreadEnd)
return;
/* If your thread class's destructor has been called without first stopping the thread, that /* If your thread class's destructor has been called without first stopping the thread, that
means that this partially destructed object is still performing some work - and that's means that this partially destructed object is still performing some work - and that's
probably a Bad Thing! probably a Bad Thing!
@@ -97,6 +100,9 @@ void Thread::threadEntryPoint()
currentThreadHolder->value.releaseCurrentThreadStorage(); currentThreadHolder->value.releaseCurrentThreadStorage();
closeThreadHandle(); closeThreadHandle();
if (deleteOnThreadEnd)
delete this;
} }
// used to wrap the incoming call from the platform-specific code // used to wrap the incoming call from the platform-specific code
@@ -162,7 +168,7 @@ void Thread::signalThreadShouldExit()
bool Thread::currentThreadShouldExit() bool Thread::currentThreadShouldExit()
{ {
if (Thread* currentThread = getCurrentThread())
if (auto* currentThread = getCurrentThread())
return currentThread->threadShouldExit(); return currentThread->threadShouldExit();
return false; return false;
@@ -273,6 +279,29 @@ void Thread::notify() const
defaultEvent.signal(); defaultEvent.signal();
} }
//==============================================================================
struct LambdaThread : public Thread
{
LambdaThread (std::function<void()> f) : Thread ("anonymous"), fn (f) {}
void run() override
{
fn();
fn = {}; // free any objects that the lambda might contain while the thread is still active
}
std::function<void()> fn;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LambdaThread)
};
void Thread::launch (std::function<void()> functionToRun)
{
auto anon = new LambdaThread (functionToRun);
anon->deleteOnThreadEnd = true;
anon->startThread();
}
//============================================================================== //==============================================================================
void SpinLock::enter() const noexcept void SpinLock::enter() const noexcept
{ {


+ 15
- 9
libs/juce/source/modules/juce_core/threads/juce_Thread.h View File

@@ -76,8 +76,6 @@ public:
virtual void run() = 0; virtual void run() = 0;
//============================================================================== //==============================================================================
// Thread control functions..
/** Starts the thread running. /** Starts the thread running.
This will cause the thread's run() method to be called by a new thread. This will cause the thread's run() method to be called by a new thread.
@@ -118,6 +116,18 @@ public:
*/ */
bool stopThread (int timeOutMilliseconds); bool stopThread (int timeOutMilliseconds);
//==============================================================================
/** Invokes a lambda or function on its own thread.
This will spin up a Thread object which calls the function and then exits.
Bear in mind that starting and stopping a thread can be a fairly heavyweight
operation, so you might prefer to use a ThreadPool if you're kicking off a lot
of short background tasks.
Also note that using an anonymous thread makes it very difficult to interrupt
the function when you need to stop it, e.g. when your app quits. So it's up to
you to deal with situations where the function may fail to stop in time.
*/
static void launch (std::function<void()> functionToRun);
//============================================================================== //==============================================================================
/** Returns true if the thread is currently active */ /** Returns true if the thread is currently active */
bool isThreadRunning() const; bool isThreadRunning() const;
@@ -154,8 +164,7 @@ public:
static bool currentThreadShouldExit(); static bool currentThreadShouldExit();
/** Waits for the thread to stop. /** Waits for the thread to stop.
This will waits until isThreadRunning() is false or until a timeout expires.
This will wait until isThreadRunning() is false or until a timeout expires.
@param timeOutMilliseconds the time to wait, in milliseconds. If this value @param timeOutMilliseconds the time to wait, in milliseconds. If this value
is less than zero, it will wait forever. is less than zero, it will wait forever.
@@ -274,21 +283,17 @@ public:
static Thread* JUCE_CALLTYPE getCurrentThread(); static Thread* JUCE_CALLTYPE getCurrentThread();
/** Returns the ID of this thread. /** Returns the ID of this thread.
That means the ID of this thread object - not of the thread that's calling the method. That means the ID of this thread object - not of the thread that's calling the method.
This can change when the thread is started and stopped, and will be invalid if the This can change when the thread is started and stopped, and will be invalid if the
thread's not actually running. thread's not actually running.
@see getCurrentThreadId @see getCurrentThreadId
*/ */
ThreadID getThreadId() const noexcept { return threadId; } ThreadID getThreadId() const noexcept { return threadId; }
/** Returns the name of the thread. /** Returns the name of the thread.
This is the name that gets set in the constructor. This is the name that gets set in the constructor.
*/ */
const String& getThreadName() const { return threadName; }
const String& getThreadName() const noexcept { return threadName; }
/** Changes the name of the caller thread. /** Changes the name of the caller thread.
Different OSes may place different length or content limits on this name. Different OSes may place different length or content limits on this name.
@@ -306,6 +311,7 @@ private:
int threadPriority = 5; int threadPriority = 5;
size_t threadStackSize; size_t threadStackSize;
uint32 affinityMask = 0; uint32 affinityMask = 0;
bool deleteOnThreadEnd = false;
bool volatile shouldExit = false; bool volatile shouldExit = false;
#if JUCE_ANDROID #if JUCE_ANDROID


+ 79
- 44
libs/juce/source/modules/juce_core/threads/juce_ThreadPool.cpp View File

@@ -23,8 +23,8 @@
class ThreadPool::ThreadPoolThread : public Thread class ThreadPool::ThreadPoolThread : public Thread
{ {
public: public:
ThreadPoolThread (ThreadPool& p, size_t stackSize = 0)
: Thread ("Pool", stackSize), currentJob (nullptr), pool (p)
ThreadPoolThread (ThreadPool& p, size_t stackSize)
: Thread ("Pool", stackSize), pool (p)
{ {
} }
@@ -35,16 +35,14 @@ public:
wait (500); wait (500);
} }
ThreadPoolJob* volatile currentJob;
ThreadPoolJob* volatile currentJob = nullptr;
ThreadPool& pool; ThreadPool& pool;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolThread)
}; };
//============================================================================== //==============================================================================
ThreadPoolJob::ThreadPoolJob (const String& name)
: jobName (name), pool (nullptr),
shouldStop (false), isActive (false), shouldBeDeleted (false)
ThreadPoolJob::ThreadPoolJob (const String& name) : jobName (name)
{ {
} }
@@ -72,7 +70,7 @@ void ThreadPoolJob::signalJobShouldExit()
ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob() ThreadPoolJob* ThreadPoolJob::getCurrentThreadPoolJob()
{ {
if (ThreadPool::ThreadPoolThread* t = dynamic_cast<ThreadPool::ThreadPoolThread*> (Thread::getCurrentThread()))
if (auto* t = dynamic_cast<ThreadPool::ThreadPoolThread*> (Thread::getCurrentThread()))
return t->currentJob; return t->currentJob;
return nullptr; return nullptr;
@@ -102,17 +100,17 @@ void ThreadPool::createThreads (int numThreads, size_t threadStackSize)
for (int i = jmax (1, numThreads); --i >= 0;) for (int i = jmax (1, numThreads); --i >= 0;)
threads.add (new ThreadPoolThread (*this, threadStackSize)); threads.add (new ThreadPoolThread (*this, threadStackSize));
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->startThread();
for (auto* t : threads)
t->startThread();
} }
void ThreadPool::stopThreads() void ThreadPool::stopThreads()
{ {
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->signalThreadShouldExit();
for (auto* t : threads)
t->signalThreadShouldExit();
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->stopThread (500);
for (auto* t : threads)
t->stopThread (500);
} }
void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinished) void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinished)
@@ -132,44 +130,83 @@ void ThreadPool::addJob (ThreadPoolJob* const job, const bool deleteJobWhenFinis
jobs.add (job); jobs.add (job);
} }
for (int i = threads.size(); --i >= 0;)
threads.getUnchecked(i)->notify();
for (auto* t : threads)
t->notify();
} }
} }
int ThreadPool::getNumJobs() const
void ThreadPool::addJob (std::function<ThreadPoolJob::JobStatus()> jobToRun)
{
struct LambdaJobWrapper : public ThreadPoolJob
{
LambdaJobWrapper (std::function<ThreadPoolJob::JobStatus()> j) : ThreadPoolJob ("lambda"), job (j) {}
JobStatus runJob() override { return job(); }
std::function<ThreadPoolJob::JobStatus()> job;
};
addJob (new LambdaJobWrapper (jobToRun), true);
}
void ThreadPool::addJob (std::function<void()> jobToRun)
{
struct LambdaJobWrapper : public ThreadPoolJob
{
LambdaJobWrapper (std::function<void()> j) : ThreadPoolJob ("lambda"), job (j) {}
JobStatus runJob() override { job(); return ThreadPoolJob::jobHasFinished; }
std::function<void()> job;
};
addJob (new LambdaJobWrapper (jobToRun), true);
}
int ThreadPool::getNumJobs() const noexcept
{ {
return jobs.size(); return jobs.size();
} }
int ThreadPool::getNumThreads() const
int ThreadPool::getNumThreads() const noexcept
{ {
return threads.size(); return threads.size();
} }
ThreadPoolJob* ThreadPool::getJob (const int index) const
ThreadPoolJob* ThreadPool::getJob (int index) const noexcept
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
return jobs [index]; return jobs [index];
} }
bool ThreadPool::contains (const ThreadPoolJob* const job) const
bool ThreadPool::contains (const ThreadPoolJob* const job) const noexcept
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
return jobs.contains (const_cast<ThreadPoolJob*> (job)); return jobs.contains (const_cast<ThreadPoolJob*> (job));
} }
bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const
bool ThreadPool::isJobRunning (const ThreadPoolJob* const job) const noexcept
{ {
const ScopedLock sl (lock); const ScopedLock sl (lock);
return jobs.contains (const_cast<ThreadPoolJob*> (job)) && job->isActive; return jobs.contains (const_cast<ThreadPoolJob*> (job)) && job->isActive;
} }
void ThreadPool::moveJobToFront (const ThreadPoolJob* job) noexcept
{
const ScopedLock sl (lock);
if (! ! job->isActive)
{
auto index = jobs.indexOf (const_cast<ThreadPoolJob*> (job));
if (index > 0)
jobs.move (index, 0);
}
}
bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, const int timeOutMs) const bool ThreadPool::waitForJobToFinish (const ThreadPoolJob* const job, const int timeOutMs) const
{ {
if (job != nullptr) if (job != nullptr)
{ {
const uint32 start = Time::getMillisecondCounter();
auto start = Time::getMillisecondCounter();
while (contains (job)) while (contains (job))
{ {
@@ -217,7 +254,7 @@ bool ThreadPool::removeJob (ThreadPoolJob* const job,
bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs, bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeOutMs,
ThreadPool::JobSelector* const selectedJobsToRemove) ThreadPool::JobSelector* const selectedJobsToRemove)
{ {
Array <ThreadPoolJob*> jobsToWaitFor;
Array<ThreadPoolJob*> jobsToWaitFor;
{ {
OwnedArray<ThreadPoolJob> deletionList; OwnedArray<ThreadPoolJob> deletionList;
@@ -227,7 +264,7 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeO
for (int i = jobs.size(); --i >= 0;) for (int i = jobs.size(); --i >= 0;)
{ {
ThreadPoolJob* const job = jobs.getUnchecked(i);
auto* job = jobs.getUnchecked(i);
if (selectedJobsToRemove == nullptr || selectedJobsToRemove->isJobSuitable (job)) if (selectedJobsToRemove == nullptr || selectedJobsToRemove->isJobSuitable (job))
{ {
@@ -248,13 +285,13 @@ bool ThreadPool::removeAllJobs (const bool interruptRunningJobs, const int timeO
} }
} }
const uint32 start = Time::getMillisecondCounter();
auto start = Time::getMillisecondCounter();
for (;;) for (;;)
{ {
for (int i = jobsToWaitFor.size(); --i >= 0;) for (int i = jobsToWaitFor.size(); --i >= 0;)
{ {
ThreadPoolJob* const job = jobsToWaitFor.getUnchecked (i);
auto* job = jobsToWaitFor.getUnchecked (i);
if (! isJobRunning (job)) if (! isJobRunning (job))
jobsToWaitFor.remove (i); jobsToWaitFor.remove (i);
@@ -277,12 +314,9 @@ StringArray ThreadPool::getNamesOfAllJobs (const bool onlyReturnActiveJobs) cons
StringArray s; StringArray s;
const ScopedLock sl (lock); const ScopedLock sl (lock);
for (int i = 0; i < jobs.size(); ++i)
{
const ThreadPoolJob* const job = jobs.getUnchecked(i);
for (auto* job : jobs)
if (job->isActive || ! onlyReturnActiveJobs) if (job->isActive || ! onlyReturnActiveJobs)
s.add (job->getJobName()); s.add (job->getJobName());
}
return s; return s;
} }
@@ -291,8 +325,8 @@ bool ThreadPool::setThreadPriorities (const int newPriority)
{ {
bool ok = true; bool ok = true;
for (int i = threads.size(); --i >= 0;)
if (! threads.getUnchecked(i)->setPriority (newPriority))
for (auto* t : threads)
if (! t->setPriority (newPriority))
ok = false; ok = false;
return ok; return ok;
@@ -307,20 +341,21 @@ ThreadPoolJob* ThreadPool::pickNextJobToRun()
for (int i = 0; i < jobs.size(); ++i) for (int i = 0; i < jobs.size(); ++i)
{ {
ThreadPoolJob* job = jobs[i];
if (job != nullptr && ! job->isActive)
if (auto* job = jobs[i])
{ {
if (job->shouldStop)
if (! job->isActive)
{ {
jobs.remove (i);
addToDeleteList (deletionList, job);
--i;
continue;
}
if (job->shouldStop)
{
jobs.remove (i);
addToDeleteList (deletionList, job);
--i;
continue;
}
job->isActive = true;
return job;
job->isActive = true;
return job;
}
} }
} }
} }
@@ -330,9 +365,9 @@ ThreadPoolJob* ThreadPool::pickNextJobToRun()
bool ThreadPool::runNextJob (ThreadPoolThread& thread) bool ThreadPool::runNextJob (ThreadPoolThread& thread)
{ {
if (ThreadPoolJob* const job = pickNextJobToRun())
if (auto* job = pickNextJobToRun())
{ {
ThreadPoolJob::JobStatus result = ThreadPoolJob::jobHasFinished;
auto result = ThreadPoolJob::jobHasFinished;
thread.currentJob = job; thread.currentJob = job;
try try


+ 24
- 11
libs/juce/source/modules/juce_core/threads/juce_ThreadPool.h View File

@@ -123,8 +123,8 @@ private:
friend class ThreadPool; friend class ThreadPool;
friend class ThreadPoolThread; friend class ThreadPoolThread;
String jobName; String jobName;
ThreadPool* pool;
bool shouldStop, isActive, shouldBeDeleted;
ThreadPool* pool = nullptr;
bool shouldStop = false, isActive = false, shouldBeDeleted = false;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob)
}; };
@@ -207,6 +207,16 @@ public:
void addJob (ThreadPoolJob* job, void addJob (ThreadPoolJob* job,
bool deleteJobWhenFinished); bool deleteJobWhenFinished);
/** Adds a lambda function to be called as a job.
This will create an internal ThreadPoolJob object to encapsulate and call the lambda.
*/
void addJob (std::function<ThreadPoolJob::JobStatus()> job);
/** Adds a lambda function to be called as a job.
This will create an internal ThreadPoolJob object to encapsulate and call the lambda.
*/
void addJob (std::function<void()> job);
/** Tries to remove a job from the pool. /** Tries to remove a job from the pool.
If the job isn't yet running, this will simply remove it. If it is running, it If the job isn't yet running, this will simply remove it. If it is running, it
@@ -244,27 +254,26 @@ public:
JobSelector* selectedJobsToRemove = nullptr); JobSelector* selectedJobsToRemove = nullptr);
/** Returns the number of jobs currently running or queued. */ /** Returns the number of jobs currently running or queued. */
int getNumJobs() const;
int getNumJobs() const noexcept;
/** Returns the number of threads assigned to this thread pool. */ /** Returns the number of threads assigned to this thread pool. */
int getNumThreads() const;
int getNumThreads() const noexcept;
/** Returns one of the jobs in the queue. /** Returns one of the jobs in the queue.
Note that this can be a very volatile list as jobs might be continuously getting shifted Note that this can be a very volatile list as jobs might be continuously getting shifted
around in the list, and this method may return nullptr if the index is currently out-of-range. around in the list, and this method may return nullptr if the index is currently out-of-range.
*/ */
ThreadPoolJob* getJob (int index) const;
ThreadPoolJob* getJob (int index) const noexcept;
/** Returns true if the given job is currently queued or running. /** Returns true if the given job is currently queued or running.
@see isJobRunning() @see isJobRunning()
*/ */
bool contains (const ThreadPoolJob* job) const;
bool contains (const ThreadPoolJob* job) const noexcept;
/** Returns true if the given job is currently being run by a thread.
*/
bool isJobRunning (const ThreadPoolJob* job) const;
/** Returns true if the given job is currently being run by a thread. */
bool isJobRunning (const ThreadPoolJob* job) const noexcept;
/** Waits until a job has finished running and has been removed from the pool. /** Waits until a job has finished running and has been removed from the pool.
@@ -277,13 +286,17 @@ public:
bool waitForJobToFinish (const ThreadPoolJob* job, bool waitForJobToFinish (const ThreadPoolJob* job,
int timeOutMilliseconds) const; int timeOutMilliseconds) const;
/** If the given job is in the queue, this will move it to the front so that it
is the next one to be executed.
*/
void moveJobToFront (const ThreadPoolJob* jobToMove) noexcept;
/** Returns a list of the names of all the jobs currently running or queued. /** Returns a list of the names of all the jobs currently running or queued.
If onlyReturnActiveJobs is true, only the ones currently running are returned. If onlyReturnActiveJobs is true, only the ones currently running are returned.
*/ */
StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const; StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const;
/** Changes the priority of all the threads. /** Changes the priority of all the threads.
This will call Thread::setPriority() for each thread in the pool. This will call Thread::setPriority() for each thread in the pool.
May return false if for some reason the priority can't be changed. May return false if for some reason the priority can't be changed.
*/ */
@@ -292,7 +305,7 @@ public:
private: private:
//============================================================================== //==============================================================================
Array <ThreadPoolJob*> jobs;
Array<ThreadPoolJob*> jobs;
class ThreadPoolThread; class ThreadPoolThread;
friend class ThreadPoolJob; friend class ThreadPoolJob;


+ 3
- 1
libs/juce/source/modules/juce_core/time/juce_PerformanceCounter.h View File

@@ -139,7 +139,7 @@ private:
class JUCE_API ScopedTimeMeasurement class JUCE_API ScopedTimeMeasurement
{ {
public: public:
ScopedTimeMeasurement (double& resultInSeconds)
ScopedTimeMeasurement (double& resultInSeconds) noexcept
: result (resultInSeconds) : result (resultInSeconds)
{ {
result = 0.0; result = 0.0;
@@ -154,4 +154,6 @@ public:
private: private:
int64 startTimeTicks = Time::getHighResolutionTicks(); int64 startTimeTicks = Time::getHighResolutionTicks();
double& result; double& result;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScopedTimeMeasurement)
}; };

+ 9
- 6
libs/juce/source/modules/juce_events/broadcasters/juce_AsyncUpdater.h View File

@@ -48,14 +48,17 @@ public:
//============================================================================== //==============================================================================
/** Causes the callback to be triggered at a later time. /** Causes the callback to be triggered at a later time.
This method returns immediately, having made sure that a callback
to the handleAsyncUpdate() method will occur as soon as possible.
This method returns immediately, after which a callback to the
handleAsyncUpdate() method will be made by the message thread as
soon as possible.
If an update callback is already pending but hasn't happened yet, calls
to this method will be ignored.
If an update callback is already pending but hasn't happened yet, calling
this method will have no effect.
It's thread-safe to call this method from any number of threads without
needing to worry about locking.
It's thread-safe to call this method from any thread, BUT beware of calling
it from a real-time (e.g. audio) thread, because it involves posting a message
to the system queue, which means it may block (and in general will do on
most OSes).
*/ */
void triggerAsyncUpdate(); void triggerAsyncUpdate();


+ 80
- 16
libs/juce/source/modules/juce_events/native/juce_android_Messaging.cpp View File

@@ -20,8 +20,61 @@
============================================================================== ==============================================================================
*/ */
void MessageManager::doPlatformSpecificInitialisation() {}
void MessageManager::doPlatformSpecificShutdown() {}
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (constructor, "<init>", "()V") \
METHOD (post, "post", "(Ljava/lang/Runnable;)Z") \
DECLARE_JNI_CLASS (JNIHandler, "android/os/Handler");
#undef JNI_CLASS_MEMBERS
//==============================================================================
namespace Android
{
class Runnable : public juce::AndroidInterfaceImplementer
{
public:
virtual void run() = 0;
private:
jobject invoke (jobject proxy, jobject method, jobjectArray args) override
{
auto* env = getEnv();
auto methodName = juce::juceString ((jstring) env->CallObjectMethod (method, Method.getName));
if (methodName == "run")
{
run();
return nullptr;
}
// invoke base class
return AndroidInterfaceImplementer::invoke (proxy, method, args);
}
};
struct Handler
{
juce_DeclareSingleton (Handler, false)
Handler() : nativeHandler (getEnv()->NewObject (JNIHandler, JNIHandler.constructor)) {}
bool post (Runnable* runnable)
{
return (getEnv()->CallBooleanMethod (nativeHandler.get(), JNIHandler.post,
CreateJavaInterface (runnable, "java/lang/Runnable").get()) != 0);
}
GlobalRef nativeHandler;
};
juce_ImplementSingleton (Handler);
}
//==============================================================================
void MessageManager::doPlatformSpecificInitialisation() { Android::Handler::getInstance(); }
void MessageManager::doPlatformSpecificShutdown() {}
//============================================================================== //==============================================================================
bool MessageManager::dispatchNextMessageOnSystemQueue (const bool) bool MessageManager::dispatchNextMessageOnSystemQueue (const bool)
@@ -33,26 +86,37 @@ bool MessageManager::dispatchNextMessageOnSystemQueue (const bool)
} }
//============================================================================== //==============================================================================
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
struct AndroidMessageCallback : public Android::Runnable
{ {
message->incReferenceCount();
android.activity.callVoidMethod (JuceAppActivity.postMessage, (jlong) (pointer_sized_uint) message);
return true;
}
AndroidMessageCallback (const MessageManager::MessageBase::Ptr& messageToDeliver)
: message (messageToDeliver)
{}
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, deliverMessage, void, (JNIEnv* env, jobject, jlong value))
{
setEnv (env);
AndroidMessageCallback (MessageManager::MessageBase::Ptr && messageToDeliver)
: message (static_cast<MessageManager::MessageBase::Ptr&&> (messageToDeliver))
{}
JUCE_TRY
void run() override
{ {
MessageManager::MessageBase* const message = (MessageManager::MessageBase*) (pointer_sized_uint) value;
message->messageCallback();
message->decReferenceCount();
JUCE_TRY
{
message->messageCallback();
// delete the message already here as Java will only run the
// destructor of this runnable the next time the garbage
// collector kicks in.
message = nullptr;
}
JUCE_CATCH_EXCEPTION
} }
JUCE_CATCH_EXCEPTION
}
MessageManager::MessageBase::Ptr message;
};
bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
{
return Android::Handler::getInstance()->post (new AndroidMessageCallback (message));
}
//============================================================================== //==============================================================================
void MessageManager::broadcastMessage (const String&) void MessageManager::broadcastMessage (const String&)
{ {


+ 19
- 29
libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.cpp View File

@@ -38,7 +38,7 @@ namespace
&& (int) h >= 0 && (int) h <= maxVal); && (int) h >= 0 && (int) h <= maxVal);
#endif #endif
return Rectangle<Type> (x, y, w, h);
return { x, y, w, h };
} }
} }
@@ -49,15 +49,13 @@ LowLevelGraphicsContext::~LowLevelGraphicsContext() {}
//============================================================================== //==============================================================================
Graphics::Graphics (const Image& imageToDrawOnto) Graphics::Graphics (const Image& imageToDrawOnto)
: context (*imageToDrawOnto.createLowLevelContext()), : context (*imageToDrawOnto.createLowLevelContext()),
contextToDelete (&context),
saveStatePending (false)
contextToDelete (&context)
{ {
jassert (imageToDrawOnto.isValid()); // Can't draw into a null image! jassert (imageToDrawOnto.isValid()); // Can't draw into a null image!
} }
Graphics::Graphics (LowLevelGraphicsContext& internalContext) noexcept Graphics::Graphics (LowLevelGraphicsContext& internalContext) noexcept
: context (internalContext),
saveStatePending (false)
: context (internalContext)
{ {
} }
@@ -85,7 +83,7 @@ bool Graphics::reduceClipRegion (Rectangle<int> area)
return context.clipToRectangle (area); return context.clipToRectangle (area);
} }
bool Graphics::reduceClipRegion (const int x, const int y, const int w, const int h)
bool Graphics::reduceClipRegion (int x, int y, int w, int h)
{ {
return reduceClipRegion (coordsToRectangle (x, y, w, h)); return reduceClipRegion (coordsToRectangle (x, y, w, h));
} }
@@ -157,7 +155,7 @@ void Graphics::setOrigin (Point<int> newOrigin)
void Graphics::setOrigin (int x, int y) void Graphics::setOrigin (int x, int y)
{ {
setOrigin (Point<int> (x, y));
setOrigin ({ x, y });
} }
void Graphics::addTransform (const AffineTransform& transform) void Graphics::addTransform (const AffineTransform& transform)
@@ -239,23 +237,20 @@ void Graphics::drawSingleLineText (const String& text, const int startX, const i
// Don't pass any vertical placement flags to this method - they'll be ignored. // Don't pass any vertical placement flags to this method - they'll be ignored.
jassert (justification.getOnlyVerticalFlags() == 0); jassert (justification.getOnlyVerticalFlags() == 0);
const int flags = justification.getOnlyHorizontalFlags();
auto flags = justification.getOnlyHorizontalFlags();
if (flags == Justification::right)
{
if (startX < context.getClipBounds().getX())
return;
}
else if (flags == Justification::left)
if (startX > context.getClipBounds().getRight())
return;
if (flags == Justification::right && startX < context.getClipBounds().getX())
return;
if (flags == Justification::left && startX > context.getClipBounds().getRight())
return;
GlyphArrangement arr; GlyphArrangement arr;
arr.addLineOfText (context.getFont(), text, (float) startX, (float) baselineY); arr.addLineOfText (context.getFont(), text, (float) startX, (float) baselineY);
if (flags != Justification::left) if (flags != Justification::left)
{ {
float w = arr.getBoundingBox (0, -1, true).getWidth();
auto w = arr.getBoundingBox (0, -1, true).getWidth();
if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0) if ((flags & (Justification::horizontallyCentred | Justification::horizontallyJustified)) != 0)
w /= 2.0f; w /= 2.0f;
@@ -371,11 +366,6 @@ void Graphics::fillRectList (const RectangleList<int>& rects) const
context.fillRect (r, false); context.fillRect (r, false);
} }
void Graphics::setPixel (int x, int y) const
{
context.fillRect (coordsToRectangle (x, y, 1, 1), false);
}
void Graphics::fillAll() const void Graphics::fillAll() const
{ {
fillRect (context.getClipBounds()); fillRect (context.getClipBounds());
@@ -385,7 +375,7 @@ void Graphics::fillAll (Colour colourToUse) const
{ {
if (! colourToUse.isTransparent()) if (! colourToUse.isTransparent())
{ {
const Rectangle<int> clip (context.getClipBounds());
auto clip = context.getClipBounds();
context.saveState(); context.saveState();
context.setFill (colourToUse); context.setFill (colourToUse);
@@ -507,7 +497,7 @@ void Graphics::drawRoundedRectangle (Rectangle<float> r, float cornerSize, float
strokePath (p, PathStrokeType (lineThickness)); strokePath (p, PathStrokeType (lineThickness));
} }
void Graphics::drawArrow (const Line<float>& line, float lineThickness, float arrowheadWidth, float arrowheadLength) const
void Graphics::drawArrow (Line<float> line, float lineThickness, float arrowheadWidth, float arrowheadLength) const
{ {
Path p; Path p;
p.addArrow (line, lineThickness, arrowheadWidth, arrowheadLength); p.addArrow (line, lineThickness, arrowheadWidth, arrowheadLength);
@@ -531,7 +521,7 @@ void Graphics::fillCheckerBoard (Rectangle<int> area,
} }
else else
{ {
const Rectangle<int> clipped (context.getClipBounds().getIntersection (area));
auto clipped = context.getClipBounds().getIntersection (area);
if (! clipped.isEmpty()) if (! clipped.isEmpty())
{ {
@@ -573,7 +563,7 @@ void Graphics::drawHorizontalLine (const int y, float left, float right) const
context.fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f)); context.fillRect (Rectangle<float> (left, (float) y, right - left, 1.0f));
} }
void Graphics::drawLine (const Line<float>& line) const
void Graphics::drawLine (Line<float> line) const
{ {
context.drawLine (line); context.drawLine (line);
} }
@@ -588,15 +578,15 @@ void Graphics::drawLine (float x1, float y1, float x2, float y2, float lineThick
drawLine (Line<float> (x1, y1, x2, y2), lineThickness); drawLine (Line<float> (x1, y1, x2, y2), lineThickness);
} }
void Graphics::drawLine (const Line<float>& line, const float lineThickness) const
void Graphics::drawLine (Line<float> line, const float lineThickness) const
{ {
Path p; Path p;
p.addLineSegment (line, lineThickness); p.addLineSegment (line, lineThickness);
fillPath (p); fillPath (p);
} }
void Graphics::drawDashedLine (const Line<float>& line, const float* const dashLengths,
const int numDashLengths, const float lineThickness, int n) const
void Graphics::drawDashedLine (Line<float> line, const float* dashLengths,
int numDashLengths, float lineThickness, int n) const
{ {
jassert (n >= 0 && n < numDashLengths); // your start index must be valid! jassert (n >= 0 && n < numDashLengths); // your start index must be valid!


+ 6
- 12
libs/juce/source/modules/juce_graphics/contexts/juce_GraphicsContext.h View File

@@ -338,12 +338,6 @@ public:
void drawRoundedRectangle (Rectangle<float> rectangle, void drawRoundedRectangle (Rectangle<float> rectangle,
float cornerSize, float lineThickness) const; float cornerSize, float lineThickness) const;
/** Fills a 1x1 pixel using the current colour or brush.
Note that because the context may be transformed, this is effectively the same as
calling fillRect (x, y, 1, 1), and the actual result may involve multiple pixels.
*/
void setPixel (int x, int y) const;
//============================================================================== //==============================================================================
/** Fills an ellipse with the current colour or brush. /** Fills an ellipse with the current colour or brush.
The ellipse is drawn to fit inside the given rectangle. The ellipse is drawn to fit inside the given rectangle.
@@ -388,14 +382,14 @@ public:
TIP: If you're trying to draw horizontal or vertical lines, don't use this - TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line. it's better to use fillRect() instead unless you really need an angled line.
*/ */
void drawLine (const Line<float>& line) const;
void drawLine (Line<float> line) const;
/** Draws a line between two points with a given thickness. /** Draws a line between two points with a given thickness.
@see Path::addLineSegment @see Path::addLineSegment
TIP: If you're trying to draw horizontal or vertical lines, don't use this - TIP: If you're trying to draw horizontal or vertical lines, don't use this -
it's better to use fillRect() instead unless you really need an angled line. it's better to use fillRect() instead unless you really need an angled line.
*/ */
void drawLine (const Line<float>& line, float lineThickness) const;
void drawLine (Line<float> line, float lineThickness) const;
/** Draws a dashed line using a custom set of dash-lengths. /** Draws a dashed line using a custom set of dash-lengths.
@@ -408,7 +402,7 @@ public:
@param dashIndexToStartFrom the index in the dash-length array to use for the first segment @param dashIndexToStartFrom the index in the dash-length array to use for the first segment
@see PathStrokeType::createDashedStroke @see PathStrokeType::createDashedStroke
*/ */
void drawDashedLine (const Line<float>& line,
void drawDashedLine (Line<float> line,
const float* dashLengths, int numDashLengths, const float* dashLengths, int numDashLengths,
float lineThickness = 1.0f, float lineThickness = 1.0f,
int dashIndexToStartFrom = 0) const; int dashIndexToStartFrom = 0) const;
@@ -441,7 +435,7 @@ public:
/** Draws a path's outline using the currently selected colour or brush. */ /** Draws a path's outline using the currently selected colour or brush. */
void strokePath (const Path& path, void strokePath (const Path& path,
const PathStrokeType& strokeType, const PathStrokeType& strokeType,
const AffineTransform& transform = AffineTransform()) const;
const AffineTransform& transform = {}) const;
/** Draws a line with an arrowhead at its end. /** Draws a line with an arrowhead at its end.
@@ -450,7 +444,7 @@ public:
@param arrowheadWidth the width of the arrow head (perpendicular to the line) @param arrowheadWidth the width of the arrow head (perpendicular to the line)
@param arrowheadLength the length of the arrow head (along the length of the line) @param arrowheadLength the length of the arrow head (along the length of the line)
*/ */
void drawArrow (const Line<float>& line,
void drawArrow (Line<float> line,
float lineThickness, float lineThickness,
float arrowheadWidth, float arrowheadWidth,
float arrowheadLength) const; float arrowheadLength) const;
@@ -743,7 +737,7 @@ private:
LowLevelGraphicsContext& context; LowLevelGraphicsContext& context;
ScopedPointer<LowLevelGraphicsContext> contextToDelete; ScopedPointer<LowLevelGraphicsContext> contextToDelete;
bool saveStatePending;
bool saveStatePending = false;
void saveStateIfPending(); void saveStateIfPending();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Graphics) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Graphics)


+ 19
- 20
libs/juce/source/modules/juce_graphics/geometry/juce_Path.cpp View File

@@ -280,7 +280,7 @@ void Path::startNewSubPath (const float x, const float y)
data.elements[numElements++] = y; data.elements[numElements++] = y;
} }
void Path::startNewSubPath (const Point<float> start)
void Path::startNewSubPath (Point<float> start)
{ {
startNewSubPath (start.x, start.y); startNewSubPath (start.x, start.y);
} }
@@ -301,7 +301,7 @@ void Path::lineTo (const float x, const float y)
bounds.extend (x, y); bounds.extend (x, y);
} }
void Path::lineTo (const Point<float> end)
void Path::lineTo (Point<float> end)
{ {
lineTo (end.x, end.y); lineTo (end.x, end.y);
} }
@@ -326,8 +326,7 @@ void Path::quadraticTo (const float x1, const float y1,
bounds.extend (x1, y1, x2, y2); bounds.extend (x1, y1, x2, y2);
} }
void Path::quadraticTo (const Point<float> controlPoint,
const Point<float> endPoint)
void Path::quadraticTo (Point<float> controlPoint, Point<float> endPoint)
{ {
quadraticTo (controlPoint.x, controlPoint.y, quadraticTo (controlPoint.x, controlPoint.y,
endPoint.x, endPoint.y); endPoint.x, endPoint.y);
@@ -358,9 +357,9 @@ void Path::cubicTo (const float x1, const float y1,
bounds.extend (x3, y3); bounds.extend (x3, y3);
} }
void Path::cubicTo (const Point<float> controlPoint1,
const Point<float> controlPoint2,
const Point<float> endPoint)
void Path::cubicTo (Point<float> controlPoint1,
Point<float> controlPoint2,
Point<float> endPoint)
{ {
cubicTo (controlPoint1.x, controlPoint1.y, cubicTo (controlPoint1.x, controlPoint1.y,
controlPoint2.x, controlPoint2.y, controlPoint2.x, controlPoint2.y,
@@ -675,7 +674,7 @@ void Path::addPieSegment (Rectangle<float> segmentBounds,
} }
//============================================================================== //==============================================================================
void Path::addLineSegment (const Line<float>& line, float lineThickness)
void Path::addLineSegment (Line<float> line, float lineThickness)
{ {
auto reversed = line.reversed(); auto reversed = line.reversed();
lineThickness *= 0.5f; lineThickness *= 0.5f;
@@ -687,7 +686,7 @@ void Path::addLineSegment (const Line<float>& line, float lineThickness)
closeSubPath(); closeSubPath();
} }
void Path::addArrow (const Line<float>& line, float lineThickness,
void Path::addArrow (Line<float> line, float lineThickness,
float arrowheadWidth, float arrowheadLength) float arrowheadWidth, float arrowheadLength)
{ {
auto reversed = line.reversed(); auto reversed = line.reversed();
@@ -705,8 +704,8 @@ void Path::addArrow (const Line<float>& line, float lineThickness,
closeSubPath(); closeSubPath();
} }
void Path::addPolygon (const Point<float> centre, const int numberOfSides,
const float radius, const float startAngle)
void Path::addPolygon (Point<float> centre, int numberOfSides,
float radius, float startAngle)
{ {
jassert (numberOfSides > 1); // this would be silly. jassert (numberOfSides > 1); // this would be silly.
@@ -729,8 +728,8 @@ void Path::addPolygon (const Point<float> centre, const int numberOfSides,
} }
} }
void Path::addStar (const Point<float> centre, const int numberOfPoints,
const float innerRadius, const float outerRadius, const float startAngle)
void Path::addStar (Point<float> centre, int numberOfPoints, float innerRadius,
float outerRadius, float startAngle)
{ {
jassert (numberOfPoints > 1); // this would be silly. jassert (numberOfPoints > 1); // this would be silly.
@@ -755,9 +754,9 @@ void Path::addStar (const Point<float> centre, const int numberOfPoints,
} }
} }
void Path::addBubble (const Rectangle<float>& bodyArea,
const Rectangle<float>& maximumArea,
const Point<float> arrowTip,
void Path::addBubble (Rectangle<float> bodyArea,
Rectangle<float> maximumArea,
Point<float> arrowTip,
const float cornerSize, const float cornerSize,
const float arrowBaseWidth) const float arrowBaseWidth)
{ {
@@ -968,8 +967,8 @@ void Path::applyTransform (const AffineTransform& transform) noexcept
//============================================================================== //==============================================================================
AffineTransform Path::getTransformToScaleToFit (const Rectangle<float>& area,
bool preserveProportions, Justification justification) const
AffineTransform Path::getTransformToScaleToFit (Rectangle<float> area, bool preserveProportions,
Justification justification) const
{ {
return getTransformToScaleToFit (area.getX(), area.getY(), area.getWidth(), area.getHeight(), return getTransformToScaleToFit (area.getX(), area.getY(), area.getWidth(), area.getHeight(),
preserveProportions, justification); preserveProportions, justification);
@@ -1059,7 +1058,7 @@ bool Path::contains (const float x, const float y, const float tolerance) const
: ((negativeCrossings + positiveCrossings) & 1) != 0; : ((negativeCrossings + positiveCrossings) & 1) != 0;
} }
bool Path::contains (const Point<float> point, const float tolerance) const
bool Path::contains (Point<float> point, const float tolerance) const
{ {
return contains (point.x, point.y, tolerance); return contains (point.x, point.y, tolerance);
} }
@@ -1138,7 +1137,7 @@ Point<float> Path::getPointAlongPath (float distanceFromStart,
return { i.x2, i.y2 }; return { i.x2, i.y2 };
} }
float Path::getNearestPoint (const Point<float> targetPoint, Point<float>& pointOnPath,
float Path::getNearestPoint (Point<float> targetPoint, Point<float>& pointOnPath,
const AffineTransform& transform, const AffineTransform& transform,
float tolerance) const float tolerance) const
{ {


+ 18
- 18
libs/juce/source/modules/juce_graphics/geometry/juce_Path.h View File

@@ -129,7 +129,7 @@ public:
@see closeSubPath, setUsingNonZeroWinding @see closeSubPath, setUsingNonZeroWinding
*/ */
bool contains (const Point<float> point,
bool contains (Point<float> point,
float tolerance = defaultToleranceForTesting) const; float tolerance = defaultToleranceForTesting) const;
/** Checks whether a line crosses the path. /** Checks whether a line crosses the path.
@@ -211,7 +211,7 @@ public:
@see lineTo, quadraticTo, cubicTo, closeSubPath @see lineTo, quadraticTo, cubicTo, closeSubPath
*/ */
void startNewSubPath (const Point<float> start);
void startNewSubPath (Point<float> start);
/** Closes a the current sub-path with a line back to its start-point. /** Closes a the current sub-path with a line back to its start-point.
@@ -247,7 +247,7 @@ public:
@see startNewSubPath, quadraticTo, cubicTo, closeSubPath @see startNewSubPath, quadraticTo, cubicTo, closeSubPath
*/ */
void lineTo (const Point<float> end);
void lineTo (Point<float> end);
/** Adds a quadratic bezier curve from the shape's last position to a new position. /** Adds a quadratic bezier curve from the shape's last position to a new position.
@@ -272,8 +272,8 @@ public:
@see startNewSubPath, lineTo, cubicTo, closeSubPath @see startNewSubPath, lineTo, cubicTo, closeSubPath
*/ */
void quadraticTo (const Point<float> controlPoint,
const Point<float> endPoint);
void quadraticTo (Point<float> controlPoint,
Point<float> endPoint);
/** Adds a cubic bezier curve from the shape's last position to a new position. /** Adds a cubic bezier curve from the shape's last position to a new position.
@@ -300,9 +300,9 @@ public:
@see startNewSubPath, lineTo, quadraticTo, closeSubPath @see startNewSubPath, lineTo, quadraticTo, closeSubPath
*/ */
void cubicTo (const Point<float> controlPoint1,
const Point<float> controlPoint2,
const Point<float> endPoint);
void cubicTo (Point<float> controlPoint1,
Point<float> controlPoint2,
Point<float> endPoint);
/** Returns the last point that was added to the path by one of the drawing methods. /** Returns the last point that was added to the path by one of the drawing methods.
*/ */
@@ -320,7 +320,7 @@ public:
@see addRoundedRectangle, addTriangle @see addRoundedRectangle, addTriangle
*/ */
template <typename ValueType> template <typename ValueType>
void addRectangle (const Rectangle<ValueType>& rectangle)
void addRectangle (Rectangle<ValueType> rectangle)
{ {
addRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()), addRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()),
static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight())); static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight()));
@@ -355,7 +355,7 @@ public:
@see addRectangle, addTriangle @see addRectangle, addTriangle
*/ */
template <typename ValueType> template <typename ValueType>
void addRoundedRectangle (const Rectangle<ValueType>& rectangle, float cornerSizeX, float cornerSizeY)
void addRoundedRectangle (Rectangle<ValueType> rectangle, float cornerSizeX, float cornerSizeY)
{ {
addRoundedRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()), addRoundedRectangle (static_cast<float> (rectangle.getX()), static_cast<float> (rectangle.getY()),
static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight()), static_cast<float> (rectangle.getWidth()), static_cast<float> (rectangle.getHeight()),
@@ -367,7 +367,7 @@ public:
@see addRectangle, addTriangle @see addRectangle, addTriangle
*/ */
template <typename ValueType> template <typename ValueType>
void addRoundedRectangle (const Rectangle<ValueType>& rectangle, float cornerSize)
void addRoundedRectangle (Rectangle<ValueType> rectangle, float cornerSize)
{ {
addRoundedRectangle (rectangle, cornerSize, cornerSize); addRoundedRectangle (rectangle, cornerSize, cornerSize);
} }
@@ -534,13 +534,13 @@ public:
@see addArrow @see addArrow
*/ */
void addLineSegment (const Line<float>& line, float lineThickness);
void addLineSegment (Line<float> line, float lineThickness);
/** Adds a line with an arrowhead on the end. /** Adds a line with an arrowhead on the end.
The arrow is added as a new closed sub-path. (Any currently open paths will be left open). The arrow is added as a new closed sub-path. (Any currently open paths will be left open).
@see PathStrokeType::createStrokeWithArrowheads @see PathStrokeType::createStrokeWithArrowheads
*/ */
void addArrow (const Line<float>& line,
void addArrow (Line<float> line,
float lineThickness, float lineThickness,
float arrowheadWidth, float arrowheadWidth,
float arrowheadLength); float arrowheadLength);
@@ -548,7 +548,7 @@ public:
/** Adds a polygon shape to the path. /** Adds a polygon shape to the path.
@see addStar @see addStar
*/ */
void addPolygon (const Point<float> centre,
void addPolygon (Point<float> centre,
int numberOfSides, int numberOfSides,
float radius, float radius,
float startAngle = 0.0f); float startAngle = 0.0f);
@@ -556,7 +556,7 @@ public:
/** Adds a star shape to the path. /** Adds a star shape to the path.
@see addPolygon @see addPolygon
*/ */
void addStar (const Point<float> centre,
void addStar (Point<float> centre,
int numberOfPoints, int numberOfPoints,
float innerRadius, float innerRadius,
float outerRadius, float outerRadius,
@@ -572,8 +572,8 @@ public:
@param cornerSize the size of the rounded corners @param cornerSize the size of the rounded corners
@param arrowBaseWidth the width of the base of the arrow where it joins the main rectangle @param arrowBaseWidth the width of the base of the arrow where it joins the main rectangle
*/ */
void addBubble (const Rectangle<float>& bodyArea,
const Rectangle<float>& maximumArea,
void addBubble (Rectangle<float> bodyArea,
Rectangle<float> maximumArea,
const Point<float> arrowTipPosition, const Point<float> arrowTipPosition,
const float cornerSize, const float cornerSize,
const float arrowBaseWidth); const float arrowBaseWidth);
@@ -677,7 +677,7 @@ public:
@see applyTransform, scaleToFit @see applyTransform, scaleToFit
*/ */
AffineTransform getTransformToScaleToFit (const Rectangle<float>& area,
AffineTransform getTransformToScaleToFit (Rectangle<float> area,
bool preserveProportions, bool preserveProportions,
Justification justificationType = Justification::centred) const; Justification justificationType = Justification::centred) const;


+ 30
- 30
libs/juce/source/modules/juce_graphics/geometry/juce_Point.h View File

@@ -41,101 +41,101 @@ class Point
{ {
public: public:
/** Creates a point at the origin */ /** Creates a point at the origin */
Point() noexcept : x(), y() {}
JUCE_CONSTEXPR Point() noexcept : x(), y() {}
/** Creates a copy of another point. */ /** Creates a copy of another point. */
Point (const Point& other) noexcept : x (other.x), y (other.y) {}
JUCE_CONSTEXPR Point (const Point& other) noexcept : x (other.x), y (other.y) {}
/** Creates a point from an (x, y) position. */ /** Creates a point from an (x, y) position. */
Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {}
JUCE_CONSTEXPR Point (ValueType initialX, ValueType initialY) noexcept : x (initialX), y (initialY) {}
//============================================================================== //==============================================================================
/** Copies this point from another one. */ /** Copies this point from another one. */
Point& operator= (const Point& other) noexcept { x = other.x; y = other.y; return *this; }
Point& operator= (const Point& other) noexcept { x = other.x; y = other.y; return *this; }
inline bool operator== (Point other) const noexcept { return x == other.x && y == other.y; }
inline bool operator!= (Point other) const noexcept { return x != other.x || y != other.y; }
JUCE_CONSTEXPR inline bool operator== (Point other) const noexcept { return x == other.x && y == other.y; }
JUCE_CONSTEXPR inline bool operator!= (Point other) const noexcept { return x != other.x || y != other.y; }
/** Returns true if the point is (0, 0). */ /** Returns true if the point is (0, 0). */
bool isOrigin() const noexcept { return x == ValueType() && y == ValueType(); }
JUCE_CONSTEXPR bool isOrigin() const noexcept { return x == ValueType() && y == ValueType(); }
/** Returns true if the coordinates are finite values. */ /** Returns true if the coordinates are finite values. */
inline bool isFinite() const noexcept { return juce_isfinite(x) && juce_isfinite(y); }
JUCE_CONSTEXPR inline bool isFinite() const noexcept { return juce_isfinite(x) && juce_isfinite(y); }
/** Returns the point's x coordinate. */ /** Returns the point's x coordinate. */
inline ValueType getX() const noexcept { return x; }
JUCE_CONSTEXPR inline ValueType getX() const noexcept { return x; }
/** Returns the point's y coordinate. */ /** Returns the point's y coordinate. */
inline ValueType getY() const noexcept { return y; }
JUCE_CONSTEXPR inline ValueType getY() const noexcept { return y; }
/** Sets the point's x coordinate. */ /** Sets the point's x coordinate. */
inline void setX (ValueType newX) noexcept { x = newX; }
inline void setX (ValueType newX) noexcept { x = newX; }
/** Sets the point's y coordinate. */ /** Sets the point's y coordinate. */
inline void setY (ValueType newY) noexcept { y = newY; }
inline void setY (ValueType newY) noexcept { y = newY; }
/** Returns a point which has the same Y position as this one, but a new X. */ /** Returns a point which has the same Y position as this one, but a new X. */
Point withX (ValueType newX) const noexcept { return Point (newX, y); }
JUCE_CONSTEXPR Point withX (ValueType newX) const noexcept { return Point (newX, y); }
/** Returns a point which has the same X position as this one, but a new Y. */ /** Returns a point which has the same X position as this one, but a new Y. */
Point withY (ValueType newY) const noexcept { return Point (x, newY); }
JUCE_CONSTEXPR Point withY (ValueType newY) const noexcept { return Point (x, newY); }
/** Changes the point's x and y coordinates. */ /** Changes the point's x and y coordinates. */
void setXY (ValueType newX, ValueType newY) noexcept { x = newX; y = newY; }
void setXY (ValueType newX, ValueType newY) noexcept { x = newX; y = newY; }
/** Adds a pair of coordinates to this value. */ /** Adds a pair of coordinates to this value. */
void addXY (ValueType xToAdd, ValueType yToAdd) noexcept { x += xToAdd; y += yToAdd; }
void addXY (ValueType xToAdd, ValueType yToAdd) noexcept { x += xToAdd; y += yToAdd; }
//============================================================================== //==============================================================================
/** Returns a point with a given offset from this one. */ /** Returns a point with a given offset from this one. */
Point translated (ValueType deltaX, ValueType deltaY) const noexcept { return Point (x + deltaX, y + deltaY); }
JUCE_CONSTEXPR Point translated (ValueType deltaX, ValueType deltaY) const noexcept { return Point (x + deltaX, y + deltaY); }
/** Adds two points together */ /** Adds two points together */
Point operator+ (Point other) const noexcept { return Point (x + other.x, y + other.y); }
JUCE_CONSTEXPR Point operator+ (Point other) const noexcept { return Point (x + other.x, y + other.y); }
/** Adds another point's coordinates to this one */ /** Adds another point's coordinates to this one */
Point& operator+= (Point other) noexcept { x += other.x; y += other.y; return *this; }
Point& operator+= (Point other) noexcept { x += other.x; y += other.y; return *this; }
/** Subtracts one points from another */ /** Subtracts one points from another */
Point operator- (Point other) const noexcept { return Point (x - other.x, y - other.y); }
JUCE_CONSTEXPR Point operator- (Point other) const noexcept { return Point (x - other.x, y - other.y); }
/** Subtracts another point's coordinates to this one */ /** Subtracts another point's coordinates to this one */
Point& operator-= (Point other) noexcept { x -= other.x; y -= other.y; return *this; }
Point& operator-= (Point other) noexcept { x -= other.x; y -= other.y; return *this; }
/** Multiplies two points together */ /** Multiplies two points together */
template <typename OtherType> template <typename OtherType>
Point operator* (Point<OtherType> other) const noexcept { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); }
JUCE_CONSTEXPR Point operator* (Point<OtherType> other) const noexcept { return Point ((ValueType) (x * other.x), (ValueType) (y * other.y)); }
/** Multiplies another point's coordinates to this one */ /** Multiplies another point's coordinates to this one */
template <typename OtherType> template <typename OtherType>
Point& operator*= (Point<OtherType> other) noexcept { *this = *this * other; return *this; }
Point& operator*= (Point<OtherType> other) noexcept { *this = *this * other; return *this; }
/** Divides one point by another */ /** Divides one point by another */
template <typename OtherType> template <typename OtherType>
Point operator/ (Point<OtherType> other) const noexcept { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); }
JUCE_CONSTEXPR Point operator/ (Point<OtherType> other) const noexcept { return Point ((ValueType) (x / other.x), (ValueType) (y / other.y)); }
/** Divides this point's coordinates by another */ /** Divides this point's coordinates by another */
template <typename OtherType> template <typename OtherType>
Point& operator/= (Point<OtherType> other) noexcept { *this = *this / other; return *this; }
Point& operator/= (Point<OtherType> other) noexcept { *this = *this / other; return *this; }
/** Returns a point whose coordinates are multiplied by a given scalar value. */ /** Returns a point whose coordinates are multiplied by a given scalar value. */
template <typename FloatType> template <typename FloatType>
Point operator* (FloatType multiplier) const noexcept { return Point ((ValueType) (x * multiplier), (ValueType) (y * multiplier)); }
JUCE_CONSTEXPR Point operator* (FloatType multiplier) const noexcept { return Point ((ValueType) (x * multiplier), (ValueType) (y * multiplier)); }
/** Returns a point whose coordinates are divided by a given scalar value. */ /** Returns a point whose coordinates are divided by a given scalar value. */
template <typename FloatType> template <typename FloatType>
Point operator/ (FloatType divisor) const noexcept { return Point ((ValueType) (x / divisor), (ValueType) (y / divisor)); }
JUCE_CONSTEXPR Point operator/ (FloatType divisor) const noexcept { return Point ((ValueType) (x / divisor), (ValueType) (y / divisor)); }
/** Multiplies the point's coordinates by a scalar value. */ /** Multiplies the point's coordinates by a scalar value. */
template <typename FloatType> template <typename FloatType>
Point& operator*= (FloatType multiplier) noexcept { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; }
Point& operator*= (FloatType multiplier) noexcept { x = (ValueType) (x * multiplier); y = (ValueType) (y * multiplier); return *this; }
/** Divides the point's coordinates by a scalar value. */ /** Divides the point's coordinates by a scalar value. */
template <typename FloatType> template <typename FloatType>
Point& operator/= (FloatType divisor) noexcept { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; }
Point& operator/= (FloatType divisor) noexcept { x = (ValueType) (x / divisor); y = (ValueType) (y / divisor); return *this; }
/** Returns the inverse of this point. */ /** Returns the inverse of this point. */
Point operator-() const noexcept { return Point (-x, -y); }
JUCE_CONSTEXPR Point operator-() const noexcept { return Point (-x, -y); }
//============================================================================== //==============================================================================
/** This type will be double if the Point's type is double, otherwise it will be float. */ /** This type will be double if the Point's type is double, otherwise it will be float. */


+ 6
- 3
libs/juce/source/modules/juce_graphics/images/juce_Image.cpp View File

@@ -443,9 +443,12 @@ void Image::BitmapData::setPixelColour (const int x, const int y, Colour colour)
//============================================================================== //==============================================================================
void Image::clear (const Rectangle<int>& area, Colour colourToClearTo) void Image::clear (const Rectangle<int>& area, Colour colourToClearTo)
{ {
const ScopedPointer<LowLevelGraphicsContext> g (image->createLowLevelContext());
g->setFill (colourToClearTo);
g->fillRect (area, true);
if (image != nullptr)
{
const ScopedPointer<LowLevelGraphicsContext> g (image->createLowLevelContext());
g->setFill (colourToClearTo);
g->fillRect (area, true);
}
} }
//============================================================================== //==============================================================================


+ 9
- 10
libs/juce/source/modules/juce_graphics/native/juce_RenderingHelpers.h View File

@@ -2295,11 +2295,11 @@ public:
} }
} }
void drawLine (const Line<float>& line)
void drawLine (Line<float> line)
{ {
Path p; Path p;
p.addLineSegment (line, 1.0f); p.addLineSegment (line, 1.0f);
fillPath (p, AffineTransform());
fillPath (p, {});
} }
void drawImage (const Image& sourceImage, const AffineTransform& trans) void drawImage (const Image& sourceImage, const AffineTransform& trans)
@@ -2319,7 +2319,7 @@ public:
void renderImage (const Image& sourceImage, const AffineTransform& trans, void renderImage (const Image& sourceImage, const AffineTransform& trans,
const BaseRegionType* const tiledFillClipRegion) const BaseRegionType* const tiledFillClipRegion)
{ {
const AffineTransform t (transform.getTransformWith (trans));
auto t = transform.getTransformWith (trans);
const int alpha = fillType.colour.getAlpha(); const int alpha = fillType.colour.getAlpha();
@@ -2356,18 +2356,17 @@ public:
{ {
if (tiledFillClipRegion != nullptr) if (tiledFillClipRegion != nullptr)
{ {
tiledFillClipRegion->renderImageTransformed (getThis(), sourceImage, alpha, t, interpolationQuality, true);
tiledFillClipRegion->renderImageTransformed (getThis(), sourceImage, alpha,
t, interpolationQuality, true);
} }
else else
{ {
Path p; Path p;
p.addRectangle (sourceImage.getBounds()); p.addRectangle (sourceImage.getBounds());
typename BaseRegionType::Ptr c (clip->clone());
c = c->clipToPath (p, t);
if (c != nullptr)
c->renderImageTransformed (getThis(), sourceImage, alpha, t, interpolationQuality, false);
if (auto c = clip->clone()->clipToPath (p, t))
c->renderImageTransformed (getThis(), sourceImage, alpha,
t, interpolationQuality, false);
} }
} }
} }
@@ -2386,7 +2385,7 @@ public:
ColourGradient g2 (*(fillType.gradient)); ColourGradient g2 (*(fillType.gradient));
g2.multiplyOpacity (fillType.getOpacity()); g2.multiplyOpacity (fillType.getOpacity());
AffineTransform t (transform.getTransformWith (fillType.transform).translated (-0.5f, -0.5f));
auto t = transform.getTransformWith (fillType.transform).translated (-0.5f, -0.5f);
const bool isIdentity = t.isOnlyTranslation(); const bool isIdentity = t.isOnlyTranslation();


+ 5
- 12
libs/juce/source/modules/juce_gui_basics/buttons/juce_Button.cpp View File

@@ -26,7 +26,7 @@
class Button::CallbackHelper : public Timer, class Button::CallbackHelper : public Timer,
public ApplicationCommandManagerListener, public ApplicationCommandManagerListener,
public ValueListener,
public Value::Listener,
public KeyListener public KeyListener
{ {
public: public:
@@ -394,15 +394,8 @@ void Button::handleCommandMessage (int commandId)
} }
//============================================================================== //==============================================================================
void Button::addListener (ButtonListener* const newListener)
{
buttonListeners.add (newListener);
}
void Button::removeListener (ButtonListener* const listener)
{
buttonListeners.remove (listener);
}
void Button::addListener (Listener* l) { buttonListeners.add (l); }
void Button::removeListener (Listener* l) { buttonListeners.remove (l); }
void Button::sendClickMessage (const ModifierKeys& modifiers) void Button::sendClickMessage (const ModifierKeys& modifiers)
{ {
@@ -420,7 +413,7 @@ void Button::sendClickMessage (const ModifierKeys& modifiers)
clicked (modifiers); clicked (modifiers);
if (! checker.shouldBailOut()) if (! checker.shouldBailOut())
buttonListeners.callChecked (checker, &ButtonListener::buttonClicked, this); // (can't use Button::Listener due to idiotic VC2005 bug)
buttonListeners.callChecked (checker, &Button::Listener::buttonClicked, this);
} }
void Button::sendStateMessage() void Button::sendStateMessage()
@@ -430,7 +423,7 @@ void Button::sendStateMessage()
buttonStateChanged(); buttonStateChanged();
if (! checker.shouldBailOut()) if (! checker.shouldBailOut())
buttonListeners.callChecked (checker, &ButtonListener::buttonStateChanged, this);
buttonListeners.callChecked (checker, &Button::Listener::buttonStateChanged, this);
} }
//============================================================================== //==============================================================================


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/buttons/juce_Button.h View File

@@ -397,7 +397,7 @@ protected:
Subclasses can override this to perform whatever they actions they need Subclasses can override this to perform whatever they actions they need
to do. to do.
Alternatively, a ButtonListener can be added to the button, and these listeners
Alternatively, a Button::Listener can be added to the button, and these listeners
will be called when the click occurs. will be called when the click occurs.
@see triggerClick @see triggerClick


+ 6
- 9
libs/juce/source/modules/juce_gui_basics/buttons/juce_DrawableButton.cpp View File

@@ -25,10 +25,7 @@
*/ */
DrawableButton::DrawableButton (const String& name, const DrawableButton::ButtonStyle buttonStyle) DrawableButton::DrawableButton (const String& name, const DrawableButton::ButtonStyle buttonStyle)
: Button (name),
style (buttonStyle),
currentImage (nullptr),
edgeIndent (3)
: Button (name), style (buttonStyle)
{ {
} }
@@ -85,12 +82,12 @@ void DrawableButton::setEdgeIndent (const int numPixelsIndent)
Rectangle<float> DrawableButton::getImageBounds() const Rectangle<float> DrawableButton::getImageBounds() const
{ {
Rectangle<int> r (getLocalBounds());
auto r = getLocalBounds();
if (style != ImageStretched) if (style != ImageStretched)
{ {
int indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
int indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
auto indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
auto indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
if (style == ImageOnButtonBackground) if (style == ImageOnButtonBackground)
{ {
@@ -178,7 +175,7 @@ void DrawableButton::paintButton (Graphics& g,
const bool isMouseOverButton, const bool isMouseOverButton,
const bool isButtonDown) const bool isButtonDown)
{ {
LookAndFeel& lf = getLookAndFeel();
auto& lf = getLookAndFeel();
if (style == ImageOnButtonBackground) if (style == ImageOnButtonBackground)
lf.drawButtonBackground (g, *this, lf.drawButtonBackground (g, *this,
@@ -217,7 +214,7 @@ Drawable* DrawableButton::getOverImage() const noexcept
Drawable* DrawableButton::getDownImage() const noexcept Drawable* DrawableButton::getDownImage() const noexcept
{ {
if (Drawable* const d = getToggleState() ? downImageOn : downImage)
if (auto* d = getToggleState() ? downImageOn.get() : downImage.get())
return d; return d;
return getOverImage(); return getOverImage();


+ 5
- 2
libs/juce/source/modules/juce_gui_basics/buttons/juce_DrawableButton.h View File

@@ -122,6 +122,9 @@ public:
*/ */
void setEdgeIndent (int numPixelsIndent); void setEdgeIndent (int numPixelsIndent);
/** Returns the current edge indent size. */
int getEdgeIndent() const noexcept { return edgeIndent; }
//============================================================================== //==============================================================================
/** Returns the image that the button is currently displaying. */ /** Returns the image that the button is currently displaying. */
Drawable* getCurrentImage() const noexcept; Drawable* getCurrentImage() const noexcept;
@@ -179,8 +182,8 @@ private:
ButtonStyle style; ButtonStyle style;
ScopedPointer<Drawable> normalImage, overImage, downImage, disabledImage, ScopedPointer<Drawable> normalImage, overImage, downImage, disabledImage,
normalImageOn, overImageOn, downImageOn, disabledImageOn; normalImageOn, overImageOn, downImageOn, disabledImageOn;
Drawable* currentImage;
int edgeIndent;
Drawable* currentImage = nullptr;
int edgeIndent = 3;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrawableButton) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrawableButton)
}; };

+ 50
- 54
libs/juce/source/modules/juce_gui_basics/components/juce_Component.cpp View File

@@ -31,10 +31,7 @@ Component* Component::currentlyFocusedComponent = nullptr;
class Component::MouseListenerList class Component::MouseListenerList
{ {
public: public:
MouseListenerList() noexcept
: numDeepMouseListeners (0)
{
}
MouseListenerList() noexcept {}
void addListener (MouseListener* const newListener, const bool wantsEventsForAllNestedChildComponents) void addListener (MouseListener* const newListener, const bool wantsEventsForAllNestedChildComponents)
{ {
@@ -54,7 +51,7 @@ public:
void removeListener (MouseListener* const listenerToRemove) void removeListener (MouseListener* const listenerToRemove)
{ {
const int index = listeners.indexOf (listenerToRemove);
auto index = listeners.indexOf (listenerToRemove);
if (index >= 0) if (index >= 0)
{ {
@@ -86,20 +83,21 @@ public:
for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent)
{ {
auto* list = p->mouseListeners.get();
if (list != nullptr && list->numDeepMouseListeners > 0)
if (auto* list = p->mouseListeners.get())
{ {
BailOutChecker2 checker2 (checker, p);
for (int i = list->numDeepMouseListeners; --i >= 0;)
if (list->numDeepMouseListeners > 0)
{ {
(list->listeners.getUnchecked(i)->*eventMethod) (e);
BailOutChecker2 checker2 (checker, p);
if (checker2.shouldBailOut())
return;
for (int i = list->numDeepMouseListeners; --i >= 0;)
{
(list->listeners.getUnchecked(i)->*eventMethod) (e);
if (checker2.shouldBailOut())
return;
i = jmin (i, list->numDeepMouseListeners);
i = jmin (i, list->numDeepMouseListeners);
}
} }
} }
} }
@@ -123,20 +121,21 @@ public:
for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent) for (Component* p = comp.parentComponent; p != nullptr; p = p->parentComponent)
{ {
MouseListenerList* const list = p->mouseListeners;
if (list != nullptr && list->numDeepMouseListeners > 0)
if (auto* list = p->mouseListeners.get())
{ {
BailOutChecker2 checker2 (checker, p);
for (int i = list->numDeepMouseListeners; --i >= 0;)
if (list->numDeepMouseListeners > 0)
{ {
list->listeners.getUnchecked(i)->mouseWheelMove (e, wheel);
BailOutChecker2 checker2 (checker, p);
if (checker2.shouldBailOut())
return;
for (int i = list->numDeepMouseListeners; --i >= 0;)
{
list->listeners.getUnchecked(i)->mouseWheelMove (e, wheel);
if (checker2.shouldBailOut())
return;
i = jmin (i, list->numDeepMouseListeners);
i = jmin (i, list->numDeepMouseListeners);
}
} }
} }
} }
@@ -144,7 +143,7 @@ public:
private: private:
Array<MouseListener*> listeners; Array<MouseListener*> listeners;
int numDeepMouseListeners;
int numDeepMouseListeners = 0;
struct BailOutChecker2 struct BailOutChecker2
{ {
@@ -175,11 +174,10 @@ struct FocusRestorer
~FocusRestorer() ~FocusRestorer()
{ {
if (lastFocus != nullptr && ! lastFocus->isCurrentlyBlockedByAnotherModalComponent())
{
if (lastFocus != nullptr && lastFocus->isShowing())
lastFocus->grabKeyboardFocus();
}
if (lastFocus != nullptr
&& lastFocus->isShowing()
&& ! lastFocus->isCurrentlyBlockedByAnotherModalComponent())
lastFocus->grabKeyboardFocus();
} }
WeakReference<Component> lastFocus; WeakReference<Component> lastFocus;
@@ -326,7 +324,7 @@ struct Component::ComponentHelpers
if (comp.isOnDesktop()) if (comp.isOnDesktop())
{ {
if (ComponentPeer* peer = comp.getPeer())
if (auto* peer = comp.getPeer())
pointInParentSpace = ScalingHelpers::unscaledScreenPosToScaled pointInParentSpace = ScalingHelpers::unscaledScreenPosToScaled
(comp, peer->globalToLocal (ScalingHelpers::scaledScreenPosToUnscaled (pointInParentSpace))); (comp, peer->globalToLocal (ScalingHelpers::scaledScreenPosToUnscaled (pointInParentSpace)));
else else
@@ -345,7 +343,7 @@ struct Component::ComponentHelpers
{ {
if (comp.isOnDesktop()) if (comp.isOnDesktop())
{ {
if (ComponentPeer* peer = comp.getPeer())
if (auto* peer = comp.getPeer())
pointInLocalSpace = ScalingHelpers::unscaledScreenPosToScaled pointInLocalSpace = ScalingHelpers::unscaledScreenPosToScaled
(peer->localToGlobal (ScalingHelpers::scaledScreenPosToUnscaled (comp, pointInLocalSpace))); (peer->localToGlobal (ScalingHelpers::scaledScreenPosToUnscaled (comp, pointInLocalSpace)));
else else
@@ -608,7 +606,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
// don't use getPeer(), so that we only get the peer that's specifically // don't use getPeer(), so that we only get the peer that's specifically
// for this comp, and not for one of its parents. // for this comp, and not for one of its parents.
ComponentPeer* peer = ComponentPeer::getPeerFor (this);
auto* peer = ComponentPeer::getPeerFor (this);
if (peer == nullptr || styleWanted != peer->getStyleFlags()) if (peer == nullptr || styleWanted != peer->getStyleFlags())
{ {
@@ -622,7 +620,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
jmax (1, getHeight())); jmax (1, getHeight()));
#endif #endif
const Point<int> topLeft (getScreenPosition());
auto topLeft = getScreenPosition();
bool wasFullscreen = false; bool wasFullscreen = false;
bool wasMinimised = false; bool wasMinimised = false;
@@ -703,7 +701,7 @@ void Component::removeFromDesktop()
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
ComponentPeer* const peer = ComponentPeer::getPeerFor (this);
auto* peer = ComponentPeer::getPeerFor (this);
jassert (peer != nullptr); jassert (peer != nullptr);
flags.hasHeavyweightPeerFlag = false; flags.hasHeavyweightPeerFlag = false;
@@ -753,7 +751,7 @@ void Component::setOpaque (const bool shouldBeOpaque)
flags.opaqueFlag = shouldBeOpaque; flags.opaqueFlag = shouldBeOpaque;
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
if (const ComponentPeer* const peer = ComponentPeer::getPeerFor (this))
if (auto* peer = ComponentPeer::getPeerFor (this))
addToDesktop (peer->getStyleFlags()); // recreates the heavyweight window addToDesktop (peer->getStyleFlags()); // recreates the heavyweight window
repaint(); repaint();
@@ -955,8 +953,8 @@ void Component::toBehind (Component* const other)
{ {
auto* us = getPeer(); auto* us = getPeer();
auto* them = other->getPeer(); auto* them = other->getPeer();
jassert (us != nullptr && them != nullptr); jassert (us != nullptr && them != nullptr);
if (us != nullptr && them != nullptr) if (us != nullptr && them != nullptr)
us->toBehind (them); us->toBehind (them);
} }
@@ -1008,7 +1006,7 @@ void Component::setAlwaysOnTop (const bool shouldStayOnTop)
{ {
// some kinds of peer can't change their always-on-top status, so // some kinds of peer can't change their always-on-top status, so
// for these, we'll need to create a new window // for these, we'll need to create a new window
const int oldFlags = peer->getStyleFlags();
auto oldFlags = peer->getStyleFlags();
removeFromDesktop(); removeFromDesktop();
addToDesktop (oldFlags); addToDesktop (oldFlags);
} }
@@ -1248,8 +1246,8 @@ void Component::setBounds (const String& newBoundsExpression)
void Component::setBoundsRelative (const float x, const float y, void Component::setBoundsRelative (const float x, const float y,
const float w, const float h) const float w, const float h)
{ {
const int pw = getParentWidth();
const int ph = getParentHeight();
auto pw = getParentWidth();
auto ph = getParentHeight();
setBounds (roundToInt (x * pw), setBounds (roundToInt (x * pw),
roundToInt (y * ph), roundToInt (y * ph),
@@ -1448,7 +1446,7 @@ Component* Component::getComponentAt (Point<int> position)
Component* Component::getComponentAt (const int x, const int y) Component* Component::getComponentAt (const int x, const int y)
{ {
return getComponentAt (Point<int> (x, y));
return getComponentAt ({ x, y });
} }
//============================================================================== //==============================================================================
@@ -1873,7 +1871,7 @@ void Component::repaint()
void Component::repaint (const int x, const int y, const int w, const int h) void Component::repaint (const int x, const int y, const int w, const int h)
{ {
internalRepaint (Rectangle<int> (x, y, w, h));
internalRepaint ({ x, y, w, h });
} }
void Component::repaint (Rectangle<int> area) void Component::repaint (Rectangle<int> area)
@@ -1964,7 +1962,7 @@ void Component::paintComponentAndChildren (Graphics& g)
{ {
g.saveState(); g.saveState();
if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, Point<int>()) && g.isClipEmpty()))
if (! (ComponentHelpers::clipObscuredRegions (*this, g, clipBounds, {}) && g.isClipEmpty()))
paint (g); paint (g);
g.restoreState(); g.restoreState();
@@ -2168,7 +2166,7 @@ void Component::sendLookAndFeelChange()
Colour Component::findColour (const int colourId, const bool inheritFromParent) const Colour Component::findColour (const int colourId, const bool inheritFromParent) const
{ {
if (const var* const v = properties.getVarPointer (ComponentHelpers::getColourPropertyId (colourId)))
if (auto* v = properties.getVarPointer (ComponentHelpers::getColourPropertyId (colourId)))
return Colour ((uint32) static_cast<int> (*v)); return Colour ((uint32) static_cast<int> (*v));
if (inheritFromParent && parentComponent != nullptr if (inheritFromParent && parentComponent != nullptr
@@ -2201,7 +2199,7 @@ void Component::copyAllExplicitColoursTo (Component& target) const
for (int i = properties.size(); --i >= 0;) for (int i = properties.size(); --i >= 0;)
{ {
const Identifier name (properties.getName(i));
auto name = properties.getName(i);
if (name.toString().startsWith ("jcclr_")) if (name.toString().startsWith ("jcclr_"))
if (target.properties.set (name, properties [name])) if (target.properties.set (name, properties [name]))
@@ -2418,7 +2416,7 @@ void Component::internalMouseExit (MouseInputSource source, Point<float> relativ
void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time, void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time,
float pressure, float orientation, float rotation, float tiltX, float tiltY) float pressure, float orientation, float rotation, float tiltX, float tiltY)
{ {
Desktop& desktop = Desktop::getInstance();
auto& desktop = Desktop::getInstance();
BailOutChecker checker (this); BailOutChecker checker (this);
if (isCurrentlyBlockedByAnotherModalComponent()) if (isCurrentlyBlockedByAnotherModalComponent())
@@ -2445,7 +2443,7 @@ void Component::internalMouseDown (MouseInputSource source, Point<float> relativ
flags.mouseDownWasBlocked = false; flags.mouseDownWasBlocked = false;
for (Component* c = this; c != nullptr; c = c->parentComponent)
for (auto* c = this; c != nullptr; c = c->parentComponent)
{ {
if (c->isBroughtToFrontOnMouseClick()) if (c->isBroughtToFrontOnMouseClick())
{ {
@@ -2502,7 +2500,7 @@ void Component::internalMouseUp (MouseInputSource source, Point<float> relativeP
if (checker.shouldBailOut()) if (checker.shouldBailOut())
return; return;
Desktop& desktop = Desktop::getInstance();
auto& desktop = Desktop::getInstance();
desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseUp, me); desktop.getMouseListeners().callChecked (checker, &MouseListener::mouseUp, me);
MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseUp, me); MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseUp, me);
@@ -2549,7 +2547,7 @@ void Component::internalMouseDrag (MouseInputSource source, Point<float> relativ
void Component::internalMouseMove (MouseInputSource source, Point<float> relativePos, Time time) void Component::internalMouseMove (MouseInputSource source, Point<float> relativePos, Time time)
{ {
Desktop& desktop = Desktop::getInstance();
auto& desktop = Desktop::getInstance();
if (isCurrentlyBlockedByAnotherModalComponent()) if (isCurrentlyBlockedByAnotherModalComponent())
{ {
@@ -2578,7 +2576,7 @@ void Component::internalMouseMove (MouseInputSource source, Point<float> relativ
void Component::internalMouseWheel (MouseInputSource source, Point<float> relativePos, void Component::internalMouseWheel (MouseInputSource source, Point<float> relativePos,
Time time, const MouseWheelDetails& wheel) Time time, const MouseWheelDetails& wheel)
{ {
Desktop& desktop = Desktop::getInstance();
auto& desktop = Desktop::getInstance();
BailOutChecker checker (this); BailOutChecker checker (this);
const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure, const MouseEvent me (source, relativePos, source.getCurrentModifiers(), MouseInputSource::invalidPressure,
@@ -2854,9 +2852,7 @@ void Component::moveKeyboardFocusToSibling (const bool moveToNext)
if (parentComponent != nullptr) if (parentComponent != nullptr)
{ {
ScopedPointer<KeyboardFocusTraverser> traverser (createFocusTraverser());
if (traverser != nullptr)
if (ScopedPointer<KeyboardFocusTraverser> traverser = createFocusTraverser())
{ {
auto* nextComp = moveToNext ? traverser->getNextComponent (this) auto* nextComp = moveToNext ? traverser->getNextComponent (this)
: traverser->getPreviousComponent (this); : traverser->getPreviousComponent (this);


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/components/juce_Component.h View File

@@ -762,8 +762,8 @@ public:
template <class TargetClass> template <class TargetClass>
TargetClass* findParentComponentOfClass() const TargetClass* findParentComponentOfClass() const
{ {
for (Component* p = parentComponent; p != nullptr; p = p->parentComponent)
if (TargetClass* const target = dynamic_cast<TargetClass*> (p))
for (auto* p = parentComponent; p != nullptr; p = p->parentComponent)
if (auto* target = dynamic_cast<TargetClass*> (p))
return target; return target;
return nullptr; return nullptr;


+ 5
- 5
libs/juce/source/modules/juce_gui_basics/components/juce_Desktop.h View File

@@ -289,13 +289,13 @@ public:
void beginDragAutoRepeat (int millisecondsBetweenCallbacks); void beginDragAutoRepeat (int millisecondsBetweenCallbacks);
//============================================================================== //==============================================================================
/** In a tablet device which can be turned around, this is used to inidicate the orientation. */
/** In a tablet/mobile device which can be turned around, this is used to indicate the orientation. */
enum DisplayOrientation enum DisplayOrientation
{ {
upright = 1, /**< Indicates that the display is the normal way up. */
upsideDown = 2, /**< Indicates that the display is upside-down. */
rotatedClockwise = 4, /**< Indicates that the display is turned 90 degrees clockwise from its upright position. */
rotatedAntiClockwise = 8, /**< Indicates that the display is turned 90 degrees anti-clockwise from its upright position. */
upright = 1, /**< Indicates that the device is the normal way up. */
upsideDown = 2, /**< Indicates that the device is upside-down. */
rotatedClockwise = 4, /**< Indicates that the device is turned 90 degrees clockwise from its upright position. */
rotatedAntiClockwise = 8, /**< Indicates that the device is turned 90 degrees anti-clockwise from its upright position. */
allOrientations = 1 + 2 + 4 + 8 /**< A combination of all the orientation values */ allOrientations = 1 + 2 + 4 + 8 /**< A combination of all the orientation values */
}; };


+ 1
- 34
libs/juce/source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -75,20 +75,6 @@ public:
} }
}; };
struct UseShapeOp
{
const SVGState* state;
Path* sourcePath;
AffineTransform* transform;
Drawable* target;
bool operator() (const XmlPath& xmlPath)
{
target = state->parseShape (xmlPath, *sourcePath, true, transform);
return target != nullptr;
}
};
struct UseTextOp struct UseTextOp
{ {
const SVGState* state; const SVGState* state;
@@ -690,22 +676,6 @@ private:
} }
//============================================================================== //==============================================================================
Drawable* useShape (const XmlPath& xml, Path& path) const
{
auto translation = AffineTransform::translation ((float) xml->getDoubleAttribute ("x", 0.0),
(float) xml->getDoubleAttribute ("y", 0.0));
UseShapeOp op = { this, &path, &translation, nullptr };
auto linkedID = getLinkedID (xml);
if (linkedID.isNotEmpty())
topLevelXml.applyOperationToChildWithID (linkedID, op);
return op.target;
}
Drawable* parseShape (const XmlPath& xml, Path& path, Drawable* parseShape (const XmlPath& xml, Path& path,
const bool shouldParseTransform = true, const bool shouldParseTransform = true,
AffineTransform* additonalTransform = nullptr) const AffineTransform* additonalTransform = nullptr) const
@@ -718,9 +688,6 @@ private:
return newState.parseShape (xml, path, false, additonalTransform); return newState.parseShape (xml, path, false, additonalTransform);
} }
if (xml->hasTagName ("use"))
return useShape (xml, path);
auto dp = new DrawablePath(); auto dp = new DrawablePath();
setCommonAttributes (*dp, xml); setCommonAttributes (*dp, xml);
dp->setFill (Colours::transparentBlack); dp->setFill (Colours::transparentBlack);
@@ -1159,7 +1126,7 @@ private:
if (getStyleAttribute (xml, "font-weight").containsIgnoreCase ("bold")) if (getStyleAttribute (xml, "font-weight").containsIgnoreCase ("bold"))
f.setBold (true); f.setBold (true);
return f.withPointHeight (getCoordLength (getStyleAttribute (xml, "font-size"), 1.0f));
return f.withPointHeight (getCoordLength (getStyleAttribute (xml, "font-size", "15"), 1.0f));
} }
//============================================================================== //==============================================================================


+ 3
- 3
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileBrowserComponent.h View File

@@ -39,9 +39,9 @@
*/ */
class JUCE_API FileBrowserComponent : public Component, class JUCE_API FileBrowserComponent : public Component,
private FileBrowserListener, private FileBrowserListener,
private TextEditorListener,
private ButtonListener,
private ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug)
private TextEditor::Listener,
private Button::Listener,
private ComboBox::Listener,
private FileFilter, private FileFilter,
private Timer private Timer
{ {


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileChooserDialogBox.h View File

@@ -63,7 +63,7 @@
@see FileChooser @see FileChooser
*/ */
class JUCE_API FileChooserDialogBox : public ResizableWindow, class JUCE_API FileChooserDialogBox : public ResizableWindow,
private ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
private Button::Listener,
private FileBrowserListener private FileBrowserListener
{ {
public: public:


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FileSearchPathListComponent.h View File

@@ -37,7 +37,7 @@
class JUCE_API FileSearchPathListComponent : public Component, class JUCE_API FileSearchPathListComponent : public Component,
public SettableTooltipClient, public SettableTooltipClient,
public FileDragAndDropTarget, public FileDragAndDropTarget,
private ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
private Button::Listener,
private ListBoxModel private ListBoxModel
{ {
public: public:


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/filebrowser/juce_FilenameComponent.h View File

@@ -65,8 +65,8 @@ class JUCE_API FilenameComponent : public Component,
public SettableTooltipClient, public SettableTooltipClient,
public FileDragAndDropTarget, public FileDragAndDropTarget,
private AsyncUpdater, private AsyncUpdater,
private ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
private ComboBoxListener
private Button::Listener,
private ComboBox::Listener
{ {
public: public:
//============================================================================== //==============================================================================


+ 8
- 0
libs/juce/source/modules/juce_gui_basics/juce_gui_basics.cpp View File

@@ -129,6 +129,9 @@
#undef KeyPress #undef KeyPress
#endif #endif
#include <map>
#include <set>
//============================================================================== //==============================================================================
namespace juce namespace juce
{ {
@@ -256,6 +259,11 @@ extern bool juce_areThereAnyAlwaysOnTopWindows();
// these classes are C++11-only // these classes are C++11-only
#if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS
#include "layout/juce_FlexBox.cpp" #include "layout/juce_FlexBox.cpp"
#include "layout/juce_GridItem.cpp"
#include "layout/juce_Grid.cpp"
#if JUCE_UNIT_TESTS
#include "layout/juce_GridUnitTests.cpp"
#endif
#endif #endif
#if JUCE_IOS || JUCE_WINDOWS #if JUCE_IOS || JUCE_WINDOWS


+ 9
- 0
libs/juce/source/modules/juce_gui_basics/juce_gui_basics.h View File

@@ -157,6 +157,7 @@ class KeyPressMappingSet;
class ApplicationCommandManagerListener; class ApplicationCommandManagerListener;
class DrawableButton; class DrawableButton;
class FlexBox; class FlexBox;
class Grid;
#include "mouse/juce_MouseCursor.h" #include "mouse/juce_MouseCursor.h"
#include "mouse/juce_MouseListener.h" #include "mouse/juce_MouseListener.h"
@@ -294,6 +295,14 @@ class FlexBox;
#if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS #if JUCE_COMPILER_SUPPORTS_INITIALIZER_LISTS
#include "layout/juce_FlexItem.h" #include "layout/juce_FlexItem.h"
#include "layout/juce_FlexBox.h" #include "layout/juce_FlexBox.h"
#include "layout/juce_GridItem.h"
#include "layout/juce_Grid.h"
constexpr Grid::Px operator"" _px (long double px) { return Grid::Px { px }; }
constexpr Grid::Px operator"" _px (unsigned long long px) { return Grid::Px { px }; }
constexpr Grid::Fr operator"" _fr (unsigned long long fr) { return Grid::Fr { fr }; }
#endif #endif
} }

+ 1025
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_Grid.cpp
File diff suppressed because it is too large
View File


+ 174
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_Grid.h View File

@@ -0,0 +1,174 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/**
Container that handles geometry for grid layouts (fixed columns and rows) using a set of declarative rules.
Implemented from the `CSS Grid Layout` specification as described at:
https://css-tricks.com/snippets/css/complete-guide-grid/
@see GridItem
*/
class JUCE_API Grid
{
public:
//==============================================================================
/** A size in pixels */
struct Px
{
explicit Px (float p) : pixels (static_cast<long double>(p)) { /*sta (p >= 0.0f);*/ }
explicit Px (int p) : pixels (static_cast<long double>(p)) { /*sta (p >= 0.0f);*/ }
explicit constexpr Px (long double p) : pixels (p) {}
explicit constexpr Px (unsigned long long p) : pixels (static_cast<long double>(p)) {}
long double pixels;
};
/** A fractional ratio integer */
struct Fr
{
explicit Fr (int f) : fraction (static_cast<unsigned long long> (f)) {}
explicit constexpr Fr (unsigned long long p) : fraction (p) {}
unsigned long long fraction;
};
//==============================================================================
/** */
struct TrackInfo
{
/** Creates a track with auto dimension. */
TrackInfo() noexcept;
/** */
TrackInfo (Px sizeInPixels) noexcept;
/** */
TrackInfo (Fr fractionOfFreeSpace) noexcept;
/** */
TrackInfo (Px sizeInPixels, const juce::String& endLineNameToUse) noexcept;
/** */
TrackInfo (Fr fractionOfFreeSpace, const juce::String& endLineNameToUse) noexcept;
/** */
TrackInfo (const juce::String& startLineNameToUse, Px sizeInPixels) noexcept;
/** */
TrackInfo (const juce::String& startLineNameToUse, Fr fractionOfFreeSpace) noexcept;
/** */
TrackInfo (const juce::String& startLineNameToUse, Px sizeInPixels, const juce::String& endLineNameToUse) noexcept;
/** */
TrackInfo (const juce::String& startLineNameToUse, Fr fractionOfFreeSpace, const juce::String& endLineNameToUse) noexcept;
private:
friend class Grid;
friend class GridItem;
float size = 0; // Either a fraction or an absolute size in pixels
bool isFraction = false;
bool hasKeyword = false;
juce::String startLineName, endLineName;
};
//==============================================================================
/** */
enum class JustifyItems : int { start = 0, end, center, stretch };
/** */
enum class AlignItems : int { start = 0, end, center, stretch };
/** */
enum class JustifyContent { start, end, center, stretch, spaceAround, spaceBetween, spaceEvenly };
/** */
enum class AlignContent { start, end, center, stretch, spaceAround, spaceBetween, spaceEvenly };
/** */
enum class AutoFlow { row, column, rowDense, columnDense };
//==============================================================================
/** */
Grid() noexcept;
/** Destructor */
~Grid() noexcept;
//==============================================================================
/** */
JustifyItems justifyItems = JustifyItems::stretch;
/** */
AlignItems alignItems = AlignItems::stretch;
/** */
JustifyContent justifyContent = JustifyContent::stretch;
/** */
AlignContent alignContent = AlignContent::stretch;
/** */
AutoFlow autoFlow = AutoFlow::row;
//==============================================================================
/** */
juce::Array<TrackInfo> templateColumns;
/** */
juce::Array<TrackInfo> templateRows;
/** Template areas */
juce::StringArray templateAreas;
/** */
TrackInfo autoRows;
/** */
TrackInfo autoColumns;
/** */
Px columnGap { 0 };
/** */
Px rowGap { 0 };
/** */
void setGap (Px sizeInPixels) noexcept { rowGap = columnGap = sizeInPixels; }
//==============================================================================
/** */
juce::Array<GridItem> items;
//==============================================================================
/** */
void performLayout (juce::Rectangle<int>);
//==============================================================================
/** */
int getNumberOfColumns() const noexcept { return templateColumns.size(); }
/** */
int getNumberOfRows() const noexcept { return templateRows.size(); }
private:
//==============================================================================
struct SizeCalculation;
struct PlacementHelpers;
struct AutoPlacement;
struct BoxAlignment;
};

+ 182
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_GridItem.cpp View File

@@ -0,0 +1,182 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
GridItem::Property::Property() noexcept : isAuto (true)
{
}
GridItem::Property::Property (GridItem::Keyword keyword) noexcept : isAuto (keyword == GridItem::Keyword::autoValue)
{
jassert (keyword == GridItem::Keyword::autoValue);
}
GridItem::Property::Property (const char* lineNameToUse) noexcept : GridItem::Property (juce::String (lineNameToUse))
{
}
GridItem::Property::Property (const juce::String& lineNameToUse) noexcept : name (lineNameToUse), number (1)
{
}
GridItem::Property::Property (int numberToUse) noexcept : number (numberToUse)
{
}
GridItem::Property::Property (int numberToUse, const juce::String& lineNameToUse) noexcept
: name (lineNameToUse), number (numberToUse)
{
}
GridItem::Property::Property (Span spanToUse) noexcept
: name (spanToUse.name), number (spanToUse.number), isSpan (true)
{
}
//==============================================================================
GridItem::Margin::Margin() noexcept : left(), right(), top(), bottom()
{}
GridItem::Margin::Margin (int v) noexcept : GridItem::Margin::Margin (static_cast<float> (v))
{}
GridItem::Margin::Margin (float v) noexcept : left (v), right (v), top (v), bottom (v)
{}
GridItem::Margin::Margin (float t, float r, float b, float l) noexcept : left (l), right (r), top (t), bottom (b)
{}
//==============================================================================
GridItem::GridItem() noexcept {}
GridItem::~GridItem() noexcept {}
GridItem::GridItem (juce::Component& componentToUse) noexcept : associatedComponent (&componentToUse) {}
GridItem::GridItem (juce::Component* componentToUse) noexcept : associatedComponent (componentToUse) {}
void GridItem::setArea (Property rowStart, Property columnStart, Property rowEnd, Property columnEnd)
{
column.start = columnStart;
column.end = columnEnd;
row.start = rowStart;
row.end = rowEnd;
}
void GridItem::setArea (Property rowStart, Property columnStart)
{
column.start = columnStart;
row.start = rowStart;
}
void GridItem::setArea (const juce::String& areaName)
{
area = areaName;
}
GridItem GridItem::withArea (Property rowStart, Property columnStart, Property rowEnd, Property columnEnd) const noexcept
{
auto gi = *this;
gi.setArea (rowStart, columnStart, rowEnd, columnEnd);
return gi;
}
GridItem GridItem::withArea (Property rowStart, Property columnStart) const noexcept
{
auto gi = *this;
gi.setArea (rowStart, columnStart);
return gi;
}
GridItem GridItem::withArea (const juce::String& areaName) const noexcept
{
auto gi = *this;
gi.setArea (areaName);
return gi;
}
GridItem GridItem::withRow (StartAndEndProperty newRow) const noexcept
{
auto gi = *this;
gi.row = newRow;
return gi;
}
GridItem GridItem::withColumn (StartAndEndProperty newColumn) const noexcept
{
auto gi = *this;
gi.column = newColumn;
return gi;
}
GridItem GridItem::withAlignSelf (AlignSelf newAlignSelf) const noexcept
{
auto gi = *this;
gi.alignSelf = newAlignSelf;
return gi;
}
GridItem GridItem::withJustifySelf (JustifySelf newJustifySelf) const noexcept
{
auto gi = *this;
gi.justifySelf = newJustifySelf;
return gi;
}
GridItem GridItem::withWidth (float newWidth) const noexcept
{
auto gi = *this;
gi.width = newWidth;
return gi;
}
GridItem GridItem::withHeight (float newHeight) const noexcept
{
auto gi = *this;
gi.height = newHeight;
return gi;
}
GridItem GridItem::withSize (float newWidth, float newHeight) const noexcept
{
auto gi = *this;
gi.width = newWidth;
gi.height = newHeight;
return gi;
}
GridItem GridItem::withMargin (Margin newHeight) const noexcept
{
auto gi = *this;
gi.margin = newHeight;
return gi;
}
GridItem GridItem::withOrder (int newOrder) const noexcept
{
auto gi = *this;
gi.order = newOrder;
return gi;
}

+ 223
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_GridItem.h View File

@@ -0,0 +1,223 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
/**
Defines an item in a Grid
@see Grid
*/
class JUCE_API GridItem
{
public:
enum class Keyword { autoValue };
//==============================================================================
/** */
struct Span
{
explicit Span (int numberToUse) noexcept : number (numberToUse)
{
/* Span must be at least one and positive */
jassert (numberToUse > 0);
}
explicit Span (int numberToUse, const juce::String& nameToUse) : Span (numberToUse)
{
/* Name must not be empty */
jassert (nameToUse.isNotEmpty());
name = nameToUse;
}
explicit Span (const juce::String& nameToUse) : name (nameToUse)
{
/* Name must not be empty */
jassert (nameToUse.isNotEmpty());
}
int number = 1;
juce::String name;
};
//==============================================================================
/** */
struct Property
{
/** */
Property() noexcept;
/** */
Property (Keyword keyword) noexcept;
/** */
Property (const char* lineNameToUse) noexcept;
/** */
Property (const juce::String& lineNameToUse) noexcept;
/** */
Property (int numberToUse) noexcept;
/** */
Property (int numberToUse, const juce::String& lineNameToUse) noexcept;
/** */
Property (Span spanToUse) noexcept;
private:
bool hasSpan() const noexcept { return isSpan && ! isAuto; }
bool hasAbsolute() const noexcept { return ! (isSpan || isAuto); }
bool hasAuto() const noexcept { return isAuto; }
bool hasName() const noexcept { return name.isNotEmpty(); }
friend class Grid;
juce::String name;
int number = 1; /** Either an absolute line number or number of lines to span across. */
bool isSpan = false;
bool isAuto = false;
};
//==============================================================================
/** */
struct StartAndEndProperty { Property start, end; };
//==============================================================================
/** */
enum class JustifySelf : int { start = 0, end, center, stretch, autoValue };
/** */
enum class AlignSelf : int { start = 0, end, center, stretch, autoValue };
/** */
GridItem() noexcept;
/** */
GridItem (juce::Component& componentToUse) noexcept;
/** */
GridItem (juce::Component* componentToUse) noexcept;
/** Destructor. */
~GridItem() noexcept;
//==============================================================================
/** */
juce::Component* associatedComponent = nullptr;
//==============================================================================
/** */
int order = 0;
/** */
JustifySelf justifySelf = JustifySelf::autoValue;
/** */
AlignSelf alignSelf = AlignSelf::autoValue;
/** */
StartAndEndProperty column = { Keyword::autoValue, Keyword::autoValue };
/** */
StartAndEndProperty row = { Keyword::autoValue, Keyword::autoValue };
/** */
juce::String area;
//==============================================================================
enum
{
useDefaultValue = -2, /* TODO: useDefaultValue should be named useAuto */
notAssigned = -1
};
/* TODO: move all of this into a common class that is shared with the FlexItem */
float width = notAssigned;
float minWidth = 0;
float maxWidth = notAssigned;
float height = notAssigned;
float minHeight = 0;
float maxHeight = notAssigned;
struct Margin
{
Margin() noexcept;
Margin (int size) noexcept;
Margin (float size) noexcept;
Margin (float top, float right, float bottom, float left) noexcept; /**< Creates a margin with these sizes. */
float left;
float right;
float top;
float bottom;
};
/** */
Margin margin;
/** */
juce::Rectangle<float> currentBounds;
/** Short-hand */
void setArea (Property rowStart, Property columnStart, Property rowEnd, Property columnEnd);
/** Short-hand, span of 1 by default */
void setArea (Property rowStart, Property columnStart);
/** Short-hand */
void setArea (const juce::String& areaName);
/** Short-hand */
GridItem withArea (Property rowStart, Property columnStart, Property rowEnd, Property columnEnd) const noexcept;
/** Short-hand, span of 1 by default */
GridItem withArea (Property rowStart, Property columnStart) const noexcept;
/** Short-hand */
GridItem withArea (const juce::String& areaName) const noexcept;
/** */
GridItem withRow (StartAndEndProperty row) const noexcept;
/** */
GridItem withColumn (StartAndEndProperty column) const noexcept;
/** */
GridItem withAlignSelf (AlignSelf newAlignSelf) const noexcept;
/** */
GridItem withJustifySelf (JustifySelf newJustifySelf) const noexcept;
/** */
GridItem withWidth (float newWidth) const noexcept;
/** */
GridItem withHeight (float newHeight) const noexcept;
/** */
GridItem withSize (float newWidth, float newHeight) const noexcept;
/** */
GridItem withMargin (Margin newMargin) const noexcept;
/** Returns a copy of this object with a new order. */
GridItem withOrder (int newOrder) const noexcept;
};

+ 257
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_GridUnitTests.cpp View File

@@ -0,0 +1,257 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
struct GridTests : public juce::UnitTest
{
GridTests() : juce::UnitTest ("Grid class") {}
void runTest() override
{
using Fr = juce::Grid::Fr;
using Tr = juce::Grid::TrackInfo;
using Rect = juce::Rectangle<float>;
using Grid = juce::Grid;
{
Grid grid;
grid.templateColumns.add (Tr (1_fr));
grid.templateRows.addArray ({ Tr (20_px), Tr (1_fr) });
grid.items.addArray ({ GridItem().withArea (1, 1),
GridItem().withArea (2, 1) });
grid.performLayout (juce::Rectangle<int> (200, 400));
beginTest ("Layout calculation test: 1 column x 2 rows: no gap");
expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 200.f, 20.0f));
expect (grid.items[1].currentBounds == Rect (0.0f, 20.0f, 200.f, 380.0f));
grid.templateColumns.add (Tr (50_px));
grid.templateRows.add (Tr (2_fr));
grid.items.addArray ( { GridItem().withArea (1, 2),
GridItem().withArea (2, 2),
GridItem().withArea (3, 1),
GridItem().withArea (3, 2) });
grid.performLayout (juce::Rectangle<int> (150, 170));
beginTest ("Layout calculation test: 2 columns x 3 rows: no gap");
expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 100.0f, 20.0f));
expect (grid.items[1].currentBounds == Rect (0.0f, 20.0f, 100.0f, 50.0f));
expect (grid.items[2].currentBounds == Rect (100.0f, 0.0f, 50.0f, 20.0f));
expect (grid.items[3].currentBounds == Rect (100.0f, 20.0f, 50.0f, 50.0f));
expect (grid.items[4].currentBounds == Rect (0.0f, 70.0f, 100.0f, 100.0f));
expect (grid.items[5].currentBounds == Rect (100.0f, 70.0f, 50.0f, 100.0f));
grid.columnGap = 20_px;
grid.rowGap = 10_px;
grid.performLayout (juce::Rectangle<int> (200, 310));
beginTest ("Layout calculation test: 2 columns x 3 rows: rowGap of 10 and columnGap of 20");
expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 130.0f, 20.0f));
expect (grid.items[1].currentBounds == Rect (0.0f, 30.0f, 130.0f, 90.0f));
expect (grid.items[2].currentBounds == Rect (150.0f, 0.0f, 50.0f, 20.0f));
expect (grid.items[3].currentBounds == Rect (150.0f, 30.0f, 50.0f, 90.0f));
expect (grid.items[4].currentBounds == Rect (0.0f, 130.0f, 130.0f, 180.0f));
expect (grid.items[5].currentBounds == Rect (150.0f, 130.0f, 50.0f, 180.0f));
}
{
Grid grid;
grid.templateColumns.addArray ({ Tr ("first", 20_px, "in"), Tr ("in", 1_fr, "in"), Tr (20_px, "last") });
grid.templateRows.addArray ({ Tr (1_fr),
Tr (20_px)});
{
beginTest ("Grid items placement tests: integer and custom ident, counting forward");
GridItem i1, i2, i3, i4, i5;
i1.column = { 1, 4 };
i1.row = { 1, 2 };
i2.column = { 1, 3 };
i2.row = { 1, 3 };
i3.column = { "first", "in" };
i3.row = { 2, 3 };
i4.column = { "first", { 2, "in" } };
i4.row = { 1, 2 };
i5.column = { "first", "last" };
i5.row = { 1, 2 };
grid.items.addArray ({ i1, i2, i3, i4, i5 });
grid.performLayout ({ 140, 100 });
expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
expect (grid.items[1].currentBounds == Rect (0.0f, 0.0f, 120.0f, 100.0f));
expect (grid.items[2].currentBounds == Rect (0.0f, 80.0f, 20.0f, 20.0f));
expect (grid.items[3].currentBounds == Rect (0.0f, 0.0f, 120.0f, 80.0f));
expect (grid.items[4].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
}
}
{
Grid grid;
grid.templateColumns.addArray ({ Tr ("first", 20_px, "in"), Tr ("in", 1_fr, "in"), Tr (20_px, "last") });
grid.templateRows.addArray ({ Tr (1_fr),
Tr (20_px)});
beginTest ("Grid items placement tests: integer and custom ident, counting forward, reversed end and start");
GridItem i1, i2, i3, i4, i5;
i1.column = { 4, 1 };
i1.row = { 2, 1 };
i2.column = { 3, 1 };
i2.row = { 3, 1 };
i3.column = { "in", "first" };
i3.row = { 3, 2 };
i4.column = { "first", { 2, "in" } };
i4.row = { 1, 2 };
i5.column = { "last", "first" };
i5.row = { 1, 2 };
grid.items.addArray ({ i1, i2, i3, i4, i5 });
grid.performLayout ({ 140, 100 });
expect (grid.items[0].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
expect (grid.items[1].currentBounds == Rect (0.0f, 0.0f, 120.0f, 100.0f));
expect (grid.items[2].currentBounds == Rect (0.0f, 80.0f, 20.0f, 20.0f));
expect (grid.items[3].currentBounds == Rect (0.0f, 0.0f, 120.0f, 80.0f));
expect (grid.items[4].currentBounds == Rect (0.0f, 0.0f, 140.0f, 80.0f));
}
{
beginTest ("Grid items placement tests: areas");
Grid grid;
grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (Fr (1_fr)), Tr (50_px) };
grid.templateRows = { Tr (50_px),
Tr (1_fr),
Tr (50_px) };
grid.templateAreas = { "header header header header",
"main main . sidebar",
"footer footer footer footer" };
grid.items.addArray ({ GridItem().withArea ("header"),
GridItem().withArea ("main"),
GridItem().withArea ("sidebar"),
GridItem().withArea ("footer"),
});
grid.performLayout ({ 300, 150 });
expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 300.f, 50.f));
expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
expect (grid.items[2].currentBounds == Rect (250.f, 50.f, 50.f, 50.f));
expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 300.f, 50.f));
}
{
beginTest ("Grid implicit rows and columns: triggered by areas");
Grid grid;
grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (1_fr), Tr (50_px) };
grid.templateRows = { Tr (50_px),
Tr (1_fr),
Tr (50_px) };
grid.autoRows = Tr (30_px);
grid.autoColumns = Tr (30_px);
grid.templateAreas = { "header header header header header",
"main main . sidebar sidebar",
"footer footer footer footer footer",
"sub sub sub sub sub"};
grid.items.addArray ({ GridItem().withArea ("header"),
GridItem().withArea ("main"),
GridItem().withArea ("sidebar"),
GridItem().withArea ("footer"),
GridItem().withArea ("sub"),
});
grid.performLayout ({ 330, 180 });
expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 330.f, 50.f));
expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
expect (grid.items[2].currentBounds == Rect (250.f, 50.f, 80.f, 50.f));
expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 330.f, 50.f));
expect (grid.items[4].currentBounds == Rect (0.f, 150.f, 330.f, 30.f));
}
{
beginTest ("Grid implicit rows and columns: triggered by areas");
Grid grid;
grid.templateColumns = { Tr (50_px), Tr (100_px), Tr (1_fr), Tr (50_px) };
grid.templateRows = { Tr (50_px),
Tr (1_fr),
Tr (50_px) };
grid.autoRows = Tr (1_fr);
grid.autoColumns = Tr (1_fr);
grid.templateAreas = { "header header header header",
"main main . sidebar",
"footer footer footer footer" };
grid.items.addArray ({ GridItem().withArea ("header"),
GridItem().withArea ("main"),
GridItem().withArea ("sidebar"),
GridItem().withArea ("footer"),
GridItem().withArea (4, 5, 6, 7)
});
grid.performLayout ({ 350, 250 });
expect (grid.items[0].currentBounds == Rect (0.f, 0.f, 250.f, 50.f));
expect (grid.items[1].currentBounds == Rect (0.f, 50.f, 150.f, 50.f));
expect (grid.items[2].currentBounds == Rect (200.f, 50.f, 50.f, 50.f));
expect (grid.items[3].currentBounds == Rect (0.f, 100.f, 250.f, 50.f));
expect (grid.items[4].currentBounds == Rect (250.f, 150.f, 100.f, 100.f));
}
}
};
static GridTests gridUnitTests;

+ 1
- 1
libs/juce/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.cpp View File

@@ -169,7 +169,7 @@ void TabBarButton::resized()
//============================================================================== //==============================================================================
class TabbedButtonBar::BehindFrontTabComp : public Component, class TabbedButtonBar::BehindFrontTabComp : public Component,
public ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
public Button::Listener
{ {
public: public:
BehindFrontTabComp (TabbedButtonBar& tb) : owner (tb) BehindFrontTabComp (TabbedButtonBar& tb) : owner (tb)


+ 1
- 0
libs/juce/source/modules/juce_gui_basics/layout/juce_TabbedButtonBar.h View File

@@ -311,6 +311,7 @@ public:
virtual Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) = 0; virtual Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) = 0;
virtual void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0; virtual void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0;
virtual Font getTabButtonFont (TabBarButton&, float height) = 0;
virtual void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0; virtual void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0;
virtual void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) = 0; virtual void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) = 0;
virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) = 0; virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) = 0;


+ 35
- 18
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -173,6 +173,11 @@ LookAndFeel_V2::LookAndFeel_V2()
BubbleComponent::backgroundColourId, 0xeeeeeebb, BubbleComponent::backgroundColourId, 0xeeeeeebb,
BubbleComponent::outlineColourId, 0x77000000, BubbleComponent::outlineColourId, 0x77000000,
TableHeaderComponent::textColourId, 0xff000000,
TableHeaderComponent::backgroundColourId, 0xffe8ebf9,
TableHeaderComponent::outlineColourId, 0x33000000,
TableHeaderComponent::highlightColourId, 0x8899aadd,
DirectoryContentsDisplayComponent::highlightColourId, textHighlightColour, DirectoryContentsDisplayComponent::highlightColourId, textHighlightColour,
DirectoryContentsDisplayComponent::textColourId, 0xff000000, DirectoryContentsDisplayComponent::textColourId, 0xff000000,
@@ -336,11 +341,9 @@ void LookAndFeel_V2::drawToggleButton (Graphics& g, ToggleButton& button,
if (! button.isEnabled()) if (! button.isEnabled())
g.setOpacity (0.5f); g.setOpacity (0.5f);
const int textX = (int) tickWidth + 5;
g.drawFittedText (button.getButtonText(), g.drawFittedText (button.getButtonText(),
textX, 0,
button.getWidth() - textX - 2, button.getHeight(),
button.getLocalBounds().withTrimmedLeft (roundToInt (tickWidth) + 5)
.withTrimmedRight (2),
Justification::centredLeft, 10); Justification::centredLeft, 10);
} }
@@ -830,22 +833,22 @@ void LookAndFeel_V2::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle<floa
const int x = ((int) area.getWidth() - boxSize) / 2 + (int) area.getX(); const int x = ((int) area.getWidth() - boxSize) / 2 + (int) area.getX();
const int y = ((int) area.getHeight() - boxSize) / 2 + (int) area.getY(); const int y = ((int) area.getHeight() - boxSize) / 2 + (int) area.getY();
const int w = boxSize;
const int h = boxSize;
Rectangle<float> boxArea ((float) x, (float) y, (float) boxSize, (float) boxSize);
g.setColour (Colour (0xe5ffffff)); g.setColour (Colour (0xe5ffffff));
g.fillRect (x, y, w, h);
g.fillRect (boxArea);
g.setColour (Colour (0x80000000)); g.setColour (Colour (0x80000000));
g.drawRect (x, y, w, h);
g.drawRect (boxArea);
const float size = boxSize / 2 + 1.0f; const float size = boxSize / 2 + 1.0f;
const float centre = (float) (boxSize / 2); const float centre = (float) (boxSize / 2);
g.fillRect (x + (w - size) * 0.5f, y + centre, size, 1.0f);
g.fillRect (x + (boxSize - size) * 0.5f, y + centre, size, 1.0f);
if (! isOpen) if (! isOpen)
g.fillRect (x + centre, y + (h - size) * 0.5f, 1.0f, size);
g.fillRect (x + centre, y + (boxSize - size) * 0.5f, 1.0f, size);
} }
bool LookAndFeel_V2::areLinesDrawnForTreeView (TreeView&) bool LookAndFeel_V2::areLinesDrawnForTreeView (TreeView&)
@@ -1106,6 +1109,8 @@ void LookAndFeel_V2::preparePopupMenuWindow (Component&) {}
bool LookAndFeel_V2::shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options&) { return true; } bool LookAndFeel_V2::shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options&) { return true; }
int LookAndFeel_V2::getPopupMenuBorderSize() { return 2; }
//============================================================================== //==============================================================================
void LookAndFeel_V2::fillTextEditorBackground (Graphics& g, int /*width*/, int /*height*/, TextEditor& textEditor) void LookAndFeel_V2::fillTextEditorBackground (Graphics& g, int /*width*/, int /*height*/, TextEditor& textEditor)
{ {
@@ -2166,6 +2171,11 @@ void LookAndFeel_V2::fillTabButtonShape (TabBarButton& button, Graphics& g, cons
g.strokePath (path, PathStrokeType (isFrontTab ? 1.0f : 0.5f)); g.strokePath (path, PathStrokeType (isFrontTab ? 1.0f : 0.5f));
} }
Font LookAndFeel_V2::getTabButtonFont (TabBarButton&, float height)
{
return { height * 0.6f };
}
void LookAndFeel_V2::drawTabButtonText (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown) void LookAndFeel_V2::drawTabButtonText (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
{ {
const Rectangle<float> area (button.getTextArea().toFloat()); const Rectangle<float> area (button.getTextArea().toFloat());
@@ -2176,7 +2186,7 @@ void LookAndFeel_V2::drawTabButtonText (TabBarButton& button, Graphics& g, bool
if (button.getTabbedButtonBar().isVertical()) if (button.getTabbedButtonBar().isVertical())
std::swap (length, depth); std::swap (length, depth);
Font font (depth * 0.6f);
Font font (getTabButtonFont (button, depth));
font.setUnderline (button.hasKeyboardFocus (false)); font.setUnderline (button.hasKeyboardFocus (false));
AffineTransform t; AffineTransform t;
@@ -2323,26 +2333,33 @@ void LookAndFeel_V2::drawTableHeaderBackground (Graphics& g, TableHeaderComponen
Rectangle<int> area (header.getLocalBounds()); Rectangle<int> area (header.getLocalBounds());
area.removeFromTop (area.getHeight() / 2); area.removeFromTop (area.getHeight() / 2);
g.setGradientFill (ColourGradient (Colour (0xffe8ebf9), 0.0f, (float) area.getY(),
Colour (0xfff6f8f9), 0.0f, (float) area.getBottom(),
auto backgroundColour = header.findColour (TableHeaderComponent::backgroundColourId);
g.setGradientFill (ColourGradient (backgroundColour,
0.0f, (float) area.getY(),
backgroundColour.withMultipliedSaturation (.5f),
0.0f, (float) area.getBottom(),
false)); false));
g.fillRect (area); g.fillRect (area);
g.setColour (Colour (0x33000000));
g.setColour (header.findColour (TableHeaderComponent::outlineColourId));
g.fillRect (area.removeFromBottom (1)); g.fillRect (area.removeFromBottom (1));
for (int i = header.getNumColumns (true); --i >= 0;) for (int i = header.getNumColumns (true); --i >= 0;)
g.fillRect (header.getColumnPosition (i).removeFromRight (1)); g.fillRect (header.getColumnPosition (i).removeFromRight (1));
} }
void LookAndFeel_V2::drawTableHeaderColumn (Graphics& g, const String& columnName, int /*columnId*/,
void LookAndFeel_V2::drawTableHeaderColumn (Graphics& g, TableHeaderComponent& header,
const String& columnName, int /*columnId*/,
int width, int height, bool isMouseOver, bool isMouseDown, int width, int height, bool isMouseOver, bool isMouseDown,
int columnFlags) int columnFlags)
{ {
auto highlightColour = header.findColour (TableHeaderComponent::highlightColourId);
if (isMouseDown) if (isMouseDown)
g.fillAll (Colour (0x8899aadd));
g.fillAll (highlightColour);
else if (isMouseOver) else if (isMouseOver)
g.fillAll (Colour (0x5599aadd));
g.fillAll (highlightColour.withMultipliedAlpha (0.625f));
Rectangle<int> area (width, height); Rectangle<int> area (width, height);
area.reduce (4, 0); area.reduce (4, 0);
@@ -2358,7 +2375,7 @@ void LookAndFeel_V2::drawTableHeaderColumn (Graphics& g, const String& columnNam
g.fillPath (sortArrow, sortArrow.getTransformToScaleToFit (area.removeFromRight (height / 2).reduced (2).toFloat(), true)); g.fillPath (sortArrow, sortArrow.getTransformToScaleToFit (area.removeFromRight (height / 2).reduced (2).toFloat(), true));
} }
g.setColour (Colours::black);
g.setColour (header.findColour (TableHeaderComponent::textColourId));
g.setFont (Font (height * 0.5f, Font::bold)); g.setFont (Font (height * 0.5f, Font::bold));
g.drawFittedText (columnName, area, Justification::centredLeft, 1); g.drawFittedText (columnName, area, Justification::centredLeft, 1);
} }


+ 6
- 3
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h View File

@@ -182,6 +182,8 @@ public:
bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) override; bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) override;
int getPopupMenuBorderSize() override;
//============================================================================== //==============================================================================
void drawComboBox (Graphics&, int width, int height, bool isButtonDown, void drawComboBox (Graphics&, int width, int height, bool isButtonDown,
int buttonX, int buttonY, int buttonW, int buttonH, int buttonX, int buttonY, int buttonW, int buttonH,
@@ -272,6 +274,7 @@ public:
Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) override; Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) override;
void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override; void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override;
Font getTabButtonFont (TabBarButton&, float height) override;
void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override; void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override;
void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) override; void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) override;
void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) override; void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) override;
@@ -289,9 +292,9 @@ public:
//============================================================================== //==============================================================================
void drawTableHeaderBackground (Graphics&, TableHeaderComponent&) override; void drawTableHeaderBackground (Graphics&, TableHeaderComponent&) override;
void drawTableHeaderColumn (Graphics&, const String& columnName, int columnId,
int width, int height, bool isMouseOver, bool isMouseDown,
int columnFlags) override;
void drawTableHeaderColumn (Graphics&, TableHeaderComponent&, const String& columnName,
int columnId, int width, int height, bool isMouseOver,
bool isMouseDown, int columnFlags) override;
//============================================================================== //==============================================================================
void paintToolbarBackground (Graphics&, int width, int height, Toolbar&) override; void paintToolbarBackground (Graphics&, int width, int height, Toolbar&) override;


+ 6
- 3
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V3.cpp View File

@@ -39,6 +39,8 @@ LookAndFeel_V3::LookAndFeel_V3()
setColour (Slider::thumbColourId, Colour (0xffddddff)); setColour (Slider::thumbColourId, Colour (0xffddddff));
setColour (BubbleComponent::backgroundColourId, Colour (0xeeeeeedd)); setColour (BubbleComponent::backgroundColourId, Colour (0xeeeeeedd));
setColour (ScrollBar::thumbColourId, Colour::greyLevel (0.8f).contrasting().withAlpha (0.13f)); setColour (ScrollBar::thumbColourId, Colour::greyLevel (0.8f).contrasting().withAlpha (0.13f));
setColour (TableHeaderComponent::backgroundColourId, Colours::white.withAlpha (0.6f));
setColour (TableHeaderComponent::outlineColourId, Colours::black.withAlpha (0.5f));
} }
LookAndFeel_V3::~LookAndFeel_V3() {} LookAndFeel_V3::~LookAndFeel_V3() {}
@@ -153,14 +155,15 @@ void LookAndFeel_V3::drawButtonBackground (Graphics& g, Button& button, const Co
void LookAndFeel_V3::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header) void LookAndFeel_V3::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header)
{ {
Rectangle<int> r (header.getLocalBounds()); Rectangle<int> r (header.getLocalBounds());
auto outlineColour = header.findColour (TableHeaderComponent::outlineColourId);
g.setColour (Colours::black.withAlpha (0.5f));
g.setColour (outlineColour);
g.fillRect (r.removeFromBottom (1)); g.fillRect (r.removeFromBottom (1));
g.setColour (Colours::white.withAlpha (0.6f));
g.setColour (header.findColour (TableHeaderComponent::backgroundColourId));
g.fillRect (r); g.fillRect (r);
g.setColour (Colours::black.withAlpha (0.5f));
g.setColour (outlineColour);
for (int i = header.getNumColumns (true); --i >= 0;) for (int i = header.getNumColumns (true); --i >= 0;)
g.fillRect (header.getColumnPosition (i).removeFromRight (1)); g.fillRect (header.getColumnPosition (i).removeFromRight (1));


+ 2
- 4
libs/juce/source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp View File

@@ -333,11 +333,9 @@ void LookAndFeel_V4::drawToggleButton (Graphics& g, ToggleButton& button,
if (! button.isEnabled()) if (! button.isEnabled())
g.setOpacity (0.5f); g.setOpacity (0.5f);
const auto textX = roundToInt (tickWidth) + 10;
g.drawFittedText (button.getButtonText(), g.drawFittedText (button.getButtonText(),
textX, 0,
button.getWidth() - textX - 2, button.getHeight(),
button.getLocalBounds().withTrimmedLeft (roundToInt (tickWidth) + 10)
.withTrimmedRight (2),
Justification::centredLeft, 10); Justification::centredLeft, 10);
} }


+ 11
- 8
libs/juce/source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -27,7 +27,6 @@
namespace PopupMenuSettings namespace PopupMenuSettings
{ {
const int scrollZone = 24; const int scrollZone = 24;
const int borderSize = 2;
const int dismissCommandId = 0x6287345f; const int dismissCommandId = 0x6287345f;
static bool menuWasHiddenBecauseOfAppChange = false; static bool menuWasHiddenBecauseOfAppChange = false;
@@ -88,7 +87,7 @@ struct ItemComponent : public Component
int itemW = 80; int itemW = 80;
int itemH = 16; int itemH = 16;
getIdealSize (itemW, itemH, standardItemHeight); getIdealSize (itemW, itemH, standardItemHeight);
setSize (itemW, jlimit (2, 600, itemH));
setSize (itemW, jlimit (1, 600, itemH));
addMouseListener (&parent, false); addMouseListener (&parent, false);
} }
@@ -290,7 +289,8 @@ public:
auto& lf = getLookAndFeel(); auto& lf = getLookAndFeel();
if (parentComponent != nullptr) if (parentComponent != nullptr)
lf.drawResizableFrame (g, getWidth(), getHeight(), BorderSize<int> (PopupMenuSettings::borderSize));
lf.drawResizableFrame (g, getWidth(), getHeight(),
BorderSize<int> (getLookAndFeel().getPopupMenuBorderSize()));
if (canScroll()) if (canScroll())
{ {
@@ -598,7 +598,7 @@ public:
return parentComponent->getLocalArea (nullptr, return parentComponent->getLocalArea (nullptr,
parentComponent->getScreenBounds() parentComponent->getScreenBounds()
.reduced (PopupMenuSettings::borderSize)
.reduced (getLookAndFeel().getPopupMenuBorderSize())
.getIntersection (parentArea)); .getIntersection (parentArea));
} }
@@ -666,6 +666,9 @@ public:
else else
x = jmax (parentArea.getX() + 4, target.getX() - widthToUse); x = jmax (parentArea.getX() + 4, target.getX() - widthToUse);
if (getLookAndFeel().getPopupMenuBorderSize() == 0) // workaround for dismissing the window on mouse up when border size is 0
x += tendTowardsRight ? 1 : -1;
y = target.getY(); y = target.getY();
if (target.getCentreY() > parentArea.getCentreY()) if (target.getCentreY() > parentArea.getCentreY())
y = jmax (parentArea.getY(), target.getBottom() - heightToUse); y = jmax (parentArea.getY(), target.getBottom() - heightToUse);
@@ -711,7 +714,7 @@ public:
needsToScroll = contentHeight > actualH; needsToScroll = contentHeight > actualH;
width = updateYPositions(); width = updateYPositions();
height = actualH + PopupMenuSettings::borderSize * 2;
height = actualH + getLookAndFeel().getPopupMenuBorderSize() * 2;
} }
int workOutBestSize (const int maxMenuW) int workOutBestSize (const int maxMenuW)
@@ -733,7 +736,7 @@ public:
colH += items.getUnchecked (childNum + i)->getHeight(); colH += items.getUnchecked (childNum + i)->getHeight();
} }
colW = jmin (maxMenuW / jmax (1, numColumns - 2), colW + PopupMenuSettings::borderSize * 2);
colW = jmin (maxMenuW / jmax (1, numColumns - 2), colW + getLookAndFeel().getPopupMenuBorderSize() * 2);
columnWidths.set (col, colW); columnWidths.set (col, colW);
totalW += colW; totalW += colW;
@@ -832,7 +835,7 @@ public:
childYOffset = jmax (childYOffset, 0); childYOffset = jmax (childYOffset, 0);
else if (delta > 0) else if (delta > 0)
childYOffset = jmin (childYOffset, childYOffset = jmin (childYOffset,
contentHeight - windowPos.getHeight() + PopupMenuSettings::borderSize);
contentHeight - windowPos.getHeight() + getLookAndFeel().getPopupMenuBorderSize());
updateYPositions(); updateYPositions();
} }
@@ -857,7 +860,7 @@ public:
const int colW = columnWidths [col]; const int colW = columnWidths [col];
int y = PopupMenuSettings::borderSize - (childYOffset + (getY() - windowPos.getY()));
int y = getLookAndFeel().getPopupMenuBorderSize() - (childYOffset + (getY() - windowPos.getY()));
for (int i = 0; i < numChildren; ++i) for (int i = 0; i < numChildren; ++i)
{ {


+ 6
- 0
libs/juce/source/modules/juce_gui_basics/menus/juce_PopupMenu.h View File

@@ -280,6 +280,8 @@ public:
This will add a user-defined component to use as a menu item. The component This will add a user-defined component to use as a menu item. The component
passed in will be deleted by this menu when it's no longer needed. passed in will be deleted by this menu when it's no longer needed.
Note that native macOS menus do not support custom components.
@see CustomComponent @see CustomComponent
*/ */
void addCustomItem (int itemResultID, void addCustomItem (int itemResultID,
@@ -296,6 +298,8 @@ public:
detection of a mouse-click on your component, and use that to trigger the detection of a mouse-click on your component, and use that to trigger the
menu ID specified in itemResultID. If this is false, the menu item can't menu ID specified in itemResultID. If this is false, the menu item can't
be triggered, so itemResultID is not used. be triggered, so itemResultID is not used.
Note that native macOS menus do support custom components.
*/ */
void addCustomItem (int itemResultID, void addCustomItem (int itemResultID,
Component* customComponent, Component* customComponent,
@@ -723,6 +727,8 @@ public:
/** Return true if you want your popup menus to scale with the target component's AffineTransform /** Return true if you want your popup menus to scale with the target component's AffineTransform
or scale factor */ or scale factor */
virtual bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) = 0; virtual bool shouldPopupMenuScaleWithTargetComponent (const PopupMenu::Options& options) = 0;
virtual int getPopupMenuBorderSize() = 0;
}; };
private: private:


+ 10
- 5
libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp View File

@@ -84,13 +84,17 @@ public:
return nullptr; return nullptr;
} }
Point<float> getScreenPosition() const
Point<float> getScreenPosition() const noexcept
{ {
// This needs to return the live position if possible, but it mustn't update the lastScreenPos // This needs to return the live position if possible, but it mustn't update the lastScreenPos
// value, because that can cause continuity problems. // value, because that can cause continuity problems.
return ScalingHelpers::unscaledScreenPosToScaled
(unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition()
: lastScreenPos));
return ScalingHelpers::unscaledScreenPosToScaled (getRawScreenPosition());
}
Point<float> getRawScreenPosition() const noexcept
{
return unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition()
: lastScreenPos);
} }
void setScreenPosition (Point<float> p) void setScreenPosition (Point<float> p)
@@ -578,6 +582,7 @@ bool MouseInputSource::hasMouseWheel() const noexcept
int MouseInputSource::getIndex() const noexcept { return pimpl->index; } int MouseInputSource::getIndex() const noexcept { return pimpl->index; }
bool MouseInputSource::isDragging() const noexcept { return pimpl->isDragging(); } bool MouseInputSource::isDragging() const noexcept { return pimpl->isDragging(); }
Point<float> MouseInputSource::getScreenPosition() const noexcept { return pimpl->getScreenPosition(); } Point<float> MouseInputSource::getScreenPosition() const noexcept { return pimpl->getScreenPosition(); }
Point<float> MouseInputSource::getRawScreenPosition() const noexcept { return pimpl->getRawScreenPosition(); }
ModifierKeys MouseInputSource::getCurrentModifiers() const noexcept { return pimpl->getCurrentModifiers(); } ModifierKeys MouseInputSource::getCurrentModifiers() const noexcept { return pimpl->getCurrentModifiers(); }
float MouseInputSource::getCurrentPressure() const noexcept { return pimpl->pressure; } float MouseInputSource::getCurrentPressure() const noexcept { return pimpl->pressure; }
bool MouseInputSource::isPressureValid() const noexcept { return pimpl->isPressureValid(); } bool MouseInputSource::isPressureValid() const noexcept { return pimpl->isPressureValid(); }
@@ -730,7 +735,7 @@ struct MouseInputSource::SourceList : public Timer
// because on some OSes the queue can get overloaded with messages so that mouse-events don't get through.. // because on some OSes the queue can get overloaded with messages so that mouse-events don't get through..
if (s->isDragging() && ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown()) if (s->isDragging() && ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
{ {
s->lastScreenPos = s->getScreenPosition();
s->lastScreenPos = s->getRawScreenPosition();
s->triggerFakeMove(); s->triggerFakeMove();
anyDragging = true; anyDragging = true;
} }


+ 3
- 0
libs/juce/source/modules/juce_gui_basics/mouse/juce_MouseInputSource.h View File

@@ -105,6 +105,9 @@ public:
/** Returns the last-known screen position of this source. */ /** Returns the last-known screen position of this source. */
Point<float> getScreenPosition() const noexcept; Point<float> getScreenPosition() const noexcept;
/** Returns the last-known screen position of this source without any scaling applied. */
Point<float> getRawScreenPosition() const noexcept;
/** Returns a set of modifiers that indicate which buttons are currently /** Returns a set of modifiers that indicate which buttons are currently
held down on this device. held down on this device.
*/ */


+ 68
- 9
libs/juce/source/modules/juce_gui_basics/native/juce_android_Windowing.cpp View File

@@ -31,6 +31,11 @@ extern juce::JUCEApplicationBase* juce_CreateApplication(); // (from START_JUCE_
namespace juce namespace juce
{ {
//==============================================================================
#if JUCE_MODULE_AVAILABLE_juce_product_unlocking
extern void juce_inAppPurchaseCompleted (void*);
#endif
//============================================================================== //==============================================================================
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, launchApp, void, (JNIEnv* env, jobject activity, JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, launchApp, void, (JNIEnv* env, jobject activity,
jstring appFile, jstring appDataDir)) jstring appFile, jstring appDataDir))
@@ -83,6 +88,18 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, quitApp, void, (JNIEnv* env,
android.shutdown (env); android.shutdown (env);
} }
JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, appActivityResult, void, (JNIEnv* env, jobject, jint requestCode, jint /*resultCode*/, jobject intentData))
{
setEnv (env);
#if JUCE_MODULE_AVAILABLE_juce_product_unlocking
if (requestCode == 1001)
juce_inAppPurchaseCompleted (intentData);
#else
ignoreUnused (intentData, requestCode);
#endif
}
//============================================================================== //==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \ #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \ METHOD (drawBitmap, "drawBitmap", "([IIIFFIIZLandroid/graphics/Paint;)V") \
@@ -248,20 +265,20 @@ public:
setFullScreen (true); setFullScreen (true);
} }
Point<int> getScreenPosition() const
Point<float> getScreenPosition() const
{ {
return Point<int> (view.callIntMethod (ComponentPeerView.getLeft),
view.callIntMethod (ComponentPeerView.getTop)) / scale;
return Point<float> (view.callIntMethod (ComponentPeerView.getLeft),
view.callIntMethod (ComponentPeerView.getTop)) / scale;
} }
Point<float> localToGlobal (Point<float> relativePosition) override Point<float> localToGlobal (Point<float> relativePosition) override
{ {
return relativePosition + getScreenPosition().toFloat();
return relativePosition + getScreenPosition();
} }
Point<float> globalToLocal (Point<float> screenPosition) override Point<float> globalToLocal (Point<float> screenPosition) override
{ {
return screenPosition - getScreenPosition().toFloat();
return screenPosition - getScreenPosition();
} }
void setMinimised (bool /*shouldBeMinimised*/) override void setMinimised (bool /*shouldBeMinimised*/) override
@@ -390,7 +407,7 @@ public:
void handleMouseDownCallback (int index, Point<float> sysPos, int64 time) void handleMouseDownCallback (int index, Point<float> sysPos, int64 time)
{ {
Point<float> pos = sysPos / scale; Point<float> pos = sysPos / scale;
lastMousePos = pos;
lastMousePos = localToGlobal (pos);
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. // this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(), handleMouseEvent (MouseInputSource::InputSourceType::touch, pos, currentModifiers.withoutMouseButtons(),
@@ -403,7 +420,7 @@ public:
void handleMouseDragCallback (int index, Point<float> pos, int64 time) void handleMouseDragCallback (int index, Point<float> pos, int64 time)
{ {
pos /= scale; pos /= scale;
lastMousePos = pos;
lastMousePos = localToGlobal (pos);
jassert (index < 64); jassert (index < 64);
touchesDown = (touchesDown | (1 << (index & 63))); touchesDown = (touchesDown | (1 << (index & 63)));
@@ -415,7 +432,7 @@ public:
void handleMouseUpCallback (int index, Point<float> pos, int64 time) void handleMouseUpCallback (int index, Point<float> pos, int64 time)
{ {
pos /= scale; pos /= scale;
lastMousePos = pos;
lastMousePos = localToGlobal (pos);
jassert (index < 64); jassert (index < 64);
touchesDown = (touchesDown & ~(1 << (index & 63))); touchesDown = (touchesDown & ~(1 << (index & 63)));
@@ -678,6 +695,18 @@ ComponentPeer* Component::createNewPeer (int styleFlags, void*)
} }
//============================================================================== //==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getRotation, "getRotation", "()I")
DECLARE_JNI_CLASS (Display, "android/view/Display");
#undef JNI_CLASS_MEMBERS
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (getDefaultDisplay, "getDefaultDisplay", "()Landroid/view/Display;")
DECLARE_JNI_CLASS (WindowManager, "android/view/WindowManager");
#undef JNI_CLASS_MEMBERS
bool Desktop::canUseSemiTransparentWindows() noexcept bool Desktop::canUseSemiTransparentWindows() noexcept
{ {
return true; return true;
@@ -690,7 +719,37 @@ double Desktop::getDefaultMasterScale()
Desktop::DisplayOrientation Desktop::getCurrentOrientation() const Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
{ {
// TODO
enum
{
ROTATION_0 = 0,
ROTATION_90 = 1,
ROTATION_180 = 2,
ROTATION_270 = 3
};
JNIEnv* env = getEnv();
LocalRef<jstring> windowServiceString (javaString ("window"));
LocalRef<jobject> windowManager = LocalRef<jobject> (env->CallObjectMethod (android.activity, JuceAppActivity.getSystemService, windowServiceString.get()));
if (windowManager.get() != 0)
{
LocalRef<jobject> display = LocalRef<jobject> (env->CallObjectMethod (windowManager, WindowManager.getDefaultDisplay));
if (display.get() != 0)
{
int rotation = env->CallIntMethod (display, Display.getRotation);
switch (rotation)
{
case ROTATION_0: return upright;
case ROTATION_90: return rotatedAntiClockwise;
case ROTATION_180: return upsideDown;
case ROTATION_270: return rotatedClockwise;
}
}
}
jassertfalse;
return upright; return upright;
} }


+ 2
- 2
libs/juce/source/modules/juce_gui_basics/native/juce_mac_MainMenu.mm View File

@@ -100,9 +100,9 @@ public:
{ {
NSMenu* superMenu = [menu supermenu]; NSMenu* superMenu = [menu supermenu];
auto menuNames = currentModel->getMenuBarNames(); auto menuNames = currentModel->getMenuBarNames();
auto indexOfMenu = (int) [superMenu indexOfItemWithSubmenu: menu];
auto indexOfMenu = (int) [superMenu indexOfItemWithSubmenu: menu] - 1;
[menu removeAllItems]; [menu removeAllItems];
auto updatedPopup = currentModel->getMenuForIndex (indexOfMenu - 1, menuNames[indexOfMenu - 1]);
auto updatedPopup = currentModel->getMenuForIndex (indexOfMenu, menuNames[indexOfMenu]);
for (PopupMenu::MenuItemIterator iter (updatedPopup); iter.next();) for (PopupMenu::MenuItemIterator iter (updatedPopup); iter.next();)
addMenuItem (iter, menu, 1, indexOfMenu); addMenuItem (iter, menu, 1, indexOfMenu);


+ 40
- 0
libs/juce/source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -57,6 +57,46 @@ static bool shouldDeactivateTitleBar = true;
extern void* getUser32Function (const char*); extern void* getUser32Function (const char*);
//============================================================================== //==============================================================================
#ifndef WM_TOUCH
enum
{
WM_TOUCH = 0x0240,
TOUCHEVENTF_MOVE = 0x0001,
TOUCHEVENTF_DOWN = 0x0002,
TOUCHEVENTF_UP = 0x0004
};
typedef HANDLE HTOUCHINPUT;
typedef HANDLE HGESTUREINFO;
struct TOUCHINPUT
{
LONG x;
LONG y;
HANDLE hSource;
DWORD dwID;
DWORD dwFlags;
DWORD dwMask;
DWORD dwTime;
ULONG_PTR dwExtraInfo;
DWORD cxContact;
DWORD cyContact;
};
struct GESTUREINFO
{
UINT cbSize;
DWORD dwFlags;
DWORD dwID;
HWND hwndTarget;
POINTS ptsLocation;
DWORD dwInstanceID;
DWORD dwSequenceID;
ULONGLONG ullArguments;
UINT cbExtraArgs;
};
#endif
#ifndef WM_NCPOINTERUPDATE #ifndef WM_NCPOINTERUPDATE
enum enum
{ {


+ 1
- 1
libs/juce/source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h View File

@@ -37,7 +37,7 @@
@see PropertyComponent @see PropertyComponent
*/ */
class JUCE_API BooleanPropertyComponent : public PropertyComponent, class JUCE_API BooleanPropertyComponent : public PropertyComponent,
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
private Button::Listener
{ {
protected: protected:
//============================================================================== //==============================================================================


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save