Rev 16 | Blame | Last modification | View Log | RSS feed
/*
* Copyright (C) 2020, 2021 by Andreas Theofilu <andreas@theosys.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "tresources.h"
#include "tpage.h"
using std::string;
using namespace Button;
TPage::TPage(const string& name)
{
DECL_TRACER("TPage::TPage(const string& name)");
TError::clear();
initialize(name);
}
TPage::~TPage()
{
DECL_TRACER("TPage::~TPage()");
MSG_DEBUG("Destroing page " << pageID << ": " << name);
BUTTONS_T *p = mButtons;
BUTTONS_T *next = nullptr;
while (p)
{
next = p->next;
delete p->button;
delete p;
p = next;
}
mButtons = nullptr;
PAGECHAIN_T *pc = mSubPages;
PAGECHAIN_T *pc_next = nullptr;
// We're not allowd to delete the subpages here, because they're managed
// by the TPageManager.
while (pc)
{
pc_next = pc->next;
delete pc;
pc = pc_next;
}
mSubPages = nullptr;
}
void TPage::initialize(const string& nm)
{
DECL_TRACER("TPage::initialize(const string& name)");
makeFileName(TConfig::getProjectPath(), nm);
if (isValidFile())
mPath = getFileName();
TReadXML reader(mPath);
if (TError::isError())
return;
reader.findElement("page", "type");
if (!reader.success())
{
MSG_ERROR("Element \"page\" with attribute \"type\" was not found!");
TError::setError();
return;
}
string type = reader.getAttribute("type");
if (type.compare("page") != 0)
{
MSG_ERROR("Invalid page type \"" << type << "\"!");
TError::setError();
return;
}
mxml_node_t *node = reader.getFirstChild();
while (node)
{
string e = reader.getElementName(node);
if (e.compare("pageID") == 0)
pageID = reader.getIntFromNode(node);
else if (e.compare("name") == 0)
name = reader.getTextFromNode(node);
else if (e.compare("width") == 0)
width = reader.getIntFromNode(node);
else if (e.compare("height") == 0)
height = reader.getIntFromNode(node);
else if (e.compare("button") == 0)
{
TButton *button = new TButton();
button->setPalette(mPalette);
button->setFonts(mFonts);
button->registerCallback(_displayButton);
button->registerCallbackFT(_setText);
button->regCallPlayVideo(_playVideo);
button->initialize(&reader, node);
if (TError::isError())
{
delete button;
return;
}
button->setHandle(((pageID << 16) & 0xffff0000) | button->getButtonIndex());
button->createButtons();
addButton(button);
}
else if (e.compare("sr") == 0)
{
SR_T bsr;
bsr.number = atoi(reader.getAttributeFromNode(node, "number").c_str());
mxml_node_t *n = reader.getFirstChild(node);
while (n)
{
string ename = reader.getElementName(n);
if (ename.compare("bs") == 0)
bsr.bs = reader.getTextFromNode(n);
else if (ename.compare("cb") == 0)
bsr.cb = reader.getTextFromNode(n);
else if (ename.compare("cf") == 0)
bsr.cf = reader.getTextFromNode(n);
else if (ename.compare("ct") == 0)
bsr.ct = reader.getTextFromNode(n);
else if (ename.compare("ec") == 0)
bsr.ec = reader.getTextFromNode(n);
else if (ename.compare("bm") == 0)
bsr.bm = reader.getTextFromNode(n);
else if (ename.compare("fi") == 0)
bsr.fi = reader.getIntFromNode(n);
n = reader.getNextChild(n);
}
sr.push_back(bsr);
}
node = reader.getNextChild();
}
sortButtons();
}
void TPage::show()
{
DECL_TRACER("TPage::show()");
if (!_setBackground)
{
MSG_WARNING("No callback \"setBackground\" was set!");
return;
}
ulong handle = (pageID << 16) & 0xffff0000;
MSG_DEBUG("Processing page " << pageID);
if (!sr[0].bm.empty())
{
sk_sp<SkData> rawImage = readImage(sr[0].bm);
if (rawImage)
{
SkBitmap bm;
DecodeDataToBitmap(rawImage, &bm);
SkImageInfo info = bm.info();
size_t rowBytes = info.minRowBytes();
size_t size = info.computeByteSize(rowBytes);
MSG_DEBUG("Setting background with image of size " << size);
_setBackground(handle, (unsigned char *)bm.getPixels(), size, rowBytes, TColor::getColor(sr[0].cf));
return;
}
else
{
MSG_WARNING("Couldn't read image " << sr[0].bm);
}
}
else
{
MSG_DEBUG("No background image defined!");
}
MSG_DEBUG("Calling \"setBackground\" with no image ...");
_setBackground(handle, nullptr, 0, 0, TColor::getColor(sr[0].cf));
mVisible = true;
}
PAGECHAIN_T *TPage::addSubPage(TSubPage* pg)
{
DECL_TRACER("TPage::addSubPage(TSubPage* pg)");
if (!pg)
{
MSG_ERROR("Parameter is NULL!");
TError::setError();
return nullptr;
}
PAGECHAIN_T *chain = new PAGECHAIN_T;
chain->subpage = pg;
chain->next = nullptr;
PAGECHAIN_T *spg = mSubPages;
if (spg)
{
// First make sure that the new page is not already in the chain.
PAGECHAIN_T *p = spg;
while (p)
{
if (p->subpage->getNumber() == pg->getNumber())
{
MSG_TRACE("Page " << pg->getNumber() << " is already in chain. Don't add it again.");
delete chain;
return p;
}
p = p->next;
}
// The subpage is not in chain. So we add it now.
p = spg;
// Find the last element in chain
while (p->next)
p = p->next;
p->next = chain;
}
else
{
mZOrder = 0;
mSubPages = chain;
}
mLastSubPage = 0;
return chain;
}
bool TPage::removeSubPage(int ID)
{
DECL_TRACER("TPage::removeSubPage(int ID)");
PAGECHAIN_T *p = mSubPages;
PAGECHAIN_T *prev = nullptr;
while (p)
{
if (p->subpage->getNumber() == ID)
{
PAGECHAIN_T *next = p->next;
if (prev)
prev->next = next;
else
mSubPages = next;
delete p;
mLastSubPage = 0;
return true;
}
prev = p;
p = p->next;
}
return false;
}
bool TPage::removeSubPage(const std::string& nm)
{
DECL_TRACER("TPage::removeSubPage(const std::string& nm)");
PAGECHAIN_T *p = mSubPages;
PAGECHAIN_T *prev = nullptr;
while (p)
{
if (p->subpage->getName().compare(nm) == 0)
{
PAGECHAIN_T *next = p->next;
if (prev)
prev->next = next;
else
mSubPages = next;
delete p;
mLastSubPage = 0;
return true;
}
prev = p;
p = p->next;
}
return false;
}
TSubPage *TPage::getSubPage(int pageID)
{
DECL_TRACER("TPage::getSubPage(int pageID)");
PAGECHAIN_T *pg = mSubPages;
while (pg)
{
if (pg->subpage->getNumber() == pageID)
{
mLastSubPage = pageID;
return pg->subpage;
}
pg = pg->next;
}
mLastSubPage = 0;
return nullptr;
}
TSubPage *TPage::getSubPage(const std::string& name)
{
DECL_TRACER("TPage::getSubPage(const std::string& name)");
PAGECHAIN_T *pg = mSubPages;
while (pg)
{
if (pg->subpage->getName().compare(name) == 0)
{
mLastSubPage = pg->subpage->getNumber();
return pg->subpage;
}
pg = pg->next;
}
mLastSubPage = 0;
return nullptr;
}
TSubPage *TPage::getFirstSubPage()
{
DECL_TRACER("TPage::getFirstSubPage()");
PAGECHAIN_T *pg = mSubPages;
if (pg)
{
if (pg->subpage)
{
mLastSubPage = pg->subpage->getNumber();
MSG_DEBUG("Subpage " << pg->subpage->getNumber() << ". " << pg->subpage->getName());
return pg->subpage;
}
}
MSG_DEBUG("No subpages in chain.");
mLastSubPage = 0;
return nullptr;
}
TSubPage *TPage::getNextSubPage()
{
DECL_TRACER("TPage::getNextSubPage()");
if (mLastSubPage > 0)
{
PAGECHAIN_T *p = mSubPages;
while (p)
{
if (p->subpage->getNumber() == mLastSubPage)
{
if (p->next && p->next->subpage)
{
TSubPage *page = p->next->subpage;
mLastSubPage = page->getNumber();
MSG_DEBUG("Subpage " << page->getNumber() << ". " << page->getName());
return page;
}
}
p = p->next;
}
}
MSG_DEBUG("No more subpages in chain.");
mLastSubPage = 0;
return nullptr;
}
BUTTONS_T *TPage::addButton(TButton* button)
{
DECL_TRACER("*TPage::addButton(TButton* button)");
if (!button)
{
MSG_ERROR("Parameter is NULL!");
TError::setError();
return nullptr;
}
BUTTONS_T *chain = new BUTTONS_T;
BUTTONS_T *bts = mButtons;
chain->button = button;
if (bts)
{
BUTTONS_T *p = bts;
while (p->next)
p = p->next;
p->next = chain;
chain->previous = p;
}
else
mButtons = chain;
return chain;
}
bool TPage::hasButton(int id)
{
DECL_TRACER("TPage::hasButton(int id)");
BUTTONS_T *bt = mButtons;
while (bt)
{
if (bt->button && bt->button->getButtonIndex() == id)
return true;
bt = bt->next;
}
return false;
}
TButton *TPage::getButton(int id)
{
DECL_TRACER("TPage::getButton(int id)");
BUTTONS_T *bt = mButtons;
while (bt)
{
if (bt->button && bt->button->getButtonIndex() == id)
return bt->button;
bt = bt->next;
}
return nullptr;
}
std::vector<TButton *> TPage::getButtons(int ap, int ad)
{
DECL_TRACER("TSubPage::getButtons(int ap, int ad)");
std::vector<TButton *> list;
BUTTONS_T *bt = mButtons;
while (bt)
{
if (bt->button->getAddressPort() == ap && bt->button->getAddressChannel() == ad)
list.push_back(bt->button);
bt = bt->next;
}
return list;
}
void TPage::drop()
{
DECL_TRACER("TPage::drop()");
PAGECHAIN_T *pc = mSubPages;
while (pc)
{
pc->subpage->drop();
pc = pc->next;
}
mZOrder = ZORDER_INVALID;
mVisible = false;
}
/*
* Sort the button according to their Z-order.
* The button with the highest Z-order will be the last button in the chain.
* The algorithm is a bubble sort algorithm.
*/
bool TPage::sortButtons()
{
DECL_TRACER("TPage::sortButtons()");
bool turned = true;
while (turned)
{
BUTTONS_T *button = mButtons;
turned = false;
while (button)
{
int zo = button->button->getZOrder();
if (button->previous)
{
if (zo < button->previous->button->getZOrder())
{
BUTTONS_T *pprev = button->previous->previous;
BUTTONS_T *prev = button->previous;
BUTTONS_T *next = button->next;
if (pprev)
pprev->next = button;
prev->next = next;
prev->previous = button;
button->next = prev;
button->previous = pprev;
if (!pprev)
mButtons = button;
button = next;
if (next)
next->previous = prev;
turned = true;
continue;
}
}
button = button->next;
}
}
return true;
}