1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 ** This file is part of the demonstration applications of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
40 ****************************************************************************/
42 #include "pathstroke.h"
43 #include "arthurstyle.h"
44 #include "arthurwidgets.h"
48 extern void draw_round_rect(QPainter
*p
, const QRect
&bounds
, int radius
);
51 PathStrokeControls::PathStrokeControls(QWidget
* parent
, PathStrokeRenderer
* renderer
, bool smallScreen
)
54 m_renderer
= renderer
;
57 layoutForSmallScreens();
62 void PathStrokeControls::createCommonControls(QWidget
* parent
)
64 m_capGroup
= new QGroupBox(parent
);
65 m_capGroup
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Fixed
);
66 QRadioButton
*flatCap
= new QRadioButton(m_capGroup
);
67 QRadioButton
*squareCap
= new QRadioButton(m_capGroup
);
68 QRadioButton
*roundCap
= new QRadioButton(m_capGroup
);
69 m_capGroup
->setTitle(tr("Cap Style"));
70 flatCap
->setText(tr("Flat"));
71 squareCap
->setText(tr("Square"));
72 roundCap
->setText(tr("Round"));
73 flatCap
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
74 squareCap
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
75 roundCap
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
77 m_joinGroup
= new QGroupBox(parent
);
78 m_joinGroup
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Fixed
);
79 QRadioButton
*bevelJoin
= new QRadioButton(m_joinGroup
);
80 QRadioButton
*miterJoin
= new QRadioButton(m_joinGroup
);
81 QRadioButton
*roundJoin
= new QRadioButton(m_joinGroup
);
82 m_joinGroup
->setTitle(tr("Join Style"));
83 bevelJoin
->setText(tr("Bevel"));
84 miterJoin
->setText(tr("Miter"));
85 roundJoin
->setText(tr("Round"));
87 m_styleGroup
= new QGroupBox(parent
);
88 m_styleGroup
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Fixed
);
89 QRadioButton
*solidLine
= new QRadioButton(m_styleGroup
);
90 QRadioButton
*dashLine
= new QRadioButton(m_styleGroup
);
91 QRadioButton
*dotLine
= new QRadioButton(m_styleGroup
);
92 QRadioButton
*dashDotLine
= new QRadioButton(m_styleGroup
);
93 QRadioButton
*dashDotDotLine
= new QRadioButton(m_styleGroup
);
94 QRadioButton
*customDashLine
= new QRadioButton(m_styleGroup
);
95 m_styleGroup
->setTitle(tr("Pen Style"));
97 QPixmap
line_solid(":res/images/line_solid.png");
98 solidLine
->setIcon(line_solid
);
99 solidLine
->setIconSize(line_solid
.size());
100 QPixmap
line_dashed(":res/images/line_dashed.png");
101 dashLine
->setIcon(line_dashed
);
102 dashLine
->setIconSize(line_dashed
.size());
103 QPixmap
line_dotted(":res/images/line_dotted.png");
104 dotLine
->setIcon(line_dotted
);
105 dotLine
->setIconSize(line_dotted
.size());
106 QPixmap
line_dash_dot(":res/images/line_dash_dot.png");
107 dashDotLine
->setIcon(line_dash_dot
);
108 dashDotLine
->setIconSize(line_dash_dot
.size());
109 QPixmap
line_dash_dot_dot(":res/images/line_dash_dot_dot.png");
110 dashDotDotLine
->setIcon(line_dash_dot_dot
);
111 dashDotDotLine
->setIconSize(line_dash_dot_dot
.size());
112 customDashLine
->setText(tr("Custom"));
114 int fixedHeight
= bevelJoin
->sizeHint().height();
115 solidLine
->setFixedHeight(fixedHeight
);
116 dashLine
->setFixedHeight(fixedHeight
);
117 dotLine
->setFixedHeight(fixedHeight
);
118 dashDotLine
->setFixedHeight(fixedHeight
);
119 dashDotDotLine
->setFixedHeight(fixedHeight
);
121 m_pathModeGroup
= new QGroupBox(parent
);
122 m_pathModeGroup
->setSizePolicy(QSizePolicy::Minimum
, QSizePolicy::Fixed
);
123 QRadioButton
*curveMode
= new QRadioButton(m_pathModeGroup
);
124 QRadioButton
*lineMode
= new QRadioButton(m_pathModeGroup
);
125 m_pathModeGroup
->setTitle(tr("Line Style"));
126 curveMode
->setText(tr("Curves"));
127 lineMode
->setText(tr("Lines"));
131 QVBoxLayout
*capGroupLayout
= new QVBoxLayout(m_capGroup
);
132 capGroupLayout
->addWidget(flatCap
);
133 capGroupLayout
->addWidget(squareCap
);
134 capGroupLayout
->addWidget(roundCap
);
136 QVBoxLayout
*joinGroupLayout
= new QVBoxLayout(m_joinGroup
);
137 joinGroupLayout
->addWidget(bevelJoin
);
138 joinGroupLayout
->addWidget(miterJoin
);
139 joinGroupLayout
->addWidget(roundJoin
);
141 QVBoxLayout
*styleGroupLayout
= new QVBoxLayout(m_styleGroup
);
142 styleGroupLayout
->addWidget(solidLine
);
143 styleGroupLayout
->addWidget(dashLine
);
144 styleGroupLayout
->addWidget(dotLine
);
145 styleGroupLayout
->addWidget(dashDotLine
);
146 styleGroupLayout
->addWidget(dashDotDotLine
);
147 styleGroupLayout
->addWidget(customDashLine
);
149 QVBoxLayout
*pathModeGroupLayout
= new QVBoxLayout(m_pathModeGroup
);
150 pathModeGroupLayout
->addWidget(curveMode
);
151 pathModeGroupLayout
->addWidget(lineMode
);
155 connect(flatCap
, SIGNAL(clicked()), m_renderer
, SLOT(setFlatCap()));
156 connect(squareCap
, SIGNAL(clicked()), m_renderer
, SLOT(setSquareCap()));
157 connect(roundCap
, SIGNAL(clicked()), m_renderer
, SLOT(setRoundCap()));
159 connect(bevelJoin
, SIGNAL(clicked()), m_renderer
, SLOT(setBevelJoin()));
160 connect(miterJoin
, SIGNAL(clicked()), m_renderer
, SLOT(setMiterJoin()));
161 connect(roundJoin
, SIGNAL(clicked()), m_renderer
, SLOT(setRoundJoin()));
163 connect(curveMode
, SIGNAL(clicked()), m_renderer
, SLOT(setCurveMode()));
164 connect(lineMode
, SIGNAL(clicked()), m_renderer
, SLOT(setLineMode()));
166 connect(solidLine
, SIGNAL(clicked()), m_renderer
, SLOT(setSolidLine()));
167 connect(dashLine
, SIGNAL(clicked()), m_renderer
, SLOT(setDashLine()));
168 connect(dotLine
, SIGNAL(clicked()), m_renderer
, SLOT(setDotLine()));
169 connect(dashDotLine
, SIGNAL(clicked()), m_renderer
, SLOT(setDashDotLine()));
170 connect(dashDotDotLine
, SIGNAL(clicked()), m_renderer
, SLOT(setDashDotDotLine()));
171 connect(customDashLine
, SIGNAL(clicked()), m_renderer
, SLOT(setCustomDashLine()));
174 flatCap
->setChecked(true);
175 bevelJoin
->setChecked(true);
176 curveMode
->setChecked(true);
177 solidLine
->setChecked(true);
181 void PathStrokeControls::layoutForDesktop()
183 QGroupBox
*mainGroup
= new QGroupBox(this);
184 mainGroup
->setFixedWidth(180);
185 mainGroup
->setTitle(tr("Path Stroking"));
187 createCommonControls(mainGroup
);
189 QGroupBox
* penWidthGroup
= new QGroupBox(mainGroup
);
190 QSlider
*penWidth
= new QSlider(Qt::Horizontal
, penWidthGroup
);
191 penWidth
->setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
192 penWidthGroup
->setTitle(tr("Pen Width"));
193 penWidth
->setRange(0, 500);
195 QPushButton
*animated
= new QPushButton(mainGroup
);
196 animated
->setText(tr("Animate"));
197 animated
->setCheckable(true);
199 QPushButton
*showSourceButton
= new QPushButton(mainGroup
);
200 showSourceButton
->setText(tr("Show Source"));
201 #ifdef QT_OPENGL_SUPPORT
202 QPushButton
*enableOpenGLButton
= new QPushButton(mainGroup
);
203 enableOpenGLButton
->setText(tr("Use OpenGL"));
204 enableOpenGLButton
->setCheckable(true);
205 enableOpenGLButton
->setChecked(m_renderer
->usesOpenGL());
206 if (!QGLFormat::hasOpenGL())
207 enableOpenGLButton
->hide();
209 QPushButton
*whatsThisButton
= new QPushButton(mainGroup
);
210 whatsThisButton
->setText(tr("What's This?"));
211 whatsThisButton
->setCheckable(true);
215 QVBoxLayout
*penWidthLayout
= new QVBoxLayout(penWidthGroup
);
216 penWidthLayout
->addWidget(penWidth
);
218 QVBoxLayout
* mainLayout
= new QVBoxLayout(this);
219 mainLayout
->setMargin(0);
220 mainLayout
->addWidget(mainGroup
);
222 QVBoxLayout
*mainGroupLayout
= new QVBoxLayout(mainGroup
);
223 mainGroupLayout
->setMargin(3);
224 mainGroupLayout
->addWidget(m_capGroup
);
225 mainGroupLayout
->addWidget(m_joinGroup
);
226 mainGroupLayout
->addWidget(m_styleGroup
);
227 mainGroupLayout
->addWidget(penWidthGroup
);
228 mainGroupLayout
->addWidget(m_pathModeGroup
);
229 mainGroupLayout
->addWidget(animated
);
230 mainGroupLayout
->addStretch(1);
231 mainGroupLayout
->addWidget(showSourceButton
);
232 #ifdef QT_OPENGL_SUPPORT
233 mainGroupLayout
->addWidget(enableOpenGLButton
);
235 mainGroupLayout
->addWidget(whatsThisButton
);
238 // Set up connections
239 connect(animated
, SIGNAL(toggled(bool)),
240 m_renderer
, SLOT(setAnimation(bool)));
242 connect(penWidth
, SIGNAL(valueChanged(int)),
243 m_renderer
, SLOT(setPenWidth(int)));
245 connect(showSourceButton
, SIGNAL(clicked()), m_renderer
, SLOT(showSource()));
246 #ifdef QT_OPENGL_SUPPORT
247 connect(enableOpenGLButton
, SIGNAL(clicked(bool)), m_renderer
, SLOT(enableOpenGL(bool)));
249 connect(whatsThisButton
, SIGNAL(clicked(bool)), m_renderer
, SLOT(setDescriptionEnabled(bool)));
250 connect(m_renderer
, SIGNAL(descriptionEnabledChanged(bool)),
251 whatsThisButton
, SLOT(setChecked(bool)));
255 animated
->setChecked(true);
256 penWidth
->setValue(50);
260 void PathStrokeControls::layoutForSmallScreens()
262 createCommonControls(this);
264 m_capGroup
->layout()->setMargin(0);
265 m_joinGroup
->layout()->setMargin(0);
266 m_styleGroup
->layout()->setMargin(0);
267 m_pathModeGroup
->layout()->setMargin(0);
269 QPushButton
* okBtn
= new QPushButton(tr("OK"), this);
270 okBtn
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
271 okBtn
->setMinimumSize(100,okBtn
->minimumSize().height());
273 QPushButton
* quitBtn
= new QPushButton(tr("Quit"), this);
274 quitBtn
->setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
275 quitBtn
->setMinimumSize(100, okBtn
->minimumSize().height());
277 QLabel
*penWidthLabel
= new QLabel(tr(" Width:"));
278 QSlider
*penWidth
= new QSlider(Qt::Horizontal
, this);
279 penWidth
->setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
280 penWidth
->setRange(0, 500);
282 #ifdef QT_OPENGL_SUPPORT
283 QPushButton
*enableOpenGLButton
= new QPushButton(this);
284 enableOpenGLButton
->setText(tr("Use OpenGL"));
285 enableOpenGLButton
->setCheckable(true);
286 enableOpenGLButton
->setChecked(m_renderer
->usesOpenGL());
287 if (!QGLFormat::hasOpenGL())
288 enableOpenGLButton
->hide();
292 QHBoxLayout
*penWidthLayout
= new QHBoxLayout(0);
293 penWidthLayout
->addWidget(penWidthLabel
, 0, Qt::AlignRight
);
294 penWidthLayout
->addWidget(penWidth
);
296 QVBoxLayout
*leftLayout
= new QVBoxLayout(0);
297 leftLayout
->addWidget(m_capGroup
);
298 leftLayout
->addWidget(m_joinGroup
);
299 #ifdef QT_OPENGL_SUPPORT
300 leftLayout
->addWidget(enableOpenGLButton
);
302 leftLayout
->addLayout(penWidthLayout
);
304 QVBoxLayout
*rightLayout
= new QVBoxLayout(0);
305 rightLayout
->addWidget(m_styleGroup
);
306 rightLayout
->addWidget(m_pathModeGroup
);
308 QGridLayout
*mainLayout
= new QGridLayout(this);
309 mainLayout
->setMargin(0);
311 // Add spacers around the form items so we don't look stupid at higher resolutions
312 mainLayout
->addItem(new QSpacerItem(0,0), 0, 0, 1, 4);
313 mainLayout
->addItem(new QSpacerItem(0,0), 1, 0, 2, 1);
314 mainLayout
->addItem(new QSpacerItem(0,0), 1, 3, 2, 1);
315 mainLayout
->addItem(new QSpacerItem(0,0), 3, 0, 1, 4);
317 mainLayout
->addLayout(leftLayout
, 1, 1);
318 mainLayout
->addLayout(rightLayout
, 1, 2);
319 mainLayout
->addWidget(quitBtn
, 2, 1, Qt::AlignHCenter
| Qt::AlignTop
);
320 mainLayout
->addWidget(okBtn
, 2, 2, Qt::AlignHCenter
| Qt::AlignTop
);
322 #ifdef QT_OPENGL_SUPPORT
323 connect(enableOpenGLButton
, SIGNAL(clicked(bool)), m_renderer
, SLOT(enableOpenGL(bool)));
326 connect(penWidth
, SIGNAL(valueChanged(int)), m_renderer
, SLOT(setPenWidth(int)));
327 connect(quitBtn
, SIGNAL(clicked()), this, SLOT(emitQuitSignal()));
328 connect(okBtn
, SIGNAL(clicked()), this, SLOT(emitOkSignal()));
330 m_renderer
->setAnimation(true);
331 penWidth
->setValue(50);
334 void PathStrokeControls::emitQuitSignal()
335 { emit
quitPressed(); }
337 void PathStrokeControls::emitOkSignal()
338 { emit
okPressed(); }
341 PathStrokeWidget::PathStrokeWidget(bool smallScreen
)
343 setWindowTitle(tr("Path Stroking"));
345 // Widget construction and property setting
346 m_renderer
= new PathStrokeRenderer(this, smallScreen
);
348 m_controls
= new PathStrokeControls(0, m_renderer
, smallScreen
);
351 QHBoxLayout
*viewLayout
= new QHBoxLayout(this);
352 viewLayout
->addWidget(m_renderer
);
355 viewLayout
->addWidget(m_controls
);
357 m_renderer
->loadSourceFile(":res/pathstroke/pathstroke.cpp");
358 m_renderer
->loadDescription(":res/pathstroke/pathstroke.html");
360 connect(m_renderer
, SIGNAL(clicked()), this, SLOT(showControls()));
361 connect(m_controls
, SIGNAL(okPressed()), this, SLOT(hideControls()));
362 connect(m_controls
, SIGNAL(quitPressed()), QApplication::instance(), SLOT(quit()));
366 void PathStrokeWidget::showControls()
368 m_controls
->showFullScreen();
372 void PathStrokeWidget::hideControls()
378 void PathStrokeWidget::setStyle( QStyle
* style
)
380 QWidget::setStyle(style
);
383 m_controls
->setStyle(style
);
385 QList
<QWidget
*> widgets
= qFindChildren
<QWidget
*>(m_controls
);
386 foreach (QWidget
*w
, widgets
)
392 PathStrokeRenderer::PathStrokeRenderer(QWidget
*parent
, bool smallScreen
)
393 : ArthurFrame(parent
)
395 m_smallScreen
= smallScreen
;
398 m_capStyle
= Qt::FlatCap
;
399 m_joinStyle
= Qt::BevelJoin
;
400 m_pathMode
= CurveMode
;
402 m_penStyle
= Qt::SolidLine
;
403 m_wasAnimated
= true;
404 setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
407 void PathStrokeRenderer::paint(QPainter
*painter
)
409 if (m_points
.isEmpty())
412 painter
->setRenderHint(QPainter::Antialiasing
);
414 QPalette pal
= palette();
415 painter
->setPen(Qt::NoPen
);
417 // Construct the path
419 path
.moveTo(m_points
.at(0));
421 if (m_pathMode
== LineMode
) {
422 for (int i
=1; i
<m_points
.size(); ++i
) {
423 path
.lineTo(m_points
.at(i
));
427 while (i
+ 2 < m_points
.size()) {
428 path
.cubicTo(m_points
.at(i
), m_points
.at(i
+1), m_points
.at(i
+2));
431 while (i
< m_points
.size()) {
432 path
.lineTo(m_points
.at(i
));
442 if (m_penStyle
== Qt::NoPen
) {
443 QPainterPathStroker stroker
;
444 stroker
.setWidth(m_penWidth
);
445 stroker
.setJoinStyle(m_joinStyle
);
446 stroker
.setCapStyle(m_capStyle
);
448 QVector
<qreal
> dashes
;
456 stroker
.setDashPattern(dashes
);
457 QPainterPath stroke
= stroker
.createStroke(path
);
458 painter
->fillPath(stroke
, lg
);
461 QPen
pen(lg
, m_penWidth
, m_penStyle
, m_capStyle
, m_joinStyle
);
462 painter
->strokePath(path
, pen
);
467 // Draw the control points
468 painter
->setPen(QColor(50, 100, 120, 200));
469 painter
->setBrush(QColor(200, 200, 210, 120));
470 for (int i
=0; i
<m_points
.size(); ++i
) {
471 QPointF pos
= m_points
.at(i
);
472 painter
->drawEllipse(QRectF(pos
.x() - m_pointSize
,
473 pos
.y() - m_pointSize
,
474 m_pointSize
*2, m_pointSize
*2));
476 painter
->setPen(QPen(Qt::lightGray
, 0, Qt::SolidLine
));
477 painter
->setBrush(Qt::NoBrush
);
478 painter
->drawPolyline(m_points
);
483 void PathStrokeRenderer::initializePoints()
490 qreal rot
= 360 / count
;
491 QPointF
center(width() / 2, height() / 2);
496 for (int i
=0; i
<count
; ++i
) {
497 m_vectors
<< QPointF(.1f
, .25f
) * (m
* vm
);
498 m_points
<< QPointF(0, 100) * m
+ center
;
503 void PathStrokeRenderer::updatePoints()
507 qreal right
= width() - pad
;
509 qreal bottom
= height() - pad
;
511 Q_ASSERT(m_points
.size() == m_vectors
.size());
512 for (int i
=0; i
<m_points
.size(); ++i
) {
514 if (i
== m_activePoint
)
517 QPointF pos
= m_points
.at(i
);
518 QPointF vec
= m_vectors
.at(i
);
520 if (pos
.x() < left
|| pos
.x() > right
) {
522 pos
.setX(pos
.x() < left
? left
: right
);
523 } if (pos
.y() < top
|| pos
.y() > bottom
) {
525 pos
.setY(pos
.y() < top
? top
: bottom
);
533 void PathStrokeRenderer::mousePressEvent(QMouseEvent
*e
)
535 setDescriptionEnabled(false);
538 for (int i
=0; i
<m_points
.size(); ++i
) {
539 qreal d
= QLineF(e
->pos(), m_points
.at(i
)).length();
540 if ((distance
< 0 && d
< 8 * m_pointSize
) || d
< distance
) {
546 if (m_activePoint
!= -1) {
547 m_wasAnimated
= m_timer
.isActive();
552 // If we're not running in small screen mode, always assume we're dragging
553 m_mouseDrag
= !m_smallScreen
;
554 m_mousePress
= e
->pos();
557 void PathStrokeRenderer::mouseMoveEvent(QMouseEvent
*e
)
559 // If we've moved more then 25 pixels, assume user is dragging
560 if (!m_mouseDrag
&& QPoint(m_mousePress
- e
->pos()).manhattanLength() > 25)
563 if (m_mouseDrag
&& m_activePoint
>= 0 && m_activePoint
< m_points
.size()) {
564 m_points
[m_activePoint
] = e
->pos();
569 void PathStrokeRenderer::mouseReleaseEvent(QMouseEvent
*)
572 setAnimation(m_wasAnimated
);
574 if (!m_mouseDrag
&& m_smallScreen
)
578 void PathStrokeRenderer::timerEvent(QTimerEvent
*e
)
580 if (e
->timerId() == m_timer
.timerId()) {
582 QApplication::syncX();
583 } // else if (e->timerId() == m_fpsTimer.timerId()) {
584 // emit frameRate(m_frameCount);
589 void PathStrokeRenderer::setAnimation(bool animation
)
592 // m_fpsTimer.stop();
595 m_timer
.start(25, this);
596 // m_fpsTimer.start(1000, this);