Browse Source

Added the ability to apply affine transforms to components - Component::setTransform(). Added a slider to the widgets demo to show this in action. Changed Component::reallyContains() to take a rectangle instead of raw coordinates.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
2c2a11dee9
15 changed files with 533 additions and 242 deletions
  1. +19
    -2
      extras/juce demo/Source/demos/WidgetsDemo.cpp
  2. +136
    -90
      juce_amalgamated.cpp
  3. +120
    -30
      juce_amalgamated.h
  4. +1
    -1
      src/core/juce_StandardHeader.h
  5. +25
    -30
      src/gui/components/buttons/juce_Button.cpp
  6. +2
    -1
      src/gui/components/buttons/juce_Button.h
  7. +1
    -1
      src/gui/components/controls/juce_ComboBox.cpp
  8. +4
    -0
      src/gui/components/controls/juce_Slider.cpp
  9. +1
    -1
      src/gui/components/controls/juce_TableHeaderComponent.cpp
  10. +98
    -50
      src/gui/components/juce_Component.cpp
  11. +118
    -28
      src/gui/components/juce_Component.h
  12. +1
    -1
      src/gui/components/menus/juce_MenuBarComponent.cpp
  13. +5
    -5
      src/gui/components/menus/juce_PopupMenu.cpp
  14. +1
    -1
      src/gui/components/mouse/juce_MouseHoverDetector.cpp
  15. +1
    -1
      src/gui/components/special/juce_MidiKeyboardComponent.cpp

+ 19
- 2
extras/juce demo/Source/demos/WidgetsDemo.cpp View File

@@ -1088,7 +1088,8 @@ public:
//============================================================================== //==============================================================================
class WidgetsDemo : public Component, class WidgetsDemo : public Component,
public ButtonListener
public ButtonListener,
public SliderListener
{ {
public: public:
//============================================================================== //==============================================================================
@@ -1111,9 +1112,17 @@ public:
//============================================================================== //==============================================================================
addAndMakeVisible (&enableButton); addAndMakeVisible (&enableButton);
enableButton.setBounds (230, 10, 180, 24); enableButton.setBounds (230, 10, 180, 24);
enableButton.setTooltip ("toggle button");
enableButton.setTooltip ("Enables/disables all the components");
enableButton.setToggleState (true, false); enableButton.setToggleState (true, false);
enableButton.addButtonListener (this); enableButton.addButtonListener (this);
addAndMakeVisible (&transformSlider);
transformSlider.setSliderStyle (Slider::LinearBar);
transformSlider.setTextValueSuffix (" degrees rotation");
transformSlider.setRange (-180.0, 180.0, 0.1);
transformSlider.setBounds (440, 10, 180, 24);
transformSlider.setTooltip ("Applies a transform to the components");
transformSlider.addListener (this);
} }
~WidgetsDemo() ~WidgetsDemo()
@@ -1397,9 +1406,17 @@ public:
} }
} }
void sliderValueChanged (Slider*)
{
// When you move the roation slider, we'll apply a rotaion transform to the whole tabs component..
tabs.setTransform (AffineTransform::rotation ((float) (transformSlider.getValue() / (180.0 / double_Pi)),
getWidth() * 0.5f, getHeight() * 0.5f));
}
private: private:
TextButton menuButton; TextButton menuButton;
ToggleButton enableButton; ToggleButton enableButton;
Slider transformSlider;
DemoTabbedComponent tabs; DemoTabbedComponent tabs;
}; };


+ 136
- 90
juce_amalgamated.cpp View File

@@ -39782,7 +39782,7 @@ END_JUCE_NAMESPACE
/*** Start of inlined file: juce_Component.cpp ***/ /*** Start of inlined file: juce_Component.cpp ***/
BEGIN_JUCE_NAMESPACE BEGIN_JUCE_NAMESPACE


#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
#define CHECK_MESSAGE_MANAGER_IS_LOCKED jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());


Component* Component::currentlyFocusedComponent = 0; Component* Component::currentlyFocusedComponent = 0;


@@ -39982,22 +39982,34 @@ public:


static const Point<int> convertFromParentSpace (const Component& comp, const Point<int>& pointInParentSpace) static const Point<int> convertFromParentSpace (const Component& comp, const Point<int>& pointInParentSpace)
{ {
return pointInParentSpace - comp.getPosition();
if (comp.affineTransform_ == 0)
return pointInParentSpace - comp.getPosition();

return pointInParentSpace.toFloat().transformedBy (comp.affineTransform_->inverted()).toInt() - comp.getPosition();
} }


static const Rectangle<int> convertFromParentSpace (const Component& comp, const Rectangle<int>& areaInParentSpace) static const Rectangle<int> convertFromParentSpace (const Component& comp, const Rectangle<int>& areaInParentSpace)
{ {
return areaInParentSpace - comp.getPosition();
if (comp.affineTransform_ == 0)
return areaInParentSpace - comp.getPosition();

return areaInParentSpace.toFloat().transformed (comp.affineTransform_->inverted()).getSmallestIntegerContainer() - comp.getPosition();
} }


static const Point<int> convertToParentSpace (const Component& comp, const Point<int>& pointInLocalSpace) static const Point<int> convertToParentSpace (const Component& comp, const Point<int>& pointInLocalSpace)
{ {
return pointInLocalSpace + comp.getPosition();
if (comp.affineTransform_ == 0)
return pointInLocalSpace + comp.getPosition();

return (pointInLocalSpace + comp.getPosition()).toFloat().transformedBy (*comp.affineTransform_).toInt();
} }


static const Rectangle<int> convertToParentSpace (const Component& comp, const Rectangle<int>& areaInLocalSpace) static const Rectangle<int> convertToParentSpace (const Component& comp, const Rectangle<int>& areaInLocalSpace)
{ {
return areaInLocalSpace + comp.getPosition();
if (comp.affineTransform_ == 0)
return areaInLocalSpace + comp.getPosition();

return (areaInLocalSpace + comp.getPosition()).toFloat().transformed (*comp.affineTransform_).getSmallestIntegerContainer();
} }


