qt 6.5.1 original
14
examples/widgets/painting/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_example(basicdrawing)
|
||||
qt_internal_add_example(concentriccircles)
|
||||
qt_internal_add_example(affine)
|
||||
# qt_internal_add_example(composition) # FIXME: Seems buggy wrt. usesOpenGL function
|
||||
qt_internal_add_example(deform)
|
||||
qt_internal_add_example(gradients)
|
||||
qt_internal_add_example(pathstroke)
|
||||
qt_internal_add_example(imagecomposition)
|
||||
qt_internal_add_example(painterpaths)
|
||||
qt_internal_add_example(transformations)
|
||||
qt_internal_add_example(fontsampler)
|
11
examples/widgets/painting/README
Normal file
@ -0,0 +1,11 @@
|
||||
Qt's painting system is able to render vector graphics, images, and outline
|
||||
font-based text with sub-pixel accuracy accuracy using anti-aliasing to
|
||||
improve rendering quality.
|
||||
|
||||
These examples show the most common techniques that are used when painting
|
||||
with Qt, from basic concepts such as drawing simple primitives to the use of
|
||||
transformations.
|
||||
|
||||
|
||||
Documentation for these examples can be found via the Examples
|
||||
link in the main Qt documentation.
|
103
examples/widgets/painting/affine/CMakeLists.txt
Normal file
@ -0,0 +1,103 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(affine LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/affine")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(affine
|
||||
main.cpp
|
||||
xform.cpp xform.h
|
||||
)
|
||||
|
||||
set_target_properties(affine PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(affine PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(affine "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(affine_resource_files
|
||||
"bg1.jpg"
|
||||
"xform.cpp"
|
||||
"xform.html"
|
||||
)
|
||||
|
||||
qt_add_resources(affine "affine"
|
||||
PREFIX
|
||||
"/res/affine"
|
||||
FILES
|
||||
${affine_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS affine
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
14
examples/widgets/painting/affine/affine.pro
Normal file
@ -0,0 +1,14 @@
|
||||
SOURCES += main.cpp xform.cpp
|
||||
HEADERS += xform.h
|
||||
|
||||
QT += widgets
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += affine.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/affine
|
||||
INSTALLS += target
|
7
examples/widgets/painting/affine/affine.qrc
Normal file
@ -0,0 +1,7 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/affine">
|
||||
<file>xform.cpp</file>
|
||||
<file>xform.html</file>
|
||||
<file>bg1.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
examples/widgets/painting/affine/bg1.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
27
examples/widgets/painting/affine/main.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "xform.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(affine);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
XFormWidget xformWidget(nullptr);
|
||||
QStyle *arthurStyle = new ArthurStyle;
|
||||
xformWidget.setStyle(arthurStyle);
|
||||
|
||||
const QList<QWidget *> widgets = xformWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets) {
|
||||
w->setStyle(arthurStyle);
|
||||
w->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
|
||||
xformWidget.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
868
examples/widgets/painting/affine/xform.cpp
Normal file
@ -0,0 +1,868 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "xform.h"
|
||||
#include "hoverpoints.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
const int alpha = 155;
|
||||
|
||||
XFormView::XFormView(QWidget *parent)
|
||||
: ArthurFrame(parent),
|
||||
m_pixmap(QPixmap(":res/affine/bg1.jpg"))
|
||||
{
|
||||
setAttribute(Qt::WA_MouseTracking);
|
||||
|
||||
m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape);
|
||||
m_hoverPoints->setConnectionType(HoverPoints::LineConnection);
|
||||
m_hoverPoints->setEditable(false);
|
||||
m_hoverPoints->setPointSize(QSize(15, 15));
|
||||
m_hoverPoints->setShapeBrush(QBrush(QColor(151, 0, 0, alpha)));
|
||||
m_hoverPoints->setShapePen(QPen(QColor(255, 100, 50, alpha)));
|
||||
m_hoverPoints->setConnectionPen(QPen(QColor(151, 0, 0, 50)));
|
||||
m_hoverPoints->setBoundingRect(QRectF(0, 0, 500, 500));
|
||||
m_hoverPoints->setPoints(m_controlPoints);
|
||||
connect(m_hoverPoints, &HoverPoints::pointsChanged,
|
||||
this, &XFormView::updateControlPoints);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
|
||||
XFormView::XFormType XFormView::type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
QPixmap XFormView::pixmap() const
|
||||
{
|
||||
return m_pixmap;
|
||||
}
|
||||
|
||||
QString XFormView::text() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
void XFormView::setText(const QString &t)
|
||||
{
|
||||
m_text = t;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setPixmap(const QPixmap &p)
|
||||
{
|
||||
m_pixmap = p;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setType(XFormType t)
|
||||
{
|
||||
m_type = t;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::mousePressEvent(QMouseEvent *)
|
||||
{
|
||||
setDescriptionEnabled(false);
|
||||
}
|
||||
|
||||
void XFormView::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
m_hoverPoints->setBoundingRect(rect());
|
||||
ArthurFrame::resizeEvent(e);
|
||||
}
|
||||
|
||||
void XFormView::paint(QPainter *p)
|
||||
{
|
||||
p->save();
|
||||
p->setRenderHint(QPainter::Antialiasing);
|
||||
p->setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
switch (m_type) {
|
||||
case VectorType:
|
||||
drawVectorType(p);
|
||||
break;
|
||||
case PixmapType:
|
||||
drawPixmapType(p);
|
||||
break;
|
||||
case TextType:
|
||||
drawTextType(p);
|
||||
break;
|
||||
}
|
||||
p->restore();
|
||||
}
|
||||
|
||||
void XFormView::updateControlPoints(const QPolygonF &points)
|
||||
{
|
||||
QPointF trans = points.at(0) - m_controlPoints.at(0);
|
||||
|
||||
if (qAbs(points.at(0).x() - points.at(1).x()) < 10
|
||||
&& qAbs(points.at(0).y() - points.at(1).y()) < 10)
|
||||
m_hoverPoints->setPoints(m_controlPoints);
|
||||
if (!trans.isNull()) {
|
||||
m_controlPoints[0] = points.at(0);
|
||||
m_controlPoints[1] += trans;
|
||||
m_hoverPoints->setPoints(m_controlPoints);
|
||||
}
|
||||
m_controlPoints = points;
|
||||
|
||||
QLineF line(m_controlPoints.at(0), m_controlPoints.at(1));
|
||||
m_rotation = 360 - QLineF(0, 0, 1, 0).angleTo(line);
|
||||
if (trans.isNull())
|
||||
emit rotationChanged(int(m_rotation * 10));
|
||||
}
|
||||
|
||||
void XFormView::setVectorType()
|
||||
{
|
||||
m_type = VectorType;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setPixmapType()
|
||||
{
|
||||
m_type = PixmapType;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setTextType()
|
||||
{
|
||||
m_type = TextType;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setAnimation(bool animate)
|
||||
{
|
||||
timer.stop();
|
||||
if (animate)
|
||||
timer.start(25, this);
|
||||
}
|
||||
|
||||
void XFormView::changeRotation(int r)
|
||||
{
|
||||
setRotation(qreal(r) / 10);
|
||||
}
|
||||
|
||||
void XFormView::changeScale(int s)
|
||||
{
|
||||
setScale(qreal(s) / 1000);
|
||||
}
|
||||
|
||||
void XFormView::changeShear(int s)
|
||||
{
|
||||
setShear(qreal(s) / 1000);
|
||||
}
|
||||
|
||||
void XFormView::setShear(qreal s)
|
||||
{
|
||||
m_shear = s;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setScale(qreal s)
|
||||
{
|
||||
m_scale = s;
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::setRotation(qreal r)
|
||||
{
|
||||
qreal old_rot = m_rotation;
|
||||
m_rotation = r;
|
||||
|
||||
QPointF center(m_hoverPoints->points().at(0));
|
||||
QTransform m;
|
||||
m.translate(center.x(), center.y());
|
||||
m.rotate(m_rotation - old_rot);
|
||||
m.translate(-center.x(), -center.y());
|
||||
m_hoverPoints->setPoints(m_hoverPoints->points() * m);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void XFormView::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() == timer.timerId()) {
|
||||
QPointF center(m_hoverPoints->points().at(0));
|
||||
QTransform m;
|
||||
m.translate(center.x(), center.y());
|
||||
m.rotate(0.2);
|
||||
m.translate(-center.x(), -center.y());
|
||||
m_hoverPoints->setPoints(m_hoverPoints->points() * m);
|
||||
|
||||
setUpdatesEnabled(false);
|
||||
static qreal scale_inc = 0.003;
|
||||
static qreal shear_inc = -0.001;
|
||||
emit scaleChanged(int((m_scale + scale_inc) * 1000));
|
||||
emit shearChanged(int((m_shear + shear_inc) * 1000));
|
||||
if (m_scale >= 4.0 || m_scale <= 0.1)
|
||||
scale_inc = -scale_inc;
|
||||
if (m_shear >= 1.0 || m_shear <= -1.0)
|
||||
shear_inc = -shear_inc;
|
||||
setUpdatesEnabled(true);
|
||||
|
||||
m_hoverPoints->firePointChange();
|
||||
}
|
||||
}
|
||||
|
||||
#if QT_CONFIG(wheelevent)
|
||||
void XFormView::wheelEvent(QWheelEvent *e)
|
||||
{
|
||||
m_scale += e->angleDelta().y() / qreal(600);
|
||||
m_scale = qMax(qreal(0.1), qMin(qreal(4), m_scale));
|
||||
emit scaleChanged(int(m_scale*1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
void XFormView::reset()
|
||||
{
|
||||
emit rotationChanged(0);
|
||||
emit scaleChanged(1000);
|
||||
emit shearChanged(0);
|
||||
m_controlPoints = {{250, 250}, {350, 250}};
|
||||
m_hoverPoints->setPoints(m_controlPoints);
|
||||
m_hoverPoints->firePointChange();
|
||||
}
|
||||
|
||||
void XFormView::drawPixmapType(QPainter *painter)
|
||||
{
|
||||
QPointF center(m_pixmap.width() / qreal(2), m_pixmap.height() / qreal(2));
|
||||
painter->translate(m_controlPoints.at(0) - center);
|
||||
|
||||
painter->translate(center);
|
||||
painter->rotate(m_rotation);
|
||||
painter->scale(m_scale, m_scale);
|
||||
painter->shear(0, m_shear);
|
||||
painter->translate(-center);
|
||||
|
||||
painter->drawPixmap(QPointF(0, 0), m_pixmap);
|
||||
painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25,
|
||||
Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(QRectF(0, 0, m_pixmap.width(),
|
||||
m_pixmap.height()).adjusted(-2, -2, 2, 2));
|
||||
}
|
||||
|
||||
void XFormView::drawTextType(QPainter *painter)
|
||||
{
|
||||
QPainterPath path;
|
||||
QFont f("times new roman,utopia");
|
||||
f.setStyleStrategy(QFont::ForceOutline);
|
||||
f.setPointSize(72);
|
||||
f.setStyleHint(QFont::Times);
|
||||
path.addText(0, 0, f, m_text);
|
||||
|
||||
QFontMetrics fm(f);
|
||||
QRectF br(fm.boundingRect(m_text));
|
||||
QPointF center(br.center());
|
||||
painter->translate(m_controlPoints.at(0) - center);
|
||||
|
||||
painter->translate(center);
|
||||
painter->rotate(m_rotation);
|
||||
painter->scale(m_scale, m_scale);
|
||||
painter->shear(0, m_shear);
|
||||
painter->translate(-center);
|
||||
|
||||
painter->fillPath(path, Qt::black);
|
||||
|
||||
painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25,
|
||||
Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(br.adjusted(-1, -1, 1, 1));
|
||||
}
|
||||
|
||||
void XFormView::drawVectorType(QPainter *painter)
|
||||
{
|
||||
QPainterPath path;
|
||||
painter->translate(m_controlPoints.at(0) - QPointF(250,250));
|
||||
|
||||
painter->scale(0.77, 0.77);
|
||||
painter->translate(98.9154 + 30 , -217.691 - 20);
|
||||
|
||||
QRect br(-55, 275, 500, 590);
|
||||
QPoint center = br.center();
|
||||
painter->translate(center.x(), center.y());
|
||||
painter->rotate(m_rotation);
|
||||
painter->scale(m_scale, m_scale);
|
||||
painter->shear(0, m_shear);
|
||||
painter->translate(-center.x(), -center.y());
|
||||
|
||||
painter->setPen(Qt::NoPen);
|
||||
path.moveTo(120, 470);
|
||||
path.lineTo(60 + 245, 470);
|
||||
path.lineTo(60 + 245, 470 + 350);
|
||||
path.lineTo(60, 470 + 350);
|
||||
path.lineTo(60, 470 + 80);
|
||||
|
||||
painter->setBrush(Qt::white);
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor( 193, 193, 191, 255));
|
||||
path.moveTo(329.336, 727.552);
|
||||
path.cubicTo(QPointF(315.224, 726.328), QPointF(304.136, 715.816), QPointF(303.128, 694.936));
|
||||
path.cubicTo(QPointF(306.368, 639.496), QPointF(309.608, 582.112), QPointF(271.232, 545.104));
|
||||
path.cubicTo(QPointF(265.256, 499.024), QPointF(244.016, 482.104), QPointF(234.008, 452.512));
|
||||
path.lineTo(218.24, 441.208);
|
||||
path.lineTo(237.104, 411.688);
|
||||
path.lineTo(245.168, 411.904);
|
||||
path.lineTo(323.936, 571.168);
|
||||
path.lineTo(340.424, 651.448);
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(136.232, 439.696);
|
||||
path.cubicTo(QPointF(133.856, 455.248), QPointF(132.56, 470.512), QPointF(134.792, 485.272));
|
||||
path.cubicTo(QPointF(118.376, 507.592), QPointF(105.92, 530.128), QPointF(104.48, 553.312));
|
||||
path.cubicTo(QPointF(92.024, 586.504), QPointF(62.432, 614.584), QPointF(67.544, 680.104));
|
||||
path.cubicTo(QPointF(84.176, 697.456), QPointF(107.432, 713.584), QPointF(127.376, 730.36));
|
||||
path.cubicTo(QPointF(152.432, 751.312), QPointF(137.528, 778.96), QPointF(102.248, 772.408));
|
||||
path.cubicTo(QPointF(94.4, 763.768), QPointF(76.616, 709.624), QPointF(42.92, 676.288));
|
||||
path.lineTo(49.544, 632.584);
|
||||
path.lineTo(81.368, 547.408);
|
||||
path.lineTo(120.968, 484.048);
|
||||
path.lineTo(125.36, 456.688);
|
||||
path.lineTo(119.816, 386.776);
|
||||
path.lineTo(124.424, 361.216);
|
||||
path.lineTo(136.232, 439.696);
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(115.64, 341.416);
|
||||
path.cubicTo(QPointF(116.576, 336.376), QPointF(117.8, 331.624), QPointF(119.312, 327.16));
|
||||
path.lineTo(121.688, 342.784);
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(120.968, 500.464);
|
||||
path.cubicTo(QPointF(108.368, 523.792), QPointF(103.976, 546.256), QPointF(132.92, 550.216));
|
||||
path.cubicTo(QPointF(117.008, 553.888), QPointF(97.208, 568.648), QPointF(77.192, 593.488));
|
||||
path.lineTo(77.624, 543.016);
|
||||
path.lineTo(101.456, 503.272);
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(-33.256, 818.488);
|
||||
path.cubicTo(QPointF(10.52, 838.144), QPointF(41.408, 837.064), QPointF(69.272, 850.96));
|
||||
path.cubicTo(QPointF(91.304, 862.552), QPointF(113.552, 861.184), QPointF(126.944, 847.144));
|
||||
path.cubicTo(QPointF(138.32, 832.456), QPointF(146.744, 831.736), QPointF(163.52, 830.224));
|
||||
path.cubicTo(QPointF(190.952, 828.568), QPointF(217.736, 828.28), QPointF(241.928, 830.8));
|
||||
path.lineTo(269.576, 833.032);
|
||||
path.cubicTo(QPointF(269.072, 864.064), QPointF(328.04, 867.88), QPointF(345.392, 844.336));
|
||||
path.cubicTo(QPointF(366.344, 819.424), QPointF(395.144, 808.264), QPointF(419.84, 790.192));
|
||||
path.lineTo(289.304, 725.536);
|
||||
path.cubicTo(QPointF(255.824, 806.464), QPointF(131.048, 827.632), QPointF(113.768, 763.264));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(286.424, 711.568);
|
||||
path.cubicTo(QPointF(273.824, 711.496), QPointF(260.936, 715.6), QPointF(261.944, 732.16));
|
||||
path.lineTo(266.192, 776.44);
|
||||
path.lineTo(304.424, 756.64);
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, 255));
|
||||
path.moveTo(-37.36, 821.224);
|
||||
path.cubicTo(QPointF(7.136, 840.88), QPointF(38.6, 839.728), QPointF(66.968, 853.696));
|
||||
path.cubicTo(QPointF(89.36, 865.216), QPointF(111.968, 863.92), QPointF(125.648, 849.808));
|
||||
path.cubicTo(QPointF(137.24, 835.192), QPointF(145.808, 834.472), QPointF(162.872, 832.96));
|
||||
path.cubicTo(QPointF(190.736, 831.232), QPointF(218.024, 831.016), QPointF(242.648, 833.464));
|
||||
path.lineTo(270.728, 835.768);
|
||||
path.cubicTo(QPointF(270.224, 866.8), QPointF(330.272, 870.544), QPointF(347.912, 847));
|
||||
path.cubicTo(QPointF(369.224, 822.088), QPointF(398.528, 811), QPointF(423.656, 792.856));
|
||||
path.lineTo(290.816, 728.272);
|
||||
path.cubicTo(QPointF(256.76, 809.128), QPointF(129.824, 830.296), QPointF(112.256, 766));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(183, 114, 0, 255));
|
||||
path.moveTo(382.328, 691.984);
|
||||
path.cubicTo(QPointF(403.64, 698.968), QPointF(389.888, 720.28), QPointF(400.76, 732.52));
|
||||
path.cubicTo(QPointF(405.44, 742.888), QPointF(415.304, 752.032), QPointF(431.792, 760.528));
|
||||
path.cubicTo(QPointF(459.368, 774.424), QPointF(426.248, 799.336), QPointF(392.768, 812.08));
|
||||
path.cubicTo(QPointF(351.944, 825.616), QPointF(344.024, 862.912), QPointF(299.312, 851.896));
|
||||
path.cubicTo(QPointF(283.112, 846.496), QPointF(278.36, 831.808), QPointF(278.864, 809.128));
|
||||
path.cubicTo(QPointF(284.264, 762.76), QPointF(277.784, 730.432), QPointF(278.792, 698.824));
|
||||
path.cubicTo(QPointF(278.72, 686.152), QPointF(283.544, 684.64), QPointF(307.232, 687.952));
|
||||
path.cubicTo(QPointF(310.04, 726.328), QPointF(352.376, 727.336), QPointF(382.328, 691.984));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(242, 183, 0, 255));
|
||||
path.moveTo(339.632, 826.624);
|
||||
path.cubicTo(QPointF(371.6, 814.312), QPointF(403.856, 798.112), QPointF(429.848, 782.128));
|
||||
path.cubicTo(QPointF(437.84, 777.448), QPointF(438.92, 765.928), QPointF(427.688, 762.328));
|
||||
path.cubicTo(QPointF(403.352, 748.504), QPointF(390.104, 731.224), QPointF(392.912, 708.76));
|
||||
path.cubicTo(QPointF(393.344, 700.912), QPointF(383.696, 692.56), QPointF(381.104, 700.048));
|
||||
path.cubicTo(QPointF(359.864, 771.472), QPointF(291.32, 767.656), QPointF(300.752, 696.952));
|
||||
path.cubicTo(QPointF(301.256, 694.864), QPointF(301.76, 692.776), QPointF(302.264, 690.76));
|
||||
path.cubicTo(QPointF(289.952, 688.24), QPointF(285.2, 690.976), QPointF(285.776, 700.408));
|
||||
path.lineTo(295.28, 806.608);
|
||||
path.cubicTo(QPointF(297.656, 830.8), QPointF(317.312, 836.128), QPointF(339.632, 826.624));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, 255));
|
||||
path.moveTo(354.464, 537.544);
|
||||
path.cubicTo(QPointF(379.16, 569.8), QPointF(404.432, 651.088), QPointF(384.416, 691.552));
|
||||
path.cubicTo(QPointF(360.944, 737.776), QPointF(307.808, 743.248), QPointF(305.504, 695.8));
|
||||
path.cubicTo(QPointF(308.816, 639.64), QPointF(311.984, 581.536), QPointF(273.68, 544.096));
|
||||
path.cubicTo(QPointF(267.704, 497.368), QPointF(246.392, 480.232), QPointF(236.384, 450.28));
|
||||
path.lineTo(203.12, 426.088);
|
||||
path.lineTo(133.568, 435.088);
|
||||
path.cubicTo(QPointF(130.76, 452.152), QPointF(129.104, 468.784), QPointF(131.552, 484.912));
|
||||
path.cubicTo(QPointF(115.064, 507.376), QPointF(102.608, 530.056), QPointF(101.168, 553.312));
|
||||
path.cubicTo(QPointF(88.712, 586.648), QPointF(59.12, 614.944), QPointF(64.232, 680.752));
|
||||
path.cubicTo(QPointF(80.864, 698.248), QPointF(104.12, 714.448), QPointF(124.064, 731.296));
|
||||
path.cubicTo(QPointF(149.12, 752.392), QPointF(135.512, 776.296), QPointF(100.232, 769.672));
|
||||
path.cubicTo(QPointF(78.848, 746.056), QPointF(56.744, 722.872), QPointF(35.288, 699.328));
|
||||
path.cubicTo(QPointF(12.392, 683.056), QPointF(3.896, 662.176), QPointF(27.368, 630.496));
|
||||
path.cubicTo(QPointF(43.424, 609.04), QPointF(47.96, 562.456), QPointF(62, 543.664));
|
||||
path.cubicTo(QPointF(74.312, 525.16), QPointF(92.24, 508.6), QPointF(105.272, 490.096));
|
||||
path.cubicTo(QPointF(112.184, 477.928), QPointF(114.344, 468.568), QPointF(113.264, 454.456));
|
||||
path.lineTo(110.312, 369.136);
|
||||
path.cubicTo(QPointF(108.368, 307.216), QPointF(142.424, 274.24), QPointF(189.8, 275.248));
|
||||
path.cubicTo(QPointF(243.512, 275.752), QPointF(287.576, 312.472), QPointF(288.152, 378.28));
|
||||
path.cubicTo(QPointF(292.688, 410.32), QPointF(283.256, 428.68), QPointF(308.672, 474.472));
|
||||
path.cubicTo(QPointF(334.52, 522.712), QPointF(338.552, 520.12), QPointF(354.464, 537.544));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(261.296, 503.632);
|
||||
path.lineTo(263.528, 512.2);
|
||||
path.cubicTo(QPointF(257.696, 501.688), QPointF(250.712, 483.616), QPointF(241.928, 475.696));
|
||||
path.cubicTo(QPointF(239.264, 473.536), QPointF(235.808, 473.608), QPointF(233.72, 475.624));
|
||||
path.cubicTo(QPointF(222.056, 486.928), QPointF(193.112, 510.112), QPointF(169.928, 507.088));
|
||||
path.cubicTo(QPointF(152.072, 505.288), QPointF(134.648, 493.264), QPointF(130.832, 480.232));
|
||||
path.cubicTo(QPointF(128.816, 470.872), QPointF(129.752, 463.168), QPointF(130.976, 455.32));
|
||||
path.lineTo(240.704, 453.52);
|
||||
path.cubicTo(QPointF(238.472, 463.168), QPointF(253.088, 487), QPointF(261.296, 503.632));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(143.144, 363.232);
|
||||
path.cubicTo(QPointF(154.088, 363.232), QPointF(163.88, 376.84), QPointF(163.808, 395.632));
|
||||
path.cubicTo(QPointF(163.736, 408.232), QPointF(155.528, 411.472), QPointF(149.336, 417.016));
|
||||
path.cubicTo(QPointF(146.6, 419.536), QPointF(145.952, 433.144), QPointF(142.568, 433.144));
|
||||
path.cubicTo(QPointF(131.696, 433.144), QPointF(123.488, 413.776), QPointF(123.488, 395.632));
|
||||
path.cubicTo(QPointF(123.488, 377.56), QPointF(132.272, 363.232), QPointF(143.144, 363.232));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(255, 255, 255, 255));
|
||||
path.moveTo(144.368, 375.04);
|
||||
path.cubicTo(QPointF(154.088, 375.04), QPointF(160.856, 379.936), QPointF(161.648, 391.312));
|
||||
path.cubicTo(QPointF(162.224, 399.16), QPointF(160.136, 411.76), QPointF(154.664, 414.424));
|
||||
path.cubicTo(QPointF(152.144, 415.648), QPointF(143.432, 426.664), QPointF(140.408, 426.52));
|
||||
path.cubicTo(QPointF(128.096, 425.944), QPointF(125, 402.112), QPointF(125.936, 390.736));
|
||||
path.cubicTo(QPointF(126.8, 379.36), QPointF(134.72, 375.04), QPointF(144.368, 375.04));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, 255));
|
||||
path.moveTo(141.848, 382.672);
|
||||
path.cubicTo(QPointF(148.544, 382.096), QPointF(154.736, 389.728), QPointF(155.6, 399.664));
|
||||
path.cubicTo(QPointF(156.464, 409.6), QPointF(151.64, 418.24), QPointF(144.944, 418.816));
|
||||
path.cubicTo(QPointF(138.248, 419.392), QPointF(132.056, 411.76), QPointF(131.192, 401.752));
|
||||
path.cubicTo(QPointF(130.328, 391.816), QPointF(135.152, 383.248), QPointF(141.848, 382.672));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(151.064, 397.288);
|
||||
path.cubicTo(QPointF(151.424, 399.088), QPointF(149.408, 400.024), QPointF(148.832, 398.224));
|
||||
path.cubicTo(QPointF(148.256, 395.992), QPointF(146.888, 393.328), QPointF(145.088, 391.168));
|
||||
path.cubicTo(QPointF(143.936, 389.872), QPointF(145.088, 388.432), QPointF(146.528, 389.44));
|
||||
path.cubicTo(QPointF(149.048, 391.528), QPointF(150.488, 394.12), QPointF(151.064, 397.288));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(216.944, 360.712);
|
||||
path.cubicTo(QPointF(232.712, 360.712), QPointF(245.6, 377.416), QPointF(245.6, 397.792));
|
||||
path.cubicTo(QPointF(245.6, 418.24), QPointF(232.712, 434.872), QPointF(216.944, 434.872));
|
||||
path.cubicTo(QPointF(201.176, 434.872), QPointF(188.432, 418.24), QPointF(188.432, 397.792));
|
||||
path.cubicTo(QPointF(188.432, 377.416), QPointF(201.176, 360.712), QPointF(216.944, 360.712));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(255, 255, 255, 255));
|
||||
path.moveTo(224.792, 374.968);
|
||||
path.cubicTo(QPointF(235.664, 378.856), QPointF(241.928, 387.424), QPointF(242.72, 396.568));
|
||||
path.cubicTo(QPointF(243.656, 407.08), QPointF(239.408, 418.96), QPointF(230.264, 425.944));
|
||||
path.cubicTo(QPointF(227.672, 427.888), QPointF(197.72, 416.08), QPointF(195.992, 411.616));
|
||||
path.cubicTo(QPointF(193.4, 405.208), QPointF(191.816, 392.896), QPointF(193.76, 385.624));
|
||||
path.cubicTo(QPointF(194.552, 382.744), QPointF(197.216, 378.568), QPointF(201.176, 376.336));
|
||||
path.cubicTo(QPointF(207.44, 372.808), QPointF(216.656, 372.088), QPointF(224.792, 374.968));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, 255));
|
||||
path.moveTo(216.872, 380.944);
|
||||
path.cubicTo(QPointF(225.584, 380.944), QPointF(232.712, 389.296), QPointF(232.712, 399.448));
|
||||
path.cubicTo(QPointF(232.712, 409.672), QPointF(225.584, 418.024), QPointF(216.872, 418.024));
|
||||
path.cubicTo(QPointF(208.16, 418.024), QPointF(201.032, 409.672), QPointF(201.032, 399.448));
|
||||
path.cubicTo(QPointF(201.032, 389.296), QPointF(208.16, 380.944), QPointF(216.872, 380.944));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(227.096, 392.392);
|
||||
path.cubicTo(QPointF(228.104, 394.048), QPointF(226.448, 395.776), QPointF(225.224, 394.12));
|
||||
path.cubicTo(QPointF(223.784, 392.104), QPointF(221.408, 389.944), QPointF(218.888, 388.432));
|
||||
path.cubicTo(QPointF(217.232, 387.568), QPointF(217.808, 385.624), QPointF(219.68, 386.2));
|
||||
path.cubicTo(QPointF(222.92, 387.28), QPointF(225.368, 389.368), QPointF(227.096, 392.392));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(183, 114, 0, 255));
|
||||
path.moveTo(164.96, 404.488);
|
||||
path.cubicTo(QPointF(172.376, 402.328), QPointF(184.112, 403.048), QPointF(192.248, 404.632));
|
||||
path.cubicTo(QPointF(200.384, 406.792), QPointF(222.056, 418.24), QPointF(245.024, 430.696));
|
||||
path.cubicTo(QPointF(247.976, 432.208), QPointF(248.84, 437.104), QPointF(245.024, 438.688));
|
||||
path.cubicTo(QPointF(239.12, 439.12), QPointF(249.272, 453.664), QPointF(238.904, 458.848));
|
||||
path.cubicTo(QPointF(223.352, 462.88), QPointF(198.44, 485.992), QPointF(186.128, 487.864));
|
||||
path.cubicTo(QPointF(179.288, 489.376), QPointF(172.232, 489.592), QPointF(164.6, 487.864));
|
||||
path.cubicTo(QPointF(140.552, 482.968), QPointF(134.216, 455.608), QPointF(122.912, 450.064));
|
||||
path.cubicTo(QPointF(119.816, 446.824), QPointF(121.4, 441.208), QPointF(122.408, 440.056));
|
||||
path.cubicTo(QPointF(123.632, 434.224), QPointF(149.696, 406.216), QPointF(164.96, 404.488));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(242, 183, 0, 255));
|
||||
path.moveTo(185.408, 405.856);
|
||||
path.cubicTo(QPointF(198.44, 407.296), QPointF(226.088, 423.928), QPointF(239.408, 430.624));
|
||||
path.cubicTo(QPointF(242.72, 432.424), QPointF(242.504, 437.824), QPointF(239.552, 438.688));
|
||||
path.cubicTo(QPointF(236.384, 440.488), QPointF(235.448, 438.256), QPointF(232.928, 437.896));
|
||||
path.cubicTo(QPointF(228.896, 435.736), QPointF(222.272, 440.92), QPointF(217.016, 444.88));
|
||||
path.cubicTo(QPointF(186.704, 467.776), QPointF(180.656, 465.256), QPointF(156.176, 462.664));
|
||||
path.cubicTo(QPointF(147.68, 460.576), QPointF(142.136, 457.984), QPointF(139.688, 455.968));
|
||||
path.cubicTo(QPointF(141.488, 445.888), QPointF(160.496, 407.656), QPointF(166.76, 406.792));
|
||||
path.cubicTo(QPointF(168.344, 404.704), QPointF(179.936, 404.632), QPointF(185.408, 405.856));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(183, 114, 0, 255));
|
||||
path.moveTo(190.664, 412.048);
|
||||
path.lineTo(193.76, 413.416);
|
||||
path.cubicTo(QPointF(196.064, 414.712), QPointF(193.256, 418.168), QPointF(190.736, 417.088));
|
||||
path.lineTo(186.2, 415.504);
|
||||
path.cubicTo(QPointF(183.536, 413.272), QPointF(186.704, 410.104), QPointF(190.664, 412.048));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(268.568, 452.368);
|
||||
path.cubicTo(QPointF(273.032, 454.384), QPointF(279.224, 457.192), QPointF(282.536, 460.144));
|
||||
path.cubicTo(QPointF(285.488, 464.104), QPointF(286.784, 468.064), QPointF(286.424, 472.024));
|
||||
path.cubicTo(QPointF(285.776, 474.544), QPointF(284.12, 476.344), QPointF(281.24, 477.424));
|
||||
path.cubicTo(QPointF(277.856, 478.216), QPointF(273.68, 477.424), QPointF(271.376, 474.112));
|
||||
path.cubicTo(QPointF(269.864, 471.448), QPointF(265.256, 462.16), QPointF(263.96, 460.576));
|
||||
path.cubicTo(QPointF(262.232, 457.12), QPointF(261.944, 454.456), QPointF(262.88, 452.368));
|
||||
path.cubicTo(QPointF(264.032, 451.288), QPointF(266.048, 451), QPointF(268.568, 452.368));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(255, 255, 255, 255));
|
||||
path.moveTo(273.752, 461.584);
|
||||
path.cubicTo(QPointF(275.48, 462.376), QPointF(277.928, 463.456), QPointF(279.224, 464.68));
|
||||
path.cubicTo(QPointF(280.376, 466.264), QPointF(280.88, 467.776), QPointF(280.736, 469.36));
|
||||
path.cubicTo(QPointF(280.52, 470.296), QPointF(279.8, 471.016), QPointF(278.72, 471.448));
|
||||
path.cubicTo(QPointF(277.352, 471.808), QPointF(275.768, 471.448), QPointF(274.832, 470.152));
|
||||
path.cubicTo(QPointF(274.256, 469.144), QPointF(272.456, 465.472), QPointF(271.952, 464.824));
|
||||
path.cubicTo(QPointF(271.232, 463.456), QPointF(271.088, 462.448), QPointF(271.448, 461.584));
|
||||
path.cubicTo(QPointF(271.952, 461.152), QPointF(272.744, 461.08), QPointF(273.752, 461.584));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(238.616, 358.552);
|
||||
path.cubicTo(QPointF(239.048, 359.2), QPointF(238.976, 359.776), QPointF(238.4, 360.28));
|
||||
path.cubicTo(QPointF(237.896, 360.784), QPointF(237.176, 360.712), QPointF(236.24, 360.208));
|
||||
path.lineTo(231.632, 356.248);
|
||||
path.cubicTo(QPointF(231.056, 355.744), QPointF(230.912, 354.952), QPointF(231.272, 354.088));
|
||||
path.cubicTo(QPointF(232.28, 353.44), QPointF(233.144, 353.44), QPointF(233.936, 354.088));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(235.592, 305.992);
|
||||
path.cubicTo(QPointF(239.624, 308.224), QPointF(240.848, 313.912), QPointF(238.184, 318.592));
|
||||
path.cubicTo(QPointF(235.592, 323.2), QPointF(230.12, 325.144), QPointF(226.016, 322.84));
|
||||
path.cubicTo(QPointF(221.984, 320.536), QPointF(220.76, 314.92), QPointF(223.424, 310.24));
|
||||
path.cubicTo(QPointF(226.016, 305.56), QPointF(231.488, 303.688), QPointF(235.592, 305.992));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(374.912, 680.536);
|
||||
path.cubicTo(QPointF(378.296, 683.128), QPointF(373.256, 687.376), QPointF(371.024, 686.296));
|
||||
path.cubicTo(QPointF(369.152, 685.648), QPointF(367.784, 683.488), QPointF(366.92, 682.408));
|
||||
path.cubicTo(QPointF(366.128, 681.184), QPointF(366.2, 679.168), QPointF(366.92, 678.448));
|
||||
path.cubicTo(QPointF(367.712, 677.44), QPointF(369.728, 677.656), QPointF(371.024, 678.52));
|
||||
path.cubicTo(QPointF(372.32, 679.168), QPointF(373.616, 679.888), QPointF(374.912, 680.536));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(297.44, 551.512);
|
||||
path.cubicTo(QPointF(338.984, 572.896), QPointF(350, 611.56), QPointF(332.072, 664.192));
|
||||
path.cubicTo(QPointF(330.992, 666.64), QPointF(334.16, 668.368), QPointF(335.24, 666.064));
|
||||
path.cubicTo(QPointF(354.824, 610.336), QPointF(341.432, 571.312), QPointF(299.024, 548.56));
|
||||
path.cubicTo(QPointF(296.864, 547.552), QPointF(295.28, 550.432), QPointF(297.44, 551.512));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(72.008, 569.512);
|
||||
path.cubicTo(QPointF(38.312, 627.256), QPointF(38.096, 662.68), QPointF(62.504, 681.328));
|
||||
path.cubicTo(QPointF(63.728, 682.264), QPointF(64.448, 680.032), QPointF(63.296, 679.168));
|
||||
path.cubicTo(QPointF(36.296, 655.48), QPointF(48.896, 615.52), QPointF(74.168, 570.88));
|
||||
path.cubicTo(QPointF(74.888, 569.584), QPointF(72.512, 568.432), QPointF(72.008, 569.512));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(289.376, 586.864);
|
||||
path.cubicTo(QPointF(289.232, 589.168), QPointF(288.368, 589.528), QPointF(286.424, 587.368));
|
||||
path.cubicTo(QPointF(279.8, 575.848), QPointF(235.088, 551.44), QPointF(213.344, 548.704));
|
||||
path.cubicTo(QPointF(209.24, 547.264), QPointF(209.456, 545.392), QPointF(213.488, 544.816));
|
||||
path.cubicTo(QPointF(229.184, 544.816), QPointF(241.28, 537.904), QPointF(254.96, 537.904));
|
||||
path.cubicTo(QPointF(258.704, 538.048), QPointF(262.304, 539.488), QPointF(264.392, 541.648));
|
||||
path.cubicTo(QPointF(269.504, 544.96), QPointF(288.08, 570.592), QPointF(289.376, 586.864));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(180.152, 546.832);
|
||||
path.cubicTo(QPointF(180.872, 550.792), QPointF(163.808, 545.68), QPointF(164.744, 556.696));
|
||||
path.cubicTo(QPointF(165.032, 559.72), QPointF(160.496, 561.376), QPointF(160.64, 556.696));
|
||||
path.cubicTo(QPointF(160.64, 548.272), QPointF(161.072, 548.416), QPointF(152.72, 546.832));
|
||||
path.cubicTo(QPointF(151.208, 546.76), QPointF(151.352, 544.528), QPointF(152.72, 544.816));
|
||||
path.lineTo(152.72, 544.816);
|
||||
path.cubicTo(QPointF(158.696, 546.472), QPointF(166.76, 542.872), QPointF(166.4, 538.84));
|
||||
path.cubicTo(QPointF(166.256, 537.472), QPointF(168.56, 537.688), QPointF(168.488, 538.84));
|
||||
path.cubicTo(QPointF(167.984, 545.248), QPointF(181.664, 542.152), QPointF(180.152, 546.832));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(193, 193, 191, 255));
|
||||
path.moveTo(151.568, 705.376);
|
||||
path.cubicTo(QPointF(151.64, 708.328), QPointF(148.76, 707.68), QPointF(148.544, 705.592));
|
||||
path.cubicTo(QPointF(140.192, 680.536), QPointF(143.72, 618.832), QPointF(151.856, 598.96));
|
||||
path.cubicTo(QPointF(152.432, 596.08), QPointF(156.248, 596.944), QPointF(155.744, 598.96));
|
||||
path.cubicTo(QPointF(147.104, 635.464), QPointF(147.248, 673.048), QPointF(151.568, 705.376));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(183, 114, 0, 255));
|
||||
path.moveTo(51.704, 684.424);
|
||||
path.cubicTo(QPointF(75.68, 707.824), QPointF(91.376, 743.248), QPointF(114.632, 775.288));
|
||||
path.cubicTo(QPointF(148.472, 816.04), QPointF(121.472, 858.304), QPointF(66.464, 845.56));
|
||||
path.cubicTo(QPointF(38.888, 835.192), QPointF(-0.784, 836.344), QPointF(-32.68, 825.832));
|
||||
path.cubicTo(QPointF(-55.072, 820.36), QPointF(-55.864, 809.272), QPointF(-44.416, 787.6));
|
||||
path.cubicTo(QPointF(-40.384, 773.776), QPointF(-40.024, 751.312), QPointF(-43.768, 732.592));
|
||||
path.cubicTo(QPointF(-45.784, 718.408), QPointF(-39.232, 710.488), QPointF(-24.112, 708.832));
|
||||
path.lineTo(-24.112, 708.832);
|
||||
path.cubicTo(QPointF(-11.296, 708.688), QPointF(6.56, 713.872), QPointF(16.28, 686.44));
|
||||
path.cubicTo(QPointF(23.552, 673.336), QPointF(40.976, 672.976), QPointF(51.704, 684.424));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
path = QPainterPath();
|
||||
|
||||
painter->setBrush(QColor(242, 183, 0, 255));
|
||||
path.moveTo(24.632, 699.04);
|
||||
path.cubicTo(QPointF(23.84, 680.968), QPointF(39.32, 677.296), QPointF(49.688, 688.312));
|
||||
path.cubicTo(QPointF(68.192, 710.992), QPointF(85.112, 736.048), QPointF(100.376, 764.992));
|
||||
path.cubicTo(QPointF(124.712, 804.16), QPointF(104.624, 842.68), QPointF(67.904, 828.064));
|
||||
path.cubicTo(QPointF(49.688, 817.84), QPointF(6.128, 813.304), QPointF(-17.344, 809.128));
|
||||
path.cubicTo(QPointF(-33.04, 807.832), QPointF(-35.128, 797.608), QPointF(-29.152, 791.848));
|
||||
path.cubicTo(QPointF(-20.944, 782.416), QPointF(-20.08, 759.808), QPointF(-27.856, 740.512));
|
||||
path.cubicTo(QPointF(-35.56, 728.56), QPointF(-21.088, 715.384), QPointF(-9.712, 720.856));
|
||||
path.cubicTo(QPointF(0.8, 727.048), QPointF(25.64, 713.08), QPointF(24.632, 699.04));
|
||||
path.closeSubpath();
|
||||
painter->drawPath(path);
|
||||
|
||||
painter->setPen(QPen(QColor(255, 0, 0, alpha), 0.25, Qt::SolidLine, Qt::FlatCap, Qt::BevelJoin));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawRect(br.adjusted(-1, -1, 1, 1));
|
||||
}
|
||||
|
||||
|
||||
XFormWidget::XFormWidget(QWidget *parent)
|
||||
: QWidget(parent), textEditor(new QLineEdit)
|
||||
{
|
||||
setWindowTitle(tr("Affine Transformations"));
|
||||
|
||||
view = new XFormView(this);
|
||||
view->setMinimumSize(200, 200);
|
||||
|
||||
QWidget *mainContentWidget = new QWidget();
|
||||
QGroupBox *mainGroup = new QGroupBox(mainContentWidget);
|
||||
mainGroup->setTitle(tr("Affine Transformations"));
|
||||
|
||||
QGroupBox *rotateGroup = new QGroupBox(mainGroup);
|
||||
rotateGroup->setTitle(tr("Rotate"));
|
||||
QSlider *rotateSlider = new QSlider(Qt::Horizontal, rotateGroup);
|
||||
rotateSlider->setRange(0, 3600);
|
||||
rotateSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *scaleGroup = new QGroupBox(mainGroup);
|
||||
scaleGroup->setTitle(tr("Scale"));
|
||||
QSlider *scaleSlider = new QSlider(Qt::Horizontal, scaleGroup);
|
||||
scaleSlider->setRange(1, 4000);
|
||||
scaleSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *shearGroup = new QGroupBox(mainGroup);
|
||||
shearGroup->setTitle(tr("Shear"));
|
||||
QSlider *shearSlider = new QSlider(Qt::Horizontal, shearGroup);
|
||||
shearSlider->setRange(-990, 990);
|
||||
shearSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *typeGroup = new QGroupBox(mainGroup);
|
||||
typeGroup->setTitle(tr("Type"));
|
||||
QRadioButton *vectorType = new QRadioButton(typeGroup);
|
||||
QRadioButton *pixmapType = new QRadioButton(typeGroup);
|
||||
QRadioButton *textType= new QRadioButton(typeGroup);
|
||||
vectorType->setText(tr("Vector Image"));
|
||||
pixmapType->setText(tr("Pixmap"));
|
||||
textType->setText(tr("Text"));
|
||||
|
||||
QPushButton *resetButton = new QPushButton(mainGroup);
|
||||
resetButton->setText(tr("Reset Transform"));
|
||||
|
||||
QPushButton *animateButton = new QPushButton(mainGroup);
|
||||
animateButton->setText(tr("Animate"));
|
||||
animateButton->setCheckable(true);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(view->usesOpenGL());
|
||||
#endif
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
QVBoxLayout *rotateGroupLayout = new QVBoxLayout(rotateGroup);
|
||||
rotateGroupLayout->addWidget(rotateSlider);
|
||||
|
||||
QVBoxLayout *scaleGroupLayout = new QVBoxLayout(scaleGroup);
|
||||
scaleGroupLayout->addWidget(scaleSlider);
|
||||
|
||||
QVBoxLayout *shearGroupLayout = new QVBoxLayout(shearGroup);
|
||||
shearGroupLayout->addWidget(shearSlider);
|
||||
|
||||
QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup);
|
||||
typeGroupLayout->addWidget(vectorType);
|
||||
typeGroupLayout->addWidget(pixmapType);
|
||||
typeGroupLayout->addWidget(textType);
|
||||
typeGroupLayout->addSpacing(4);
|
||||
typeGroupLayout->addWidget(textEditor);
|
||||
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->addWidget(rotateGroup);
|
||||
mainGroupLayout->addWidget(scaleGroup);
|
||||
mainGroupLayout->addWidget(shearGroup);
|
||||
mainGroupLayout->addWidget(typeGroup);
|
||||
mainGroupLayout->addStretch(1);
|
||||
mainGroupLayout->addWidget(resetButton);
|
||||
mainGroupLayout->addWidget(animateButton);
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
|
||||
mainGroup->setLayout(mainGroupLayout);
|
||||
|
||||
QVBoxLayout *mainContentLayout = new QVBoxLayout();
|
||||
mainContentLayout->addWidget(mainGroup);
|
||||
mainContentWidget->setLayout(mainContentLayout);
|
||||
|
||||
QScrollArea *mainScrollArea = new QScrollArea();
|
||||
mainScrollArea->setWidget(mainContentWidget);
|
||||
mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
|
||||
QHBoxLayout *viewLayout = new QHBoxLayout(this);
|
||||
viewLayout->addWidget(view);
|
||||
viewLayout->addWidget(mainScrollArea);
|
||||
|
||||
connect(rotateSlider, &QSlider::valueChanged, view, &XFormView::changeRotation);
|
||||
connect(shearSlider, &QSlider::valueChanged, view, &XFormView::changeShear);
|
||||
connect(scaleSlider, &QSlider::valueChanged, view, &XFormView::changeScale);
|
||||
|
||||
connect(vectorType, &QRadioButton::clicked, view, &XFormView::setVectorType);
|
||||
connect(pixmapType, &QRadioButton::clicked, view, &XFormView::setPixmapType);
|
||||
connect(textType, &QRadioButton::clicked, view, &XFormView::setTextType);
|
||||
connect(textType, &QRadioButton::toggled, textEditor, &XFormView::setEnabled);
|
||||
connect(textEditor, &QLineEdit::textChanged, view, &XFormView::setText);
|
||||
|
||||
connect(view, &XFormView::rotationChanged, rotateSlider, &QSlider::setValue);
|
||||
connect(view, &XFormView::scaleChanged, scaleSlider, &QAbstractSlider::setValue);
|
||||
connect(view, &XFormView::shearChanged, shearSlider, &QAbstractSlider::setValue);
|
||||
|
||||
connect(resetButton, &QPushButton::clicked, view, &XFormView::reset);
|
||||
connect(animateButton, &QPushButton::clicked, view, &XFormView::setAnimation);
|
||||
connect(whatsThisButton, &QPushButton::clicked, view, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(whatsThisButton, &QPushButton::clicked, view->hoverPoints(), &HoverPoints::setDisabled);
|
||||
connect(view, &XFormView::descriptionEnabledChanged, view->hoverPoints(), &HoverPoints::setDisabled);
|
||||
connect(view, &XFormView::descriptionEnabledChanged, whatsThisButton, &QPushButton::setChecked);
|
||||
connect(showSourceButton, &QPushButton::clicked, view, &XFormView::showSource);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QPushButton::clicked, view, &XFormView::enableOpenGL);
|
||||
#endif
|
||||
view->loadSourceFile(":res/affine/xform.cpp");
|
||||
view->loadDescription(":res/affine/xform.html");
|
||||
|
||||
// defaults
|
||||
view->reset();
|
||||
vectorType->setChecked(true);
|
||||
textEditor->setText("Qt Affine Transformation Example");
|
||||
textEditor->setEnabled(false);
|
||||
|
||||
animateButton->animateClick();
|
||||
}
|
108
examples/widgets/painting/affine/xform.h
Normal file
@ -0,0 +1,108 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef XFORM_H
|
||||
#define XFORM_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QPolygonF>
|
||||
|
||||
class HoverPoints;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLineEdit;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class XFormView : public ArthurFrame
|
||||
{
|
||||
public:
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(XFormType type READ type WRITE setType)
|
||||
Q_PROPERTY(bool animation READ animation WRITE setAnimation)
|
||||
Q_PROPERTY(qreal shear READ shear WRITE setShear)
|
||||
Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
|
||||
Q_PROPERTY(qreal scale READ scale WRITE setScale)
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap)
|
||||
Q_ENUMS(XFormType)
|
||||
|
||||
public:
|
||||
enum XFormType { VectorType, PixmapType, TextType };
|
||||
|
||||
XFormView(QWidget *parent);
|
||||
void paint(QPainter *) override;
|
||||
void drawVectorType(QPainter *painter);
|
||||
void drawPixmapType(QPainter *painter);
|
||||
void drawTextType(QPainter *painter);
|
||||
QSize sizeHint() const override { return QSize(500, 500); }
|
||||
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
HoverPoints *hoverPoints() { return m_hoverPoints; }
|
||||
|
||||
bool animation() const { return timer.isActive(); }
|
||||
qreal shear() const { return m_shear; }
|
||||
qreal scale() const { return m_scale; }
|
||||
qreal rotation() const { return m_rotation; }
|
||||
void setShear(qreal s);
|
||||
void setScale(qreal s);
|
||||
void setRotation(qreal r);
|
||||
|
||||
XFormType type() const;
|
||||
QPixmap pixmap() const;
|
||||
QString text() const;
|
||||
|
||||
public slots:
|
||||
void setAnimation(bool animate);
|
||||
void updateControlPoints(const QPolygonF &);
|
||||
void changeRotation(int rotation);
|
||||
void changeScale(int scale);
|
||||
void changeShear(int shear);
|
||||
|
||||
void setText(const QString &);
|
||||
void setPixmap(const QPixmap &);
|
||||
void setType(XFormType t);
|
||||
|
||||
void setVectorType();
|
||||
void setPixmapType();
|
||||
void setTextType();
|
||||
void reset();
|
||||
|
||||
signals:
|
||||
void rotationChanged(int rotation);
|
||||
void scaleChanged(int scale);
|
||||
void shearChanged(int shear);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *e) override;
|
||||
#if QT_CONFIG(wheelevent)
|
||||
void wheelEvent(QWheelEvent *) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
QPolygonF m_controlPoints{{250, 250}, {350, 250}};
|
||||
HoverPoints *m_hoverPoints;
|
||||
qreal m_rotation = 0;
|
||||
qreal m_scale = 1;
|
||||
qreal m_shear = 0;
|
||||
XFormType m_type = VectorType;
|
||||
QPixmap m_pixmap;
|
||||
QString m_text;
|
||||
QBasicTimer timer;
|
||||
};
|
||||
|
||||
class XFormWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
XFormWidget(QWidget *parent);
|
||||
|
||||
private:
|
||||
XFormView *view;
|
||||
QLineEdit *textEditor;
|
||||
};
|
||||
|
||||
#endif // XFORM_H
|
23
examples/widgets/painting/affine/xform.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
<center>
|
||||
<h2>Affine Transformations</h2>
|
||||
</center>
|
||||
|
||||
<p>In this demo we demonstrate Qt's ability to perform affine transformations
|
||||
on painting operations.</p>
|
||||
|
||||
<p>Transformations can be performed on any kind of graphics drawn using
|
||||
QPainter. The transformations used to display the vector graphics, images,
|
||||
and text can be adjusted in the following ways:</p>
|
||||
|
||||
<ul>
|
||||
<li>Dragging the red circle in the centre of each drawing moves it to a new
|
||||
position.</li>
|
||||
<li>Dragging the displaced red circle causes the current drawing to be
|
||||
rotated about the central circle. Rotation can also be controlled with
|
||||
the <b>Rotate</b> slider.</li>
|
||||
<li>Scaling is controlled with the <b>Scale</b> slider.</li>
|
||||
<li>Each drawing can be sheared with the <b>Shear</b> slider.</li>
|
||||
</ul>
|
||||
|
||||
</html>
|
51
examples/widgets/painting/basicdrawing/CMakeLists.txt
Normal file
@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(basicdrawing LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/basicdrawing")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(basicdrawing
|
||||
main.cpp
|
||||
renderarea.cpp renderarea.h
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(basicdrawing PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(basicdrawing PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(basicdrawing_resource_files
|
||||
"images/brick.png"
|
||||
"images/qt-logo.png"
|
||||
)
|
||||
|
||||
qt_add_resources(basicdrawing "basicdrawing"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${basicdrawing_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS basicdrawing
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
13
examples/widgets/painting/basicdrawing/basicdrawing.pro
Normal file
@ -0,0 +1,13 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(combobox))
|
||||
|
||||
HEADERS = renderarea.h \
|
||||
window.h
|
||||
SOURCES = main.cpp \
|
||||
renderarea.cpp \
|
||||
window.cpp
|
||||
RESOURCES = basicdrawing.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/basicdrawing
|
||||
INSTALLS += target
|
6
examples/widgets/painting/basicdrawing/basicdrawing.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>images/brick.png</file>
|
||||
<file>images/qt-logo.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
examples/widgets/painting/basicdrawing/images/brick.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
examples/widgets/painting/basicdrawing/images/qt-logo.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
16
examples/widgets/painting/basicdrawing/main.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(basicdrawing);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
Window window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
173
examples/widgets/painting/basicdrawing/renderarea.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "renderarea.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
//! [0]
|
||||
RenderArea::RenderArea(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
shape = Polygon;
|
||||
antialiased = false;
|
||||
transformed = false;
|
||||
pixmap.load(":/images/qt-logo.png");
|
||||
|
||||
setBackgroundRole(QPalette::Base);
|
||||
setAutoFillBackground(true);
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
QSize RenderArea::minimumSizeHint() const
|
||||
{
|
||||
return QSize(100, 100);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QSize RenderArea::sizeHint() const
|
||||
{
|
||||
return QSize(400, 200);
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
void RenderArea::setShape(Shape shape)
|
||||
{
|
||||
this->shape = shape;
|
||||
update();
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void RenderArea::setPen(const QPen &pen)
|
||||
{
|
||||
this->pen = pen;
|
||||
update();
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
void RenderArea::setBrush(const QBrush &brush)
|
||||
{
|
||||
this->brush = brush;
|
||||
update();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
void RenderArea::setAntialiased(bool antialiased)
|
||||
{
|
||||
this->antialiased = antialiased;
|
||||
update();
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
void RenderArea::setTransformed(bool transformed)
|
||||
{
|
||||
this->transformed = transformed;
|
||||
update();
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void RenderArea::paintEvent(QPaintEvent * /* event */)
|
||||
{
|
||||
static const QPoint points[4] = {
|
||||
QPoint(10, 80),
|
||||
QPoint(20, 10),
|
||||
QPoint(80, 30),
|
||||
QPoint(90, 70)
|
||||
};
|
||||
|
||||
QRect rect(10, 20, 80, 60);
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo(20, 80);
|
||||
path.lineTo(20, 30);
|
||||
path.cubicTo(80, 0, 50, 50, 80, 80);
|
||||
|
||||
int startAngle = 20 * 16;
|
||||
int arcLength = 120 * 16;
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
QPainter painter(this);
|
||||
painter.setPen(pen);
|
||||
painter.setBrush(brush);
|
||||
if (antialiased)
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
for (int x = 0; x < width(); x += 100) {
|
||||
for (int y = 0; y < height(); y += 100) {
|
||||
painter.save();
|
||||
painter.translate(x, y);
|
||||
//! [10] //! [11]
|
||||
if (transformed) {
|
||||
painter.translate(50, 50);
|
||||
painter.rotate(60.0);
|
||||
painter.scale(0.6, 0.9);
|
||||
painter.translate(-50, -50);
|
||||
}
|
||||
//! [11]
|
||||
|
||||
//! [12]
|
||||
switch (shape) {
|
||||
case Line:
|
||||
painter.drawLine(rect.bottomLeft(), rect.topRight());
|
||||
break;
|
||||
case Points:
|
||||
painter.drawPoints(points, 4);
|
||||
break;
|
||||
case Polyline:
|
||||
painter.drawPolyline(points, 4);
|
||||
break;
|
||||
case Polygon:
|
||||
painter.drawPolygon(points, 4);
|
||||
break;
|
||||
case Rect:
|
||||
painter.drawRect(rect);
|
||||
break;
|
||||
case RoundedRect:
|
||||
painter.drawRoundedRect(rect, 25, 25, Qt::RelativeSize);
|
||||
break;
|
||||
case Ellipse:
|
||||
painter.drawEllipse(rect);
|
||||
break;
|
||||
case Arc:
|
||||
painter.drawArc(rect, startAngle, arcLength);
|
||||
break;
|
||||
case Chord:
|
||||
painter.drawChord(rect, startAngle, arcLength);
|
||||
break;
|
||||
case Pie:
|
||||
painter.drawPie(rect, startAngle, arcLength);
|
||||
break;
|
||||
case Path:
|
||||
painter.drawPath(path);
|
||||
break;
|
||||
case Text:
|
||||
painter.drawText(rect,
|
||||
Qt::AlignCenter,
|
||||
tr("Qt by\nThe Qt Company"));
|
||||
break;
|
||||
case Pixmap:
|
||||
painter.drawPixmap(10, 10, pixmap);
|
||||
}
|
||||
//! [12] //! [13]
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||
painter.setPen(palette().dark().color());
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawRect(QRect(0, 0, width() - 1, height() - 1));
|
||||
}
|
||||
//! [13]
|
46
examples/widgets/painting/basicdrawing/renderarea.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef RENDERAREA_H
|
||||
#define RENDERAREA_H
|
||||
|
||||
#include <QBrush>
|
||||
#include <QPen>
|
||||
#include <QPixmap>
|
||||
#include <QWidget>
|
||||
|
||||
//! [0]
|
||||
class RenderArea : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Shape { Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse, Arc,
|
||||
Chord, Pie, Path, Text, Pixmap };
|
||||
|
||||
explicit RenderArea(QWidget *parent = nullptr);
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
void setShape(Shape shape);
|
||||
void setPen(const QPen &pen);
|
||||
void setBrush(const QBrush &brush);
|
||||
void setAntialiased(bool antialiased);
|
||||
void setTransformed(bool transformed);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
Shape shape;
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
bool antialiased;
|
||||
bool transformed;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // RENDERAREA_H
|
222
examples/widgets/painting/basicdrawing/window.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "renderarea.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
//! [0]
|
||||
const int IdRole = Qt::UserRole;
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
Window::Window()
|
||||
{
|
||||
renderArea = new RenderArea;
|
||||
|
||||
shapeComboBox = new QComboBox;
|
||||
shapeComboBox->addItem(tr("Polygon"), RenderArea::Polygon);
|
||||
shapeComboBox->addItem(tr("Rectangle"), RenderArea::Rect);
|
||||
shapeComboBox->addItem(tr("Rounded Rectangle"), RenderArea::RoundedRect);
|
||||
shapeComboBox->addItem(tr("Ellipse"), RenderArea::Ellipse);
|
||||
shapeComboBox->addItem(tr("Pie"), RenderArea::Pie);
|
||||
shapeComboBox->addItem(tr("Chord"), RenderArea::Chord);
|
||||
shapeComboBox->addItem(tr("Path"), RenderArea::Path);
|
||||
shapeComboBox->addItem(tr("Line"), RenderArea::Line);
|
||||
shapeComboBox->addItem(tr("Polyline"), RenderArea::Polyline);
|
||||
shapeComboBox->addItem(tr("Arc"), RenderArea::Arc);
|
||||
shapeComboBox->addItem(tr("Points"), RenderArea::Points);
|
||||
shapeComboBox->addItem(tr("Text"), RenderArea::Text);
|
||||
shapeComboBox->addItem(tr("Pixmap"), RenderArea::Pixmap);
|
||||
|
||||
shapeLabel = new QLabel(tr("&Shape:"));
|
||||
shapeLabel->setBuddy(shapeComboBox);
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
penWidthSpinBox = new QSpinBox;
|
||||
penWidthSpinBox->setRange(0, 20);
|
||||
penWidthSpinBox->setSpecialValueText(tr("0 (cosmetic pen)"));
|
||||
|
||||
penWidthLabel = new QLabel(tr("Pen &Width:"));
|
||||
penWidthLabel->setBuddy(penWidthSpinBox);
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
penStyleComboBox = new QComboBox;
|
||||
penStyleComboBox->addItem(tr("Solid"), static_cast<int>(Qt::SolidLine));
|
||||
penStyleComboBox->addItem(tr("Dash"), static_cast<int>(Qt::DashLine));
|
||||
penStyleComboBox->addItem(tr("Dot"), static_cast<int>(Qt::DotLine));
|
||||
penStyleComboBox->addItem(tr("Dash Dot"), static_cast<int>(Qt::DashDotLine));
|
||||
penStyleComboBox->addItem(tr("Dash Dot Dot"), static_cast<int>(Qt::DashDotDotLine));
|
||||
penStyleComboBox->addItem(tr("None"), static_cast<int>(Qt::NoPen));
|
||||
|
||||
penStyleLabel = new QLabel(tr("&Pen Style:"));
|
||||
penStyleLabel->setBuddy(penStyleComboBox);
|
||||
|
||||
penCapComboBox = new QComboBox;
|
||||
penCapComboBox->addItem(tr("Flat"), Qt::FlatCap);
|
||||
penCapComboBox->addItem(tr("Square"), Qt::SquareCap);
|
||||
penCapComboBox->addItem(tr("Round"), Qt::RoundCap);
|
||||
|
||||
penCapLabel = new QLabel(tr("Pen &Cap:"));
|
||||
penCapLabel->setBuddy(penCapComboBox);
|
||||
|
||||
penJoinComboBox = new QComboBox;
|
||||
penJoinComboBox->addItem(tr("Miter"), Qt::MiterJoin);
|
||||
penJoinComboBox->addItem(tr("Bevel"), Qt::BevelJoin);
|
||||
penJoinComboBox->addItem(tr("Round"), Qt::RoundJoin);
|
||||
|
||||
penJoinLabel = new QLabel(tr("Pen &Join:"));
|
||||
penJoinLabel->setBuddy(penJoinComboBox);
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
brushStyleComboBox = new QComboBox;
|
||||
brushStyleComboBox->addItem(tr("Linear Gradient"),
|
||||
static_cast<int>(Qt::LinearGradientPattern));
|
||||
brushStyleComboBox->addItem(tr("Radial Gradient"),
|
||||
static_cast<int>(Qt::RadialGradientPattern));
|
||||
brushStyleComboBox->addItem(tr("Conical Gradient"),
|
||||
static_cast<int>(Qt::ConicalGradientPattern));
|
||||
brushStyleComboBox->addItem(tr("Texture"), static_cast<int>(Qt::TexturePattern));
|
||||
brushStyleComboBox->addItem(tr("Solid"), static_cast<int>(Qt::SolidPattern));
|
||||
brushStyleComboBox->addItem(tr("Horizontal"), static_cast<int>(Qt::HorPattern));
|
||||
brushStyleComboBox->addItem(tr("Vertical"), static_cast<int>(Qt::VerPattern));
|
||||
brushStyleComboBox->addItem(tr("Cross"), static_cast<int>(Qt::CrossPattern));
|
||||
brushStyleComboBox->addItem(tr("Backward Diagonal"), static_cast<int>(Qt::BDiagPattern));
|
||||
brushStyleComboBox->addItem(tr("Forward Diagonal"), static_cast<int>(Qt::FDiagPattern));
|
||||
brushStyleComboBox->addItem(tr("Diagonal Cross"), static_cast<int>(Qt::DiagCrossPattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 1"), static_cast<int>(Qt::Dense1Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 2"), static_cast<int>(Qt::Dense2Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 3"), static_cast<int>(Qt::Dense3Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 4"), static_cast<int>(Qt::Dense4Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 5"), static_cast<int>(Qt::Dense5Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 6"), static_cast<int>(Qt::Dense6Pattern));
|
||||
brushStyleComboBox->addItem(tr("Dense 7"), static_cast<int>(Qt::Dense7Pattern));
|
||||
brushStyleComboBox->addItem(tr("None"), static_cast<int>(Qt::NoBrush));
|
||||
|
||||
brushStyleLabel = new QLabel(tr("&Brush:"));
|
||||
brushStyleLabel->setBuddy(brushStyleComboBox);
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
otherOptionsLabel = new QLabel(tr("Options:"));
|
||||
//! [5] //! [6]
|
||||
antialiasingCheckBox = new QCheckBox(tr("&Antialiasing"));
|
||||
//! [6] //! [7]
|
||||
transformationsCheckBox = new QCheckBox(tr("&Transformations"));
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
connect(shapeComboBox, &QComboBox::activated,
|
||||
this, &Window::shapeChanged);
|
||||
connect(penWidthSpinBox, &QSpinBox::valueChanged,
|
||||
this, &Window::penChanged);
|
||||
connect(penStyleComboBox, &QComboBox::activated,
|
||||
this, &Window::penChanged);
|
||||
connect(penCapComboBox, &QComboBox::activated,
|
||||
this, &Window::penChanged);
|
||||
connect(penJoinComboBox, &QComboBox::activated,
|
||||
this, &Window::penChanged);
|
||||
connect(brushStyleComboBox, &QComboBox::activated,
|
||||
this, &Window::brushChanged);
|
||||
connect(antialiasingCheckBox, &QAbstractButton::toggled,
|
||||
renderArea, &RenderArea::setAntialiased);
|
||||
connect(transformationsCheckBox, &QAbstractButton::toggled,
|
||||
renderArea, &RenderArea::setTransformed);
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
//! [9] //! [10]
|
||||
mainLayout->setColumnStretch(0, 1);
|
||||
mainLayout->setColumnStretch(3, 1);
|
||||
mainLayout->addWidget(renderArea, 0, 0, 1, 4);
|
||||
mainLayout->addWidget(shapeLabel, 2, 0, Qt::AlignRight);
|
||||
mainLayout->addWidget(shapeComboBox, 2, 1);
|
||||
mainLayout->addWidget(penWidthLabel, 3, 0, Qt::AlignRight);
|
||||
mainLayout->addWidget(penWidthSpinBox, 3, 1);
|
||||
mainLayout->addWidget(penStyleLabel, 4, 0, Qt::AlignRight);
|
||||
mainLayout->addWidget(penStyleComboBox, 4, 1);
|
||||
mainLayout->addWidget(penCapLabel, 3, 2, Qt::AlignRight);
|
||||
mainLayout->addWidget(penCapComboBox, 3, 3);
|
||||
mainLayout->addWidget(penJoinLabel, 2, 2, Qt::AlignRight);
|
||||
mainLayout->addWidget(penJoinComboBox, 2, 3);
|
||||
mainLayout->addWidget(brushStyleLabel, 4, 2, Qt::AlignRight);
|
||||
mainLayout->addWidget(brushStyleComboBox, 4, 3);
|
||||
mainLayout->addWidget(otherOptionsLabel, 5, 0, Qt::AlignRight);
|
||||
mainLayout->addWidget(antialiasingCheckBox, 5, 1, 1, 1, Qt::AlignRight);
|
||||
mainLayout->addWidget(transformationsCheckBox, 5, 2, 1, 2, Qt::AlignRight);
|
||||
setLayout(mainLayout);
|
||||
|
||||
shapeChanged();
|
||||
penChanged();
|
||||
brushChanged();
|
||||
antialiasingCheckBox->setChecked(true);
|
||||
|
||||
setWindowTitle(tr("Basic Drawing"));
|
||||
}
|
||||
//! [10]
|
||||
|
||||
//! [11]
|
||||
void Window::shapeChanged()
|
||||
{
|
||||
RenderArea::Shape shape = RenderArea::Shape(shapeComboBox->itemData(
|
||||
shapeComboBox->currentIndex(), IdRole).toInt());
|
||||
renderArea->setShape(shape);
|
||||
}
|
||||
//! [11]
|
||||
|
||||
//! [12]
|
||||
void Window::penChanged()
|
||||
{
|
||||
int width = penWidthSpinBox->value();
|
||||
Qt::PenStyle style = Qt::PenStyle(penStyleComboBox->itemData(
|
||||
penStyleComboBox->currentIndex(), IdRole).toInt());
|
||||
Qt::PenCapStyle cap = Qt::PenCapStyle(penCapComboBox->itemData(
|
||||
penCapComboBox->currentIndex(), IdRole).toInt());
|
||||
Qt::PenJoinStyle join = Qt::PenJoinStyle(penJoinComboBox->itemData(
|
||||
penJoinComboBox->currentIndex(), IdRole).toInt());
|
||||
|
||||
renderArea->setPen(QPen(Qt::blue, width, style, cap, join));
|
||||
}
|
||||
//! [12]
|
||||
|
||||
//! [13]
|
||||
void Window::brushChanged()
|
||||
{
|
||||
Qt::BrushStyle style = Qt::BrushStyle(brushStyleComboBox->itemData(
|
||||
//! [13]
|
||||
brushStyleComboBox->currentIndex(), IdRole).toInt());
|
||||
|
||||
//! [14]
|
||||
if (style == Qt::LinearGradientPattern) {
|
||||
QLinearGradient linearGradient(0, 0, 100, 100);
|
||||
linearGradient.setColorAt(0.0, Qt::white);
|
||||
linearGradient.setColorAt(0.2, Qt::green);
|
||||
linearGradient.setColorAt(1.0, Qt::black);
|
||||
renderArea->setBrush(linearGradient);
|
||||
//! [14] //! [15]
|
||||
} else if (style == Qt::RadialGradientPattern) {
|
||||
QRadialGradient radialGradient(50, 50, 50, 70, 70);
|
||||
radialGradient.setColorAt(0.0, Qt::white);
|
||||
radialGradient.setColorAt(0.2, Qt::green);
|
||||
radialGradient.setColorAt(1.0, Qt::black);
|
||||
renderArea->setBrush(radialGradient);
|
||||
} else if (style == Qt::ConicalGradientPattern) {
|
||||
QConicalGradient conicalGradient(50, 50, 150);
|
||||
conicalGradient.setColorAt(0.0, Qt::white);
|
||||
conicalGradient.setColorAt(0.2, Qt::green);
|
||||
conicalGradient.setColorAt(1.0, Qt::black);
|
||||
renderArea->setBrush(conicalGradient);
|
||||
//! [15] //! [16]
|
||||
} else if (style == Qt::TexturePattern) {
|
||||
renderArea->setBrush(QBrush(QPixmap(":/images/brick.png")));
|
||||
//! [16] //! [17]
|
||||
} else {
|
||||
renderArea->setBrush(QBrush(Qt::green, style));
|
||||
}
|
||||
}
|
||||
//! [17]
|
50
examples/widgets/painting/basicdrawing/window.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
QT_END_NAMESPACE
|
||||
class RenderArea;
|
||||
|
||||
//! [0]
|
||||
class Window : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window();
|
||||
|
||||
private slots:
|
||||
void shapeChanged();
|
||||
void penChanged();
|
||||
void brushChanged();
|
||||
|
||||
private:
|
||||
RenderArea *renderArea;
|
||||
QLabel *shapeLabel;
|
||||
QLabel *penWidthLabel;
|
||||
QLabel *penStyleLabel;
|
||||
QLabel *penCapLabel;
|
||||
QLabel *penJoinLabel;
|
||||
QLabel *brushStyleLabel;
|
||||
QLabel *otherOptionsLabel;
|
||||
QComboBox *shapeComboBox;
|
||||
QSpinBox *penWidthSpinBox;
|
||||
QComboBox *penStyleComboBox;
|
||||
QComboBox *penCapComboBox;
|
||||
QComboBox *penJoinComboBox;
|
||||
QComboBox *brushStyleComboBox;
|
||||
QCheckBox *antialiasingCheckBox;
|
||||
QCheckBox *transformationsCheckBox;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // WINDOW_H
|
104
examples/widgets/painting/composition/CMakeLists.txt
Normal file
@ -0,0 +1,104 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(composition LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/composition")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(composition
|
||||
composition.cpp composition.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(composition PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(composition PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(composition "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(composition_resource_files
|
||||
"composition.cpp"
|
||||
"composition.html"
|
||||
"flower.jpg"
|
||||
"flower_alpha.jpg"
|
||||
)
|
||||
|
||||
qt_add_resources(composition "composition"
|
||||
PREFIX
|
||||
"/res/composition"
|
||||
FILES
|
||||
${composition_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS composition
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
454
examples/widgets/painting/composition/composition.cpp
Normal file
@ -0,0 +1,454 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "composition.h"
|
||||
#include <QBoxLayout>
|
||||
#include <QRadioButton>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QSlider>
|
||||
#include <QMouseEvent>
|
||||
#include <qmath.h>
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWindow>
|
||||
#endif
|
||||
|
||||
const int animationInterval = 15; // update every 16 ms = ~60FPS
|
||||
|
||||
CompositionWidget::CompositionWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
CompositionRenderer *view = new CompositionRenderer(this);
|
||||
|
||||
QGroupBox *mainGroup = new QGroupBox(parent);
|
||||
mainGroup->setTitle(tr("Composition Modes"));
|
||||
|
||||
QGroupBox *modesGroup = new QGroupBox(mainGroup);
|
||||
modesGroup->setTitle(tr("Mode"));
|
||||
|
||||
rbClear = new QRadioButton(tr("Clear"), modesGroup);
|
||||
connect(rbClear, &QAbstractButton::clicked, view, &CompositionRenderer::setClearMode);
|
||||
rbSource = new QRadioButton(tr("Source"), modesGroup);
|
||||
connect(rbSource, &QAbstractButton::clicked, view, &CompositionRenderer::setSourceMode);
|
||||
rbDest = new QRadioButton(tr("Destination"), modesGroup);
|
||||
connect(rbDest, &QAbstractButton::clicked, view, &CompositionRenderer::setDestMode);
|
||||
rbSourceOver = new QRadioButton(tr("Source Over"), modesGroup);
|
||||
connect(rbSourceOver, &QAbstractButton::clicked, view, &CompositionRenderer::setSourceOverMode);
|
||||
rbDestOver = new QRadioButton(tr("Destination Over"), modesGroup);
|
||||
connect(rbDestOver, &QAbstractButton::clicked, view, &CompositionRenderer::setDestOverMode);
|
||||
rbSourceIn = new QRadioButton(tr("Source In"), modesGroup);
|
||||
connect(rbSourceIn, &QAbstractButton::clicked, view, &CompositionRenderer::setSourceInMode);
|
||||
rbDestIn = new QRadioButton(tr("Dest In"), modesGroup);
|
||||
connect(rbDestIn, &QAbstractButton::clicked, view, &CompositionRenderer::setDestInMode);
|
||||
rbSourceOut = new QRadioButton(tr("Source Out"), modesGroup);
|
||||
connect(rbSourceOut, &QAbstractButton::clicked, view, &CompositionRenderer::setSourceOutMode);
|
||||
rbDestOut = new QRadioButton(tr("Dest Out"), modesGroup);
|
||||
connect(rbDestOut, &QAbstractButton::clicked, view, &CompositionRenderer::setDestOutMode);
|
||||
rbSourceAtop = new QRadioButton(tr("Source Atop"), modesGroup);
|
||||
connect(rbSourceAtop, &QAbstractButton::clicked, view, &CompositionRenderer::setSourceAtopMode);
|
||||
rbDestAtop = new QRadioButton(tr("Dest Atop"), modesGroup);
|
||||
connect(rbDestAtop, &QAbstractButton::clicked, view, &CompositionRenderer::setDestAtopMode);
|
||||
rbXor = new QRadioButton(tr("Xor"), modesGroup);
|
||||
connect(rbXor, &QAbstractButton::clicked, view, &CompositionRenderer::setXorMode);
|
||||
|
||||
rbPlus = new QRadioButton(tr("Plus"), modesGroup);
|
||||
connect(rbPlus, &QAbstractButton::clicked, view, &CompositionRenderer::setPlusMode);
|
||||
rbMultiply = new QRadioButton(tr("Multiply"), modesGroup);
|
||||
connect(rbMultiply, &QAbstractButton::clicked, view, &CompositionRenderer::setMultiplyMode);
|
||||
rbScreen = new QRadioButton(tr("Screen"), modesGroup);
|
||||
connect(rbScreen, &QAbstractButton::clicked, view, &CompositionRenderer::setScreenMode);
|
||||
rbOverlay = new QRadioButton(tr("Overlay"), modesGroup);
|
||||
connect(rbOverlay, &QAbstractButton::clicked, view, &CompositionRenderer::setOverlayMode);
|
||||
rbDarken = new QRadioButton(tr("Darken"), modesGroup);
|
||||
connect(rbDarken, &QAbstractButton::clicked, view, &CompositionRenderer::setDarkenMode);
|
||||
rbLighten = new QRadioButton(tr("Lighten"), modesGroup);
|
||||
connect(rbLighten, &QAbstractButton::clicked, view, &CompositionRenderer::setLightenMode);
|
||||
rbColorDodge = new QRadioButton(tr("Color Dodge"), modesGroup);
|
||||
connect(rbColorDodge, &QAbstractButton::clicked, view, &CompositionRenderer::setColorDodgeMode);
|
||||
rbColorBurn = new QRadioButton(tr("Color Burn"), modesGroup);
|
||||
connect(rbColorBurn, &QAbstractButton::clicked, view, &CompositionRenderer::setColorBurnMode);
|
||||
rbHardLight = new QRadioButton(tr("Hard Light"), modesGroup);
|
||||
connect(rbHardLight, &QAbstractButton::clicked, view, &CompositionRenderer::setHardLightMode);
|
||||
rbSoftLight = new QRadioButton(tr("Soft Light"), modesGroup);
|
||||
connect(rbSoftLight, &QAbstractButton::clicked, view, &CompositionRenderer::setSoftLightMode);
|
||||
rbDifference = new QRadioButton(tr("Difference"), modesGroup);
|
||||
connect(rbDifference, &QAbstractButton::clicked, view, &CompositionRenderer::setDifferenceMode);
|
||||
rbExclusion = new QRadioButton(tr("Exclusion"), modesGroup);
|
||||
connect(rbExclusion, &QAbstractButton::clicked, view, &CompositionRenderer::setExclusionMode);
|
||||
|
||||
QGroupBox *circleColorGroup = new QGroupBox(mainGroup);
|
||||
circleColorGroup->setTitle(tr("Circle color"));
|
||||
QSlider *circleColorSlider = new QSlider(Qt::Horizontal, circleColorGroup);
|
||||
circleColorSlider->setRange(0, 359);
|
||||
circleColorSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
connect(circleColorSlider, &QAbstractSlider::valueChanged, view, &CompositionRenderer::setCircleColor);
|
||||
|
||||
QGroupBox *circleAlphaGroup = new QGroupBox(mainGroup);
|
||||
circleAlphaGroup->setTitle(tr("Circle alpha"));
|
||||
QSlider *circleAlphaSlider = new QSlider(Qt::Horizontal, circleAlphaGroup);
|
||||
circleAlphaSlider->setRange(0, 255);
|
||||
circleAlphaSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
connect(circleAlphaSlider, &QAbstractSlider::valueChanged, view, &CompositionRenderer::setCircleAlpha);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(view->usesOpenGL());
|
||||
#endif
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
QPushButton *animateButton = new QPushButton(mainGroup);
|
||||
animateButton->setText(tr("Animated"));
|
||||
animateButton->setCheckable(true);
|
||||
animateButton->setChecked(true);
|
||||
|
||||
QHBoxLayout *viewLayout = new QHBoxLayout(this);
|
||||
viewLayout->addWidget(view);
|
||||
viewLayout->addWidget(mainGroup);
|
||||
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->addWidget(circleColorGroup);
|
||||
mainGroupLayout->addWidget(circleAlphaGroup);
|
||||
mainGroupLayout->addWidget(modesGroup);
|
||||
mainGroupLayout->addStretch();
|
||||
mainGroupLayout->addWidget(animateButton);
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
|
||||
QGridLayout *modesLayout = new QGridLayout(modesGroup);
|
||||
modesLayout->addWidget(rbClear, 0, 0);
|
||||
modesLayout->addWidget(rbSource, 1, 0);
|
||||
modesLayout->addWidget(rbDest, 2, 0);
|
||||
modesLayout->addWidget(rbSourceOver, 3, 0);
|
||||
modesLayout->addWidget(rbDestOver, 4, 0);
|
||||
modesLayout->addWidget(rbSourceIn, 5, 0);
|
||||
modesLayout->addWidget(rbDestIn, 6, 0);
|
||||
modesLayout->addWidget(rbSourceOut, 7, 0);
|
||||
modesLayout->addWidget(rbDestOut, 8, 0);
|
||||
modesLayout->addWidget(rbSourceAtop, 9, 0);
|
||||
modesLayout->addWidget(rbDestAtop, 10, 0);
|
||||
modesLayout->addWidget(rbXor, 11, 0);
|
||||
|
||||
modesLayout->addWidget(rbPlus, 0, 1);
|
||||
modesLayout->addWidget(rbMultiply, 1, 1);
|
||||
modesLayout->addWidget(rbScreen, 2, 1);
|
||||
modesLayout->addWidget(rbOverlay, 3, 1);
|
||||
modesLayout->addWidget(rbDarken, 4, 1);
|
||||
modesLayout->addWidget(rbLighten, 5, 1);
|
||||
modesLayout->addWidget(rbColorDodge, 6, 1);
|
||||
modesLayout->addWidget(rbColorBurn, 7, 1);
|
||||
modesLayout->addWidget(rbHardLight, 8, 1);
|
||||
modesLayout->addWidget(rbSoftLight, 9, 1);
|
||||
modesLayout->addWidget(rbDifference, 10, 1);
|
||||
modesLayout->addWidget(rbExclusion, 11, 1);
|
||||
|
||||
|
||||
QVBoxLayout *circleColorLayout = new QVBoxLayout(circleColorGroup);
|
||||
circleColorLayout->addWidget(circleColorSlider);
|
||||
|
||||
QVBoxLayout *circleAlphaLayout = new QVBoxLayout(circleAlphaGroup);
|
||||
circleAlphaLayout->addWidget(circleAlphaSlider);
|
||||
|
||||
view->loadDescription(":res/composition/composition.html");
|
||||
view->loadSourceFile(":res/composition/composition.cpp");
|
||||
|
||||
connect(whatsThisButton, &QAbstractButton::clicked, view, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(view, &ArthurFrame::descriptionEnabledChanged, whatsThisButton, &QAbstractButton::setChecked);
|
||||
connect(showSourceButton, &QAbstractButton::clicked, view, &ArthurFrame::showSource);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked, view, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
connect(animateButton, &QAbstractButton::toggled, view, &CompositionRenderer::setAnimationEnabled);
|
||||
|
||||
circleColorSlider->setValue(270);
|
||||
circleAlphaSlider->setValue(200);
|
||||
rbSourceOut->animateClick();
|
||||
|
||||
setWindowTitle(tr("Composition Modes"));
|
||||
}
|
||||
|
||||
CompositionWidget::~CompositionWidget()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CompositionWidget::nextMode()
|
||||
{
|
||||
/*
|
||||
if (!m_animation_enabled)
|
||||
return;
|
||||
if (rbClear->isChecked()) rbSource->animateClick();
|
||||
if (rbSource->isChecked()) rbDest->animateClick();
|
||||
if (rbDest->isChecked()) rbSourceOver->animateClick();
|
||||
if (rbSourceOver->isChecked()) rbDestOver->animateClick();
|
||||
if (rbDestOver->isChecked()) rbSourceIn->animateClick();
|
||||
if (rbSourceIn->isChecked()) rbDestIn->animateClick();
|
||||
if (rbDestIn->isChecked()) rbSourceOut->animateClick();
|
||||
if (rbSourceOut->isChecked()) rbDestOut->animateClick();
|
||||
if (rbDestOut->isChecked()) rbSourceAtop->animateClick();
|
||||
if (rbSourceAtop->isChecked()) rbDestAtop->animateClick();
|
||||
if (rbDestAtop->isChecked()) rbXor->animateClick();
|
||||
if (rbXor->isChecked()) rbClear->animateClick();
|
||||
*/
|
||||
}
|
||||
|
||||
CompositionRenderer::CompositionRenderer(QWidget *parent)
|
||||
: ArthurFrame(parent)
|
||||
{
|
||||
m_animation_enabled = true;
|
||||
m_animationTimer = startTimer(animationInterval);
|
||||
m_image = QImage(":res/composition/flower.jpg");
|
||||
m_image.setAlphaChannel(QImage(":res/composition/flower_alpha.jpg"));
|
||||
m_circle_alpha = 127;
|
||||
m_circle_hue = 255;
|
||||
m_current_object = NoObject;
|
||||
m_composition_mode = QPainter::CompositionMode_SourceOut;
|
||||
|
||||
m_circle_pos = QPoint(200, 100);
|
||||
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
#if QT_CONFIG(opengl)
|
||||
m_pbuffer_size = 1024;
|
||||
m_base_tex = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
CompositionRenderer::~CompositionRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
QRectF rectangle_around(const QPointF &p, const QSizeF &size = QSize(250, 200))
|
||||
{
|
||||
QRectF rect(p, size);
|
||||
rect.translate(-size.width()/2, -size.height()/2);
|
||||
return rect;
|
||||
}
|
||||
|
||||
void CompositionRenderer::setAnimationEnabled(bool enabled)
|
||||
{
|
||||
if (m_animation_enabled == enabled)
|
||||
return;
|
||||
m_animation_enabled = enabled;
|
||||
if (enabled) {
|
||||
Q_ASSERT(!m_animationTimer);
|
||||
m_animationTimer = startTimer(animationInterval);
|
||||
} else {
|
||||
killTimer(m_animationTimer);
|
||||
m_animationTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositionRenderer::updateCirclePos()
|
||||
{
|
||||
if (m_current_object != NoObject)
|
||||
return;
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
qreal t = dt.toMSecsSinceEpoch() / 1000.0;
|
||||
|
||||
qreal x = width() / qreal(2) + (qCos(t*8/11) + qSin(-t)) * width() / qreal(4);
|
||||
qreal y = height() / qreal(2) + (qSin(t*6/7) + qCos(t * qreal(1.5))) * height() / qreal(4);
|
||||
|
||||
setCirclePos(QLineF(m_circle_pos, QPointF(x, y)).pointAt(0.02));
|
||||
}
|
||||
|
||||
void CompositionRenderer::drawBase(QPainter &p)
|
||||
{
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
QLinearGradient rect_gradient(0, 0, 0, height());
|
||||
rect_gradient.setColorAt(0, Qt::red);
|
||||
rect_gradient.setColorAt(.17, Qt::yellow);
|
||||
rect_gradient.setColorAt(.33, Qt::green);
|
||||
rect_gradient.setColorAt(.50, Qt::cyan);
|
||||
rect_gradient.setColorAt(.66, Qt::blue);
|
||||
rect_gradient.setColorAt(.81, Qt::magenta);
|
||||
rect_gradient.setColorAt(1, Qt::red);
|
||||
p.setBrush(rect_gradient);
|
||||
p.drawRect(width() / 2, 0, width() / 2, height());
|
||||
|
||||
QLinearGradient alpha_gradient(0, 0, width(), 0);
|
||||
alpha_gradient.setColorAt(0, Qt::white);
|
||||
alpha_gradient.setColorAt(0.2, Qt::white);
|
||||
alpha_gradient.setColorAt(0.5, Qt::transparent);
|
||||
alpha_gradient.setColorAt(0.8, Qt::white);
|
||||
alpha_gradient.setColorAt(1, Qt::white);
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
p.setBrush(alpha_gradient);
|
||||
p.drawRect(0, 0, width(), height());
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationOver);
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
p.drawImage(rect(), m_image);
|
||||
}
|
||||
|
||||
void CompositionRenderer::drawSource(QPainter &p)
|
||||
{
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setCompositionMode(m_composition_mode);
|
||||
|
||||
QRectF circle_rect = rectangle_around(m_circle_pos);
|
||||
QColor color = QColor::fromHsvF(m_circle_hue / 360.0, 1, 1, m_circle_alpha / 255.0);
|
||||
QLinearGradient circle_gradient(circle_rect.topLeft(), circle_rect.bottomRight());
|
||||
circle_gradient.setColorAt(0, color.lighter());
|
||||
circle_gradient.setColorAt(0.5, color);
|
||||
circle_gradient.setColorAt(1, color.darker());
|
||||
p.setBrush(circle_gradient);
|
||||
|
||||
p.drawEllipse(circle_rect);
|
||||
}
|
||||
|
||||
void CompositionRenderer::paint(QPainter *painter)
|
||||
{
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL() && glWindow()->isValid()) {
|
||||
auto *funcs = QOpenGLContext::currentContext()->functions();
|
||||
|
||||
if (!m_blitter.isCreated())
|
||||
m_blitter.create();
|
||||
|
||||
int new_pbuf_size = m_pbuffer_size;
|
||||
while (size().width() > new_pbuf_size || size().height() > new_pbuf_size)
|
||||
new_pbuf_size *= 2;
|
||||
|
||||
while (size().width() < new_pbuf_size/2 && size().height() < new_pbuf_size/2)
|
||||
new_pbuf_size /= 2;
|
||||
|
||||
if (!m_fbo || new_pbuf_size != m_pbuffer_size) {
|
||||
m_fbo.reset(new QFboPaintDevice(QSize(new_pbuf_size, new_pbuf_size), false, false));
|
||||
m_pbuffer_size = new_pbuf_size;
|
||||
}
|
||||
|
||||
if (size() != m_previous_size) {
|
||||
m_previous_size = size();
|
||||
QPainter p(m_fbo.get());
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(QRect(QPoint(0, 0), size()), Qt::transparent);
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
drawBase(p);
|
||||
p.end();
|
||||
if (m_base_tex)
|
||||
funcs->glDeleteTextures(1, &m_base_tex);
|
||||
m_base_tex = m_fbo->takeTexture();
|
||||
}
|
||||
|
||||
painter->beginNativePainting();
|
||||
uint compositingTex;
|
||||
{
|
||||
QPainter p(m_fbo.get());
|
||||
p.beginNativePainting();
|
||||
m_blitter.bind();
|
||||
const QRect targetRect(QPoint(0, 0), m_fbo->size());
|
||||
const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), m_fbo->size()));
|
||||
m_blitter.blit(m_base_tex, target, QOpenGLTextureBlitter::OriginBottomLeft);
|
||||
m_blitter.release();
|
||||
p.endNativePainting();
|
||||
drawSource(p);
|
||||
p.end();
|
||||
compositingTex = m_fbo->texture();
|
||||
}
|
||||
painter->endNativePainting();
|
||||
|
||||
painter->beginNativePainting();
|
||||
funcs->glEnable(GL_BLEND);
|
||||
funcs->glBlendEquation(GL_FUNC_ADD);
|
||||
funcs->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
m_blitter.bind();
|
||||
const QRect targetRect(QPoint(0, 0), m_fbo->size());
|
||||
const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), size()));
|
||||
m_blitter.blit(compositingTex, target, QOpenGLTextureBlitter::OriginBottomLeft);
|
||||
m_blitter.release();
|
||||
painter->endNativePainting();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// using a QImage
|
||||
if (m_buffer.size() != size()) {
|
||||
m_buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
m_base_buffer = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
m_base_buffer.fill(0);
|
||||
|
||||
QPainter p(&m_base_buffer);
|
||||
|
||||
drawBase(p);
|
||||
}
|
||||
|
||||
memcpy(m_buffer.bits(), m_base_buffer.bits(), m_buffer.sizeInBytes());
|
||||
|
||||
{
|
||||
QPainter p(&m_buffer);
|
||||
drawSource(p);
|
||||
}
|
||||
|
||||
painter->drawImage(0, 0, m_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void CompositionRenderer::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
setDescriptionEnabled(false);
|
||||
|
||||
QRectF circle = rectangle_around(m_circle_pos);
|
||||
|
||||
if (circle.contains(e->pos())) {
|
||||
m_current_object = Circle;
|
||||
m_offset = circle.center() - e->pos();
|
||||
} else {
|
||||
m_current_object = NoObject;
|
||||
}
|
||||
if (m_animation_enabled) {
|
||||
killTimer(m_animationTimer);
|
||||
m_animationTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositionRenderer::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (m_current_object == Circle)
|
||||
setCirclePos(e->pos() + m_offset);
|
||||
}
|
||||
|
||||
void CompositionRenderer::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
m_current_object = NoObject;
|
||||
|
||||
if (m_animation_enabled) {
|
||||
Q_ASSERT(!m_animationTimer);
|
||||
m_animationTimer = startTimer(animationInterval);
|
||||
}
|
||||
}
|
||||
|
||||
void CompositionRenderer::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == m_animationTimer)
|
||||
updateCirclePos();
|
||||
}
|
||||
|
||||
void CompositionRenderer::setCirclePos(const QPointF &pos)
|
||||
{
|
||||
const QRect oldRect = rectangle_around(m_circle_pos).toAlignedRect();
|
||||
m_circle_pos = pos;
|
||||
const QRect newRect = rectangle_around(m_circle_pos).toAlignedRect();
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL()) {
|
||||
update();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
update(oldRect | newRect);
|
||||
}
|
||||
|
156
examples/widgets/painting/composition/composition.h
Normal file
@ -0,0 +1,156 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef COMPOSITION_H
|
||||
#define COMPOSITION_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
#include "fbopaintdevice.h"
|
||||
#include <QOpenGLTextureBlitter>
|
||||
#endif
|
||||
|
||||
#include <QPainter>
|
||||
#include <QEvent>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPushButton;
|
||||
class QRadioButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class CompositionWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CompositionWidget(QWidget *parent = nullptr);
|
||||
~CompositionWidget();
|
||||
|
||||
public slots:
|
||||
void nextMode();
|
||||
|
||||
private:
|
||||
bool m_cycle_enabled;
|
||||
|
||||
QRadioButton *rbClear;
|
||||
QRadioButton *rbSource;
|
||||
QRadioButton *rbDest;
|
||||
QRadioButton *rbSourceOver;
|
||||
QRadioButton *rbDestOver;
|
||||
QRadioButton *rbSourceIn;
|
||||
QRadioButton *rbDestIn;
|
||||
QRadioButton *rbSourceOut;
|
||||
QRadioButton *rbDestOut;
|
||||
QRadioButton *rbSourceAtop;
|
||||
QRadioButton *rbDestAtop;
|
||||
QRadioButton *rbXor;
|
||||
|
||||
QRadioButton *rbPlus;
|
||||
QRadioButton *rbMultiply;
|
||||
QRadioButton *rbScreen;
|
||||
QRadioButton *rbOverlay;
|
||||
QRadioButton *rbDarken;
|
||||
QRadioButton *rbLighten;
|
||||
QRadioButton *rbColorDodge;
|
||||
QRadioButton *rbColorBurn;
|
||||
QRadioButton *rbHardLight;
|
||||
QRadioButton *rbSoftLight;
|
||||
QRadioButton *rbDifference;
|
||||
QRadioButton *rbExclusion;
|
||||
};
|
||||
|
||||
class CompositionRenderer : public ArthurFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
enum ObjectType { NoObject, Circle, Rectangle, Image };
|
||||
|
||||
Q_PROPERTY(int circleColor READ circleColor WRITE setCircleColor)
|
||||
Q_PROPERTY(int circleAlpha READ circleAlpha WRITE setCircleAlpha)
|
||||
Q_PROPERTY(bool animation READ animationEnabled WRITE setAnimationEnabled)
|
||||
|
||||
public:
|
||||
explicit CompositionRenderer(QWidget *parent = nullptr);
|
||||
~CompositionRenderer();
|
||||
|
||||
void paint(QPainter *) override;
|
||||
|
||||
void setCirclePos(const QPointF &pos);
|
||||
|
||||
QSize sizeHint() const override { return QSize(500, 400); }
|
||||
|
||||
bool animationEnabled() const { return m_animation_enabled; }
|
||||
int circleColor() const { return m_circle_hue; }
|
||||
int circleAlpha() const { return m_circle_alpha; }
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *) override;
|
||||
void mouseMoveEvent(QMouseEvent *) override;
|
||||
void mouseReleaseEvent(QMouseEvent *) override;
|
||||
void timerEvent(QTimerEvent *) override;
|
||||
|
||||
public slots:
|
||||
void setClearMode() { m_composition_mode = QPainter::CompositionMode_Clear; update(); }
|
||||
void setSourceMode() { m_composition_mode = QPainter::CompositionMode_Source; update(); }
|
||||
void setDestMode() { m_composition_mode = QPainter::CompositionMode_Destination; update(); }
|
||||
void setSourceOverMode() { m_composition_mode = QPainter::CompositionMode_SourceOver; update(); }
|
||||
void setDestOverMode() { m_composition_mode = QPainter::CompositionMode_DestinationOver; update(); }
|
||||
void setSourceInMode() { m_composition_mode = QPainter::CompositionMode_SourceIn; update(); }
|
||||
void setDestInMode() { m_composition_mode = QPainter::CompositionMode_DestinationIn; update(); }
|
||||
void setSourceOutMode() { m_composition_mode = QPainter::CompositionMode_SourceOut; update(); }
|
||||
void setDestOutMode() { m_composition_mode = QPainter::CompositionMode_DestinationOut; update(); }
|
||||
void setSourceAtopMode() { m_composition_mode = QPainter::CompositionMode_SourceAtop; update(); }
|
||||
void setDestAtopMode() { m_composition_mode = QPainter::CompositionMode_DestinationAtop; update(); }
|
||||
void setXorMode() { m_composition_mode = QPainter::CompositionMode_Xor; update(); }
|
||||
|
||||
void setPlusMode() { m_composition_mode = QPainter::CompositionMode_Plus; update(); }
|
||||
void setMultiplyMode() { m_composition_mode = QPainter::CompositionMode_Multiply; update(); }
|
||||
void setScreenMode() { m_composition_mode = QPainter::CompositionMode_Screen; update(); }
|
||||
void setOverlayMode() { m_composition_mode = QPainter::CompositionMode_Overlay; update(); }
|
||||
void setDarkenMode() { m_composition_mode = QPainter::CompositionMode_Darken; update(); }
|
||||
void setLightenMode() { m_composition_mode = QPainter::CompositionMode_Lighten; update(); }
|
||||
void setColorDodgeMode() { m_composition_mode = QPainter::CompositionMode_ColorDodge; update(); }
|
||||
void setColorBurnMode() { m_composition_mode = QPainter::CompositionMode_ColorBurn; update(); }
|
||||
void setHardLightMode() { m_composition_mode = QPainter::CompositionMode_HardLight; update(); }
|
||||
void setSoftLightMode() { m_composition_mode = QPainter::CompositionMode_SoftLight; update(); }
|
||||
void setDifferenceMode() { m_composition_mode = QPainter::CompositionMode_Difference; update(); }
|
||||
void setExclusionMode() { m_composition_mode = QPainter::CompositionMode_Exclusion; update(); }
|
||||
|
||||
void setCircleAlpha(int alpha) { m_circle_alpha = alpha; update(); }
|
||||
void setCircleColor(int hue) { m_circle_hue = hue; update(); }
|
||||
void setAnimationEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
void updateCirclePos();
|
||||
void drawBase(QPainter &p);
|
||||
void drawSource(QPainter &p);
|
||||
|
||||
QPainter::CompositionMode m_composition_mode;
|
||||
|
||||
QImage m_image;
|
||||
QImage m_buffer;
|
||||
QImage m_base_buffer;
|
||||
|
||||
int m_circle_alpha;
|
||||
int m_circle_hue;
|
||||
|
||||
QPointF m_circle_pos;
|
||||
QPointF m_offset;
|
||||
|
||||
ObjectType m_current_object;
|
||||
bool m_animation_enabled;
|
||||
int m_animationTimer;
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
std::unique_ptr<QFboPaintDevice> m_fbo;
|
||||
int m_pbuffer_size; // width==height==size of pbuffer
|
||||
uint m_base_tex;
|
||||
QSize m_previous_size;
|
||||
QOpenGLTextureBlitter m_blitter;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // COMPOSITION_H
|
23
examples/widgets/painting/composition/composition.html
Normal file
@ -0,0 +1,23 @@
|
||||
<html>
|
||||
|
||||
<h1>Example for composition modes</h1>
|
||||
|
||||
<p>
|
||||
This example shows some of the more advanced composition modes supported by Qt.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The two most common forms of composition are <b>Source</b> and <b>SourceOver</b>.
|
||||
<b>Source</b> is used to draw opaque objects onto a paint device. In this mode,
|
||||
each pixel in the source replaces the corresponding pixel in the destination.
|
||||
In <b>SourceOver</b> composition mode, the source object is transparent and is
|
||||
drawn on top of the destination.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In addition to these standard modes, Qt defines the complete set of composition
|
||||
modes as defined by Thomas Porter and Tom Duff. See the <tt>QPainter</tt> documentation
|
||||
for details.
|
||||
</p>
|
||||
|
||||
</html>
|
13
examples/widgets/painting/composition/composition.pro
Normal file
@ -0,0 +1,13 @@
|
||||
SOURCES += main.cpp composition.cpp
|
||||
HEADERS += composition.h
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += composition.qrc
|
||||
QT += widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/composition
|
||||
INSTALLS += target
|
8
examples/widgets/painting/composition/composition.qrc
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/composition">
|
||||
<file>composition.cpp</file>
|
||||
<file>composition.html</file>
|
||||
<file>flower.jpg</file>
|
||||
<file>flower_alpha.jpg</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
examples/widgets/painting/composition/flower.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
examples/widgets/painting/composition/flower_alpha.jpg
Normal file
After Width: | Height: | Size: 66 KiB |
22
examples/widgets/painting/composition/main.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "composition.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QScopedPointer<QStyle> arthurStyle(new ArthurStyle());
|
||||
CompositionWidget compWidget(nullptr);
|
||||
compWidget.setStyle(arthurStyle.data());
|
||||
|
||||
const QList<QWidget *> widgets = compWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets)
|
||||
w->setStyle(arthurStyle.data());
|
||||
compWidget.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
38
examples/widgets/painting/concentriccircles/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(concentriccircles LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/concentriccircles")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(concentriccircles
|
||||
circlewidget.cpp circlewidget.h
|
||||
main.cpp
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(concentriccircles PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(concentriccircles PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
install(TARGETS concentriccircles
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
84
examples/widgets/painting/concentriccircles/circlewidget.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "circlewidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//! [0]
|
||||
CircleWidget::CircleWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
floatBased = false;
|
||||
antialiased = false;
|
||||
frameNo = 0;
|
||||
|
||||
setBackgroundRole(QPalette::Base);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
void CircleWidget::setFloatBased(bool floatBased)
|
||||
{
|
||||
this->floatBased = floatBased;
|
||||
update();
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
void CircleWidget::setAntialiased(bool antialiased)
|
||||
{
|
||||
this->antialiased = antialiased;
|
||||
update();
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QSize CircleWidget::minimumSizeHint() const
|
||||
{
|
||||
return QSize(50, 50);
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QSize CircleWidget::sizeHint() const
|
||||
{
|
||||
return QSize(180, 180);
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
void CircleWidget::nextAnimationFrame()
|
||||
{
|
||||
++frameNo;
|
||||
update();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
void CircleWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, antialiased);
|
||||
painter.translate(width() / 2, height() / 2);
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
for (int diameter = 0; diameter < 256; diameter += 9) {
|
||||
int delta = abs((frameNo % 128) - diameter / 2);
|
||||
int alpha = 255 - (delta * delta) / 4 - diameter;
|
||||
//! [7] //! [8]
|
||||
if (alpha > 0) {
|
||||
painter.setPen(QPen(QColor(0, diameter / 2, 127, alpha), 3));
|
||||
|
||||
if (floatBased)
|
||||
painter.drawEllipse(QRectF(-diameter / 2.0, -diameter / 2.0, diameter, diameter));
|
||||
else
|
||||
painter.drawEllipse(QRect(-diameter / 2, -diameter / 2, diameter, diameter));
|
||||
}
|
||||
}
|
||||
}
|
||||
//! [8]
|
36
examples/widgets/painting/concentriccircles/circlewidget.h
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef CIRCLEWIDGET_H
|
||||
#define CIRCLEWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
//! [0]
|
||||
class CircleWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CircleWidget(QWidget *parent = nullptr);
|
||||
|
||||
void setFloatBased(bool floatBased);
|
||||
void setAntialiased(bool antialiased);
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
void nextAnimationFrame();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private:
|
||||
bool floatBased;
|
||||
bool antialiased;
|
||||
int frameNo;
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // CIRCLEWIDGET_H
|
@ -0,0 +1,11 @@
|
||||
QT += widgets
|
||||
|
||||
HEADERS = circlewidget.h \
|
||||
window.h
|
||||
SOURCES = circlewidget.cpp \
|
||||
main.cpp \
|
||||
window.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/concentriccircles
|
||||
INSTALLS += target
|
14
examples/widgets/painting/concentriccircles/main.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Window window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
56
examples/widgets/painting/concentriccircles/window.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "circlewidget.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
//! [0]
|
||||
Window::Window()
|
||||
{
|
||||
aliasedLabel = createLabel(tr("Aliased"));
|
||||
antialiasedLabel = createLabel(tr("Antialiased"));
|
||||
intLabel = createLabel(tr("Int"));
|
||||
floatLabel = createLabel(tr("Float"));
|
||||
|
||||
QGridLayout *layout = new QGridLayout;
|
||||
layout->addWidget(aliasedLabel, 0, 1);
|
||||
layout->addWidget(antialiasedLabel, 0, 2);
|
||||
layout->addWidget(intLabel, 1, 0);
|
||||
layout->addWidget(floatLabel, 2, 0);
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
QTimer *timer = new QTimer(this);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
circleWidgets[i][j] = new CircleWidget;
|
||||
circleWidgets[i][j]->setAntialiased(j != 0);
|
||||
circleWidgets[i][j]->setFloatBased(i != 0);
|
||||
|
||||
connect(timer, &QTimer::timeout,
|
||||
circleWidgets[i][j], &CircleWidget::nextAnimationFrame);
|
||||
|
||||
layout->addWidget(circleWidgets[i][j], i + 1, j + 1);
|
||||
}
|
||||
}
|
||||
//! [1] //! [2]
|
||||
timer->start(100);
|
||||
setLayout(layout);
|
||||
|
||||
setWindowTitle(tr("Concentric Circles"));
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QLabel *Window::createLabel(const QString &text)
|
||||
{
|
||||
QLabel *label = new QLabel(text);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setMargin(2);
|
||||
label->setFrameStyle(QFrame::Box | QFrame::Sunken);
|
||||
return label;
|
||||
}
|
||||
//! [3]
|
33
examples/widgets/painting/concentriccircles/window.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
class CircleWidget;
|
||||
|
||||
//! [0]
|
||||
class Window : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window();
|
||||
|
||||
private:
|
||||
QLabel *createLabel(const QString &text);
|
||||
|
||||
QLabel *aliasedLabel;
|
||||
QLabel *antialiasedLabel;
|
||||
QLabel *intLabel;
|
||||
QLabel *floatLabel;
|
||||
CircleWidget *circleWidgets[2][2];
|
||||
};
|
||||
//! [0]
|
||||
|
||||
#endif // WINDOW_H
|
102
examples/widgets/painting/deform/CMakeLists.txt
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(deform LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/deform")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(deform
|
||||
main.cpp
|
||||
pathdeform.cpp pathdeform.h
|
||||
)
|
||||
|
||||
set_target_properties(deform PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(deform PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(deform "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(deform_resource_files
|
||||
"pathdeform.cpp"
|
||||
"pathdeform.html"
|
||||
)
|
||||
|
||||
qt_add_resources(deform "deform"
|
||||
PREFIX
|
||||
"/res/deform"
|
||||
FILES
|
||||
${deform_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS deform
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
14
examples/widgets/painting/deform/deform.pro
Normal file
@ -0,0 +1,14 @@
|
||||
SOURCES += main.cpp pathdeform.cpp
|
||||
HEADERS += pathdeform.h
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += deform.qrc
|
||||
|
||||
QT += widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/deform
|
||||
INSTALLS += target
|
6
examples/widgets/painting/deform/deform.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/deform">
|
||||
<file>pathdeform.cpp</file>
|
||||
<file>pathdeform.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
33
examples/widgets/painting/deform/main.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathdeform.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(deform);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
bool smallScreen = QApplication::arguments().contains("-small-screen");
|
||||
|
||||
PathDeformWidget deformWidget(nullptr, smallScreen);
|
||||
|
||||
QStyle *arthurStyle = new ArthurStyle;
|
||||
deformWidget.setStyle(arthurStyle);
|
||||
const QList<QWidget *> widgets = deformWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets)
|
||||
w->setStyle(arthurStyle);
|
||||
|
||||
if (smallScreen)
|
||||
deformWidget.showFullScreen();
|
||||
else
|
||||
deformWidget.show();
|
||||
|
||||
#ifdef QT_KEYPAD_NAVIGATION
|
||||
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
|
||||
#endif
|
||||
return app.exec();
|
||||
}
|
596
examples/widgets/painting/deform/pathdeform.cpp
Normal file
@ -0,0 +1,596 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathdeform.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QScreen>
|
||||
#include <QtDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QTimerEvent>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QPainter>
|
||||
#include <QSlider>
|
||||
#include <QLabel>
|
||||
#include <qmath.h>
|
||||
|
||||
PathDeformControls::PathDeformControls(QWidget *parent,
|
||||
PathDeformRenderer* renderer, bool smallScreen)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
|
||||
if (smallScreen)
|
||||
layoutForSmallScreen();
|
||||
else
|
||||
layoutForDesktop();
|
||||
}
|
||||
|
||||
void PathDeformControls::layoutForDesktop()
|
||||
{
|
||||
QGroupBox* mainGroup = new QGroupBox(this);
|
||||
mainGroup->setTitle(tr("Controls"));
|
||||
|
||||
QGroupBox *radiusGroup = new QGroupBox(mainGroup);
|
||||
radiusGroup->setTitle(tr("Lens Radius"));
|
||||
QSlider *radiusSlider = new QSlider(Qt::Horizontal, radiusGroup);
|
||||
radiusSlider->setRange(15, 150);
|
||||
radiusSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *deformGroup = new QGroupBox(mainGroup);
|
||||
deformGroup->setTitle(tr("Deformation"));
|
||||
QSlider *deformSlider = new QSlider(Qt::Horizontal, deformGroup);
|
||||
deformSlider->setRange(-100, 100);
|
||||
deformSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *fontSizeGroup = new QGroupBox(mainGroup);
|
||||
fontSizeGroup->setTitle(tr("Font Size"));
|
||||
QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, fontSizeGroup);
|
||||
fontSizeSlider->setRange(16, 200);
|
||||
fontSizeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
QGroupBox *textGroup = new QGroupBox(mainGroup);
|
||||
textGroup->setTitle(tr("Text"));
|
||||
QLineEdit *textInput = new QLineEdit(textGroup);
|
||||
|
||||
QPushButton *animateButton = new QPushButton(mainGroup);
|
||||
animateButton->setText(tr("Animated"));
|
||||
animateButton->setCheckable(true);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
|
||||
mainGroup->setFixedWidth(180);
|
||||
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->addWidget(radiusGroup);
|
||||
mainGroupLayout->addWidget(deformGroup);
|
||||
mainGroupLayout->addWidget(fontSizeGroup);
|
||||
mainGroupLayout->addWidget(textGroup);
|
||||
mainGroupLayout->addWidget(animateButton);
|
||||
mainGroupLayout->addStretch(1);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
|
||||
QVBoxLayout *radiusGroupLayout = new QVBoxLayout(radiusGroup);
|
||||
radiusGroupLayout->addWidget(radiusSlider);
|
||||
|
||||
QVBoxLayout *deformGroupLayout = new QVBoxLayout(deformGroup);
|
||||
deformGroupLayout->addWidget(deformSlider);
|
||||
|
||||
QVBoxLayout *fontSizeGroupLayout = new QVBoxLayout(fontSizeGroup);
|
||||
fontSizeGroupLayout->addWidget(fontSizeSlider);
|
||||
|
||||
QVBoxLayout *textGroupLayout = new QVBoxLayout(textGroup);
|
||||
textGroupLayout->addWidget(textInput);
|
||||
|
||||
QVBoxLayout * mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(mainGroup);
|
||||
mainLayout->setContentsMargins(QMargins());
|
||||
|
||||
connect(radiusSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setRadius);
|
||||
connect(deformSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setIntensity);
|
||||
connect(fontSizeSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setFontSize);
|
||||
connect(animateButton, &QAbstractButton::clicked, m_renderer, &PathDeformRenderer::setAnimated);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
|
||||
connect(textInput, &QLineEdit::textChanged, m_renderer, &PathDeformRenderer::setText);
|
||||
connect(m_renderer, &ArthurFrame::descriptionEnabledChanged,
|
||||
whatsThisButton, &QAbstractButton::setChecked);
|
||||
connect(whatsThisButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(showSourceButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::showSource);
|
||||
|
||||
animateButton->animateClick();
|
||||
deformSlider->setValue(80);
|
||||
fontSizeSlider->setValue(120);
|
||||
radiusSlider->setValue(100);
|
||||
textInput->setText(tr("Qt"));
|
||||
}
|
||||
|
||||
void PathDeformControls::layoutForSmallScreen()
|
||||
{
|
||||
QGroupBox* mainGroup = new QGroupBox(this);
|
||||
mainGroup->setTitle(tr("Controls"));
|
||||
|
||||
QLabel *radiusLabel = new QLabel(mainGroup);
|
||||
radiusLabel->setText(tr("Lens Radius:"));
|
||||
QSlider *radiusSlider = new QSlider(Qt::Horizontal, mainGroup);
|
||||
radiusSlider->setRange(15, 150);
|
||||
radiusSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
QLabel *deformLabel = new QLabel(mainGroup);
|
||||
deformLabel->setText(tr("Deformation:"));
|
||||
QSlider *deformSlider = new QSlider(Qt::Horizontal, mainGroup);
|
||||
deformSlider->setRange(-100, 100);
|
||||
deformSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
QLabel *fontSizeLabel = new QLabel(mainGroup);
|
||||
fontSizeLabel->setText(tr("Font Size:"));
|
||||
QSlider *fontSizeSlider = new QSlider(Qt::Horizontal, mainGroup);
|
||||
fontSizeSlider->setRange(16, 200);
|
||||
fontSizeSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
QPushButton *animateButton = new QPushButton(tr("Animated"), mainGroup);
|
||||
animateButton->setCheckable(true);
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(mainGroup);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
|
||||
QPushButton *quitButton = new QPushButton(tr("Quit"), mainGroup);
|
||||
QPushButton *okButton = new QPushButton(tr("OK"), mainGroup);
|
||||
|
||||
|
||||
QGridLayout *mainGroupLayout = new QGridLayout(mainGroup);
|
||||
mainGroupLayout->setContentsMargins(QMargins());
|
||||
mainGroupLayout->addWidget(radiusLabel, 0, 0, Qt::AlignRight);
|
||||
mainGroupLayout->addWidget(radiusSlider, 0, 1);
|
||||
mainGroupLayout->addWidget(deformLabel, 1, 0, Qt::AlignRight);
|
||||
mainGroupLayout->addWidget(deformSlider, 1, 1);
|
||||
mainGroupLayout->addWidget(fontSizeLabel, 2, 0, Qt::AlignRight);
|
||||
mainGroupLayout->addWidget(fontSizeSlider, 2, 1);
|
||||
mainGroupLayout->addWidget(animateButton, 3,0, 1,2);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton, 4,0, 1,2);
|
||||
#endif
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->addWidget(mainGroup);
|
||||
mainLayout->addStretch(1);
|
||||
mainLayout->addWidget(okButton);
|
||||
mainLayout->addWidget(quitButton);
|
||||
|
||||
connect(quitButton, &QAbstractButton::clicked, this, &PathDeformControls::quitPressed);
|
||||
connect(okButton, &QAbstractButton::clicked, this, &PathDeformControls::okPressed);
|
||||
connect(radiusSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setRadius);
|
||||
connect(deformSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setIntensity);
|
||||
connect(fontSizeSlider, &QAbstractSlider::valueChanged, m_renderer, &PathDeformRenderer::setFontSize);
|
||||
connect(animateButton, &QAbstractButton::clicked, m_renderer, &PathDeformRenderer::setAnimated);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
|
||||
|
||||
animateButton->animateClick();
|
||||
deformSlider->setValue(80);
|
||||
fontSizeSlider->setValue(120);
|
||||
|
||||
QRect screen_size = QGuiApplication::primaryScreen()->geometry();
|
||||
radiusSlider->setValue(qMin(screen_size.width(), screen_size.height())/5);
|
||||
|
||||
m_renderer->setText(tr("Qt"));
|
||||
}
|
||||
|
||||
PathDeformWidget::PathDeformWidget(QWidget *parent, bool smallScreen)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setWindowTitle(tr("Vector Deformation"));
|
||||
|
||||
m_renderer = new PathDeformRenderer(this, smallScreen);
|
||||
m_renderer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
// Layouts
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->addWidget(m_renderer);
|
||||
|
||||
m_controls = new PathDeformControls(nullptr, m_renderer, smallScreen);
|
||||
m_controls->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
|
||||
|
||||
if (!smallScreen)
|
||||
mainLayout->addWidget(m_controls);
|
||||
|
||||
m_renderer->loadSourceFile(":res/deform/pathdeform.cpp");
|
||||
m_renderer->loadDescription(":res/deform/pathdeform.html");
|
||||
m_renderer->setDescriptionEnabled(false);
|
||||
|
||||
connect(m_renderer, &PathDeformRenderer::clicked,
|
||||
this, &PathDeformWidget::showControls);
|
||||
connect(m_controls, &PathDeformControls::okPressed,
|
||||
this, &PathDeformWidget::hideControls);
|
||||
connect(m_controls, &PathDeformControls::quitPressed,
|
||||
qApp, &QCoreApplication::quit);
|
||||
}
|
||||
|
||||
|
||||
void PathDeformWidget::showControls()
|
||||
{
|
||||
m_controls->showFullScreen();
|
||||
}
|
||||
|
||||
void PathDeformWidget::hideControls()
|
||||
{
|
||||
m_controls->hide();
|
||||
}
|
||||
|
||||
void PathDeformWidget::setStyle(QStyle *style)
|
||||
{
|
||||
QWidget::setStyle(style);
|
||||
if (!m_controls)
|
||||
return;
|
||||
|
||||
m_controls->setStyle(style);
|
||||
|
||||
const QList<QWidget *> widgets = m_controls->findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets)
|
||||
w->setStyle(style);
|
||||
}
|
||||
|
||||
static inline QRect circle_bounds(const QPointF ¢er, qreal radius, qreal compensation)
|
||||
{
|
||||
return QRect(qRound(center.x() - radius - compensation),
|
||||
qRound(center.y() - radius - compensation),
|
||||
qRound((radius + compensation) * 2),
|
||||
qRound((radius + compensation) * 2));
|
||||
|
||||
}
|
||||
|
||||
const int LENS_EXTENT = 10;
|
||||
|
||||
PathDeformRenderer::PathDeformRenderer(QWidget *widget, bool smallScreen)
|
||||
: ArthurFrame(widget)
|
||||
{
|
||||
m_radius = 100;
|
||||
m_pos = QPointF(m_radius, m_radius);
|
||||
m_direction = QPointF(1, 1);
|
||||
m_fontSize = 24;
|
||||
m_animated = true;
|
||||
m_repaintTimer.start(25, this);
|
||||
m_repaintTracker.start();
|
||||
m_intensity = 100;
|
||||
m_smallScreen = smallScreen;
|
||||
|
||||
// m_fpsTimer.start(1000, this);
|
||||
// m_fpsCounter = 0;
|
||||
|
||||
generateLensPixmap();
|
||||
}
|
||||
|
||||
void PathDeformRenderer::setText(const QString &text)
|
||||
{
|
||||
m_text = text;
|
||||
|
||||
QFont f("times new roman,utopia");
|
||||
f.setStyleStrategy(QFont::ForceOutline);
|
||||
f.setPointSize(m_fontSize);
|
||||
f.setStyleHint(QFont::Times);
|
||||
|
||||
QFontMetrics fm(f);
|
||||
|
||||
m_paths.clear();
|
||||
m_pathBounds = QRect();
|
||||
|
||||
QPointF advance(0, 0);
|
||||
|
||||
bool do_quick = true;
|
||||
for (int i=0; i<text.size(); ++i) {
|
||||
if (text.at(i).unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) {
|
||||
do_quick = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_quick) {
|
||||
for (int i=0; i<text.size(); ++i) {
|
||||
QPainterPath path;
|
||||
path.addText(advance, f, text.mid(i, 1));
|
||||
m_pathBounds |= path.boundingRect();
|
||||
m_paths << path;
|
||||
advance += QPointF(fm.horizontalAdvance(text.mid(i, 1)), 0);
|
||||
}
|
||||
} else {
|
||||
QPainterPath path;
|
||||
path.addText(advance, f, text);
|
||||
m_pathBounds |= path.boundingRect();
|
||||
m_paths << path;
|
||||
}
|
||||
|
||||
for (int i=0; i<m_paths.size(); ++i)
|
||||
m_paths[i] = m_paths[i] * QTransform(1, 0, 0, 1, -m_pathBounds.x(), -m_pathBounds.y());
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void PathDeformRenderer::generateLensPixmap()
|
||||
{
|
||||
qreal rad = m_radius + LENS_EXTENT;
|
||||
|
||||
QRect bounds = circle_bounds(QPointF(), rad, 0);
|
||||
|
||||
QPainter painter;
|
||||
|
||||
if (preferImage()) {
|
||||
m_lens_image = QImage(bounds.size(), QImage::Format_ARGB32_Premultiplied);
|
||||
m_lens_image.fill(0);
|
||||
painter.begin(&m_lens_image);
|
||||
} else {
|
||||
m_lens_pixmap = QPixmap(bounds.size());
|
||||
m_lens_pixmap.fill(Qt::transparent);
|
||||
painter.begin(&m_lens_pixmap);
|
||||
}
|
||||
|
||||
QRadialGradient gr(rad, rad, rad, 3 * rad / 5, 3 * rad / 5);
|
||||
gr.setColorAt(0.0, QColor(255, 255, 255, 191));
|
||||
gr.setColorAt(0.2, QColor(255, 255, 127, 191));
|
||||
gr.setColorAt(0.9, QColor(150, 150, 200, 63));
|
||||
gr.setColorAt(0.95, QColor(0, 0, 0, 127));
|
||||
gr.setColorAt(1, QColor(0, 0, 0, 0));
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(gr);
|
||||
painter.setPen(Qt::NoPen);
|
||||
painter.drawEllipse(0, 0, bounds.width(), bounds.height());
|
||||
}
|
||||
|
||||
|
||||
void PathDeformRenderer::setAnimated(bool animated)
|
||||
{
|
||||
m_animated = animated;
|
||||
|
||||
if (m_animated) {
|
||||
// m_fpsTimer.start(1000, this);
|
||||
// m_fpsCounter = 0;
|
||||
m_repaintTimer.start(25, this);
|
||||
m_repaintTracker.start();
|
||||
} else {
|
||||
// m_fpsTimer.stop();
|
||||
m_repaintTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void PathDeformRenderer::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
|
||||
if (e->timerId() == m_repaintTimer.timerId()) {
|
||||
|
||||
if (QLineF(QPointF(0,0), m_direction).length() > 1)
|
||||
m_direction *= 0.995;
|
||||
qreal time = m_repaintTracker.restart();
|
||||
|
||||
QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
|
||||
|
||||
qreal dx = m_direction.x();
|
||||
qreal dy = m_direction.y();
|
||||
if (time > 0) {
|
||||
dx = dx * time * .1;
|
||||
dy = dy * time * .1;
|
||||
}
|
||||
|
||||
m_pos += QPointF(dx, dy);
|
||||
|
||||
if (m_pos.x() - m_radius < 0) {
|
||||
m_direction.setX(-m_direction.x());
|
||||
m_pos.setX(m_radius);
|
||||
} else if (m_pos.x() + m_radius > width()) {
|
||||
m_direction.setX(-m_direction.x());
|
||||
m_pos.setX(width() - m_radius);
|
||||
}
|
||||
|
||||
if (m_pos.y() - m_radius < 0) {
|
||||
m_direction.setY(-m_direction.y());
|
||||
m_pos.setY(m_radius);
|
||||
} else if (m_pos.y() + m_radius > height()) {
|
||||
m_direction.setY(-m_direction.y());
|
||||
m_pos.setY(height() - m_radius);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL()) {
|
||||
update();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
|
||||
update(rectAfter | rectBefore);
|
||||
}
|
||||
}
|
||||
// else if (e->timerId() == m_fpsTimer.timerId()) {
|
||||
// printf("fps: %d\n", m_fpsCounter);
|
||||
// emit frameRate(m_fpsCounter);
|
||||
// m_fpsCounter = 0;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
void PathDeformRenderer::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
if (m_showDoc) {
|
||||
setDescriptionEnabled(false);
|
||||
return;
|
||||
}
|
||||
setDescriptionEnabled(false);
|
||||
|
||||
m_repaintTimer.stop();
|
||||
m_offset = QPointF();
|
||||
if (QLineF(m_pos, e->position().toPoint()).length() <= m_radius)
|
||||
m_offset = m_pos - e->position().toPoint();
|
||||
|
||||
m_mousePress = e->position().toPoint();
|
||||
|
||||
// If we're not running in small screen mode, always assume we're dragging
|
||||
m_mouseDrag = !m_smallScreen;
|
||||
|
||||
mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
void PathDeformRenderer::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
if (e->buttons() == Qt::NoButton && m_animated) {
|
||||
m_repaintTimer.start(10, this);
|
||||
m_repaintTracker.start();
|
||||
}
|
||||
|
||||
if (!m_mouseDrag && m_smallScreen)
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
void PathDeformRenderer::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_mouseDrag && (QLineF(m_mousePress, e->position().toPoint()).length() > 25.0) )
|
||||
m_mouseDrag = true;
|
||||
|
||||
if (m_mouseDrag) {
|
||||
QRect rectBefore = circle_bounds(m_pos, m_radius, m_fontSize);
|
||||
if (e->type() == QEvent::MouseMove) {
|
||||
QLineF line(m_pos, e->position().toPoint() + m_offset);
|
||||
line.setLength(line.length() * .1);
|
||||
QPointF dir(line.dx(), line.dy());
|
||||
m_direction = (m_direction + dir) / 2;
|
||||
}
|
||||
m_pos = e->position().toPoint() + m_offset;
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL()) {
|
||||
update();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
QRect rectAfter = circle_bounds(m_pos, m_radius, m_fontSize);
|
||||
update(rectBefore | rectAfter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QPainterPath PathDeformRenderer::lensDeform(const QPainterPath &source, const QPointF &offset)
|
||||
{
|
||||
QPainterPath path;
|
||||
path.addPath(source);
|
||||
|
||||
qreal flip = m_intensity / qreal(100);
|
||||
|
||||
for (int i=0; i<path.elementCount(); ++i) {
|
||||
const QPainterPath::Element &e = path.elementAt(i);
|
||||
|
||||
qreal x = e.x + offset.x();
|
||||
qreal y = e.y + offset.y();
|
||||
|
||||
qreal dx = x - m_pos.x();
|
||||
qreal dy = y - m_pos.y();
|
||||
qreal len = m_radius - qSqrt(dx * dx + dy * dy);
|
||||
|
||||
if (len > 0) {
|
||||
path.setElementPositionAt(i,
|
||||
x + flip * dx * len / m_radius,
|
||||
y + flip * dy * len / m_radius);
|
||||
} else {
|
||||
path.setElementPositionAt(i, x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void PathDeformRenderer::paint(QPainter *painter)
|
||||
{
|
||||
int pad_x = 5;
|
||||
int pad_y = 5;
|
||||
|
||||
int skip_x = qRound(m_pathBounds.width() + pad_x + m_fontSize/2);
|
||||
int skip_y = qRound(m_pathBounds.height() + pad_y);
|
||||
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(Qt::black);
|
||||
|
||||
QRectF clip(painter->clipPath().boundingRect());
|
||||
|
||||
int overlap = pad_x / 2;
|
||||
|
||||
for (int start_y=0; start_y < height(); start_y += skip_y) {
|
||||
|
||||
if (start_y > clip.bottom())
|
||||
break;
|
||||
|
||||
int start_x = -overlap;
|
||||
for (; start_x < width(); start_x += skip_x) {
|
||||
|
||||
if (start_y + skip_y >= clip.top() &&
|
||||
start_x + skip_x >= clip.left() &&
|
||||
start_x <= clip.right()) {
|
||||
for (int i=0; i<m_paths.size(); ++i) {
|
||||
QPainterPath path = lensDeform(m_paths[i], QPointF(start_x, start_y));
|
||||
painter->drawPath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
overlap = skip_x - (start_x - width());
|
||||
|
||||
}
|
||||
|
||||
if (preferImage()) {
|
||||
painter->drawImage(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
|
||||
m_lens_image);
|
||||
} else {
|
||||
painter->drawPixmap(m_pos - QPointF(m_radius + LENS_EXTENT, m_radius + LENS_EXTENT),
|
||||
m_lens_pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
void PathDeformRenderer::setRadius(int radius)
|
||||
{
|
||||
qreal max = qMax(m_radius, (qreal)radius);
|
||||
m_radius = radius;
|
||||
generateLensPixmap();
|
||||
if (!m_animated || m_radius < max) {
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL()){
|
||||
update();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
update(circle_bounds(m_pos, max, m_fontSize));
|
||||
}
|
||||
}
|
||||
|
||||
void PathDeformRenderer::setIntensity(int intensity)
|
||||
{
|
||||
m_intensity = intensity;
|
||||
if (!m_animated) {
|
||||
#if QT_CONFIG(opengl)
|
||||
if (usesOpenGL()) {
|
||||
update();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
update(circle_bounds(m_pos, m_radius, m_fontSize));
|
||||
}
|
||||
}
|
112
examples/widgets/painting/deform/pathdeform.h
Normal file
@ -0,0 +1,112 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PATHDEFORM_H
|
||||
#define PATHDEFORM_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QPainterPath>
|
||||
|
||||
class PathDeformRenderer : public ArthurFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool animated READ animated WRITE setAnimated)
|
||||
Q_PROPERTY(int radius READ radius WRITE setRadius)
|
||||
Q_PROPERTY(int fontSize READ fontSize WRITE setFontSize)
|
||||
Q_PROPERTY(int intensity READ intensity WRITE setIntensity)
|
||||
Q_PROPERTY(QString text READ text WRITE setText)
|
||||
|
||||
public:
|
||||
explicit PathDeformRenderer(QWidget *widget, bool smallScreen = false);
|
||||
|
||||
void paint(QPainter *painter) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void timerEvent(QTimerEvent *e) override;
|
||||
|
||||
QSize sizeHint() const override { return QSize(600, 500); }
|
||||
|
||||
bool animated() const { return m_animated; }
|
||||
int radius() const { return int(m_radius); }
|
||||
int fontSize() const { return m_fontSize; }
|
||||
int intensity() const { return int(m_intensity); }
|
||||
QString text() const { return m_text; }
|
||||
|
||||
public slots:
|
||||
void setRadius(int radius);
|
||||
void setFontSize(int fontSize) { m_fontSize = fontSize; setText(m_text); }
|
||||
void setText(const QString &text);
|
||||
void setIntensity(int intensity);
|
||||
|
||||
void setAnimated(bool animated);
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
// void frameRate(double fps);
|
||||
|
||||
private:
|
||||
void generateLensPixmap();
|
||||
QPainterPath lensDeform(const QPainterPath &source, const QPointF &offset);
|
||||
|
||||
QBasicTimer m_repaintTimer;
|
||||
// QBasicTimer m_fpsTimer;
|
||||
// int m_fpsCounter;
|
||||
QElapsedTimer m_repaintTracker;
|
||||
|
||||
QList<QPainterPath> m_paths;
|
||||
QList<QPointF> m_advances;
|
||||
QRectF m_pathBounds;
|
||||
QString m_text;
|
||||
|
||||
QPixmap m_lens_pixmap;
|
||||
QImage m_lens_image;
|
||||
|
||||
int m_fontSize;
|
||||
bool m_animated;
|
||||
|
||||
qreal m_intensity;
|
||||
qreal m_radius;
|
||||
QPointF m_pos;
|
||||
QPointF m_offset;
|
||||
QPointF m_direction;
|
||||
QPointF m_mousePress;
|
||||
bool m_mouseDrag;
|
||||
bool m_smallScreen;
|
||||
};
|
||||
|
||||
class PathDeformControls : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PathDeformControls(QWidget *parent, PathDeformRenderer* renderer, bool smallScreen);
|
||||
signals:
|
||||
void okPressed();
|
||||
void quitPressed();
|
||||
private:
|
||||
PathDeformRenderer *m_renderer;
|
||||
void layoutForDesktop();
|
||||
void layoutForSmallScreen();
|
||||
};
|
||||
|
||||
class PathDeformWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PathDeformWidget(QWidget *parent, bool smallScreen);
|
||||
void setStyle(QStyle *style);
|
||||
|
||||
private:
|
||||
PathDeformRenderer *m_renderer;
|
||||
PathDeformControls *m_controls;
|
||||
|
||||
private slots:
|
||||
void showControls();
|
||||
void hideControls();
|
||||
};
|
||||
|
||||
#endif // PATHDEFORM_H
|
24
examples/widgets/painting/deform/pathdeform.html
Normal file
@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<center>
|
||||
<h2>Vector deformation</h2>
|
||||
</center>
|
||||
|
||||
<p>This demo shows how to use advanced vector techniques to draw text
|
||||
using a <code>QPainterPath</code>.</p>
|
||||
|
||||
<p>We define a vector deformation field in the shape of a lens and apply
|
||||
this to all points in a path. This means that what is rendered on
|
||||
screen is not pixel manipulation, but modified vector representations of
|
||||
the glyphs themselves. This is visible from the high quality of the
|
||||
antialiased edges for the deformed glyphs.</p>
|
||||
|
||||
<p>To get a fairly complex path we allow the user to type in text and
|
||||
convert the text to paths. This is done using the
|
||||
<code>QPainterPath::addText()</code> function.</p>
|
||||
|
||||
<p>The lens is drawn using a single call to <code>drawEllipse()</code>, using
|
||||
a <code>QRadialGradient</code> to fill it with a specialized color table,
|
||||
giving the effect of the Sun's reflection and a drop shadow. The lens
|
||||
is cached as a pixmap for better performance.</p>
|
||||
|
||||
</html>
|
45
examples/widgets/painting/fontsampler/CMakeLists.txt
Normal file
@ -0,0 +1,45 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(fontsampler LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/fontsampler")
|
||||
|
||||
find_package(Qt6
|
||||
REQUIRED COMPONENTS Core Gui Widgets
|
||||
OPTIONAL_COMPONENTS PrintSupport
|
||||
)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(fontsampler
|
||||
main.cpp
|
||||
mainwindow.cpp mainwindow.h
|
||||
mainwindowbase.ui
|
||||
)
|
||||
|
||||
set_target_properties(fontsampler PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(fontsampler PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
if(TARGET Qt6::PrintSupport)
|
||||
target_link_libraries(fontsampler PRIVATE Qt6::PrintSupport)
|
||||
endif()
|
||||
|
||||
install(TARGETS fontsampler
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
12
examples/widgets/painting/fontsampler/fontsampler.pro
Normal file
@ -0,0 +1,12 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(combobox))
|
||||
qtHaveModule(printsupport): QT += printsupport
|
||||
|
||||
FORMS = mainwindowbase.ui
|
||||
HEADERS = mainwindow.h
|
||||
SOURCES = main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/fontsampler
|
||||
INSTALLS += target
|
14
examples/widgets/painting/fontsampler/main.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
MainWindow window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
314
examples/widgets/painting/fontsampler/mainwindow.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include <QtWidgets>
|
||||
#if defined(QT_PRINTSUPPORT_LIB)
|
||||
#include <QtPrintSupport/qtprintsupportglobal.h>
|
||||
#if QT_CONFIG(printdialog)
|
||||
#include <QPrinter>
|
||||
#include <QPrintDialog>
|
||||
#if QT_CONFIG(printpreviewdialog)
|
||||
#include <QPrintPreviewDialog>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
sampleSizes << 32 << 24 << 16 << 14 << 12 << 8 << 4 << 2 << 1;
|
||||
markedCount = 0;
|
||||
setupFontTree();
|
||||
|
||||
connect(quitAction, &QAction::triggered,
|
||||
qApp, &QApplication::quit);
|
||||
connect(fontTree, &QTreeWidget::currentItemChanged,
|
||||
this, &MainWindow::showFont);
|
||||
connect(fontTree, &QTreeWidget::itemChanged,
|
||||
this, &MainWindow::updateStyles);
|
||||
|
||||
fontTree->topLevelItem(0)->setSelected(true);
|
||||
showFont(fontTree->topLevelItem(0));
|
||||
}
|
||||
|
||||
void MainWindow::setupFontTree()
|
||||
{
|
||||
fontTree->setColumnCount(1);
|
||||
fontTree->setHeaderLabels({ tr("Font") });
|
||||
|
||||
const QStringList fontFamilies = QFontDatabase::families();
|
||||
for (const QString &family : fontFamilies) {
|
||||
const QStringList styles = QFontDatabase::styles(family);
|
||||
if (styles.isEmpty())
|
||||
continue;
|
||||
|
||||
QTreeWidgetItem *familyItem = new QTreeWidgetItem(fontTree);
|
||||
familyItem->setText(0, family);
|
||||
familyItem->setCheckState(0, Qt::Unchecked);
|
||||
familyItem->setFlags(familyItem->flags() | Qt::ItemIsAutoTristate);
|
||||
|
||||
for (const QString &style : styles) {
|
||||
QTreeWidgetItem *styleItem = new QTreeWidgetItem(familyItem);
|
||||
styleItem->setText(0, style);
|
||||
styleItem->setCheckState(0, Qt::Unchecked);
|
||||
styleItem->setData(0, Qt::UserRole, QVariant(QFontDatabase::weight(family, style)));
|
||||
styleItem->setData(0, Qt::UserRole + 1, QVariant(QFontDatabase::italic(family, style)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_clearAction_triggered()
|
||||
{
|
||||
const QList<QTreeWidgetItem *> items = fontTree->selectedItems();
|
||||
for (QTreeWidgetItem *item : items)
|
||||
item->setSelected(false);
|
||||
fontTree->currentItem()->setSelected(true);
|
||||
}
|
||||
|
||||
void MainWindow::on_markAction_triggered()
|
||||
{
|
||||
markUnmarkFonts(Qt::Checked);
|
||||
}
|
||||
|
||||
void MainWindow::on_unmarkAction_triggered()
|
||||
{
|
||||
markUnmarkFonts(Qt::Unchecked);
|
||||
}
|
||||
|
||||
void MainWindow::markUnmarkFonts(Qt::CheckState state)
|
||||
{
|
||||
const QList<QTreeWidgetItem *> items = fontTree->selectedItems();
|
||||
for (QTreeWidgetItem *item : items) {
|
||||
if (item->checkState(0) != state)
|
||||
item->setCheckState(0, state);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showFont(QTreeWidgetItem *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
QString family;
|
||||
QString style;
|
||||
int weight;
|
||||
bool italic;
|
||||
|
||||
if (item->parent()) {
|
||||
family = item->parent()->text(0);
|
||||
style = item->text(0);
|
||||
weight = item->data(0, Qt::UserRole).toInt();
|
||||
italic = item->data(0, Qt::UserRole + 1).toBool();
|
||||
} else {
|
||||
family = item->text(0);
|
||||
style = item->child(0)->text(0);
|
||||
weight = item->child(0)->data(0, Qt::UserRole).toInt();
|
||||
italic = item->child(0)->data(0, Qt::UserRole + 1).toBool();
|
||||
}
|
||||
|
||||
QString oldText = textEdit->toPlainText().trimmed();
|
||||
bool modified = textEdit->document()->isModified();
|
||||
textEdit->clear();
|
||||
QFont font(family, 32, weight, italic);
|
||||
font.setStyleName(style);
|
||||
textEdit->document()->setDefaultFont(font);
|
||||
|
||||
QTextCursor cursor = textEdit->textCursor();
|
||||
QTextBlockFormat blockFormat;
|
||||
blockFormat.setAlignment(Qt::AlignCenter);
|
||||
cursor.insertBlock(blockFormat);
|
||||
|
||||
if (modified)
|
||||
cursor.insertText(QString(oldText));
|
||||
else
|
||||
cursor.insertText(QString("%1 %2").arg(family).arg(style));
|
||||
|
||||
textEdit->document()->setModified(modified);
|
||||
}
|
||||
|
||||
void MainWindow::updateStyles(QTreeWidgetItem *item, int column)
|
||||
{
|
||||
if (!item || column != 0)
|
||||
return;
|
||||
|
||||
Qt::CheckState state = item->checkState(0);
|
||||
QTreeWidgetItem *parent = item->parent();
|
||||
|
||||
if (parent) {
|
||||
// Only count style items.
|
||||
if (state == Qt::Checked)
|
||||
++markedCount;
|
||||
else
|
||||
--markedCount;
|
||||
}
|
||||
|
||||
printAction->setEnabled(markedCount > 0);
|
||||
printPreviewAction->setEnabled(markedCount > 0);
|
||||
}
|
||||
|
||||
QMap<QString, StyleItems> MainWindow::currentPageMap()
|
||||
{
|
||||
QMap<QString, StyleItems> pageMap;
|
||||
|
||||
for (int row = 0; row < fontTree->topLevelItemCount(); ++row) {
|
||||
QTreeWidgetItem *familyItem = fontTree->topLevelItem(row);
|
||||
QString family;
|
||||
|
||||
if (familyItem->checkState(0) == Qt::Checked) {
|
||||
family = familyItem->text(0);
|
||||
pageMap[family] = StyleItems();
|
||||
}
|
||||
|
||||
for (int childRow = 0; childRow < familyItem->childCount(); ++childRow) {
|
||||
QTreeWidgetItem *styleItem = familyItem->child(childRow);
|
||||
if (styleItem->checkState(0) == Qt::Checked)
|
||||
pageMap[family].append(styleItem);
|
||||
}
|
||||
}
|
||||
|
||||
return pageMap;
|
||||
}
|
||||
|
||||
void MainWindow::on_printAction_triggered()
|
||||
{
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||
pageMap = currentPageMap();
|
||||
|
||||
if (pageMap.count() == 0)
|
||||
return;
|
||||
|
||||
QPrinter printer(QPrinter::HighResolution);
|
||||
QPrintDialog dialog(&printer, this);
|
||||
if (dialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
|
||||
int from = printer.fromPage();
|
||||
int to = printer.toPage();
|
||||
if (from <= 0 && to <= 0)
|
||||
printer.setFromTo(1, pageMap.keys().count());
|
||||
|
||||
printDocument(&printer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::printDocument(QPrinter *printer)
|
||||
{
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||
printer->setFromTo(1, pageMap.count());
|
||||
|
||||
QProgressDialog progress(tr("Preparing font samples..."), tr("&Cancel"),
|
||||
0, pageMap.count(), this);
|
||||
progress.setWindowModality(Qt::ApplicationModal);
|
||||
progress.setWindowTitle(tr("Font Sampler"));
|
||||
progress.setMinimum(printer->fromPage() - 1);
|
||||
progress.setMaximum(printer->toPage());
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(printer);
|
||||
bool firstPage = true;
|
||||
|
||||
for (int page = printer->fromPage(); page <= printer->toPage(); ++page) {
|
||||
|
||||
if (!firstPage)
|
||||
printer->newPage();
|
||||
|
||||
qApp->processEvents();
|
||||
if (progress.wasCanceled())
|
||||
break;
|
||||
|
||||
printPage(page - 1, &painter, printer);
|
||||
progress.setValue(page);
|
||||
firstPage = false;
|
||||
}
|
||||
|
||||
painter.end();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::on_printPreviewAction_triggered()
|
||||
{
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog)
|
||||
pageMap = currentPageMap();
|
||||
|
||||
if (pageMap.count() == 0)
|
||||
return;
|
||||
|
||||
QPrinter printer(QPrinter::HighResolution);
|
||||
QPrintPreviewDialog preview(&printer, this);
|
||||
connect(&preview, &QPrintPreviewDialog::paintRequested,
|
||||
this, &MainWindow::printDocument);
|
||||
preview.exec();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::printPage(int index, QPainter *painter, QPrinter *printer)
|
||||
{
|
||||
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
|
||||
const QString family = std::next(pageMap.begin(), index).key();
|
||||
const StyleItems items = pageMap.value(family);
|
||||
|
||||
// Find the dimensions of the text on each page.
|
||||
qreal width = 0.0;
|
||||
qreal height = 0.0;
|
||||
for (const QTreeWidgetItem *item : items) {
|
||||
QString style = item->text(0);
|
||||
int weight = item->data(0, Qt::UserRole).toInt();
|
||||
bool italic = item->data(0, Qt::UserRole + 1).toBool();
|
||||
|
||||
// Calculate the maximum width and total height of the text.
|
||||
for (int size : std::as_const(sampleSizes)) {
|
||||
QFont font(family, size, weight, italic);
|
||||
font.setStyleName(style);
|
||||
font = QFont(font, painter->device());
|
||||
QFontMetricsF fontMetrics(font);
|
||||
QRectF rect = fontMetrics.boundingRect(
|
||||
QString("%1 %2").arg(family).arg(style));
|
||||
width = qMax(rect.width(), width);
|
||||
height += rect.height();
|
||||
}
|
||||
}
|
||||
|
||||
qreal xScale = printer->pageRect(QPrinter::DevicePixel).width() / width;
|
||||
qreal yScale = printer->pageRect(QPrinter::DevicePixel).height() / height;
|
||||
qreal scale = qMin(xScale, yScale);
|
||||
|
||||
qreal remainingHeight = printer->pageRect(QPrinter::DevicePixel).height()/scale - height;
|
||||
qreal spaceHeight = (remainingHeight / 4.0) / (items.count() + 1);
|
||||
qreal interLineHeight = (remainingHeight / 4.0) / (sampleSizes.count() * items.count());
|
||||
|
||||
painter->save();
|
||||
painter->translate(printer->pageRect(QPrinter::DevicePixel).width() / 2.0, printer->pageRect(QPrinter::DevicePixel).height() / 2.0);
|
||||
painter->scale(scale, scale);
|
||||
painter->setBrush(QBrush(Qt::black));
|
||||
|
||||
qreal x = -width / 2.0;
|
||||
qreal y = -height / 2.0 - remainingHeight / 4.0 + spaceHeight;
|
||||
|
||||
for (const QTreeWidgetItem *item : items) {
|
||||
QString style = item->text(0);
|
||||
int weight = item->data(0, Qt::UserRole).toInt();
|
||||
bool italic = item->data(0, Qt::UserRole + 1).toBool();
|
||||
|
||||
// Draw each line of text.
|
||||
for (int size : std::as_const(sampleSizes)) {
|
||||
QFont font(family, size, weight, italic);
|
||||
font.setStyleName(style);
|
||||
font = QFont(font, painter->device());
|
||||
QFontMetricsF fontMetrics(font);
|
||||
QRectF rect = fontMetrics.boundingRect(QString("%1 %2").arg(
|
||||
font.family()).arg(style));
|
||||
y += rect.height();
|
||||
painter->setFont(font);
|
||||
painter->drawText(QPointF(x, y), QString("%1 %2").arg(family).arg(style));
|
||||
y += interLineHeight;
|
||||
}
|
||||
y += spaceHeight;
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
#endif
|
||||
}
|
54
examples/widgets/painting/fontsampler/mainwindow.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "ui_mainwindowbase.h"
|
||||
|
||||
#if defined(QT_PRINTSUPPORT_LIB)
|
||||
#include <QtPrintSupport/qtprintsupportglobal.h>
|
||||
#endif
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPrinter;
|
||||
class QTextEdit;
|
||||
class QTreeWidget;
|
||||
class QTreeWidgetItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
typedef QList<QTreeWidgetItem *> StyleItems;
|
||||
|
||||
class MainWindow : public QMainWindow, private Ui::MainWindowBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void on_clearAction_triggered();
|
||||
void on_markAction_triggered();
|
||||
void on_unmarkAction_triggered();
|
||||
void on_printAction_triggered();
|
||||
void on_printPreviewAction_triggered();
|
||||
void printDocument(QPrinter *printer);
|
||||
void printPage(int index, QPainter *painter, QPrinter *printer);
|
||||
void showFont(QTreeWidgetItem *item);
|
||||
void updateStyles(QTreeWidgetItem *item, int column);
|
||||
|
||||
private:
|
||||
QMap<QString, StyleItems> currentPageMap();
|
||||
void markUnmarkFonts(Qt::CheckState state);
|
||||
void setupFontTree();
|
||||
|
||||
QList<int> sampleSizes;
|
||||
QMap<QString, StyleItems> pageMap;
|
||||
int markedCount;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
142
examples/widgets/painting/fontsampler/mainwindowbase.ui
Normal file
@ -0,0 +1,142 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindowBase</class>
|
||||
<widget class="QMainWindow" name="MainWindowBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>345</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Font Sampler</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>18</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_Selection">
|
||||
<property name="title">
|
||||
<string>&Selection</string>
|
||||
</property>
|
||||
<addaction name="markAction"/>
|
||||
<addaction name="unmarkAction"/>
|
||||
<addaction name="clearAction"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="printPreviewAction"/>
|
||||
<addaction name="printAction"/>
|
||||
<addaction name="quitAction"/>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
<addaction name="menu_Selection"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QDockWidget" name="dockWidget">
|
||||
<property name="features">
|
||||
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Available Fonts</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>1</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="fontTree">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<action name="printAction">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Print...</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="quitAction">
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="markAction">
|
||||
<property name="text">
|
||||
<string>&Mark</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+M</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="unmarkAction">
|
||||
<property name="text">
|
||||
<string>&Unmark</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+U</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="clearAction">
|
||||
<property name="text">
|
||||
<string>&Clear</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="printPreviewAction">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Print Preview...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
102
examples/widgets/painting/gradients/CMakeLists.txt
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(gradients LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/gradients")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(gradients
|
||||
gradients.cpp gradients.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(gradients PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(gradients PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(gradients "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(gradients_resource_files
|
||||
"gradients.cpp"
|
||||
"gradients.html"
|
||||
)
|
||||
|
||||
qt_add_resources(gradients "gradients"
|
||||
PREFIX
|
||||
"/res/gradients"
|
||||
FILES
|
||||
${gradients_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS gradients
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
547
examples/widgets/painting/gradients/gradients.cpp
Normal file
@ -0,0 +1,547 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "gradients.h"
|
||||
#include "hoverpoints.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
ShadeWidget::ShadeWidget(ShadeType type, QWidget *parent)
|
||||
: QWidget(parent), m_shade_type(type), m_alpha_gradient(QLinearGradient(0, 0, 0, 0))
|
||||
{
|
||||
|
||||
// Checkers background
|
||||
if (m_shade_type == ARGBShade) {
|
||||
QPixmap pm(20, 20);
|
||||
QPainter pmp(&pm);
|
||||
pmp.fillRect(0, 0, 10, 10, Qt::lightGray);
|
||||
pmp.fillRect(10, 10, 10, 10, Qt::lightGray);
|
||||
pmp.fillRect(0, 10, 10, 10, Qt::darkGray);
|
||||
pmp.fillRect(10, 0, 10, 10, Qt::darkGray);
|
||||
pmp.end();
|
||||
QPalette pal = palette();
|
||||
pal.setBrush(backgroundRole(), QBrush(pm));
|
||||
setAutoFillBackground(true);
|
||||
setPalette(pal);
|
||||
|
||||
} else {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
}
|
||||
|
||||
QPolygonF points;
|
||||
points << QPointF(0, sizeHint().height())
|
||||
<< QPointF(sizeHint().width(), 0);
|
||||
|
||||
m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape);
|
||||
// m_hoverPoints->setConnectionType(HoverPoints::LineConnection);
|
||||
m_hoverPoints->setPoints(points);
|
||||
m_hoverPoints->setPointLock(0, HoverPoints::LockToLeft);
|
||||
m_hoverPoints->setPointLock(1, HoverPoints::LockToRight);
|
||||
m_hoverPoints->setSortType(HoverPoints::XSort);
|
||||
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
connect(m_hoverPoints, &HoverPoints::pointsChanged,
|
||||
this, &ShadeWidget::colorsChanged);
|
||||
}
|
||||
|
||||
QPolygonF ShadeWidget::points() const
|
||||
{
|
||||
return m_hoverPoints->points();
|
||||
}
|
||||
|
||||
uint ShadeWidget::colorAt(int x)
|
||||
{
|
||||
generateShade();
|
||||
|
||||
QPolygonF pts = m_hoverPoints->points();
|
||||
for (int i = 1; i < pts.size(); ++i) {
|
||||
if (pts.at(i - 1).x() <= x && pts.at(i).x() >= x) {
|
||||
QLineF l(pts.at(i - 1), pts.at(i));
|
||||
if (qIsNull(l.dx()))
|
||||
continue;
|
||||
l.setLength(l.length() * ((x - l.x1()) / l.dx()));
|
||||
return m_shade.pixel(qRound(qMin(l.x2(), (qreal(m_shade.width() - 1)))),
|
||||
qRound(qMin(l.y2(), qreal(m_shade.height() - 1))));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ShadeWidget::setGradientStops(const QGradientStops &stops)
|
||||
{
|
||||
if (m_shade_type == ARGBShade) {
|
||||
m_alpha_gradient = QLinearGradient(0, 0, width(), 0);
|
||||
|
||||
for (const auto &stop : stops) {
|
||||
QColor c = stop.second;
|
||||
m_alpha_gradient.setColorAt(stop.first, QColor(c.red(), c.green(), c.blue()));
|
||||
}
|
||||
|
||||
m_shade = QImage();
|
||||
generateShade();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void ShadeWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
generateShade();
|
||||
|
||||
QPainter p(this);
|
||||
p.drawImage(0, 0, m_shade);
|
||||
|
||||
p.setPen(QColor(146, 146, 146));
|
||||
p.drawRect(0, 0, width() - 1, height() - 1);
|
||||
}
|
||||
|
||||
void ShadeWidget::generateShade()
|
||||
{
|
||||
if (m_shade.isNull() || m_shade.size() != size()) {
|
||||
|
||||
if (m_shade_type == ARGBShade) {
|
||||
m_shade = QImage(size(), QImage::Format_ARGB32_Premultiplied);
|
||||
m_shade.fill(0);
|
||||
|
||||
QPainter p(&m_shade);
|
||||
p.fillRect(rect(), m_alpha_gradient);
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
QLinearGradient fade(0, 0, 0, height());
|
||||
fade.setColorAt(0, QColor(0, 0, 0, 255));
|
||||
fade.setColorAt(1, QColor(0, 0, 0, 0));
|
||||
p.fillRect(rect(), fade);
|
||||
|
||||
} else {
|
||||
m_shade = QImage(size(), QImage::Format_RGB32);
|
||||
QLinearGradient shade(0, 0, 0, height());
|
||||
shade.setColorAt(1, Qt::black);
|
||||
|
||||
if (m_shade_type == RedShade)
|
||||
shade.setColorAt(0, Qt::red);
|
||||
else if (m_shade_type == GreenShade)
|
||||
shade.setColorAt(0, Qt::green);
|
||||
else
|
||||
shade.setColorAt(0, Qt::blue);
|
||||
|
||||
QPainter p(&m_shade);
|
||||
p.fillRect(rect(), shade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GradientEditor::GradientEditor(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *vbox = new QVBoxLayout(this);
|
||||
vbox->setSpacing(1);
|
||||
vbox->setContentsMargins(1, 1, 1, 1);
|
||||
|
||||
m_red_shade = new ShadeWidget(ShadeWidget::RedShade, this);
|
||||
m_green_shade = new ShadeWidget(ShadeWidget::GreenShade, this);
|
||||
m_blue_shade = new ShadeWidget(ShadeWidget::BlueShade, this);
|
||||
m_alpha_shade = new ShadeWidget(ShadeWidget::ARGBShade, this);
|
||||
|
||||
vbox->addWidget(m_red_shade);
|
||||
vbox->addWidget(m_green_shade);
|
||||
vbox->addWidget(m_blue_shade);
|
||||
vbox->addWidget(m_alpha_shade);
|
||||
|
||||
connect(m_red_shade, &ShadeWidget::colorsChanged,
|
||||
this, &GradientEditor::pointsUpdated);
|
||||
connect(m_green_shade, &ShadeWidget::colorsChanged,
|
||||
this, &GradientEditor::pointsUpdated);
|
||||
connect(m_blue_shade, &ShadeWidget::colorsChanged,
|
||||
this, &GradientEditor::pointsUpdated);
|
||||
connect(m_alpha_shade, &ShadeWidget::colorsChanged,
|
||||
this, &GradientEditor::pointsUpdated);
|
||||
}
|
||||
|
||||
inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
|
||||
{
|
||||
return p1.x() < p2.x();
|
||||
}
|
||||
|
||||
void GradientEditor::pointsUpdated()
|
||||
{
|
||||
qreal w = m_alpha_shade->width();
|
||||
|
||||
QGradientStops stops;
|
||||
|
||||
QPolygonF points;
|
||||
|
||||
points += m_red_shade->points();
|
||||
points += m_green_shade->points();
|
||||
points += m_blue_shade->points();
|
||||
points += m_alpha_shade->points();
|
||||
|
||||
std::sort(points.begin(), points.end(), x_less_than);
|
||||
|
||||
for (int i = 0; i < points.size(); ++i) {
|
||||
const int x = int(points.at(i).x());
|
||||
if (i + 1 < points.size() && x == int(points.at(i + 1).x()))
|
||||
continue;
|
||||
QColor color((0x00ff0000 & m_red_shade->colorAt(x)) >> 16,
|
||||
(0x0000ff00 & m_green_shade->colorAt(x)) >> 8,
|
||||
(0x000000ff & m_blue_shade->colorAt(x)),
|
||||
(0xff000000 & m_alpha_shade->colorAt(x)) >> 24);
|
||||
|
||||
if (x / w > 1)
|
||||
return;
|
||||
|
||||
stops << QGradientStop(x / w, color);
|
||||
}
|
||||
|
||||
m_alpha_shade->setGradientStops(stops);
|
||||
|
||||
emit gradientStopsChanged(stops);
|
||||
}
|
||||
|
||||
static void set_shade_points(const QPolygonF &points, ShadeWidget *shade)
|
||||
{
|
||||
shade->hoverPoints()->setPoints(points);
|
||||
shade->hoverPoints()->setPointLock(0, HoverPoints::LockToLeft);
|
||||
shade->hoverPoints()->setPointLock(points.size() - 1, HoverPoints::LockToRight);
|
||||
shade->update();
|
||||
}
|
||||
|
||||
void GradientEditor::setGradientStops(const QGradientStops &stops)
|
||||
{
|
||||
QPolygonF pts_red, pts_green, pts_blue, pts_alpha;
|
||||
|
||||
qreal h_red = m_red_shade->height();
|
||||
qreal h_green = m_green_shade->height();
|
||||
qreal h_blue = m_blue_shade->height();
|
||||
qreal h_alpha = m_alpha_shade->height();
|
||||
|
||||
for (int i = 0; i < stops.size(); ++i) {
|
||||
qreal pos = stops.at(i).first;
|
||||
QRgb color = stops.at(i).second.rgba();
|
||||
pts_red << QPointF(pos * m_red_shade->width(), h_red - qRed(color) * h_red / 255);
|
||||
pts_green << QPointF(pos * m_green_shade->width(), h_green - qGreen(color) * h_green / 255);
|
||||
pts_blue << QPointF(pos * m_blue_shade->width(), h_blue - qBlue(color) * h_blue / 255);
|
||||
pts_alpha << QPointF(pos * m_alpha_shade->width(), h_alpha - qAlpha(color) * h_alpha / 255);
|
||||
}
|
||||
|
||||
set_shade_points(pts_red, m_red_shade);
|
||||
set_shade_points(pts_green, m_green_shade);
|
||||
set_shade_points(pts_blue, m_blue_shade);
|
||||
set_shade_points(pts_alpha, m_alpha_shade);
|
||||
|
||||
}
|
||||
|
||||
GradientWidget::GradientWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setWindowTitle(tr("Gradients"));
|
||||
|
||||
m_renderer = new GradientRenderer(this);
|
||||
|
||||
QWidget *mainContentWidget = new QWidget();
|
||||
QGroupBox *mainGroup = new QGroupBox(mainContentWidget);
|
||||
mainGroup->setTitle(tr("Gradients"));
|
||||
|
||||
QGroupBox *editorGroup = new QGroupBox(mainGroup);
|
||||
editorGroup->setTitle(tr("Color Editor"));
|
||||
m_editor = new GradientEditor(editorGroup);
|
||||
|
||||
QGroupBox *typeGroup = new QGroupBox(mainGroup);
|
||||
typeGroup->setTitle(tr("Gradient Type"));
|
||||
m_linearButton = new QRadioButton(tr("Linear Gradient"), typeGroup);
|
||||
m_radialButton = new QRadioButton(tr("Radial Gradient"), typeGroup);
|
||||
m_conicalButton = new QRadioButton(tr("Conical Gradient"), typeGroup);
|
||||
|
||||
QGroupBox *spreadGroup = new QGroupBox(mainGroup);
|
||||
spreadGroup->setTitle(tr("Spread Method"));
|
||||
m_padSpreadButton = new QRadioButton(tr("Pad Spread"), spreadGroup);
|
||||
m_reflectSpreadButton = new QRadioButton(tr("Reflect Spread"), spreadGroup);
|
||||
m_repeatSpreadButton = new QRadioButton(tr("Repeat Spread"), spreadGroup);
|
||||
|
||||
QGroupBox *presetsGroup = new QGroupBox(mainGroup);
|
||||
presetsGroup->setTitle(tr("Presets"));
|
||||
QPushButton *prevPresetButton = new QPushButton(tr("<"), presetsGroup);
|
||||
m_presetButton = new QPushButton(tr("(unset)"), presetsGroup);
|
||||
QPushButton *nextPresetButton = new QPushButton(tr(">"), presetsGroup);
|
||||
updatePresetName();
|
||||
|
||||
QGroupBox *defaultsGroup = new QGroupBox(mainGroup);
|
||||
defaultsGroup->setTitle(tr("Examples"));
|
||||
QPushButton *default1Button = new QPushButton(tr("1"), defaultsGroup);
|
||||
QPushButton *default2Button = new QPushButton(tr("2"), defaultsGroup);
|
||||
QPushButton *default3Button = new QPushButton(tr("3"), defaultsGroup);
|
||||
QPushButton *default4Button = new QPushButton(tr("Reset"), editorGroup);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
mainGroup->setFixedWidth(200);
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->addWidget(editorGroup);
|
||||
mainGroupLayout->addWidget(typeGroup);
|
||||
mainGroupLayout->addWidget(spreadGroup);
|
||||
mainGroupLayout->addWidget(presetsGroup);
|
||||
mainGroupLayout->addWidget(defaultsGroup);
|
||||
mainGroupLayout->addStretch(1);
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
|
||||
QVBoxLayout *editorGroupLayout = new QVBoxLayout(editorGroup);
|
||||
editorGroupLayout->addWidget(m_editor);
|
||||
|
||||
QVBoxLayout *typeGroupLayout = new QVBoxLayout(typeGroup);
|
||||
typeGroupLayout->addWidget(m_linearButton);
|
||||
typeGroupLayout->addWidget(m_radialButton);
|
||||
typeGroupLayout->addWidget(m_conicalButton);
|
||||
|
||||
QVBoxLayout *spreadGroupLayout = new QVBoxLayout(spreadGroup);
|
||||
spreadGroupLayout->addWidget(m_padSpreadButton);
|
||||
spreadGroupLayout->addWidget(m_repeatSpreadButton);
|
||||
spreadGroupLayout->addWidget(m_reflectSpreadButton);
|
||||
|
||||
QHBoxLayout *presetsGroupLayout = new QHBoxLayout(presetsGroup);
|
||||
presetsGroupLayout->addWidget(prevPresetButton);
|
||||
presetsGroupLayout->addWidget(m_presetButton, 1);
|
||||
presetsGroupLayout->addWidget(nextPresetButton);
|
||||
|
||||
QHBoxLayout *defaultsGroupLayout = new QHBoxLayout(defaultsGroup);
|
||||
defaultsGroupLayout->addWidget(default1Button);
|
||||
defaultsGroupLayout->addWidget(default2Button);
|
||||
defaultsGroupLayout->addWidget(default3Button);
|
||||
editorGroupLayout->addWidget(default4Button);
|
||||
|
||||
mainGroup->setLayout(mainGroupLayout);
|
||||
|
||||
QVBoxLayout *mainContentLayout = new QVBoxLayout();
|
||||
mainContentLayout->addWidget(mainGroup);
|
||||
mainContentWidget->setLayout(mainContentLayout);
|
||||
|
||||
QScrollArea *mainScrollArea = new QScrollArea();
|
||||
mainScrollArea->setWidget(mainContentWidget);
|
||||
mainScrollArea->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
|
||||
|
||||
// Layouts
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->addWidget(m_renderer);
|
||||
mainLayout->addWidget(mainScrollArea);
|
||||
|
||||
connect(m_editor, &GradientEditor::gradientStopsChanged,
|
||||
m_renderer, &GradientRenderer::setGradientStops);
|
||||
connect(m_linearButton, &QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setLinearGradient);
|
||||
connect(m_radialButton, &QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setRadialGradient);
|
||||
connect(m_conicalButton,&QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setConicalGradient);
|
||||
|
||||
connect(m_padSpreadButton, &QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setPadSpread);
|
||||
connect(m_reflectSpreadButton, &QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setReflectSpread);
|
||||
connect(m_repeatSpreadButton, &QRadioButton::clicked,
|
||||
m_renderer, &GradientRenderer::setRepeatSpread);
|
||||
|
||||
connect(prevPresetButton, &QPushButton::clicked,
|
||||
this, &GradientWidget::setPrevPreset);
|
||||
connect(m_presetButton, &QPushButton::clicked,
|
||||
this, &GradientWidget::setPreset);
|
||||
connect(nextPresetButton, &QPushButton::clicked,
|
||||
this, &GradientWidget::setNextPreset);
|
||||
|
||||
connect(default1Button, &QPushButton::clicked,
|
||||
this, &GradientWidget::setDefault1);
|
||||
connect(default2Button, &QPushButton::clicked,
|
||||
this, &GradientWidget::setDefault2);
|
||||
connect(default3Button, &QPushButton::clicked,
|
||||
this, &GradientWidget::setDefault3);
|
||||
connect(default4Button, &QPushButton::clicked,
|
||||
this, &GradientWidget::setDefault4);
|
||||
|
||||
connect(showSourceButton, &QPushButton::clicked,
|
||||
m_renderer, &GradientRenderer::showSource);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, QOverload<bool>::of(&QPushButton::clicked),
|
||||
m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
|
||||
connect(whatsThisButton, QOverload<bool>::of(&QPushButton::clicked),
|
||||
m_renderer, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(whatsThisButton, QOverload<bool>::of(&QPushButton::clicked),
|
||||
m_renderer->hoverPoints(), &HoverPoints::setDisabled);
|
||||
connect(m_renderer, QOverload<bool>::of(&ArthurFrame::descriptionEnabledChanged),
|
||||
whatsThisButton, &QPushButton::setChecked);
|
||||
connect(m_renderer, QOverload<bool>::of(&ArthurFrame::descriptionEnabledChanged),
|
||||
m_renderer->hoverPoints(), &HoverPoints::setDisabled);
|
||||
|
||||
m_renderer->loadSourceFile(":res/gradients/gradients.cpp");
|
||||
m_renderer->loadDescription(":res/gradients/gradients.html");
|
||||
|
||||
QTimer::singleShot(50, this, &GradientWidget::setDefault1);
|
||||
}
|
||||
|
||||
void GradientWidget::setDefault(int config)
|
||||
{
|
||||
QGradientStops stops;
|
||||
QPolygonF points;
|
||||
switch (config) {
|
||||
case 1:
|
||||
stops << QGradientStop(0.00, QColor::fromRgba(0));
|
||||
stops << QGradientStop(0.04, QColor::fromRgba(0xff131360));
|
||||
stops << QGradientStop(0.08, QColor::fromRgba(0xff202ccc));
|
||||
stops << QGradientStop(0.42, QColor::fromRgba(0xff93d3f9));
|
||||
stops << QGradientStop(0.51, QColor::fromRgba(0xffb3e6ff));
|
||||
stops << QGradientStop(0.73, QColor::fromRgba(0xffffffec));
|
||||
stops << QGradientStop(0.92, QColor::fromRgba(0xff5353d9));
|
||||
stops << QGradientStop(0.96, QColor::fromRgba(0xff262666));
|
||||
stops << QGradientStop(1.00, QColor::fromRgba(0));
|
||||
m_linearButton->animateClick();
|
||||
m_repeatSpreadButton->animateClick();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
stops << QGradientStop(0.00, QColor::fromRgba(0xffffffff));
|
||||
stops << QGradientStop(0.11, QColor::fromRgba(0xfff9ffa0));
|
||||
stops << QGradientStop(0.13, QColor::fromRgba(0xfff9ff99));
|
||||
stops << QGradientStop(0.14, QColor::fromRgba(0xfff3ff86));
|
||||
stops << QGradientStop(0.49, QColor::fromRgba(0xff93b353));
|
||||
stops << QGradientStop(0.87, QColor::fromRgba(0xff264619));
|
||||
stops << QGradientStop(0.96, QColor::fromRgba(0xff0c1306));
|
||||
stops << QGradientStop(1.00, QColor::fromRgba(0));
|
||||
m_radialButton->animateClick();
|
||||
m_padSpreadButton->animateClick();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
stops << QGradientStop(0.00, QColor::fromRgba(0));
|
||||
stops << QGradientStop(0.10, QColor::fromRgba(0xffe0cc73));
|
||||
stops << QGradientStop(0.17, QColor::fromRgba(0xffc6a006));
|
||||
stops << QGradientStop(0.46, QColor::fromRgba(0xff600659));
|
||||
stops << QGradientStop(0.72, QColor::fromRgba(0xff0680ac));
|
||||
stops << QGradientStop(0.92, QColor::fromRgba(0xffb9d9e6));
|
||||
stops << QGradientStop(1.00, QColor::fromRgba(0));
|
||||
m_conicalButton->animateClick();
|
||||
m_padSpreadButton->animateClick();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
stops << QGradientStop(0.00, QColor::fromRgba(0xff000000));
|
||||
stops << QGradientStop(1.00, QColor::fromRgba(0xffffffff));
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning("bad default: %d\n", config);
|
||||
break;
|
||||
}
|
||||
|
||||
QPolygonF pts;
|
||||
int h_off = m_renderer->width() / 10;
|
||||
int v_off = m_renderer->height() / 8;
|
||||
pts << QPointF(m_renderer->width() / 2, m_renderer->height() / 2)
|
||||
<< QPointF(m_renderer->width() / 2 - h_off, m_renderer->height() / 2 - v_off);
|
||||
|
||||
m_editor->setGradientStops(stops);
|
||||
m_renderer->hoverPoints()->setPoints(pts);
|
||||
m_renderer->setGradientStops(stops);
|
||||
}
|
||||
|
||||
void GradientWidget::updatePresetName()
|
||||
{
|
||||
QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>();
|
||||
m_presetButton->setText(QLatin1String(presetEnum.key(m_presetIndex)));
|
||||
}
|
||||
|
||||
void GradientWidget::changePresetBy(int indexOffset)
|
||||
{
|
||||
QMetaEnum presetEnum = QMetaEnum::fromType<QGradient::Preset>();
|
||||
m_presetIndex = qBound(0, m_presetIndex + indexOffset, presetEnum.keyCount() - 1);
|
||||
|
||||
QGradient::Preset preset = static_cast<QGradient::Preset>(presetEnum.value(m_presetIndex));
|
||||
QGradient gradient(preset);
|
||||
if (gradient.type() != QGradient::LinearGradient)
|
||||
return;
|
||||
|
||||
QLinearGradient *linearGradientPointer = static_cast<QLinearGradient *>(&gradient);
|
||||
QLineF objectStopsLine(linearGradientPointer->start(), linearGradientPointer->finalStop());
|
||||
qreal scaleX = qFuzzyIsNull(objectStopsLine.dx()) ? 1.0 : (0.8 * m_renderer->width() / qAbs(objectStopsLine.dx()));
|
||||
qreal scaleY = qFuzzyIsNull(objectStopsLine.dy()) ? 1.0 : (0.8 * m_renderer->height() / qAbs(objectStopsLine.dy()));
|
||||
QLineF logicalStopsLine = QTransform::fromScale(scaleX, scaleY).map(objectStopsLine);
|
||||
logicalStopsLine.translate(m_renderer->rect().center() - logicalStopsLine.center());
|
||||
QPolygonF logicalStops;
|
||||
logicalStops << logicalStopsLine.p1() << logicalStopsLine.p2();
|
||||
|
||||
m_linearButton->animateClick();
|
||||
m_padSpreadButton->animateClick();
|
||||
m_editor->setGradientStops(gradient.stops());
|
||||
m_renderer->hoverPoints()->setPoints(logicalStops);
|
||||
m_renderer->setGradientStops(gradient.stops());
|
||||
|
||||
updatePresetName();
|
||||
}
|
||||
|
||||
GradientRenderer::GradientRenderer(QWidget *parent)
|
||||
: ArthurFrame(parent)
|
||||
{
|
||||
m_hoverPoints = new HoverPoints(this, HoverPoints::CircleShape);
|
||||
m_hoverPoints->setPointSize(QSize(20, 20));
|
||||
m_hoverPoints->setConnectionType(HoverPoints::NoConnection);
|
||||
m_hoverPoints->setEditable(false);
|
||||
|
||||
QList<QPointF> points;
|
||||
points << QPointF(100, 100) << QPointF(200, 200);
|
||||
m_hoverPoints->setPoints(points);
|
||||
|
||||
m_spread = QGradient::PadSpread;
|
||||
m_gradientType = Qt::LinearGradientPattern;
|
||||
}
|
||||
|
||||
void GradientRenderer::setGradientStops(const QGradientStops &stops)
|
||||
{
|
||||
m_stops = stops;
|
||||
update();
|
||||
}
|
||||
|
||||
void GradientRenderer::mousePressEvent(QMouseEvent *)
|
||||
{
|
||||
setDescriptionEnabled(false);
|
||||
}
|
||||
|
||||
void GradientRenderer::paint(QPainter *p)
|
||||
{
|
||||
QPolygonF pts = m_hoverPoints->points();
|
||||
|
||||
QGradient g;
|
||||
|
||||
if (m_gradientType == Qt::LinearGradientPattern) {
|
||||
g = QLinearGradient(pts.at(0), pts.at(1));
|
||||
|
||||
} else if (m_gradientType == Qt::RadialGradientPattern) {
|
||||
g = QRadialGradient(pts.at(0), qMin(width(), height()) / 3.0, pts.at(1));
|
||||
|
||||
} else {
|
||||
QLineF l(pts.at(0), pts.at(1));
|
||||
qreal angle = QLineF(0, 0, 1, 0).angleTo(l);
|
||||
g = QConicalGradient(pts.at(0), angle);
|
||||
}
|
||||
|
||||
for (const auto &stop : std::as_const(m_stops))
|
||||
g.setColorAt(stop.first, stop.second);
|
||||
|
||||
g.setSpread(m_spread);
|
||||
|
||||
p->setBrush(g);
|
||||
p->setPen(Qt::NoPen);
|
||||
|
||||
p->drawRect(rect());
|
||||
|
||||
}
|
143
examples/widgets/painting/gradients/gradients.h
Normal file
@ -0,0 +1,143 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef GRADIENTS_H
|
||||
#define GRADIENTS_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QRadioButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class HoverPoints;
|
||||
|
||||
|
||||
class ShadeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ShadeType {
|
||||
RedShade,
|
||||
GreenShade,
|
||||
BlueShade,
|
||||
ARGBShade
|
||||
};
|
||||
|
||||
ShadeWidget(ShadeType type, QWidget *parent);
|
||||
|
||||
void setGradientStops(const QGradientStops &stops);
|
||||
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
QSize sizeHint() const override { return QSize(150, 40); }
|
||||
QPolygonF points() const;
|
||||
|
||||
HoverPoints *hoverPoints() const { return m_hoverPoints; }
|
||||
|
||||
uint colorAt(int x);
|
||||
|
||||
signals:
|
||||
void colorsChanged();
|
||||
|
||||
private:
|
||||
void generateShade();
|
||||
|
||||
ShadeType m_shade_type;
|
||||
QImage m_shade;
|
||||
HoverPoints *m_hoverPoints;
|
||||
QLinearGradient m_alpha_gradient;
|
||||
};
|
||||
|
||||
class GradientEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GradientEditor(QWidget *parent);
|
||||
|
||||
void setGradientStops(const QGradientStops &stops);
|
||||
|
||||
public slots:
|
||||
void pointsUpdated();
|
||||
|
||||
signals:
|
||||
void gradientStopsChanged(const QGradientStops &stops);
|
||||
|
||||
private:
|
||||
ShadeWidget *m_red_shade;
|
||||
ShadeWidget *m_green_shade;
|
||||
ShadeWidget *m_blue_shade;
|
||||
ShadeWidget *m_alpha_shade;
|
||||
};
|
||||
|
||||
class GradientRenderer : public ArthurFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GradientRenderer(QWidget *parent);
|
||||
void paint(QPainter *p) override;
|
||||
|
||||
QSize sizeHint() const override { return QSize(400, 400); }
|
||||
|
||||
HoverPoints *hoverPoints() const { return m_hoverPoints; }
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
|
||||
public slots:
|
||||
void setGradientStops(const QGradientStops &stops);
|
||||
|
||||
void setPadSpread() { m_spread = QGradient::PadSpread; update(); }
|
||||
void setRepeatSpread() { m_spread = QGradient::RepeatSpread; update(); }
|
||||
void setReflectSpread() { m_spread = QGradient::ReflectSpread; update(); }
|
||||
|
||||
void setLinearGradient() { m_gradientType = Qt::LinearGradientPattern; update(); }
|
||||
void setRadialGradient() { m_gradientType = Qt::RadialGradientPattern; update(); }
|
||||
void setConicalGradient() { m_gradientType = Qt::ConicalGradientPattern; update(); }
|
||||
|
||||
|
||||
private:
|
||||
QGradientStops m_stops;
|
||||
HoverPoints *m_hoverPoints;
|
||||
|
||||
QGradient::Spread m_spread;
|
||||
Qt::BrushStyle m_gradientType;
|
||||
};
|
||||
|
||||
class GradientWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GradientWidget(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
void setDefault1() { setDefault(1); }
|
||||
void setDefault2() { setDefault(2); }
|
||||
void setDefault3() { setDefault(3); }
|
||||
void setDefault4() { setDefault(4); }
|
||||
void setPreset() { changePresetBy(0); }
|
||||
void setPrevPreset() { changePresetBy(-1); }
|
||||
void setNextPreset() { changePresetBy(1); }
|
||||
|
||||
private:
|
||||
void setDefault(int i);
|
||||
void updatePresetName();
|
||||
void changePresetBy(int indexOffset);
|
||||
|
||||
GradientRenderer *m_renderer;
|
||||
GradientEditor *m_editor;
|
||||
|
||||
QRadioButton *m_linearButton;
|
||||
QRadioButton *m_radialButton;
|
||||
QRadioButton *m_conicalButton;
|
||||
QRadioButton *m_padSpreadButton;
|
||||
QRadioButton *m_reflectSpreadButton;
|
||||
QRadioButton *m_repeatSpreadButton;
|
||||
QPushButton *m_presetButton;
|
||||
|
||||
int m_presetIndex = 0;
|
||||
};
|
||||
|
||||
#endif // GRADIENTS_H
|
35
examples/widgets/painting/gradients/gradients.html
Normal file
@ -0,0 +1,35 @@
|
||||
<html>
|
||||
<center>
|
||||
<h2>Gradients</h2>
|
||||
</center>
|
||||
|
||||
<p>In this demo we show the various types of gradients that can
|
||||
be used in Qt.</p>
|
||||
|
||||
<p>There are three types of gradients:
|
||||
|
||||
<ul>
|
||||
<li><b>Linear</b> gradients interpolate colors between start and end
|
||||
points.</li>
|
||||
<li><b>Radial</b> gradients interpolate colors between a focal point and the
|
||||
points on a circle surrounding it.</li>
|
||||
<li><b>Conical</b> gradients interpolate colors around a center point.</li>
|
||||
</ul>
|
||||
|
||||
</p>
|
||||
|
||||
<p>The panel on the right contains a color table editor that defines
|
||||
the colors in the gradient. The three topmost controls determine the red,
|
||||
green and blue components while the last defines the alpha of the
|
||||
gradient. You can move points, and add new ones, by clicking with the left
|
||||
mouse button, and remove points by clicking with the right button.</p>
|
||||
|
||||
<p>There are three example configurations available at the bottom of
|
||||
the page that are provided as suggestions on how a color table could be
|
||||
configured.</p>
|
||||
|
||||
<p>Qt also provides a suite of named gradient presets. They are based on the
|
||||
free WebGradients collection. Click on the name in the Presets box to show the
|
||||
gradient. Use the arrow buttons to browse through the available presets.</p>
|
||||
|
||||
</html>
|
14
examples/widgets/painting/gradients/gradients.pro
Normal file
@ -0,0 +1,14 @@
|
||||
SOURCES += main.cpp gradients.cpp
|
||||
HEADERS += gradients.h
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += gradients.qrc
|
||||
QT += widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/gradients
|
||||
INSTALLS += target
|
||||
|
6
examples/widgets/painting/gradients/gradients.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/gradients">
|
||||
<file>gradients.cpp</file>
|
||||
<file>gradients.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
25
examples/widgets/painting/gradients/main.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "gradients.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(gradients);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
GradientWidget gradientWidget;
|
||||
QStyle *arthurStyle = new ArthurStyle;
|
||||
gradientWidget.setStyle(arthurStyle);
|
||||
const QList<QWidget *> widgets = gradientWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets) {
|
||||
w->setStyle(arthurStyle);
|
||||
w->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
gradientWidget.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
50
examples/widgets/painting/imagecomposition/CMakeLists.txt
Normal file
@ -0,0 +1,50 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(imagecomposition LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/imagecomposition")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(imagecomposition
|
||||
imagecomposer.cpp imagecomposer.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
set_target_properties(imagecomposition PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(imagecomposition PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(imagecomposition_resource_files
|
||||
"images/butterfly.png"
|
||||
"images/checker.png"
|
||||
)
|
||||
|
||||
qt_add_resources(imagecomposition "imagecomposition"
|
||||
PREFIX
|
||||
"/"
|
||||
FILES
|
||||
${imagecomposition_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS imagecomposition
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
174
examples/widgets/painting/imagecomposition/imagecomposer.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "imagecomposer.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
//! [0]
|
||||
static const QSize resultSize(200, 200);
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
ImageComposer::ImageComposer()
|
||||
{
|
||||
sourceButton = new QToolButton;
|
||||
sourceButton->setIconSize(resultSize);
|
||||
|
||||
operatorComboBox = new QComboBox;
|
||||
addOp(QPainter::CompositionMode_SourceOver, tr("SourceOver"));
|
||||
addOp(QPainter::CompositionMode_DestinationOver, tr("DestinationOver"));
|
||||
addOp(QPainter::CompositionMode_Clear, tr("Clear"));
|
||||
addOp(QPainter::CompositionMode_Source, tr("Source"));
|
||||
addOp(QPainter::CompositionMode_Destination, tr("Destination"));
|
||||
addOp(QPainter::CompositionMode_SourceIn, tr("SourceIn"));
|
||||
addOp(QPainter::CompositionMode_DestinationIn, tr("DestinationIn"));
|
||||
addOp(QPainter::CompositionMode_SourceOut, tr("SourceOut"));
|
||||
addOp(QPainter::CompositionMode_DestinationOut, tr("DestinationOut"));
|
||||
addOp(QPainter::CompositionMode_SourceAtop, tr("SourceAtop"));
|
||||
addOp(QPainter::CompositionMode_DestinationAtop, tr("DestinationAtop"));
|
||||
addOp(QPainter::CompositionMode_Xor, tr("Xor"));
|
||||
addOp(QPainter::CompositionMode_Plus, tr("Plus"));
|
||||
addOp(QPainter::CompositionMode_Multiply, tr("Multiply"));
|
||||
addOp(QPainter::CompositionMode_Screen, tr("Screen"));
|
||||
addOp(QPainter::CompositionMode_Overlay, tr("Overlay"));
|
||||
addOp(QPainter::CompositionMode_Darken, tr("Darken"));
|
||||
addOp(QPainter::CompositionMode_Lighten, tr("Lighten"));
|
||||
addOp(QPainter::CompositionMode_ColorDodge, tr("ColorDodge"));
|
||||
addOp(QPainter::CompositionMode_ColorBurn, tr("ColorBurn"));
|
||||
addOp(QPainter::CompositionMode_HardLight, tr("HardLight"));
|
||||
addOp(QPainter::CompositionMode_SoftLight, tr("SoftLight"));
|
||||
addOp(QPainter::CompositionMode_Difference, tr("Difference"));
|
||||
addOp(QPainter::CompositionMode_Exclusion, tr("Exclusion"));
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
destinationButton = new QToolButton;
|
||||
destinationButton->setIconSize(resultSize);
|
||||
|
||||
equalLabel = new QLabel(tr("="));
|
||||
|
||||
resultLabel = new QLabel;
|
||||
resultLabel->setMinimumWidth(resultSize.width());
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
connect(sourceButton, &QAbstractButton::clicked,
|
||||
this, &ImageComposer::chooseSource);
|
||||
connect(operatorComboBox, &QComboBox::activated,
|
||||
this, &ImageComposer::recalculateResult);
|
||||
connect(destinationButton, &QAbstractButton::clicked,
|
||||
this, &ImageComposer::chooseDestination);
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(sourceButton, 0, 0, 3, 1);
|
||||
mainLayout->addWidget(operatorComboBox, 1, 1);
|
||||
mainLayout->addWidget(destinationButton, 0, 2, 3, 1);
|
||||
mainLayout->addWidget(equalLabel, 1, 3);
|
||||
mainLayout->addWidget(resultLabel, 0, 4, 3, 1);
|
||||
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
setLayout(mainLayout);
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
resultImage = QImage(resultSize, QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
loadImage(":/images/butterfly.png", &sourceImage, sourceButton);
|
||||
loadImage(":/images/checker.png", &destinationImage, destinationButton);
|
||||
|
||||
setWindowTitle(tr("Image Composition"));
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
void ImageComposer::chooseSource()
|
||||
{
|
||||
chooseImage(tr("Choose Source Image"), &sourceImage, sourceButton);
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
void ImageComposer::chooseDestination()
|
||||
{
|
||||
chooseImage(tr("Choose Destination Image"), &destinationImage, destinationButton);
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void ImageComposer::recalculateResult()
|
||||
{
|
||||
QPainter::CompositionMode mode = currentMode();
|
||||
|
||||
QPainter painter(&resultImage);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
painter.fillRect(resultImage.rect(), Qt::transparent);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter.drawImage(0, 0, destinationImage);
|
||||
painter.setCompositionMode(mode);
|
||||
painter.drawImage(0, 0, sourceImage);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
|
||||
painter.fillRect(resultImage.rect(), Qt::white);
|
||||
painter.end();
|
||||
|
||||
resultLabel->setPixmap(QPixmap::fromImage(resultImage));
|
||||
}
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
void ImageComposer::addOp(QPainter::CompositionMode mode, const QString &name)
|
||||
{
|
||||
operatorComboBox->addItem(name, mode);
|
||||
}
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
void ImageComposer::chooseImage(const QString &title, QImage *image,
|
||||
QToolButton *button)
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(this, title);
|
||||
if (!fileName.isEmpty())
|
||||
loadImage(fileName, image, button);
|
||||
}
|
||||
//! [10]
|
||||
|
||||
//! [11]
|
||||
void ImageComposer::loadImage(const QString &fileName, QImage *image,
|
||||
QToolButton *button)
|
||||
{
|
||||
image->load(fileName);
|
||||
|
||||
// Scale the image to given size
|
||||
*image = image->scaled(resultSize, Qt::KeepAspectRatio);
|
||||
|
||||
QImage fixedImage(resultSize, QImage::Format_ARGB32_Premultiplied);
|
||||
QPainter painter(&fixedImage);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
painter.fillRect(fixedImage.rect(), Qt::transparent);
|
||||
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter.drawImage(imagePos(*image), *image);
|
||||
painter.end();
|
||||
button->setIcon(QPixmap::fromImage(fixedImage));
|
||||
|
||||
*image = fixedImage;
|
||||
|
||||
recalculateResult();
|
||||
}
|
||||
//! [11]
|
||||
|
||||
//! [12]
|
||||
QPainter::CompositionMode ImageComposer::currentMode() const
|
||||
{
|
||||
return (QPainter::CompositionMode)
|
||||
operatorComboBox->itemData(operatorComboBox->currentIndex()).toInt();
|
||||
}
|
||||
//! [12]
|
||||
|
||||
//! [13]
|
||||
QPoint ImageComposer::imagePos(const QImage &image) const
|
||||
{
|
||||
return QPoint((resultSize.width() - image.width()) / 2,
|
||||
(resultSize.height() - image.height()) / 2);
|
||||
}
|
||||
//! [13]
|
50
examples/widgets/painting/imagecomposition/imagecomposer.h
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef IMAGECOMPOSER_H
|
||||
#define IMAGECOMPOSER_H
|
||||
|
||||
#include <QPainter>
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QToolButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
//! [0]
|
||||
class ImageComposer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ImageComposer();
|
||||
|
||||
private slots:
|
||||
void chooseSource();
|
||||
void chooseDestination();
|
||||
void recalculateResult();
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
private:
|
||||
void addOp(QPainter::CompositionMode mode, const QString &name);
|
||||
void chooseImage(const QString &title, QImage *image, QToolButton *button);
|
||||
void loadImage(const QString &fileName, QImage *image, QToolButton *button);
|
||||
QPainter::CompositionMode currentMode() const;
|
||||
QPoint imagePos(const QImage &image) const;
|
||||
|
||||
QToolButton *sourceButton;
|
||||
QToolButton *destinationButton;
|
||||
QComboBox *operatorComboBox;
|
||||
QLabel *equalLabel;
|
||||
QLabel *resultLabel;
|
||||
|
||||
QImage sourceImage;
|
||||
QImage destinationImage;
|
||||
QImage resultImage;
|
||||
};
|
||||
//! [1]
|
||||
|
||||
#endif // IMAGECOMPOSER_H
|
@ -0,0 +1,11 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(combobox))
|
||||
|
||||
HEADERS = imagecomposer.h
|
||||
SOURCES = imagecomposer.cpp \
|
||||
main.cpp
|
||||
RESOURCES = imagecomposition.qrc
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/imagecomposition
|
||||
INSTALLS += target
|
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>images/butterfly.png</file>
|
||||
<file>images/checker.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
examples/widgets/painting/imagecomposition/images/background.png
Normal file
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 90 B |
BIN
examples/widgets/painting/imagecomposition/images/butterfly.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
examples/widgets/painting/imagecomposition/images/checker.png
Normal file
After Width: | Height: | Size: 10 KiB |
18
examples/widgets/painting/imagecomposition/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "imagecomposer.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
//! [0]
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Q_INIT_RESOURCE(imagecomposition);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
ImageComposer composer;
|
||||
composer.show();
|
||||
return app.exec();
|
||||
}
|
||||
//! [0]
|
44
examples/widgets/painting/painterpaths/CMakeLists.txt
Normal file
@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(painterpaths LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/painterpaths")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(painterpaths
|
||||
main.cpp
|
||||
renderarea.cpp renderarea.h
|
||||
window.cpp window.h
|
||||
)
|
||||
|
||||
set_target_properties(painterpaths PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(painterpaths PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT HAIKU AND NOT INTEGRITY AND NOT VXWORKS)
|
||||
target_link_libraries(painterpaths PRIVATE
|
||||
m
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS painterpaths
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
14
examples/widgets/painting/painterpaths/main.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
Window window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
13
examples/widgets/painting/painterpaths/painterpaths.pro
Normal file
@ -0,0 +1,13 @@
|
||||
QT += widgets
|
||||
requires(qtConfig(combobox))
|
||||
|
||||
HEADERS = renderarea.h \
|
||||
window.h
|
||||
SOURCES = main.cpp \
|
||||
renderarea.cpp \
|
||||
window.cpp
|
||||
unix:!mac:!vxworks:!integrity:!haiku:LIBS += -lm
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/painterpaths
|
||||
INSTALLS += target
|
92
examples/widgets/painting/painterpaths/renderarea.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "renderarea.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
//! [0]
|
||||
RenderArea::RenderArea(const QPainterPath &path, QWidget *parent)
|
||||
: QWidget(parent), path(path)
|
||||
{
|
||||
penWidth = 1;
|
||||
rotationAngle = 0;
|
||||
setBackgroundRole(QPalette::Base);
|
||||
}
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
QSize RenderArea::minimumSizeHint() const
|
||||
{
|
||||
return QSize(50, 50);
|
||||
}
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QSize RenderArea::sizeHint() const
|
||||
{
|
||||
return QSize(100, 100);
|
||||
}
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
void RenderArea::setFillRule(Qt::FillRule rule)
|
||||
{
|
||||
path.setFillRule(rule);
|
||||
update();
|
||||
}
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
void RenderArea::setFillGradient(const QColor &color1, const QColor &color2)
|
||||
{
|
||||
fillColor1 = color1;
|
||||
fillColor2 = color2;
|
||||
update();
|
||||
}
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
void RenderArea::setPenWidth(int width)
|
||||
{
|
||||
penWidth = width;
|
||||
update();
|
||||
}
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
void RenderArea::setPenColor(const QColor &color)
|
||||
{
|
||||
penColor = color;
|
||||
update();
|
||||
}
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
void RenderArea::setRotationAngle(int degrees)
|
||||
{
|
||||
rotationAngle = degrees;
|
||||
update();
|
||||
}
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
void RenderArea::paintEvent(QPaintEvent *)
|
||||
{
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
//! [8] //! [9]
|
||||
painter.scale(width() / 100.0, height() / 100.0);
|
||||
painter.translate(50.0, 50.0);
|
||||
painter.rotate(-rotationAngle);
|
||||
painter.translate(-50.0, -50.0);
|
||||
|
||||
//! [9] //! [10]
|
||||
painter.setPen(QPen(penColor, penWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
|
||||
QLinearGradient gradient(0, 0, 0, 100);
|
||||
gradient.setColorAt(0.0, fillColor1);
|
||||
gradient.setColorAt(1.0, fillColor2);
|
||||
painter.setBrush(gradient);
|
||||
painter.drawPath(path);
|
||||
}
|
||||
//! [10]
|
43
examples/widgets/painting/painterpaths/renderarea.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef RENDERAREA_H
|
||||
#define RENDERAREA_H
|
||||
|
||||
#include <QPainterPath>
|
||||
#include <QWidget>
|
||||
|
||||
//! [0]
|
||||
class RenderArea : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RenderArea(const QPainterPath &path, QWidget *parent = nullptr);
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
void setFillRule(Qt::FillRule rule);
|
||||
void setFillGradient(const QColor &color1, const QColor &color2);
|
||||
void setPenWidth(int width);
|
||||
void setPenColor(const QColor &color);
|
||||
void setRotationAngle(int degrees);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
private:
|
||||
QPainterPath path;
|
||||
QColor fillColor1;
|
||||
QColor fillColor2;
|
||||
int penWidth;
|
||||
QColor penColor;
|
||||
int rotationAngle;
|
||||
};
|
||||
//! [1]
|
||||
|
||||
#endif // RENDERAREA_H
|
247
examples/widgets/painting/painterpaths/window.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "renderarea.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
#include <qmath.h>
|
||||
|
||||
//! [1]
|
||||
Window::Window()
|
||||
{
|
||||
QPainterPath rectPath;
|
||||
rectPath.moveTo(20.0, 30.0);
|
||||
rectPath.lineTo(80.0, 30.0);
|
||||
rectPath.lineTo(80.0, 70.0);
|
||||
rectPath.lineTo(20.0, 70.0);
|
||||
rectPath.closeSubpath();
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QPainterPath roundRectPath;
|
||||
roundRectPath.moveTo(80.0, 35.0);
|
||||
roundRectPath.arcTo(70.0, 30.0, 10.0, 10.0, 0.0, 90.0);
|
||||
roundRectPath.lineTo(25.0, 30.0);
|
||||
roundRectPath.arcTo(20.0, 30.0, 10.0, 10.0, 90.0, 90.0);
|
||||
roundRectPath.lineTo(20.0, 65.0);
|
||||
roundRectPath.arcTo(20.0, 60.0, 10.0, 10.0, 180.0, 90.0);
|
||||
roundRectPath.lineTo(75.0, 70.0);
|
||||
roundRectPath.arcTo(70.0, 60.0, 10.0, 10.0, 270.0, 90.0);
|
||||
roundRectPath.closeSubpath();
|
||||
//! [2]
|
||||
|
||||
//! [3]
|
||||
QPainterPath ellipsePath;
|
||||
ellipsePath.moveTo(80.0, 50.0);
|
||||
ellipsePath.arcTo(20.0, 30.0, 60.0, 40.0, 0.0, 360.0);
|
||||
//! [3]
|
||||
|
||||
//! [4]
|
||||
QPainterPath piePath;
|
||||
piePath.moveTo(50.0, 50.0);
|
||||
piePath.arcTo(20.0, 30.0, 60.0, 40.0, 60.0, 240.0);
|
||||
piePath.closeSubpath();
|
||||
//! [4]
|
||||
|
||||
//! [5]
|
||||
QPainterPath polygonPath;
|
||||
polygonPath.moveTo(10.0, 80.0);
|
||||
polygonPath.lineTo(20.0, 10.0);
|
||||
polygonPath.lineTo(80.0, 30.0);
|
||||
polygonPath.lineTo(90.0, 70.0);
|
||||
polygonPath.closeSubpath();
|
||||
//! [5]
|
||||
|
||||
//! [6]
|
||||
QPainterPath groupPath;
|
||||
groupPath.moveTo(60.0, 40.0);
|
||||
groupPath.arcTo(20.0, 20.0, 40.0, 40.0, 0.0, 360.0);
|
||||
groupPath.moveTo(40.0, 40.0);
|
||||
groupPath.lineTo(40.0, 80.0);
|
||||
groupPath.lineTo(80.0, 80.0);
|
||||
groupPath.lineTo(80.0, 40.0);
|
||||
groupPath.closeSubpath();
|
||||
//! [6]
|
||||
|
||||
//! [7]
|
||||
QPainterPath textPath;
|
||||
QFont timesFont("Times", 50);
|
||||
timesFont.setStyleStrategy(QFont::ForceOutline);
|
||||
textPath.addText(10, 70, timesFont, tr("Qt"));
|
||||
//! [7]
|
||||
|
||||
//! [8]
|
||||
QPainterPath bezierPath;
|
||||
bezierPath.moveTo(20, 30);
|
||||
bezierPath.cubicTo(80, 0, 50, 50, 80, 80);
|
||||
//! [8]
|
||||
|
||||
//! [9]
|
||||
QPainterPath starPath;
|
||||
starPath.moveTo(90, 50);
|
||||
for (int i = 1; i < 5; ++i) {
|
||||
starPath.lineTo(50 + 40 * std::cos(0.8 * i * M_PI),
|
||||
50 + 40 * std::sin(0.8 * i * M_PI));
|
||||
}
|
||||
starPath.closeSubpath();
|
||||
//! [9]
|
||||
|
||||
//! [10]
|
||||
renderAreas.push_back(new RenderArea(rectPath));
|
||||
renderAreas.push_back(new RenderArea(roundRectPath));
|
||||
renderAreas.push_back(new RenderArea(ellipsePath));
|
||||
renderAreas.push_back(new RenderArea(piePath));
|
||||
renderAreas.push_back(new RenderArea(polygonPath));
|
||||
renderAreas.push_back(new RenderArea(groupPath));
|
||||
renderAreas.push_back(new RenderArea(textPath));
|
||||
renderAreas.push_back(new RenderArea(bezierPath));
|
||||
renderAreas.push_back(new RenderArea(starPath));
|
||||
//! [10]
|
||||
|
||||
//! [11]
|
||||
fillRuleComboBox = new QComboBox;
|
||||
fillRuleComboBox->addItem(tr("Odd Even"), Qt::OddEvenFill);
|
||||
fillRuleComboBox->addItem(tr("Winding"), Qt::WindingFill);
|
||||
|
||||
fillRuleLabel = new QLabel(tr("Fill &Rule:"));
|
||||
fillRuleLabel->setBuddy(fillRuleComboBox);
|
||||
//! [11]
|
||||
|
||||
//! [12]
|
||||
fillColor1ComboBox = new QComboBox;
|
||||
populateWithColors(fillColor1ComboBox);
|
||||
fillColor1ComboBox->setCurrentIndex(fillColor1ComboBox->findText("mediumslateblue"));
|
||||
|
||||
fillColor2ComboBox = new QComboBox;
|
||||
populateWithColors(fillColor2ComboBox);
|
||||
fillColor2ComboBox->setCurrentIndex(fillColor2ComboBox->findText("cornsilk"));
|
||||
|
||||
fillGradientLabel = new QLabel(tr("&Fill Gradient:"));
|
||||
fillGradientLabel->setBuddy(fillColor1ComboBox);
|
||||
|
||||
fillToLabel = new QLabel(tr("to"));
|
||||
fillToLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
penWidthSpinBox = new QSpinBox;
|
||||
penWidthSpinBox->setRange(0, 20);
|
||||
|
||||
penWidthLabel = new QLabel(tr("&Pen Width:"));
|
||||
penWidthLabel->setBuddy(penWidthSpinBox);
|
||||
|
||||
penColorComboBox = new QComboBox;
|
||||
populateWithColors(penColorComboBox);
|
||||
penColorComboBox->setCurrentIndex(penColorComboBox->findText("darkslateblue"));
|
||||
|
||||
penColorLabel = new QLabel(tr("Pen &Color:"));
|
||||
penColorLabel->setBuddy(penColorComboBox);
|
||||
|
||||
rotationAngleSpinBox = new QSpinBox;
|
||||
rotationAngleSpinBox->setRange(0, 359);
|
||||
rotationAngleSpinBox->setWrapping(true);
|
||||
rotationAngleSpinBox->setSuffix(QLatin1String("\xB0"));
|
||||
|
||||
rotationAngleLabel = new QLabel(tr("&Rotation Angle:"));
|
||||
rotationAngleLabel->setBuddy(rotationAngleSpinBox);
|
||||
//! [12]
|
||||
|
||||
//! [16]
|
||||
connect(fillRuleComboBox, &QComboBox::activated,
|
||||
this, &Window::fillRuleChanged);
|
||||
connect(fillColor1ComboBox, &QComboBox::activated,
|
||||
this, &Window::fillGradientChanged);
|
||||
connect(fillColor2ComboBox, &QComboBox::activated,
|
||||
this, &Window::fillGradientChanged);
|
||||
connect(penColorComboBox, &QComboBox::activated,
|
||||
this, &Window::penColorChanged);
|
||||
|
||||
for (RenderArea *area : std::as_const(renderAreas)) {
|
||||
connect(penWidthSpinBox, &QSpinBox::valueChanged,
|
||||
area, &RenderArea::setPenWidth);
|
||||
connect(rotationAngleSpinBox, &QSpinBox::valueChanged,
|
||||
area, &RenderArea::setRotationAngle);
|
||||
}
|
||||
|
||||
//! [16] //! [17]
|
||||
QGridLayout *topLayout = new QGridLayout;
|
||||
|
||||
int i = 0;
|
||||
for (RenderArea *area : std::as_const(renderAreas)) {
|
||||
topLayout->addWidget(area, i / 3, i % 3);
|
||||
++i;
|
||||
}
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->addLayout(topLayout, 0, 0, 1, 4);
|
||||
mainLayout->addWidget(fillRuleLabel, 1, 0);
|
||||
mainLayout->addWidget(fillRuleComboBox, 1, 1, 1, 3);
|
||||
mainLayout->addWidget(fillGradientLabel, 2, 0);
|
||||
mainLayout->addWidget(fillColor1ComboBox, 2, 1);
|
||||
mainLayout->addWidget(fillToLabel, 2, 2);
|
||||
mainLayout->addWidget(fillColor2ComboBox, 2, 3);
|
||||
mainLayout->addWidget(penWidthLabel, 3, 0);
|
||||
mainLayout->addWidget(penWidthSpinBox, 3, 1, 1, 3);
|
||||
mainLayout->addWidget(penColorLabel, 4, 0);
|
||||
mainLayout->addWidget(penColorComboBox, 4, 1, 1, 3);
|
||||
mainLayout->addWidget(rotationAngleLabel, 5, 0);
|
||||
mainLayout->addWidget(rotationAngleSpinBox, 5, 1, 1, 3);
|
||||
setLayout(mainLayout);
|
||||
//! [17]
|
||||
|
||||
//! [18]
|
||||
fillRuleChanged();
|
||||
fillGradientChanged();
|
||||
penColorChanged();
|
||||
penWidthSpinBox->setValue(2);
|
||||
|
||||
setWindowTitle(tr("Painter Paths"));
|
||||
}
|
||||
//! [18]
|
||||
|
||||
//! [19]
|
||||
void Window::fillRuleChanged()
|
||||
{
|
||||
Qt::FillRule rule = (Qt::FillRule)currentItemData(fillRuleComboBox).toInt();
|
||||
|
||||
for (RenderArea *area : std::as_const(renderAreas))
|
||||
area->setFillRule(rule);
|
||||
}
|
||||
//! [19]
|
||||
|
||||
//! [20]
|
||||
void Window::fillGradientChanged()
|
||||
{
|
||||
QColor color1 = qvariant_cast<QColor>(currentItemData(fillColor1ComboBox));
|
||||
QColor color2 = qvariant_cast<QColor>(currentItemData(fillColor2ComboBox));
|
||||
|
||||
for (RenderArea *area : std::as_const(renderAreas))
|
||||
area->setFillGradient(color1, color2);
|
||||
}
|
||||
//! [20]
|
||||
|
||||
//! [21]
|
||||
void Window::penColorChanged()
|
||||
{
|
||||
QColor color = qvariant_cast<QColor>(currentItemData(penColorComboBox));
|
||||
|
||||
for (RenderArea *area : std::as_const(renderAreas))
|
||||
area->setPenColor(color);
|
||||
}
|
||||
//! [21]
|
||||
|
||||
//! [22]
|
||||
void Window::populateWithColors(QComboBox *comboBox)
|
||||
{
|
||||
const QStringList colorNames = QColor::colorNames();
|
||||
for (const QString &name : colorNames)
|
||||
comboBox->addItem(name, QColor(name));
|
||||
}
|
||||
//! [22]
|
||||
|
||||
//! [23]
|
||||
QVariant Window::currentItemData(QComboBox *comboBox)
|
||||
{
|
||||
return comboBox->itemData(comboBox->currentIndex());
|
||||
}
|
||||
//! [23]
|
53
examples/widgets/painting/painterpaths/window.h
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef WINDOW_H
|
||||
#define WINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
QT_END_NAMESPACE
|
||||
class RenderArea;
|
||||
|
||||
//! [0]
|
||||
class Window : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Window();
|
||||
|
||||
private slots:
|
||||
void fillRuleChanged();
|
||||
void fillGradientChanged();
|
||||
void penColorChanged();
|
||||
//! [0]
|
||||
|
||||
//! [1]
|
||||
private:
|
||||
void populateWithColors(QComboBox *comboBox);
|
||||
QVariant currentItemData(QComboBox *comboBox);
|
||||
//! [1]
|
||||
|
||||
//! [2]
|
||||
QList<RenderArea*> renderAreas;
|
||||
QLabel *fillRuleLabel;
|
||||
QLabel *fillGradientLabel;
|
||||
QLabel *fillToLabel;
|
||||
QLabel *penWidthLabel;
|
||||
QLabel *penColorLabel;
|
||||
QLabel *rotationAngleLabel;
|
||||
QComboBox *fillRuleComboBox;
|
||||
QComboBox *fillColor1ComboBox;
|
||||
QComboBox *fillColor2ComboBox;
|
||||
QSpinBox *penWidthSpinBox;
|
||||
QComboBox *penColorComboBox;
|
||||
QSpinBox *rotationAngleSpinBox;
|
||||
};
|
||||
//! [2]
|
||||
|
||||
#endif // WINDOW_H
|
15
examples/widgets/painting/painting.pro
Normal file
@ -0,0 +1,15 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = basicdrawing \
|
||||
concentriccircles \
|
||||
affine \
|
||||
composition \
|
||||
deform \
|
||||
gradients \
|
||||
pathstroke \
|
||||
imagecomposition \
|
||||
painterpaths \
|
||||
transformations \
|
||||
fontsampler
|
||||
|
||||
EXAMPLE_FILES = \
|
||||
shared
|
102
examples/widgets/painting/pathstroke/CMakeLists.txt
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(pathstroke LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/pathstroke")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(pathstroke
|
||||
main.cpp
|
||||
pathstroke.cpp pathstroke.h
|
||||
)
|
||||
|
||||
set_target_properties(pathstroke PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(pathstroke PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(pathstroke "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(pathstroke_resource_files
|
||||
"pathstroke.cpp"
|
||||
"pathstroke.html"
|
||||
)
|
||||
|
||||
qt_add_resources(pathstroke "pathstroke"
|
||||
PREFIX
|
||||
"/res/pathstroke"
|
||||
FILES
|
||||
${pathstroke_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS pathstroke
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
34
examples/widgets/painting/pathstroke/main.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathstroke.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(pathstroke);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
bool smallScreen = QApplication::arguments().contains("-small-screen");
|
||||
|
||||
PathStrokeWidget pathStrokeWidget(smallScreen);
|
||||
QStyle *arthurStyle = new ArthurStyle();
|
||||
pathStrokeWidget.setStyle(arthurStyle);
|
||||
const QList<QWidget *> widgets = pathStrokeWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets) {
|
||||
w->setStyle(arthurStyle);
|
||||
w->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
|
||||
if (smallScreen)
|
||||
pathStrokeWidget.showFullScreen();
|
||||
else
|
||||
pathStrokeWidget.show();
|
||||
|
||||
#ifdef QT_KEYPAD_NAVIGATION
|
||||
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
|
||||
#endif
|
||||
return app.exec();
|
||||
}
|
663
examples/widgets/painting/pathstroke/pathstroke.cpp
Normal file
@ -0,0 +1,663 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathstroke.h"
|
||||
#include "arthurstyle.h"
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
extern void draw_round_rect(QPainter *p, const QRect &bounds, int radius);
|
||||
|
||||
|
||||
PathStrokeControls::PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
|
||||
if (smallScreen)
|
||||
layoutForSmallScreens();
|
||||
else
|
||||
layoutForDesktop();
|
||||
}
|
||||
|
||||
void PathStrokeControls::createCommonControls(QWidget* parent)
|
||||
{
|
||||
m_capGroup = new QGroupBox(parent);
|
||||
m_capGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *flatCap = new QRadioButton(m_capGroup);
|
||||
QRadioButton *squareCap = new QRadioButton(m_capGroup);
|
||||
QRadioButton *roundCap = new QRadioButton(m_capGroup);
|
||||
m_capGroup->setTitle(tr("Cap Style"));
|
||||
flatCap->setText(tr("Flat"));
|
||||
squareCap->setText(tr("Square"));
|
||||
roundCap->setText(tr("Round"));
|
||||
flatCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
squareCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
roundCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
m_joinGroup = new QGroupBox(parent);
|
||||
m_joinGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *bevelJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *miterJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *svgMiterJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *roundJoin = new QRadioButton(m_joinGroup);
|
||||
m_joinGroup->setTitle(tr("Join Style"));
|
||||
bevelJoin->setText(tr("Bevel"));
|
||||
miterJoin->setText(tr("Miter"));
|
||||
svgMiterJoin->setText(tr("SvgMiter"));
|
||||
roundJoin->setText(tr("Round"));
|
||||
|
||||
m_styleGroup = new QGroupBox(parent);
|
||||
m_styleGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *solidLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashDotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashDotDotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *customDashLine = new QRadioButton(m_styleGroup);
|
||||
m_styleGroup->setTitle(tr("Pen Style"));
|
||||
|
||||
QPixmap line_solid(":res/images/line_solid.png");
|
||||
solidLine->setIcon(line_solid);
|
||||
solidLine->setIconSize(line_solid.size());
|
||||
QPixmap line_dashed(":res/images/line_dashed.png");
|
||||
dashLine->setIcon(line_dashed);
|
||||
dashLine->setIconSize(line_dashed.size());
|
||||
QPixmap line_dotted(":res/images/line_dotted.png");
|
||||
dotLine->setIcon(line_dotted);
|
||||
dotLine->setIconSize(line_dotted.size());
|
||||
QPixmap line_dash_dot(":res/images/line_dash_dot.png");
|
||||
dashDotLine->setIcon(line_dash_dot);
|
||||
dashDotLine->setIconSize(line_dash_dot.size());
|
||||
QPixmap line_dash_dot_dot(":res/images/line_dash_dot_dot.png");
|
||||
dashDotDotLine->setIcon(line_dash_dot_dot);
|
||||
dashDotDotLine->setIconSize(line_dash_dot_dot.size());
|
||||
customDashLine->setText(tr("Custom"));
|
||||
|
||||
int fixedHeight = bevelJoin->sizeHint().height();
|
||||
solidLine->setFixedHeight(fixedHeight);
|
||||
dashLine->setFixedHeight(fixedHeight);
|
||||
dotLine->setFixedHeight(fixedHeight);
|
||||
dashDotLine->setFixedHeight(fixedHeight);
|
||||
dashDotDotLine->setFixedHeight(fixedHeight);
|
||||
|
||||
m_pathModeGroup = new QGroupBox(parent);
|
||||
m_pathModeGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *curveMode = new QRadioButton(m_pathModeGroup);
|
||||
QRadioButton *lineMode = new QRadioButton(m_pathModeGroup);
|
||||
m_pathModeGroup->setTitle(tr("Line Style"));
|
||||
curveMode->setText(tr("Curves"));
|
||||
lineMode->setText(tr("Lines"));
|
||||
|
||||
|
||||
// Layouts
|
||||
QVBoxLayout *capGroupLayout = new QVBoxLayout(m_capGroup);
|
||||
capGroupLayout->addWidget(flatCap);
|
||||
capGroupLayout->addWidget(squareCap);
|
||||
capGroupLayout->addWidget(roundCap);
|
||||
|
||||
QVBoxLayout *joinGroupLayout = new QVBoxLayout(m_joinGroup);
|
||||
joinGroupLayout->addWidget(bevelJoin);
|
||||
joinGroupLayout->addWidget(miterJoin);
|
||||
joinGroupLayout->addWidget(svgMiterJoin);
|
||||
joinGroupLayout->addWidget(roundJoin);
|
||||
|
||||
QVBoxLayout *styleGroupLayout = new QVBoxLayout(m_styleGroup);
|
||||
styleGroupLayout->addWidget(solidLine);
|
||||
styleGroupLayout->addWidget(dashLine);
|
||||
styleGroupLayout->addWidget(dotLine);
|
||||
styleGroupLayout->addWidget(dashDotLine);
|
||||
styleGroupLayout->addWidget(dashDotDotLine);
|
||||
styleGroupLayout->addWidget(customDashLine);
|
||||
|
||||
QVBoxLayout *pathModeGroupLayout = new QVBoxLayout(m_pathModeGroup);
|
||||
pathModeGroupLayout->addWidget(curveMode);
|
||||
pathModeGroupLayout->addWidget(lineMode);
|
||||
|
||||
|
||||
// Connections
|
||||
connect(flatCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setFlatCap);
|
||||
connect(squareCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSquareCap);
|
||||
connect(roundCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setRoundCap);
|
||||
|
||||
connect(bevelJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setBevelJoin);
|
||||
connect(miterJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setMiterJoin);
|
||||
connect(svgMiterJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSvgMiterJoin);
|
||||
connect(roundJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setRoundJoin);
|
||||
|
||||
connect(curveMode, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setCurveMode);
|
||||
connect(lineMode, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setLineMode);
|
||||
|
||||
connect(solidLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSolidLine);
|
||||
connect(dashLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashLine);
|
||||
connect(dotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDotLine);
|
||||
connect(dashDotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashDotLine);
|
||||
connect(dashDotDotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashDotDotLine);
|
||||
connect(customDashLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setCustomDashLine);
|
||||
|
||||
// Set the defaults:
|
||||
flatCap->setChecked(true);
|
||||
bevelJoin->setChecked(true);
|
||||
curveMode->setChecked(true);
|
||||
solidLine->setChecked(true);
|
||||
}
|
||||
|
||||
|
||||
void PathStrokeControls::layoutForDesktop()
|
||||
{
|
||||
QGroupBox *mainGroup = new QGroupBox(this);
|
||||
mainGroup->setFixedWidth(180);
|
||||
mainGroup->setTitle(tr("Path Stroking"));
|
||||
|
||||
createCommonControls(mainGroup);
|
||||
|
||||
QGroupBox* penWidthGroup = new QGroupBox(mainGroup);
|
||||
QSlider *penWidth = new QSlider(Qt::Horizontal, penWidthGroup);
|
||||
penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
penWidthGroup->setTitle(tr("Pen Width"));
|
||||
penWidth->setRange(0, 500);
|
||||
|
||||
QPushButton *animated = new QPushButton(mainGroup);
|
||||
animated->setText(tr("Animate"));
|
||||
animated->setCheckable(true);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
|
||||
// Layouts:
|
||||
QVBoxLayout *penWidthLayout = new QVBoxLayout(penWidthGroup);
|
||||
penWidthLayout->addWidget(penWidth);
|
||||
|
||||
QVBoxLayout * mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(QMargins());
|
||||
mainLayout->addWidget(mainGroup);
|
||||
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->setContentsMargins(3, 3, 3, 3);
|
||||
mainGroupLayout->addWidget(m_capGroup);
|
||||
mainGroupLayout->addWidget(m_joinGroup);
|
||||
mainGroupLayout->addWidget(m_styleGroup);
|
||||
mainGroupLayout->addWidget(penWidthGroup);
|
||||
mainGroupLayout->addWidget(m_pathModeGroup);
|
||||
mainGroupLayout->addWidget(animated);
|
||||
mainGroupLayout->addStretch(1);
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
|
||||
|
||||
// Set up connections
|
||||
connect(animated, &QAbstractButton::toggled,
|
||||
m_renderer, &PathStrokeRenderer::setAnimation);
|
||||
|
||||
connect(penWidth, &QAbstractSlider::valueChanged,
|
||||
m_renderer, &PathStrokeRenderer::setPenWidth);
|
||||
|
||||
connect(showSourceButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::showSource);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
connect(whatsThisButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(m_renderer, &ArthurFrame::descriptionEnabledChanged,
|
||||
whatsThisButton, &QAbstractButton::setChecked);
|
||||
|
||||
|
||||
// Set the defaults
|
||||
animated->setChecked(true);
|
||||
penWidth->setValue(50);
|
||||
|
||||
}
|
||||
|
||||
void PathStrokeControls::layoutForSmallScreens()
|
||||
{
|
||||
createCommonControls(this);
|
||||
|
||||
m_capGroup->layout()->setContentsMargins(QMargins());
|
||||
m_joinGroup->layout()->setContentsMargins(QMargins());
|
||||
m_styleGroup->layout()->setContentsMargins(QMargins());
|
||||
m_pathModeGroup->layout()->setContentsMargins(QMargins());
|
||||
|
||||
QPushButton* okBtn = new QPushButton(tr("OK"), this);
|
||||
okBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
okBtn->setMinimumSize(100,okBtn->minimumSize().height());
|
||||
|
||||
QPushButton* quitBtn = new QPushButton(tr("Quit"), this);
|
||||
quitBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
quitBtn->setMinimumSize(100, okBtn->minimumSize().height());
|
||||
|
||||
QLabel *penWidthLabel = new QLabel(tr(" Width:"));
|
||||
QSlider *penWidth = new QSlider(Qt::Horizontal, this);
|
||||
penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
penWidth->setRange(0, 500);
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(this);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
|
||||
// Layouts:
|
||||
QHBoxLayout *penWidthLayout = new QHBoxLayout;
|
||||
penWidthLayout->addWidget(penWidthLabel, 0, Qt::AlignRight);
|
||||
penWidthLayout->addWidget(penWidth);
|
||||
|
||||
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||||
leftLayout->addWidget(m_capGroup);
|
||||
leftLayout->addWidget(m_joinGroup);
|
||||
#if QT_CONFIG(opengl)
|
||||
leftLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
leftLayout->addLayout(penWidthLayout);
|
||||
|
||||
QVBoxLayout *rightLayout = new QVBoxLayout;
|
||||
rightLayout->addWidget(m_styleGroup);
|
||||
rightLayout->addWidget(m_pathModeGroup);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout(this);
|
||||
mainLayout->setContentsMargins(QMargins());
|
||||
|
||||
// Add spacers around the form items so we don't look stupid at higher resolutions
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 0, 0, 1, 4);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 1, 0, 2, 1);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 1, 3, 2, 1);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 3, 0, 1, 4);
|
||||
|
||||
mainLayout->addLayout(leftLayout, 1, 1);
|
||||
mainLayout->addLayout(rightLayout, 1, 2);
|
||||
mainLayout->addWidget(quitBtn, 2, 1, Qt::AlignHCenter | Qt::AlignTop);
|
||||
mainLayout->addWidget(okBtn, 2, 2, Qt::AlignHCenter | Qt::AlignTop);
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
|
||||
connect(penWidth, &QAbstractSlider::valueChanged, m_renderer, &PathStrokeRenderer::setPenWidth);
|
||||
connect(quitBtn, &QAbstractButton::clicked, this, &PathStrokeControls::emitQuitSignal);
|
||||
connect(okBtn, &QAbstractButton::clicked, this, &PathStrokeControls::emitOkSignal);
|
||||
|
||||
m_renderer->setAnimation(true);
|
||||
penWidth->setValue(50);
|
||||
}
|
||||
|
||||
void PathStrokeControls::emitQuitSignal()
|
||||
{
|
||||
emit quitPressed();
|
||||
}
|
||||
|
||||
void PathStrokeControls::emitOkSignal()
|
||||
{
|
||||
emit okPressed();
|
||||
}
|
||||
|
||||
|
||||
PathStrokeWidget::PathStrokeWidget(bool smallScreen)
|
||||
{
|
||||
setWindowTitle(tr("Path Stroking"));
|
||||
|
||||
// Widget construction and property setting
|
||||
m_renderer = new PathStrokeRenderer(this, smallScreen);
|
||||
|
||||
m_controls = new PathStrokeControls(nullptr, m_renderer, smallScreen);
|
||||
|
||||
// Layouting
|
||||
QHBoxLayout *viewLayout = new QHBoxLayout(this);
|
||||
viewLayout->addWidget(m_renderer);
|
||||
|
||||
if (!smallScreen)
|
||||
viewLayout->addWidget(m_controls);
|
||||
|
||||
m_renderer->loadSourceFile(":res/pathstroke/pathstroke.cpp");
|
||||
m_renderer->loadDescription(":res/pathstroke/pathstroke.html");
|
||||
|
||||
connect(m_renderer, &PathStrokeRenderer::clicked, this, &PathStrokeWidget::showControls);
|
||||
connect(m_controls, &PathStrokeControls::okPressed, this, &PathStrokeWidget::hideControls);
|
||||
connect(m_controls, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
|
||||
}
|
||||
|
||||
void PathStrokeWidget::showControls()
|
||||
{
|
||||
m_controls->showFullScreen();
|
||||
}
|
||||
|
||||
void PathStrokeWidget::hideControls()
|
||||
{
|
||||
m_controls->hide();
|
||||
}
|
||||
|
||||
void PathStrokeWidget::setStyle(QStyle *style)
|
||||
{
|
||||
QWidget::setStyle(style);
|
||||
if (m_controls != nullptr)
|
||||
{
|
||||
m_controls->setStyle(style);
|
||||
|
||||
const QList<QWidget *> widgets = m_controls->findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets)
|
||||
w->setStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
PathStrokeRenderer::PathStrokeRenderer(QWidget *parent, bool smallScreen)
|
||||
: ArthurFrame(parent)
|
||||
{
|
||||
m_smallScreen = smallScreen;
|
||||
m_pointSize = 10;
|
||||
m_activePoint = -1;
|
||||
m_capStyle = Qt::FlatCap;
|
||||
m_joinStyle = Qt::BevelJoin;
|
||||
m_pathMode = CurveMode;
|
||||
m_penWidth = 1;
|
||||
m_penStyle = Qt::SolidLine;
|
||||
m_wasAnimated = true;
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::paint(QPainter *painter)
|
||||
{
|
||||
if (m_points.isEmpty())
|
||||
initializePoints();
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QPalette pal = palette();
|
||||
painter->setPen(Qt::NoPen);
|
||||
|
||||
// Construct the path
|
||||
QPainterPath path;
|
||||
path.moveTo(m_points.at(0));
|
||||
|
||||
if (m_pathMode == LineMode) {
|
||||
for (int i=1; i<m_points.size(); ++i)
|
||||
path.lineTo(m_points.at(i));
|
||||
} else {
|
||||
int i=1;
|
||||
while (i + 2 < m_points.size()) {
|
||||
path.cubicTo(m_points.at(i), m_points.at(i+1), m_points.at(i+2));
|
||||
i += 3;
|
||||
}
|
||||
while (i < m_points.size()) {
|
||||
path.lineTo(m_points.at(i));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the path
|
||||
{
|
||||
QColor lg = Qt::red;
|
||||
|
||||
// The "custom" pen
|
||||
if (m_penStyle == Qt::NoPen) {
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(m_penWidth);
|
||||
stroker.setJoinStyle(m_joinStyle);
|
||||
stroker.setCapStyle(m_capStyle);
|
||||
|
||||
QList<qreal> dashes;
|
||||
qreal space = 4;
|
||||
dashes << 1 << space
|
||||
<< 3 << space
|
||||
<< 9 << space
|
||||
<< 27 << space
|
||||
<< 9 << space
|
||||
<< 3 << space;
|
||||
stroker.setDashPattern(dashes);
|
||||
QPainterPath stroke = stroker.createStroke(path);
|
||||
painter->fillPath(stroke, lg);
|
||||
|
||||
} else {
|
||||
QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
|
||||
painter->strokePath(path, pen);
|
||||
}
|
||||
}
|
||||
|
||||
if (1) {
|
||||
// Draw the control points
|
||||
painter->setPen(QColor(50, 100, 120, 200));
|
||||
painter->setBrush(QColor(200, 200, 210, 120));
|
||||
for (int i=0; i<m_points.size(); ++i) {
|
||||
QPointF pos = m_points.at(i);
|
||||
painter->drawEllipse(QRectF(pos.x() - m_pointSize,
|
||||
pos.y() - m_pointSize,
|
||||
m_pointSize*2, m_pointSize*2));
|
||||
}
|
||||
painter->setPen(QPen(Qt::lightGray, 0, Qt::SolidLine));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawPolyline(m_points);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::initializePoints()
|
||||
{
|
||||
const int count = 7;
|
||||
m_points.clear();
|
||||
m_vectors.clear();
|
||||
|
||||
QTransform m;
|
||||
qreal rot = 360.0 / count;
|
||||
QPointF center(width() / 2, height() / 2);
|
||||
QTransform vm;
|
||||
vm.shear(2, -1);
|
||||
vm.scale(3, 3);
|
||||
|
||||
for (int i=0; i<count; ++i) {
|
||||
m_vectors << QPointF(.1f, .25f) * (m * vm);
|
||||
m_points << QPointF(0, 100) * m + center;
|
||||
m.rotate(rot);
|
||||
}
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::updatePoints()
|
||||
{
|
||||
qreal pad = 10;
|
||||
qreal left = pad;
|
||||
qreal right = width() - pad;
|
||||
qreal top = pad;
|
||||
qreal bottom = height() - pad;
|
||||
|
||||
Q_ASSERT(m_points.size() == m_vectors.size());
|
||||
for (int i = 0; i < m_points.size(); ++i) {
|
||||
QPointF pos = m_points.at(i);
|
||||
QPointF vec = m_vectors.at(i);
|
||||
pos += vec;
|
||||
if (pos.x() < left || pos.x() > right) {
|
||||
vec.setX(-vec.x());
|
||||
pos.setX(pos.x() < left ? left : right);
|
||||
} if (pos.y() < top || pos.y() > bottom) {
|
||||
vec.setY(-vec.y());
|
||||
pos.setY(pos.y() < top ? top : bottom);
|
||||
}
|
||||
m_points[i] = pos;
|
||||
m_vectors[i] = vec;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
setDescriptionEnabled(false);
|
||||
m_activePoint = -1;
|
||||
qreal distance = -1;
|
||||
for (int i = 0; i < m_points.size(); ++i) {
|
||||
qreal d = QLineF(e->position().toPoint(), m_points.at(i)).length();
|
||||
if ((distance < 0 && d < 8 * m_pointSize) || d < distance) {
|
||||
distance = d;
|
||||
m_activePoint = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_activePoint != -1) {
|
||||
m_wasAnimated = m_timer.isActive();
|
||||
setAnimation(false);
|
||||
mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
// If we're not running in small screen mode, always assume we're dragging
|
||||
m_mouseDrag = !m_smallScreen;
|
||||
m_mousePress = e->position().toPoint();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
// If we've moved more then 25 pixels, assume user is dragging
|
||||
if (!m_mouseDrag && QPoint(m_mousePress - e->position().toPoint()).manhattanLength() > 25)
|
||||
m_mouseDrag = true;
|
||||
|
||||
if (m_mouseDrag && m_activePoint >= 0 && m_activePoint < m_points.size()) {
|
||||
m_points[m_activePoint] = e->position().toPoint();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
m_activePoint = -1;
|
||||
setAnimation(m_wasAnimated);
|
||||
|
||||
if (!m_mouseDrag && m_smallScreen)
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() == m_timer.timerId()) {
|
||||
updatePoints();
|
||||
} // else if (e->timerId() == m_fpsTimer.timerId()) {
|
||||
// emit frameRate(m_frameCount);
|
||||
// m_frameCount = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
bool PathStrokeRenderer::event(QEvent *e)
|
||||
{
|
||||
bool touchBegin = false;
|
||||
switch (e->type()) {
|
||||
case QEvent::TouchBegin:
|
||||
touchBegin = true;
|
||||
Q_FALLTHROUGH();
|
||||
case QEvent::TouchUpdate:
|
||||
{
|
||||
const QTouchEvent *const event = static_cast<const QTouchEvent*>(e);
|
||||
const auto points = event->points();
|
||||
for (const auto &point : points) {
|
||||
const int id = point.id();
|
||||
switch (point.state()) {
|
||||
case QEventPoint::Pressed:
|
||||
{
|
||||
// find the point, move it
|
||||
const auto mappedPoints = m_fingerPointMapping.values();
|
||||
QSet<int> activePoints = QSet<int>(mappedPoints.begin(), mappedPoints.end());
|
||||
int activePoint = -1;
|
||||
qreal distance = -1;
|
||||
const int pointsCount = m_points.size();
|
||||
for (int i=0; i<pointsCount; ++i) {
|
||||
if (activePoints.contains(i))
|
||||
continue;
|
||||
|
||||
qreal d = QLineF(point.position(), m_points.at(i)).length();
|
||||
if ((distance < 0 && d < 12 * m_pointSize) || d < distance) {
|
||||
distance = d;
|
||||
activePoint = i;
|
||||
}
|
||||
}
|
||||
if (activePoint != -1) {
|
||||
m_fingerPointMapping.insert(point.id(), activePoint);
|
||||
m_points[activePoint] = point.position();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEventPoint::Released:
|
||||
{
|
||||
// move the point and release
|
||||
QHash<int,int>::iterator it = m_fingerPointMapping.find(id);
|
||||
m_points[it.value()] = point.position();
|
||||
m_fingerPointMapping.erase(it);
|
||||
break;
|
||||
}
|
||||
case QEventPoint::Updated:
|
||||
{
|
||||
// move the point
|
||||
const int pointIdx = m_fingerPointMapping.value(id, -1);
|
||||
if (pointIdx >= 0)
|
||||
m_points[pointIdx] = point.position();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
e->ignore();
|
||||
return false;
|
||||
} else {
|
||||
if (touchBegin) {
|
||||
m_wasAnimated = m_timer.isActive();
|
||||
setAnimation(false);
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::TouchEnd:
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
e->ignore();
|
||||
return false;
|
||||
}
|
||||
m_fingerPointMapping.clear();
|
||||
setAnimation(m_wasAnimated);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::setAnimation(bool animation)
|
||||
{
|
||||
m_timer.stop();
|
||||
// m_fpsTimer.stop();
|
||||
|
||||
if (animation) {
|
||||
m_timer.start(25, this);
|
||||
// m_fpsTimer.start(1000, this);
|
||||
// m_frameCount = 0;
|
||||
}
|
||||
}
|
136
examples/widgets/painting/pathstroke/pathstroke.h
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PATHSTROKE_H
|
||||
#define PATHSTROKE_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
class PathStrokeRenderer : public ArthurFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool animation READ animation WRITE setAnimation)
|
||||
Q_PROPERTY(qreal penWidth READ realPenWidth WRITE setRealPenWidth)
|
||||
public:
|
||||
enum PathMode { CurveMode, LineMode };
|
||||
|
||||
explicit PathStrokeRenderer(QWidget *parent, bool smallScreen = false);
|
||||
|
||||
void paint(QPainter *) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void timerEvent(QTimerEvent *e) override;
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
QSize sizeHint() const override { return QSize(500, 500); }
|
||||
|
||||
bool animation() const { return m_timer.isActive(); }
|
||||
|
||||
qreal realPenWidth() const { return m_penWidth; }
|
||||
void setRealPenWidth(qreal penWidth) { m_penWidth = penWidth; update(); }
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
public slots:
|
||||
void setPenWidth(int penWidth) { m_penWidth = penWidth / 10.0; update(); }
|
||||
void setAnimation(bool animation);
|
||||
|
||||
void setFlatCap() { m_capStyle = Qt::FlatCap; update(); }
|
||||
void setSquareCap() { m_capStyle = Qt::SquareCap; update(); }
|
||||
void setRoundCap() { m_capStyle = Qt::RoundCap; update(); }
|
||||
|
||||
void setBevelJoin() { m_joinStyle = Qt::BevelJoin; update(); }
|
||||
void setMiterJoin() { m_joinStyle = Qt::MiterJoin; update(); }
|
||||
void setSvgMiterJoin() { m_joinStyle = Qt::SvgMiterJoin; update(); }
|
||||
void setRoundJoin() { m_joinStyle = Qt::RoundJoin; update(); }
|
||||
|
||||
void setCurveMode() { m_pathMode = CurveMode; update(); }
|
||||
void setLineMode() { m_pathMode = LineMode; update(); }
|
||||
|
||||
void setSolidLine() { m_penStyle = Qt::SolidLine; update(); }
|
||||
void setDashLine() { m_penStyle = Qt::DashLine; update(); }
|
||||
void setDotLine() { m_penStyle = Qt::DotLine; update(); }
|
||||
void setDashDotLine() { m_penStyle = Qt::DashDotLine; update(); }
|
||||
void setDashDotDotLine() { m_penStyle = Qt::DashDotDotLine; update(); }
|
||||
void setCustomDashLine() { m_penStyle = Qt::NoPen; update(); }
|
||||
|
||||
private:
|
||||
void initializePoints();
|
||||
void updatePoints();
|
||||
|
||||
QBasicTimer m_timer;
|
||||
|
||||
PathMode m_pathMode;
|
||||
|
||||
bool m_wasAnimated;
|
||||
|
||||
qreal m_penWidth;
|
||||
int m_pointCount;
|
||||
int m_pointSize;
|
||||
int m_activePoint;
|
||||
QList<QPointF> m_points;
|
||||
QList<QPointF> m_vectors;
|
||||
|
||||
Qt::PenJoinStyle m_joinStyle;
|
||||
Qt::PenCapStyle m_capStyle;
|
||||
|
||||
Qt::PenStyle m_penStyle;
|
||||
|
||||
bool m_smallScreen;
|
||||
QPoint m_mousePress;
|
||||
bool m_mouseDrag;
|
||||
|
||||
QHash<int, int> m_fingerPointMapping;
|
||||
};
|
||||
|
||||
class PathStrokeControls : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen);
|
||||
|
||||
signals:
|
||||
void okPressed();
|
||||
void quitPressed();
|
||||
|
||||
private:
|
||||
PathStrokeRenderer* m_renderer;
|
||||
|
||||
QGroupBox *m_capGroup;
|
||||
QGroupBox *m_joinGroup;
|
||||
QGroupBox *m_styleGroup;
|
||||
QGroupBox *m_pathModeGroup;
|
||||
|
||||
void createCommonControls(QWidget* parent);
|
||||
void layoutForDesktop();
|
||||
void layoutForSmallScreens();
|
||||
|
||||
private slots:
|
||||
void emitQuitSignal();
|
||||
void emitOkSignal();
|
||||
|
||||
};
|
||||
|
||||
class PathStrokeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PathStrokeWidget(bool smallScreen);
|
||||
void setStyle(QStyle *style);
|
||||
|
||||
private:
|
||||
PathStrokeRenderer *m_renderer;
|
||||
PathStrokeControls *m_controls;
|
||||
|
||||
private slots:
|
||||
void showControls();
|
||||
void hideControls();
|
||||
};
|
||||
|
||||
#endif // PATHSTROKE_H
|
20
examples/widgets/painting/pathstroke/pathstroke.html
Normal file
@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<center>
|
||||
<h2>Primitive Stroking</h2>
|
||||
</center>
|
||||
|
||||
<p>In this demo we show some of the various types of pens that can be
|
||||
used in Qt.</p>
|
||||
|
||||
<p>Qt defines cap styles for how the end points are treated and join
|
||||
styles for how path segments are joined together. A standard set of
|
||||
predefined dash patterns are also included that can be used with
|
||||
<code>QPen</code>.</p>
|
||||
|
||||
<p>In addition to the predefined patterns available in
|
||||
<code>QPen</code> we also demonstrate direct use of the
|
||||
<code>QPainterPathStroker</code> class which can be used to define
|
||||
custom dash patterns. You can see this by enabling the
|
||||
<i>Custom Pattern</i> option.</p>
|
||||
|
||||
</html>
|
15
examples/widgets/painting/pathstroke/pathstroke.pro
Normal file
@ -0,0 +1,15 @@
|
||||
SOURCES += main.cpp pathstroke.cpp
|
||||
HEADERS += pathstroke.h
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += pathstroke.qrc
|
||||
|
||||
QT += widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/pathstroke
|
||||
INSTALLS += target
|
||||
|
6
examples/widgets/painting/pathstroke/pathstroke.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/pathstroke">
|
||||
<file>pathstroke.cpp</file>
|
||||
<file>pathstroke.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
29
examples/widgets/painting/shared/CMakeLists.txt
Normal file
@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_library(painting_shared OBJECT)
|
||||
add_library(painting_shared::painting_shared ALIAS painting_shared)
|
||||
qt6_wrap_cpp(moc_files arthurwidgets.h hoverpoints.h) # no automoc for OBJECT libs:-/
|
||||
target_sources(painting_shared PRIVATE
|
||||
arthurstyle.cpp arthurstyle.h
|
||||
arthurwidgets.cpp arthurwidgets.h
|
||||
hoverpoints.cpp hoverpoints.h
|
||||
${moc_files}
|
||||
)
|
||||
|
||||
set_target_properties(painting_shared PROPERTIES UNITY_BUILD OFF)
|
||||
|
||||
target_link_libraries(painting_shared PUBLIC Qt6::Widgets)
|
||||
target_include_directories(painting_shared PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
## Scopes:
|
||||
#####################################################################
|
||||
|
||||
if (TARGET Qt6::OpenGL OR QT_FEATURE_opengles2)
|
||||
target_compile_definitions(painting_shared PRIVATE QT_OPENGL_SUPPORT)
|
||||
target_link_libraries(painting_shared PUBLIC
|
||||
Qt6::OpenGL
|
||||
)
|
||||
qt6_wrap_cpp(moc_files_gl fbopaintdevice.h) # no automoc for OBJECT libs
|
||||
target_sources(painting_shared PRIVATE fbopaintdevice.cpp fbopaintdevice.h ${moc_files_gl})
|
||||
endif()
|
452
examples/widgets/painting/shared/arthurstyle.cpp
Normal file
@ -0,0 +1,452 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "arthurstyle.h"
|
||||
#include "arthurwidgets.h"
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPixmapCache>
|
||||
#include <QRadioButton>
|
||||
#include <QString>
|
||||
#include <QStyleOption>
|
||||
#include <QtDebug>
|
||||
|
||||
QPixmap cached(const QString &img)
|
||||
{
|
||||
QPixmap pm;
|
||||
if (QPixmapCache::find(img, &pm))
|
||||
return pm;
|
||||
|
||||
pm = QPixmap::fromImage(QImage(img), Qt::OrderedDither | Qt::OrderedAlphaDither);
|
||||
if (pm.isNull())
|
||||
return QPixmap();
|
||||
|
||||
QPixmapCache::insert(img, pm);
|
||||
return pm;
|
||||
}
|
||||
|
||||
|
||||
ArthurStyle::ArthurStyle()
|
||||
: QCommonStyle()
|
||||
{
|
||||
Q_INIT_RESOURCE(shared);
|
||||
}
|
||||
|
||||
|
||||
void ArthurStyle::drawHoverRect(QPainter *painter, const QRect &r) const
|
||||
{
|
||||
qreal h = r.height();
|
||||
qreal h2 = r.height() / qreal(2);
|
||||
QPainterPath path;
|
||||
path.addRect(r.x() + h2, r.y() + 0, r.width() - h2 * 2, r.height());
|
||||
path.addEllipse(r.x(), r.y(), h, h);
|
||||
path.addEllipse(r.x() + r.width() - h, r.y(), h, h);
|
||||
path.setFillRule(Qt::WindingFill);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(191, 215, 191));
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
painter->drawPath(path);
|
||||
}
|
||||
|
||||
|
||||
void ArthurStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
|
||||
QPainter *painter, const QWidget *widget) const
|
||||
{
|
||||
|
||||
Q_ASSERT(option);
|
||||
switch (element) {
|
||||
case PE_FrameFocusRect:
|
||||
break;
|
||||
|
||||
case PE_IndicatorRadioButton:
|
||||
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
|
||||
bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
|
||||
painter->save();
|
||||
QPixmap radio;
|
||||
if (hover)
|
||||
drawHoverRect(painter, widget->rect());
|
||||
|
||||
if (button->state & State_Sunken)
|
||||
radio = cached(":res/images/radiobutton-on.png");
|
||||
else if (button->state & State_On)
|
||||
radio = cached(":res/images/radiobutton_on.png");
|
||||
else
|
||||
radio = cached(":res/images/radiobutton_off.png");
|
||||
painter->drawPixmap(button->rect.topLeft(), radio);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
break;
|
||||
|
||||
case PE_PanelButtonCommand:
|
||||
if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
|
||||
bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver);
|
||||
|
||||
painter->save();
|
||||
const QPushButton *pushButton = qobject_cast<const QPushButton *>(widget);
|
||||
Q_ASSERT(pushButton);
|
||||
QWidget *parent = pushButton->parentWidget();
|
||||
if (parent && qobject_cast<QGroupBox *>(parent)) {
|
||||
QLinearGradient lg(0, 0, 0, parent->height());
|
||||
lg.setColorAt(0, QColor(224,224,224));
|
||||
lg.setColorAt(1, QColor(255,255,255));
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(lg);
|
||||
painter->setBrushOrigin(-widget->mapToParent(QPoint(0,0)));
|
||||
painter->drawRect(button->rect);
|
||||
painter->setBrushOrigin(0,0);
|
||||
}
|
||||
|
||||
bool down = (button->state & State_Sunken) || (button->state & State_On);
|
||||
|
||||
QPixmap left, right, mid;
|
||||
if (down) {
|
||||
left = cached(":res/images/button_pressed_cap_left.png");
|
||||
right = cached(":res/images/button_pressed_cap_right.png");
|
||||
mid = cached(":res/images/button_pressed_stretch.png");
|
||||
} else {
|
||||
left = cached(":res/images/button_normal_cap_left.png");
|
||||
right = cached(":res/images/button_normal_cap_right.png");
|
||||
mid = cached(":res/images/button_normal_stretch.png");
|
||||
}
|
||||
painter->drawPixmap(button->rect.topLeft(), left);
|
||||
painter->drawTiledPixmap(QRect(button->rect.x() + left.width(),
|
||||
button->rect.y(),
|
||||
button->rect.width() - left.width() - right.width(),
|
||||
left.height()),
|
||||
mid);
|
||||
painter->drawPixmap(button->rect.x() + button->rect.width() - right.width(),
|
||||
button->rect.y(),
|
||||
right);
|
||||
if (hover)
|
||||
painter->fillRect(widget->rect().adjusted(3,5,-3,-5), QColor(31,127,31,63));
|
||||
painter->restore();
|
||||
}
|
||||
break;
|
||||
|
||||
case PE_FrameGroupBox:
|
||||
if (const QStyleOptionFrame *group
|
||||
= qstyleoption_cast<const QStyleOptionFrame *>(option)) {
|
||||
const QRect &r = group->rect;
|
||||
|
||||
painter->save();
|
||||
int radius = 14;
|
||||
int radius2 = radius*2;
|
||||
QPainterPath clipPath;
|
||||
clipPath.moveTo(radius, 0);
|
||||
clipPath.arcTo(r.right() - radius2, 0, radius2, radius2, 90, -90);
|
||||
clipPath.arcTo(r.right() - radius2, r.bottom() - radius2, radius2, radius2, 0, -90);
|
||||
clipPath.arcTo(r.left(), r.bottom() - radius2, radius2, radius2, 270, -90);
|
||||
clipPath.arcTo(r.left(), r.top(), radius2, radius2, 180, -90);
|
||||
painter->setClipPath(clipPath);
|
||||
QPixmap titleStretch = cached(":res/images/title_stretch.png");
|
||||
QPixmap topLeft = cached(":res/images/groupframe_topleft.png");
|
||||
QPixmap topRight = cached(":res/images/groupframe_topright.png");
|
||||
QPixmap bottomLeft = cached(":res/images/groupframe_bottom_left.png");
|
||||
QPixmap bottomRight = cached(":res/images/groupframe_bottom_right.png");
|
||||
QPixmap leftStretch = cached(":res/images/groupframe_left_stretch.png");
|
||||
QPixmap topStretch = cached(":res/images/groupframe_top_stretch.png");
|
||||
QPixmap rightStretch = cached(":res/images/groupframe_right_stretch.png");
|
||||
QPixmap bottomStretch = cached(":res/images/groupframe_bottom_stretch.png");
|
||||
QLinearGradient lg(0, 0, 0, r.height());
|
||||
lg.setColorAt(0, QColor(224,224,224));
|
||||
lg.setColorAt(1, QColor(255,255,255));
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(lg);
|
||||
painter->drawRect(r.adjusted(0, titleStretch.height()/2, 0, 0));
|
||||
painter->setClipping(false);
|
||||
|
||||
int topFrameOffset = titleStretch.height()/2 - 2;
|
||||
painter->drawPixmap(r.topLeft() + QPoint(0, topFrameOffset), topLeft);
|
||||
painter->drawPixmap(r.topRight() - QPoint(topRight.width()-1, 0)
|
||||
+ QPoint(0, topFrameOffset), topRight);
|
||||
painter->drawPixmap(r.bottomLeft() - QPoint(0, bottomLeft.height()-1), bottomLeft);
|
||||
painter->drawPixmap(r.bottomRight() - QPoint(bottomRight.width()-1,
|
||||
bottomRight.height()-1), bottomRight);
|
||||
|
||||
QRect left = r;
|
||||
left.setY(r.y() + topLeft.height() + topFrameOffset);
|
||||
left.setWidth(leftStretch.width());
|
||||
left.setHeight(r.height() - topLeft.height() - bottomLeft.height() - topFrameOffset);
|
||||
painter->drawTiledPixmap(left, leftStretch);
|
||||
|
||||
QRect top = r;
|
||||
top.setX(r.x() + topLeft.width());
|
||||
top.setY(r.y() + topFrameOffset);
|
||||
top.setWidth(r.width() - topLeft.width() - topRight.width());
|
||||
top.setHeight(topLeft.height());
|
||||
painter->drawTiledPixmap(top, topStretch);
|
||||
|
||||
QRect right = r;
|
||||
right.setX(r.right() - rightStretch.width()+1);
|
||||
right.setY(r.y() + topRight.height() + topFrameOffset);
|
||||
right.setWidth(rightStretch.width());
|
||||
right.setHeight(r.height() - topRight.height()
|
||||
- bottomRight.height() - topFrameOffset);
|
||||
painter->drawTiledPixmap(right, rightStretch);
|
||||
|
||||
QRect bottom = r;
|
||||
bottom.setX(r.x() + bottomLeft.width());
|
||||
bottom.setY(r.bottom() - bottomStretch.height()+1);
|
||||
bottom.setWidth(r.width() - bottomLeft.width() - bottomRight.width());
|
||||
bottom.setHeight(bottomLeft.height());
|
||||
painter->drawTiledPixmap(bottom, bottomStretch);
|
||||
painter->restore();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
QCommonStyle::drawPrimitive(element, option, painter, widget);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ArthurStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
|
||||
QPainter *painter, const QWidget *widget) const
|
||||
{
|
||||
switch (control) {
|
||||
case CC_Slider:
|
||||
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
|
||||
QRect groove = subControlRect(CC_Slider, option, SC_SliderGroove, widget);
|
||||
QRect handle = subControlRect(CC_Slider, option, SC_SliderHandle, widget);
|
||||
|
||||
painter->save();
|
||||
|
||||
bool hover = (slider->state & State_Enabled) && (slider->state & State_MouseOver);
|
||||
if (hover) {
|
||||
QRect moderated = widget->rect().adjusted(0, 4, 0, -4);
|
||||
drawHoverRect(painter, moderated);
|
||||
}
|
||||
|
||||
if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
|
||||
QPixmap grv = cached(":res/images/slider_bar.png");
|
||||
painter->drawPixmap(QRect(groove.x() + 5, groove.y(),
|
||||
groove.width() - 10, grv.height()),
|
||||
grv);
|
||||
}
|
||||
if ((option->subControls & SC_SliderHandle) && handle.isValid()) {
|
||||
QPixmap hndl = cached(":res/images/slider_thumb_on.png");
|
||||
painter->drawPixmap(handle.topLeft(), hndl);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
break;
|
||||
case CC_GroupBox:
|
||||
if (const QStyleOptionGroupBox *groupBox
|
||||
= qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
|
||||
QStyleOptionGroupBox groupBoxCopy(*groupBox);
|
||||
groupBoxCopy.subControls &= ~SC_GroupBoxLabel;
|
||||
QCommonStyle::drawComplexControl(control, &groupBoxCopy, painter, widget);
|
||||
|
||||
if (groupBox->subControls & SC_GroupBoxLabel) {
|
||||
const QRect &r = groupBox->rect;
|
||||
QPixmap titleLeft = cached(":res/images/title_cap_left.png");
|
||||
QPixmap titleRight = cached(":res/images/title_cap_right.png");
|
||||
QPixmap titleStretch = cached(":res/images/title_stretch.png");
|
||||
int txt_width = groupBox->fontMetrics.horizontalAdvance(groupBox->text) + 20;
|
||||
painter->drawPixmap(r.center().x() - txt_width/2, 0, titleLeft);
|
||||
QRect tileRect = subControlRect(control, groupBox, SC_GroupBoxLabel, widget);
|
||||
painter->drawTiledPixmap(tileRect, titleStretch);
|
||||
painter->drawPixmap(tileRect.x() + tileRect.width(), 0, titleRight);
|
||||
int opacity = 31;
|
||||
painter->setPen(QColor(0, 0, 0, opacity));
|
||||
painter->drawText(tileRect.translated(0, 1),
|
||||
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
|
||||
painter->drawText(tileRect.translated(2, 1),
|
||||
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
|
||||
painter->setPen(QColor(0, 0, 0, opacity * 2));
|
||||
painter->drawText(tileRect.translated(1, 1),
|
||||
Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
|
||||
painter->setPen(Qt::white);
|
||||
painter->drawText(tileRect, Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QCommonStyle::drawComplexControl(control, option, painter, widget);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void ArthurStyle::drawControl(QStyle::ControlElement element, const QStyleOption *option,
|
||||
QPainter *painter, const QWidget *widget) const
|
||||
{
|
||||
switch (element) {
|
||||
case CE_RadioButtonLabel:
|
||||
if (const QStyleOptionButton *button
|
||||
= qstyleoption_cast<const QStyleOptionButton *>(option)) {
|
||||
|
||||
if (button->text.isEmpty()) {
|
||||
QCommonStyle::drawControl(element, option, painter, widget);
|
||||
} else {
|
||||
painter->save();
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawText(button->rect, Qt::AlignVCenter, button->text);
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CE_PushButtonLabel:
|
||||
if (const QStyleOptionButton *button
|
||||
= qstyleoption_cast<const QStyleOptionButton *>(option)) {
|
||||
|
||||
if (button->text.isEmpty()) {
|
||||
QCommonStyle::drawControl(element, option, painter, widget);
|
||||
} else {
|
||||
painter->save();
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawText(button->rect, Qt::AlignVCenter | Qt::AlignHCenter, button->text);
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
QCommonStyle::drawControl(element, option, painter, widget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QRect ArthurStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
|
||||
SubControl subControl, const QWidget *widget) const
|
||||
{
|
||||
QRect rect;
|
||||
|
||||
switch (control) {
|
||||
default:
|
||||
rect = QCommonStyle::subControlRect(control, option, subControl, widget);
|
||||
break;
|
||||
case CC_GroupBox:
|
||||
if (const QStyleOptionGroupBox *group
|
||||
= qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
|
||||
switch (subControl) {
|
||||
default:
|
||||
rect = QCommonStyle::subControlRect(control, option, subControl, widget);
|
||||
break;
|
||||
case SC_GroupBoxContents:
|
||||
rect = QCommonStyle::subControlRect(control, option, subControl, widget);
|
||||
rect.adjust(0, -8, 0, 0);
|
||||
break;
|
||||
case SC_GroupBoxFrame:
|
||||
rect = group->rect;
|
||||
break;
|
||||
case SC_GroupBoxLabel:
|
||||
QPixmap titleLeft = cached(":res/images/title_cap_left.png");
|
||||
QPixmap titleRight = cached(":res/images/title_cap_right.png");
|
||||
QPixmap titleStretch = cached(":res/images/title_stretch.png");
|
||||
int txt_width = group->fontMetrics.horizontalAdvance(group->text) + 20;
|
||||
rect = QRect(group->rect.center().x() - txt_width/2 + titleLeft.width(), 0,
|
||||
txt_width - titleLeft.width() - titleRight.width(),
|
||||
titleStretch.height());
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (control == CC_Slider && subControl == SC_SliderHandle) {
|
||||
rect.setWidth(13);
|
||||
rect.setHeight(27);
|
||||
} else if (control == CC_Slider && subControl == SC_SliderGroove) {
|
||||
rect.setHeight(9);
|
||||
rect.moveTop(27/2 - 9/2);
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
QSize ArthurStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
|
||||
const QSize &size, const QWidget *widget) const
|
||||
{
|
||||
QSize newSize = QCommonStyle::sizeFromContents(type, option, size, widget);
|
||||
|
||||
|
||||
switch (type) {
|
||||
case CT_RadioButton:
|
||||
newSize += QSize(20, 0);
|
||||
break;
|
||||
|
||||
case CT_PushButton:
|
||||
newSize.setHeight(26);
|
||||
break;
|
||||
|
||||
case CT_Slider:
|
||||
newSize.setHeight(27);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
int ArthurStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QWidget *widget) const
|
||||
{
|
||||
if (pm == PM_SliderLength)
|
||||
return 13;
|
||||
return QCommonStyle::pixelMetric(pm, opt, widget);
|
||||
}
|
||||
|
||||
void ArthurStyle::polish(QWidget *widget)
|
||||
{
|
||||
if (widget->layout() && qobject_cast<QGroupBox *>(widget)) {
|
||||
if (!widget->findChild<QGroupBox *>()) {
|
||||
widget->layout()->setSpacing(0);
|
||||
widget->layout()->setContentsMargins(12, 12, 12, 12);
|
||||
} else {
|
||||
widget->layout()->setContentsMargins(13, 13, 13, 13);
|
||||
}
|
||||
}
|
||||
|
||||
if (qobject_cast<QPushButton *>(widget)
|
||||
|| qobject_cast<QRadioButton *>(widget)
|
||||
|| qobject_cast<QSlider *>(widget)) {
|
||||
widget->setAttribute(Qt::WA_Hover);
|
||||
}
|
||||
|
||||
QPalette pal = widget->palette();
|
||||
if (widget->isWindow()) {
|
||||
pal.setColor(QPalette::Window, QColor(241, 241, 241));
|
||||
widget->setPalette(pal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ArthurStyle::unpolish(QWidget *widget)
|
||||
{
|
||||
if (qobject_cast<QPushButton *>(widget)
|
||||
|| qobject_cast<QRadioButton *>(widget)
|
||||
|| qobject_cast<QSlider *>(widget)) {
|
||||
widget->setAttribute(Qt::WA_Hover, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ArthurStyle::polish(QPalette &palette)
|
||||
{
|
||||
palette.setColor(QPalette::Window, QColor(241, 241, 241));
|
||||
}
|
||||
|
||||
QRect ArthurStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
|
||||
{
|
||||
QRect r;
|
||||
switch(element) {
|
||||
case SE_RadioButtonClickRect:
|
||||
r = widget->rect();
|
||||
break;
|
||||
case SE_RadioButtonContents:
|
||||
r = widget->rect().adjusted(20, 0, 0, 0);
|
||||
break;
|
||||
default:
|
||||
r = QCommonStyle::subElementRect(element, option, widget);
|
||||
break;
|
||||
}
|
||||
|
||||
if (qobject_cast<const QRadioButton*>(widget))
|
||||
r = r.adjusted(5, 0, -5, 0);
|
||||
|
||||
return r;
|
||||
}
|
38
examples/widgets/painting/shared/arthurstyle.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef ARTHURSTYLE_H
|
||||
#define ARTHURSTYLE_H
|
||||
|
||||
#include <QCommonStyle>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
class ArthurStyle : public QCommonStyle
|
||||
{
|
||||
public:
|
||||
ArthurStyle();
|
||||
|
||||
void drawHoverRect(QPainter *painter, const QRect &rect) const;
|
||||
|
||||
void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
|
||||
QPainter *painter, const QWidget *widget = nullptr) const override;
|
||||
void drawControl(ControlElement element, const QStyleOption *option,
|
||||
QPainter *painter, const QWidget *widget) const override;
|
||||
void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
|
||||
QPainter *painter, const QWidget *widget) const override;
|
||||
QSize sizeFromContents(ContentsType type, const QStyleOption *option,
|
||||
const QSize &size, const QWidget *widget) const override;
|
||||
|
||||
QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override;
|
||||
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
|
||||
SubControl sc, const QWidget *widget) const override;
|
||||
|
||||
int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const override;
|
||||
|
||||
void polish(QPalette &palette) override;
|
||||
void polish(QWidget *widget) override;
|
||||
void unpolish(QWidget *widget) override;
|
||||
};
|
||||
|
||||
#endif
|
330
examples/widgets/painting/shared/arthurwidgets.cpp
Normal file
@ -0,0 +1,330 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPixmapCache>
|
||||
#include <QtEvents>
|
||||
#include <QTextDocument>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QFile>
|
||||
#include <QTextBrowser>
|
||||
#include <QBoxLayout>
|
||||
#include <QRegularExpression>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLContext>
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QtOpenGL/QOpenGLPaintDevice>
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#endif
|
||||
|
||||
extern QPixmap cached(const QString &img);
|
||||
|
||||
ArthurFrame::ArthurFrame(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_tile(QPixmap(128, 128))
|
||||
{
|
||||
m_tile.fill(Qt::white);
|
||||
QPainter pt(&m_tile);
|
||||
QColor color(230, 230, 230);
|
||||
pt.fillRect(0, 0, 64, 64, color);
|
||||
pt.fillRect(64, 64, 64, 64, color);
|
||||
pt.end();
|
||||
}
|
||||
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
void ArthurFrame::enableOpenGL(bool use_opengl)
|
||||
{
|
||||
if (m_use_opengl == use_opengl)
|
||||
return;
|
||||
|
||||
m_use_opengl = use_opengl;
|
||||
|
||||
if (!m_glWindow && use_opengl) {
|
||||
createGlWindow();
|
||||
QApplication::postEvent(this, new QResizeEvent(size(), size()));
|
||||
}
|
||||
|
||||
if (use_opengl) {
|
||||
m_glWidget->show();
|
||||
} else {
|
||||
if (m_glWidget)
|
||||
m_glWidget->hide();
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void ArthurFrame::createGlWindow()
|
||||
{
|
||||
Q_ASSERT(m_use_opengl);
|
||||
|
||||
m_glWindow = new QOpenGLWindow();
|
||||
QSurfaceFormat f = QSurfaceFormat::defaultFormat();
|
||||
f.setSamples(4);
|
||||
f.setAlphaBufferSize(8);
|
||||
f.setStencilBufferSize(8);
|
||||
m_glWindow->setFormat(f);
|
||||
m_glWindow->setFlags(Qt::WindowTransparentForInput);
|
||||
m_glWindow->resize(width(), height());
|
||||
m_glWidget = QWidget::createWindowContainer(m_glWindow, this);
|
||||
// create() must be called after createWindowContainer() otherwise
|
||||
// an incorrect offsetting of the position will occur.
|
||||
m_glWindow->create();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void ArthurFrame::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
static QImage *static_image = nullptr;
|
||||
|
||||
QPainter painter;
|
||||
|
||||
if (preferImage()
|
||||
#if QT_CONFIG(opengl)
|
||||
&& !m_use_opengl
|
||||
#endif
|
||||
) {
|
||||
if (!static_image || static_image->size() != size()) {
|
||||
delete static_image;
|
||||
static_image = new QImage(size(), QImage::Format_RGB32);
|
||||
}
|
||||
painter.begin(static_image);
|
||||
|
||||
int o = 10;
|
||||
|
||||
QBrush bg = palette().brush(QPalette::Window);
|
||||
painter.fillRect(0, 0, o, o, bg);
|
||||
painter.fillRect(width() - o, 0, o, o, bg);
|
||||
painter.fillRect(0, height() - o, o, o, bg);
|
||||
painter.fillRect(width() - o, height() - o, o, o, bg);
|
||||
} else {
|
||||
#if QT_CONFIG(opengl)
|
||||
if (m_use_opengl && m_glWindow->isValid()) {
|
||||
m_glWindow->makeCurrent();
|
||||
|
||||
painter.begin(m_glWindow);
|
||||
painter.fillRect(QRectF(0, 0, m_glWindow->width(), m_glWindow->height()), palette().color(backgroundRole()));
|
||||
} else {
|
||||
painter.begin(this);
|
||||
}
|
||||
#else
|
||||
painter.begin(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
painter.setClipRect(e->rect());
|
||||
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QPainterPath clipPath;
|
||||
|
||||
QRect r = rect();
|
||||
qreal left = r.x() + 1;
|
||||
qreal top = r.y() + 1;
|
||||
qreal right = r.right();
|
||||
qreal bottom = r.bottom();
|
||||
qreal radius2 = 8 * 2;
|
||||
|
||||
clipPath.moveTo(right - radius2, top);
|
||||
clipPath.arcTo(right - radius2, top, radius2, radius2, 90, -90);
|
||||
clipPath.arcTo(right - radius2, bottom - radius2, radius2, radius2, 0, -90);
|
||||
clipPath.arcTo(left, bottom - radius2, radius2, radius2, 270, -90);
|
||||
clipPath.arcTo(left, top, radius2, radius2, 180, -90);
|
||||
clipPath.closeSubpath();
|
||||
|
||||
painter.save();
|
||||
painter.setClipPath(clipPath, Qt::IntersectClip);
|
||||
|
||||
painter.drawTiledPixmap(rect(), m_tile);
|
||||
|
||||
// client painting
|
||||
|
||||
paint(&painter);
|
||||
|
||||
painter.restore();
|
||||
|
||||
painter.save();
|
||||
if (m_showDoc)
|
||||
paintDescription(&painter);
|
||||
painter.restore();
|
||||
|
||||
int level = 180;
|
||||
painter.setPen(QPen(QColor(level, level, level), 2));
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.drawPath(clipPath);
|
||||
|
||||
if (preferImage()
|
||||
#if QT_CONFIG(opengl)
|
||||
&& !m_use_opengl
|
||||
#endif
|
||||
) {
|
||||
painter.end();
|
||||
painter.begin(this);
|
||||
painter.drawImage(e->rect(), *static_image, e->rect());
|
||||
}
|
||||
#if QT_CONFIG(opengl)
|
||||
if (m_use_opengl)
|
||||
m_glWindow->update();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ArthurFrame::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
#if QT_CONFIG(opengl)
|
||||
if (m_glWidget)
|
||||
m_glWidget->setGeometry(0, 0, e->size().width(), e->size().height());
|
||||
#endif
|
||||
QWidget::resizeEvent(e);
|
||||
}
|
||||
|
||||
void ArthurFrame::setDescriptionEnabled(bool enabled)
|
||||
{
|
||||
if (m_showDoc != enabled) {
|
||||
m_showDoc = enabled;
|
||||
emit descriptionEnabledChanged(m_showDoc);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void ArthurFrame::loadDescription(const QString &fileName)
|
||||
{
|
||||
QFile textFile(fileName);
|
||||
QString text;
|
||||
if (!textFile.open(QFile::ReadOnly))
|
||||
text = QString("Unable to load resource file: '%1'").arg(fileName);
|
||||
else
|
||||
text = textFile.readAll();
|
||||
setDescription(text);
|
||||
}
|
||||
|
||||
|
||||
void ArthurFrame::setDescription(const QString &text)
|
||||
{
|
||||
m_document = new QTextDocument(this);
|
||||
m_document->setHtml(text);
|
||||
}
|
||||
|
||||
void ArthurFrame::paintDescription(QPainter *painter)
|
||||
{
|
||||
if (!m_document)
|
||||
return;
|
||||
|
||||
int pageWidth = qMax(width() - 100, 100);
|
||||
int pageHeight = qMax(height() - 100, 100);
|
||||
if (pageWidth != m_document->pageSize().width())
|
||||
m_document->setPageSize(QSize(pageWidth, pageHeight));
|
||||
|
||||
QRect textRect(width() / 2 - pageWidth / 2,
|
||||
height() / 2 - pageHeight / 2,
|
||||
pageWidth,
|
||||
pageHeight);
|
||||
int pad = 10;
|
||||
QRect clearRect = textRect.adjusted(-pad, -pad, pad, pad);
|
||||
painter->setPen(Qt::NoPen);
|
||||
painter->setBrush(QColor(0, 0, 0, 63));
|
||||
int shade = 10;
|
||||
painter->drawRect(clearRect.x() + clearRect.width() + 1,
|
||||
clearRect.y() + shade,
|
||||
shade,
|
||||
clearRect.height() + 1);
|
||||
painter->drawRect(clearRect.x() + shade,
|
||||
clearRect.y() + clearRect.height() + 1,
|
||||
clearRect.width() - shade + 1,
|
||||
shade);
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||
painter->setBrush(QColor(255, 255, 255, 220));
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawRect(clearRect);
|
||||
|
||||
painter->setClipRegion(textRect, Qt::IntersectClip);
|
||||
painter->translate(textRect.topLeft());
|
||||
|
||||
QAbstractTextDocumentLayout::PaintContext ctx;
|
||||
|
||||
QLinearGradient g(0, 0, 0, textRect.height());
|
||||
g.setColorAt(0, Qt::black);
|
||||
g.setColorAt(0.9, Qt::black);
|
||||
g.setColorAt(1, Qt::transparent);
|
||||
|
||||
QPalette pal = palette();
|
||||
pal.setBrush(QPalette::Text, g);
|
||||
|
||||
ctx.palette = pal;
|
||||
ctx.clip = QRect(0, 0, textRect.width(), textRect.height());
|
||||
m_document->documentLayout()->draw(painter, ctx);
|
||||
}
|
||||
|
||||
void ArthurFrame::loadSourceFile(const QString &sourceFile)
|
||||
{
|
||||
m_sourceFileName = sourceFile;
|
||||
}
|
||||
|
||||
void ArthurFrame::showSource()
|
||||
{
|
||||
// Check for existing source
|
||||
if (findChild<QTextBrowser *>())
|
||||
return;
|
||||
|
||||
QString contents;
|
||||
if (m_sourceFileName.isEmpty()) {
|
||||
contents = tr("No source for widget: '%1'").arg(objectName());
|
||||
} else {
|
||||
QFile f(m_sourceFileName);
|
||||
if (!f.open(QFile::ReadOnly))
|
||||
contents = tr("Could not open file: '%1'").arg(m_sourceFileName);
|
||||
else
|
||||
contents = QString::fromUtf8(f.readAll());
|
||||
}
|
||||
|
||||
contents.replace(QLatin1Char('&'), QStringLiteral("&"));
|
||||
contents.replace(QLatin1Char('<'), QStringLiteral("<"));
|
||||
contents.replace(QLatin1Char('>'), QStringLiteral(">"));
|
||||
|
||||
static const QString keywords[] = {
|
||||
QStringLiteral("for "), QStringLiteral("if "),
|
||||
QStringLiteral("switch "), QStringLiteral(" int "),
|
||||
QStringLiteral("#include "), QStringLiteral("const"),
|
||||
QStringLiteral("void "), QStringLiteral("uint "),
|
||||
QStringLiteral("case "), QStringLiteral("double "),
|
||||
QStringLiteral("#define "), QStringLiteral("static"),
|
||||
QStringLiteral("new"), QStringLiteral("this")
|
||||
};
|
||||
|
||||
for (const QString &keyword : keywords)
|
||||
contents.replace(keyword, QLatin1String("<font color=olive>") + keyword + QLatin1String("</font>"));
|
||||
contents.replace(QStringLiteral("(int "), QStringLiteral("(<font color=olive><b>int </b></font>"));
|
||||
|
||||
static const QString ppKeywords[] = {
|
||||
QStringLiteral("#ifdef"), QStringLiteral("#ifndef"),
|
||||
QStringLiteral("#if"), QStringLiteral("#endif"),
|
||||
QStringLiteral("#else")
|
||||
};
|
||||
|
||||
for (const QString &keyword : ppKeywords)
|
||||
contents.replace(keyword, QLatin1String("<font color=navy>") + keyword + QLatin1String("</font>"));
|
||||
|
||||
contents.replace(QRegularExpression("(\\d\\d?)"), QLatin1String("<font color=navy>\\1</font>"));
|
||||
|
||||
QRegularExpression commentRe("(//.+?)\\n");
|
||||
contents.replace(commentRe, QLatin1String("<font color=red>\\1</font>\n"));
|
||||
|
||||
QRegularExpression stringLiteralRe("(\".+?\")");
|
||||
contents.replace(stringLiteralRe, QLatin1String("<font color=green>\\1</font>"));
|
||||
|
||||
const QString html = QStringLiteral("<html><pre>") + contents + QStringLiteral("</pre></html>");
|
||||
|
||||
QTextBrowser *sourceViewer = new QTextBrowser;
|
||||
sourceViewer->setWindowTitle(tr("Source: %1").arg(QStringView{ m_sourceFileName }.mid(5)));
|
||||
sourceViewer->setParent(this, Qt::Dialog);
|
||||
sourceViewer->setAttribute(Qt::WA_DeleteOnClose);
|
||||
sourceViewer->setLineWrapMode(QTextEdit::NoWrap);
|
||||
sourceViewer->setHtml(html);
|
||||
sourceViewer->resize(600, 600);
|
||||
sourceViewer->show();
|
||||
}
|
69
examples/widgets/painting/shared/arthurwidgets.h
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef ARTHURWIDGETS_H
|
||||
#define ARTHURWIDGETS_H
|
||||
|
||||
#include "arthurstyle.h"
|
||||
#include <QBitmap>
|
||||
#include <QPushButton>
|
||||
#include <QGroupBox>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QOpenGLWindow)
|
||||
QT_FORWARD_DECLARE_CLASS(QTextDocument)
|
||||
QT_FORWARD_DECLARE_CLASS(QTextEdit)
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
|
||||
class ArthurFrame : public QWidget
|
||||
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ArthurFrame(QWidget *parent);
|
||||
virtual void paint(QPainter *) {}
|
||||
|
||||
void paintDescription(QPainter *p);
|
||||
|
||||
void loadDescription(const QString &filename);
|
||||
void setDescription(const QString &htmlDesc);
|
||||
|
||||
void loadSourceFile(const QString &fileName);
|
||||
|
||||
bool preferImage() const { return m_preferImage; }
|
||||
#if QT_CONFIG(opengl)
|
||||
QOpenGLWindow *glWindow() const { return m_glWindow; }
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void setPreferImage(bool pi) { m_preferImage = pi; }
|
||||
void setDescriptionEnabled(bool enabled);
|
||||
void showSource();
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
void enableOpenGL(bool use_opengl);
|
||||
bool usesOpenGL() { return m_use_opengl; }
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void descriptionEnabledChanged(bool);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *) override;
|
||||
void resizeEvent(QResizeEvent *) override;
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
virtual void createGlWindow();
|
||||
QOpenGLWindow *m_glWindow = nullptr;
|
||||
QWidget *m_glWidget = nullptr;
|
||||
bool m_use_opengl = false;
|
||||
#endif
|
||||
QPixmap m_tile;
|
||||
|
||||
bool m_showDoc = false;
|
||||
bool m_preferImage = false;
|
||||
QTextDocument *m_document = nullptr;;
|
||||
|
||||
QString m_sourceFileName;
|
||||
};
|
||||
|
||||
#endif
|
75
examples/widgets/painting/shared/fbopaintdevice.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "fbopaintdevice.h"
|
||||
|
||||
#include <QOffscreenSurface>
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
QFboPaintDevice::QFboPaintDevice(const QSize &size, bool flipped, bool clearOnInit,
|
||||
QOpenGLFramebufferObject::Attachment attachment)
|
||||
: QOpenGLPaintDevice(size)
|
||||
{
|
||||
QOpenGLFramebufferObjectFormat format;
|
||||
format.setAttachment(attachment);
|
||||
format.setSamples(4);
|
||||
m_framebufferObject = new QOpenGLFramebufferObject(size, format);
|
||||
QOffscreenSurface *surface = new QOffscreenSurface();
|
||||
surface->create();
|
||||
m_surface = surface;
|
||||
setPaintFlipped(flipped);
|
||||
if (clearOnInit) {
|
||||
m_framebufferObject->bind();
|
||||
|
||||
context()->functions()->glClearColor(0, 0, 0, 0);
|
||||
context()->functions()->glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
m_resolvedFbo = new QOpenGLFramebufferObject(m_framebufferObject->size(), m_framebufferObject->attachment());
|
||||
}
|
||||
|
||||
QFboPaintDevice::~QFboPaintDevice()
|
||||
{
|
||||
delete m_framebufferObject;
|
||||
delete m_resolvedFbo;
|
||||
delete m_surface;
|
||||
}
|
||||
|
||||
void QFboPaintDevice::ensureActiveTarget()
|
||||
{
|
||||
if (QOpenGLContext::currentContext() != context())
|
||||
context()->makeCurrent(m_surface);
|
||||
|
||||
m_framebufferObject->bind();
|
||||
}
|
||||
|
||||
GLuint QFboPaintDevice::texture()
|
||||
{
|
||||
m_resolvedFbo->bind(); // to get the backing texture recreated if it was taken (in takeTexture) previously
|
||||
QOpenGLFramebufferObject::blitFramebuffer(m_resolvedFbo, m_framebufferObject);
|
||||
return m_resolvedFbo->texture();
|
||||
}
|
||||
|
||||
GLuint QFboPaintDevice::takeTexture()
|
||||
{
|
||||
m_resolvedFbo->bind(); // to get the backing texture recreated if it was taken (in takeTexture) previously
|
||||
// We have multisamples so we can't just forward takeTexture(), have to resolve first.
|
||||
QOpenGLFramebufferObject::blitFramebuffer(m_resolvedFbo, m_framebufferObject);
|
||||
return m_resolvedFbo->takeTexture();
|
||||
}
|
||||
|
||||
QImage QFboPaintDevice::toImage() const
|
||||
{
|
||||
QOpenGLContext *currentContext = QOpenGLContext::currentContext();
|
||||
QSurface *currentSurface = currentContext ? currentContext->surface() : nullptr;
|
||||
|
||||
context()->makeCurrent(m_surface);
|
||||
|
||||
QImage image = m_framebufferObject->toImage(!paintFlipped());
|
||||
|
||||
if (currentContext)
|
||||
currentContext->makeCurrent(currentSurface);
|
||||
else
|
||||
context()->doneCurrent();
|
||||
|
||||
return image;
|
||||
}
|
46
examples/widgets/painting/shared/fbopaintdevice.h
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright (C) 2018 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef QFBOPAINTDEVICE_H
|
||||
#define QFBOPAINTDEVICE_H
|
||||
|
||||
#ifndef QT_NO_OPENGL
|
||||
|
||||
#include <QImage>
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLPaintDevice>
|
||||
#include <QSurface>
|
||||
|
||||
class QFboPaintDevice : public QOpenGLPaintDevice {
|
||||
public:
|
||||
QFboPaintDevice(const QSize &size, bool flipped = false, bool clearOnInit = true,
|
||||
QOpenGLFramebufferObject::Attachment = QOpenGLFramebufferObject::CombinedDepthStencil);
|
||||
~QFboPaintDevice();
|
||||
|
||||
// QOpenGLPaintDevice:
|
||||
void ensureActiveTarget() override;
|
||||
|
||||
bool isValid() const { return m_framebufferObject->isValid(); }
|
||||
GLuint handle() const { return m_framebufferObject->handle(); }
|
||||
GLuint texture();
|
||||
GLuint takeTexture();
|
||||
QImage toImage() const;
|
||||
|
||||
bool bind() { return m_framebufferObject->bind(); }
|
||||
bool release() { return m_framebufferObject->release(); }
|
||||
QSize size() const { return m_framebufferObject->size(); }
|
||||
|
||||
QOpenGLFramebufferObject* framebufferObject() { return m_framebufferObject; }
|
||||
const QOpenGLFramebufferObject* framebufferObject() const { return m_framebufferObject; }
|
||||
|
||||
static bool isSupported() { return QOpenGLFramebufferObject::hasOpenGLFramebufferObjects(); }
|
||||
|
||||
private:
|
||||
QOpenGLFramebufferObject *m_framebufferObject;
|
||||
QOpenGLFramebufferObject *m_resolvedFbo;
|
||||
QSurface *m_surface;
|
||||
};
|
||||
|
||||
#endif // QT_NO_OPENGL
|
||||
|
||||
#endif // QFBOPAINTDEVICE_H
|
355
examples/widgets/painting/shared/hoverpoints.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
#include "hoverpoints.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
#include <QtOpenGL/QOpenGLWindow>
|
||||
#endif
|
||||
|
||||
HoverPoints::HoverPoints(QWidget *widget, PointShape shape)
|
||||
: QObject(widget),
|
||||
m_widget(widget),
|
||||
m_shape(shape)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
widget->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
|
||||
connect(this, &HoverPoints::pointsChanged,
|
||||
m_widget, QOverload<>::of(&QWidget::update));
|
||||
}
|
||||
|
||||
void HoverPoints::setEnabled(bool enabled)
|
||||
{
|
||||
if (m_enabled != enabled) {
|
||||
m_enabled = enabled;
|
||||
m_widget->update();
|
||||
}
|
||||
}
|
||||
|
||||
bool HoverPoints::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
if (object != m_widget || !m_enabled)
|
||||
return false;
|
||||
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return true;
|
||||
auto *me = static_cast<const QMouseEvent *>(event);
|
||||
QPointF clickPos = me->position().toPoint();
|
||||
qsizetype index = -1;
|
||||
for (qsizetype i = 0; i < m_points.size(); ++i) {
|
||||
QPainterPath path;
|
||||
const QRectF rect = pointBoundingRect(m_points.at(i));
|
||||
if (m_shape == CircleShape)
|
||||
path.addEllipse(rect);
|
||||
else
|
||||
path.addRect(rect);
|
||||
|
||||
if (path.contains(clickPos)) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (me->button() == Qt::LeftButton) {
|
||||
if (index == -1) {
|
||||
if (!m_editable)
|
||||
return false;
|
||||
qsizetype pos = 0;
|
||||
// Insert sort for x or y
|
||||
switch (m_sortType) {
|
||||
case XSort:
|
||||
for (qsizetype i = 0; i < m_points.size(); ++i) {
|
||||
if (m_points.at(i).x() > clickPos.x()) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case YSort:
|
||||
for (qsizetype i = 0; i < m_points.size(); ++i) {
|
||||
if (m_points.at(i).y() > clickPos.y()) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_points.insert(pos, clickPos);
|
||||
m_locks.insert(pos, 0);
|
||||
m_currentIndex = pos;
|
||||
firePointChange();
|
||||
} else {
|
||||
m_currentIndex = index;
|
||||
}
|
||||
return true;
|
||||
|
||||
} else if (me->button() == Qt::RightButton) {
|
||||
if (index >= 0 && m_editable) {
|
||||
if (m_locks[index] == 0) {
|
||||
m_locks.remove(index);
|
||||
m_points.remove(index);
|
||||
}
|
||||
firePointChange();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QEvent::MouseButtonRelease:
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return true;
|
||||
m_currentIndex = -1;
|
||||
break;
|
||||
|
||||
case QEvent::MouseMove:
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return true;
|
||||
if (m_currentIndex >= 0) {
|
||||
auto *me = static_cast<const QMouseEvent *>(event);
|
||||
movePoint(m_currentIndex, me->position().toPoint());
|
||||
}
|
||||
break;
|
||||
|
||||
case QEvent::TouchBegin:
|
||||
case QEvent::TouchUpdate:
|
||||
{
|
||||
auto *touchEvent = static_cast<const QTouchEvent*>(event);
|
||||
const auto points = touchEvent->points();
|
||||
const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height());
|
||||
for (const auto &point : points) {
|
||||
const int id = point.id();
|
||||
switch (point.state()) {
|
||||
case QEventPoint::Pressed:
|
||||
{
|
||||
// find the point, move it
|
||||
const auto mappedPoints = m_fingerPointMapping.values();
|
||||
QSet<qsizetype> activePoints(mappedPoints.begin(), mappedPoints.end());
|
||||
qsizetype activePoint = -1;
|
||||
qreal distance = -1;
|
||||
const qsizetype pointsCount = m_points.size();
|
||||
const qsizetype activePointCount = activePoints.size();
|
||||
if (pointsCount == 2 && activePointCount == 1) { // only two points
|
||||
activePoint = activePoints.contains(0) ? 1 : 0;
|
||||
} else {
|
||||
for (qsizetype i = 0; i < pointsCount; ++i) {
|
||||
if (activePoints.contains(i))
|
||||
continue;
|
||||
|
||||
qreal d = QLineF(point.position(), m_points.at(i)).length();
|
||||
if ((distance < 0 && d < 12 * pointSize) || d < distance) {
|
||||
distance = d;
|
||||
activePoint = i;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (activePoint != -1) {
|
||||
m_fingerPointMapping.insert(point.id(), activePoint);
|
||||
movePoint(activePoint, point.position());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEventPoint::Released:
|
||||
{
|
||||
// move the point and release
|
||||
const auto it = m_fingerPointMapping.constFind(id);
|
||||
movePoint(it.value(), point.position());
|
||||
m_fingerPointMapping.erase(it);
|
||||
}
|
||||
break;
|
||||
case QEventPoint::Updated:
|
||||
{
|
||||
// move the point
|
||||
const qsizetype pointIdx = m_fingerPointMapping.value(id, -1);
|
||||
if (pointIdx >= 0) // do we track this point?
|
||||
movePoint(pointIdx, point.position());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
event->ignore();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case QEvent::TouchEnd:
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
event->ignore();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case QEvent::Resize:
|
||||
{
|
||||
auto *e = static_cast<const QResizeEvent *>(event);
|
||||
if (e->oldSize().width() <= 0 || e->oldSize().height() <= 0)
|
||||
break;
|
||||
qreal stretch_x = e->size().width() / qreal(e->oldSize().width());
|
||||
qreal stretch_y = e->size().height() / qreal(e->oldSize().height());
|
||||
for (qsizetype i = 0; i < m_points.size(); ++i) {
|
||||
QPointF p = m_points.at(i);
|
||||
movePoint(i, QPointF(p.x() * stretch_x, p.y() * stretch_y), false);
|
||||
}
|
||||
|
||||
firePointChange();
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::Paint:
|
||||
{
|
||||
QWidget *that_widget = m_widget;
|
||||
m_widget = nullptr;
|
||||
QCoreApplication::sendEvent(object, event);
|
||||
m_widget = that_widget;
|
||||
paintPoints();
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void HoverPoints::paintPoints()
|
||||
{
|
||||
QPainter p;
|
||||
#if QT_CONFIG(opengl)
|
||||
ArthurFrame *af = qobject_cast<ArthurFrame *>(m_widget);
|
||||
if (af && af->usesOpenGL() && af->glWindow()->isValid()) {
|
||||
af->glWindow()->makeCurrent();
|
||||
p.begin(af->glWindow());
|
||||
} else {
|
||||
p.begin(m_widget);
|
||||
}
|
||||
#else
|
||||
p.begin(m_widget);
|
||||
#endif
|
||||
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) {
|
||||
p.setPen(m_connectionPen);
|
||||
|
||||
if (m_connectionType == CurveConnection) {
|
||||
QPainterPath path;
|
||||
path.moveTo(m_points.at(0));
|
||||
for (qsizetype i = 1; i < m_points.size(); ++i) {
|
||||
QPointF p1 = m_points.at(i - 1);
|
||||
QPointF p2 = m_points.at(i);
|
||||
qreal distance = p2.x() - p1.x();
|
||||
|
||||
path.cubicTo(p1.x() + distance / 2, p1.y(),
|
||||
p1.x() + distance / 2, p2.y(),
|
||||
p2.x(), p2.y());
|
||||
}
|
||||
p.drawPath(path);
|
||||
} else {
|
||||
p.drawPolyline(m_points);
|
||||
}
|
||||
}
|
||||
|
||||
p.setPen(m_pointPen);
|
||||
p.setBrush(m_pointBrush);
|
||||
|
||||
for (const auto &point : std::as_const(m_points)) {
|
||||
QRectF bounds = pointBoundingRect(point);
|
||||
if (m_shape == CircleShape)
|
||||
p.drawEllipse(bounds);
|
||||
else
|
||||
p.drawRect(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
static QPointF bound_point(const QPointF &point, const QRectF &bounds, int lock)
|
||||
{
|
||||
QPointF p = point;
|
||||
|
||||
qreal left = bounds.left();
|
||||
qreal right = bounds.right();
|
||||
qreal top = bounds.top();
|
||||
qreal bottom = bounds.bottom();
|
||||
|
||||
if (p.x() < left || (lock & HoverPoints::LockToLeft)) p.setX(left);
|
||||
else if (p.x() > right || (lock & HoverPoints::LockToRight)) p.setX(right);
|
||||
|
||||
if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top);
|
||||
else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void HoverPoints::setPoints(const QPolygonF &points)
|
||||
{
|
||||
if (points.size() != m_points.size())
|
||||
m_fingerPointMapping.clear();
|
||||
m_points.clear();
|
||||
for (qsizetype i = 0; i < points.size(); ++i)
|
||||
m_points << bound_point(points.at(i), boundingRect(), 0);
|
||||
|
||||
m_locks.clear();
|
||||
if (m_points.size() > 0) {
|
||||
m_locks.resize(m_points.size());
|
||||
m_locks.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
void HoverPoints::movePoint(qsizetype index, const QPointF &point, bool emitUpdate)
|
||||
{
|
||||
m_points[index] = bound_point(point, boundingRect(), m_locks.at(index));
|
||||
if (emitUpdate)
|
||||
firePointChange();
|
||||
}
|
||||
|
||||
inline static bool x_less_than(const QPointF &p1, const QPointF &p2)
|
||||
{
|
||||
return p1.x() < p2.x();
|
||||
}
|
||||
|
||||
inline static bool y_less_than(const QPointF &p1, const QPointF &p2)
|
||||
{
|
||||
return p1.y() < p2.y();
|
||||
}
|
||||
|
||||
void HoverPoints::firePointChange()
|
||||
{
|
||||
if (m_sortType != NoSort) {
|
||||
|
||||
QPointF oldCurrent;
|
||||
if (m_currentIndex != -1)
|
||||
oldCurrent = m_points[m_currentIndex];
|
||||
|
||||
if (m_sortType == XSort)
|
||||
std::sort(m_points.begin(), m_points.end(), x_less_than);
|
||||
else if (m_sortType == YSort)
|
||||
std::sort(m_points.begin(), m_points.end(), y_less_than);
|
||||
|
||||
// Compensate for changed order...
|
||||
if (m_currentIndex != -1) {
|
||||
for (qsizetype i = 0; i < m_points.size(); ++i) {
|
||||
if (m_points[i] == oldCurrent) {
|
||||
m_currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit pointsChanged(m_points);
|
||||
}
|
122
examples/widgets/painting/shared/hoverpoints.h
Normal file
@ -0,0 +1,122 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef HOVERPOINTS_H
|
||||
#define HOVERPOINTS_H
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QBypassWidget)
|
||||
|
||||
class HoverPoints : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum PointShape {
|
||||
CircleShape,
|
||||
RectangleShape
|
||||
};
|
||||
|
||||
enum LockType {
|
||||
LockToLeft = 0x01,
|
||||
LockToRight = 0x02,
|
||||
LockToTop = 0x04,
|
||||
LockToBottom = 0x08
|
||||
};
|
||||
|
||||
enum SortType {
|
||||
NoSort,
|
||||
XSort,
|
||||
YSort
|
||||
};
|
||||
|
||||
enum ConnectionType {
|
||||
NoConnection,
|
||||
LineConnection,
|
||||
CurveConnection
|
||||
};
|
||||
|
||||
HoverPoints(QWidget *widget, PointShape shape);
|
||||
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
void paintPoints();
|
||||
|
||||
inline QRectF boundingRect() const;
|
||||
void setBoundingRect(const QRectF &boundingRect) { m_bounds = boundingRect; }
|
||||
|
||||
QPolygonF points() const { return m_points; }
|
||||
void setPoints(const QPolygonF &points);
|
||||
|
||||
QSizeF pointSize() const { return m_pointSize; }
|
||||
void setPointSize(const QSizeF &size) { m_pointSize = size; }
|
||||
|
||||
SortType sortType() const { return m_sortType; }
|
||||
void setSortType(SortType sortType) { m_sortType = sortType; }
|
||||
|
||||
ConnectionType connectionType() const { return m_connectionType; }
|
||||
void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; }
|
||||
|
||||
void setConnectionPen(const QPen &pen) { m_connectionPen = pen; }
|
||||
void setShapePen(const QPen &pen) { m_pointPen = pen; }
|
||||
void setShapeBrush(const QBrush &brush) { m_pointBrush = brush; }
|
||||
|
||||
void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; }
|
||||
|
||||
void setEditable(bool editable) { m_editable = editable; }
|
||||
bool editable() const { return m_editable; }
|
||||
|
||||
public slots:
|
||||
void setEnabled(bool enabled);
|
||||
void setDisabled(bool disabled) { setEnabled(!disabled); }
|
||||
|
||||
signals:
|
||||
void pointsChanged(const QPolygonF &points);
|
||||
|
||||
public:
|
||||
void firePointChange();
|
||||
|
||||
private:
|
||||
inline QRectF pointBoundingRect(const QPointF &p) const;
|
||||
void movePoint(qsizetype i, const QPointF &newPos, bool emitChange = true);
|
||||
|
||||
QWidget *m_widget;
|
||||
|
||||
QPolygonF m_points;
|
||||
QRectF m_bounds;
|
||||
PointShape m_shape;
|
||||
SortType m_sortType = NoSort;
|
||||
ConnectionType m_connectionType = CurveConnection;
|
||||
|
||||
QList<uint> m_locks;
|
||||
|
||||
QSizeF m_pointSize{11, 11};
|
||||
qsizetype m_currentIndex= -1;
|
||||
bool m_editable = true;
|
||||
bool m_enabled = true;
|
||||
|
||||
QHash<int, qsizetype> m_fingerPointMapping;
|
||||
|
||||
QPen m_pointPen{QColor(255, 255, 255, 191), 1};
|
||||
QBrush m_pointBrush{QColor(191, 191, 191, 127)};
|
||||
QPen m_connectionPen{QColor(255, 255, 255, 127), 2};
|
||||
};
|
||||
|
||||
inline QRectF HoverPoints::pointBoundingRect(const QPointF &p) const
|
||||
{
|
||||
qreal w = m_pointSize.width();
|
||||
qreal h = m_pointSize.height();
|
||||
qreal x = p.x() - w / 2;
|
||||
qreal y = p.y() - h / 2;
|
||||
return QRectF(x, y, w, h);
|
||||
}
|
||||
|
||||
inline QRectF HoverPoints::boundingRect() const
|
||||
{
|
||||
if (m_bounds.isEmpty())
|
||||
return m_widget->rect();
|
||||
else
|
||||
return m_bounds;
|
||||
}
|
||||
|
||||
#endif // HOVERPOINTS_H
|
BIN
examples/widgets/painting/shared/images/bg_pattern.png
Normal file
After Width: | Height: | Size: 104 B |
After Width: | Height: | Size: 654 B |
After Width: | Height: | Size: 674 B |
After Width: | Height: | Size: 185 B |
After Width: | Height: | Size: 710 B |
After Width: | Height: | Size: 785 B |
After Width: | Height: | Size: 217 B |
BIN
examples/widgets/painting/shared/images/curve_thing_edit-6.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
examples/widgets/painting/shared/images/frame_bottom.png
Normal file
After Width: | Height: | Size: 166 B |
BIN
examples/widgets/painting/shared/images/frame_bottomleft.png
Normal file
After Width: | Height: | Size: 602 B |