Browse Source

Update juce

tags/1.9.5
falkTX 11 years ago
parent
commit
2a0e12e136
100 changed files with 1823 additions and 725 deletions
  1. +124
    -5
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp
  2. +30
    -0
      source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h
  3. +2
    -0
      source/modules/juce_audio_basics/juce_audio_basics.cpp
  4. +6
    -4
      source/modules/juce_audio_basics/midi/juce_MidiBuffer.h
  5. +1
    -1
      source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp
  6. +2
    -1
      source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp
  7. +73
    -24
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp
  8. +56
    -30
      source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h
  9. +1
    -1
      source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp
  10. +149
    -26
      source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp
  11. +3
    -0
      source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h
  12. +48
    -75
      source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp
  13. +22
    -6
      source/modules/juce_audio_formats/format/juce_AudioFormatReader.h
  14. +5
    -5
      source/modules/juce_audio_formats/sampler/juce_Sampler.cpp
  15. +3
    -3
      source/modules/juce_audio_formats/sampler/juce_Sampler.h
  16. +11
    -1
      source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  17. +1
    -1
      source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp
  18. +5
    -1
      source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  19. +1
    -0
      source/modules/juce_audio_processors/juce_audio_processors.h
  20. +164
    -17
      source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  21. +26
    -7
      source/modules/juce_audio_processors/processors/juce_AudioProcessor.h
  22. +158
    -0
      source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h
  23. +1
    -1
      source/modules/juce_core/containers/juce_OwnedArray.h
  24. +26
    -27
      source/modules/juce_core/files/juce_WildcardFileFilter.cpp
  25. +0
    -4
      source/modules/juce_core/files/juce_WildcardFileFilter.h
  26. +17
    -11
      source/modules/juce_core/javascript/juce_Javascript.cpp
  27. +5
    -2
      source/modules/juce_core/javascript/juce_Javascript.h
  28. +8
    -11
      source/modules/juce_core/juce_core.cpp
  29. +1
    -4
      source/modules/juce_core/juce_core.h
  30. +169
    -0
      source/modules/juce_core/maths/juce_NormalisableRange.h
  31. +3
    -3
      source/modules/juce_core/memory/juce_MemoryBlock.cpp
  32. +4
    -4
      source/modules/juce_core/memory/juce_ScopedPointer.h
  33. +0
    -27
      source/modules/juce_core/native/juce_BasicNativeHeaders.h
  34. +19
    -18
      source/modules/juce_core/native/juce_linux_Network.cpp
  35. +21
    -30
      source/modules/juce_core/native/juce_posix_SharedCode.h
  36. +33
    -13
      source/modules/juce_core/native/juce_win32_Network.cpp
  37. +0
    -5
      source/modules/juce_core/native/juce_win32_Threads.cpp
  38. +10
    -2
      source/modules/juce_core/network/juce_Socket.cpp
  39. +5
    -4
      source/modules/juce_core/network/juce_URL.cpp
  40. +3
    -0
      source/modules/juce_core/network/juce_URL.h
  41. +1
    -1
      source/modules/juce_core/streams/juce_MemoryOutputStream.cpp
  42. +53
    -7
      source/modules/juce_core/system/juce_PlatformDefs.h
  43. +1
    -0
      source/modules/juce_core/system/juce_StandardHeader.h
  44. +1
    -1
      source/modules/juce_core/system/juce_SystemStats.cpp
  45. +2
    -4
      source/modules/juce_core/system/juce_TargetPlatform.h
  46. +3
    -3
      source/modules/juce_core/text/juce_String.h
  47. +0
    -5
      source/modules/juce_core/threads/juce_ChildProcess.cpp
  48. +0
    -2
      source/modules/juce_core/threads/juce_ChildProcess.h
  49. +1
    -1
      source/modules/juce_core/xml/juce_XmlElement.cpp
  50. +1
    -1
      source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp
  51. +33
    -15
      source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp
  52. +28
    -19
      source/modules/juce_data_structures/undomanager/juce_UndoManager.h
  53. +4
    -1
      source/modules/juce_data_structures/values/juce_ValueTree.h
  54. +19
    -0
      source/modules/juce_events/messages/juce_MessageManager.cpp
  55. +7
    -0
      source/modules/juce_events/messages/juce_MessageManager.h
  56. +1
    -1
      source/modules/juce_events/native/juce_linux_Messaging.cpp
  57. +3
    -3
      source/modules/juce_graphics/contexts/juce_GraphicsContext.h
  58. +1
    -1
      source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp
  59. +4
    -3
      source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp
  60. +1
    -1
      source/modules/juce_graphics/image_formats/pnglib/pngread.c
  61. +3
    -3
      source/modules/juce_graphics/images/juce_Image.cpp
  62. +3
    -3
      source/modules/juce_graphics/images/juce_Image.h
  63. +6
    -6
      source/modules/juce_gui_basics/buttons/juce_Button.cpp
  64. +4
    -6
      source/modules/juce_gui_basics/buttons/juce_Button.h
  65. +25
    -14
      source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp
  66. +1
    -0
      source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h
  67. +1
    -1
      source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp
  68. +5
    -4
      source/modules/juce_gui_basics/components/juce_Component.h
  69. +64
    -72
      source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp
  70. +1
    -1
      source/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp
  71. +13
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp
  72. +3
    -0
      source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h
  73. +17
    -13
      source/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp
  74. +4
    -5
      source/modules/juce_gui_basics/menus/juce_MenuBarComponent.h
  75. +6
    -8
      source/modules/juce_gui_basics/menus/juce_MenuBarModel.h
  76. +2
    -7
      source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp
  77. +3
    -0
      source/modules/juce_gui_basics/menus/juce_PopupMenu.h
  78. +32
    -5
      source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp
  79. +6
    -0
      source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h
  80. +76
    -47
      source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm
  81. +6
    -6
      source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp
  82. +3
    -3
      source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp
  83. +36
    -12
      source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp
  84. +1
    -1
      source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.cpp
  85. +18
    -0
      source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h
  86. +5
    -3
      source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.h
  87. +4
    -0
      source/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.h
  88. +0
    -2
      source/modules/juce_gui_basics/widgets/juce_Label.cpp
  89. +1
    -1
      source/modules/juce_gui_basics/widgets/juce_Label.h
  90. +10
    -6
      source/modules/juce_gui_basics/widgets/juce_ListBox.cpp
  91. +15
    -3
      source/modules/juce_gui_basics/widgets/juce_ListBox.h
  92. +7
    -6
      source/modules/juce_gui_basics/widgets/juce_Slider.cpp
  93. +10
    -15
      source/modules/juce_gui_basics/widgets/juce_TableListBox.cpp
  94. +20
    -17
      source/modules/juce_gui_basics/widgets/juce_TableListBox.h
  95. +4
    -4
      source/modules/juce_gui_basics/widgets/juce_Toolbar.cpp
  96. +7
    -2
      source/modules/juce_gui_basics/widgets/juce_TreeView.cpp
  97. +8
    -4
      source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp
  98. +11
    -0
      source/modules/juce_gui_basics/windows/juce_CallOutBox.h
  99. +1
    -1
      source/modules/juce_gui_basics/windows/juce_DialogWindow.h
  100. +1
    -1
      source/modules/juce_gui_basics/windows/juce_TopLevelWindow.h

+ 124
- 5
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.cpp View File

@@ -24,8 +24,9 @@
namespace FloatVectorHelpers
{
#define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
#define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
#define JUCE_INCREMENT_SRC_DEST dest += (16 / sizeof (*dest)); src += (16 / sizeof (*dest));
#define JUCE_INCREMENT_SRC1_SRC2_DEST dest += (16 / sizeof (*dest)); src1 += (16 / sizeof (*dest)); src2 += (16 / sizeof (*dest));
#define JUCE_INCREMENT_DEST dest += (16 / sizeof (*dest));
#if JUCE_USE_SSE_INTRINSICS
static bool sse2Present = false;
@@ -122,6 +123,17 @@ namespace FloatVectorHelpers
} \
JUCE_FINISH_VEC_OP (normalOp)
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
{ \
Mode::ParallelType (&loadSrc1) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src1) ? Mode::loadA : Mode::loadU; \
Mode::ParallelType (&loadSrc2) (const Mode::Type* v) = FloatVectorHelpers::isAligned (src2) ? Mode::loadA : Mode::loadU; \
void (&storeDst) (Mode::Type* dest, Mode::ParallelType a) = FloatVectorHelpers::isAligned (dest) ? Mode::storeA : Mode::storeU; \
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, loadSrc1, loadSrc2, storeDst, locals, increment); \
} \
JUCE_FINISH_VEC_OP (normalOp)
//==============================================================================
#elif JUCE_USE_ARM_NEON
@@ -193,6 +205,12 @@ namespace FloatVectorHelpers
JUCE_VEC_LOOP (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
JUCE_FINISH_VEC_OP (normalOp)
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
JUCE_BEGIN_VEC_OP \
setupOp \
JUCE_VEC_LOOP_TWO_SOURCES (vecOp, Mode::loadU, Mode::loadU, Mode::storeU, locals, increment) \
JUCE_FINISH_VEC_OP (normalOp)
//==============================================================================
#else
#define JUCE_PERFORM_VEC_OP_DEST(normalOp, vecOp, locals, setupOp) \
@@ -201,6 +219,8 @@ namespace FloatVectorHelpers
#define JUCE_PERFORM_VEC_OP_SRC_DEST(normalOp, vecOp, locals, increment, setupOp) \
for (int i = 0; i < num; ++i) normalOp;
#define JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST(normalOp, vecOp, locals, increment, setupOp) \
for (int i = 0; i < num; ++i) normalOp;
#endif
//==============================================================================
@@ -212,10 +232,19 @@ namespace FloatVectorHelpers
increment; \
}
#define JUCE_VEC_LOOP_TWO_SOURCES(vecOp, src1Load, src2Load, dstStore, locals, increment) \
for (int i = 0; i < numLongOps; ++i) \
{ \
locals (src1Load, src2Load); \
dstStore (dest, vecOp); \
increment; \
}
#define JUCE_LOAD_NONE(srcLoad, dstLoad)
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
#define JUCE_LOAD_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest);
#define JUCE_LOAD_SRC(srcLoad, dstLoad) const Mode::ParallelType s = srcLoad (src);
#define JUCE_LOAD_SRC1_SRC2(src1Load, src2Load) const Mode::ParallelType s1 = src1Load (src1), s2 = src2Load (src2);
#define JUCE_LOAD_SRC_DEST(srcLoad, dstLoad) const Mode::ParallelType d = dstLoad (dest), s = srcLoad (src);
#if JUCE_USE_SSE_INTRINSICS || JUCE_USE_ARM_NEON
template<int typeSize> struct ModeType { typedef BasicOps32 Mode; };
@@ -443,6 +472,28 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double amount, int
const Mode::ParallelType amountToAdd = Mode::load1 (amount);)
}
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, float* src, float amount, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsadd (src, 1, &amount, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType am = Mode::load1 (amount);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, double* src, double amount, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsaddD (src, 1, &amount, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] + amount, Mode::add (am, s),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType am = Mode::load1 (amount);)
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
@@ -461,6 +512,24 @@ void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src,
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vadd (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::add (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vaddD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] + src2[i], Mode::add (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
@@ -479,6 +548,24 @@ void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double*
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::subtract (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsub (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::subtract (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vsubD (src2, 1, src1, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] - src2[i], Mode::sub (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::addWithMultiply (float* dest, const float* src, float multiplier, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] += src[i] * multiplier, Mode::add (d, Mode::mul (mult, s)),
@@ -511,6 +598,24 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double*
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src1, const float* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmul (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src1, const double* src2, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
vDSP_vmulD (src1, 1, src2, 1, dest, 1, (vDSP_Length) num);
#else
JUCE_PERFORM_VEC_OP_SRC1_SRC2_DEST (dest[i] = src1[i] * src2[i], Mode::mul (s1, s2), JUCE_LOAD_SRC1_SRC2, JUCE_INCREMENT_SRC1_SRC2_DEST, )
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, float multiplier, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK
@@ -531,6 +636,20 @@ void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, double multipl
#endif
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (float* dest, const float* src, float multiplier, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mult = Mode::load1 (multiplier);)
}
void JUCE_CALLTYPE FloatVectorOperations::multiply (double* dest, const double* src, double multiplier, int num) noexcept
{
JUCE_PERFORM_VEC_OP_SRC_DEST (dest[i] = src[i] * multiplier, Mode::mul (mult, s),
JUCE_LOAD_SRC, JUCE_INCREMENT_SRC_DEST,
const Mode::ParallelType mult = Mode::load1 (multiplier);)
}
void FloatVectorOperations::negate (float* dest, const float* src, int num) noexcept
{
#if JUCE_USE_VDSP_FRAMEWORK


+ 30
- 0
source/modules/juce_audio_basics/buffers/juce_FloatVectorOperations.h View File

@@ -65,18 +65,36 @@ public:
/** Adds a fixed value to the destination values. */
static void JUCE_CALLTYPE add (double* dest, double amountToAdd, int numValues) noexcept;
/** Adds a fixed value to each source value and stores it in the destination array. */
static void JUCE_CALLTYPE add (float* dest, float* src, float amount, int numValues) noexcept;
/** Adds a fixed value to each source value and stores it in the destination array. */
static void JUCE_CALLTYPE add (double* dest, double* src, double amount, int numValues) noexcept;
/** Adds the source values to the destination values. */
static void JUCE_CALLTYPE add (float* dest, const float* src, int numValues) noexcept;
/** Adds the source values to the destination values. */
static void JUCE_CALLTYPE add (double* dest, const double* src, int numValues) noexcept;
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
static void JUCE_CALLTYPE add (float* dest, const float* src1, const float* src2, int num) noexcept;
/** Adds each source1 value to the corresponding source2 value and stores the result in the destination array. */
static void JUCE_CALLTYPE add (double* dest, const double* src1, const double* src2, int num) noexcept;
/** Subtracts the source values from the destination values. */
static void JUCE_CALLTYPE subtract (float* dest, const float* src, int numValues) noexcept;
/** Subtracts the source values from the destination values. */
static void JUCE_CALLTYPE subtract (double* dest, const double* src, int numValues) noexcept;
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
static void JUCE_CALLTYPE subtract (float* dest, const float* src1, const float* src2, int num) noexcept;
/** Subtracts each source2 value from the corresponding source1 value and stores the result in the destination array. */
static void JUCE_CALLTYPE subtract (double* dest, const double* src1, const double* src2, int num) noexcept;
/** Multiplies each source value by the given multiplier, then adds it to the destination value. */
static void JUCE_CALLTYPE addWithMultiply (float* dest, const float* src, float multiplier, int numValues) noexcept;
@@ -89,12 +107,24 @@ public:
/** Multiplies the destination values by the source values. */
static void JUCE_CALLTYPE multiply (double* dest, const double* src, int numValues) noexcept;
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
static void JUCE_CALLTYPE multiply (float* dest, const float* src1, const float* src2, int numValues) noexcept;
/** Multiplies each source1 value by the correspinding source2 value, then stores it in the destination array. */
static void JUCE_CALLTYPE multiply (double* dest, const double* src1, const double* src2, int numValues) noexcept;
/** Multiplies each of the destination values by a fixed multiplier. */
static void JUCE_CALLTYPE multiply (float* dest, float multiplier, int numValues) noexcept;
/** Multiplies each of the destination values by a fixed multiplier. */
static void JUCE_CALLTYPE multiply (double* dest, double multiplier, int numValues) noexcept;
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
static void JUCE_CALLTYPE multiply (float* dest, const float* src, float multiplier, int num) noexcept;
/** Multiplies each of the source values by a fixed multiplier and stores the result in the destination array. */
static void JUCE_CALLTYPE multiply (double* dest, const double* src, double multiplier, int num) noexcept;
/** Copies a source vector to a destination, negating each value. */
static void JUCE_CALLTYPE negate (float* dest, const float* src, int numValues) noexcept;


+ 2
- 0
source/modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -57,7 +57,9 @@
#endif
#if (JUCE_MAC || JUCE_IOS) && JUCE_USE_VDSP_FRAMEWORK
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
#include <Accelerate/Accelerate.h>
#undef Point
#else
#undef JUCE_USE_VDSP_FRAMEWORK
#endif


+ 6
- 4
source/modules/juce_audio_basics/midi/juce_MidiBuffer.h View File

@@ -186,9 +186,10 @@ public:
/** Retrieves a copy of the next event from the buffer.
@param result on return, this will be the message (the MidiMessage's timestamp
is not set)
@param samplePosition on return, this will be the position of the event
@param result on return, this will be the message. The MidiMessage's timestamp
is set to the same value as samplePosition.
@param samplePosition on return, this will be the position of the event, as a
sample index in the buffer
@returns true if an event was found, or false if the iterator has reached
the end of the buffer
*/
@@ -203,7 +204,8 @@ public:
temporarily until the MidiBuffer is altered.
@param numBytesOfMidiData on return, this is the number of bytes of data used by the
midi message
@param samplePosition on return, this will be the position of the event
@param samplePosition on return, this will be the position of the event, as a
sample index in the buffer
@returns true if an event was found, or false if the iterator has reached
the end of the buffer
*/


+ 1
- 1
source/modules/juce_audio_basics/midi/juce_MidiMessage.cpp View File

@@ -661,7 +661,7 @@ String MidiMessage::getTextFromTextMetaEvent() const
MidiMessage MidiMessage::textMetaEvent (int type, StringRef text)
{
jassert (type > 0 && type < 16)
jassert (type > 0 && type < 16);
MidiMessage result;


+ 2
- 1
source/modules/juce_audio_basics/sources/juce_ResamplingAudioSource.cpp View File

@@ -230,7 +230,8 @@ void ResamplingAudioSource::setFilterCoefficients (double c1, double c2, double
void ResamplingAudioSource::resetFilters()
{
filterStates.clear ((size_t) numChannels);
if (filterStates != nullptr)
filterStates.clear ((size_t) numChannels);
}
void ResamplingAudioSource::applyFilter (float* samples, int num, FilterState& fs)


+ 73
- 24
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp View File

@@ -163,10 +163,7 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
: numSamples;
if (numThisTime > 0)
{
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (outputBuffer, startSample, numThisTime);
}
renderVoices (outputBuffer, startSample, numThisTime);
if (useEvent)
handleMidiEvent (m);
@@ -176,6 +173,12 @@ void Synthesiser::renderNextBlock (AudioSampleBuffer& outputBuffer, const MidiBu
}
}
void Synthesiser::renderVoices (AudioSampleBuffer& buffer, int startSample, int numSamples)
{
for (int i = voices.size(); --i >= 0;)
voices.getUnchecked (i)->renderNextBlock (buffer, startSample, numSamples);
}
void Synthesiser::handleMidiEvent (const MidiMessage& m)
{
if (m.isNoteOn())
@@ -184,7 +187,7 @@ void Synthesiser::handleMidiEvent (const MidiMessage& m)
}
else if (m.isNoteOff())
{
noteOff (m.getChannel(), m.getNoteNumber(), true);
noteOff (m.getChannel(), m.getNoteNumber(), m.getFloatVelocity(), true);
}
else if (m.isAllNotesOff() || m.isAllSoundOff())
{
@@ -230,10 +233,10 @@ void Synthesiser::noteOn (const int midiChannel,
if (voice->getCurrentlyPlayingNote() == midiNoteNumber
&& voice->isPlayingChannel (midiChannel))
stopVoice (voice, true);
stopVoice (voice, 1.0f, true);
}
startVoice (findFreeVoice (sound, shouldStealNotes),
startVoice (findFreeVoice (sound, midiChannel, midiNoteNumber, shouldStealNotes),
sound, midiChannel, midiNoteNumber, velocity);
}
}
@@ -248,7 +251,7 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
if (voice != nullptr && sound != nullptr)
{
if (voice->currentlyPlayingSound != nullptr)
voice->stopNote (false);
voice->stopNote (0.0f, false);
voice->startNote (midiNoteNumber, velocity, sound,
lastPitchWheelValues [midiChannel - 1]);
@@ -261,11 +264,11 @@ void Synthesiser::startVoice (SynthesiserVoice* const voice,
}
}
void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
void Synthesiser::stopVoice (SynthesiserVoice* voice, float velocity, const bool allowTailOff)
{
jassert (voice != nullptr);
voice->stopNote (allowTailOff);
voice->stopNote (velocity, allowTailOff);
// the subclass MUST call clearCurrentNote() if it's not tailing off! RTFM for stopNote()!
jassert (allowTailOff || (voice->getCurrentlyPlayingNote() < 0 && voice->getCurrentlyPlayingSound() == 0));
@@ -273,6 +276,7 @@ void Synthesiser::stopVoice (SynthesiserVoice* voice, const bool allowTailOff)
void Synthesiser::noteOff (const int midiChannel,
const int midiNoteNumber,
const float velocity,
const bool allowTailOff)
{
const ScopedLock sl (lock);
@@ -291,7 +295,7 @@ void Synthesiser::noteOff (const int midiChannel,
voice->keyIsDown = false;
if (! (sustainPedalsDown [midiChannel] || voice->sostenutoPedalDown))
stopVoice (voice, allowTailOff);
stopVoice (voice, velocity, allowTailOff);
}
}
}
@@ -307,7 +311,7 @@ void Synthesiser::allNotesOff (const int midiChannel, const bool allowTailOff)
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel))
voice->stopNote (allowTailOff);
voice->stopNote (1.0f, allowTailOff);
}
sustainPedalsDown.clear();
@@ -379,7 +383,7 @@ void Synthesiser::handleSustainPedal (int midiChannel, bool isDown)
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->isPlayingChannel (midiChannel) && ! voice->keyIsDown)
stopVoice (voice, true);
stopVoice (voice, 1.0f, true);
}
sustainPedalsDown.clearBit (midiChannel);
@@ -400,7 +404,7 @@ void Synthesiser::handleSostenutoPedal (int midiChannel, bool isDown)
if (isDown)
voice->sostenutoPedalDown = true;
else if (voice->sostenutoPedalDown)
stopVoice (voice, true);
stopVoice (voice, 1.0f, true);
}
}
}
@@ -412,7 +416,9 @@ void Synthesiser::handleSoftPedal (int midiChannel, bool /*isDown*/)
}
//==============================================================================
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, const bool stealIfNoneAvailable) const
SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay,
int midiChannel, int midiNoteNumber,
const bool stealIfNoneAvailable) const
{
const ScopedLock sl (lock);
@@ -425,25 +431,68 @@ SynthesiserVoice* Synthesiser::findFreeVoice (SynthesiserSound* soundToPlay, con
}
if (stealIfNoneAvailable)
return findVoiceToSteal (soundToPlay);
return findVoiceToSteal (soundToPlay, midiChannel, midiNoteNumber);
return nullptr;
}
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay) const
struct VoiceAgeSorter
{
static int compareElements (SynthesiserVoice* v1, SynthesiserVoice* v2) noexcept
{
return v1->wasStartedBefore (*v2) ? 1 : (v2->wasStartedBefore (*v1) ? -1 : 0);
}
};
SynthesiserVoice* Synthesiser::findVoiceToSteal (SynthesiserSound* soundToPlay,
int /*midiChannel*/, int midiNoteNumber) const
{
// currently this just steals the one that's been playing the longest, but could be made a bit smarter..
SynthesiserVoice* oldest = nullptr;
SynthesiserVoice* bottom = nullptr;
SynthesiserVoice* top = nullptr;
// this is a list of voices we can steal, sorted by how long they've been running
Array<SynthesiserVoice*> usableVoices;
usableVoices.ensureStorageAllocated (voices.size());
for (int i = 0; i < voices.size(); ++i)
{
SynthesiserVoice* const voice = voices.getUnchecked (i);
if (voice->canPlaySound (soundToPlay)
&& (oldest == nullptr || voice->wasStartedBefore (*oldest)))
oldest = voice;
if (voice->canPlaySound (soundToPlay))
{
VoiceAgeSorter sorter;
usableVoices.addSorted (sorter, voice);
const int note = voice->getCurrentlyPlayingNote();
if (bottom == nullptr || note < bottom->getCurrentlyPlayingNote())
bottom = voice;
if (top == nullptr || note > top->getCurrentlyPlayingNote())
top = voice;
}
}
jassert (bottom != nullptr && top != nullptr);
// The oldest note that's playing with the target pitch playing is ideal..
for (int i = 0; i < usableVoices.size(); ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice->getCurrentlyPlayingNote() == midiNoteNumber)
return voice;
}
// ..otherwise, look for the oldest note that isn't the top or bottom note..
for (int i = 0; i < usableVoices.size(); ++i)
{
SynthesiserVoice* const voice = usableVoices.getUnchecked (i);
if (voice != bottom && voice != top)
return voice;
}
jassert (oldest != nullptr);
return oldest;
// ..otherwise, there's only one or two voices to choose from - we'll return the top one..
return top;
}

+ 56
- 30
source/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h View File

@@ -55,14 +55,14 @@ public:
The Synthesiser will use this information when deciding which sounds to trigger
for a given note.
*/
virtual bool appliesToNote (const int midiNoteNumber) = 0;
virtual bool appliesToNote (int midiNoteNumber) = 0;
/** Returns true if the sound should be triggered by midi events on a given channel.
The Synthesiser will use this information when deciding which sounds to trigger
for a given note.
*/
virtual bool appliesToChannel (const int midiChannel) = 0;
virtual bool appliesToChannel (int midiChannel) = 0;
/** The class is reference-counted, so this is a handy pointer class for it. */
typedef ReferenceCountedObjectPtr<SynthesiserSound> Ptr;
@@ -127,6 +127,8 @@ public:
This will be called during the rendering callback, so must be fast and thread-safe.
The velocity indicates how quickly the note was released - 0 is slowly, 1 is quickly.
If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all
sound immediately, and must call clearCurrentNote() to reset the state of this voice
and allow the synth to reassign it another sound.
@@ -136,7 +138,7 @@ public:
finishes playing (during the rendering callback), it must make sure that it calls
clearCurrentNote().
*/
virtual void stopNote (bool allowTailOff) = 0;
virtual void stopNote (float velocity, bool allowTailOff) = 0;
/** Called to let the voice know that the pitch wheel has been moved.
This will be called during the rendering callback, so must be fast and thread-safe.
@@ -173,13 +175,6 @@ public:
int startSample,
int numSamples) = 0;
/** Returns true if the voice is currently playing a sound which is mapped to the given
midi channel.
If it's not currently playing, this will return false.
*/
bool isPlayingChannel (int midiChannel) const;
/** Changes the voice's reference sample rate.
The rate is set so that subclasses know the output rate and can set their pitch
@@ -188,7 +183,19 @@ public:
This method is called by the synth, and subclasses can access the current rate with
the currentSampleRate member.
*/
void setCurrentPlaybackSampleRate (double newRate);
virtual void setCurrentPlaybackSampleRate (double newRate);
/** Returns the current target sample rate at which rendering is being done.
Subclasses may need to know this so that they can pitch things correctly.
*/
double getSampleRate() const noexcept { return currentSampleRate; }
/** Returns true if the voice is currently playing a sound which is mapped to the given
midi channel.
If it's not currently playing, this will return false.
*/
bool isPlayingChannel (int midiChannel) const;
/** Returns true if the key that triggered this voice is still held down.
Note that the voice may still be playing after the key was released (e.g because the
@@ -203,13 +210,6 @@ public:
bool wasStartedBefore (const SynthesiserVoice& other) const noexcept;
protected:
//==============================================================================
/** Returns the current target sample rate at which rendering is being done.
This is available for subclasses so they can pitch things correctly.
*/
double getSampleRate() const { return currentSampleRate; }
/** Resets the state of this voice after a sound has finished playing.
The subclass must call this when it finishes playing a note and becomes available
@@ -235,6 +235,11 @@ private:
SynthesiserSound::Ptr currentlyPlayingSound;
bool keyIsDown, sostenutoPedalDown;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// Note the new parameters for this method.
virtual int stopNote (bool) { return 0; }
#endif
JUCE_LEAK_DETECTOR (SynthesiserVoice)
};
@@ -268,8 +273,7 @@ class JUCE_API Synthesiser
public:
//==============================================================================
/** Creates a new synthesiser.
You'll need to add some sounds and voices before it'll make any sound..
You'll need to add some sounds and voices before it'll make any sound.
*/
Synthesiser();
@@ -365,6 +369,7 @@ public:
*/
virtual void noteOff (int midiChannel,
int midiNoteNumber,
float velocity,
bool allowTailOff);
/** Turns off all notes.
@@ -444,7 +449,7 @@ public:
This value is propagated to the voices so that they can use it to render the correct
pitches.
*/
void setCurrentPlaybackSampleRate (double sampleRate);
virtual void setCurrentPlaybackSampleRate (double sampleRate);
/** Creates the next block of audio output.
@@ -463,6 +468,11 @@ public:
int startSample,
int numSamples);
/** Returns the current target sample rate at which rendering is being done.
Subclasses may need to know this so that they can pitch things correctly.
*/
double getSampleRate() const noexcept { return sampleRate; }
protected:
//==============================================================================
/** This is used to control access to the rendering callback and the note trigger methods. */
@@ -474,21 +484,34 @@ protected:
/** The last pitch-wheel values for each midi channel. */
int lastPitchWheelValues [16];
/** Searches through the voices to find one that's not currently playing, and which
can play the given sound.
/** Renders the voices for the given range.
By default this just calls renderNextBlock() on each voice, but you may need
to override it to handle custom cases.
*/
virtual void renderVoices (AudioSampleBuffer& outputAudio,
int startSample, int numSamples);
/** Searches through the voices to find one that's not currently playing, and
which can play the given sound.
Returns nullptr if all voices are busy and stealing isn't enabled.
This can be overridden to implement custom voice-stealing algorithms.
To implement a custom note-stealing algorithm, you can either override this
method, or (preferably) override findVoiceToSteal().
*/
virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay,
const bool stealIfNoneAvailable) const;
int midiChannel,
int midiNoteNumber,
bool stealIfNoneAvailable) const;
/** Chooses a voice that is most suitable for being re-used.
The default method returns the one that has been playing for the longest, but
you may want to override this and do something more cunning instead.
The default method will attempt to find the oldest voice that isn't the
bottom or top note being played. If that's not suitable for your synth,
you can override this method and do something more cunning instead.
*/
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay) const;
virtual SynthesiserVoice* findVoiceToSteal (SynthesiserSound* soundToPlay,
int midiChannel,
int midiNoteNumber) const;
/** Starts a specified voice playing a particular sound.
@@ -511,11 +534,14 @@ private:
bool shouldStealNotes;
BigInteger sustainPedalsDown;
void stopVoice (SynthesiserVoice*, bool allowTailOff);
void stopVoice (SynthesiserVoice*, float velocity, bool allowTailOff);
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// Note the new parameters for this method.
// Note the new parameters for these methods.
virtual int findFreeVoice (const bool) const { return 0; }
virtual int noteOff (int, int, int) { return 0; }
virtual int findFreeVoice (SynthesiserSound*, const bool) { return 0; }
virtual int findVoiceToSteal (SynthesiserSound*) const { return 0; }
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser)


+ 1
- 1
source/modules/juce_audio_devices/native/juce_linux_ALSA.cpp View File

@@ -41,7 +41,7 @@ namespace
return err;
}
#else
#define JUCE_ALSA_LOG(x)
#define JUCE_ALSA_LOG(x) {}
#define JUCE_CHECKED_RESULT(x) (x)
#endif


+ 149
- 26
source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.cpp View File

@@ -65,6 +65,7 @@ const char* const WavAudioFormat::acidNumerator = "acid numerator";
const char* const WavAudioFormat::acidTempo = "acid tempo";
const char* const WavAudioFormat::ISRC = "ISRC";
const char* const WavAudioFormat::tracktionLoopInfo = "tracktion loop info";
//==============================================================================
namespace WavFileHelpers
@@ -471,6 +472,46 @@ namespace WavFileHelpers
}
}
//==============================================================================
namespace ListInfoChunk
{
static bool writeValue (const StringPairArray& values, MemoryOutputStream& out, const char* paramName)
{
const String value (values.getValue (paramName, String()));
if (value.isEmpty())
return false;
const int valueLength = (int) value.getNumBytesAsUTF8() + 1;
const int chunkLength = valueLength + (valueLength & 1);
out.writeInt (chunkName (paramName));
out.writeInt (chunkLength);
out.write (value.toUTF8(), (size_t) valueLength);
if ((out.getDataSize() & 1) != 0)
out.writeByte (0);
return true;
}
static MemoryBlock createFrom (const StringPairArray& values)
{
static const char* params[] = { "INAM", "IART", "IPRD", "IPRT", "ISFT",
"ISRC", "IGNR", "ICMT", "ICOP", "ICRD" };
MemoryOutputStream out;
out.writeInt (chunkName ("INFO"));
bool anyParamsDefined = false;
for (int i = 0; i < numElementsInArray (params); ++i)
if (writeValue (values, out, params[i]))
anyParamsDefined = true;
return anyParamsDefined ? out.getMemoryBlock() : MemoryBlock();
}
}
//==============================================================================
struct AcidChunk
{
@@ -481,6 +522,38 @@ namespace WavFileHelpers
input.read (this, (int) jmin (sizeof (*this), length));
}
AcidChunk (const StringPairArray& values)
{
zerostruct (*this);
flags = getFlagIfPresent (values, WavAudioFormat::acidOneShot, 0x01)
| getFlagIfPresent (values, WavAudioFormat::acidRootSet, 0x02)
| getFlagIfPresent (values, WavAudioFormat::acidStretch, 0x04)
| getFlagIfPresent (values, WavAudioFormat::acidDiskBased, 0x08)
| getFlagIfPresent (values, WavAudioFormat::acidizerFlag, 0x10);
if (values[WavAudioFormat::acidRootSet].getIntValue() != 0)
rootNote = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidRootNote].getIntValue());
numBeats = ByteOrder::swapIfBigEndian ((uint32) values[WavAudioFormat::acidBeats].getIntValue());
meterDenominator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidDenominator].getIntValue());
meterNumerator = ByteOrder::swapIfBigEndian ((uint16) values[WavAudioFormat::acidNumerator].getIntValue());
if (values.containsKey (WavAudioFormat::acidTempo))
tempo = swapFloatByteOrder (values[WavAudioFormat::acidTempo].getFloatValue());
}
static MemoryBlock createFrom (const StringPairArray& values)
{
return AcidChunk (values).toMemoryBlock();
}
MemoryBlock toMemoryBlock() const
{
return (flags != 0 || rootNote != 0 || numBeats != 0 || meterDenominator != 0 || meterNumerator != 0)
? MemoryBlock (this, sizeof (*this)) : MemoryBlock();
}
void addToMetadata (StringPairArray& values) const
{
setBoolFlag (values, WavAudioFormat::acidOneShot, 0x01);
@@ -490,30 +563,65 @@ namespace WavFileHelpers
setBoolFlag (values, WavAudioFormat::acidizerFlag, 0x10);
if (flags & 0x02) // root note set
values.set (WavAudioFormat::acidRootNote, String (rootNote));
values.set (WavAudioFormat::acidRootNote, String (ByteOrder::swapIfBigEndian (rootNote)));
values.set (WavAudioFormat::acidBeats, String (numBeats));
values.set (WavAudioFormat::acidDenominator, String (meterDenominator));
values.set (WavAudioFormat::acidNumerator, String (meterNumerator));
values.set (WavAudioFormat::acidTempo, String (tempo));
values.set (WavAudioFormat::acidBeats, String (ByteOrder::swapIfBigEndian (numBeats)));
values.set (WavAudioFormat::acidDenominator, String (ByteOrder::swapIfBigEndian (meterDenominator)));
values.set (WavAudioFormat::acidNumerator, String (ByteOrder::swapIfBigEndian (meterNumerator)));
values.set (WavAudioFormat::acidTempo, String (swapFloatByteOrder (tempo)));
}
void setBoolFlag (StringPairArray& values, const char* name, int32 mask) const
void setBoolFlag (StringPairArray& values, const char* name, uint32 mask) const
{
values.set (name, (flags & mask) ? "1" : "0");
values.set (name, (flags & ByteOrder::swapIfBigEndian (mask)) ? "1" : "0");
}
static uint32 getFlagIfPresent (const StringPairArray& values, const char* name, uint32 flag)
{
return values[name].getIntValue() != 0 ? ByteOrder::swapIfBigEndian (flag) : 0;
}
static float swapFloatByteOrder (const float x) noexcept
{
#ifdef JUCE_BIG_ENDIAN
union { uint32 asInt; float asFloat; } n;
n.asFloat = x;
n.asInt = ByteOrder::swap (n.asInt);
return n.asFloat;
#else
return x;
#endif
}
int32 flags;
int16 rootNote;
int16 reserved1;
uint32 flags;
uint16 rootNote;
uint16 reserved1;
float reserved2;
int32 numBeats;
int16 meterDenominator;
int16 meterNumerator;
uint32 numBeats;
uint16 meterDenominator;
uint16 meterNumerator;
float tempo;
} JUCE_PACKED;
//==============================================================================
struct TracktionChunk
{
static MemoryBlock createFrom (const StringPairArray& values)
{
const String s = values[WavAudioFormat::tracktionLoopInfo];
MemoryBlock data;
if (s.isNotEmpty())
{
MemoryOutputStream os (data, false);
os.writeString (s);
}
return data;
}
};
//==============================================================================
namespace AXMLChunk
{
@@ -816,6 +924,12 @@ public:
{
AcidChunk (*input, length).addToMetadata (metadataValues);
}
else if (chunkType == chunkName ("Trkn"))
{
MemoryBlock tracktion;
input->readIntoMemoryBlock (tracktion, (ssize_t) length);
metadataValues.set (WavAudioFormat::tracktionLoopInfo, tracktion.toString());
}
else if (chunkEnd <= input->getPosition())
{
break;
@@ -913,12 +1027,15 @@ public:
// key should be removed (or set to "WAV") once this has been done
jassert (metadataValues.getValue ("MetaDataSource", "None") != "AIFF");
bwavChunk = BWAVChunk::createFrom (metadataValues);
axmlChunk = AXMLChunk::createFrom (metadataValues);
smplChunk = SMPLChunk::createFrom (metadataValues);
instChunk = InstChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (metadataValues);
listChunk = ListChunk::createFrom (metadataValues);
bwavChunk = BWAVChunk::createFrom (metadataValues);
axmlChunk = AXMLChunk::createFrom (metadataValues);
smplChunk = SMPLChunk::createFrom (metadataValues);
instChunk = InstChunk::createFrom (metadataValues);
cueChunk = CueChunk ::createFrom (metadataValues);
listChunk = ListChunk::createFrom (metadataValues);
listInfoChunk = ListInfoChunk::createFrom (metadataValues);
acidChunk = AcidChunk::createFrom (metadataValues);
trckChunk = TracktionChunk::createFrom (metadataValues);
}
headerPosition = out->getPosition();
@@ -981,7 +1098,7 @@ public:
}
private:
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk;
MemoryBlock tempBlock, bwavChunk, axmlChunk, smplChunk, instChunk, cueChunk, listChunk, listInfoChunk, acidChunk, trckChunk;
uint64 lengthInSamples, bytesWritten;
int64 headerPosition;
bool writeFailed;
@@ -1033,6 +1150,9 @@ private:
+ chunkSize (instChunk)
+ chunkSize (cueChunk)
+ chunkSize (listChunk)
+ chunkSize (listInfoChunk)
+ chunkSize (acidChunk)
+ chunkSize (trckChunk)
+ (8 + 28)); // (ds64 chunk)
riffChunkSize += (riffChunkSize & 1);
@@ -1106,12 +1226,15 @@ private:
output->write (subFormat.data4, sizeof (subFormat.data4));
}
writeChunk (bwavChunk, chunkName ("bext"));
writeChunk (axmlChunk, chunkName ("axml"));
writeChunk (smplChunk, chunkName ("smpl"));
writeChunk (instChunk, chunkName ("inst"), 7);
writeChunk (cueChunk, chunkName ("cue "));
writeChunk (listChunk, chunkName ("LIST"));
writeChunk (bwavChunk, chunkName ("bext"));
writeChunk (axmlChunk, chunkName ("axml"));
writeChunk (smplChunk, chunkName ("smpl"));
writeChunk (instChunk, chunkName ("inst"), 7);
writeChunk (cueChunk, chunkName ("cue "));
writeChunk (listChunk, chunkName ("LIST"));
writeChunk (listInfoChunk, chunkName ("LIST"));
writeChunk (acidChunk, chunkName ("acid"));
writeChunk (trckChunk, chunkName ("Trkn"));
writeChunkHeader (chunkName ("data"), isRF64 ? -1 : (int) (lengthInSamples * bytesPerFrame));


+ 3
- 0
source/modules/juce_audio_formats/codecs/juce_WavAudioFormat.h View File

@@ -135,6 +135,9 @@ public:
/** Metadata property name used when reading an ISRC code from an AXML chunk. */
static const char* const ISRC;
/** Metadata property name used when reading a WAV file with a Tracktion chunk. */
static const char* const tracktionLoopInfo;
//==============================================================================
Array<int> getPossibleSampleRates() override;
Array<int> getPossibleBitDepths() override;


+ 48
- 75
source/modules/juce_audio_formats/format/juce_AudioFormatReader.cpp View File

@@ -173,102 +173,75 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer,
}
}
template <typename SampleType>
static Range<SampleType> getChannelMinAndMax (SampleType* channel, int numSamples) noexcept
{
return Range<SampleType>::findMinAndMax (channel, numSamples);
}
static Range<float> getChannelMinAndMax (float* channel, int numSamples) noexcept
{
return FloatVectorOperations::findMinAndMax (channel, numSamples);
}
template <typename SampleType>
static void getStereoMinAndMax (SampleType* const* channels, const int numChannels, const int numSamples,
SampleType& lmin, SampleType& lmax, SampleType& rmin, SampleType& rmax)
{
Range<SampleType> range (getChannelMinAndMax (channels[0], numSamples));
lmax = jmax (lmax, range.getEnd());
lmin = jmin (lmin, range.getStart());
if (numChannels > 1)
{
range = getChannelMinAndMax (channels[1], numSamples);
rmax = jmax (rmax, range.getEnd());
rmin = jmin (rmin, range.getStart());
}
else
{
rmax = lmax;
rmin = lmin;
}
}
void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
float& lowestLeft, float& highestLeft,
float& lowestRight, float& highestRight)
Range<float>* const results, const int channelsToRead)
{
jassert (channelsToRead > 0 && channelsToRead <= (int) numChannels);
if (numSamples <= 0)
{
lowestLeft = 0;
lowestRight = 0;
highestLeft = 0;
highestRight = 0;
for (int i = 0; i < channelsToRead; ++i)
results[i] = Range<float>();
return;
}
const int bufferSize = (int) jmin (numSamples, (int64) 4096);
AudioSampleBuffer tempSampleBuffer ((int) numChannels, bufferSize);
AudioSampleBuffer tempSampleBuffer ((int) channelsToRead, bufferSize);
float* const* const floatBuffer = tempSampleBuffer.getArrayOfWritePointers();
int* const* intBuffer = reinterpret_cast<int* const*> (floatBuffer);
bool isFirstBlock = true;
if (usesFloatingPointData)
while (numSamples > 0)
{
float lmin = 1.0e6f;
float lmax = -lmin;
float rmin = lmin;
float rmax = lmax;
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, channelsToRead, startSampleInFile, numToDo, false))
break;
while (numSamples > 0)
for (int i = 0; i < channelsToRead; ++i)
{
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
break;
Range<float> r;
if (usesFloatingPointData)
{
r = FloatVectorOperations::findMinAndMax (floatBuffer[i], numToDo);
}
else
{
Range<int> intRange (Range<int>::findMinAndMax (intBuffer[i], numToDo));
numSamples -= numToDo;
startSampleInFile += numToDo;
getStereoMinAndMax (floatBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
r = Range<float> (intRange.getStart() / (float) std::numeric_limits<int>::max(),
intRange.getEnd() / (float) std::numeric_limits<int>::max());
}
results[i] = isFirstBlock ? r : results[i].getUnionWith (r);
}
lowestLeft = lmin;
highestLeft = lmax;
lowestRight = rmin;
highestRight = rmax;
isFirstBlock = false;
numSamples -= numToDo;
startSampleInFile += numToDo;
}
else
{
int lmax = std::numeric_limits<int>::min();
int lmin = std::numeric_limits<int>::max();
int rmax = std::numeric_limits<int>::min();
int rmin = std::numeric_limits<int>::max();
while (numSamples > 0)
{
const int numToDo = (int) jmin (numSamples, (int64) bufferSize);
if (! read (intBuffer, 2, startSampleInFile, numToDo, false))
break;
}
numSamples -= numToDo;
startSampleInFile += numToDo;
getStereoMinAndMax (intBuffer, (int) numChannels, numToDo, lmin, lmax, rmin, rmax);
}
void AudioFormatReader::readMaxLevels (int64 startSampleInFile, int64 numSamples,
float& lowestLeft, float& highestLeft,
float& lowestRight, float& highestRight)
{
Range<float> levels[2];
readMaxLevels (startSampleInFile, numSamples, levels, jmin (2, (int) numChannels));
lowestLeft = levels[0].getStart();
highestLeft = levels[0].getEnd();
lowestLeft = lmin / (float) std::numeric_limits<int>::max();
highestLeft = lmax / (float) std::numeric_limits<int>::max();
lowestRight = rmin / (float) std::numeric_limits<int>::max();
highestRight = rmax / (float) std::numeric_limits<int>::max();
if (numChannels > 1)
{
lowestRight = levels[1].getStart();
highestRight = levels[1].getEnd();
}
else
{
lowestRight = lowestLeft;
highestRight = highestLeft;
}
}


+ 22
- 6
source/modules/juce_audio_formats/format/juce_AudioFormatReader.h View File

@@ -121,6 +121,25 @@ public:
bool useReaderLeftChan,
bool useReaderRightChan);
/** Finds the highest and lowest sample levels from a section of the audio stream.
This will read a block of samples from the stream, and measure the
highest and lowest sample levels from the channels in that section, returning
these as normalised floating-point levels.
@param startSample the offset into the audio stream to start reading from. It's
ok for this to be beyond the start or end of the stream.
@param numSamples how many samples to read
@param results this array will be filled with Range values for each channel.
The array must contain numChannels elements.
@param numChannelsToRead the number of channels of data to scan. This must be
more than zero, but not more than the total number of channels
that the reader contains
@see read
*/
virtual void readMaxLevels (int64 startSample, int64 numSamples,
Range<float>* results, int numChannelsToRead);
/** Finds the highest and lowest sample levels from a section of the audio stream.
This will read a block of samples from the stream, and measure the
@@ -138,12 +157,9 @@ public:
channel (if there is one)
@see read
*/
virtual void readMaxLevels (int64 startSample,
int64 numSamples,
float& lowestLeft,
float& highestLeft,
float& lowestRight,
float& highestRight);
virtual void readMaxLevels (int64 startSample, int64 numSamples,
float& lowestLeft, float& highestLeft,
float& lowestRight, float& highestRight);
/** Scans the source looking for a sample whose magnitude is in a specified range.


+ 5
- 5
source/modules/juce_audio_formats/sampler/juce_Sampler.cpp View File

@@ -59,12 +59,12 @@ SamplerSound::~SamplerSound()
{
}
bool SamplerSound::appliesToNote (const int midiNoteNumber)
bool SamplerSound::appliesToNote (int midiNoteNumber)
{
return midiNotes [midiNoteNumber];
}
bool SamplerSound::appliesToChannel (const int /*midiChannel*/)
bool SamplerSound::appliesToChannel (int /*midiChannel*/)
{
return true;
}
@@ -127,7 +127,7 @@ void SamplerVoice::startNote (const int midiNoteNumber,
}
}
void SamplerVoice::stopNote (const bool allowTailOff)
void SamplerVoice::stopNote (float /*velocity*/, bool allowTailOff)
{
if (allowTailOff)
{
@@ -197,7 +197,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
if (attackReleaseLevel <= 0.0f)
{
stopNote (false);
stopNote (0.0f, false);
break;
}
}
@@ -216,7 +216,7 @@ void SamplerVoice::renderNextBlock (AudioSampleBuffer& outputBuffer, int startSa
if (sourceSamplePosition > playingSound->length)
{
stopNote (false);
stopNote (0.0f, false);
break;
}
}


+ 3
- 3
source/modules/juce_audio_formats/sampler/juce_Sampler.h View File

@@ -82,8 +82,8 @@ public:
//==============================================================================
bool appliesToNote (const int midiNoteNumber) override;
bool appliesToChannel (const int midiChannel) override;
bool appliesToNote (int midiNoteNumber) override;
bool appliesToChannel (int midiChannel) override;
private:
@@ -124,7 +124,7 @@ public:
bool canPlaySound (SynthesiserSound*) override;
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int pitchWheel) override;
void stopNote (bool allowTailOff) override;
void stopNote (float velocity, bool allowTailOff) override;
void pitchWheelMoved (int newValue);
void controllerMoved (int controllerNumber, int newValue) override;


+ 11
- 1
source/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -345,11 +345,21 @@ public:
refreshParameterList();
updateNumChannels();
producesMidiMessages = canProduceMidiOutput();
setPluginCallbacks();
setPlayConfigDetails (numInputBusChannels * numInputBusses,
numOutputBusChannels * numOutputBusses,
rate, blockSize);
setLatencySamples (0);
if (parameters.size() == 0)
{
// some plugins crash if initialiseAudioUnit() is called too soon (sigh..), so we'll
// only call it here if it seems like they it's one of the awkward plugins that can
// only create their parameters after it has been initialised.
initialiseAudioUnit();
refreshParameterList();
}
setPluginCallbacks();
}
//==============================================================================


+ 1
- 1
source/modules/juce_audio_processors/format_types/juce_LADSPAPluginFormat.cpp View File

@@ -26,7 +26,7 @@
} // (juce namespace)
#include "ladspa.h"
#include <ladspa.h>
namespace juce
{


+ 5
- 1
source/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -2112,7 +2112,11 @@ private:
MemoryBlock mem;
if (mem.fromBase64Encoding (state->getAllSubText()))
stream = new Steinberg::MemoryStream (mem.getData(), (TSize) mem.getSize());
{
stream = new Steinberg::MemoryStream();
stream->setSize ((TSize) mem.getSize());
mem.copyTo (stream->getData(), 0, mem.getSize());
}
}
return stream;


+ 1
- 0
source/modules/juce_audio_processors/juce_audio_processors.h View File

@@ -76,6 +76,7 @@ class AudioProcessor;
#include "processors/juce_AudioPlayHead.h"
#include "processors/juce_AudioProcessorEditor.h"
#include "processors/juce_AudioProcessorListener.h"
#include "processors/juce_AudioProcessorParameter.h"
#include "processors/juce_AudioProcessor.h"
#include "processors/juce_PluginDescription.h"
#include "processors/juce_AudioPluginInstance.h"


+ 164
- 17
source/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -120,19 +120,6 @@ void AudioProcessor::setParameterNotifyingHost (const int parameterIndex,
sendParamChangeMessageToListeners (parameterIndex, newValue);
}
String AudioProcessor::getParameterName (int parameterIndex, int maximumStringLength)
{
return getParameterName (parameterIndex).substring (0, maximumStringLength);
}
String AudioProcessor::getParameterText (int parameterIndex, int maximumStringLength)
{
return getParameterText (parameterIndex).substring (0, maximumStringLength);
}
int AudioProcessor::getParameterNumSteps (int /*parameterIndex*/) { return 0x7fffffff; }
float AudioProcessor::getParameterDefaultValue (int /*parameterIndex*/) { return 0.0f; }
AudioProcessorListener* AudioProcessor::getListenerLocked (const int index) const noexcept
{
const ScopedLock sl (listenerLock);
@@ -203,10 +190,129 @@ void AudioProcessor::updateHostDisplay()
l->audioProcessorChanged (this);
}
String AudioProcessor::getParameterLabel (int) const { return String(); }
bool AudioProcessor::isParameterOrientationInverted (int) const { return false; }
bool AudioProcessor::isParameterAutomatable (int) const { return true; }
bool AudioProcessor::isMetaParameter (int) const { return false; }
const OwnedArray<AudioProcessorParameter>& AudioProcessor::getParameters() const noexcept
{
return managedParameters;
}
int AudioProcessor::getNumParameters()
{
return managedParameters.size();
}
float AudioProcessor::getParameter (int index)
{
if (AudioProcessorParameter* p = getParamChecked (index))
return p->getValue();
return 0;
}
void AudioProcessor::setParameter (int index, float newValue)
{
if (AudioProcessorParameter* p = getParamChecked (index))
p->setValue (newValue);
}
float AudioProcessor::getParameterDefaultValue (int index)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getDefaultValue();
return 0;
}
const String AudioProcessor::getParameterName (int index)
{
if (AudioProcessorParameter* p = getParamChecked (index))
return p->getName (512);
return String();
}
String AudioProcessor::getParameterName (int index, int maximumStringLength)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getName (maximumStringLength);
return getParameterName (index).substring (0, maximumStringLength);
}
const String AudioProcessor::getParameterText (int index)
{
return getParameterText (index, 1024);
}
String AudioProcessor::getParameterText (int index, int maximumStringLength)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getText (p->getValue(), maximumStringLength);
return getParameterText (index).substring (0, maximumStringLength);
}
int AudioProcessor::getParameterNumSteps (int index)
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getNumSteps();
return AudioProcessor::getDefaultNumParameterSteps();
}
int AudioProcessor::getDefaultNumParameterSteps() noexcept
{
return 0x7fffffff;
}
String AudioProcessor::getParameterLabel (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->getLabel();
return String();
}
bool AudioProcessor::isParameterAutomatable (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isAutomatable();
return true;
}
bool AudioProcessor::isParameterOrientationInverted (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isOrientationInverted();
return false;
}
bool AudioProcessor::isMetaParameter (int index) const
{
if (AudioProcessorParameter* p = managedParameters[index])
return p->isMetaParameter();
return false;
}
AudioProcessorParameter* AudioProcessor::getParamChecked (int index) const noexcept
{
AudioProcessorParameter* p = managedParameters[index];
// If you hit this, then you're either trying to access parameters that are out-of-range,
// or you're not using addParameter and the managed parameter list, but have failed
// to override some essential virtual methods and implement them appropriately.
jassert (p != nullptr);
return p;
}
void AudioProcessor::addParameter (AudioProcessorParameter* p)
{
p->processor = this;
p->parameterIndex = managedParameters.size();
managedParameters.add (p);
}
void AudioProcessor::suspendProcessing (const bool shouldBeSuspended)
{
@@ -299,6 +405,47 @@ XmlElement* AudioProcessor::getXmlFromBinary (const void* data, const int sizeIn
void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioProcessor*, int) {}
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}
//==============================================================================
AudioProcessorParameter::AudioProcessorParameter() noexcept
: processor (nullptr), parameterIndex (-1)
{}
AudioProcessorParameter::~AudioProcessorParameter() {}
void AudioProcessorParameter::setValueNotifyingHost (float newValue)
{
// This method can't be used until the parameter has been attached to a processor!
jassert (processor != nullptr && parameterIndex >= 0);
return processor->setParameterNotifyingHost (parameterIndex, newValue);
}
void AudioProcessorParameter::beginChangeGesture()
{
// This method can't be used until the parameter has been attached to a processor!
jassert (processor != nullptr && parameterIndex >= 0);
processor->beginParameterChangeGesture (parameterIndex);
}
void AudioProcessorParameter::endChangeGesture()
{
// This method can't be used until the parameter has been attached to a processor!
jassert (processor != nullptr && parameterIndex >= 0);
processor->endParameterChangeGesture (parameterIndex);
}
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
bool AudioProcessorParameter::isAutomatable() const { return true; }
bool AudioProcessorParameter::isMetaParameter() const { return false; }
int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); }
String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
{
return String (value, 2);
}
//==============================================================================
bool AudioPlayHead::CurrentPositionInfo::operator== (const CurrentPositionInfo& other) const noexcept
{


+ 26
- 7
source/modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -379,10 +379,10 @@ public:
/** This must return the correct value immediately after the object has been
created, and mustn't change the number of parameters later.
*/
virtual int getNumParameters() = 0;
virtual int getNumParameters();
/** Returns the name of a particular parameter. */
virtual const String getParameterName (int parameterIndex) = 0;
virtual const String getParameterName (int parameterIndex);
/** Called by the host to find out the value of one of the filter's parameters.
@@ -392,10 +392,10 @@ public:
It's also likely to be called by non-UI threads, so the code in here should
be thread-aware.
*/
virtual float getParameter (int parameterIndex) = 0;
virtual float getParameter (int parameterIndex);
/** Returns the value of a parameter as a text string. */
virtual const String getParameterText (int parameterIndex) = 0;
virtual const String getParameterText (int parameterIndex);
/** Returns the name of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter names that
@@ -416,12 +416,18 @@ public:
virtual String getParameterText (int parameterIndex, int maximumStringLength);
/** Returns the number of discrete steps that this parameter can represent.
The default return value if you don't implement this method is 0x7fffffff.
The default return value if you don't implement this method is
AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
The value that is returned may or may not be used, depending on the host.
*/
virtual int getParameterNumSteps (int parameterIndex);
/** Returns the default number of steps for a parameter.
@see getParameterNumSteps
*/
static int getDefaultNumParameterSteps() noexcept;
/** Returns the default value for the parameter.
By default, this just returns 0.
The value that is returned may or may not be used, depending on the host.
@@ -451,7 +457,7 @@ public:
The value passed will be between 0 and 1.0.
*/
virtual void setParameter (int parameterIndex, float newValue) = 0;
virtual void setParameter (int parameterIndex, float newValue);
/** Your filter can call this when it needs to change one of its parameters.
@@ -503,6 +509,16 @@ public:
*/
void updateHostDisplay();
//==============================================================================
/** Adds a parameter to the list.
The parameter object will be managed and deleted automatically by the list
when no longer needed.
*/
void addParameter (AudioProcessorParameter*);
/** Returns the current list of parameters. */
const OwnedArray<AudioProcessorParameter>& getParameters() const noexcept;
//==============================================================================
/** Returns the number of preset programs the filter supports.
@@ -582,7 +598,7 @@ public:
//==============================================================================
/** LV2 specific calls, saving/restore as string. */
virtual String getStateInformationString () { return String::empty; }
virtual void setStateInformationString (const String& data) {}
virtual void setStateInformationString (const String&) {}
//==============================================================================
/** Adds a listener that will be called when an aspect of this processor changes. */
@@ -668,6 +684,9 @@ private:
CriticalSection callbackLock, listenerLock;
String inputSpeakerArrangement, outputSpeakerArrangement;
OwnedArray<AudioProcessorParameter> managedParameters;
AudioProcessorParameter* getParamChecked (int) const noexcept;
#if JUCE_DEBUG
BigInteger changingParams;
#endif


+ 158
- 0
source/modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h View File

@@ -0,0 +1,158 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
Permission is granted to use this software under the terms of either:
a) the GPL v2 (or any later version)
b) the Affero GPL v3
Details of these licenses can be found at: www.gnu.org/licenses
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.juce.com for more information.
==============================================================================
*/
#ifndef JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED
#define JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED
//==============================================================================
/** An abstract base class for parameter objects that can be added to an
AudioProcessor.
@see AudioProcessor::addParameter
*/
class JUCE_API AudioProcessorParameter
{
public:
AudioProcessorParameter() noexcept;
/** Destructor. */
virtual ~AudioProcessorParameter();
/** Called by the host to find out the value of this parameter.
Hosts will expect the value returned to be between 0 and 1.0.
This could be called quite frequently, so try to make your code efficient.
It's also likely to be called by non-UI threads, so the code in here should
be thread-aware.
*/
virtual float getValue() const = 0;
/** The host will call this method to change the value of one of the filter's parameters.
The host may call this at any time, including during the audio processing
callback, so the filter has to process this very fast and avoid blocking.
If you want to set the value of a parameter internally, e.g. from your
editor component, then don't call this directly - instead, use the
setValueNotifyingHost() method, which will also send a message to
the host telling it about the change. If the message isn't sent, the host
won't be able to automate your parameters properly.
The value passed will be between 0 and 1.0.
*/
virtual void setValue (float newValue) = 0;
/** Your filter can call this when it needs to change one of its parameters.
This could happen when the editor or some other internal operation changes
a parameter. This method will call the setParameter() method to change the
value, and will then send a message to the host telling it about the change.
Note that to make sure the host correctly handles automation, you should call
the beginChangeGesture() and endChangeGesture() methods to tell the host when
the user has started and stopped changing the parameter.
*/
void setValueNotifyingHost (float newValue);
/** Sends a signal to the host to tell it that the user is about to start changing this
parameter.
This allows the host to know when a parameter is actively being held by the user, and
it may use this information to help it record automation.
If you call this, it must be matched by a later call to endChangeGesture().
*/
void beginChangeGesture();
/** Tells the host that the user has finished changing this parameter.
This allows the host to know when a parameter is actively being held by the user,
and it may use this information to help it record automation.
A call to this method must follow a call to beginChangeGesture().
*/
void endChangeGesture();
/** This should return the default value for this parameter. */
virtual float getDefaultValue() const = 0;
/** Returns the name to display for this parameter, which should be made
to fit within the given string length.
*/
virtual String getName (int maximumStringLength) const = 0;
/** Some parameters may be able to return a label string for
their units. For example "Hz" or "%".
*/
virtual String getLabel() const = 0;
/** Returns the number of discrete interval steps that this parameter's range
should be quantised into.
If you want a continuous range of values, don't override this method, and allow
the default implementation to return AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
The value that is returned may or may not be used, depending on the host.
*/
virtual int getNumSteps() const;
/** Returns a textual version of the supplied parameter value.
The default implementation just returns the floating point value
as a string, but this could do anything you need for a custom type
of value.
*/
virtual String getText (float value, int /*maximumStringLength*/) const;
/** Should parse a string and return the appropriate value for it. */
virtual float getValueForText (const String& text) const = 0;
/** This can be overridden to tell the host that this parameter operates in the
reverse direction.
(Not all plugin formats or hosts will actually use this information).
*/
virtual bool isOrientationInverted() const;
/** Returns true if the host can automate this parameter.
By default, this returns true.
*/
virtual bool isAutomatable() const;
/** Should return true if this parameter is a "meta" parameter.
A meta-parameter is a parameter that changes other params. It is used
by some hosts (e.g. AudioUnit hosts).
By default this returns false.
*/
virtual bool isMetaParameter() const;
/** Returns the index of this parameter in its parent processor's parameter list. */
int getParameterIndex() const noexcept { return parameterIndex; }
private:
friend class AudioProcessor;
AudioProcessor* processor;
int parameterIndex;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorParameter)
};
#endif // JUCE_AUDIOPROCESSORPARAMETER_H_INCLUDED

+ 1
- 1
source/modules/juce_core/containers/juce_OwnedArray.h View File

@@ -830,7 +830,7 @@ public:
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType first, ElementType second);
int compareElements (ElementType* first, ElementType* second);
@endcode
..and this method must return:


+ 26
- 27
source/modules/juce_core/files/juce_WildcardFileFilter.cpp View File

@@ -26,32 +26,7 @@
==============================================================================
*/
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& desc)
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
: (desc + " (" + fileWildcardPatterns + ")"))
{
parse (fileWildcardPatterns, fileWildcards);
parse (directoryWildcardPatterns, directoryWildcards);
}
WildcardFileFilter::~WildcardFileFilter()
{
}
bool WildcardFileFilter::isFileSuitable (const File& file) const
{
return match (file, fileWildcards);
}
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
{
return match (file, directoryWildcards);
}
//==============================================================================
void WildcardFileFilter::parse (const String& pattern, StringArray& result)
static void parseWildcard (const String& pattern, StringArray& result)
{
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
@@ -65,7 +40,7 @@ void WildcardFileFilter::parse (const String& pattern, StringArray& result)
result.set (i, "*");
}
bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
static bool matchWildcard (const File& file, const StringArray& wildcards)
{
const String filename (file.getFileName());
@@ -75,3 +50,27 @@ bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
return false;
}
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& desc)
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
: (desc + " (" + fileWildcardPatterns + ")"))
{
parseWildcard (fileWildcardPatterns, fileWildcards);
parseWildcard (directoryWildcardPatterns, directoryWildcards);
}
WildcardFileFilter::~WildcardFileFilter()
{
}
bool WildcardFileFilter::isFileSuitable (const File& file) const
{
return matchWildcard (file, fileWildcards);
}
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
{
return matchWildcard (file, directoryWildcards);
}

+ 0
- 4
source/modules/juce_core/files/juce_WildcardFileFilter.h View File

@@ -75,12 +75,8 @@ private:
//==============================================================================
StringArray fileWildcards, directoryWildcards;
static void parse (const String& pattern, StringArray& result);
static bool match (const File& file, const StringArray& wildcards);
JUCE_LEAK_DETECTOR (WildcardFileFilter)
};
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED

+ 17
- 11
source/modules/juce_core/javascript/juce_Javascript.cpp View File

@@ -102,6 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); }
static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); }
static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); }
//==============================================================================
struct CodeLocation
@@ -139,13 +140,13 @@ struct JavascriptEngine::RootObject : public DynamicObject
{
if (DynamicObject* o = targetObject.getDynamicObject())
{
if (var* prop = o->getProperties().getVarPointer (functionName))
if (const var* prop = getPropertyPointer (o, functionName))
return *prop;
for (DynamicObject* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
{
if (var* prop = p->getProperties().getVarPointer (functionName))
if (const var* prop = getPropertyPointer (p, functionName))
return *prop;
}
}
@@ -168,14 +169,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
var* findRootClassProperty (Identifier className, Identifier propName) const
{
if (DynamicObject* cls = root->getProperty (className).getDynamicObject())
return cls->getProperties().getVarPointer (propName);
return getPropertyPointer (cls, propName);
return nullptr;
}
var findSymbolInParentScopes (Identifier name) const
{
if (var* v = scope->getProperties().getVarPointer (name))
if (const var* v = getPropertyPointer (scope, name))
return *v;
return parent != nullptr ? parent->findSymbolInParentScopes (name)
@@ -184,13 +185,11 @@ struct JavascriptEngine::RootObject : public DynamicObject
bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const
{
const NamedValueSet& props = scope->getProperties();
DynamicObject* target = args.thisObject.getDynamicObject();
if (target == nullptr || target == scope)
{
if (const var* m = props.getVarPointer (function))
if (const var* m = getPropertyPointer (scope, function))
{
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
{
@@ -200,6 +199,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
}
}
const NamedValueSet& props = scope->getProperties();
for (int i = 0; i < props.size(); ++i)
if (DynamicObject* o = props.getValueAt (i).getDynamicObject())
if (Scope (this, root, o).findAndInvokeMethod (function, args, result))
@@ -353,7 +354,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
void assign (const Scope& s, const var& newValue) const override
{
if (var* v = s.scope->getProperties().getVarPointer (name))
if (var* v = getPropertyPointer (s.scope, name))
*v = newValue;
else
s.root->setProperty (name, newValue);
@@ -378,7 +379,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
}
if (DynamicObject* o = p.getDynamicObject())
if (var* v = o->getProperties().getVarPointer (child))
if (const var* v = getPropertyPointer (o, child))
return *v;
return var::undefined();
@@ -544,7 +545,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
{
DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); }
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / b) : var (std::numeric_limits<double>::infinity()); }
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / (double) b) : var (std::numeric_limits<double>::infinity()); }
};
struct ModuloOp : public BinaryOperator
@@ -1658,7 +1659,7 @@ JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new R
JavascriptEngine::~JavascriptEngine() {}
void JavascriptEngine::prepareTimeout() const { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
{
@@ -1714,6 +1715,11 @@ var JavascriptEngine::callFunction (Identifier function, const var::NativeFuncti
return returnVal;
}
const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept
{
return root->getProperties();
}
#if JUCE_MSVC
#pragma warning (pop)
#endif

+ 5
- 2
source/modules/juce_core/javascript/juce_Javascript.h View File

@@ -96,10 +96,13 @@ public:
*/
RelativeTime maximumExecutionTime;
/** Provides access to the set of properties of the root namespace object. */
const NamedValueSet& getRootObjectProperties() const noexcept;
private:
JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const;
const ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
};

+ 8
- 11
source/modules/juce_core/juce_core.cpp View File

@@ -71,16 +71,19 @@
#endif
#else
#if JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU
#if JUCE_LINUX || JUCE_ANDROID
#include <sys/types.h>
#include <sys/socket.h>
#if ! JUCE_HAIKU
#include <sys/errno.h>
#endif
#include <sys/errno.h>
#include <unistd.h>
#include <netinet/in.h>
#endif
#if JUCE_LINUX
#include <langinfo.h>
#include <ifaddrs.h>
#endif
#include <pwd.h>
#include <fcntl.h>
#include <netdb.h>
@@ -90,14 +93,12 @@
#include <net/if.h>
#include <sys/ioctl.h>
#if JUCE_LINUX
#if ! JUCE_ANDROID
#include <execinfo.h>
#include <langinfo.h>
#endif
#endif
#if JUCE_MAC || JUCE_IOS
#include <execinfo.h>
#include <xlocale.h>
#include <mach/mach.h>
#endif
@@ -216,10 +217,6 @@ namespace juce
#include "native/juce_android_SystemStats.cpp"
#include "native/juce_android_Threads.cpp"
//==============================================================================
#elif JUCE_HAIKU
// TODO
#endif
#include "threads/juce_ChildProcess.cpp"


+ 1
- 4
source/modules/juce_core/juce_core.h View File

@@ -129,10 +129,6 @@
#define JUCE_STRING_UTF_TYPE 8
#endif
#ifndef JUCE_USE_VFORK
#define JUCE_USE_VFORK 0
#endif
//=============================================================================
//=============================================================================
#if JUCE_MSVC
@@ -198,6 +194,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
#include "threads/juce_ScopedLock.h"
#include "threads/juce_CriticalSection.h"
#include "maths/juce_Range.h"
#include "maths/juce_NormalisableRange.h"
#include "containers/juce_ElementComparator.h"
#include "containers/juce_ArrayAllocationBase.h"
#include "containers/juce_Array.h"


+ 169
- 0
source/modules/juce_core/maths/juce_NormalisableRange.h View File

@@ -0,0 +1,169 @@
/*
==============================================================================
This file is part of the juce_core module of the JUCE library.
Copyright (c) 2013 - Raw Material Software Ltd.
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.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
------------------------------------------------------------------------------
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
using any other modules, be sure to check that you also comply with their license.
For more details, visit www.juce.com
==============================================================================
*/
#ifndef JUCE_NORMALISABLERANGE_H_INCLUDED
#define JUCE_NORMALISABLERANGE_H_INCLUDED
//==============================================================================
/**
Represents a mapping between an arbitrary range of values and a
normalised 0->1 range.
The properties of the mapping also include an optional snapping interval
and skew-factor.
@see Range
*/
template<typename ValueType>
class NormalisableRange
{
public:
/** Creates a continuous range that performs a dummy mapping. */
NormalisableRange() noexcept : start(), end (1), interval(), skew (static_cast<ValueType> (1)) {}
/** Creates a copy of another range. */
NormalisableRange (const NormalisableRange& other) noexcept
: start (other.start), end (other.end),
interval (other.interval), skew (other.skew)
{
checkInvariants();
}
/** Creates a copy of another range. */
NormalisableRange& operator= (const NormalisableRange& other) noexcept
{
start = other.start;
end = other.end;
interval = other.interval;
skew = other.skew;
checkInvariants();
return *this;
}
/** Creates a NormalisableRange with a given range, interval and skew factor. */
NormalisableRange (ValueType rangeStart,
ValueType rangeEnd,
ValueType intervalValue,
ValueType skewFactor) noexcept
: start (rangeStart), end (rangeEnd),
interval (intervalValue), skew (skewFactor)
{
checkInvariants();
}
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
NormalisableRange (ValueType rangeStart,
ValueType rangeEnd,
ValueType intervalValue) noexcept
: start (rangeStart), end (rangeEnd),
interval (intervalValue), skew (static_cast<ValueType> (1))
{
checkInvariants();
}
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
NormalisableRange (ValueType rangeStart,
ValueType rangeEnd) noexcept
: start (rangeStart), end (rangeEnd),
interval(), skew (static_cast<ValueType> (1))
{
checkInvariants();
}
/** Uses the properties of this mapping to convert a non-normalised value to
its 0->1 representation.
*/
ValueType convertTo0to1 (ValueType v) const noexcept
{
ValueType proportion = (v - start) / (end - start);
if (skew != static_cast<ValueType> (1))
proportion = pow (proportion, skew);
return proportion;
}
/** Uses the properties of this mapping to convert a normalised 0->1 value to
its full-range representation.
*/
ValueType convertFrom0to1 (ValueType proportion) const noexcept
{
if (skew != static_cast<ValueType> (1) && proportion > ValueType())
proportion = exp (log (proportion) / skew);
return start + (end - start) * proportion;
}
/** Takes a non-normalised value and snaps it based on the interval property of
this NormalisedRange. */
ValueType snapToLegalValue (ValueType v) const noexcept
{
if (interval > ValueType())
v = start + interval * std::floor ((v - start) / interval + static_cast<ValueType> (0.5));
if (v <= start || end <= start)
return start;
if (v >= end)
return end;
return v;
}
/** The start of the non-normalised range. */
ValueType start;
/** The end of the non-normalised range. */
ValueType end;
/** The snapping interval that should be used (in non-normalised value). Use 0 for a continuous range. */
ValueType interval;
/** An optional skew factor that alters the way values are distribute across the range.
The skew factor lets you skew the mapping logarithmically so that larger or smaller
values are given a larger proportion of the avilable space.
A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
of the range will fill more of the slider's length; if the factor is > 1.0, the upper
end of the range will be expanded.
*/
ValueType skew;
private:
void checkInvariants() const
{
jassert (end > start);
jassert (interval >= ValueType());
jassert (skew > ValueType());
}
};
#endif // JUCE_NORMALISABLERANGE_H_INCLUDED

+ 3
- 3
source/modules/juce_core/memory/juce_MemoryBlock.cpp View File

@@ -88,14 +88,14 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast <HeapBlock<char>&&> (other.data)),
: data (static_cast<HeapBlock<char>&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast <HeapBlock<char>&&> (other.data);
data = static_cast<HeapBlock<char>&&> (other.data);
size = other.size;
return *this;
}
@@ -346,7 +346,7 @@ void MemoryBlock::loadFromHexString (StringRef hex)
if (c == 0)
{
setSize (static_cast <size_t> (dest - data));
setSize (static_cast<size_t> (dest - data));
return;
}
}


+ 4
- 4
source/modules/juce_core/memory/juce_ScopedPointer.h View File

@@ -182,11 +182,11 @@ public:
/** Swaps this object with that of another ScopedPointer.
The two objects simply exchange their pointers.
*/
void swapWith (ScopedPointer <ObjectType>& other) noexcept
void swapWith (ScopedPointer<ObjectType>& other) noexcept
{
// Two ScopedPointers should never be able to refer to the same object - if
// this happens, you must have done something dodgy!
jassert (object != other.object || this == other.getAddress());
jassert (object != other.object || this == other.getAddress() || object == nullptr);
std::swap (object, other.object);
}
@@ -231,7 +231,7 @@ private:
template <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
{
return static_cast <ObjectType*> (pointer1) == pointer2;
return static_cast<ObjectType*> (pointer1) == pointer2;
}
/** Compares a ScopedPointer with another pointer.
@@ -240,7 +240,7 @@ bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const po
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
{
return static_cast <ObjectType*> (pointer1) != pointer2;
return static_cast<ObjectType*> (pointer1) != pointer2;
}
//==============================================================================


+ 0
- 27
source/modules/juce_core/native/juce_BasicNativeHeaders.h View File

@@ -212,33 +212,6 @@
#include <dirent.h>
#include <fnmatch.h>
#include <sys/wait.h>
//==============================================================================
#elif JUCE_HAIKU
#include <sched.h>
#include <pthread.h>
#include <sys/time.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fnmatch.h>
#include <utime.h>
#include <pwd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <sys/file.h>
#include <signal.h>
#include <stddef.h>
#endif
// Need to clear various moronic redefinitions made by system headers..


+ 19
- 18
source/modules/juce_core/native/juce_linux_Network.cpp View File

@@ -31,26 +31,26 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
struct ifaddrs* addrs = nullptr;
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
if (getifaddrs (&addrs) != -1)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next)
{
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
struct ifreq ifr;
strcpy (ifr.ifr_name, i->ifa_name);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
{
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
}
freeifaddrs (addrs);
}
close (s);
@@ -263,7 +263,7 @@ private:
}
}
String responseHeader (readResponse (socketHandle, timeOutTime));
String responseHeader (readResponse (timeOutTime));
position = 0;
if (responseHeader.isNotEmpty())
@@ -302,7 +302,7 @@ private:
}
//==============================================================================
String readResponse (const int socketHandle, const uint32 timeOutTime)
String readResponse (const uint32 timeOutTime)
{
int numConsecutiveLFs = 0;
MemoryOutputStream buffer;
@@ -338,7 +338,8 @@ private:
dest << "\r\n" << key << ' ' << value;
}
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
static void writeHost (MemoryOutputStream& dest, const bool isPost,
const String& path, const String& host, int /*port*/)
{
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
}


+ 21
- 30
source/modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -142,7 +142,7 @@ void JUCE_CALLTYPE Thread::sleep (int millisecs)
void JUCE_CALLTYPE Process::terminate()
{
#if JUCE_ANDROID || JUCE_HAIKU
#if JUCE_ANDROID
_exit (EXIT_FAILURE);
#else
std::_Exit (EXIT_FAILURE);
@@ -203,10 +203,6 @@ namespace
#define JUCE_STAT stat
#endif
#if JUCE_HAIKU
#define statfs statvfs
#endif
bool juce_stat (const String& fileName, juce_statStruct& info)
{
return fileName.isNotEmpty()
@@ -227,6 +223,12 @@ namespace
return statfs (f.getFullPathName().toUTF8(), &result) == 0;
}
#if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; }
#else
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; }
#endif
void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
@@ -236,9 +238,9 @@ namespace
const bool statOk = juce_stat (path, info);
if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
if (fileSize != nullptr) *fileSize = statOk ? info.st_size : 0;
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
if (creationTime != nullptr) *creationTime = Time (statOk ? (int64) info.st_ctime * 1000 : 0);
if (fileSize != nullptr) *fileSize = statOk ? (int64) info.st_size : 0;
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
if (creationTime != nullptr) *creationTime = Time (statOk ? getCreationTime (info) * 1000 : 0);
}
if (isReadOnly != nullptr)
@@ -546,11 +548,7 @@ void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
if (m != MAP_FAILED)
{
address = m;
#if JUCE_HAIKU
posix_madvise (m, (size_t) range.getLength(), POSIX_MADV_SEQUENTIAL);
#else
madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL);
#endif
madvise (m, (size_t) range.getLength(), MADV_SEQUENTIAL);
}
else
{
@@ -671,11 +669,8 @@ int File::getVolumeSerialNumber() const
return result;
}
#if JUCE_HAIKU
#undef statvfs
#endif
//==============================================================================
#if ! JUCE_IOS
void juce_runSystemCommand (const String&);
void juce_runSystemCommand (const String& command)
{
@@ -696,7 +691,7 @@ String juce_getOutputFromCommand (const String& command)
tempFile.deleteFile();
return result;
}
#endif
//==============================================================================
#if JUCE_IOS
@@ -1012,15 +1007,15 @@ public:
int pipeHandles[2] = { 0 };
Array<char*> argv;
for (int i = 0; i < arguments.size(); ++i)
if (arguments[i].isNotEmpty())
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
argv.add (nullptr);
if (pipe (pipeHandles) == 0)
{
Array<char*> argv;
for (int i = 0; i < arguments.size(); ++i)
if (arguments[i].isNotEmpty())
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
argv.add (nullptr);
#if JUCE_USE_VFORK
const pid_t result = vfork();
#else
@@ -1050,6 +1045,7 @@ public:
close (pipeHandles[1]);
#endif
execvp (argv[0], argv.getRawDataPointer());
exit (-1);
}
@@ -1120,11 +1116,6 @@ public:
return 0;
}
int getPID() const noexcept
{
return childPID;
}
int childPID;
private:


+ 33
- 13
source/modules/juce_core/native/juce_win32_Network.cpp View File

@@ -45,13 +45,14 @@ public:
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (! isError())
for (int maxRedirects = 10; --maxRedirects >= 0;)
{
if (responseHeaders != nullptr)
createConnection (progressCallback, progressCallbackContext);
if (! isError())
{
DWORD bufferSizeBytes = 4096;
StringPairArray headers (false);
for (;;)
{
@@ -65,11 +66,10 @@ public:
for (int i = 0; i < headersArray.size(); ++i)
{
const String& header = headersArray[i];
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String value (header.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
const String previousValue (headers[key]);
headers.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
break;
@@ -77,14 +77,34 @@ public:
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break;
bufferSizeBytes += 4096;
}
}
DWORD status = 0;
DWORD statusSize = sizeof (status);
DWORD status = 0;
DWORD statusSize = sizeof (status);
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
{
statusCode = (int) status;
if (status == 301 || status == 302 || status == 303 || status == 307)
{
const String newLocation (headers["Location"]);
if (newLocation.isNotEmpty() && newLocation != address)
{
address = newLocation;
continue;
}
}
}
if (responseHeaders != nullptr)
responseHeaders->addArray (headers);
}
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
statusCode = (int) status;
break;
}
}


+ 0
- 5
source/modules/juce_core/native/juce_win32_Threads.cpp View File

@@ -534,11 +534,6 @@ public:
return (uint32) exitCode;
}
int getPID() const noexcept
{
return 0;
}
bool ok;
private:


+ 10
- 2
source/modules/juce_core/network/juce_Socket.cpp View File

@@ -263,6 +263,12 @@ namespace SocketHelpers
return true;
}
static void makeReusable (int handle) noexcept
{
const int reuse = 1;
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
}
}
//==============================================================================
@@ -418,8 +424,9 @@ bool StreamingSocket::createListener (const int newPortNumber, const String& loc
if (handle < 0)
return false;
const int reuse = 1;
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
#if ! JUCE_WINDOWS // on windows, adding this option produces behaviour different to posix
SocketHelpers::makeReusable (handle);
#endif
if (bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) < 0
|| listen (handle, SOMAXCONN) < 0)
@@ -470,6 +477,7 @@ DatagramSocket::DatagramSocket (const int localPortNumber, const bool canBroadca
SocketHelpers::initSockets();
handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
SocketHelpers::makeReusable (handle);
bindToPort (localPortNumber);
}


+ 5
- 4
source/modules/juce_core/network/juce_URL.cpp View File

@@ -179,6 +179,11 @@ String URL::toString (const bool includeGetParameters) const
return url;
}
bool URL::isEmpty() const noexcept
{
return url.isEmpty();
}
bool URL::isWellFormed() const
{
//xxx TODO
@@ -342,7 +347,6 @@ InputStream* URL::createInputStream (const bool usePostCommand,
if (! headers.endsWithChar ('\n'))
headers << "\r\n";
#if ! JUCE_HAIKU
ScopedPointer<WebInputStream> wi (new WebInputStream (toString (! usePostCommand),
usePostCommand, headersAndPostData,
progressCallback, progressCallbackContext,
@@ -352,9 +356,6 @@ InputStream* URL::createInputStream (const bool usePostCommand,
*statusCode = wi->statusCode;
return wi->isError() ? nullptr : wi.release();
#else
return nullptr; // TODO
#endif
}
//==============================================================================


+ 3
- 0
source/modules/juce_core/network/juce_URL.h View File

@@ -76,6 +76,9 @@ public:
*/
String toString (bool includeGetParameters) const;
/** Returns true if the URL is an empty string. */
bool isEmpty() const noexcept;
/** True if it seems to be valid. */
bool isWellFormed() const;


+ 1
- 1
source/modules/juce_core/streams/juce_MemoryOutputStream.cpp View File

@@ -182,7 +182,7 @@ int64 MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNu
if (availableData > 0)
{
if (maxNumBytesToWrite > availableData)
if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0)
maxNumBytesToWrite = availableData;
if (blockToUse != nullptr)


+ 53
- 7
source/modules/juce_core/system/juce_PlatformDefs.h View File

@@ -94,20 +94,34 @@
#define JUCE_ANALYZER_NORETURN
#endif
//==============================================================================
#if JUCE_MSVC && ! DOXYGEN
#define MACRO_WITH_FORCED_SEMICOLON(x) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { x } while (false) \
__pragma(warning(pop))
#else
/** This is the good old C++ trick for creating a macro that forces the user to put
a semicolon after it when they use it.
*/
#define MACRO_WITH_FORCED_SEMICOLON(x) do { x } while (false)
#endif
//==============================================================================
#if JUCE_DEBUG || DOXYGEN
/** Writes a string to the standard error stream.
This is only compiled in a debug build.
@see Logger::outputDebugString
*/
#define DBG(dbgtext) { juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf); }
#define DBG(dbgtext) MACRO_WITH_FORCED_SEMICOLON (juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf);)
//==============================================================================
/** This will always cause an assertion failure.
It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
@see jassert
*/
#define jassertfalse { juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN }
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN)
//==============================================================================
/** Platform-independent assertion macro.
@@ -117,19 +131,19 @@
correct behaviour of your program!
@see jassertfalse
*/
#define jassert(expression) { if (! (expression)) jassertfalse; }
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
//==============================================================================
// If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(dbgtext)
#define jassertfalse { juce_LogCurrentAssertion }
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion)
#if JUCE_LOG_ASSERTIONS
#define jassert(expression) { if (! (expression)) jassertfalse; }
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
#define jassert(a) {}
#define jassert(a) MACRO_WITH_FORCED_SEMICOLON ( ; )
#endif
#endif
@@ -139,7 +153,7 @@
namespace juce
{
template <bool b> struct JuceStaticAssert;
template <> struct JuceStaticAssert <true> { static void dummy() {} };
template <> struct JuceStaticAssert<true> { static void dummy() {} };
}
#endif
@@ -211,6 +225,26 @@ namespace juce
#define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item)
//==============================================================================
#if JUCE_MSVC && ! defined (DOXYGEN)
#define JUCE_WARNING_HELPER(file, line, mess) message(file "(" JUCE_STRINGIFY (line) ") : Warning: " #mess)
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message));
#else
#ifndef DOXYGEN
#define JUCE_WARNING_HELPER(mess) message(#mess)
#endif
/** This macro allows you to emit a custom compiler warning message.
Very handy for marking bits of code as "to-do" items, or for shaming
code written by your co-workers in a way that's hard to ignore.
GCC and Clang provide the \#warning directive, but MSVC doesn't, so this macro
is a cross-compiler way to get the same functionality as \#warning.
*/
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message)));
#endif
//==============================================================================
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
@@ -317,6 +351,10 @@ namespace juce
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_DELETED_FUNCTION)
#define JUCE_DELETED_FUNCTION = delete
#endif
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && ! defined (JUCE_COMPILER_SUPPORTS_LAMBDAS)
#define JUCE_COMPILER_SUPPORTS_LAMBDAS 1
#endif
#endif
#if JUCE_CLANG && defined (__has_feature)
@@ -336,6 +374,13 @@ namespace juce
#define JUCE_DELETED_FUNCTION = delete
#endif
#if __has_feature (cxx_lambdas) \
&& ((JUCE_MAC && defined (MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8) \
|| (JUCE_IOS && defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0) \
|| ! (JUCE_MAC || JUCE_IOS))
#define JUCE_COMPILER_SUPPORTS_LAMBDAS 1
#endif
#ifndef JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#endif
@@ -352,6 +397,7 @@ namespace juce
#if defined (_MSC_VER) && _MSC_VER >= 1700
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#define JUCE_COMPILER_SUPPORTS_LAMBDAS 1
#endif
#ifndef JUCE_DELETED_FUNCTION


+ 1
- 0
source/modules/juce_core/system/juce_StandardHeader.h View File

@@ -72,6 +72,7 @@
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#if JUCE_USE_MSVC_INTRINSICS
#include <intrin.h>


+ 1
- 1
source/modules/juce_core/system/juce_SystemStats.cpp View File

@@ -97,7 +97,7 @@ String SystemStats::getStackBacktrace()
{
String result;
#if JUCE_ANDROID || JUCE_MINGW || JUCE_HAIKU
#if JUCE_ANDROID || JUCE_MINGW
jassertfalse; // sorry, not implemented yet!
#elif JUCE_WINDOWS


+ 2
- 4
source/modules/juce_core/system/juce_TargetPlatform.h View File

@@ -51,8 +51,6 @@
#define JUCE_ANDROID 1
#elif defined (LINUX) || defined (__linux__)
#define JUCE_LINUX 1
#elif defined (__HAIKU__)
#define JUCE_HAIKU 1
#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__)
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
#define Component CarbonDummyCompName
@@ -142,7 +140,7 @@
#endif
//==============================================================================
#if JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU
#if JUCE_LINUX || JUCE_ANDROID
#ifdef _DEBUG
#define JUCE_DEBUG 1
@@ -157,7 +155,7 @@
#define JUCE_BIG_ENDIAN 1
#endif
#if defined (__LP64__) || defined (_LP64)
#if defined (__LP64__) || defined (_LP64) || defined (__arm64__)
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1


+ 3
- 3
source/modules/juce_core/text/juce_String.h View File

@@ -1204,16 +1204,16 @@ public:
//==============================================================================
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** MAC ONLY - Creates a String from an OSX CFString. */
/** OSX ONLY - Creates a String from an OSX CFString. */
static String fromCFString (CFStringRef cfString);
/** MAC ONLY - Converts this string to a CFString.
/** OSX ONLY - Converts this string to a CFString.
Remember that you must use CFRelease() to free the returned string when you're
finished with it.
*/
CFStringRef toCFString() const;
/** MAC ONLY - Returns a copy of this string in which any decomposed unicode characters have
/** OSX ONLY - Returns a copy of this string in which any decomposed unicode characters have
been converted to their precomposed equivalents. */
String convertToPrecomposedUnicode() const;
#endif


+ 0
- 5
source/modules/juce_core/threads/juce_ChildProcess.cpp View File

@@ -81,11 +81,6 @@ String ChildProcess::readAllProcessOutput()
return result.toString();
}
uint32 ChildProcess::getPID() const noexcept
{
return activeProcess != nullptr ? activeProcess->getPID() : 0;
}
//==============================================================================
#if JUCE_UNIT_TESTS


+ 0
- 2
source/modules/juce_core/threads/juce_ChildProcess.h View File

@@ -106,8 +106,6 @@ public:
*/
bool kill();
uint32 getPID() const noexcept;
private:
//==============================================================================
class ActiveProcess;


+ 1
- 1
source/modules/juce_core/xml/juce_XmlElement.cpp View File

@@ -53,7 +53,7 @@ static void sanityCheckTagName (const String& tag)
(void) tag;
// the tag name mustn't be empty, or it'll look like a text element!
jassert (tag.containsNonWhitespaceChars())
jassert (tag.containsNonWhitespaceChars());
// The tag can't contain spaces or other characters that would create invalid XML!
jassert (! tag.containsAnyOf (" <>/&(){}"));


+ 1
- 1
source/modules/juce_data_structures/app_properties/juce_PropertiesFile.cpp View File

@@ -82,7 +82,7 @@ File PropertiesFile::Options::getDefaultFile() const
if (folderName.isNotEmpty())
dir = dir.getChildFile (folderName);
#elif JUCE_LINUX || JUCE_ANDROID || JUCE_HAIKU
#elif JUCE_LINUX || JUCE_ANDROID
const File dir (File (commonToAllUsers ? "/var" : "~")
.getChildFile (folderName.isNotEmpty() ? folderName
: ("." + applicationName)));


+ 33
- 15
source/modules/juce_data_structures/undomanager/juce_UndoManager.cpp View File

@@ -29,10 +29,6 @@ struct UndoManager::ActionSet
time (Time::getCurrentTime())
{}
OwnedArray <UndoableAction> actions;
String name;
Time time;
bool perform() const
{
for (int i = 0; i < actions.size(); ++i)
@@ -60,6 +56,10 @@ struct UndoManager::ActionSet
return total;
}
OwnedArray<UndoableAction> actions;
String name;
Time time;
};
//==============================================================================
@@ -101,6 +101,19 @@ void UndoManager::setMaxNumberOfStoredUnits (const int maxNumberOfUnitsToKeep,
//==============================================================================
bool UndoManager::perform (UndoableAction* const newAction, const String& actionName)
{
if (perform (newAction))
{
if (actionName.isNotEmpty())
setCurrentTransactionName (actionName);
return true;
}
return false;
}
bool UndoManager::perform (UndoableAction* const newAction)
{
if (newAction != nullptr)
{
@@ -113,9 +126,6 @@ bool UndoManager::perform (UndoableAction* const newAction, const String& action
return false;
}
if (actionName.isNotEmpty())
currentTransactionName = actionName;
if (action->perform())
{
ActionSet* actionSet = getCurrentSet();
@@ -134,7 +144,7 @@ bool UndoManager::perform (UndoableAction* const newAction, const String& action
}
else
{
actionSet = new ActionSet (currentTransactionName);
actionSet = new ActionSet (newTransactionName);
transactions.insert (nextIndex, actionSet);
++nextIndex;
}
@@ -174,23 +184,31 @@ void UndoManager::clearFutureTransactions()
}
}
void UndoManager::beginNewTransaction (const String& actionName)
void UndoManager::beginNewTransaction() noexcept
{
beginNewTransaction (String());
}
void UndoManager::beginNewTransaction (const String& actionName) noexcept
{
newTransaction = true;
currentTransactionName = actionName;
newTransactionName = actionName;
}
void UndoManager::setCurrentTransactionName (const String& newName)
void UndoManager::setCurrentTransactionName (const String& newName) noexcept
{
currentTransactionName = newName;
if (newTransaction)
newTransactionName = newName;
else if (ActionSet* action = getCurrentSet())
action->name = newName;
}
//==============================================================================
UndoManager::ActionSet* UndoManager::getCurrentSet() const noexcept { return transactions [nextIndex - 1]; }
UndoManager::ActionSet* UndoManager::getNextSet() const noexcept { return transactions [nextIndex]; }
bool UndoManager::canUndo() const { return getCurrentSet() != nullptr; }
bool UndoManager::canRedo() const { return getNextSet() != nullptr; }
bool UndoManager::canUndo() const noexcept { return getCurrentSet() != nullptr; }
bool UndoManager::canRedo() const noexcept { return getNextSet() != nullptr; }
bool UndoManager::undo()
{
@@ -267,7 +285,7 @@ bool UndoManager::undoCurrentTransactionOnly()
return newTransaction ? false : undo();
}
void UndoManager::getActionsInCurrentTransaction (Array <const UndoableAction*>& actionsFound) const
void UndoManager::getActionsInCurrentTransaction (Array<const UndoableAction*>& actionsFound) const
{
if (! newTransaction)
if (const ActionSet* const s = getCurrentSet())


+ 28
- 19
source/modules/juce_data_structures/undomanager/juce_UndoManager.h View File

@@ -98,16 +98,32 @@ public:
//==============================================================================
/** Performs an action and adds it to the undo history list.
@param action the action to perform - this will be deleted by the UndoManager
when no longer needed
@param action the action to perform - this object will be deleted by
the UndoManager when no longer needed
@returns true if the command succeeds - see UndoableAction::perform
@see beginNewTransaction
*/
bool perform (UndoableAction* action);
/** Performs an action and also gives it a name.
@param action the action to perform - this object will be deleted by
the UndoManager when no longer needed
@param actionName if this string is non-empty, the current transaction will be
given this name; if it's empty, the current transaction name will
be left unchanged. See setCurrentTransactionName()
@returns true if the command succeeds - see UndoableAction::perform
@see beginNewTransaction
*/
bool perform (UndoableAction* action,
const String& actionName = String());
bool perform (UndoableAction* action, const String& actionName);
/** Starts a new group of actions that together will be treated as a single transaction.
All actions that are passed to the perform() method between calls to this
method are grouped together and undone/redone together by a single call to
undo() or redo().
*/
void beginNewTransaction() noexcept;
/** Starts a new group of actions that together will be treated as a single transaction.
@@ -118,7 +134,7 @@ public:
@param actionName a description of the transaction that is about to be
performed
*/
void beginNewTransaction (const String& actionName = String());
void beginNewTransaction (const String& actionName) noexcept;
/** Changes the name stored for the current transaction.
@@ -126,19 +142,15 @@ public:
called, but this can be used to change that name without starting a new
transaction.
*/
void setCurrentTransactionName (const String& newName);
void setCurrentTransactionName (const String& newName) noexcept;
//==============================================================================
/** Returns true if there's at least one action in the list to undo.
@see getUndoDescription, undo, canRedo
*/
bool canUndo() const;
/** Returns the description of the transaction that would be next to get undone.
The description returned is the one that was passed into beginNewTransaction
before the set of actions was performed.
bool canUndo() const noexcept;
/** Returns the name of the transaction that will be rolled-back when undo() is called.
@see undo
*/
String getUndoDescription() const;
@@ -172,7 +184,7 @@ public:
The first item in the list is the earliest action performed.
*/
void getActionsInCurrentTransaction (Array <const UndoableAction*>& actionsFound) const;
void getActionsInCurrentTransaction (Array<const UndoableAction*>& actionsFound) const;
/** Returns the number of UndoableAction objects that have been performed during the
transaction that is currently open.
@@ -194,12 +206,9 @@ public:
/** Returns true if there's at least one action in the list to redo.
@see getRedoDescription, redo, canUndo
*/
bool canRedo() const;
/** Returns the description of the transaction that would be next to get redone.
The description returned is the one that was passed into beginNewTransaction
before the set of actions was performed.
bool canRedo() const noexcept;
/** Returns the name of the transaction that will be redone when redo() is called.
@see redo
*/
String getRedoDescription() const;
@@ -216,7 +225,7 @@ private:
struct ActionSet;
friend struct ContainerDeletePolicy<ActionSet>;
OwnedArray<ActionSet> transactions;
String currentTransactionName;
String newTransactionName;
int totalUnitsStored, maxNumUnitsToKeep, minimumTransactionsToKeep, nextIndex;
bool newTransaction, reentrancyCheck;
ActionSet* getCurrentSet() const noexcept;


+ 4
- 1
source/modules/juce_data_structures/values/juce_ValueTree.h View File

@@ -318,7 +318,10 @@ public:
/** Creates an XmlElement that holds a complete image of this node and all its children.
If this node is invalid, this may return nullptr. Otherwise, the XML that is produced can
be used to recreate a similar node by calling fromXml()
be used to recreate a similar node by calling fromXml().
The caller must delete the object that is returned.
@see fromXml
*/
XmlElement* createXml() const;


+ 19
- 0
source/modules/juce_events/messages/juce_MessageManager.cpp View File

@@ -130,6 +130,25 @@ void MessageManager::stopDispatchLoop()
#endif
//==============================================================================
#if JUCE_COMPILER_SUPPORTS_LAMBDAS
struct AsyncFunction : private MessageManager::MessageBase
{
AsyncFunction (std::function<void(void)> f) : fn (f) { post(); }
private:
std::function<void(void)> fn;
void messageCallback() override { fn(); }
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncFunction)
};
void MessageManager::callAsync (std::function<void(void)> f)
{
new AsyncFunction (f);
}
#endif
//==============================================================================
class AsyncFunctionCallback : public MessageManager::MessageBase
{


+ 7
- 0
source/modules/juce_events/messages/juce_MessageManager.h View File

@@ -91,6 +91,13 @@ public:
#endif
//==============================================================================
#if JUCE_COMPILER_SUPPORTS_LAMBDAS
/** Asynchronously invokes a function or C++11 lambda on the message thread.
Internally this uses the CallbackMessage class to invoke the callback.
*/
static void callAsync (std::function<void(void)>);
#endif
/** Calls a function using the message-thread.
This can be used by any thread to cause this function to be called-back


+ 1
- 1
source/modules/juce_events/native/juce_linux_Messaging.cpp View File

@@ -360,7 +360,7 @@ bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* cons
if (InternalMessageQueue* const queue = InternalMessageQueue::getInstanceWithoutCreating())
{
InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message);
queue->postMessage (message);
return true;
}


+ 3
- 3
source/modules/juce_graphics/contexts/juce_GraphicsContext.h View File

@@ -158,7 +158,7 @@ public:
void drawText (const String& text,
int x, int y, int width, int height,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Draws a line of text within a specified rectangle.
@@ -172,7 +172,7 @@ public:
void drawText (const String& text,
const Rectangle<int>& area,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Draws a line of text within a specified rectangle.
@@ -186,7 +186,7 @@ public:
void drawText (const String& text,
const Rectangle<float>& area,
Justification justificationType,
bool useEllipsesIfTooBig) const;
bool useEllipsesIfTooBig = true) const;
/** Tries to draw a text string inside a given space.


+ 1
- 1
source/modules/juce_graphics/contexts/juce_LowLevelGraphicsPostScriptRenderer.cpp View File

@@ -384,7 +384,7 @@ void LowLevelGraphicsPostScriptRenderer::fillPath (const Path& path, const Affin
{
// this doesn't work correctly yet - it could be improved to handle solid gradients, but
// postscript can't do semi-transparent ones.
notPossibleInPostscriptAssert // you can disable this warning by setting the WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS flag at the top of this file
notPossibleInPostscriptAssert; // you can disable this warning by setting the WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS flag at the top of this file
writeClip();
out << "gsave ";


+ 4
- 3
source/modules/juce_graphics/image_formats/juce_PNGLoader.cpp View File

@@ -488,12 +488,13 @@ bool PNGImageFormat::writeImageToStream (const Image& image, OutputStream& out)
PNG_COMPRESSION_TYPE_BASE,
PNG_FILTER_TYPE_BASE);
HeapBlock <uint8> rowData ((size_t) width * 4);
HeapBlock<uint8> rowData ((size_t) width * 4);
png_color_8 sig_bit;
sig_bit.red = 8;
sig_bit.red = 8;
sig_bit.green = 8;
sig_bit.blue = 8;
sig_bit.blue = 8;
sig_bit.gray = 0;
sig_bit.alpha = 8;
png_set_sBIT (pngWriteStruct, pngInfoStruct, &sig_bit);


+ 1
- 1
source/modules/juce_graphics/image_formats/pnglib/pngread.c View File

@@ -1026,7 +1026,7 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr,
if ((transforms & PNG_TRANSFORM_SHIFT)
&& png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
{
png_color_8p sig_bit;
png_color_8p sig_bit = 0;
png_get_sBIT(png_ptr, info_ptr, &sig_bit);
png_set_shift(png_ptr, sig_bit);


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

@@ -197,11 +197,11 @@ Image Image::getClippedImage (const Rectangle<int>& area) const
//==============================================================================
Image::Image()
Image::Image() noexcept
{
}
Image::Image (ImagePixelData* const instance)
Image::Image (ImagePixelData* const instance) noexcept
: image (instance)
{
}
@@ -216,7 +216,7 @@ Image::Image (const PixelFormat format, int width, int height, bool clearImage,
{
}
Image::Image (const Image& other)
Image::Image (const Image& other) noexcept
: image (other.image)
{
}


+ 3
- 3
source/modules/juce_graphics/images/juce_Image.h View File

@@ -67,7 +67,7 @@ public:
//==============================================================================
/** Creates a null image. */
Image();
Image() noexcept;
/** Creates an image with a specified size and format.
@@ -106,7 +106,7 @@ public:
point to the same shared image data. To make sure that an Image object has its own unique,
unshared internal data, call duplicateIfShared().
*/
Image (const Image&);
Image (const Image&) noexcept;
/** Makes this image refer to the same underlying image as another object.
@@ -408,7 +408,7 @@ public:
ImagePixelData* getPixelData() const noexcept { return image; }
/** @internal */
explicit Image (ImagePixelData*);
explicit Image (ImagePixelData*) noexcept;
private:
//==============================================================================


+ 6
- 6
source/modules/juce_gui_basics/buttons/juce_Button.cpp View File

@@ -125,11 +125,12 @@ void Button::setTooltip (const String& newTooltip)
generateTooltip = false;
}
String Button::getTooltip()
void Button::updateAutomaticTooltip (const ApplicationCommandInfo& info)
{
if (generateTooltip && commandManagerToUse != nullptr && commandID != 0)
if (generateTooltip && commandManagerToUse != nullptr)
{
String tt (commandManagerToUse->getDescriptionOfCommand (commandID));
String tt (info.description.isNotEmpty() ? info.description
: info.shortName);
Array<KeyPress> keyPresses (commandManagerToUse->getKeyMappings()->getKeyPressesAssignedToCommand (commandID));
@@ -145,10 +146,8 @@ String Button::getTooltip()
tt << key << ']';
}
return tt;
SettableTooltipClient::setTooltip (tt);
}
return SettableTooltipClient::getTooltip();
}
void Button::setConnectedEdges (const int newFlags)
@@ -542,6 +541,7 @@ void Button::applicationCommandListChangeCallback()
if (commandManagerToUse->getTargetForCommand (commandID, info) != nullptr)
{
updateAutomaticTooltip (info);
setEnabled ((info.flags & ApplicationCommandInfo::isDisabled) == 0);
setToggleState ((info.flags & ApplicationCommandInfo::isTicked) != 0, dontSendNotification);
}


+ 4
- 6
source/modules/juce_gui_basics/buttons/juce_Button.h View File

@@ -277,12 +277,6 @@ public:
*/
void setTooltip (const String& newTooltip) override;
/** Returns the tooltip set by setTooltip(), or the description corresponding to
the currently mapped command if one is enabled (see setCommandToTrigger).
*/
String getTooltip() override;
//==============================================================================
/** A combination of these flags are used by setConnectedEdges(). */
enum ConnectedEdgeFlags
@@ -349,6 +343,9 @@ public:
*/
void setState (ButtonState newState);
/** Returns the button's current over/down/up state. */
ButtonState getState() const noexcept { return buttonState; }
// This method's parameters have changed - see the new version.
JUCE_DEPRECATED (void setToggleState (bool, bool));
@@ -495,6 +492,7 @@ private:
void repeatTimerCallback();
bool keyStateChangedCallback();
void applicationCommandListChangeCallback();
void updateAutomaticTooltip (const ApplicationCommandInfo&);
ButtonState updateState();
ButtonState updateState (bool isOver, bool isDown);


+ 25
- 14
source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp View File

@@ -51,7 +51,20 @@ void ApplicationCommandManager::registerCommand (const ApplicationCommandInfo& n
// the name isn't optional!
jassert (newCommand.shortName.isNotEmpty());
if (getCommandForID (newCommand.commandID) == 0)
if (ApplicationCommandInfo* command = getMutableCommandForID (newCommand.commandID))
{
// Trying to re-register the same command ID with different parameters can often indicate a typo.
// This assertion is here because I've found it useful catching some mistakes, but it may also cause
// false alarms if you're deliberately updating some flags for a command.
jassert (newCommand.shortName == getCommandForID (newCommand.commandID)->shortName
&& newCommand.categoryName == getCommandForID (newCommand.commandID)->categoryName
&& newCommand.defaultKeypresses == getCommandForID (newCommand.commandID)->defaultKeypresses
&& (newCommand.flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor))
== (getCommandForID (newCommand.commandID)->flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor)));
*command = newCommand;
}
else
{
ApplicationCommandInfo* const newInfo = new ApplicationCommandInfo (newCommand);
newInfo->flags &= ~ApplicationCommandInfo::isTicked;
@@ -61,16 +74,6 @@ void ApplicationCommandManager::registerCommand (const ApplicationCommandInfo& n
triggerAsyncUpdate();
}
else
{
// trying to re-register the same command ID with different parameters?
jassert (newCommand.shortName == getCommandForID (newCommand.commandID)->shortName
&& (newCommand.description == getCommandForID (newCommand.commandID)->description || newCommand.description.isEmpty())
&& newCommand.categoryName == getCommandForID (newCommand.commandID)->categoryName
&& newCommand.defaultKeypresses == getCommandForID (newCommand.commandID)->defaultKeypresses
&& (newCommand.flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor))
== (getCommandForID (newCommand.commandID)->flags & (ApplicationCommandInfo::wantsKeyUpDownCallbacks | ApplicationCommandInfo::hiddenFromKeyEditor | ApplicationCommandInfo::readOnlyInKeyEditor)));
}
}
void ApplicationCommandManager::registerAllCommandsForTarget (ApplicationCommandTarget* target)
@@ -113,7 +116,7 @@ void ApplicationCommandManager::commandStatusChanged()
}
//==============================================================================
const ApplicationCommandInfo* ApplicationCommandManager::getCommandForID (const CommandID commandID) const noexcept
ApplicationCommandInfo* ApplicationCommandManager::getMutableCommandForID (CommandID commandID) const noexcept
{
for (int i = commands.size(); --i >= 0;)
if (commands.getUnchecked(i)->commandID == commandID)
@@ -122,6 +125,11 @@ const ApplicationCommandInfo* ApplicationCommandManager::getCommandForID (const
return nullptr;
}
const ApplicationCommandInfo* ApplicationCommandManager::getCommandForID (const CommandID commandID) const noexcept
{
return getMutableCommandForID (commandID);
}
String ApplicationCommandManager::getNameOfCommand (const CommandID commandID) const noexcept
{
if (const ApplicationCommandInfo* const ci = getCommandForID (commandID))
@@ -215,7 +223,10 @@ ApplicationCommandTarget* ApplicationCommandManager::getTargetForCommand (const
target = target->getTargetForCommand (commandID);
if (target != nullptr)
{
upToDateInfo.commandID = commandID;
target->getCommandInfo (commandID, upToDateInfo);
}
return target;
}
@@ -223,7 +234,7 @@ ApplicationCommandTarget* ApplicationCommandManager::getTargetForCommand (const
//==============================================================================
ApplicationCommandTarget* ApplicationCommandManager::findTargetForComponent (Component* c)
{
ApplicationCommandTarget* target = dynamic_cast <ApplicationCommandTarget*> (c);
ApplicationCommandTarget* target = dynamic_cast<ApplicationCommandTarget*> (c);
if (target == nullptr && c != nullptr)
target = c->findParentComponentOfClass<ApplicationCommandTarget>();
@@ -263,7 +274,7 @@ ApplicationCommandTarget* ApplicationCommandManager::findDefaultComponentTarget(
// component that really should get the event. And if not, the event will
// still be passed up to the top level window anyway, so let's send it to the
// content comp.
if (ResizableWindow* const resizableWindow = dynamic_cast <ResizableWindow*> (c))
if (ResizableWindow* const resizableWindow = dynamic_cast<ResizableWindow*> (c))
if (Component* const content = resizableWindow->getContentComponent())
c = content;


+ 1
- 0
source/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.h View File

@@ -308,6 +308,7 @@ private:
void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo&);
void handleAsyncUpdate() override;
void globalFocusChanged (Component*) override;
ApplicationCommandInfo* getMutableCommandForID (CommandID) const noexcept;
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// This is just here to cause a compile error in old code that hasn't been changed to use the new


+ 1
- 1
source/modules/juce_gui_basics/commands/juce_KeyPressMappingSet.cpp View File

@@ -252,7 +252,7 @@ bool KeyPressMappingSet::restoreFromXml (const XmlElement& xmlVersion)
XmlElement* KeyPressMappingSet::createXml (const bool saveDifferencesFromDefaultSet) const
{
ScopedPointer <KeyPressMappingSet> defaultSet;
ScopedPointer<KeyPressMappingSet> defaultSet;
if (saveDifferencesFromDefaultSet)
{


+ 5
- 4
source/modules/juce_gui_basics/components/juce_Component.h View File

@@ -1747,11 +1747,14 @@ public:
*/
virtual void focusLost (FocusChangeType cause);
/** Called to indicate that one of this component's children has been focused or unfocused.
/** Called to indicate a change in whether or not this component is the parent of the
currently-focused component.
Essentially this means that the return value of a call to hasKeyboardFocus (true) has
Essentially this is called when the return value of a call to hasKeyboardFocus (true) has
changed. It happens when focus moves from one of this component's children (at any depth)
to a component that isn't contained in this one, (or vice-versa).
Note that this method does NOT get called to when focus simply moves from one of its
child components to another.
@see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus
*/
@@ -1786,9 +1789,7 @@ public:
bool isMouseButtonDown() const;
/** True if the mouse is over this component, or if it's being dragged in this component.
This is a handy equivalent to (isMouseOver() || isMouseButtonDown()).
@see isMouseOver, isMouseButtonDown, isMouseButtonDownAnywhere
*/
bool isMouseOverOrDragging() const;


+ 64
- 72
source/modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -85,31 +85,13 @@ public:
newState.viewBoxW = vwh.x;
newState.viewBoxH = vwh.y;
int placementFlags = 0;
const int placementFlags = parsePlacementFlags (xml->getStringAttribute ("preserveAspectRatio").trim());
const String aspect (xml->getStringAttribute ("preserveAspectRatio"));
if (aspect.containsIgnoreCase ("none"))
{
placementFlags = RectanglePlacement::stretchToFit;
}
else
{
if (aspect.containsIgnoreCase ("slice")) placementFlags |= RectanglePlacement::fillDestination;
if (aspect.containsIgnoreCase ("xMin")) placementFlags |= RectanglePlacement::xLeft;
else if (aspect.containsIgnoreCase ("xMax")) placementFlags |= RectanglePlacement::xRight;
else placementFlags |= RectanglePlacement::xMid;
if (aspect.containsIgnoreCase ("yMin")) placementFlags |= RectanglePlacement::yTop;
else if (aspect.containsIgnoreCase ("yMax")) placementFlags |= RectanglePlacement::yBottom;
else placementFlags |= RectanglePlacement::yMid;
}
newState.transform = RectanglePlacement (placementFlags)
.getTransformToFit (Rectangle<float> (viewboxXY.x, viewboxXY.y, vwh.x, vwh.y),
Rectangle<float> (newState.width, newState.height))
.followedBy (newState.transform);
if (placementFlags != 0)
newState.transform = RectanglePlacement (placementFlags)
.getTransformToFit (Rectangle<float> (viewboxXY.x, viewboxXY.y, vwh.x, vwh.y),
Rectangle<float> (newState.width, newState.height))
.followedBy (newState.transform);
}
}
else
@@ -560,24 +542,12 @@ private:
path.applyTransform (transform);
dp->setPath (path);
Path::Iterator iter (path);
bool containsClosedSubPath = false;
while (iter.next())
{
if (iter.elementType == Path::Iterator::closePath)
{
containsClosedSubPath = true;
break;
}
}
dp->setFill (getPathFillType (path,
getStyleAttribute (xml, "fill"),
getStyleAttribute (xml, "fill-opacity"),
getStyleAttribute (xml, "opacity"),
containsClosedSubPath ? Colours::black
: Colours::transparentBlack));
pathContainsClosedSubPath (path) ? Colours::black
: Colours::transparentBlack));
const String strokeType (getStyleAttribute (xml, "stroke"));
@@ -594,6 +564,15 @@ private:
return dp;
}
static bool pathContainsClosedSubPath (const Path& path) noexcept
{
for (Path::Iterator iter (path); iter.next();)
if (iter.elementType == Path::Iterator::closePath)
return true;
return false;
}
struct SetGradientStopsOp
{
const SVGState* state;
@@ -796,44 +775,41 @@ private:
return parseColour (fill, i, defaultColour).withMultipliedAlpha (opacity);
}
PathStrokeType getStrokeFor (const XmlPath& xml) const
static PathStrokeType::JointStyle getJointStyle (const String& join) noexcept
{
const String strokeWidth (getStyleAttribute (xml, "stroke-width"));
const String cap (getStyleAttribute (xml, "stroke-linecap"));
const String join (getStyleAttribute (xml, "stroke-linejoin"));
if (join.equalsIgnoreCase ("round")) return PathStrokeType::curved;
if (join.equalsIgnoreCase ("bevel")) return PathStrokeType::beveled;
//const String mitreLimit (getStyleAttribute (xml, "stroke-miterlimit"));
//const String dashArray (getStyleAttribute (xml, "stroke-dasharray"));
//const String dashOffset (getStyleAttribute (xml, "stroke-dashoffset"));
PathStrokeType::JointStyle joinStyle = PathStrokeType::mitered;
PathStrokeType::EndCapStyle capStyle = PathStrokeType::butt;
return PathStrokeType::mitered;
}
if (join.equalsIgnoreCase ("round"))
joinStyle = PathStrokeType::curved;
else if (join.equalsIgnoreCase ("bevel"))
joinStyle = PathStrokeType::beveled;
static PathStrokeType::EndCapStyle getEndCapStyle (const String& cap) noexcept
{
if (cap.equalsIgnoreCase ("round")) return PathStrokeType::rounded;
if (cap.equalsIgnoreCase ("square")) return PathStrokeType::square;
if (cap.equalsIgnoreCase ("round"))
capStyle = PathStrokeType::rounded;
else if (cap.equalsIgnoreCase ("square"))
capStyle = PathStrokeType::square;
return PathStrokeType::butt;
}
float ox = 0.0f, oy = 0.0f;
float x = getCoordLength (strokeWidth, viewBoxW), y = 0.0f;
transform.transformPoints (ox, oy, x, y);
float getStrokeWidth (const String& strokeWidth) const noexcept
{
return transform.getScaleFactor() * getCoordLength (strokeWidth, viewBoxW);
}
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypot (x - ox, y - oy) : 1.0f,
joinStyle, capStyle);
PathStrokeType getStrokeFor (const XmlPath& xml) const
{
return PathStrokeType (getStrokeWidth (getStyleAttribute (xml, "stroke-width", "1")),
getJointStyle (getStyleAttribute (xml, "stroke-linejoin")),
getEndCapStyle (getStyleAttribute (xml, "stroke-linecap")));
}
//==============================================================================
Drawable* parseText (const XmlPath& xml)
{
Array <float> xCoords, yCoords, dxCoords, dyCoords;
Array<float> xCoords, yCoords, dxCoords, dyCoords;
getCoordList (xCoords, getInheritedAttribute (xml, "x"), true, true);
getCoordList (yCoords, getInheritedAttribute (xml, "y"), true, false);
getCoordList (xCoords, getInheritedAttribute (xml, "x"), true, true);
getCoordList (yCoords, getInheritedAttribute (xml, "y"), true, false);
getCoordList (dxCoords, getInheritedAttribute (xml, "dx"), true, true);
getCoordList (dyCoords, getInheritedAttribute (xml, "dy"), true, false);
@@ -898,7 +874,7 @@ private:
return false;
}
float getCoordLength (const String& s, const float sizeForProportions) const
float getCoordLength (const String& s, const float sizeForProportions) const noexcept
{
float n = s.getFloatValue();
const int len = s.length();
@@ -920,13 +896,12 @@ private:
return n;
}
float getCoordLength (const XmlPath& xml, const char* attName, const float sizeForProportions) const
float getCoordLength (const XmlPath& xml, const char* attName, const float sizeForProportions) const noexcept
{
return getCoordLength (xml->getStringAttribute (attName), sizeForProportions);
}
void getCoordList (Array <float>& coords, const String& list,
const bool allowUnits, const bool isX) const
void getCoordList (Array<float>& coords, const String& list, bool allowUnits, const bool isX) const
{
String::CharPointerType text (list.getCharPointer());
float value;
@@ -960,7 +935,7 @@ private:
return source;
}
String getStyleAttribute (const XmlPath& xml, const String& attributeName,
String getStyleAttribute (const XmlPath& xml, StringRef attributeName,
const String& defaultValue = String()) const
{
if (xml->hasAttribute (attributeName))
@@ -1000,7 +975,7 @@ private:
return defaultValue;
}
String getInheritedAttribute (const XmlPath& xml, const String& attributeName) const
String getInheritedAttribute (const XmlPath& xml, StringRef attributeName) const
{
if (xml->hasAttribute (attributeName))
return xml->getStringAttribute (attributeName);
@@ -1011,13 +986,30 @@ private:
return String();
}
static int parsePlacementFlags (const String& align) noexcept
{
if (align.isEmpty())
return 0;
if (align.containsIgnoreCase ("none"))
return RectanglePlacement::stretchToFit;
return (align.containsIgnoreCase ("slice") ? RectanglePlacement::fillDestination : 0)
| (align.containsIgnoreCase ("xMin") ? RectanglePlacement::xLeft
: (align.containsIgnoreCase ("xMax") ? RectanglePlacement::xRight
: RectanglePlacement::xMid))
| (align.containsIgnoreCase ("yMin") ? RectanglePlacement::yTop
: (align.containsIgnoreCase ("yMax") ? RectanglePlacement::yBottom
: RectanglePlacement::yMid));
}
//==============================================================================
static bool isIdentifierChar (const juce_wchar c)
{
return CharacterFunctions::isLetter (c) || c == '-';
}
static String getAttributeFromStyleList (const String& list, const String& attributeName, const String& defaultValue)
static String getAttributeFromStyleList (const String& list, StringRef attributeName, const String& defaultValue)
{
int i = 0;
@@ -1221,7 +1213,7 @@ private:
const bool largeArc, const bool sweep,
double& rx, double& ry,
double& centreX, double& centreY,
double& startAngle, double& deltaAngle)
double& startAngle, double& deltaAngle) noexcept
{
const double midX = (x1 - x2) * 0.5;
const double midY = (y1 - y2) * 0.5;


+ 1
- 1
source/modules/juce_gui_basics/layout/juce_ComponentAnimator.cpp View File

@@ -217,7 +217,7 @@ void ComponentAnimator::animateComponent (Component* const component,
const double endSpeed)
{
// the speeds must be 0 or greater!
jassert (startSpeed >= 0 && endSpeed >= 0)
jassert (startSpeed >= 0 && endSpeed >= 0);
if (component != nullptr)
{


+ 13
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.cpp View File

@@ -111,6 +111,9 @@ LookAndFeel_V2::LookAndFeel_V2()
TextPropertyComponent::textColourId, 0xff000000,
TextPropertyComponent::outlineColourId, standardOutlineColour,
BooleanPropertyComponent::backgroundColourId, 0xffffffff,
BooleanPropertyComponent::outlineColourId, standardOutlineColour,
ListBox::backgroundColourId, 0xffffffff,
ListBox::outlineColourId, standardOutlineColour,
ListBox::textColourId, 0xff000000,
@@ -1001,6 +1004,16 @@ void LookAndFeel_V2::drawPopupMenuItem (Graphics& g, const Rectangle<int>& area,
}
}
void LookAndFeel_V2::drawPopupMenuSectionHeader (Graphics& g, const Rectangle<int>& area, const String& sectionName)
{
g.setFont (getPopupMenuFont().boldened());
g.setColour (findColour (PopupMenu::headerTextColourId));
g.drawFittedText (sectionName,
area.getX() + 12, area.getY(), area.getWidth() - 16, (int) (area.getHeight() * 0.8f),
Justification::bottomLeft, 1);
}
//==============================================================================
int LookAndFeel_V2::getMenuWindowFlags()
{


+ 3
- 0
source/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V2.h View File

@@ -137,6 +137,9 @@ public:
const String& text, const String& shortcutKeyText,
const Drawable* icon, const Colour* textColour) override;
void drawPopupMenuSectionHeader (Graphics&, const Rectangle<int>& area,
const String& sectionName) override;
Font getPopupMenuFont() override;
void drawPopupMenuUpDownArrow (Graphics&, int width, int height, bool isScrollUpArrow) override;


+ 17
- 13
source/modules/juce_gui_basics/menus/juce_MenuBarComponent.cpp View File

@@ -22,7 +22,7 @@
==============================================================================
*/
MenuBarComponent::MenuBarComponent (MenuBarModel* model_)
MenuBarComponent::MenuBarComponent (MenuBarModel* m)
: model (nullptr),
itemUnderMouse (-1),
currentPopupIndex (-1),
@@ -32,7 +32,7 @@ MenuBarComponent::MenuBarComponent (MenuBarModel* model_)
setWantsKeyboardFocus (false);
setMouseClickGrabsKeyboardFocus (false);
setModel (model_);
setModel (m);
}
MenuBarComponent::~MenuBarComponent()
@@ -284,22 +284,26 @@ void MenuBarComponent::mouseMove (const MouseEvent& e)
bool MenuBarComponent::keyPressed (const KeyPress& key)
{
bool used = false;
const int numMenus = menuNames.size();
const int currentIndex = jlimit (0, menuNames.size() - 1, currentPopupIndex);
if (key.isKeyCode (KeyPress::leftKey))
if (numMenus > 0)
{
showMenu ((currentIndex + numMenus - 1) % numMenus);
used = true;
}
else if (key.isKeyCode (KeyPress::rightKey))
{
showMenu ((currentIndex + 1) % numMenus);
used = true;
const int currentIndex = jlimit (0, numMenus - 1, currentPopupIndex);
if (key.isKeyCode (KeyPress::leftKey))
{
showMenu ((currentIndex + numMenus - 1) % numMenus);
return true;
}
if (key.isKeyCode (KeyPress::rightKey))
{
showMenu ((currentIndex + 1) % numMenus);
return true;
}
}
return used;
return false;
}
void MenuBarComponent::menuBarItemsChanged (MenuBarModel* /*menuBarModel*/)


+ 4
- 5
source/modules/juce_gui_basics/menus/juce_MenuBarComponent.h View File

@@ -40,9 +40,9 @@ public:
//==============================================================================
/** Creates a menu bar.
@param model the model object to use to control this bar. You can
pass 0 into this if you like, and set the model later
using the setModel() method
@param model the model object to use to control this bar. You can
pass nullptr into this if you like, and set the model
later using the setModel() method
*/
MenuBarComponent (MenuBarModel* model);
@@ -57,8 +57,7 @@ public:
*/
void setModel (MenuBarModel* newModel);
/** Returns the current menu bar model being used.
*/
/** Returns the current menu bar model being used. */
MenuBarModel* getModel() const noexcept;
//==============================================================================


+ 6
- 8
source/modules/juce_gui_basics/menus/juce_MenuBarModel.h View File

@@ -80,8 +80,7 @@ public:
virtual ~Listener() {}
//==============================================================================
/** This callback is made when items are changed in the menu bar model.
*/
/** This callback is made when items are changed in the menu bar model. */
virtual void menuBarItemsChanged (MenuBarModel* menuBarModel) = 0;
/** This callback is made when an application command is invoked that
@@ -101,7 +100,6 @@ public:
void addListener (Listener* listenerToAdd) noexcept;
/** Removes a listener.
@see addListener
*/
void removeListener (Listener* listenerToRemove) noexcept;
@@ -130,7 +128,7 @@ public:
//==============================================================================
#if JUCE_MAC || DOXYGEN
/** MAC ONLY - Sets the model that is currently being shown as the main
/** OSX ONLY - Sets the model that is currently being shown as the main
menu bar at the top of the screen on the Mac.
You can pass 0 to stop the current model being displayed. Be careful
@@ -151,12 +149,12 @@ public:
const PopupMenu* extraAppleMenuItems = nullptr,
const String& recentItemsMenuName = String::empty);
/** MAC ONLY - Returns the menu model that is currently being shown as
/** OSX ONLY - Returns the menu model that is currently being shown as
the main menu bar.
*/
static MenuBarModel* getMacMainMenu();
/** MAC ONLY - Returns the menu that was last passed as the extraAppleMenuItems
/** OSX ONLY - Returns the menu that was last passed as the extraAppleMenuItems
argument to setMacMainMenu(), or nullptr if none was specified.
*/
static const PopupMenu* getMacExtraAppleItemsMenu();
@@ -164,7 +162,7 @@ public:
//==============================================================================
/** @internal */
void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) override;
void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&) override;
/** @internal */
void applicationCommandListChanged() override;
/** @internal */
@@ -172,7 +170,7 @@ public:
private:
ApplicationCommandManager* manager;
ListenerList <Listener> listeners;
ListenerList<Listener> listeners;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuBarModel)
};


