1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | #include "qpen.h" |
40 | #include "qpen_p.h" |
41 | #include "qdatastream.h" |
42 | #include "qvariant.h" |
43 | #include "qbrush.h" |
44 | |
45 | #include <qdebug.h> |
46 | |
47 | QT_BEGIN_NAMESPACE |
48 | |
49 | typedef QPenPrivate QPenData; |
50 | |
51 | /*! |
52 | \class QPen |
53 | \inmodule QtGui |
54 | \ingroup painting |
55 | \ingroup shared |
56 | |
57 | |
58 | \brief The QPen class defines how a QPainter should draw lines and outlines |
59 | of shapes. |
60 | |
61 | A pen has a style(), width(), brush(), capStyle() and joinStyle(). |
62 | |
63 | The pen style defines the line type. The brush is used to fill |
64 | strokes generated with the pen. Use the QBrush class to specify |
65 | fill styles. The cap style determines the line end caps that can |
66 | be drawn using QPainter, while the join style describes how joins |
67 | between two lines are drawn. The pen width can be specified in |
68 | both integer (width()) and floating point (widthF()) precision. A |
69 | line width of zero indicates a cosmetic pen. This means that the |
70 | pen width is always drawn one pixel wide, independent of the \l |
71 | {QPainter#Coordinate Transformations}{transformation} set on the |
72 | painter. |
73 | |
74 | The various settings can easily be modified using the |
75 | corresponding setStyle(), setWidth(), setBrush(), setCapStyle() |
76 | and setJoinStyle() functions (note that the painter's pen must be |
77 | reset when altering the pen's properties). |
78 | |
79 | For example: |
80 | |
81 | \snippet code/src_gui_painting_qpen.cpp 0 |
82 | |
83 | which is equivalent to |
84 | |
85 | \snippet code/src_gui_painting_qpen.cpp 1 |
86 | |
87 | The default pen is a solid black brush with 1 width, square |
88 | cap style (Qt::SquareCap), and bevel join style (Qt::BevelJoin). |
89 | |
90 | In addition QPen provides the color() and setColor() |
91 | convenience functions to extract and set the color of the pen's |
92 | brush, respectively. Pens may also be compared and streamed. |
93 | |
94 | For more information about painting in general, see the \l{Paint |
95 | System} documentation. |
96 | |
97 | \tableofcontents |
98 | |
99 | \section1 Pen Style |
100 | |
101 | Qt provides several built-in styles represented by the |
102 | Qt::PenStyle enum: |
103 | |
104 | \table |
105 | \row |
106 | \li \inlineimage qpen-solid.png |
107 | \li \inlineimage qpen-dash.png |
108 | \li \inlineimage qpen-dot.png |
109 | \row |
110 | \li Qt::SolidLine |
111 | \li Qt::DashLine |
112 | \li Qt::DotLine |
113 | \row |
114 | \li \inlineimage qpen-dashdot.png |
115 | \li \inlineimage qpen-dashdotdot.png |
116 | \li \inlineimage qpen-custom.png |
117 | \row |
118 | \li Qt::DashDotLine |
119 | \li Qt::DashDotDotLine |
120 | \li Qt::CustomDashLine |
121 | \endtable |
122 | |
123 | Simply use the setStyle() function to convert the pen style to |
124 | either of the built-in styles, except the Qt::CustomDashLine style |
125 | which we will come back to shortly. Setting the style to Qt::NoPen |
126 | tells the painter to not draw lines or outlines. The default pen |
127 | style is Qt::SolidLine. |
128 | |
129 | Since Qt 4.1 it is also possible to specify a custom dash pattern |
130 | using the setDashPattern() function which implicitly converts the |
131 | style of the pen to Qt::CustomDashLine. The pattern argument, a |
132 | QList, must be specified as an even number of \l qreal entries |
133 | where the entries 1, 3, 5... are the dashes and 2, 4, 6... are the |
134 | spaces. For example, the custom pattern shown above is created |
135 | using the following code: |
136 | |
137 | \snippet code/src_gui_painting_qpen.cpp 2 |
138 | |
139 | Note that the dash pattern is specified in units of the pens |
140 | width, e.g. a dash of length 5 in width 10 is 50 pixels long. |
141 | |
142 | The currently set dash pattern can be retrieved using the |
143 | dashPattern() function. Use the isSolid() function to determine |
144 | whether the pen has a solid fill, or not. |
145 | |
146 | \section1 Cap Style |
147 | |
148 | The cap style defines how the end points of lines are drawn using |
149 | QPainter. The cap style only apply to wide lines, i.e. when the |
150 | width is 1 or greater. The Qt::PenCapStyle enum provides the |
151 | following styles: |
152 | |
153 | \table |
154 | \row |
155 | \li \inlineimage qpen-square.png |
156 | \li \inlineimage qpen-flat.png |
157 | \li \inlineimage qpen-roundcap.png |
158 | \row |
159 | \li Qt::SquareCap |
160 | \li Qt::FlatCap |
161 | \li Qt::RoundCap |
162 | \endtable |
163 | |
164 | The Qt::SquareCap style is a square line end that covers the end |
165 | point and extends beyond it by half the line width. The |
166 | Qt::FlatCap style is a square line end that does not cover the end |
167 | point of the line. And the Qt::RoundCap style is a rounded line |
168 | end covering the end point. |
169 | |
170 | The default is Qt::SquareCap. |
171 | |
172 | Whether or not end points are drawn when the pen width is 0 or 1 |
173 | depends on the cap style. Using Qt::SquareCap or Qt::RoundCap they |
174 | are drawn, using Qt::FlatCap they are not drawn. |
175 | |
176 | \section1 Join Style |
177 | |
178 | The join style defines how joins between two connected lines can |
179 | be drawn using QPainter. The join style only apply to wide lines, |
180 | i.e. when the width is 1 or greater. The Qt::PenJoinStyle enum |
181 | provides the following styles: |
182 | |
183 | \table |
184 | \row |
185 | \li \inlineimage qpen-bevel.png |
186 | \li \inlineimage qpen-miter.png |
187 | \li \inlineimage qpen-roundjoin.png |
188 | \row |
189 | \li Qt::BevelJoin |
190 | \li Qt::MiterJoin |
191 | \li Qt::RoundJoin |
192 | \endtable |
193 | |
194 | The Qt::BevelJoin style fills the triangular notch between the two |
195 | lines. The Qt::MiterJoin style extends the lines to meet at an |
196 | angle. And the Qt::RoundJoin style fills a circular arc between |
197 | the two lines. |
198 | |
199 | The default is Qt::BevelJoin. |
200 | |
201 | \image qpen-miterlimit.png |
202 | |
203 | When the Qt::MiterJoin style is applied, it is possible to use the |
204 | setMiterLimit() function to specify how far the miter join can |
205 | extend from the join point. The miterLimit() is used to reduce |
206 | artifacts between line joins where the lines are close to |
207 | parallel. |
208 | |
209 | The miterLimit() must be specified in units of the pens width, |
210 | e.g. a miter limit of 5 in width 10 is 50 pixels long. The |
211 | default miter limit is 2, i.e. twice the pen width in pixels. |
212 | |
213 | \table 100% |
214 | \row |
215 | \li \inlineimage qpen-demo.png |
216 | \li \b {\l {painting/pathstroke}{The Path Stroking Example}} |
217 | |
218 | The Path Stroking example shows Qt's built-in dash patterns and shows |
219 | how custom patterns can be used to extend the range of available |
220 | patterns. |
221 | \endtable |
222 | |
223 | \sa QPainter, QBrush, {painting/pathstroke}{Path Stroking Example}, |
224 | {Scribble Example} |
225 | */ |
226 | |
227 | /*! |
228 | \internal |
229 | */ |
230 | inline QPenPrivate::QPenPrivate(const QBrush &_brush, qreal _width, Qt::PenStyle penStyle, |
231 | Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle, bool _defaultWidth) |
232 | : ref(1), dashOffset(0), miterLimit(2), |
233 | cosmetic(false), defaultWidth(_defaultWidth) |
234 | { |
235 | width = _width; |
236 | brush = _brush; |
237 | style = penStyle; |
238 | capStyle = _capStyle; |
239 | joinStyle = _joinStyle; |
240 | } |
241 | |
242 | static const Qt::PenCapStyle qpen_default_cap = Qt::SquareCap; |
243 | static const Qt::PenJoinStyle qpen_default_join = Qt::BevelJoin; |
244 | |
245 | class QPenDataHolder |
246 | { |
247 | public: |
248 | QPenData *pen; |
249 | QPenDataHolder(const QBrush &brush, qreal width, Qt::PenStyle penStyle, |
250 | Qt::PenCapStyle penCapStyle, Qt::PenJoinStyle _joinStyle) |
251 | : pen(new QPenData(brush, width, penStyle, penCapStyle, _joinStyle)) |
252 | { } |
253 | ~QPenDataHolder() |
254 | { |
255 | if (!pen->ref.deref()) |
256 | delete pen; |
257 | pen = nullptr; |
258 | } |
259 | }; |
260 | |
261 | Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, defaultPenInstance, |
262 | (Qt::black, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join)) |
263 | Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, nullPenInstance, |
264 | (Qt::black, 1, Qt::NoPen, qpen_default_cap, qpen_default_join)) |
265 | |
266 | /*! |
267 | Constructs a default black solid line pen with 1 width. |
268 | */ |
269 | |
270 | QPen::QPen() |
271 | { |
272 | d = defaultPenInstance()->pen; |
273 | d->ref.ref(); |
274 | } |
275 | |
276 | /*! |
277 | Constructs a black pen with 1 width and the given \a style. |
278 | |
279 | \sa setStyle() |
280 | */ |
281 | |
282 | QPen::QPen(Qt::PenStyle style) |
283 | { |
284 | if (style == Qt::NoPen) { |
285 | d = nullPenInstance()->pen; |
286 | d->ref.ref(); |
287 | } else { |
288 | d = new QPenData(Qt::black, 1, style, qpen_default_cap, qpen_default_join); |
289 | } |
290 | } |
291 | |
292 | |
293 | /*! |
294 | Constructs a solid line pen with 1 width and the given \a color. |
295 | |
296 | \sa setBrush(), setColor() |
297 | */ |
298 | |
299 | QPen::QPen(const QColor &color) |
300 | { |
301 | d = new QPenData(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join); |
302 | } |
303 | |
304 | |
305 | /*! |
306 | \fn QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle style, Qt::PenCapStyle cap, Qt::PenJoinStyle join) |
307 | |
308 | Constructs a pen with the specified \a brush, \a width, pen \a style, |
309 | \a cap style and \a join style. |
310 | |
311 | \sa setBrush(), setWidth(), setStyle(), setCapStyle(), setJoinStyle() |
312 | */ |
313 | |
314 | QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c, Qt::PenJoinStyle j) |
315 | { |
316 | d = new QPenData(brush, width, s, c, j, false); |
317 | } |
318 | |
319 | /*! |
320 | \fn QPen::QPen(const QPen &pen) |
321 | |
322 | Constructs a pen that is a copy of the given \a pen. |
323 | */ |
324 | |
325 | QPen::QPen(const QPen &p) noexcept |
326 | { |
327 | d = p.d; |
328 | if (d) |
329 | d->ref.ref(); |
330 | } |
331 | |
332 | |
333 | /*! |
334 | \fn QPen::QPen(QPen &&pen) |
335 | \since 5.4 |
336 | |
337 | Constructs a pen that is moved from the given \a pen. |
338 | |
339 | The moved-from pen can only be assigned to, copied, or |
340 | destroyed. Any other operation (prior to assignment) leads to |
341 | undefined behavior. |
342 | */ |
343 | |
344 | /*! |
345 | Destroys the pen. |
346 | */ |
347 | |
348 | QPen::~QPen() |
349 | { |
350 | if (d && !d->ref.deref()) |
351 | delete d; |
352 | } |
353 | |
354 | /*! |
355 | \fn void QPen::detach() |
356 | Detaches from shared pen data to make sure that this pen is the |
357 | only one referring the data. |
358 | |
359 | If multiple pens share common data, this pen dereferences the data |
360 | and gets a copy of the data. Nothing is done if there is just a |
361 | single reference. |
362 | */ |
363 | |
364 | void QPen::detach() |
365 | { |
366 | if (d->ref.loadRelaxed() == 1) |
367 | return; |
368 | |
369 | QPenData *x = new QPenData(*static_cast<QPenData *>(d)); |
370 | if (!d->ref.deref()) |
371 | delete d; |
372 | x->ref.storeRelaxed(1); |
373 | d = x; |
374 | } |
375 | |
376 | |
377 | /*! |
378 | \fn QPen &QPen::operator=(const QPen &pen) |
379 | |
380 | Assigns the given \a pen to this pen and returns a reference to |
381 | this pen. |
382 | */ |
383 | |
384 | QPen &QPen::operator=(const QPen &p) noexcept |
385 | { |
386 | QPen(p).swap(*this); |
387 | return *this; |
388 | } |
389 | |
390 | /*! |
391 | \fn QPen &QPen::operator=(QPen &&other) |
392 | |
393 | Move-assigns \a other to this QPen instance. |
394 | |
395 | \since 5.2 |
396 | */ |
397 | |
398 | /*! |
399 | \fn void QPen::swap(QPen &other) |
400 | \since 4.8 |
401 | |
402 | Swaps pen \a other with this pen. This operation is very |
403 | fast and never fails. |
404 | */ |
405 | |
406 | /*! |
407 | Returns the pen as a QVariant. |
408 | */ |
409 | QPen::operator QVariant() const |
410 | { |
411 | return QVariant::fromValue(*this); |
412 | } |
413 | |
414 | /*! |
415 | \fn Qt::PenStyle QPen::style() const |
416 | |
417 | Returns the pen style. |
418 | |
419 | \sa setStyle(), {QPen#Pen Style}{Pen Style} |
420 | */ |
421 | Qt::PenStyle QPen::style() const |
422 | { |
423 | return d->style; |
424 | } |
425 | /*! |
426 | \fn void QPen::setStyle(Qt::PenStyle style) |
427 | |
428 | Sets the pen style to the given \a style. |
429 | |
430 | See the \l Qt::PenStyle documentation for a list of the available |
431 | styles. Since Qt 4.1 it is also possible to specify a custom dash |
432 | pattern using the setDashPattern() function which implicitly |
433 | converts the style of the pen to Qt::CustomDashLine. |
434 | |
435 | \note This function resets the dash offset to zero. |
436 | |
437 | \sa style(), {QPen#Pen Style}{Pen Style} |
438 | */ |
439 | |
440 | void QPen::setStyle(Qt::PenStyle s) |
441 | { |
442 | if (d->style == s) |
443 | return; |
444 | detach(); |
445 | d->style = s; |
446 | QPenData *dd = static_cast<QPenData *>(d); |
447 | dd->dashPattern.clear(); |
448 | dd->dashOffset = 0; |
449 | } |
450 | |
451 | /*! |
452 | Returns the dash pattern of this pen. |
453 | |
454 | \sa style(), isSolid() |
455 | */ |
456 | QList<qreal> QPen::dashPattern() const |
457 | { |
458 | QPenData *dd = static_cast<QPenData *>(d); |
459 | if (d->style == Qt::SolidLine || d->style == Qt::NoPen) { |
460 | return QList<qreal>(); |
461 | } else if (dd->dashPattern.isEmpty()) { |
462 | const qreal space = 2; |
463 | const qreal dot = 1; |
464 | const qreal dash = 4; |
465 | |
466 | switch (d->style) { |
467 | case Qt::DashLine: |
468 | dd->dashPattern.reserve(2); |
469 | dd->dashPattern << dash << space; |
470 | break; |
471 | case Qt::DotLine: |
472 | dd->dashPattern.reserve(2); |
473 | dd->dashPattern << dot << space; |
474 | break; |
475 | case Qt::DashDotLine: |
476 | dd->dashPattern.reserve(4); |
477 | dd->dashPattern << dash << space << dot << space; |
478 | break; |
479 | case Qt::DashDotDotLine: |
480 | dd->dashPattern.reserve(6); |
481 | dd->dashPattern << dash << space << dot << space << dot << space; |
482 | break; |
483 | default: |
484 | break; |
485 | } |
486 | } |
487 | return dd->dashPattern; |
488 | } |
489 | |
490 | /*! |
491 | Sets the dash pattern for this pen to the given \a pattern. This |
492 | implicitly converts the style of the pen to Qt::CustomDashLine. |
493 | |
494 | The pattern must be specified as an even number of positive entries |
495 | where the entries 1, 3, 5... are the dashes and 2, 4, 6... are the |
496 | spaces. For example: |
497 | |
498 | \table 100% |
499 | \row |
500 | \li \inlineimage qpen-custom.png |
501 | \li |
502 | \snippet code/src_gui_painting_qpen.cpp 3 |
503 | \endtable |
504 | |
505 | The dash pattern is specified in units of the pens width; e.g. a |
506 | dash of length 5 in width 10 is 50 pixels long. Note that a pen |
507 | with zero width is equivalent to a cosmetic pen with a width of 1 |
508 | pixel. |
509 | |
510 | Each dash is also subject to cap styles so a dash of 1 with square |
511 | cap set will extend 0.5 pixels out in each direction resulting in |
512 | a total width of 2. |
513 | |
514 | Note that the default cap style is Qt::SquareCap, meaning that a |
515 | square line end covers the end point and extends beyond it by half |
516 | the line width. |
517 | |
518 | \sa setStyle(), dashPattern(), setCapStyle(), setCosmetic() |
519 | */ |
520 | void QPen::setDashPattern(const QList<qreal> &pattern) |
521 | { |
522 | if (pattern.isEmpty()) |
523 | return; |
524 | detach(); |
525 | |
526 | QPenData *dd = static_cast<QPenData *>(d); |
527 | dd->dashPattern = pattern; |
528 | d->style = Qt::CustomDashLine; |
529 | |
530 | if ((dd->dashPattern.size() % 2) == 1) { |
531 | qWarning("QPen::setDashPattern: Pattern not of even length" ); |
532 | dd->dashPattern << 1; |
533 | } |
534 | } |
535 | |
536 | |
537 | /*! |
538 | Returns the dash offset for the pen. |
539 | |
540 | \sa setDashOffset() |
541 | */ |
542 | qreal QPen::dashOffset() const |
543 | { |
544 | QPenData *dd = static_cast<QPenData *>(d); |
545 | return dd->dashOffset; |
546 | } |
547 | /*! |
548 | Sets the dash offset (the starting point on the dash pattern) for this pen |
549 | to the \a offset specified. The offset is measured in terms of the units used |
550 | to specify the dash pattern. |
551 | |
552 | \table |
553 | \row \li \inlineimage qpen-dashpattern.png |
554 | \li For example, a pattern where each stroke is four units long, followed by a gap |
555 | of two units, will begin with the stroke when drawn as a line. |
556 | |
557 | However, if the dash offset is set to 4.0, any line drawn will begin with the gap. |
558 | Values of the offset up to 4.0 will cause part of the stroke to be drawn first, |
559 | and values of the offset between 4.0 and 6.0 will cause the line to begin with |
560 | part of the gap. |
561 | \endtable |
562 | |
563 | \note This implicitly converts the style of the pen to Qt::CustomDashLine. |
564 | */ |
565 | void QPen::setDashOffset(qreal offset) |
566 | { |
567 | if (qFuzzyCompare(offset, static_cast<QPenData *>(d)->dashOffset)) |
568 | return; |
569 | detach(); |
570 | QPenData *dd = static_cast<QPenData *>(d); |
571 | dd->dashOffset = offset; |
572 | if (d->style != Qt::CustomDashLine) { |
573 | dd->dashPattern = dashPattern(); |
574 | d->style = Qt::CustomDashLine; |
575 | } |
576 | } |
577 | |
578 | /*! |
579 | Returns the miter limit of the pen. The miter limit is only |
580 | relevant when the join style is set to Qt::MiterJoin. |
581 | |
582 | \sa setMiterLimit(), {QPen#Join Style}{Join Style} |
583 | */ |
584 | qreal QPen::miterLimit() const |
585 | { |
586 | const QPenData *dd = static_cast<QPenData *>(d); |
587 | return dd->miterLimit; |
588 | } |
589 | |
590 | /*! |
591 | Sets the miter limit of this pen to the given \a limit. |
592 | |
593 | \image qpen-miterlimit.png |
594 | |
595 | The miter limit describes how far a miter join can extend from the |
596 | join point. This is used to reduce artifacts between line joins |
597 | where the lines are close to parallel. |
598 | |
599 | This value does only have effect when the pen style is set to |
600 | Qt::MiterJoin. The value is specified in units of the pen's width, |
601 | e.g. a miter limit of 5 in width 10 is 50 pixels long. The default |
602 | miter limit is 2, i.e. twice the pen width in pixels. |
603 | |
604 | \sa miterLimit(), setJoinStyle(), {QPen#Join Style}{Join Style} |
605 | */ |
606 | void QPen::setMiterLimit(qreal limit) |
607 | { |
608 | detach(); |
609 | QPenData *dd = static_cast<QPenData *>(d); |
610 | dd->miterLimit = limit; |
611 | } |
612 | |
613 | |
614 | /*! |
615 | \fn qreal QPen::width() const |
616 | |
617 | Returns the pen width with integer precision. |
618 | |
619 | \sa setWidth(), widthF() |
620 | */ |
621 | |
622 | int QPen::width() const |
623 | { |
624 | return qRound(d->width); |
625 | } |
626 | |
627 | /*! |
628 | \fn qreal QPen::widthF() const |
629 | |
630 | Returns the pen width with floating point precision. |
631 | |
632 | \sa setWidthF(), width() |
633 | */ |
634 | qreal QPen::widthF() const |
635 | { |
636 | return d->width; |
637 | } |
638 | |
639 | /*! |
640 | \fn QPen::setWidth(int width) |
641 | |
642 | Sets the pen width to the given \a width in pixels with integer |
643 | precision. |
644 | |
645 | A line width of zero indicates a cosmetic pen. This means that the |
646 | pen width is always drawn one pixel wide, independent of the \l |
647 | {QPainter#Coordinate Transformations}{transformation} set on the |
648 | painter. |
649 | |
650 | Setting a pen width with a negative value is not supported. |
651 | |
652 | \sa setWidthF(), width() |
653 | */ |
654 | void QPen::setWidth(int width) |
655 | { |
656 | if (width < 0) |
657 | qWarning("QPen::setWidth: Setting a pen width with a negative value is not defined" ); |
658 | if ((qreal)width == d->width) |
659 | return; |
660 | detach(); |
661 | d->width = width; |
662 | } |
663 | |
664 | /*! |
665 | Sets the pen width to the given \a width in pixels with floating point |
666 | precision. |
667 | |
668 | A line width of zero indicates a cosmetic pen. This means that the |
669 | pen width is always drawn one pixel wide, independent of the \l |
670 | {QPainter#Coordinate Transformations}{transformation} on the |
671 | painter. |
672 | |
673 | Setting a pen width with a negative value is not supported. |
674 | |
675 | \sa setWidth(), widthF() |
676 | */ |
677 | |
678 | void QPen::setWidthF(qreal width) |
679 | { |
680 | if (width < 0.f) { |
681 | qWarning("QPen::setWidthF: Setting a pen width with a negative value is not defined" ); |
682 | return; |
683 | } |
684 | if (qAbs(d->width - width) < 0.00000001f) |
685 | return; |
686 | detach(); |
687 | d->width = width; |
688 | d->defaultWidth = false; |
689 | } |
690 | |
691 | |
692 | /*! |
693 | Returns the pen's cap style. |
694 | |
695 | \sa setCapStyle(), {QPen#Cap Style}{Cap Style} |
696 | */ |
697 | Qt::PenCapStyle QPen::capStyle() const |
698 | { |
699 | return d->capStyle; |
700 | } |
701 | |
702 | /*! |
703 | \fn void QPen::setCapStyle(Qt::PenCapStyle style) |
704 | |
705 | Sets the pen's cap style to the given \a style. The default value |
706 | is Qt::SquareCap. |
707 | |
708 | \sa capStyle(), {QPen#Cap Style}{Cap Style} |
709 | */ |
710 | |
711 | void QPen::setCapStyle(Qt::PenCapStyle c) |
712 | { |
713 | if (d->capStyle == c) |
714 | return; |
715 | detach(); |
716 | d->capStyle = c; |
717 | } |
718 | |
719 | /*! |
720 | Returns the pen's join style. |
721 | |
722 | \sa setJoinStyle(), {QPen#Join Style}{Join Style} |
723 | */ |
724 | Qt::PenJoinStyle QPen::joinStyle() const |
725 | { |
726 | return d->joinStyle; |
727 | } |
728 | |
729 | /*! |
730 | \fn void QPen::setJoinStyle(Qt::PenJoinStyle style) |
731 | |
732 | Sets the pen's join style to the given \a style. The default value |
733 | is Qt::BevelJoin. |
734 | |
735 | \sa joinStyle(), {QPen#Join Style}{Join Style} |
736 | */ |
737 | |
738 | void QPen::setJoinStyle(Qt::PenJoinStyle j) |
739 | { |
740 | if (d->joinStyle == j) |
741 | return; |
742 | detach(); |
743 | d->joinStyle = j; |
744 | } |
745 | |
746 | /*! |
747 | \fn const QColor &QPen::color() const |
748 | |
749 | Returns the color of this pen's brush. |
750 | |
751 | \sa brush(), setColor() |
752 | */ |
753 | QColor QPen::color() const |
754 | { |
755 | return d->brush.color(); |
756 | } |
757 | |
758 | /*! |
759 | \fn void QPen::setColor(const QColor &color) |
760 | |
761 | Sets the color of this pen's brush to the given \a color. |
762 | |
763 | \sa setBrush(), color() |
764 | */ |
765 | |
766 | void QPen::setColor(const QColor &c) |
767 | { |
768 | detach(); |
769 | d->brush = QBrush(c); |
770 | } |
771 | |
772 | |
773 | /*! |
774 | Returns the brush used to fill strokes generated with this pen. |
775 | */ |
776 | QBrush QPen::brush() const |
777 | { |
778 | return d->brush; |
779 | } |
780 | |
781 | /*! |
782 | Sets the brush used to fill strokes generated with this pen to the given |
783 | \a brush. |
784 | |
785 | \sa brush(), setColor() |
786 | */ |
787 | void QPen::setBrush(const QBrush &brush) |
788 | { |
789 | detach(); |
790 | d->brush = brush; |
791 | } |
792 | |
793 | |
794 | /*! |
795 | Returns \c true if the pen has a solid fill, otherwise false. |
796 | |
797 | \sa style(), dashPattern() |
798 | */ |
799 | bool QPen::isSolid() const |
800 | { |
801 | return d->brush.style() == Qt::SolidPattern; |
802 | } |
803 | |
804 | |
805 | /*! |
806 | Returns \c true if the pen is cosmetic; otherwise returns \c false. |
807 | |
808 | Cosmetic pens are used to draw strokes that have a constant width |
809 | regardless of any transformations applied to the QPainter they are |
810 | used with. Drawing a shape with a cosmetic pen ensures that its |
811 | outline will have the same thickness at different scale factors. |
812 | |
813 | A zero width pen is cosmetic by default. |
814 | |
815 | \sa setCosmetic(), widthF() |
816 | */ |
817 | |
818 | bool QPen::isCosmetic() const |
819 | { |
820 | QPenData *dd = static_cast<QPenData *>(d); |
821 | return (dd->cosmetic == true) || d->width == 0; |
822 | } |
823 | |
824 | |
825 | /*! |
826 | Sets this pen to cosmetic or non-cosmetic, depending on the value of |
827 | \a cosmetic. |
828 | |
829 | \sa isCosmetic() |
830 | */ |
831 | |
832 | void QPen::setCosmetic(bool cosmetic) |
833 | { |
834 | detach(); |
835 | QPenData *dd = static_cast<QPenData *>(d); |
836 | dd->cosmetic = cosmetic; |
837 | } |
838 | |
839 | |
840 | |
841 | /*! |
842 | \fn bool QPen::operator!=(const QPen &pen) const |
843 | |
844 | Returns \c true if the pen is different from the given \a pen; |
845 | otherwise false. Two pens are different if they have different |
846 | styles, widths or colors. |
847 | |
848 | \sa operator==() |
849 | */ |
850 | |
851 | /*! |
852 | \fn bool QPen::operator==(const QPen &pen) const |
853 | |
854 | Returns \c true if the pen is equal to the given \a pen; otherwise |
855 | false. Two pens are equal if they have equal styles, widths and |
856 | colors. |
857 | |
858 | \sa operator!=() |
859 | */ |
860 | |
861 | bool QPen::operator==(const QPen &p) const |
862 | { |
863 | QPenData *dd = static_cast<QPenData *>(d); |
864 | QPenData *pdd = static_cast<QPenData *>(p.d); |
865 | return (p.d == d) |
866 | || (p.d->style == d->style |
867 | && p.d->capStyle == d->capStyle |
868 | && p.d->joinStyle == d->joinStyle |
869 | && p.d->width == d->width |
870 | && pdd->miterLimit == dd->miterLimit |
871 | && (d->style != Qt::CustomDashLine |
872 | || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) && |
873 | pdd->dashPattern == dd->dashPattern)) |
874 | && p.d->brush == d->brush |
875 | && pdd->cosmetic == dd->cosmetic |
876 | && pdd->defaultWidth == dd->defaultWidth); |
877 | } |
878 | |
879 | |
880 | /*! |
881 | \fn bool QPen::isDetached() |
882 | |
883 | \internal |
884 | */ |
885 | |
886 | bool QPen::isDetached() |
887 | { |
888 | return d->ref.loadRelaxed() == 1; |
889 | } |
890 | |
891 | |
892 | /***************************************************************************** |
893 | QPen stream functions |
894 | *****************************************************************************/ |
895 | #ifndef QT_NO_DATASTREAM |
896 | /*! |
897 | \fn QDataStream &operator<<(QDataStream &stream, const QPen &pen) |
898 | \relates QPen |
899 | |
900 | Writes the given \a pen to the given \a stream and returns a reference to |
901 | the \a stream. |
902 | |
903 | \sa {Serializing Qt Data Types} |
904 | */ |
905 | |
906 | QDataStream &operator<<(QDataStream &s, const QPen &p) |
907 | { |
908 | QPenData *dd = static_cast<QPenData *>(p.d); |
909 | if (s.version() < 3) { |
910 | s << (quint8)p.style(); |
911 | } else if (s.version() < QDataStream::Qt_4_3) { |
912 | s << (quint8)(p.style() | p.capStyle() | p.joinStyle()); |
913 | } else { |
914 | s << (quint16)(p.style() | p.capStyle() | p.joinStyle()); |
915 | s << (bool)(dd->cosmetic); |
916 | } |
917 | |
918 | if (s.version() < 7) { |
919 | s << (quint8)p.width(); |
920 | s << p.color(); |
921 | } else { |
922 | s << double(p.widthF()); |
923 | s << p.brush(); |
924 | s << double(p.miterLimit()); |
925 | if (sizeof(qreal) == sizeof(double)) { |
926 | s << p.dashPattern(); |
927 | } else { |
928 | // ensure that we write doubles here instead of streaming the pattern |
929 | // directly; otherwise, platforms that redefine qreal might generate |
930 | // data that cannot be read on other platforms. |
931 | QList<qreal> pattern = p.dashPattern(); |
932 | s << quint32(pattern.size()); |
933 | for (int i = 0; i < pattern.size(); ++i) |
934 | s << double(pattern.at(i)); |
935 | } |
936 | if (s.version() >= 9) |
937 | s << double(p.dashOffset()); |
938 | if (s.version() >= QDataStream::Qt_5_0) |
939 | s << bool(dd->defaultWidth); |
940 | } |
941 | return s; |
942 | } |
943 | |
944 | /*! |
945 | \fn QDataStream &operator>>(QDataStream &stream, QPen &pen) |
946 | \relates QPen |
947 | |
948 | Reads a pen from the given \a stream into the given \a pen and |
949 | returns a reference to the \a stream. |
950 | |
951 | \sa {Serializing Qt Data Types} |
952 | */ |
953 | |
954 | QDataStream &operator>>(QDataStream &s, QPen &p) |
955 | { |
956 | quint16 style; |
957 | quint8 width8 = 0; |
958 | double width = 0; |
959 | QColor color; |
960 | QBrush brush; |
961 | double miterLimit = 2; |
962 | QList<qreal> dashPattern; |
963 | double dashOffset = 0; |
964 | bool cosmetic = false; |
965 | bool defaultWidth = false; |
966 | if (s.version() < QDataStream::Qt_4_3) { |
967 | quint8 style8; |
968 | s >> style8; |
969 | style = style8; |
970 | } else { |
971 | s >> style; |
972 | s >> cosmetic; |
973 | } |
974 | if (s.version() < 7) { |
975 | s >> width8; |
976 | s >> color; |
977 | brush = color; |
978 | width = width8; |
979 | } else { |
980 | s >> width; |
981 | s >> brush; |
982 | s >> miterLimit; |
983 | if (sizeof(qreal) == sizeof(double)) { |
984 | s >> dashPattern; |
985 | } else { |
986 | quint32 numDashes; |
987 | s >> numDashes; |
988 | double dash; |
989 | dashPattern.reserve(numDashes); |
990 | for (quint32 i = 0; i < numDashes; ++i) { |
991 | s >> dash; |
992 | dashPattern << dash; |
993 | } |
994 | } |
995 | if (s.version() >= 9) |
996 | s >> dashOffset; |
997 | } |
998 | |
999 | if (s.version() >= QDataStream::Qt_5_0) { |
1000 | s >> defaultWidth; |
1001 | } else { |
1002 | // best we can do for legacy pens |
1003 | defaultWidth = qFuzzyIsNull(width); |
1004 | } |
1005 | |
1006 | p.detach(); |
1007 | QPenData *dd = static_cast<QPenData *>(p.d); |
1008 | dd->width = width; |
1009 | dd->brush = brush; |
1010 | dd->style = Qt::PenStyle(style & Qt::MPenStyle); |
1011 | dd->capStyle = Qt::PenCapStyle(style & Qt::MPenCapStyle); |
1012 | dd->joinStyle = Qt::PenJoinStyle(style & Qt::MPenJoinStyle); |
1013 | dd->dashPattern = dashPattern; |
1014 | dd->miterLimit = miterLimit; |
1015 | dd->dashOffset = dashOffset; |
1016 | dd->cosmetic = cosmetic; |
1017 | dd->defaultWidth = defaultWidth; |
1018 | |
1019 | return s; |
1020 | } |
1021 | #endif //QT_NO_DATASTREAM |
1022 | |
1023 | #ifndef QT_NO_DEBUG_STREAM |
1024 | QDebug operator<<(QDebug dbg, const QPen &p) |
1025 | { |
1026 | const char *PEN_STYLES[] = { |
1027 | "NoPen" , |
1028 | "SolidLine" , |
1029 | "DashLine" , |
1030 | "DotLine" , |
1031 | "DashDotLine" , |
1032 | "DashDotDotLine" , |
1033 | "CustomDashLine" |
1034 | }; |
1035 | |
1036 | QDebugStateSaver saver(dbg); |
1037 | dbg.nospace() << "QPen(" << p.width() << ',' << p.brush() |
1038 | << ',' << PEN_STYLES[p.style()] << ',' << int(p.capStyle()) |
1039 | << ',' << int(p.joinStyle()) << ',' << p.dashPattern() |
1040 | << ',' << p.dashOffset() |
1041 | << ',' << p.miterLimit() << ')'; |
1042 | return dbg; |
1043 | } |
1044 | #endif |
1045 | |
1046 | /*! |
1047 | \fn DataPtr &QPen::data_ptr() |
1048 | \internal |
1049 | */ |
1050 | |
1051 | /*! |
1052 | \typedef QPen::DataPtr |
1053 | |
1054 | \internal |
1055 | */ |
1056 | |
1057 | QT_END_NAMESPACE |
1058 | |
1059 | #undef QT_COMPILING_QPEN |
1060 | |