better close button rect calc

This commit is contained in:
Alex Okonechnikov 2025-12-31 08:22:11 -05:00
parent 4af15ab532
commit 763327b7b5
2 changed files with 65 additions and 34 deletions

View file

@ -17,6 +17,7 @@
#include <QLabel> #include <QLabel>
#include <QPainter> #include <QPainter>
#include <QScrollBar> #include <QScrollBar>
#include <QStyle>
#include <QStyleOption> #include <QStyleOption>
#include <libcockatrice/protocol/pb/command_shuffle.pb.h> #include <libcockatrice/protocol/pb/command_shuffle.pb.h>
@ -257,6 +258,47 @@ void ZoneViewWidget::stopWindowDrag()
ungrabMouse(); ungrabMouse();
} }
void ZoneViewWidget::startWindowDrag(QGraphicsSceneMouseEvent *event)
{
draggingWindow = true;
dragStartItemPos = pos();
dragStartScreenPos = event->screenPos();
dragView = findDragView(event->widget());
// need to grab mouse to receive events and not miss initial movement
grabMouse();
}
QRectF ZoneViewWidget::closeButtonRect(QWidget *styleWidget) const
{
const QRectF frameRectF = windowFrameRect();
const QRect titleBarRect(frameRectF.toRect().x(), frameRectF.toRect().y(), frameRectF.toRect().width(),
static_cast<int>(kTitleBarHeight));
// query the style for the close button position (handles macOS top-left placement)
if (styleWidget) {
QStyleOptionTitleBar opt;
opt.initFrom(styleWidget);
opt.rect = titleBarRect;
opt.text = windowTitle();
opt.icon = styleWidget->windowIcon();
opt.titleBarFlags = Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
opt.subControls = QStyle::SC_TitleBarCloseButton;
opt.activeSubControls = QStyle::SC_TitleBarCloseButton;
opt.titleBarState = styleWidget->isActiveWindow() ? Qt::WindowActive : Qt::WindowNoState;
if (styleWidget->isActiveWindow())
opt.state |= QStyle::State_Active;
const QRect r = styleWidget->style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarCloseButton,
styleWidget);
if (r.isValid() && !r.isEmpty()) {
return QRectF(r);
}
}
// fallback: square at right end of titlebar (Windows/Linux style)
return QRectF(frameRectF.right() - kTitleBarHeight, frameRectF.top(), kTitleBarHeight, kTitleBarHeight);
}
QGraphicsView *ZoneViewWidget::findDragView(QWidget *eventWidget) const QGraphicsView *ZoneViewWidget::findDragView(QWidget *eventWidget) const
{ {
QWidget *current = eventWidget; QWidget *current = eventWidget;
@ -289,64 +331,51 @@ QPointF ZoneViewWidget::calcDraggedWindowPos(const QPoint &screenPos,
bool ZoneViewWidget::windowFrameEvent(QEvent *event) bool ZoneViewWidget::windowFrameEvent(QEvent *event)
{ {
// Intercept and move the widget in a stable coordinate space if (event->type() == QEvent::UngrabMouse) {
stopWindowDrag();
return QGraphicsWidget::windowFrameEvent(event);
}
auto *me = dynamic_cast<QGraphicsSceneMouseEvent *>(event);
if (!me)
return QGraphicsWidget::windowFrameEvent(event);
switch (event->type()) { switch (event->type()) {
case QEvent::UngrabMouse: case QEvent::GraphicsSceneMousePress:
stopWindowDrag(); if (me->button() == Qt::LeftButton && windowFrameSectionAt(me->pos()) == Qt::TitleBarArea) {
break;
case QEvent::GraphicsSceneMousePress: {
auto *me = static_cast<QGraphicsSceneMouseEvent *>(event);
const Qt::WindowFrameSection section = windowFrameSectionAt(me->pos());
if (me->button() == Qt::LeftButton && section == Qt::TitleBarArea) {
// avoid drag on close button // avoid drag on close button
const QRectF frameRectF = windowFrameRect(); if (closeButtonRect(me->widget()).contains(me->pos())) {
// square at right end of the title bar is the close button
const QRectF closeRect(frameRectF.right() - kTitleBarHeight, frameRectF.top(), kTitleBarHeight,
kTitleBarHeight);
if (closeRect.contains(me->pos())) {
me->accept(); me->accept();
close(); close();
return true; return true;
} }
startWindowDrag(me);
draggingWindow = true;
dragStartItemPos = pos();
dragStartScreenPos = me->screenPos();
dragView = findDragView(me->widget());
// need to grab mouse to receive events and not miss initial movement
grabMouse();
me->accept(); me->accept();
return true; return true;
} }
break; break;
}
case QEvent::GraphicsSceneMouseMove: { case QEvent::GraphicsSceneMouseMove:
auto *me = static_cast<QGraphicsSceneMouseEvent *>(event);
if (draggingWindow) { if (draggingWindow) {
if (!(me->buttons() & Qt::LeftButton)) { if (!(me->buttons() & Qt::LeftButton)) {
stopWindowDrag(); stopWindowDrag();
me->accept(); } else {
return true; setPos(
calcDraggedWindowPos(me->screenPos(), me->scenePos(), me->buttonDownScenePos(Qt::LeftButton)));
} }
setPos(calcDraggedWindowPos(me->screenPos(), me->scenePos(), me->buttonDownScenePos(Qt::LeftButton)));
me->accept(); me->accept();
return true; return true;
} }
break; break;
}
case QEvent::GraphicsSceneMouseRelease: { case QEvent::GraphicsSceneMouseRelease:
auto *me = static_cast<QGraphicsSceneMouseEvent *>(event);
if (draggingWindow && me->button() == Qt::LeftButton) { if (draggingWindow && me->button() == Qt::LeftButton) {
stopWindowDrag(); stopWindowDrag();
me->accept(); me->accept();
return true; return true;
} }
break; break;
}
default: default:
break; break;
} }

View file

@ -74,6 +74,8 @@ private:
QPointer<QGraphicsView> dragView; QPointer<QGraphicsView> dragView;
void stopWindowDrag(); void stopWindowDrag();
void startWindowDrag(QGraphicsSceneMouseEvent *event);
QRectF closeButtonRect(QWidget *styleWidget) const;
/** /**
* @brief Resolves the QGraphicsView to use for drag coordinate mapping * @brief Resolves the QGraphicsView to use for drag coordinate mapping
* *