+ 2
- 7
source/modules/juce_gui_basics/menus/juce_PopupMenu.cpp View File

@@ -740,7 +740,7 @@ public:
void ensureItemIsVisible (const int itemID, int wantedY)
{
jassert (itemID != 0)
jassert (itemID != 0);
for (int i = items.size(); --i >= 0;)
{
@@ -1216,12 +1216,7 @@ public:
void paint (Graphics& g) override
{
g.setFont (getLookAndFeel().getPopupMenuFont().boldened());
g.setColour (findColour (PopupMenu::headerTextColourId));
g.drawFittedText (getName(),
12, 0, getWidth() - 16, proportionOfHeight (0.8f),
Justification::bottomLeft, 1);
getLookAndFeel().drawPopupMenuSectionHeader (g, getLocalBounds(), getName());
}
void getIdealSize (int& idealWidth, int& idealHeight)


+ 3
- 0
source/modules/juce_gui_basics/menus/juce_PopupMenu.h View File

@@ -562,6 +562,9 @@ public:
const Drawable* icon,
const Colour* textColour) = 0;
virtual void drawPopupMenuSectionHeader (Graphics&, const Rectangle<int>& area,
const String& sectionName) = 0;
/** Returns the size and style of font to use in popup menus. */
virtual Font getPopupMenuFont() = 0;


+ 32
- 5
source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp View File

@@ -69,6 +69,8 @@ public:
if (current->isInterestedInDragSource (sourceDetails))
current->itemDragExit (sourceDetails);
}
owner.dragOperationEnded();
}
void paint (Graphics& g) override
@@ -164,14 +166,14 @@ public:
if (sourceDetails.sourceComponent == nullptr)
{
delete this;
deleteSelf();
}
else if (! isMouseButtonDownAnywhere())
{
if (mouseDragSource != nullptr)
mouseDragSource->removeMouseListener (this);
delete this;
deleteSelf();
}
}
@@ -180,7 +182,7 @@ public:
if (key == KeyPress::escapeKey)
{
dismissWithAnimation (true);
delete this;
deleteSelf();
return true;
}
@@ -215,13 +217,28 @@ private:
return dynamic_cast<DragAndDropTarget*> (currentlyOverComp.get());
}
static Component* findDesktopComponentBelow (Point<int> screenPos)
{
Desktop& desktop = Desktop::getInstance();
for (int i = desktop.getNumComponents(); --i >= 0;)
{
Component* c = desktop.getComponent(i);
if (Component* hit = c->getComponentAt (c->getLocalPoint (nullptr, screenPos)))
return hit;
}
return nullptr;
}
DragAndDropTarget* findTarget (Point<int> screenPos, Point<int>& relativePos,
Component*& resultComponent) const
{
Component* hit = getParentComponent();
if (hit == nullptr)
hit = Desktop::getInstance().findComponentAt (screenPos);
hit = findDesktopComponentBelow (screenPos);
else
hit = hit->getComponentAt (hit->getLocalPoint (nullptr, screenPos));
@@ -296,12 +313,17 @@ private:
&& ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
{
(new ExternalDragAndDropMessage (files, canMoveFiles))->post();
delete this;
deleteSelf();
}
}
}
}
void deleteSelf()
{
delete this;
}
void dismissWithAnimation (const bool shouldSnapBack)
{
setVisible (true);
@@ -434,6 +456,8 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
if (ComponentPeer* const peer = dragImageComponent->getPeer())
peer->performAnyPendingRepaintsNow();
#endif
dragOperationStarted();
}
}
@@ -458,6 +482,9 @@ bool DragAndDropContainer::shouldDropFilesWhenDraggedExternally (const DragAndDr
return false;
}
void DragAndDropContainer::dragOperationStarted() {}
void DragAndDropContainer::dragOperationEnded() {}
//==============================================================================
DragAndDropTarget::SourceDetails::SourceDetails (const var& desc, Component* comp, Point<int> pos) noexcept
: description (desc),


