source: trunk/examples/script/context2d/context2d.cpp@ 842

Last change on this file since 842 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 21.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
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.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "context2d.h"
43
44#include <QVariant>
45
46#include <math.h>
47static const double Q_PI = 3.14159265358979323846; // pi
48
49#define DEGREES(t) ((t) * 180.0 / Q_PI)
50
51#define qClamp(val, min, max) qMin(qMax(val, min), max)
52static QList<qreal> parseNumbersList(QString::const_iterator &itr)
53{
54 QList<qreal> points;
55 QString temp;
56 while ((*itr).isSpace())
57 ++itr;
58 while ((*itr).isNumber() ||
59 (*itr) == '-' || (*itr) == '+' || (*itr) == '.') {
60 temp = QString();
61
62 if ((*itr) == '-')
63 temp += *itr++;
64 else if ((*itr) == '+')
65 temp += *itr++;
66 while ((*itr).isDigit())
67 temp += *itr++;
68 if ((*itr) == '.')
69 temp += *itr++;
70 while ((*itr).isDigit())
71 temp += *itr++;
72 while ((*itr).isSpace())
73 ++itr;
74 if ((*itr) == ',')
75 ++itr;
76 points.append(temp.toDouble());
77 //eat spaces
78 while ((*itr).isSpace())
79 ++itr;
80 }
81
82 return points;
83}
84
85QColor colorFromString(const QString &name)
86{
87 QString::const_iterator itr = name.constBegin();
88 QList<qreal> compo;
89 if (name.startsWith("rgba(")) {
90 ++itr; ++itr; ++itr; ++itr; ++itr;
91 compo = parseNumbersList(itr);
92 if (compo.size() != 4) {
93 return QColor();
94 }
95 //alpha seems to be always between 0-1
96 compo[3] *= 255;
97 return QColor((int)compo[0], (int)compo[1],
98 (int)compo[2], (int)compo[3]);
99 } else if (name.startsWith("rgb(")) {
100 ++itr; ++itr; ++itr; ++itr;
101 compo = parseNumbersList(itr);
102 if (compo.size() != 3) {
103 return QColor();
104 }
105 return QColor((int)qClamp(compo[0], qreal(0), qreal(255)),
106 (int)qClamp(compo[1], qreal(0), qreal(255)),
107 (int)qClamp(compo[2], qreal(0), qreal(255)));
108 } else {
109 //QRgb color;
110 //CSSParser::parseColor(name, color);
111 return QColor(name);
112 }
113}
114
115
116static QPainter::CompositionMode compositeOperatorFromString(const QString &compositeOperator)
117{
118 if ( compositeOperator == "source-over" ) {
119 return QPainter::CompositionMode_SourceOver;
120 } else if ( compositeOperator == "source-out" ) {
121 return QPainter::CompositionMode_SourceOut;
122 } else if ( compositeOperator == "source-in" ) {
123 return QPainter::CompositionMode_SourceIn;
124 } else if ( compositeOperator == "source-atop" ) {
125 return QPainter::CompositionMode_SourceAtop;
126 } else if ( compositeOperator == "destination-atop" ) {
127 return QPainter::CompositionMode_DestinationAtop;
128 } else if ( compositeOperator == "destination-in" ) {
129 return QPainter::CompositionMode_DestinationIn;
130 } else if ( compositeOperator == "destination-out" ) {
131 return QPainter::CompositionMode_DestinationOut;
132 } else if ( compositeOperator == "destination-over" ) {
133 return QPainter::CompositionMode_DestinationOver;
134 } else if ( compositeOperator == "darker" ) {
135 return QPainter::CompositionMode_SourceOver;
136 } else if ( compositeOperator == "lighter" ) {
137 return QPainter::CompositionMode_SourceOver;
138 } else if ( compositeOperator == "copy" ) {
139 return QPainter::CompositionMode_Source;
140 } else if ( compositeOperator == "xor" ) {
141 return QPainter::CompositionMode_Xor;
142 }
143
144 return QPainter::CompositionMode_SourceOver;
145}
146
147static QString compositeOperatorToString(QPainter::CompositionMode op)
148{
149 switch (op) {
150 case QPainter::CompositionMode_SourceOver:
151 return "source-over";
152 case QPainter::CompositionMode_DestinationOver:
153 return "destination-over";
154 case QPainter::CompositionMode_Clear:
155 return "clear";
156 case QPainter::CompositionMode_Source:
157 return "source";
158 case QPainter::CompositionMode_Destination:
159 return "destination";
160 case QPainter::CompositionMode_SourceIn:
161 return "source-in";
162 case QPainter::CompositionMode_DestinationIn:
163 return "destination-in";
164 case QPainter::CompositionMode_SourceOut:
165 return "source-out";
166 case QPainter::CompositionMode_DestinationOut:
167 return "destination-out";
168 case QPainter::CompositionMode_SourceAtop:
169 return "source-atop";
170 case QPainter::CompositionMode_DestinationAtop:
171 return "destination-atop";
172 case QPainter::CompositionMode_Xor:
173 return "xor";
174 case QPainter::CompositionMode_Plus:
175 return "plus";
176 case QPainter::CompositionMode_Multiply:
177 return "multiply";
178 case QPainter::CompositionMode_Screen:
179 return "screen";
180 case QPainter::CompositionMode_Overlay:
181 return "overlay";
182 case QPainter::CompositionMode_Darken:
183 return "darken";
184 case QPainter::CompositionMode_Lighten:
185 return "lighten";
186 case QPainter::CompositionMode_ColorDodge:
187 return "color-dodge";
188 case QPainter::CompositionMode_ColorBurn:
189 return "color-burn";
190 case QPainter::CompositionMode_HardLight:
191 return "hard-light";
192 case QPainter::CompositionMode_SoftLight:
193 return "soft-light";
194 case QPainter::CompositionMode_Difference:
195 return "difference";
196 case QPainter::CompositionMode_Exclusion:
197 return "exclusion";
198 default:
199 break;
200 }
201 return QString();
202}
203
204void Context2D::save()
205{
206 m_stateStack.push(m_state);
207}
208
209
210void Context2D::restore()
211{
212 if (!m_stateStack.isEmpty()) {
213 m_state = m_stateStack.pop();
214 m_state.flags = AllIsFullOfDirt;
215 }
216}
217
218
219void Context2D::scale(qreal x, qreal y)
220{
221 m_state.matrix.scale(x, y);
222 m_state.flags |= DirtyTransformationMatrix;
223}
224
225
226void Context2D::rotate(qreal angle)
227{
228 m_state.matrix.rotate(DEGREES(angle));
229 m_state.flags |= DirtyTransformationMatrix;
230}
231
232
233void Context2D::translate(qreal x, qreal y)
234{
235 m_state.matrix.translate(x, y);
236 m_state.flags |= DirtyTransformationMatrix;
237}
238
239
240void Context2D::transform(qreal m11, qreal m12, qreal m21, qreal m22,
241 qreal dx, qreal dy)
242{
243 QMatrix mat(m11, m12,
244 m21, m22,
245 dx, dy);
246 m_state.matrix *= mat;
247 m_state.flags |= DirtyTransformationMatrix;
248}
249
250
251void Context2D::setTransform(qreal m11, qreal m12, qreal m21, qreal m22,
252 qreal dx, qreal dy)
253{
254 QMatrix mat(m11, m12,
255 m21, m22,
256 dx, dy);
257 m_state.matrix = mat;
258 m_state.flags |= DirtyTransformationMatrix;
259}
260
261
262QString Context2D::globalCompositeOperation() const
263{
264 return compositeOperatorToString(m_state.globalCompositeOperation);
265}
266
267void Context2D::setGlobalCompositeOperation(const QString &op)
268{
269 QPainter::CompositionMode mode =
270 compositeOperatorFromString(op);
271 m_state.globalCompositeOperation = mode;
272 m_state.flags |= DirtyGlobalCompositeOperation;
273}
274
275QVariant Context2D::strokeStyle() const
276{
277 return m_state.strokeStyle;
278}
279
280void Context2D::setStrokeStyle(const QVariant &style)
281{
282 if (qVariantCanConvert<CanvasGradient>(style)) {
283 CanvasGradient cg = qvariant_cast<CanvasGradient>(style);
284 m_state.strokeStyle = cg.value;
285 } else {
286 QColor color = colorFromString(style.toString());
287 m_state.strokeStyle = color;
288 }
289 m_state.flags |= DirtyStrokeStyle;
290}
291
292QVariant Context2D::fillStyle() const
293{
294 return m_state.fillStyle;
295}
296
297//! [3]
298void Context2D::setFillStyle(const QVariant &style)
299{
300 if (qVariantCanConvert<CanvasGradient>(style)) {
301 CanvasGradient cg = qvariant_cast<CanvasGradient>(style);
302 m_state.fillStyle = cg.value;
303 } else {
304 QColor color = colorFromString(style.toString());
305 m_state.fillStyle = color;
306 }
307 m_state.flags |= DirtyFillStyle;
308}
309//! [3]
310
311qreal Context2D::globalAlpha() const
312{
313 return m_state.globalAlpha;
314}
315
316void Context2D::setGlobalAlpha(qreal alpha)
317{
318 m_state.globalAlpha = alpha;
319 m_state.flags |= DirtyGlobalAlpha;
320}
321
322
323CanvasGradient Context2D::createLinearGradient(qreal x0, qreal y0,
324 qreal x1, qreal y1)
325{
326 QLinearGradient g(x0, y0, x1, y1);
327 return CanvasGradient(g);
328}
329
330
331CanvasGradient Context2D::createRadialGradient(qreal x0, qreal y0,
332 qreal r0, qreal x1,
333 qreal y1, qreal r1)
334{
335 QRadialGradient g(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
336 return CanvasGradient(g);
337}
338
339qreal Context2D::lineWidth() const
340{
341 return m_state.lineWidth;
342}
343
344void Context2D::setLineWidth(qreal w)
345{
346 m_state.lineWidth = w;
347 m_state.flags |= DirtyLineWidth;
348}
349
350//! [0]
351QString Context2D::lineCap() const
352{
353 switch (m_state.lineCap) {
354 case Qt::FlatCap:
355 return "butt";
356 case Qt::SquareCap:
357 return "square";
358 case Qt::RoundCap:
359 return "round";
360 default: ;
361 }
362 return QString();
363}
364
365void Context2D::setLineCap(const QString &capString)
366{
367 Qt::PenCapStyle style;
368 if (capString == "round")
369 style = Qt::RoundCap;
370 else if (capString == "square")
371 style = Qt::SquareCap;
372 else //if (capString == "butt")
373 style = Qt::FlatCap;
374 m_state.lineCap = style;
375 m_state.flags |= DirtyLineCap;
376}
377//! [0]
378
379QString Context2D::lineJoin() const
380{
381 switch (m_state.lineJoin) {
382 case Qt::RoundJoin:
383 return "round";
384 case Qt::BevelJoin:
385 return "bevel";
386 case Qt::MiterJoin:
387 return "miter";
388 default: ;
389 }
390 return QString();
391}
392
393void Context2D::setLineJoin(const QString &joinString)
394{
395 Qt::PenJoinStyle style;
396 if (joinString == "round")
397 style = Qt::RoundJoin;
398 else if (joinString == "bevel")
399 style = Qt::BevelJoin;
400 else //if (joinString == "miter")
401 style = Qt::MiterJoin;
402 m_state.lineJoin = style;
403 m_state.flags |= DirtyLineJoin;
404}
405
406qreal Context2D::miterLimit() const
407{
408 return m_state.miterLimit;
409}
410
411void Context2D::setMiterLimit(qreal m)
412{
413 m_state.miterLimit = m;
414 m_state.flags |= DirtyMiterLimit;
415}
416
417void Context2D::setShadowOffsetX(qreal x)
418{
419 m_state.shadowOffsetX = x;
420 m_state.flags |= DirtyShadowOffsetX;
421}
422
423void Context2D::setShadowOffsetY(qreal y)
424{
425 m_state.shadowOffsetY = y;
426 m_state.flags |= DirtyShadowOffsetY;
427}
428
429void Context2D::setShadowBlur(qreal b)
430{
431 m_state.shadowBlur = b;
432 m_state.flags |= DirtyShadowBlur;
433}
434
435void Context2D::setShadowColor(const QString &str)
436{
437 m_state.shadowColor = colorFromString(str);
438 m_state.flags |= DirtyShadowColor;
439}
440
441qreal Context2D::shadowOffsetX() const
442{
443 return m_state.shadowOffsetX;
444}
445
446qreal Context2D::shadowOffsetY() const
447{
448 return m_state.shadowOffsetY;
449}
450
451
452qreal Context2D::shadowBlur() const
453{
454 return m_state.shadowBlur;
455}
456
457
458QString Context2D::shadowColor() const
459{
460 return m_state.shadowColor.name();
461}
462
463
464void Context2D::clearRect(qreal x, qreal y, qreal w, qreal h)
465{
466 beginPainting();
467 m_painter.save();
468 m_painter.setMatrix(m_state.matrix, false);
469 m_painter.setCompositionMode(QPainter::CompositionMode_Source);
470 m_painter.fillRect(QRectF(x, y, w, h), QColor(0, 0, 0, 0));
471 m_painter.restore();
472 scheduleChange();
473}
474
475
476//! [1]
477void Context2D::fillRect(qreal x, qreal y, qreal w, qreal h)
478{
479 beginPainting();
480 m_painter.save();
481 m_painter.setMatrix(m_state.matrix, false);
482 m_painter.fillRect(QRectF(x, y, w, h), m_painter.brush());
483 m_painter.restore();
484 scheduleChange();
485}
486//! [1]
487
488
489void Context2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
490{
491 QPainterPath path;
492 path.addRect(x, y, w, h);
493 beginPainting();
494 m_painter.save();
495 m_painter.setMatrix(m_state.matrix, false);
496 m_painter.strokePath(path, m_painter.pen());
497 m_painter.restore();
498 scheduleChange();
499}
500
501
502void Context2D::beginPath()
503{
504 m_path = QPainterPath();
505}
506
507
508void Context2D::closePath()
509{
510 m_path.closeSubpath();
511}
512
513
514void Context2D::moveTo(qreal x, qreal y)
515{
516 QPointF pt = m_state.matrix.map(QPointF(x, y));
517 m_path.moveTo(pt);
518}
519
520
521void Context2D::lineTo(qreal x, qreal y)
522{
523 QPointF pt = m_state.matrix.map(QPointF(x, y));
524 m_path.lineTo(pt);
525}
526
527
528void Context2D::quadraticCurveTo(qreal cpx, qreal cpy, qreal x, qreal y)
529{
530 QPointF cp = m_state.matrix.map(QPointF(cpx, cpy));
531 QPointF xy = m_state.matrix.map(QPointF(x, y));
532 m_path.quadTo(cp, xy);
533}
534
535
536void Context2D::bezierCurveTo(qreal cp1x, qreal cp1y,
537 qreal cp2x, qreal cp2y, qreal x, qreal y)
538{
539 QPointF cp1 = m_state.matrix.map(QPointF(cp1x, cp1y));
540 QPointF cp2 = m_state.matrix.map(QPointF(cp2x, cp2y));
541 QPointF end = m_state.matrix.map(QPointF(x, y));
542 m_path.cubicTo(cp1, cp2, end);
543}
544
545
546void Context2D::arcTo(qreal x1, qreal y1, qreal x2, qreal y2, qreal radius)
547{
548 //FIXME: this is surely busted
549 QPointF st = m_state.matrix.map(QPointF(x1, y1));
550 QPointF end = m_state.matrix.map(QPointF(x2, y2));
551 m_path.arcTo(st.x(), st.y(),
552 end.x()-st.x(), end.y()-st.y(),
553 radius, 90);
554}
555
556
557void Context2D::rect(qreal x, qreal y, qreal w, qreal h)
558{
559 QPainterPath path; path.addRect(x, y, w, h);
560 path = m_state.matrix.map(path);
561 m_path.addPath(path);
562}
563
564void Context2D::arc(qreal xc, qreal yc, qreal radius,
565 qreal sar, qreal ear,
566 bool anticlockwise)
567{
568 //### HACK
569 // In Qt we don't switch the coordinate system for degrees
570 // and still use the 0,0 as bottom left for degrees so we need
571 // to switch
572 sar = -sar;
573 ear = -ear;
574 anticlockwise = !anticlockwise;
575 //end hack
576
577 float sa = DEGREES(sar);
578 float ea = DEGREES(ear);
579
580 double span = 0;
581
582 double xs = xc - radius;
583 double ys = yc - radius;
584 double width = radius*2;
585 double height = radius*2;
586
587 if (!anticlockwise && (ea < sa)) {
588 span += 360;
589 } else if (anticlockwise && (sa < ea)) {
590 span -= 360;
591 }
592
593 //### this is also due to switched coordinate system
594 // we would end up with a 0 span instead of 360
595 if (!(qFuzzyCompare(span + (ea - sa) + 1, 1) &&
596 qFuzzyCompare(qAbs(span), 360))) {
597 span += ea - sa;
598 }
599
600 QPainterPath path;
601 path.moveTo(QPointF(xc + radius * cos(sar),
602 yc - radius * sin(sar)));
603
604 path.arcTo(xs, ys, width, height, sa, span);
605 path = m_state.matrix.map(path);
606 m_path.addPath(path);
607}
608
609
610void Context2D::fill()
611{
612 beginPainting();
613 m_painter.fillPath(m_path, m_painter.brush());
614 scheduleChange();
615}
616
617
618void Context2D::stroke()
619{
620 beginPainting();
621 m_painter.save();
622 m_painter.setMatrix(m_state.matrix, false);
623 QPainterPath tmp = m_state.matrix.inverted().map(m_path);
624 m_painter.strokePath(tmp, m_painter.pen());
625 m_painter.restore();
626 scheduleChange();
627}
628
629
630void Context2D::clip()
631{
632 m_state.clipPath = m_path;
633 m_state.flags |= DirtyClippingRegion;
634}
635
636
637bool Context2D::isPointInPath(qreal x, qreal y) const
638{
639 return m_path.contains(QPointF(x, y));
640}
641
642
643ImageData Context2D::getImageData(qreal sx, qreal sy, qreal sw, qreal sh)
644{
645 Q_UNUSED(sx);
646 Q_UNUSED(sy);
647 Q_UNUSED(sw);
648 Q_UNUSED(sh);
649 return ImageData();
650}
651
652
653void Context2D::putImageData(ImageData image, qreal dx, qreal dy)
654{
655 Q_UNUSED(image);
656 Q_UNUSED(dx);
657 Q_UNUSED(dy);
658}
659
660Context2D::Context2D(QObject *parent)
661 : QObject(parent), m_changeTimerId(-1)
662{
663 reset();
664}
665
666const QImage &Context2D::endPainting()
667{
668 if (m_painter.isActive())
669 m_painter.end();
670 return m_image;
671}
672
673void Context2D::beginPainting()
674{
675 if (!m_painter.isActive()) {
676 m_painter.begin(&m_image);
677 m_painter.setRenderHint(QPainter::Antialiasing);
678 if (!m_state.clipPath.isEmpty())
679 m_painter.setClipPath(m_state.clipPath);
680 m_painter.setBrush(m_state.fillStyle);
681 m_painter.setOpacity(m_state.globalAlpha);
682 QPen pen;
683 pen.setBrush(m_state.strokeStyle);
684 if (pen.style() == Qt::NoPen)
685 pen.setStyle(Qt::SolidLine);
686 pen.setCapStyle(m_state.lineCap);
687 pen.setJoinStyle(m_state.lineJoin);
688 pen.setWidthF(m_state.lineWidth);
689 pen.setMiterLimit(m_state.miterLimit);
690 m_painter.setPen(pen);
691 } else {
692 if ((m_state.flags & DirtyClippingRegion) && !m_state.clipPath.isEmpty())
693 m_painter.setClipPath(m_state.clipPath);
694 if (m_state.flags & DirtyFillStyle)
695 m_painter.setBrush(m_state.fillStyle);
696 if (m_state.flags & DirtyGlobalAlpha)
697 m_painter.setOpacity(m_state.globalAlpha);
698 if (m_state.flags & DirtyGlobalCompositeOperation)
699 m_painter.setCompositionMode(m_state.globalCompositeOperation);
700 if (m_state.flags & MDirtyPen) {
701 QPen pen = m_painter.pen();
702 if (m_state.flags & DirtyStrokeStyle)
703 pen.setBrush(m_state.strokeStyle);
704 if (m_state.flags & DirtyLineWidth)
705 pen.setWidthF(m_state.lineWidth);
706 if (m_state.flags & DirtyLineCap)
707 pen.setCapStyle(m_state.lineCap);
708 if (m_state.flags & DirtyLineJoin)
709 pen.setJoinStyle(m_state.lineJoin);
710 if (m_state.flags & DirtyMiterLimit)
711 pen.setMiterLimit(m_state.miterLimit);
712 m_painter.setPen(pen);
713 }
714 m_state.flags = 0;
715 }
716}
717
718void Context2D::clear()
719{
720 endPainting();
721 m_image.fill(qRgba(0,0,0,0));
722 scheduleChange();
723}
724
725void Context2D::reset()
726{
727 m_stateStack.clear();
728 m_state.matrix = QMatrix();
729 m_state.clipPath = QPainterPath();
730 m_state.globalAlpha = 1.0;
731 m_state.globalCompositeOperation = QPainter::CompositionMode_SourceOver;
732 m_state.strokeStyle = Qt::black;
733 m_state.fillStyle = Qt::black;
734 m_state.lineWidth = 1;
735 m_state.lineCap = Qt::FlatCap;
736 m_state.lineJoin = Qt::MiterJoin;
737 m_state.miterLimit = 10;
738 m_state.shadowOffsetX = 0;
739 m_state.shadowOffsetY = 0;
740 m_state.shadowBlur = 0;
741 m_state.shadowColor = qRgba(0, 0, 0, 0);
742 m_state.flags = AllIsFullOfDirt;
743 clear();
744}
745
746void Context2D::setSize(int width, int height)
747{
748 endPainting();
749 QImage newi(width, height, QImage::Format_ARGB32_Premultiplied);
750 newi.fill(qRgba(0,0,0,0));
751 QPainter p(&newi);
752 p.drawImage(0, 0, m_image);
753 p.end();
754 m_image = newi;
755 scheduleChange();
756}
757
758void Context2D::setSize(const QSize &size)
759{
760 setSize(size.width(), size.height());
761}
762
763QSize Context2D::size() const
764{
765 return m_image.size();
766}
767
768void Context2D::drawImage(DomImage *image, qreal dx, qreal dy)
769{
770 if (!image)
771 return;
772 if (dx < 0) {
773 qreal sx = qAbs(dx);
774 qreal sy = qAbs(dy);
775 qreal sw = image->width() - sx;
776 qreal sh = image->height() - sy;
777
778 drawImage(image, sx, sy, sw, sh, 0, 0, sw, sh);
779 } else {
780 beginPainting();
781 m_painter.drawImage(QPointF(dx, dy), image->image());
782 scheduleChange();
783 }
784}
785
786void Context2D::drawImage(DomImage *image, qreal dx, qreal dy,
787 qreal dw, qreal dh)
788{
789 if (!image)
790 return;
791 beginPainting();
792 m_painter.drawImage(QRectF(dx, dy, dw, dh).toRect(), image->image());
793 scheduleChange();
794}
795
796void Context2D::drawImage(DomImage *image, qreal sx, qreal sy,
797 qreal sw, qreal sh, qreal dx, qreal dy,
798 qreal dw, qreal dh)
799{
800 if (!image)
801 return;
802 beginPainting();
803 m_painter.drawImage(QRectF(dx, dy, dw, dh), image->image(),
804 QRectF(sx, sy, sw, sh));
805 scheduleChange();
806}
807
808//! [2]
809void Context2D::scheduleChange()
810{
811 if (m_changeTimerId == -1)
812 m_changeTimerId = startTimer(0);
813}
814
815void Context2D::timerEvent(QTimerEvent *e)
816{
817 if (e->timerId() == m_changeTimerId) {
818 killTimer(m_changeTimerId);
819 m_changeTimerId = -1;
820 emit changed(endPainting());
821 } else {
822 QObject::timerEvent(e);
823 }
824}
825//! [2]
Note: See TracBrowser for help on using the repository browser.