From 6c9b3990480d96469b08b741fc36ac8b5c6d93a2 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Wed, 3 Nov 2021 09:11:55 -0500 Subject: [PATCH] some cleanup. Try only hovering the actually hovered button --- .../TerminalApp/MinMaxCloseControl.cpp | 58 ++++++++++++++++- src/cascadia/TerminalApp/MinMaxCloseControl.h | 4 ++ .../TerminalApp/MinMaxCloseControl.idl | 4 ++ src/cascadia/TerminalApp/TitlebarControl.cpp | 14 ++++ src/cascadia/TerminalApp/TitlebarControl.h | 6 +- src/cascadia/TerminalApp/TitlebarControl.idl | 11 ++++ .../WindowsTerminal/NonClientIslandWindow.cpp | 64 +++++++++++++------ .../WindowsTerminal/NonClientIslandWindow.h | 1 + 8 files changed, 137 insertions(+), 25 deletions(-) diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp index 0072b2093..b20868a8f 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.cpp +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. +// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. // // MinMaxCloseControl.xaml.cpp @@ -95,4 +95,60 @@ namespace winrt::TerminalApp::implementation break; } } + + void MinMaxCloseControl::HoverButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + VisualStateManager::GoToState(MinimizeButton(), L"PointerOver", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Maximize: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"PointerOver", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"PointerOver", false); + break; + } + } + void MinMaxCloseControl::PressButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + VisualStateManager::GoToState(MinimizeButton(), L"Pressed", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Maximize: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Pressed", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Pressed", false); + break; + } + } + void MinMaxCloseControl::ReleaseButton(CaptionButton button) + { + switch (button) + { + case CaptionButton::Minimize: + case CaptionButton::Maximize: + case CaptionButton::Close: + VisualStateManager::GoToState(MinimizeButton(), L"Normal", false); + VisualStateManager::GoToState(MaximizeButton(), L"Normal", false); + VisualStateManager::GoToState(CloseButton(), L"Normal", false); + break; + } + } } diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.h b/src/cascadia/TerminalApp/MinMaxCloseControl.h index 0a8d66654..ab8e34c76 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.h +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.h @@ -20,6 +20,10 @@ namespace winrt::TerminalApp::implementation void SetWindowVisualState(WindowVisualState visualState); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + void _MinimizeClick(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); void _MaximizeClick(winrt::Windows::Foundation::IInspectable const& sender, diff --git a/src/cascadia/TerminalApp/MinMaxCloseControl.idl b/src/cascadia/TerminalApp/MinMaxCloseControl.idl index eb8fbd16e..91356743b 100644 --- a/src/cascadia/TerminalApp/MinMaxCloseControl.idl +++ b/src/cascadia/TerminalApp/MinMaxCloseControl.idl @@ -11,6 +11,10 @@ namespace TerminalApp void SetWindowVisualState(WindowVisualState visualState); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + event Windows.Foundation.TypedEventHandler MinimizeClick; event Windows.Foundation.TypedEventHandler MaximizeClick; event Windows.Foundation.TypedEventHandler CloseClick; diff --git a/src/cascadia/TerminalApp/TitlebarControl.cpp b/src/cascadia/TerminalApp/TitlebarControl.cpp index 14fcdb898..61ceeae4a 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.cpp +++ b/src/cascadia/TerminalApp/TitlebarControl.cpp @@ -103,4 +103,18 @@ namespace winrt::TerminalApp::implementation { MinMaxCloseControl().SetWindowVisualState(visualState); } + + void TitlebarControl::HoverButton(CaptionButton button) + { + MinMaxCloseControl().HoverButton(button); + } + void TitlebarControl::PressButton(CaptionButton button) + { + MinMaxCloseControl().PressButton(button); + } + void TitlebarControl::ReleaseButton(CaptionButton button) + { + MinMaxCloseControl().ReleaseButton(button); + } + } diff --git a/src/cascadia/TerminalApp/TitlebarControl.h b/src/cascadia/TerminalApp/TitlebarControl.h index 342b59c2c..6695e7471 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.h +++ b/src/cascadia/TerminalApp/TitlebarControl.h @@ -6,9 +6,6 @@ #pragma once -#include "winrt/Windows.UI.Xaml.h" -#include "winrt/Windows.UI.Xaml.Markup.h" -#include "winrt/Windows.UI.Xaml.Interop.h" #include "TitlebarControl.g.h" namespace winrt::TerminalApp::implementation @@ -19,6 +16,9 @@ namespace winrt::TerminalApp::implementation void MaxButtonEntered(); void MaxButtonExited(); + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); IInspectable Content(); void Content(IInspectable content); diff --git a/src/cascadia/TerminalApp/TitlebarControl.idl b/src/cascadia/TerminalApp/TitlebarControl.idl index 6b9892a42..515055fcb 100644 --- a/src/cascadia/TerminalApp/TitlebarControl.idl +++ b/src/cascadia/TerminalApp/TitlebarControl.idl @@ -10,10 +10,21 @@ namespace TerminalApp WindowVisualStateIconified }; + enum CaptionButton { + Minimize, + Maximize, + Close + }; + [default_interface] runtimeclass TitlebarControl : Windows.UI.Xaml.Controls.Grid { TitlebarControl(UInt64 parentWindowHandle); void SetWindowVisualState(WindowVisualState visualState); + + void HoverButton(CaptionButton button); + void PressButton(CaptionButton button); + void ReleaseButton(CaptionButton button); + void MaxButtonEntered(); void MaxButtonExited(); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp index 86b70973f..b98ea3840 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp @@ -87,6 +87,30 @@ void NonClientIslandWindow::MakeWindow() noexcept THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow); } +LRESULT NonClientIslandWindow::_dragBarNcHitTest(const til::point& pointer) +{ + RECT rcParent = GetWindowRect(); + // Consider the entire caption control area (rough estimate) to be the maximize button + // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, + // I just didn't duplicate it here. + // TODO! this 130 shouldn't be hardcoded + // TODO! other buttons too + if ((rcParent.right - pointer.x()) < 130) + { + return HTMAXBUTTON; + } + else + { + // If we're not on a caption button, then check if we're on the top + // border. If we're not on the top border, then we're just generally in + // the caption area. + const auto resizeBorderHeight = _GetResizeHandleHeight(); + const auto isOnResizeBorder = pointer.y() < rcParent.top + resizeBorderHeight; + + return isOnResizeBorder ? HTTOP : HTCAPTION; + } +} + // Function Description: // - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks. LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept @@ -95,47 +119,44 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR { case WM_NCHITTEST: { - RECT rcParent = GetWindowRect(); - // Consider the entire caption control area (rough estimate) to be the maximize button - // TODO: Should consider drag distance also. This is considered in the parent window's nc hittest handler, - // I just didn't duplicate it here. - if ((rcParent.right - GET_X_LPARAM(lparam)) < 130) - { - return HTMAXBUTTON; - } - else - { - RECT rcWindow; - winrt::check_bool(::GetWindowRect(_window.get(), &rcWindow)); + til::point pointer{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) }; - const auto resizeBorderHeight = _GetResizeHandleHeight(); - const auto isOnResizeBorder = GET_Y_LPARAM(lparam) < rcWindow.top + resizeBorderHeight; - - return isOnResizeBorder ? HTTOP : HTCAPTION; - } + return _dragBarNcHitTest(pointer); } break; case WM_NCMOUSEMOVE: // Communicate state to the title bar control so that it can update its visuals. + // TODO! other buttons too if (wparam == HTMAXBUTTON) { - _titlebar.MaxButtonEntered(); + _titlebar.HoverButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.MaxButtonEntered(); } else { - _titlebar.MaxButtonExited(); + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); + // _titlebar.MaxButtonExited(); } break; case WM_NCMOUSELEAVE: case WM_MOUSELEAVE: - _titlebar.MaxButtonExited(); + // _titlebar.MaxButtonExited(); + _titlebar.ReleaseButton(winrt::TerminalApp::CaptionButton::Maximize); break; // NB: *Shouldn't be forwarding these* when they're not over the caption because they can inadvertently take action using the system's default metrics instead of our own. case WM_NCLBUTTONDOWN: case WM_NCLBUTTONDBLCLK: + switch (wparam) + { + case HTMAXBUTTON: + _titlebar.PressButton(winrt::TerminalApp::CaptionButton::Maximize); + break; + } + return 0; + // TODO!: I think we only want WM_NCLBUTTONUP case WM_NCLBUTTONUP: switch (wparam) { @@ -153,6 +174,7 @@ LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPAR case HTCLOSE: // Forward along to the button state machine. // As a proof of concept just locally handle the maximize button. + // TODO! if ((wparam == HTMAXBUTTON) && (message == WM_NCLBUTTONUP)) { ShowWindow(GetHandle(), SW_MAXIMIZE); @@ -310,7 +332,7 @@ RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{ 0.0f, 0.0f, - static_cast(/*_dragBar*/_rootGrid.ActualWidth()), + static_cast(/*_dragBar*/ _rootGrid.ActualWidth()), static_cast(_dragBar.ActualHeight()) }; const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect); diff --git a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h index cae2bc0da..ac8e7f29c 100644 --- a/src/cascadia/WindowsTerminal/NonClientIslandWindow.h +++ b/src/cascadia/WindowsTerminal/NonClientIslandWindow.h @@ -71,6 +71,7 @@ private: int _GetResizeHandleHeight() const noexcept; RECT _GetDragAreaRect() const noexcept; int _GetTopBorderHeight() const noexcept; + LRESULT _dragBarNcHitTest(const til::point& pointer); [[nodiscard]] LRESULT _OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept override; [[nodiscard]] LRESULT _OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept;