| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "editor/scene/scene_item_canvas.h"
- #include <QGraphicsScene>
- #include <QGraphicsSceneMouseEvent>
- namespace Editor {
- namespace {
- QRectF NormalizedRect(const QPointF& p1, const QPointF& p2) {
- return QRectF(
- std::min(p1.x(), p2.x()),
- std::min(p1.y(), p2.y()),
- std::abs(p2.x() - p1.x()) + 1,
- std::abs(p2.y() - p1.y()) + 1);
- }
- std::vector<QPointF> InterpolatedPoints(
- const QPointF &startPoint,
- const QPointF &endPoint) {
- std::vector<QPointF> points;
- const auto x1 = startPoint.x();
- const auto y1 = startPoint.y();
- const auto x2 = endPoint.x();
- const auto y2 = endPoint.y();
- // Difference of x and y values.
- const auto dx = x2 - x1;
- const auto dy = y2 - y1;
- // Absolute values of differences.
- const auto ix = std::abs(dx);
- const auto iy = std::abs(dy);
- // Larger of the x and y differences.
- const auto inc = ix > iy ? ix : iy;
- // Plot location.
- auto plotx = x1;
- auto ploty = y1;
- auto x = 0;
- auto y = 0;
- points.push_back(QPointF(plotx, ploty));
- for (auto i = 0; i <= inc; i++) {
- const auto xInc = x > inc;
- const auto yInc = y > inc;
- x += ix;
- y += iy;
- if (xInc) {
- x -= inc;
- plotx += 1 * ((dx < 0) ? -1 : 1);
- }
- if (yInc) {
- y -= inc;
- ploty += 1 * ((dy < 0) ? -1 : 1);
- }
- if (xInc || yInc) {
- points.push_back(QPointF(plotx, ploty));
- }
- }
- return points;
- }
- } // namespace
- ItemCanvas::ItemCanvas() {
- setAcceptedMouseButtons({});
- }
- void ItemCanvas::clearPixmap() {
- _hq = nullptr;
- _p = nullptr;
- _pixmap = QPixmap(
- (scene()->sceneRect().size() * style::DevicePixelRatio()).toSize());
- _pixmap.setDevicePixelRatio(style::DevicePixelRatio());
- _pixmap.fill(Qt::transparent);
- _p = std::make_unique<Painter>(&_pixmap);
- _hq = std::make_unique<PainterHighQualityEnabler>(*_p);
- _p->setPen(Qt::NoPen);
- _p->setBrush(_brushData.color);
- }
- void ItemCanvas::applyBrush(const QColor &color, float size) {
- _brushData.color = color;
- _brushData.size = size;
- _p->setBrush(color);
- _brushMargins = QMarginsF(size, size, size, size);// / 2.;
- }
- QRectF ItemCanvas::boundingRect() const {
- return scene()->sceneRect();
- }
- void ItemCanvas::computeContentRect(const QPointF &p) {
- if (!scene()) {
- return;
- }
- const auto sceneSize = scene()->sceneRect().size();
- _contentRect = QRectF(
- QPointF(
- std::clamp(p.x() - _brushMargins.left(), 0., _contentRect.x()),
- std::clamp(p.y() - _brushMargins.top(), 0., _contentRect.y())
- ),
- QPointF(
- std::clamp(
- p.x() + _brushMargins.right(),
- _contentRect.x() + _contentRect.width(),
- sceneSize.width()),
- std::clamp(
- p.y() + _brushMargins.bottom(),
- _contentRect.y() + _contentRect.height(),
- sceneSize.height())
- ));
- }
- void ItemCanvas::drawLine(
- const QPointF ¤tPoint,
- const QPointF &lastPoint) {
- const auto halfBrushSize = _brushData.size / 2.;
- const auto points = InterpolatedPoints(lastPoint, currentPoint);
- _rectToUpdate |= NormalizedRect(currentPoint, lastPoint) + _brushMargins;
- for (const auto &point : points) {
- _p->drawEllipse(point, halfBrushSize, halfBrushSize);
- }
- }
- void ItemCanvas::handleMousePressEvent(
- not_null<QGraphicsSceneMouseEvent*> e) {
- _lastPoint = e->scenePos();
- _contentRect = QRectF(_lastPoint, _lastPoint);
- _drawing = true;
- }
- void ItemCanvas::handleMouseMoveEvent(
- not_null<QGraphicsSceneMouseEvent*> e) {
- if (!_drawing) {
- return;
- }
- const auto scenePos = e->scenePos();
- drawLine(scenePos, _lastPoint);
- update(_rectToUpdate);
- computeContentRect(scenePos);
- _lastPoint = scenePos;
- }
- void ItemCanvas::handleMouseReleaseEvent(
- not_null<QGraphicsSceneMouseEvent*> e) {
- if (!_drawing) {
- return;
- }
- _drawing = false;
- if (_contentRect.isValid()) {
- const auto scaledContentRect = QRectF(
- _contentRect.x() * style::DevicePixelRatio(),
- _contentRect.y() * style::DevicePixelRatio(),
- _contentRect.width() * style::DevicePixelRatio(),
- _contentRect.height() * style::DevicePixelRatio());
- _grabContentRequests.fire({
- .pixmap = _pixmap.copy(scaledContentRect.toRect()),
- .position = _contentRect.topLeft(),
- });
- }
- clearPixmap();
- update();
- }
- void ItemCanvas::paint(
- QPainter *p,
- const QStyleOptionGraphicsItem *,
- QWidget *) {
- p->fillRect(_rectToUpdate, Qt::transparent);
- p->drawPixmap(0, 0, _pixmap);
- _rectToUpdate = QRectF();
- }
- rpl::producer<ItemCanvas::Content> ItemCanvas::grabContentRequests() const {
- return _grabContentRequests.events();
- }
- bool ItemCanvas::collidesWithItem(
- const QGraphicsItem *,
- Qt::ItemSelectionMode) const {
- return false;
- }
- bool ItemCanvas::collidesWithPath(
- const QPainterPath &,
- Qt::ItemSelectionMode) const {
- return false;
- }
- void ItemCanvas::cancelDrawing() {
- _drawing = false;
- _contentRect = QRectF();
- clearPixmap();
- update();
- }
- ItemCanvas::~ItemCanvas() {
- _hq = nullptr;
- _p = nullptr;
- }
- } // namespace Editor
|