+ 6
- 0
source/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h View File

@@ -165,6 +165,12 @@ protected:
virtual bool shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
StringArray& files, bool& canMoveFiles);
/** Subclasses can override this to be told when a drag starts. */
virtual void dragOperationStarted();
/** Subclasses can override this to be told when a drag finishes. */
virtual void dragOperationEnded();
private:
//==============================================================================
class DragImageComponent;


+ 76
- 47
source/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm View File

@@ -24,6 +24,14 @@
class UIViewComponentPeer;
// The way rotation works changed in iOS8..
static bool isUsingOldRotationMethod() noexcept
{
static bool isPreV8 = ([[[UIDevice currentDevice] systemVersion] compare: @"8.0"
options: NSNumericSearch] == NSOrderedAscending);
return isPreV8;
}
namespace Orientations
{
static Desktop::DisplayOrientation convertToJuce (UIInterfaceOrientation orientation)
@@ -42,12 +50,15 @@ namespace Orientations
static CGAffineTransform getCGTransformFor (const Desktop::DisplayOrientation orientation) noexcept
{
switch (orientation)
if (isUsingOldRotationMethod())
{
case Desktop::upsideDown: return CGAffineTransformMake (-1, 0, 0, -1, 0, 0);
case Desktop::rotatedClockwise: return CGAffineTransformMake (0, -1, 1, 0, 0, 0);
case Desktop::rotatedAntiClockwise: return CGAffineTransformMake (0, 1, -1, 0, 0, 0);
default: break;
switch (orientation)
{
case Desktop::upsideDown: return CGAffineTransformMake (-1, 0, 0, -1, 0, 0);
case Desktop::rotatedClockwise: return CGAffineTransformMake (0, -1, 1, 0, 0, 0);
case Desktop::rotatedAntiClockwise: return CGAffineTransformMake (0, 1, -1, 0, 0, 0);
default: break;
}
}
return CGAffineTransformIdentity;
@@ -85,10 +96,10 @@ using namespace juce;
- (void) drawRect: (CGRect) r;
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event;
- (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event;
- (BOOL) becomeFirstResponder;
- (BOOL) resignFirstResponder;
@@ -106,6 +117,7 @@ using namespace juce;
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation;
- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation duration: (NSTimeInterval) duration;
- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation;
- (void) viewWillTransitionToSize: (CGSize) size withTransitionCoordinator: (id<UIViewControllerTransitionCoordinator>) coordinator;
- (void) viewDidLoad;
- (void) viewWillAppear: (BOOL) animated;
@@ -189,7 +201,7 @@ public:
bool isSharedWindow, fullScreen, insideDrawRect;
static ModifierKeys currentModifiers;
static int64 getMouseTime (UIEvent* e)
static int64 getMouseTime (UIEvent* e) noexcept
{
return (Time::currentTimeMillis() - Time::getMillisecondCounter())
+ (int64) ([e timestamp] * 1000.0);
@@ -197,26 +209,29 @@ public:
static Rectangle<int> rotatedScreenPosToReal (const Rectangle<int>& r)
{
const Rectangle<int> screen (convertToRectInt ([UIScreen mainScreen].bounds));
switch ([[UIApplication sharedApplication] statusBarOrientation])
if (isUsingOldRotationMethod())
{
case UIInterfaceOrientationPortrait:
return r;
const Rectangle<int> screen (convertToRectInt ([UIScreen mainScreen].bounds));
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case UIInterfaceOrientationPortrait:
return r;
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (r.getY(), screen.getHeight() - r.getRight(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (r.getY(), screen.getHeight() - r.getRight(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (screen.getWidth() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (screen.getWidth() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
default: jassertfalse; // unknown orientation!
default: jassertfalse; // unknown orientation!
}
}
return r;
@@ -224,26 +239,29 @@ public:
static Rectangle<int> realScreenPosToRotated (const Rectangle<int>& r)
{
const Rectangle<int> screen (convertToRectInt ([UIScreen mainScreen].bounds));
switch ([[UIApplication sharedApplication] statusBarOrientation])
if (isUsingOldRotationMethod())
{
case UIInterfaceOrientationPortrait:
return r;
const Rectangle<int> screen (convertToRectInt ([UIScreen mainScreen].bounds));
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case UIInterfaceOrientationPortrait:
return r;
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (screen.getHeight() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (screen.getHeight() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (r.getY(), screen.getWidth() - r.getRight(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (r.getY(), screen.getWidth() - r.getRight(),
r.getHeight(), r.getWidth());
default: jassertfalse; // unknown orientation!
default: jassertfalse; // unknown orientation!
}
}
return r;
@@ -273,6 +291,13 @@ private:
};
};
static void sendScreenBoundsUpdate (JuceUIViewController* c)
{
JuceUIView* juceView = (JuceUIView*) [c view];
jassert (juceView != nil && juceView->owner != nullptr);
juceView->owner->updateTransformAndScreenBounds();
}
} // (juce namespace)
//==============================================================================
@@ -301,19 +326,23 @@ private:
- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation
{
(void) fromInterfaceOrientation;
sendScreenBoundsUpdate (self);
[UIView setAnimationsEnabled: YES];
}
JuceUIView* juceView = (JuceUIView*) [self view];
jassert (juceView != nil && juceView->owner != nullptr);
juceView->owner->updateTransformAndScreenBounds();
- (void) viewWillTransitionToSize: (CGSize) size withTransitionCoordinator: (id<UIViewControllerTransitionCoordinator>) coordinator
{
[super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
sendScreenBoundsUpdate (self);
[UIView setAnimationsEnabled: YES];
// On some devices the screen-size isn't yet updated at this point, so also trigger another
// async update to double-check..
MessageManager::callAsync ([=]() { sendScreenBoundsUpdate (self); });
}
- (void) viewDidLoad
{
JuceUIView* juceView = (JuceUIView*) [self view];
jassert (juceView != nil && juceView->owner != nullptr);
juceView->owner->updateTransformAndScreenBounds();
sendScreenBoundsUpdate (self);
}
- (void) viewWillAppear: (BOOL) animated


+ 6
- 6
source/modules/juce_gui_basics/native/juce_linux_FileChooser.cpp View File

@@ -65,6 +65,12 @@ static void addKDialogArgs (StringArray& args, String& separator,
if (title.isNotEmpty())
args.add ("--title=" + title);
if (uint64 topWindowID = getTopWindowID())
{
args.add ("--attach");
args.add (String (topWindowID));
}
if (selectMultipleFiles)
{
separator = "\n";
@@ -79,12 +85,6 @@ static void addKDialogArgs (StringArray& args, String& separator,
else args.add ("--getopenfilename");
}
if (uint64 topWindowID = getTopWindowID())
{
args.add ("--attach");
args.add (String (topWindowID));
}
File startPath;
if (file.exists())


+ 3
- 3
source/modules/juce_gui_basics/native/juce_linux_Windowing.cpp View File

@@ -979,11 +979,13 @@ public:
Point<float> localToGlobal (Point<float> relativePosition) override
{
updateWindowBounds();
return relativePosition + bounds.getPosition().toFloat();
}
Point<float> globalToLocal (Point<float> screenPosition) override
{
updateWindowBounds();
return screenPosition - bounds.getPosition().toFloat();
}
@@ -1087,9 +1089,7 @@ public:
{
for (int i = windowListSize; --i >= 0;)
{
LinuxComponentPeer* const peer = LinuxComponentPeer::getPeerFor (windowList[i]);
if (peer != 0)
if (LinuxComponentPeer* const peer = LinuxComponentPeer::getPeerFor (windowList[i]))
{
result = (peer == this);
break;


+ 36
- 12
source/modules/juce_gui_basics/native/juce_win32_Windowing.cpp View File

@@ -177,6 +177,7 @@ static void setWindowZOrder (HWND hwnd, HWND insertAfter)
//==============================================================================
static void setDPIAwareness()
{
#if ! JUCE_DISABLE_WIN32_DPI_AWARENESS
if (JUCEApplicationBase::isStandaloneApp())
{
if (setProcessDPIAwareness == nullptr)
@@ -203,6 +204,7 @@ static void setDPIAwareness()
}
}
}
#endif
}
static double getGlobalDPI()
@@ -845,7 +847,7 @@ public:
void toBehind (ComponentPeer* other) override
{
if (HWNDComponentPeer* const otherPeer = dynamic_cast <HWNDComponentPeer*> (other))
if (HWNDComponentPeer* const otherPeer = dynamic_cast<HWNDComponentPeer*> (other))
{
setMinimised (false);
@@ -960,7 +962,7 @@ public:
static ModifierKeys modifiersAtLastCallback;
//==============================================================================
class JuceDropTarget : public ComBaseClassHelper <IDropTarget>
class JuceDropTarget : public ComBaseClassHelper<IDropTarget>
{
public:
JuceDropTarget (HWNDComponentPeer& p) : ownerInfo (new OwnerInfo (p)) {}
@@ -1099,13 +1101,13 @@ public:
if (SUCCEEDED (fileData.error))
{
const LPDROPFILES dropFiles = static_cast <const LPDROPFILES> (fileData.data);
const LPDROPFILES dropFiles = static_cast<const LPDROPFILES> (fileData.data);
const void* const names = addBytesToPointer (dropFiles, sizeof (DROPFILES));
if (dropFiles->fWide)
ownerInfo->parseFileList (static_cast <const WCHAR*> (names), fileData.dataSize);
ownerInfo->parseFileList (static_cast<const WCHAR*> (names), fileData.dataSize);
else
ownerInfo->parseFileList (static_cast <const char*> (names), fileData.dataSize);
ownerInfo->parseFileList (static_cast<const char*> (names), fileData.dataSize);
}
else
{
@@ -1300,7 +1302,7 @@ private:
//==============================================================================
static void* createWindowCallback (void* userData)
{
static_cast <HWNDComponentPeer*> (userData)->createWindow();
static_cast<HWNDComponentPeer*> (userData)->createWindow();
return nullptr;
}
@@ -1643,7 +1645,7 @@ private:
handlePaint (*context);
}
static_cast <WindowsBitmapImage*> (offscreenImage.getPixelData())
static_cast<WindowsBitmapImage*> (offscreenImage.getPixelData())
->blitToWindow (hwnd, dc, transparent, x, y, updateLayeredWindowAlpha);
}
@@ -2261,6 +2263,24 @@ private:
}
}
void handlePowerBroadcast (WPARAM wParam)
{
if (JUCEApplicationBase* const app = JUCEApplicationBase::getInstance())
{
switch (wParam)
{
case PBT_APMSUSPEND: app->suspended(); break;
case PBT_APMQUERYSUSPENDFAILED:
case PBT_APMRESUMECRITICAL:
case PBT_APMRESUMESUSPEND:
case PBT_APMRESUMEAUTOMATIC: app->resumed(); break;
default: break;
}
}
}
void handleLeftClickInNCArea (WPARAM wParam)
{
if (! sendInputAttemptWhenModalMessage())
@@ -2309,7 +2329,7 @@ private:
{
Desktop& desktop = Desktop::getInstance();
const_cast <Desktop::Displays&> (desktop.getDisplays()).refresh();
const_cast<Desktop::Displays&> (desktop.getDisplays()).refresh();
if (fullScreen && ! isMinimised())
{
@@ -2550,6 +2570,10 @@ private:
}
return TRUE;
case WM_POWERBROADCAST:
handlePowerBroadcast (wParam);
break;
case WM_SYNCPAINT:
return 0;
@@ -2879,7 +2903,7 @@ private:
void moveCandidateWindowToLeftAlignWithSelection (HIMC hImc, ComponentPeer& peer, TextInputTarget* target) const
{
if (Component* const targetComp = dynamic_cast <Component*> (target))
if (Component* const targetComp = dynamic_cast<Component*> (target))
{
const Rectangle<int> area (peer.getComponent().getLocalArea (targetComp, target->getCaretRectangle()));
@@ -2981,7 +3005,7 @@ bool JUCE_CALLTYPE Process::isForegroundProcess()
fg = GetAncestor (fg, GA_ROOT);
for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
if (HWNDComponentPeer* const wp = dynamic_cast <HWNDComponentPeer*> (ComponentPeer::getPeer (i)))
if (HWNDComponentPeer* const wp = dynamic_cast<HWNDComponentPeer*> (ComponentPeer::getPeer (i)))
if (wp->isInside (fg))
return true;
@@ -3007,7 +3031,7 @@ static BOOL CALLBACK enumAlwaysOnTopWindows (HWND hwnd, LPARAM lParam)
if (GetWindowInfo (hwnd, &info)
&& (info.dwExStyle & WS_EX_TOPMOST) != 0)
{
*reinterpret_cast <bool*> (lParam) = true;
*reinterpret_cast<bool*> (lParam) = true;
return FALSE;
}
}
@@ -3212,7 +3236,7 @@ void SystemClipboard::copyTextToClipboard (const String& text)
{
if (HGLOBAL bufH = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT, bytesNeeded + sizeof (WCHAR)))
{
if (WCHAR* const data = static_cast <WCHAR*> (GlobalLock (bufH)))
if (WCHAR* const data = static_cast<WCHAR*> (GlobalLock (bufH)))
{
text.copyToUTF16 (data, bytesNeeded);
GlobalUnlock (bufH);


+ 1
- 1
source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.cpp View File

@@ -66,7 +66,7 @@ void BooleanPropertyComponent::paint (Graphics& g)
{
PropertyComponent::paint (g);
g.setColour (Colours::white);
g.setColour (findColour (backgroundColourId));
g.fillRect (button.getBounds());
g.setColour (findColour (ComboBox::outlineColourId));


+ 18
- 0
source/modules/juce_gui_basics/properties/juce_BooleanPropertyComponent.h View File

@@ -56,6 +56,10 @@ protected:
public:
/** Creates a button component.
Note that if you call this constructor then you must use the Value to interact with the
button state, and you can't override the class with your own setState or getState methods.
If you want to use getState and setState, call the other constructor instead.
@param valueToControl a Value object that this property should refer to.
@param propertyName the property name to be passed to the PropertyComponent
@param buttonText the text shown in the ToggleButton component
@@ -74,6 +78,20 @@ public:
/** Must return the current value of the property. */
virtual bool getState() const;
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the component.
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
methods.
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
*/
enum ColourIds
{
backgroundColourId = 0x100e801, /**< The colour to fill the background of the button area. */
outlineColourId = 0x100e803, /**< The colour to use to draw an outline around the text area. */
};
//==============================================================================
/** @internal */
void paint (Graphics&) override;


+ 5
- 3
source/modules/juce_gui_basics/properties/juce_ChoicePropertyComponent.h View File

@@ -50,15 +50,17 @@ class JUCE_API ChoicePropertyComponent : public PropertyComponent,
{
protected:
/** Creates the component.
Your subclass's constructor must add a list of options to the choices
member variable.
Your subclass's constructor must add a list of options to the choices member variable.
*/
ChoicePropertyComponent (const String& propertyName);
public:
/** Creates the component.
Note that if you call this constructor then you must use the Value to interact with the
index, and you can't override the class with your own setIndex or getIndex methods.
If you want to use those methods, call the other constructor instead.
@param valueToControl the value that the combo box will read and control
@param propertyName the name of the property
@param choices the list of possible values that the drop-down list will contain


+ 4
- 0
source/modules/juce_gui_basics/properties/juce_SliderPropertyComponent.h View File

@@ -58,6 +58,10 @@ public:
If you need to customise the slider in other ways, your constructor can
access the slider member variable and change it directly.
Note that if you call this constructor then you must use the Value to interact with
the value, and you can't override the class with your own setValue or getValue methods.
If you want to use those methods, call the other constructor instead.
*/
SliderPropertyComponent (const Value& valueToControl,
const String& propertyName,


+ 0
- 2
source/modules/juce_gui_basics/widgets/juce_Label.cpp View File

@@ -460,5 +460,3 @@ void Label::textEditorFocusLost (TextEditor& ed)
{
textEditorTextChanged (ed);
}
void Label::Listener::editorShown (Label*, TextEditor&) {}

+ 1
- 1
source/modules/juce_gui_basics/widgets/juce_Label.h View File

@@ -184,7 +184,7 @@ public:
virtual void labelTextChanged (Label* labelThatHasChanged) = 0;
/** Called when a Label goes into editing mode and displays a TextEditor. */
virtual void editorShown (Label*, TextEditor& textEditorShown);
virtual void editorShown (Label*, TextEditor&) {}
};
/** Registers a listener that will be called when the label's text changes. */


+ 10
- 6
source/modules/juce_gui_basics/widgets/juce_ListBox.cpp View File

@@ -367,6 +367,7 @@ ListBox::ListBox (const String& name, ListBoxModel* const m)
outlineThickness (0),
lastRowSelected (-1),
multipleSelection (false),
alwaysFlipSelection (false),
hasDoneInitialUpdate (false)
{
addAndMakeVisible (viewport = new ListViewport (*this));
@@ -391,11 +392,16 @@ void ListBox::setModel (ListBoxModel* const newModel)
}
}
void ListBox::setMultipleSelectionEnabled (bool b)
void ListBox::setMultipleSelectionEnabled (bool b) noexcept
{
multipleSelection = b;
}
void ListBox::setClickingTogglesRowSelection (bool b) noexcept
{
alwaysFlipSelection = b;
}
void ListBox::setMouseMoveSelectsRows (bool b)
{
if (b)
@@ -470,9 +476,7 @@ void ListBox::updateContent()
}
//==============================================================================
void ListBox::selectRow (const int row,
bool dontScroll,
bool deselectOthersFirst)
void ListBox::selectRow (int row, bool dontScroll, bool deselectOthersFirst)
{
selectRowInternal (row, dontScroll, deselectOthersFirst, false);
}
@@ -589,7 +593,7 @@ void ListBox::selectRowsBasedOnModifierKeys (const int row,
ModifierKeys mods,
const bool isMouseUpEvent)
{
if (multipleSelection && mods.isCommandDown())
if (multipleSelection && (mods.isCommandDown() || alwaysFlipSelection))
{
flipRowSelection (row);
}
@@ -883,7 +887,7 @@ void ListBox::repaintRow (const int rowNumber) noexcept
Image ListBox::createSnapshotOfSelectedRows (int& imageX, int& imageY)
{
Rectangle<int> imageArea;
const int firstRow = getRowContainingPosition (0, 0);
const int firstRow = getRowContainingPosition (0, viewport->getY());
for (int i = getNumRowsOnScreen() + 2; --i >= 0;)
{


+ 15
- 3
source/modules/juce_gui_basics/widgets/juce_ListBox.h View File

@@ -45,7 +45,10 @@ public:
*/
virtual int getNumRows() = 0;
/** This method must be implemented to draw a row of the list. */
/** This method must be implemented to draw a row of the list.
Note that the rowNumber value may be greater than the number of rows in your
list, so be careful that you don't assume it's less than getNumRows().
*/
virtual void paintListBoxItem (int rowNumber,
Graphics& g,
int width, int height,
@@ -216,7 +219,16 @@ public:
clicked and to get it to do the appropriate selection based on whether
the ctrl/shift keys are held down.
*/
void setMultipleSelectionEnabled (bool shouldBeEnabled);
void setMultipleSelectionEnabled (bool shouldBeEnabled) noexcept;
/** If enabled, this makes the listbox flip the selection status of
each row that the user clicks, without affecting other selected rows.
(This only has an effect if multiple selection is also enabled).
If not enabled, you can still get the same row-flipping behaviour by holding
down CMD or CTRL when clicking.
*/
void setClickingTogglesRowSelection (bool flipRowSelection) noexcept;
/** Makes the list react to mouse moves by selecting the row that the mouse if over.
@@ -557,7 +569,7 @@ private:
int totalItems, rowHeight, minimumRowWidth;
int outlineThickness;
int lastRowSelected;
bool multipleSelection, hasDoneInitialUpdate;
bool multipleSelection, alwaysFlipSelection, hasDoneInitialUpdate;
SparseSet<int> selected;
void selectRowInternal (int rowNumber, bool dontScrollToShowThisRow,


+ 7
- 6
source/modules/juce_gui_basics/widgets/juce_Slider.cpp View File

@@ -464,9 +464,9 @@ public:
const bool stopAtEnd)
{
// make sure the values are sensible..
jassert (rotaryStart >= 0 && rotaryEnd >= 0);
jassert (rotaryStart < float_Pi * 4.0f && rotaryEnd < float_Pi * 4.0f);
jassert (rotaryStart < rotaryEnd);
jassert (startAngleRadians >= 0 && endAngleRadians >= 0);
jassert (startAngleRadians < float_Pi * 4.0f && endAngleRadians < float_Pi * 4.0f);
jassert (startAngleRadians < endAngleRadians);
rotaryStart = startAngleRadians;
rotaryEnd = endAngleRadians;
@@ -1006,9 +1006,9 @@ public:
valueBox->hideEditor (false);
const double value = (double) currentValue.getValue();
const double delta = getMouseWheelDelta (value, (wheel.deltaX != 0 ? -wheel.deltaX : wheel.deltaY)
* (wheel.isReversed ? -1.0f : 1.0f));
const double delta = getMouseWheelDelta (value, (std::abs (wheel.deltaX) > std::abs (wheel.deltaY)
? -wheel.deltaX : wheel.deltaY)
* (wheel.isReversed ? -1.0f : 1.0f));
if (delta != 0)
{
const double newValue = value + jmax (interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0);
@@ -1287,6 +1287,7 @@ public:
{
setAlwaysOnTop (true);
setAllowedPlacement (owner.getLookAndFeel().getSliderPopupPlacement (s));
setLookAndFeel (&s.getLookAndFeel());
}
void paintContent (Graphics& g, int w, int h)


+ 10
- 15
source/modules/juce_gui_basics/widgets/juce_TableListBox.cpp View File

@@ -26,7 +26,7 @@ class TableListBox::RowComp : public Component,
public TooltipClient
{
public:
RowComp (TableListBox& tlb) : owner (tlb), row (-1), isSelected (false)
RowComp (TableListBox& tlb) noexcept : owner (tlb), row (-1), isSelected (false)
{
}
@@ -192,7 +192,7 @@ public:
if (TableListBoxModel* m = owner.getModel())
return m->getCellTooltip (row, columnId);
return String::empty;
return String();
}
Component* findChildComponentForColumn (const int columnId) const
@@ -275,7 +275,7 @@ void TableListBox::setHeader (TableHeaderComponent* newHeader)
{
jassert (newHeader != nullptr); // you need to supply a real header for a table!
Rectangle<int> newBounds (0, 0, 100, 28);
Rectangle<int> newBounds (100, 28);
if (header != nullptr)
newBounds = header->getBounds();
@@ -287,7 +287,7 @@ void TableListBox::setHeader (TableHeaderComponent* newHeader)
header->addListener (this);
}
int TableListBox::getHeaderHeight() const
int TableListBox::getHeaderHeight() const noexcept
{
return header->getHeight();
}
@@ -312,16 +312,11 @@ void TableListBox::autoSizeAllColumns()
autoSizeColumn (header->getColumnIdOfIndex (i, true));
}
void TableListBox::setAutoSizeMenuOptionShown (const bool shouldBeShown)
void TableListBox::setAutoSizeMenuOptionShown (const bool shouldBeShown) noexcept
{
autoSizeOptionsShown = shouldBeShown;
}
bool TableListBox::isAutoSizeMenuOptionShown() const
{
return autoSizeOptionsShown;
}
Rectangle<int> TableListBox::getCellPosition (const int columnId, const int rowNumber,
const bool relativeToComponentTopLeft) const
{
@@ -337,7 +332,7 @@ Rectangle<int> TableListBox::getCellPosition (const int columnId, const int rowN
Component* TableListBox::getCellComponent (int columnId, int rowNumber) const
{
if (RowComp* const rowComp = dynamic_cast <RowComp*> (getComponentForRowNumber (rowNumber)))
if (RowComp* const rowComp = dynamic_cast<RowComp*> (getComponentForRowNumber (rowNumber)))
return rowComp->findChildComponentForColumn (columnId);
return nullptr;
@@ -370,12 +365,12 @@ void TableListBox::paintListBoxItem (int, Graphics&, int, int, bool)
{
}
Component* TableListBox::refreshComponentForRow (int rowNumber, bool isRowSelected_, Component* existingComponentToUpdate)
Component* TableListBox::refreshComponentForRow (int rowNumber, bool rowSelected, Component* existingComponentToUpdate)
{
if (existingComponentToUpdate == nullptr)
existingComponentToUpdate = new RowComp (*this);
static_cast <RowComp*> (existingComponentToUpdate)->update (rowNumber, isRowSelected_);
static_cast<RowComp*> (existingComponentToUpdate)->update (rowNumber, rowSelected);
return existingComponentToUpdate;
}
@@ -450,7 +445,7 @@ void TableListBox::updateColumnComponents() const
const int firstRow = getRowContainingPosition (0, 0);
for (int i = firstRow + getNumRowsOnScreen() + 2; --i >= firstRow;)
if (RowComp* const rowComp = dynamic_cast <RowComp*> (getComponentForRowNumber (i)))
if (RowComp* const rowComp = dynamic_cast<RowComp*> (getComponentForRowNumber (i)))
rowComp->resized();
}
@@ -465,7 +460,7 @@ void TableListBoxModel::deleteKeyPressed (int) {}
void TableListBoxModel::returnKeyPressed (int) {}
void TableListBoxModel::listWasScrolled() {}
String TableListBoxModel::getCellTooltip (int /*rowNumber*/, int /*columnId*/) { return String::empty; }
String TableListBoxModel::getCellTooltip (int /*rowNumber*/, int /*columnId*/) { return String(); }
var TableListBoxModel::getDragSourceDescription (const SparseSet<int>&) { return var(); }
Component* TableListBoxModel::refreshComponentForCell (int, int, bool, Component* existingComponentToUpdate)


+ 20
- 17
source/modules/juce_gui_basics/widgets/juce_TableListBox.h View File

@@ -57,7 +57,7 @@ public:
The graphics context has its origin at the row's top-left, and your method
should fill the area specified by the width and height parameters.
*/
virtual void paintRowBackground (Graphics& g,
virtual void paintRowBackground (Graphics&,
int rowNumber,
int width, int height,
bool rowIsSelected) = 0;
@@ -66,8 +66,11 @@ public:
The graphics context's origin will already be set to the top-left of the cell,
whose size is specified by (width, height).
Note that the rowNumber value may be greater than the number of rows in your
list, so be careful that you don't assume it's less than getNumRows().
*/
virtual void paintCell (Graphics& g,
virtual void paintCell (Graphics&,
int rowNumber,
int columnId,
int width, int height,
@@ -142,25 +145,21 @@ public:
*/
virtual int getColumnAutoSizeWidth (int columnId);
/** Returns a tooltip for a particular cell in the table.
*/
/** Returns a tooltip for a particular cell in the table. */
virtual String getCellTooltip (int rowNumber, int columnId);
//==============================================================================
/** Override this to be informed when rows are selected or deselected.
@see ListBox::selectedRowsChanged()
*/
virtual void selectedRowsChanged (int lastRowSelected);
/** Override this to be informed when the delete key is pressed.
@see ListBox::deleteKeyPressed()
*/
virtual void deleteKeyPressed (int lastRowSelected);
/** Override this to be informed when the return key is pressed.
@see ListBox::returnKeyPressed()
*/
virtual void returnKeyPressed (int lastRowSelected);
@@ -210,29 +209,34 @@ public:
/** Creates a TableListBox.
The model pointer passed-in can be null, in which case you can set it later
with setModel().
with setModel(). The TableListBox does not take ownership of the model - it's
the caller's responsibility to manage its lifetime and make sure it
doesn't get deleted while still being used.
*/
TableListBox (const String& componentName = String::empty,
TableListBoxModel* model = 0);
TableListBox (const String& componentName = String(),
TableListBoxModel* model = nullptr);
/** Destructor. */
~TableListBox();
//==============================================================================
/** Changes the TableListBoxModel that is being used for this table.
The TableListBox does not take ownership of the model - it's the caller's responsibility
to manage its lifetime and make sure it doesn't get deleted while still being used.
*/
void setModel (TableListBoxModel* newModel);
/** Returns the model currently in use. */
TableListBoxModel* getModel() const { return model; }
TableListBoxModel* getModel() const noexcept { return model; }
//==============================================================================
/** Returns the header component being used in this table. */
TableHeaderComponent& getHeader() const { return *header; }
TableHeaderComponent& getHeader() const noexcept { return *header; }
/** Sets the header component to use for the table.
The table will take ownership of the component that you pass in, and will delete it
when it's no longer needed.
The pointer passed in may not be null.
*/
void setHeader (TableHeaderComponent* newHeader);
@@ -244,7 +248,7 @@ public:
/** Returns the height of the table header.
@see setHeaderHeight
*/
int getHeaderHeight() const;
int getHeaderHeight() const noexcept;
//==============================================================================
/** Resizes a column to fit its contents.
@@ -260,15 +264,14 @@ public:
void autoSizeAllColumns();
/** Enables or disables the auto size options on the popup menu.
By default, these are enabled.
*/
void setAutoSizeMenuOptionShown (bool shouldBeShown);
void setAutoSizeMenuOptionShown (bool shouldBeShown) noexcept;
/** True if the auto-size options should be shown on the menu.
@see setAutoSizeMenuOptionsShown
@see setAutoSizeMenuOptionShown
*/
bool isAutoSizeMenuOptionShown() const;
bool isAutoSizeMenuOptionShown() const noexcept { return autoSizeOptionsShown; }
/** Returns the position of one of the cells in the table.


+ 4
- 4
source/modules/juce_gui_basics/widgets/juce_Toolbar.cpp View File

@@ -591,8 +591,8 @@ void Toolbar::itemDragMove (const SourceDetails& dragSourceDetails)
{
const Rectangle<int> previousPos (animator.getComponentDestination (prev));
if (abs (dragObjectLeft - (vertical ? previousPos.getY() : previousPos.getX())
< abs (dragObjectRight - (vertical ? current.getBottom() : current.getRight()))))
if (std::abs (dragObjectLeft - (vertical ? previousPos.getY() : previousPos.getX()))
< std::abs (dragObjectRight - (vertical ? current.getBottom() : current.getRight())))
{
newIndex = getIndexOfChildComponent (prev);
}
@@ -602,8 +602,8 @@ void Toolbar::itemDragMove (const SourceDetails& dragSourceDetails)
{
const Rectangle<int> nextPos (animator.getComponentDestination (next));
if (abs (dragObjectLeft - (vertical ? current.getY() : current.getX())
> abs (dragObjectRight - (vertical ? nextPos.getBottom() : nextPos.getRight()))))
if (std::abs (dragObjectLeft - (vertical ? current.getY() : current.getX()))
> std::abs (dragObjectRight - (vertical ? nextPos.getBottom() : nextPos.getRight())))
{
newIndex = getIndexOfChildComponent (next) + 1;
}


+ 7
- 2
source/modules/juce_gui_basics/widgets/juce_TreeView.cpp View File

@@ -1773,6 +1773,11 @@ TreeViewItem* TreeViewItem::getNextVisibleItem (const bool recurse) const noexce
return nullptr;
}
static String escapeSlashesInTreeViewItemName (const String& s)
{
return s.replaceCharacter ('/', '\\');
}
String TreeViewItem::getItemIdentifierString() const
{
String s;
@@ -1780,12 +1785,12 @@ String TreeViewItem::getItemIdentifierString() const
if (parentItem != nullptr)
s = parentItem->getItemIdentifierString();
return s + "/" + getUniqueName().replaceCharacter ('/', '\\');
return s + "/" + escapeSlashesInTreeViewItemName (getUniqueName());
}
TreeViewItem* TreeViewItem::findItemFromIdentifierString (const String& identifierString)
{
const String thisId ("/" + getUniqueName());
const String thisId ("/" + escapeSlashesInTreeViewItemName (getUniqueName()));
if (thisId == identifierString)
return this;


+ 8
- 4
source/modules/juce_gui_basics/windows/juce_CallOutBox.cpp View File

@@ -23,7 +23,7 @@
*/
CallOutBox::CallOutBox (Component& c, const Rectangle<int>& area, Component* const parent)
: arrowSize (16.0f), content (c)
: arrowSize (16.0f), content (c), dismissalMouseClicksAreAlwaysConsumed (false)
{
addAndMakeVisible (content);
@@ -123,9 +123,8 @@ bool CallOutBox::hitTest (int x, int y)
void CallOutBox::inputAttemptWhenModal()
{
const Point<int> mousePos (getMouseXYRelative() + getBounds().getPosition());
if (targetArea.contains (mousePos))
if (dismissalMouseClicksAreAlwaysConsumed
|| targetArea.contains (getMouseXYRelative() + getBounds().getPosition()))
{
// if you click on the area that originally popped-up the callout, you expect it
// to get rid of the box, but deleting the box here allows the click to pass through and
@@ -139,6 +138,11 @@ void CallOutBox::inputAttemptWhenModal()
}
}
void CallOutBox::setDismissalMouseClicksAreAlwaysConsumed (bool b) noexcept
{
dismissalMouseClicksAreAlwaysConsumed = b;
}
enum { callOutBoxDismissCommandId = 0x4f83a04b };
void CallOutBox::handleCommandMessage (int commandId)


+ 11
- 0
source/modules/juce_gui_basics/windows/juce_CallOutBox.h View File

@@ -123,6 +123,16 @@ public:
*/
void dismiss();
/** Determines whether the mouse events for clicks outside the calloutbox are
consumed, or allowed to arrive at the other component that they were aimed at.
By default this is false, so that when you click on something outside the calloutbox,
that event will also be sent to the component that was clicked on. If you set it to
true, then the first click will always just dismiss the box and not be sent to
anything else.
*/
void setDismissalMouseClicksAreAlwaysConsumed (bool shouldAlwaysBeConsumed) noexcept;
//==============================================================================
/** This abstract base class is implemented by LookAndFeel classes. */
struct JUCE_API LookAndFeelMethods
@@ -161,6 +171,7 @@ private:
Point<float> targetPoint;
Rectangle<int> availableArea, targetArea;
Image background;
bool dismissalMouseClicksAreAlwaysConsumed;
void refreshPath();


+ 1
- 1
source/modules/juce_gui_basics/windows/juce_DialogWindow.h View File

@@ -78,7 +78,7 @@ public:
initialise its fields with the appropriate details, and then call its launchAsync()
method to launch the dialog.
*/
struct LaunchOptions
struct JUCE_API LaunchOptions
{
LaunchOptions() noexcept;


+ 1
- 1
source/modules/juce_gui_basics/windows/juce_TopLevelWindow.h View File

@@ -127,7 +127,7 @@ public:
//==============================================================================
/** @internal */
virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
protected:
//==============================================================================


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

Loading…
Cancel
Save