|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the demonstration applications of the Qt Toolkit. |
|
8 ** |
|
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 |
|
14 ** this package. |
|
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 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "textbutton.h" |
|
43 #include "demoitemanimation.h" |
|
44 #include "demotextitem.h" |
|
45 #include "colors.h" |
|
46 #include "menumanager.h" |
|
47 |
|
48 #define BUTTON_WIDTH 180 |
|
49 #define BUTTON_HEIGHT 19 |
|
50 |
|
51 class ButtonBackground : public DemoItem |
|
52 { |
|
53 public: |
|
54 TextButton::BUTTONTYPE type; |
|
55 bool highlighted; |
|
56 bool pressed; |
|
57 QSize logicalSize; |
|
58 |
|
59 ButtonBackground(TextButton::BUTTONTYPE type, bool highlighted, bool pressed, QSize logicalSize, |
|
60 QGraphicsScene *scene, QGraphicsItem *parent) : DemoItem(scene, parent) |
|
61 { |
|
62 this->type = type; |
|
63 this->highlighted = highlighted; |
|
64 this->pressed = pressed; |
|
65 this->logicalSize = logicalSize; |
|
66 useSharedImage(QString(__FILE__) + static_cast<int>(type) + highlighted + pressed); |
|
67 } |
|
68 |
|
69 protected: |
|
70 QImage *createImage(const QMatrix &matrix) const |
|
71 { |
|
72 if (type == TextButton::SIDEBAR || type == TextButton::PANEL) |
|
73 return createRoundButtonBackground(matrix); |
|
74 else |
|
75 return createArrowBackground(matrix); |
|
76 } |
|
77 |
|
78 QImage *createRoundButtonBackground(const QMatrix &matrix) const |
|
79 { |
|
80 QRect scaledRect; |
|
81 scaledRect = matrix.mapRect(QRect(0, 0, this->logicalSize.width(), this->logicalSize.height())); |
|
82 |
|
83 QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied); |
|
84 image->fill(QColor(0, 0, 0, 0).rgba()); |
|
85 QPainter painter(image); |
|
86 painter.setRenderHint(QPainter::SmoothPixmapTransform); |
|
87 painter.setRenderHint(QPainter::Antialiasing); |
|
88 painter.setPen(Qt::NoPen); |
|
89 |
|
90 if (Colors::useEightBitPalette){ |
|
91 painter.setPen(QColor(120, 120, 120)); |
|
92 if (this->pressed) |
|
93 painter.setBrush(QColor(60, 60, 60)); |
|
94 else if (this->highlighted) |
|
95 painter.setBrush(QColor(100, 100, 100)); |
|
96 else |
|
97 painter.setBrush(QColor(80, 80, 80)); |
|
98 } |
|
99 else { |
|
100 QLinearGradient outlinebrush(0, 0, 0, scaledRect.height()); |
|
101 QLinearGradient brush(0, 0, 0, scaledRect.height()); |
|
102 |
|
103 brush.setSpread(QLinearGradient::PadSpread); |
|
104 QColor highlight(255, 255, 255, 70); |
|
105 QColor shadow(0, 0, 0, 70); |
|
106 QColor sunken(220, 220, 220, 30); |
|
107 QColor normal1(255, 255, 245, 60); |
|
108 QColor normal2(255, 255, 235, 10); |
|
109 |
|
110 if (this->type == TextButton::PANEL){ |
|
111 normal1 = QColor(200, 170, 160, 50); |
|
112 normal2 = QColor(50, 10, 0, 50); |
|
113 } |
|
114 |
|
115 if (pressed) { |
|
116 outlinebrush.setColorAt(0.0f, shadow); |
|
117 outlinebrush.setColorAt(1.0f, highlight); |
|
118 brush.setColorAt(0.0f, sunken); |
|
119 painter.setPen(Qt::NoPen); |
|
120 } else { |
|
121 outlinebrush.setColorAt(1.0f, shadow); |
|
122 outlinebrush.setColorAt(0.0f, highlight); |
|
123 brush.setColorAt(0.0f, normal1); |
|
124 if (!this->highlighted) |
|
125 brush.setColorAt(1.0f, normal2); |
|
126 painter.setPen(QPen(outlinebrush, 1)); |
|
127 } |
|
128 painter.setBrush(brush); |
|
129 } |
|
130 |
|
131 if (this->type == TextButton::PANEL) |
|
132 painter.drawRect(0, 0, scaledRect.width(), scaledRect.height()); |
|
133 else |
|
134 painter.drawRoundedRect(0, 0, scaledRect.width(), scaledRect.height(), 10, 90, Qt::RelativeSize); |
|
135 return image; |
|
136 } |
|
137 |
|
138 QImage *createArrowBackground(const QMatrix &matrix) const |
|
139 { |
|
140 QRect scaledRect; |
|
141 scaledRect = matrix.mapRect(QRect(0, 0, this->logicalSize.width(), this->logicalSize.height())); |
|
142 |
|
143 QImage *image = new QImage(scaledRect.width(), scaledRect.height(), QImage::Format_ARGB32_Premultiplied); |
|
144 image->fill(QColor(0, 0, 0, 0).rgba()); |
|
145 QPainter painter(image); |
|
146 painter.setRenderHint(QPainter::SmoothPixmapTransform); |
|
147 painter.setRenderHint(QPainter::Antialiasing); |
|
148 painter.setPen(Qt::NoPen); |
|
149 |
|
150 if (Colors::useEightBitPalette){ |
|
151 painter.setPen(QColor(120, 120, 120)); |
|
152 if (this->pressed) |
|
153 painter.setBrush(QColor(60, 60, 60)); |
|
154 else if (this->highlighted) |
|
155 painter.setBrush(QColor(100, 100, 100)); |
|
156 else |
|
157 painter.setBrush(QColor(80, 80, 80)); |
|
158 } |
|
159 else { |
|
160 QLinearGradient outlinebrush(0, 0, 0, scaledRect.height()); |
|
161 QLinearGradient brush(0, 0, 0, scaledRect.height()); |
|
162 |
|
163 brush.setSpread(QLinearGradient::PadSpread); |
|
164 QColor highlight(255, 255, 255, 70); |
|
165 QColor shadow(0, 0, 0, 70); |
|
166 QColor sunken(220, 220, 220, 30); |
|
167 QColor normal1 = QColor(200, 170, 160, 50); |
|
168 QColor normal2 = QColor(50, 10, 0, 50); |
|
169 |
|
170 if (pressed) { |
|
171 outlinebrush.setColorAt(0.0f, shadow); |
|
172 outlinebrush.setColorAt(1.0f, highlight); |
|
173 brush.setColorAt(0.0f, sunken); |
|
174 painter.setPen(Qt::NoPen); |
|
175 } else { |
|
176 outlinebrush.setColorAt(1.0f, shadow); |
|
177 outlinebrush.setColorAt(0.0f, highlight); |
|
178 brush.setColorAt(0.0f, normal1); |
|
179 if (!this->highlighted) |
|
180 brush.setColorAt(1.0f, normal2); |
|
181 painter.setPen(QPen(outlinebrush, 1)); |
|
182 } |
|
183 painter.setBrush(brush); |
|
184 } |
|
185 |
|
186 painter.drawRect(0, 0, scaledRect.width(), scaledRect.height()); |
|
187 |
|
188 float xOff = scaledRect.width() / 2; |
|
189 float yOff = scaledRect.height() / 2; |
|
190 float sizex = 3.0f * matrix.m11(); |
|
191 float sizey = 1.5f * matrix.m22(); |
|
192 if (this->type == TextButton::UP) |
|
193 sizey *= -1; |
|
194 QPainterPath path; |
|
195 path.moveTo(xOff, yOff + (5 * sizey)); |
|
196 path.lineTo(xOff - (4 * sizex), yOff - (3 * sizey)); |
|
197 path.lineTo(xOff + (4 * sizex), yOff - (3 * sizey)); |
|
198 path.lineTo(xOff, yOff + (5 * sizey)); |
|
199 painter.drawPath(path); |
|
200 |
|
201 return image; |
|
202 } |
|
203 |
|
204 }; |
|
205 |
|
206 TextButton::TextButton(const QString &text, ALIGNMENT align, int userCode, |
|
207 QGraphicsScene *scene, QGraphicsItem *parent, BUTTONTYPE type) |
|
208 : DemoItem(scene, parent) |
|
209 { |
|
210 this->menuString = text; |
|
211 this->buttonLabel = text; |
|
212 this->alignment = align; |
|
213 this->buttonType = type; |
|
214 this->userCode = userCode; |
|
215 this->bgOn = 0; |
|
216 this->bgOff = 0; |
|
217 this->bgHighlight = 0; |
|
218 this->bgDisabled = 0; |
|
219 this->state = OFF; |
|
220 |
|
221 this->setAcceptsHoverEvents(true); |
|
222 this->setCursor(Qt::PointingHandCursor); |
|
223 |
|
224 // Calculate button size: |
|
225 const int w = 180; |
|
226 const int h = 19; |
|
227 if (type == SIDEBAR || type == PANEL) |
|
228 this->logicalSize = QSize(w, h); |
|
229 else |
|
230 this->logicalSize = QSize(int((w / 2.0f) - 5), int(h * 1.5f)); |
|
231 } |
|
232 |
|
233 void TextButton::setMenuString(const QString &menu) |
|
234 { |
|
235 this->menuString = menu; |
|
236 } |
|
237 |
|
238 void TextButton::prepare() |
|
239 { |
|
240 if (!this->prepared){ |
|
241 this->prepared = true; |
|
242 this->setupHoverText(); |
|
243 this->setupScanItem(); |
|
244 this->setupButtonBg(); |
|
245 } |
|
246 } |
|
247 |
|
248 TextButton::~TextButton() |
|
249 { |
|
250 if (this->prepared){ |
|
251 if (Colors::useButtonBalls) |
|
252 delete this->scanAnim; |
|
253 } |
|
254 } |
|
255 |
|
256 QRectF TextButton::boundingRect() const |
|
257 { |
|
258 return QRectF(0, 0, this->logicalSize.width(), this->logicalSize.height()); |
|
259 }; |
|
260 |
|
261 void TextButton::setupHoverText() |
|
262 { |
|
263 if (this->buttonLabel.isEmpty()) |
|
264 return; |
|
265 |
|
266 DemoTextItem *textItem = new DemoTextItem(this->buttonLabel, Colors::buttonFont(), Colors::buttonText, -1, this->scene(), this); |
|
267 textItem->setZValue(zValue() + 2); |
|
268 textItem->setPos(16, 0); |
|
269 } |
|
270 |
|
271 void TextButton::setupScanItem() |
|
272 { |
|
273 if (Colors::useButtonBalls){ |
|
274 ScanItem *scanItem = new ScanItem(0, this); |
|
275 scanItem->setZValue(zValue() + 1); |
|
276 |
|
277 this->scanAnim = new DemoItemAnimation(scanItem); |
|
278 this->scanAnim->timeline->setLoopCount(1); |
|
279 |
|
280 float x = 1; |
|
281 float y = 1.5f; |
|
282 float stop = BUTTON_WIDTH - scanItem->boundingRect().width() - x; |
|
283 if (this->alignment == LEFT){ |
|
284 this->scanAnim->setDuration(2500); |
|
285 this->scanAnim->setPosAt(0.0, QPointF(x, y)); |
|
286 this->scanAnim->setPosAt(0.5, QPointF(x, y)); |
|
287 this->scanAnim->setPosAt(0.7, QPointF(stop, y)); |
|
288 this->scanAnim->setPosAt(1.0, QPointF(x, y)); |
|
289 scanItem->setPos(QPointF(x, y)); |
|
290 } |
|
291 else { |
|
292 this->scanAnim->setPosAt(0.0, QPointF(stop, y)); |
|
293 this->scanAnim->setPosAt(0.5, QPointF(x, y)); |
|
294 this->scanAnim->setPosAt(1.0, QPointF(stop, y)); |
|
295 scanItem->setPos(QPointF(stop, y)); |
|
296 } |
|
297 } |
|
298 } |
|
299 |
|
300 void TextButton::setState(STATE state) |
|
301 { |
|
302 this->state = state; |
|
303 this->bgOn->setRecursiveVisible(state == ON); |
|
304 this->bgOff->setRecursiveVisible(state == OFF); |
|
305 this->bgHighlight->setRecursiveVisible(state == HIGHLIGHT); |
|
306 this->bgDisabled->setRecursiveVisible(state == DISABLED); |
|
307 this->setCursor(state == DISABLED ? Qt::ArrowCursor : Qt::PointingHandCursor); |
|
308 |
|
309 } |
|
310 |
|
311 void TextButton::setupButtonBg() |
|
312 { |
|
313 this->bgOn = new ButtonBackground(this->buttonType, true, true, this->logicalSize, this->scene(), this); |
|
314 this->bgOff = new ButtonBackground(this->buttonType, false, false, this->logicalSize, this->scene(), this); |
|
315 this->bgHighlight = new ButtonBackground(this->buttonType, true, false, this->logicalSize, this->scene(), this); |
|
316 this->bgDisabled = new ButtonBackground(this->buttonType, true, true, this->logicalSize, this->scene(), this); |
|
317 this->setState(OFF); |
|
318 } |
|
319 |
|
320 void TextButton::hoverEnterEvent(QGraphicsSceneHoverEvent *) |
|
321 { |
|
322 if (this->locked || this->state == DISABLED) |
|
323 return; |
|
324 |
|
325 if (this->state == OFF){ |
|
326 this->setState(HIGHLIGHT); |
|
327 |
|
328 if (Colors::noAnimations && Colors::useButtonBalls){ |
|
329 // wait a bit in the beginning |
|
330 // to enhance the effect. Have to this here |
|
331 // so that the adaption can be dynamic |
|
332 this->scanAnim->setDuration(1000); |
|
333 this->scanAnim->setPosAt(0.2, this->scanAnim->posAt(0)); |
|
334 } |
|
335 |
|
336 if (MenuManager::instance()->window->fpsMedian > 10 |
|
337 || Colors::noAdapt |
|
338 || Colors::noTimerUpdate){ |
|
339 if (Colors::useButtonBalls) |
|
340 this->scanAnim->play(true, true); |
|
341 } |
|
342 } |
|
343 } |
|
344 |
|
345 void TextButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) |
|
346 { |
|
347 Q_UNUSED(event); |
|
348 if (this->state == DISABLED) |
|
349 return; |
|
350 |
|
351 this->setState(OFF); |
|
352 |
|
353 if (Colors::noAnimations && Colors::useButtonBalls) |
|
354 this->scanAnim->stop(); |
|
355 } |
|
356 |
|
357 void TextButton::mousePressEvent(QGraphicsSceneMouseEvent *) |
|
358 { |
|
359 if (this->state == DISABLED) |
|
360 return; |
|
361 |
|
362 if (this->state == HIGHLIGHT || this->state == OFF) |
|
363 this->setState(ON); |
|
364 } |
|
365 |
|
366 void TextButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) |
|
367 { |
|
368 if (this->state == ON){ |
|
369 this->setState(OFF); |
|
370 if (!this->locked && this->boundingRect().contains(event->pos())){ |
|
371 MenuManager::instance()->itemSelected(this->userCode, this->menuString); |
|
372 } |
|
373 } |
|
374 } |
|
375 |
|
376 void TextButton::animationStarted(int) |
|
377 { |
|
378 if (this->state == DISABLED) |
|
379 return; |
|
380 this->setState(OFF); |
|
381 } |
|
382 |
|
383 |
|
384 |