MythTV master
lcdprocclient.cpp
Go to the documentation of this file.
1/*
2 lcdprocclient.cpp
3
4 a MythTV project object to control an
5 LCDproc server
6
7 (c) 2002, 2003 Thor Sigvaldason, Dan Morphis and Isaac Richards
8*/
9
10// c/c++
11#include <algorithm>
12#include <chrono> // for milliseconds
13#include <cmath>
14#include <cstdlib>
15#include <thread> // for sleep_for
16#include <utility>
17
18//qt
19#include <QCoreApplication>
20#include <QEvent>
21#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
22#include <QStringConverter>
23#endif
24#include <QTimer>
25
26// mythtv
27#include "libmythbase/compat.h"
33#include "libmythtv/tv.h"
34
35// mythlcdserver
36#include "lcdprocclient.h"
37#include "lcdserver.h"
38
39static constexpr uint8_t LCD_START_COL { 3 };
40
41static constexpr uint8_t LCD_VERSION_4 { 1 };
42static constexpr uint8_t LCD_VERSION_5 { 2 };
43
44static constexpr std::chrono::milliseconds LCD_TIME_TIME { 3s };
45static constexpr std::chrono::milliseconds LCD_SCROLLLIST_TIME { 2s };
46
48
50 : QObject(nullptr),
51 m_socket(new QTcpSocket(this)),
52 m_timeTimer (new QTimer(this)),
53 m_scrollWTimer (new QTimer(this)),
54 m_preScrollWTimer (new QTimer(this)),
55 m_menuScrollTimer (new QTimer(this)),
56 m_menuPreScrollTimer (new QTimer(this)),
57 m_popMenuTimer (new QTimer(this)),
58 m_checkConnectionsTimer (new QTimer(this)),
59 m_recStatusTimer (new QTimer(this)),
60 m_scrollListTimer (new QTimer(this)),
61 m_showMessageTimer (new QTimer(this)),
62 m_updateRecInfoTimer (new QTimer(this)),
63 m_lcdTextItems (new QList<LCDTextItem>),
64 m_lcdMenuItems (new QList<LCDMenuItem>),
65 m_parentLCDServer (lparent)
66{
67 // Constructor for LCDProcClient
68 //
69 // Note that this does *not* include opening the socket and initiating
70 // communications with the LDCd daemon.
71
72 if (debug_level > 0)
73 LOG(VB_GENERAL, LOG_INFO,
74 "LCDProcClient: An LCDProcClient object now exists");
75
76 connect(m_socket, &QAbstractSocket::errorOccurred, this, &LCDProcClient::veryBadThings);
77 connect(m_socket, &QIODevice::readyRead, this, &LCDProcClient::serverSendingData);
78
80 if ( m_lcdWidth < 12)
81 {
82 if ( m_lcdHeight == 1)
83 lcdStartCol = 0;
84 else
85 lcdStartCol = 1;
86 }
87
89
91
92 m_preScrollWTimer->setSingleShot(true);
93 connect( m_preScrollWTimer, &QTimer::timeout, this,
95
96 m_popMenuTimer->setSingleShot(true);
98
100
101 connect( m_menuPreScrollTimer, &QTimer::timeout, this,
103
106 m_checkConnectionsTimer->start(10s);
107
109
111
112 m_showMessageTimer->setSingleShot(true);
113 connect( m_showMessageTimer, &QTimer::timeout, this,
115
116 m_updateRecInfoTimer->setSingleShot(true);
117 connect( m_updateRecInfoTimer, &QTimer::timeout, this,
119
121}
122
124{
125 QString lcd_host = gCoreContext->GetSetting("LCDHost", "localhost");
126 int lcd_port = gCoreContext->GetNumSetting("LCDPort", 13666);
127
128 if (lcd_host.length() > 0 && lcd_port > 1024)
129 connectToHost(lcd_host, lcd_port);
130
131 return m_connected;
132}
133
134bool LCDProcClient::connectToHost(const QString &lhostname, unsigned int lport)
135{
136 // Open communications
137 // Store the hostname and port in case we need to reconnect.
138
139 m_hostname = lhostname;
140 m_port = lport;
141
142 // Don't even try to connect if we're currently disabled.
143 if (!gCoreContext->GetBoolSetting("LCDEnable", false))
144 {
145 m_connected = false;
146 return m_connected;
147 }
148
149 if (!m_connected )
150 {
151 QTextStream os(m_socket);
152 m_socket->connectToHost(m_hostname, m_port);
153
154 int timeout = 1000;
155 while (--timeout && m_socket->state() != QAbstractSocket::ConnectedState)
156 {
157 qApp->processEvents();
158 std::this_thread::sleep_for(1ms);
159
160 if (m_socket->state() == QAbstractSocket::ConnectedState)
161 {
162 m_connected = true;
163 os << "hello\n";
164 break;
165 }
166 }
167 }
168
169 return m_connected;
170}
171
172void LCDProcClient::sendToServer(const QString &someText)
173{
174 // Check the socket, make sure the connection is still up
175 if (m_socket->state() != QAbstractSocket::ConnectedState)
176 {
177 if (!m_lcdReady )
178 return;
179
180 m_lcdReady = false;
181
182 //Stop everything
183 stopAll();
184
185 // Ack, connection to server has been severed try to re-establish the
186 // connection
187 LOG(VB_GENERAL, LOG_ERR,
188 "LCDProcClient: Connection to LCDd died unexpectedly.");
189 return;
190 }
191
192 QTextStream os(m_socket);
193#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
194 os.setCodec("ISO 8859-1");
195#else
196 os.setEncoding(QStringConverter::Latin1);
197#endif
198
199 m_lastCommand = someText;
200
201 if ( m_connected )
202 {
203 if (debug_level > 9)
204 LOG(VB_NETWORK, LOG_INFO,
205 "LCDProcClient: Sending to Server: " + someText);
206
207 // Just stream the text out the socket
208
209 os << someText << "\n";
210 }
211 else
212 {
213 // Buffer this up in the hope that the connection will open soon
214
215 m_sendBuffer += someText;
216 m_sendBuffer += "\n";
217 }
218}
219
220void LCDProcClient::setPriority(const QString &screen, PRIORITY priority)
221{
222 QString aString;
223 int err = 0;
224 aString = "screen_set ";
225 aString += screen;
226 aString += " priority ";
227
228 switch (priority) {
229 case TOP:
230 aString += m_prioTop;
231 break;
232 case URGENT:
233 aString += m_prioUrgent;
234 break;
235 case HIGH:
236 aString += m_prioHigh;
237 break;
238 case MEDIUM:
239 aString += m_prioMedium;
240 break;
241 case LOW:
242 aString += m_prioLow;
243 break;
244 case OFF:
245 aString += m_prioOff;
246 break;
247 default:
248 err = 1;
249 break;
250 }
251 if (err == 0)
252 sendToServer (aString);
253}
254
255void LCDProcClient::setHeartbeat (const QString &screen, bool onoff)
256{
257 QString msg;
258 if (onoff)
259 {
261 {
262 msg = "widget_add " + screen + " heartbeat";
263 }
265 {
266 msg = "screen_set " + screen + " heartbeat on";
267 }
268 }
269 else
270 {
272 {
273 msg = "widget_del " + screen + " heartbeat";
274 }
276 {
277 msg = "screen_set " + screen + " heartbeat off";
278 }
279 }
280 sendToServer (msg);
281}
282
284{
285 if (debug_level > 0)
286 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: checking connections");
287
288 // check connection to mythbackend
290 {
291 if (debug_level > 0)
292 LOG(VB_GENERAL, LOG_INFO,
293 "LCDProcClient: connecting to master server");
295 LOG(VB_GENERAL, LOG_ERR,
296 "LCDProcClient: connecting to master server failed");
297 }
298
299 //check connection to LCDProc server
300 if (m_socket->state() != QAbstractSocket::ConnectedState)
301 {
302 if (debug_level > 0)
303 LOG(VB_GENERAL, LOG_INFO,
304 "LCDProcClient: connecting to LCDProc server");
305
306 m_lcdReady = false;
307 m_connected = false;
308
309 // Retry to connect. . . Maybe the user restarted LCDd?
311 }
312}
313
315{
316 QString lineFromServer;
317 QString tempString;
318 QStringList aList;
319 QStringList::Iterator it;
320
321 // This gets activated automatically by the QSocket class whenever
322 // there's something to read.
323 //
324 // We currently spend most of our time (except for the first line sent
325 // back) ignoring it.
326 //
327 // Note that if anyone has an LCDproc type lcd with buttons on it, this is
328 // where we would want to catch button presses and make the rest of
329 // mythTV/mythMusic do something (change tracks, channels, etc.)
330
331 while(m_socket->canReadLine())
332 {
333 lineFromServer = m_socket->readLine();
334 lineFromServer = lineFromServer.remove("\n");
335 lineFromServer = lineFromServer.remove("\r");
336
337 if (debug_level > 0)
338 {
339 // Make debugging be less noisy
340 if (lineFromServer != "success")
341 LOG(VB_NETWORK, LOG_INFO,
342 "LCDProcClient: Received from server: " + lineFromServer);
343 }
344
345 aList = lineFromServer.split(" ");
346 if (aList.first() == "connect")
347 {
348 // We got a connect, which is a response to "hello"
349 //
350 // Need to parse out some data according the LCDproc client/server
351 // spec (which is poorly documented)
352 it = aList.begin();
353 it++;
354 if ((*it) != "LCDproc")
355 {
356 LOG(VB_GENERAL, LOG_WARNING,
357 "LCDProcClient: WARNING: Second parameter "
358 "returned from LCDd was not \"LCDproc\"");
359 }
360
361 // Skip through some stuff
362 it++; // server version
363 QString server_version = *it;
364 it++; // the string "protocol"
365 it++; // protocol version
366 QString protocol_version = *it;
367 setVersion (server_version, protocol_version);
368 it++; // the string "lcd"
369 it++; // the string "wid";
370 it++; // Ah, the LCD width
371
372 tempString = *it;
373 setWidth(tempString.toInt());
374
375 it++; // the string "hgt"
376 it++; // the LCD height
377
378 tempString = *it;
379 setHeight(tempString.toInt());
380 it++; // the string "cellwid"
381 it++; // Cell width in pixels;
382
383 tempString = *it;
384 setCellWidth(tempString.toInt());
385
386 it++; // the string "cellhgt"
387 it++; // Cell height in pixels;
388
389 tempString = *it;
390 setCellHeight(tempString.toInt());
391
392 init();
393
395 }
396
397 if (aList.first() == "huh?")
398 {
399 LOG(VB_GENERAL, LOG_WARNING,
400 "LCDProcClient: WARNING: Something is getting"
401 "passed to LCDd that it doesn't understand");
402 LOG(VB_GENERAL, LOG_WARNING, "last command: " + m_lastCommand );
403 }
404 else if (aList.first() == "key")
405 {
406 if ( m_parentLCDServer )
407 m_parentLCDServer->sendKeyPress(aList.last().trimmed());
408 }
409 }
410}
411
413{
414 QString aString;
415 m_lcdKeyString = "";
416
417 m_connected = true;
418
419 // This gets called when we receive the "connect" string from the server
420 // indicating that "hello" was succesful
421 sendToServer("client_set name Myth");
422
423 // Create all the screens and widgets (when we change activity in the myth
424 // program, we just swap the priorities of the screens to show only the
425 // "current one")
426 sendToServer("screen_add Time");
427 setPriority("Time", MEDIUM);
428
429 if (gCoreContext->GetSetting("LCDBigClock", "1") == "1")
430 {
431 // Big Clock - spans multiple lines
432 sendToServer("widget_add Time rec1 string");
433 sendToServer("widget_add Time rec2 string");
434 sendToServer("widget_add Time rec3 string");
435 sendToServer("widget_add Time recCnt string");
436 sendToServer("widget_add Time d0 num");
437 sendToServer("widget_add Time d1 num");
438 sendToServer("widget_add Time sep num");
439 sendToServer("widget_add Time d2 num");
440 sendToServer("widget_add Time d3 num");
441 sendToServer("widget_add Time ampm string");
442 sendToServer("widget_add Time dot string");
443 }
444 else
445 {
446 sendToServer("widget_add Time timeWidget string");
447 sendToServer("widget_add Time topWidget string");
448 }
449
450 // The Menu Screen
451 // I'm not sure how to do multi-line widgets with lcdproc so we're going
452 // the ghetto way
453 sendToServer("screen_add Menu");
454 setPriority("Menu", LOW);
455 sendToServer("widget_add Menu topWidget string");
456 for (unsigned int i = 1; i <= m_lcdHeight; i++)
457 {
458 aString = "widget_add Menu menuWidget";
459 aString += QString::number (i);
460 aString += " string";
461 sendToServer(aString);
462 }
463
464 // The Music Screen
465 sendToServer("screen_add Music");
466 setPriority("Music", LOW);
467 sendToServer("widget_add Music topWidget1 string");
468 sendToServer("widget_add Music topWidget2 string");
469 sendToServer("widget_add Music timeWidget string");
470 sendToServer("widget_add Music infoWidget string");
471 sendToServer("widget_add Music progressBar hbar");
472
473 // The Channel Screen
474 sendToServer("screen_add Channel");
475 setPriority("Channel", LOW);
476 sendToServer("widget_add Channel topWidget string");
477 sendToServer("widget_add Channel botWidget string");
478 sendToServer("widget_add Channel timeWidget string");
479 sendToServer("widget_add Channel progressBar hbar");
480
481 // The Generic Screen
482 sendToServer("screen_add Generic");
483 setPriority("Generic", LOW);
484 sendToServer("widget_add Generic textWidget1 string");
485 sendToServer("widget_add Generic textWidget2 string");
486 sendToServer("widget_add Generic textWidget3 string");
487 sendToServer("widget_add Generic textWidget4 string");
488 sendToServer("widget_add Generic progressBar hbar");
489
490 // The Volume Screen
491 sendToServer("screen_add Volume");
492 setPriority("Volume", LOW);
493 sendToServer("widget_add Volume topWidget string");
494 sendToServer("widget_add Volume botWidget string");
495 sendToServer("widget_add Volume progressBar hbar");
496
497 // The Recording Status Screen
498 sendToServer("screen_add RecStatus");
499 setPriority("RecStatus", LOW);
500 sendToServer("widget_add RecStatus textWidget1 string");
501 sendToServer("widget_add RecStatus textWidget2 string");
502 sendToServer("widget_add RecStatus textWidget3 string");
503 sendToServer("widget_add RecStatus textWidget4 string");
504 sendToServer("widget_add RecStatus progressBar hbar");
505
506 m_lcdReady = true;
507 loadSettings();
508
509 // default to showing time
510 switchToTime();
511
513
514 // do we need to show the startup message
515 if (!m_startupMessage.isEmpty())
517
518 // send buffer if there's anything in there
519 if ( m_sendBuffer.length() > 0)
520 {
522 m_sendBuffer = "";
523 }
524}
525
526QString LCDProcClient::expandString(const QString &aString) const
527{
529 return aString;
530
531 // if version 5 then white space seperate the list of characters
532 auto add_ws = [](const QString& str, auto x){ return str + x + QString(" "); };
533 return std::accumulate(aString.cbegin(), aString.cend(), QString(), add_ws);
534}
535
537{
538 if (!m_lcdReady )
539 return;
540
541 QString aString;
542 QString old_keystring = m_lcdKeyString;
543
544 m_timeFormat = gCoreContext->GetSetting("LCDTimeFormat", "");
545 if ( m_timeFormat.isEmpty())
546 m_timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
547
548 m_dateFormat = gCoreContext->GetSetting("DateFormat", "dd.MM.yyyy");
549
550 // Get LCD settings
551 m_lcdShowMusic=(gCoreContext->GetSetting("LCDShowMusic", "1")=="1");
552 m_lcdShowMusicItems=(gCoreContext->GetSetting("LCDShowMusicItems", "ArtistAlbumTitle"));
553 m_lcdShowTime=(gCoreContext->GetSetting("LCDShowTime", "1")=="1");
554 m_lcdShowChannel=(gCoreContext->GetSetting("LCDShowChannel", "1")=="1");
555 m_lcdShowGeneric=(gCoreContext->GetSetting("LCDShowGeneric", "1")=="1");
556 m_lcdShowVolume=(gCoreContext->GetSetting("LCDShowVolume", "1")=="1");
557 m_lcdShowMenu=(gCoreContext->GetSetting("LCDShowMenu", "1")=="1");
558 m_lcdShowRecstatus=(gCoreContext->GetSetting("LCDShowRecStatus", "1")=="1");
559 m_lcdBacklightOn=(gCoreContext->GetSetting("LCDBacklightOn", "1")=="1");
560 m_lcdHeartbeatOn=(gCoreContext->GetSetting("LCDHeartBeatOn", "1")=="1");
561 m_lcdPopupTime = gCoreContext->GetDurSetting<std::chrono::seconds>("LCDPopupTime", 5s);
562 m_lcdBigClock = (gCoreContext->GetSetting("LCDBigClock", "1")=="1");
563 m_lcdKeyString = gCoreContext->GetSetting("LCDKeyString", "ABCDEF");
564
565 if (!old_keystring.isEmpty())
566 {
567 aString = "client_del_key " + expandString(old_keystring);
568 sendToServer(aString);
569 }
570
571 aString = "client_add_key " + expandString( m_lcdKeyString );
572 sendToServer(aString);
573
575 if ( m_lcdBacklightOn )
576 sendToServer("screen_set Time backlight on");
577 else
578 sendToServer("screen_set Time backlight off");
579
581 sendToServer("screen_set Menu backlight on");
582
583 setHeartbeat ("Music", m_lcdHeartbeatOn );
584 sendToServer("screen_set Music backlight on");
585
586 setHeartbeat ("Channel", m_lcdHeartbeatOn );
587 sendToServer("screen_set Channel backlight on");
588
589 setHeartbeat ("Generic", m_lcdHeartbeatOn );
590 sendToServer("screen_set Generic backlight on");
591
592 setHeartbeat ("Volume", m_lcdHeartbeatOn );
593 sendToServer("screen_set Volume backlight on");
594
595 setHeartbeat ("RecStatus", m_lcdHeartbeatOn );
596 sendToServer("screen_set RecStatus backlight on");
597}
598
600{
601 QList<LCDTextItem> textItems;
602
603 QStringList list = formatScrollerText( m_startupMessage );
604
605 int startrow = 1;
606 if (list.count() < (int) m_lcdHeight )
607 startrow = (( m_lcdHeight - list.count()) / 2) + 1;
608
609 for (int x = 0; x < list.count(); x++)
610 {
611 if (x == (int) m_lcdHeight )
612 break;
613 textItems.append(LCDTextItem(x + startrow, ALIGN_LEFT, list[x],
614 "Generic", false));
615 }
616
617 switchToGeneric(&textItems);
618
620}
621
623{
624 switchToTime();
625}
626
627void LCDProcClient::setStartupMessage(QString msg, std::chrono::seconds messagetime)
628{
629 m_startupMessage = std::move(msg);
630 m_startupShowTime = messagetime;
631}
632
633void LCDProcClient::setWidth(unsigned int x)
634{
635 if (x < 1 || x > 80)
636 return;
637 m_lcdWidth = x;
638}
639
640void LCDProcClient::setHeight(unsigned int x)
641{
642 if (x < 1 || x > 80)
643 return;
644 m_lcdHeight = x;
645}
646
647void LCDProcClient::setCellWidth(unsigned int x)
648{
649 if (x < 1 || x > 16)
650 return;
651 m_cellWidth = x;
652}
653
655{
656 if (x < 1 || x > 16)
657 return;
658 m_cellHeight = x;
659}
660
661void LCDProcClient::setVersion(const QString &sversion, const QString &pversion)
662{
663 m_protocolVersion = pversion;
664 m_serverVersion = sversion;
665
666 // the pVersion number is used internally to designate which protocol
667 // version LCDd is using:
668
669 if ( m_serverVersion.startsWith ("CVS-current") ||
670 m_serverVersion.startsWith ("0.5"))
671 {
672 // Latest CVS versions of LCDd has priorities switched
674 m_prioTop = "input";
675 m_prioUrgent = "alert";
676 m_prioHigh = "foreground";
677 m_prioMedium = "info";
678 m_prioLow = "background";
679 m_prioOff = "hidden";
680 }
681 else
682 {
684 m_prioTop = "64";
685 m_prioUrgent = "128";
686 m_prioHigh = "240";
687 m_prioMedium = "248";
688 m_prioLow = "252";
689 m_prioOff = "255";
690 }
691}
692
694{
695 if (debug_level > 0)
696 {
697 LOG(VB_GENERAL, LOG_INFO,
698 QString("LCDProcClient: The server is %1x%2 with each cell "
699 "being %3x%4.")
700 .arg( m_lcdWidth ).arg( m_lcdHeight ).arg( m_cellWidth ).arg( m_cellHeight ));
701 LOG(VB_GENERAL, LOG_INFO,
702 QString("LCDProcClient: LCDd version %1, protocol version %2.")
704 }
705
706 if (debug_level > 1)
707 {
708 LOG(VB_GENERAL, LOG_INFO,
709 QString("LCDProcClient: MythTV LCD settings:"));
710 LOG(VB_GENERAL, LOG_INFO,
711 QString("LCDProcClient: - showmusic : %1")
712 .arg( m_lcdShowMusic ));
713 LOG(VB_GENERAL, LOG_INFO,
714 QString("LCDProcClient: - showmusicitems : %1")
715 .arg( m_lcdShowMusicItems ));
716 LOG(VB_GENERAL, LOG_INFO,
717 QString("LCDProcClient: - showtime : %1")
718 .arg( m_lcdShowTime ));
719 LOG(VB_GENERAL, LOG_INFO,
720 QString("LCDProcClient: - showchannel : %1")
721 .arg( m_lcdShowChannel ));
722 LOG(VB_GENERAL, LOG_INFO,
723 QString("LCDProcClient: - showrecstatus : %1")
724 .arg( m_lcdShowRecstatus ));
725 LOG(VB_GENERAL, LOG_INFO,
726 QString("LCDProcClient: - showgeneric : %1")
727 .arg( m_lcdShowGeneric ));
728 LOG(VB_GENERAL, LOG_INFO,
729 QString("LCDProcClient: - showvolume : %1")
730 .arg( m_lcdShowVolume ));
731 LOG(VB_GENERAL, LOG_INFO,
732 QString("LCDProcClient: - showmenu : %1")
733 .arg( m_lcdShowMenu ));
734 LOG(VB_GENERAL, LOG_INFO,
735 QString("LCDProcClient: - backlighton : %1")
736 .arg( m_lcdBacklightOn ));
737 LOG(VB_GENERAL, LOG_INFO,
738 QString("LCDProcClient: - heartbeaton : %1")
739 .arg( m_lcdHeartbeatOn ));
740 LOG(VB_GENERAL, LOG_INFO,
741 QString("LCDProcClient: - popuptime : %1")
742 .arg( m_lcdPopupTime.count() ));
743 }
744}
745
746void LCDProcClient::veryBadThings(QAbstractSocket::SocketError /*error*/)
747{
748 // Deal with failures to connect and inabilities to communicate
749 LOG(VB_GENERAL, LOG_ERR, QString("Could not connect to LCDd: %1")
750 .arg(m_socket->errorString()));
751 m_socket->close();
752}
753
755{
756 if ( m_scrollListItems.count() == 0)
757 return;
758
760 return;
761
764
766 if ((int) m_scrollListItem >= m_scrollListItems.count())
768}
769
771{
772 // The usual reason things would get this far and then lcd_ready being
773 // false is the connection died and we're trying to re-establish the
774 // connection
775 if (debug_level > 1)
776 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: stopAll");
777
778 if ( m_lcdReady )
779 {
780 setPriority("Time", OFF);
781 setPriority("Music", OFF);
782 setPriority("Channel", OFF);
783 setPriority("Generic", OFF);
784 setPriority("Volume", OFF);
785 setPriority("Menu", OFF);
786 setPriority("RecStatus", OFF);
787 }
788
789 m_timeTimer->stop();
790 m_preScrollWTimer->stop();
791 m_scrollWTimer->stop();
792 m_popMenuTimer->stop();
793 m_menuScrollTimer->stop();
794 m_menuPreScrollTimer->stop();
795 m_recStatusTimer->stop();
796 m_scrollListTimer->stop();
797
798 unPopMenu();
799}
800
802{
803 setPriority("Time", MEDIUM);
804 setPriority("RecStatus", LOW);
805
806 m_timeTimer->start(1s);
807 outputTime();
808 m_activeScreen = "Time";
809 m_isTimeVisible = true;
810
813}
814
815void LCDProcClient::outputText(QList<LCDTextItem> *textItems)
816{
817 if (!m_lcdReady )
818 return;
819
820 QList<LCDTextItem>::iterator it = textItems->begin();
821 QString num;
822 unsigned int counter = 1;
823
824 // Do the definable scrolling in here.
825 // Use asignScrollingWidgets(curItem->getText(), "textWidget" + num);
826 // When scrolling is set, alignment has no effect
827 while (it != textItems->end() && counter < m_lcdHeight )
828 {
829 LCDTextItem *curItem = &(*it);
830 ++it;
831 num.setNum(curItem->getRow());
832
833 if (curItem->getScroll())
834 {
835 assignScrollingWidgets(curItem->getText(), curItem->getScreen(),
836 "textWidget" + num, curItem->getRow());
837 }
838 else
839 {
840 switch (curItem->getAlignment())
841 {
842 case ALIGN_LEFT:
843 outputLeftText(curItem->getScreen(), curItem->getText(),
844 "textWidget" + num, curItem->getRow());
845 break;
846 case ALIGN_RIGHT:
847 outputRightText(curItem->getScreen(), curItem->getText(),
848 "textWidget" + num, curItem->getRow());
849 break;
850 case ALIGN_CENTERED:
851 outputCenteredText(curItem->getScreen(), curItem->getText(),
852 "textWidget" + num, curItem->getRow());
853 break;
854 default: break;
855 }
856 }
857
858 ++counter;
859 }
860}
861
862void LCDProcClient::outputCenteredText(const QString& theScreen, QString theText, const QString& widget,
863 int row)
864{
865 QString aString;
866 unsigned int x = 0;
867
868 x = (( m_lcdWidth - theText.length()) / 2) + 1;
869
870 if (x > m_lcdWidth )
871 x = 1;
872
873 aString = "widget_set ";
874 aString += theScreen;
875 aString += " " + widget + " ";
876 aString += QString::number(x);
877 aString += " ";
878 aString += QString::number(row);
879 aString += " \"";
880 aString += theText.replace ('"', "\"");
881 aString += "\"";
882 sendToServer(aString);
883}
884
885void LCDProcClient::outputLeftText(const QString& theScreen, QString theText, const QString& widget,
886 int row)
887{
888 QString aString;
889 aString = "widget_set ";
890 aString += theScreen;
891 aString += " " + widget + " 1 ";
892 aString += QString::number(row);
893 aString += " \"";
894 aString += theText.replace ('"', "\"");
895 aString += "\"";
896 sendToServer(aString);
897}
898
899void LCDProcClient::outputRightText(const QString& theScreen, QString theText, const QString& widget,
900 int row)
901{
902 QString aString;
903 unsigned int x = (int)( m_lcdWidth - theText.length()) + 1;
904
905 aString = "widget_set ";
906 aString += theScreen;
907 aString += " " + widget + " ";
908 aString += QString::number(x);
909 aString += " ";
910 aString += QString::number(row);
911 aString += " \"";
912 aString += theText.replace ('"', "\"");
913 aString += "\"";
914 sendToServer(aString);
915}
916
917void LCDProcClient::assignScrollingList(QStringList theList, QString theScreen,
918 QString theWidget, int theRow)
919{
920 m_scrollListScreen = std::move(theScreen);
921 m_scrollListWidget = std::move(theWidget);
922 m_scrollListRow = theRow;
923 m_scrollListItems = std::move(theList);
924
926 scrollList();
928}
929
930//
931// Prepare for scrolling one or more text widgets on a single screen.
932// Notes:
933// - Before assigning the first text, call: lcdTextItems->clear();
934// - After assigning the last text, call: formatScrollingWidgets()
935// That's it ;-)
936
937void LCDProcClient::assignScrollingWidgets(const QString& theText, const QString& theScreen,
938 const QString& theWidget, int theRow)
939{
940 m_scrollScreen = theScreen;
941
942 // Alignment is not used...
943 m_lcdTextItems->append(LCDTextItem(theRow, ALIGN_LEFT, theText,
944 theScreen, true, theWidget));
945}
946
948{
949 m_scrollWTimer->stop();
950 m_preScrollWTimer->stop();
951
952 if ( m_lcdTextItems->isEmpty())
953 return; // Weird...
954
955 // Get the length of the longest item to scroll
956 auto longest = [](int cur, const auto & item)
957 { return std::max(cur, static_cast<int>(item.getText().length())); };
958 int max_len = std::accumulate(m_lcdTextItems->cbegin(), m_lcdTextItems->cend(),
959 0, longest);
960
961 // Make all scrollable items the same lenght and do the initial output
962 auto it = m_lcdTextItems->begin();
963 while (it != m_lcdTextItems->end())
964 {
965 LCDTextItem *curItem = &(*it);
966 ++it;
967 if (curItem->getText().length() > (int) m_lcdWidth )
968 {
969 QString temp;
970 QString temp2;
971 temp = temp.fill(QChar(' '), max_len - curItem->getText().length());
972 temp2 = temp2.fill(QChar(' '), m_lcdWidth );
973 curItem->setText(temp2 + curItem->getText() + temp);
975 curItem->getText().mid( m_lcdWidth, max_len),
976 curItem->getWidget(), curItem->getRow());
977 }
978 else
979 {
980 curItem->setScrollable(false);
982 curItem->getWidget(), curItem->getRow());
983 }
984 }
985
986 if (max_len <= (int) m_lcdWidth )
987 // We're done, no scrolling
988 return;
989
990 m_preScrollWTimer->start(2s);
991}
992
994{
996 m_preScrollWTimer->stop();
997 m_scrollWTimer->start(400ms);
998}
999
1001{
1003 return;
1004
1005 if ( m_lcdTextItems->isEmpty())
1006 return; // Weird...
1007
1008 unsigned int len = 0;
1009 for (const auto & item : std::as_const(*m_lcdTextItems))
1010 {
1011 if (item.getScroll())
1012 {
1013 // Note that all scrollable items have the same length!
1014 len = item.getText().length();
1015
1017 item.getText().mid( m_scrollPosition, m_lcdWidth ),
1018 item.getWidget(), item.getRow());
1019 }
1020 }
1021
1022 if (len == 0)
1023 {
1024 // Shouldn't happen, but....
1025 LOG(VB_GENERAL, LOG_ERR,
1026 "LCDProcClient::scrollWidgets called without scrollable items");
1027 m_scrollWTimer->stop();
1028 return;
1029 }
1031 if ( m_scrollPosition >= len)
1033}
1034
1035void LCDProcClient::startMusic(QString artist, const QString& album, const QString& track)
1036{
1037 // Playing music displays:
1038 // For 1-line displays:
1039 // <ArtistAlbumTitle>
1040 // For 2-line displays:
1041 // <ArtistAlbumTitle>
1042 // <Elapse/Remaining Time>
1043 // For 3-line displays:
1044 // <ArtistAlbumTitle>
1045 // <Elapse/Remaining Time>
1046 // <Info+ProgressBar>
1047 // For displays with more than 3 lines:
1048 // <ArtistAlbum>
1049 // <Title>
1050 // <Elapse/Remaining Time>
1051 // <Info+ProgressBar>
1052
1053 // Clear the progressBar and timeWidget before activating the Music
1054 // screen. This prevents the display of outdated junk.
1055 sendToServer("widget_set Music progressBar 1 1 0");
1056 sendToServer("widget_set Music timeWidget 1 1 \"\"");
1057 m_lcdTextItems->clear();
1058
1059 m_musicProgress = 0.0F;
1060 QString aString = std::move(artist);
1061 if ( m_lcdShowMusicItems == "ArtistAlbumTitle")
1062 {
1063 aString += " [";
1064 aString += album;
1065 aString += "] ";
1066 }
1067 else if ( m_lcdHeight < 4)
1068 {
1069 aString += " - ";
1070 }
1071
1072 if ( m_lcdHeight < 4)
1073 {
1074 aString += track;
1075 }
1076 else
1077 {
1078 assignScrollingWidgets(track, "Music", "topWidget2", 2);
1079 }
1080 assignScrollingWidgets(aString, "Music", "topWidget1", 1);
1082
1083 // OK, everything is at least somewhat initialised. Activate
1084 // the music screen.
1085 m_activeScreen = "Music";
1086 if ( m_lcdShowMusic )
1087 setPriority("Music", HIGH);
1088}
1089
1090void LCDProcClient::startChannel(const QString& channum, const QString& title, const QString& subtitle)
1091{
1092 QString aString;
1093
1094 if ( m_lcdShowChannel )
1095 setPriority("Channel", HIGH);
1096
1097 m_activeScreen = "Channel";
1098
1099 if ( m_lcdHeight <= 2)
1100 {
1101 aString = channum + "|" + title;
1102 if (!subtitle.isEmpty())
1103 aString += "|" + subtitle;
1104 QStringList list = formatScrollerText(aString);
1105 assignScrollingList(list, "Channel", "topWidget", 1);
1106 }
1107 else
1108 {
1109 aString = channum;
1110 m_lcdTextItems->clear();
1111 assignScrollingWidgets(aString, "Channel", "topWidget", 1);
1112 aString = title;
1113 if (subtitle.length() > 0)
1114 {
1115 aString += " - '";
1116 aString += subtitle;
1117 aString += "'";
1118 }
1119 assignScrollingWidgets(aString, "Channel", "botWidget", 2);
1121 }
1122
1123 m_channelTime = "";
1124 m_progress = 0.0;
1125 outputChannel();
1126}
1127
1128void LCDProcClient::startGeneric(QList<LCDTextItem> *textItems)
1129{
1130 QList<LCDTextItem>::iterator it = textItems->begin();
1131 LCDTextItem *curItem = &(*it);
1132
1133 if ( m_lcdShowGeneric )
1134 setPriority("Generic", TOP);
1135
1136 // Clear out the LCD. Do this before checking if its empty incase the user
1137 // wants to just clear the lcd
1138 outputLeftText("Generic", "", "textWidget1", 1);
1139 outputLeftText("Generic", "", "textWidget2", 2);
1140 outputLeftText("Generic", "", "textWidget3", 3);
1141
1142 // If nothing, return without setting up the timer, etc
1143 if (textItems->isEmpty())
1144 return;
1145
1146 m_activeScreen = "Generic";
1147
1148 m_busyProgress = false;
1149 m_busyPos = 1;
1150 m_busyDirection = 1;
1151 m_busyIndicatorSize = 2.0F;
1152 m_genericProgress = 0.0;
1153
1154 // Todo, make scrolling definable in LCDTextItem
1155 ++it;
1156
1157
1158 // Weird observations:
1159 // - The first item is always assumed 'scrolling', for this
1160 // item, the scrollable property is ignored...
1161 // - Why output line 1, progressbar, rest of lines? Why not
1162 // all outputlines, progressbar? That way, outputText() can
1163 // just handle the whole thing and the 'pop off' stuff can go.
1164 //
1165 m_lcdTextItems->clear();
1166 assignScrollingWidgets(curItem->getText(), "Generic",
1167 "textWidget1", curItem->getRow());
1168
1169 outputGeneric();
1170
1171 // Pop off the first item so item one isn't written twice
1172 textItems->removeFirst();
1173 if (!textItems->isEmpty())
1174 outputText(textItems);
1176}
1177
1178void LCDProcClient::startMenu(QList<LCDMenuItem> *menuItems, QString app_name,
1179 bool popMenu)
1180{
1181 // Now do the menu items
1182 if (menuItems->isEmpty())
1183 return;
1184
1185 QString aString;
1186
1187 // Stop the scrolling if the menu has changed
1188 m_menuScrollTimer->stop();
1189
1190 // Menu is higher priority than volume
1191 if ( m_lcdShowMenu )
1192 setPriority("Menu", URGENT);
1193
1194 // Write out the app name
1195 if ( m_lcdHeight > 1)
1196 outputCenteredText("Menu", std::move(app_name), "topWidget", 1);
1197
1198 QList<LCDMenuItem>::iterator it = menuItems->begin();
1199
1200 // First loop through and figure out where the selected item is in the
1201 // list so we know how many above and below to display
1202 unsigned int selectedItem = 0;
1203 unsigned int counter = 0;
1204 bool oneSelected = false;
1205
1206 while (it != menuItems->end())
1207 {
1208 LCDMenuItem *curItem = &(*it);
1209 ++it;
1210 if (curItem->isSelected() && !oneSelected)
1211 {
1212 selectedItem = counter + 1;
1213 oneSelected = true;
1214 break;
1215 }
1216 ++counter;
1217 }
1218
1219 // If there isn't one selected item, then write it on the display and return
1220 if (!oneSelected)
1221 {
1222 sendToServer("widget_set Menu topWidget 1 1 \"No menu item selected\"");
1223 sendToServer("widget_set Menu menuWidget1 1 2 \" ABORTING \"");
1224 m_menuScrollTimer->stop();
1225 return;
1226 }
1227
1228 m_popMenuTimer->stop();
1229 // Start the unPop timer if this is a popup menu
1230 if (popMenu)
1232
1233 // QPtrListIterator doesn't contain a deep copy constructor. . .
1234 // This will contain a copy of the menuItems for scrolling purposes
1235 QList<LCDMenuItem>::iterator itTemp = menuItems->begin();
1236 m_lcdMenuItems->clear();
1237 counter = 1;
1238 while (itTemp != menuItems->end())
1239 {
1240 LCDMenuItem *curItem = &(*itTemp);
1241 ++itTemp;
1242 m_lcdMenuItems->append(LCDMenuItem(curItem->isSelected(),
1243 curItem->isChecked(), curItem->ItemName(),
1244 curItem->getIndent()));
1245 ++counter;
1246 }
1247
1248 // If there is only one or two lines on the display, then just write the selected
1249 // item and leave
1250 if ( m_lcdHeight <= 2)
1251 {
1252 it = menuItems->begin();
1253 while (it != menuItems->end())
1254 {
1255 LCDMenuItem *curItem = &(*it);
1256 ++it;
1257 if (curItem->isSelected())
1258 {
1259 // Set the scroll flag if necessary, otherwise set it to false
1260 if (curItem->ItemName().length() > (int)( m_lcdWidth -lcdStartCol))
1261 {
1262 m_menuPreScrollTimer->setSingleShot(true);
1263 m_menuPreScrollTimer->start(2s);
1264 curItem->setScroll(true);
1265 }
1266 else
1267 {
1268 m_menuPreScrollTimer->stop();
1269 curItem->setScroll(false);
1270 }
1271 if ( m_lcdHeight == 2)
1272 {
1273 aString = "widget_set Menu menuWidget1 1 2 \">";
1274 }
1275 else
1276 {
1277 aString = "widget_set Menu menuWidget1 1 1 \"";
1278 }
1279
1280 if (lcdStartCol != 0)
1281 {
1282 switch (curItem->isChecked())
1283 {
1284 case CHECKED: aString += "X "; break;
1285 case UNCHECKED: aString += "O "; break;
1286 case NOTCHECKABLE: aString += " "; break;
1287 default: break;
1288 }
1289 }
1290
1291 aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) +
1292 "\"";
1293 sendToServer(aString);
1294 return;
1295 }
1296 }
1297
1298 return;
1299 }
1300
1301 // Reset things
1302 counter = 1;
1303 it = menuItems->begin();
1304
1305 // Move the iterator to selectedItem lcdHeight/2, if > 1, -1.
1306 unsigned int midPoint = ( m_lcdHeight/2) - 1;
1307 if (selectedItem > midPoint && menuItems->size() >= (int) m_lcdHeight-1)
1308 {
1309 while (counter != selectedItem)
1310 {
1311 ++it;
1312 ++counter;
1313 }
1314 it -= midPoint;
1315 counter -= midPoint;
1316 }
1317
1318 // Back up one if we're at the end so the last item shows up at the bottom
1319 // of the display
1320 if (counter + midPoint > menuItems->size() - midPoint && counter > midPoint)
1321 {
1322 it -= (counter + ( m_lcdHeight / 2) - 1) - (menuItems->size() - midPoint);
1323 }
1324
1325 counter = 1;
1326 while (it != menuItems->end())
1327 {
1328 LCDMenuItem *curItem = &(*it);
1329 // Can't write more menu items then we have on the display
1330 if ((counter + 1) > m_lcdHeight )
1331 break;
1332
1333 ++it;
1334
1335 aString = "widget_set Menu menuWidget";
1336 aString += QString::number(counter) + " 1 ";
1337 aString += QString::number(counter + 1) + " \"";
1338
1339 if (curItem->isSelected())
1340 aString += ">";
1341 else
1342 aString += " ";
1343
1344 switch (curItem->isChecked())
1345 {
1346 case CHECKED: aString += "X "; break;
1347 case UNCHECKED: aString += "O "; break;
1348 case NOTCHECKABLE: aString += " "; break;
1349 default: break;
1350 }
1351
1352 aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) + "\"";
1353 sendToServer(aString);
1354
1355 ++counter;
1356 }
1357
1358 // Make sure to clear out the rest of the screen
1359 while (counter < m_lcdHeight )
1360 {
1361 aString = "widget_set Menu menuWidget";
1362 aString += QString::number(counter) + " 1 ";
1363 aString += QString::number(counter + 1) + " \"\"";
1364 sendToServer(aString);
1365
1366 ++counter;
1367 }
1368
1369 m_menuPreScrollTimer->setSingleShot(true);
1370 m_menuPreScrollTimer->start(2s);
1371}
1372
1374{
1375 // If there are items to scroll, wait 2 seconds for the user to read whats
1376 // already there
1377
1378 if (!m_lcdMenuItems )
1379 return;
1380
1382
1383 QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1384
1385 QString temp;
1386 // Loop through and prepend everything with enough spaces
1387 // for smooth scrolling, and update the position
1388 while (it != m_lcdMenuItems->end())
1389 {
1390 LCDMenuItem *curItem = &(*it);
1391 ++it;
1392 // Don't setup for smooth scrolling if the item isn't long enough
1393 // (It causes problems with items being scrolled when they shouldn't)
1394 if (curItem->ItemName().length() > (int)( m_lcdWidth - lcdStartCol))
1395 {
1396 temp = temp.fill(QChar(' '), m_lcdWidth - curItem->getIndent() -
1397 lcdStartCol);
1398 curItem->setItemName(temp + curItem->ItemName());
1399 curItem->setScrollPos(curItem->getIndent() + temp.length());
1400 curItem->setScroll(true);
1401 }
1402 else
1403 {
1404 curItem->setScroll(false);
1405 }
1406 }
1407
1408 // Can get segfaults if we try to start a timer thats already running. . .
1409 m_menuScrollTimer->stop();
1410 m_menuScrollTimer->start(250ms);
1411}
1412
1414{
1415 if (!m_lcdMenuItems )
1416 return;
1417
1418 QString aString;
1419 QString bString;
1420 QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1421
1423
1424 // First loop through and figure out where the selected item is in the
1425 // list so we know how many above and below to display
1426 unsigned int selectedItem = 0;
1427 unsigned int counter = 0;
1428
1429 while (it != m_lcdMenuItems->end())
1430 {
1431 LCDMenuItem *curItem = &(*it);
1432 ++it;
1433 if (curItem->isSelected())
1434 {
1435 selectedItem = counter + 1;
1436 break;
1437 }
1438 ++counter;
1439 }
1440
1441 // If there is only one or two lines on the display, then just write
1442 // the selected item and leave
1443 it = m_lcdMenuItems->begin();
1444 if ( m_lcdHeight <= 2)
1445 {
1446 while (it != m_lcdMenuItems->end())
1447 {
1448 LCDMenuItem *curItem = &(*it);
1449 ++it;
1450 if (curItem->isSelected())
1451 {
1452 curItem->incrementScrollPos();
1453 if ((int)curItem->getScrollPos() > curItem->ItemName().length())
1454 {
1455 // Scroll slower second and subsequent times through
1456 m_menuScrollTimer->stop();
1457 m_menuScrollTimer->start(500ms);
1458 curItem->setScrollPos(curItem->getIndent());
1459 }
1460
1461 // Stop the timer if this item really doesn't need to scroll.
1462 // This should never have to get invoked because in theory
1463 // the code in startMenu has done its job. . .
1464 if (curItem->ItemName().length() < (int)( m_lcdWidth - lcdStartCol))
1465 m_menuScrollTimer->stop();
1466
1467 if ( m_lcdHeight == 2)
1468 {
1469 aString = "widget_set Menu menuWidget1 1 2 \">";
1470 }
1471 else
1472 {
1473 aString = "widget_set Menu menuWidget1 1 1 \"";
1474 }
1475
1476 if ( m_lcdWidth < 12)
1477 {
1478 switch(curItem->isChecked())
1479 {
1480 case CHECKED: aString += "X"; break;
1481 case UNCHECKED: aString += "O"; break;
1482 case NOTCHECKABLE: aString += ""; break;
1483 default: break;
1484 }
1485 }
1486 else
1487 {
1488 switch(curItem->isChecked())
1489 {
1490 case CHECKED: aString += "X "; break;
1491 case UNCHECKED: aString += "O "; break;
1492 case NOTCHECKABLE: aString += " "; break;
1493 default: break;
1494 }
1495 }
1496
1497 // Indent this item if nessicary
1498 aString += bString.fill(' ', curItem->getIndent());
1499
1500 aString += curItem->ItemName().mid(curItem->getScrollPos(),
1501 ( m_lcdWidth - lcdStartCol));
1502 aString += "\"";
1503 sendToServer(aString);
1504 return;
1505 }
1506 }
1507
1508 return;
1509 }
1510
1511 // Find the longest line, if menuScrollPosition is longer then this, then
1512 // reset them all
1513 it = m_lcdMenuItems->begin();
1514 int longest_line = 0;
1515 int max_scroll_pos = 0;
1516
1517 while (it != m_lcdMenuItems->end())
1518 {
1519 LCDMenuItem *curItem = &(*it);
1520 ++it;
1521 longest_line = std::max(
1522#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1523 curItem->ItemName().length(),
1524#else
1525 static_cast<int>(curItem->ItemName().length()),
1526#endif
1527 longest_line);
1528
1529 if ((int)curItem->getScrollPos() > max_scroll_pos)
1530 max_scroll_pos = curItem->getScrollPos();
1531 }
1532
1533 // If max_scroll_pos > longest_line then reset
1534 if (max_scroll_pos > longest_line)
1535 {
1536 // Scroll slower second and subsequent times through
1537 m_menuScrollTimer->stop();
1538 m_menuScrollTimer->start(500ms);
1540
1541 it = m_lcdMenuItems->begin();
1542 while (it != m_lcdMenuItems->end())
1543 {
1544 LCDMenuItem *curItem = &(*it);
1545 ++it;
1546 curItem->setScrollPos(curItem->getIndent());
1547 }
1548 }
1549
1550 // Reset things
1551 counter = 1;
1552 it = m_lcdMenuItems->begin();
1553
1554 // Move the iterator to selectedItem -1
1555 if (selectedItem != 1 && m_lcdMenuItems->size() >= (int) m_lcdHeight )
1556 {
1557 while (counter != selectedItem)
1558 {
1559 ++it;
1560 ++counter;
1561 }
1562 --it;
1563 }
1564
1565 // Back up one if were at the end so the last item shows up at the bottom
1566 // of the display
1567 if (counter > 1 && (int)counter == m_lcdMenuItems->size())
1568 --it;
1569
1570 bool stopTimer = true;
1571
1572 counter = 1;
1573 while (it != m_lcdMenuItems->end() && counter <= m_lcdHeight )
1574 {
1575 LCDMenuItem *curItem = &(*it);
1576 // Can't write more menu items then we have on the display
1577 if ((counter + 1) > m_lcdHeight )
1578 break;
1579
1580 ++it;
1581
1582 if (curItem->Scroll())
1583 {
1584 stopTimer = false;
1585 aString = "widget_set Menu menuWidget";
1586 aString += QString::number(counter) + " 1 ";
1587 aString += QString::number(counter + 1) + " \"";
1588
1589 if (curItem->isSelected())
1590 aString += ">";
1591 else
1592 aString += " ";
1593
1594 switch (curItem->isChecked())
1595 {
1596 case CHECKED: aString += "X "; break;
1597 case UNCHECKED: aString += "O "; break;
1598 case NOTCHECKABLE: aString += " "; break;
1599 default: break;
1600 }
1601
1602 // Indent this item if nessicary
1603 bString = "";
1604 bString.fill(' ', curItem->getIndent());
1605 aString += bString;
1606
1607 // Increment the scroll position counter for this item
1608 curItem->incrementScrollPos();
1609
1610 if ((int)curItem->getScrollPos() <= longest_line)
1611 aString += curItem->ItemName().mid(curItem->getScrollPos(),
1613
1614 aString += "\"";
1615 sendToServer(aString);
1616 }
1617
1618 ++counter;
1619 }
1620
1621 // If there are no items to scroll, don't waste our time
1622 if (stopTimer)
1623 m_menuScrollTimer->stop();
1624}
1625
1626void LCDProcClient::startVolume(const QString& app_name)
1627{
1628 if ( m_lcdShowVolume )
1629 setPriority("Volume", TOP);
1630 if ( m_lcdHeight > 1)
1631 outputCenteredText("Volume", "MythTV " + app_name + " Volume");
1632 m_volumeLevel = 0.0;
1633
1634 outputVolume();
1635}
1636
1638{
1639 // Stop the scrolling timer
1640 m_menuScrollTimer->stop();
1641 setPriority("Menu", OFF);
1642}
1643
1644void LCDProcClient::setChannelProgress(const QString &time, float value)
1645{
1646 if (!m_lcdReady )
1647 return;
1648
1649 m_progress = value;
1650 m_channelTime = time;
1651
1652 if ( m_progress < 0.0F)
1653 m_progress = 0.0F;
1654 else if ( m_progress > 1.0F)
1655 m_progress = 1.0F;
1656
1657 outputChannel();
1658}
1659
1660void LCDProcClient::setGenericProgress(bool b, float value)
1661{
1662 if (!m_lcdReady )
1663 return;
1664
1665 m_genericProgress = value;
1666
1667 if ( m_genericProgress < 0.0F)
1668 m_genericProgress = 0.0F;
1669 else if ( m_genericProgress > 1.0F)
1670 m_genericProgress = 1.0F;
1671
1672 // Note, this will let us switch to/from busy indicator by
1673 // alternating between being passed true or false for b.
1674 m_busyProgress = b;
1675 if ( m_busyProgress )
1676 {
1677 // If we're at either end of the line, switch direction
1678 if (( m_busyPos + m_busyDirection >
1679 (signed int) m_lcdWidth - m_busyIndicatorSize ) ||
1680 ( m_busyPos + m_busyDirection < 1))
1681 {
1683 }
1686 }
1687 else
1688 {
1689 m_busyPos = 1;
1690 }
1691
1692 outputGeneric();
1693}
1694
1695void LCDProcClient::setMusicProgress(QString time, float value)
1696{
1697 if (!m_lcdReady )
1698 return;
1699
1700 m_musicProgress = value;
1701 m_musicTime = std::move(time);
1702
1703 if ( m_musicProgress < 0.0F)
1704 m_musicProgress = 0.0F;
1705 else if ( m_musicProgress > 1.0F)
1706 m_musicProgress = 1.0F;
1707
1708 outputMusic();
1709}
1710
1712{
1713 if (!m_lcdReady )
1714 return;
1715
1716 m_musicRepeat = repeat;
1717
1718 outputMusic ();
1719}
1720
1722{
1723 if (!m_lcdReady )
1724 return;
1725
1726 m_musicShuffle = shuffle;
1727
1728 outputMusic ();
1729}
1730
1732{
1733 if (!m_lcdReady )
1734 return;
1735
1736 m_volumeLevel = value;
1737
1738 m_volumeLevel = std::clamp(m_volumeLevel, 0.0F, 1.0F);
1739
1740 outputVolume();
1741}
1742
1744{
1745 QString aString;
1746 aString = "output ";
1747 aString += QString::number(mask);
1748 sendToServer(aString);
1749}
1750
1752{
1753 removeWidgets();
1754 loadSettings();
1755 init();
1756}
1757
1759{
1760 QString aString;
1761 QString time = QTime::currentTime().toString( m_timeFormat );
1762 int toffset = 0;
1763 int xoffset = 0;
1764
1765 // kludge ahead: use illegal number (11) to clear num display type
1766
1767 // kluge - Uses string length to determine time format for parsing
1768 // 1:00 = 4 characters = 24-hour format, 1 digit hour
1769 // 12:00 = 5 characters = 24-hour format, 2 digit hour
1770 // 1:00 am = 7 characters = 12-hour format, 1 digit hour
1771 // 12:00 am = 8 characters = 12-hour format, 2 digit hour
1772 if ((time.length() == 8) || (time.length() == 5))
1773 toffset = 1;
1774
1775 // if 12-hour clock, add AM/PM indicator to end of the 2nd line
1776 if (time.length() > 6)
1777 {
1778 aString = time.at(5 + toffset);
1779 aString += time.at(6 + toffset);
1780 xoffset = 1;
1781 }
1782 else
1783 {
1784 aString = " ";
1785 }
1786 outputRightText("Time", aString, "ampm", m_lcdHeight - 1);
1787
1788 if ( m_isRecording )
1789 {
1790 outputLeftText("Time","R","rec1",1);
1791 outputLeftText("Time","E","rec2",2);
1792 outputLeftText("Time","C","rec3",3);
1793 aString = QString::number((int) m_tunerList.size());
1794 outputLeftText("Time",aString,"recCnt",4);
1795
1796 }
1797 else
1798 {
1799 outputLeftText("Time"," ","rec1",1);
1800 outputLeftText("Time"," ","rec2",2);
1801 outputLeftText("Time"," ","rec3",3);
1802 outputLeftText("Time"," ","recCnt",4);
1803 }
1804
1805 // Add Hour 10's Digit
1806 aString = "widget_set Time d0 ";
1807 aString += QString::number( (m_lcdWidth/2) - 5 - xoffset) + " ";
1808 if (toffset == 0)
1809 aString += "11";
1810 else
1811 aString += time.at(0);
1812 sendToServer(aString);
1813
1814 // Add Hour 1's Digit
1815 aString = "widget_set Time d1 ";
1816 aString += QString::number( (m_lcdWidth/2) - 2 - xoffset) + " ";
1817 aString += time.at(0 + toffset);
1818 sendToServer(aString);
1819
1820 // Add the Colon
1821 aString = "widget_set Time sep ";
1822 aString += QString::number( (m_lcdWidth/2) + 1 - xoffset);
1823 aString += " 10"; // 10 means: colon
1824 sendToServer(aString);
1825
1826 // Add Minute 10's Digit
1827 aString = "widget_set Time d2 ";
1828 aString += QString::number( (m_lcdWidth/2) + 2 - xoffset) + " ";
1829 aString += time.at(2 + toffset);
1830 sendToServer(aString);
1831
1832 // Add Minute 1's Digit
1833 aString = "widget_set Time d3 ";
1834 aString += QString::number( (m_lcdWidth/2) + 5 - xoffset) + " ";
1835 aString += time.at(3 + toffset);
1836 sendToServer(aString);
1837
1838 // Added a flashing dot in the bottom-right corner
1839 if ( m_timeFlash )
1840 {
1841 outputRightText("Time", ".", "dot", m_lcdHeight );
1842 m_timeFlash = false;
1843 }
1844 else
1845 {
1846 outputRightText("Time", " ", "dot", m_lcdHeight );
1847 m_timeFlash = true;
1848 }
1849}
1850
1852{
1853 if ( m_lcdBigClock )
1854 dobigclock();
1855 else
1856 dostdclock();
1857}
1858
1860{
1861 if (!m_lcdShowTime )
1862 return;
1863
1865 {
1866 outputCenteredText("Time", tr("RECORDING"), "topWidget", 1);
1867 }
1868 else
1869 {
1871 "Time", MythDate::current().toLocalTime().toString( m_dateFormat ),
1872 "topWidget", 1);
1873 }
1874
1875 QString aString;
1876 int x = 0;
1877 int y = 0;
1878
1879 if ( m_lcdHeight < 3)
1880 y = m_lcdHeight;
1881 else
1882 y = (int) std::rint( m_lcdHeight / 2) + 1;
1883
1884 QString time = QTime::currentTime().toString( m_timeFormat );
1885 x = (( m_lcdWidth - time.length()) / 2) + 1;
1886 aString = "widget_set Time timeWidget ";
1887 aString += QString::number(x);
1888 aString += " ";
1889 aString += QString::number(y);
1890 aString += " \"";
1891 if ( m_lcdShowTime ) {
1892 aString += time + "\"";
1893 if ( m_timeFlash )
1894 {
1895 aString = aString.replace(':', ' ');
1896 m_timeFlash = false;
1897 }
1898 else
1899 {
1900 m_timeFlash = true;
1901 }
1902 }
1903 else
1904 {
1905 aString += " \"";
1906 }
1907 sendToServer(aString);
1908}
1909
1910// if one or more recordings are taking place we alternate between
1911// showing the time and the recording status screen
1913{
1915 return;
1916
1918 {
1919 // switch to the rec status screen
1920 setPriority("RecStatus", MEDIUM);
1921 setPriority("Time", LOW);
1922
1923 m_timeTimer->stop();
1924 m_scrollWTimer->stop();
1925 m_scrollListTimer->stop();
1926 m_isTimeVisible = false;
1927 m_activeScreen = "RecStatus";
1928
1929 if (m_lcdTunerNo > (int) m_tunerList.size() - 1)
1930 m_lcdTunerNo = 0;
1931 }
1932 else if ( m_lcdTunerNo > (int) m_tunerList.size() - 1)
1933 {
1934 m_lcdTunerNo = 0;
1935
1936 // switch to the time screen
1937 setPriority("Time", MEDIUM);
1938 setPriority("RecStatus", LOW);
1939
1940 m_timeTimer->start(1s);
1941 m_scrollWTimer->stop();
1942 m_scrollListTimer->stop();
1944
1945 outputTime();
1946 m_activeScreen = "Time";
1947 m_isTimeVisible = true;
1948
1949 return;
1950 }
1951
1952 QString aString;
1953 QString status;
1954 QStringList list;
1955 std::chrono::milliseconds listTime { 1 };
1956
1958
1959 m_scrollListItems.clear();
1960 if ( m_lcdHeight >= 4)
1961 {
1962 // LINE 1 - "R" + Channel
1963 status = tr("R ");
1964 status += tuner.channame;
1965 outputLeftText("RecStatus", status, "textWidget1", 1);
1966
1967 // LINE 2 - "E" + Program Title
1968 status = tr("E ");
1969 status += tuner.title;
1970 outputLeftText("RecStatus", status, "textWidget2", 2);
1971 //list = formatScrollerText(status);
1972 //assignScrollingList(list, "RecStatus", "textWidget2", 2);
1973
1974 // LINE 3 - "C" + Program Subtitle
1975 status = tr("C ");
1976 status += tuner.subtitle;
1977 outputLeftText("RecStatus", status, "textWidget3", 3);
1978 //list = formatScrollerText(status);
1979 //assignScrollingList(list, "RecStatus", "textWidget3", 3);
1980
1981 // LINE 4 - hh:mm-hh:mm + Progress Bar
1982 status = tuner.startTime.toLocalTime().toString("hh:mm") + "-" +
1983 tuner.endTime.toLocalTime().toString("hh:mm");
1984 outputLeftText("RecStatus", status, "textWidget4", 4);
1985
1986 int length = tuner.startTime.secsTo(tuner.endTime);
1987 int delta = tuner.startTime.secsTo(MythDate::current());
1988 double rec_progress = (double) delta / length;
1989
1990 aString = "widget_set RecStatus progressBar 13 ";
1991 aString += QString::number( m_lcdHeight );
1992 aString += " ";
1993 aString += QString::number((int)rint(rec_progress * ( m_lcdWidth - 13) *
1994 m_cellWidth ));
1995 sendToServer(aString);
1996
1997 listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
1998 }
1999 else
2000 {
2001 status = tr("RECORDING|");
2002 status += tuner.title;
2003 if (!tuner.subtitle.isEmpty())
2004 status += "|(" + tuner.subtitle + ")";
2005
2006 status += "|" + tuner.startTime.toLocalTime().toString("hh:mm")
2007 + " to " +
2008 tuner.endTime.toLocalTime().toString("hh:mm");
2009
2010 list = formatScrollerText(status);
2011 assignScrollingList(list, "RecStatus", "textWidget1", 1);
2012
2013 if ( m_lcdHeight > 1)
2014 {
2015 int length = tuner.startTime.secsTo(tuner.endTime);
2016 int delta = tuner.startTime.secsTo(MythDate::current());
2017 double rec_progress = (double) delta / length;
2018
2019 aString = "widget_set RecStatus progressBar 1 ";
2020 aString += QString::number( m_lcdHeight );
2021 aString += " ";
2022 aString += QString::number((int)rint(rec_progress * m_lcdWidth *
2023 m_cellWidth ));
2024 sendToServer(aString);
2025 }
2026 else
2027 {
2028 sendToServer("widget_set RecStatus progressBar 1 1 0");
2029 }
2030
2031 listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
2032 }
2033
2034 if (listTime < LCD_TIME_TIME)
2035 listTime = LCD_TIME_TIME;
2036
2037 m_recStatusTimer->start(listTime);
2038 m_lcdTunerNo++;
2039}
2040
2041void LCDProcClient::outputScrollerText(const QString& theScreen, const QString& theText,
2042 const QString& widget, int top, int bottom)
2043{
2044 QString aString;
2045 aString = "widget_set " + theScreen + " " + widget;
2046 aString += " 1 ";
2047 aString += QString::number(top) + " ";
2048 aString += QString::number( m_lcdWidth ) + " ";
2049 aString += QString::number(bottom);
2050 aString += " v 8 \"" + theText + "\"";
2051
2052 sendToServer(aString);
2053}
2054
2055QStringList LCDProcClient::formatScrollerText(const QString &text) const
2056{
2057 QString separators = " |-_/:('<~";
2058 QStringList lines;
2059
2060 int lastSplit = 0;
2061 QString line = "";
2062
2063 for (const auto& x : std::as_const(text))
2064 {
2065 if (separators.contains(x))
2066 lastSplit = line.length();
2067
2068 line += x;
2069 if (line.length() > (int) m_lcdWidth || x == '|')
2070 {
2071 QString formatedLine;
2072 formatedLine.fill(' ', m_lcdWidth );
2073 formatedLine = formatedLine.replace(( m_lcdWidth - lastSplit) / 2,
2074 lastSplit, line.left(lastSplit));
2075
2076 lines.append(formatedLine);
2077
2078 if (line[lastSplit] == ' ' || line[lastSplit] == '|')
2079 line = line.mid(lastSplit + 1);
2080 else
2081 line = line.mid(lastSplit);
2082
2083 lastSplit = m_lcdWidth;
2084 }
2085 }
2086
2087 // make sure we add the last line
2088 QString formatedLine;
2089 formatedLine.fill(' ', m_lcdWidth );
2090 formatedLine = formatedLine.replace(( m_lcdWidth - line.length()) / 2,
2091 line.length(), line);
2092
2093 lines.append(formatedLine);
2094
2095 return lines;
2096}
2097
2099{
2100 // See startMusic() for a discription of the Music screen contents
2101
2102 outputCenteredText("Music", m_musicTime, "timeWidget",
2103 m_lcdHeight < 4 ? 2 : 3);
2104
2105 if ( m_lcdHeight > 2)
2106 {
2107 QString aString;
2108 QString shuffle = "";
2109 QString repeat = "";
2110 int info_width = 0;
2111
2112 if ( m_musicShuffle == 1)
2113 {
2114 shuffle = "S:? ";
2115 }
2116 else if ( m_musicShuffle == 2)
2117 {
2118 shuffle = "S:i ";
2119 }
2120 else if ( m_musicShuffle == 3)
2121 {
2122 shuffle = "S:a ";
2123 }
2124
2125 if ( m_musicRepeat == 1)
2126 {
2127 repeat = "R:1 ";
2128 }
2129 else if ( m_musicRepeat == 2)
2130 {
2131 repeat = "R:* ";
2132 }
2133
2134 if (shuffle.length() != 0 || repeat.length() != 0)
2135 {
2136 aString = shuffle + repeat;
2137 info_width = aString.length();
2138 outputLeftText("Music", aString, "infoWidget", m_lcdHeight );
2139 }
2140 else
2141 {
2142 outputLeftText("Music", " ", "infoWidget", m_lcdHeight );
2143 }
2144
2145 aString = "widget_set Music progressBar ";
2146 aString += QString::number(info_width + 1);
2147 aString += " ";
2148 aString += QString::number( m_lcdHeight );
2149 aString += " ";
2150 aString += QString::number((int)std::rint( m_musicProgress *
2151 ( m_lcdWidth - info_width) * m_cellWidth ));
2152 sendToServer(aString);
2153 }
2154}
2155
2157{
2158 if ( m_lcdHeight > 1)
2159 {
2160 QString aString;
2161 aString = "widget_set Channel progressBar 1 ";
2162 aString += QString::number( m_lcdHeight );
2163 aString += " ";
2164 aString += QString::number((int)std::rint( m_progress * m_lcdWidth * m_cellWidth ));
2165 sendToServer(aString);
2166
2167 if ( m_lcdHeight >= 4)
2168 outputCenteredText("Channel", m_channelTime, "timeWidget", 3);
2169 }
2170 else
2171 {
2172 sendToServer("widget_set Channel progressBar 1 1 0");
2173 }
2174}
2175
2177{
2178 if ( m_lcdHeight > 1)
2179 {
2180 QString aString;
2181 aString = "widget_set Generic progressBar ";
2182 aString += QString::number ( m_busyPos );
2183 aString += " ";
2184 aString += QString::number( m_lcdHeight );
2185 aString += " ";
2186 aString += QString::number((int)std::rint( m_genericProgress * m_lcdWidth *
2187 m_cellWidth ));
2188 sendToServer(aString);
2189 }
2190 else
2191 {
2192 sendToServer("widget_set Generic progressBar 1 1 0");
2193 }
2194}
2195
2197{
2198 QString aString;
2199 int line = 3;
2200
2201 if ( m_lcdHeight > 1)
2202 {
2203 aString = "widget_set Volume progressBar 1 ";
2204 aString += QString::number( m_lcdHeight );
2205 aString += " ";
2206 aString += QString::number((int)std::rint( m_volumeLevel * m_lcdWidth * m_cellWidth ));
2207 sendToServer(aString);
2208 }
2209
2210 aString = QString::number((int)( m_volumeLevel * 100));
2211 aString += "%";
2212
2213 if ( m_lcdHeight > 3)
2214 line = 3;
2215 else
2216 line = m_lcdHeight;
2217 outputRightText("Volume", aString, "botWidget", line);
2218}
2219
2221{
2222 if (!m_lcdReady )
2223 return;
2224
2225 stopAll();
2226
2227 if (debug_level > 1)
2228 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToTime");
2229
2230 startTime();
2231}
2232
2233void LCDProcClient::switchToMusic(const QString &artist, const QString &album, const QString &track)
2234{
2235 if (!m_lcdReady )
2236 return;
2237
2238 stopAll();
2239
2240 if (debug_level > 1)
2241 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMusic") ;
2242
2243 startMusic(artist, album, track);
2244}
2245
2246void LCDProcClient::switchToChannel(const QString& channum, const QString& title, const QString& subtitle)
2247{
2248 if (!m_lcdReady )
2249 return;
2250
2251 stopAll();
2252
2253 if (debug_level > 1)
2254 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToChannel");
2255
2256 startChannel(channum, title, subtitle);
2257}
2258
2259void LCDProcClient::switchToMenu(QList<LCDMenuItem> *menuItems, const QString& app_name,
2260 bool popMenu)
2261{
2262 if (!m_lcdReady )
2263 return;
2264
2265 if (debug_level > 1)
2266 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMenu");
2267
2268 startMenu(menuItems, app_name, popMenu);
2269}
2270
2271void LCDProcClient::switchToGeneric(QList<LCDTextItem> *textItems)
2272{
2273 if (!m_lcdReady )
2274 return;
2275 stopAll();
2276
2277 if (debug_level > 1)
2278 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToGeneric");
2279
2280 startGeneric(textItems);
2281}
2282
2283void LCDProcClient::switchToVolume(const QString& app_name)
2284{
2285 if (!m_lcdReady )
2286 return;
2287
2288 stopAll();
2289
2290 if (debug_level > 1)
2291 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToVolume");
2292
2293 startVolume(app_name);
2294}
2295
2297{
2298 if (!m_lcdReady )
2299 return;
2300
2301 stopAll();
2302
2303 if (debug_level > 1)
2304 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToNothing");
2305}
2306
2308{
2309 if (debug_level > 1)
2310 LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: shutdown");
2311
2312 stopAll();
2313
2314 // Remove all the widgets and screens for a clean exit from the server
2315 removeWidgets();
2316
2317 m_socket->close();
2318
2319 m_lcdReady = false;
2320 m_connected = false;
2321}
2322
2324{
2325 sendToServer("widget_del Channel progressBar");
2326 sendToServer("widget_del Channel topWidget");
2327 sendToServer("widget_del Channel timeWidget");
2328 sendToServer("screen_del Channel");
2329
2330 sendToServer("widget_del Generic progressBar");
2331 sendToServer("widget_del Generic textWidget1");
2332 sendToServer("widget_del Generic textWidget2");
2333 sendToServer("widget_del Generic textWidget3");
2334 sendToServer("screen_del Generic");
2335
2336 sendToServer("widget_del Volume progressBar");
2337 sendToServer("widget_del Volume topWidget");
2338 sendToServer("screen_del Volume");
2339
2340 sendToServer("widget_del Menu topWidget");
2341 sendToServer("widget_del Menu menuWidget1");
2342 sendToServer("widget_del Menu menuWidget2");
2343 sendToServer("widget_del Menu menuWidget3");
2344 sendToServer("widget_del Menu menuWidget4");
2345 sendToServer("widget_del Menu menuWidget5");
2346 sendToServer("screen_del Menu");
2347
2348 sendToServer("widget_del Music progressBar");
2349 sendToServer("widget_del Music infoWidget");
2350 sendToServer("widget_del Music timeWidget");
2351 sendToServer("widget_del Music topWidget");
2352 sendToServer("screen_del Music");
2353
2354 if ( m_lcdBigClock )
2355 {
2356 sendToServer("widget_del Time rec1");
2357 sendToServer("widget_del Time rec2");
2358 sendToServer("widget_del Time rec3");
2359 sendToServer("widget_del Time recCnt");
2360 sendToServer("widget_del Time d0");
2361 sendToServer("widget_del Time d1");
2362 sendToServer("widget_del Time sep");
2363 sendToServer("widget_del Time d2");
2364 sendToServer("widget_del Time d3");
2365 sendToServer("widget_del Time ampm");
2366 sendToServer("widget_del Time dot");
2367 }
2368 else
2369 {
2370 sendToServer("widget_del Time timeWidget");
2371 sendToServer("widget_del Time topWidget");
2372 }
2373
2374 sendToServer("screen_del Time");
2375
2376 sendToServer("widget_del RecStatus textWidget1");
2377 sendToServer("widget_del RecStatus textWidget2");
2378 sendToServer("widget_del RecStatus textWidget3");
2379 sendToServer("widget_del RecStatus textWidget4");
2380 sendToServer("widget_del RecStatus progressBar");
2381}
2382
2384{
2385 if (debug_level > 1)
2386 {
2387 LOG(VB_GENERAL, LOG_INFO,
2388 "LCDProcClient: An LCD device is being snuffed out"
2389 "of existence (~LCDProcClient() was called)");
2390 }
2391
2392 if (m_socket)
2393 {
2394 delete m_socket;
2395 m_lcdReady = false;
2396 }
2397
2398 delete m_lcdMenuItems;
2399
2401}
2402
2404{
2405 if (e->type() == MythEvent::kMythEventMessage)
2406 {
2407 auto *me = dynamic_cast<MythEvent *>(e);
2408 if (me == nullptr)
2409 return;
2410
2411 if (me->Message().startsWith("RECORDING_LIST_CHANGE") ||
2412 me->Message() == "UPDATE_PROG_INFO")
2413 {
2414 if ( m_lcdShowRecstatus && !m_updateRecInfoTimer->isActive())
2415 {
2416 if (debug_level > 1)
2417 LOG(VB_GENERAL, LOG_INFO,
2418 "LCDProcClient: Received recording list change");
2419
2420 // we can't query the backend from inside the customEvent
2421 // so fire the recording list update from a timer
2422 m_updateRecInfoTimer->start(500ms);
2423 }
2424 }
2425 }
2426}
2427
2429{
2430 m_tunerList.clear();
2431 m_isRecording = false;
2432
2434 {
2436 {
2437 LOG(VB_GENERAL, LOG_ERR,
2438 "LCDProcClient: Cannot get recording status "
2439 "- is the master server running?\n\t\t\t"
2440 "Will retry in 30 seconds");
2441 QTimer::singleShot(30s, this, &LCDProcClient::updateRecordingList);
2442
2443 // If we can't get the recording status and we're showing
2444 // it, switch back to time. Maybe it would be even better
2445 // to show that the backend is unreachable ?
2446 if (m_activeScreen == "RecStatus")
2447 switchToTime();
2448 return;
2449 }
2450 }
2451
2453
2454 m_lcdTunerNo = 0;
2455
2456 if (m_activeScreen == "Time" || m_activeScreen == "RecStatus")
2457 startTime();
2458}
2459/* vim: set expandtab tabstop=4 shiftwidth=4: */
void setScroll(bool value)
Definition: lcddevice.h:43
unsigned int getIndent() const
Definition: lcddevice.h:37
void setItemName(const QString &value)
Definition: lcddevice.h:42
CHECKED_STATE isChecked() const
Definition: lcddevice.h:33
void incrementScrollPos()
Definition: lcddevice.h:46
unsigned int getScrollPos() const
Definition: lcddevice.h:38
bool isSelected() const
Definition: lcddevice.h:34
void setScrollPos(unsigned int value)
Definition: lcddevice.h:45
bool Scroll() const
Definition: lcddevice.h:36
QString ItemName() const
Definition: lcddevice.h:35
void startMenu(QList< LCDMenuItem > *menuItems, QString app_name, bool popMenu)
void switchToChannel(const QString &channum="", const QString &title="", const QString &subtitle="")
bool m_lcdShowRecstatus
void outputText(QList< LCDTextItem > *textItems)
std::chrono::seconds m_startupShowTime
void setWidth(unsigned int x)
void assignScrollingList(QStringList theList, QString theScreen, QString theWidget="topWidget", int theRow=1)
void startMusic(QString artist, const QString &album, const QString &track)
void startChannel(const QString &channum, const QString &title, const QString &subtitle)
uint8_t m_cellWidth
void reset(void)
void setMusicShuffle(int shuffle)
QString m_activeScreen
void showStartupMessage(void)
void setHeight(unsigned int x)
QString m_scrollScreen
void setCellHeight(unsigned int x)
QString m_serverVersion
QString m_startupMessage
void checkConnections()
void setGenericProgress(bool busy, float value)
QTimer * m_scrollListTimer
void startVolume(const QString &app_name)
QTimer * m_showMessageTimer
uint8_t m_pVersion
QList< LCDMenuItem > * m_lcdMenuItems
void switchToVolume(const QString &app_name)
QTimer * m_recStatusTimer
void stopAll(void)
QString m_lcdKeyString
int m_busyDirection
Direction of the busy indicator on the, -1 or 1, used if m_busyProgress is true.
void formatScrollingWidgets(void)
QTimer * m_scrollWTimer
QString m_prioTop
QTimer * m_preScrollWTimer
bool m_busyProgress
true if the generic progress indicator is a busy (ie.
uint8_t m_cellHeight
QString m_channelTime
QString m_prioMedium
void setMusicRepeat(int repeat)
void dobigclock(void)
bool connectToHost(const QString &hostname, unsigned int port)
QTcpSocket * m_socket
QTimer * m_timeTimer
std::vector< TunerStatus > m_tunerList
QStringList formatScrollerText(const QString &text) const
void beginScrollingMenuText()
QTimer * m_updateRecInfoTimer
void veryBadThings(QAbstractSocket::SocketError error)
float m_genericProgress
int m_busyPos
Current position of the busy indicator, used if m_busyProgress is true.
QString m_lcdShowMusicItems
void switchToMenu(QList< LCDMenuItem > *menuItems, const QString &app_name="", bool popMenu=true)
void startGeneric(QList< LCDTextItem > *textItems)
QTimer * m_popMenuTimer
QString m_protocolVersion
void serverSendingData()
QTimer * m_menuPreScrollTimer
void outputRightText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
void switchToGeneric(QList< LCDTextItem > *textItems)
LCDServer * m_parentLCDServer
void setCellWidth(unsigned int x)
void outputCenteredText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
QString m_scrollListWidget
QTimer * m_checkConnectionsTimer
void switchToMusic(const QString &artist, const QString &album, const QString &track)
QString m_scrollListScreen
~LCDProcClient() override
QString m_musicTime
void sendToServer(const QString &someText)
QString m_lastCommand
void setVolumeLevel(float value)
unsigned int m_menuScrollPosition
QString m_prioUrgent
void beginScrollingWidgets(void)
void outputLeftText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
unsigned int m_port
QString m_hostname
void setMusicProgress(QString time, float value)
QString m_timeFormat
float m_musicProgress
std::chrono::milliseconds m_lcdPopupTime
void setVersion(const QString &sversion, const QString &pversion)
void setChannelProgress(const QString &time, float value)
QString expandString(const QString &aString) const
void setHeartbeat(const QString &screen, bool onoff)
unsigned int m_scrollPosition
uint8_t m_lcdWidth
bool SetupLCD(void)
uint8_t m_lcdHeight
QString m_dateFormat
QTimer * m_menuScrollTimer
void customEvent(QEvent *e) override
QString m_prioLow
LCDProcClient(LCDServer *lparent)
void assignScrollingWidgets(const QString &theText, const QString &theScreen, const QString &theWidget="topWidget", int theRow=1)
void setPriority(const QString &screen, PRIORITY priority)
QString m_prioHigh
QList< LCDTextItem > * m_lcdTextItems
void updateRecordingList(void)
float m_busyIndicatorSize
How many "blocks" the busy indicator must be, used if m_busyProgress is true.
unsigned int m_scrollListItem
void scrollWidgets(void)
QStringList m_scrollListItems
void setStartupMessage(QString msg, std::chrono::seconds messagetime)
void removeStartupMessage(void)
void outputScrollerText(const QString &theScreen, const QString &theText, const QString &widget="scroller", int top=1, int bottom=1)
QString m_prioOff
QString m_sendBuffer
void updateLEDs(int mask)
void sendKeyPress(const QString &key_pressed)
Definition: lcdserver.cpp:298
QString getWidget() const
Definition: lcddevice.h:75
QString getScreen() const
Definition: lcddevice.h:74
TEXT_ALIGNMENT getAlignment() const
Definition: lcddevice.h:72
void setText(const QString &value)
Definition: lcddevice.h:80
unsigned int getRow() const
Definition: lcddevice.h:71
QString getText() const
Definition: lcddevice.h:73
bool getScroll() const
Definition: lcddevice.h:76
void setScrollable(bool value)
Definition: lcddevice.h:83
bool IsConnectedToMaster(void)
QString GetSetting(const QString &key, const QString &defaultval="")
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
int GetNumSetting(const QString &key, int defaultval=0)
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
bool GetBoolSetting(const QString &key, bool defaultval=false)
This class is used as a container for messages.
Definition: mythevent.h:17
static const Type kMythEventMessage
Definition: mythevent.h:79
void addListener(QObject *listener)
Add a listener to the observable.
void removeListener(QObject *listener)
Remove a listener to the observable.
recording status stuff
Definition: tvremoteutil.h:17
QDateTime endTime
Definition: tvremoteutil.h:25
QString subtitle
Definition: tvremoteutil.h:23
QString channame
Definition: tvremoteutil.h:21
QString title
Definition: tvremoteutil.h:22
QDateTime startTime
Definition: tvremoteutil.h:24
@ ALIGN_CENTERED
Definition: lcddevice.h:57
@ ALIGN_LEFT
Definition: lcddevice.h:57
@ ALIGN_RIGHT
Definition: lcddevice.h:57
@ NOTCHECKABLE
Definition: lcddevice.h:17
@ CHECKED
Definition: lcddevice.h:17
@ UNCHECKED
Definition: lcddevice.h:17
static constexpr std::chrono::milliseconds LCD_TIME_TIME
uint8_t lcdStartCol
static constexpr uint8_t LCD_VERSION_4
static constexpr uint8_t LCD_START_COL
static constexpr uint8_t LCD_VERSION_5
static constexpr std::chrono::milliseconds LCD_SCROLLLIST_TIME
int debug_level
Definition: lcdserver.cpp:76
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:93
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:206
bool RemoteGetRecordingStatus(std::vector< TunerStatus > *tunerList, bool list_inactive)