MythTV master
mythscreentype.cpp
Go to the documentation of this file.
1
2#include "mythscreentype.h"
3
4#include <QCoreApplication>
5#include <QDomDocument>
6#include <QInputMethodEvent>
7#include <QRunnable>
8#include <utility>
9
15
16#include "mythscreenstack.h"
17#include "mythmainwindow.h"
18#include "mythuihelper.h"
19#include "mythprogressdialog.h"
20#include "mythuigroup.h"
21#include "mythuistatetype.h"
22#include "mythgesture.h"
23#include "mythuitext.h"
24
26{
27 public:
28 explicit SemaphoreLocker(QSemaphore *lock) : m_lock(lock)
29 {
30 if (m_lock)
31 m_lock->acquire();
32 }
34 {
35 if (m_lock)
36 m_lock->release();
37 }
38 private:
39 QSemaphore *m_lock {nullptr};
40};
41
43 (QEvent::Type) QEvent::registerEventType();
44
45class ScreenLoadTask : public QRunnable
46{
47 public:
48 explicit ScreenLoadTask(MythScreenType &parent) : m_parent(parent) {}
49
50 private:
51 void run(void) override // QRunnable
52 {
53 m_parent.Load();
54 m_parent.m_isLoaded = true;
55 m_parent.m_isLoading = false;
56 m_parent.m_loadLock.release();
57 }
58
60};
61
63 MythScreenStack *parent, const QString &name, bool fullscreen) :
64 MythUIComposite(parent, name),
65 m_fullScreen(fullscreen),
66 m_screenStack(parent)
67{
68 // Can be overridden, of course, but default to full sized.
70
71 if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
73 QString("SCREEN_TYPE CREATED %1").arg(name));
74}
75
77 MythUIType *parent, const QString &name, bool fullscreen) :
78 MythUIComposite(parent, name),
79 m_fullScreen(fullscreen)
80{
82
83 if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
85 QString("SCREEN_TYPE CREATED %1").arg(name));
86}
87
89{
90 if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
92 QString("SCREEN_TYPE DESTROYED %1").arg(objectName()));
93
94 // locking ensures background screen load can finish running
96
97 m_currentFocusWidget = nullptr;
98 emit Exiting();
99}
100
102{
103 return m_fullScreen;
104}
105
107{
108 m_fullScreen = full;
109}
110
112{
114}
115
117{
118 if (!widget || !widget->IsVisible(true))
119 {
120 for (auto *current : std::as_const(m_focusWidgetList))
121 {
122 if (current->CanTakeFocus() && current->IsVisible(true))
123 {
124 widget = current;
125 break;
126 }
127 }
128 }
129
130 if (!widget)
131 return false;
132
133 if (m_currentFocusWidget == widget)
134 return true;
135
136 MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
137 if (helpText)
138 helpText->Reset();
139
140 // Let each 'buttonlist' know the name of the currently active buttonlist
141 QString name = widget->GetXMLName();
142 for (auto *w : std::as_const(m_focusWidgetList))
143 w->SetFocusedName(name);
144
147 m_currentFocusWidget = widget;
149
150 if (helpText && !widget->GetHelpText().isEmpty())
151 helpText->SetText(widget->GetHelpText());
152
153 return true;
154}
155
157{
158 if (!m_currentFocusWidget || m_focusWidgetList.isEmpty())
159 return SetFocusWidget(nullptr);
160 if (m_focusWidgetList.size() == 1)
161 return false;
162
163 // Run the list from the current pointer to the end/begin and loop
164 // around back to itself. Start by geting an iterator pointing at
165 // the current focus (or at the end if the focus isn't in the
166 // list).
169 if (up)
170 {
171 if (it != m_focusWidgetList.end())
172 it++;
173 if (it == m_focusWidgetList.end())
174 it = m_focusWidgetList.begin();
175 // Put an upper limit on loops to guarantee exit at some point.
176 for (auto count = m_focusWidgetList.size() * 2; count > 0; count--)
177 {
178 MythUIType *current = *it;
179 if (current->IsVisible(true) && current->IsEnabled())
180 return SetFocusWidget(current);
181 it++;
182 if (it == m_focusWidgetList.end())
183 it = m_focusWidgetList.begin();
184 if (*it == m_currentFocusWidget)
185 return false;
186 }
187 }
188 else
189 {
190 if (it == m_focusWidgetList.begin())
191 it = m_focusWidgetList.end();
192 // Put an upper limit on loops to guarantee exit at some point.
193 for (auto count = m_focusWidgetList.size() * 2; count > 0; count--)
194 {
195 it--;
196 if (*it == m_currentFocusWidget)
197 return false;
198 MythUIType *current = *it;
199 if (current->IsVisible(true) && current->IsEnabled())
200 return SetFocusWidget(current);
201 if (it == m_focusWidgetList.begin())
202 it = m_focusWidgetList.end();
203 }
204 }
205
206 return false;
207}
208
210{
211 m_focusWidgetList.clear();
212 m_currentFocusWidget = nullptr;
213
215
216 if (!m_focusWidgetList.empty())
218}
219
221{
222 return m_screenStack;
223}
224
226{
227 if (!m_fullScreen)
228 {
229 if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
230 {
231 // remove this screen's area from the mask so any embedded video is
232 // shown which was covered by this screen
233 if (!m_savedMask.isEmpty())
235 }
236 }
237
239}
240
242{
243 if (!m_fullScreen)
244 {
245 if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
246 {
247 // add this screens area to the mask so any embedded video isn't
248 // shown in front of this screen
249 QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
250 m_savedMask = region;
251 region = region.united(QRegion(m_area));
252 GetMythMainWindow()->GetPaintWindow()->setMask(region);
253 }
254 }
255
257}
258
260{
261 return m_isDeleting;
262}
263
265{
266 m_isDeleting = deleting;
267}
268
270{
271 return true;
272}
273
285{
286 // Virtual
287}
288
289void MythScreenType::LoadInBackground(const QString& message)
290{
291 m_loadLock.acquire();
292
293 m_isLoading = true;
294 m_isLoaded = false;
295
297
298 OpenBusyPopup(message);
299
300 auto *loadTask = new ScreenLoadTask(*this);
301 MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
302}
303
305{
307
308 m_isLoading = true;
309 m_isLoaded = false;
310
312 Load();
313 m_isLoaded = true;
314 m_isLoading = false;
315}
316
318{
319 m_isInitialized = false;
321}
322
323void MythScreenType::OpenBusyPopup(const QString& message)
324{
325 if (m_busyPopup)
326 return;
327
328 QString msg(tr("Loading..."));
329 if (!message.isEmpty())
330 msg = message;
331
332 MythScreenStack *popupStack =
333 GetMythMainWindow()->GetStack("popup stack");
335 new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
336
337 if (m_busyPopup->Create())
338 popupStack->AddScreen(m_busyPopup, false);
339}
340
342{
343 if (m_busyPopup)
345 m_busyPopup = nullptr;
346}
347
348void MythScreenType::SetBusyPopupMessage(const QString &message)
349{
350 if (m_busyPopup)
351 m_busyPopup->SetMessage(message);
352}
353
355{
356 if (m_busyPopup)
358}
359
364{
365 return m_isInitialized;
366}
367
369{
370 SemaphoreLocker locker(&m_loadLock); // don't run while loading..
371
373 Init();
374 m_isInitialized = true;
375}
376
385{
386 // Virtual
387}
388
390{
392 if (GetScreenStack())
393 GetScreenStack()->PopScreen(this);
394}
395
397{
398 // Virtual
399}
400
401bool MythScreenType::inputMethodEvent(QInputMethodEvent *event)
402{
405}
406
407bool MythScreenType::keyPressEvent(QKeyEvent *event)
408{
409 if (!GetMythMainWindow()->IsExitingToMain() && m_currentFocusWidget &&
411 return true;
412
413 bool handled = false;
414 QStringList actions;
415 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
416
417 for (int i = 0; i < actions.size() && !handled; i++)
418 {
419 const QString& action = actions[i];
420 handled = true;
421
422 if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
423 {
424 if (!NextPrevWidgetFocus(false))
425 handled = false;
426 }
427 else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
428 {
429 if (!NextPrevWidgetFocus(true))
430 handled = false;
431 }
432 else if (action == "ESCAPE")
433 {
434 Close();
435 }
436 else if (action == "MENU")
437 {
438 ShowMenu();
439 }
440 else if (action.startsWith("SYSEVENT"))
441 {
442 gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
443 }
444 else if (action == ACTION_SCREENSHOT)
445 {
447 }
449 {
451 }
452 else
453 {
454 handled = false;
455 }
456 }
457
458 return handled;
459}
460
462{
463 bool handled = false;
464 if (event->GetGesture() == MythGestureEvent::Click)
465 {
466 switch (event->GetButton())
467 {
468 case Qt::RightButton:
469 ShowMenu();
470 handled = true;
471 break;
472 default :
473 break;
474 }
475
476 }
477
478 if (!handled)
479 {
480 MythUIType *clicked = GetChildAt(event->GetPosition());
481 if (clicked && clicked->IsEnabled())
482 {
483 SetFocusWidget(clicked);
484 if (clicked->gestureEvent(event))
485 handled = true;
486 }
487 }
488
489 return handled;
490}
491
496 const QString &filename, QDomElement &element, bool showWarnings)
497{
498 if (element.tagName() == "area")
499 {
500 MythRect rect = parseRect(element, false);
501 MythRect rectN = parseRect(element);
502 QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
503
504 if (rect.x() == -1)
505 rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
506
507 if (rect.y() == -1)
508 rectN.moveTop((screenArea.height() - rectN.height()) / 2);
509
510 SetArea(rectN);
511
512 m_fullScreen = (m_area.width() >= screenArea.width() &&
513 m_area.height() >= screenArea.height());
514 }
515 else
516 {
517 return MythUIType::ParseElement(filename, element, showWarnings);
518 }
519
520 return true;
521}
522
527{
528 auto *st = dynamic_cast<MythScreenType *>(base);
529 if (!st)
530 {
531 LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
532 return;
533 }
534
535 m_fullScreen = st->m_fullScreen;
536 m_isDeleting = false;
537
539
540 ConnectDependants(true);
541
543};
544
552{
553 LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
554}
555
557{
558 if (m_painter)
559 return m_painter;
560 if (m_screenStack)
562 return GetMythPainter();
563}
static MThreadPool * globalInstance(void)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
void SendSystemEvent(const QString &msg)
A custom event that represents a mouse gesture.
Definition: mythgesture.h:40
Gesture GetGesture() const
Definition: mythgesture.h:85
QPoint GetPosition() const
Definition: mythgesture.h:87
Qt::MouseButton GetButton() const
Definition: mythgesture.h:88
QWidget * GetPaintWindow()
void HandleTVAction(const QString &Action)
static bool ScreenShot(int Width=0, int Height=0, QString Filename="")
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
bool IsExitingToMain() const
MythScreenStack * GetStack(const QString &Stackname)
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:18
void moveTop(const QString &sY)
Definition: mythrect.cpp:319
void moveLeft(const QString &sX)
Definition: mythrect.cpp:309
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
static MythPainter * GetPainter(void)
void AllowReInit(void)
Screen in which all other widgets are contained and rendered.
void SetFullscreen(bool full)
bool gestureEvent(MythGestureEvent *event) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
void SetDeleting(bool deleting)
void LoadInBackground(const QString &message="")
MythUIType * m_currentFocusWidget
virtual bool NextPrevWidgetFocus(bool up_or_down)
MythPainter * GetPainter(void) override
volatile bool m_isLoaded
QSemaphore m_loadLock
bool inputMethodEvent(QInputMethodEvent *event) override
Input Method event handler.
volatile bool m_isLoading
virtual void ShowMenu(void)
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings) override
Parse the xml definition of this widget setting the state of the object accordingly.
virtual bool Create(void)
MythScreenStack * m_screenStack
virtual void aboutToShow(void)
virtual void aboutToHide(void)
FocusInfoType m_focusWidgetList
void OpenBusyPopup(const QString &message="")
virtual void Init(void)
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
void BuildFocusList(void)
MythUIType * GetFocusWidget(void) const
MythUIBusyDialog * m_busyPopup
MythScreenStack * GetScreenStack() const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
~MythScreenType() override
bool IsDeleting(void) const
bool IsInitialized(void) const
Has Init() been called on this screen?
bool SetFocusWidget(MythUIType *widget=nullptr)
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
void SetBusyPopupMessage(const QString &message)
virtual void Load(void)
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
void LoadInForeground(void)
void CloseBusyPopup(void)
friend class ScreenLoadTask
void ReloadInBackground(void)
void ResetBusyPopup(void)
bool IsFullscreen(void) const
virtual void Close()
bool Create(void) override
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
void SetMessage(const QString &message)
All purpose text widget, displays a text string.
Definition: mythuitext.h:29
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:65
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:115
The base class on which all widgets and screens are based.
Definition: mythuitype.h:86
bool IsEnabled(void) const
Definition: mythuitype.h:119
void AddFocusableChildrenToList(FocusInfoType &focusList)
int m_focusOrder
Definition: mythuitype.h:275
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:903
void ActivateAnimations(MythUIAnimation::Trigger trigger)
Definition: mythuitype.cpp:288
friend class MythScreenType
Definition: mythuitype.h:310
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:610
virtual bool gestureEvent(MythGestureEvent *event)
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
void LoseFocus(void)
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
MythUIType * GetChildAt(QPoint p, bool recursive=true, bool focusable=true) const
Return the first MythUIType at the given coordinates.
Definition: mythuitype.cpp:241
bool TakeFocus(void)
void ConnectDependants(bool recurse=false)
QString GetHelpText(void) const
Definition: mythuitype.h:178
MythPainter * m_painter
Definition: mythuitype.h:298
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:138
virtual bool inputMethodEvent(QInputMethodEvent *event)
Input Method event handler.
Definition: mythuitype.cpp:998
QString GetXMLName(void) const
Definition: mythuitype.h:185
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
virtual bool keyPressEvent(QKeyEvent *event)
Key event handler.
Definition: mythuitype.cpp:989
MythRect m_area
Definition: mythuitype.h:277
static const Type kEventType
void run(void) override
MythScreenType & m_parent
ScreenLoadTask(MythScreenType &parent)
SemaphoreLocker(QSemaphore *lock)
QSemaphore * m_lock
static MythRect parseRect(const QString &text, bool normalize=true)
static constexpr const char * MYTH_APPNAME_MYTHFRONTEND
Definition: mythappname.h:6
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
A C++ ripoff of the stroke library for MythTV.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythPainter * GetMythPainter(void)
MythMainWindow * GetMythMainWindow(void)
static constexpr const char * ACTION_SCREENSHOT
Definition: mythuiactions.h:22
static constexpr const char * ACTION_TVPOWERON
Definition: mythuiactions.h:25
static constexpr const char * ACTION_TVPOWEROFF
Definition: mythuiactions.h:24
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15