blob: fea1055935b6a09d079a9acddbf37cd186268adc [file] [log] [blame]
Robert Bieberd8827b52010-06-18 21:10:01 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Robert Bieber
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <QPainter>
23#include <QPainterPath>
Robert Biebera83adc72010-08-03 08:42:30 +000024#include <QGraphicsSceneMouseEvent>
25#include <QTransform>
26
27#include <QDebug>
28
Robert Bieber13e97cd2010-07-07 22:25:42 +000029#include <cmath>
Robert Bieberd8827b52010-06-18 21:10:01 +000030
31#include "rbviewport.h"
32#include "rbscreen.h"
33#include "rbrenderinfo.h"
34#include "parsetreemodel.h"
35#include "tag_table.h"
36#include "skin_parser.h"
Robert Bieber49865b22010-08-04 09:16:52 +000037#include "skindocument.h"
Robert Bieberd8827b52010-06-18 21:10:01 +000038
Robert Bieber13e97cd2010-07-07 22:25:42 +000039/* Pixels/second of text scrolling */
40const double RBViewport::scrollRate = 30;
41
Robert Bieber49865b22010-08-04 09:16:52 +000042RBViewport::RBViewport(skin_element* node, const RBRenderInfo& info,
43 ParseTreeNode* pNode)
Robert Bieber83c60a12010-08-03 22:29:26 +000044 : RBMovable(info.screen()), foreground(info.screen()->foreground()),
Robert Bieber273b9d62010-06-25 05:14:13 +000045 background(info.screen()->background()), textOffset(0,0),
Robert Bieber35150b62010-06-30 21:28:11 +000046 screen(info.screen()), textAlign(Left), showStatusBar(false),
Robert Bieber3214e372010-07-07 06:50:30 +000047 statusBarTexture(":/render/statusbar.png"),
Robert Bieber49865b22010-08-04 09:16:52 +000048 leftGraphic(0), centerGraphic(0), rightGraphic(0), scrollTime(0),
49 node(pNode), doc(info.document())
Robert Bieberd8827b52010-06-18 21:10:01 +000050{
Robert Bieber1ee2cdd2010-08-12 23:05:53 +000051
Robert Bieberd8827b52010-06-18 21:10:01 +000052 if(!node->tag)
53 {
54 /* Default viewport takes up the entire screen */
55 size = QRectF(0, 0, info.screen()->getWidth(),
56 info.screen()->getHeight());
Robert Bieberd3027052010-06-23 07:18:22 +000057 customUI = false;
Robert Bieber39e25202010-07-06 19:19:11 +000058 font = screen->getFont(1);
Robert Bieberd8827b52010-06-18 21:10:01 +000059
Robert Bieberd1a392a2010-08-09 19:37:23 +000060 screen->setDefault(this);
61
62 if(screen->getCustomUI())
63 {
64 RBViewport* cui = screen->getCustomUI();
65 size = cui->boundingRect();
66 setPos(cui->pos());
67
68 }
69
Robert Bieber87d25902010-08-06 08:01:07 +000070 /* Making sure the default viewport can't be graphically manipulated */
71 setFlag(ItemIsSelectable, false);
72 setFlag(ItemIsMovable, false);
73
Robert Bieberd8827b52010-06-18 21:10:01 +000074 if(info.model()->rowCount(QModelIndex()) > 1)
75 {
76 /* If there is more than one viewport in the document */
Robert Bieber364af4f2010-07-11 04:36:05 +000077 textOffset.setX(-1);
Robert Bieberd8827b52010-06-18 21:10:01 +000078 }
79 else
80 {
Robert Bieberac9287b2010-06-22 07:55:50 +000081 setVisible(true);
Robert Bieberd8827b52010-06-18 21:10:01 +000082 }
83 }
84 else
85 {
Robert Biebere1d8a3d2010-06-21 20:11:58 +000086 QString ident;
87 int x,y,w,h;
88 /* Rendering one of the other types of viewport */
Robert Bieberd8827b52010-06-18 21:10:01 +000089 switch(node->tag->name[1])
90 {
91 case '\0':
Robert Biebere1d8a3d2010-06-21 20:11:58 +000092 customUI = false;
Robert Bieber49865b22010-08-04 09:16:52 +000093 baseParam= 0;
Robert Bieberd8827b52010-06-18 21:10:01 +000094 break;
95
96 case 'l':
Robert Biebere1d8a3d2010-06-21 20:11:58 +000097 /* A preloaded viewport definition */
98 ident = node->params[0].data.text;
99 customUI = false;
Robert Bieber1fbea622010-06-29 21:09:29 +0000100 if(!screen->viewPortDisplayed(ident))
101 hide();
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000102 info.screen()->loadViewport(ident, this);
Robert Bieber49865b22010-08-04 09:16:52 +0000103 baseParam= 1;
Robert Bieberd8827b52010-06-18 21:10:01 +0000104 break;
105
106 case 'i':
107 /* Custom UI Viewport */
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000108 customUI = true;
Robert Bieber49865b22010-08-04 09:16:52 +0000109 baseParam= 1;
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000110 if(node->params[0].type == skin_tag_parameter::DEFAULT)
111 {
Robert Bieberac9287b2010-06-22 07:55:50 +0000112 setVisible(true);
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000113 }
114 else
115 {
Robert Bieberac9287b2010-06-22 07:55:50 +0000116 hide();
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000117 info.screen()->loadViewport(ident, this);
118 }
Robert Bieberd8827b52010-06-18 21:10:01 +0000119 break;
Robert Bieberd8827b52010-06-18 21:10:01 +0000120 }
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000121 /* Now we grab the info common to all viewports */
Robert Bieber49865b22010-08-04 09:16:52 +0000122 int param = baseParam;
Robert Bieber15488a02010-07-15 06:24:11 +0000123 x = node->params[param++].data.number;
Robert Bieber8cd51a72010-07-01 02:07:41 +0000124 if(x < 0)
125 x = info.screen()->boundingRect().right() + x;
Robert Bieber15488a02010-07-15 06:24:11 +0000126 y = node->params[param++].data.number;
Robert Bieber8cd51a72010-07-01 02:07:41 +0000127 if(y < 0)
128 y = info.screen()->boundingRect().bottom() + y;
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000129
130 if(node->params[param].type == skin_tag_parameter::DEFAULT)
131 w = info.screen()->getWidth() - x;
132 else
Robert Bieber15488a02010-07-15 06:24:11 +0000133 w = node->params[param].data.number;
Robert Bieber8cd51a72010-07-01 02:07:41 +0000134 if(w < 0)
135 w = info.screen()->getWidth() + w - x;
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000136
137 if(node->params[++param].type == skin_tag_parameter::DEFAULT)
138 h = info.screen()->getHeight() - y;
139 else
Robert Bieber15488a02010-07-15 06:24:11 +0000140 h = node->params[param].data.number;
Robert Bieber8cd51a72010-07-01 02:07:41 +0000141 if(h < 0)
142 h = info.screen()->getHeight() + h - y;
Robert Biebere1d8a3d2010-06-21 20:11:58 +0000143
Robert Bieber2f68e5b2010-07-03 22:57:42 +0000144 /* Adjusting to screen coordinates if necessary */
145 if(screen->parentItem() != 0)
146 {
147 x -= screen->parentItem()->pos().x();
148 y -= screen->parentItem()->pos().y();
149 }
150
Robert Bieber39e25202010-07-06 19:19:11 +0000151 if(node->params[++param].type == skin_tag_parameter::DEFAULT)
152 font = screen->getFont(1);
153 else
Robert Bieber15488a02010-07-15 06:24:11 +0000154 font = screen->getFont(node->params[param].data.number);
Robert Bieber2f68e5b2010-07-03 22:57:42 +0000155
Robert Bieberf4fd16c2010-06-23 07:23:47 +0000156 setPos(x, y);
157 size = QRectF(0, 0, w, h);
Robert Bieberd8827b52010-06-18 21:10:01 +0000158 }
Robert Bieberd2ed5942010-06-30 07:00:05 +0000159
Robert Bieber9d685162010-07-02 05:58:06 +0000160 debug = info.device()->data("showviewports").toBool();
Robert Bieberd2ed5942010-06-30 07:00:05 +0000161 lineHeight = font->lineHeight();
Robert Bieberb4774632010-08-13 02:05:38 +0000162
163 if(info.screen()->isRtlMirrored() && info.device()->data("rtl").toBool())
164 {
165 /* Mirroring the viewport */
166 double x = screen->boundingRect().width() - 2 * pos().x();
167 QTransform t;
168 t.translate(x, 0);
169 t.scale(-1, 1);
170 setTransform(t);
171 }
172
Robert Bieber2f68e5b2010-07-03 22:57:42 +0000173 if(customUI)
174 screen->setCustomUI(this);
Robert Bieberd8827b52010-06-18 21:10:01 +0000175}
176
177RBViewport::~RBViewport()
178{
179}
180
181QPainterPath RBViewport::shape() const
182{
183 QPainterPath retval;
184 retval.addRect(size);
185 return retval;
186}
187
Robert Bieberd8827b52010-06-18 21:10:01 +0000188void RBViewport::paint(QPainter *painter,
189 const QStyleOptionGraphicsItem *option, QWidget *widget)
190{
Robert Bieber273b9d62010-06-25 05:14:13 +0000191 if(!screen->hasBackdrop() && background != screen->background())
192 {
193 painter->fillRect(size, QBrush(background));
194 }
195
Robert Bieberd3027052010-06-23 07:18:22 +0000196 painter->setBrush(Qt::NoBrush);
197 painter->setPen(customUI ? Qt::blue : Qt::red);
Robert Bieber5300c702010-06-26 05:51:07 +0000198 if(debug)
199 painter->drawRect(size);
Robert Bieber35150b62010-06-30 21:28:11 +0000200
201 if(showStatusBar)
202 painter->fillRect(QRectF(0, 0, size.width(), 8), statusBarTexture);
Robert Bieber83c60a12010-08-03 22:29:26 +0000203
204 RBMovable::paint(painter, option, widget);
Robert Bieberd8827b52010-06-18 21:10:01 +0000205}
206
Robert Biebera54bfaa2010-07-01 20:30:19 +0000207void RBViewport::newLine()
Robert Bieberac9287b2010-06-22 07:55:50 +0000208{
Robert Bieber364af4f2010-07-11 04:36:05 +0000209 if(textOffset.x() < 0)
210 return;
211
Robert Bieber88145652010-07-07 07:49:00 +0000212 if(leftText != "")
213 alignLeft();
214
215 if(centerText != "")
216 alignCenter();
217
218 if(rightText != "")
219 alignRight();
220
Robert Biebera54bfaa2010-07-01 20:30:19 +0000221 textOffset.setY(textOffset.y() + lineHeight);
222 textOffset.setX(0);
223 textAlign = Left;
Robert Bieber3214e372010-07-07 06:50:30 +0000224
Robert Biebera54bfaa2010-07-01 20:30:19 +0000225 leftText.clear();
226 rightText.clear();
227 centerText.clear();
Robert Bieber3214e372010-07-07 06:50:30 +0000228
229 leftGraphic = 0;
230 centerGraphic = 0;
231 rightGraphic = 0;
Robert Bieber13e97cd2010-07-07 22:25:42 +0000232
233 scrollTime = 0;
Robert Bieber273b9d62010-06-25 05:14:13 +0000234}
Robert Bieberac9287b2010-06-22 07:55:50 +0000235
Robert Bieber273b9d62010-06-25 05:14:13 +0000236void RBViewport::write(QString text)
237{
Robert Bieber364af4f2010-07-11 04:36:05 +0000238 if(textOffset.x() < 0)
239 return;
240
Robert Bieber1ee2cdd2010-08-12 23:05:53 +0000241 Alignment align = textAlign;
Robert Bieber1ee2cdd2010-08-12 23:05:53 +0000242
243 if(align == Left)
Robert Bieberd2ed5942010-06-30 07:00:05 +0000244 {
Robert Bieber3214e372010-07-07 06:50:30 +0000245 leftText.append(text);
Robert Bieberd2ed5942010-06-30 07:00:05 +0000246 }
Robert Bieber1ee2cdd2010-08-12 23:05:53 +0000247 else if(align == Center)
Robert Bieberd2ed5942010-06-30 07:00:05 +0000248 {
Robert Bieber3214e372010-07-07 06:50:30 +0000249 centerText.append(text);
Robert Bieberd2ed5942010-06-30 07:00:05 +0000250 }
Robert Bieber1ee2cdd2010-08-12 23:05:53 +0000251 else if(align == Right)
Robert Bieberd2ed5942010-06-30 07:00:05 +0000252 {
Robert Bieber3214e372010-07-07 06:50:30 +0000253 rightText.append(text);
Robert Bieberd2ed5942010-06-30 07:00:05 +0000254 }
Robert Bieberac9287b2010-06-22 07:55:50 +0000255}
Robert Bieberd2ed5942010-06-30 07:00:05 +0000256
Robert Bieber26a2f812010-07-01 21:49:55 +0000257void RBViewport::showPlaylist(const RBRenderInfo &info, int start,
Robert Bieberb4131692010-08-15 02:04:06 +0000258 ParseTreeNode* lines)
Robert Bieber26a2f812010-07-01 21:49:55 +0000259{
Robert Bieber26a2f812010-07-01 21:49:55 +0000260
261 int song = start + info.device()->data("pp").toInt();
262 int numSongs = info.device()->data("pe").toInt();
263
264 while(song <= numSongs && textOffset.y() + lineHeight < size.height())
265 {
Robert Bieberb4131692010-08-15 02:04:06 +0000266 lines->render(info, this);
Robert Bieber26a2f812010-07-01 21:49:55 +0000267 newLine();
268 song++;
269 }
270}
271
Robert Bieberd1a392a2010-08-09 19:37:23 +0000272void RBViewport::makeFullScreen()
273{
274 size = screen->boundingRect();
275 setPos(screen->pos());
276}
277
Robert Bieber83c60a12010-08-03 22:29:26 +0000278void RBViewport::saveGeometry()
Robert Biebera83adc72010-08-03 08:42:30 +0000279{
Robert Bieber49865b22010-08-04 09:16:52 +0000280 QRectF bounds = boundingRect();
281 QPointF origin = pos();
Robert Biebera83adc72010-08-03 08:42:30 +0000282
Robert Bieber49865b22010-08-04 09:16:52 +0000283 node->modParam(static_cast<int>(origin.x()), baseParam);
284 node->modParam(static_cast<int>(origin.y()), baseParam + 1);
285 node->modParam(static_cast<int>(bounds.width()), baseParam + 2);
286 node->modParam(static_cast<int>(bounds.height()), baseParam + 3);
Robert Biebera83adc72010-08-03 08:42:30 +0000287}
288
Robert Bieberd2ed5942010-06-30 07:00:05 +0000289void RBViewport::alignLeft()
290{
291 int y = textOffset.y();
Robert Bieberd2ed5942010-06-30 07:00:05 +0000292
Robert Bieber3214e372010-07-07 06:50:30 +0000293 if(leftGraphic)
294 delete leftGraphic;
295
296 leftGraphic = font->renderText(leftText, foreground, size.width(), this);
297 leftGraphic->setPos(0, y);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000298
299 /* Setting scroll position if necessary */
300 int difference = leftGraphic->realWidth()
301 - leftGraphic->boundingRect().width();
302 if(difference > 0)
303 {
304 /* Subtracting out complete cycles */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000305 double totalTime = 2 * difference / scrollRate;
Robert Bieber13e97cd2010-07-07 22:25:42 +0000306 scrollTime -= totalTime * std::floor(scrollTime / totalTime);
307
308 /* Calculating the offset */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000309 if(scrollTime < static_cast<double>(difference) / scrollRate)
Robert Bieber13e97cd2010-07-07 22:25:42 +0000310 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000311 leftGraphic->setOffset(scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000312 }
313 else
314 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000315 scrollTime -= static_cast<double>(difference) / scrollRate;
316 leftGraphic->setOffset(difference - scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000317 }
318 }
Robert Bieberd2ed5942010-06-30 07:00:05 +0000319}
320
321void RBViewport::alignCenter()
322{
323 int y = textOffset.y();
324 int x = 0;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000325
Robert Bieber3214e372010-07-07 06:50:30 +0000326 if(centerGraphic)
327 delete centerGraphic;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000328
Robert Bieber3214e372010-07-07 06:50:30 +0000329 centerGraphic = font->renderText(centerText, foreground, size.width(),
330 this);
Robert Bieberd2ed5942010-06-30 07:00:05 +0000331
Robert Bieber3214e372010-07-07 06:50:30 +0000332 if(centerGraphic->boundingRect().width() < size.width())
Robert Bieberd2ed5942010-06-30 07:00:05 +0000333 {
Robert Bieber3214e372010-07-07 06:50:30 +0000334 x = size.width() - centerGraphic->boundingRect().width();
335 x /= 2;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000336 }
Robert Bieber3214e372010-07-07 06:50:30 +0000337 else
338 {
339 x = 0;
340 }
341
342 centerGraphic->setPos(x, y);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000343
344 /* Setting scroll position if necessary */
345 int difference = centerGraphic->realWidth()
346 - centerGraphic->boundingRect().width();
347 if(difference > 0)
348 {
349 /* Subtracting out complete cycles */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000350 double totalTime = 2 * difference / scrollRate;
Robert Bieber13e97cd2010-07-07 22:25:42 +0000351 scrollTime -= totalTime * std::floor(scrollTime / totalTime);
352
353 /* Calculating the offset */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000354 if(scrollTime < static_cast<double>(difference) / scrollRate)
Robert Bieber13e97cd2010-07-07 22:25:42 +0000355 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000356 centerGraphic->setOffset(scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000357 }
358 else
359 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000360 scrollTime -= static_cast<double>(difference) / scrollRate;
361 centerGraphic->setOffset(difference - scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000362 }
363 }
364
Robert Bieberd2ed5942010-06-30 07:00:05 +0000365}
366
367void RBViewport::alignRight()
368{
Robert Bieberd2ed5942010-06-30 07:00:05 +0000369 int y = textOffset.y();
370 int x = 0;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000371
Robert Bieber3214e372010-07-07 06:50:30 +0000372 if(rightGraphic)
373 delete rightGraphic;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000374
Robert Bieber3214e372010-07-07 06:50:30 +0000375 rightGraphic = font->renderText(rightText, foreground, size.width(), this);
Robert Bieberd2ed5942010-06-30 07:00:05 +0000376
Robert Bieber3214e372010-07-07 06:50:30 +0000377 if(rightGraphic->boundingRect().width() < size.width())
378 x = size.width() - rightGraphic->boundingRect().width();
379 else
380 x = 0;
Robert Bieberd2ed5942010-06-30 07:00:05 +0000381
Robert Bieber3214e372010-07-07 06:50:30 +0000382 rightGraphic->setPos(x, y);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000383
384 /* Setting scroll position if necessary */
385 int difference = rightGraphic->realWidth()
386 - rightGraphic->boundingRect().width();
387 if(difference > 0)
388 {
389 /* Subtracting out complete cycles */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000390 double totalTime = 2 * difference / scrollRate;
Robert Bieber13e97cd2010-07-07 22:25:42 +0000391 scrollTime -= totalTime * std::floor(scrollTime / totalTime);
392
393 /* Calculating the offset */
Robert Biebereb93e3b2010-07-08 05:30:00 +0000394 if(scrollTime < static_cast<double>(difference) / scrollRate)
Robert Bieber13e97cd2010-07-07 22:25:42 +0000395 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000396 rightGraphic->setOffset(scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000397 }
398 else
399 {
Robert Biebereb93e3b2010-07-08 05:30:00 +0000400 scrollTime -= static_cast<double>(difference) / scrollRate;
401 rightGraphic->setOffset(difference - scrollRate * scrollTime);
Robert Bieber13e97cd2010-07-07 22:25:42 +0000402 }
403 }
Robert Bieberd2ed5942010-06-30 07:00:05 +0000404}
405