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 <QRunnable>
7 #include <utility>
8 
9 #include "mythcorecontext.h"
10 #include "mythobservable.h"
11 #include "mthreadpool.h"
12 
13 #include "mythscreenstack.h"
14 #include "mythmainwindow.h"
15 #include "mythuihelper.h"
16 #include "mythprogressdialog.h"
17 #include "mythuigroup.h"
18 #include "mythuistatetype.h"
19 #include "mythlogging.h"
20 #include "mythgesture.h"
21 #include "mythuitext.h"
22 
24 {
25  public:
26  explicit SemaphoreLocker(QSemaphore *lock) : m_lock(lock)
27  {
28  if (m_lock)
29  m_lock->acquire();
30  }
32  {
33  if (m_lock)
34  m_lock->release();
35  }
36  private:
37  QSemaphore *m_lock {nullptr};
38 };
39 
41  (QEvent::Type) QEvent::registerEventType();
42 
43 class ScreenLoadTask : public QRunnable
44 {
45  public:
46  explicit ScreenLoadTask(MythScreenType &parent) : m_parent(parent) {}
47 
48  private:
49  void run(void) override // QRunnable
50  {
51  m_parent.Load();
52  m_parent.m_IsLoaded = true;
53  m_parent.m_IsLoading = false;
54  m_parent.m_LoadLock.release();
55  }
56 
58 };
59 
61  MythScreenStack *parent, const QString &name, bool fullscreen) :
62  MythUIComposite(parent, name)
63 {
64  m_FullScreen = fullscreen;
65 
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 {
80  m_FullScreen = fullscreen;
81 
83 
84  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
86  QString("SCREEN_TYPE CREATED %1").arg(name));
87 }
88 
90 {
91  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
93  QString("SCREEN_TYPE DESTROYED %1").arg(objectName()));
94 
95  // locking ensures background screen load can finish running
96  SemaphoreLocker locker(&m_LoadLock);
97 
98  m_CurrentFocusWidget = nullptr;
99  emit Exiting();
100 }
101 
103 {
104  return m_FullScreen;
105 }
106 
108 {
109  m_FullScreen = full;
110 }
111 
113 {
114  return m_CurrentFocusWidget;
115 }
116 
118 {
119  if (!widget || !widget->IsVisible(true))
120  {
121  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
122 
123  while (it != m_FocusWidgetList.end())
124  {
125  MythUIType *current = *it;
126 
127  if (current->CanTakeFocus() && current->IsVisible(true))
128  {
129  widget = current;
130  break;
131  }
132  ++it;
133  }
134  }
135 
136  if (!widget)
137  return false;
138 
139  if (m_CurrentFocusWidget == widget)
140  return true;
141 
142  MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
143  if (helpText)
144  helpText->Reset();
145 
148  m_CurrentFocusWidget = widget;
150 
151  if (helpText && !widget->GetHelpText().isEmpty())
152  helpText->SetText(widget->GetHelpText());
153 
154  return true;
155 }
156 
158 {
159  if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
160  return SetFocusWidget(nullptr);
161 
162  bool reachedCurrent = false;
163  bool looped = false;
164 
165  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
166 
167  // There is probably a more efficient way to do this, but the list
168  // is never going to be that big so it will do for now
169  if (up)
170  {
171  while (it != m_FocusWidgetList.end())
172  {
173  MythUIType *current = *it;
174 
175  if ((looped || reachedCurrent) &&
176  current->IsVisible(true) && current->IsEnabled())
177  return SetFocusWidget(current);
178 
180  reachedCurrent = true;
181 
182  ++it;
183 
184  if (it == m_FocusWidgetList.end())
185  {
186  if (looped)
187  return false;
188  looped = true;
189  it = m_FocusWidgetList.begin();
190  }
191  }
192  }
193  else
194  {
195  it = m_FocusWidgetList.end() - 1;
196  while (it != m_FocusWidgetList.begin() - 1)
197  {
198  MythUIType *current = *it;
199 
200  if ((looped || reachedCurrent) &&
201  current->IsVisible(true) && current->IsEnabled())
202  return SetFocusWidget(current);
203 
205  reachedCurrent = true;
206 
207  --it;
208 
209  if (it == m_FocusWidgetList.begin() - 1)
210  {
211  if (looped)
212  return false;
213  looped = true;
214  it = m_FocusWidgetList.end() - 1;
215  }
216  }
217  }
218 
219  return false;
220 }
221 
223 {
224  m_FocusWidgetList.clear();
225  m_CurrentFocusWidget = nullptr;
226 
228 
229  if (!m_FocusWidgetList.empty())
230  SetFocusWidget();
231 }
232 
234 {
235  return m_ScreenStack;
236 }
237 
239 {
240  if (!m_FullScreen)
241  {
242  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
243  {
244  // remove this screen's area from the mask so any embedded video is
245  // shown which was covered by this screen
246  if (!m_SavedMask.isEmpty())
248  }
249  }
250 
252 }
253 
255 {
256  if (!m_FullScreen)
257  {
258  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
259  {
260  // add this screens area to the mask so any embedded video isn't
261  // shown in front of this screen
262  QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
263  m_SavedMask = region;
264  region = region.united(QRegion(m_Area));
265  GetMythMainWindow()->GetPaintWindow()->setMask(region);
266  }
267  }
268 
270 }
271 
273 {
274  return m_IsDeleting;
275 }
276 
277 void MythScreenType::SetDeleting(bool deleting)
278 {
279  m_IsDeleting = deleting;
280 }
281 
283 {
284  return true;
285 }
286 
298 {
299  // Virtual
300 }
301 
302 void MythScreenType::LoadInBackground(const QString& message)
303 {
304  m_LoadLock.acquire();
305 
306  m_IsLoading = true;
307  m_IsLoaded = false;
308 
310 
311  OpenBusyPopup(message);
312 
313  auto *loadTask = new ScreenLoadTask(*this);
314  MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
315 }
316 
318 {
319  SemaphoreLocker locker(&m_LoadLock);
320 
321  m_IsLoading = true;
322  m_IsLoaded = false;
323 
325  Load();
326  m_IsLoaded = true;
327  m_IsLoading = false;
328 }
329 
331 {
332  m_IsInitialized = false;
334 }
335 
336 void MythScreenType::OpenBusyPopup(const QString& message)
337 {
338  if (m_BusyPopup)
339  return;
340 
341  QString msg(tr("Loading..."));
342  if (!message.isEmpty())
343  msg = message;
344 
345  MythScreenStack *popupStack =
346  GetMythMainWindow()->GetStack("popup stack");
347  m_BusyPopup =
348  new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
349 
350  if (m_BusyPopup->Create())
351  popupStack->AddScreen(m_BusyPopup, false);
352 }
353 
355 {
356  if (m_BusyPopup)
357  m_BusyPopup->Close();
358  m_BusyPopup = nullptr;
359 }
360 
361 void MythScreenType::SetBusyPopupMessage(const QString &message)
362 {
363  if (m_BusyPopup)
364  m_BusyPopup->SetMessage(message);
365 }
366 
368 {
369  if (m_BusyPopup)
370  m_BusyPopup->Reset();
371 }
372 
377 {
378  return m_IsInitialized;
379 }
380 
382 {
383  SemaphoreLocker locker(&m_LoadLock); // don't run while loading..
384 
385  CloseBusyPopup();
386  Init();
387  m_IsInitialized = true;
388 }
389 
398 {
399  // Virtual
400 }
401 
403 {
404  CloseBusyPopup();
405  if (GetScreenStack())
406  GetScreenStack()->PopScreen(this);
407 }
408 
410 {
411  // Virtual
412 }
413 
414 bool MythScreenType::keyPressEvent(QKeyEvent *event)
415 {
416  if (!GetMythMainWindow()->IsExitingToMain() && m_CurrentFocusWidget &&
418  return true;
419 
420  bool handled = false;
421  QStringList actions;
422  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
423 
424  for (int i = 0; i < actions.size() && !handled; i++)
425  {
426  QString action = actions[i];
427  handled = true;
428 
429  if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
430  {
431  if (!NextPrevWidgetFocus(false))
432  handled = false;
433  }
434  else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
435  {
436  if (!NextPrevWidgetFocus(true))
437  handled = false;
438  }
439  else if (action == "ESCAPE")
440  Close();
441  else if (action == "MENU")
442  ShowMenu();
443  else if (action.startsWith("SYSEVENT"))
444  gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
445  else if (action == ACTION_SCREENSHOT)
447  else if (action == ACTION_TVPOWERON)
449  else if (action == ACTION_TVPOWEROFF)
451  else
452  handled = false;
453  }
454 
455  return handled;
456 }
457 
459 {
460  bool handled = false;
461  if (event->gesture() == MythGestureEvent::Click)
462  {
463  switch (event->GetButton())
464  {
466  ShowMenu();
467  handled = true;
468  break;
469  default :
470  break;
471  }
472 
473  }
474 
475  if (!handled)
476  {
477  MythUIType *clicked = GetChildAt(event->GetPosition());
478  if (clicked && clicked->IsEnabled())
479  {
480  SetFocusWidget(clicked);
481  if (clicked->gestureEvent(event))
482  handled = true;
483  }
484  }
485 
486  return handled;
487 }
488 
493  const QString &filename, QDomElement &element, bool showWarnings)
494 {
495  if (element.tagName() == "area")
496  {
497  MythRect rect = parseRect(element, false);
498  MythRect rectN = parseRect(element);
499  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
500 
501  if (rect.x() == -1)
502  rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
503 
504  if (rect.y() == -1)
505  rectN.moveTop((screenArea.height() - rectN.height()) / 2);
506 
507  SetArea(rectN);
508 
509  m_FullScreen = (m_Area.width() >= screenArea.width() &&
510  m_Area.height() >= screenArea.height());
511  }
512  else
513  {
514  return MythUIType::ParseElement(filename, element, showWarnings);
515  }
516 
517  return true;
518 }
519 
524 {
525  auto *st = dynamic_cast<MythScreenType *>(base);
526  if (!st)
527  {
528  LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
529  return;
530  }
531 
532  m_FullScreen = st->m_FullScreen;
533  m_IsDeleting = false;
534 
535  MythUIType::CopyFrom(base);
536 
537  ConnectDependants(true);
538 
539  BuildFocusList();
540 };
541 
549 {
550  LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
551 }
552 
554 {
555  if (m_Painter)
556  return m_Painter;
557  if (m_ScreenStack)
559  return GetMythPainter();
560 }
SemaphoreLocker(QSemaphore *lock)
virtual void aboutToShow(void)
QSemaphore * m_lock
void SetMessage(const QString &message)
MythScreenStack * GetScreenStack() const
QString GetHelpText(void) const
Definition: mythuitype.h:151
virtual void ShowMenu(void)
virtual bool keyPressEvent(QKeyEvent *event)
Key event handler.
Definition: mythuitype.cpp:974
volatile bool m_IsLoading
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
#define ACTION_SCREENSHOT
Definition: mythuiactions.h:22
All purpose text widget, displays a text string.
Definition: mythuitext.h:28
virtual bool gestureEvent(MythGestureEvent *event)
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
Definition: mythuitype.cpp:990
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:884
virtual bool Create(void)
void LoseFocus()
bool IsFullscreen(void) const
ScreenLoadTask(MythScreenType &parent)
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:135
MythPainter * GetMythPainter(void)
MythUIBusyDialog * m_BusyPopup
MythUIType * m_CurrentFocusWidget
MythScreenStack * GetStack(const QString &stackname)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool ScreenShot(int w=0, int h=0, QString filename="")
Gesture gesture(void) const
Get the gesture type.
Definition: mythgesture.h:107
void ConnectDependants(bool recurse=false)
MythScreenType(MythScreenStack *parent, const QString &name, bool fullscreen=true)
void HandleTVPower(bool poweron)
The base class on which all widgets and screens are based.
Definition: mythuitype.h:63
void CopyFrom(MythUIType *base) override
Copy this widgets state from another.
void BuildFocusList(void)
bool IsInitialized(void) const
Has Init() been called on this screen?
void AddFocusableChildrenToList(QMap< int, MythUIType * > &focusList)
void LoadInForeground(void)
bool gestureEvent(MythGestureEvent *) override
Mouse click/movement handler, receives mouse gesture events from the QCoreApplication event loop.
static MythPainter * GetPainter(void)
virtual void Close()
void LoadInBackground(const QString &message="")
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void SetDeleting(bool deleting)
bool Create(void) override
void SetFullscreen(bool full)
MythScreenType & m_parent
A C++ ripoff of the stroke library for MythTV.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
virtual bool NextPrevWidgetFocus(bool up_or_down)
QWidget * GetPaintWindow()
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:83
QMap< int, MythUIType * > m_FocusWidgetList
void OpenBusyPopup(const QString &message="")
Wrapper around QRect allowing us to handle percentage and other relative values for areas in mythui.
Definition: mythrect.h:17
void AllowReInit(void)
void ReloadInBackground(void)
#define ACTION_TVPOWERON
Definition: mythuiactions.h:25
void moveLeft(const QString &sX)
Definition: mythrect.cpp:258
MythRect m_Area
Definition: mythuitype.h:249
MythUIType * GetChildAt(const QPoint &p, bool recursive=true, bool focusable=true) const
Return the first MythUIType at the given coordinates.
Definition: mythuitype.cpp:223
virtual ~MythScreenType()
void SetBusyPopupMessage(const QString &message)
A custom event that represents a mouse gesture.
Definition: mythgesture.h:39
MythPainter * m_Painter
Definition: mythuitype.h:271
#define ACTION_TVPOWEROFF
Definition: mythuiactions.h:24
friend class ScreenLoadTask
void run(void) override
MythUIType * GetFocusWidget(void) const
MythMainWindow * GetMythMainWindow(void)
static MThreadPool * globalInstance(void)
QSemaphore m_LoadLock
virtual void SetArea(const MythRect &rect)
Definition: mythuitype.cpp:591
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
virtual void aboutToHide(void)
Button GetButton(void) const
Definition: mythgesture.h:119
void CloseBusyPopup(void)
void start(QRunnable *runnable, const QString &debugName, int priority=0)
#define MYTH_APPNAME_MYTHFRONTEND
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
MythScreenStack * m_ScreenStack
MythPainter * GetPainter(void) override
virtual void CopyFrom(MythUIType *base)
Copy this widgets state from another.
bool IsEnabled(void) const
Definition: mythuitype.h:94
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 void Init(void)
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
void CreateCopy(MythUIType *parent) override
Copy the state of this widget to the one given, it must be of the same type.
volatile bool m_IsLoaded
static MythRect parseRect(const QString &text, bool normalize=true)
virtual void Load(void)
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
bool SetFocusWidget(MythUIType *widget=nullptr)
bool TakeFocus()
Screen in which all other widgets are contained and rendered.
void ActivateAnimations(MythUIAnimation::Trigger trigger)
Definition: mythuitype.cpp:270
bool IsDeleting(void) const
void moveTop(const QString &sY)
Definition: mythrect.cpp:268
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:132
void SendSystemEvent(const QString &msg)
virtual bool ParseElement(const QString &filename, QDomElement &element, bool showWarnings)
Parse the xml definition of this widget setting the state of the object accordingly.
QPoint GetPosition() const
Definition: mythgesture.h:116
void ResetBusyPopup(void)