mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
manual drag override (#6461)
* manual drag override * fix styles * pr comments * better close button rect calc
This commit is contained in:
parent
db3bdb586b
commit
0085015ebe
2 changed files with 210 additions and 20 deletions
|
|
@ -13,12 +13,20 @@
|
|||
#include <QGraphicsLinearLayout>
|
||||
#include <QGraphicsProxyWidget>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QGraphicsView>
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr qreal kTitleBarHeight = 24.0;
|
||||
constexpr qreal kMinVisibleWidth = 100.0;
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @param _player the player the cards were revealed to.
|
||||
* @param _origZone the zone the cards were revealed from.
|
||||
|
|
@ -241,33 +249,182 @@ void ZoneViewWidget::retranslateUi()
|
|||
pileViewCheckBox.setText(tr("pile view"));
|
||||
}
|
||||
|
||||
void ZoneViewWidget::moveEvent(QGraphicsSceneMoveEvent * /* event */)
|
||||
void ZoneViewWidget::stopWindowDrag()
|
||||
{
|
||||
if (!scene())
|
||||
if (!draggingWindow)
|
||||
return;
|
||||
|
||||
int titleBarHeight = 24;
|
||||
draggingWindow = false;
|
||||
ungrabMouse();
|
||||
}
|
||||
|
||||
QPointF scenePos = pos();
|
||||
void ZoneViewWidget::startWindowDrag(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
draggingWindow = true;
|
||||
dragStartItemPos = pos();
|
||||
dragStartScreenPos = event->screenPos();
|
||||
dragView = findDragView(event->widget());
|
||||
|
||||
if (scenePos.x() < 0) {
|
||||
scenePos.setX(0);
|
||||
} else {
|
||||
qreal maxw = scene()->sceneRect().width() - 100;
|
||||
if (scenePos.x() > maxw)
|
||||
scenePos.setX(maxw);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (scenePos.y() < titleBarHeight) {
|
||||
scenePos.setY(titleBarHeight);
|
||||
} else {
|
||||
qreal maxh = scene()->sceneRect().height() - titleBarHeight;
|
||||
if (scenePos.y() > maxh)
|
||||
scenePos.setY(maxh);
|
||||
// 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
|
||||
{
|
||||
QWidget *current = eventWidget;
|
||||
while (current) {
|
||||
if (auto *view = qobject_cast<QGraphicsView *>(current))
|
||||
return view;
|
||||
current = current->parentWidget();
|
||||
}
|
||||
|
||||
if (scenePos != pos())
|
||||
setPos(scenePos);
|
||||
if (scene() && !scene()->views().isEmpty())
|
||||
return scene()->views().constFirst();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QPointF ZoneViewWidget::calcDraggedWindowPos(const QPoint &screenPos,
|
||||
const QPointF &scenePos,
|
||||
const QPointF &buttonDownScenePos) const
|
||||
{
|
||||
if (dragView && dragView->viewport()) {
|
||||
const QPoint vpStart = dragView->viewport()->mapFromGlobal(dragStartScreenPos);
|
||||
const QPoint vpNow = dragView->viewport()->mapFromGlobal(screenPos);
|
||||
const QPointF sceneStart = dragView->mapToScene(vpStart);
|
||||
const QPointF sceneNow = dragView->mapToScene(vpNow);
|
||||
return dragStartItemPos + (sceneNow - sceneStart);
|
||||
}
|
||||
|
||||
return dragStartItemPos + (scenePos - buttonDownScenePos);
|
||||
}
|
||||
|
||||
bool ZoneViewWidget::windowFrameEvent(QEvent *event)
|
||||
{
|
||||
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()) {
|
||||
case QEvent::GraphicsSceneMousePress:
|
||||
if (me->button() == Qt::LeftButton && windowFrameSectionAt(me->pos()) == Qt::TitleBarArea) {
|
||||
// avoid drag on close button
|
||||
if (closeButtonRect(me->widget()).contains(me->pos())) {
|
||||
me->accept();
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
startWindowDrag(me);
|
||||
me->accept();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case QEvent::GraphicsSceneMouseMove:
|
||||
if (draggingWindow) {
|
||||
if (!(me->buttons() & Qt::LeftButton)) {
|
||||
stopWindowDrag();
|
||||
} else {
|
||||
setPos(
|
||||
calcDraggedWindowPos(me->screenPos(), me->scenePos(), me->buttonDownScenePos(Qt::LeftButton)));
|
||||
}
|
||||
me->accept();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case QEvent::GraphicsSceneMouseRelease:
|
||||
if (draggingWindow && me->button() == Qt::LeftButton) {
|
||||
stopWindowDrag();
|
||||
me->accept();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QGraphicsWidget::windowFrameEvent(event);
|
||||
}
|
||||
|
||||
void ZoneViewWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
// move if the scene routes moves while dragging
|
||||
if (draggingWindow && (event->buttons() & Qt::LeftButton)) {
|
||||
setPos(calcDraggedWindowPos(event->screenPos(), event->scenePos(), event->buttonDownScenePos(Qt::LeftButton)));
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QGraphicsWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void ZoneViewWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (draggingWindow && event->button() == Qt::LeftButton) {
|
||||
stopWindowDrag();
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QGraphicsWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
QVariant ZoneViewWidget::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == QGraphicsItem::ItemPositionChange && scene()) {
|
||||
// Keep grab area in main view
|
||||
const QRectF sceneRect = scene()->sceneRect();
|
||||
const QPointF requestedPos = value.toPointF();
|
||||
QPointF desiredPos = requestedPos;
|
||||
|
||||
const qreal minX = sceneRect.left();
|
||||
const qreal maxX = qMax(minX, sceneRect.right() - kMinVisibleWidth);
|
||||
const qreal minY = sceneRect.top() + kTitleBarHeight;
|
||||
const qreal maxY = qMax(minY, sceneRect.bottom() - kTitleBarHeight);
|
||||
|
||||
desiredPos.setX(qBound(minX, desiredPos.x(), maxX));
|
||||
desiredPos.setY(qBound(minY, desiredPos.y(), maxY));
|
||||
return desiredPos;
|
||||
}
|
||||
|
||||
return QGraphicsWidget::itemChange(change, value);
|
||||
}
|
||||
|
||||
void ZoneViewWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
|
||||
|
|
@ -350,6 +507,7 @@ void ZoneViewWidget::handleScrollBarChange(int value)
|
|||
|
||||
void ZoneViewWidget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
stopWindowDrag();
|
||||
disconnect(zone, &ZoneViewZone::closed, this, 0);
|
||||
// manually call zone->close in order to remove it from the origZones views
|
||||
zone->close();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
* @ingroup GameGraphicsZones
|
||||
* @brief TODO: Document this.
|
||||
*/
|
||||
|
||||
#ifndef ZONEVIEWWIDGET_H
|
||||
#define ZONEVIEWWIDGET_H
|
||||
|
||||
|
|
@ -14,6 +13,7 @@
|
|||
#include <QGraphicsProxyWidget>
|
||||
#include <QGraphicsWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPointer>
|
||||
#include <libcockatrice/utility/macros.h>
|
||||
|
||||
class QLabel;
|
||||
|
|
@ -28,6 +28,8 @@ class ServerInfo_Card;
|
|||
class QGraphicsSceneMouseEvent;
|
||||
class QGraphicsSceneWheelEvent;
|
||||
class QStyleOption;
|
||||
class QGraphicsView;
|
||||
class QWidget;
|
||||
|
||||
class ScrollableGraphicsProxyWidget : public QGraphicsProxyWidget
|
||||
{
|
||||
|
|
@ -66,6 +68,33 @@ private:
|
|||
int extraHeight;
|
||||
Player *player;
|
||||
|
||||
bool draggingWindow = false;
|
||||
QPoint dragStartScreenPos;
|
||||
QPointF dragStartItemPos;
|
||||
QPointer<QGraphicsView> dragView;
|
||||
|
||||
void stopWindowDrag();
|
||||
void startWindowDrag(QGraphicsSceneMouseEvent *event);
|
||||
QRectF closeButtonRect(QWidget *styleWidget) const;
|
||||
/**
|
||||
* @brief Resolves the QGraphicsView to use for drag coordinate mapping
|
||||
*
|
||||
* @param eventWidget QWidget that originated the mouse event
|
||||
* @return The resolved QGraphicsView
|
||||
*/
|
||||
QGraphicsView *findDragView(QWidget *eventWidget) const;
|
||||
/**
|
||||
* @brief Calculates the desired widget position while dragging
|
||||
*
|
||||
* @param screenPos Global screen coordinates of the current mouse position
|
||||
* @param scenePos Scene coordinates of the current mouse position
|
||||
* @param buttonDownScenePos Scene coordinates of the initial mouse press position
|
||||
*
|
||||
* @return The new widget position in scene coordinates
|
||||
*/
|
||||
QPointF
|
||||
calcDraggedWindowPos(const QPoint &screenPos, const QPointF &scenePos, const QPointF &buttonDownScenePos) const;
|
||||
|
||||
void resizeScrollbar(qreal newZoneHeight);
|
||||
signals:
|
||||
void closePressed(ZoneViewWidget *zv);
|
||||
|
|
@ -76,7 +105,6 @@ private slots:
|
|||
void resizeToZoneContents(bool forceInitialHeight = false);
|
||||
void handleScrollBarChange(int value);
|
||||
void zoneDeleted();
|
||||
void moveEvent(QGraphicsSceneMoveEvent * /* event */) override;
|
||||
void resizeEvent(QGraphicsSceneResizeEvent * /* event */) override;
|
||||
void expandWindow();
|
||||
|
||||
|
|
@ -101,6 +129,10 @@ public:
|
|||
protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void initStyleOption(QStyleOption *option) const override;
|
||||
bool windowFrameEvent(QEvent *event) override;
|
||||
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue