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();
123 
124  while (it != m_FocusWidgetList.end())
125  {
126  current = *it;
127 
128  if (current->CanTakeFocus() && current->IsVisible(true))
129  {
130  widget = current;
131  break;
132  }
133  ++it;
134  }
135  }
136 
137  if (!widget)
138  return false;
139 
140  if (m_CurrentFocusWidget == widget)
141  return true;
142 
143  MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
144  if (helpText)
145  helpText->Reset();
146 
149  m_CurrentFocusWidget = widget;
151 
152  if (helpText && !widget->GetHelpText().isEmpty())
153  helpText->SetText(widget->GetHelpText());
154 
155  return true;
156 }
157 
159 {
160  if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
161  return SetFocusWidget(nullptr);
162 
163  bool reachedCurrent = false;
164  bool looped = false;
165 
166  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
168 
169  // There is probably a more efficient way to do this, but the list
170  // is never going to be that big so it will do for now
171  if (up)
172  {
173  while (it != m_FocusWidgetList.end())
174  {
175  current = *it;
176 
177  if ((looped || reachedCurrent) &&
178  current->IsVisible(true) && current->IsEnabled())
179  return SetFocusWidget(current);
180 
182  reachedCurrent = true;
183 
184  ++it;
185 
186  if (it == m_FocusWidgetList.end())
187  {
188  if (looped)
189  return false;
190  looped = true;
191  it = m_FocusWidgetList.begin();
192  }
193  }
194  }
195  else
196  {
197  it = m_FocusWidgetList.end() - 1;
198  while (it != m_FocusWidgetList.begin() - 1)
199  {
200  current = *it;
201 
202  if ((looped || reachedCurrent) &&
203  current->IsVisible(true) && current->IsEnabled())
204  return SetFocusWidget(current);
205 
207  reachedCurrent = true;
208 
209  --it;
210 
211  if (it == m_FocusWidgetList.begin() - 1)
212  {
213  if (looped)
214  return false;
215  looped = true;
216  it = m_FocusWidgetList.end() - 1;
217  }
218  }
219  }
220 
221  return false;
222 }
223 
225 {
226  m_FocusWidgetList.clear();
227  m_CurrentFocusWidget = nullptr;
228 
230 
231  if (!m_FocusWidgetList.empty())
232  SetFocusWidget();
233 }
234 
236 {
237  return m_ScreenStack;
238 }
239 
241 {
242  if (!m_FullScreen)
243  {
244  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
245  {
246  // remove this screen's area from the mask so any embedded video is
247  // shown which was covered by this screen
248  if (!m_SavedMask.isEmpty())
250  }
251  }
252 
254 }
255 
257 {
258  if (!m_FullScreen)
259  {
260  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
261  {
262  // add this screens area to the mask so any embedded video isn't
263  // shown in front of this screen
264  QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
265  m_SavedMask = region;
266  region = region.united(QRegion(m_Area));
267  GetMythMainWindow()->GetPaintWindow()->setMask(region);
268  }
269  }
270 
272 }
273 
275 {
276  return m_IsDeleting;
277 }
278 
279 void MythScreenType::SetDeleting(bool deleting)
280 {
281  m_IsDeleting = deleting;
282 }
283 
285 {
286  return true;
287 }
288 
300 {
301  // Virtual
302 }
303 
304 void MythScreenType::LoadInBackground(QString message)
305 {
306  m_LoadLock.acquire();
307 
308  m_IsLoading = true;
309  m_IsLoaded = false;
310 
312 
313  OpenBusyPopup(std::move(message));
314 
315  ScreenLoadTask *loadTask = new ScreenLoadTask(*this);
316  MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
317 }
318 
320 {
321  SemaphoreLocker locker(&m_LoadLock);
322 
323  m_IsLoading = true;
324  m_IsLoaded = false;
325 
327  Load();
328  m_IsLoaded = true;
329  m_IsLoading = false;
330 }
331 
333 {
334  m_IsInitialized = false;
336 }
337 
338 void MythScreenType::OpenBusyPopup(const QString& message)
339 {
340  if (m_BusyPopup)
341  return;
342 
343  QString msg(tr("Loading..."));
344  if (!message.isEmpty())
345  msg = message;
346 
347  MythScreenStack *popupStack =
348  GetMythMainWindow()->GetStack("popup stack");
349  m_BusyPopup =
350  new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
351 
352  if (m_BusyPopup->Create())
353  popupStack->AddScreen(m_BusyPopup, false);
354 }
355 
357 {
358  if (m_BusyPopup)
359  m_BusyPopup->Close();
360  m_BusyPopup = nullptr;
361 }
362 
363 void MythScreenType::SetBusyPopupMessage(const QString &message)
364 {
365  if (m_BusyPopup)
366  m_BusyPopup->SetMessage(message);
367 }
368 
370 {
371  if (m_BusyPopup)
372  m_BusyPopup->Reset();
373 }
374 
379 {
380  return m_IsInitialized;
381 }
382 
384 {
385  SemaphoreLocker locker(&m_LoadLock); // don't run while loading..
386 
387  CloseBusyPopup();
388  Init();
389  m_IsInitialized = true;
390 }
391 
400 {
401  // Virtual
402 }
403 
405 {
406  CloseBusyPopup();
407  if (GetScreenStack())
408  GetScreenStack()->PopScreen(this);
409 }
410 
412 {
413  // Virtual
414 }
415 
416 bool MythScreenType::keyPressEvent(QKeyEvent *event)
417 {
418  if (!GetMythMainWindow()->IsExitingToMain() && m_CurrentFocusWidget &&
420  return true;
421 
422  bool handled = false;
423  QStringList actions;
424  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
425 
426  for (int i = 0; i < actions.size() && !handled; i++)
427  {
428  QString action = actions[i];
429  handled = true;
430 
431  if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
432  {
433  if (!NextPrevWidgetFocus(false))
434  handled = false;
435  }
436  else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
437  {
438  if (!NextPrevWidgetFocus(true))
439  handled = false;
440  }
441  else if (action == "ESCAPE")
442  Close();
443  else if (action == "MENU")
444  ShowMenu();
445  else if (action.startsWith("SYSEVENT"))
446  gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
447  else if (action == ACTION_SCREENSHOT)
449  else if (action == ACTION_TVPOWERON)
451  else if (action == ACTION_TVPOWEROFF)
453  else
454  handled = false;
455  }
456 
457  return handled;
458 }
459 
461 {
462  bool handled = false;
463  if (event->gesture() == MythGestureEvent::Click)
464  {
465  switch (event->GetButton())
466  {
468  ShowMenu();
469  handled = true;
470  break;
471  default :
472  break;
473  }
474 
475  }
476 
477  if (!handled)
478  {
479  MythUIType *clicked = GetChildAt(event->GetPosition());
480  if (clicked && clicked->IsEnabled())
481  {
482  SetFocusWidget(clicked);
483  if (clicked->gestureEvent(event))
484  handled = true;
485  }
486  }
487 
488  return handled;
489 }
490 
495  const QString &filename, QDomElement &element, bool showWarnings)
496 {
497  if (element.tagName() == "area")
498  {
499  MythRect rect = parseRect(element, false);
500  MythRect rectN = parseRect(element);
501  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
502 
503  if (rect.x() == -1)
504  rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
505 
506  if (rect.y() == -1)
507  rectN.moveTop((screenArea.height() - rectN.height()) / 2);
508 
509  SetArea(rectN);
510 
511  if (m_Area.width() < screenArea.width() ||
512  m_Area.height() < screenArea.height())
513  {
514  m_FullScreen = false;
515  }
516  else
517  {
518  m_FullScreen = true;
519  }
520  }
521  else
522  {
523  return MythUIType::ParseElement(filename, element, showWarnings);
524  }
525 
526  return true;
527 }
528 
533 {
534  MythScreenType *st = dynamic_cast<MythScreenType *>(base);
535  if (!st)
536  {
537  LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
538  return;
539  }
540 
542  m_IsDeleting = false;
543 
544  MythUIType::CopyFrom(base);
545 
546  ConnectDependants(true);
547 
548  BuildFocusList();
549 };
550 
558 {
559  LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
560 }
561 
563 {
564  if (m_Painter)
565  return m_Painter;
566  if (m_ScreenStack)
567  return m_ScreenStack->GetPainter();
568  return GetMythPainter();
569 }
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:971
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:986
bool IsVisible(bool recurse=false) const
Definition: mythuitype.cpp:881
virtual bool Create(void)
void LoseFocus()
Definition: mythuitype.cpp:999
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:136
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:84
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
const char * name
Definition: ParseText.cpp:328
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)
void LoadInBackground(QString message="")