GeekTrack/2.Firmware/components/GeekOS/System/PageManager/PM_Base.cpp

321 lines
7.6 KiB
C++

/*
* MIT License
* Copyright (c) 2021 _VIFEXTech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "PageManager.h"
#include "PM_Log.h"
#include <algorithm>
#define PM_EMPTY_PAGE_NAME "EMPTY_PAGE"
/**
* @brief Page manager constructor
* @param factory: Pointer to the page factory
* @retval None
*/
PageManager::PageManager(PageFactory* factory)
: _Factory(factory)
, _PagePrev(nullptr)
, _PageCurrent(nullptr)
, _RootDefaultStyle(nullptr)
{
memset(&_AnimState, 0, sizeof(_AnimState));
SetGlobalLoadAnimType();
}
/**
* @brief Page manager destructor
* @param None
* @retval None
*/
PageManager::~PageManager()
{
SetStackClear();
}
/**
* @brief Search pages in the page pool
* @param name: Page name
* @retval A pointer to the base class of the page, or nullptr if not found
*/
PageBase* PageManager::FindPageInPool(const char* name)
{
for (auto iter : _PagePool)
{
if (strcmp(name, iter->_Name) == 0)
{
return iter;
}
}
return nullptr;
}
/**
* @brief Search pages in the page stack
* @param name: Page name
* @retval A pointer to the base class of the page, or nullptr if not found
*/
PageBase* PageManager::FindPageInStack(const char* name)
{
decltype(_PageStack) stk = _PageStack;
while (!stk.empty())
{
PageBase* base = stk.top();
if (strcmp(name, base->_Name) == 0)
{
return base;
}
stk.pop();
}
return nullptr;
}
/**
* @brief Install the page, and register the page to the page pool
* @param className: The class name of the page
* @param appName: Page application name, no duplicates allowed
* @retval Return true if successful
*/
bool PageManager::Install(const char* className, const char* appName)
{
if (_Factory == nullptr)
{
PM_LOG_ERROR("Factory was not registered, can't install page");
return false;
}
if (appName == nullptr)
{
PM_LOG_WARN("appName has not set");
appName = className;
}
if (FindPageInPool(appName) != nullptr)
{
PM_LOG_ERROR("Page(%s) was registered", appName);
return false;
}
PageBase* base = _Factory->CreatePage(className);
if (base == nullptr)
{
PM_LOG_ERROR("Factory has not %s", className);
return false;
}
base->_root = nullptr;
base->_ID = 0;
base->_Manager = nullptr;
base->_UserData = nullptr;
memset(&base->priv, 0, sizeof(base->priv));
PM_LOG_INFO("Install Page[class = %s, name = %s]", className, appName);
bool retval = Register(base, appName);
base->onCustomAttrConfig();
return retval;
}
/**
* @brief Uninstall page
* @param appName: Page application name, no duplicates allowed
* @retval Return true if the uninstallation is successful
*/
bool PageManager::Uninstall(const char* appName)
{
PM_LOG_INFO("Page(%s) uninstall...", appName);
PageBase* base = FindPageInPool(appName);
if (base == nullptr)
{
PM_LOG_ERROR("Page(%s) was not found", appName);
return false;
}
if (!Unregister(appName))
{
PM_LOG_ERROR("Page(%s) unregister failed", appName);
return false;
}
if (base->priv.IsCached)
{
PM_LOG_WARN("Page(%s) has cached, unloading...", appName);
base->priv.State = PageBase::PAGE_STATE_UNLOAD;
StateUpdate(base);
}
else
{
PM_LOG_INFO("Page(%s) has not cache", appName);
}
delete base;
PM_LOG_INFO("Uninstall OK");
return true;
}
/**
* @brief Register the page to the page pool
* @param name: Page application name, duplicate registration is not allowed
* @retval Return true if the registration is successful
*/
bool PageManager::Register(PageBase* base, const char* name)
{
if (FindPageInPool(name) != nullptr)
{
PM_LOG_ERROR("Page(%s) was multi registered", name);
return false;
}
base->_Manager = this;
base->_Name = name;
_PagePool.push_back(base);
return true;
}
/**
* @brief Log out the page from the page pool
* @param name: Page application name
* @retval Return true if the logout is successful
*/
bool PageManager::Unregister(const char* name)
{
PM_LOG_INFO("Page(%s) unregister...", name);
PageBase* base = FindPageInStack(name);
if (base != nullptr)
{
PM_LOG_ERROR("Page(%s) was in stack", name);
return false;
}
base = FindPageInPool(name);
if (base == nullptr)
{
PM_LOG_ERROR("Page(%s) was not found", name);
return false;
}
auto iter = std::find(_PagePool.begin(), _PagePool.end(), base);
if (iter == _PagePool.end())
{
PM_LOG_ERROR("Page(%s) was not found in PagePool", name);
return false;
}
_PagePool.erase(iter);
PM_LOG_INFO("Unregister OK");
return true;
}
/**
* @brief Get the top page of the page stack
* @param None
* @retval A pointer to the base class of the page
*/
PageBase* PageManager::GetStackTop()
{
return _PageStack.empty() ? nullptr : _PageStack.top();
}
/**
* @brief Get the page below the top of the page stack
* @param None
* @retval A pointer to the base class of the page
*/
PageBase* PageManager::GetStackTopAfter()
{
PageBase* top = GetStackTop();
if (top == nullptr)
{
return nullptr;
}
_PageStack.pop();
PageBase* topAfter = GetStackTop();
_PageStack.push(top);
return topAfter;
}
/**
* @brief Clear the page stack and end the life cycle of all pages in the page stack
* @param keepBottom: Whether to keep the bottom page of the stack
* @retval None
*/
void PageManager::SetStackClear(bool keepBottom)
{
while (1)
{
PageBase* top = GetStackTop();
if (top == nullptr)
{
PM_LOG_INFO("Page stack is empty, breaking...");
break;
}
PageBase* topAfter = GetStackTopAfter();
if (topAfter == nullptr)
{
if (keepBottom)
{
_PagePrev = top;
PM_LOG_INFO("Keep page stack bottom(%s), breaking...", top->_Name);
break;
}
else
{
_PagePrev = nullptr;
}
}
FourceUnload(top);
_PageStack.pop();
}
PM_LOG_INFO("Stack clear done");
}
/**
* @brief Get the name of the previous page
* @param None
* @retval The name of the previous page, if it does not exist, return PM_EMPTY_PAGE_NAME
*/
const char* PageManager::GetPagePrevName()
{
return _PagePrev ? _PagePrev->_Name : PM_EMPTY_PAGE_NAME;
}