Files
XCEngine/new_editor/app/Platform/Win32/EditorWindowTitleBarInteraction.cpp

262 lines
8.8 KiB
C++

#include "Platform/Win32/EditorWindow.h"
#include "Platform/Win32/EditorWindowConstants.h"
#include <algorithm>
#include <windowsx.h>
namespace XCEngine::UI::Editor::App {
using namespace EditorWindowSupport;
bool EditorWindow::UpdateBorderlessWindowChromeHover(LPARAM lParam) {
if (m_chrome.runtime.GetHoveredBorderlessResizeEdge() !=
Host::BorderlessWindowResizeEdge::None ||
m_chrome.runtime.IsBorderlessResizeActive()) {
const bool changed =
m_chrome.chromeState.hoveredTarget !=
Host::BorderlessWindowChromeHitTarget::None;
m_chrome.chromeState.hoveredTarget =
Host::BorderlessWindowChromeHitTarget::None;
return changed;
}
const Host::BorderlessWindowChromeHitTarget hitTarget =
HitTestBorderlessWindowChrome(lParam);
const Host::BorderlessWindowChromeHitTarget buttonTarget =
hitTarget == Host::BorderlessWindowChromeHitTarget::MinimizeButton ||
hitTarget == Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton ||
hitTarget == Host::BorderlessWindowChromeHitTarget::CloseButton
? hitTarget
: Host::BorderlessWindowChromeHitTarget::None;
if (m_chrome.chromeState.hoveredTarget == buttonTarget) {
return false;
}
m_chrome.chromeState.hoveredTarget = buttonTarget;
return true;
}
bool EditorWindow::HandleBorderlessWindowChromeButtonDown(LPARAM lParam) {
if (m_chrome.runtime.GetHoveredBorderlessResizeEdge() !=
Host::BorderlessWindowResizeEdge::None ||
m_chrome.runtime.IsBorderlessResizeActive()) {
return false;
}
const Host::BorderlessWindowChromeHitTarget hitTarget =
HitTestBorderlessWindowChrome(lParam);
switch (hitTarget) {
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
case Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
case Host::BorderlessWindowChromeHitTarget::CloseButton:
m_chrome.chromeState.pressedTarget = hitTarget;
if (m_window.hwnd != nullptr) {
SetCapture(m_window.hwnd);
}
InvalidateHostWindow();
return true;
case Host::BorderlessWindowChromeHitTarget::DragRegion:
if (m_window.hwnd != nullptr) {
if (IsBorderlessWindowMaximized()) {
POINT screenPoint = {};
if (GetCursorPos(&screenPoint)) {
m_chrome.runtime.BeginBorderlessWindowDragRestore(screenPoint);
SetCapture(m_window.hwnd);
return true;
}
}
ReleaseCapture();
SendMessageW(m_window.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
}
return true;
case Host::BorderlessWindowChromeHitTarget::None:
default:
return false;
}
}
bool EditorWindow::HandleBorderlessWindowChromeButtonUp(
EditorContext& editorContext,
bool globalTabDragActive,
LPARAM lParam) {
if (m_chrome.runtime.IsBorderlessWindowDragRestoreArmed()) {
ClearBorderlessWindowChromeDragRestoreState();
return true;
}
const Host::BorderlessWindowChromeHitTarget pressedTarget =
m_chrome.chromeState.pressedTarget;
if (pressedTarget != Host::BorderlessWindowChromeHitTarget::MinimizeButton &&
pressedTarget != Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton &&
pressedTarget != Host::BorderlessWindowChromeHitTarget::CloseButton) {
return false;
}
const Host::BorderlessWindowChromeHitTarget releasedTarget =
HitTestBorderlessWindowChrome(lParam);
m_chrome.chromeState.pressedTarget =
Host::BorderlessWindowChromeHitTarget::None;
if (GetCapture() == m_window.hwnd) {
ReleaseCapture();
}
InvalidateHostWindow();
if (pressedTarget == releasedTarget) {
ExecuteBorderlessWindowChromeAction(
editorContext,
globalTabDragActive,
pressedTarget);
}
return true;
}
bool EditorWindow::HandleBorderlessWindowChromeDoubleClick(
EditorContext& editorContext,
bool globalTabDragActive,
LPARAM lParam) {
if (m_chrome.runtime.IsBorderlessWindowDragRestoreArmed()) {
ClearBorderlessWindowChromeDragRestoreState();
}
if (HitTestBorderlessWindowChrome(lParam) !=
Host::BorderlessWindowChromeHitTarget::DragRegion) {
return false;
}
ExecuteBorderlessWindowChromeAction(
editorContext,
globalTabDragActive,
Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton);
return true;
}
bool EditorWindow::HandleBorderlessWindowChromeDragRestorePointerMove(
EditorContext& editorContext,
bool globalTabDragActive) {
if (!m_chrome.runtime.IsBorderlessWindowDragRestoreArmed() || m_window.hwnd == nullptr) {
return false;
}
POINT currentScreenPoint = {};
if (!GetCursorPos(&currentScreenPoint)) {
return true;
}
const POINT initialScreenPoint =
m_chrome.runtime.GetBorderlessWindowDragRestoreInitialScreenPoint();
const int dragThresholdX = (std::max)(GetSystemMetrics(SM_CXDRAG), 1);
const int dragThresholdY = (std::max)(GetSystemMetrics(SM_CYDRAG), 1);
const LONG deltaX = currentScreenPoint.x - initialScreenPoint.x;
const LONG deltaY = currentScreenPoint.y - initialScreenPoint.y;
if (std::abs(deltaX) < dragThresholdX &&
std::abs(deltaY) < dragThresholdY) {
return true;
}
RECT restoreRect = {};
RECT currentRect = {};
RECT workAreaRect = {};
if (!m_chrome.runtime.TryGetBorderlessWindowRestoreRect(restoreRect) ||
!QueryCurrentWindowRect(currentRect) ||
!QueryBorderlessWindowWorkAreaRect(workAreaRect)) {
ClearBorderlessWindowChromeDragRestoreState();
return true;
}
const int restoreWidth = restoreRect.right - restoreRect.left;
const int restoreHeight = restoreRect.bottom - restoreRect.top;
const int currentWidth = currentRect.right - currentRect.left;
if (restoreWidth <= 0 || restoreHeight <= 0 || currentWidth <= 0) {
ClearBorderlessWindowChromeDragRestoreState();
return true;
}
const float pointerRatio =
static_cast<float>(currentScreenPoint.x - currentRect.left) /
static_cast<float>(currentWidth);
const float clampedPointerRatio = (std::clamp)(pointerRatio, 0.0f, 1.0f);
const int newLeft =
(std::clamp)(
currentScreenPoint.x -
static_cast<int>(clampedPointerRatio * static_cast<float>(restoreWidth)),
workAreaRect.left,
workAreaRect.right - restoreWidth);
const int titleBarHeightPixels =
static_cast<int>(kBorderlessTitleBarHeightDips * GetDpiScale());
const int newTop =
(std::clamp)(
currentScreenPoint.y - (std::max)(titleBarHeightPixels / 2, 1),
workAreaRect.top,
workAreaRect.bottom - restoreHeight);
const RECT targetRect = {
newLeft,
newTop,
newLeft + restoreWidth,
newTop + restoreHeight
};
m_chrome.runtime.SetBorderlessWindowMaximized(false);
ApplyPredictedWindowRectTransition(
editorContext,
globalTabDragActive,
targetRect);
ClearBorderlessWindowChromeDragRestoreState();
ReleaseCapture();
SendMessageW(m_window.hwnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
return true;
}
void EditorWindow::ClearBorderlessWindowChromeDragRestoreState() {
if (!m_chrome.runtime.IsBorderlessWindowDragRestoreArmed()) {
return;
}
m_chrome.runtime.EndBorderlessWindowDragRestore();
if (GetCapture() == m_window.hwnd) {
ReleaseCapture();
}
}
void EditorWindow::ClearBorderlessWindowChromeState() {
if (m_chrome.chromeState.hoveredTarget ==
Host::BorderlessWindowChromeHitTarget::None &&
m_chrome.chromeState.pressedTarget ==
Host::BorderlessWindowChromeHitTarget::None) {
return;
}
m_chrome.chromeState = {};
InvalidateHostWindow();
}
void EditorWindow::ExecuteBorderlessWindowChromeAction(
EditorContext& editorContext,
bool globalTabDragActive,
Host::BorderlessWindowChromeHitTarget target) {
if (m_window.hwnd == nullptr) {
return;
}
switch (target) {
case Host::BorderlessWindowChromeHitTarget::MinimizeButton:
ShowWindow(m_window.hwnd, SW_MINIMIZE);
break;
case Host::BorderlessWindowChromeHitTarget::MaximizeRestoreButton:
ToggleBorderlessWindowMaximizeRestore(editorContext, globalTabDragActive);
break;
case Host::BorderlessWindowChromeHitTarget::CloseButton:
PostMessageW(m_window.hwnd, WM_CLOSE, 0, 0);
break;
case Host::BorderlessWindowChromeHitTarget::DragRegion:
case Host::BorderlessWindowChromeHitTarget::None:
default:
break;
}
InvalidateHostWindow();
}
} // namespace XCEngine::UI::Editor::App