| @@ -337,8 +337,7 @@ private: | |||
| if (svgDrawable != 0) | |||
| { | |||
| // to make our icon the right size, we'll put it inside a DrawableComposite, and | |||
| // set its bounding box to the size and position that we want. | |||
| // to make our icon the right size, we'll set its bounding box to the size and position that we want. | |||
| svgDrawable->setBoundingBox (RelativeParallelogram (Point<float> (-100, -100), | |||
| Point<float> (100, -100), | |||
| Point<float> (-100, 100))); | |||
| @@ -1408,7 +1408,7 @@ public: | |||
| void sliderValueChanged (Slider*) | |||
| { | |||
| // When you move the roation slider, we'll apply a rotaion transform to the whole tabs component.. | |||
| // When you move the rotation 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)); | |||
| } | |||
| @@ -62,7 +62,7 @@ AsyncUpdater::~AsyncUpdater() | |||
| // pending on the main event thread - that's pretty dodgy threading, as the callback could | |||
| // happen after this destructor has finished. You should either use a MessageManagerLock while | |||
| // deleting this object, or find some other way to avoid such a race condition. | |||
| jassert (/*(! isUpdatePending()) ||*/ MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | |||
| jassert ((! isUpdatePending()) || MessageManager::getInstance()->currentThreadHasLockedMessageManager()); | |||
| pendingMessage = 0; | |||
| } | |||
| @@ -60,10 +60,7 @@ MessageManager::~MessageManager() throw() | |||
| doPlatformSpecificShutdown(); | |||
| /* If you hit this assertion, then you've probably leaked some kind of MessageListener object. | |||
| This could also be caused by leaking AsyncUpdaters, ChangeBroadcasters, and various other types | |||
| of event class. | |||
| */ | |||
| // If you hit this assertion, then you've probably leaked some kind of MessageListener object.. | |||
| jassert (messageListeners.size() == 0); | |||
| jassert (instance == this); | |||
| @@ -1197,6 +1197,10 @@ bool Component::isTransformed() const throw() | |||
| void Component::setTransform (const AffineTransform& newTransform) | |||
| { | |||
| // If you pass in a transform with no inverse, the component will have no dimensions, | |||
| // and there will be all sorts of maths errors when converting coordinates. | |||
| jassert (! newTransform.isSingularity()); | |||
| if (newTransform.isIdentity()) | |||
| { | |||
| if (affineTransform_ != 0) | |||
| @@ -1204,6 +1208,8 @@ void Component::setTransform (const AffineTransform& newTransform) | |||
| repaint(); | |||
| affineTransform_ = 0; | |||
| repaint(); | |||
| sendMovedResizedMessages (false, false); | |||
| } | |||
| } | |||
| else if (affineTransform_ == 0) | |||
| @@ -1211,12 +1217,14 @@ void Component::setTransform (const AffineTransform& newTransform) | |||
| repaint(); | |||
| affineTransform_ = new AffineTransform (newTransform); | |||
| repaint(); | |||
| sendMovedResizedMessages (false, false); | |||
| } | |||
| else if (*affineTransform_ != newTransform) | |||
| { | |||
| repaint(); | |||
| *affineTransform_ = newTransform; | |||
| repaint(); | |||
| sendMovedResizedMessages (false, false); | |||
| } | |||
| } | |||
| @@ -2064,6 +2072,12 @@ const Rectangle<int> Component::getLocalBounds() const throw() | |||
| return Rectangle<int> (getWidth(), getHeight()); | |||
| } | |||
| const Rectangle<int> Component::getBoundsInParent() const throw() | |||
| { | |||
| return affineTransform_ == 0 ? bounds_ | |||
| : bounds_.toFloat().transformed (*affineTransform_).getSmallestIntegerContainer(); | |||
| } | |||
| void Component::getVisibleArea (RectangleList& result, const bool includeSiblings) const | |||
| { | |||
| result.clear(); | |||
| @@ -318,6 +318,15 @@ public: | |||
| */ | |||
| const Rectangle<int> getLocalBounds() const throw(); | |||
| /** Returns the area of this component's parent which this component covers. | |||
| The returned area is relative to the parent's coordinate space. | |||
| If the component has an affine transform specified, then the resulting area will be | |||
| the smallest rectangle that fully covers the component's transformed bounding box. | |||
| If this component has no parent, the return value will simply be the same as getBounds(). | |||
| */ | |||
| const Rectangle<int> getBoundsInParent() const throw(); | |||
| /** Returns the region of this component that's not obscured by other, opaque components. | |||
| The RectangleList that is returned represents the area of this component | |||
| @@ -1291,7 +1300,18 @@ public: | |||
| */ | |||
| virtual void enablementChanged(); | |||
| /** Changes the transparency of this component. | |||
| When painted, the entire component and all its children will be rendered | |||
| with this as the overall opacity level, where 0 is completely invisible, and | |||
| 1.0 is fully opaque (i.e. normal). | |||
| @see getAlpha | |||
| */ | |||
| void setAlpha (float newAlpha); | |||
| /** Returns the component's current transparancy level. | |||
| See setAlpha() for more details. | |||
| */ | |||
| float getAlpha() const; | |||
| //============================================================================== | |||
| @@ -215,8 +215,8 @@ void MenuBarComponent::showMenu (int index) | |||
| const Rectangle<int> itemPos (xPositions [index], 0, xPositions [index + 1] - xPositions [index], getHeight()); | |||
| m.showMenu (itemPos + getScreenPosition(), | |||
| 0, itemPos.getWidth(), 0, 0, true, this, | |||
| m.showMenu (localAreaToGlobal (itemPos), | |||
| 0, itemPos.getWidth(), 0, 0, this, | |||
| new AsyncCallback (this, index)); | |||
| } | |||
| } | |||
| @@ -1467,7 +1467,6 @@ int PopupMenu::showMenu (const Rectangle<int>& target, | |||
| const int minimumWidth, | |||
| const int maximumNumColumns, | |||
| const int standardItemHeight, | |||
| const bool alignToRectangle, | |||
| Component* const componentAttachedTo, | |||
| ModalComponentManager::Callback* userCallback) | |||
| { | |||
| @@ -1482,7 +1481,7 @@ int PopupMenu::showMenu (const Rectangle<int>& target, | |||
| callback->component = Window::create (*this, ModifierKeys::getCurrentModifiers().isAnyMouseButtonDown(), | |||
| 0, target, minimumWidth, maximumNumColumns > 0 ? maximumNumColumns : 7, | |||
| standardItemHeight, alignToRectangle, itemIdThatMustBeVisible, | |||
| standardItemHeight, ! target.isEmpty(), itemIdThatMustBeVisible, | |||
| &callback->managerOfChosenCommand, componentAttachedTo); | |||
| if (callback->component == 0) | |||
| @@ -1518,23 +1517,20 @@ int PopupMenu::show (const int itemIdThatMustBeVisible, | |||
| const int standardItemHeight, | |||
| ModalComponentManager::Callback* callback) | |||
| { | |||
| const Point<int> mousePos (Desktop::getMousePosition()); | |||
| return showAt (mousePos.getX(), mousePos.getY(), | |||
| itemIdThatMustBeVisible, | |||
| minimumWidth, maximumNumColumns, | |||
| standardItemHeight, callback); | |||
| return showMenu (Rectangle<int>().withPosition (Desktop::getMousePosition()), | |||
| itemIdThatMustBeVisible, minimumWidth, maximumNumColumns, | |||
| standardItemHeight, 0, callback); | |||
| } | |||
| int PopupMenu::showAt (const int screenX, const int screenY, | |||
| int PopupMenu::showAt (const Rectangle<int>& screenAreaToAttachTo, | |||
| const int itemIdThatMustBeVisible, | |||
| const int minimumWidth, const int maximumNumColumns, | |||
| const int standardItemHeight, | |||
| ModalComponentManager::Callback* callback) | |||
| { | |||
| return showMenu (Rectangle<int> (screenX, screenY, 1, 1), | |||
| return showMenu (screenAreaToAttachTo, | |||
| itemIdThatMustBeVisible, minimumWidth, maximumNumColumns, | |||
| standardItemHeight, false, 0, callback); | |||
| standardItemHeight, 0, callback); | |||
| } | |||
| int PopupMenu::showAt (Component* componentToAttachTo, | |||
| @@ -1546,16 +1542,12 @@ int PopupMenu::showAt (Component* componentToAttachTo, | |||
| if (componentToAttachTo != 0) | |||
| { | |||
| return showMenu (componentToAttachTo->getScreenBounds(), | |||
| itemIdThatMustBeVisible, | |||
| minimumWidth, | |||
| maximumNumColumns, | |||
| standardItemHeight, | |||
| true, componentToAttachTo, callback); | |||
| itemIdThatMustBeVisible, minimumWidth, maximumNumColumns, | |||
| standardItemHeight, componentToAttachTo, callback); | |||
| } | |||
| else | |||
| { | |||
| return show (itemIdThatMustBeVisible, | |||
| minimumWidth, maximumNumColumns, | |||
| return show (itemIdThatMustBeVisible, minimumWidth, maximumNumColumns, | |||
| standardItemHeight, callback); | |||
| } | |||
| } | |||
| @@ -260,14 +260,15 @@ public: | |||
| This is the same as show(), but uses a specific location (in global screen | |||
| co-ordinates) rather than the current mouse position. | |||
| Note that the co-ordinates don't specify the top-left of the menu - they | |||
| indicate a point of interest, and the menu will position itself nearby to | |||
| this point, trying to keep it fully on-screen. | |||
| The screenAreaToAttachTo parameter indicates a screen area to which the menu | |||
| will be adjacent. Depending on where this is, the menu will decide which edge to | |||
| attach itself to, in order to fit itself fully on-screen. If you just want to | |||
| trigger a menu at a specific point, you can pass in a rectangle of size (0, 0) | |||
| with the position that you want. | |||
| @see show() | |||
| */ | |||
| int showAt (int screenX, | |||
| int screenY, | |||
| int showAt (const Rectangle<int>& screenAreaToAttachTo, | |||
| int itemIdThatMustBeVisible = 0, | |||
| int minimumWidth = 0, | |||
| int maximumNumColumns = 0, | |||
| @@ -403,14 +404,9 @@ private: | |||
| void addSeparatorIfPending(); | |||
| int showMenu (const Rectangle<int>& target, | |||
| int itemIdThatMustBeVisible, | |||
| int minimumWidth, | |||
| int maximumNumColumns, | |||
| int standardItemHeight, | |||
| bool alignToRectangle, | |||
| Component* componentAttachedTo, | |||
| ModalComponentManager::Callback* callback); | |||
| int showMenu (const Rectangle<int>& target, int itemIdThatMustBeVisible, | |||
| int minimumWidth, int maximumNumColumns, int standardItemHeight, | |||
| Component* componentAttachedTo, ModalComponentManager::Callback* callback); | |||
| }; | |||
| #endif // __JUCE_POPUPMENU_JUCEHEADER__ | |||
| @@ -76,6 +76,12 @@ ResizableWindow::ResizableWindow (const String& name, | |||
| ResizableWindow::~ResizableWindow() | |||
| { | |||
| // Don't delete or remove the resizer components yourself! They're managed by the | |||
| // ResizableWindow, and you should leave them alone! You may have deleted them | |||
| // accidentally by careless use of deleteAllChildren()..? | |||
| jassert (resizableCorner == 0 || getIndexOfChildComponent (resizableCorner) >= 0); | |||
| jassert (resizableBorder == 0 || getIndexOfChildComponent (resizableBorder) >= 0); | |||
| resizableCorner = 0; | |||
| resizableBorder = 0; | |||
| contentComponent.deleteAndZero(); | |||
| @@ -32,37 +32,21 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| AffineTransform::AffineTransform() throw() | |||
| : mat00 (1.0f), | |||
| mat01 (0), | |||
| mat02 (0), | |||
| mat10 (0), | |||
| mat11 (1.0f), | |||
| mat12 (0) | |||
| : mat00 (1.0f), mat01 (0), mat02 (0), | |||
| mat10 (0), mat11 (1.0f), mat12 (0) | |||
| { | |||
| } | |||
| AffineTransform::AffineTransform (const AffineTransform& other) throw() | |||
| : mat00 (other.mat00), | |||
| mat01 (other.mat01), | |||
| mat02 (other.mat02), | |||
| mat10 (other.mat10), | |||
| mat11 (other.mat11), | |||
| mat12 (other.mat12) | |||
| : mat00 (other.mat00), mat01 (other.mat01), mat02 (other.mat02), | |||
| mat10 (other.mat10), mat11 (other.mat11), mat12 (other.mat12) | |||
| { | |||
| } | |||
| AffineTransform::AffineTransform (const float mat00_, | |||
| const float mat01_, | |||
| const float mat02_, | |||
| const float mat10_, | |||
| const float mat11_, | |||
| const float mat12_) throw() | |||
| : mat00 (mat00_), | |||
| mat01 (mat01_), | |||
| mat02 (mat02_), | |||
| mat10 (mat10_), | |||
| mat11 (mat11_), | |||
| mat12 (mat12_) | |||
| AffineTransform::AffineTransform (const float mat00_, const float mat01_, const float mat02_, | |||
| const float mat10_, const float mat11_, const float mat12_) throw() | |||
| : mat00 (mat00_), mat01 (mat01_), mat02 (mat02_), | |||
| mat10 (mat10_), mat11 (mat11_), mat12 (mat12_) | |||
| { | |||
| } | |||
| @@ -117,31 +101,13 @@ const AffineTransform AffineTransform::followedBy (const AffineTransform& other) | |||
| other.mat10 * mat02 + other.mat11 * mat12 + other.mat12); | |||
| } | |||
| const AffineTransform AffineTransform::followedBy (const float omat00, | |||
| const float omat01, | |||
| const float omat02, | |||
| const float omat10, | |||
| const float omat11, | |||
| const float omat12) const throw() | |||
| { | |||
| return AffineTransform (omat00 * mat00 + omat01 * mat10, | |||
| omat00 * mat01 + omat01 * mat11, | |||
| omat00 * mat02 + omat01 * mat12 + omat02, | |||
| omat10 * mat00 + omat11 * mat10, | |||
| omat10 * mat01 + omat11 * mat11, | |||
| omat10 * mat02 + omat11 * mat12 + omat12); | |||
| } | |||
| //============================================================================== | |||
| const AffineTransform AffineTransform::translated (const float dx, | |||
| const float dy) const throw() | |||
| const AffineTransform AffineTransform::translated (const float dx, const float dy) const throw() | |||
| { | |||
| return AffineTransform (mat00, mat01, mat02 + dx, | |||
| mat10, mat11, mat12 + dy); | |||
| } | |||
| const AffineTransform AffineTransform::translation (const float dx, | |||
| const float dy) throw() | |||
| const AffineTransform AffineTransform::translation (const float dx, const float dy) throw() | |||
| { | |||
| return AffineTransform (1.0f, 0, dx, | |||
| 0, 1.0f, dy); | |||
| @@ -152,8 +118,12 @@ const AffineTransform AffineTransform::rotated (const float rad) const throw() | |||
| const float cosRad = std::cos (rad); | |||
| const float sinRad = std::sin (rad); | |||
| return followedBy (cosRad, -sinRad, 0, | |||
| sinRad, cosRad, 0); | |||
| return AffineTransform (cosRad * mat00 + -sinRad * mat10, | |||
| cosRad * mat01 + -sinRad * mat11, | |||
| cosRad * mat02 + -sinRad * mat12, | |||
| sinRad * mat00 + cosRad * mat10, | |||
| sinRad * mat01 + cosRad * mat11, | |||
| sinRad * mat02 + cosRad * mat12); | |||
| } | |||
| const AffineTransform AffineTransform::rotation (const float rad) throw() | |||
| @@ -165,33 +135,27 @@ const AffineTransform AffineTransform::rotation (const float rad) throw() | |||
| sinRad, cosRad, 0); | |||
| } | |||
| const AffineTransform AffineTransform::rotated (const float angle, | |||
| const float pivotX, | |||
| const float pivotY) const throw() | |||
| const AffineTransform AffineTransform::rotation (const float rad, const float pivotX, const float pivotY) throw() | |||
| { | |||
| return translated (-pivotX, -pivotY) | |||
| .rotated (angle) | |||
| .translated (pivotX, pivotY); | |||
| const float cosRad = std::cos (rad); | |||
| const float sinRad = std::sin (rad); | |||
| return AffineTransform (cosRad, -sinRad, -cosRad * pivotX + sinRad * pivotY + pivotX, | |||
| sinRad, cosRad, -sinRad * pivotX + -cosRad * pivotY + pivotY); | |||
| } | |||
| const AffineTransform AffineTransform::rotation (const float angle, | |||
| const float pivotX, | |||
| const float pivotY) throw() | |||
| const AffineTransform AffineTransform::rotated (const float angle, const float pivotX, const float pivotY) const throw() | |||
| { | |||
| return translation (-pivotX, -pivotY) | |||
| .rotated (angle) | |||
| .translated (pivotX, pivotY); | |||
| return followedBy (rotation (angle, pivotX, pivotY)); | |||
| } | |||
| const AffineTransform AffineTransform::scaled (const float factorX, | |||
| const float factorY) const throw() | |||
| const AffineTransform AffineTransform::scaled (const float factorX, const float factorY) const throw() | |||
| { | |||
| return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02, | |||
| factorY * mat10, factorY * mat11, factorY * mat12); | |||
| } | |||
| const AffineTransform AffineTransform::scale (const float factorX, | |||
| const float factorY) throw() | |||
| const AffineTransform AffineTransform::scale (const float factorX, const float factorY) throw() | |||
| { | |||
| return AffineTransform (factorX, 0, 0, | |||
| 0, factorY, 0); | |||
| @@ -200,9 +164,8 @@ const AffineTransform AffineTransform::scale (const float factorX, | |||
| const AffineTransform AffineTransform::scaled (const float factorX, const float factorY, | |||
| const float pivotX, const float pivotY) const throw() | |||
| { | |||
| return translated (-pivotX, -pivotY) | |||
| .scaled (factorX, factorY) | |||
| .translated (pivotX, pivotY); | |||
| return AffineTransform (factorX * mat00, factorX * mat01, factorX * mat02 + pivotX * (1.0f - factorX), | |||
| factorY * mat10, factorY * mat11, factorY * mat12 + pivotY * (1.0f - factorY)); | |||
| } | |||
| const AffineTransform AffineTransform::scale (const float factorX, const float factorY, | |||
| @@ -212,11 +175,20 @@ const AffineTransform AffineTransform::scale (const float factorX, const float f | |||
| 0, factorY, pivotY * (1.0f - factorY)); | |||
| } | |||
| const AffineTransform AffineTransform::sheared (const float shearX, | |||
| const float shearY) const throw() | |||
| const AffineTransform AffineTransform::shear (float shearX, float shearY) throw() | |||
| { | |||
| return AffineTransform (1.0f, shearX, 0, | |||
| shearY, 1.0f, 0); | |||
| } | |||
| const AffineTransform AffineTransform::sheared (const float shearX, const float shearY) const throw() | |||
| { | |||
| return followedBy (1.0f, shearX, 0, | |||
| shearY, 1.0f, 0); | |||
| return AffineTransform (mat00 + shearX * mat10, | |||
| mat01 + shearX * mat11, | |||
| mat02 + shearX * mat12, | |||
| shearY * mat00 + mat10, | |||
| shearY * mat01 + mat11, | |||
| shearY * mat02 + mat12); | |||
| } | |||
| const AffineTransform AffineTransform::inverted() const throw() | |||
| @@ -178,11 +178,12 @@ public: | |||
| float pivotX, float pivotY) throw(); | |||
| /** Returns a transform which is the same as this one followed by a shear. | |||
| The shear is centred around the origin (0, 0). | |||
| */ | |||
| const AffineTransform sheared (float shearX, | |||
| float shearY) const throw(); | |||
| const AffineTransform sheared (float shearX, float shearY) const throw(); | |||
| /** Returns a shear transform, centred around the origin (0, 0). */ | |||
| static const AffineTransform shear (float shearX, float shearY) throw(); | |||
| /** Returns a matrix which is the inverse operation of this one. | |||
| @@ -244,11 +245,6 @@ public: | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| //============================================================================== | |||
| const AffineTransform followedBy (float mat00, float mat01, float mat02, | |||
| float mat10, float mat11, float mat12) const throw(); | |||
| }; | |||
| #endif // __JUCE_AFFINETRANSFORM_JUCEHEADER__ | |||
| @@ -2630,6 +2630,11 @@ void MouseCursor::deleteMouseCursor (void* const cursorHandle, const bool isStan | |||
| DestroyCursor ((HCURSOR) cursorHandle); | |||
| } | |||
| enum | |||
| { | |||
| hiddenMouseCursorHandle = 32500 // (arbitrary non-zero value to mark this type of cursor) | |||
| }; | |||
| void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType type) | |||
| { | |||
| LPCTSTR cursorName = IDC_ARROW; | |||
| @@ -2637,7 +2642,7 @@ void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorT | |||
| switch (type) | |||
| { | |||
| case NormalCursor: break; | |||
| case NoCursor: return 0; | |||
| case NoCursor: return (void*) hiddenMouseCursorHandle; | |||
| case WaitCursor: cursorName = IDC_WAIT; break; | |||
| case IBeamCursor: cursorName = IDC_IBEAM; break; | |||
| case PointingHandCursor: cursorName = MAKEINTRESOURCE(32649); break; | |||
| @@ -2696,6 +2701,8 @@ void MouseCursor::showInWindow (ComponentPeer*) const | |||
| if (c == 0) | |||
| c = LoadCursor (0, IDC_ARROW); | |||
| else if (c == (HCURSOR) hiddenMouseCursorHandle) | |||
| c = 0; | |||
| SetCursor (c); | |||
| } | |||
| @@ -208,6 +208,23 @@ void XmlDocument::skipHeader() | |||
| if (input == 0) | |||
| return; | |||
| #if JUCE_DEBUG | |||
| const String header (found, input - found); | |||
| const String encoding (header.fromFirstOccurrenceOf ("encoding", false, true) | |||
| .fromFirstOccurrenceOf ("=", false, false) | |||
| .fromFirstOccurrenceOf ("\"", false, false) | |||
| .upToFirstOccurrenceOf ("\"", false, false).trim()); | |||
| /* If you load an XML document with a non-UTF encoding type, it may have been | |||
| loaded wrongly.. Since all the files are read via the normal juce file streams, | |||
| they're treated as UTF-8, so by the time it gets to the parser, the encoding will | |||
| have been lost. Best plan is to stick to utf-8 or if you have specific files to | |||
| read, use your own code to convert them to a unicode String, and pass that to the | |||
| XML parser. | |||
| */ | |||
| jassert (encoding.isEmpty() || encoding.startsWithIgnoreCase ("utf-")); | |||
| #endif | |||
| input += 2; | |||
| } | |||