From 62d9766ee02a04279bded25eef84f3d363db9891 Mon Sep 17 00:00:00 2001 From: elasota Date: Sat, 2 May 2020 02:59:19 -0400 Subject: [PATCH] Add close box support to floating windows --- GpApp/Map.cpp | 2 +- PortabilityLayer/PLCore.cpp | 5 +- PortabilityLayer/WindowManager.cpp | 195 +++++++++++++++++++++++++++++ PortabilityLayer/WindowManager.h | 1 + 4 files changed, 200 insertions(+), 3 deletions(-) diff --git a/GpApp/Map.cpp b/GpApp/Map.cpp index c450800..218a049 100644 --- a/GpApp/Map.cpp +++ b/GpApp/Map.cpp @@ -391,7 +391,7 @@ void OpenMapWindow (void) mapRoomsWide * kMapRoomWidth + kMapScrollBarWidth - 1, mapRoomsHigh * kMapRoomHeight + kMapScrollBarWidth - 1); - const uint16_t windowStyle = PortabilityLayer::WindowStyleFlags::kTitleBar | PortabilityLayer::WindowStyleFlags::kResizable | PortabilityLayer::WindowStyleFlags::kMiniBar | PortabilityLayer::WindowStyleFlags::kCloseBox;; + const uint16_t windowStyle = PortabilityLayer::WindowStyleFlags::kTitleBar | PortabilityLayer::WindowStyleFlags::kResizable | PortabilityLayer::WindowStyleFlags::kMiniBar | PortabilityLayer::WindowStyleFlags::kCloseBox; PortabilityLayer::WindowDef wdef = PortabilityLayer::WindowDef::Create(mapWindowRect, windowStyle, false, 0, 0, PSTR("Map")); diff --git a/PortabilityLayer/PLCore.cpp b/PortabilityLayer/PLCore.cpp index 4641548..f190723 100644 --- a/PortabilityLayer/PLCore.cpp +++ b/PortabilityLayer/PLCore.cpp @@ -110,8 +110,9 @@ short FindWindow(Point point, WindowPtr *window) bool TrackGoAway(WindowPtr window, Point point) { - PL_NotYetImplemented(); - return false; + PortabilityLayer::WindowManager *wm = PortabilityLayer::WindowManager::GetInstance(); + + return wm->HandleCloseBoxClick(window, point); } PortabilityLayer::Vec2i TrackResize(WindowPtr window, Point start, uint16_t minWidth, uint16_t minHeight, Rect *size) diff --git a/PortabilityLayer/WindowManager.cpp b/PortabilityLayer/WindowManager.cpp index c972b17..1d0b29f 100644 --- a/PortabilityLayer/WindowManager.cpp +++ b/PortabilityLayer/WindowManager.cpp @@ -32,6 +32,8 @@ namespace PortabilityLayer virtual void GetChromePadding(const WindowImpl *window, uint16_t padding[WindowChromeSides::kCount]) const = 0; virtual void RenderChrome(WindowImpl *window, DrawSurface *surface, WindowChromeSide_t chromeSide) const = 0; virtual bool GetChromeInteractionZone(const WindowImpl *window, const Vec2i &point, RegionID_t &outRegion) const = 0; + virtual bool GetChromeRegionRect(const WindowImpl *window, RegionID_t region, Rect2i &outRect) const = 0; + virtual void UpdateRegionChromeState(const WindowImpl *window, RegionID_t region, const void *data) const = 0; }; template @@ -50,6 +52,8 @@ namespace PortabilityLayer void GetChromePadding(const WindowImpl *window, uint16_t padding[WindowChromeSides::kCount]) const override; void RenderChrome(WindowImpl *window, DrawSurface *surface, WindowChromeSide_t chromeSide) const override; bool GetChromeInteractionZone(const WindowImpl *window, const Vec2i &point, RegionID_t &outRegion) const override; + bool GetChromeRegionRect(const WindowImpl *window, RegionID_t region, Rect2i &outRect) const override; + void UpdateRegionChromeState(const WindowImpl *window, RegionID_t region, const void *data) const override; }; class GenericWindowChromeTheme final : public WindowChromeThemeSingleton @@ -58,6 +62,8 @@ namespace PortabilityLayer void GetChromePadding(const WindowImpl *window, uint16_t padding[WindowChromeSides::kCount]) const override; void RenderChrome(WindowImpl *window, DrawSurface *surface, WindowChromeSide_t chromeSide) const override; bool GetChromeInteractionZone(const WindowImpl *window, const Vec2i &point, RegionID_t &outRegion) const override; + bool GetChromeRegionRect(const WindowImpl *window, RegionID_t region, Rect2i &outRect) const override; + void UpdateRegionChromeState(const WindowImpl *window, RegionID_t region, const void *data) const override; private: void RenderChromeTop(WindowImpl *window, DrawSurface *surface) const; @@ -70,6 +76,10 @@ namespace PortabilityLayer void RenderChromeBottomMini(WindowImpl *window, DrawSurface *surface) const; void RenderChromeRightMini(WindowImpl *window, DrawSurface *surface) const; + static Rect GetCloseBoxRectInTopChrome(); + static Rect GetCloseBoxRectInTopChromeMini(); + + void RenderChromeCloseBox(DrawSurface *surface, const Rect &windowRect, bool isClicked) const; static const int kDarkGray = 85; static const int kMidGray = 187; @@ -97,6 +107,8 @@ namespace PortabilityLayer void GetChromePadding(uint16_t padding[WindowChromeSides::kCount]) const; void GetChromeDimensions(int width, int height, Rect dimensions[WindowChromeSides::kCount]) const; bool GetChromeInteractionZone(const Vec2i &point, RegionID_t &outRegion) const; + bool GetChromeRegionRect(RegionID_t region, Rect2i &outRect) const; + void UpdateRegionChromeState(RegionID_t region, const void *data) const; bool IsBorderless() const; uint16_t GetStyleFlags() const; @@ -130,6 +142,7 @@ namespace PortabilityLayer void FindWindow(const Point &point, Window **outWindow, short *outRegion) const override; void DestroyWindow(Window *window) override; void DragWindow(Window *window, const Point &startPoint, const Rect &constraintRect) override; + bool HandleCloseBoxClick(Window *window, const Point &startPoint) override; void SetWindowTitle(Window *window, const PLPasStr &title) override; Rect2i GetWindowFullRect(Window *window) const override; @@ -188,6 +201,15 @@ namespace PortabilityLayer return false; } + bool SimpleBoxChromeTheme::GetChromeRegionRect(const WindowImpl *window, RegionID_t region, Rect2i &outRect) const + { + return false; + } + + void SimpleBoxChromeTheme::UpdateRegionChromeState(const WindowImpl *window, RegionID_t region, const void *data) const + { + } + void SimpleBoxChromeTheme::RenderChrome(WindowImpl *window, DrawSurface *surface, WindowChromeSide_t chromeSide) const { surface->SetForeColor(StdColors::Black()); @@ -237,6 +259,21 @@ namespace PortabilityLayer { if (point.m_x >= 0 && point.m_x < w && point.m_y < 0 && point.m_y >= -13) { + if (window->GetStyleFlags() & WindowStyleFlags::kCloseBox) + { + uint16_t padding[WindowChromeSides::kCount]; + GetChromePadding(window, padding); + + const Rect closeBoxRect = GetCloseBoxRectInTopChromeMini(); + const Vec2i topChromePos = Vec2i(point.m_x + padding[WindowChromeSides::kLeft], point.m_y + padding[WindowChromeSides::kTop]); + + if (closeBoxRect.Contains(Point::Create(topChromePos.m_x, topChromePos.m_y))) + { + outRegion = RegionIDs::kClose; + return true; + } + } + outRegion = RegionIDs::kTitleBar; return true; } @@ -262,6 +299,45 @@ namespace PortabilityLayer return false; } + bool GenericWindowChromeTheme::GetChromeRegionRect(const WindowImpl *window, RegionID_t region, Rect2i &outRect) const + { + if (region == RegionIDs::kClose) + { + if (window->GetStyleFlags() & WindowStyleFlags::kCloseBox) + { + if (window->GetStyleFlags() & WindowStyleFlags::kMiniBar) + { + uint16_t padding[WindowChromeSides::kCount]; + GetChromePadding(window, padding); + + const Rect closeBoxRect = GetCloseBoxRectInTopChromeMini(); + outRect = Rect2i(closeBoxRect.top - padding[WindowChromeSides::kTop], closeBoxRect.left - padding[WindowChromeSides::kLeft], + closeBoxRect.bottom - padding[WindowChromeSides::kTop], closeBoxRect.right - padding[WindowChromeSides::kLeft]); + return true; + } + } + } + + return false; + } + + void GenericWindowChromeTheme::UpdateRegionChromeState(const WindowImpl *window, RegionID_t region, const void *data) const + { + if (region == RegionIDs::kClose) + { + const bool state = *static_cast(data); + + if (window->GetStyleFlags() & WindowStyleFlags::kCloseBox) + { + if (window->GetStyleFlags() & WindowStyleFlags::kMiniBar) + { + DrawSurface *topChromeSurface = window->GetChromeSurface(WindowChromeSides::kTop); + RenderChromeCloseBox(topChromeSurface, GetCloseBoxRectInTopChromeMini(), state); + } + } + } + } + void GenericWindowChromeTheme::RenderChrome(WindowImpl *window, DrawSurface *surface, WindowChromeSide_t chromeSide) const { if (window->GetStyleFlags() & WindowStyleFlags::kMiniBar) @@ -329,6 +405,9 @@ namespace PortabilityLayer surface->FillRect(Rect::Create(rect.top + 1, rect.left + 1, rect.top + 2, rect.right - 2)); surface->FillRect(Rect::Create(rect.bottom - 1, rect.right - 5, rect.bottom, rect.right - 4)); + if (window->GetStyleFlags() & WindowStyleFlags::kCloseBox) + RenderChromeCloseBox(surface, rect, false); + surface->SetForeColor(StdColors::Black()); surface->SetSystemFont(12, PortabilityLayer::FontFamilyFlags::FontFamilyFlag_Bold); int32_t ascender = surface->MeasureFontAscender(); @@ -427,6 +506,9 @@ namespace PortabilityLayer surface->FillRect(Rect::Create(rect.top + 1, rect.left + 1, rect.bottom - 2, rect.left + 2)); surface->FillRect(Rect::Create(rect.top + 1, rect.left + 1, rect.top + 2, rect.right - 2)); + if (window->GetStyleFlags() & WindowStyleFlags::kCloseBox) + RenderChromeCloseBox(surface, rect, false); + surface->SetForeColor(StdColors::Black()); surface->SetApplicationFont(10, PortabilityLayer::FontFamilyFlags::FontFamilyFlag_Bold); int32_t ascender = surface->MeasureFontAscender(); @@ -464,6 +546,45 @@ namespace PortabilityLayer surface->FillRect(rect); } + Rect GenericWindowChromeTheme::GetCloseBoxRectInTopChrome() + { + return GetCloseBoxRectInTopChromeMini(); // Temp, maybe... I don't think this is ever actually used + } + + Rect GenericWindowChromeTheme::GetCloseBoxRectInTopChromeMini() + { + int boxDimensions = 8; + return Rect::Create(2, 2, 2 + boxDimensions, 2 + boxDimensions); + } + + void GenericWindowChromeTheme::RenderChromeCloseBox(DrawSurface *surface, const Rect &chromeRect, bool isClicked) const + { + const Rect closeBoxRect = GetCloseBoxRectInTopChromeMini(); + + if (isClicked) + { + surface->SetForeColor(StdColors::Black()); + surface->FillRect(closeBoxRect); + + surface->SetForeColor(PortabilityLayer::RGBAColor::Create(kDarkGray, kDarkGray, kDarkGray, 255)); + surface->FillRect(Rect::Create(closeBoxRect.top + 1, closeBoxRect.left + 1, closeBoxRect.bottom - 1, closeBoxRect.right - 1)); + } + else + { + surface->SetForeColor(PortabilityLayer::RGBAColor::Create(kDarkGray, kDarkGray, kDarkGray, 255)); + surface->FillRect(closeBoxRect); + + surface->SetForeColor(PortabilityLayer::RGBAColor::Create(kMidGray, kMidGray, kMidGray, 255)); + surface->FillRect(Rect::Create(closeBoxRect.top + 1, closeBoxRect.left + 1, closeBoxRect.bottom, closeBoxRect.right)); + + surface->SetForeColor(PortabilityLayer::RGBAColor::Create(kDarkGray, kDarkGray, kDarkGray, 255)); + surface->FillRect(Rect::Create(closeBoxRect.top + 2, closeBoxRect.left + 2, closeBoxRect.bottom - 1, closeBoxRect.right - 1)); + + surface->SetForeColor(PortabilityLayer::RGBAColor::Create(kLightGray, kLightGray, kLightGray, 255)); + surface->FillRect(Rect::Create(closeBoxRect.top + 2, closeBoxRect.left + 2, closeBoxRect.bottom - 2, closeBoxRect.right - 2)); + } + } + //--------------------------------------------------------------------------- WindowImpl::WindowImpl() : m_windowAbove(nullptr) @@ -613,6 +734,22 @@ namespace PortabilityLayer return m_chromeTheme->GetChromeInteractionZone(this, point, outRegion); } + bool WindowImpl::GetChromeRegionRect(RegionID_t region, Rect2i &outRect) const + { + if (!m_chromeTheme) + return false; + + return m_chromeTheme->GetChromeRegionRect(this, region, outRect); + } + + void WindowImpl::UpdateRegionChromeState(RegionID_t region, const void *data) const + { + if (!m_chromeTheme) + return; + + m_chromeTheme->UpdateRegionChromeState(this, region, data); + } + bool WindowImpl::IsBorderless() const { return (m_styleFlags & WindowStyleFlags::kBorderless) != 0; @@ -823,6 +960,64 @@ namespace PortabilityLayer } } + bool WindowManagerImpl::HandleCloseBoxClick(Window *window, const Point &startPoint) + { + bool isInBounds = false; + + const Vec2i windowCoord = Vec2i(window->m_wmX, window->m_wmY); + + Rect2i closeBoxRect; + if (!static_cast(window)->GetChromeRegionRect(RegionIDs::kClose, closeBoxRect)) + return false; + + { + const Vec2i relativeCoord = Vec2i(startPoint.h, startPoint.v) - windowCoord; + const bool coordIsInBounds = closeBoxRect.Contains(relativeCoord); + + if (coordIsInBounds != isInBounds) + { + const bool state = coordIsInBounds; + isInBounds = coordIsInBounds; + + static_cast(window)->UpdateRegionChromeState(RegionIDs::kClose, &state); + } + } + + for (;;) + { + TimeTaggedVOSEvent evt; + if (WaitForEvent(&evt, 1)) + { + if (evt.m_vosEvent.m_eventType == GpVOSEventTypes::kMouseInput) + { + const GpMouseInputEvent &mouseEvent = evt.m_vosEvent.m_event.m_mouseInputEvent; + + const Vec2i relativeCoord = Vec2i(mouseEvent.m_x, mouseEvent.m_y) - windowCoord; + const bool coordIsInBounds = closeBoxRect.Contains(relativeCoord); + + if (coordIsInBounds != isInBounds) + { + const bool state = coordIsInBounds; + isInBounds = coordIsInBounds; + + static_cast(window)->UpdateRegionChromeState(RegionIDs::kClose, &state); + } + + if (mouseEvent.m_eventType == GpMouseEventTypes::kUp) + break; + } + } + } + + if (isInBounds) + { + const bool state = false; + static_cast(window)->UpdateRegionChromeState(RegionIDs::kClose, &state); + } + + return isInBounds; + } + void WindowManagerImpl::SetWindowTitle(Window *window, const PLPasStr &title) { static_cast(window)->SetTitle(title); diff --git a/PortabilityLayer/WindowManager.h b/PortabilityLayer/WindowManager.h index c07cd95..da4ca8c 100644 --- a/PortabilityLayer/WindowManager.h +++ b/PortabilityLayer/WindowManager.h @@ -30,6 +30,7 @@ namespace PortabilityLayer virtual void FindWindow(const Point &point, Window **outWindow, short *outRegion) const = 0; virtual void DestroyWindow(Window *window) = 0; virtual void DragWindow(Window *window, const Point &startPoint, const Rect &constraintRect) = 0; + virtual bool HandleCloseBoxClick(Window *window, const Point &startPoint) = 0; virtual void SetWindowTitle(Window *window, const PLPasStr &title) = 0; virtual Rect2i GetWindowFullRect(Window *window) const = 0;