mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-03 07:45:30 +08:00
qt 6.5.1 original
This commit is contained in:
102
examples/widgets/painting/pathstroke/CMakeLists.txt
Normal file
102
examples/widgets/painting/pathstroke/CMakeLists.txt
Normal file
@ -0,0 +1,102 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(pathstroke LANGUAGES CXX)
|
||||
|
||||
if(NOT DEFINED INSTALL_EXAMPLESDIR)
|
||||
set(INSTALL_EXAMPLESDIR "examples")
|
||||
endif()
|
||||
|
||||
set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/widgets/painting/pathstroke")
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
|
||||
|
||||
qt_standard_project_setup()
|
||||
|
||||
qt_add_executable(pathstroke
|
||||
main.cpp
|
||||
pathstroke.cpp pathstroke.h
|
||||
)
|
||||
|
||||
set_target_properties(pathstroke PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
|
||||
if(NOT TARGET painting_shared::painting_shared)
|
||||
include(../shared/use_lib.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(pathstroke PRIVATE
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Widgets
|
||||
painting_shared::painting_shared
|
||||
)
|
||||
|
||||
# Resources:
|
||||
set(shared_resource_files
|
||||
"../shared/images/button_normal_cap_left.png"
|
||||
"../shared/images/button_normal_cap_right.png"
|
||||
"../shared/images/button_normal_stretch.png"
|
||||
"../shared/images/button_pressed_cap_left.png"
|
||||
"../shared/images/button_pressed_cap_right.png"
|
||||
"../shared/images/button_pressed_stretch.png"
|
||||
"../shared/images/frame_bottom.png"
|
||||
"../shared/images/frame_bottomleft.png"
|
||||
"../shared/images/frame_bottomright.png"
|
||||
"../shared/images/frame_left.png"
|
||||
"../shared/images/frame_right.png"
|
||||
"../shared/images/frame_top.png"
|
||||
"../shared/images/frame_topleft.png"
|
||||
"../shared/images/frame_topright.png"
|
||||
"../shared/images/groupframe_bottom_left.png"
|
||||
"../shared/images/groupframe_bottom_right.png"
|
||||
"../shared/images/groupframe_bottom_stretch.png"
|
||||
"../shared/images/groupframe_left_stretch.png"
|
||||
"../shared/images/groupframe_right_stretch.png"
|
||||
"../shared/images/groupframe_top_stretch.png"
|
||||
"../shared/images/groupframe_topleft.png"
|
||||
"../shared/images/groupframe_topright.png"
|
||||
"../shared/images/line_dash_dot.png"
|
||||
"../shared/images/line_dash_dot_dot.png"
|
||||
"../shared/images/line_dashed.png"
|
||||
"../shared/images/line_dotted.png"
|
||||
"../shared/images/line_solid.png"
|
||||
"../shared/images/radiobutton-on.png"
|
||||
"../shared/images/radiobutton_off.png"
|
||||
"../shared/images/radiobutton_on.png"
|
||||
"../shared/images/slider_bar.png"
|
||||
"../shared/images/slider_thumb_on.png"
|
||||
"../shared/images/title_cap_left.png"
|
||||
"../shared/images/title_cap_right.png"
|
||||
"../shared/images/title_stretch.png"
|
||||
)
|
||||
|
||||
qt_add_resources(pathstroke "shared"
|
||||
PREFIX
|
||||
"/res"
|
||||
BASE
|
||||
"../shared"
|
||||
FILES
|
||||
${shared_resource_files}
|
||||
)
|
||||
|
||||
set(pathstroke_resource_files
|
||||
"pathstroke.cpp"
|
||||
"pathstroke.html"
|
||||
)
|
||||
|
||||
qt_add_resources(pathstroke "pathstroke"
|
||||
PREFIX
|
||||
"/res/pathstroke"
|
||||
FILES
|
||||
${pathstroke_resource_files}
|
||||
)
|
||||
|
||||
install(TARGETS pathstroke
|
||||
RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
|
||||
)
|
34
examples/widgets/painting/pathstroke/main.cpp
Normal file
34
examples/widgets/painting/pathstroke/main.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathstroke.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Q_INIT_RESOURCE(pathstroke);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
bool smallScreen = QApplication::arguments().contains("-small-screen");
|
||||
|
||||
PathStrokeWidget pathStrokeWidget(smallScreen);
|
||||
QStyle *arthurStyle = new ArthurStyle();
|
||||
pathStrokeWidget.setStyle(arthurStyle);
|
||||
const QList<QWidget *> widgets = pathStrokeWidget.findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets) {
|
||||
w->setStyle(arthurStyle);
|
||||
w->setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
|
||||
if (smallScreen)
|
||||
pathStrokeWidget.showFullScreen();
|
||||
else
|
||||
pathStrokeWidget.show();
|
||||
|
||||
#ifdef QT_KEYPAD_NAVIGATION
|
||||
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
|
||||
#endif
|
||||
return app.exec();
|
||||
}
|
663
examples/widgets/painting/pathstroke/pathstroke.cpp
Normal file
663
examples/widgets/painting/pathstroke/pathstroke.cpp
Normal file
@ -0,0 +1,663 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#include "pathstroke.h"
|
||||
#include "arthurstyle.h"
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
extern void draw_round_rect(QPainter *p, const QRect &bounds, int radius);
|
||||
|
||||
|
||||
PathStrokeControls::PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_renderer = renderer;
|
||||
|
||||
if (smallScreen)
|
||||
layoutForSmallScreens();
|
||||
else
|
||||
layoutForDesktop();
|
||||
}
|
||||
|
||||
void PathStrokeControls::createCommonControls(QWidget* parent)
|
||||
{
|
||||
m_capGroup = new QGroupBox(parent);
|
||||
m_capGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *flatCap = new QRadioButton(m_capGroup);
|
||||
QRadioButton *squareCap = new QRadioButton(m_capGroup);
|
||||
QRadioButton *roundCap = new QRadioButton(m_capGroup);
|
||||
m_capGroup->setTitle(tr("Cap Style"));
|
||||
flatCap->setText(tr("Flat"));
|
||||
squareCap->setText(tr("Square"));
|
||||
roundCap->setText(tr("Round"));
|
||||
flatCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
squareCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
roundCap->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
m_joinGroup = new QGroupBox(parent);
|
||||
m_joinGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *bevelJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *miterJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *svgMiterJoin = new QRadioButton(m_joinGroup);
|
||||
QRadioButton *roundJoin = new QRadioButton(m_joinGroup);
|
||||
m_joinGroup->setTitle(tr("Join Style"));
|
||||
bevelJoin->setText(tr("Bevel"));
|
||||
miterJoin->setText(tr("Miter"));
|
||||
svgMiterJoin->setText(tr("SvgMiter"));
|
||||
roundJoin->setText(tr("Round"));
|
||||
|
||||
m_styleGroup = new QGroupBox(parent);
|
||||
m_styleGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *solidLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashDotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *dashDotDotLine = new QRadioButton(m_styleGroup);
|
||||
QRadioButton *customDashLine = new QRadioButton(m_styleGroup);
|
||||
m_styleGroup->setTitle(tr("Pen Style"));
|
||||
|
||||
QPixmap line_solid(":res/images/line_solid.png");
|
||||
solidLine->setIcon(line_solid);
|
||||
solidLine->setIconSize(line_solid.size());
|
||||
QPixmap line_dashed(":res/images/line_dashed.png");
|
||||
dashLine->setIcon(line_dashed);
|
||||
dashLine->setIconSize(line_dashed.size());
|
||||
QPixmap line_dotted(":res/images/line_dotted.png");
|
||||
dotLine->setIcon(line_dotted);
|
||||
dotLine->setIconSize(line_dotted.size());
|
||||
QPixmap line_dash_dot(":res/images/line_dash_dot.png");
|
||||
dashDotLine->setIcon(line_dash_dot);
|
||||
dashDotLine->setIconSize(line_dash_dot.size());
|
||||
QPixmap line_dash_dot_dot(":res/images/line_dash_dot_dot.png");
|
||||
dashDotDotLine->setIcon(line_dash_dot_dot);
|
||||
dashDotDotLine->setIconSize(line_dash_dot_dot.size());
|
||||
customDashLine->setText(tr("Custom"));
|
||||
|
||||
int fixedHeight = bevelJoin->sizeHint().height();
|
||||
solidLine->setFixedHeight(fixedHeight);
|
||||
dashLine->setFixedHeight(fixedHeight);
|
||||
dotLine->setFixedHeight(fixedHeight);
|
||||
dashDotLine->setFixedHeight(fixedHeight);
|
||||
dashDotDotLine->setFixedHeight(fixedHeight);
|
||||
|
||||
m_pathModeGroup = new QGroupBox(parent);
|
||||
m_pathModeGroup->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
QRadioButton *curveMode = new QRadioButton(m_pathModeGroup);
|
||||
QRadioButton *lineMode = new QRadioButton(m_pathModeGroup);
|
||||
m_pathModeGroup->setTitle(tr("Line Style"));
|
||||
curveMode->setText(tr("Curves"));
|
||||
lineMode->setText(tr("Lines"));
|
||||
|
||||
|
||||
// Layouts
|
||||
QVBoxLayout *capGroupLayout = new QVBoxLayout(m_capGroup);
|
||||
capGroupLayout->addWidget(flatCap);
|
||||
capGroupLayout->addWidget(squareCap);
|
||||
capGroupLayout->addWidget(roundCap);
|
||||
|
||||
QVBoxLayout *joinGroupLayout = new QVBoxLayout(m_joinGroup);
|
||||
joinGroupLayout->addWidget(bevelJoin);
|
||||
joinGroupLayout->addWidget(miterJoin);
|
||||
joinGroupLayout->addWidget(svgMiterJoin);
|
||||
joinGroupLayout->addWidget(roundJoin);
|
||||
|
||||
QVBoxLayout *styleGroupLayout = new QVBoxLayout(m_styleGroup);
|
||||
styleGroupLayout->addWidget(solidLine);
|
||||
styleGroupLayout->addWidget(dashLine);
|
||||
styleGroupLayout->addWidget(dotLine);
|
||||
styleGroupLayout->addWidget(dashDotLine);
|
||||
styleGroupLayout->addWidget(dashDotDotLine);
|
||||
styleGroupLayout->addWidget(customDashLine);
|
||||
|
||||
QVBoxLayout *pathModeGroupLayout = new QVBoxLayout(m_pathModeGroup);
|
||||
pathModeGroupLayout->addWidget(curveMode);
|
||||
pathModeGroupLayout->addWidget(lineMode);
|
||||
|
||||
|
||||
// Connections
|
||||
connect(flatCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setFlatCap);
|
||||
connect(squareCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSquareCap);
|
||||
connect(roundCap, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setRoundCap);
|
||||
|
||||
connect(bevelJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setBevelJoin);
|
||||
connect(miterJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setMiterJoin);
|
||||
connect(svgMiterJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSvgMiterJoin);
|
||||
connect(roundJoin, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setRoundJoin);
|
||||
|
||||
connect(curveMode, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setCurveMode);
|
||||
connect(lineMode, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setLineMode);
|
||||
|
||||
connect(solidLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setSolidLine);
|
||||
connect(dashLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashLine);
|
||||
connect(dotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDotLine);
|
||||
connect(dashDotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashDotLine);
|
||||
connect(dashDotDotLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setDashDotDotLine);
|
||||
connect(customDashLine, &QAbstractButton::clicked,
|
||||
m_renderer, &PathStrokeRenderer::setCustomDashLine);
|
||||
|
||||
// Set the defaults:
|
||||
flatCap->setChecked(true);
|
||||
bevelJoin->setChecked(true);
|
||||
curveMode->setChecked(true);
|
||||
solidLine->setChecked(true);
|
||||
}
|
||||
|
||||
|
||||
void PathStrokeControls::layoutForDesktop()
|
||||
{
|
||||
QGroupBox *mainGroup = new QGroupBox(this);
|
||||
mainGroup->setFixedWidth(180);
|
||||
mainGroup->setTitle(tr("Path Stroking"));
|
||||
|
||||
createCommonControls(mainGroup);
|
||||
|
||||
QGroupBox* penWidthGroup = new QGroupBox(mainGroup);
|
||||
QSlider *penWidth = new QSlider(Qt::Horizontal, penWidthGroup);
|
||||
penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
penWidthGroup->setTitle(tr("Pen Width"));
|
||||
penWidth->setRange(0, 500);
|
||||
|
||||
QPushButton *animated = new QPushButton(mainGroup);
|
||||
animated->setText(tr("Animate"));
|
||||
animated->setCheckable(true);
|
||||
|
||||
QPushButton *showSourceButton = new QPushButton(mainGroup);
|
||||
showSourceButton->setText(tr("Show Source"));
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
QPushButton *whatsThisButton = new QPushButton(mainGroup);
|
||||
whatsThisButton->setText(tr("What's This?"));
|
||||
whatsThisButton->setCheckable(true);
|
||||
|
||||
|
||||
// Layouts:
|
||||
QVBoxLayout *penWidthLayout = new QVBoxLayout(penWidthGroup);
|
||||
penWidthLayout->addWidget(penWidth);
|
||||
|
||||
QVBoxLayout * mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(QMargins());
|
||||
mainLayout->addWidget(mainGroup);
|
||||
|
||||
QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
|
||||
mainGroupLayout->setContentsMargins(3, 3, 3, 3);
|
||||
mainGroupLayout->addWidget(m_capGroup);
|
||||
mainGroupLayout->addWidget(m_joinGroup);
|
||||
mainGroupLayout->addWidget(m_styleGroup);
|
||||
mainGroupLayout->addWidget(penWidthGroup);
|
||||
mainGroupLayout->addWidget(m_pathModeGroup);
|
||||
mainGroupLayout->addWidget(animated);
|
||||
mainGroupLayout->addStretch(1);
|
||||
mainGroupLayout->addWidget(showSourceButton);
|
||||
#if QT_CONFIG(opengl)
|
||||
mainGroupLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
mainGroupLayout->addWidget(whatsThisButton);
|
||||
|
||||
|
||||
// Set up connections
|
||||
connect(animated, &QAbstractButton::toggled,
|
||||
m_renderer, &PathStrokeRenderer::setAnimation);
|
||||
|
||||
connect(penWidth, &QAbstractSlider::valueChanged,
|
||||
m_renderer, &PathStrokeRenderer::setPenWidth);
|
||||
|
||||
connect(showSourceButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::showSource);
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
connect(whatsThisButton, &QAbstractButton::clicked,
|
||||
m_renderer, &ArthurFrame::setDescriptionEnabled);
|
||||
connect(m_renderer, &ArthurFrame::descriptionEnabledChanged,
|
||||
whatsThisButton, &QAbstractButton::setChecked);
|
||||
|
||||
|
||||
// Set the defaults
|
||||
animated->setChecked(true);
|
||||
penWidth->setValue(50);
|
||||
|
||||
}
|
||||
|
||||
void PathStrokeControls::layoutForSmallScreens()
|
||||
{
|
||||
createCommonControls(this);
|
||||
|
||||
m_capGroup->layout()->setContentsMargins(QMargins());
|
||||
m_joinGroup->layout()->setContentsMargins(QMargins());
|
||||
m_styleGroup->layout()->setContentsMargins(QMargins());
|
||||
m_pathModeGroup->layout()->setContentsMargins(QMargins());
|
||||
|
||||
QPushButton* okBtn = new QPushButton(tr("OK"), this);
|
||||
okBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
okBtn->setMinimumSize(100,okBtn->minimumSize().height());
|
||||
|
||||
QPushButton* quitBtn = new QPushButton(tr("Quit"), this);
|
||||
quitBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
quitBtn->setMinimumSize(100, okBtn->minimumSize().height());
|
||||
|
||||
QLabel *penWidthLabel = new QLabel(tr(" Width:"));
|
||||
QSlider *penWidth = new QSlider(Qt::Horizontal, this);
|
||||
penWidth->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
penWidth->setRange(0, 500);
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
QPushButton *enableOpenGLButton = new QPushButton(this);
|
||||
enableOpenGLButton->setText(tr("Use OpenGL"));
|
||||
enableOpenGLButton->setCheckable(true);
|
||||
enableOpenGLButton->setChecked(m_renderer->usesOpenGL());
|
||||
#endif
|
||||
|
||||
// Layouts:
|
||||
QHBoxLayout *penWidthLayout = new QHBoxLayout;
|
||||
penWidthLayout->addWidget(penWidthLabel, 0, Qt::AlignRight);
|
||||
penWidthLayout->addWidget(penWidth);
|
||||
|
||||
QVBoxLayout *leftLayout = new QVBoxLayout;
|
||||
leftLayout->addWidget(m_capGroup);
|
||||
leftLayout->addWidget(m_joinGroup);
|
||||
#if QT_CONFIG(opengl)
|
||||
leftLayout->addWidget(enableOpenGLButton);
|
||||
#endif
|
||||
leftLayout->addLayout(penWidthLayout);
|
||||
|
||||
QVBoxLayout *rightLayout = new QVBoxLayout;
|
||||
rightLayout->addWidget(m_styleGroup);
|
||||
rightLayout->addWidget(m_pathModeGroup);
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout(this);
|
||||
mainLayout->setContentsMargins(QMargins());
|
||||
|
||||
// Add spacers around the form items so we don't look stupid at higher resolutions
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 0, 0, 1, 4);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 1, 0, 2, 1);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 1, 3, 2, 1);
|
||||
mainLayout->addItem(new QSpacerItem(0,0), 3, 0, 1, 4);
|
||||
|
||||
mainLayout->addLayout(leftLayout, 1, 1);
|
||||
mainLayout->addLayout(rightLayout, 1, 2);
|
||||
mainLayout->addWidget(quitBtn, 2, 1, Qt::AlignHCenter | Qt::AlignTop);
|
||||
mainLayout->addWidget(okBtn, 2, 2, Qt::AlignHCenter | Qt::AlignTop);
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
connect(enableOpenGLButton, &QAbstractButton::clicked, m_renderer, &ArthurFrame::enableOpenGL);
|
||||
#endif
|
||||
|
||||
connect(penWidth, &QAbstractSlider::valueChanged, m_renderer, &PathStrokeRenderer::setPenWidth);
|
||||
connect(quitBtn, &QAbstractButton::clicked, this, &PathStrokeControls::emitQuitSignal);
|
||||
connect(okBtn, &QAbstractButton::clicked, this, &PathStrokeControls::emitOkSignal);
|
||||
|
||||
m_renderer->setAnimation(true);
|
||||
penWidth->setValue(50);
|
||||
}
|
||||
|
||||
void PathStrokeControls::emitQuitSignal()
|
||||
{
|
||||
emit quitPressed();
|
||||
}
|
||||
|
||||
void PathStrokeControls::emitOkSignal()
|
||||
{
|
||||
emit okPressed();
|
||||
}
|
||||
|
||||
|
||||
PathStrokeWidget::PathStrokeWidget(bool smallScreen)
|
||||
{
|
||||
setWindowTitle(tr("Path Stroking"));
|
||||
|
||||
// Widget construction and property setting
|
||||
m_renderer = new PathStrokeRenderer(this, smallScreen);
|
||||
|
||||
m_controls = new PathStrokeControls(nullptr, m_renderer, smallScreen);
|
||||
|
||||
// Layouting
|
||||
QHBoxLayout *viewLayout = new QHBoxLayout(this);
|
||||
viewLayout->addWidget(m_renderer);
|
||||
|
||||
if (!smallScreen)
|
||||
viewLayout->addWidget(m_controls);
|
||||
|
||||
m_renderer->loadSourceFile(":res/pathstroke/pathstroke.cpp");
|
||||
m_renderer->loadDescription(":res/pathstroke/pathstroke.html");
|
||||
|
||||
connect(m_renderer, &PathStrokeRenderer::clicked, this, &PathStrokeWidget::showControls);
|
||||
connect(m_controls, &PathStrokeControls::okPressed, this, &PathStrokeWidget::hideControls);
|
||||
connect(m_controls, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
|
||||
}
|
||||
|
||||
void PathStrokeWidget::showControls()
|
||||
{
|
||||
m_controls->showFullScreen();
|
||||
}
|
||||
|
||||
void PathStrokeWidget::hideControls()
|
||||
{
|
||||
m_controls->hide();
|
||||
}
|
||||
|
||||
void PathStrokeWidget::setStyle(QStyle *style)
|
||||
{
|
||||
QWidget::setStyle(style);
|
||||
if (m_controls != nullptr)
|
||||
{
|
||||
m_controls->setStyle(style);
|
||||
|
||||
const QList<QWidget *> widgets = m_controls->findChildren<QWidget *>();
|
||||
for (QWidget *w : widgets)
|
||||
w->setStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
PathStrokeRenderer::PathStrokeRenderer(QWidget *parent, bool smallScreen)
|
||||
: ArthurFrame(parent)
|
||||
{
|
||||
m_smallScreen = smallScreen;
|
||||
m_pointSize = 10;
|
||||
m_activePoint = -1;
|
||||
m_capStyle = Qt::FlatCap;
|
||||
m_joinStyle = Qt::BevelJoin;
|
||||
m_pathMode = CurveMode;
|
||||
m_penWidth = 1;
|
||||
m_penStyle = Qt::SolidLine;
|
||||
m_wasAnimated = true;
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setAttribute(Qt::WA_AcceptTouchEvents);
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::paint(QPainter *painter)
|
||||
{
|
||||
if (m_points.isEmpty())
|
||||
initializePoints();
|
||||
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
QPalette pal = palette();
|
||||
painter->setPen(Qt::NoPen);
|
||||
|
||||
// Construct the path
|
||||
QPainterPath path;
|
||||
path.moveTo(m_points.at(0));
|
||||
|
||||
if (m_pathMode == LineMode) {
|
||||
for (int i=1; i<m_points.size(); ++i)
|
||||
path.lineTo(m_points.at(i));
|
||||
} else {
|
||||
int i=1;
|
||||
while (i + 2 < m_points.size()) {
|
||||
path.cubicTo(m_points.at(i), m_points.at(i+1), m_points.at(i+2));
|
||||
i += 3;
|
||||
}
|
||||
while (i < m_points.size()) {
|
||||
path.lineTo(m_points.at(i));
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the path
|
||||
{
|
||||
QColor lg = Qt::red;
|
||||
|
||||
// The "custom" pen
|
||||
if (m_penStyle == Qt::NoPen) {
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(m_penWidth);
|
||||
stroker.setJoinStyle(m_joinStyle);
|
||||
stroker.setCapStyle(m_capStyle);
|
||||
|
||||
QList<qreal> dashes;
|
||||
qreal space = 4;
|
||||
dashes << 1 << space
|
||||
<< 3 << space
|
||||
<< 9 << space
|
||||
<< 27 << space
|
||||
<< 9 << space
|
||||
<< 3 << space;
|
||||
stroker.setDashPattern(dashes);
|
||||
QPainterPath stroke = stroker.createStroke(path);
|
||||
painter->fillPath(stroke, lg);
|
||||
|
||||
} else {
|
||||
QPen pen(lg, m_penWidth, m_penStyle, m_capStyle, m_joinStyle);
|
||||
painter->strokePath(path, pen);
|
||||
}
|
||||
}
|
||||
|
||||
if (1) {
|
||||
// Draw the control points
|
||||
painter->setPen(QColor(50, 100, 120, 200));
|
||||
painter->setBrush(QColor(200, 200, 210, 120));
|
||||
for (int i=0; i<m_points.size(); ++i) {
|
||||
QPointF pos = m_points.at(i);
|
||||
painter->drawEllipse(QRectF(pos.x() - m_pointSize,
|
||||
pos.y() - m_pointSize,
|
||||
m_pointSize*2, m_pointSize*2));
|
||||
}
|
||||
painter->setPen(QPen(Qt::lightGray, 0, Qt::SolidLine));
|
||||
painter->setBrush(Qt::NoBrush);
|
||||
painter->drawPolyline(m_points);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::initializePoints()
|
||||
{
|
||||
const int count = 7;
|
||||
m_points.clear();
|
||||
m_vectors.clear();
|
||||
|
||||
QTransform m;
|
||||
qreal rot = 360.0 / count;
|
||||
QPointF center(width() / 2, height() / 2);
|
||||
QTransform vm;
|
||||
vm.shear(2, -1);
|
||||
vm.scale(3, 3);
|
||||
|
||||
for (int i=0; i<count; ++i) {
|
||||
m_vectors << QPointF(.1f, .25f) * (m * vm);
|
||||
m_points << QPointF(0, 100) * m + center;
|
||||
m.rotate(rot);
|
||||
}
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::updatePoints()
|
||||
{
|
||||
qreal pad = 10;
|
||||
qreal left = pad;
|
||||
qreal right = width() - pad;
|
||||
qreal top = pad;
|
||||
qreal bottom = height() - pad;
|
||||
|
||||
Q_ASSERT(m_points.size() == m_vectors.size());
|
||||
for (int i = 0; i < m_points.size(); ++i) {
|
||||
QPointF pos = m_points.at(i);
|
||||
QPointF vec = m_vectors.at(i);
|
||||
pos += vec;
|
||||
if (pos.x() < left || pos.x() > right) {
|
||||
vec.setX(-vec.x());
|
||||
pos.setX(pos.x() < left ? left : right);
|
||||
} if (pos.y() < top || pos.y() > bottom) {
|
||||
vec.setY(-vec.y());
|
||||
pos.setY(pos.y() < top ? top : bottom);
|
||||
}
|
||||
m_points[i] = pos;
|
||||
m_vectors[i] = vec;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mousePressEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
setDescriptionEnabled(false);
|
||||
m_activePoint = -1;
|
||||
qreal distance = -1;
|
||||
for (int i = 0; i < m_points.size(); ++i) {
|
||||
qreal d = QLineF(e->position().toPoint(), m_points.at(i)).length();
|
||||
if ((distance < 0 && d < 8 * m_pointSize) || d < distance) {
|
||||
distance = d;
|
||||
m_activePoint = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_activePoint != -1) {
|
||||
m_wasAnimated = m_timer.isActive();
|
||||
setAnimation(false);
|
||||
mouseMoveEvent(e);
|
||||
}
|
||||
|
||||
// If we're not running in small screen mode, always assume we're dragging
|
||||
m_mouseDrag = !m_smallScreen;
|
||||
m_mousePress = e->position().toPoint();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
// If we've moved more then 25 pixels, assume user is dragging
|
||||
if (!m_mouseDrag && QPoint(m_mousePress - e->position().toPoint()).manhattanLength() > 25)
|
||||
m_mouseDrag = true;
|
||||
|
||||
if (m_mouseDrag && m_activePoint >= 0 && m_activePoint < m_points.size()) {
|
||||
m_points[m_activePoint] = e->position().toPoint();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
if (!m_fingerPointMapping.isEmpty())
|
||||
return;
|
||||
m_activePoint = -1;
|
||||
setAnimation(m_wasAnimated);
|
||||
|
||||
if (!m_mouseDrag && m_smallScreen)
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::timerEvent(QTimerEvent *e)
|
||||
{
|
||||
if (e->timerId() == m_timer.timerId()) {
|
||||
updatePoints();
|
||||
} // else if (e->timerId() == m_fpsTimer.timerId()) {
|
||||
// emit frameRate(m_frameCount);
|
||||
// m_frameCount = 0;
|
||||
// }
|
||||
}
|
||||
|
||||
bool PathStrokeRenderer::event(QEvent *e)
|
||||
{
|
||||
bool touchBegin = false;
|
||||
switch (e->type()) {
|
||||
case QEvent::TouchBegin:
|
||||
touchBegin = true;
|
||||
Q_FALLTHROUGH();
|
||||
case QEvent::TouchUpdate:
|
||||
{
|
||||
const QTouchEvent *const event = static_cast<const QTouchEvent*>(e);
|
||||
const auto points = event->points();
|
||||
for (const auto &point : points) {
|
||||
const int id = point.id();
|
||||
switch (point.state()) {
|
||||
case QEventPoint::Pressed:
|
||||
{
|
||||
// find the point, move it
|
||||
const auto mappedPoints = m_fingerPointMapping.values();
|
||||
QSet<int> activePoints = QSet<int>(mappedPoints.begin(), mappedPoints.end());
|
||||
int activePoint = -1;
|
||||
qreal distance = -1;
|
||||
const int pointsCount = m_points.size();
|
||||
for (int i=0; i<pointsCount; ++i) {
|
||||
if (activePoints.contains(i))
|
||||
continue;
|
||||
|
||||
qreal d = QLineF(point.position(), m_points.at(i)).length();
|
||||
if ((distance < 0 && d < 12 * m_pointSize) || d < distance) {
|
||||
distance = d;
|
||||
activePoint = i;
|
||||
}
|
||||
}
|
||||
if (activePoint != -1) {
|
||||
m_fingerPointMapping.insert(point.id(), activePoint);
|
||||
m_points[activePoint] = point.position();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEventPoint::Released:
|
||||
{
|
||||
// move the point and release
|
||||
QHash<int,int>::iterator it = m_fingerPointMapping.find(id);
|
||||
m_points[it.value()] = point.position();
|
||||
m_fingerPointMapping.erase(it);
|
||||
break;
|
||||
}
|
||||
case QEventPoint::Updated:
|
||||
{
|
||||
// move the point
|
||||
const int pointIdx = m_fingerPointMapping.value(id, -1);
|
||||
if (pointIdx >= 0)
|
||||
m_points[pointIdx] = point.position();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
e->ignore();
|
||||
return false;
|
||||
} else {
|
||||
if (touchBegin) {
|
||||
m_wasAnimated = m_timer.isActive();
|
||||
setAnimation(false);
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QEvent::TouchEnd:
|
||||
if (m_fingerPointMapping.isEmpty()) {
|
||||
e->ignore();
|
||||
return false;
|
||||
}
|
||||
m_fingerPointMapping.clear();
|
||||
setAnimation(m_wasAnimated);
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
void PathStrokeRenderer::setAnimation(bool animation)
|
||||
{
|
||||
m_timer.stop();
|
||||
// m_fpsTimer.stop();
|
||||
|
||||
if (animation) {
|
||||
m_timer.start(25, this);
|
||||
// m_fpsTimer.start(1000, this);
|
||||
// m_frameCount = 0;
|
||||
}
|
||||
}
|
136
examples/widgets/painting/pathstroke/pathstroke.h
Normal file
136
examples/widgets/painting/pathstroke/pathstroke.h
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
||||
|
||||
#ifndef PATHSTROKE_H
|
||||
#define PATHSTROKE_H
|
||||
|
||||
#include "arthurwidgets.h"
|
||||
|
||||
#include <QtWidgets>
|
||||
|
||||
class PathStrokeRenderer : public ArthurFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool animation READ animation WRITE setAnimation)
|
||||
Q_PROPERTY(qreal penWidth READ realPenWidth WRITE setRealPenWidth)
|
||||
public:
|
||||
enum PathMode { CurveMode, LineMode };
|
||||
|
||||
explicit PathStrokeRenderer(QWidget *parent, bool smallScreen = false);
|
||||
|
||||
void paint(QPainter *) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void timerEvent(QTimerEvent *e) override;
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
QSize sizeHint() const override { return QSize(500, 500); }
|
||||
|
||||
bool animation() const { return m_timer.isActive(); }
|
||||
|
||||
qreal realPenWidth() const { return m_penWidth; }
|
||||
void setRealPenWidth(qreal penWidth) { m_penWidth = penWidth; update(); }
|
||||
|
||||
signals:
|
||||
void clicked();
|
||||
|
||||
public slots:
|
||||
void setPenWidth(int penWidth) { m_penWidth = penWidth / 10.0; update(); }
|
||||
void setAnimation(bool animation);
|
||||
|
||||
void setFlatCap() { m_capStyle = Qt::FlatCap; update(); }
|
||||
void setSquareCap() { m_capStyle = Qt::SquareCap; update(); }
|
||||
void setRoundCap() { m_capStyle = Qt::RoundCap; update(); }
|
||||
|
||||
void setBevelJoin() { m_joinStyle = Qt::BevelJoin; update(); }
|
||||
void setMiterJoin() { m_joinStyle = Qt::MiterJoin; update(); }
|
||||
void setSvgMiterJoin() { m_joinStyle = Qt::SvgMiterJoin; update(); }
|
||||
void setRoundJoin() { m_joinStyle = Qt::RoundJoin; update(); }
|
||||
|
||||
void setCurveMode() { m_pathMode = CurveMode; update(); }
|
||||
void setLineMode() { m_pathMode = LineMode; update(); }
|
||||
|
||||
void setSolidLine() { m_penStyle = Qt::SolidLine; update(); }
|
||||
void setDashLine() { m_penStyle = Qt::DashLine; update(); }
|
||||
void setDotLine() { m_penStyle = Qt::DotLine; update(); }
|
||||
void setDashDotLine() { m_penStyle = Qt::DashDotLine; update(); }
|
||||
void setDashDotDotLine() { m_penStyle = Qt::DashDotDotLine; update(); }
|
||||
void setCustomDashLine() { m_penStyle = Qt::NoPen; update(); }
|
||||
|
||||
private:
|
||||
void initializePoints();
|
||||
void updatePoints();
|
||||
|
||||
QBasicTimer m_timer;
|
||||
|
||||
PathMode m_pathMode;
|
||||
|
||||
bool m_wasAnimated;
|
||||
|
||||
qreal m_penWidth;
|
||||
int m_pointCount;
|
||||
int m_pointSize;
|
||||
int m_activePoint;
|
||||
QList<QPointF> m_points;
|
||||
QList<QPointF> m_vectors;
|
||||
|
||||
Qt::PenJoinStyle m_joinStyle;
|
||||
Qt::PenCapStyle m_capStyle;
|
||||
|
||||
Qt::PenStyle m_penStyle;
|
||||
|
||||
bool m_smallScreen;
|
||||
QPoint m_mousePress;
|
||||
bool m_mouseDrag;
|
||||
|
||||
QHash<int, int> m_fingerPointMapping;
|
||||
};
|
||||
|
||||
class PathStrokeControls : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PathStrokeControls(QWidget* parent, PathStrokeRenderer* renderer, bool smallScreen);
|
||||
|
||||
signals:
|
||||
void okPressed();
|
||||
void quitPressed();
|
||||
|
||||
private:
|
||||
PathStrokeRenderer* m_renderer;
|
||||
|
||||
QGroupBox *m_capGroup;
|
||||
QGroupBox *m_joinGroup;
|
||||
QGroupBox *m_styleGroup;
|
||||
QGroupBox *m_pathModeGroup;
|
||||
|
||||
void createCommonControls(QWidget* parent);
|
||||
void layoutForDesktop();
|
||||
void layoutForSmallScreens();
|
||||
|
||||
private slots:
|
||||
void emitQuitSignal();
|
||||
void emitOkSignal();
|
||||
|
||||
};
|
||||
|
||||
class PathStrokeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PathStrokeWidget(bool smallScreen);
|
||||
void setStyle(QStyle *style);
|
||||
|
||||
private:
|
||||
PathStrokeRenderer *m_renderer;
|
||||
PathStrokeControls *m_controls;
|
||||
|
||||
private slots:
|
||||
void showControls();
|
||||
void hideControls();
|
||||
};
|
||||
|
||||
#endif // PATHSTROKE_H
|
20
examples/widgets/painting/pathstroke/pathstroke.html
Normal file
20
examples/widgets/painting/pathstroke/pathstroke.html
Normal file
@ -0,0 +1,20 @@
|
||||
<html>
|
||||
<center>
|
||||
<h2>Primitive Stroking</h2>
|
||||
</center>
|
||||
|
||||
<p>In this demo we show some of the various types of pens that can be
|
||||
used in Qt.</p>
|
||||
|
||||
<p>Qt defines cap styles for how the end points are treated and join
|
||||
styles for how path segments are joined together. A standard set of
|
||||
predefined dash patterns are also included that can be used with
|
||||
<code>QPen</code>.</p>
|
||||
|
||||
<p>In addition to the predefined patterns available in
|
||||
<code>QPen</code> we also demonstrate direct use of the
|
||||
<code>QPainterPathStroker</code> class which can be used to define
|
||||
custom dash patterns. You can see this by enabling the
|
||||
<i>Custom Pattern</i> option.</p>
|
||||
|
||||
</html>
|
15
examples/widgets/painting/pathstroke/pathstroke.pro
Normal file
15
examples/widgets/painting/pathstroke/pathstroke.pro
Normal file
@ -0,0 +1,15 @@
|
||||
SOURCES += main.cpp pathstroke.cpp
|
||||
HEADERS += pathstroke.h
|
||||
|
||||
SHARED_FOLDER = ../shared
|
||||
|
||||
include($$SHARED_FOLDER/shared.pri)
|
||||
|
||||
RESOURCES += pathstroke.qrc
|
||||
|
||||
QT += widgets
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/widgets/painting/pathstroke
|
||||
INSTALLS += target
|
||||
|
6
examples/widgets/painting/pathstroke/pathstroke.qrc
Normal file
6
examples/widgets/painting/pathstroke/pathstroke.qrc
Normal file
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/res/pathstroke">
|
||||
<file>pathstroke.cpp</file>
|
||||
<file>pathstroke.html</file>
|
||||
</qresource>
|
||||
</RCC>
|
Reference in New Issue
Block a user