template <typename Type> template <typename Type>
@@ -40070,8 +40082,7 @@ public:
{ {
const Component& child = *comp.childComponentList_.getUnchecked(i); const Component& child = *comp.childComponentList_.getUnchecked(i);


//xxx if (child.isVisible() && ! child.isTransformed())
if (child.isVisible())
if (child.isVisible() && ! child.isTransformed())
{ {
const Rectangle<int> newClip (clipRect.getIntersection (child.bounds_)); const Rectangle<int> newClip (clipRect.getIntersection (child.bounds_));


@@ -40195,7 +40206,7 @@ void Component::setName (const String& name)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (componentName_ != name) if (componentName_ != name)
{ {
@@ -40221,7 +40232,7 @@ void Component::setVisible (bool shouldBeVisible)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


SafePointer<Component> safePointer (this); SafePointer<Component> safePointer (this);


@@ -40309,7 +40320,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (isOpaque()) if (isOpaque())
styleWanted &= ~ComponentPeer::windowIsSemiTransparent; styleWanted &= ~ComponentPeer::windowIsSemiTransparent;
@@ -40397,7 +40408,7 @@ void Component::removeFromDesktop()
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
@@ -40472,7 +40483,7 @@ void Component::toFront (const bool setAsForeground)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
@@ -40711,7 +40722,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 // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (w < 0) w = 0; if (w < 0) w = 0;
if (h < 0) h = 0; if (h < 0) h = 0;
@@ -40899,6 +40910,41 @@ void Component::setBoundsToFit (int x, int y, int width, int height,
} }
} }


bool Component::isTransformed() const throw()
{
return affineTransform_ != 0;
}

void Component::setTransform (const AffineTransform& newTransform)
{
if (newTransform.isIdentity())
{
if (affineTransform_ != 0)
{
repaint();
affineTransform_ = 0;
repaint();
}
}
else if (affineTransform_ == 0)
{
repaint();
affineTransform_ = new AffineTransform (newTransform);
repaint();
}
else if (*affineTransform_ != newTransform)
{
repaint();
*affineTransform_ = newTransform;
repaint();
}
}

const AffineTransform Component::getTransform() const
{
return affineTransform_ != 0 ? *affineTransform_ : AffineTransform::identity;
}

bool Component::hitTest (int x, int y) bool Component::hitTest (int x, int y)
{ {
if (! flags.ignoresMouseClicksFlag) if (! flags.ignoresMouseClicksFlag)
@@ -40953,15 +40999,13 @@ bool Component::contains (const Point<int>& point)
return false; return false;
} }


bool Component::reallyContains (const int x, const int y, const bool returnTrueIfWithinAChild)
bool Component::reallyContains (const Point<int>& point, const bool returnTrueIfWithinAChild)
{ {
const Point<int> p (x, y);

if (! contains (p))
if (! contains (point))
return false; return false;


Component* const top = getTopLevelComponent(); Component* const top = getTopLevelComponent();
const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, p));
const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, point));


return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition)); return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition));
} }
@@ -40994,7 +41038,7 @@ void Component::addChildComponent (Component* const child, int zOrder)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (child != 0 && child->parentComponent_ != this) if (child != 0 && child->parentComponent_ != this)
{ {
@@ -41047,7 +41091,7 @@ Component* Component::removeChildComponent (const int index)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


Component* const child = childComponentList_ [index]; Component* const child = childComponentList_ [index];


@@ -41215,7 +41259,7 @@ void Component::enterModalState (const bool takeKeyboardFocus_, ModalComponentMa
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


// Check for an attempt to make a component modal when it already is! // Check for an attempt to make a component modal when it already is!
// This can cause nasty problems.. // This can cause nasty problems..
@@ -41385,7 +41429,7 @@ void Component::internalRepaint (int x, int y, int w, int h)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (x < 0) if (x < 0)
{ {
@@ -41412,7 +41456,17 @@ void Component::internalRepaint (int x, int y, int w, int h)
if (parentComponent_ != 0) if (parentComponent_ != 0)
{ {
if (parentComponent_->flags.visibleFlag) if (parentComponent_->flags.visibleFlag)
parentComponent_->internalRepaint (x + getX(), y + getY(), w, h);
{
if (affineTransform_ == 0)
{
parentComponent_->internalRepaint (x + getX(), y + getY(), w, h);
}
else
{
const Rectangle<int> r (ComponentHelpers::convertToParentSpace (*this, Rectangle<int> (x, y, w, h)));
parentComponent_->internalRepaint (r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
}
} }
else if (flags.hasHeavyweightPeerFlag) else if (flags.hasHeavyweightPeerFlag)
{ {
@@ -41447,6 +41501,15 @@ void Component::paintComponent (Graphics& g)
} }
} }


void Component::paintTransformedChild (Graphics& g)
{
if (affineTransform_ != 0)
g.addTransform (*affineTransform_);

g.setOrigin (getX(), getY());
paintEntireComponent (g, false);
}

void Component::paintComponentAndChildren (Graphics& g) void Component::paintComponentAndChildren (Graphics& g)
{ {
const Rectangle<int> clipBounds (g.getClipBounds()); const Rectangle<int> clipBounds (g.getClipBounds());
@@ -41476,8 +41539,7 @@ void Component::paintComponentAndChildren (Graphics& g)


if (child->flags.dontClipGraphicsFlag) if (child->flags.dontClipGraphicsFlag)
{ {
g.setOrigin (child->getX(), child->getY());
child->paintEntireComponent (g, false);
child->paintTransformedChild (g);
} }
else else
{ {
@@ -41497,10 +41559,7 @@ void Component::paintComponentAndChildren (Graphics& g)
} }


if (nothingClipped || ! g.isClipEmpty()) if (nothingClipped || ! g.isClipEmpty())
{
g.setOrigin (child->getX(), child->getY());
child->paintEntireComponent (g, false);
}
child->paintTransformedChild (g);
} }
} }


@@ -41860,7 +41919,7 @@ void Component::addMouseListener (MouseListener* const newListener,
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


// If you register a component as a mouselistener for itself, it'll receive all the events // 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! // twice - once via the direct callback that all components get anyway, and then again as a listener!
@@ -41876,7 +41935,7 @@ void Component::removeMouseListener (MouseListener* const listenerToRemove)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (mouseListeners_ != 0) if (mouseListeners_ != 0)
mouseListeners_->removeListener (listenerToRemove); mouseListeners_->removeListener (listenerToRemove);
@@ -42131,7 +42190,7 @@ void Component::internalMouseDrag (MouseInputSource& source, const Point<int>& r
{ {
Desktop& desktop = Desktop::getInstance(); Desktop& desktop = Desktop::getInstance();


flags.mouseOverFlag = reallyContains (relativePos.getX(), relativePos.getY(), false);
flags.mouseOverFlag = reallyContains (relativePos, false);


BailOutChecker checker (this); BailOutChecker checker (this);


@@ -42499,7 +42558,7 @@ void Component::grabKeyboardFocus()
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


grabFocusInternal (focusChangedDirectly); grabFocusInternal (focusChangedDirectly);
} }
@@ -42508,7 +42567,7 @@ void Component::moveKeyboardFocusToSibling (const bool moveToNext)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED


if (parentComponent_ != 0) if (parentComponent_ != 0)
{ {
@@ -42563,20 +42622,9 @@ void Component::giveAwayFocus()
componentLosingFocus->internalFocusLoss (focusChangedDirectly); componentLosingFocus->internalFocusLoss (focusChangedDirectly);
} }


bool Component::isMouseOver() const throw()
{
return flags.mouseOverFlag;
}

bool Component::isMouseButtonDown() const throw()
{
return flags.mouseDownFlag;
}

bool Component::isMouseOverOrDragging() const throw()
{
return flags.mouseOverFlag || flags.mouseDownFlag;
}
bool Component::isMouseOver() const throw() { return flags.mouseOverFlag; }
bool Component::isMouseButtonDown() const throw() { return flags.mouseDownFlag; }
bool Component::isMouseOverOrDragging() const throw() { return flags.mouseOverFlag || flags.mouseDownFlag; }


bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw() bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw()
{ {
@@ -42590,8 +42638,7 @@ const Point<int> Component::getMouseXYRelative() const


const Rectangle<int> Component::getParentMonitorArea() const const Rectangle<int> Component::getParentMonitorArea() const
{ {
return Desktop::getInstance()
.getMonitorAreaContaining (localPointToGlobal (getLocalBounds().getCentre()));
return Desktop::getInstance().getMonitorAreaContaining (getScreenBounds().getCentre());
} }


void Component::addKeyListener (KeyListener* const newListener) void Component::addKeyListener (KeyListener* const newListener)
@@ -43515,34 +43562,29 @@ void Button::turnOffOtherButtonsInGroup (const bool sendChangeNotification)


void Button::enablementChanged() void Button::enablementChanged()
{ {
updateState (0);
updateState();
repaint(); repaint();
} }


Button::ButtonState Button::updateState (const MouseEvent* const e)
Button::ButtonState Button::updateState()
{
return updateState (reallyContains (getMouseXYRelative(), true), isMouseButtonDown());
}

Button::ButtonState Button::updateState (const bool over, const bool down)
{ {
ButtonState state = buttonNormal;
ButtonState newState = buttonNormal;


if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent()) if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent())
{ {
Point<int> mousePos;

if (e == 0)
mousePos = getMouseXYRelative();
else
mousePos = e->getEventRelativeTo (this).getPosition();

const bool over = reallyContains (mousePos.getX(), mousePos.getY(), true);
const bool down = isMouseButtonDown();

if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown) if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown)
state = buttonDown;
newState = buttonDown;
else if (over) else if (over)
state = buttonOver;
newState = buttonOver;
} }


setState (state);
return state;
setState (newState);
return newState;
} }


void Button::setState (const ButtonState newState) void Button::setState (const ButtonState newState)
@@ -43687,19 +43729,19 @@ void Button::paint (Graphics& g)
paintButton (g, isOver(), isDown()); paintButton (g, isOver(), isDown());
} }


void Button::mouseEnter (const MouseEvent& e)
void Button::mouseEnter (const MouseEvent&)
{ {
updateState (&e);
updateState (true, false);
} }


void Button::mouseExit (const MouseEvent& e)
void Button::mouseExit (const MouseEvent&)
{ {
updateState (&e);
updateState (false, false);
} }


void Button::mouseDown (const MouseEvent& e) void Button::mouseDown (const MouseEvent& e)
{ {
updateState (&e);
updateState (true, true);


if (isDown()) if (isDown())
{ {
@@ -43714,7 +43756,7 @@ void Button::mouseDown (const MouseEvent& e)
void Button::mouseUp (const MouseEvent& e) void Button::mouseUp (const MouseEvent& e)
{ {
const bool wasDown = isDown(); const bool wasDown = isDown();
updateState (&e);
updateState (isMouseOver(), false);


if (wasDown && isOver() && ! triggerOnMouseDown) if (wasDown && isOver() && ! triggerOnMouseDown)
internalClickCallback (e.mods); internalClickCallback (e.mods);
@@ -43723,7 +43765,7 @@ void Button::mouseUp (const MouseEvent& e)
void Button::mouseDrag (const MouseEvent& e) void Button::mouseDrag (const MouseEvent& e)
{ {
const ButtonState oldState = buttonState; const ButtonState oldState = buttonState;
updateState (&e);
updateState (isMouseOver(), true);


if (autoRepeatDelay >= 0 && buttonState != oldState && isDown()) if (autoRepeatDelay >= 0 && buttonState != oldState && isDown())
getRepeatTimer().startTimer (autoRepeatSpeed); getRepeatTimer().startTimer (autoRepeatSpeed);
@@ -43731,13 +43773,13 @@ void Button::mouseDrag (const MouseEvent& e)


void Button::focusGained (FocusChangeType) void Button::focusGained (FocusChangeType)
{ {
updateState (0);
updateState();
repaint(); repaint();
} }


void Button::focusLost (FocusChangeType) void Button::focusLost (FocusChangeType)
{ {
updateState (0);
updateState();
repaint(); repaint();
} }


@@ -43750,7 +43792,7 @@ void Button::setVisible (bool shouldBeVisible)
if (! shouldBeVisible) if (! shouldBeVisible)
needsToRelease = false; needsToRelease = false;


updateState (0);
updateState();
} }
else else
{ {
@@ -43878,7 +43920,7 @@ bool Button::keyStateChanged (const bool, Component*)
if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown)) if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown))
getRepeatTimer().startTimer (autoRepeatDelay); getRepeatTimer().startTimer (autoRepeatDelay);


updateState (0);
updateState();


if (isEnabled() && wasDown && ! isKeyDown) if (isEnabled() && wasDown && ! isKeyDown)
{ {
@@ -43922,10 +43964,10 @@ void Button::repeatTimerCallback()
if (needsRepainting) if (needsRepainting)
{ {
getRepeatTimer().stopTimer(); getRepeatTimer().stopTimer();
updateState (0);
updateState();
needsRepainting = false; needsRepainting = false;
} }
else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState (0) == buttonDown)))
else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState() == buttonDown)))
{ {
int repeatSpeed = autoRepeatSpeed; int repeatSpeed = autoRepeatSpeed;


@@ -48020,7 +48062,7 @@ void ComboBox::mouseUp (const MouseEvent& e2)


const MouseEvent e (e2.getEventRelativeTo (this)); const MouseEvent e (e2.getEventRelativeTo (this));


if (reallyContains (e.x, e.y, true)
if (reallyContains (e.getPosition(), true)
&& (e2.eventComponent == this || ! label->isEditable())) && (e2.eventComponent == this || ! label->isEditable()))
{ {
showPopup(); showPopup();
@@ -49804,6 +49846,10 @@ void Slider::lookAndFeelChanged()


valueBox->setTooltip (getTooltip()); valueBox->setTooltip (getTooltip());
} }
else
{
valueBox = 0;
}


if (style == IncDecButtons) if (style == IncDecButtons)
{ {
@@ -51750,7 +51796,7 @@ int TableHeaderComponent::getResizeDraggerAt (const int mouseX) const


void TableHeaderComponent::updateColumnUnderMouse (int x, int y) void TableHeaderComponent::updateColumnUnderMouse (int x, int y)
{ {
const int newCol = (reallyContains (x, y, true) && getResizeDraggerAt (x) == 0)
const int newCol = (reallyContains (Point<int> (x, y), true) && getResizeDraggerAt (x) == 0)
? getColumnIdAtX (x) : 0; ? getColumnIdAtX (x) : 0;


if (newCol != columnIdUnderMouse) if (newCol != columnIdUnderMouse)
@@ -68454,7 +68500,7 @@ int MenuBarComponent::getItemAt (const int x, const int y)
{ {
for (int i = 0; i < xPositions.size(); ++i) for (int i = 0; i < xPositions.size(); ++i)
if (x >= xPositions[i] && x < xPositions[i + 1]) if (x >= xPositions[i] && x < xPositions[i + 1])
return reallyContains (x, y, true) ? i : -1;
return reallyContains (Point<int> (x, y), true) ? i : -1;


return -1; return -1;
} }
@@ -69243,7 +69289,7 @@ public:
// comp that we're attached to. // comp that we're attached to.
const Point<int> mousePos (componentAttachedTo->getMouseXYRelative()); const Point<int> mousePos (componentAttachedTo->getMouseXYRelative());


if (componentAttachedTo->reallyContains (mousePos.getX(), mousePos.getY(), true))
if (componentAttachedTo->reallyContains (mousePos, true))
{ {
postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously
return; return;
@@ -69287,7 +69333,7 @@ public:
const uint32 now = Time::getMillisecondCounter(); const uint32 now = Time::getMillisecondCounter();


if (now > timeEnteredCurrentChildComp + 100 if (now > timeEnteredCurrentChildComp + 100
&& reallyContains (localMousePos.getX(), localMousePos.getY(), true)
&& reallyContains (localMousePos, true)
&& currentChild != 0 && currentChild != 0
&& (! disableMouseMoves) && (! disableMouseMoves)
&& ! (activeSubMenu != 0 && activeSubMenu->isVisible())) && ! (activeSubMenu != 0 && activeSubMenu->isVisible()))
@@ -69379,7 +69425,7 @@ public:
else if (wasDown && now > menuCreationTime + 250 else if (wasDown && now > menuCreationTime + 250
&& ! (isDown || overScrollArea)) && ! (isDown || overScrollArea))
{ {
isOver = reallyContains (localMousePos.getX(), localMousePos.getY(), true);
isOver = reallyContains (localMousePos, true);


if (isOver) if (isOver)
{ {
@@ -69452,7 +69498,7 @@ private:
void updateMouseOverStatus (const Point<int>& globalMousePos) void updateMouseOverStatus (const Point<int>& globalMousePos)
{ {
const Point<int> relPos (getLocalPoint (0, globalMousePos)); const Point<int> relPos (getLocalPoint (0, globalMousePos));
isOver = reallyContains (relPos.getX(), relPos.getY(), true);
isOver = reallyContains (relPos, true);


if (activeSubMenu != 0) if (activeSubMenu != 0)
activeSubMenu->updateMouseOverStatus (globalMousePos); activeSubMenu->updateMouseOverStatus (globalMousePos);
@@ -69798,7 +69844,7 @@ private:


void highlightItemUnderMouse (const Point<int>& globalMousePos, const Point<int>& localMousePos) void highlightItemUnderMouse (const Point<int>& globalMousePos, const Point<int>& localMousePos)
{ {
isOver = reallyContains (localMousePos.getX(), localMousePos.getY(), true);
isOver = reallyContains (localMousePos, true);


if (isOver) if (isOver)
hasBeenOver = true; hasBeenOver = true;
@@ -71732,7 +71778,7 @@ void MouseHoverDetector::hoverTimerCallback()
{ {
const Point<int> pos (source->getMouseXYRelative()); const Point<int> pos (source->getMouseXYRelative());


if (source->reallyContains (pos.getX(), pos.getY(), false))
if (source->reallyContains (pos, false))
{ {
hasJustHovered = true; hasJustHovered = true;
mouseHovered (pos.getX(), pos.getY()); mouseHovered (pos.getX(), pos.getY());
@@ -75390,7 +75436,7 @@ const uint8 MidiKeyboardComponent::blackNotes[] = { 1, 3, 6, 8, 10 };


int MidiKeyboardComponent::xyToNote (const Point<int>& pos, float& mousePositionVelocity) int MidiKeyboardComponent::xyToNote (const Point<int>& pos, float& mousePositionVelocity)
{ {
if (! reallyContains (pos.getX(), pos.getY(), false))
if (! reallyContains (pos, false))
return -1; return -1;


Point<int> p (pos); Point<int> p (pos);


+ 120
- 30
juce_amalgamated.h View File

@@ -64,7 +64,7 @@
*/ */
#define JUCE_MAJOR_VERSION 1 #define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52 #define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 94
#define JUCE_BUILDNUMBER 95


/** Current Juce version number. /** Current Juce version number.


@@ -26113,15 +26113,21 @@ public:
*/ */
bool isAlwaysOnTop() const throw(); bool isAlwaysOnTop() const throw();


/** Returns the x co-ordinate of the component's left edge.
/** Returns the x coordinate of the component's left edge.
This is a distance in pixels from the left edge of the component's parent. This is a distance in pixels from the left edge of the component's parent.
@see getScreenX

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
inline int getX() const throw() { return bounds_.getX(); } inline int getX() const throw() { return bounds_.getX(); }


/** Returns the y co-ordinate of the top of this component.
/** Returns the y coordinate of the top of this component.
This is a distance in pixels from the top edge of the component's parent. This is a distance in pixels from the top edge of the component's parent.
@see getScreenY

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
inline int getY() const throw() { return bounds_.getY(); } inline int getY() const throw() { return bounds_.getY(); }


@@ -26131,26 +26137,38 @@ public:
/** Returns the component's height in pixels. */ /** Returns the component's height in pixels. */
inline int getHeight() const throw() { return bounds_.getHeight(); } inline int getHeight() const throw() { return bounds_.getHeight(); }


/** Returns the x co-ordinate of the component's right-hand edge.
/** Returns the x coordinate of the component's right-hand edge.
This is a distance in pixels from the left edge of the component's parent. This is a distance in pixels from the left edge of the component's parent.

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
int getRight() const throw() { return bounds_.getRight(); } int getRight() const throw() { return bounds_.getRight(); }


/** Returns the component's top-left position as a Point. */ /** Returns the component's top-left position as a Point. */
const Point<int> getPosition() const throw() { return bounds_.getPosition(); } const Point<int> getPosition() const throw() { return bounds_.getPosition(); }


/** Returns the y co-ordinate of the bottom edge of this component.
/** Returns the y coordinate of the bottom edge of this component.
This is a distance in pixels from the top edge of the component's parent. This is a distance in pixels from the top edge of the component's parent.

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
int getBottom() const throw() { return bounds_.getBottom(); } int getBottom() const throw() { return bounds_.getBottom(); }


/** Returns this component's bounding box. /** Returns this component's bounding box.
The rectangle returned is relative to the top-left of the component's parent. The rectangle returned is relative to the top-left of the component's parent.

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
const Rectangle<int>& getBounds() const throw() { return bounds_; } const Rectangle<int>& getBounds() const throw() { return bounds_; }


/** Returns the component's bounds, relative to its own origin. /** Returns the component's bounds, relative to its own origin.
This is like getBounds(), but returns the rectangle in local co-ordinates, In practice, it'll
This is like getBounds(), but returns the rectangle in local coordinates, In practice, it'll
return a rectangle with position (0, 0), and the same size as this component. return a rectangle with position (0, 0), and the same size as this component.
*/ */
const Rectangle<int> getLocalBounds() const throw(); const Rectangle<int> getLocalBounds() const throw();
@@ -26166,12 +26184,12 @@ public:
void getVisibleArea (RectangleList& result, void getVisibleArea (RectangleList& result,
bool includeSiblings) const; bool includeSiblings) const;


/** Returns this component's x co-ordinate relative the the screen's top-left origin.
/** Returns this component's x coordinate relative the the screen's top-left origin.
@see getX, localPointToGlobal @see getX, localPointToGlobal
*/ */
int getScreenX() const; int getScreenX() const;


/** Returns this component's y co-ordinate relative the the screen's top-left origin.
/** Returns this component's y coordinate relative the the screen's top-left origin.
@see getY, localPointToGlobal @see getY, localPointToGlobal
*/ */
int getScreenY() const; int getScreenY() const;
@@ -26200,6 +26218,10 @@ public:
This takes a rectangle that is relative to a different component, and returns its position relative This takes a rectangle that is relative to a different component, and returns its position relative
to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be
a screen coordinate. a screen coordinate.

If you've used setTransform() to apply one or more transforms to components, then the source rectangle
may not actually be rectanglular when converted to the target space, so in that situation this will return
the smallest rectangle that fully contains the transformed area.
*/ */
const Rectangle<int> getLocalArea (const Component* sourceComponent, const Rectangle<int> getLocalArea (const Component* sourceComponent,
const Rectangle<int>& areaRelativeToSourceComponent) const; const Rectangle<int>& areaRelativeToSourceComponent) const;
@@ -26210,6 +26232,10 @@ public:
const Point<int> localPointToGlobal (const Point<int>& localPoint) const; const Point<int> localPointToGlobal (const Point<int>& localPoint) const;


/** Converts a rectangle from this component's coordinate space to a screen coordinate. /** 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
may not actually be rectanglular when converted to the target space, so in that situation this will return
the smallest rectangle that fully contains the transformed area.
@see getLocalPoint, localPointToGlobal @see getLocalPoint, localPointToGlobal
*/ */
const Rectangle<int> localAreaToGlobal (const Rectangle<int>& localArea) const; const Rectangle<int> localAreaToGlobal (const Rectangle<int>& localArea) const;
@@ -26221,6 +26247,10 @@ public:


If the component actually moves, this method will make a synchronous call to moved(). If the component actually moves, this method will make a synchronous call to moved().


Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.

@see setBounds, ComponentListener::componentMovedOrResized @see setBounds, ComponentListener::componentMovedOrResized
*/ */
void setTopLeftPosition (int x, int y); void setTopLeftPosition (int x, int y);
@@ -26231,29 +26261,51 @@ public:
The position is relative to the top-left of the component's parent. The position is relative to the top-left of the component's parent.


If the component actually moves, this method will make a synchronous call to moved(). If the component actually moves, this method will make a synchronous call to moved().

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
*/ */
void setTopRightPosition (int x, int y); void setTopRightPosition (int x, int y);


/** Changes the size of the component. /** Changes the size of the component.


A synchronous call to resized() will be occur if the size actually changes. A synchronous call to resized() will be occur if the size actually changes.

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
*/ */
void setSize (int newWidth, int newHeight); void setSize (int newWidth, int newHeight);


/** Changes the component's position and size. /** Changes the component's position and size.


The co-ordinates are relative to the top-left of the component's parent, or relative
The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop. to the origin of the screen is the component is on the desktop.


If this method changes the component's top-left position, it will make a synchronous If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized(). call to moved(). If it changes the size, it will also make a call to resized().


Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.

@see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized
*/ */
void setBounds (int x, int y, int width, int height); void setBounds (int x, int y, int width, int height);


/** Changes the component's position and size. /** Changes the component's position and size.


The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop.

If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized().

Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.

@see setBounds @see setBounds
*/ */
void setBounds (const Rectangle<int>& newBounds); void setBounds (const Rectangle<int>& newBounds);
@@ -26264,6 +26316,8 @@ public:
setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the
width and height of the parent, with its top-left position 20% of width and height of the parent, with its top-left position 20% of
the way across and down the parent. the way across and down the parent.

@see setBounds
*/ */
void setBoundsRelative (float proportionalX, float proportionalY, void setBoundsRelative (float proportionalX, float proportionalY,
float proportionalWidth, float proportionalHeight); float proportionalWidth, float proportionalHeight);
@@ -26272,6 +26326,8 @@ public:


This will position the component within its parent, leaving the specified number of This will position the component within its parent, leaving the specified number of
pixels around each edge. pixels around each edge.

@see setBounds
*/ */
void setBoundsInset (const BorderSize& borders); void setBoundsInset (const BorderSize& borders);


@@ -26286,6 +26342,8 @@ public:


It will then be positioned within the rectangle according to the justification flags It will then be positioned within the rectangle according to the justification flags
specified. specified.

@see setBounds
*/ */
void setBoundsToFit (int x, int y, int width, int height, void setBoundsToFit (int x, int y, int width, int height,
const Justification& justification, const Justification& justification,
@@ -26295,6 +26353,8 @@ public:


Leaves the component's size unchanged, but sets the position of its centre Leaves the component's size unchanged, but sets the position of its centre
relative to its parent's top-left. relative to its parent's top-left.

@see setBounds
*/ */
void setCentrePosition (int x, int y); void setCentrePosition (int x, int y);


@@ -26314,6 +26374,37 @@ public:
*/ */
void centreWithSize (int width, int height); void centreWithSize (int width, int height);


/** Sets a transform matrix to be applied to this component.

If you set a transform for a component, the component's position will be warped by it, relative to
the component's parent's top-left origin. This means that the values you pass into setBounds() will no
longer reflect the actual area within the parent that the component covers, as the bounds will be
transformed and the component will probably end up actually appearing somewhere else within its parent.

When using transforms you need to be extremely careful when converting coordinates between the
coordinate spaces of different components or the screen - you should always use getLocalPoint(),
getLocalArea(), etc to do this, and never just manually add a component's position to a point in order to
convert it between different components (but I'm sure you would never have done that anyway...).

Currently, transforms are not supported for desktop windows, so the transform will be ignored if you
put a component on the desktop.

To remove a component's transform, simply pass AffineTransform::identity as the parameter to this method.
*/
void setTransform (const AffineTransform& transform);

/** Returns the transform that is currently being applied to this component.
For more details about transforms, see setTransform().
@see setTransform
*/
const AffineTransform getTransform() const;

/** Returns true if a non-identity transform is being applied to this component.
For more details about transforms, see setTransform().
@see setTransform
*/
bool isTransformed() const throw();

/** Returns a proportion of the component's width. /** Returns a proportion of the component's width.


This is a handy equivalent of (getWidth() * proportion). This is a handy equivalent of (getWidth() * proportion).
@@ -26340,7 +26431,7 @@ public:
*/ */
int getParentHeight() const throw(); int getParentHeight() const throw();


/** Returns the screen co-ordinates of the monitor that contains this component.
/** Returns the screen coordinates of the monitor that contains this component.


If there's only one monitor, this will return its size - if there are multiple If there's only one monitor, this will return its size - if there are multiple
monitors, it will return the area of the monitor that contains the component's monitors, it will return the area of the monitor that contains the component's
@@ -26509,7 +26600,7 @@ public:
Overriding this method allows you to create components which only intercept Overriding this method allows you to create components which only intercept
mouse-clicks within a user-defined area. mouse-clicks within a user-defined area.


This is called to find out whether a particular x, y co-ordinate is
This is called to find out whether a particular x, y coordinate is
considered to be inside the component or not, and is used by methods such considered to be inside the component or not, and is used by methods such
as contains() and getComponentAt() to work out which component as contains() and getComponentAt() to work out which component
the mouse is clicked on. the mouse is clicked on.
@@ -26531,10 +26622,10 @@ public:
Note that for components on the desktop, this method will be ignored, because it's Note that for components on the desktop, this method will be ignored, because it's
not always possible to implement this behaviour on all platforms. not always possible to implement this behaviour on all platforms.


@param x the x co-ordinate to test, relative to the left hand edge of this
@param x the x coordinate to test, relative to the left hand edge of this
component. This value is guaranteed to be greater than or equal to component. This value is guaranteed to be greater than or equal to
zero, and less than the component's width zero, and less than the component's width
@param y the y co-ordinate to test, relative to the top edge of this
@param y the y coordinate to test, relative to the top edge of this
component. This value is guaranteed to be greater than or equal to component. This value is guaranteed to be greater than or equal to
zero, and less than the component's height zero, and less than the component's height
@returns true if the click is considered to be inside the component @returns true if the click is considered to be inside the component
@@ -26576,32 +26667,29 @@ public:


Never override this method! Use hitTest to create custom hit regions. Never override this method! Use hitTest to create custom hit regions.


@param point the x co-ordinate to test, relative to this component's top-left.
@param localPoint the coordinate to test, relative to this component's top-left.
@returns true if the point is within the component's hit-test area, but only if @returns true if the point is within the component's hit-test area, but only if
that part of the component isn't clipped by its parent component. Note that part of the component isn't clipped by its parent component. Note
that this won't take into account any overlapping sibling components that this won't take into account any overlapping sibling components
which might be in the way - for that, see reallyContains() which might be in the way - for that, see reallyContains()
@see hitTest, reallyContains, getComponentAt @see hitTest, reallyContains, getComponentAt
*/ */
bool contains (const Point<int>& point);
bool contains (const Point<int>& localPoint);


/** Returns true if a given point lies in this component, taking any overlapping /** Returns true if a given point lies in this component, taking any overlapping
siblings into account. siblings into account.


@param x the x co-ordinate to test, relative to this component's left hand edge.
@param y the y co-ordinate to test, relative to this component's top edge.
@param returnTrueIfWithinAChild if the point actually lies within a child of this
component, this determines the value that will
be returned.

@param localPoint the coordinate to test, relative to this component's top-left.
@param returnTrueIfWithinAChild if the point actually lies within a child of this component,
this determines whether that is counted as a hit.
@see contains, getComponentAt @see contains, getComponentAt
*/ */
bool reallyContains (int x, int y, bool returnTrueIfWithinAChild);
bool reallyContains (const Point<int>& localPoint, bool returnTrueIfWithinAChild);


/** Returns the component at a certain point within this one. /** Returns the component at a certain point within this one.


@param x the x co-ordinate to test, relative to this component's left hand edge.
@param y the y co-ordinate to test, relative to this component's top edge.
@param x the x coordinate to test, relative to this component's left edge.
@param y the y coordinate to test, relative to this component's top edge.
@returns the component that is at this position - which may be 0, this component, @returns the component that is at this position - which may be 0, this component,
or one of its children. Note that overlapping siblings that might actually or one of its children. Note that overlapping siblings that might actually
be in the way are not taken into account by this method - to account for these, be in the way are not taken into account by this method - to account for these,
@@ -26612,7 +26700,7 @@ public:


/** Returns the component at a certain point within this one. /** Returns the component at a certain point within this one.


@param position the co-ordinates to test, relative to this component's top-left.
@param position the coordinate to test, relative to this component's top-left.
@returns the component that is at this position - which may be 0, this component, @returns the component that is at this position - which may be 0, this component,
or one of its children. Note that overlapping siblings that might actually or one of its children. Note that overlapping siblings that might actually
be in the way are not taken into account by this method - to account for these, be in the way are not taken into account by this method - to account for these,
@@ -27442,8 +27530,7 @@ public:
static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw(); static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw();


/** Returns the mouse's current position, relative to this component. /** Returns the mouse's current position, relative to this component.

The co-ordinates are relative to the component's top-left corner.
The return value is relative to the component's top-left corner.
*/ */
const Point<int> getMouseXYRelative() const; const Point<int> getMouseXYRelative() const;


@@ -27849,6 +27936,7 @@ private:
String componentName_; String componentName_;
Component* parentComponent_; Component* parentComponent_;
Rectangle<int> bounds_; Rectangle<int> bounds_;
ScopedPointer <AffineTransform> affineTransform_;
Array <Component*> childComponentList_; Array <Component*> childComponentList_;
LookAndFeel* lookAndFeel_; LookAndFeel* lookAndFeel_;
MouseCursor cursor_; MouseCursor cursor_;
@@ -27914,6 +28002,7 @@ private:
void internalHierarchyChanged(); void internalHierarchyChanged();
void paintComponentAndChildren (Graphics& g); void paintComponentAndChildren (Graphics& g);
void paintComponent (Graphics& g); void paintComponent (Graphics& g);
void paintTransformedChild (Graphics& g);
void sendMovedResizedMessages (bool wasMoved, bool wasResized); void sendMovedResizedMessages (bool wasMoved, bool wasResized);
void repaintParent(); void repaintParent();
void sendFakeMouseMove() const; void sendFakeMouseMove() const;
@@ -36206,7 +36295,8 @@ private:
void repeatTimerCallback(); void repeatTimerCallback();
RepeatTimer& getRepeatTimer(); RepeatTimer& getRepeatTimer();


ButtonState updateState (const MouseEvent*);
ButtonState updateState();
ButtonState updateState (bool isOver, bool isDown);
bool isShortcutPressed() const; bool isShortcutPressed() const;
void turnOffOtherButtonsInGroup (bool sendChangeNotification); void turnOffOtherButtonsInGroup (bool sendChangeNotification);




+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/ */
#define JUCE_MAJOR_VERSION 1 #define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52 #define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 94
#define JUCE_BUILDNUMBER 95
/** Current Juce version number. /** Current Juce version number.


+ 25
- 30
src/gui/components/buttons/juce_Button.cpp View File

@@ -227,34 +227,29 @@ void Button::turnOffOtherButtonsInGroup (const bool sendChangeNotification)
//============================================================================== //==============================================================================
void Button::enablementChanged() void Button::enablementChanged()
{ {
updateState (0);
updateState();
repaint(); repaint();
} }
Button::ButtonState Button::updateState (const MouseEvent* const e)
Button::ButtonState Button::updateState()
{ {
ButtonState state = buttonNormal;
return updateState (reallyContains (getMouseXYRelative(), true), isMouseButtonDown());
}
Button::ButtonState Button::updateState (const bool over, const bool down)
{
ButtonState newState = buttonNormal;
if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent()) if (isEnabled() && isVisible() && ! isCurrentlyBlockedByAnotherModalComponent())
{ {
Point<int> mousePos;
if (e == 0)
mousePos = getMouseXYRelative();
else
mousePos = e->getEventRelativeTo (this).getPosition();
const bool over = reallyContains (mousePos.getX(), mousePos.getY(), true);
const bool down = isMouseButtonDown();
if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown) if ((down && (over || (triggerOnMouseDown && buttonState == buttonDown))) || isKeyDown)
state = buttonDown;
newState = buttonDown;
else if (over) else if (over)
state = buttonOver;
newState = buttonOver;
} }
setState (state);
return state;
setState (newState);
return newState;
} }
void Button::setState (const ButtonState newState) void Button::setState (const ButtonState newState)
@@ -403,19 +398,19 @@ void Button::paint (Graphics& g)
} }
//============================================================================== //==============================================================================
void Button::mouseEnter (const MouseEvent& e)
void Button::mouseEnter (const MouseEvent&)
{ {
updateState (&e);
updateState (true, false);
} }
void Button::mouseExit (const MouseEvent& e)
void Button::mouseExit (const MouseEvent&)
{ {
updateState (&e);
updateState (false, false);
} }
void Button::mouseDown (const MouseEvent& e) void Button::mouseDown (const MouseEvent& e)
{ {
updateState (&e);
updateState (true, true);
if (isDown()) if (isDown())
{ {
@@ -430,7 +425,7 @@ void Button::mouseDown (const MouseEvent& e)
void Button::mouseUp (const MouseEvent& e) void Button::mouseUp (const MouseEvent& e)
{ {
const bool wasDown = isDown(); const bool wasDown = isDown();
updateState (&e);
updateState (isMouseOver(), false);
if (wasDown && isOver() && ! triggerOnMouseDown) if (wasDown && isOver() && ! triggerOnMouseDown)
internalClickCallback (e.mods); internalClickCallback (e.mods);
@@ -439,7 +434,7 @@ void Button::mouseUp (const MouseEvent& e)
void Button::mouseDrag (const MouseEvent& e) void Button::mouseDrag (const MouseEvent& e)
{ {
const ButtonState oldState = buttonState; const ButtonState oldState = buttonState;
updateState (&e);
updateState (isMouseOver(), true);
if (autoRepeatDelay >= 0 && buttonState != oldState && isDown()) if (autoRepeatDelay >= 0 && buttonState != oldState && isDown())
getRepeatTimer().startTimer (autoRepeatSpeed); getRepeatTimer().startTimer (autoRepeatSpeed);
@@ -447,13 +442,13 @@ void Button::mouseDrag (const MouseEvent& e)
void Button::focusGained (FocusChangeType) void Button::focusGained (FocusChangeType)
{ {
updateState (0);
updateState();
repaint(); repaint();
} }
void Button::focusLost (FocusChangeType) void Button::focusLost (FocusChangeType)
{ {
updateState (0);
updateState();
repaint(); repaint();
} }
@@ -467,7 +462,7 @@ void Button::setVisible (bool shouldBeVisible)
if (! shouldBeVisible) if (! shouldBeVisible)
needsToRelease = false; needsToRelease = false;
updateState (0);
updateState();
} }
else else
{ {
@@ -597,7 +592,7 @@ bool Button::keyStateChanged (const bool, Component*)
if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown)) if (autoRepeatDelay >= 0 && (isKeyDown && ! wasDown))
getRepeatTimer().startTimer (autoRepeatDelay); getRepeatTimer().startTimer (autoRepeatDelay);
updateState (0);
updateState();
if (isEnabled() && wasDown && ! isKeyDown) if (isEnabled() && wasDown && ! isKeyDown)
{ {
@@ -642,10 +637,10 @@ void Button::repeatTimerCallback()
if (needsRepainting) if (needsRepainting)
{ {
getRepeatTimer().stopTimer(); getRepeatTimer().stopTimer();
updateState (0);
updateState();
needsRepainting = false; needsRepainting = false;
} }
else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState (0) == buttonDown)))
else if (autoRepeatSpeed > 0 && (isKeyDown || (updateState() == buttonDown)))
{ {
int repeatSpeed = autoRepeatSpeed; int repeatSpeed = autoRepeatSpeed;


+ 2
- 1
src/gui/components/buttons/juce_Button.h View File

@@ -495,7 +495,8 @@ private:
void repeatTimerCallback(); void repeatTimerCallback();
RepeatTimer& getRepeatTimer(); RepeatTimer& getRepeatTimer();
ButtonState updateState (const MouseEvent*);
ButtonState updateState();
ButtonState updateState (bool isOver, bool isDown);
bool isShortcutPressed() const; bool isShortcutPressed() const;
void turnOffOtherButtonsInGroup (bool sendChangeNotification); void turnOffOtherButtonsInGroup (bool sendChangeNotification);


+ 1
- 1
src/gui/components/controls/juce_ComboBox.cpp View File

@@ -590,7 +590,7 @@ void ComboBox::mouseUp (const MouseEvent& e2)
const MouseEvent e (e2.getEventRelativeTo (this)); const MouseEvent e (e2.getEventRelativeTo (this));
if (reallyContains (e.x, e.y, true)
if (reallyContains (e.getPosition(), true)
&& (e2.eventComponent == this || ! label->isEditable())) && (e2.eventComponent == this || ! label->isEditable()))
{ {
showPopup(); showPopup();


+ 4
- 0
src/gui/components/controls/juce_Slider.cpp View File

@@ -352,6 +352,10 @@ void Slider::lookAndFeelChanged()
valueBox->setTooltip (getTooltip()); valueBox->setTooltip (getTooltip());
} }
else
{
valueBox = 0;
}
if (style == IncDecButtons) if (style == IncDecButtons)
{ {


+ 1
- 1
src/gui/components/controls/juce_TableHeaderComponent.cpp View File

@@ -909,7 +909,7 @@ int TableHeaderComponent::getResizeDraggerAt (const int mouseX) const
void TableHeaderComponent::updateColumnUnderMouse (int x, int y) void TableHeaderComponent::updateColumnUnderMouse (int x, int y)
{ {
const int newCol = (reallyContains (x, y, true) && getResizeDraggerAt (x) == 0)
const int newCol = (reallyContains (Point<int> (x, y), true) && getResizeDraggerAt (x) == 0)
? getColumnIdAtX (x) : 0; ? getColumnIdAtX (x) : 0;
if (newCol != columnIdUnderMouse) if (newCol != columnIdUnderMouse)


+ 98
- 50
src/gui/components/juce_Component.cpp View File

@@ -44,7 +44,7 @@ BEGIN_JUCE_NAMESPACE
//============================================================================== //==============================================================================
#define checkMessageManagerIsLocked jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
#define CHECK_MESSAGE_MANAGER_IS_LOCKED jassert (MessageManager::getInstance()->currentThreadHasLockedMessageManager());
Component* Component::currentlyFocusedComponent = 0; Component* Component::currentlyFocusedComponent = 0;
@@ -249,22 +249,34 @@ public:
static const Point<int> convertFromParentSpace (const Component& comp, const Point<int>& pointInParentSpace) static const Point<int> convertFromParentSpace (const Component& comp, const Point<int>& pointInParentSpace)
{ {
return pointInParentSpace - comp.getPosition();
if (comp.affineTransform_ == 0)
return pointInParentSpace - comp.getPosition();
return pointInParentSpace.toFloat().transformedBy (comp.affineTransform_->inverted()).toInt() - comp.getPosition();
} }
static const Rectangle<int> convertFromParentSpace (const Component& comp, const Rectangle<int>& areaInParentSpace) static const Rectangle<int> convertFromParentSpace (const Component& comp, const Rectangle<int>& areaInParentSpace)
{ {
return areaInParentSpace - comp.getPosition();
if (comp.affineTransform_ == 0)
return areaInParentSpace - comp.getPosition();
return areaInParentSpace.toFloat().transformed (comp.affineTransform_->inverted()).getSmallestIntegerContainer() - comp.getPosition();
} }
static const Point<int> convertToParentSpace (const Component& comp, const Point<int>& pointInLocalSpace) static const Point<int> convertToParentSpace (const Component& comp, const Point<int>& pointInLocalSpace)
{ {
return pointInLocalSpace + comp.getPosition();
if (comp.affineTransform_ == 0)
return pointInLocalSpace + comp.getPosition();
return (pointInLocalSpace + comp.getPosition()).toFloat().transformedBy (*comp.affineTransform_).toInt();
} }
static const Rectangle<int> convertToParentSpace (const Component& comp, const Rectangle<int>& areaInLocalSpace) static const Rectangle<int> convertToParentSpace (const Component& comp, const Rectangle<int>& areaInLocalSpace)
{ {
return areaInLocalSpace + comp.getPosition();
if (comp.affineTransform_ == 0)
return areaInLocalSpace + comp.getPosition();
return (areaInLocalSpace + comp.getPosition()).toFloat().transformed (*comp.affineTransform_).getSmallestIntegerContainer();
} }
template <typename Type> template <typename Type>
@@ -337,8 +349,7 @@ public:
{ {
const Component& child = *comp.childComponentList_.getUnchecked(i); const Component& child = *comp.childComponentList_.getUnchecked(i);
//xxx if (child.isVisible() && ! child.isTransformed())
if (child.isVisible())
if (child.isVisible() && ! child.isTransformed())
{ {
const Rectangle<int> newClip (clipRect.getIntersection (child.bounds_)); const Rectangle<int> newClip (clipRect.getIntersection (child.bounds_));
@@ -465,7 +476,7 @@ void Component::setName (const String& name)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (componentName_ != name) if (componentName_ != name)
{ {
@@ -491,7 +502,7 @@ void Component::setVisible (bool shouldBeVisible)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
SafePointer<Component> safePointer (this); SafePointer<Component> safePointer (this);
@@ -582,7 +593,7 @@ void Component::addToDesktop (int styleWanted, void* nativeWindowToAttachTo)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (isOpaque()) if (isOpaque())
styleWanted &= ~ComponentPeer::windowIsSemiTransparent; styleWanted &= ~ComponentPeer::windowIsSemiTransparent;
@@ -670,7 +681,7 @@ void Component::removeFromDesktop()
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
@@ -748,7 +759,7 @@ void Component::toFront (const bool setAsForeground)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (flags.hasHeavyweightPeerFlag) if (flags.hasHeavyweightPeerFlag)
{ {
@@ -990,7 +1001,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 // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (w < 0) w = 0; if (w < 0) w = 0;
if (h < 0) h = 0; if (h < 0) h = 0;
@@ -1178,6 +1189,42 @@ void Component::setBoundsToFit (int x, int y, int width, int height,
} }
} }
//==============================================================================
bool Component::isTransformed() const throw()
{
return affineTransform_ != 0;
}
void Component::setTransform (const AffineTransform& newTransform)
{
if (newTransform.isIdentity())
{
if (affineTransform_ != 0)
{
repaint();
affineTransform_ = 0;
repaint();
}
}
else if (affineTransform_ == 0)
{
repaint();
affineTransform_ = new AffineTransform (newTransform);
repaint();
}
else if (*affineTransform_ != newTransform)
{
repaint();
*affineTransform_ = newTransform;
repaint();
}
}
const AffineTransform Component::getTransform() const
{
return affineTransform_ != 0 ? *affineTransform_ : AffineTransform::identity;
}
//============================================================================== //==============================================================================
bool Component::hitTest (int x, int y) bool Component::hitTest (int x, int y)
{ {
@@ -1233,15 +1280,13 @@ bool Component::contains (const Point<int>& point)
return false; return false;
} }
bool Component::reallyContains (const int x, const int y, const bool returnTrueIfWithinAChild)
bool Component::reallyContains (const Point<int>& point, const bool returnTrueIfWithinAChild)
{ {
const Point<int> p (x, y);
if (! contains (p))
if (! contains (point))
return false; return false;
Component* const top = getTopLevelComponent(); Component* const top = getTopLevelComponent();
const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, p));
const Component* const compAtPosition = top->getComponentAt (top->getLocalPoint (this, point));
return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition)); return (compAtPosition == this) || (returnTrueIfWithinAChild && isParentOf (compAtPosition));
} }
@@ -1275,7 +1320,7 @@ void Component::addChildComponent (Component* const child, int zOrder)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (child != 0 && child->parentComponent_ != this) if (child != 0 && child->parentComponent_ != this)
{ {
@@ -1328,7 +1373,7 @@ Component* Component::removeChildComponent (const int index)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
Component* const child = childComponentList_ [index]; Component* const child = childComponentList_ [index];
@@ -1500,7 +1545,7 @@ void Component::enterModalState (const bool takeKeyboardFocus_, ModalComponentMa
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
// Check for an attempt to make a component modal when it already is! // Check for an attempt to make a component modal when it already is!
// This can cause nasty problems.. // This can cause nasty problems..
@@ -1674,7 +1719,7 @@ void Component::internalRepaint (int x, int y, int w, int h)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (x < 0) if (x < 0)
{ {
@@ -1701,7 +1746,17 @@ void Component::internalRepaint (int x, int y, int w, int h)
if (parentComponent_ != 0) if (parentComponent_ != 0)
{ {
if (parentComponent_->flags.visibleFlag) if (parentComponent_->flags.visibleFlag)
parentComponent_->internalRepaint (x + getX(), y + getY(), w, h);
{
if (affineTransform_ == 0)
{
parentComponent_->internalRepaint (x + getX(), y + getY(), w, h);
}
else
{
const Rectangle<int> r (ComponentHelpers::convertToParentSpace (*this, Rectangle<int> (x, y, w, h)));
parentComponent_->internalRepaint (r.getX(), r.getY(), r.getWidth(), r.getHeight());
}
}
} }
else if (flags.hasHeavyweightPeerFlag) else if (flags.hasHeavyweightPeerFlag)
{ {
@@ -1737,6 +1792,15 @@ void Component::paintComponent (Graphics& g)
} }
} }
void Component::paintTransformedChild (Graphics& g)
{
if (affineTransform_ != 0)
g.addTransform (*affineTransform_);
g.setOrigin (getX(), getY());
paintEntireComponent (g, false);
}
void Component::paintComponentAndChildren (Graphics& g) void Component::paintComponentAndChildren (Graphics& g)
{ {
const Rectangle<int> clipBounds (g.getClipBounds()); const Rectangle<int> clipBounds (g.getClipBounds());
@@ -1766,8 +1830,7 @@ void Component::paintComponentAndChildren (Graphics& g)
if (child->flags.dontClipGraphicsFlag) if (child->flags.dontClipGraphicsFlag)
{ {
g.setOrigin (child->getX(), child->getY());
child->paintEntireComponent (g, false);
child->paintTransformedChild (g);
} }
else else
{ {
@@ -1787,10 +1850,7 @@ void Component::paintComponentAndChildren (Graphics& g)
} }
if (nothingClipped || ! g.isClipEmpty()) if (nothingClipped || ! g.isClipEmpty())
{
g.setOrigin (child->getX(), child->getY());
child->paintEntireComponent (g, false);
}
child->paintTransformedChild (g);
} }
} }
@@ -2161,7 +2221,7 @@ void Component::addMouseListener (MouseListener* const newListener,
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
// If you register a component as a mouselistener for itself, it'll receive all the events // 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! // twice - once via the direct callback that all components get anyway, and then again as a listener!
@@ -2177,7 +2237,7 @@ void Component::removeMouseListener (MouseListener* const listenerToRemove)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (mouseListeners_ != 0) if (mouseListeners_ != 0)
mouseListeners_->removeListener (listenerToRemove); mouseListeners_->removeListener (listenerToRemove);
@@ -2437,7 +2497,7 @@ void Component::internalMouseDrag (MouseInputSource& source, const Point<int>& r
{ {
Desktop& desktop = Desktop::getInstance(); Desktop& desktop = Desktop::getInstance();
flags.mouseOverFlag = reallyContains (relativePos.getX(), relativePos.getY(), false);
flags.mouseOverFlag = reallyContains (relativePos, false);
BailOutChecker checker (this); BailOutChecker checker (this);
@@ -2807,7 +2867,7 @@ void Component::grabKeyboardFocus()
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
grabFocusInternal (focusChangedDirectly); grabFocusInternal (focusChangedDirectly);
} }
@@ -2816,7 +2876,7 @@ void Component::moveKeyboardFocusToSibling (const bool moveToNext)
{ {
// if component methods are being called from threads other than the message // 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. // thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
checkMessageManagerIsLocked
CHECK_MESSAGE_MANAGER_IS_LOCKED
if (parentComponent_ != 0) if (parentComponent_ != 0)
{ {
@@ -2872,20 +2932,9 @@ void Component::giveAwayFocus()
} }
//============================================================================== //==============================================================================
bool Component::isMouseOver() const throw()
{
return flags.mouseOverFlag;
}
bool Component::isMouseButtonDown() const throw()
{
return flags.mouseDownFlag;
}
bool Component::isMouseOverOrDragging() const throw()
{
return flags.mouseOverFlag || flags.mouseDownFlag;
}
bool Component::isMouseOver() const throw() { return flags.mouseOverFlag; }
bool Component::isMouseButtonDown() const throw() { return flags.mouseDownFlag; }
bool Component::isMouseOverOrDragging() const throw() { return flags.mouseOverFlag || flags.mouseDownFlag; }
bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw() bool JUCE_CALLTYPE Component::isMouseButtonDownAnywhere() throw()
{ {
@@ -2900,8 +2949,7 @@ const Point<int> Component::getMouseXYRelative() const
//============================================================================== //==============================================================================
const Rectangle<int> Component::getParentMonitorArea() const const Rectangle<int> Component::getParentMonitorArea() const
{ {
return Desktop::getInstance()
.getMonitorAreaContaining (localPointToGlobal (getLocalBounds().getCentre()));
return Desktop::getInstance().getMonitorAreaContaining (getScreenBounds().getCentre());
} }
//============================================================================== //==============================================================================


+ 118
- 28
src/gui/components/juce_Component.h View File

@@ -258,15 +258,21 @@ public:
bool isAlwaysOnTop() const throw(); bool isAlwaysOnTop() const throw();
//============================================================================== //==============================================================================
/** Returns the x co-ordinate of the component's left edge.
/** Returns the x coordinate of the component's left edge.
This is a distance in pixels from the left edge of the component's parent. This is a distance in pixels from the left edge of the component's parent.
@see getScreenX
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
inline int getX() const throw() { return bounds_.getX(); } inline int getX() const throw() { return bounds_.getX(); }
/** Returns the y co-ordinate of the top of this component.
/** Returns the y coordinate of the top of this component.
This is a distance in pixels from the top edge of the component's parent. This is a distance in pixels from the top edge of the component's parent.
@see getScreenY
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
inline int getY() const throw() { return bounds_.getY(); } inline int getY() const throw() { return bounds_.getY(); }
@@ -276,26 +282,38 @@ public:
/** Returns the component's height in pixels. */ /** Returns the component's height in pixels. */
inline int getHeight() const throw() { return bounds_.getHeight(); } inline int getHeight() const throw() { return bounds_.getHeight(); }
/** Returns the x co-ordinate of the component's right-hand edge.
/** Returns the x coordinate of the component's right-hand edge.
This is a distance in pixels from the left edge of the component's parent. This is a distance in pixels from the left edge of the component's parent.
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
int getRight() const throw() { return bounds_.getRight(); } int getRight() const throw() { return bounds_.getRight(); }
/** Returns the component's top-left position as a Point. */ /** Returns the component's top-left position as a Point. */
const Point<int> getPosition() const throw() { return bounds_.getPosition(); } const Point<int> getPosition() const throw() { return bounds_.getPosition(); }
/** Returns the y co-ordinate of the bottom edge of this component.
/** Returns the y coordinate of the bottom edge of this component.
This is a distance in pixels from the top edge of the component's parent. This is a distance in pixels from the top edge of the component's parent.
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
int getBottom() const throw() { return bounds_.getBottom(); } int getBottom() const throw() { return bounds_.getBottom(); }
/** Returns this component's bounding box. /** Returns this component's bounding box.
The rectangle returned is relative to the top-left of the component's parent. The rectangle returned is relative to the top-left of the component's parent.
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to its bounding box.
*/ */
const Rectangle<int>& getBounds() const throw() { return bounds_; } const Rectangle<int>& getBounds() const throw() { return bounds_; }
/** Returns the component's bounds, relative to its own origin. /** Returns the component's bounds, relative to its own origin.
This is like getBounds(), but returns the rectangle in local co-ordinates, In practice, it'll
This is like getBounds(), but returns the rectangle in local coordinates, In practice, it'll
return a rectangle with position (0, 0), and the same size as this component. return a rectangle with position (0, 0), and the same size as this component.
*/ */
const Rectangle<int> getLocalBounds() const throw(); const Rectangle<int> getLocalBounds() const throw();
@@ -312,12 +330,12 @@ public:
bool includeSiblings) const; bool includeSiblings) const;
//============================================================================== //==============================================================================
/** Returns this component's x co-ordinate relative the the screen's top-left origin.
/** Returns this component's x coordinate relative the the screen's top-left origin.
@see getX, localPointToGlobal @see getX, localPointToGlobal
*/ */
int getScreenX() const; int getScreenX() const;
/** Returns this component's y co-ordinate relative the the screen's top-left origin.
/** Returns this component's y coordinate relative the the screen's top-left origin.
@see getY, localPointToGlobal @see getY, localPointToGlobal
*/ */
int getScreenY() const; int getScreenY() const;
@@ -346,6 +364,10 @@ public:
This takes a rectangle that is relative to a different component, and returns its position relative This takes a rectangle that is relative to a different component, and returns its position relative
to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be
a screen coordinate. a screen coordinate.
If you've used setTransform() to apply one or more transforms to components, then the source rectangle
may not actually be rectanglular when converted to the target space, so in that situation this will return
the smallest rectangle that fully contains the transformed area.
*/ */
const Rectangle<int> getLocalArea (const Component* sourceComponent, const Rectangle<int> getLocalArea (const Component* sourceComponent,
const Rectangle<int>& areaRelativeToSourceComponent) const; const Rectangle<int>& areaRelativeToSourceComponent) const;
@@ -356,6 +378,10 @@ public:
const Point<int> localPointToGlobal (const Point<int>& localPoint) const; const Point<int> localPointToGlobal (const Point<int>& localPoint) const;
/** Converts a rectangle from this component's coordinate space to a screen coordinate. /** 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
may not actually be rectanglular when converted to the target space, so in that situation this will return
the smallest rectangle that fully contains the transformed area.
@see getLocalPoint, localPointToGlobal @see getLocalPoint, localPointToGlobal
*/ */
const Rectangle<int> localAreaToGlobal (const Rectangle<int>& localArea) const; const Rectangle<int> localAreaToGlobal (const Rectangle<int>& localArea) const;
@@ -368,6 +394,10 @@ public:
If the component actually moves, this method will make a synchronous call to moved(). If the component actually moves, this method will make a synchronous call to moved().
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
@see setBounds, ComponentListener::componentMovedOrResized @see setBounds, ComponentListener::componentMovedOrResized
*/ */
void setTopLeftPosition (int x, int y); void setTopLeftPosition (int x, int y);
@@ -378,29 +408,51 @@ public:
The position is relative to the top-left of the component's parent. The position is relative to the top-left of the component's parent.
If the component actually moves, this method will make a synchronous call to moved(). If the component actually moves, this method will make a synchronous call to moved().
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
*/ */
void setTopRightPosition (int x, int y); void setTopRightPosition (int x, int y);
/** Changes the size of the component. /** Changes the size of the component.
A synchronous call to resized() will be occur if the size actually changes. A synchronous call to resized() will be occur if the size actually changes.
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
*/ */
void setSize (int newWidth, int newHeight); void setSize (int newWidth, int newHeight);
/** Changes the component's position and size. /** Changes the component's position and size.
The co-ordinates are relative to the top-left of the component's parent, or relative
The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop. to the origin of the screen is the component is on the desktop.
If this method changes the component's top-left position, it will make a synchronous If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized(). call to moved(). If it changes the size, it will also make a call to resized().
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
@see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized
*/ */
void setBounds (int x, int y, int width, int height); void setBounds (int x, int y, int width, int height);
/** Changes the component's position and size. /** Changes the component's position and size.
The coordinates are relative to the top-left of the component's parent, or relative
to the origin of the screen is the component is on the desktop.
If this method changes the component's top-left position, it will make a synchronous
call to moved(). If it changes the size, it will also make a call to resized().
Note that if you've used setTransform() to apply a transform, then the component's
bounds will no longer be a direct reflection of the position at which it appears within
its parent, as the transform will be applied to whatever bounds you set for it.
@see setBounds @see setBounds
*/ */
void setBounds (const Rectangle<int>& newBounds); void setBounds (const Rectangle<int>& newBounds);
@@ -411,6 +463,8 @@ public:
setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the
width and height of the parent, with its top-left position 20% of width and height of the parent, with its top-left position 20% of
the way across and down the parent. the way across and down the parent.
@see setBounds
*/ */
void setBoundsRelative (float proportionalX, float proportionalY, void setBoundsRelative (float proportionalX, float proportionalY,
float proportionalWidth, float proportionalHeight); float proportionalWidth, float proportionalHeight);
@@ -419,6 +473,8 @@ public:
This will position the component within its parent, leaving the specified number of This will position the component within its parent, leaving the specified number of
pixels around each edge. pixels around each edge.
@see setBounds
*/ */
void setBoundsInset (const BorderSize& borders); void setBoundsInset (const BorderSize& borders);
@@ -433,6 +489,8 @@ public:
It will then be positioned within the rectangle according to the justification flags It will then be positioned within the rectangle according to the justification flags
specified. specified.
@see setBounds
*/ */
void setBoundsToFit (int x, int y, int width, int height, void setBoundsToFit (int x, int y, int width, int height,
const Justification& justification, const Justification& justification,
@@ -442,6 +500,8 @@ public:
Leaves the component's size unchanged, but sets the position of its centre Leaves the component's size unchanged, but sets the position of its centre
relative to its parent's top-left. relative to its parent's top-left.
@see setBounds
*/ */
void setCentrePosition (int x, int y); void setCentrePosition (int x, int y);
@@ -461,6 +521,38 @@ public:
*/ */
void centreWithSize (int width, int height); void centreWithSize (int width, int height);
//==============================================================================
/** Sets a transform matrix to be applied to this component.
If you set a transform for a component, the component's position will be warped by it, relative to
the component's parent's top-left origin. This means that the values you pass into setBounds() will no
longer reflect the actual area within the parent that the component covers, as the bounds will be
transformed and the component will probably end up actually appearing somewhere else within its parent.
When using transforms you need to be extremely careful when converting coordinates between the
coordinate spaces of different components or the screen - you should always use getLocalPoint(),
getLocalArea(), etc to do this, and never just manually add a component's position to a point in order to
convert it between different components (but I'm sure you would never have done that anyway...).
Currently, transforms are not supported for desktop windows, so the transform will be ignored if you
put a component on the desktop.
To remove a component's transform, simply pass AffineTransform::identity as the parameter to this method.
*/
void setTransform (const AffineTransform& transform);
/** Returns the transform that is currently being applied to this component.
For more details about transforms, see setTransform().
@see setTransform
*/
const AffineTransform getTransform() const;
/** Returns true if a non-identity transform is being applied to this component.
For more details about transforms, see setTransform().
@see setTransform
*/
bool isTransformed() const throw();
//============================================================================== //==============================================================================
/** Returns a proportion of the component's width. /** Returns a proportion of the component's width.
@@ -488,7 +580,7 @@ public:
*/ */
int getParentHeight() const throw(); int getParentHeight() const throw();
/** Returns the screen co-ordinates of the monitor that contains this component.
/** Returns the screen coordinates of the monitor that contains this component.
If there's only one monitor, this will return its size - if there are multiple If there's only one monitor, this will return its size - if there are multiple
monitors, it will return the area of the monitor that contains the component's monitors, it will return the area of the monitor that contains the component's
@@ -660,7 +752,7 @@ public:
Overriding this method allows you to create components which only intercept Overriding this method allows you to create components which only intercept
mouse-clicks within a user-defined area. mouse-clicks within a user-defined area.
This is called to find out whether a particular x, y co-ordinate is
This is called to find out whether a particular x, y coordinate is
considered to be inside the component or not, and is used by methods such considered to be inside the component or not, and is used by methods such
as contains() and getComponentAt() to work out which component as contains() and getComponentAt() to work out which component
the mouse is clicked on. the mouse is clicked on.
@@ -682,10 +774,10 @@ public:
Note that for components on the desktop, this method will be ignored, because it's Note that for components on the desktop, this method will be ignored, because it's
not always possible to implement this behaviour on all platforms. not always possible to implement this behaviour on all platforms.
@param x the x co-ordinate to test, relative to the left hand edge of this
@param x the x coordinate to test, relative to the left hand edge of this
component. This value is guaranteed to be greater than or equal to component. This value is guaranteed to be greater than or equal to
zero, and less than the component's width zero, and less than the component's width
@param y the y co-ordinate to test, relative to the top edge of this
@param y the y coordinate to test, relative to the top edge of this
component. This value is guaranteed to be greater than or equal to component. This value is guaranteed to be greater than or equal to
zero, and less than the component's height zero, and less than the component's height
@returns true if the click is considered to be inside the component @returns true if the click is considered to be inside the component
@@ -728,32 +820,29 @@ public:
Never override this method! Use hitTest to create custom hit regions. Never override this method! Use hitTest to create custom hit regions.
@param point the x co-ordinate to test, relative to this component's top-left.
@param localPoint the coordinate to test, relative to this component's top-left.
@returns true if the point is within the component's hit-test area, but only if @returns true if the point is within the component's hit-test area, but only if
that part of the component isn't clipped by its parent component. Note that part of the component isn't clipped by its parent component. Note
that this won't take into account any overlapping sibling components that this won't take into account any overlapping sibling components
which might be in the way - for that, see reallyContains() which might be in the way - for that, see reallyContains()
@see hitTest, reallyContains, getComponentAt @see hitTest, reallyContains, getComponentAt
*/ */
bool contains (const Point<int>& point);
bool contains (const Point<int>& localPoint);
/** Returns true if a given point lies in this component, taking any overlapping /** Returns true if a given point lies in this component, taking any overlapping
siblings into account. siblings into account.
@param x the x co-ordinate to test, relative to this component's left hand edge.
@param y the y co-ordinate to test, relative to this component's top edge.
@param returnTrueIfWithinAChild if the point actually lies within a child of this
component, this determines the value that will
be returned.
@param localPoint the coordinate to test, relative to this component's top-left.
@param returnTrueIfWithinAChild if the point actually lies within a child of this component,
this determines whether that is counted as a hit.
@see contains, getComponentAt @see contains, getComponentAt
*/ */
bool reallyContains (int x, int y, bool returnTrueIfWithinAChild);
bool reallyContains (const Point<int>& localPoint, bool returnTrueIfWithinAChild);
/** Returns the component at a certain point within this one. /** Returns the component at a certain point within this one.
@param x the x co-ordinate to test, relative to this component's left hand edge.
@param y the y co-ordinate to test, relative to this component's top edge.
@param x the x coordinate to test, relative to this component's left edge.
@param y the y coordinate to test, relative to this component's top edge.
@returns the component that is at this position - which may be 0, this component, @returns the component that is at this position - which may be 0, this component,
or one of its children. Note that overlapping siblings that might actually or one of its children. Note that overlapping siblings that might actually
be in the way are not taken into account by this method - to account for these, be in the way are not taken into account by this method - to account for these,
@@ -764,7 +853,7 @@ public:
/** Returns the component at a certain point within this one. /** Returns the component at a certain point within this one.
@param position the co-ordinates to test, relative to this component's top-left.
@param position the coordinate to test, relative to this component's top-left.
@returns the component that is at this position - which may be 0, this component, @returns the component that is at this position - which may be 0, this component,
or one of its children. Note that overlapping siblings that might actually or one of its children. Note that overlapping siblings that might actually
be in the way are not taken into account by this method - to account for these, be in the way are not taken into account by this method - to account for these,
@@ -1613,8 +1702,7 @@ public:
static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw(); static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw();
/** Returns the mouse's current position, relative to this component. /** Returns the mouse's current position, relative to this component.
The co-ordinates are relative to the component's top-left corner.
The return value is relative to the component's top-left corner.
*/ */
const Point<int> getMouseXYRelative() const; const Point<int> getMouseXYRelative() const;
@@ -2033,6 +2121,7 @@ private:
String componentName_; String componentName_;
Component* parentComponent_; Component* parentComponent_;
Rectangle<int> bounds_; Rectangle<int> bounds_;
ScopedPointer <AffineTransform> affineTransform_;
Array <Component*> childComponentList_; Array <Component*> childComponentList_;
LookAndFeel* lookAndFeel_; LookAndFeel* lookAndFeel_;
MouseCursor cursor_; MouseCursor cursor_;
@@ -2099,6 +2188,7 @@ private:
void internalHierarchyChanged(); void internalHierarchyChanged();
void paintComponentAndChildren (Graphics& g); void paintComponentAndChildren (Graphics& g);
void paintComponent (Graphics& g); void paintComponent (Graphics& g);
void paintTransformedChild (Graphics& g);
void sendMovedResizedMessages (bool wasMoved, bool wasResized); void sendMovedResizedMessages (bool wasMoved, bool wasResized);
void repaintParent(); void repaintParent();
void sendFakeMouseMove() const; void sendFakeMouseMove() const;


+ 1
- 1
src/gui/components/menus/juce_MenuBarComponent.cpp View File

@@ -127,7 +127,7 @@ int MenuBarComponent::getItemAt (const int x, const int y)
{ {
for (int i = 0; i < xPositions.size(); ++i) for (int i = 0; i < xPositions.size(); ++i)
if (x >= xPositions[i] && x < xPositions[i + 1]) if (x >= xPositions[i] && x < xPositions[i + 1])
return reallyContains (x, y, true) ? i : -1;
return reallyContains (Point<int> (x, y), true) ? i : -1;
return -1; return -1;
} }


+ 5
- 5
src/gui/components/menus/juce_PopupMenu.cpp View File

@@ -522,7 +522,7 @@ public:
// comp that we're attached to. // comp that we're attached to.
const Point<int> mousePos (componentAttachedTo->getMouseXYRelative()); const Point<int> mousePos (componentAttachedTo->getMouseXYRelative());
if (componentAttachedTo->reallyContains (mousePos.getX(), mousePos.getY(), true))
if (componentAttachedTo->reallyContains (mousePos, true))
{ {
postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously postCommandMessage (PopupMenuSettings::dismissCommandId); // dismiss asynchrounously
return; return;
@@ -567,7 +567,7 @@ public:
const uint32 now = Time::getMillisecondCounter(); const uint32 now = Time::getMillisecondCounter();
if (now > timeEnteredCurrentChildComp + 100 if (now > timeEnteredCurrentChildComp + 100
&& reallyContains (localMousePos.getX(), localMousePos.getY(), true)
&& reallyContains (localMousePos, true)
&& currentChild != 0 && currentChild != 0
&& (! disableMouseMoves) && (! disableMouseMoves)
&& ! (activeSubMenu != 0 && activeSubMenu->isVisible())) && ! (activeSubMenu != 0 && activeSubMenu->isVisible()))
@@ -659,7 +659,7 @@ public:
else if (wasDown && now > menuCreationTime + 250 else if (wasDown && now > menuCreationTime + 250
&& ! (isDown || overScrollArea)) && ! (isDown || overScrollArea))
{ {
isOver = reallyContains (localMousePos.getX(), localMousePos.getY(), true);
isOver = reallyContains (localMousePos, true);
if (isOver) if (isOver)
{ {
@@ -734,7 +734,7 @@ private:
void updateMouseOverStatus (const Point<int>& globalMousePos) void updateMouseOverStatus (const Point<int>& globalMousePos)
{ {
const Point<int> relPos (getLocalPoint (0, globalMousePos)); const Point<int> relPos (getLocalPoint (0, globalMousePos));
isOver = reallyContains (relPos.getX(), relPos.getY(), true);
isOver = reallyContains (relPos, true);
if (activeSubMenu != 0) if (activeSubMenu != 0)
activeSubMenu->updateMouseOverStatus (globalMousePos); activeSubMenu->updateMouseOverStatus (globalMousePos);
@@ -1081,7 +1081,7 @@ private:
void highlightItemUnderMouse (const Point<int>& globalMousePos, const Point<int>& localMousePos) void highlightItemUnderMouse (const Point<int>& globalMousePos, const Point<int>& localMousePos)
{ {
isOver = reallyContains (localMousePos.getX(), localMousePos.getY(), true);
isOver = reallyContains (localMousePos, true);
if (isOver) if (isOver)
hasBeenOver = true; hasBeenOver = true;


+ 1
- 1
src/gui/components/mouse/juce_MouseHoverDetector.cpp View File

@@ -76,7 +76,7 @@ void MouseHoverDetector::hoverTimerCallback()
{ {
const Point<int> pos (source->getMouseXYRelative()); const Point<int> pos (source->getMouseXYRelative());
if (source->reallyContains (pos.getX(), pos.getY(), false))
if (source->reallyContains (pos, false))
{ {
hasJustHovered = true; hasJustHovered = true;
mouseHovered (pos.getX(), pos.getY()); mouseHovered (pos.getX(), pos.getY());


+ 1
- 1
src/gui/components/special/juce_MidiKeyboardComponent.cpp View File

@@ -244,7 +244,7 @@ const uint8 MidiKeyboardComponent::blackNotes[] = { 1, 3, 6, 8, 10 };
int MidiKeyboardComponent::xyToNote (const Point<int>& pos, float& mousePositionVelocity) int MidiKeyboardComponent::xyToNote (const Point<int>& pos, float& mousePositionVelocity)
{ {
if (! reallyContains (pos.getX(), pos.getY(), false))
if (! reallyContains (pos, false))
return -1; return -1;
Point<int> p (pos); Point<int> p (pos);


Loading…
Cancel
Save