mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
f032df223f
When you clicked, and then move towards top-left with the cursor, and release, the handles were displayed inside the resulting rectangle, instead of outside.
354 lines
9.8 KiB
C++
354 lines
9.8 KiB
C++
/*
|
|
Copyright (C) 2014 by Project Tox <https://tox.im>
|
|
|
|
This file is part of qTox, a Qt-based graphical interface for Tox.
|
|
|
|
This program is libre software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
#include "screengrabberchooserrectitem.h"
|
|
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QGraphicsScene>
|
|
#include <QPainter>
|
|
#include <QCursor>
|
|
|
|
enum {
|
|
HandleSize = 10,
|
|
MinRectSize = 2,
|
|
};
|
|
|
|
ScreenGrabberChooserRectItem::ScreenGrabberChooserRectItem(QGraphicsScene* scene)
|
|
{
|
|
scene->addItem(this);
|
|
setCursor(QCursor(Qt::OpenHandCursor));
|
|
|
|
this->mainRect = createHandleItem(scene);
|
|
this->topLeft = createHandleItem(scene);
|
|
this->topCenter = createHandleItem(scene);
|
|
this->topRight = createHandleItem(scene);
|
|
this->rightCenter = createHandleItem(scene);
|
|
this->bottomRight = createHandleItem(scene);
|
|
this->bottomCenter = createHandleItem(scene);
|
|
this->bottomLeft = createHandleItem(scene);
|
|
this->leftCenter = createHandleItem(scene);
|
|
|
|
this->topLeft->setCursor(QCursor(Qt::SizeFDiagCursor));
|
|
this->bottomRight->setCursor(QCursor(Qt::SizeFDiagCursor));
|
|
this->topRight->setCursor(QCursor(Qt::SizeBDiagCursor));
|
|
this->bottomLeft->setCursor(QCursor(Qt::SizeBDiagCursor));
|
|
this->leftCenter->setCursor(QCursor(Qt::SizeHorCursor));
|
|
this->rightCenter->setCursor(QCursor(Qt::SizeHorCursor));
|
|
this->topCenter->setCursor(QCursor(Qt::SizeVerCursor));
|
|
this->bottomCenter->setCursor(QCursor(Qt::SizeVerCursor));
|
|
|
|
this->mainRect->setRect(QRect());
|
|
hideHandles();
|
|
|
|
}
|
|
|
|
ScreenGrabberChooserRectItem::~ScreenGrabberChooserRectItem()
|
|
{
|
|
|
|
}
|
|
|
|
QRectF ScreenGrabberChooserRectItem::boundingRect() const
|
|
{
|
|
return QRectF(-HandleSize - 1, -HandleSize - 1,
|
|
rectWidth + HandleSize + 1, rectHeight + HandleSize + 1);
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::beginResize(QPointF mousePos)
|
|
{
|
|
rectWidth = this->rectHeight = 0;
|
|
mainRect->setRect(QRect());
|
|
state = Resizing;
|
|
startPos = mousePos;
|
|
|
|
setCursor(QCursor(Qt::CrossCursor));
|
|
hideHandles();
|
|
mainRect->grabMouse();
|
|
}
|
|
|
|
QRect ScreenGrabberChooserRectItem::chosenRect() const
|
|
{
|
|
QRect rect (x(), y(), rectWidth, rectHeight);
|
|
if (rectWidth < 0)
|
|
{
|
|
rect.setX(rect.x() + rectWidth);
|
|
rect.setWidth(-rectWidth);
|
|
}
|
|
|
|
if (rectHeight < 0)
|
|
{
|
|
rect.setY(rect.y() + rectHeight);
|
|
rect.setHeight(-rectHeight);
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::showHandles()
|
|
{
|
|
this->topLeft->show();
|
|
this->topCenter->show();
|
|
this->topRight->show();
|
|
this->rightCenter->show();
|
|
this->bottomRight->show();
|
|
this->bottomCenter->show();
|
|
this->bottomLeft->show();
|
|
this->leftCenter->show();
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::hideHandles()
|
|
{
|
|
this->topLeft->hide();
|
|
this->topCenter->hide();
|
|
this->topRight->hide();
|
|
this->rightCenter->hide();
|
|
this->bottomRight->hide();
|
|
this->bottomCenter->hide();
|
|
this->bottomLeft->hide();
|
|
this->leftCenter->hide();
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mousePress(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton)
|
|
{
|
|
this->state = Moving;
|
|
setCursor(QCursor(Qt::ClosedHandCursor));
|
|
}
|
|
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mouseMove(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
if (this->state == Moving)
|
|
{
|
|
QPointF delta = event->scenePos() - event->lastScenePos();
|
|
moveBy (delta.x(), delta.y());
|
|
}
|
|
else if (this->state == Resizing)
|
|
{
|
|
prepareGeometryChange();
|
|
QPointF size = event->scenePos() - scenePos();
|
|
mainRect->setRect (0, 0, size.x(), size.y());
|
|
rectWidth = size.x();
|
|
rectHeight = size.y();
|
|
|
|
updateHandlePositions();
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
emit regionChosen(chosenRect());
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mouseRelease(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton)
|
|
{
|
|
setCursor(QCursor(Qt::OpenHandCursor));
|
|
|
|
QPointF delta = (event->scenePos() - startPos);
|
|
if (qAbs(delta.x()) < MinRectSize || qAbs(delta.y()) < MinRectSize)
|
|
{
|
|
rectWidth = rectHeight = 0;
|
|
mainRect->setRect(QRect());
|
|
}
|
|
else
|
|
{
|
|
QRect normalized = chosenRect();
|
|
|
|
rectWidth = normalized.width();
|
|
rectHeight = normalized.height();
|
|
setPos(normalized.x(), normalized.y());
|
|
mainRect->setRect(0, 0, rectWidth, rectHeight);
|
|
|
|
updateHandlePositions();
|
|
showHandles();
|
|
}
|
|
|
|
emit regionChosen(chosenRect());
|
|
state = None;
|
|
mainRect->ungrabMouse();
|
|
}
|
|
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mouseDoubleClick(QGraphicsSceneMouseEvent* event)
|
|
{
|
|
Q_UNUSED(event);
|
|
emit doubleClicked();
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mousePressHandle(int x, int y, QGraphicsSceneMouseEvent* event)
|
|
{
|
|
Q_UNUSED(x);
|
|
Q_UNUSED(y);
|
|
|
|
if(event->button() == Qt::LeftButton)
|
|
this->state = HandleResizing;
|
|
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mouseMoveHandle(int x, int y, QGraphicsSceneMouseEvent* event)
|
|
{
|
|
if (this->state != HandleResizing)
|
|
return;
|
|
|
|
QPointF delta = event->scenePos() - event->lastScenePos();
|
|
delta.rx() *= qreal(std::abs(x));
|
|
delta.ry() *= qreal(std::abs(y));
|
|
|
|
// We increase if the multiplier and the delta have the same sign
|
|
bool increaseX = ((x < 0) == (delta.x() < 0));
|
|
bool increaseY = ((y < 0) == (delta.y() < 0));
|
|
|
|
if((delta.x() < 0 && increaseX) || (delta.x() >= 0 && !increaseX))
|
|
{
|
|
moveBy(delta.x(), 0);
|
|
delta.rx() *= -1;
|
|
}
|
|
|
|
if((delta.y() < 0 && increaseY) || (delta.y() >= 0 && !increaseY))
|
|
{
|
|
moveBy(0, delta.y());
|
|
delta.ry() *= -1;
|
|
}
|
|
|
|
//
|
|
this->rectWidth += delta.x();
|
|
this->rectHeight += delta.y();
|
|
this->mainRect->setRect (0, 0, this->rectWidth, this->rectHeight);
|
|
updateHandlePositions();
|
|
emit regionChosen(chosenRect());
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::mouseReleaseHandle(int x, int y, QGraphicsSceneMouseEvent* event)
|
|
{
|
|
Q_UNUSED(x);
|
|
Q_UNUSED(y);
|
|
|
|
if (event->button() == Qt::LeftButton)
|
|
this->state = None;
|
|
|
|
}
|
|
|
|
QPoint ScreenGrabberChooserRectItem::getHandleMultiplier(QGraphicsItem* handle)
|
|
{
|
|
if (handle == this->topLeft)
|
|
return QPoint(-1, -1);
|
|
|
|
if (handle == this->topCenter)
|
|
return QPoint(0, -1);
|
|
|
|
if (handle == this->topRight)
|
|
return QPoint(1, -1);
|
|
|
|
if (handle == this->rightCenter)
|
|
return QPoint(1, 0);
|
|
|
|
if (handle == this->bottomRight)
|
|
return QPoint(1, 1);
|
|
|
|
if (handle == this->bottomCenter)
|
|
return QPoint(0, 1);
|
|
|
|
if (handle == this->bottomLeft)
|
|
return QPoint(-1, 1);
|
|
|
|
if (handle == this->leftCenter)
|
|
return QPoint(-1, 0);
|
|
|
|
return QPoint();
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::updateHandlePositions()
|
|
{
|
|
this->topLeft->setPos(-HandleSize, -HandleSize);
|
|
this->topCenter->setPos((this->rectWidth - HandleSize) / 2, -HandleSize);
|
|
this->topRight->setPos(this->rectWidth, -HandleSize);
|
|
this->rightCenter->setPos(this->rectWidth, (this->rectHeight - HandleSize) / 2);
|
|
this->bottomRight->setPos(this->rectWidth, this->rectHeight);
|
|
this->bottomCenter->setPos((this->rectWidth - HandleSize) / 2, this->rectHeight);
|
|
this->bottomLeft->setPos(-HandleSize, this->rectHeight);
|
|
this->leftCenter->setPos(-HandleSize, (this->rectHeight - HandleSize) / 2);
|
|
}
|
|
|
|
QGraphicsRectItem* ScreenGrabberChooserRectItem::createHandleItem(QGraphicsScene* scene)
|
|
{
|
|
QGraphicsRectItem* handle = new QGraphicsRectItem(0, 0, HandleSize, HandleSize);
|
|
handle->setPen(QPen(Qt::blue));
|
|
handle->setBrush(Qt::NoBrush);
|
|
|
|
scene->addItem(handle);
|
|
addToGroup(handle);
|
|
|
|
handle->installSceneEventFilter(this);
|
|
return handle;
|
|
}
|
|
|
|
bool ScreenGrabberChooserRectItem::sceneEventFilter(QGraphicsItem* watched, QEvent* event)
|
|
{
|
|
if (watched == this->mainRect)
|
|
forwardMainRectEvent(event);
|
|
else
|
|
forwardHandleEvent(watched, event);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::forwardMainRectEvent(QEvent* event)
|
|
{
|
|
QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
|
|
|
|
switch(event->type())
|
|
{
|
|
case QEvent::GraphicsSceneMousePress:
|
|
return mousePress(mouseEvent);
|
|
case QEvent::GraphicsSceneMouseMove:
|
|
return mouseMove(mouseEvent);
|
|
case QEvent::GraphicsSceneMouseRelease:
|
|
return mouseRelease(mouseEvent);
|
|
case QEvent::GraphicsSceneMouseDoubleClick:
|
|
return mouseDoubleClick(mouseEvent);
|
|
default:
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
void ScreenGrabberChooserRectItem::forwardHandleEvent(QGraphicsItem* watched, QEvent* event)
|
|
{
|
|
QGraphicsSceneMouseEvent* mouseEvent = static_cast<QGraphicsSceneMouseEvent*>(event);
|
|
QPoint multiplier = getHandleMultiplier(watched);
|
|
|
|
if (multiplier.isNull())
|
|
return;
|
|
|
|
switch(event->type())
|
|
{
|
|
case QEvent::GraphicsSceneMousePress:
|
|
return mousePressHandle(multiplier.x(), multiplier.y(), mouseEvent);
|
|
case QEvent::GraphicsSceneMouseMove:
|
|
return mouseMoveHandle(multiplier.x(), multiplier.y(), mouseEvent);
|
|
case QEvent::GraphicsSceneMouseRelease:
|
|
return mouseReleaseHandle(multiplier.x(), multiplier.y(), mouseEvent);
|
|
default:
|
|
return;
|
|
}
|
|
|
|
}
|