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 
8 #include "mythcorecontext.h"
9 #include "mythobservable.h"
10 #include "mthreadpool.h"
11 
12 #include "mythscreenstack.h"
13 #include "mythmainwindow.h"
14 #include "mythuihelper.h"
15 #include "mythprogressdialog.h"
16 #include "mythuigroup.h"
17 #include "mythuistatetype.h"
18 #include "mythlogging.h"
19 #include "mythgesture.h"
20 #include "mythuitext.h"
21 
23 {
24  public:
25  explicit SemaphoreLocker(QSemaphore *lock) : m_lock(lock)
26  {
27  if (m_lock)
28  m_lock->acquire();
29  }
31  {
32  if (m_lock)
33  m_lock->release();
34  }
35  private:
36  QSemaphore *m_lock;
37 };
38 
40  (QEvent::Type) QEvent::registerEventType();
41 
42 class ScreenLoadTask : public QRunnable
43 {
44  public:
45  explicit ScreenLoadTask(MythScreenType &parent) : m_parent(parent) {}
46 
47  private:
48  void run(void) override // QRunnable
49  {
50  m_parent.Load();
51  m_parent.m_IsLoaded = true;
52  m_parent.m_IsLoading = false;
53  m_parent.m_LoadLock.release();
54  }
55 
57 };
58 
60  MythScreenStack *parent, const QString &name, bool fullscreen) :
61  MythUIComposite(parent, name), m_LoadLock(1)
62 {
63  m_FullScreen = fullscreen;
64  m_CurrentFocusWidget = nullptr;
65 
66  m_ScreenStack = parent;
67  m_BusyPopup = nullptr;
68  m_IsDeleting = false;
69  m_IsLoading = false;
70  m_IsLoaded = false;
71  m_IsInitialized = false;
72 
73  // Can be overridden, of course, but default to full sized.
75 
76  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
78  QString("SCREEN_TYPE CREATED %1").arg(name));
79 }
80 
82  MythUIType *parent, const QString &name, bool fullscreen) :
83  MythUIComposite(parent, name), m_LoadLock(1)
84 {
85  m_FullScreen = fullscreen;
86  m_CurrentFocusWidget = nullptr;
87 
88  m_ScreenStack = nullptr;
89  m_BusyPopup = nullptr;
90  m_IsDeleting = false;
91  m_IsLoading = false;
92  m_IsLoaded = false;
93  m_IsInitialized = false;
94 
96 
97  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
99  QString("SCREEN_TYPE CREATED %1").arg(name));
100 }
101 
103 {
104  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
106  QString("SCREEN_TYPE DESTROYED %1").arg(objectName()));
107 
108  // locking ensures background screen load can finish running
109  SemaphoreLocker locker(&m_LoadLock);
110 
111  m_CurrentFocusWidget = nullptr;
112  emit Exiting();
113 }
114 
116 {
117  return m_FullScreen;
118 }
119 
121 {
122  m_FullScreen = full;
123 }
124 
126 {
127  return m_CurrentFocusWidget;
128 }
129 
131 {
132  if (!widget || !widget->IsVisible(true))
133  {
134  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
136 
137  while (it != m_FocusWidgetList.end())
138  {
139  current = *it;
140 
141  if (current->CanTakeFocus() && current->IsVisible(true))
142  {
143  widget = current;
144  break;
145  }
146  ++it;
147  }
148  }
149 
150  if (!widget)
151  return false;
152 
153  if (m_CurrentFocusWidget == widget)
154  return true;
155 
156  MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
157  if (helpText)
158  helpText->Reset();
159 
162  m_CurrentFocusWidget = widget;
164 
165  if (helpText && !widget->GetHelpText().isEmpty())
166  helpText->SetText(widget->GetHelpText());
167 
168  return true;
169 }
170 
172 {
173  if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
174  return SetFocusWidget(nullptr);
175 
176  bool reachedCurrent = false;
177  bool looped = false;
178 
179  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
181 
182  // There is probably a more efficient way to do this, but the list
183  // is never going to be that big so it will do for now
184  if (up)
185  {
186  while (it != m_FocusWidgetList.end())
187  {
188  current = *it;
189 
190  if ((looped || reachedCurrent) &&
191  current->IsVisible(true) && current->IsEnabled())
192  return SetFocusWidget(current);
193 
195  reachedCurrent = true;
196 
197  ++it;
198 
199  if (it == m_FocusWidgetList.end())
200  {
201  if (looped)
202  return false;
203  else
204  {
205  looped = true;
206  it = m_FocusWidgetList.begin();
207  }
208  }
209  }
210  }
211  else
212  {
213  it = m_FocusWidgetList.end() - 1;
214  while (it != m_FocusWidgetList.begin() - 1)
215  {
216  current = *it;
217 
218  if ((looped || reachedCurrent) &&
219  current->IsVisible(true) && current->IsEnabled())
220  return SetFocusWidget(current);
221 
223  reachedCurrent = true;
224 
225  --it;
226 
227  if (it == m_FocusWidgetList.begin() - 1)
228  {
229  if (looped)
230  return false;
231  else
232  {
233  looped = true;
234  it = m_FocusWidgetList.end() - 1;
235  }
236  }
237  }
238  }
239 
240  return false;
241 }
242 
244 {
245  m_FocusWidgetList.clear();
246  m_CurrentFocusWidget = nullptr;
247 
249 
250  if (m_FocusWidgetList.size() > 0)
251  SetFocusWidget();
252 }
253 
255 {
256  return m_ScreenStack;
257 }
258 
260 {
261  if (!m_FullScreen)
262  {
263  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
264  {
265  // remove this screen's area from the mask so any embedded video is
266  // shown which was covered by this screen
267  if (!m_SavedMask.isEmpty())
269  }
270  }
271 
273 }
274 
276 {
277  if (!m_FullScreen)
278  {
279  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
280  {
281  // add this screens area to the mask so any embedded video isn't
282  // shown in front of this screen
283  QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
284  m_SavedMask = region;
285  region = region.united(QRegion(m_Area));
286  GetMythMainWindow()->GetPaintWindow()->setMask(region);
287  }
288  }
289 
291 }
292 
294 {
295  return m_IsDeleting;
296 }
297 
298 void MythScreenType::SetDeleting(bool deleting)
299 {
300  m_IsDeleting = deleting;
301 }
302 
304 {
305  return true;
306 }
307 
319 {
320  // Virtual
321 }
322 
323 void MythScreenType::LoadInBackground(QString message)
324 {
325  m_LoadLock.acquire();
326 
327  m_IsLoading = true;
328  m_IsLoaded = false;
329 
331 
332  OpenBusyPopup(message);
333 
334  ScreenLoadTask *loadTask = new ScreenLoadTask(*this);
335  MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
336 }
337 
339 {
340  SemaphoreLocker locker(&m_LoadLock);
341 
342  m_IsLoading = true;
343  m_IsLoaded = false;
344 
346  Load();
347  m_IsLoaded = true;
348  m_IsLoading = false;
349 }
350 
352 {
353  m_IsInitialized = false;
355 }
356 
357 void MythScreenType::OpenBusyPopup(QString message)
358 {
359  if (m_BusyPopup)
360  return;
361 
362  QString msg(tr("Loading..."));
363  if (!message.isEmpty())
364  msg = message;
365 
366  MythScreenStack *popupStack =
367  GetMythMainWindow()->GetStack("popup stack");
368  m_BusyPopup =
369  new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
370 
371  if (m_BusyPopup->Create())
372  popupStack->AddScreen(m_BusyPopup, false);
373 }
374 
376 {
377  if (m_BusyPopup)
378  m_BusyPopup->Close();
379  m_BusyPopup = nullptr;
380 }
381 
382 void MythScreenType::SetBusyPopupMessage(const QString &message)
383 {
384  if (m_BusyPopup)
385  m_BusyPopup->SetMessage(message);
386 }
387 
389 {
390  if (m_BusyPopup)
391  m_BusyPopup->Reset();
392 }
393 
398 {
399  return m_IsInitialized;
400 }
401 
403 {
404  SemaphoreLocker locker(&m_LoadLock); // don't run while loading..
405 
406  CloseBusyPopup();
407  Init();
408  m_IsInitialized = true;
409 }
410 
419 {
420  // Virtual
421 }
422 
424 {
425  CloseBusyPopup();
426  if (GetScreenStack())
427  GetScreenStack()->PopScreen(this);
428 }
429 
431 {
432  // Virtual
433 }
434 
435 bool MythScreenType::keyPressEvent(QKeyEvent *event)
436 {
437  if (!GetMythMainWindow()->IsExitingToMain() && m_CurrentFocusWidget &&
439  return true;
440 
441  bool handled = false;
442  QStringList actions;
443  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
444 
445  for (int i = 0; i < actions.size() && !handled; i++)
446  {
447  QString action = actions[i];
448  handled = true;
449 
450  if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
451  {
452  if (!NextPrevWidgetFocus(false))
453  handled = false;
454  }
455  else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
456  {
457  if (!NextPrevWidgetFocus(true))
458  handled = false;
459  }
460  else if (action == "ESCAPE")
461  Close();
462  else if (action == "MENU")
463  ShowMenu();
464  else if (action.startsWith("SYSEVENT"))
465  gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
466  else if (action == ACTION_SCREENSHOT)
468  else if (action == ACTION_TVPOWERON)
470  else if (action == ACTION_TVPOWEROFF)
472  else
473  handled = false;
474  }
475 
476  return handled;
477 }
478 
480 {
481  bool handled = false;
482  if (event->gesture() == MythGestureEvent::Click)
483  {
484  switch (event->GetButton())
485  {
487  ShowMenu();
488  handled = true;
489  break;
490  default :
491  break;
492  }
493 
494  }
495 
496  if (!handled)
497  {
498  MythUIType *clicked = GetChildAt(event->GetPosition());
499  if (clicked && clicked->IsEnabled())
500  {
501  SetFocusWidget(clicked);
502  if (clicked->gestureEvent(event))
503  handled = true;
504  }
505  }
506 
507  return handled;
508 }
509 
514  const QString &filename, QDomElement &element, bool showWarnings)
515 {
516  if (element.tagName() == "area")
517  {
518  MythRect rect = parseRect(element, false);
519  MythRect rectN = parseRect(element);
520  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
521 
522  if (rect.x() == -1)
523  rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
524 
525  if (rect.y() == -1)
526  rectN.moveTop((screenArea.height() - rectN.height()) / 2);
527 
528  SetArea(rectN);
529 
530  if (m_Area.width() < screenArea.width() ||
531  m_Area.height() < screenArea.height())
532  {
533  m_FullScreen = false;
534  }
535  else
536  {
537  m_FullScreen = true;
538  }
539  }
540  else
541  {
542  return MythUIType::ParseElement(filename, element, showWarnings);
543  }
544 
545  return true;
546 }
547 
552 {
553  MythScreenType *st = dynamic_cast<MythScreenType *>(base);
554  if (!st)
555  {
556  LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
557  return;
558  }
559 
561  m_IsDeleting = false;
562 
563  MythUIType::CopyFrom(base);
564 
565  ConnectDependants(true);
566 
567  BuildFocusList();
568 };
569 
577 {
578  LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
579 }
580 
582 {
583  if (m_Painter)
584  return m_Painter;
585  if (m_ScreenStack)
586  return m_ScreenStack->GetPainter();
587  return GetMythPainter();
588 }
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)
void start(QRunnable *runnable, QString debugName, int priority=0)
virtual bool keyPressEvent(QKeyEvent *event)
Key event handler.
Definition: mythuitype.cpp:993
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.
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:903
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:168
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.
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.
MythPainter * GetPainter(void)
virtual void Close()
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:116
QMap< int, MythUIType * > m_FocusWidgetList
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:285
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:246
virtual ~MythScreenType()
void SetBusyPopupMessage(const QString &message)
A custom event that represents a mouse gesture.
Definition: mythgesture.h:39
const char * name
Definition: ParseText.cpp:339
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:613
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)
#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)
void OpenBusyPopup(QString message="")
bool TakeFocus()
Screen in which all other widgets are contained and rendered.
void moveTop(const QString &sX)
Definition: mythrect.cpp:295
void ActivateAnimations(MythUIAnimation::Trigger trigger)
Definition: mythuitype.cpp:293
bool IsDeleting(void) const
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:155
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)
void LoadInBackground(QString message="")