qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View 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)

View 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.

View 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}"
)

View 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

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View 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();
}

View 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();
}

View 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

View 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>

View 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}"
)

View 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

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View 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();
}

View 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]

View 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

View 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]

View 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

View 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}"
)

View 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);
}

View 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

View 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>

View 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

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View 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();
}

View 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}"
)

View 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]

View 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

View File

@ -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

View 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();
}

View 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]

View 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

View 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}"
)

View 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

View 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>

View 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();
}

View 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 &center, 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));
}
}

View 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

View 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>

View 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}"
)

View 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

View 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();
}

View 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
}

View 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

View 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>&amp;Selection</string>
</property>
<addaction name="markAction"/>
<addaction name="unmarkAction"/>
<addaction name="clearAction"/>
</widget>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;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>&amp;Print...</string>
</property>
<property name="shortcut">
<string>Ctrl+P</string>
</property>
</action>
<action name="quitAction">
<property name="text">
<string>E&amp;xit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="markAction">
<property name="text">
<string>&amp;Mark</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="unmarkAction">
<property name="text">
<string>&amp;Unmark</string>
</property>
<property name="shortcut">
<string>Ctrl+U</string>
</property>
</action>
<action name="clearAction">
<property name="text">
<string>&amp;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>

View 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}"
)

View 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());
}

View 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

View 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>

View 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

View 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>

View 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();
}

View 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}"
)

View 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]

View 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

View File

@ -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

View File

@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>images/butterfly.png</file>
<file>images/checker.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View 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]

View 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}"
)

View 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();
}

View 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

View 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]

View 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

View 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]

View 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

View File

@ -0,0 +1,15 @@
TEMPLATE = subdirs
SUBDIRS = basicdrawing \
concentriccircles \
affine \
composition \
deform \
gradients \
pathstroke \
imagecomposition \
painterpaths \
transformations \
fontsampler
EXAMPLE_FILES = \
shared

View 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}"
)

View 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();
}

View 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;
}
}

View 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

View 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>

View 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

View 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>

View 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()

View 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;
}

View 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

View 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("&amp;"));
contents.replace(QLatin1Char('<'), QStringLiteral("&lt;"));
contents.replace(QLatin1Char('>'), QStringLiteral("&gt;"));
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();
}

View 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

View 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;
}

View 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

View 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);
}

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Some files were not shown because too many files have changed in this diff Show More