Added scene base item for photo editor.

This commit is contained in:
23rd 2021-02-23 09:58:25 +03:00
parent 183408cb2d
commit 812d616f66
4 changed files with 241 additions and 0 deletions

View File

@ -522,6 +522,8 @@ PRIVATE
editor/photo_editor_controls.h
editor/photo_editor_layer_widget.cpp
editor/photo_editor_layer_widget.h
editor/scene_item_base.cpp
editor/scene_item_base.h
editor/undo_controller.cpp
editor/undo_controller.h
export/export_manager.cpp

View File

@ -56,3 +56,7 @@ photoEditorColorPickerCircleSkip: 50px;
photoEditorCropPointSize: 10px;
photoEditorCropMinSize: 20px;
photoEditorItemHandleSize: 10px;
photoEditorItemMinSize: 16px;
photoEditorItemMaxSize: 512px;

View File

@ -0,0 +1,174 @@
/*
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_item_base.h"
#include "styles/style_editor.h"
#include <QGraphicsSceneHoverEvent>
#include <QGraphicsSceneMouseEvent>
#include <QStyleOptionGraphicsItem>
namespace Editor {
namespace {
auto Normalized(float64 angle) {
return angle
+ ((std::abs(angle) < 360) ? 0 : (-360 * (angle < 0 ? -1 : 1)));
}
QPen PenStyled(QPen pen, Qt::PenStyle style) {
pen.setStyle(style);
return pen;
}
} // namespace
ItemBase::ItemBase(std::shared_ptr<float64> zPtr, int size, int x, int y)
: _lastZ(zPtr)
, _handleSize(st::photoEditorItemHandleSize)
, _innerMargins(
_handleSize / 2,
_handleSize / 2,
_handleSize / 2,
_handleSize / 2)
, _selectPen(QBrush(Qt::white), 1, Qt::DashLine, Qt::SquareCap, Qt::RoundJoin)
, _selectPenInactive(
QBrush(Qt::gray),
1,
Qt::DashLine,
Qt::SquareCap,
Qt::RoundJoin)
, _size(size) {
setFlags(QGraphicsItem::ItemIsMovable
| QGraphicsItem::ItemIsSelectable
| QGraphicsItem::ItemIsFocusable);
setAcceptHoverEvents(true);
setPos(x, y);
}
QRectF ItemBase::boundingRect() const {
return innerRect() + _innerMargins;
}
QRectF ItemBase::innerRect() const {
return QRectF(-_size / 2, -_size / 2, _size, _size);
}
void ItemBase::paint(
QPainter *p,
const QStyleOptionGraphicsItem *option,
QWidget *) {
if (!(option->state & QStyle::State_Selected)) {
return;
}
PainterHighQualityEnabler hq(*p);
const auto &pen = (option->state & QStyle::State_HasFocus)
? _selectPen
: _selectPenInactive;
p->setPen(pen);
p->drawRect(innerRect());
p->setPen(PenStyled(pen, Qt::SolidLine));
p->setBrush(st::photoEditorItemBaseHandleFg);
p->drawEllipse(rightHandleRect());
p->drawEllipse(leftHandleRect());
}
void ItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if (isHandling()) {
const auto mousePos = event->pos();
const auto isLeft = (_handle == HandleType::Left);
// Resize.
const auto p = isLeft ? (mousePos * -1) : mousePos;
const auto dx = int(2.0 * p.x());
const auto dy = int(2.0 * p.y());
prepareGeometryChange();
_size = std::clamp(
(dx > dy ? dx : dy),
st::photoEditorItemMinSize,
st::photoEditorItemMaxSize);
// Rotate.
const auto origin = mapToScene(boundingRect().center());
const auto pos = mapToScene(mousePos);
const auto diff = pos - origin;
const auto angle = Normalized((isLeft ? 180 : 0)
+ (std::atan2(diff.y(), diff.x()) * 180 / M_PI));
setRotation(angle);
} else {
QGraphicsItem::mouseMoveEvent(event);
}
}
void ItemBase::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
setCursor(isHandling()
? Qt::ClosedHandCursor
: (handleType(event->pos()) != HandleType::None) && isSelected()
? Qt::OpenHandCursor
: Qt::ArrowCursor);
QGraphicsItem::hoverMoveEvent(event);
}
void ItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event) {
setZValue((*_lastZ)++);
if (event->button() == Qt::LeftButton) {
_handle = handleType(event->pos());
if (isHandling()) {
setCursor(Qt::ClosedHandCursor);
}
} else {
QGraphicsItem::mousePressEvent(event);
}
}
void ItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
if ((event->button() == Qt::LeftButton) && isHandling()) {
_handle = HandleType::None;
} else {
QGraphicsItem::mouseReleaseEvent(event);
}
}
int ItemBase::type() const {
return Type;
}
QRectF ItemBase::rightHandleRect() const {
return QRectF(
(_size / 2) - (_handleSize / 2),
0 - (_handleSize / 2),
_handleSize,
_handleSize);
}
QRectF ItemBase::leftHandleRect() const {
return QRectF(
(-_size / 2) - (_handleSize / 2),
0 - (_handleSize / 2),
_handleSize,
_handleSize);
}
bool ItemBase::isHandling() const {
return _handle != HandleType::None;
}
int ItemBase::size() const {
return _size;
}
ItemBase::HandleType ItemBase::handleType(const QPointF &pos) const {
return rightHandleRect().contains(pos)
? HandleType::Right
: leftHandleRect().contains(pos)
? HandleType::Left
: HandleType::None;
}
} // namespace Editor

View File

@ -0,0 +1,61 @@
/*
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
*/
#pragma once
#include <QGraphicsItem>
class QGraphicsSceneHoverEvent;
class QGraphicsSceneMouseEvent;
class QStyleOptionGraphicsItem;
namespace Editor {
class ItemBase : public QGraphicsItem {
public:
enum { Type = UserType + 1 };
ItemBase(std::shared_ptr<float64> zPtr, int size, int x, int y);
QRectF boundingRect() const override;
void paint(
QPainter *p,
const QStyleOptionGraphicsItem *option,
QWidget *widget) override;
protected:
enum HandleType {
None,
Left,
Right,
};
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
int type() const override;
QRectF innerRect() const;
int size() const;
private:
HandleType handleType(const QPointF &pos) const;
QRectF rightHandleRect() const;
QRectF leftHandleRect() const;
bool isHandling() const;
const std::shared_ptr<float64> _lastZ;
const int _handleSize;
const QMargins _innerMargins;
const QPen _selectPen;
const QPen _selectPenInactive;
const QPen _handlePen;
int _size;
HandleType _handle = HandleType::None;
};
} // namespace Editor