A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 405 lines 11 kB view raw
1/*************************************************************************** 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> 24#include <QGraphicsSceneMouseEvent> 25#include <QTransform> 26 27#include <QDebug> 28 29#include <cmath> 30 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" 37#include "skindocument.h" 38 39/* Pixels/second of text scrolling */ 40const double RBViewport::scrollRate = 30; 41 42RBViewport::RBViewport(skin_element* node, const RBRenderInfo& info, 43 ParseTreeNode* pNode) 44 : RBMovable(info.screen()), foreground(info.screen()->foreground()), 45 background(info.screen()->background()), textOffset(0,0), 46 screen(info.screen()), textAlign(Left), showStatusBar(false), 47 statusBarTexture(":/render/statusbar.png"), 48 leftGraphic(0), centerGraphic(0), rightGraphic(0), scrollTime(0), 49 node(pNode), doc(info.document()) 50{ 51 52 if(!node->tag) 53 { 54 /* Default viewport takes up the entire screen */ 55 size = QRectF(0, 0, info.screen()->getWidth(), 56 info.screen()->getHeight()); 57 customUI = false; 58 font = screen->getFont(1); 59 60 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 70 /* Making sure the default viewport can't be graphically manipulated */ 71 setFlag(ItemIsSelectable, false); 72 setFlag(ItemIsMovable, false); 73 74 if(info.model()->rowCount(QModelIndex()) > 1) 75 { 76 /* If there is more than one viewport in the document */ 77 textOffset.setX(-1); 78 } 79 else 80 { 81 setVisible(true); 82 } 83 } 84 else 85 { 86 QString ident; 87 int x,y,w,h; 88 /* Rendering one of the other types of viewport */ 89 switch(node->tag->name[1]) 90 { 91 case '\0': 92 customUI = false; 93 baseParam= 0; 94 break; 95 96 case 'l': 97 /* A preloaded viewport definition */ 98 ident = node->params[0].data.text; 99 customUI = false; 100 if(!screen->viewPortDisplayed(ident)) 101 hide(); 102 info.screen()->loadViewport(ident, this); 103 baseParam= 1; 104 break; 105 106 case 'i': 107 /* Custom UI Viewport */ 108 customUI = true; 109 baseParam= 1; 110 if(node->params[0].type == skin_tag_parameter::DEFAULT) 111 { 112 setVisible(true); 113 } 114 else 115 { 116 hide(); 117 info.screen()->loadViewport(ident, this); 118 } 119 break; 120 } 121 /* Now we grab the info common to all viewports */ 122 int param = baseParam; 123 x = node->params[param++].data.number; 124 if(x < 0) 125 x = info.screen()->boundingRect().right() + x; 126 y = node->params[param++].data.number; 127 if(y < 0) 128 y = info.screen()->boundingRect().bottom() + y; 129 130 if(node->params[param].type == skin_tag_parameter::DEFAULT) 131 w = info.screen()->getWidth() - x; 132 else 133 w = node->params[param].data.number; 134 if(w < 0) 135 w = info.screen()->getWidth() + w - x; 136 137 if(node->params[++param].type == skin_tag_parameter::DEFAULT) 138 h = info.screen()->getHeight() - y; 139 else 140 h = node->params[param].data.number; 141 if(h < 0) 142 h = info.screen()->getHeight() + h - y; 143 144 /* 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 151 if(node->params[++param].type == skin_tag_parameter::DEFAULT) 152 font = screen->getFont(1); 153 else 154 font = screen->getFont(node->params[param].data.number); 155 156 setPos(x, y); 157 size = QRectF(0, 0, w, h); 158 } 159 160 debug = info.device()->data("showviewports").toBool(); 161 lineHeight = font->lineHeight(); 162 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 173 if(customUI) 174 screen->setCustomUI(this); 175} 176 177RBViewport::~RBViewport() 178{ 179} 180 181QPainterPath RBViewport::shape() const 182{ 183 QPainterPath retval; 184 retval.addRect(size); 185 return retval; 186} 187 188void RBViewport::paint(QPainter *painter, 189 const QStyleOptionGraphicsItem *option, QWidget *widget) 190{ 191 if(!screen->hasBackdrop() && background != screen->background()) 192 { 193 painter->fillRect(size, QBrush(background)); 194 } 195 196 painter->setBrush(Qt::NoBrush); 197 painter->setPen(customUI ? Qt::blue : Qt::red); 198 if(debug) 199 painter->drawRect(size); 200 201 if(showStatusBar) 202 painter->fillRect(QRectF(0, 0, size.width(), 8), statusBarTexture); 203 204 RBMovable::paint(painter, option, widget); 205} 206 207void RBViewport::newLine() 208{ 209 if(textOffset.x() < 0) 210 return; 211 212 if(leftText != "") 213 alignLeft(); 214 215 if(centerText != "") 216 alignCenter(); 217 218 if(rightText != "") 219 alignRight(); 220 221 textOffset.setY(textOffset.y() + lineHeight); 222 textOffset.setX(0); 223 textAlign = Left; 224 225 leftText.clear(); 226 rightText.clear(); 227 centerText.clear(); 228 229 leftGraphic = 0; 230 centerGraphic = 0; 231 rightGraphic = 0; 232 233 scrollTime = 0; 234} 235 236void RBViewport::write(QString text) 237{ 238 if(textOffset.x() < 0) 239 return; 240 241 Alignment align = textAlign; 242 243 if(align == Left) 244 { 245 leftText.append(text); 246 } 247 else if(align == Center) 248 { 249 centerText.append(text); 250 } 251 else if(align == Right) 252 { 253 rightText.append(text); 254 } 255} 256 257void RBViewport::showPlaylist(const RBRenderInfo &info, int start, 258 ParseTreeNode* lines) 259{ 260 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 { 266 lines->render(info, this); 267 newLine(); 268 song++; 269 } 270} 271 272void RBViewport::makeFullScreen() 273{ 274 size = screen->boundingRect(); 275 setPos(screen->pos()); 276} 277 278void RBViewport::saveGeometry() 279{ 280 QRectF bounds = boundingRect(); 281 QPointF origin = pos(); 282 283 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); 287} 288 289void RBViewport::alignLeft() 290{ 291 int y = textOffset.y(); 292 293 if(leftGraphic) 294 delete leftGraphic; 295 296 leftGraphic = font->renderText(leftText, foreground, size.width(), this); 297 leftGraphic->setPos(0, y); 298 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 */ 305 double totalTime = 2 * difference / scrollRate; 306 scrollTime -= totalTime * std::floor(scrollTime / totalTime); 307 308 /* Calculating the offset */ 309 if(scrollTime < static_cast<double>(difference) / scrollRate) 310 { 311 leftGraphic->setOffset(scrollRate * scrollTime); 312 } 313 else 314 { 315 scrollTime -= static_cast<double>(difference) / scrollRate; 316 leftGraphic->setOffset(difference - scrollRate * scrollTime); 317 } 318 } 319} 320 321void RBViewport::alignCenter() 322{ 323 int y = textOffset.y(); 324 int x = 0; 325 326 if(centerGraphic) 327 delete centerGraphic; 328 329 centerGraphic = font->renderText(centerText, foreground, size.width(), 330 this); 331 332 if(centerGraphic->boundingRect().width() < size.width()) 333 { 334 x = size.width() - centerGraphic->boundingRect().width(); 335 x /= 2; 336 } 337 else 338 { 339 x = 0; 340 } 341 342 centerGraphic->setPos(x, y); 343 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 */ 350 double totalTime = 2 * difference / scrollRate; 351 scrollTime -= totalTime * std::floor(scrollTime / totalTime); 352 353 /* Calculating the offset */ 354 if(scrollTime < static_cast<double>(difference) / scrollRate) 355 { 356 centerGraphic->setOffset(scrollRate * scrollTime); 357 } 358 else 359 { 360 scrollTime -= static_cast<double>(difference) / scrollRate; 361 centerGraphic->setOffset(difference - scrollRate * scrollTime); 362 } 363 } 364 365} 366 367void RBViewport::alignRight() 368{ 369 int y = textOffset.y(); 370 int x = 0; 371 372 if(rightGraphic) 373 delete rightGraphic; 374 375 rightGraphic = font->renderText(rightText, foreground, size.width(), this); 376 377 if(rightGraphic->boundingRect().width() < size.width()) 378 x = size.width() - rightGraphic->boundingRect().width(); 379 else 380 x = 0; 381 382 rightGraphic->setPos(x, y); 383 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 */ 390 double totalTime = 2 * difference / scrollRate; 391 scrollTime -= totalTime * std::floor(scrollTime / totalTime); 392 393 /* Calculating the offset */ 394 if(scrollTime < static_cast<double>(difference) / scrollRate) 395 { 396 rightGraphic->setOffset(scrollRate * scrollTime); 397 } 398 else 399 { 400 scrollTime -= static_cast<double>(difference) / scrollRate; 401 rightGraphic->setOffset(difference - scrollRate * scrollTime); 402 } 403 } 404} 405