00001 #include "mythscreenstack.h"
00002 #include "mythmainwindow.h"
00003 #include "mythscreentype.h"
00004 #include "mythpainter.h"
00005 #include "mythevent.h"
00006
00007 #include <cassert>
00008
00009 #include <QCoreApplication>
00010 #include <QTimer>
00011 #include <QString>
00012
00013 const int kFadeVal = 20;
00014
00015 MythScreenStack::MythScreenStack(MythMainWindow *parent, const QString &name,
00016 bool mainstack)
00017 : QObject(parent)
00018 {
00019 setObjectName(name);
00020
00021 if (parent)
00022 parent->AddScreenStack(this, mainstack);
00023
00024 m_newTop = NULL;
00025 m_topScreen = NULL;
00026
00027 EnableEffects();
00028 m_InNewTransition = false;
00029
00030 m_DoInit = false;
00031 m_InitTimerStarted = false;
00032 }
00033
00034 MythScreenStack::~MythScreenStack()
00035 {
00036 CheckDeletes(true);
00037
00038 while (!m_Children.isEmpty())
00039 {
00040 MythScreenType *child = m_Children.back();
00041 PopScreen(child, false, true);
00042 }
00043 }
00044
00045 void MythScreenStack::EnableEffects(void)
00046 {
00047 m_DoTransitions = (GetPainter()->SupportsAlpha() &&
00048 GetPainter()->SupportsAnimation());
00049 }
00050
00051 int MythScreenStack::TotalScreens(void) const
00052 {
00053 return m_Children.count();
00054 }
00055
00056 void MythScreenStack::AddScreen(MythScreenType *screen, bool allowFade)
00057 {
00058 if (!screen)
00059 return;
00060
00061 m_DoInit = false;
00062
00063 MythScreenType *old = m_topScreen;
00064 if (old && screen->IsFullscreen())
00065 old->aboutToHide();
00066
00067 m_Children.push_back(screen);
00068
00069 if (allowFade && m_DoTransitions)
00070 {
00071 m_newTop = screen;
00072 DoNewFadeTransition();
00073 }
00074 else
00075 {
00076 if (parent())
00077 reinterpret_cast<MythMainWindow *>(parent())->update();
00078 RecalculateDrawOrder();
00079 if (!screen->IsInitialized())
00080 m_DoInit = true;
00081 }
00082
00083 screen->aboutToShow();
00084
00085 m_topScreen = screen;
00086
00087 emit topScreenChanged(m_topScreen);
00088 }
00089
00090 void MythScreenStack::PopScreen(bool allowFade,
00091 bool deleteScreen)
00092 {
00093 PopScreen(m_topScreen, allowFade, deleteScreen);
00094 }
00095
00096 void MythScreenStack::PopScreen(MythScreenType *screen, bool allowFade,
00097 bool deleteScreen)
00098 {
00099 if (!screen || screen->IsDeleting())
00100 return;
00101
00102 bool poppedFullscreen = screen->IsFullscreen();
00103
00104 screen->aboutToHide();
00105
00106 if (m_Children.isEmpty())
00107 return;
00108
00109 MythMainWindow *mainwindow = GetMythMainWindow();
00110
00111 screen->setParent(0);
00112 if ((screen == m_topScreen) && allowFade && m_DoTransitions
00113 && !mainwindow->IsExitingToMain())
00114 {
00115 screen->SetFullscreen(false);
00116 if (deleteScreen)
00117 {
00118 screen->SetDeleting(true);
00119 m_ToDelete.push_back(screen);
00120 }
00121 screen->AdjustAlpha(1, -kFadeVal);
00122 }
00123 else
00124 {
00125 for (int i = 0; i < m_Children.size(); ++i)
00126 {
00127 if (m_Children.at(i) == screen)
00128 m_Children.remove(i);
00129 }
00130 if (deleteScreen)
00131 delete screen;
00132
00133 screen = NULL;
00134
00135 mainwindow->update();
00136 if (mainwindow->IsExitingToMain())
00137 {
00138 QCoreApplication::postEvent(
00139 mainwindow, new QEvent(MythEvent::kExitToMainMenuEventType));
00140 }
00141 }
00142
00143 m_topScreen = NULL;
00144
00145 RecalculateDrawOrder();
00146
00147
00148 if (screen)
00149 m_DrawOrder.push_back(screen);
00150
00151 if (!m_Children.isEmpty())
00152 {
00153 QVector<MythScreenType *>::Iterator it;
00154 for (it = m_DrawOrder.begin(); it != m_DrawOrder.end(); ++it)
00155 {
00156 if (*it != screen && !(*it)->IsDeleting())
00157 {
00158 m_topScreen = (*it);
00159 (*it)->SetAlpha(255);
00160 if (poppedFullscreen)
00161 (*it)->aboutToShow();
00162 }
00163 }
00164 }
00165
00166 if (m_topScreen)
00167 {
00168 m_topScreen->SetRedraw();
00169
00170 if (!allowFade || !m_DoTransitions)
00171 emit topScreenChanged(m_topScreen);
00172 }
00173 else
00174 {
00175
00176
00177 if (mainwindow->GetMainStack())
00178 {
00179 MythScreenType *mainscreen = mainwindow->GetMainStack()->GetTopScreen();
00180 if (mainscreen)
00181 mainscreen->SetRedraw();
00182 }
00183
00184 if (!allowFade || !m_DoTransitions)
00185 emit topScreenChanged(NULL);
00186 }
00187 }
00188
00189 MythScreenType *MythScreenStack::GetTopScreen(void) const
00190 {
00191 if (m_topScreen)
00192 return m_topScreen;
00193 if (!m_DrawOrder.isEmpty())
00194 return m_DrawOrder.back();
00195 return NULL;
00196 }
00197
00198 void MythScreenStack::GetDrawOrder(QVector<MythScreenType *> &screens)
00199 {
00200 if (m_InNewTransition)
00201 CheckNewFadeTransition();
00202 CheckDeletes();
00203
00204 screens = m_DrawOrder;
00205 }
00206
00207 void MythScreenStack::GetScreenList(QVector<MythScreenType *> &screens)
00208 {
00209 if (m_InNewTransition)
00210 CheckNewFadeTransition();
00211 CheckDeletes();
00212
00213 screens = m_Children;
00214 }
00215
00216 void MythScreenStack::ScheduleInitIfNeeded(void)
00217 {
00218
00219 if (m_DoInit && m_topScreen && !m_InitTimerStarted &&
00220 !m_topScreen->IsLoading())
00221 {
00222 m_InitTimerStarted = true;
00223 QTimer::singleShot(100, this, SLOT(doInit()));
00224 }
00225 }
00226
00227 void MythScreenStack::doInit(void)
00228 {
00229 if (m_DoInit && m_topScreen)
00230 {
00231 m_DoInit = false;
00232
00233 if (!m_topScreen->IsLoaded())
00234 m_topScreen->LoadInForeground();
00235
00236 if (!m_topScreen->IsInitialized())
00237 m_topScreen->doInit();
00238 }
00239 m_InitTimerStarted = false;
00240 }
00241
00242 void MythScreenStack::RecalculateDrawOrder(void)
00243 {
00244 m_DrawOrder.clear();
00245
00246 if (m_Children.isEmpty())
00247 return;
00248
00249 QVector<MythScreenType *>::Iterator it;
00250
00251 for (it = m_Children.begin(); it != m_Children.end(); ++it)
00252 {
00253 MythScreenType *screen = (*it);
00254
00255 if (screen->IsFullscreen())
00256 m_DrawOrder.clear();
00257
00258 m_DrawOrder.push_back(screen);
00259 }
00260
00261 if (m_DrawOrder.isEmpty())
00262 {
00263 MythScreenType *screen = GetTopScreen();
00264 if (screen)
00265 m_DrawOrder.push_back(screen);
00266 }
00267 }
00268
00269 void MythScreenStack::DoNewFadeTransition(void)
00270 {
00271 m_InNewTransition = true;
00272 m_newTop->SetAlpha(0);
00273 m_newTop->AdjustAlpha(1, kFadeVal);
00274
00275 if (m_newTop->IsFullscreen())
00276 {
00277 QVector<MythScreenType *>::Iterator it;
00278 for (it = m_DrawOrder.begin(); it != m_DrawOrder.end(); ++it)
00279 {
00280 if (!(*it)->IsDeleting())
00281 (*it)->AdjustAlpha(1, -kFadeVal);
00282 }
00283
00284 m_DrawOrder.push_back(m_newTop);
00285 }
00286 else
00287 RecalculateDrawOrder();
00288 }
00289
00290 void MythScreenStack::CheckNewFadeTransition(void)
00291 {
00292 if (!m_newTop)
00293 {
00294 m_InNewTransition = false;
00295 return;
00296 }
00297
00298 if (m_newTop->GetAlpha() >= 255)
00299 {
00300 m_InNewTransition = false;
00301 if (!m_newTop->IsInitialized())
00302 m_DoInit = true;
00303 m_newTop = NULL;
00304
00305 RecalculateDrawOrder();
00306 }
00307 }
00308
00309 void MythScreenStack::CheckDeletes(bool force)
00310 {
00311 if (m_ToDelete.isEmpty())
00312 return;
00313
00314 bool changed = false;
00315
00316 QVector<MythScreenType *>::Iterator it = m_ToDelete.begin();
00317 while (it != m_ToDelete.end() && !m_ToDelete.isEmpty())
00318 {
00319 bool deleteit = false;
00320
00321 if (force || (*it)->GetAlpha() <= 0)
00322 {
00323 deleteit = true;
00324 }
00325
00326 if (!deleteit)
00327 {
00328 bool found = false;
00329
00330 QVector<MythScreenType *>::Iterator test;
00331 for (test = m_DrawOrder.begin(); test != m_DrawOrder.end(); ++test)
00332 {
00333 if (*it == *test)
00334 {
00335 found = true;
00336 break;
00337 }
00338 }
00339
00340 if (!found)
00341 deleteit = true;
00342 }
00343
00344 if (deleteit)
00345 {
00346 QVector<MythScreenType *>::Iterator test;
00347 for (test = m_Children.begin(); test != m_Children.end(); ++test)
00348 {
00349 if (*test == *it)
00350 {
00351 m_Children.erase(test);
00352 break;
00353 }
00354 }
00355
00356 if (*it == m_newTop)
00357 m_newTop = NULL;
00358 delete (*it);
00359 m_ToDelete.erase(it);
00360 it = m_ToDelete.begin();
00361 changed = true;
00362 continue;
00363 }
00364
00365 ++it;
00366 }
00367
00368 if (changed)
00369 {
00370 RecalculateDrawOrder();
00371 emit topScreenChanged(GetTopScreen());
00372 }
00373 }
00374
00375 QString MythScreenStack::GetLocation(bool fullPath) const
00376 {
00377 if (fullPath)
00378 {
00379 QString path;
00380 QVector<MythScreenType *>::const_iterator it;
00381 for (it = m_Children.begin(); it != m_Children.end(); ++it)
00382 {
00383 if (!(*it)->IsDeleting())
00384 {
00385 if (path.isEmpty())
00386 path = (*it)->objectName();
00387 else
00388 path += '/' + (*it)->objectName();
00389 }
00390 }
00391 return path;
00392 }
00393 else
00394 {
00395 if (m_topScreen)
00396 return m_topScreen->objectName();
00397 }
00398
00399 return QString();
00400 }
00401
00402 MythPainter* MythScreenStack::GetPainter(void)
00403 {
00404 return GetMythPainter();
00405 }