- Library code update

- project update (added Eigen)

git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-12-20 20:59:48 +00:00
parent 1b4d8e9f54
commit dc5560392f
312 changed files with 6349 additions and 4195 deletions
@@ -53,24 +53,24 @@
MyJUCEApp() {}
~MyJUCEApp() {}
void initialise (const String& commandLine)
void initialise (const String& commandLine) override
{
myMainWindow = new MyApplicationWindow();
myMainWindow->setBounds (100, 100, 400, 500);
myMainWindow->setVisible (true);
}
void shutdown()
void shutdown() override
{
myMainWindow = nullptr;
}
const String getApplicationName()
const String getApplicationName() override
{
return "Super JUCE-o-matic";
}
const String getApplicationVersion()
const String getApplicationVersion() override
{
return "1.0";
}
@@ -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);
}
@@ -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));
@@ -363,9 +360,8 @@ public:
virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool isMouseOverButton, bool isButtonDown) = 0;
virtual Font getTextButtonFont (TextButton&) = 0;
virtual void changeTextButtonWidthToFitText (TextButton&, int newHeight) = 0;
virtual Font getTextButtonFont (TextButton&, int buttonHeight) = 0;
virtual int getTextButtonWidthToFitText (TextButton&, int buttonHeight) = 0;
/** Draws the text for a TextButton. */
virtual void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) = 0;
@@ -379,6 +375,13 @@ public:
bool ticked, bool isEnabled, bool isMouseOverButton, bool isButtonDown) = 0;
virtual void drawDrawableButton (Graphics&, DrawableButton&, bool isMouseOverButton, bool isButtonDown) = 0;
private:
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// These method have been deprecated: see their replacements above.
virtual int getTextButtonFont (TextButton&) { return 0; }
virtual int changeTextButtonWidthToFitText (TextButton&, int) { return 0; }
#endif
};
protected:
@@ -489,6 +492,7 @@ private:
void repeatTimerCallback();
bool keyStateChangedCallback();
void applicationCommandListChangeCallback();
void updateAutomaticTooltip (const ApplicationCommandInfo&);
ButtonState updateState();
ButtonState updateState (bool isOver, bool isDown);
@@ -80,6 +80,31 @@ void DrawableButton::setEdgeIndent (const int numPixelsIndent)
resized();
}
Rectangle<float> DrawableButton::getImageBounds() const
{
Rectangle<int> r (getLocalBounds());
if (style != ImageStretched)
{
int indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
int indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
if (style == ImageOnButtonBackground)
{
indentX = jmax (getWidth() / 4, indentX);
indentY = jmax (getHeight() / 4, indentY);
}
else if (style == ImageAboveTextLabel)
{
r = r.withTrimmedBottom (jmin (16, proportionOfHeight (0.25f)));
}
r = r.reduced (indentX, indentY);
}
return r.toFloat();
}
void DrawableButton::resized()
{
Button::resized();
@@ -87,36 +112,11 @@ void DrawableButton::resized()
if (currentImage != nullptr)
{
if (style == ImageRaw)
{
currentImage->setOriginWithOriginalSize (Point<float>());
}
else if (style == ImageStretched)
{
currentImage->setTransformToFit (getLocalBounds().toFloat(), RectanglePlacement::stretchToFit);
}
else
{
Rectangle<int> imageSpace;
const int indentX = jmin (edgeIndent, proportionOfWidth (0.3f));
const int indentY = jmin (edgeIndent, proportionOfHeight (0.3f));
if (style == ImageOnButtonBackground)
{
imageSpace = getLocalBounds().reduced (jmax (getWidth() / 4, indentX),
jmax (getHeight() / 4, indentY));
}
else
{
const int textH = (style == ImageAboveTextLabel) ? jmin (16, proportionOfHeight (0.25f)) : 0;
imageSpace.setBounds (indentX, indentY,
getWidth() - indentX * 2,
getHeight() - indentY * 2 - textH);
}
currentImage->setTransformToFit (imageSpace.toFloat(), RectanglePlacement::centred);
}
currentImage->setTransformToFit (getImageBounds(),
style == ImageStretched ? RectanglePlacement::stretchToFit
: RectanglePlacement::centred);
}
}
@@ -152,7 +152,7 @@ void DrawableButton::buttonStateChanged()
{
currentImage->setInterceptsMouseClicks (false, false);
addAndMakeVisible (currentImage);
DrawableButton::resized();
resized();
}
}
@@ -132,6 +132,9 @@ public:
/** Returns the image that the button will use when the mouse is held down on it. */
Drawable* getDownImage() const noexcept;
/** Can be overridden to specify a custom position for the image within the button. */
virtual Rectangle<float> getImageBounds() const;
//==============================================================================
/** A set of colour IDs to use to change the colour of various aspects of the link.
@@ -173,8 +176,8 @@ public:
private:
//==============================================================================
ButtonStyle style;
ScopedPointer <Drawable> normalImage, overImage, downImage, disabledImage,
normalImageOn, overImageOn, downImageOn, disabledImageOn;
ScopedPointer<Drawable> normalImage, overImage, downImage, disabledImage,
normalImageOn, overImageOn, downImageOn, disabledImageOn;
Drawable* currentImage;
int edgeIndent;
@@ -1,7 +1,6 @@
/*
==============================================================================
This file is part of the JUCE library.
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:
@@ -26,8 +25,11 @@ TextButton::TextButton() : Button (String())
{
}
TextButton::TextButton (const String& name, const String& toolTip)
: Button (name)
TextButton::TextButton (const String& name) : Button (name)
{
}
TextButton::TextButton (const String& name, const String& toolTip) : Button (name)
{
setTooltip (toolTip);
}
@@ -52,12 +54,17 @@ void TextButton::colourChanged()
repaint();
}
Font TextButton::getFont()
void TextButton::changeWidthToFitText()
{
return Font (jmin (15.0f, getHeight() * 0.6f));
changeWidthToFitText (getHeight());
}
void TextButton::changeWidthToFitText (const int newHeight)
{
getLookAndFeel().changeTextButtonWidthToFitText (*this, newHeight);
setSize (getBestWidthForHeight (newHeight), newHeight);
}
int TextButton::getBestWidthForHeight (int buttonHeight)
{
return getLookAndFeel().getTextButtonWidthToFitText (*this, buttonHeight);
}
@@ -44,11 +44,16 @@ public:
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
@param toolTip an optional string to use as a toolip
@see Button
*/
explicit TextButton (const String& buttonName,
const String& toolTip = String::empty);
explicit TextButton (const String& buttonName);
/** Creates a TextButton.
@param buttonName the text to put in the button (the component's name is also
initially set to this string, but these can be changed later
using the setName() and setButtonText() methods)
@param toolTip an optional string to use as a toolip
*/
TextButton (const String& buttonName, const String& toolTip);
/** Destructor. */
~TextButton();
@@ -74,17 +79,20 @@ public:
};
//==============================================================================
/** Resizes the button to fit neatly around its current text.
If newHeight is >= 0, the button's height will be changed to this
value. If it's less than zero, its height will be unaffected.
/** Changes this button's width to fit neatly around its current text, without
changing its height.
*/
void changeWidthToFitText (int newHeight = -1);
void changeWidthToFitText();
/** This can be overridden to use different fonts than the default one.
Note that you'll need to set the font's size appropriately, too.
/** Resizes the button's width to fit neatly around its current text, and gives it
the specified height.
*/
virtual Font getFont();
void changeWidthToFitText (int newHeight);
/** Returns the width that the LookAndFeel suggests would be best for this button if it
had the given height.
*/
int getBestWidthForHeight (int buttonHeight);
//==============================================================================
/** @internal */
@@ -93,6 +101,11 @@ public:
void colourChanged() override;
private:
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// Note that this method has been removed - instead, see LookAndFeel::getTextButtonWidthToFitText()
virtual int getFont() { return 0; }
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextButton)
};
@@ -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;
@@ -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
@@ -91,7 +91,7 @@ ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const C
while (target != nullptr)
{
Array <CommandID> commandIDs;
Array<CommandID> commandIDs;
target->getAllCommands (commandIDs);
if (commandIDs.contains (commandID))
@@ -113,7 +113,7 @@ ApplicationCommandTarget* ApplicationCommandTarget::getTargetForCommand (const C
if (target != nullptr)
{
Array <CommandID> commandIDs;
Array<CommandID> commandIDs;
target->getAllCommands (commandIDs);
if (commandIDs.contains (commandID))
@@ -134,7 +134,7 @@ public:
Your target should add all the command IDs that it handles to the array that is
passed-in.
*/
virtual void getAllCommands (Array <CommandID>& commands) = 0;
virtual void getAllCommands (Array<CommandID>& commands) = 0;
/** This must provide details about one of the commands that this target can perform.
@@ -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)
{
@@ -22,12 +22,6 @@
==============================================================================
*/
#define CHECK_MESSAGE_MANAGER_IS_LOCKED \
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
#define CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager() || getPeer() == nullptr);
Component* Component::currentlyFocusedComponent = nullptr;
@@ -147,7 +141,7 @@ public:
}
private:
Array <MouseListener*> listeners;
Array<MouseListener*> listeners;
int numDeepMouseListeners;
class BailOutChecker2
@@ -245,6 +239,15 @@ struct ScalingHelpers
{
return scaledScreenPosToUnscaled (comp.getDesktopScaleFactor(), pos);
}
static Point<int> addPosition (Point<int> p, const Component& c) noexcept { return p + c.getPosition(); }
static Rectangle<int> addPosition (Rectangle<int> p, const Component& c) noexcept { return p + c.getPosition(); }
static Point<float> addPosition (Point<float> p, const Component& c) noexcept { return p + c.getPosition().toFloat(); }
static Rectangle<float> addPosition (Rectangle<float> p, const Component& c) noexcept { return p + c.getPosition().toFloat(); }
static Point<int> subtractPosition (Point<int> p, const Component& c) noexcept { return p - c.getPosition(); }
static Rectangle<int> subtractPosition (Rectangle<int> p, const Component& c) noexcept { return p - c.getPosition(); }
static Point<float> subtractPosition (Point<float> p, const Component& c) noexcept { return p - c.getPosition().toFloat(); }
static Rectangle<float> subtractPosition (Rectangle<float> p, const Component& c) noexcept { return p - c.getPosition().toFloat(); }
};
//==============================================================================
@@ -253,7 +256,7 @@ struct Component::ComponentHelpers
#if JUCE_MODAL_LOOPS_PERMITTED
static void* runModalLoopCallback (void* userData)
{
return (void*) (pointer_sized_int) static_cast <Component*> (userData)->runModalLoop();
return (void*) (pointer_sized_int) static_cast<Component*> (userData)->runModalLoop();
}
#endif
@@ -327,7 +330,7 @@ struct Component::ComponentHelpers
}
else
{
pointInParentSpace -= comp.getPosition();
pointInParentSpace = ScalingHelpers::subtractPosition (pointInParentSpace, comp);
}
return pointInParentSpace;
@@ -346,7 +349,7 @@ struct Component::ComponentHelpers
}
else
{
pointInLocalSpace += comp.getPosition();
pointInLocalSpace = ScalingHelpers::addPosition (pointInLocalSpace, comp);
}
if (comp.affineTransform != nullptr)
@@ -396,16 +399,6 @@ struct Component::ComponentHelpers
return convertFromDistantParentSpace (topLevelComp, *target, p);
}
static Rectangle<int> getUnclippedArea (const Component& comp)
{
Rectangle<int> r (comp.getLocalBounds());
if (Component* const p = comp.getParentComponent())
r = r.getIntersection (convertFromParentSpace (comp, getUnclippedArea (*p)));
return r;
}
static bool clipObscuredRegions (const Component& comp, Graphics& g, const Rectangle<int>& clipRect, Point<int> delta)
{
bool nothingChanged = true;
@@ -438,35 +431,6 @@ struct Component::ComponentHelpers
return nothingChanged;
}
static void subtractObscuredRegions (const Component& comp, RectangleList<int>& result,
Point<int> delta, const Rectangle<int>& clipRect,
const Component* const compToAvoid)
{
for (int i = comp.childComponentList.size(); --i >= 0;)
{
const Component* const c = comp.childComponentList.getUnchecked(i);
if (c != compToAvoid && c->isVisible())
{
if (c->isOpaque() && c->componentTransparency == 0)
{
Rectangle<int> childBounds (c->bounds.getIntersection (clipRect));
childBounds.translate (delta.x, delta.y);
result.subtract (childBounds);
}
else
{
Rectangle<int> newClip (clipRect.getIntersection (c->bounds));
newClip.translate (-c->getX(), -c->getY());
subtractObscuredRegions (*c, result, c->getPosition() + delta,
newClip, compToAvoid);
}
}
}
}
static Rectangle<int> getParentOrMainMonitorBounds (const Component& comp)
{
if (Component* p = comp.getParentComponent())
@@ -477,7 +441,7 @@ struct Component::ComponentHelpers
};
//==============================================================================
Component::Component()
Component::Component() noexcept
: parentComponent (nullptr),
lookAndFeel (nullptr),
effect (nullptr),
@@ -486,7 +450,7 @@ Component::Component()
{
}
Component::Component (const String& name)
Component::Component (const String& name) noexcept
: componentName (name),
parentComponent (nullptr),
lookAndFeel (nullptr),
@@ -524,7 +488,7 @@ void Component::setName (const String& name)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
if (componentName != name)
{
@@ -550,7 +514,7 @@ void Component::setVisible (bool shouldBeVisible)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
const WeakReference<Component> safePointer (this);
flags.visibleFlag = shouldBeVisible;
@@ -617,7 +581,6 @@ bool Component::isShowing() const
return false;
}
//==============================================================================
void* Component::getWindowHandle() const
{
@@ -632,7 +595,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (isOpaque())
styleWanted &= ~ComponentPeer::windowIsSemiTransparent;
@@ -659,7 +622,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
bool wasFullscreen = false;
bool wasMinimised = false;
ComponentBoundsConstrainer* currentConstainer = nullptr;
ComponentBoundsConstrainer* currentConstrainer = nullptr;
Rectangle<int> oldNonFullScreenBounds;
int oldRenderingEngine = -1;
@@ -669,7 +632,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
wasFullscreen = peer->isFullScreen();
wasMinimised = peer->isMinimised();
currentConstainer = peer->getConstrainer();
currentConstrainer = peer->getConstrainer();
oldNonFullScreenBounds = peer->getNonFullScreenBounds();
oldRenderingEngine = peer->getCurrentRenderingEngine();
@@ -720,7 +683,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
peer->setAlwaysOnTop (true);
#endif
peer->setConstrainer (currentConstainer);
peer->setConstrainer (currentConstrainer);
repaint();
internalHierarchyChanged();
@@ -732,7 +695,7 @@ void Component::removeFromDesktop()
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
if (flags.hasHeavyweightPeerFlag)
{
@@ -877,7 +840,7 @@ void Component::setBufferedToImage (const bool shouldBeBuffered)
// so by calling setBufferedToImage, you'll be deleting the custom one - this is almost certainly
// not what you wanted to happen... If you really do know what you're doing here, and want to
// avoid this assertion, just call setCachedComponentImage (nullptr) before setBufferedToImage().
jassert (cachedImage == nullptr || dynamic_cast <StandardCachedComponentImage*> (cachedImage.get()) != nullptr);
jassert (cachedImage == nullptr || dynamic_cast<StandardCachedComponentImage*> (cachedImage.get()) != nullptr);
if (shouldBeBuffered)
{
@@ -910,7 +873,7 @@ void Component::toFront (const bool setAsForeground)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
if (flags.hasHeavyweightPeerFlag)
{
@@ -1092,6 +1055,11 @@ Point<int> Component::getLocalPoint (const Component* source, Point<int> point)
return ComponentHelpers::convertCoordinate (this, source, point);
}
Point<float> Component::getLocalPoint (const Component* source, Point<float> point) const
{
return ComponentHelpers::convertCoordinate (this, source, point);
}
Rectangle<int> Component::getLocalArea (const Component* source, const Rectangle<int>& area) const
{
return ComponentHelpers::convertCoordinate (this, source, area);
@@ -1102,6 +1070,11 @@ Point<int> Component::localPointToGlobal (Point<int> point) const
return ComponentHelpers::convertCoordinate (nullptr, this, point);
}
Point<float> Component::localPointToGlobal (Point<float> point) const
{
return ComponentHelpers::convertCoordinate (nullptr, this, point);
}
Rectangle<int> Component::localAreaToGlobal (const Rectangle<int>& area) const
{
return ComponentHelpers::convertCoordinate (nullptr, this, area);
@@ -1130,7 +1103,7 @@ void Component::setBounds (const int x, const int y, int w, int h)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
if (w < 0) w = 0;
if (h < 0) h = 0;
@@ -1169,11 +1142,25 @@ void Component::setBounds (const int x, const int y, int w, int h)
cachedImage->invalidateAll();
}
flags.isMoveCallbackPending = wasMoved;
flags.isResizeCallbackPending = wasResized;
if (flags.hasHeavyweightPeerFlag)
if (ComponentPeer* const peer = getPeer())
peer->updateBounds();
sendMovedResizedMessages (wasMoved, wasResized);
sendMovedResizedMessagesIfPending();
}
}
void Component::sendMovedResizedMessagesIfPending()
{
if (flags.isMoveCallbackPending || flags.isResizeCallbackPending)
{
sendMovedResizedMessages (flags.isMoveCallbackPending, flags.isResizeCallbackPending);
flags.isMoveCallbackPending = false;
flags.isResizeCallbackPending = false;
}
}
@@ -1463,7 +1450,7 @@ void Component::addChildComponent (Component& child, int zOrder)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
if (child.parentComponent != this)
{
@@ -1539,7 +1526,7 @@ Component* Component::removeChildComponent (const int index, bool sendParentEven
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN
Component* const child = childComponentList [index];
@@ -1616,7 +1603,7 @@ Component* Component::getChildComponent (const int index) const noexcept
int Component::getIndexOfChildComponent (const Component* const child) const noexcept
{
return childComponentList.indexOf (const_cast <Component*> (child));
return childComponentList.indexOf (const_cast<Component*> (child));
}
Component* Component::findChildWithID (StringRef targetID) const noexcept
@@ -1638,7 +1625,7 @@ Component* Component::getTopLevelComponent() const noexcept
while (comp->parentComponent != nullptr)
comp = comp->parentComponent;
return const_cast <Component*> (comp);
return const_cast<Component*> (comp);
}
bool Component::isParentOf (const Component* possibleChild) const noexcept
@@ -1730,7 +1717,7 @@ void Component::enterModalState (const bool shouldTakeKeyboardFocus,
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
// Check for an attempt to make a component modal when it already is!
// This can cause nasty problems..
@@ -1917,7 +1904,7 @@ void Component::internalRepaintUnchecked (const Rectangle<int>& area, const bool
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (ComponentPeer* const peer = getPeer())
{
@@ -2034,6 +2021,14 @@ void Component::paintComponentAndChildren (Graphics& g)
void Component::paintEntireComponent (Graphics& g, const bool ignoreAlphaLevel)
{
// If sizing a top-level-window and the OS paint message is delivered synchronously
// before resized() is called, then we'll invoke the callback here, to make sure
// the components inside have had a chance to sort their sizes out..
#if JUCE_DEBUG
if (! flags.isInsidePaintCall) // (avoids an assertion in plugins hosted in WaveLab)
#endif
sendMovedResizedMessagesIfPending();
#if JUCE_DEBUG
flags.isInsidePaintCall = true;
#endif
@@ -2170,7 +2165,7 @@ void Component::sendLookAndFeelChange()
Colour Component::findColour (const int colourId, const bool inheritFromParent) const
{
if (const var* const v = properties.getVarPointer (ComponentHelpers::getColourPropertyId (colourId)))
return Colour ((uint32) static_cast <int> (*v));
return Colour ((uint32) static_cast<int> (*v));
if (inheritFromParent && parentComponent != nullptr
&& (lookAndFeel == nullptr || ! lookAndFeel->isColourSpecified (colourId)))
@@ -2249,28 +2244,6 @@ Rectangle<int> Component::getBoundsInParent() const noexcept
: bounds.transformedBy (*affineTransform);
}
void Component::getVisibleArea (RectangleList<int>& result, const bool includeSiblings) const
{
result.clear();
const Rectangle<int> unclipped (ComponentHelpers::getUnclippedArea (*this));
if (! unclipped.isEmpty())
{
result.add (unclipped);
if (includeSiblings)
{
const Component* const c = getTopLevelComponent();
ComponentHelpers::subtractObscuredRegions (*c, result, getLocalPoint (c, Point<int>()),
c->getLocalBounds(), this);
}
ComponentHelpers::subtractObscuredRegions (*this, result, Point<int>(), unclipped, nullptr);
result.consolidate();
}
}
//==============================================================================
void Component::mouseEnter (const MouseEvent&) {}
void Component::mouseExit (const MouseEvent&) {}
@@ -2306,7 +2279,7 @@ void Component::addComponentListener (ComponentListener* const newListener)
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
#if JUCE_DEBUG || JUCE_LOG_ASSERTIONS
if (getParentComponent() != nullptr)
CHECK_MESSAGE_MANAGER_IS_LOCKED;
ASSERT_MESSAGE_MANAGER_IS_LOCKED;
#endif
componentListeners.add (newListener);
@@ -2369,7 +2342,7 @@ void Component::addMouseListener (MouseListener* const newListener,
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
// If you register a component as a mouselistener for itself, it'll receive all the events
// twice - once via the direct callback that all components get anyway, and then again as a listener!
@@ -2385,14 +2358,14 @@ void Component::removeMouseListener (MouseListener* const listenerToRemove)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (mouseListeners != nullptr)
mouseListeners->removeListener (listenerToRemove);
}
//==============================================================================
void Component::internalMouseEnter (MouseInputSource source, Point<int> relativePos, Time time)
void Component::internalMouseEnter (MouseInputSource source, Point<float> relativePos, Time time)
{
if (isCurrentlyBlockedByAnotherModalComponent())
{
@@ -2418,7 +2391,7 @@ void Component::internalMouseEnter (MouseInputSource source, Point<int> relative
MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseEnter, me);
}
void Component::internalMouseExit (MouseInputSource source, Point<int> relativePos, Time time)
void Component::internalMouseExit (MouseInputSource source, Point<float> relativePos, Time time)
{
if (flags.repaintOnMouseActivityFlag)
repaint();
@@ -2438,7 +2411,7 @@ void Component::internalMouseExit (MouseInputSource source, Point<int> relativeP
MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseExit, me);
}
void Component::internalMouseDown (MouseInputSource source, Point<int> relativePos, Time time)
void Component::internalMouseDown (MouseInputSource source, Point<float> relativePos, Time time)
{
Desktop& desktop = Desktop::getInstance();
BailOutChecker checker (this);
@@ -2502,7 +2475,7 @@ void Component::internalMouseDown (MouseInputSource source, Point<int> relativeP
MouseListenerList::sendMouseEvent (*this, checker, &MouseListener::mouseDown, me);
}
void Component::internalMouseUp (MouseInputSource source, Point<int> relativePos,
void Component::internalMouseUp (MouseInputSource source, Point<float> relativePos,
Time time, const ModifierKeys oldModifiers)
{
if (flags.mouseDownWasBlocked && isCurrentlyBlockedByAnotherModalComponent())
@@ -2545,7 +2518,7 @@ void Component::internalMouseUp (MouseInputSource source, Point<int> relativePos
}
}
void Component::internalMouseDrag (MouseInputSource source, Point<int> relativePos, Time time)
void Component::internalMouseDrag (MouseInputSource source, Point<float> relativePos, Time time)
{
if (! isCurrentlyBlockedByAnotherModalComponent())
{
@@ -2568,7 +2541,7 @@ void Component::internalMouseDrag (MouseInputSource source, Point<int> relativeP
}
}
void Component::internalMouseMove (MouseInputSource source, Point<int> relativePos, Time time)
void Component::internalMouseMove (MouseInputSource source, Point<float> relativePos, Time time)
{
Desktop& desktop = Desktop::getInstance();
@@ -2594,7 +2567,7 @@ void Component::internalMouseMove (MouseInputSource source, Point<int> relativeP
}
}
void Component::internalMouseWheel (MouseInputSource source, Point<int> relativePos,
void Component::internalMouseWheel (MouseInputSource source, Point<float> relativePos,
Time time, const MouseWheelDetails& wheel)
{
Desktop& desktop = Desktop::getInstance();
@@ -2622,7 +2595,7 @@ void Component::internalMouseWheel (MouseInputSource source, Point<int> relative
}
}
void Component::internalMagnifyGesture (MouseInputSource source, Point<int> relativePos,
void Component::internalMagnifyGesture (MouseInputSource source, Point<float> relativePos,
Time time, float amount)
{
if (! isCurrentlyBlockedByAnotherModalComponent())
@@ -2821,7 +2794,7 @@ void Component::grabFocusInternal (const FocusChangeType cause, const bool canTr
else
{
// find the default child component..
ScopedPointer <KeyboardFocusTraverser> traverser (createFocusTraverser());
ScopedPointer<KeyboardFocusTraverser> traverser (createFocusTraverser());
if (traverser != nullptr)
{
@@ -2850,7 +2823,7 @@ void Component::grabKeyboardFocus()
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
grabFocusInternal (focusChangedDirectly, true);
}
@@ -2859,11 +2832,11 @@ void Component::moveKeyboardFocusToSibling (const bool moveToNext)
{
// if component methods are being called from threads other than the message
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
CHECK_MESSAGE_MANAGER_IS_LOCKED
ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (parentComponent != nullptr)
{
ScopedPointer <KeyboardFocusTraverser> traverser (createFocusTraverser());
ScopedPointer<KeyboardFocusTraverser> traverser (createFocusTraverser());
if (traverser != nullptr)
{
@@ -2972,7 +2945,7 @@ bool Component::isMouseOver (const bool includeChildren) const
Component* const c = mi->getComponentUnderMouse();
if ((c == this || (includeChildren && isParentOf (c)))
&& c->reallyContains (c->getLocalPoint (nullptr, mi->getScreenPosition()), false)
&& c->reallyContains (c->getLocalPoint (nullptr, mi->getScreenPosition()).roundToInt(), false)
&& (mi->isMouse() || mi->isDragging()))
return true;
}
@@ -3017,7 +2990,7 @@ Point<int> Component::getMouseXYRelative() const
void Component::addKeyListener (KeyListener* const newListener)
{
if (keyListeners == nullptr)
keyListeners = new Array <KeyListener*>();
keyListeners = new Array<KeyListener*>();
keyListeners->addIfNotAlreadyThere (newListener);
}
@@ -46,7 +46,7 @@ public:
subclass of Component or use one of the other types of component from
the library.
*/
Component();
Component() noexcept;
/** Destructor.
@@ -66,7 +66,7 @@ public:
/** Creates a component, setting its name at the same time.
@see getName, setName
*/
explicit Component (const String& componentName);
explicit Component (const String& componentName) noexcept;
/** Returns the name of this component.
@see setName
@@ -315,16 +315,6 @@ public:
*/
Rectangle<int> getBoundsInParent() const noexcept;
/** Returns the region of this component that's not obscured by other, opaque components.
The RectangleList that is returned represents the area of this component
which isn't covered by opaque child components.
If includeSiblings is true, it will also take into account any siblings
that may be overlapping the component.
*/
void getVisibleArea (RectangleList<int>& result, bool includeSiblings) const;
//==============================================================================
/** Returns this component's x coordinate relative the screen's top-left origin.
@see getX, localPointToGlobal
@@ -355,6 +345,15 @@ public:
Point<int> getLocalPoint (const Component* sourceComponent,
Point<int> pointRelativeToSourceComponent) const;
/** Converts a point to be relative to this component's coordinate space.
This takes a point relative to a different component, and returns its position relative to this
component. If the sourceComponent parameter is null, the source point is assumed to be a global
screen coordinate.
*/
Point<float> getLocalPoint (const Component* sourceComponent,
Point<float> pointRelativeToSourceComponent) const;
/** Converts a rectangle to be relative to this component's coordinate space.
This takes a rectangle that is relative to a different component, and returns its position relative
@@ -373,6 +372,11 @@ public:
*/
Point<int> localPointToGlobal (Point<int> localPoint) const;
/** Converts a point relative to this component's top-left into a screen coordinate.
@see getLocalPoint, localAreaToGlobal
*/
Point<float> localPointToGlobal (Point<float> localPoint) const;
/** Converts a rectangle from this component's coordinate space to a screen coordinate.
If you've used setTransform() to apply one or more transforms to components, then the source rectangle
@@ -793,7 +797,7 @@ public:
TargetClass* findParentComponentOfClass() const
{
for (Component* p = parentComponent; p != nullptr; p = p->parentComponent)
if (TargetClass* const target = dynamic_cast <TargetClass*> (p))
if (TargetClass* const target = dynamic_cast<TargetClass*> (p))
return target;
return nullptr;
@@ -1152,7 +1156,7 @@ public:
By default, components are considered transparent, unless this is used to
make it otherwise.
@see isOpaque, getVisibleArea
@see isOpaque
*/
void setOpaque (bool shouldBeOpaque);
@@ -1743,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
*/
@@ -1782,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;
@@ -2122,31 +2127,31 @@ public:
SafePointer() noexcept {}
/** Creates a SafePointer that points at the given component. */
SafePointer (ComponentType* const component) : weakRef (component) {}
SafePointer (ComponentType* component) : weakRef (component) {}
/** Creates a copy of another SafePointer. */
SafePointer (const SafePointer& other) noexcept : weakRef (other.weakRef) {}
SafePointer (const SafePointer& other) noexcept : weakRef (other.weakRef) {}
/** Copies another pointer to this one. */
SafePointer& operator= (const SafePointer& other) { weakRef = other.weakRef; return *this; }
SafePointer& operator= (const SafePointer& other) { weakRef = other.weakRef; return *this; }
/** Copies another pointer to this one. */
SafePointer& operator= (ComponentType* const newComponent) { weakRef = newComponent; return *this; }
SafePointer& operator= (ComponentType* newComponent) { weakRef = newComponent; return *this; }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
ComponentType* getComponent() const noexcept { return dynamic_cast <ComponentType*> (weakRef.get()); }
ComponentType* getComponent() const noexcept { return dynamic_cast<ComponentType*> (weakRef.get()); }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
operator ComponentType*() const noexcept { return getComponent(); }
operator ComponentType*() const noexcept { return getComponent(); }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
ComponentType* operator->() noexcept { return getComponent(); }
ComponentType* operator->() noexcept { return getComponent(); }
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
const ComponentType* operator->() const noexcept { return getComponent(); }
const ComponentType* operator->() const noexcept { return getComponent(); }
/** If the component is valid, this deletes it and sets this pointer to null. */
void deleteAndZero() { delete getComponent(); }
void deleteAndZero() { delete getComponent(); }
bool operator== (ComponentType* component) const noexcept { return weakRef == component; }
bool operator!= (ComponentType* component) const noexcept { return weakRef != component; }
@@ -2254,20 +2259,20 @@ private:
String componentName, componentID;
Component* parentComponent;
Rectangle<int> bounds;
ScopedPointer <Positioner> positioner;
ScopedPointer <AffineTransform> affineTransform;
Array <Component*> childComponentList;
ScopedPointer<Positioner> positioner;
ScopedPointer<AffineTransform> affineTransform;
Array<Component*> childComponentList;
LookAndFeel* lookAndFeel;
MouseCursor cursor;
ImageEffectFilter* effect;
ScopedPointer <CachedComponentImage> cachedImage;
ScopedPointer<CachedComponentImage> cachedImage;
class MouseListenerList;
friend class MouseListenerList;
friend struct ContainerDeletePolicy<MouseListenerList>;
ScopedPointer <MouseListenerList> mouseListeners;
ScopedPointer <Array <KeyListener*> > keyListeners;
ListenerList <ComponentListener> componentListeners;
ScopedPointer<MouseListenerList> mouseListeners;
ScopedPointer<Array<KeyListener*> > keyListeners;
ListenerList<ComponentListener> componentListeners;
NamedValueSet properties;
friend class WeakReference<Component>;
@@ -2292,9 +2297,11 @@ private:
bool childCompFocusedFlag : 1;
bool dontClipGraphicsFlag : 1;
bool mouseDownWasBlocked : 1;
#if JUCE_DEBUG
bool isMoveCallbackPending : 1;
bool isResizeCallbackPending : 1;
#if JUCE_DEBUG
bool isInsidePaintCall : 1;
#endif
#endif
};
union
@@ -2306,18 +2313,18 @@ private:
uint8 componentTransparency;
//==============================================================================
void internalMouseEnter (MouseInputSource, Point<int>, Time);
void internalMouseExit (MouseInputSource, Point<int>, Time);
void internalMouseDown (MouseInputSource, Point<int>, Time);
void internalMouseUp (MouseInputSource, Point<int>, Time, const ModifierKeys oldModifiers);
void internalMouseDrag (MouseInputSource, Point<int>, Time);
void internalMouseMove (MouseInputSource, Point<int>, Time);
void internalMouseWheel (MouseInputSource, Point<int>, Time, const MouseWheelDetails&);
void internalMagnifyGesture (MouseInputSource, Point<int>, Time, float);
void internalMouseEnter (MouseInputSource, Point<float>, Time);
void internalMouseExit (MouseInputSource, Point<float>, Time);
void internalMouseDown (MouseInputSource, Point<float>, Time);
void internalMouseUp (MouseInputSource, Point<float>, Time, const ModifierKeys oldModifiers);
void internalMouseDrag (MouseInputSource, Point<float>, Time);
void internalMouseMove (MouseInputSource, Point<float>, Time);
void internalMouseWheel (MouseInputSource, Point<float>, Time, const MouseWheelDetails&);
void internalMagnifyGesture (MouseInputSource, Point<float>, Time, float);
void internalBroughtToFront();
void internalFocusGain (const FocusChangeType, const WeakReference<Component>&);
void internalFocusGain (const FocusChangeType);
void internalFocusLoss (const FocusChangeType);
void internalFocusGain (FocusChangeType, const WeakReference<Component>&);
void internalFocusGain (FocusChangeType);
void internalFocusLoss (FocusChangeType);
void internalChildFocusChange (FocusChangeType, const WeakReference<Component>&);
void internalModalInputAttempt();
void internalModifierKeysChanged();
@@ -2330,6 +2337,7 @@ private:
void paintComponentAndChildren (Graphics&);
void paintWithinParentContext (Graphics&);
void sendMovedResizedMessages (bool wasMoved, bool wasResized);
void sendMovedResizedMessagesIfPending();
void repaintParent();
void sendFakeMouseMove() const;
void takeKeyboardFocus (const FocusChangeType);
@@ -68,6 +68,8 @@ Component* Desktop::getComponent (const int index) const noexcept
Component* Desktop::findComponentAt (Point<int> screenPosition) const
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
for (int i = desktopComponents.size(); --i >= 0;)
{
Component* const c = desktopComponents.getUnchecked(i);
@@ -100,6 +102,7 @@ LookAndFeel& Desktop::getDefaultLookAndFeel() noexcept
void Desktop::setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel)
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
currentLookAndFeel = newDefaultLookAndFeel;
for (int i = getNumComponents(); --i >= 0;)
@@ -145,18 +148,23 @@ void Desktop::componentBroughtToFront (Component* const c)
//==============================================================================
Point<int> Desktop::getMousePosition()
{
return getMousePositionFloat().roundToInt();
}
Point<float> Desktop::getMousePositionFloat()
{
return getInstance().getMainMouseSource().getScreenPosition();
}
void Desktop::setMousePosition (Point<int> newPosition)
{
getInstance().getMainMouseSource().setScreenPosition (newPosition);
getInstance().getMainMouseSource().setScreenPosition (newPosition.toFloat());
}
Point<int> Desktop::getLastMouseDownPosition()
{
return getInstance().getMainMouseSource().getLastMouseDownPosition();
return getInstance().getMainMouseSource().getLastMouseDownPosition().roundToInt();
}
int Desktop::getMouseButtonClickCounter() const noexcept { return mouseClickCounter; }
@@ -194,10 +202,10 @@ void Desktop::resetTimer()
else
startTimer (100);
lastFakeMouseMove = getMousePosition();
lastFakeMouseMove = getMousePositionFloat();
}
ListenerList <MouseListener>& Desktop::getMouseListeners()
ListenerList<MouseListener>& Desktop::getMouseListeners()
{
resetTimer();
return mouseListeners;
@@ -205,19 +213,21 @@ ListenerList <MouseListener>& Desktop::getMouseListeners()
void Desktop::addGlobalMouseListener (MouseListener* const listener)
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
mouseListeners.add (listener);
resetTimer();
}
void Desktop::removeGlobalMouseListener (MouseListener* const listener)
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
mouseListeners.remove (listener);
resetTimer();
}
void Desktop::timerCallback()
{
if (lastFakeMouseMove != getMousePosition())
if (lastFakeMouseMove != getMousePositionFloat())
sendMouseMove();
}
@@ -227,12 +237,12 @@ void Desktop::sendMouseMove()
{
startTimer (20);
lastFakeMouseMove = getMousePosition();
lastFakeMouseMove = getMousePositionFloat();
if (Component* const target = findComponentAt (lastFakeMouseMove))
if (Component* const target = findComponentAt (lastFakeMouseMove.roundToInt()))
{
Component::BailOutChecker checker (target);
const Point<int> pos (target->getLocalPoint (nullptr, lastFakeMouseMove));
const Point<float> pos (target->getLocalPoint (nullptr, lastFakeMouseMove));
const Time now (Time::getCurrentTime());
const MouseEvent me (getMainMouseSource(), pos, ModifierKeys::getCurrentModifiers(),
@@ -253,12 +263,14 @@ Desktop::Displays::~Displays() {}
const Desktop::Displays::Display& Desktop::Displays::getMainDisplay() const noexcept
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
jassert (displays.getReference(0).isMain);
return displays.getReference(0);
}
const Desktop::Displays::Display& Desktop::Displays::getDisplayContaining (Point<int> position) const noexcept
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
const Display* best = &displays.getReference(0);
double bestDistance = 1.0e10;
@@ -286,6 +298,7 @@ const Desktop::Displays::Display& Desktop::Displays::getDisplayContaining (Point
RectangleList<int> Desktop::Displays::getRectangleList (bool userAreasOnly) const
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
RectangleList<int> rl;
for (int i = 0; i < displays.size(); ++i)
@@ -329,6 +342,7 @@ void Desktop::Displays::refresh()
oldDisplays.swapWith (displays);
init (Desktop::getInstance());
jassert (displays.size() > 0);
if (oldDisplays != displays)
{
@@ -391,6 +405,8 @@ bool Desktop::isOrientationEnabled (const DisplayOrientation orientation) const
void Desktop::setGlobalScaleFactor (float newScaleFactor) noexcept
{
ASSERT_MESSAGE_MANAGER_IS_LOCKED
if (masterScaleFactor != newScaleFactor)
{
masterScaleFactor = newScaleFactor;
@@ -414,7 +414,7 @@ private:
ScopedPointer<Displays> displays;
Point<int> lastFakeMouseMove;
Point<float> lastFakeMouseMove;
void sendMouseMove();
int mouseClickCounter, mouseWheelCounter;
@@ -441,11 +441,13 @@ private:
void removeDesktopComponent (Component*);
void componentBroughtToFront (Component*);
void setKioskComponent (Component*, bool enableOrDisable, bool allowMenusAndBars);
void setKioskComponent (Component*, bool shouldBeEnabled, bool allowMenusAndBars);
void triggerFocusCallback();
void handleAsyncUpdate() override;
static Point<float> getMousePositionFloat();
static double getDefaultMasterScale();
Desktop();
@@ -234,6 +234,17 @@ void ModalComponentManager::bringModalComponentsToFront (bool topOneShouldGrabFo
}
}
bool ModalComponentManager::cancelAllModalComponents()
{
const int numModal = getNumModalComponents();
for (int i = numModal; --i >= 0;)
if (Component* const c = getModalComponent(i))
c->exitModalState (0);
return numModal > 0;
}
#if JUCE_MODAL_LOOPS_PERMITTED
class ModalComponentManager::ReturnValueRetriever : public ModalComponentManager::Callback
{
@@ -107,6 +107,11 @@ public:
/** Brings any modal components to the front. */
void bringModalComponentsToFront (bool topOneShouldGrabFocus = true);
/** Calls exitModalState (0) on any components that are currently modal.
@returns true if any components were modal; false if nothing needed cancelling
*/
bool cancelAllModalComponents();
#if JUCE_MODAL_LOOPS_PERMITTED
/** Runs the event loop until the currently topmost modal component is dismissed, and
returns the exit code for that component.
@@ -54,7 +54,7 @@ public:
DrawableComposite* const drawable = new DrawableComposite();
drawable->setName (xml->getStringAttribute ("id"));
setDrawableID (*drawable, xml);
SVGState newState (*this);
@@ -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
@@ -349,6 +331,11 @@ public:
if (! carryOn)
break;
}
// paths that finish back at their start position often seem to be
// left without a 'z', so need to be closed explicitly..
if (path.getCurrentPosition() == subpathStart)
path.closeSubPath();
}
private:
@@ -358,6 +345,13 @@ private:
AffineTransform transform;
String cssStyleText;
static void setDrawableID (Drawable& d, const XmlPath& xml)
{
String compID (xml->getStringAttribute ("id"));
d.setName (compID);
d.setComponentID (compID);
}
//==============================================================================
void parseSubElements (const XmlPath& xml, DrawableComposite& parentDrawable)
{
@@ -397,7 +391,7 @@ private:
{
DrawableComposite* const drawable = new DrawableComposite();
drawable->setName (xml->getStringAttribute ("id"));
setDrawableID (*drawable, xml);
if (xml->hasAttribute ("transform"))
{
@@ -542,30 +536,18 @@ private:
}
DrawablePath* dp = new DrawablePath();
dp->setName (xml->getStringAttribute ("id"));
setDrawableID (*dp, xml);
dp->setFill (Colours::transparentBlack);
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"));
@@ -582,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;
@@ -784,44 +775,41 @@ private:
return parseColour (fill, i, defaultColour).withMultipliedAlpha (opacity);
}
static PathStrokeType::JointStyle getJointStyle (const String& join) noexcept
{
if (join.equalsIgnoreCase ("round")) return PathStrokeType::curved;
if (join.equalsIgnoreCase ("bevel")) return PathStrokeType::beveled;
return PathStrokeType::mitered;
}
static PathStrokeType::EndCapStyle getEndCapStyle (const String& cap) noexcept
{
if (cap.equalsIgnoreCase ("round")) return PathStrokeType::rounded;
if (cap.equalsIgnoreCase ("square")) return PathStrokeType::square;
return PathStrokeType::butt;
}
float getStrokeWidth (const String& strokeWidth) const noexcept
{
return transform.getScaleFactor() * getCoordLength (strokeWidth, viewBoxW);
}
PathStrokeType getStrokeFor (const XmlPath& xml) const
{
const String strokeWidth (getStyleAttribute (xml, "stroke-width"));
const String cap (getStyleAttribute (xml, "stroke-linecap"));
const String join (getStyleAttribute (xml, "stroke-linejoin"));
//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;
if (join.equalsIgnoreCase ("round"))
joinStyle = PathStrokeType::curved;
else if (join.equalsIgnoreCase ("bevel"))
joinStyle = PathStrokeType::beveled;
if (cap.equalsIgnoreCase ("round"))
capStyle = PathStrokeType::rounded;
else if (cap.equalsIgnoreCase ("square"))
capStyle = PathStrokeType::square;
float ox = 0.0f, oy = 0.0f;
float x = getCoordLength (strokeWidth, viewBoxW), y = 0.0f;
transform.transformPoints (ox, oy, x, y);
return PathStrokeType (strokeWidth.isNotEmpty() ? juce_hypot (x - ox, y - oy) : 1.0f,
joinStyle, capStyle);
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);
@@ -886,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();
@@ -908,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;
@@ -948,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))
@@ -988,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);
@@ -999,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;
@@ -1209,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;
@@ -115,8 +115,7 @@ void DirectoryContentsList::setFileFilter (const FileFilter* newFileFilter)
}
//==============================================================================
bool DirectoryContentsList::getFileInfo (const int index,
FileInfo& result) const
bool DirectoryContentsList::getFileInfo (const int index, FileInfo& result) const
{
const ScopedLock sl (fileListLock);
@@ -222,7 +221,7 @@ struct FileInfoComparator
return first->isDirectory ? -1 : 1;
#endif
return first->filename.compareIgnoreCase (second->filename);
return first->filename.compareNatural (second->filename);
}
};
@@ -203,7 +203,7 @@ void FileChooserDialogBox::okButtonPressed()
{
AlertWindow::showOkCancelBox (AlertWindow::WarningIcon,
TRANS("File already exists"),
TRANS("There's already a file called: FLMN")
TRANS("There's already a file called: FLNM")
.replace ("FLNM", content->chooserComponent.getSelectedFile(0).getFullPathName())
+ "\n\n"
+ TRANS("Are you sure you want to overwrite it?"),
@@ -68,6 +68,13 @@ void FilenameComponent::resized()
getLookAndFeel().layoutFilenameComponent (*this, &filenameBox, browseButton);
}
KeyboardFocusTraverser* FilenameComponent::createFocusTraverser()
{
// This prevents the sub-components from grabbing focus if the
// FilenameComponent has been set to refuse focus.
return getWantsKeyboardFocus() ? Component::createFocusTraverser() : nullptr;
}
void FilenameComponent::setBrowseButtonText (const String& newBrowseButtonText)
{
browseButtonText = newBrowseButtonText;
@@ -155,9 +162,14 @@ void FilenameComponent::fileDragExit (const StringArray&)
}
//==============================================================================
String FilenameComponent::getCurrentFileText() const
{
return filenameBox.getText();
}
File FilenameComponent::getCurrentFile() const
{
File f (File::getCurrentWorkingDirectory().getChildFile (filenameBox.getText()));
File f (File::getCurrentWorkingDirectory().getChildFile (getCurrentFileText()));
if (enforcedSuffix.isNotEmpty())
f = f.withFileExtension (enforcedSuffix);
@@ -103,6 +103,9 @@ public:
/** Returns the currently displayed filename. */
File getCurrentFile() const;
/** Returns the raw text that the user has entered. */
String getCurrentFileText() const;
/** Changes the current filename.
@param newFile the new filename to use
@@ -205,6 +208,8 @@ public:
void fileDragEnter (const StringArray&, int, int) override;
/** @internal */
void fileDragExit (const StringArray&) override;
/** @internal */
KeyboardFocusTraverser* createFocusTraverser() override;
private:
//==============================================================================
@@ -49,7 +49,7 @@
#import <WebKit/WebKit.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
#if JUCE_SUPPORT_CARBON
#if JUCE_SUPPORT_CARBON && ! (defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
#define Point CarbonDummyPointName
#define Component CarbonDummyCompName
#import <Carbon/Carbon.h> // still needed for SetSystemUIMode()
@@ -135,6 +135,12 @@
namespace juce
{
#define ASSERT_MESSAGE_MANAGER_IS_LOCKED \
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
#define ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN \
jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager() || getPeer() == nullptr);
extern bool juce_areThereAnyAlwaysOnTopWindows();
#include "components/juce_Component.cpp"
@@ -1,7 +1,7 @@
{
"id": "juce_gui_basics",
"name": "JUCE GUI core classes",
"version": "3.0.5",
"version": "3.0.8",
"description": "Basic user-interface components and related classes.",
"website": "http://www.juce.com/juce",
"license": "GPL/Commercial",
@@ -71,6 +71,23 @@ public:
/** Returns the position of the caret, relative to the component's origin. */
virtual Rectangle<int> getCaretRectangle() = 0;
/** A set of possible on-screen keyboard types, for use in the
getKeyboardType() method.
*/
enum VirtualKeyboardType
{
textKeyboard = 0,
numericKeyboard,
urlKeyboard,
emailAddressKeyboard,
phoneNumberKeyboard
};
/** Returns the target's preference for the type of keyboard that would be most appropriate.
This may be ignored, depending on the capabilities of the OS.
*/
virtual VirtualKeyboardType getKeyboardType() { return textKeyboard; }
};
@@ -25,8 +25,7 @@
class ComponentAnimator::AnimationTask
{
public:
AnimationTask (Component* const comp)
: component (comp)
AnimationTask (Component* const comp) noexcept : component (comp)
{
}
@@ -34,7 +33,7 @@ public:
float finalAlpha,
int millisecondsToSpendMoving,
bool useProxyComponent,
double startSpeed_, double endSpeed_)
double startSpd, double endSpd)
{
msElapsed = 0;
msTotal = jmax (1, millisecondsToSpendMoving);
@@ -51,10 +50,10 @@ public:
bottom = component->getBottom();
alpha = component->getAlpha();
const double invTotalDistance = 4.0 / (startSpeed_ + endSpeed_ + 2.0);
startSpeed = jmax (0.0, startSpeed_ * invTotalDistance);
const double invTotalDistance = 4.0 / (startSpd + endSpd + 2.0);
startSpeed = jmax (0.0, startSpd * invTotalDistance);
midSpeed = invTotalDistance;
endSpeed = jmax (0.0, endSpeed_ * invTotalDistance);
endSpeed = jmax (0.0, endSpd * invTotalDistance);
if (useProxyComponent)
proxy = new ProxyComponent (*component);
@@ -218,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)
{
@@ -148,10 +148,10 @@ public:
private:
//==============================================================================
class AnimationTask;
OwnedArray <AnimationTask> tasks;
OwnedArray<AnimationTask> tasks;
uint32 lastTime;
AnimationTask* findTaskFor (Component* component) const noexcept;
AnimationTask* findTaskFor (Component*) const noexcept;
void timerCallback();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentAnimator)
@@ -238,7 +238,7 @@ void ComponentBuilder::updateChildComponents (Component& parent, const ValueTree
const int numExistingChildComps = parent.getNumChildComponents();
Array <Component*> componentsInOrder;
Array<Component*> componentsInOrder;
componentsInOrder.ensureStorageAllocated (numExistingChildComps);
{
@@ -226,7 +226,7 @@ public:
private:
//=============================================================================
OwnedArray <TypeHandler> types;
OwnedArray<TypeHandler> types;
ScopedPointer<Component> component;
ImageProvider* imageProvider;
#if JUCE_DEBUG
@@ -287,7 +287,7 @@ void TabbedButtonBar::setTabName (const int tabIndex, const String& newName)
}
}
void TabbedButtonBar::removeTab (const int tabIndex)
void TabbedButtonBar::removeTab (const int tabIndex, const bool animate)
{
const int oldIndex = currentTabIndex;
if (tabIndex == currentTabIndex)
@@ -296,7 +296,7 @@ void TabbedButtonBar::removeTab (const int tabIndex)
tabs.remove (tabIndex);
setCurrentTabIndex (oldIndex);
resized();
updateTabPositions (animate);
}
void TabbedButtonBar::moveTab (const int currentIndex, const int newIndex, const bool animate)
@@ -212,7 +212,7 @@ public:
void setTabName (int tabIndex, const String& newName);
/** Gets rid of one of the tabs. */
void removeTab (int tabIndex);
void removeTab (int tabIndex, bool animate = false);
/** Moves a tab to a new index in the list.
Pass -1 as the index to move it to the end of the list.
@@ -346,15 +346,15 @@ void Viewport::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& whe
Component::mouseWheelMove (e, wheel);
}
static float rescaleMouseWheelDistance (float distance, int singleStepSize) noexcept
static int rescaleMouseWheelDistance (float distance, int singleStepSize) noexcept
{
if (distance == 0)
return 0;
distance *= 14.0f * singleStepSize;
return distance < 0 ? jmin (distance, -1.0f)
: jmax (distance, 1.0f);
return roundToInt (distance < 0 ? jmin (distance, -1.0f)
: jmax (distance, 1.0f));
}
bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelDetails& wheel)
@@ -366,26 +366,23 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelD
if (canScrollHorz || canScrollVert)
{
float wheelIncrementX = rescaleMouseWheelDistance (wheel.deltaX, singleStepX);
float wheelIncrementY = rescaleMouseWheelDistance (wheel.deltaY, singleStepY);
const int deltaX = rescaleMouseWheelDistance (wheel.deltaX, singleStepX);
const int deltaY = rescaleMouseWheelDistance (wheel.deltaY, singleStepY);
Point<int> pos (getViewPosition());
if (wheelIncrementX != 0 && wheelIncrementY != 0 && canScrollHorz && canScrollVert)
if (deltaX != 0 && deltaY != 0 && canScrollHorz && canScrollVert)
{
pos.setX (pos.x - roundToInt (wheelIncrementX));
pos.setY (pos.y - roundToInt (wheelIncrementY));
pos.x -= deltaX;
pos.y -= deltaY;
}
else if (canScrollHorz && (wheelIncrementX != 0 || e.mods.isShiftDown() || ! canScrollVert))
else if (canScrollHorz && (deltaX != 0 || e.mods.isShiftDown() || ! canScrollVert))
{
if (wheelIncrementX == 0 && ! canScrollVert)
wheelIncrementX = wheelIncrementY;
pos.setX (pos.x - roundToInt (wheelIncrementX));
pos.x -= deltaX != 0 ? deltaX : deltaY;
}
else if (canScrollVert && wheelIncrementY != 0)
else if (canScrollVert && deltaY != 0)
{
pos.setY (pos.y - roundToInt (wheelIncrementY));
pos.y -= deltaY;
}
if (pos != getViewPosition())
@@ -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,
@@ -238,24 +241,19 @@ void LookAndFeel_V2::drawButtonBackground (Graphics& g,
button.isConnectedOnBottom());
}
Font LookAndFeel_V2::getTextButtonFont (TextButton& button)
Font LookAndFeel_V2::getTextButtonFont (TextButton&, int buttonHeight)
{
return button.getFont();
return Font (jmin (15.0f, buttonHeight * 0.6f));
}
void LookAndFeel_V2::changeTextButtonWidthToFitText (TextButton& b, int newHeight)
int LookAndFeel_V2::getTextButtonWidthToFitText (TextButton& b, int buttonHeight)
{
if (newHeight >= 0)
b.setSize (jmax (1, b.getWidth()), newHeight);
else
newHeight = b.getHeight();
b.setSize (getTextButtonFont (b).getStringWidth (b.getButtonText()) + newHeight, newHeight);
return getTextButtonFont (b, buttonHeight).getStringWidth (b.getButtonText()) + buttonHeight;
}
void LookAndFeel_V2::drawButtonText (Graphics& g, TextButton& button, bool /*isMouseOverButton*/, bool /*isButtonDown*/)
{
Font font (getTextButtonFont (button));
Font font (getTextButtonFont (button, button.getHeight()));
g.setFont (font);
g.setColour (button.findColour (button.getToggleState() ? TextButton::textColourOnId
: TextButton::textColourOffId)
@@ -452,8 +450,7 @@ void LookAndFeel_V2::drawAlertBox (Graphics& g, AlertWindow& alert,
colour = alert.getAlertType() == AlertWindow::InfoIcon ? (uint32) 0x605555ff : (uint32) 0x40b69900;
character = alert.getAlertType() == AlertWindow::InfoIcon ? 'i' : '?';
icon.addEllipse ((float) iconRect.getX(), (float) iconRect.getY(),
(float) iconRect.getWidth(), (float) iconRect.getHeight());
icon.addEllipse (iconRect.toFloat());
}
GlyphArrangement ga;
@@ -1007,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()
{
@@ -1183,13 +1190,11 @@ void LookAndFeel_V2::drawLabel (Graphics& g, Label& label)
g.setColour (label.findColour (Label::textColourId).withMultipliedAlpha (alpha));
g.setFont (font);
g.drawFittedText (label.getText(),
label.getHorizontalBorderSize(),
label.getVerticalBorderSize(),
label.getWidth() - 2 * label.getHorizontalBorderSize(),
label.getHeight() - 2 * label.getVerticalBorderSize(),
label.getJustificationType(),
jmax (1, (int) (label.getHeight() / font.getHeight())),
Rectangle<int> textArea (label.getBorderSize().subtractedFrom (label.getLocalBounds()));
g.drawFittedText (label.getText(), textArea, label.getJustificationType(),
jmax (1, (int) (textArea.getHeight() / font.getHeight())),
label.getMinimumHorizontalScale());
g.setColour (label.findColour (Label::outlineColourId).withMultipliedAlpha (alpha));
@@ -2365,6 +2370,10 @@ void LookAndFeel_V2::drawCallOutBoxBackground (CallOutBox& box, Graphics& g,
g.strokePath (path, PathStrokeType (2.0f));
}
int LookAndFeel_V2::getCallOutBoxBorderSize (const CallOutBox&)
{
return 20;
}
//==============================================================================
AttributedString LookAndFeel_V2::createFileChooserHeaderText (const String& title,
@@ -39,16 +39,14 @@ public:
~LookAndFeel_V2();
//==============================================================================
void drawButtonBackground (Graphics&, Button& button, const Colour& backgroundColour,
void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool isMouseOverButton, bool isButtonDown) override;
Font getTextButtonFont (TextButton&, int buttonHeight) override;
Font getTextButtonFont (TextButton&) override;
void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) override;
int getTextButtonWidthToFitText (TextButton&, int buttonHeight) override;
void drawButtonText (Graphics&, TextButton& button,
bool isMouseOverButton, bool isButtonDown) override;
void changeTextButtonWidthToFitText (TextButton&, int newHeight) override;
void drawToggleButton (Graphics&, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) override;
void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) override;
void changeToggleButtonWidthToFitText (ToggleButton&) override;
@@ -78,17 +76,17 @@ public:
//==============================================================================
bool areScrollbarButtonsVisible() override;
void drawScrollbarButton (Graphics& g, ScrollBar&, int width, int height, int buttonDirection,
void drawScrollbarButton (Graphics&, ScrollBar&, int width, int height, int buttonDirection,
bool isScrollbarVertical, bool isMouseOverButton, bool isButtonDown) override;
void drawScrollbar (Graphics& g, ScrollBar&, int x, int y, int width, int height,
void drawScrollbar (Graphics&, ScrollBar&, int x, int y, int width, int height,
bool isScrollbarVertical, int thumbStartPosition, int thumbSize,
bool isMouseOver, bool isMouseDown) override;
ImageEffectFilter* getScrollbarEffect() override;
int getMinimumScrollbarThumbSize (ScrollBar&) override;
int getDefaultScrollbarWidth() override;
int getScrollbarButtonSize (ScrollBar& scrollbar) override;
int getScrollbarButtonSize (ScrollBar&) override;
//==============================================================================
Path getTickShape (float height) override;
@@ -139,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;
@@ -199,7 +200,7 @@ public:
//==============================================================================
Button* createFilenameComponentBrowseButton (const String& text) override;
void layoutFilenameComponent (FilenameComponent& filenameComp, ComboBox* filenameBox, Button* browseButton) override;
void layoutFilenameComponent (FilenameComponent&, ComboBox* filenameBox, Button* browseButton) override;
//==============================================================================
void drawConcertinaPanelHeader (Graphics&, const Rectangle<int>& area,
@@ -250,8 +251,8 @@ public:
void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) override;
void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) override;
void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown) override;
void fillTabButtonShape (TabBarButton&, Graphics&, const Path& path, bool isMouseOver, bool isMouseDown) override;
void createTabButtonShape (TabBarButton&, Path&, bool isMouseOver, bool isMouseDown) override;
void fillTabButtonShape (TabBarButton&, Graphics&, const Path&, bool isMouseOver, bool isMouseDown) override;
Button* createTabBarExtrasButton() override;
@@ -287,11 +288,12 @@ public:
//==============================================================================
void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path& path, Image& cachedImage) override;
int getCallOutBoxBorderSize (const CallOutBox&) override;
//==============================================================================
void drawLevelMeter (Graphics&, int width, int height, float level) override;
void drawKeymapChangeButton (Graphics&, int width, int height, Button& button, const String& keyDescription) override;
void drawKeymapChangeButton (Graphics&, int width, int height, Button&, const String& keyDescription) override;
//==============================================================================
/** Draws a 3D raised (or indented) bevel using two colours.
@@ -318,15 +320,15 @@ public:
/** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */
static void drawGlassSphere (Graphics&, float x, float y, float diameter,
const Colour& colour, float outlineThickness) noexcept;
const Colour&, float outlineThickness) noexcept;
static void drawGlassPointer (Graphics&, float x, float y, float diameter,
const Colour& colour, float outlineThickness, int direction) noexcept;
const Colour&, float outlineThickness, int direction) noexcept;
/** Utility function to draw a shiny, glassy oblong (for text buttons). */
static void drawGlassLozenge (Graphics&,
float x, float y, float width, float height,
const Colour& colour, float outlineThickness, float cornerSize,
const Colour&, float outlineThickness, float cornerSize,
bool flatOnLeft, bool flatOnRight, bool flatOnTop, bool flatOnBottom) noexcept;
private:
@@ -335,7 +337,7 @@ private:
void drawShinyButtonShape (Graphics&,
float x, float y, float w, float h, float maxCornerSize,
const Colour& baseColour, float strokeWidth,
const Colour&, float strokeWidth,
bool flatOnLeft, bool flatOnRight, bool flatOnTop, bool flatOnBottom) noexcept;
class GlassWindowButton;
@@ -30,8 +30,8 @@ LookAndFeel_V3::LookAndFeel_V3()
setColour (TextButton::buttonColourId, textButtonColour);
setColour (ComboBox::buttonColourId, textButtonColour);
setColour (TextEditor::outlineColourId, Colours::transparentBlack);
setColour (TabbedButtonBar::tabOutlineColourId, Colour (0xff999999));
setColour (TabbedComponent::outlineColourId, Colour (0xff999999));
setColour (TabbedButtonBar::tabOutlineColourId, Colour (0x66000000));
setColour (TabbedComponent::outlineColourId, Colour (0x66000000));
setColour (Slider::trackColourId, Colour (0xbbffffff));
setColour (Slider::thumbColourId, Colour (0xffddddff));
setColour (BubbleComponent::backgroundColourId, Colour (0xeeeeeedd));
@@ -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*/)
@@ -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;
//==============================================================================
@@ -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)
};
@@ -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;)
{
@@ -980,12 +980,12 @@ public:
void timerCallback() override
{
if (window.windowIsStillValid())
handleMousePosition (source.getScreenPosition());
handleMousePosition (source.getScreenPosition().roundToInt());
}
bool isOver() const
{
return window.reallyContains (window.getLocalPoint (nullptr, source.getScreenPosition()), true);
return window.reallyContains (window.getLocalPoint (nullptr, source.getScreenPosition()).roundToInt(), true);
}
MenuWindow& window;
@@ -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)
@@ -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;
@@ -49,7 +49,7 @@ void ComponentDragger::dragComponent (Component* const componentToDrag, const Mo
// so their coordinates become wrong after the first one moves the window, so in that case, we'll use
// the current mouse position instead of the one that the event contains...
if (componentToDrag->isOnDesktop())
bounds += componentToDrag->getLocalPoint (nullptr, e.source.getScreenPosition()) - mouseDownWithinTarget;
bounds += componentToDrag->getLocalPoint (nullptr, e.source.getScreenPosition()).roundToInt() - mouseDownWithinTarget;
else
bounds += e.getEventRelativeTo (componentToDrag).getPosition() - mouseDownWithinTarget;
@@ -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;
}
@@ -212,7 +214,22 @@ private:
DragAndDropTarget* getCurrentlyOver() const noexcept
{
return dynamic_cast <DragAndDropTarget*> (currentlyOverComp.get());
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,
@@ -221,7 +238,7 @@ private:
Component* hit = getParentComponent();
if (hit == nullptr)
hit = Desktop::getInstance().findComponentAt (screenPos);
hit = findDesktopComponentBelow (screenPos);
else
hit = hit->getComponentAt (hit->getLocalPoint (nullptr, screenPos));
@@ -231,7 +248,7 @@ private:
while (hit != nullptr)
{
if (DragAndDropTarget* const ddt = dynamic_cast <DragAndDropTarget*> (hit))
if (DragAndDropTarget* const ddt = dynamic_cast<DragAndDropTarget*> (hit))
{
if (ddt->isInterestedInDragSource (details))
{
@@ -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);
@@ -353,7 +375,7 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
return;
}
const Point<int> lastMouseDown (draggingSource->getLastMouseDownPosition());
const Point<int> lastMouseDown (draggingSource->getLastMouseDownPosition().roundToInt());
Point<int> imageOffset;
if (dragImage.isNull())
@@ -383,7 +405,7 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
{
const float alpha = (distance > hi) ? 0
: (hi - distance) / (float) (hi - lo)
+ random.nextFloat() * 0.008f;
+ random.nextFloat() * 0.008f;
dragImage.multiplyAlphaAt (x, y, alpha);
}
@@ -414,7 +436,7 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
}
else
{
if (Component* const thisComp = dynamic_cast <Component*> (this))
if (Component* const thisComp = dynamic_cast<Component*> (this))
{
thisComp->addChildComponent (dragImageComponent);
}
@@ -425,8 +447,7 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
}
}
static_cast <DragImageComponent*> (dragImageComponent.get())->updateLocation (false, lastMouseDown);
dragImageComponent->setVisible (true);
static_cast<DragImageComponent*> (dragImageComponent.get())->updateLocation (false, lastMouseDown);
dragImageComponent->enterModalState();
#if JUCE_WINDOWS
@@ -435,6 +456,8 @@ void DragAndDropContainer::startDragging (const var& sourceDescription,
if (ComponentPeer* const peer = dragImageComponent->getPeer())
peer->performAnyPendingRepaintsNow();
#endif
dragOperationStarted();
}
}
@@ -459,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),
@@ -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;
@@ -128,7 +128,7 @@ private:
SpinLock MouseCursor::SharedCursorHandle::lock;
//==============================================================================
MouseCursor::MouseCursor()
MouseCursor::MouseCursor() noexcept
: cursorHandle (nullptr)
{
}
@@ -72,10 +72,10 @@ public:
//==============================================================================
/** Creates the standard arrow cursor. */
MouseCursor();
MouseCursor() noexcept;
/** Creates one of the standard mouse cursor */
MouseCursor (StandardCursorType type);
MouseCursor (StandardCursorType);
/** Creates a custom cursor from an image.
@@ -23,17 +23,18 @@
*/
MouseEvent::MouseEvent (MouseInputSource inputSource,
Point<int> position,
Point<float> pos,
ModifierKeys modKeys,
Component* const eventComp,
Component* const originator,
Time time,
Point<int> downPos,
Point<float> downPos,
Time downTime,
const int numClicks,
const bool mouseWasDragged) noexcept
: x (position.x),
y (position.y),
: position (pos),
x (roundToInt (pos.x)),
y (roundToInt (pos.y)),
mods (modKeys),
eventComponent (eventComp),
originalComponent (originator),
@@ -55,19 +56,26 @@ MouseEvent MouseEvent::getEventRelativeTo (Component* const otherComponent) cons
{
jassert (otherComponent != nullptr);
return MouseEvent (source, otherComponent->getLocalPoint (eventComponent, getPosition()),
return MouseEvent (source, otherComponent->getLocalPoint (eventComponent, position),
mods, otherComponent, originalComponent, eventTime,
otherComponent->getLocalPoint (eventComponent, mouseDownPos),
mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0);
}
MouseEvent MouseEvent::withNewPosition (Point<int> newPosition) const noexcept
MouseEvent MouseEvent::withNewPosition (Point<float> newPosition) const noexcept
{
return MouseEvent (source, newPosition, mods, eventComponent, originalComponent,
eventTime, mouseDownPos, mouseDownTime,
numberOfClicks, wasMovedSinceMouseDown != 0);
}
MouseEvent MouseEvent::withNewPosition (Point<int> newPosition) const noexcept
{
return MouseEvent (source, newPosition.toFloat(), mods, eventComponent, originalComponent,
eventTime, mouseDownPos, mouseDownTime,
numberOfClicks, wasMovedSinceMouseDown != 0);
}
//==============================================================================
bool MouseEvent::mouseWasClicked() const noexcept
{
@@ -86,17 +94,17 @@ int MouseEvent::getLengthOfMousePress() const noexcept
Point<int> MouseEvent::getPosition() const noexcept { return Point<int> (x, y); }
Point<int> MouseEvent::getScreenPosition() const { return eventComponent->localPointToGlobal (getPosition()); }
Point<int> MouseEvent::getMouseDownPosition() const noexcept { return mouseDownPos; }
Point<int> MouseEvent::getMouseDownScreenPosition() const { return eventComponent->localPointToGlobal (mouseDownPos); }
Point<int> MouseEvent::getMouseDownPosition() const noexcept { return mouseDownPos.roundToInt(); }
Point<int> MouseEvent::getMouseDownScreenPosition() const { return eventComponent->localPointToGlobal (mouseDownPos).roundToInt(); }
Point<int> MouseEvent::getOffsetFromDragStart() const noexcept { return getPosition() - mouseDownPos; }
int MouseEvent::getDistanceFromDragStart() const noexcept { return mouseDownPos.getDistanceFrom (getPosition()); }
Point<int> MouseEvent::getOffsetFromDragStart() const noexcept { return (position - mouseDownPos).roundToInt(); }
int MouseEvent::getDistanceFromDragStart() const noexcept { return roundToInt (mouseDownPos.getDistanceFrom (position)); }
int MouseEvent::getMouseDownX() const noexcept { return mouseDownPos.x; }
int MouseEvent::getMouseDownY() const noexcept { return mouseDownPos.y; }
int MouseEvent::getMouseDownX() const noexcept { return roundToInt (mouseDownPos.x); }
int MouseEvent::getMouseDownY() const noexcept { return roundToInt (mouseDownPos.y); }
int MouseEvent::getDistanceFromDragStartX() const noexcept { return x - mouseDownPos.x; }
int MouseEvent::getDistanceFromDragStartY() const noexcept { return y - mouseDownPos.y; }
int MouseEvent::getDistanceFromDragStartX() const noexcept { return getOffsetFromDragStart().x; }
int MouseEvent::getDistanceFromDragStartY() const noexcept { return getOffsetFromDragStart().y; }
int MouseEvent::getScreenX() const { return getScreenPosition().x; }
int MouseEvent::getScreenY() const { return getScreenPosition().y; }
@@ -57,12 +57,12 @@ public:
@param mouseWasDragged whether the mouse has been dragged significantly since the previous mouse-down
*/
MouseEvent (MouseInputSource source,
Point<int> position,
Point<float> position,
ModifierKeys modifiers,
Component* eventComponent,
Component* originator,
Time eventTime,
Point<int> mouseDownPos,
Point<float> mouseDownPos,
Time mouseDownTime,
int numberOfClicks,
bool mouseWasDragged) noexcept;
@@ -71,10 +71,22 @@ public:
~MouseEvent() noexcept;
//==============================================================================
/** The position of the mouse when the event occurred.
This value is relative to the top-left of the component to which the
event applies (as indicated by the MouseEvent::eventComponent field).
This is a more accurate floating-point version of the position returned by
getPosition() and the integer x and y member variables.
*/
const Point<float> position;
/** The x-position of the mouse when the event occurred.
This value is relative to the top-left of the component to which the
event applies (as indicated by the MouseEvent::eventComponent field).
For a floating-point coordinate, see MouseEvent::position
*/
const int x;
@@ -82,6 +94,8 @@ public:
This value is relative to the top-left of the component to which the
event applies (as indicated by the MouseEvent::eventComponent field).
For a floating-point coordinate, see MouseEvent::position
*/
const int y;
@@ -130,25 +144,19 @@ public:
//==============================================================================
/** Returns the x coordinate of the last place that a mouse was pressed.
The coordinate is relative to the component specified in MouseEvent::component.
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked
*/
int getMouseDownX() const noexcept;
/** Returns the y coordinate of the last place that a mouse was pressed.
The coordinate is relative to the component specified in MouseEvent::component.
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked
*/
int getMouseDownY() const noexcept;
/** Returns the coordinates of the last place that a mouse was pressed.
The coordinates are relative to the component specified in MouseEvent::component.
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked
*/
Point<int> getMouseDownPosition() const noexcept;
@@ -221,6 +229,8 @@ public:
This position is relative to the top-left of the component to which the
event applies (as indicated by the MouseEvent::eventComponent field).
For a floating-point position, see MouseEvent::position
*/
Point<int> getPosition() const noexcept;
@@ -269,6 +279,12 @@ public:
*/
MouseEvent getEventRelativeTo (Component* newComponent) const noexcept;
/** Creates a copy of this event with a different position.
All other members of the event object are the same, but the x and y are
replaced with these new values.
*/
MouseEvent withNewPosition (Point<float> newPosition) const noexcept;
/** Creates a copy of this event with a different position.
All other members of the event object are the same, but the x and y are
replaced with these new values.
@@ -297,7 +313,7 @@ public:
private:
//==============================================================================
const Point<int> mouseDownPos;
const Point<float> mouseDownPos;
const uint8 numberOfClicks, wasMovedSinceMouseDown;
MouseEvent& operator= (const MouseEvent&);
@@ -58,7 +58,7 @@ public:
return lastPeer;
}
static Point<int> screenPosToLocalPos (Component& comp, Point<int> pos)
static Point<float> screenPosToLocalPos (Component& comp, Point<float> pos)
{
if (ComponentPeer* const peer = comp.getPeer())
{
@@ -70,23 +70,25 @@ public:
return comp.getLocalPoint (nullptr, ScalingHelpers::unscaledScreenPosToScaled (comp, pos));
}
Component* findComponentAt (Point<int> screenPos)
Component* findComponentAt (Point<float> screenPos)
{
if (ComponentPeer* const peer = getPeer())
{
Point<int> relativePos (ScalingHelpers::unscaledScreenPosToScaled (peer->getComponent(),
peer->globalToLocal (screenPos)));
Point<float> relativePos (ScalingHelpers::unscaledScreenPosToScaled (peer->getComponent(),
peer->globalToLocal (screenPos)));
Component& comp = peer->getComponent();
const Point<int> pos (relativePos.roundToInt());
// (the contains() call is needed to test for overlapping desktop windows)
if (comp.contains (relativePos))
return comp.getComponentAt (relativePos);
if (comp.contains (pos))
return comp.getComponentAt (pos);
}
return nullptr;
}
Point<int> getScreenPosition() const
Point<float> getScreenPosition() const
{
// This needs to return the live position if possible, but it mustn't update the lastScreenPos
// value, because that can cause continuity problems.
@@ -95,63 +97,63 @@ public:
: lastScreenPos));
}
void setScreenPosition (Point<int> p)
void setScreenPosition (Point<float> p)
{
MouseInputSource::setRawMousePosition (ScalingHelpers::scaledScreenPosToUnscaled (p));
}
//==============================================================================
#if JUCE_DUMP_MOUSE_EVENTS
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " desc << " #" << source.getIndex() \
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " << desc << " #" << index \
<< ": " << screenPosToLocalPos (comp, screenPos).toString() \
<< " - Comp: " << String::toHexString ((int) &comp));
<< " - Comp: " << String::toHexString ((pointer_sized_int) &comp));
#else
#define JUCE_MOUSE_EVENT_DBG(desc)
#endif
void sendMouseEnter (Component& comp, Point<int> screenPos, Time time)
void sendMouseEnter (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("enter")
comp.internalMouseEnter (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
}
void sendMouseExit (Component& comp, Point<int> screenPos, Time time)
void sendMouseExit (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("exit")
comp.internalMouseExit (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
}
void sendMouseMove (Component& comp, Point<int> screenPos, Time time)
void sendMouseMove (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("move")
comp.internalMouseMove (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
}
void sendMouseDown (Component& comp, Point<int> screenPos, Time time)
void sendMouseDown (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("down")
comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
}
void sendMouseDrag (Component& comp, Point<int> screenPos, Time time)
void sendMouseDrag (Component& comp, Point<float> screenPos, Time time)
{
JUCE_MOUSE_EVENT_DBG ("drag")
comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
}
void sendMouseUp (Component& comp, Point<int> screenPos, Time time, const ModifierKeys oldMods)
void sendMouseUp (Component& comp, Point<float> screenPos, Time time, const ModifierKeys oldMods)
{
JUCE_MOUSE_EVENT_DBG ("up")
comp.internalMouseUp (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, oldMods);
}
void sendMouseWheel (Component& comp, Point<int> screenPos, Time time, const MouseWheelDetails& wheel)
void sendMouseWheel (Component& comp, Point<float> screenPos, Time time, const MouseWheelDetails& wheel)
{
JUCE_MOUSE_EVENT_DBG ("wheel")
comp.internalMouseWheel (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, wheel);
}
void sendMagnifyGesture (Component& comp, Point<int> screenPos, Time time, const float amount)
void sendMagnifyGesture (Component& comp, Point<float> screenPos, Time time, const float amount)
{
JUCE_MOUSE_EVENT_DBG ("magnify")
comp.internalMagnifyGesture (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, amount);
@@ -159,7 +161,7 @@ public:
//==============================================================================
// (returns true if the button change caused a modal event loop)
bool setButtons (Point<int> screenPos, Time time, const ModifierKeys newButtonState)
bool setButtons (Point<float> screenPos, Time time, const ModifierKeys newButtonState)
{
if (buttonState == newButtonState)
return false;
@@ -209,7 +211,7 @@ public:
return lastCounter != mouseEventCounter;
}
void setComponentUnderMouse (Component* const newComponent, Point<int> screenPos, Time time)
void setComponentUnderMouse (Component* const newComponent, Point<float> screenPos, Time time)
{
Component* current = getComponentUnderMouse();
@@ -242,7 +244,7 @@ public:
}
}
void setPeer (ComponentPeer& newPeer, Point<int> screenPos, Time time)
void setPeer (ComponentPeer& newPeer, Point<float> screenPos, Time time)
{
ModifierKeys::updateCurrentModifiers();
@@ -254,7 +256,7 @@ public:
}
}
void setScreenPos (Point<int> newScreenPos, Time time, const bool forceUpdate)
void setScreenPos (Point<float> newScreenPos, Time time, const bool forceUpdate)
{
if (! isDragging())
setComponentUnderMouse (findComponentAt (newScreenPos), newScreenPos, time);
@@ -272,7 +274,7 @@ public:
sendMouseDrag (*current, newScreenPos + unboundedMouseOffset, time);
if (isUnboundedMouseModeOn)
handleUnboundedDrag (current);
handleUnboundedDrag (*current);
}
else
{
@@ -285,11 +287,11 @@ public:
}
//==============================================================================
void handleEvent (ComponentPeer& newPeer, Point<int> positionWithinPeer, Time time, const ModifierKeys newMods)
void handleEvent (ComponentPeer& newPeer, Point<float> positionWithinPeer, Time time, const ModifierKeys newMods)
{
lastTime = time;
++mouseEventCounter;
const Point<int> screenPos (newPeer.localToGlobal (positionWithinPeer));
const Point<float> screenPos (newPeer.localToGlobal (positionWithinPeer));
if (isDragging() && newMods.isAnyMouseButtonDown())
{
@@ -311,8 +313,8 @@ public:
}
}
Component* getTargetForGesture (ComponentPeer& peer, Point<int> positionWithinPeer,
Time time, Point<int>& screenPos)
Component* getTargetForGesture (ComponentPeer& peer, Point<float> positionWithinPeer,
Time time, Point<float>& screenPos)
{
lastTime = time;
++mouseEventCounter;
@@ -325,27 +327,27 @@ public:
return isDragging() ? nullptr : getComponentUnderMouse();
}
void handleWheel (ComponentPeer& peer, Point<int> positionWithinPeer,
void handleWheel (ComponentPeer& peer, Point<float> positionWithinPeer,
Time time, const MouseWheelDetails& wheel)
{
Desktop::getInstance().incrementMouseWheelCounter();
Point<int> screenPos;
Point<float> screenPos;
if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos))
sendMouseWheel (*current, screenPos, time, wheel);
}
void handleMagnifyGesture (ComponentPeer& peer, Point<int> positionWithinPeer,
void handleMagnifyGesture (ComponentPeer& peer, Point<float> positionWithinPeer,
Time time, const float scaleFactor)
{
Point<int> screenPos;
Point<float> screenPos;
if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos))
sendMagnifyGesture (*current, screenPos, time, scaleFactor);
}
//==============================================================================
Time getLastMouseDownTime() const noexcept { return mouseDowns[0].time; }
Point<int> getLastMouseDownPosition() const noexcept { return ScalingHelpers::unscaledScreenPosToScaled (mouseDowns[0].position); }
Point<float> getLastMouseDownPosition() const noexcept { return ScalingHelpers::unscaledScreenPosToScaled (mouseDowns[0].position); }
int getNumberOfMultipleClicks() const noexcept
{
@@ -397,33 +399,34 @@ public:
{
// when released, return the mouse to within the component's bounds
if (Component* current = getComponentUnderMouse())
Desktop::setMousePosition (current->getScreenBounds()
.getConstrainedPoint (lastScreenPos));
setScreenPosition (current->getScreenBounds().toFloat()
.getConstrainedPoint (ScalingHelpers::unscaledScreenPosToScaled (lastScreenPos)));
}
isUnboundedMouseModeOn = enable;
unboundedMouseOffset = Point<int>();
unboundedMouseOffset = Point<float>();
revealCursor (true);
}
}
void handleUnboundedDrag (Component* current)
void handleUnboundedDrag (Component& current)
{
const Rectangle<int> screenArea (current->getParentMonitorArea().expanded (-2, -2));
const Rectangle<float> componentScreenBounds
= ScalingHelpers::scaledScreenPosToUnscaled (current.getParentMonitorArea().reduced (2, 2).toFloat());
if (! screenArea.contains (lastScreenPos))
if (! componentScreenBounds.contains (lastScreenPos))
{
const Point<int> componentCentre (current->getScreenBounds().getCentre());
unboundedMouseOffset += (lastScreenPos - componentCentre);
Desktop::setMousePosition (componentCentre);
const Point<float> componentCentre (current.getScreenBounds().toFloat().getCentre());
unboundedMouseOffset += (lastScreenPos - ScalingHelpers::scaledScreenPosToUnscaled (componentCentre));
setScreenPosition (componentCentre);
}
else if (isCursorVisibleUntilOffscreen
&& (! unboundedMouseOffset.isOrigin())
&& screenArea.contains (lastScreenPos + unboundedMouseOffset))
&& componentScreenBounds.contains (lastScreenPos + unboundedMouseOffset))
{
Desktop::setMousePosition (lastScreenPos + unboundedMouseOffset);
unboundedMouseOffset = Point<int>();
MouseInputSource::setRawMousePosition (lastScreenPos + unboundedMouseOffset);
unboundedMouseOffset = Point<float>();
}
}
@@ -461,10 +464,9 @@ public:
//==============================================================================
const int index;
const bool isMouseDevice;
Point<int> lastScreenPos;
Point<float> lastScreenPos, unboundedMouseOffset; // NB: these are unscaled coords
ModifierKeys buttonState;
Point<int> unboundedMouseOffset;
bool isUnboundedMouseModeOn, isCursorVisibleUntilOffscreen;
private:
@@ -478,7 +480,7 @@ private:
{
RecentMouseDown() noexcept : peerID (0) {}
Point<int> position;
Point<float> position;
Time time;
ModifierKeys buttons;
uint32 peerID;
@@ -486,8 +488,8 @@ private:
bool canBePartOfMultipleClickWith (const RecentMouseDown& other, const int maxTimeBetweenMs) const
{
return time - other.time < RelativeTime::milliseconds (maxTimeBetweenMs)
&& abs (position.x - other.position.x) < 8
&& abs (position.y - other.position.y) < 8
&& std::abs (position.x - other.position.x) < 8
&& std::abs (position.y - other.position.y) < 8
&& buttons == other.buttons
&& peerID == other.peerID;
}
@@ -497,7 +499,7 @@ private:
Time lastTime;
bool mouseMovedSignificantlySincePressed;
void registerMouseDown (Point<int> screenPos, Time time,
void registerMouseDown (Point<float> screenPos, Time time,
Component& component, const ModifierKeys modifiers) noexcept
{
for (int i = numElementsInArray (mouseDowns); --i > 0;)
@@ -515,7 +517,7 @@ private:
mouseMovedSignificantlySincePressed = false;
}
void registerMouseDrag (Point<int> screenPos) noexcept
void registerMouseDrag (Point<float> screenPos) noexcept
{
mouseMovedSignificantlySincePressed = mouseMovedSignificantlySincePressed
|| mouseDowns[0].position.getDistanceFrom (screenPos) >= 4;
@@ -535,47 +537,44 @@ MouseInputSource& MouseInputSource::operator= (const MouseInputSource& other) no
return *this;
}
bool MouseInputSource::isMouse() const { return pimpl->isMouseDevice; }
bool MouseInputSource::isTouch() const { return ! isMouse(); }
bool MouseInputSource::canHover() const { return isMouse(); }
bool MouseInputSource::hasMouseWheel() const { return isMouse(); }
int MouseInputSource::getIndex() const { return pimpl->index; }
bool MouseInputSource::isDragging() const { return pimpl->isDragging(); }
Point<int> MouseInputSource::getScreenPosition() const { return pimpl->getScreenPosition(); }
ModifierKeys MouseInputSource::getCurrentModifiers() const { return pimpl->getCurrentModifiers(); }
Component* MouseInputSource::getComponentUnderMouse() const { return pimpl->getComponentUnderMouse(); }
void MouseInputSource::triggerFakeMove() const { pimpl->triggerFakeMove(); }
int MouseInputSource::getNumberOfMultipleClicks() const noexcept { return pimpl->getNumberOfMultipleClicks(); }
Time MouseInputSource::getLastMouseDownTime() const noexcept { return pimpl->getLastMouseDownTime(); }
Point<int> MouseInputSource::getLastMouseDownPosition() const noexcept { return pimpl->getLastMouseDownPosition(); }
bool MouseInputSource::isMouse() const { return pimpl->isMouseDevice; }
bool MouseInputSource::isTouch() const { return ! isMouse(); }
bool MouseInputSource::canHover() const { return isMouse(); }
bool MouseInputSource::hasMouseWheel() const { return isMouse(); }
int MouseInputSource::getIndex() const { return pimpl->index; }
bool MouseInputSource::isDragging() const { return pimpl->isDragging(); }
Point<float> MouseInputSource::getScreenPosition() const { return pimpl->getScreenPosition(); }
ModifierKeys MouseInputSource::getCurrentModifiers() const { return pimpl->getCurrentModifiers(); }
Component* MouseInputSource::getComponentUnderMouse() const { return pimpl->getComponentUnderMouse(); }
void MouseInputSource::triggerFakeMove() const { pimpl->triggerFakeMove(); }
int MouseInputSource::getNumberOfMultipleClicks() const noexcept { return pimpl->getNumberOfMultipleClicks(); }
Time MouseInputSource::getLastMouseDownTime() const noexcept { return pimpl->getLastMouseDownTime(); }
Point<float> MouseInputSource::getLastMouseDownPosition() const noexcept { return pimpl->getLastMouseDownPosition(); }
bool MouseInputSource::hasMouseMovedSignificantlySincePressed() const noexcept { return pimpl->hasMouseMovedSignificantlySincePressed(); }
bool MouseInputSource::canDoUnboundedMovement() const noexcept { return isMouse(); }
bool MouseInputSource::canDoUnboundedMovement() const noexcept { return isMouse(); }
void MouseInputSource::enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen) const
{ pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); }
bool MouseInputSource::isUnboundedMouseMovementEnabled() const { return pimpl->isUnboundedMouseModeOn; }
bool MouseInputSource::hasMouseCursor() const noexcept { return isMouse(); }
void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); }
void MouseInputSource::hideCursor() { pimpl->hideCursor(); }
void MouseInputSource::revealCursor() { pimpl->revealCursor (false); }
void MouseInputSource::forceMouseCursorUpdate() { pimpl->revealCursor (true); }
void MouseInputSource::setScreenPosition (Point<int> p) { pimpl->setScreenPosition (p); }
{ pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); }
bool MouseInputSource::isUnboundedMouseMovementEnabled() const { return pimpl->isUnboundedMouseModeOn; }
bool MouseInputSource::hasMouseCursor() const noexcept { return isMouse(); }
void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); }
void MouseInputSource::hideCursor() { pimpl->hideCursor(); }
void MouseInputSource::revealCursor() { pimpl->revealCursor (false); }
void MouseInputSource::forceMouseCursorUpdate() { pimpl->revealCursor (true); }
void MouseInputSource::setScreenPosition (Point<float> p) { pimpl->setScreenPosition (p); }
void MouseInputSource::handleEvent (ComponentPeer& peer, Point<int> positionWithinPeer,
const int64 time, const ModifierKeys mods)
void MouseInputSource::handleEvent (ComponentPeer& peer, Point<float> pos, int64 time, ModifierKeys mods)
{
pimpl->handleEvent (peer, positionWithinPeer, Time (time), mods.withOnlyMouseButtons());
pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons());
}
void MouseInputSource::handleWheel (ComponentPeer& peer, Point<int> positionWithinPeer,
const int64 time, const MouseWheelDetails& wheel)
void MouseInputSource::handleWheel (ComponentPeer& peer, Point<float> pos, int64 time, const MouseWheelDetails& wheel)
{
pimpl->handleWheel (peer, positionWithinPeer, Time (time), wheel);
pimpl->handleWheel (peer, pos, Time (time), wheel);
}
void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point<int> positionWithinPeer,
const int64 time, const float scaleFactor)
void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point<float> pos, int64 time, float scaleFactor)
{
pimpl->handleMagnifyGesture (peer, positionWithinPeer, Time (time), scaleFactor);
pimpl->handleMagnifyGesture (peer, pos, Time (time), scaleFactor);
}
//==============================================================================
@@ -88,7 +88,7 @@ public:
bool isDragging() const;
/** Returns the last-known screen position of this source. */
Point<int> getScreenPosition() const;
Point<float> getScreenPosition() const;
/** Returns a set of modifiers that indicate which buttons are currently
held down on this device.
@@ -114,7 +114,7 @@ public:
Time getLastMouseDownTime() const noexcept;
/** Returns the screen position at which the last mouse-down occurred. */
Point<int> getLastMouseDownPosition() const noexcept;
Point<float> getLastMouseDownPosition() const noexcept;
/** Returns true if this mouse is currently down, and if it has been dragged more
than a couple of pixels from the place it was pressed.
@@ -162,7 +162,7 @@ public:
bool isUnboundedMouseMovementEnabled() const;
/** Attempts to set this mouse pointer's screen position. */
void setScreenPosition (Point<int> newPosition);
void setScreenPosition (Point<float> newPosition);
private:
//==============================================================================
@@ -174,12 +174,12 @@ private:
struct SourceList;
explicit MouseInputSource (MouseInputSourceInternal*) noexcept;
void handleEvent (ComponentPeer&, Point<int>, int64 time, const ModifierKeys);
void handleWheel (ComponentPeer&, Point<int>, int64 time, const MouseWheelDetails&);
void handleMagnifyGesture (ComponentPeer&, Point<int>, int64 time, float scaleFactor);
void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys);
void handleWheel (ComponentPeer&, Point<float>, int64 time, const MouseWheelDetails&);
void handleMagnifyGesture (ComponentPeer&, Point<float>, int64 time, float scaleFactor);
static Point<int> getCurrentRawMousePosition();
static void setRawMousePosition (Point<int>);
static Point<float> getCurrentRawMousePosition();
static void setRawMousePosition (Point<float>);
JUCE_LEAK_DETECTOR (MouseInputSource)
};
@@ -43,7 +43,7 @@ JUCE_JNI_CALLBACK (JUCE_ANDROID_ACTIVITY_CLASSNAME, launchApp, void, (JNIEnv* en
JUCEApplicationBase* app = JUCEApplicationBase::createInstance();
if (! app->initialiseApp())
exit (0);
exit (app->getApplicationReturnValue());
jassert (MessageManager::getInstance()->isThisTheMessageThread());
}
@@ -91,7 +91,7 @@ DECLARE_JNI_CLASS (CanvasMinimal, "android/graphics/Canvas");
METHOD (hasFocus, "hasFocus", "()Z") \
METHOD (invalidate, "invalidate", "(IIII)V") \
METHOD (containsPoint, "containsPoint", "(II)Z") \
METHOD (showKeyboard, "showKeyboard", "(Z)V") \
METHOD (showKeyboard, "showKeyboard", "(Ljava/lang/String;)V") \
METHOD (createGLView, "createGLView", "()L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$OpenGLView;") \
DECLARE_JNI_CLASS (ComponentPeerView, JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView");
@@ -234,14 +234,14 @@ public:
view.callIntMethod (ComponentPeerView.getTop));
}
Point<int> localToGlobal (Point<int> relativePosition) override
Point<float> localToGlobal (Point<float> relativePosition) override
{
return relativePosition + getScreenPosition();
return relativePosition + getScreenPosition().toFloat();
}
Point<int> globalToLocal (Point<int> screenPosition) override
Point<float> globalToLocal (Point<float> screenPosition) override
{
return screenPosition - getScreenPosition();
return screenPosition - getScreenPosition().toFloat();
}
void setMinimised (bool shouldBeMinimised) override
@@ -320,7 +320,7 @@ public:
lastMousePos = pos;
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons(), time);
handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time);
if (isValidPeer (this))
handleMouseDragCallback (index, pos, time);
@@ -333,8 +333,8 @@ public:
jassert (index < 64);
touchesDown = (touchesDown | (1 << (index & 63)));
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier);
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons()
.withFlags (ModifierKeys::leftButtonModifier), time);
handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons()
.withFlags (ModifierKeys::leftButtonModifier), time);
}
void handleMouseUpCallback (int index, Point<float> pos, int64 time)
@@ -347,7 +347,7 @@ public:
if (touchesDown == 0)
currentModifiers = currentModifiers.withoutMouseButtons();
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons(), time);
handleMouseEvent (index, pos, currentModifiers.withoutMouseButtons(), time);
}
void handleKeyDownCallback (int k, int kc)
@@ -378,14 +378,30 @@ public:
handleFocusLoss();
}
void textInputRequired (const Point<int>&) override
static const char* getVirtualKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
{
view.callVoidMethod (ComponentPeerView.showKeyboard, true);
switch (type)
{
case TextInputTarget::textKeyboard: return "text";
case TextInputTarget::numericKeyboard: return "number";
case TextInputTarget::urlKeyboard: return "textUri";
case TextInputTarget::emailAddressKeyboard: return "textEmailAddress";
case TextInputTarget::phoneNumberKeyboard: return "phone";
default: jassertfalse; break;
}
return "text";
}
void textInputRequired (Point<int>, TextInputTarget& target) override
{
view.callVoidMethod (ComponentPeerView.showKeyboard,
javaString (getVirtualKeyboardType (target.getKeyboardType())).get());
}
void dismissPendingTextInput() override
{
view.callVoidMethod (ComponentPeerView.showKeyboard, false);
view.callVoidMethod (ComponentPeerView.showKeyboard, javaString ("").get());
}
//==============================================================================
@@ -595,12 +611,12 @@ bool MouseInputSource::SourceList::addSource()
return true;
}
Point<int> MouseInputSource::getCurrentRawMousePosition()
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
return AndroidComponentPeer::lastMousePos.toInt();
return AndroidComponentPeer::lastMousePos;
}
void MouseInputSource::setRawMousePosition (Point<int>)
void MouseInputSource::setRawMousePosition (Point<float>)
{
// not needed
}
@@ -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;
@@ -145,8 +157,8 @@ public:
Rectangle<int> getBounds() const override { return getBounds (! isSharedWindow); }
Rectangle<int> getBounds (bool global) const;
Point<int> localToGlobal (Point<int> relativePosition) override;
Point<int> globalToLocal (Point<int> screenPosition) override;
Point<float> localToGlobal (Point<float> relativePosition) override;
Point<float> globalToLocal (Point<float> screenPosition) override;
void setAlpha (float newAlpha) override;
void setMinimised (bool) override {}
bool isMinimised() const override { return false; }
@@ -168,7 +180,7 @@ public:
void viewFocusLoss();
bool isFocused() const override;
void grabFocus() override;
void textInputRequired (const Point<int>&) override;
void textInputRequired (Point<int>, TextInputTarget&) override;
BOOL textViewReplaceCharacters (Range<int>, const String&);
void updateHiddenTextContent (TextInputTarget*);
@@ -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));
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case UIInterfaceOrientationPortrait:
return r;
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (r.getY(), screen.getHeight() - r.getRight(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (screen.getWidth() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (r.getY(), screen.getHeight() - r.getRight(),
r.getHeight(), r.getWidth());
default: jassertfalse; // unknown orientation!
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (screen.getWidth() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
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));
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
switch ([[UIApplication sharedApplication] statusBarOrientation])
{
case UIInterfaceOrientationPortrait:
return r;
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (screen.getHeight() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationPortraitUpsideDown:
return Rectangle<int> (screen.getWidth() - r.getRight(), screen.getHeight() - r.getBottom(),
r.getWidth(), r.getHeight());
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (r.getY(), screen.getWidth() - r.getRight(),
r.getHeight(), r.getWidth());
case UIInterfaceOrientationLandscapeLeft:
return Rectangle<int> (screen.getHeight() - r.getBottom(), r.getX(),
r.getHeight(), r.getWidth());
default: jassertfalse; // unknown orientation!
case UIInterfaceOrientationLandscapeRight:
return Rectangle<int> (r.getY(), screen.getWidth() - r.getRight(),
r.getHeight(), r.getWidth());
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;
JuceUIView* juceView = (JuceUIView*) [self view];
jassert (juceView != nil && juceView->owner != nullptr);
juceView->owner->updateTransformAndScreenBounds();
sendScreenBoundsUpdate (self);
[UIView setAnimationsEnabled: YES];
}
- (void) viewWillTransitionToSize: (CGSize) size withTransitionCoordinator: (id<UIViewControllerTransitionCoordinator>) coordinator
{
[super viewWillTransitionToSize: size withTransitionCoordinator: coordinator];
sendScreenBoundsUpdate (self);
// 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
@@ -477,7 +506,7 @@ void ModifierKeys::updateCurrentModifiers() noexcept
currentModifiers = UIViewComponentPeer::currentModifiers;
}
Point<int> juce_lastMousePos;
Point<float> juce_lastMousePos;
//==============================================================================
UIViewComponentPeer::UIViewComponentPeer (Component& comp, const int windowStyleFlags, UIView* viewToAttachTo)
@@ -603,14 +632,14 @@ Rectangle<int> UIViewComponentPeer::getBounds (const bool global) const
return convertToRectInt (r);
}
Point<int> UIViewComponentPeer::localToGlobal (Point<int> relativePosition)
Point<float> UIViewComponentPeer::localToGlobal (Point<float> relativePosition)
{
return relativePosition + getBounds (true).getPosition();
return relativePosition + getBounds (true).getPosition().toFloat();
}
Point<int> UIViewComponentPeer::globalToLocal (Point<int> screenPosition)
Point<float> UIViewComponentPeer::globalToLocal (Point<float> screenPosition)
{
return screenPosition - getBounds (true).getPosition();
return screenPosition - getBounds (true).getPosition().toFloat();
}
void UIViewComponentPeer::setAlpha (float newAlpha)
@@ -702,10 +731,7 @@ void UIViewComponentPeer::toFront (bool makeActiveWindow)
void UIViewComponentPeer::toBehind (ComponentPeer* other)
{
UIViewComponentPeer* const otherPeer = dynamic_cast <UIViewComponentPeer*> (other);
jassert (otherPeer != nullptr); // wrong type of window?
if (otherPeer != nullptr)
if (UIViewComponentPeer* const otherPeer = dynamic_cast<UIViewComponentPeer*> (other))
{
if (isSharedWindow)
{
@@ -716,6 +742,10 @@ void UIViewComponentPeer::toBehind (ComponentPeer* other)
// don't know how to do this
}
}
else
{
jassertfalse; // wrong type of window?
}
}
void UIViewComponentPeer::setIcon (const Image& /*newIcon*/)
@@ -736,8 +766,8 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons
continue;
CGPoint p = [touch locationInView: view];
const Point<int> pos ((int) p.x, (int) p.y);
juce_lastMousePos = pos + getBounds (true).getPosition();
const Point<float> pos (p.x, p.y);
juce_lastMousePos = pos + getBounds (true).getPosition().toFloat();
const int64 time = getMouseTime (event);
const int touchIndex = currentTouches.getIndexOfTouch (touch);
@@ -781,7 +811,7 @@ void UIViewComponentPeer::handleTouches (UIEvent* event, const bool isDown, cons
if (isUp || isCancel)
{
handleMouseEvent (touchIndex, Point<int> (-1, -1), modsToSend, time);
handleMouseEvent (touchIndex, Point<float> (-1.0f, -1.0f), modsToSend, time);
if (! isValidPeer (this))
return;
}
@@ -828,12 +858,28 @@ void UIViewComponentPeer::grabFocus()
}
}
void UIViewComponentPeer::textInputRequired (const Point<int>&)
void UIViewComponentPeer::textInputRequired (Point<int>, TextInputTarget&)
{
}
static UIKeyboardType getUIKeyboardType (TextInputTarget::VirtualKeyboardType type) noexcept
{
switch (type)
{
case TextInputTarget::textKeyboard: return UIKeyboardTypeAlphabet;
case TextInputTarget::numericKeyboard: return UIKeyboardTypeNumbersAndPunctuation;
case TextInputTarget::urlKeyboard: return UIKeyboardTypeURL;
case TextInputTarget::emailAddressKeyboard: return UIKeyboardTypeEmailAddress;
case TextInputTarget::phoneNumberKeyboard: return UIKeyboardTypePhonePad;
default: jassertfalse; break;
}
return UIKeyboardTypeDefault;
}
void UIViewComponentPeer::updateHiddenTextContent (TextInputTarget* target)
{
view->hiddenTextView.keyboardType = getUIKeyboardType (target->getKeyboardType());
view->hiddenTextView.text = juceStringToNS (target->getTextInRange (Range<int> (0, target->getHighlightedRegion().getStart())));
view->hiddenTextView.selectedRange = NSMakeRange (target->getHighlightedRegion().getStart(), 0);
}
@@ -189,7 +189,7 @@ private:
- (void) alertView: (UIAlertView*) alertView clickedButtonAtIndex: (NSInteger) buttonIndex
{
owner->buttonClicked (buttonIndex);
owner->buttonClicked ((int) buttonIndex);
alertView.hidden = true;
}
@@ -312,12 +312,12 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
return true;
}
Point<int> MouseInputSource::getCurrentRawMousePosition()
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
return juce_lastMousePos;
}
void MouseInputSource::setRawMousePosition (Point<int>)
void MouseInputSource::setRawMousePosition (Point<float>)
{
}
@@ -42,99 +42,134 @@ bool FileChooser::isPlatformDialogAvailable()
#endif
}
void FileChooser::showPlatformDialog (Array<File>& results,
const String& title,
const File& file,
const String& filters,
bool isDirectory,
bool /* selectsFiles */,
bool isSave,
bool /* warnAboutOverwritingExistingFiles */,
bool selectMultipleFiles,
FilePreviewComponent* /* previewComponent */)
static uint64 getTopWindowID() noexcept
{
String separator;
StringArray args;
if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
return (uint64) (pointer_sized_uint) top->getWindowHandle();
const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
const bool isKdeFullSession = SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String::empty)
.equalsIgnoreCase ("true");
return 0;
}
if (exeIsAvailable ("kdialog") && (isKdeFullSession || ! exeIsAvailable ("zenity")))
static bool isKdeFullSession()
{
return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
.equalsIgnoreCase ("true");
}
static void addKDialogArgs (StringArray& args, String& separator,
const String& title, const File& file, const String& filters,
bool isDirectory, bool isSave, bool selectMultipleFiles)
{
args.add ("kdialog");
if (title.isNotEmpty())
args.add ("--title=" + title);
if (uint64 topWindowID = getTopWindowID())
{
// use kdialog for KDE sessions or if zenity is missing
args.add ("kdialog");
args.add ("--attach");
args.add (String (topWindowID));
}
if (title.isNotEmpty())
args.add ("--title=" + title);
if (selectMultipleFiles)
{
separator = "\n";
args.add ("--multiple");
args.add ("--separate-output");
args.add ("--getopenfilename");
}
else
{
if (isSave) args.add ("--getsavefilename");
else if (isDirectory) args.add ("--getexistingdirectory");
else args.add ("--getopenfilename");
}
String startPath;
if (file.exists())
{
startPath = file.getFullPathName();
}
else if (file.getParentDirectory().exists())
{
startPath = file.getParentDirectory().getFullPathName();
}
else
{
startPath = File::getSpecialLocation (File::userHomeDirectory).getFullPathName();
if (isSave)
startPath += "/" + file.getFileName();
}
args.add (startPath);
args.add (filters.replaceCharacter (';', ' '));
if (selectMultipleFiles)
{
separator = "\n";
args.add ("--multiple");
args.add ("--separate-output");
args.add ("--getopenfilename");
}
else
{
// zenity
args.add ("zenity");
args.add ("--file-selection");
if (title.isNotEmpty())
args.add ("--title=" + title);
if (selectMultipleFiles)
{
separator = ":";
args.add ("--multiple");
args.add ("--separator=" + separator);
}
else
{
if (isDirectory) args.add ("--directory");
if (isSave) args.add ("--save");
}
if (file.isDirectory())
file.setAsCurrentWorkingDirectory();
else if (file.getParentDirectory().exists())
file.getParentDirectory().setAsCurrentWorkingDirectory();
else
File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
if (! file.getFileName().isEmpty())
args.add ("--filename=" + file.getFileName());
if (isSave) args.add ("--getsavefilename");
else if (isDirectory) args.add ("--getexistingdirectory");
else args.add ("--getopenfilename");
}
File startPath;
if (file.exists())
{
startPath = file;
}
else if (file.getParentDirectory().exists())
{
startPath = file.getParentDirectory();
}
else
{
startPath = File::getSpecialLocation (File::userHomeDirectory);
if (isSave)
startPath = startPath.getChildFile (file.getFileName());
}
args.add (startPath.getFullPathName());
args.add (filters.replaceCharacter (';', ' '));
}
static void addZenityArgs (StringArray& args, String& separator,
const String& title, const File& file, const String& filters,
bool isDirectory, bool isSave, bool selectMultipleFiles)
{
args.add ("zenity");
args.add ("--file-selection");
if (title.isNotEmpty())
args.add ("--title=" + title);
if (selectMultipleFiles)
{
separator = ":";
args.add ("--multiple");
args.add ("--separator=" + separator);
}
else
{
if (isDirectory) args.add ("--directory");
if (isSave) args.add ("--save");
}
if (filters.isNotEmpty() && filters != "*" && filters != "*.*")
{
args.add ("--file-filter");
args.add (filters.replaceCharacter (';', ' '));
args.add ("--file-filter");
args.add ("All files | *");
}
if (file.isDirectory())
file.setAsCurrentWorkingDirectory();
else if (file.getParentDirectory().exists())
file.getParentDirectory().setAsCurrentWorkingDirectory();
else
File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
if (! file.getFileName().isEmpty())
args.add ("--filename=" + file.getFileName());
// supplying the window ID of the topmost window makes sure that Zenity pops up..
if (uint64 topWindowID = getTopWindowID())
setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
}
void FileChooser::showPlatformDialog (Array<File>& results,
const String& title, const File& file, const String& filters,
bool isDirectory, bool /* selectsFiles */,
bool isSave, bool /* warnAboutOverwritingExistingFiles */,
bool selectMultipleFiles, FilePreviewComponent*)
{
const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
StringArray args;
String separator;
// use kdialog for KDE sessions or if zenity is missing
if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
addKDialogArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
else
addZenityArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
args.add ("2>/dev/null"); // (to avoid logging info ending up in the results)
ChildProcess child;
@@ -33,17 +33,18 @@ struct Atoms
{
Atoms()
{
Protocols = getIfExists ("WM_PROTOCOLS");
ProtocolList [TAKE_FOCUS] = getIfExists ("WM_TAKE_FOCUS");
ProtocolList [DELETE_WINDOW] = getIfExists ("WM_DELETE_WINDOW");
ProtocolList [PING] = getIfExists ("_NET_WM_PING");
ChangeState = getIfExists ("WM_CHANGE_STATE");
State = getIfExists ("WM_STATE");
UserTime = getCreating ("_NET_WM_USER_TIME");
ActiveWin = getCreating ("_NET_ACTIVE_WINDOW");
Pid = getCreating ("_NET_WM_PID");
WindowType = getIfExists ("_NET_WM_WINDOW_TYPE");
WindowState = getIfExists ("_NET_WM_STATE");
protocols = getIfExists ("WM_PROTOCOLS");
protocolList [TAKE_FOCUS] = getIfExists ("WM_TAKE_FOCUS");
protocolList [DELETE_WINDOW] = getIfExists ("WM_DELETE_WINDOW");
protocolList [PING] = getIfExists ("_NET_WM_PING");
changeState = getIfExists ("WM_CHANGE_STATE");
state = getIfExists ("WM_STATE");
userTime = getCreating ("_NET_WM_USER_TIME");
activeWin = getCreating ("_NET_ACTIVE_WINDOW");
pid = getCreating ("_NET_WM_PID");
windowType = getIfExists ("_NET_WM_WINDOW_TYPE");
windowState = getIfExists ("_NET_WM_STATE");
compositingManager = getCreating ("_NET_WM_CM_S0");
XdndAware = getCreating ("XdndAware");
XdndEnter = getCreating ("XdndEnter");
@@ -88,8 +89,8 @@ struct Atoms
PING = 2
};
Atom Protocols, ProtocolList[3], ChangeState, State, UserTime,
ActiveWin, Pid, WindowType, WindowState,
Atom protocols, protocolList[3], changeState, state, userTime,
activeWin, pid, windowType, windowState, compositingManager,
XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus,
XdndDrop, XdndFinished, XdndSelection, XdndTypeList, XdndActionList,
XdndActionDescription, XdndActionCopy, XdndActionPrivate,
@@ -314,6 +315,11 @@ namespace XRender
return xRenderQueryVersion != nullptr;
}
static bool hasCompositingWindowManager()
{
return XGetSelectionOwner (display, Atoms::get().compositingManager) != 0;
}
static XRenderPictFormat* findPictureFormat()
{
ScopedXLock xlock;
@@ -915,7 +921,7 @@ public:
clientMsg.window = windowH;
clientMsg.type = ClientMessage;
clientMsg.format = 32;
clientMsg.message_type = Atoms::get().WindowState;
clientMsg.message_type = Atoms::get().windowState;
clientMsg.data.l[0] = 0; // Remove
clientMsg.data.l[1] = fs;
clientMsg.data.l[2] = 0;
@@ -971,14 +977,14 @@ public:
Rectangle<int> getBounds() const override { return bounds; }
Point<int> localToGlobal (Point<int> relativePosition) override
Point<float> localToGlobal (Point<float> relativePosition) override
{
return relativePosition + bounds.getPosition();
return relativePosition + bounds.getPosition().toFloat();
}
Point<int> globalToLocal (Point<int> screenPosition) override
Point<float> globalToLocal (Point<float> screenPosition) override
{
return screenPosition - bounds.getPosition();
return screenPosition - bounds.getPosition().toFloat();
}
void setAlpha (float /* newAlpha */) override
@@ -1002,7 +1008,7 @@ public:
clientMsg.window = windowH;
clientMsg.type = ClientMessage;
clientMsg.format = 32;
clientMsg.message_type = Atoms::get().ChangeState;
clientMsg.message_type = Atoms::get().changeState;
clientMsg.data.l[0] = IconicState;
ScopedXLock xlock;
@@ -1018,10 +1024,10 @@ public:
{
ScopedXLock xlock;
const Atoms& atoms = Atoms::get();
GetXProperty prop (windowH, atoms.State, 0, 64, false, atoms.State);
GetXProperty prop (windowH, atoms.state, 0, 64, false, atoms.state);
return prop.success
&& prop.actualType == atoms.State
&& prop.actualType == atoms.state
&& prop.actualFormat == 32
&& prop.numItems > 0
&& ((unsigned long*) prop.data)[0] == IconicState;
@@ -1039,7 +1045,7 @@ public:
r = Desktop::getInstance().getDisplays().getMainDisplay().userArea;
if (! r.isEmpty())
setBounds (r, shouldBeFullScreen);
setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, r), shouldBeFullScreen);
component.repaint();
}
@@ -1081,9 +1087,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;
@@ -1109,9 +1113,9 @@ public:
if (c == &component)
break;
// TODO: needs scaling correctly
if (c->contains (localPos + bounds.getPosition() - c->getScreenPosition()))
return false;
if (ComponentPeer* peer = c->getPeer())
if (peer->contains (localPos + bounds.getPosition() - peer->getBounds().getPosition(), true))
return false;
}
if (trueIfInAChildWindow)
@@ -1152,7 +1156,7 @@ public:
ev.xclient.type = ClientMessage;
ev.xclient.serial = 0;
ev.xclient.send_event = True;
ev.xclient.message_type = Atoms::get().ActiveWin;
ev.xclient.message_type = Atoms::get().activeWin;
ev.xclient.window = windowH;
ev.xclient.format = 32;
ev.xclient.data.l[0] = 2;
@@ -1178,10 +1182,7 @@ public:
void toBehind (ComponentPeer* other) override
{
LinuxComponentPeer* const otherPeer = dynamic_cast <LinuxComponentPeer*> (other);
jassert (otherPeer != nullptr); // wrong type of window?
if (otherPeer != nullptr)
if (LinuxComponentPeer* const otherPeer = dynamic_cast<LinuxComponentPeer*> (other))
{
setMinimised (false);
@@ -1190,6 +1191,8 @@ public:
ScopedXLock xlock;
XRestackWindows (display, newStack, 2);
}
else
jassertfalse; // wrong type of window?
}
bool isFocused() const override
@@ -1217,11 +1220,11 @@ public:
}
}
void textInputRequired (const Point<int>&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
void repaint (const Rectangle<int>& area) override
{
repainter->repaint (area.getIntersection (component.getLocalBounds()));
repainter->repaint (area.getIntersection (bounds.withZeroOrigin()));
}
void performAnyPendingRepaintsNow() override
@@ -1327,6 +1330,7 @@ public:
default:
#if JUCE_USE_XSHM
if (XSHMHelpers::isShmAvailable())
{
ScopedXLock xlock;
if (event.xany.type == XShmGetEventBase (display))
@@ -1368,7 +1372,7 @@ public:
const ModifierKeys oldMods (currentModifiers);
bool keyPressed = false;
if ((sym & 0xff00) == 0xff00 || sym == XK_ISO_Left_Tab)
if ((sym & 0xff00) == 0xff00 || keyCode == XK_ISO_Left_Tab)
{
switch (sym) // Translate keypad
{
@@ -1427,6 +1431,11 @@ public:
keyCode &= 0xff;
break;
case XK_ISO_Left_Tab:
keyPressed = true;
keyCode = XK_Tab & 0xff;
break;
default:
if (sym >= XK_F1 && sym <= XK_F16)
{
@@ -1490,9 +1499,9 @@ public:
}
template <typename EventType>
static Point<int> getMousePos (const EventType& e) noexcept
static Point<float> getMousePos (const EventType& e) noexcept
{
return Point<int> (e.x, e.y);
return Point<float> ((float) e.x, (float) e.y);
}
void handleWheelEvent (const XButtonPressedEvent& buttonPressEvent, const float amount)
@@ -1698,11 +1707,11 @@ public:
{
const Atoms& atoms = Atoms::get();
if (clientMsg.message_type == atoms.Protocols && clientMsg.format == 32)
if (clientMsg.message_type == atoms.protocols && clientMsg.format == 32)
{
const Atom atom = (Atom) clientMsg.data.l[0];
if (atom == atoms.ProtocolList [Atoms::PING])
if (atom == atoms.protocolList [Atoms::PING])
{
Window root = RootWindow (display, DefaultScreen (display));
@@ -1711,7 +1720,7 @@ public:
XSendEvent (display, root, False, NoEventMask, &event);
XFlush (display);
}
else if (atom == atoms.ProtocolList [Atoms::TAKE_FOCUS])
else if (atom == atoms.protocolList [Atoms::TAKE_FOCUS])
{
if ((getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0)
{
@@ -1726,7 +1735,7 @@ public:
}
}
}
else if (atom == atoms.ProtocolList [Atoms::DELETE_WINDOW])
else if (atom == atoms.protocolList [Atoms::DELETE_WINDOW])
{
handleUserClosingWindow();
}
@@ -1902,7 +1911,8 @@ private:
for (const Rectangle<int>* i = originalRepaintRegion.begin(), * const e = originalRepaintRegion.end(); i != e; ++i)
{
#if JUCE_USE_XSHM
++shmPaintsPending;
if (XSHMHelpers::isShmAvailable())
++shmPaintsPending;
#endif
static_cast<XBitmapImage*> (image.getPixelData())
@@ -2166,7 +2176,7 @@ private:
netHints[1] = Atoms::getIfExists ("_KDE_NET_WM_WINDOW_TYPE_OVERRIDE");
xchangeProperty (windowH, Atoms::get().WindowType, XA_ATOM, 32, &netHints, 2);
xchangeProperty (windowH, Atoms::get().windowType, XA_ATOM, 32, &netHints, 2);
int numHints = 0;
@@ -2177,7 +2187,7 @@ private:
netHints [numHints++] = Atoms::getIfExists ("_NET_WM_STATE_ABOVE");
if (numHints > 0)
xchangeProperty (windowH, Atoms::get().WindowState, XA_ATOM, 32, &netHints, numHints);
xchangeProperty (windowH, Atoms::get().windowState, XA_ATOM, 32, &netHints, numHints);
}
void createWindow (Window parentToAddTo)
@@ -2254,10 +2264,10 @@ private:
// Associate the PID, allowing to be shut down when something goes wrong
unsigned long pid = getpid();
xchangeProperty (windowH, atoms.Pid, XA_CARDINAL, 32, &pid, 1);
xchangeProperty (windowH, atoms.pid, XA_CARDINAL, 32, &pid, 1);
// Set window manager protocols
xchangeProperty (windowH, atoms.Protocols, XA_ATOM, 32, atoms.ProtocolList, 2);
xchangeProperty (windowH, atoms.protocols, XA_ATOM, 32, atoms.protocolList, 2);
// Set drag and drop flags
xchangeProperty (windowH, atoms.XdndTypeList, XA_ATOM, 32, atoms.allowedMimeTypes, numElementsInArray (atoms.allowedMimeTypes));
@@ -2314,7 +2324,7 @@ private:
long getUserTime() const
{
GetXProperty prop (windowH, Atoms::get().UserTime, 0, 65536, false, XA_CARDINAL);
GetXProperty prop (windowH, Atoms::get().userTime, 0, 65536, false, XA_CARDINAL);
return prop.success ? *(long*) prop.data : 0;
}
@@ -3042,10 +3052,10 @@ void Desktop::Displays::findDisplays (float masterScale)
d.userArea = d.totalArea = Rectangle<int> (screens[j].x_org,
screens[j].y_org,
screens[j].width,
screens[j].height) * masterScale;
screens[j].height) / masterScale;
d.isMain = (index == 0);
d.scale = masterScale;
d.dpi = getDisplayDPI (index);
d.dpi = getDisplayDPI (0); // (all screens share the same DPI)
displays.add (d);
}
@@ -3114,14 +3124,20 @@ bool MouseInputSource::SourceList::addSource()
bool Desktop::canUseSemiTransparentWindows() noexcept
{
int matchedDepth = 0;
const int desiredDepth = 32;
#if JUCE_USE_XRENDER
if (XRender::hasCompositingWindowManager())
{
int matchedDepth = 0, desiredDepth = 32;
return Visuals::findVisualFormat (desiredDepth, matchedDepth) != 0
&& (matchedDepth == desiredDepth);
return Visuals::findVisualFormat (desiredDepth, matchedDepth) != 0
&& matchedDepth == desiredDepth;
}
#endif
return false;
}
Point<int> MouseInputSource::getCurrentRawMousePosition()
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
Window root, child;
int x, y, winx, winy;
@@ -3138,14 +3154,14 @@ Point<int> MouseInputSource::getCurrentRawMousePosition()
x = y = -1;
}
return Point<int> (x, y);
return Point<float> ((float) x, (float) y);
}
void MouseInputSource::setRawMousePosition (Point<int> newPosition)
void MouseInputSource::setRawMousePosition (Point<float> newPosition)
{
ScopedXLock xlock;
Window root = RootWindow (display, DefaultScreen (display));
XWarpPointer (display, None, root, 0, 0, 0, 0, newPosition.getX(), newPosition.getY());
XWarpPointer (display, None, root, 0, 0, 0, 0, roundToInt (newPosition.getX()), roundToInt (newPosition.getY()));
}
double Desktop::getDefaultMasterScale()
@@ -3364,7 +3380,7 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty
void MouseCursor::showInWindow (ComponentPeer* peer) const
{
if (LinuxComponentPeer* const lp = dynamic_cast <LinuxComponentPeer*> (peer))
if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (peer))
lp->showMouseCursor ((Cursor) getHandle());
}
@@ -3388,7 +3404,7 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi
if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
if (Component* sourceComp = draggingSource->getComponentUnderMouse())
if (LinuxComponentPeer* const lp = dynamic_cast <LinuxComponentPeer*> (sourceComp->getPeer()))
if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (sourceComp->getPeer()))
return lp->externalDragFileInit (files, canMoveFiles);
// This method must be called in response to a component's mouseDown or mouseDrag event!
@@ -3403,7 +3419,7 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text)
if (MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
if (Component* sourceComp = draggingSource->getComponentUnderMouse())
if (LinuxComponentPeer* const lp = dynamic_cast <LinuxComponentPeer*> (sourceComp->getPeer()))
if (LinuxComponentPeer* const lp = dynamic_cast<LinuxComponentPeer*> (sourceComp->getPeer()))
return lp->externalDragTextInit (text);
// This method must be called in response to a component's mouseDown or mouseDrag event!
@@ -295,14 +295,14 @@ public:
return getBounds (! isSharedWindow);
}
Point<int> localToGlobal (Point<int> relativePosition) override
Point<float> localToGlobal (Point<float> relativePosition) override
{
return relativePosition + getBounds (true).getPosition();
return relativePosition + getBounds (true).getPosition().toFloat();
}
Point<int> globalToLocal (Point<int> screenPosition) override
Point<float> globalToLocal (Point<float> screenPosition) override
{
return screenPosition - getBounds (true).getPosition();
return screenPosition - getBounds (true).getPosition().toFloat();
}
void setAlpha (float newAlpha) override
@@ -369,7 +369,7 @@ public:
// (can't call the component's setBounds method because that'll reset our fullscreen flag)
if (r != component.getBounds() && ! r.isEmpty())
setBounds (r, shouldBeFullScreen);
setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, r), shouldBeFullScreen);
}
}
}
@@ -390,16 +390,37 @@ public:
return ComponentPeer::isKioskMode();
}
static bool isWindowAtPoint (NSWindow* w, NSPoint screenPoint)
{
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
if ([NSWindow respondsToSelector: @selector (windowNumberAtPoint:belowWindowWithWindowNumber:)])
return [NSWindow windowNumberAtPoint: screenPoint belowWindowWithWindowNumber: 0] == [w windowNumber];
#endif
return true;
}
bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
{
NSRect frameRect = [view frame];
NSRect viewFrame = [view frame];
if (! (isPositiveAndBelow (localPos.getX(), (int) frameRect.size.width)
&& isPositiveAndBelow (localPos.getY(), (int) frameRect.size.height)))
if (! (isPositiveAndBelow (localPos.getX(), (int) viewFrame.size.width)
&& isPositiveAndBelow (localPos.getY(), (int) viewFrame.size.height)))
return false;
NSView* v = [view hitTest: NSMakePoint (frameRect.origin.x + localPos.getX(),
frameRect.origin.y + frameRect.size.height - localPos.getY())];
if (NSWindow* const viewWindow = [view window])
{
const NSRect windowFrame = [viewWindow frame];
const NSPoint windowPoint = [view convertPoint: NSMakePoint (localPos.x, localPos.y) toView: nil];
const NSPoint screenPoint = NSMakePoint (windowFrame.origin.x + windowPoint.x,
windowFrame.origin.y + windowFrame.size.height - windowPoint.y);
if (! isWindowAtPoint (viewWindow, screenPoint))
return false;
}
NSView* v = [view hitTest: NSMakePoint (viewFrame.origin.x + localPos.getX(),
viewFrame.origin.y + viewFrame.size.height - localPos.getY())];
return trueIfInAChildWindow ? (v != nil)
: (v == view);
@@ -553,19 +574,11 @@ public:
{
currentModifiers = currentModifiers.withoutMouseButtons();
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
if ([NSWindow respondsToSelector: @selector (windowNumberAtPoint:belowWindowWithWindowNumber:)]
&& [NSWindow windowNumberAtPoint: [[ev window] convertBaseToScreen: [ev locationInWindow]]
belowWindowWithWindowNumber: 0] != [window windowNumber])
{
// moved into another window which overlaps this one, so trigger an exit
handleMouseEvent (0, Point<int> (-1, -1), currentModifiers, getMouseTime (ev));
}
else
#endif
{
if (isWindowAtPoint ([ev window], [[ev window] convertBaseToScreen: [ev locationInWindow]]))
sendMouseEvent (ev);
}
else
// moved into another window which overlaps this one, so trigger an exit
handleMouseEvent (0, Point<float> (-1.0f, -1.0f), currentModifiers, getMouseTime (ev));
showArrowCursorIfNeeded();
}
@@ -936,7 +949,7 @@ public:
MouseInputSource mouse = desktop.getMainMouseSource();
if (mouse.getComponentUnderMouse() == nullptr
&& desktop.findComponentAt (mouse.getScreenPosition()) == nullptr)
&& desktop.findComponentAt (mouse.getScreenPosition().roundToInt()) == nullptr)
{
[[NSCursor arrowCursor] set];
}
@@ -1010,10 +1023,10 @@ public:
+ (int64) ([e timestamp] * 1000.0);
}
static Point<int> getMousePos (NSEvent* e, NSView* view)
static Point<float> getMousePos (NSEvent* e, NSView* view)
{
NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil];
return Point<int> ((int) p.x, (int) ([view frame].size.height - p.y));
return Point<float> ((float) p.x, (float) ([view frame].size.height - p.y));
}
static int getModifierForButtonNumber (const NSInteger num)
@@ -1136,8 +1149,9 @@ public:
bool isFocused() const override
{
return isSharedWindow ? this == currentlyFocusedPeer
: [window isKeyWindow];
return (isSharedWindow || ! JUCEApplication::isStandaloneApp())
? this == currentlyFocusedPeer
: [window isKeyWindow];
}
void grabFocus() override
@@ -1151,7 +1165,7 @@ public:
}
}
void textInputRequired (const Point<int>&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
//==============================================================================
void repaint (const Rectangle<int>& area) override
@@ -1221,6 +1235,8 @@ private:
const Rectangle<int> clipBounds (clipW, clipH);
const CGFloat viewH = [view frame].size.height;
clip.ensureStorageAllocated ((int) numRects);
for (int i = 0; i < numRects; ++i)
clip.addWithoutMerging (clipBounds.getIntersection (Rectangle<int> (roundToInt (rects[i].origin.x) + offset.x,
roundToInt (viewH - (rects[i].origin.y + rects[i].size.height)) + offset.y,
@@ -1687,21 +1703,22 @@ private:
};
//==============================================================================
struct JuceNSWindowClass : public ObjCClass <NSWindow>
struct JuceNSWindowClass : public ObjCClass<NSWindow>
{
JuceNSWindowClass() : ObjCClass <NSWindow> ("JUCEWindow_")
JuceNSWindowClass() : ObjCClass<NSWindow> ("JUCEWindow_")
{
addIvar<NSViewComponentPeer*> ("owner");
addMethod (@selector (canBecomeKeyWindow), canBecomeKeyWindow, "c@:");
addMethod (@selector (becomeKeyWindow), becomeKeyWindow, "v@:");
addMethod (@selector (windowShouldClose:), windowShouldClose, "c@:@");
addMethod (@selector (constrainFrameRect:toScreen:), constrainFrameRect, @encode (NSRect), "@:", @encode (NSRect), "@");
addMethod (@selector (windowWillResize:toSize:), windowWillResize, @encode (NSSize), "@:@", @encode (NSSize));
addMethod (@selector (zoom:), zoom, "v@:@");
addMethod (@selector (windowWillMove:), windowWillMove, "v@:@");
addMethod (@selector (canBecomeKeyWindow), canBecomeKeyWindow, "c@:");
addMethod (@selector (becomeKeyWindow), becomeKeyWindow, "v@:");
addMethod (@selector (windowShouldClose:), windowShouldClose, "c@:@");
addMethod (@selector (constrainFrameRect:toScreen:), constrainFrameRect, @encode (NSRect), "@:", @encode (NSRect), "@");
addMethod (@selector (windowWillResize:toSize:), windowWillResize, @encode (NSSize), "@:@", @encode (NSSize));
addMethod (@selector (windowDidExitFullScreen:), windowDidExitFullScreen, "v@:@");
addMethod (@selector (zoom:), zoom, "v@:@");
addMethod (@selector (windowWillMove:), windowWillMove, "v@:@");
addMethod (@selector (windowWillStartLiveResize:), windowWillStartLiveResize, "v@:@");
addMethod (@selector (windowDidEndLiveResize:), windowDidEndLiveResize, "v@:@");
addMethod (@selector (windowDidEndLiveResize:), windowDidEndLiveResize, "v@:@");
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
addProtocol (@protocol (NSWindowDelegate));
@@ -1767,6 +1784,11 @@ private:
return frameRect.size;
}
static void windowDidExitFullScreen (id, SEL, NSNotification*)
{
[NSApp setPresentationOptions: NSApplicationPresentationDefault];
}
static void zoom (id self, SEL, id sender)
{
if (NSViewComponentPeer* const owner = getOwner (self))
@@ -1865,7 +1887,7 @@ bool MouseInputSource::SourceList::addSource()
}
//==============================================================================
void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, bool allowMenusAndBars)
void Desktop::setKioskComponent (Component* kioskComp, bool shouldBeEnabled, bool allowMenusAndBars)
{
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
@@ -1876,13 +1898,15 @@ void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, boo
if (peer->hasNativeTitleBar()
&& [peer->window respondsToSelector: @selector (toggleFullScreen:)])
{
[peer->window performSelector: @selector (toggleFullScreen:)
withObject: [NSNumber numberWithBool: (BOOL) enableOrDisable]];
if (shouldBeEnabled && ! allowMenusAndBars)
[NSApp setPresentationOptions: NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar];
[peer->window performSelector: @selector (toggleFullScreen:) withObject: nil];
}
else
#endif
{
if (enableOrDisable)
if (shouldBeEnabled)
{
if (peer->hasNativeTitleBar())
[peer->window setStyleMask: NSBorderlessWindowMask];
@@ -1904,9 +1928,7 @@ void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, boo
}
}
#elif JUCE_SUPPORT_CARBON
(void) kioskComp; (void) enableOrDisable; (void) allowMenusAndBars;
if (enableOrDisable)
if (shouldBeEnabled)
{
SetSystemUIMode (kUIModeAllSuppressed, allowMenusAndBars ? kUIOptionAutoShowMenuBar : 0);
kioskComp->setBounds (Desktop::getInstance().getDisplays().getMainDisplay().totalArea);
@@ -1916,7 +1938,7 @@ void Desktop::setKioskComponent (Component* kioskComp, bool enableOrDisable, boo
SetSystemUIMode (kUIModeNormal, 0);
}
#else
(void) kioskComp; (void) enableOrDisable; (void) allowMenusAndBars;
(void) kioskComp; (void) shouldBeEnabled; (void) allowMenusAndBars;
// If you're targeting OSes earlier than 10.6 and want to use this feature,
// you'll need to enable JUCE_SUPPORT_CARBON.
@@ -209,16 +209,16 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
return true;
}
Point<int> MouseInputSource::getCurrentRawMousePosition()
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
JUCE_AUTORELEASEPOOL
{
const NSPoint p ([NSEvent mouseLocation]);
return Point<int> (roundToInt (p.x), roundToInt (getMainScreenHeight() - p.y));
return Point<float> ((float) p.x, (float) (getMainScreenHeight() - p.y));
}
}
void MouseInputSource::setRawMousePosition (Point<int> newPosition)
void MouseInputSource::setRawMousePosition (Point<float> newPosition)
{
// this rubbish needs to be done around the warp call, to avoid causing a
// bizarre glitch..
@@ -354,6 +354,30 @@ static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
return convertToRectInt (r);
}
static Desktop::Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& mainScreenBottom, const float masterScale)
{
Desktop::Displays::Display d;
d.isMain = (mainScreenBottom == 0);
if (d.isMain)
mainScreenBottom = [s frame].size.height;
d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom) / masterScale;
d.totalArea = convertDisplayRect ([s frame], mainScreenBottom) / masterScale;
d.scale = masterScale;
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
if ([s respondsToSelector: @selector (backingScaleFactor)])
d.scale *= s.backingScaleFactor;
#endif
NSSize dpi = [[[s deviceDescription] objectForKey: NSDeviceResolution] sizeValue];
d.dpi = (dpi.width + dpi.height) / 2.0;
return d;
}
void Desktop::Displays::findDisplays (const float masterScale)
{
JUCE_AUTORELEASEPOOL
@@ -363,30 +387,7 @@ void Desktop::Displays::findDisplays (const float masterScale)
CGFloat mainScreenBottom = 0;
for (NSScreen* s in [NSScreen screens])
{
Display d;
d.isMain = false;
if (mainScreenBottom == 0)
{
mainScreenBottom = [s frame].size.height;
d.isMain = true;
}
d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom) / masterScale;
d.totalArea = convertDisplayRect ([s frame], mainScreenBottom) / masterScale;
d.scale = masterScale;
#if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
if ([s respondsToSelector: @selector (backingScaleFactor)])
d.scale *= s.backingScaleFactor;
#endif
NSSize dpi = [[[s deviceDescription] objectForKey: NSDeviceResolution] sizeValue];
d.dpi = (dpi.width + dpi.height) / 2.0;
displays.add (d);
}
displays.add (getDisplayFromScreen (s, mainScreenBottom, masterScale));
}
}
@@ -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()
@@ -704,8 +706,8 @@ public:
r.top + windowBorder.getTop());
}
Point<int> localToGlobal (Point<int> relativePosition) override { return relativePosition + getScreenPosition(); }
Point<int> globalToLocal (Point<int> screenPosition) override { return screenPosition - getScreenPosition(); }
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getScreenPosition().toFloat(); }
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getScreenPosition().toFloat(); }
void setAlpha (float newAlpha) override
{
@@ -763,7 +765,7 @@ public:
ShowWindow (hwnd, SW_SHOWNORMAL);
if (! boundsCopy.isEmpty())
setBounds (boundsCopy, false);
setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, boundsCopy), false);
}
else
{
@@ -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);
@@ -877,7 +879,7 @@ public:
shouldDeactivateTitleBar = oldDeactivate;
}
void textInputRequired (const Point<int>&) override
void textInputRequired (Point<int>, TextInputTarget&) override
{
if (! hasCreatedCaret)
{
@@ -902,10 +904,15 @@ public:
void performAnyPendingRepaintsNow() override
{
MSG m;
if (component.isVisible()
&& (PeekMessage (&m, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE) || isUsingUpdateLayeredWindow()))
handlePaintMessage();
if (component.isVisible())
{
WeakReference<Component> localRef (&component);
MSG m;
if (isUsingUpdateLayeredWindow() || PeekMessage (&m, hwnd, WM_PAINT, WM_PAINT, PM_REMOVE))
if (localRef != nullptr) // (the PeekMessage call can dispatch messages, which may delete this comp)
handlePaintMessage();
}
}
//==============================================================================
@@ -955,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)) {}
@@ -988,7 +995,7 @@ public:
if (ownerInfo == nullptr)
return S_FALSE;
ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos);
ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos).roundToInt();
const bool wasWanted = ownerInfo->owner.handleDragMove (ownerInfo->dragInfo);
*pdwEffect = wasWanted ? (DWORD) DROPEFFECT_COPY : (DWORD) DROPEFFECT_NONE;
return S_OK;
@@ -999,7 +1006,7 @@ public:
HRESULT hr = updateFileList (pDataObject);
if (SUCCEEDED (hr))
{
ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos);
ownerInfo->dragInfo.position = ownerInfo->getMousePos (mousePos).roundToInt();
const bool wasWanted = ownerInfo->owner.handleDragDrop (ownerInfo->dragInfo);
*pdwEffect = wasWanted ? (DWORD) DROPEFFECT_COPY : (DWORD) DROPEFFECT_NONE;
hr = S_OK;
@@ -1013,9 +1020,10 @@ public:
{
OwnerInfo (HWNDComponentPeer& p) : owner (p) {}
Point<int> getMousePos (const POINTL& mousePos) const
Point<float> getMousePos (const POINTL& mousePos) const
{
return owner.globalToLocal (Point<int> (mousePos.x, mousePos.y));
return owner.globalToLocal (Point<float> (static_cast<float> (mousePos.x),
static_cast<float> (mousePos.y)));
}
template <typename CharType>
@@ -1093,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
{
@@ -1294,7 +1302,7 @@ private:
//==============================================================================
static void* createWindowCallback (void* userData)
{
static_cast <HWNDComponentPeer*> (userData)->createWindow();
static_cast<HWNDComponentPeer*> (userData)->createWindow();
return nullptr;
}
@@ -1522,10 +1530,14 @@ private:
// if something in a paint handler calls, e.g. a message box, this can become reentrant and
// corrupt the image it's using to paint into, so do a check here.
static bool reentrant = false;
if (! (reentrant || dontRepaint))
if (! reentrant)
{
const ScopedValueSetter<bool> setter (reentrant, true, false);
performPaint (dc, rgn, regionType, paintStruct);
if (dontRepaint)
component.handleCommandMessage (0); // (this triggers a repaint in the openGL context)
else
performPaint (dc, rgn, regionType, paintStruct);
}
DeleteObject (rgn);
@@ -1633,7 +1645,7 @@ private:
handlePaint (*context);
}
static_cast <WindowsBitmapImage*> (offscreenImage.getPixelData())
static_cast<WindowsBitmapImage*> (offscreenImage.getPixelData())
->blitToWindow (hwnd, dc, transparent, x, y, updateLayeredWindowAlpha);
}
@@ -1643,7 +1655,7 @@ private:
}
//==============================================================================
void doMouseEvent (Point<int> position)
void doMouseEvent (Point<float> position)
{
handleMouseEvent (0, position, currentModifiers, getMouseEventTime());
}
@@ -1694,7 +1706,7 @@ private:
return 1000 / 60; // Throttling the incoming mouse-events seems to still be needed in XP..
}
void doMouseMove (Point<int> position)
void doMouseMove (Point<float> position)
{
if (! isMouseOver)
{
@@ -1715,7 +1727,7 @@ private:
}
else if (! isDragging)
{
if (! contains (position, false))
if (! contains (position.roundToInt(), false))
return;
}
@@ -1730,7 +1742,7 @@ private:
}
}
void doMouseDown (Point<int> position, const WPARAM wParam)
void doMouseDown (Point<float> position, const WPARAM wParam)
{
if (GetCapture() != hwnd)
SetCapture (hwnd);
@@ -1743,7 +1755,7 @@ private:
doMouseEvent (position);
}
void doMouseUp (Point<int> position, const WPARAM wParam)
void doMouseUp (Point<float> position, const WPARAM wParam)
{
updateModifiersFromWParam (wParam);
const bool wasDragging = isDragging;
@@ -1779,9 +1791,9 @@ private:
doMouseEvent (getCurrentMousePos());
}
ComponentPeer* findPeerUnderMouse (Point<int>& localPos)
ComponentPeer* findPeerUnderMouse (Point<float>& localPos)
{
const Point<int> globalPos (getCurrentMousePosGlobal());
const Point<int> globalPos (getCurrentMousePosGlobal().roundToInt());
// Because Windows stupidly sends all wheel events to the window with the keyboard
// focus, we have to redirect them here according to the mouse pos..
@@ -1791,7 +1803,7 @@ private:
if (peer == nullptr)
peer = this;
localPos = peer->globalToLocal (globalPos);
localPos = peer->globalToLocal (globalPos.toFloat());
return peer;
}
@@ -1806,7 +1818,7 @@ private:
wheel.isReversed = false;
wheel.isSmooth = false;
Point<int> localPos;
Point<float> localPos;
if (ComponentPeer* const peer = findPeerUnderMouse (localPos))
peer->handleMouseWheel (0, localPos, getMouseEventTime(), wheel);
}
@@ -1820,7 +1832,7 @@ private:
if (getGestureInfo != nullptr && getGestureInfo ((HGESTUREINFO) lParam, &gi))
{
updateKeyModifiers();
Point<int> localPos;
Point<float> localPos;
if (ComponentPeer* const peer = findPeerUnderMouse (localPos))
{
@@ -1878,8 +1890,8 @@ private:
bool isCancel = false;
const int touchIndex = currentTouches.getIndexOfTouch (touch.dwID);
const int64 time = getMouseEventTime();
const Point<int> pos (globalToLocal (Point<int> ((int) TOUCH_COORD_TO_PIXEL (touch.x),
(int) TOUCH_COORD_TO_PIXEL (touch.y))));
const Point<float> pos (globalToLocal (Point<float> (static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.x)),
static_cast<float> (TOUCH_COORD_TO_PIXEL (touch.y)))));
ModifierKeys modsToSend (currentModifiers);
if (isDown)
@@ -1890,7 +1902,7 @@ private:
if (! isPrimary)
{
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before.
handleMouseEvent (touchIndex, pos, modsToSend.withoutMouseButtons(), time);
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend.withoutMouseButtons(), time);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return false;
}
@@ -1916,14 +1928,14 @@ private:
if (! isPrimary)
{
handleMouseEvent (touchIndex, pos, modsToSend, time);
handleMouseEvent (touchIndex, pos.toFloat(), modsToSend, time);
if (! isValidPeer (this)) // (in case this component was deleted by the event)
return false;
}
if ((isUp || isCancel) && ! isPrimary)
{
handleMouseEvent (touchIndex, Point<int> (-10, -10), currentModifiers, time);
handleMouseEvent (touchIndex, Point<float> (-10.0f, -10.0f), currentModifiers, time);
if (! isValidPeer (this))
return false;
}
@@ -2203,6 +2215,22 @@ private:
return 0;
}
bool handlePositionChanged()
{
const Point<float> pos (getCurrentMousePos());
if (contains (pos.roundToInt(), false))
{
doMouseEvent (pos);
if (! isValidPeer (this))
return true;
}
handleMovedOrResized();
return ! dontRepaint; // to allow non-accelerated openGL windows to draw themselves correctly..
}
void handleAppActivation (const WPARAM wParam)
{
modifiersAtLastCallback = -1;
@@ -2213,7 +2241,7 @@ private:
component.repaint();
handleMovedOrResized();
if (! ComponentPeer::isValidPeer (this))
if (! isValidPeer (this))
return;
}
@@ -2235,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())
@@ -2283,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())
{
@@ -2321,17 +2367,18 @@ private:
return MessageManager::getInstance()->callFunctionOnMessageThread (callback, userData);
}
static Point<int> getPointFromLParam (LPARAM lParam) noexcept
static Point<float> getPointFromLParam (LPARAM lParam) noexcept
{
return Point<int> (GET_X_LPARAM (lParam), GET_Y_LPARAM (lParam));
return Point<float> (static_cast<float> (GET_X_LPARAM (lParam)),
static_cast<float> (GET_Y_LPARAM (lParam)));
}
static Point<int> getCurrentMousePosGlobal() noexcept
static Point<float> getCurrentMousePosGlobal() noexcept
{
return getPointFromLParam (GetMessagePos());
}
Point<int> getCurrentMousePos() noexcept
Point<float> getCurrentMousePos() noexcept
{
return globalToLocal (getCurrentMousePosGlobal());
}
@@ -2411,18 +2458,10 @@ private:
case WM_WINDOWPOSCHANGING: return handlePositionChanging (*(WINDOWPOS*) lParam);
case WM_WINDOWPOSCHANGED:
{
const Point<int> pos (getCurrentMousePos());
if (contains (pos, false))
doMouseEvent (pos);
}
if (handlePositionChanged())
return 0;
handleMovedOrResized();
if (dontRepaint)
break; // needed for non-accelerated openGL windows to draw themselves correctly..
return 0;
break;
//==============================================================================
case WM_KEYDOWN:
@@ -2531,6 +2570,10 @@ private:
}
return TRUE;
case WM_POWERBROADCAST:
handlePowerBroadcast (wParam);
break;
case WM_SYNCPAINT:
return 0;
@@ -2860,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()));
@@ -2881,18 +2924,15 @@ private:
ModifierKeys HWNDComponentPeer::currentModifiers;
ModifierKeys HWNDComponentPeer::modifiersAtLastCallback;
ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindowToAttachTo)
ComponentPeer* Component::createNewPeer (int styleFlags, void* parentHWND)
{
return new HWNDComponentPeer (*this, styleFlags,
(HWND) nativeWindowToAttachTo, false);
return new HWNDComponentPeer (*this, styleFlags, (HWND) parentHWND, false);
}
ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component* component, void* parent)
ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component& component, void* parentHWND)
{
jassert (component != nullptr);
return new HWNDComponentPeer (*component, ComponentPeer::windowIgnoresMouseClicks,
(HWND) parent, true);
return new HWNDComponentPeer (component, ComponentPeer::windowIgnoresMouseClicks,
(HWND) parentHWND, true);
}
@@ -2965,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;
@@ -2991,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;
}
}
@@ -3126,16 +3166,17 @@ bool MouseInputSource::SourceList::addSource()
return false;
}
Point<int> MouseInputSource::getCurrentRawMousePosition()
Point<float> MouseInputSource::getCurrentRawMousePosition()
{
POINT mousePos;
GetCursorPos (&mousePos);
return Point<int> (mousePos.x, mousePos.y);
return Point<float> ((float) mousePos.x, (float) mousePos.y);
}
void MouseInputSource::setRawMousePosition (Point<int> newPosition)
void MouseInputSource::setRawMousePosition (Point<float> newPosition)
{
SetCursorPos (newPosition.x, newPosition.y);
SetCursorPos (roundToInt (newPosition.x),
roundToInt (newPosition.y));
}
//==============================================================================
@@ -3195,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);
@@ -81,8 +81,9 @@ public:
bool isDynamic() const;
/** Returns a string which represents this point.
This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of
the string syntax used by the coordinates, see the RelativeCoordinate constructor notes.
This returns a comma-separated list of coordinates, in the order left, top, right, bottom.
If you're using this to position a Component, then see the notes for
Component::setBounds (const RelativeRectangle&) for details of the syntax used.
The string that is returned can be passed to the RelativeRectangle constructor to recreate the rectangle.
*/
String toString() const;
@@ -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));
@@ -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;
@@ -74,7 +74,7 @@ ChoicePropertyComponent::ChoicePropertyComponent (const String& name)
ChoicePropertyComponent::ChoicePropertyComponent (const Value& valueToControl,
const String& name,
const StringArray& choiceList,
const Array <var>& correspondingValues)
const Array<var>& correspondingValues)
: PropertyComponent (name),
choices (choiceList),
isCustomClass (false)
@@ -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
@@ -70,7 +72,7 @@ public:
ChoicePropertyComponent (const Value& valueToControl,
const String& propertyName,
const StringArray& choices,
const Array <var>& correspondingValues);
const Array<var>& correspondingValues);
/** Destructor. */
~ChoicePropertyComponent();
@@ -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,
@@ -49,7 +49,7 @@ ComboBox::ComboBox (const String& name)
noChoicesMessage (TRANS("(no choices)"))
{
setRepaintsOnMouseActivity (true);
ComboBox::lookAndFeelChanged();
lookAndFeelChanged();
currentId.addListener (this);
}
@@ -410,12 +410,22 @@ void ComboBox::enablementChanged()
repaint();
}
void ComboBox::colourChanged()
{
lookAndFeelChanged();
}
void ComboBox::parentHierarchyChanged()
{
lookAndFeelChanged();
}
void ComboBox::lookAndFeelChanged()
{
repaint();
{
ScopedPointer <Label> newLabel (getLookAndFeel().createComboBoxTextBox (*this));
ScopedPointer<Label> newLabel (getLookAndFeel().createComboBoxTextBox (*this));
jassert (newLabel != nullptr);
if (label != nullptr)
@@ -446,11 +456,6 @@ void ComboBox::lookAndFeelChanged()
resized();
}
void ComboBox::colourChanged()
{
lookAndFeelChanged();
}
//==============================================================================
bool ComboBox::keyPressed (const KeyPress& key)
{
@@ -94,7 +94,7 @@ public:
@param newItemId an associated ID number that can be set or retrieved - see
getSelectedId() and setSelectedId(). Note that this value can not
be 0!
@see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId
@see setItemEnabled, addSeparator, addSectionHeading, getNumItems, getItemText, getItemId
*/
void addItem (const String& newItemText, int newItemId);
@@ -142,7 +142,7 @@ public:
If this call causes the content to be cleared, and a change-message
will be broadcast according to the notification parameter.
@see addItem, removeItem, getNumItems
@see addItem, getNumItems
*/
void clear (NotificationType notification = sendNotificationAsync);
@@ -257,8 +257,11 @@ public:
*/
void showEditor();
/** Pops up the combo box's list. */
void showPopup();
/** Pops up the combo box's list.
This is virtual so that you can override it with your own custom popup
mechanism if you need some really unusual behaviour.
*/
virtual void showPopup();
//==============================================================================
/**
@@ -393,6 +396,8 @@ public:
bool keyPressed (const KeyPress&) override;
/** @internal */
void valueChanged (Value&) override;
/** @internal */
void parentHierarchyChanged() override;
// These methods' bool parameters have changed: see their new method signatures.
JUCE_DEPRECATED (void clear (bool));
@@ -413,7 +418,7 @@ private:
bool isEnabled : 1, isHeading : 1;
};
OwnedArray <ItemInfo> items;
OwnedArray<ItemInfo> items;
Value currentId;
int lastCurrentId;
bool isButtonDown, separatorPending, menuActive, scrollWheelEnabled;
@@ -28,8 +28,7 @@ Label::Label (const String& name, const String& labelText)
lastTextValue (labelText),
font (15.0f),
justification (Justification::centredLeft),
horizontalBorderSize (5),
verticalBorderSize (1),
border (1, 5, 1, 5),
minimumHorizontalScale (0.7f),
editSingleClick (false),
editDoubleClick (false),
@@ -123,12 +122,11 @@ void Label::setJustificationType (Justification newJustification)
}
}
void Label::setBorderSize (int h, int v)
void Label::setBorderSize (BorderSize<int> newBorder)
{
if (horizontalBorderSize != h || verticalBorderSize != v)
if (border != newBorder)
{
horizontalBorderSize = h;
verticalBorderSize = v;
border = newBorder;
repaint();
}
}
@@ -191,7 +189,12 @@ void Label::componentVisibilityChanged (Component& component)
//==============================================================================
void Label::textWasEdited() {}
void Label::textWasChanged() {}
void Label::editorShown (TextEditor*) {}
void Label::editorShown (TextEditor* textEditor)
{
Component::BailOutChecker checker (this);
listeners.callChecked (checker, &LabelListener::editorShown, this, *textEditor);
}
void Label::editorAboutToBeHidden (TextEditor*)
{
@@ -286,11 +289,22 @@ bool Label::isBeingEdited() const noexcept
return editor != nullptr;
}
static void copyColourIfSpecified (Label& l, TextEditor& ed, int colourID, int targetColourID)
{
if (l.isColourSpecified (colourID) || l.getLookAndFeel().isColourSpecified (colourID))
ed.setColour (targetColourID, l.findColour (colourID));
}
TextEditor* Label::createEditorComponent()
{
TextEditor* const ed = new TextEditor (getName());
ed->applyFontToAllText (getLookAndFeel().getLabelFont (*this));
copyAllExplicitColoursTo (*ed);
copyColourIfSpecified (*this, *ed, textWhenEditingColourId, TextEditor::textColourId);
copyColourIfSpecified (*this, *ed, backgroundWhenEditingColourId, TextEditor::backgroundColourId);
copyColourIfSpecified (*this, *ed, outlineWhenEditingColourId, TextEditor::outlineColourId);
return ed;
}
@@ -325,7 +339,7 @@ void Label::mouseDoubleClick (const MouseEvent& e)
void Label::resized()
{
if (editor != nullptr)
editor->setBoundsInset (BorderSize<int> (0));
editor->setBounds (getLocalBounds());
}
void Label::focusGained (FocusChangeType cause)
@@ -74,7 +74,7 @@ public:
You can call Value::referTo() on this object to make the label read and control
a Value object that you supply.
*/
Value& getTextValue() { return textValue; }
Value& getTextValue() noexcept { return textValue; }
//==============================================================================
/** Changes the font to use to draw the text.
@@ -101,33 +101,32 @@ public:
*/
enum ColourIds
{
backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */
textColourId = 0x1000281, /**< The colour for the text. */
outlineColourId = 0x1000282 /**< An optional colour to use to draw a border around the label.
Leave this transparent to not have an outline. */
backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */
textColourId = 0x1000281, /**< The colour for the text. */
outlineColourId = 0x1000282, /**< An optional colour to use to draw a border around the label.
Leave this transparent to not have an outline. */
backgroundWhenEditingColourId = 0x1000283, /**< The background colour when the label is being edited. */
textWhenEditingColourId = 0x1000284, /**< The colour for the text when the label is being edited. */
outlineWhenEditingColourId = 0x1000285 /**< An optional border colour when the label is being edited. */
};
//==============================================================================
/** Sets the style of justification to be used for positioning the text.
(The default is Justification::centredLeft)
*/
void setJustificationType (Justification justification);
/** Returns the type of justification, as set in setJustificationType(). */
Justification getJustificationType() const noexcept { return justification; }
Justification getJustificationType() const noexcept { return justification; }
/** Changes the gap that is left between the edge of the component and the text.
/** Changes the border that is left between the edge of the component and the text.
By default there's a small gap left at the sides of the component to allow for
the drawing of the border, but you can change this if necessary.
*/
void setBorderSize (int horizontalBorder, int verticalBorder);
void setBorderSize (BorderSize<int> newBorderSize);
/** Returns the size of the horizontal gap being left around the text. */
int getHorizontalBorderSize() const noexcept { return horizontalBorderSize; }
/** Returns the size of the vertical gap being left around the text. */
int getVerticalBorderSize() const noexcept { return verticalBorderSize; }
/** Returns the size of the border to be left around the text. */
BorderSize<int> getBorderSize() const noexcept { return border; }
/** Makes this label "stick to" another component.
@@ -152,16 +151,17 @@ public:
Returns false if the label is above the other component. This is only relevent if
attachToComponent() has been called.
*/
bool isAttachedOnLeft() const noexcept { return leftOfOwnerComp; }
bool isAttachedOnLeft() const noexcept { return leftOfOwnerComp; }
/** Specifies the minimum amount that the font can be squashed horizantally before it starts
/** Specifies the minimum amount that the font can be squashed horizontally before it starts
using ellipsis.
@see Graphics::drawFittedText
*/
void setMinimumHorizontalScale (float newScale);
float getMinimumHorizontalScale() const noexcept { return minimumHorizontalScale; }
/** Specifies the amount that the font can be squashed horizontally. */
float getMinimumHorizontalScale() const noexcept { return minimumHorizontalScale; }
//==============================================================================
/**
@@ -182,6 +182,9 @@ public:
/** Called when a Label's text has changed. */
virtual void labelTextChanged (Label* labelThatHasChanged) = 0;
/** Called when a Label goes into editing mode and displays a TextEditor. */
virtual void editorShown (Label*, TextEditor&) {}
};
/** Registers a listener that will be called when the label's text changes. */
@@ -228,7 +231,6 @@ public:
bool isEditable() const noexcept { return editSingleClick || editDoubleClick; }
/** Makes the editor appear as if the label had been clicked by the user.
@see textWasEdited, setEditable
*/
void showEditor();
@@ -327,7 +329,7 @@ private:
ScopedPointer<TextEditor> editor;
ListenerList<Listener> listeners;
WeakReference<Component> ownerComponent;
int horizontalBorderSize, verticalBorderSize;
BorderSize<int> border;
float minimumHorizontalScale;
bool editSingleClick;
bool editDoubleClick;
@@ -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)
@@ -457,7 +463,7 @@ void ListBox::updateContent()
if (selected.size() > 0 && selected [selected.size() - 1] >= totalItems)
{
selected.removeRange (Range <int> (totalItems, std::numeric_limits<int>::max()));
selected.removeRange (Range<int> (totalItems, std::numeric_limits<int>::max()));
lastRowSelected = getSelectedRow (0);
selectionChanged = true;
}
@@ -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);
}
@@ -516,7 +520,7 @@ void ListBox::deselectRow (const int row)
{
if (selected.contains (row))
{
selected.removeRange (Range <int> (row, row + 1));
selected.removeRange (Range<int> (row, row + 1));
if (row == lastRowSelected)
lastRowSelected = getSelectedRow (0);
@@ -530,7 +534,7 @@ void ListBox::setSelectedRows (const SparseSet<int>& setOfRowsToBeSelected,
const NotificationType sendNotificationEventToModel)
{
selected = setOfRowsToBeSelected;
selected.removeRange (Range <int> (totalItems, std::numeric_limits<int>::max()));
selected.removeRange (Range<int> (totalItems, std::numeric_limits<int>::max()));
if (! isRowSelected (lastRowSelected))
lastRowSelected = getSelectedRow (0);
@@ -554,10 +558,10 @@ void ListBox::selectRangeOfRows (int firstRow, int lastRow)
firstRow = jlimit (0, jmax (0, numRows), firstRow);
lastRow = jlimit (0, jmax (0, numRows), lastRow);
selected.addRange (Range <int> (jmin (firstRow, lastRow),
jmax (firstRow, lastRow) + 1));
selected.addRange (Range<int> (jmin (firstRow, lastRow),
jmax (firstRow, lastRow) + 1));
selected.removeRange (Range <int> (lastRow, lastRow + 1));
selected.removeRange (Range<int> (lastRow, lastRow + 1));
}
selectRowInternal (lastRow, false, false, true);
@@ -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);
}
@@ -652,7 +656,7 @@ int ListBox::getInsertionIndexForPosition (const int x, const int y) const noexc
Component* ListBox::getComponentForRowNumber (const int row) const noexcept
{
if (RowComponent* const listRowComp = viewport->getComponentForRowIfOnscreen (row))
return static_cast <Component*> (listRowComp->customComponent);
return static_cast<Component*> (listRowComp->customComponent);
return nullptr;
}
@@ -809,7 +813,7 @@ void ListBox::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& whee
void ListBox::mouseUp (const MouseEvent& e)
{
if (e.mouseWasClicked() && model != nullptr)
model->backgroundClicked();
model->backgroundClicked (e);
}
//==============================================================================
@@ -853,6 +857,11 @@ void ListBox::colourChanged()
repaint();
}
void ListBox::parentHierarchyChanged()
{
colourChanged();
}
void ListBox::setOutlineThickness (const int newThickness)
{
outlineThickness = newThickness;
@@ -878,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;)
{
@@ -947,7 +956,7 @@ Component* ListBoxModel::refreshComponentForRow (int, bool, Component* existingC
void ListBoxModel::listBoxItemClicked (int, const MouseEvent&) {}
void ListBoxModel::listBoxItemDoubleClicked (int, const MouseEvent&) {}
void ListBoxModel::backgroundClicked() {}
void ListBoxModel::backgroundClicked (const MouseEvent&) {}
void ListBoxModel::selectedRowsChanged (int) {}
void ListBoxModel::deleteKeyPressed (int) {}
void ListBoxModel::returnKeyPressed (int) {}
@@ -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,
@@ -84,18 +87,18 @@ public:
/** This can be overridden to react to the user clicking on a row.
@see listBoxItemDoubleClicked
*/
virtual void listBoxItemClicked (int row, const MouseEvent& e);
virtual void listBoxItemClicked (int row, const MouseEvent&);
/** This can be overridden to react to the user double-clicking on a row.
@see listBoxItemClicked
*/
virtual void listBoxItemDoubleClicked (int row, const MouseEvent& e);
virtual void listBoxItemDoubleClicked (int row, const MouseEvent&);
/** This can be overridden to react to the user clicking on a part of the list where
there are no rows.
@see listBoxItemClicked
*/
virtual void backgroundClicked();
virtual void backgroundClicked (const MouseEvent&);
/** Override this to be informed when rows are selected or deselected.
@@ -152,6 +155,12 @@ public:
/** You can override this to return a custom mouse cursor for each row. */
virtual MouseCursor getMouseCursorForRow (int row);
private:
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// This method's signature has changed to take a MouseEvent parameter - please update your code!
JUCE_DEPRECATED_WITH_BODY (virtual int backgroundClicked(), { return 0; })
#endif
};
@@ -210,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.
@@ -534,6 +552,8 @@ public:
/** @internal */
void colourChanged() override;
/** @internal */
void parentHierarchyChanged() override;
/** @internal */
void startDragAndDrop (const MouseEvent&, const var& dragDescription, bool allowDraggingToOtherWindows);
private:
@@ -549,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,
@@ -320,12 +320,12 @@ public:
{
if (notification != dontSendNotification)
{
owner.valueChanged();
if (notification == sendNotificationSync)
handleAsyncUpdate();
else
triggerAsyncUpdate();
owner.valueChanged();
}
}
@@ -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;
@@ -566,6 +566,7 @@ public:
valueBox->setWantsKeyboardFocus (false);
valueBox->setText (previousTextBoxContent, dontSendNotification);
valueBox->setTooltip (owner.getTooltip());
if (valueBox->isEditable() != editableText) // (avoid overriding the single/double click flags unless we have to)
valueBox->setEditable (editableText && owner.isEnabled());
@@ -577,10 +578,6 @@ public:
valueBox->addMouseListener (&owner, false);
valueBox->setMouseCursor (MouseCursor::ParentCursor);
}
else
{
valueBox->setTooltip (owner.getTooltip());
}
}
else
{
@@ -667,7 +664,7 @@ public:
if (isTwoValue || isThreeValue)
{
const float mousePos = (float) (isVertical() ? e.y : e.x);
const float mousePos = isVertical() ? e.position.y : e.position.x;
const float normalPosDistance = std::abs (getLinearSliderPos (currentValue.getValue()) - mousePos);
const float minPosDistance = std::abs (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos);
@@ -689,10 +686,10 @@ public:
//==============================================================================
void handleRotaryDrag (const MouseEvent& e)
{
const int dx = e.x - sliderRect.getCentreX();
const int dy = e.y - sliderRect.getCentreY();
const float dx = e.position.x - sliderRect.getCentreX();
const float dy = e.position.y - sliderRect.getCentreY();
if (dx * dx + dy * dy > 25)
if (dx * dx + dy * dy > 25.0f)
{
double angle = std::atan2 ((double) dx, (double) -dy);
while (angle < 0.0)
@@ -736,7 +733,7 @@ public:
void handleAbsoluteDrag (const MouseEvent& e)
{
const int mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.x : e.y;
const float mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.position.x : e.position.y;
double newPos = (mousePos - sliderRegionStart) / (double) sliderRegionSize;
if (style == RotaryHorizontalDrag
@@ -745,12 +742,12 @@ public:
|| ((style == LinearHorizontal || style == LinearVertical || style == LinearBar || style == LinearBarVertical)
&& ! snapsToMousePos))
{
const int mouseDiff = (style == RotaryHorizontalDrag
|| style == LinearHorizontal
|| style == LinearBar
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mouseDragStartPos.x
: mouseDragStartPos.y - e.y;
const float mouseDiff = (style == RotaryHorizontalDrag
|| style == LinearHorizontal
|| style == LinearBar
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.position.x - mouseDragStartPos.x
: mouseDragStartPos.y - e.position.y;
newPos = owner.valueToProportionOfLength (valueOnMouseDown)
+ mouseDiff * (1.0 / pixelsForFullDragExtent);
@@ -763,7 +760,8 @@ public:
}
else if (style == RotaryHorizontalVerticalDrag)
{
const int mouseDiff = (e.x - mouseDragStartPos.x) + (mouseDragStartPos.y - e.y);
const float mouseDiff = (e.position.x - mouseDragStartPos.x)
+ (mouseDragStartPos.y - e.position.y);
newPos = owner.valueToProportionOfLength (valueOnMouseDown)
+ mouseDiff * (1.0 / pixelsForFullDragExtent);
@@ -779,16 +777,16 @@ public:
void handleVelocityDrag (const MouseEvent& e)
{
const int mouseDiff = style == RotaryHorizontalVerticalDrag
? (e.x - mousePosWhenLastDragged.x) + (mousePosWhenLastDragged.y - e.y)
: (isHorizontal()
|| style == RotaryHorizontalDrag
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mousePosWhenLastDragged.x
: e.y - mousePosWhenLastDragged.y;
const float mouseDiff = style == RotaryHorizontalVerticalDrag
? (e.position.x - mousePosWhenLastDragged.x) + (mousePosWhenLastDragged.y - e.position.y)
: (isHorizontal()
|| style == RotaryHorizontalDrag
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.position.x - mousePosWhenLastDragged.x
: e.position.y - mousePosWhenLastDragged.y;
const double maxSpeed = jmax (200, sliderRegionSize);
double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff));
double speed = jlimit (0.0, maxSpeed, (double) std::abs (mouseDiff));
if (speed != 0)
{
@@ -816,7 +814,7 @@ public:
{
incDecDragged = false;
useDragEvents = false;
mouseDragStartPos = mousePosWhenLastDragged = e.getPosition();
mouseDragStartPos = mousePosWhenLastDragged = e.position;
currentDrag = nullptr;
if (owner.isEnabled())
@@ -887,7 +885,7 @@ public:
return;
incDecDragged = true;
mouseDragStartPos = e.getPosition();
mouseDragStartPos = e.position;
}
if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval)
@@ -930,7 +928,7 @@ public:
minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue();
}
mousePosWhenLastDragged = e.getPosition();
mousePosWhenLastDragged = e.position;
}
}
@@ -980,29 +978,45 @@ public:
}
}
double getMouseWheelDelta (double value, double wheelAmount)
{
if (style == IncDecButtons)
return interval * wheelAmount;
const double proportionDelta = wheelAmount * 0.15f;
const double currentPos = owner.valueToProportionOfLength (value);
return owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)) - value;
}
bool mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel)
{
if (scrollWheelEnabled
&& style != TwoValueHorizontal
&& style != TwoValueVertical)
{
if (maximum > minimum && ! e.mods.isAnyMouseButtonDown())
// sometimes duplicate wheel events seem to be sent, so since we're going to
// bump the value by a minimum of the interval, avoid doing this twice..
if (e.eventTime != lastMouseWheelTime)
{
if (valueBox != nullptr)
valueBox->hideEditor (false);
lastMouseWheelTime = e.eventTime;
const double value = (double) currentValue.getValue();
const double proportionDelta = (wheel.deltaX != 0 ? -wheel.deltaX : wheel.deltaY)
* (wheel.isReversed ? -0.15f : 0.15f);
const double currentPos = owner.valueToProportionOfLength (value);
const double newValue = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta));
if (maximum > minimum && ! e.mods.isAnyMouseButtonDown())
{
if (valueBox != nullptr)
valueBox->hideEditor (false);
double delta = (newValue != value) ? jmax (std::abs (newValue - value), interval) : 0;
if (value > newValue)
delta = -delta;
const double value = (double) currentValue.getValue();
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);
DragInProgress drag (*this);
setValue (owner.snapValue (value + delta, notDragging), sendNotificationSync);
DragInProgress drag (*this);
setValue (owner.snapValue (newValue, notDragging), sendNotificationSync);
}
}
}
return true;
@@ -1036,29 +1050,29 @@ public:
const double pos = sliderBeingDragged == 2 ? getMaxValue()
: (sliderBeingDragged == 1 ? getMinValue()
: (double) currentValue.getValue());
Point<int> mousePos;
Point<float> mousePos;
if (isRotary())
{
mousePos = mi->getLastMouseDownPosition();
const int delta = roundToInt (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown)
- owner.valueToProportionOfLength (pos)));
const float delta = (float) (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown)
- owner.valueToProportionOfLength (pos)));
if (style == RotaryHorizontalDrag) mousePos += Point<int> (-delta, 0);
else if (style == RotaryVerticalDrag) mousePos += Point<int> (0, delta);
else mousePos += Point<int> (delta / -2, delta / 2);
if (style == RotaryHorizontalDrag) mousePos += Point<float> (-delta, 0.0f);
else if (style == RotaryVerticalDrag) mousePos += Point<float> (0.0f, delta);
else mousePos += Point<float> (delta / -2.0f, delta / 2.0f);
mousePos = owner.getScreenBounds().reduced (4).getConstrainedPoint (mousePos);
mousePos = owner.getScreenBounds().reduced (4).toFloat().getConstrainedPoint (mousePos);
mouseDragStartPos = mousePosWhenLastDragged = owner.getLocalPoint (nullptr, mousePos);
valueOnMouseDown = valueWhenLastDragged;
}
else
{
const int pixelPos = (int) getLinearSliderPos (pos);
const float pixelPos = (float) getLinearSliderPos (pos);
mousePos = owner.localPointToGlobal (Point<int> (isHorizontal() ? pixelPos : (owner.getWidth() / 2),
isVertical() ? pixelPos : (owner.getHeight() / 2)));
mousePos = owner.localPointToGlobal (Point<float> (isHorizontal() ? pixelPos : (owner.getWidth() / 2.0f),
isVertical() ? pixelPos : (owner.getHeight() / 2.0f)));
}
mi->setScreenPosition (mousePos);
@@ -1231,10 +1245,11 @@ public:
double velocityModeSensitivity, velocityModeOffset, minMaxDiff;
int velocityModeThreshold;
float rotaryStart, rotaryEnd;
Point<int> mouseDragStartPos, mousePosWhenLastDragged;
Point<float> mouseDragStartPos, mousePosWhenLastDragged;
int sliderRegionStart, sliderRegionSize;
int sliderBeingDragged;
int pixelsForFullDragExtent;
Time lastMouseWheelTime;
Rectangle<int> sliderRect;
ScopedPointer<DragInProgress> currentDrag;
@@ -1272,6 +1287,7 @@ public:
{
setAlwaysOnTop (true);
setAllowedPlacement (owner.getLookAndFeel().getSliderPopupPlacement (s));
setLookAndFeel (&s.getLookAndFeel());
}
void paintContent (Graphics& g, int w, int h)
@@ -623,7 +623,7 @@ void TableHeaderComponent::mouseDrag (const MouseEvent& e)
minWidthOnRight += columns.getUnchecked (i)->minimumWidth;
const Rectangle<int> currentPos (getColumnPosition (getIndexOfColumnId (columnIdBeingResized, true)));
w = jmax (ci->minimumWidth, jmin (w, getWidth() - minWidthOnRight - currentPos.getX()));
w = jmax (ci->minimumWidth, jmin (w, lastDeliberateWidth - minWidthOnRight - currentPos.getX()));
}
setColumnWidth (columnIdBeingResized, w);
@@ -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;
}
@@ -398,10 +393,10 @@ void TableListBox::returnKeyPressed (int row)
model->returnKeyPressed (row);
}
void TableListBox::backgroundClicked()
void TableListBox::backgroundClicked (const MouseEvent& e)
{
if (model != nullptr)
model->backgroundClicked();
model->backgroundClicked (e);
}
void TableListBox::listWasScrolled()
@@ -450,14 +445,14 @@ 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();
}
//==============================================================================
void TableListBoxModel::cellClicked (int, int, const MouseEvent&) {}
void TableListBoxModel::cellDoubleClicked (int, int, const MouseEvent&) {}
void TableListBoxModel::backgroundClicked() {}
void TableListBoxModel::backgroundClicked (const MouseEvent&) {}
void TableListBoxModel::sortOrderChanged (int, const bool) {}
int TableListBoxModel::getColumnAutoSizeWidth (int) { return 0; }
void TableListBoxModel::selectedRowsChanged (int) {}
@@ -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)
@@ -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,
@@ -103,21 +106,21 @@ public:
The mouse event's coordinates will be relative to the entire table row.
@see cellDoubleClicked, backgroundClicked
*/
virtual void cellClicked (int rowNumber, int columnId, const MouseEvent& e);
virtual void cellClicked (int rowNumber, int columnId, const MouseEvent&);
/** This callback is made when the user clicks on one of the cells in the table.
The mouse event's coordinates will be relative to the entire table row.
@see cellClicked, backgroundClicked
*/
virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent& e);
virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent&);
/** This can be overridden to react to the user double-clicking on a part of the list where
there are no rows.
@see cellClicked
*/
virtual void backgroundClicked();
virtual void backgroundClicked (const MouseEvent&);
//==============================================================================
/** This callback is made when the table's sort order is changed.
@@ -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);
@@ -182,6 +181,12 @@ public:
@see getDragSourceCustomData, DragAndDropContainer::startDragging
*/
virtual var getDragSourceDescription (const SparseSet<int>& currentlySelectedRows);
private:
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
// This method's signature has changed to take a MouseEvent parameter - please update your code!
JUCE_DEPRECATED_WITH_BODY (virtual int backgroundClicked(), { return 0; })
#endif
};
@@ -204,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);
@@ -238,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.
@@ -254,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.
@@ -303,7 +312,7 @@ public:
/** @internal */
void returnKeyPressed (int currentSelectedRow) override;
/** @internal */
void backgroundClicked() override;
void backgroundClicked (const MouseEvent&) override;
/** @internal */
void listWasScrolled() override;
/** @internal */
@@ -1931,7 +1931,7 @@ bool TextEditor::deleteBackwards (bool moveInWholeWordSteps)
if (moveInWholeWordSteps)
moveCaretTo (findWordBreakBefore (getCaretPosition()), true);
else if (selection.isEmpty() && selection.getStart() > 0)
selection.setStart (selection.getEnd() - 1);
selection = Range<int> (selection.getEnd() - 1, selection.getEnd());
cut();
return true;
@@ -1940,7 +1940,7 @@ bool TextEditor::deleteBackwards (bool moveInWholeWordSteps)
bool TextEditor::deleteForwards (bool /*moveInWholeWordSteps*/)
{
if (selection.isEmpty() && selection.getStart() < getTotalNumChars())
selection.setEnd (selection.getStart() + 1);
selection = Range<int> (selection.getStart(), selection.getStart() + 1);
cut();
return true;
@@ -2059,7 +2059,7 @@ void TextEditor::focusGained (FocusChangeType)
if (ComponentPeer* const peer = getPeer())
if (! isReadOnly())
peer->textInputRequired (peer->globalToLocal (getScreenPosition()));
peer->textInputRequired (peer->globalToLocal (getScreenPosition()), *this);
}
void TextEditor::focusLost (FocusChangeType)
@@ -568,6 +568,9 @@ public:
*/
void setInputFilter (InputFilter* newFilter, bool takeOwnership);
/** Returns the current InputFilter, as set by setInputFilter(). */
InputFilter* getInputFilter() const noexcept { return inputFilter; }
/** Sets limits on the characters that can be entered.
This is just a shortcut that passes an instance of the LengthAndCharacterRestriction
class to setInputFilter().
@@ -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;
}
@@ -67,7 +67,7 @@ public:
selectBasedOnModifiers (item, e.mods);
if (e.x >= pos.getX())
item->itemClicked (e.withNewPosition (e.getPosition() - pos.getPosition()));
item->itemClicked (e.withNewPosition (e.position - pos.getPosition().toFloat()));
}
}
}
@@ -92,7 +92,7 @@ public:
Rectangle<int> pos;
if (TreeViewItem* const item = findItemAt (e.y, pos))
if (e.x >= pos.getX() || ! owner.openCloseButtonsVisible)
item->itemDoubleClicked (e.withNewPosition (e.getPosition() - pos.getPosition()));
item->itemDoubleClicked (e.withNewPosition (e.position - pos.getPosition().toFloat()));
}
}
@@ -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;
@@ -744,7 +744,7 @@ public:
void setIndentSize (int newIndentSize);
/** Searches the tree for an item with the specified identifier.
The identifer string must have been created by calling TreeViewItem::getItemIdentifierString().
The identifier string must have been created by calling TreeViewItem::getItemIdentifierString().
If no such item exists, this will return false. If the item is found, all of its items
will be automatically opened.
*/
@@ -404,7 +404,7 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize)
for (int i = textBlocks.size(); --i >= 0;)
{
const AlertTextComp* const ac = static_cast <const AlertTextComp*> (textBlocks.getUnchecked(i));
const AlertTextComp* const ac = static_cast<const AlertTextComp*> (textBlocks.getUnchecked(i));
w = jmax (w, ac->getPreferredWidth());
}
@@ -412,7 +412,7 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize)
for (int i = textBlocks.size(); --i >= 0;)
{
AlertTextComp* const ac = static_cast <AlertTextComp*> (textBlocks.getUnchecked(i));
AlertTextComp* const ac = static_cast<AlertTextComp*> (textBlocks.getUnchecked(i));
ac->updateLayout ((int) (w * 0.8f));
h += ac->getHeight() + 10;
}
@@ -470,11 +470,11 @@ void AlertWindow::updateLayout (const bool onlyIncreaseSize)
Component* const c = allComps.getUnchecked(i);
h = 22;
const int comboIndex = comboBoxes.indexOf (dynamic_cast <ComboBox*> (c));
const int comboIndex = comboBoxes.indexOf (dynamic_cast<ComboBox*> (c));
if (comboIndex >= 0 && comboBoxNames [comboIndex].isNotEmpty())
y += labelHeight;
const int tbIndex = textBoxes.indexOf (dynamic_cast <TextEditor*> (c));
const int tbIndex = textBoxes.indexOf (dynamic_cast<TextEditor*> (c));
if (tbIndex >= 0 && textboxNames[tbIndex].isNotEmpty())
y += labelHeight;
@@ -536,7 +536,8 @@ bool AlertWindow::keyPressed (const KeyPress& key)
exitModalState (0);
return true;
}
else if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
if (key.isKeyCode (KeyPress::returnKey) && buttons.size() == 1)
{
buttons.getUnchecked(0)->triggerClick();
return true;
@@ -592,8 +593,8 @@ private:
LookAndFeel& lf = associatedComponent != nullptr ? associatedComponent->getLookAndFeel()
: LookAndFeel::getDefaultLookAndFeel();
ScopedPointer <Component> alertBox (lf.createAlertWindow (title, message, button1, button2, button3,
iconType, numButtons, associatedComponent));
ScopedPointer<Component> alertBox (lf.createAlertWindow (title, message, button1, button2, button3,
iconType, numButtons, associatedComponent));
jassert (alertBox != nullptr); // you have to return one of these!
@@ -614,7 +615,7 @@ private:
static void* showCallback (void* userData)
{
static_cast <AlertWindowInfo*> (userData)->show();
static_cast<AlertWindowInfo*> (userData)->show();
return nullptr;
}
};
@@ -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);
@@ -91,7 +91,7 @@ void CallOutBox::setArrowSize (const float newSize)
int CallOutBox::getBorderSize() const noexcept
{
return jmax (20, (int) arrowSize);
return jmax (getLookAndFeel().getCallOutBoxBorderSize (*this), (int) arrowSize);
}
void CallOutBox::paint (Graphics& g)
@@ -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)
@@ -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
@@ -130,6 +140,7 @@ public:
virtual ~LookAndFeelMethods() {}
virtual void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image& cachedImage) = 0;
virtual int getCallOutBoxBorderSize (const CallOutBox&) = 0;
};
//==============================================================================
@@ -160,6 +171,7 @@ private:
Point<float> targetPoint;
Rectangle<int> availableArea, targetArea;
Image background;
bool dismissalMouseClicksAreAlwaysConsumed;
void refreshPath();
@@ -85,25 +85,22 @@ bool ComponentPeer::isKioskMode() const
}
//==============================================================================
void ComponentPeer::handleMouseEvent (const int touchIndex, const Point<int> positionWithinPeer,
const ModifierKeys newMods, const int64 time)
void ComponentPeer::handleMouseEvent (int touchIndex, Point<float> pos, ModifierKeys newMods, int64 time)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
MouseInputSource (*mouse).handleEvent (*this, positionWithinPeer, time, newMods);
MouseInputSource (*mouse).handleEvent (*this, pos, time, newMods);
}
void ComponentPeer::handleMouseWheel (const int touchIndex, const Point<int> positionWithinPeer,
const int64 time, const MouseWheelDetails& wheel)
void ComponentPeer::handleMouseWheel (int touchIndex, Point<float> pos, int64 time, const MouseWheelDetails& wheel)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
MouseInputSource (*mouse).handleWheel (*this, positionWithinPeer, time, wheel);
MouseInputSource (*mouse).handleWheel (*this, pos, time, wheel);
}
void ComponentPeer::handleMagnifyGesture (const int touchIndex, const Point<int> positionWithinPeer,
const int64 time, const float scaleFactor)
void ComponentPeer::handleMagnifyGesture (int touchIndex, Point<float> pos, int64 time, float scaleFactor)
{
if (MouseInputSource* mouse = Desktop::getInstance().mouseSources->getOrCreateMouseInputSource (touchIndex))
MouseInputSource (*mouse).handleMagnifyGesture (*this, positionWithinPeer, time, scaleFactor);
MouseInputSource (*mouse).handleMagnifyGesture (*this, pos, time, scaleFactor);
}
//==============================================================================
@@ -402,6 +399,9 @@ const Rectangle<int>& ComponentPeer::getNonFullScreenBounds() const noexcept
return lastNonFullscreenBounds;
}
Point<int> ComponentPeer::localToGlobal (Point<int> p) { return localToGlobal (p.toFloat()).roundToInt(); }
Point<int> ComponentPeer::globalToLocal (Point<int> p) { return globalToLocal (p.toFloat()).roundToInt(); }
Rectangle<int> ComponentPeer::localToGlobal (const Rectangle<int>& relativePosition)
{
return relativePosition.withPosition (localToGlobal (relativePosition.getPosition()));
@@ -148,14 +148,20 @@ public:
virtual Rectangle<int> getBounds() const = 0;
/** Converts a position relative to the top-left of this component to screen coordinates. */
virtual Point<int> localToGlobal (Point<int> relativePosition) = 0;
virtual Point<float> localToGlobal (Point<float> relativePosition) = 0;
/** Converts a screen coordinate to a position relative to the top-left of this component. */
virtual Point<float> globalToLocal (Point<float> screenPosition) = 0;
/** Converts a position relative to the top-left of this component to screen coordinates. */
Point<int> localToGlobal (Point<int> relativePosition);
/** Converts a screen coordinate to a position relative to the top-left of this component. */
Point<int> globalToLocal (Point<int> screenPosition);
/** Converts a rectangle relative to the top-left of this component to screen coordinates. */
virtual Rectangle<int> localToGlobal (const Rectangle<int>& relativePosition);
/** Converts a screen coordinate to a position relative to the top-left of this component. */
virtual Point<int> globalToLocal (Point<int> screenPosition) = 0;
/** Converts a screen area to a position relative to the top-left of this component. */
virtual Rectangle<int> globalToLocal (const Rectangle<int>& screenPosition);
@@ -276,7 +282,7 @@ public:
This may cause things like a virtual on-screen keyboard to appear, depending
on the OS.
*/
virtual void textInputRequired (const Point<int>& position) = 0;
virtual void textInputRequired (Point<int> position, TextInputTarget&) = 0;
/** If there's some kind of OS input-method in progress, this should dismiss it. */
virtual void dismissPendingTextInput();
@@ -300,9 +306,9 @@ public:
virtual void setAlpha (float newAlpha) = 0;
//==============================================================================
void handleMouseEvent (int touchIndex, const Point<int> positionWithinPeer, const ModifierKeys newMods, int64 time);
void handleMouseWheel (int touchIndex, const Point<int> positionWithinPeer, int64 time, const MouseWheelDetails&);
void handleMagnifyGesture (int touchIndex, const Point<int> positionWithinPeer, int64 time, float scaleFactor);
void handleMouseEvent (int touchIndex, Point<float> positionWithinPeer, ModifierKeys newMods, int64 time);
void handleMouseWheel (int touchIndex, Point<float> positionWithinPeer, int64 time, const MouseWheelDetails&);
void handleMagnifyGesture (int touchIndex, Point<float> positionWithinPeer, int64 time, float scaleFactor);
void handleUserClosingWindow();
@@ -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;
@@ -138,7 +138,7 @@ void TooltipWindow::timerCallback()
mouseClicks = clickCount;
mouseWheelMoves = wheelCount;
const Point<int> mousePos (mouseSource.getScreenPosition());
const Point<float> mousePos (mouseSource.getScreenPosition());
const bool mouseMovedQuickly = mousePos.getDistanceFrom (lastMousePos) > 12;
lastMousePos = mousePos;
@@ -159,7 +159,7 @@ void TooltipWindow::timerCallback()
}
else if (tipChanged)
{
displayTip (mousePos, newTip);
displayTip (mousePos.roundToInt(), newTip);
}
}
else
@@ -170,7 +170,7 @@ void TooltipWindow::timerCallback()
&& newTip != tipShowing
&& now > lastCompChangeTime + (unsigned int) millisecondsBeforeTipAppears)
{
displayTip (mousePos, newTip);
displayTip (mousePos.roundToInt(), newTip);
}
}
}
@@ -111,7 +111,7 @@ public:
private:
//==============================================================================
int millisecondsBeforeTipAppears;
Point<int> lastMousePos;
Point<float> lastMousePos;
int mouseClicks, mouseWheelMoves;
unsigned int lastCompChangeTime, lastHideTime;
Component* lastComponentUnderMouse;
@@ -27,7 +27,6 @@ class TopLevelWindowManager : private Timer,
private DeletedAtShutdown
{
public:
//==============================================================================
TopLevelWindowManager() : currentActive (nullptr)
{
}
@@ -48,33 +47,15 @@ public:
{
startTimer (jmin (1731, getTimerInterval() * 2));
TopLevelWindow* active = nullptr;
TopLevelWindow* newActive = findCurrentlyActiveWindow();
if (Process::isForegroundProcess())
if (newActive != currentActive)
{
active = currentActive;
Component* const c = Component::getCurrentlyFocusedComponent();
TopLevelWindow* tlw = dynamic_cast <TopLevelWindow*> (c);
if (tlw == nullptr && c != nullptr)
tlw = c->findParentComponentOfClass<TopLevelWindow>();
if (tlw != nullptr)
active = tlw;
}
if (active != currentActive)
{
currentActive = active;
currentActive = newActive;
for (int i = windows.size(); --i >= 0;)
{
TopLevelWindow* const tlw = windows.getUnchecked (i);
tlw->setWindowActive (isWindowActive (tlw));
i = jmin (i, windows.size() - 1);
}
if (TopLevelWindow* tlw = windows[i])
tlw->setWindowActive (isWindowActive (tlw));
Desktop::getInstance().triggerFocusCallback();
}
@@ -101,7 +82,7 @@ public:
deleteInstance();
}
Array <TopLevelWindow*> windows;
Array<TopLevelWindow*> windows;
private:
TopLevelWindow* currentActive;
@@ -119,6 +100,26 @@ private:
&& tlw->isShowing();
}
TopLevelWindow* findCurrentlyActiveWindow() const
{
if (Process::isForegroundProcess())
{
Component* const focusedComp = Component::getCurrentlyFocusedComponent();
TopLevelWindow* w = dynamic_cast<TopLevelWindow*> (focusedComp);
if (w == nullptr && focusedComp != nullptr)
w = focusedComp->findParentComponentOfClass<TopLevelWindow>();
if (w == nullptr)
w = currentActive;
if (w != nullptr && w->isShowing())
return w;
}
return nullptr;
}
JUCE_DECLARE_NON_COPYABLE (TopLevelWindowManager)
};
@@ -187,12 +188,11 @@ bool TopLevelWindow::isUsingNativeTitleBar() const noexcept
void TopLevelWindow::visibilityChanged()
{
if (isShowing()
&& (getPeer()->getStyleFlags() & (ComponentPeer::windowIsTemporary
| ComponentPeer::windowIgnoresKeyPresses)) == 0)
{
toFront (true);
}
if (isShowing())
if (ComponentPeer* p = getPeer())
if ((p->getStyleFlags() & (ComponentPeer::windowIsTemporary
| ComponentPeer::windowIgnoresKeyPresses)) == 0)
toFront (true);
}
void TopLevelWindow::parentHierarchyChanged()
@@ -127,7 +127,7 @@ public:
//==============================================================================
/** @internal */
virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr) override;
protected:
//==============================================================================
@@ -155,7 +155,7 @@ private:
bool useDropShadow, useNativeTitleBar, isCurrentlyActive;
ScopedPointer<DropShadower> shadower;
void setWindowActive (bool isNowActive);
void setWindowActive (bool);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopLevelWindow)
};