From edd5745d7f55d4d9414f4c406293c05779cedece Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 28 May 2024 19:30:42 +0100 Subject: [PATCH] DocumentWindow: Implement window hit-testing API --- .../windows/juce_DocumentWindow.cpp | 57 ++++++++++++++++++- .../windows/juce_DocumentWindow.h | 4 +- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp b/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp index 7a6263d0f9..a3ac6a0d74 100644 --- a/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp +++ b/modules/juce_gui_basics/windows/juce_DocumentWindow.cpp @@ -264,7 +264,7 @@ int DocumentWindow::getTitleBarHeight() const return isUsingNativeTitleBar() ? 0 : jmin (titleBarHeight, getHeight() - 4); } -Rectangle DocumentWindow::getTitleBarArea() +Rectangle DocumentWindow::getTitleBarArea() const { if (isKioskMode()) return {}; @@ -273,6 +273,61 @@ Rectangle DocumentWindow::getTitleBarArea() return { border.getLeft(), border.getTop(), getWidth() - border.getLeftAndRight(), getTitleBarHeight() }; } +auto DocumentWindow::findControlAtPoint (Point pt) const -> WindowControlKind +{ + if (resizableBorder != nullptr) + { + using Zone = ResizableBorderComponent::Zone; + const auto zone = Zone::fromPositionOnBorder (getLocalBounds(), + resizableBorder->getBorderThickness(), + pt.roundToInt()); + + switch (zone.getZoneFlags()) + { + case Zone::top: return WindowControlKind::sizeTop; + case Zone::left: return WindowControlKind::sizeLeft; + case Zone::right: return WindowControlKind::sizeRight; + case Zone::bottom: return WindowControlKind::sizeBottom; + + case Zone::top | Zone::left: return WindowControlKind::sizeTopLeft; + case Zone::top | Zone::right: return WindowControlKind::sizeTopRight; + case Zone::bottom | Zone::left: return WindowControlKind::sizeBottomLeft; + case Zone::bottom | Zone::right: return WindowControlKind::sizeBottomRight; + } + } + + const auto topArea = getTitleBarArea().withTop (0); + + if (! topArea.toFloat().contains (pt)) + return WindowControlKind::client; + + for (const auto& [control, kind] : { std::tuple (getMinimiseButton(), WindowControlKind::minimise), + std::tuple (getMaximiseButton(), WindowControlKind::maximise), + std::tuple (getCloseButton(), WindowControlKind::close) }) + { + if (control != nullptr && control->contains (control->getLocalPoint (this, pt))) + return kind; + } + + // Add a few pixels for the top resizer, because Windows 11 expects the top resizer to be inside + // the window, unlike the resizers on the bottom/left/right. + constexpr auto topResizerSize = 4; + const auto topResizerArea = getLocalBounds().withHeight (topResizerSize).toFloat(); + + if (topResizerArea.contains (pt)) + { + if (pt.x <= topResizerArea.getX() + topResizerSize) + return WindowControlKind::sizeTopLeft; + + if (topResizerArea.getRight() - topResizerSize <= pt.x) + return WindowControlKind::sizeTopRight; + + return WindowControlKind::sizeTop; + } + + return WindowControlKind::caption; +} + Button* DocumentWindow::getCloseButton() const noexcept { return titleBarButtons[2].get(); } Button* DocumentWindow::getMinimiseButton() const noexcept { return titleBarButtons[0].get(); } Button* DocumentWindow::getMaximiseButton() const noexcept { return titleBarButtons[1].get(); } diff --git a/modules/juce_gui_basics/windows/juce_DocumentWindow.h b/modules/juce_gui_basics/windows/juce_DocumentWindow.h index 43116882e3..09e4484ca4 100644 --- a/modules/juce_gui_basics/windows/juce_DocumentWindow.h +++ b/modules/juce_gui_basics/windows/juce_DocumentWindow.h @@ -291,7 +291,9 @@ public: /** @internal */ void parentHierarchyChanged() override; /** @internal */ - Rectangle getTitleBarArea(); + Rectangle getTitleBarArea() const; + /** @internal */ + WindowControlKind findControlAtPoint (Point) const override; #endif private: