| @@ -138,6 +138,11 @@ public: | |||
| } | |||
| } | |||
| void mouseMagnify (const MouseEvent&, float zoomFactor) | |||
| { | |||
| owner.sizeSlider->setValue (owner.sizeSlider->getValue() * zoomFactor); | |||
| } | |||
| private: | |||
| RenderingTestComponent& owner; | |||
| double averageTime; | |||
| @@ -151,13 +156,13 @@ private: | |||
| float speeds[8]; | |||
| Time lastSVGLoadTime; | |||
| const AffineTransform getTransform() | |||
| AffineTransform getTransform() | |||
| { | |||
| return AffineTransform::rotation ((float) owner.angleSlider->getValue() / (180.0f / float_Pi)) | |||
| .scaled ((float) owner.sizeSlider->getValue(), | |||
| (float) owner.sizeSlider->getValue()) | |||
| .translated (getWidth() / 2 + (float) owner.xSlider->getValue(), | |||
| getHeight() / 2 + (float) owner.ySlider->getValue()); | |||
| .scaled ((float) owner.sizeSlider->getValue(), | |||
| (float) owner.sizeSlider->getValue()) | |||
| .translated (getWidth() / 2 + (float) owner.xSlider->getValue(), | |||
| getHeight() / 2 + (float) owner.ySlider->getValue()); | |||
| } | |||
| void clipToRectangle (Graphics& g) | |||
| @@ -2151,6 +2151,12 @@ void Component::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wh | |||
| parentComponent->mouseWheelMove (e.getEventRelativeTo (parentComponent), wheel); | |||
| } | |||
| void Component::mouseMagnify (const MouseEvent& e, float magnifyAmount) | |||
| { | |||
| // the base class just passes this event up to its parent.. | |||
| if (parentComponent != nullptr) | |||
| parentComponent->mouseMagnify (e.getEventRelativeTo (parentComponent), magnifyAmount); | |||
| } | |||
| //============================================================================== | |||
| void Component::resized() {} | |||
| @@ -2477,6 +2483,18 @@ void Component::internalMouseWheel (MouseInputSource& source, const Point<int>& | |||
| } | |||
| } | |||
| void Component::internalMagnifyGesture (MouseInputSource& source, const Point<int>& relativePos, | |||
| const Time& time, float amount) | |||
| { | |||
| if (! isCurrentlyBlockedByAnotherModalComponent()) | |||
| { | |||
| const MouseEvent me (source, relativePos, source.getCurrentModifiers(), | |||
| this, this, time, relativePos, time, 0, false); | |||
| mouseMagnify (me, amount); | |||
| } | |||
| } | |||
| void Component::sendFakeMouseMove() const | |||
| { | |||
| MouseInputSource& mainMouse = Desktop::getInstance().getMainMouseSource(); | |||
| @@ -1559,6 +1559,18 @@ public: | |||
| virtual void mouseWheelMove (const MouseEvent& event, | |||
| const MouseWheelDetails& wheel); | |||
| /** Called when a pinch-to-zoom mouse-gesture is used. | |||
| If not overridden, a component will forward this message to its parent, so | |||
| that parent components can collect gesture messages that are unused by child | |||
| components. | |||
| @param scaleFactor a multiplier to indicate by how much the size of the target | |||
| should be changed. A value of 1.0 would indicate no change, | |||
| values greater than 1.0 mean it should be enlarged. | |||
| */ | |||
| virtual void mouseMagnify (const MouseEvent& event, float scaleFactor); | |||
| //============================================================================== | |||
| /** Ensures that a non-stop stream of mouse-drag events will be sent during the | |||
| current mouse-drag operation. | |||
| @@ -2281,6 +2293,7 @@ private: | |||
| void internalMouseDrag (MouseInputSource&, const Point<int>&, const Time&); | |||
| void internalMouseMove (MouseInputSource&, const Point<int>&, const Time&); | |||
| void internalMouseWheel (MouseInputSource&, const Point<int>&, const Time&, const MouseWheelDetails&); | |||
| void internalMagnifyGesture (MouseInputSource&, const Point<int>&, const Time&, float); | |||
| void internalBroughtToFront(); | |||
| void internalFocusGain (const FocusChangeType, const WeakReference<Component>&); | |||
| void internalFocusGain (const FocusChangeType); | |||
| @@ -82,48 +82,62 @@ public: | |||
| } | |||
| //============================================================================== | |||
| #if JUCE_DUMP_MOUSE_EVENTS | |||
| #define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " desc << " #" << source.getIndex() \ | |||
| << ": " << comp->getLocalPoint (nullptr, screenPos).toString() \ | |||
| << " - Comp: " << String::toHexString ((int) comp)); | |||
| #else | |||
| #define JUCE_MOUSE_EVENT_DBG(desc) | |||
| #endif | |||
| void sendMouseEnter (Component* const comp, const Point<int>& screenPos, const Time& time) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " enter: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("enter") | |||
| comp->internalMouseEnter (source, comp->getLocalPoint (nullptr, screenPos), time); | |||
| } | |||
| void sendMouseExit (Component* const comp, const Point<int>& screenPos, const Time& time) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " exit: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("exit") | |||
| comp->internalMouseExit (source, comp->getLocalPoint (nullptr, screenPos), time); | |||
| } | |||
| void sendMouseMove (Component* const comp, const Point<int>& screenPos, const Time& time) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " move: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("move") | |||
| comp->internalMouseMove (source, comp->getLocalPoint (nullptr, screenPos), time); | |||
| } | |||
| void sendMouseDown (Component* const comp, const Point<int>& screenPos, const Time& time) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " down: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("down") | |||
| comp->internalMouseDown (source, comp->getLocalPoint (nullptr, screenPos), time); | |||
| } | |||
| void sendMouseDrag (Component* const comp, const Point<int>& screenPos, const Time& time) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " drag: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("drag") | |||
| comp->internalMouseDrag (source, comp->getLocalPoint (nullptr, screenPos), time); | |||
| } | |||
| void sendMouseUp (Component* const comp, const Point<int>& screenPos, const Time& time, const ModifierKeys& oldMods) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " up: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("up") | |||
| comp->internalMouseUp (source, comp->getLocalPoint (nullptr, screenPos), time, oldMods); | |||
| } | |||
| void sendMouseWheel (Component* const comp, const Point<int>& screenPos, const Time& time, const MouseWheelDetails& wheel) | |||
| { | |||
| //DBG ("Mouse " + String (source.getIndex()) + " wheel: " + comp->getLocalPoint (nullptr, screenPos).toString() + " - Comp: " + String::toHexString ((int) comp)); | |||
| JUCE_MOUSE_EVENT_DBG ("wheel") | |||
| comp->internalMouseWheel (source, comp->getLocalPoint (nullptr, screenPos), time, wheel); | |||
| } | |||
| void sendMagnifyGesture (Component* const comp, const Point<int>& screenPos, const Time& time, const float amount) | |||
| { | |||
| JUCE_MOUSE_EVENT_DBG ("magnify") | |||
| comp->internalMagnifyGesture (source, comp->getLocalPoint (nullptr, screenPos), time, amount); | |||
| } | |||
| //============================================================================== | |||
| // (returns true if the button change caused a modal event loop) | |||
| bool setButtons (const Point<int>& screenPos, const Time& time, const ModifierKeys& newButtonState) | |||
| @@ -276,24 +290,37 @@ public: | |||
| } | |||
| } | |||
| void handleWheel (ComponentPeer* const peer, const Point<int>& positionWithinPeer, | |||
| const Time& time, const MouseWheelDetails& wheel) | |||
| Component* getTargetForGesture (ComponentPeer* const peer, const Point<int>& positionWithinPeer, | |||
| const Time& time, Point<int>& screenPos) | |||
| { | |||
| jassert (peer != nullptr); | |||
| lastTime = time; | |||
| ++mouseEventCounter; | |||
| Desktop::getInstance().incrementMouseWheelCounter(); | |||
| const Point<int> screenPos (peer->localToGlobal (positionWithinPeer)); | |||
| screenPos = peer->localToGlobal (positionWithinPeer); | |||
| setPeer (peer, screenPos, time); | |||
| setScreenPos (screenPos, time, false); | |||
| triggerFakeMove(); | |||
| if (! isDragging()) | |||
| { | |||
| if (Component* current = getComponentUnderMouse()) | |||
| sendMouseWheel (current, screenPos, time, wheel); | |||
| } | |||
| return isDragging() ? nullptr : getComponentUnderMouse(); | |||
| } | |||
| void handleWheel (ComponentPeer* const peer, const Point<int>& positionWithinPeer, | |||
| const Time& time, const MouseWheelDetails& wheel) | |||
| { | |||
| Desktop::getInstance().incrementMouseWheelCounter(); | |||
| Point<int> screenPos; | |||
| if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos)) | |||
| sendMouseWheel (current, screenPos, time, wheel); | |||
| } | |||
| void handleMagnifyGesture (ComponentPeer* const peer, const Point<int>& positionWithinPeer, | |||
| const Time& time, const float scaleFactor) | |||
| { | |||
| Point<int> screenPos; | |||
| if (Component* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos)) | |||
| sendMagnifyGesture (current, screenPos, time, scaleFactor); | |||
| } | |||
| //============================================================================== | |||
| @@ -518,3 +545,9 @@ void MouseInputSource::handleWheel (ComponentPeer* const peer, const Point<int>& | |||
| { | |||
| pimpl->handleWheel (peer, positionWithinPeer, Time (time), wheel); | |||
| } | |||
| void MouseInputSource::handleMagnifyGesture (ComponentPeer* const peer, const Point<int>& positionWithinPeer, | |||
| const int64 time, const float scaleFactor) | |||
| { | |||
| pimpl->handleMagnifyGesture (peer, positionWithinPeer, Time (time), scaleFactor); | |||
| } | |||
| @@ -166,9 +166,11 @@ public: | |||
| //============================================================================== | |||
| /** @internal */ | |||
| void handleEvent (ComponentPeer*, const Point<int>& positionWithinPeer, int64 time, const ModifierKeys&); | |||
| void handleEvent (ComponentPeer*, const Point<int>&, int64 time, const ModifierKeys&); | |||
| /** @internal */ | |||
| void handleWheel (ComponentPeer*, const Point<int>& positionWithinPeer, int64 time, const MouseWheelDetails&); | |||
| void handleWheel (ComponentPeer*, const Point<int>&, int64 time, const MouseWheelDetails&); | |||
| /** @internal */ | |||
| void handleMagnifyGesture (ComponentPeer*, const Point<int>&, int64 time, float scaleFactor); | |||
| private: | |||
| //============================================================================== | |||
| @@ -626,6 +626,14 @@ public: | |||
| handleMouseWheel (0, getMousePos (ev, view), getMouseTime (ev), wheel); | |||
| } | |||
| void redirectMagnify (NSEvent* ev) | |||
| { | |||
| const float invScale = 1.0f - [ev magnification]; | |||
| if (invScale != 0.0f) | |||
| handleMagnifyGesture (0, getMousePos (ev, view), getMouseTime (ev), 1.0f / invScale); | |||
| } | |||
| void sendMouseEvent (NSEvent* ev) | |||
| { | |||
| updateModifiers (ev); | |||
| @@ -1347,6 +1355,7 @@ struct JuceNSViewClass : public ObjCClass <NSView> | |||
| addMethod (@selector (otherMouseDragged:), mouseDragged, "v@:@"); | |||
| addMethod (@selector (otherMouseUp:), mouseUp, "v@:@"); | |||
| addMethod (@selector (scrollWheel:), scrollWheel, "v@:@"); | |||
| addMethod (@selector (magnifyWithEvent:), magnify, "v@:@"); | |||
| addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@"); | |||
| addMethod (@selector (frameChanged:), frameChanged, "v@:@"); | |||
| addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow, "v@:"); | |||
| @@ -1425,6 +1434,7 @@ private: | |||
| static void mouseEntered (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseEnter (ev); } | |||
| static void mouseExited (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseExit (ev); } | |||
| static void scrollWheel (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseWheel (ev); } | |||
| static void magnify (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMagnify (ev); } | |||
| static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; } | |||
| @@ -77,8 +77,9 @@ bool Desktop::canUseSemiTransparentWindows() noexcept | |||
| #define TOUCHEVENTF_DOWN 0x0002 | |||
| #define TOUCHEVENTF_UP 0x0004 | |||
| DECLARE_HANDLE (HTOUCHINPUT); | |||
| DECLARE_HANDLE (HGESTUREINFO); | |||
| typedef struct tagTOUCHINPUT | |||
| struct TOUCHINPUT | |||
| { | |||
| LONG x; | |||
| LONG y; | |||
| @@ -90,16 +91,32 @@ bool Desktop::canUseSemiTransparentWindows() noexcept | |||
| ULONG_PTR dwExtraInfo; | |||
| DWORD cxContact; | |||
| DWORD cyContact; | |||
| } TOUCHINPUT, *PTOUCHINPUT; | |||
| }; | |||
| struct GESTUREINFO | |||
| { | |||
| UINT cbSize; | |||
| DWORD dwFlags; | |||
| DWORD dwID; | |||
| HWND hwndTarget; | |||
| POINTS ptsLocation; | |||
| DWORD dwInstanceID; | |||
| DWORD dwSequenceID; | |||
| ULONGLONG ullArguments; | |||
| UINT cbExtraArgs; | |||
| }; | |||
| #endif | |||
| typedef BOOL (WINAPI* RegisterTouchWindowFunc) (HWND, ULONG); | |||
| typedef BOOL (WINAPI* GetTouchInputInfoFunc) (HTOUCHINPUT, UINT, PTOUCHINPUT, int); | |||
| typedef BOOL (WINAPI* GetTouchInputInfoFunc) (HTOUCHINPUT, UINT, TOUCHINPUT*, int); | |||
| typedef BOOL (WINAPI* CloseTouchInputHandleFunc) (HTOUCHINPUT); | |||
| typedef BOOL (WINAPI* GetGestureInfoFunc) (HGESTUREINFO, GESTUREINFO*); | |||
| static RegisterTouchWindowFunc registerTouchWindow = nullptr; | |||
| static GetTouchInputInfoFunc getTouchInputInfo = nullptr; | |||
| static CloseTouchInputHandleFunc closeTouchInputHandle = nullptr; | |||
| static GetGestureInfoFunc getGestureInfo = nullptr; | |||
| static bool hasCheckedForMultiTouch = false; | |||
| @@ -112,6 +129,7 @@ static bool canUseMultiTouch() | |||
| registerTouchWindow = (RegisterTouchWindowFunc) getUser32Function ("RegisterTouchWindow"); | |||
| getTouchInputInfo = (GetTouchInputInfoFunc) getUser32Function ("GetTouchInputInfo"); | |||
| closeTouchInputHandle = (CloseTouchInputHandleFunc) getUser32Function ("CloseTouchInputHandle"); | |||
| getGestureInfo = (GetGestureInfoFunc) getUser32Function ("GetGestureInfo"); | |||
| } | |||
| return registerTouchWindow != nullptr; | |||
| @@ -473,6 +491,7 @@ public: | |||
| parentToAddTo (parent), | |||
| currentRenderingEngine (softwareRenderingEngine), | |||
| lastPaintTime (0), | |||
| lastMagnifySize (0), | |||
| fullScreen (false), | |||
| isDragging (false), | |||
| isMouseOver (false), | |||
| @@ -1070,6 +1089,7 @@ private: | |||
| ScopedPointer<Direct2DLowLevelGraphicsContext> direct2DContext; | |||
| #endif | |||
| uint32 lastPaintTime; | |||
| ULONGLONG lastMagnifySize; | |||
| bool fullScreen, isDragging, isMouseOver, hasCreatedCaret, constrainerIsResizing; | |||
| BorderSize<int> windowBorder; | |||
| HICON currentWindowIcon; | |||
| @@ -1690,10 +1710,9 @@ private: | |||
| doMouseEvent (getCurrentMousePos()); | |||
| } | |||
| void doMouseWheel (const Point<int>& globalPos, const WPARAM wParam, const bool isVertical) | |||
| ComponentPeer* findPeerUnderMouse (Point<int>& localPos) | |||
| { | |||
| updateKeyModifiers(); | |||
| const float amount = jlimit (-1000.0f, 1000.0f, 0.5f * (short) HIWORD (wParam)); | |||
| const Point<int> globalPos (getCurrentMousePosGlobal()); | |||
| // Because Windows stupidly sends all wheel events to the window with the keyboard | |||
| // focus, we have to redirect them here according to the mouse pos.. | |||
| @@ -1703,13 +1722,60 @@ private: | |||
| if (peer == nullptr) | |||
| peer = this; | |||
| localPos = peer->globalToLocal (globalPos); | |||
| return peer; | |||
| } | |||
| void doMouseWheel (const WPARAM wParam, const bool isVertical) | |||
| { | |||
| updateKeyModifiers(); | |||
| const float amount = jlimit (-1000.0f, 1000.0f, 0.5f * (short) HIWORD (wParam)); | |||
| MouseWheelDetails wheel; | |||
| wheel.deltaX = isVertical ? 0.0f : amount / -256.0f; | |||
| wheel.deltaY = isVertical ? amount / 256.0f : 0.0f; | |||
| wheel.isReversed = false; | |||
| wheel.isSmooth = false; | |||
| peer->handleMouseWheel (0, peer->globalToLocal (globalPos), getMouseEventTime(), wheel); | |||
| Point<int> localPos; | |||
| if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) | |||
| peer->handleMouseWheel (0, localPos, getMouseEventTime(), wheel); | |||
| } | |||
| bool doGestureEvent (LPARAM lParam) | |||
| { | |||
| GESTUREINFO gi; | |||
| zerostruct (gi); | |||
| gi.cbSize = sizeof (gi); | |||
| if (getGestureInfo != nullptr && getGestureInfo ((HGESTUREINFO) lParam, &gi)) | |||
| { | |||
| updateKeyModifiers(); | |||
| Point<int> localPos; | |||
| if (ComponentPeer* const peer = findPeerUnderMouse (localPos)) | |||
| { | |||
| switch (gi.dwID) | |||
| { | |||
| case 3: /*GID_ZOOM*/ | |||
| if (gi.dwFlags != 1 /*GF_BEGIN*/ && lastMagnifySize > 0) | |||
| peer->handleMagnifyGesture (0, localPos, getMouseEventTime(), | |||
| (float) (gi.ullArguments / (double) lastMagnifySize)); | |||
| lastMagnifySize = gi.ullArguments; | |||
| return true; | |||
| case 4: /*GID_PAN*/ | |||
| case 5: /*GID_ROTATE*/ | |||
| case 6: /*GID_TWOFINGERTAP*/ | |||
| case 7: /*GID_PRESSANDTAP*/ | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void doTouchEvent (const int numInputs, HTOUCHINPUT eventHandle) | |||
| @@ -2226,7 +2292,7 @@ private: | |||
| case 0x020A: /* WM_MOUSEWHEEL */ | |||
| case 0x020E: /* WM_MOUSEHWHEEL */ | |||
| doMouseWheel (getCurrentMousePosGlobal(), wParam, message == 0x020A); | |||
| doMouseWheel (wParam, message == 0x020A); | |||
| return 0; | |||
| case WM_TOUCH: | |||
| @@ -2236,6 +2302,12 @@ private: | |||
| doTouchEvent ((int) wParam, (HTOUCHINPUT) lParam); | |||
| return 0; | |||
| case 0x119: /* WM_GESTURE */ | |||
| if (doGestureEvent (lParam)) | |||
| return 0; | |||
| break; | |||
| //============================================================================== | |||
| case WM_SIZING: return handleSizeConstraining (*(RECT*) lParam, wParam); | |||
| case WM_WINDOWPOSCHANGING: return handlePositionChanging (*(WINDOWPOS*) lParam); | |||
| @@ -113,6 +113,13 @@ void ComponentPeer::handleMouseWheel (const int touchIndex, const Point<int>& po | |||
| mouse->handleWheel (this, positionWithinPeer, time, wheel); | |||
| } | |||
| void ComponentPeer::handleMagnifyGesture (const int touchIndex, const Point<int>& positionWithinPeer, | |||
| const int64 time, const float scaleFactor) | |||
| { | |||
| if (MouseInputSource* mouse = getOrCreateMouseInputSource (touchIndex)) | |||
| mouse->handleMagnifyGesture (this, positionWithinPeer, time, scaleFactor); | |||
| } | |||
| //============================================================================== | |||
| void ComponentPeer::handlePaint (LowLevelGraphicsContext& contextToPaintTo) | |||
| { | |||
| @@ -315,6 +315,7 @@ public: | |||
| //============================================================================== | |||
| void handleMouseEvent (int touchIndex, const Point<int>& positionWithinPeer, const ModifierKeys& newMods, int64 time); | |||
| void handleMouseWheel (int touchIndex, const Point<int>& positionWithinPeer, int64 time, const MouseWheelDetails&); | |||
| void handleMagnifyGesture (int touchIndex, const Point<int>& positionWithinPeer, int64 time, float scaleFactor); | |||
| void handleUserClosingWindow(); | |||