From 9f1aca35afff2a82f46b1188f679ce07d65e8962 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 26 Nov 2010 21:36:45 +0000 Subject: [PATCH] Implemented Humdinger's resizing method, activated on Cmd-Ctrl-middle-click. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39656 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/DefaultWindowBehaviour.cpp | 226 ++++++++++++++------- src/servers/app/DefaultWindowBehaviour.h | 7 +- 2 files changed, 161 insertions(+), 72 deletions(-) diff --git a/src/servers/app/DefaultWindowBehaviour.cpp b/src/servers/app/DefaultWindowBehaviour.cpp index 77c6042d34..2266753453 100644 --- a/src/servers/app/DefaultWindowBehaviour.cpp +++ b/src/servers/app/DefaultWindowBehaviour.cpp @@ -668,53 +668,10 @@ private: float y = (where.y - (frame.top + frame.bottom) / 2) / (frame.Height() + 1); - // compute the angle - if (x == 0 && y == 0) - return; - - float angle = atan2f(y, x); - - // rotate by 22.5 degree to align our sectors with 45 degree multiples - angle += M_PI / 8; - - // add 180 degree to the negative values, so we get a nice 0 to 360 - // degree range - if (angle < 0) - angle += M_PI * 2; - - int8 horizontal = NONE; - int8 vertical = NONE; - switch (int(angle / M_PI_4)) { - case 0: - horizontal = RIGHT; - break; - case 1: - horizontal = RIGHT; - vertical = BOTTOM; - break; - case 2: - vertical = BOTTOM; - break; - case 3: - horizontal = LEFT; - vertical = BOTTOM; - break; - case 4: - horizontal = LEFT; - break; - case 5: - horizontal = LEFT; - vertical = TOP; - break; - case 6: - vertical = TOP; - break; - case 7: - default: - horizontal = RIGHT; - vertical = TOP; - break; - } + // compute the resize direction + int8 horizontal; + int8 vertical; + _ComputeResizeDirection(x, y, horizontal, vertical); // update the highlight, if necessary if (horizontal != fHorizontal || vertical != fVertical) { @@ -732,6 +689,68 @@ private: }; +// #pragma mark - State + + +struct DefaultWindowBehaviour::HumdingerResizeState : State { + HumdingerResizeState(DefaultWindowBehaviour& behavior, BPoint where) + : + State(behavior), + fInitialMousePosition(where), + fJitterPhase(true) + { + } + + virtual void EnterState(State* previousState) + { + fDesktop->SetManagementCursor( + fDesktop->GetCursorManager().GetCursor(B_CURSOR_ID_MOVE)); + } + + virtual void ExitState(State* nextState) + { + fBehavior._ResetResizeCursor(); + } + + virtual void MouseUp(BMessage* message, BPoint where) + { + // Leave the state, when the middle mouse button has been released. + int32 buttons = message->FindInt32("buttons"); + if ((buttons & B_TERTIARY_MOUSE_BUTTON) == 0) + fBehavior._NextState(NULL); + } + + virtual void MouseMoved(BMessage* message, BPoint where, bool isFake) + { + // ignore the initial movement + float dx = where.x - fInitialMousePosition.x; + float dy = where.y - fInitialMousePosition.y; + if (dx * dx + dy * dy < (fJitterPhase ? 16 : 64)) + return; + + // Enter the next phase, if we're still in the first one. + if (fJitterPhase) { + fInitialMousePosition = where; + fJitterPhase = false; + return; + } + + // The mouse has moved far enough for us to take a guess in which + // direction. + int8 horizontal; + int8 vertical; + _ComputeResizeDirection(dx, dy, horizontal, vertical); + + fBehavior._NextState(new (std::nothrow) ResizeBorderState(fBehavior, + where, horizontal, vertical)); + } + +private: + BPoint fInitialMousePosition; + bool fJitterPhase; +}; + + // #pragma mark - DefaultWindowBehaviour @@ -870,6 +889,11 @@ DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where, default: break; } + } else if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0) { + // Middle-click anywhere on the window shall initiate + // humdinger-resize mode. + if (windowModifier && hitRegion != Decorator::REGION_NONE) + action = ACTION_HUMDINGER_RESIZE; } } @@ -939,6 +963,11 @@ DefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where, STRACE_CLICK(("===> ACTION_RESIZE_BORDER\n")); break; + case ACTION_HUMDINGER_RESIZE: + _NextState(new (std::nothrow) HumdingerResizeState(*this, where)); + STRACE_CLICK(("===> ACTION_HUMDINGER_RESIZE\n")); + break; + default: break; } @@ -1096,30 +1125,6 @@ DefaultWindowBehaviour::_SetBorderHighlights(int8 horizontal, int8 vertical, } -void -DefaultWindowBehaviour::_NextState(State* state) -{ - // exit the old state - if (fState != NULL) - fState->ExitState(state); - - // set and enter the new state - State* oldState = fState; - fState = state; - - if (fState != NULL) { - fState->EnterState(oldState); - fDesktop->SetMouseEventWindow(fWindow); - } else if (oldState != NULL) { - // no state anymore -- reset the mouse event window, if it's still us - if (fDesktop->MouseEventWindow() == fWindow) - fDesktop->SetMouseEventWindow(NULL); - } - - delete oldState; -} - - ServerCursor* DefaultWindowBehaviour::_ResizeCursorFor(int8 horizontal, int8 vertical) { @@ -1163,3 +1168,82 @@ DefaultWindowBehaviour::_ResetResizeCursor() { fDesktop->SetManagementCursor(NULL); } + + +/*static*/ void +DefaultWindowBehaviour::_ComputeResizeDirection(float x, float y, + int8& _horizontal, int8& _vertical) +{ + _horizontal = NONE; + _vertical = NONE; + + // compute the angle + if (x == 0 && y == 0) + return; + + float angle = atan2f(y, x); + + // rotate by 22.5 degree to align our sectors with 45 degree multiples + angle += M_PI / 8; + + // add 180 degree to the negative values, so we get a nice 0 to 360 + // degree range + if (angle < 0) + angle += M_PI * 2; + + switch (int(angle / M_PI_4)) { + case 0: + _horizontal = RIGHT; + break; + case 1: + _horizontal = RIGHT; + _vertical = BOTTOM; + break; + case 2: + _vertical = BOTTOM; + break; + case 3: + _horizontal = LEFT; + _vertical = BOTTOM; + break; + case 4: + _horizontal = LEFT; + break; + case 5: + _horizontal = LEFT; + _vertical = TOP; + break; + case 6: + _vertical = TOP; + break; + case 7: + default: + _horizontal = RIGHT; + _vertical = TOP; + break; + } +} + + +void +DefaultWindowBehaviour::_NextState(State* state) +{ + // exit the old state + if (fState != NULL) + fState->ExitState(state); + + // set and enter the new state + State* oldState = fState; + fState = state; + + if (fState != NULL) { + fState->EnterState(oldState); + fDesktop->SetMouseEventWindow(fWindow); + } else if (oldState != NULL) { + // no state anymore -- reset the mouse event window, if it's still us + if (fDesktop->MouseEventWindow() == fWindow) + fDesktop->SetMouseEventWindow(NULL); + } + + delete oldState; +} diff --git a/src/servers/app/DefaultWindowBehaviour.h b/src/servers/app/DefaultWindowBehaviour.h index c770e30753..b75d95125e 100644 --- a/src/servers/app/DefaultWindowBehaviour.h +++ b/src/servers/app/DefaultWindowBehaviour.h @@ -49,7 +49,8 @@ private: ACTION_DRAG, ACTION_SLIDE_TAB, ACTION_RESIZE, - ACTION_RESIZE_BORDER + ACTION_RESIZE_BORDER, + ACTION_HUMDINGER_RESIZE }; enum { @@ -71,6 +72,7 @@ private: struct ResizeBorderState; struct DecoratorButtonState; struct ManageWindowState; + struct HumdingerResizeState; // to keep gcc 2 happy friend struct State; @@ -81,6 +83,7 @@ private: friend struct ResizeBorderState; friend struct DecoratorButtonState; friend struct ManageWindowState; + friend struct HumdingerResizeState; private: bool _IsWindowModifier(int32 modifiers) const; @@ -94,6 +97,8 @@ private: void _SetResizeCursor(int8 horizontal, int8 vertical); void _ResetResizeCursor(); + static void _ComputeResizeDirection(float x, float y, + int8& _horizontal, int8& _vertical); void _NextState(State* state);