1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the demonstration applications of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "composition.h"
44 #include <QRadioButton>
48 #include <QMouseEvent>
51 CompositionWidget::CompositionWidget(QWidget
*parent
)
54 CompositionRenderer
*view
= new CompositionRenderer(this);
56 QGroupBox
*mainGroup
= new QGroupBox(parent
);
57 mainGroup
->setTitle(tr("Composition Modes"));
59 QGroupBox
*modesGroup
= new QGroupBox(mainGroup
);
60 modesGroup
->setTitle(tr("Mode"));
62 rbClear
= new QRadioButton(tr("Clear"), modesGroup
);
63 connect(rbClear
, SIGNAL(clicked()), view
, SLOT(setClearMode()));
64 rbSource
= new QRadioButton(tr("Source"), modesGroup
);
65 connect(rbSource
, SIGNAL(clicked()), view
, SLOT(setSourceMode()));
66 rbDest
= new QRadioButton(tr("Destination"), modesGroup
);
67 connect(rbDest
, SIGNAL(clicked()), view
, SLOT(setDestMode()));
68 rbSourceOver
= new QRadioButton(tr("Source Over"), modesGroup
);
69 connect(rbSourceOver
, SIGNAL(clicked()), view
, SLOT(setSourceOverMode()));
70 rbDestOver
= new QRadioButton(tr("Destination Over"), modesGroup
);
71 connect(rbDestOver
, SIGNAL(clicked()), view
, SLOT(setDestOverMode()));
72 rbSourceIn
= new QRadioButton(tr("Source In"), modesGroup
);
73 connect(rbSourceIn
, SIGNAL(clicked()), view
, SLOT(setSourceInMode()));
74 rbDestIn
= new QRadioButton(tr("Dest In"), modesGroup
);
75 connect(rbDestIn
, SIGNAL(clicked()), view
, SLOT(setDestInMode()));
76 rbSourceOut
= new QRadioButton(tr("Source Out"), modesGroup
);
77 connect(rbSourceOut
, SIGNAL(clicked()), view
, SLOT(setSourceOutMode()));
78 rbDestOut
= new QRadioButton(tr("Dest Out"), modesGroup
);
79 connect(rbDestOut
, SIGNAL(clicked()), view
, SLOT(setDestOutMode()));
80 rbSourceAtop
= new QRadioButton(tr("Source Atop"), modesGroup
);
81 connect(rbSourceAtop
, SIGNAL(clicked()), view
, SLOT(setSourceAtopMode()));
82 rbDestAtop
= new QRadioButton(tr("Dest Atop"), modesGroup
);
83 connect(rbDestAtop
, SIGNAL(clicked()), view
, SLOT(setDestAtopMode()));
84 rbXor
= new QRadioButton(tr("Xor"), modesGroup
);
85 connect(rbXor
, SIGNAL(clicked()), view
, SLOT(setXorMode()));
87 rbPlus
= new QRadioButton(tr("Plus"), modesGroup
);
88 connect(rbPlus
, SIGNAL(clicked()), view
, SLOT(setPlusMode()));
89 rbMultiply
= new QRadioButton(tr("Multiply"), modesGroup
);
90 connect(rbMultiply
, SIGNAL(clicked()), view
, SLOT(setMultiplyMode()));
91 rbScreen
= new QRadioButton(tr("Screen"), modesGroup
);
92 connect(rbScreen
, SIGNAL(clicked()), view
, SLOT(setScreenMode()));
93 rbOverlay
= new QRadioButton(tr("Overlay"), modesGroup
);
94 connect(rbOverlay
, SIGNAL(clicked()), view
, SLOT(setOverlayMode()));
95 rbDarken
= new QRadioButton(tr("Darken"), modesGroup
);
96 connect(rbDarken
, SIGNAL(clicked()), view
, SLOT(setDarkenMode()));
97 rbLighten
= new QRadioButton(tr("Lighten"), modesGroup
);
98 connect(rbLighten
, SIGNAL(clicked()), view
, SLOT(setLightenMode()));
99 rbColorDodge
= new QRadioButton(tr("Color Dodge"), modesGroup
);
100 connect(rbColorDodge
, SIGNAL(clicked()), view
, SLOT(setColorDodgeMode()));
101 rbColorBurn
= new QRadioButton(tr("Color Burn"), modesGroup
);
102 connect(rbColorBurn
, SIGNAL(clicked()), view
, SLOT(setColorBurnMode()));
103 rbHardLight
= new QRadioButton(tr("Hard Light"), modesGroup
);
104 connect(rbHardLight
, SIGNAL(clicked()), view
, SLOT(setHardLightMode()));
105 rbSoftLight
= new QRadioButton(tr("Soft Light"), modesGroup
);
106 connect(rbSoftLight
, SIGNAL(clicked()), view
, SLOT(setSoftLightMode()));
107 rbDifference
= new QRadioButton(tr("Difference"), modesGroup
);
108 connect(rbDifference
, SIGNAL(clicked()), view
, SLOT(setDifferenceMode()));
109 rbExclusion
= new QRadioButton(tr("Exclusion"), modesGroup
);
110 connect(rbExclusion
, SIGNAL(clicked()), view
, SLOT(setExclusionMode()));
112 QGroupBox
*circleColorGroup
= new QGroupBox(mainGroup
);
113 circleColorGroup
->setTitle(tr("Circle color"));
114 QSlider
*circleColorSlider
= new QSlider(Qt::Horizontal
, circleColorGroup
);
115 circleColorSlider
->setRange(0, 359);
116 circleColorSlider
->setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
117 connect(circleColorSlider
, SIGNAL(valueChanged(int)), view
, SLOT(setCircleColor(int)));
119 QGroupBox
*circleAlphaGroup
= new QGroupBox(mainGroup
);
120 circleAlphaGroup
->setTitle(tr("Circle alpha"));
121 QSlider
*circleAlphaSlider
= new QSlider(Qt::Horizontal
, circleAlphaGroup
);
122 circleAlphaSlider
->setRange(0, 255);
123 circleAlphaSlider
->setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
124 connect(circleAlphaSlider
, SIGNAL(valueChanged(int)), view
, SLOT(setCircleAlpha(int)));
126 QPushButton
*showSourceButton
= new QPushButton(mainGroup
);
127 showSourceButton
->setText(tr("Show Source"));
128 #if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
129 QPushButton
*enableOpenGLButton
= new QPushButton(mainGroup
);
130 enableOpenGLButton
->setText(tr("Use OpenGL"));
131 enableOpenGLButton
->setCheckable(true);
132 enableOpenGLButton
->setChecked(view
->usesOpenGL());
134 if (!QGLFormat::hasOpenGL() || !QGLPixelBuffer::hasOpenGLPbuffers())
135 enableOpenGLButton
->hide();
137 QPushButton
*whatsThisButton
= new QPushButton(mainGroup
);
138 whatsThisButton
->setText(tr("What's This?"));
139 whatsThisButton
->setCheckable(true);
141 QPushButton
*animateButton
= new QPushButton(mainGroup
);
142 animateButton
->setText(tr("Animated"));
143 animateButton
->setCheckable(true);
144 animateButton
->setChecked(true);
146 QHBoxLayout
*viewLayout
= new QHBoxLayout(this);
147 viewLayout
->addWidget(view
);
148 viewLayout
->addWidget(mainGroup
);
150 QVBoxLayout
*mainGroupLayout
= new QVBoxLayout(mainGroup
);
151 mainGroupLayout
->addWidget(circleColorGroup
);
152 mainGroupLayout
->addWidget(circleAlphaGroup
);
153 mainGroupLayout
->addWidget(modesGroup
);
154 mainGroupLayout
->addStretch();
155 mainGroupLayout
->addWidget(animateButton
);
156 mainGroupLayout
->addWidget(whatsThisButton
);
157 mainGroupLayout
->addWidget(showSourceButton
);
158 #if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
159 mainGroupLayout
->addWidget(enableOpenGLButton
);
162 QGridLayout
*modesLayout
= new QGridLayout(modesGroup
);
163 modesLayout
->addWidget(rbClear
, 0, 0);
164 modesLayout
->addWidget(rbSource
, 1, 0);
165 modesLayout
->addWidget(rbDest
, 2, 0);
166 modesLayout
->addWidget(rbSourceOver
, 3, 0);
167 modesLayout
->addWidget(rbDestOver
, 4, 0);
168 modesLayout
->addWidget(rbSourceIn
, 5, 0);
169 modesLayout
->addWidget(rbDestIn
, 6, 0);
170 modesLayout
->addWidget(rbSourceOut
, 7, 0);
171 modesLayout
->addWidget(rbDestOut
, 8, 0);
172 modesLayout
->addWidget(rbSourceAtop
, 9, 0);
173 modesLayout
->addWidget(rbDestAtop
, 10, 0);
174 modesLayout
->addWidget(rbXor
, 11, 0);
176 modesLayout
->addWidget(rbPlus
, 0, 1);
177 modesLayout
->addWidget(rbMultiply
, 1, 1);
178 modesLayout
->addWidget(rbScreen
, 2, 1);
179 modesLayout
->addWidget(rbOverlay
, 3, 1);
180 modesLayout
->addWidget(rbDarken
, 4, 1);
181 modesLayout
->addWidget(rbLighten
, 5, 1);
182 modesLayout
->addWidget(rbColorDodge
, 6, 1);
183 modesLayout
->addWidget(rbColorBurn
, 7, 1);
184 modesLayout
->addWidget(rbHardLight
, 8, 1);
185 modesLayout
->addWidget(rbSoftLight
, 9, 1);
186 modesLayout
->addWidget(rbDifference
, 10, 1);
187 modesLayout
->addWidget(rbExclusion
, 11, 1);
190 QVBoxLayout
*circleColorLayout
= new QVBoxLayout(circleColorGroup
);
191 circleColorLayout
->addWidget(circleColorSlider
);
193 QVBoxLayout
*circleAlphaLayout
= new QVBoxLayout(circleAlphaGroup
);
194 circleAlphaLayout
->addWidget(circleAlphaSlider
);
196 view
->loadDescription(":res/composition/composition.html");
197 view
->loadSourceFile(":res/composition/composition.cpp");
199 connect(whatsThisButton
, SIGNAL(clicked(bool)), view
, SLOT(setDescriptionEnabled(bool)));
200 connect(view
, SIGNAL(descriptionEnabledChanged(bool)), whatsThisButton
, SLOT(setChecked(bool)));
201 connect(showSourceButton
, SIGNAL(clicked()), view
, SLOT(showSource()));
202 #if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
203 connect(enableOpenGLButton
, SIGNAL(clicked(bool)), view
, SLOT(enableOpenGL(bool)));
205 connect(animateButton
, SIGNAL(toggled(bool)), view
, SLOT(setAnimationEnabled(bool)));
207 circleColorSlider
->setValue(270);
208 circleAlphaSlider
->setValue(200);
209 rbSourceOut
->animateClick();
211 setWindowTitle(tr("Composition Modes"));
215 void CompositionWidget::nextMode()
218 if (!m_animation_enabled)
220 if (rbClear->isChecked()) rbSource->animateClick();
221 if (rbSource->isChecked()) rbDest->animateClick();
222 if (rbDest->isChecked()) rbSourceOver->animateClick();
223 if (rbSourceOver->isChecked()) rbDestOver->animateClick();
224 if (rbDestOver->isChecked()) rbSourceIn->animateClick();
225 if (rbSourceIn->isChecked()) rbDestIn->animateClick();
226 if (rbDestIn->isChecked()) rbSourceOut->animateClick();
227 if (rbSourceOut->isChecked()) rbDestOut->animateClick();
228 if (rbDestOut->isChecked()) rbSourceAtop->animateClick();
229 if (rbSourceAtop->isChecked()) rbDestAtop->animateClick();
230 if (rbDestAtop->isChecked()) rbXor->animateClick();
231 if (rbXor->isChecked()) rbClear->animateClick();
235 CompositionRenderer::CompositionRenderer(QWidget
*parent
)
236 : ArthurFrame(parent
)
238 m_animation_enabled
= true;
240 m_image
= QPixmap(":res/composition/flower.jpg");
241 m_image
.setAlphaChannel(QPixmap(":res/composition/flower_alpha.jpg"));
243 m_image
= QImage(":res/composition/flower.jpg");
244 m_image
.setAlphaChannel(QImage(":res/composition/flower_alpha.jpg"));
246 m_circle_alpha
= 127;
248 m_current_object
= NoObject
;
249 m_composition_mode
= QPainter::CompositionMode_SourceOut
;
251 m_circle_pos
= QPoint(200, 100);
253 setSizePolicy(QSizePolicy::Expanding
, QSizePolicy::Expanding
);
254 #ifdef QT_OPENGL_SUPPORT
256 m_pbuffer_size
= 1024;
260 QRectF
rectangle_around(const QPointF
&p
, const QSizeF
&size
= QSize(250, 200))
262 QRectF
rect(p
, size
);
263 rect
.translate(-size
.width()/2, -size
.height()/2);
267 void CompositionRenderer::updateCirclePos()
269 if (m_current_object
!= NoObject
)
271 QDateTime dt
= QDateTime::currentDateTime();
272 qreal t
= (dt
.toTime_t() * 1000 + dt
.time().msec()) / 1000.0;
274 qreal x
= width() / qreal(2) + (qCos(t
*8/11) + qSin(-t
)) * width() / qreal(4);
275 qreal y
= height() / qreal(2) + (qSin(t
*6/7) + qCos(t
* qreal(1.5))) * height() / qreal(4);
277 setCirclePos(QLineF(m_circle_pos
, QPointF(x
, y
)).pointAt(0.02));
280 void CompositionRenderer::drawBase(QPainter
&p
)
284 QLinearGradient
rect_gradient(0, 0, 0, height());
285 rect_gradient
.setColorAt(0, Qt::red
);
286 rect_gradient
.setColorAt(.17, Qt::yellow
);
287 rect_gradient
.setColorAt(.33, Qt::green
);
288 rect_gradient
.setColorAt(.50, Qt::cyan
);
289 rect_gradient
.setColorAt(.66, Qt::blue
);
290 rect_gradient
.setColorAt(.81, Qt::magenta
);
291 rect_gradient
.setColorAt(1, Qt::red
);
292 p
.setBrush(rect_gradient
);
293 p
.drawRect(width() / 2, 0, width() / 2, height());
295 QLinearGradient
alpha_gradient(0, 0, width(), 0);
296 alpha_gradient
.setColorAt(0, Qt::white
);
297 alpha_gradient
.setColorAt(0.2, Qt::white
);
298 alpha_gradient
.setColorAt(0.5, Qt::transparent
);
299 alpha_gradient
.setColorAt(0.8, Qt::white
);
300 alpha_gradient
.setColorAt(1, Qt::white
);
302 p
.setCompositionMode(QPainter::CompositionMode_DestinationIn
);
303 p
.setBrush(alpha_gradient
);
304 p
.drawRect(0, 0, width(), height());
306 p
.setCompositionMode(QPainter::CompositionMode_DestinationOver
);
309 p
.setRenderHint(QPainter::SmoothPixmapTransform
);
311 p
.drawPixmap(rect(), m_image
);
313 p
.drawImage(rect(), m_image
);
317 void CompositionRenderer::drawSource(QPainter
&p
)
320 p
.setRenderHint(QPainter::Antialiasing
);
321 p
.setCompositionMode(m_composition_mode
);
323 QRectF circle_rect
= rectangle_around(m_circle_pos
);
324 QColor color
= QColor::fromHsvF(m_circle_hue
/ 360.0, 1, 1, m_circle_alpha
/ 255.0);
325 QLinearGradient
circle_gradient(circle_rect
.topLeft(), circle_rect
.bottomRight());
326 circle_gradient
.setColorAt(0, color
.light());
327 circle_gradient
.setColorAt(0.5, color
);
328 circle_gradient
.setColorAt(1, color
.dark());
329 p
.setBrush(circle_gradient
);
331 p
.drawEllipse(circle_rect
);
334 void CompositionRenderer::paint(QPainter
*painter
)
336 #if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
339 int new_pbuf_size
= m_pbuffer_size
;
340 if (size().width() > m_pbuffer_size
||
341 size().height() > m_pbuffer_size
)
344 if (size().width() < m_pbuffer_size
/2 &&
345 size().height() < m_pbuffer_size
/2)
348 if (!m_pbuffer
|| new_pbuf_size
!= m_pbuffer_size
) {
350 m_pbuffer
->deleteTexture(m_base_tex
);
351 m_pbuffer
->deleteTexture(m_compositing_tex
);
355 m_pbuffer
= new QGLPixelBuffer(QSize(new_pbuf_size
, new_pbuf_size
), QGLFormat::defaultFormat(), glWidget());
356 m_pbuffer
->makeCurrent();
357 m_base_tex
= m_pbuffer
->generateDynamicTexture();
358 m_compositing_tex
= m_pbuffer
->generateDynamicTexture();
359 m_pbuffer_size
= new_pbuf_size
;
362 if (size() != m_previous_size
) {
363 m_previous_size
= size();
364 QPainter
p(m_pbuffer
);
365 p
.setCompositionMode(QPainter::CompositionMode_Source
);
366 p
.fillRect(QRect(0, 0, m_pbuffer
->width(), m_pbuffer
->height()), Qt::transparent
);
369 m_pbuffer
->updateDynamicTexture(m_base_tex
);
372 qreal x_fraction
= width()/float(m_pbuffer
->width());
373 qreal y_fraction
= height()/float(m_pbuffer
->height());
376 QPainter
p(m_pbuffer
);
377 p
.setCompositionMode(QPainter::CompositionMode_Source
);
378 p
.fillRect(QRect(0, 0, m_pbuffer
->width(), m_pbuffer
->height()), Qt::transparent
);
380 p
.save(); // Needed when using the GL1 engine
381 p
.beginNativePainting(); // Needed when using the GL2 engine
383 glBindTexture(GL_TEXTURE_2D
, m_base_tex
);
384 glEnable(GL_TEXTURE_2D
);
385 glColor4f(1.,1.,1.,1.);
389 glTexCoord2f(0, 1.0);
392 glTexCoord2f(x_fraction
, 1.0);
393 glVertex2f(width(), 0);
395 glTexCoord2f(x_fraction
, 1.0-y_fraction
);
396 glVertex2f(width(), height());
398 glTexCoord2f(0, 1.0-y_fraction
);
399 glVertex2f(0, height());
403 glDisable(GL_TEXTURE_2D
);
405 p
.endNativePainting(); // Needed when using the GL2 engine
406 p
.restore(); // Needed when using the GL1 engine
410 m_pbuffer
->updateDynamicTexture(m_compositing_tex
);
413 painter
->beginNativePainting(); // Needed when using the GL2 engine
414 glWidget()->makeCurrent(); // Needed when using the GL1 engine
415 glBindTexture(GL_TEXTURE_2D
, m_compositing_tex
);
416 glEnable(GL_TEXTURE_2D
);
418 glBlendFunc(GL_ONE
, GL_ONE_MINUS_SRC_ALPHA
);
419 glColor4f(1.,1.,1.,1.);
422 glTexCoord2f(0, 1.0);
425 glTexCoord2f(x_fraction
, 1.0);
426 glVertex2f(width(), 0);
428 glTexCoord2f(x_fraction
, 1.0-y_fraction
);
429 glVertex2f(width(), height());
431 glTexCoord2f(0, 1.0-y_fraction
);
432 glVertex2f(0, height());
435 glDisable(GL_TEXTURE_2D
);
436 painter
->endNativePainting(); // Needed when using the GL2 engine
441 if (m_buffer
.size() != size()) {
443 m_base_buffer
= QPixmap(size());
444 m_base_buffer
.fill(Qt::transparent
);
446 m_buffer
= QImage(size(), QImage::Format_ARGB32_Premultiplied
);
447 m_base_buffer
= QImage(size(), QImage::Format_ARGB32_Premultiplied
);
449 m_base_buffer
.fill(0);
452 QPainter
p(&m_base_buffer
);
458 m_buffer
= m_base_buffer
;
460 memcpy(m_buffer
.bits(), m_base_buffer
.bits(), m_buffer
.byteCount());
464 QPainter
p(&m_buffer
);
469 painter
->drawPixmap(0, 0, m_buffer
);
471 painter
->drawImage(0, 0, m_buffer
);
475 if (m_animation_enabled
&& m_current_object
== NoObject
) {
480 void CompositionRenderer::mousePressEvent(QMouseEvent
*e
)
482 setDescriptionEnabled(false);
484 QRectF circle
= rectangle_around(m_circle_pos
);
486 if (circle
.contains(e
->pos())) {
487 m_current_object
= Circle
;
488 m_offset
= circle
.center() - e
->pos();
490 m_current_object
= NoObject
;
494 void CompositionRenderer::mouseMoveEvent(QMouseEvent
*e
)
496 if (m_current_object
== Circle
) setCirclePos(e
->pos() + m_offset
);
499 void CompositionRenderer::mouseReleaseEvent(QMouseEvent
*)
501 m_current_object
= NoObject
;
503 if (m_animation_enabled
)
507 void CompositionRenderer::setCirclePos(const QPointF
&pos
)
509 const QRect oldRect
= rectangle_around(m_circle_pos
).toAlignedRect();
511 const QRect newRect
= rectangle_around(m_circle_pos
).toAlignedRect();
512 #if defined(QT_OPENGL_SUPPORT) && !defined(QT_OPENGL_ES)
517 update(oldRect
| newRect
);