diff --git a/AltSnap.dni b/AltSnap.dni index 76650740..406892cc 100644 Binary files a/AltSnap.dni and b/AltSnap.dni differ diff --git a/Lang/_en_US baseline.txt b/Lang/_en_US baseline.txt index c7f9ef85..4f366828 100644 Binary files a/Lang/_en_US baseline.txt and b/Lang/_en_US baseline.txt differ diff --git a/Lang/de_DE.ini b/Lang/de_DE.ini index 156ba8ba..ce84617c 100644 Binary files a/Lang/de_DE.ini and b/Lang/de_DE.ini differ diff --git a/config.c b/config.c index 9a5ef088..c9a164a3 100644 --- a/config.c +++ b/config.c @@ -1189,6 +1189,11 @@ INT_PTR CALLBACK KeyboardPageDialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR {TEXT("FocusT"), L10NIDX(input_actions_focust) }, {TEXT("FocusR"), L10NIDX(input_actions_focusr) }, {TEXT("FocusB"), L10NIDX(input_actions_focusb) }, + + {TEXT("SwapL"), L10NIDX(input_actions_swapl) }, + {TEXT("SwapT"), L10NIDX(input_actions_swapt) }, + {TEXT("SwapR"), L10NIDX(input_actions_swapr) }, + {TEXT("SwapB"), L10NIDX(input_actions_swapb) }, {NULL, 0} }; diff --git a/hooks.c b/hooks.c index 92640e7c..3da49edb 100644 --- a/hooks.c +++ b/hooks.c @@ -199,6 +199,9 @@ static struct config { UCHAR MenuShowOffscreenWin; UCHAR MenuShowEmptyLabelWin; UCHAR IgnoreMinMaxInfo; + UCHAR SwapAnimationSteps; + UCHAR SwapAnimationDelay; + UCHAR SwapAnimateResize; // [Performance] UCHAR FullWin; UCHAR TransWinOpacity; @@ -310,6 +313,9 @@ static const struct OptionListItem Advanced_uchars[] = { { "MenuShowOffscreenWin", 0 }, { "MenuShowEmptyLabelWin", 0 }, { "IgnoreMinMaxInfo", 0 }, + { "SwapAnimationSteps", 10 }, + { "SwapAnimationDelay", 5 }, + { "SwapAnimateResize", 0 }, }; // [Performance] static const struct OptionListItem Performance_uchars[] = { @@ -2453,6 +2459,36 @@ static void SetForegroundWindowL(HWND hwnd) PostMessage(state.mdiclient, WM_MDIACTIVATE, (WPARAM)hwnd, 0); } } +// Swaps the position/size of the two specified windows +static void SwapWindows(HWND hwnd1, HWND hwnd2) +{ + if (!hwnd1 || !hwnd2) return; + + RECT rc1, rc2; + if (!GetWindowRect(hwnd1, &rc1) || !GetWindowRect(hwnd2, &rc2)) return; + + if (conf.SwapAnimationSteps > 0) { + float steps = (float)conf.SwapAnimationSteps; + float dleft = (rc2.left - rc1.left) / steps; + float dtop = (rc2.top - rc1.top) / steps; + + float dwidth = 0.0; + float dheight = 0.0; + if (conf.SwapAnimateResize) { + dwidth = (rc2.right - rc2.left - rc1.right + rc1.left) / steps; + dheight = (rc2.bottom - rc2.top - rc1.bottom + rc1.top) / steps; + } + + for (int i = 0; i < conf.SwapAnimationSteps; i++) { + SetWindowPos(hwnd1, NULL, rc1.left + i*dleft, rc1.top + i*dtop, rc1.right - rc1.left + i*dwidth, rc1.bottom - rc1.top + i*dheight, SWP_NOZORDER | SWP_NOACTIVATE); + SetWindowPos(hwnd2, NULL, rc2.left - i*dleft, rc2.top - i*dtop, rc2.right - rc2.left - i*dwidth, rc2.bottom - rc2.top - i*dheight, SWP_NOZORDER | SWP_NOACTIVATE); + Sleep(conf.SwapAnimationDelay); + } + } + + SetWindowPos(hwnd2, NULL, rc1.left, rc1.top, rc1.right-rc1.left, rc1.bottom-rc1.top, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOACTIVATE|SWP_ASYNCWINDOWPOS); + SetWindowPos(hwnd1, NULL, rc2.left, rc2.top, rc2.right-rc2.left, rc2.bottom-rc2.top, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_ASYNCWINDOWPOS); +} // Returns true if AltDrag must be disabled based on scroll lock // If conf.ScrollLockState&2 then Altdrag is disabled by Scroll Lock // otherwise it is enabled by Scroll lock. @@ -4762,6 +4798,10 @@ static void SClickActions(HWND hwnd, enum action action) case AC_FOCUST: ReallySetForegroundWindow(FindTiledWindow(hwnd, 1)); break; case AC_FOCUSR: ReallySetForegroundWindow(FindTiledWindow(hwnd, 2)); break; case AC_FOCUSB: ReallySetForegroundWindow(FindTiledWindow(hwnd, 3)); break; + case AC_SWAPL: SwapWindows(hwnd, FindTiledWindow(hwnd, 0)); break; + case AC_SWAPT: SwapWindows(hwnd, FindTiledWindow(hwnd, 1)); break; + case AC_SWAPR: SwapWindows(hwnd, FindTiledWindow(hwnd, 2)); break; + case AC_SWAPB: SwapWindows(hwnd, FindTiledWindow(hwnd, 3)); break; case AC_ASONOFF: ActionASOnOff(); break; case AC_MOVEONOFF: ActionMoveOnOff(hwnd); break; diff --git a/hooks.h b/hooks.h index 39314fa7..5a7eda0a 100644 --- a/hooks.h +++ b/hooks.h @@ -143,7 +143,12 @@ ACVALUE(AC_ZOOM, "Zoom", MR) \ ACVALUE(AC_ZOOM2, "Zoom2", MR) \ ACVALUE(AC_NPSTACKED, "NPStacked", ZO) \ - ACVALUE(AC_NPSTACKED2, "NPStacked2", ZO) + ACVALUE(AC_NPSTACKED2, "NPStacked2", ZO) \ + \ + ACVALUE(AC_SWAPL, "SwapL", MR) \ + ACVALUE(AC_SWAPT, "SwapT", MR) \ + ACVALUE(AC_SWAPR, "SwapR", MR) \ + ACVALUE(AC_SWAPB, "SwapB", MR) #define ACVALUE(a, b, c) a, enum action { ACTION_MAP AC_MAXVALUE, AC_SHRT0, AC_SHRTF=AC_SHRT0+36, AC_ORICLICK }; diff --git a/languages.h b/languages.h index b7025e8c..0c89303b 100644 --- a/languages.h +++ b/languages.h @@ -181,6 +181,11 @@ struct strings { TCHAR *input_actions_focusr; TCHAR *input_actions_focusb; + TCHAR *input_actions_swapl; + TCHAR *input_actions_swapt; + TCHAR *input_actions_swapr; + TCHAR *input_actions_swapb; + TCHAR *input_actions_roll; TCHAR *input_actions_alwaysontop; TCHAR *input_actions_borderless; @@ -421,6 +426,10 @@ static const char* l10n_inimapping[] = { "InputActionFocusT", "InputActionFocusR", "InputActionFocusB", + "InputActionSwapL", + "InputActionSwapT", + "InputActionSwapR", + "InputActionSwapB", "InputActionRoll", "InputActionAlwaysOnTop", "InputActionBorderless", @@ -664,6 +673,10 @@ static const struct strings en_US = { /* focust */ TEXT("Focus top window"), /* focusr */ TEXT("Focus right window"), /* focusb */ TEXT("Focus bottom window"), + /* swapl */ TEXT("Swap with left window"), + /* swapt */ TEXT("Swap with top window"), + /* swapr */ TEXT("Swap with right window"), + /* swapb */ TEXT("Swap with bottom window"), /* roll */ TEXT("&Roll/Unroll window"), /* alwaysontop */ TEXT("Toggle always on &top"), /* borderless */ TEXT("Toggle &borderless"),