diff --git a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp index 447a240a2559..9f6d1120aaf5 100644 --- a/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp +++ b/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp @@ -236,8 +236,9 @@ static void addIfNotNull (OwnedArray& list, AudioIODeviceType void AudioDeviceManager::createAudioDeviceTypes (OwnedArray& list) { addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::shared)); - addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::exclusive)); - addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::sharedLowLatency)); + // Acon Digital modification - no need for special WASAPI modes + //addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::exclusive)); + //addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_WASAPI (WASAPIDeviceMode::sharedLowLatency)); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_DirectSound()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_ASIO()); addIfNotNull (list, AudioIODeviceType::createAudioIODeviceType_CoreAudio()); diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp index e8bf84295545..80e6a1a5a64f 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_AAX.cpp @@ -85,6 +85,11 @@ static_assert (AAX_SDK_CURRENT_REVISION >= AAX_SDK_2p4p0_REVISION, "JUCE require #include #include +#if JucePlugin_Enable_ARA +#include +#include +#endif + JUCE_END_IGNORE_WARNINGS_MSVC JUCE_END_IGNORE_WARNINGS_GCC_LIKE @@ -723,6 +728,12 @@ namespace AAXClasses void mouseUp (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseUp); } void mouseDrag (const MouseEvent& e) override { callMouseMethod (e, &AAX_IViewContainer::HandleParameterMouseDrag); } + void resized() override + { + if (pluginEditor != nullptr) + pluginEditor->setBounds (getLocalBounds()); + } + void parentSizeChanged() override { resizeHostWindow(); @@ -847,6 +858,14 @@ namespace AAXClasses return new JuceAAX_Processor(); } + #if JucePlugin_Enable_ARA + AAX_Result Initialize (IACFUnknown* iController) override + { + aaxaraBinding.reset (new ARA::AAX_VARABinding (iController)); + return AAX_CEffectParameters::Initialize (iController); + } + #endif + AAX_Result Uninitialize() override { cancelPendingUpdate(); @@ -866,6 +885,36 @@ namespace AAXClasses AAX_Result EffectInit() override { cancelPendingUpdate(); + + #if JucePlugin_Enable_ARA + ARA::ARAPlugInInstanceRoleFlags knownRoles = 0; + auto result = aaxaraBinding->GetInstanceRoleFlags (&knownRoles, &assignedRoles); + + // If no ARA roles provided - work as a regular AAX plug-in + if (result == AAX_SUCCESS) + { + assignedRoles &= (ARA::kARAPlaybackRendererRole | ARA::kARAEditorRendererRole | ARA::kARAEditorViewRole); + if (assignedRoles) + { + result = aaxaraBinding->GetDocumentController (&documentControllerRef); + if (result != AAX_SUCCESS) + return result; + + auto araPluginExtension = dynamic_cast (pluginInstance.get()); + if (!araPluginExtension) + return AAX_ERROR_NULL_OBJECT; + + auto* const plugInEnxtensionInstance = araPluginExtension->bindToARA (documentControllerRef, knownRoles, assignedRoles); + if (!plugInEnxtensionInstance) + return AAX_ERROR_NULL_OBJECT; + + result = aaxaraBinding->SetPlugInExtensionInstance (plugInEnxtensionInstance); + if (result != AAX_SUCCESS) + return result; + } + } + #endif + check (Controller()->GetSampleRate (&sampleRate)); processingSidechainChange = false; auto err = preparePlugin(); @@ -2290,6 +2339,12 @@ namespace AAXClasses std::atomic state { 0 }; }; + #if JucePlugin_Enable_ARA + std::unique_ptr aaxaraBinding; + ARA::ARADocumentControllerRef documentControllerRef; + ARA::ARAPlugInInstanceRoleFlags assignedRoles; + #endif + RecordingState recordingState; std::atomic processingSidechainChange, sidechainDesired; @@ -2557,6 +2612,12 @@ namespace AAXClasses } } + #if JucePlugin_Enable_ARA + properties->AddProperty (AAX_eProperty_UsesTransport, true); + properties->AddProperty (AAX_eProperty_Constraint_Topology, AAX_eConstraintTopology_Monolithic); + properties->AddPointerProperty (ARA::AAX_eProperty_ARAFactoryPointer, createARAFactory()); + #endif + check (desc.AddProcessProc_Native (algorithmProcessCallback, properties)); } diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp index 262f0a00c06a..a414981d060a 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp @@ -972,7 +972,18 @@ class JuceVSTWrapper final : public AudioProcessorListener, void getEditorBounds (Vst2::ERect& bounds) { auto editorBounds = getSizeToContainChild(); - bounds = convertToHostBounds ({ 0, 0, (int16) editorBounds.getHeight(), (int16) editorBounds.getWidth() }); + + // Acon Digital modification - circumvention of VST hosting error in EDIUS when runnng high-DPI mode + String hostPath = File::getSpecialLocation (File::hostApplicationPath).getFileNameWithoutExtension(); + if (hostPath.containsIgnoreCase ("edius")) { + auto mainDisplay = Desktop::getInstance().getDisplays().getPrimaryDisplay(); + float desktopScale = mainDisplay != nullptr ? mainDisplay->dpi / 96.f : 1.f; + float ediusCorrectionScale = 1.f + (desktopScale - 1.f) / desktopScale; + bounds = { 0, 0, (int16) roundToInt (editorBounds.getHeight() * ediusCorrectionScale), + (int16) roundToInt (editorBounds.getWidth() * ediusCorrectionScale) }; + } + else + bounds = convertToHostBounds ({ 0, 0, (int16) editorBounds.getHeight(), (int16) editorBounds.getWidth() }); } void attachToHost (VstOpCodeArguments args) diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h index 162484190fc3..fec96649db0e 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.h @@ -47,6 +47,21 @@ class JUCE_API AudioUnitPluginFormat : public AudioPluginFormat bool canScanForPlugins() const override { return true; } bool isTrivialToScan() const override { return false; } + //============================================================================== + /** Attempts to reload an AU plugin's state from some preset file data. + + @see VSTPluginFormat::loadFromFXBFile + */ + static bool setStateFromAUPresetFile (AudioPluginInstance*, const MemoryBlock&); + + //============================================================================== + /** Attempts to save an AU plugin's state to some preset file data. + + @see VSTPluginFormat::saveToFXBFile + */ + static bool saveStateToAUPresetFile (AudioPluginInstance*, MemoryBlock&); + + //============================================================================== void findAllTypesForFile (OwnedArray&, const String& fileOrIdentifier) override; bool fileMightContainThisPluginType (const String& fileOrIdentifier) override; String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) override; diff --git a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm index 4977541ae568..01092f27ba00 100644 --- a/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm +++ b/modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm @@ -2796,6 +2796,72 @@ void messageCallback() override { } +bool AudioUnitPluginFormat::setStateFromAUPresetFile (AudioPluginInstance* api, const MemoryBlock& rawData) +{ + AudioUnit audioUnit = (AudioUnit) api->getPlatformSpecificData(); + jassert (audioUnit != nullptr); + + CFReadStreamRef stream = CFReadStreamCreateWithBytesNoCopy (kCFAllocatorDefault, (const UInt8*) rawData.getData(), + rawData.getSize(), kCFAllocatorNull); + CFReadStreamOpen (stream); + + CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0; + CFPropertyListRef propertyList = CFPropertyListCreateFromStream (kCFAllocatorDefault, stream, 0, + kCFPropertyListImmutable, &format, 0); + CFRelease (stream); + + if (propertyList != 0) + { + AudioUnitSetProperty (audioUnit, kAudioUnitProperty_ClassInfo, kAudioUnitScope_Global, + 0, &propertyList, sizeof (propertyList)); + + AudioUnitParameter param; + param.mAudioUnit = audioUnit; + param.mParameterID = kAUParameterListener_AnyParameter; + + AUParameterListenerNotify (nullptr, nullptr, ¶m); + + CFRelease (propertyList); + return true; + } + else + return false; +} + +bool AudioUnitPluginFormat::saveStateToAUPresetFile (AudioPluginInstance* api, MemoryBlock& rawData) +{ + AudioUnit audioUnit = (AudioUnit) api->getPlatformSpecificData(); + jassert (audioUnit != nullptr); + + CFPropertyListRef propertyList = 0; + UInt32 sz = sizeof (CFPropertyListRef); + + if (AudioUnitGetProperty (audioUnit, + kAudioUnitProperty_ClassInfo, + kAudioUnitScope_Global, + 0, &propertyList, &sz) == noErr) + { + CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers (kCFAllocatorDefault, kCFAllocatorDefault); + CFWriteStreamOpen (stream); + + CFIndex bytesWritten = CFPropertyListWriteToStream (propertyList, stream, kCFPropertyListBinaryFormat_v1_0, 0); + CFWriteStreamClose (stream); + + CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty (stream, kCFStreamPropertyDataWritten); + + rawData.setSize ((size_t) bytesWritten); + rawData.copyFrom (CFDataGetBytePtr (data), 0, bytesWritten); + CFRelease (data); + + CFRelease (stream); + CFRelease (propertyList); + + return true; + } + else + return false; +} + void AudioUnitPluginFormat::findAllTypesForFile (OwnedArray& results, const String& fileOrIdentifier) { diff --git a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp index d08e11f5daeb..f60c00fdde61 100644 --- a/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp @@ -1884,14 +1884,15 @@ struct VSTPluginInstance final : public AudioPluginInstance, auto totalLen = sizeof (fxProgramSet) + chunk.getSize() - 8; dest.setSize (totalLen, true); + // Acon Digital modification - fixed errors in FXB format auto set = (fxProgramSet*) dest.getData(); set->chunkMagic = fxbName ("CcnK"); - set->byteSize = 0; + set->byteSize = fxbSwap ((int) totalLen - 8); set->fxMagic = fxbName ("FPCh"); set->version = fxbSwap (fxbVersionNum); set->fxID = fxbSwap (getUID()); set->fxVersion = fxbSwap (getVersionNumber()); - set->numPrograms = fxbSwap (numPrograms); + set->numPrograms = fxbSwap (getNumParameters()); set->chunkSize = fxbSwap ((int32) chunk.getSize()); getCurrentProgramName().copyToUTF8 (set->name, sizeof (set->name) - 1); diff --git a/modules/juce_gui_basics/buttons/juce_Button.cpp b/modules/juce_gui_basics/buttons/juce_Button.cpp index 02818c511d38..949a076f031e 100644 --- a/modules/juce_gui_basics/buttons/juce_Button.cpp +++ b/modules/juce_gui_basics/buttons/juce_Button.cpp @@ -509,8 +509,10 @@ bool Button::isMouseSourceOver (const MouseEvent& e) return isMouseOver(); } -void Button::focusGained (FocusChangeType) +void Button::focusGained (FocusChangeType cause) { + // Acon Digital modification - keep track of focus change cause + lastFocusChangeCause = cause; updateState(); repaint(); } @@ -664,6 +666,12 @@ bool Button::keyPressed (const KeyPress& key) return false; } +// Acon Digital modification - keep track of focus change cause +Component::FocusChangeType Button::getLastFocusChangeCause() +{ + return lastFocusChangeCause; +} + //============================================================================== void Button::setRepeatSpeed (int initialDelayMillisecs, int repeatMillisecs, diff --git a/modules/juce_gui_basics/buttons/juce_Button.h b/modules/juce_gui_basics/buttons/juce_Button.h index e9878fb09f0f..d6195a881a4d 100644 --- a/modules/juce_gui_basics/buttons/juce_Button.h +++ b/modules/juce_gui_basics/buttons/juce_Button.h @@ -384,6 +384,10 @@ class JUCE_API Button : public Component, /** Returns the button's current over/down/up state. */ ButtonState getState() const noexcept { return buttonState; } + + /** Acon Digital modification - keep track of focus change cause */ + FocusChangeType getLastFocusChangeCause(); + //============================================================================== /** This abstract base class is implemented by LookAndFeel classes to provide button-drawing functionality. @@ -524,6 +528,8 @@ class JUCE_API Button : public Component, bool triggerOnMouseDown = false; bool generateTooltip = false; + /** Acon Digital modification - keep track of focus change cause */ + FocusChangeType lastFocusChangeCause = focusChangedDirectly; void checkToggleableState (bool wasToggleable); void repeatTimerCallback(); diff --git a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp index f45e32bfd5e1..15315b61a7ca 100644 --- a/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp +++ b/modules/juce_gui_basics/commands/juce_ApplicationCommandManager.cpp @@ -59,11 +59,13 @@ void ApplicationCommandManager::registerCommand (const ApplicationCommandInfo& n // 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))); + + /** Acon Digital modification - disable unnecessary assert */ + //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; } diff --git a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp index 5fec572261ad..858e7c12a0fe 100644 --- a/modules/juce_gui_basics/drawables/juce_SVGParser.cpp +++ b/modules/juce_gui_basics/drawables/juce_SVGParser.cpp @@ -944,7 +944,9 @@ class SVGState FillType type (gradient); - auto gradientTransform = parseTransform (fillXml->getStringAttribute ("gradientTransform")); + /** Acon Digital modification - fixed error in SVG parsing */ + auto gradientTransform = parseTransform (fillXml->getStringAttribute ("gradientTransform")) + .followedBy (transform); if (gradient.isRadial) { diff --git a/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp b/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp index 95645ec45705..368b4626d45b 100644 --- a/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp +++ b/modules/juce_gui_basics/keyboard/juce_KeyPress.cpp @@ -176,7 +176,8 @@ KeyPress KeyPress::createFromDescription (const String& desc) int modifiers = 0; for (int i = 0; i < numElementsInArray (KeyPressHelpers::modifierNames); ++i) - if (desc.containsWholeWordIgnoreCase (KeyPressHelpers::modifierNames[i].name)) + /** Acon Digital modification - translate modifier names */ + if (desc.containsWholeWordIgnoreCase (TRANS (KeyPressHelpers::modifierNames[i].name))) modifiers |= KeyPressHelpers::modifierNames[i].flag; int key = 0; @@ -237,14 +238,15 @@ String KeyPress::getTextDescription() const if (textCharacter == '/' && keyCode != numberPadDivide) return "/"; - if (mods.isCtrlDown()) desc << "ctrl + "; - if (mods.isShiftDown()) desc << "shift + "; + /** Acon Digital modification - translate modifier names */ + if (mods.isCtrlDown()) desc << TRANS ("ctrl") + " + "; + if (mods.isShiftDown()) desc << TRANS ("shift") + " + "; #if JUCE_MAC || JUCE_IOS - if (mods.isAltDown()) desc << "option + "; - if (mods.isCommandDown()) desc << "command + "; + if (mods.isAltDown()) desc << TRANS ("option") + " + "; + if (mods.isCommandDown()) desc << TRANS ("command") + " + "; #else - if (mods.isAltDown()) desc << "alt + "; + if (mods.isAltDown()) desc << TRANS ("alt") + " + "; #endif for (int i = 0; i < numElementsInArray (KeyPressHelpers::translations); ++i) diff --git a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp index f898fa3c2060..fb1ea86617a2 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_windows.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_windows.cpp @@ -2085,6 +2085,8 @@ class HWNDComponentPeer final : public ComponentPeer, void repaint (const Rectangle& area) override { deferredRepaints.add ((area.toDouble() * getPlatformScaleFactor()).getSmallestIntegerContainer()); + /** Acon Digital modification - fix issues with freezed UI */ + dispatchDeferredRepaints(); } void dispatchDeferredRepaints() diff --git a/modules/juce_gui_basics/widgets/juce_ComboBox.cpp b/modules/juce_gui_basics/widgets/juce_ComboBox.cpp index bcedfe3c797e..e670545a06c8 100644 --- a/modules/juce_gui_basics/widgets/juce_ComboBox.cpp +++ b/modules/juce_gui_basics/widgets/juce_ComboBox.cpp @@ -548,7 +548,19 @@ void ComboBox::showPopup() ModalCallbackFunction::forComponent (comboBoxPopupMenuFinishedCallback, this)); } -//============================================================================== +/** Acon Digital modification - allow for visual mouse over indications */ +void ComboBox::mouseEnter (const MouseEvent& e) +{ + Component::mouseEnter (e); + repaint(); +} + +void ComboBox::mouseExit (const MouseEvent& e) +{ + Component::mouseExit (e); + repaint(); +} + void ComboBox::mouseDown (const MouseEvent& e) { beginDragAutoRepeat (300); diff --git a/modules/juce_gui_basics/widgets/juce_ComboBox.h b/modules/juce_gui_basics/widgets/juce_ComboBox.h index 15ee5fabd294..785a46e6113d 100644 --- a/modules/juce_gui_basics/widgets/juce_ComboBox.h +++ b/modules/juce_gui_basics/widgets/juce_ComboBox.h @@ -397,6 +397,11 @@ class JUCE_API ComboBox : public Component, void handleAsyncUpdate() override; /** @internal */ String getTooltip() override { return label->getTooltip(); } + /** Acon Digital modification - allow for visual mouse over indications */ + /** @internal */ + void mouseEnter (const MouseEvent&) override; + /** @internal */ + void mouseExit (const MouseEvent&) override; /** @internal */ void mouseDown (const MouseEvent&) override; /** @internal */ diff --git a/modules/juce_gui_basics/widgets/juce_Label.cpp b/modules/juce_gui_basics/widgets/juce_Label.cpp index 31dad478f551..f26049eabb3d 100644 --- a/modules/juce_gui_basics/widgets/juce_Label.cpp +++ b/modules/juce_gui_basics/widgets/juce_Label.cpp @@ -228,6 +228,10 @@ void Label::showEditor() editor->addListener (this); editor->grabKeyboardFocus(); + /** Acon Digital modification - allow edit boxes with centerred text */ + if (getJustificationType().testFlags (Justification::horizontallyCentred)) + editor->setJustification (Justification::centredTop); + if (editor == nullptr) // may be deleted by a callback return; diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp index c9360ed92327..fc92fc47d9d7 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp @@ -1839,7 +1839,19 @@ void TextEditor::performPopupMenuAction (const int menuItemID) } } -//============================================================================== +/** Acon Digital modification - allow for visual mouse over indications */ +void TextEditor::mouseEnter (const MouseEvent& e) +{ + Component::mouseEnter (e); + repaint(); +} + +void TextEditor::mouseExit (const MouseEvent& e) +{ + Component::mouseExit (e); + repaint(); +} + void TextEditor::mouseDown (const MouseEvent& e) { beginDragAutoRepeat (100); diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.h b/modules/juce_gui_basics/widgets/juce_TextEditor.h index c30decc618c9..8f84d28068c1 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.h +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.h @@ -711,6 +711,11 @@ class JUCE_API TextEditor : public TextInputTarget, void paint (Graphics&) override; /** @internal */ void paintOverChildren (Graphics&) override; + /** Acon Digital modification - allow for visual mouse over indications */ + /** @internal */ + void mouseEnter (const MouseEvent&) override; + /** @internal */ + void mouseExit (const MouseEvent&) override; /** @internal */ void mouseDown (const MouseEvent&) override; /** @internal */