diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index 78b56a8..4dd34eb 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -3,14 +3,14 @@ name: CMake Build
on:
push:
paths-ignore:
- - 'doc/**'
+ - 'docs/**'
- '.clang-format'
- '.gitignore'
- 'LICENSE'
- 'README*'
pull_request:
paths-ignore:
- - 'doc/**'
+ - 'docs/**'
- '.clang-format'
- '.gitignore'
- 'LICENSE'
diff --git a/.github/workflows/qmake.yml b/.github/workflows/qmake.yml
index e279306..fe4ff04 100644
--- a/.github/workflows/qmake.yml
+++ b/.github/workflows/qmake.yml
@@ -3,14 +3,14 @@ name: QMake Build
on:
push:
paths-ignore:
- - 'doc/**'
+ - 'docs/**'
- '.clang-format'
- '.gitignore'
- 'LICENSE'
- 'README*'
pull_request:
paths-ignore:
- - 'doc/**'
+ - 'docs/**'
- '.clang-format'
- '.gitignore'
- 'LICENSE'
diff --git a/Qt-Graphics.pro b/Qt-Graphics.pro
index 36fca8f..32a2853 100644
--- a/Qt-Graphics.pro
+++ b/Qt-Graphics.pro
@@ -6,7 +6,7 @@ SUBDIRS += \
examples
DISTFILES += \
- doc/** \
+ docs/** \
.clang* \
LICENSE \
README*
diff --git a/README.md b/README.md
index 1cfa44a..507e254 100644
--- a/README.md
+++ b/README.md
@@ -31,7 +31,7 @@
## 看图界面
-
+
## Opengl看图界面
@@ -45,7 +45,7 @@
## 马赛克绘制界面(橡皮擦效果)
-
+
## 圆角编辑窗口(也可编辑成圆形图标)
@@ -53,15 +53,13 @@
1. 一定要保存为PNG,不然圆角处会变成黑色;
## 简单图形绘制界面
-
+
## 电影字幕拼接界面
@@ -71,7 +69,7 @@
3. 虽然第一眼看起来模糊,但是实际生成的时候都是重新载入左侧原图剪切生成,保存后可用其他图片查看工具验证,或者按照上一点(2)查看;
-
+
## GIF录制(egif和gif-h库)和截图功能
@@ -80,5 +78,5 @@
2. 截屏之后可以使用(4)绘制图形;
-
+
diff --git a/doc/RoundEdit_1.png b/doc/RoundEdit_1.png
deleted file mode 100644
index d490ca3..0000000
Binary files a/doc/RoundEdit_1.png and /dev/null differ
diff --git a/doc/RoundEdit_2.png b/doc/RoundEdit_2.png
deleted file mode 100644
index 00ed734..0000000
Binary files a/doc/RoundEdit_2.png and /dev/null differ
diff --git a/doc/RoundEdit_3.png b/doc/RoundEdit_3.png
deleted file mode 100644
index 280d95b..0000000
Binary files a/doc/RoundEdit_3.png and /dev/null differ
diff --git a/doc/DrawScene.png b/docs/DrawScene.png
similarity index 100%
rename from doc/DrawScene.png
rename to docs/DrawScene.png
diff --git a/doc/FilmSubTiltleSplicing.png b/docs/FilmSubTiltleSplicing.png
similarity index 100%
rename from doc/FilmSubTiltleSplicing.png
rename to docs/FilmSubTiltleSplicing.png
diff --git a/doc/ImageView.png b/docs/ImageView.png
similarity index 100%
rename from doc/ImageView.png
rename to docs/ImageView.png
diff --git a/doc/MaskEdit.png b/docs/MaskEdit.png
similarity index 100%
rename from doc/MaskEdit.png
rename to docs/MaskEdit.png
diff --git a/doc/Record_Screenshot.gif b/docs/Record_Screenshot.gif
similarity index 100%
rename from doc/Record_Screenshot.gif
rename to docs/Record_Screenshot.gif
diff --git a/docs/RoundEdit.jpg b/docs/RoundEdit.jpg
new file mode 100644
index 0000000..4e6dde1
Binary files /dev/null and b/docs/RoundEdit.jpg differ
diff --git a/examples/graphics/drawwidget.cpp b/examples/graphics/drawwidget.cpp
index 6b9f3a8..d34a9f5 100644
--- a/examples/graphics/drawwidget.cpp
+++ b/examples/graphics/drawwidget.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -100,11 +101,12 @@ void DrawWidget::onAddShape(QListWidgetItem *item)
switch (type) {
case BasicGraphicsItem::LINE: shape = new GraphicsLineItem; break;
case BasicGraphicsItem::RECT: shape = new GraphicsRectItem; break;
+ case BasicGraphicsItem::ROUNDEDRECT: shape = new GraphicsRoundedRectItem; break;
+ case BasicGraphicsItem::ROTATEDRECT: shape = new GraphicsRotatedRectItem; break;
case BasicGraphicsItem::CIRCLE: shape = new GraphicsCircleItem; break;
case BasicGraphicsItem::POLYGON: shape = new GraphicsPolygonItem; break;
case BasicGraphicsItem::RING: shape = new GraphicsRingItem; break;
case BasicGraphicsItem::ARC: shape = new GraphicsArcItem; break;
- case BasicGraphicsItem::ROTATEDRECT: shape = new GraphicsRotatedRectItem; break;
default: break;
}
if (shape) {
diff --git a/examples/graphics/maskdialog.cpp b/examples/graphics/maskdialog.cpp
index 7fbdb83..f18d12e 100644
--- a/examples/graphics/maskdialog.cpp
+++ b/examples/graphics/maskdialog.cpp
@@ -166,24 +166,24 @@ void MaskDialog::onSave()
auto newFlatBlueButton(const QString &text, QWidget *parent) -> QPushButton *
{
- QPushButton *button = new QPushButton(text, parent);
+ auto *button = new QPushButton(text, parent);
return button;
}
void MaskDialog::setupUI()
{
- QPushButton *button1 = newFlatBlueButton(tr("Mask"), this);
- QPushButton *button2 = newFlatBlueButton(tr("Erase"), this);
- QPushButton *button3 = new QPushButton(tr("Clear"), this);
+ auto *button1 = newFlatBlueButton(tr("Mask"), this);
+ auto *button2 = newFlatBlueButton(tr("Erase"), this);
+ auto *button3 = new QPushButton(tr("Clear"), this);
d_ptr->buttonGroup->addButton(button1, 1);
d_ptr->buttonGroup->addButton(button2, 2);
d_ptr->buttonGroup->addButton(button3, 3);
d_ptr->buttonGroup->button(1)->setChecked(true);
- QPushButton *saveButton = newFlatBlueButton(tr("Save"), this);
+ auto *saveButton = newFlatBlueButton(tr("Save"), this);
connect(saveButton, &QPushButton::clicked, this, &MaskDialog::onSave);
- QHBoxLayout *editLayout = new QHBoxLayout;
+ auto *editLayout = new QHBoxLayout;
editLayout->addStretch();
editLayout->addWidget(new QLabel(tr("Pen Size: "), this));
editLayout->addWidget(d_ptr->penSizeSpinBox);
@@ -195,7 +195,7 @@ void MaskDialog::setupUI()
editLayout->addWidget(saveButton);
editLayout->addStretch();
- QVBoxLayout *layout = new QVBoxLayout(this);
+ auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 10);
layout->addWidget(d_ptr->imageView);
layout->addLayout(editLayout);
diff --git a/examples/graphics/rounddialog.cc b/examples/graphics/rounddialog.cc
index 231781e..c2bf606 100644
--- a/examples/graphics/rounddialog.cc
+++ b/examples/graphics/rounddialog.cc
@@ -2,26 +2,41 @@
#include "stretchparamssettingdailog.hpp"
#include
-#include
+#include
#include
#include
using namespace Graphics;
+auto radiusImage(const QPixmap &pixmap, int radius) -> QImage
+{
+ QImage image(pixmap.size(), QImage::Format_RGBA8888_Premultiplied);
+ image.fill(Qt::transparent);
+ QPainter painter(&image);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ painter.setBrush(pixmap);
+ painter.setPen(Qt::transparent);
+ painter.drawRoundedRect(pixmap.rect(), radius, radius);
+ return image;
+}
+
class RoundDialog::RoundDialogPrivate
{
public:
- RoundDialogPrivate(QWidget *parent)
- : q_ptr(parent)
- , graphicsRectItemPtr(new GraphicsRectItem)
+ explicit RoundDialogPrivate(RoundDialog *q)
+ : q_ptr(q)
+ , roundedRectItemPtr(new GraphicsRoundedRectItem)
{
+ roundedRectItemPtr->setShowBoundingRect(true);
+
imageView = new ImageView(q_ptr);
- buttonGroup = new QButtonGroup(q_ptr);
- buttonGroup->setExclusive(true);
- cropWidget = new QWidget(q_ptr);
- rectGroupBox = new QGroupBox(QObject::tr("Rect Info"), q_ptr);
+ previewLabel = new QLabel(q_ptr);
+ previewLabel->setMinimumHeight(200);
+ previewLabel->setAlignment(Qt::AlignCenter);
+
+ rectGroupBox = new QGroupBox(QObject::tr("Rounded rect info"), q_ptr);
topLeftXSpinBox = new QSpinBox(q_ptr);
topLeftXSpinBox->setKeyboardTracking(false);
topLeftYSpinBox = new QSpinBox(q_ptr);
@@ -30,31 +45,83 @@ class RoundDialog::RoundDialogPrivate
widthSpinBox->setKeyboardTracking(false);
heightSpinBox = new QSpinBox(q_ptr);
heightSpinBox->setKeyboardTracking(false);
-
radiusSpinBox = new QSpinBox(q_ptr);
radiusSpinBox->setKeyboardTracking(false);
}
~RoundDialogPrivate() {}
- QWidget *q_ptr;
+ void setRoundedRect(const RoundedRect &roundedRect)
+ {
+ roundedRectItemPtr->setRoundedRect(roundedRect);
+ radiusSpinBox->setRange(0, qMin(roundedRect.rect.width(), roundedRect.rect.height()) / 2.0);
+ if (radiusSpinBox->value() > radiusSpinBox->maximum()) {
+ radiusSpinBox->setValue(radiusSpinBox->maximum());
+ }
+
+ QMetaObject::invokeMethod(
+ roundedRectItemPtr.data(), [=] { roundedRectItemPtr->update(); }, Qt::QueuedConnection);
+ updatePreview();
+ }
+
+ void updatePreview()
+ {
+ static QAtomicInt count = 0;
+ count.ref();
+ auto currentCount = count.loadAcquire();
+
+ QThreadPool::globalInstance()->start([this, currentCount] {
+ auto roundedRect = roundedRectItemPtr->roundedRect();
+ auto previewPixmap = pixmap.copy(roundedRect.rect.toRect());
+ previewPixmap = QPixmap::fromImage(radiusImage(previewPixmap, roundedRect.xRadius));
+ previewPixmap = previewPixmap.scaled(previewLabel->size(),
+ Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
+ if (currentCount == count.loadAcquire()) {
+ QMetaObject::invokeMethod(
+ q_ptr, [=] { previewLabel->setPixmap(previewPixmap); }, Qt::QueuedConnection);
+ }
+ });
+
+ QThreadPool::globalInstance()->start([this, currentCount] {
+ auto roundedRect = roundedRectItemPtr->roundedRect();
+ QImage image(pixmap.size(), QImage::Format_RGBA8888_Premultiplied);
+ image.fill(Qt::transparent);
+ QPainterPath p1, p2;
+ p1.addRect(pixmap.rect());
+ p2.addRoundedRect(roundedRect.rect, roundedRect.xRadius, roundedRect.yRadius);
+ p1 = p1.subtracted(p2);
+ {
+ QPainter painter(&image);
+ painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ painter.setOpacity(0.6);
+ painter.fillPath(p1, QBrush(Qt::black));
+ }
+ if (currentCount == count.loadAcquire()) {
+ QMetaObject::invokeMethod(
+ q_ptr,
+ [=] { imageView->pixmapItem()->setMaskImage(image); },
+ Qt::QueuedConnection);
+ }
+ });
+ }
+
+ RoundDialog *q_ptr;
ImageView *imageView;
- QWidget *cropWidget;
- QButtonGroup *buttonGroup;
+ QLabel *previewLabel;
+
QGroupBox *rectGroupBox;
QSpinBox *topLeftXSpinBox;
QSpinBox *topLeftYSpinBox;
QSpinBox *widthSpinBox;
QSpinBox *heightSpinBox;
-
QSpinBox *radiusSpinBox;
QString name;
- QScopedPointer graphicsRectItemPtr;
+ QScopedPointer roundedRectItemPtr;
QPixmap pixmap;
- QPixmap cutPixmap;
};
RoundDialog::RoundDialog(QWidget *parent)
@@ -84,53 +151,22 @@ void RoundDialog::setPixmap(const QPixmap &pixmap)
d_ptr->widthSpinBox->setRange(0, pixmap.width());
d_ptr->heightSpinBox->setRange(0, pixmap.height());
d_ptr->imageView->setPixmap(pixmap);
- d_ptr->graphicsRectItemPtr->setRect(pixmap.rect().adjusted(10, 10, -10, -10));
- if (!d_ptr->imageView->scene()->items().contains(d_ptr->graphicsRectItemPtr.data())) {
- d_ptr->imageView->scene()->addItem(d_ptr->graphicsRectItemPtr.data());
- }
- buildConnect2();
-}
-void RoundDialog::onStartRound(bool checked)
-{
- QPushButton *button = qobject_cast(sender());
- if (!button) {
- return;
+ RoundedRect roundedRect;
+ roundedRect.rect = pixmap.rect().adjusted(10, 10, -10, -10);
+ roundedRect.xRadius = roundedRect.yRadius = d_ptr->radiusSpinBox->value();
+ d_ptr->setRoundedRect(roundedRect);
+ if (!d_ptr->imageView->scene()->items().contains(d_ptr->roundedRectItemPtr.data())) {
+ d_ptr->imageView->scene()->addItem(d_ptr->roundedRectItemPtr.data());
}
- if (checked) {
- if (d_ptr->buttonGroup->button(1)->isChecked()) {
- d_ptr->cutPixmap = d_ptr->pixmap;
- } else {
- d_ptr->cutPixmap = d_ptr->pixmap.copy(d_ptr->graphicsRectItemPtr->rect().toRect());
- }
- d_ptr->imageView->setPixmap(d_ptr->cutPixmap);
- d_ptr->graphicsRectItemPtr->setRect(d_ptr->cutPixmap.rect().adjusted(10, 10, -10, -10));
- d_ptr->cropWidget->hide();
- d_ptr->graphicsRectItemPtr->hide();
- button->setText(tr("Reset Crop"));
- d_ptr->radiusSpinBox->setRange(0,
- qMin(d_ptr->cutPixmap.size().width(),
- d_ptr->cutPixmap.size().height())
- / 2.0);
- return;
- }
- d_ptr->cropWidget->show();
- d_ptr->rectGroupBox->show();
- setPixmap(d_ptr->pixmap);
- d_ptr->graphicsRectItemPtr->show();
- button->setText(tr("Start Round"));
+ buildConnect2();
}
void RoundDialog::onSave()
{
- if (d_ptr->cropWidget->isVisible()) {
- return;
- }
-
- QPixmap pixmap(d_ptr->imageView->pixmap());
- if (pixmap.isNull()) {
- return;
- }
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ auto pixmap = d_ptr->pixmap.copy(roundedRect.rect.toRect());
+ pixmap = QPixmap::fromImage(radiusImage(pixmap, roundedRect.xRadius));
StretchParamsSettingDailog::StretchParams params{pixmap.size(), Qt::KeepAspectRatio};
StretchParamsSettingDailog dialog(this);
@@ -161,29 +197,10 @@ void RoundDialog::onSave()
qDebug() << pixmap.save(filename, "PNG", params.quality);
}
-void RoundDialog::onButtonClicked(int id)
+void RoundDialog::onRoundedRectChanged(const Graphics::RoundedRect &roundedRect)
{
- GraphicsPixmapItem *pixmapItem = d_ptr->imageView->pixmapItem();
- if (!pixmapItem) {
- return;
- }
- switch (id) {
- case 1:
- d_ptr->graphicsRectItemPtr->hide();
- d_ptr->rectGroupBox->hide();
- d_ptr->radiusSpinBox
- ->setRange(0, qMin(d_ptr->widthSpinBox->value(), d_ptr->heightSpinBox->value()) / 2);
- break;
- case 2:
- d_ptr->graphicsRectItemPtr->show();
- d_ptr->rectGroupBox->show();
- break;
- default: break;
- }
-}
+ auto rectF = roundedRect.rect;
-void RoundDialog::onRectChanged(const QRectF &rectF)
-{
d_ptr->topLeftXSpinBox->blockSignals(true);
d_ptr->topLeftYSpinBox->blockSignals(true);
d_ptr->widthSpinBox->blockSignals(true);
@@ -199,91 +216,76 @@ void RoundDialog::onRectChanged(const QRectF &rectF)
d_ptr->widthSpinBox->setRange(0, d_ptr->pixmap.width() - rectF.x());
d_ptr->heightSpinBox->setRange(0, d_ptr->pixmap.height() - rectF.y());
+ d_ptr->updatePreview();
}
void RoundDialog::onTopLeftXChanged(int value)
{
- QRectF rectF = d_ptr->graphicsRectItemPtr->rect();
- QPointF point1 = rectF.topLeft();
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ QPointF point1 = roundedRect.rect.topLeft();
point1.setX(value);
- d_ptr->graphicsRectItemPtr->setRect(QRectF(point1, rectF.bottomRight()));
- d_ptr->graphicsRectItemPtr->update();
+ roundedRect.rect = QRectF(point1, roundedRect.rect.bottomRight());
+ d_ptr->setRoundedRect(roundedRect);
}
void RoundDialog::onTopLeftYChanged(int value)
{
- QRectF rectF = d_ptr->graphicsRectItemPtr->rect();
- QPointF point1 = rectF.topLeft();
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ QPointF point1 = roundedRect.rect.topLeft();
point1.setY(value);
- d_ptr->graphicsRectItemPtr->setRect(QRectF(point1, rectF.bottomRight()));
- d_ptr->graphicsRectItemPtr->update();
+ roundedRect.rect = QRectF(point1, roundedRect.rect.bottomRight());
+ d_ptr->setRoundedRect(roundedRect);
}
void RoundDialog::onWidthChanged(int value)
{
- QRectF rectF = d_ptr->graphicsRectItemPtr->rect();
- QPointF point1 = rectF.bottomRight();
- point1.setX(value + rectF.x());
- d_ptr->graphicsRectItemPtr->setRect(QRectF(rectF.topLeft(), point1));
- d_ptr->graphicsRectItemPtr->update();
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ QPointF point1 = roundedRect.rect.bottomRight();
+ point1.setX(value + roundedRect.rect.x());
+ roundedRect.rect = QRectF(roundedRect.rect.topLeft(), point1);
+ d_ptr->setRoundedRect(roundedRect);
}
void RoundDialog::onHeightChanged(int value)
{
- QRectF rectF = d_ptr->graphicsRectItemPtr->rect();
- QPointF point1 = rectF.bottomRight();
- point1.setY(value + rectF.y());
- d_ptr->graphicsRectItemPtr->setRect(QRectF(rectF.topLeft(), point1));
- d_ptr->graphicsRectItemPtr->update();
-}
-
-auto radiusImage(const QPixmap &pixmap, int radius) -> QImage
-{
- QImage image(pixmap.size(), QImage::Format_ARGB32);
- image.fill(Qt::transparent);
- QPainter painter(&image);
- painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
- painter.setBrush(pixmap);
- painter.setPen(Qt::transparent);
- painter.drawRoundedRect(pixmap.rect(), radius, radius);
- return image;
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ QPointF point1 = roundedRect.rect.bottomRight();
+ point1.setY(value + roundedRect.rect.y());
+ roundedRect.rect = QRectF(roundedRect.rect.topLeft(), point1);
+ d_ptr->setRoundedRect(roundedRect);
}
void RoundDialog::onRadiusChanged(int value)
{
- if (d_ptr->cropWidget->isVisible()) {
- return;
- }
-
- d_ptr->imageView->setPixmap(QPixmap::fromImage(radiusImage(d_ptr->cutPixmap, value)));
+ auto roundedRect = d_ptr->roundedRectItemPtr->roundedRect();
+ roundedRect.xRadius = roundedRect.yRadius = value;
+ d_ptr->setRoundedRect(roundedRect);
}
void RoundDialog::setupUI()
{
- QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
+ auto *splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(d_ptr->imageView);
splitter->addWidget(toolWidget());
splitter->setStretchFactor(0, 1);
splitter->setStretchFactor(1, 1);
splitter->setSizes({INT_MAX, 1});
- QVBoxLayout *layout = new QVBoxLayout(this);
+ auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(QMargins());
layout->addWidget(splitter);
}
void RoundDialog::buildConnect()
{
- connect(d_ptr->buttonGroup, &QButtonGroup::idClicked, this, &RoundDialog::onButtonClicked);
- connect(d_ptr->graphicsRectItemPtr.data(),
- &Graphics::GraphicsRectItem::rectChanged,
+ connect(d_ptr->roundedRectItemPtr.data(),
+ &Graphics::GraphicsRoundedRectItem::roundedRectChanged,
this,
- &RoundDialog::onRectChanged);
+ &RoundDialog::onRoundedRectChanged);
connect(d_ptr->radiusSpinBox,
QOverload::of(&QSpinBox::valueChanged),
this,
&RoundDialog::onRadiusChanged);
- d_ptr->buttonGroup->button(1)->click();
}
void RoundDialog::buildConnect2()
@@ -312,39 +314,22 @@ void RoundDialog::buildConnect2()
QWidget *RoundDialog::toolWidget()
{
- QRadioButton *radioButton1 = new QRadioButton(tr("Original Image"), this);
- QRadioButton *radioButton2 = new QRadioButton(tr("Rect Crop"), this);
- d_ptr->buttonGroup->addButton(radioButton1, 1);
- d_ptr->buttonGroup->addButton(radioButton2, 2);
-
- QFormLayout *formLayout = new QFormLayout(d_ptr->rectGroupBox);
+ auto *formLayout = new QFormLayout(d_ptr->rectGroupBox);
formLayout->addRow(tr("TopLeft X:"), d_ptr->topLeftXSpinBox);
formLayout->addRow(tr("TopLeft Y:"), d_ptr->topLeftYSpinBox);
formLayout->addRow(tr("Width:"), d_ptr->widthSpinBox);
formLayout->addRow(tr("Height:"), d_ptr->heightSpinBox);
+ formLayout->addRow(tr("Radius:"), d_ptr->radiusSpinBox);
- QVBoxLayout *cropLayout = new QVBoxLayout(d_ptr->cropWidget);
- cropLayout->setContentsMargins(QMargins());
- cropLayout->addWidget(radioButton1);
- cropLayout->addWidget(radioButton2);
- cropLayout->addWidget(d_ptr->rectGroupBox);
-
- QPushButton *startRoundButton = new QPushButton(tr("Start Round"), this);
- startRoundButton->setCheckable(true);
- connect(startRoundButton, &QPushButton::clicked, this, &RoundDialog::onStartRound);
-
- QFormLayout *radiusLayout = new QFormLayout;
- radiusLayout->addRow(tr("Radius:"), d_ptr->radiusSpinBox);
-
- QPushButton *saveButton = new QPushButton(tr("Save"), this);
+ auto *saveButton = new QPushButton(tr("Save"), this);
connect(saveButton, &QPushButton::clicked, this, &RoundDialog::onSave);
- QWidget *toolWidget = new QWidget(this);
+ auto *toolWidget = new QWidget(this);
toolWidget->setMaximumWidth(250);
- QVBoxLayout *toolLayout = new QVBoxLayout(toolWidget);
- toolLayout->addWidget(d_ptr->cropWidget);
- toolLayout->addWidget(startRoundButton);
- toolLayout->addLayout(radiusLayout);
+ auto *toolLayout = new QVBoxLayout(toolWidget);
+ toolLayout->addWidget(new QLabel(tr("Preview:"), this));
+ toolLayout->addWidget(d_ptr->previewLabel);
+ toolLayout->addWidget(d_ptr->rectGroupBox);
toolLayout->addWidget(saveButton);
toolLayout->addStretch();
return toolWidget;
diff --git a/examples/graphics/rounddialog.hpp b/examples/graphics/rounddialog.hpp
index 44f8bcd..21ff65e 100644
--- a/examples/graphics/rounddialog.hpp
+++ b/examples/graphics/rounddialog.hpp
@@ -3,6 +3,10 @@
#include
+namespace Graphics {
+struct RoundedRect;
+}
+
class RoundDialog : public QDialog
{
Q_OBJECT
@@ -15,10 +19,8 @@ class RoundDialog : public QDialog
void setPixmap(const QPixmap &pixmap);
private slots:
- void onStartRound(bool checked);
void onSave();
- void onButtonClicked(int id);
- void onRectChanged(const QRectF &rectF);
+ void onRoundedRectChanged(const Graphics::RoundedRect &roundedRect);
void onTopLeftXChanged(int value);
void onTopLeftYChanged(int value);
void onWidthChanged(int value);
diff --git a/examples/graphics/subtitlsplicingwidget.cc b/examples/graphics/subtitlsplicingwidget.cc
index 2009c1b..88f517d 100644
--- a/examples/graphics/subtitlsplicingwidget.cc
+++ b/examples/graphics/subtitlsplicingwidget.cc
@@ -27,7 +27,7 @@ class GenerateTask : public QRunnable
auto clipImage = i.copy(info.imageRect);
QImage tmpImage(image.width(),
image.height() + clipImage.height(),
- QImage::Format_ARGB32);
+ QImage::Format_RGBA8888_Premultiplied);
QPainter painter(&tmpImage);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter.drawImage(image.rect(), image);
@@ -141,7 +141,7 @@ void SubtitlSplicingWidget::onGenerated()
// auto clipImage = view->clipImage();
// QImage tmpImage(image.width(),
// image.height() + clipImage.height(),
- // QImage::Format_ARGB32);
+ // QImage::Format_RGBA8888_Premultiplied);
// QPainter painter(&tmpImage);
// painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
// painter.drawImage(image.rect(), image);
diff --git a/src/graphics/CMakeLists.txt b/src/graphics/CMakeLists.txt
index 491e290..fdf3df1 100644
--- a/src/graphics/CMakeLists.txt
+++ b/src/graphics/CMakeLists.txt
@@ -20,6 +20,8 @@ set(PROJECT_SOURCES
graphicsringitem.h
graphicsrotatedrectitem.cpp
graphicsrotatedrectitem.h
+ graphicsroundedrectitem.cc
+ graphicsroundedrectitem.hpp
graphicstextitem.cc
graphicstextitem.hpp
imageview.cpp
diff --git a/src/graphics/basicgraphicsitem.cpp b/src/graphics/basicgraphicsitem.cpp
index 0a941f6..a3b2350 100644
--- a/src/graphics/basicgraphicsitem.cpp
+++ b/src/graphics/basicgraphicsitem.cpp
@@ -14,17 +14,19 @@ namespace Graphics {
class BasicGraphicsItem::BasicGraphicsItemPrivate
{
public:
- explicit BasicGraphicsItemPrivate(QObject *parent)
- : q_ptr(parent)
+ explicit BasicGraphicsItemPrivate(BasicGraphicsItem *q)
+ : q_ptr(q)
{}
- QObject *q_ptr;
+ BasicGraphicsItem *q_ptr;
+
QString name;
BasicGraphicsItem::MouseRegion mouseRegin = BasicGraphicsItem::None;
int hoveredDotIndex = -1;
QPointF clickedPos;
QPolygonF cache;
double margin = 10;
+ bool showBoundingRect = false;
};
BasicGraphicsItem::BasicGraphicsItem(QGraphicsItem *parent)
@@ -84,6 +86,17 @@ void BasicGraphicsItem::setItemEditable(bool editable)
setAcceptHoverEvents(editable);
}
+void BasicGraphicsItem::setShowBoundingRect(bool show)
+{
+ d_ptr->showBoundingRect = show;
+ QMetaObject::invokeMethod(this, [this] { update(); }, Qt::QueuedConnection);
+}
+
+bool BasicGraphicsItem::showBoundingRect() const
+{
+ return d_ptr->showBoundingRect;
+}
+
//QVariant BasicGraphicsItem::itemChange(QGraphicsItem::GraphicsItemChange change,
// const QVariant &value)
//{
@@ -187,6 +200,18 @@ void BasicGraphicsItem::drawAnchor(QPainter *painter)
}
}
+void BasicGraphicsItem::drawBoundingRect(QPainter *painter)
+{
+ if (!d_ptr->showBoundingRect || !isValid()) {
+ return;
+ }
+
+ QPen outline(Qt::black, 1, Qt::DashLine);
+ outline.setCosmetic(true);
+ painter->setPen(outline);
+ painter->drawRect(boundingRect());
+}
+
void BasicGraphicsItem::setMyCursor(const QPointF ¢er, const QPointF &pos)
{
double angle = QLineF(center, pos).angle();
diff --git a/src/graphics/basicgraphicsitem.h b/src/graphics/basicgraphicsitem.h
index d0c37d9..9f78ec4 100644
--- a/src/graphics/basicgraphicsitem.h
+++ b/src/graphics/basicgraphicsitem.h
@@ -15,7 +15,16 @@ class GRAPHICS_EXPORT BasicGraphicsItem : public QObject, public QAbstractGraphi
Q_OBJECT
public:
// Why does add UserType not draw
- enum Shape { LINE = /*UserType +*/ 1, RECT, CIRCLE, POLYGON, RING, ARC, ROTATEDRECT };
+ enum Shape {
+ LINE = /*UserType +*/ 1,
+ RECT,
+ ROUNDEDRECT,
+ ROTATEDRECT,
+ CIRCLE,
+ POLYGON,
+ RING,
+ ARC
+ };
Q_ENUM(Shape)
enum MouseRegion { DotRegion, All, Edge, None };
@@ -35,6 +44,9 @@ class GRAPHICS_EXPORT BasicGraphicsItem : public QObject, public QAbstractGraphi
void setItemEditable(bool editable);
+ void setShowBoundingRect(bool show);
+ bool showBoundingRect() const;
+
protected:
//QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
@@ -52,6 +64,7 @@ class GRAPHICS_EXPORT BasicGraphicsItem : public QObject, public QAbstractGraphi
[[nodiscard]] auto hoveredDotIndex() const -> int;
void drawAnchor(QPainter *painter);
+ void drawBoundingRect(QPainter *painter);
void setMyCursor(const QPointF ¢er, const QPointF &pos);
diff --git a/src/graphics/graphics.pro b/src/graphics/graphics.pro
index 57f0c75..eb713b0 100644
--- a/src/graphics/graphics.pro
+++ b/src/graphics/graphics.pro
@@ -16,6 +16,7 @@ SOURCES += \
graphicsrectitem.cpp \
graphicsringitem.cpp \
graphicsrotatedrectitem.cpp \
+ graphicsroundedrectitem.cc \
graphicstextitem.cc \
imageview.cpp
@@ -31,6 +32,7 @@ HEADERS += \
graphicsrectitem.h \
graphicsringitem.h \
graphicsrotatedrectitem.h \
+ graphicsroundedrectitem.hpp \
graphicstextitem.hpp \
imageview.h
diff --git a/src/graphics/graphicsarcitem.cpp b/src/graphics/graphicsarcitem.cpp
index 74a5185..319630d 100644
--- a/src/graphics/graphicsarcitem.cpp
+++ b/src/graphics/graphicsarcitem.cpp
@@ -241,7 +241,7 @@ auto GraphicsArcItem::isValid() const -> bool
auto GraphicsArcItem::type() const -> int
{
- return ARC;
+ return Shape::ARC;
}
auto GraphicsArcItem::boundingRect() const -> QRectF
@@ -356,7 +356,7 @@ void GraphicsArcItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
return;
}
BasicGraphicsItem::hoverMoveEvent(event);
- if (mouseRegion() == DotRegion){
+ if (mouseRegion() == DotRegion) {
return;
}
setMouseRegion(BasicGraphicsItem::None);
@@ -404,6 +404,7 @@ void GraphicsArcItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
}
if (option->state & QStyle::State_Selected) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
diff --git a/src/graphics/graphicscircleitem.cpp b/src/graphics/graphicscircleitem.cpp
index 1482398..71f908b 100644
--- a/src/graphics/graphicscircleitem.cpp
+++ b/src/graphics/graphicscircleitem.cpp
@@ -196,6 +196,7 @@ void GraphicsCircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem
}
if ((option->state & QStyle::State_Selected)) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
diff --git a/src/graphics/graphicslineitem.cpp b/src/graphics/graphicslineitem.cpp
index 8797192..fb6e164 100644
--- a/src/graphics/graphicslineitem.cpp
+++ b/src/graphics/graphicslineitem.cpp
@@ -123,6 +123,7 @@ void GraphicsLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
}
if (option->state & QStyle::State_Selected) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
diff --git a/src/graphics/graphicspixmapitem.cpp b/src/graphics/graphicspixmapitem.cpp
index 3880dc9..39ccbaa 100644
--- a/src/graphics/graphicspixmapitem.cpp
+++ b/src/graphics/graphicspixmapitem.cpp
@@ -46,8 +46,9 @@ GraphicsPixmapItem::~GraphicsPixmapItem() {}
void GraphicsPixmapItem::setCustomPixmap(const QPixmap &pixmap)
{
setPixmap(pixmap);
- if (pixmap.size() != d_ptr->mask.size())
+ if (pixmap.size() != d_ptr->mask.size()) {
clearMask();
+ }
setPenSize(qMin(pixmap.width(), pixmap.height()) / 20.0);
}
@@ -59,22 +60,7 @@ void GraphicsPixmapItem::setMaskImage(const QImage &mask)
if (pixmap().size() != mask.size()) {
return;
}
- // generate 4 channel color mask image
- QImage temp = QImage(pixmap().size(), QImage::Format_ARGB32);
- temp.fill(Qt::transparent);
- QRgb dstRgb = d_ptr->color.rgb();
- int cols = temp.width();
- int rows = temp.height();
- for (int y = 0; y < rows; y++) {
- QRgb *dst_row = (QRgb *) temp.scanLine(y);
- const uchar *mask_row = mask.scanLine(y);
- for (int x = 0; x < cols; x++) {
- if (mask_row[x] != 0) {
- dst_row[x] = dstRgb;
- }
- }
- }
- d_ptr->mask = temp;
+ d_ptr->mask = mask;
update();
}
@@ -140,7 +126,7 @@ auto GraphicsPixmapItem::maskColor2() -> QColor
void GraphicsPixmapItem::clearMask()
{
if (!pixmap().isNull()) {
- d_ptr->mask = QImage(pixmap().size(), QImage::Format_ARGB32);
+ d_ptr->mask = QImage(pixmap().size(), QImage::Format_RGBA8888_Premultiplied);
d_ptr->mask.fill(Qt::transparent);
}
update();
diff --git a/src/graphics/graphicspolygonitem.cpp b/src/graphics/graphicspolygonitem.cpp
index 1e03fc7..0697cd7 100644
--- a/src/graphics/graphicspolygonitem.cpp
+++ b/src/graphics/graphicspolygonitem.cpp
@@ -1,8 +1,8 @@
#include "graphicspolygonitem.h"
#include "graphics.h"
-#include
#include
+#include
#include
#include
@@ -18,17 +18,17 @@ struct GraphicsPolygonItem::GraphicsPolygonItemPrivate
GraphicsPolygonItem::GraphicsPolygonItem(QGraphicsItem *parent)
: BasicGraphicsItem(parent)
- , d_ptr(new GraphicsPolygonItemPrivate){}
+ , d_ptr(new GraphicsPolygonItemPrivate)
+{}
-GraphicsPolygonItem::GraphicsPolygonItem(const QPolygonF& polygon,
- QGraphicsItem* parent)
+GraphicsPolygonItem::GraphicsPolygonItem(const QPolygonF &polygon, QGraphicsItem *parent)
: BasicGraphicsItem(parent)
, d_ptr(new GraphicsPolygonItemPrivate)
{
setPolygon(polygon);
}
-GraphicsPolygonItem::~GraphicsPolygonItem(){}
+GraphicsPolygonItem::~GraphicsPolygonItem() {}
inline auto checkPolygon(const QPolygonF &ply, const double margin) -> bool
{
@@ -71,7 +71,7 @@ void GraphicsPolygonItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
return;
}
QPolygonF pts_tmp = cache();
- pts_tmp.append( event->pos());
+ pts_tmp.append(event->pos());
pointsChanged(pts_tmp);
}
@@ -105,7 +105,7 @@ void GraphicsPolygonItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
void GraphicsPolygonItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
{
QPolygonF pts_tmp = cache();
- if(pts_tmp.size() > 0){
+ if (pts_tmp.size() > 0) {
pts_tmp.append(event->scenePos());
showHoverPolygon(pts_tmp);
}
@@ -113,9 +113,7 @@ void GraphicsPolygonItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
BasicGraphicsItem::hoverMoveEvent(event);
}
-void GraphicsPolygonItem::paint(QPainter *painter,
- const QStyleOptionGraphicsItem *option,
- QWidget*)
+void GraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
painter->setRenderHint(QPainter::Antialiasing);
double linew = 2 * pen().widthF() / painter->transform().m11();
@@ -129,6 +127,7 @@ void GraphicsPolygonItem::paint(QPainter *painter,
}
if (option->state & QStyle::State_Selected) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
@@ -159,4 +158,4 @@ void GraphicsPolygonItem::showHoverPolygon(const QPolygonF &ply)
update();
}
-}
+} // namespace Graphics
diff --git a/src/graphics/graphicsrectitem.cpp b/src/graphics/graphicsrectitem.cpp
index 003236a..db3b322 100644
--- a/src/graphics/graphicsrectitem.cpp
+++ b/src/graphics/graphicsrectitem.cpp
@@ -1,222 +1,55 @@
#include "graphicsrectitem.h"
-#include "graphics.h"
-
-#include
-#include
-#include
-#include
-#include
namespace Graphics {
-struct GraphicsRectItem::GraphicsRectItemPrivate
-{
- QRectF rect;
- QRectF tempRect;
- bool linehovered = false;
- QLineF hoveredLine;
-};
-
GraphicsRectItem::GraphicsRectItem(QGraphicsItem *parent)
- : BasicGraphicsItem(parent)
- , d_ptr(new GraphicsRectItemPrivate)
-{}
-
-GraphicsRectItem::GraphicsRectItem(const QRectF &rectF, QGraphicsItem *parent)
- : BasicGraphicsItem(parent)
- , d_ptr(new GraphicsRectItemPrivate)
+ : GraphicsRoundedRectItem(parent)
{
- setRect(rectF);
+ m_roundedRect = m_tempRoundedRect = RoundedRect(QRectF());
+ buildConnect();
}
-GraphicsRectItem::~GraphicsRectItem() {}
-
-inline auto checkRect(const QRectF &rect, const double margin) -> bool
+GraphicsRectItem::GraphicsRectItem(const QRectF &rect, QGraphicsItem *parent)
+ : GraphicsRoundedRectItem(parent)
{
- return rect.isValid() && rect.x() > 0 && rect.y() > 0 && rect.width() > margin
- && rect.height() > margin;
+ buildConnect();
+ setRect(rect);
}
+GraphicsRectItem::~GraphicsRectItem() {}
+
void GraphicsRectItem::setRect(const QRectF &rect)
{
- if (!checkRect(rect, margin())) {
- return;
- }
- prepareGeometryChange();
- d_ptr->rect = rect;
- QPolygonF cache;
- cache << rect.topLeft() << rect.bottomRight();
- setCache(cache);
- emit rectChanged(d_ptr->rect);
+ RoundedRect roundedRect(rect);
+ setRoundedRect(roundedRect);
}
-auto GraphicsRectItem::rect() const -> QRectF
+QRectF GraphicsRectItem::rect() const
{
- return d_ptr->rect;
+ return roundedRect().rect;
}
-auto GraphicsRectItem::isValid() const -> bool
+bool GraphicsRectItem::isValid() const
{
- return checkRect(d_ptr->rect, margin());
+ return GraphicsRoundedRectItem::isValid();
}
-auto GraphicsRectItem::type() const -> int
+int GraphicsRectItem::type() const
{
return RECT;
}
-void GraphicsRectItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
-{
- if (event->button() != Qt::LeftButton) {
- return BasicGraphicsItem::mousePressEvent(event);
- }
- setClickedPos(event->scenePos());
- if (isValid()) {
- return;
- }
- QPointF point = event->pos();
- QPolygonF pts_tmp = cache();
- pts_tmp.append(point);
- pointsChanged(pts_tmp);
-}
-
-auto polygonFromRect(const QRectF &rect) -> QPolygonF
-{
- QPolygonF ply;
- ply.append(rect.topLeft());
- ply.append(rect.topRight());
- ply.append(rect.bottomRight());
- ply.append(rect.bottomLeft());
- return ply;
-}
-
-void GraphicsRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
-{
- if ((event->buttons() & Qt::LeftButton) == 0 || !isValid()) {
- return;
- }
- if (!isSelected()) {
- setSelected(true);
- }
- QPointF point = event->scenePos();
- QPolygonF pts_tmp = cache();
- QPointF dp = point - clickedPos();
- setClickedPos(point);
-
- if (d_ptr->linehovered) {
- QPointF p1 = d_ptr->hoveredLine.p1();
- QPointF p2 = d_ptr->hoveredLine.p2();
-
- QPolygonF ply1 = polygonFromRect(rect());
- int index0 = ply1.indexOf(p1);
- int index1 = ply1.indexOf(p2);
- if (index0 < 0 || index1 < 0) {
- return;
- }
- if (abs(p1.x() - p2.x()) < 0.0001) { //vertical line
- p1 = p1 + QPointF(dp.x(), 0);
- p2 = p2 + QPointF(dp.x(), 0);
- } else {
- p1 = p1 + QPointF(0, dp.y());
- p2 = p2 + QPointF(0, dp.y());
- }
-
- ply1.replace(index0, p1);
- ply1.replace(index1, p2);
-
- d_ptr->hoveredLine = QLineF(p1, p2);
-
- pts_tmp.clear();
- pts_tmp.append(ply1.at(0));
- pts_tmp.append(ply1.at(2));
- } else {
- switch (mouseRegion()) {
- case DotRegion: {
- int index = hoveredDotIndex();
- pts_tmp.replace(index, point);
- } break;
- case All: pts_tmp.translate(dp); break;
- default: return;
- }
- }
- pointsChanged(pts_tmp);
-}
-
-void GraphicsRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
-{
- QPointF point = event->scenePos();
- QPolygonF pts_tmp = cache();
- if (pts_tmp.size() == 1) {
- pts_tmp.append(point);
- showHoverRect(pts_tmp);
- }
- if (!isValid()) {
- return;
- }
- BasicGraphicsItem::hoverMoveEvent(event);
- if (mouseRegion() == DotRegion) {
- return;
- }
- QPolygonF ply = polygonFromRect(rect());
- for (int i = 0; i < ply.count(); ++i) {
- QLineF pl(ply.at(i), ply.at((i + 1) % 4));
- QPolygonF tmp = Graphics::boundingFromLine(pl, margin() / 4);
- if (tmp.containsPoint(point, Qt::OddEvenFill)) {
- d_ptr->linehovered = true;
- d_ptr->hoveredLine = pl;
- setCursor(Graphics::curorFromAngle(pl.angle()));
- return;
- }
- }
-
- d_ptr->linehovered = false;
-}
-
-void GraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
-{
- painter->setRenderHint(QPainter::Antialiasing);
- double linew = 2 * pen().widthF() / painter->transform().m11();
- painter->setPen(QPen(LineColor, linew));
- setMargin(painter->transform().m11());
-
- if (isValid()) {
- painter->drawRect(d_ptr->rect);
- } else {
- painter->drawRect(d_ptr->tempRect);
- }
- if (option->state & QStyle::State_Selected) {
- drawAnchor(painter);
- }
-}
-
-void GraphicsRectItem::pointsChanged(const QPolygonF &ply)
+void GraphicsRectItem::onRoundedRectChanged(const RoundedRect &roundedRect)
{
- QRectF rect = scene()->sceneRect();
- if (!rect.contains(ply.last())) {
- return;
- }
- switch (ply.size()) {
- case 1: setCache(ply); break;
- case 2: {
- QRectF rect_(ply[0], ply[1]);
- if (checkRect(rect_, margin())) {
- setRect(rect_);
- } else {
- return;
- }
- } break;
- default: return;
- }
- update();
+ emit rectChanged(roundedRect.rect);
}
-void GraphicsRectItem::showHoverRect(const QPolygonF &ply)
+void GraphicsRectItem::buildConnect()
{
- if (ply.size() != 2) {
- return;
- }
- d_ptr->tempRect = QRectF(ply[0], ply[1]);
- update();
+ connect(this,
+ &GraphicsRectItem::roundedRectChanged,
+ this,
+ &GraphicsRectItem::onRoundedRectChanged);
}
} // namespace Graphics
diff --git a/src/graphics/graphicsrectitem.h b/src/graphics/graphicsrectitem.h
index 21a5aa0..8279338 100644
--- a/src/graphics/graphicsrectitem.h
+++ b/src/graphics/graphicsrectitem.h
@@ -1,19 +1,18 @@
-#ifndef GRAPHICSRECTITEM_H
-#define GRAPHICSRECTITEM_H
+#pragma once
-#include "basicgraphicsitem.h"
+#include "graphicsroundedrectitem.hpp"
namespace Graphics {
-class GRAPHICS_EXPORT GraphicsRectItem : public BasicGraphicsItem
+class GRAPHICS_EXPORT GraphicsRectItem : public GraphicsRoundedRectItem
{
Q_OBJECT
public:
explicit GraphicsRectItem(QGraphicsItem *parent = nullptr);
- explicit GraphicsRectItem(const QRectF &, QGraphicsItem *parent = nullptr);
+ explicit GraphicsRectItem(const QRectF &rect, QGraphicsItem *parent = nullptr);
~GraphicsRectItem() override;
- void setRect(const QRectF &);
+ void setRect(const QRectF &rect);
[[nodiscard]] auto rect() const -> QRectF;
[[nodiscard]] auto isValid() const -> bool override;
@@ -22,22 +21,11 @@ class GRAPHICS_EXPORT GraphicsRectItem : public BasicGraphicsItem
signals:
void rectChanged(const QRectF &rectF);
-protected:
- void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
- void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
- void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
- void paint(QPainter *painter,
- const QStyleOptionGraphicsItem *option,
- QWidget *widget = nullptr) override;
+private slots:
+ void onRoundedRectChanged(const RoundedRect &roundedRect);
private:
- void pointsChanged(const QPolygonF &ply);
- void showHoverRect(const QPolygonF &ply);
-
- struct GraphicsRectItemPrivate;
- QScopedPointer d_ptr;
+ void buildConnect();
};
} // namespace Graphics
-
-#endif // GRAPHICSRECTITEM_H
diff --git a/src/graphics/graphicsringitem.cpp b/src/graphics/graphicsringitem.cpp
index 746e67d..c6e1896 100644
--- a/src/graphics/graphicsringitem.cpp
+++ b/src/graphics/graphicsringitem.cpp
@@ -241,6 +241,7 @@ void GraphicsRingItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *
if (option->state & QStyle::State_Selected) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
diff --git a/src/graphics/graphicsrotatedrectitem.cpp b/src/graphics/graphicsrotatedrectitem.cpp
index 848f4c4..9ed7d76 100644
--- a/src/graphics/graphicsrotatedrectitem.cpp
+++ b/src/graphics/graphicsrotatedrectitem.cpp
@@ -233,6 +233,7 @@ void GraphicsRotatedRectItem::paint(QPainter *painter,
if (!isValid() || (option->state & QStyle::State_Selected)) {
drawAnchor(painter);
+ drawBoundingRect(painter);
}
}
diff --git a/src/graphics/graphicsroundedrectitem.cc b/src/graphics/graphicsroundedrectitem.cc
new file mode 100644
index 0000000..b27e98a
--- /dev/null
+++ b/src/graphics/graphicsroundedrectitem.cc
@@ -0,0 +1,243 @@
+#include "graphicsroundedrectitem.hpp"
+#include "graphics.h"
+
+#include
+#include
+#include
+#include
+#include
+
+namespace Graphics {
+
+inline auto checkRect(const QRectF &rect, const double margin) -> bool
+{
+ return rect.isValid() && rect.x() > 0 && rect.y() > 0 && rect.width() > margin
+ && rect.height() > margin;
+}
+
+RoundedRect::RoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius)
+{
+ this->rect = rect;
+ this->xRadius = xRadius;
+ this->yRadius = yRadius;
+}
+
+bool RoundedRect::isValid() const
+{
+ return rect.isValid() && xRadius >= 0 && yRadius >= 0 && xRadius < rect.width() / 2
+ && yRadius < rect.height() / 2;
+}
+
+class GraphicsRoundedRectItem::GraphicsRoundedRectItemPrivate
+{
+public:
+ explicit GraphicsRoundedRectItemPrivate(GraphicsRoundedRectItem *q)
+ : q_ptr(q)
+ {
+ qRegisterMetaType("Graphics::RoundedRect");
+ }
+
+ GraphicsRoundedRectItem *q_ptr = nullptr;
+
+ bool linehovered = false;
+ QLineF hoveredLine;
+};
+
+GraphicsRoundedRectItem::GraphicsRoundedRectItem(QGraphicsItem *parent)
+ : BasicGraphicsItem(parent)
+ , d_ptr(new GraphicsRoundedRectItemPrivate(this))
+{}
+
+GraphicsRoundedRectItem::GraphicsRoundedRectItem(const RoundedRect &roundedRect,
+ QGraphicsItem *parent)
+ : BasicGraphicsItem(parent)
+ , d_ptr(new GraphicsRoundedRectItemPrivate(this))
+{
+ setRoundedRect(roundedRect);
+}
+
+GraphicsRoundedRectItem::~GraphicsRoundedRectItem() {}
+
+void GraphicsRoundedRectItem::setRoundedRect(const RoundedRect &roundedRect)
+{
+ if (!roundedRect.isValid() || !checkRect(roundedRect.rect, margin())) {
+ return;
+ }
+ prepareGeometryChange();
+ m_roundedRect = roundedRect;
+ QPolygonF cache;
+ cache << roundedRect.rect.topLeft() << roundedRect.rect.bottomRight();
+ setCache(cache);
+ emit roundedRectChanged(m_roundedRect);
+}
+
+RoundedRect GraphicsRoundedRectItem::roundedRect() const
+{
+ return m_roundedRect;
+}
+
+auto GraphicsRoundedRectItem::isValid() const -> bool
+{
+ return m_roundedRect.isValid() && checkRect(m_roundedRect.rect, margin());
+}
+
+auto GraphicsRoundedRectItem::type() const -> int
+{
+ return ROUNDEDRECT;
+}
+
+void GraphicsRoundedRectItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() != Qt::LeftButton) {
+ return BasicGraphicsItem::mousePressEvent(event);
+ }
+ setClickedPos(event->scenePos());
+ if (isValid()) {
+ return;
+ }
+ QPointF point = event->pos();
+ QPolygonF pts_tmp = cache();
+ pts_tmp.append(point);
+ pointsChanged(pts_tmp);
+}
+
+auto polygonFromRect(const QRectF &rect) -> QPolygonF
+{
+ QPolygonF ply;
+ ply.append(rect.topLeft());
+ ply.append(rect.topRight());
+ ply.append(rect.bottomRight());
+ ply.append(rect.bottomLeft());
+ return ply;
+}
+
+void GraphicsRoundedRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if ((event->buttons() & Qt::LeftButton) == 0 || !isValid()) {
+ return;
+ }
+ if (!isSelected()) {
+ setSelected(true);
+ }
+ QPointF point = event->scenePos();
+ QPolygonF pts_tmp = cache();
+ QPointF dp = point - clickedPos();
+ setClickedPos(point);
+
+ if (d_ptr->linehovered) {
+ QPointF p1 = d_ptr->hoveredLine.p1();
+ QPointF p2 = d_ptr->hoveredLine.p2();
+
+ QPolygonF ply1 = polygonFromRect(m_roundedRect.rect);
+ int index0 = ply1.indexOf(p1);
+ int index1 = ply1.indexOf(p2);
+ if (index0 < 0 || index1 < 0) {
+ return;
+ }
+ if (abs(p1.x() - p2.x()) < 0.0001) { //vertical line
+ p1 = p1 + QPointF(dp.x(), 0);
+ p2 = p2 + QPointF(dp.x(), 0);
+ } else {
+ p1 = p1 + QPointF(0, dp.y());
+ p2 = p2 + QPointF(0, dp.y());
+ }
+
+ ply1.replace(index0, p1);
+ ply1.replace(index1, p2);
+
+ d_ptr->hoveredLine = QLineF(p1, p2);
+
+ pts_tmp.clear();
+ pts_tmp.append(ply1.at(0));
+ pts_tmp.append(ply1.at(2));
+ } else {
+ switch (mouseRegion()) {
+ case DotRegion: {
+ int index = hoveredDotIndex();
+ pts_tmp.replace(index, point);
+ } break;
+ case All: pts_tmp.translate(dp); break;
+ default: return;
+ }
+ }
+ pointsChanged(pts_tmp);
+}
+
+void GraphicsRoundedRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ QPointF point = event->scenePos();
+ QPolygonF pts_tmp = cache();
+ if (pts_tmp.size() == 1) {
+ pts_tmp.append(point);
+ showHoverRect(pts_tmp);
+ }
+ if (!isValid()) {
+ return;
+ }
+ BasicGraphicsItem::hoverMoveEvent(event);
+ if (mouseRegion() == DotRegion) {
+ return;
+ }
+ QPolygonF ply = polygonFromRect(m_roundedRect.rect);
+ for (int i = 0; i < ply.count(); ++i) {
+ QLineF pl(ply.at(i), ply.at((i + 1) % 4));
+ QPolygonF tmp = Graphics::boundingFromLine(pl, margin() / 4);
+ if (tmp.containsPoint(point, Qt::OddEvenFill)) {
+ d_ptr->linehovered = true;
+ d_ptr->hoveredLine = pl;
+ setCursor(Graphics::curorFromAngle(pl.angle()));
+ return;
+ }
+ }
+
+ d_ptr->linehovered = false;
+}
+
+void GraphicsRoundedRectItem::paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *)
+{
+ painter->setRenderHint(QPainter::Antialiasing);
+ double linew = 2 * pen().widthF() / painter->transform().m11();
+ painter->setPen(QPen(LineColor, linew));
+ setMargin(painter->transform().m11());
+ auto roundedRect = isValid() ? m_roundedRect : m_tempRoundedRect;
+ painter->drawRoundedRect(roundedRect.rect, roundedRect.xRadius, roundedRect.yRadius);
+
+ if (option->state & QStyle::State_Selected) {
+ drawAnchor(painter);
+ drawBoundingRect(painter);
+ }
+}
+
+void GraphicsRoundedRectItem::pointsChanged(const QPolygonF &ply)
+{
+ QRectF rect = scene()->sceneRect();
+ if (!rect.contains(ply.last())) {
+ return;
+ }
+ switch (ply.size()) {
+ case 1: setCache(ply); break;
+ case 2: {
+ QRectF rect_(ply[0], ply[1]);
+ if (checkRect(rect_, margin())) {
+ setRoundedRect({rect_, m_roundedRect.xRadius, m_roundedRect.yRadius});
+ } else {
+ return;
+ }
+ } break;
+ default: return;
+ }
+ update();
+}
+
+void GraphicsRoundedRectItem::showHoverRect(const QPolygonF &ply)
+{
+ if (ply.size() != 2) {
+ return;
+ }
+ m_tempRoundedRect.rect = QRectF(ply[0], ply[1]);
+ update();
+}
+
+} // namespace Graphics
diff --git a/src/graphics/graphicsroundedrectitem.hpp b/src/graphics/graphicsroundedrectitem.hpp
new file mode 100644
index 0000000..1961ac2
--- /dev/null
+++ b/src/graphics/graphicsroundedrectitem.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "basicgraphicsitem.h"
+
+namespace Graphics {
+
+struct GRAPHICS_EXPORT RoundedRect
+{
+ RoundedRect() = default;
+ RoundedRect(const QRectF &rect, qreal xRadius = 0, qreal yRadius = 0);
+
+ bool isValid() const;
+
+ QRectF rect;
+ qreal xRadius = 10;
+ qreal yRadius = 10;
+};
+
+class GRAPHICS_EXPORT GraphicsRoundedRectItem : public BasicGraphicsItem
+{
+ Q_OBJECT
+public:
+ explicit GraphicsRoundedRectItem(QGraphicsItem *parent = nullptr);
+ explicit GraphicsRoundedRectItem(const RoundedRect &roundedRect,
+ QGraphicsItem *parent = nullptr);
+ virtual ~GraphicsRoundedRectItem() override;
+
+ void setRoundedRect(const RoundedRect &roundedRect);
+ [[nodiscard]] auto roundedRect() const -> RoundedRect;
+
+ [[nodiscard]] auto isValid() const -> bool override;
+ [[nodiscard]] auto type() const -> int override;
+
+signals:
+ void roundedRectChanged(const RoundedRect &roundedRect);
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
+ void paint(QPainter *painter,
+ const QStyleOptionGraphicsItem *option,
+ QWidget *widget = nullptr) override;
+
+ RoundedRect m_roundedRect;
+ RoundedRect m_tempRoundedRect;
+
+private:
+ void pointsChanged(const QPolygonF &ply);
+ void showHoverRect(const QPolygonF &ply);
+
+ class GraphicsRoundedRectItemPrivate;
+ QScopedPointer d_ptr;
+};
+
+} // namespace Graphics