vdr-plugin-tvguide/recmenu.c

702 lines
20 KiB
C
Raw Normal View History

#include <list>
2013-07-09 00:17:42 +02:00
#include "recmenu.h"
// --- cRecMenu -------------------------------------------------------------
cRecMenu::cRecMenu(void) {
2013-12-21 11:25:03 +01:00
border = geoManager.borderRecMenus;
2019-06-16 14:01:22 +02:00
height = 2 * border;
2013-07-09 00:17:42 +02:00
headerHeight = 0;
footerHeight = 0;
currentHeight = 0;
deleteMenuItems = true;
2013-07-09 00:17:42 +02:00
scrollable = false;
scrollbarWidth = 3 * border;
pixmapScrollBar = NULL;
imgScrollBar = NULL;
startIndex = 0;
stopIndex = 0;
numItems = 0;
header = NULL;
footer = NULL;
}
cRecMenu::~cRecMenu(void) {
if (header)
delete header;
ClearMenuItems(true);
2013-07-09 00:17:42 +02:00
if (footer)
delete footer;
if (pixmapScrollBar)
2019-11-10 15:37:28 +01:00
osdManager.DestroyPixmap(pixmapScrollBar);
2013-07-09 00:17:42 +02:00
if (imgScrollBar)
delete imgScrollBar;
}
void cRecMenu::SetWidthPercent(int percentOSDWidth) {
2013-12-21 11:25:03 +01:00
width = geoManager.osdWidth * percentOSDWidth / 100;
x = (geoManager.osdWidth - width) / 2;
2013-07-09 00:17:42 +02:00
}
void cRecMenu::SetWidthPixel(int pixel) {
width = pixel;
2013-12-21 11:25:03 +01:00
x = (geoManager.osdWidth - width) / 2;
2013-07-09 00:17:42 +02:00
}
int cRecMenu::CalculateOptimalWidth(void) {
int optWidth = 0;
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
int itemWidth = (*item)->GetWidth();
2013-07-09 00:17:42 +02:00
if (itemWidth > optWidth)
optWidth = itemWidth;
}
return optWidth;
}
bool cRecMenu::CalculateHeight(bool reDraw) {
2019-06-16 14:01:22 +02:00
int newHeight = 2 * border;
bool returnvalue = false;
if (header) {
newHeight += headerHeight;
2019-06-16 14:01:22 +02:00
}
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
2019-06-16 14:01:22 +02:00
newHeight += (*item)->GetHeight();
2013-07-09 00:17:42 +02:00
}
2019-06-16 14:01:22 +02:00
if (footer) {
newHeight += footerHeight;
2019-06-16 14:01:22 +02:00
}
y = (geoManager.osdHeight - newHeight) / 2;
if (newHeight != height) {
height = newHeight;
2019-06-16 14:01:22 +02:00
returnvalue = true;
2013-07-09 00:17:42 +02:00
}
2019-06-16 14:01:22 +02:00
if (scrollable && !reDraw) {
width += scrollbarWidth + border;
returnvalue = true;
}
return returnvalue;
2013-07-09 00:17:42 +02:00
}
void cRecMenu::CreatePixmap(void) {
if (pixmap)
2019-11-10 15:37:28 +01:00
osdManager.DestroyPixmap(pixmap);
pixmap = osdManager.CreatePixmap(3, cRect(x, y, width, height));
2013-07-09 00:17:42 +02:00
if (scrollable) {
int scrollBarX = x + width - scrollbarWidth - border;
int scrollBarY = y + border + headerHeight;
int scrollBarHeight = height - headerHeight - footerHeight - 2 * border;
if (pixmapScrollBar)
2019-11-10 15:37:28 +01:00
osdManager.DestroyPixmap(pixmapScrollBar);
pixmapScrollBar = osdManager.CreatePixmap(4, cRect(scrollBarX, scrollBarY, scrollbarWidth, scrollBarHeight));
} else
pixmapScrollBar = NULL;
}
2019-11-09 11:22:02 +01:00
void cRecMenu::AddHeader(cRecMenuItem *header) {
this->header = header;
headerHeight = header->GetHeight();
height += headerHeight;
}
void cRecMenu::AddFooter(cRecMenuItem *footer) {
this->footer = footer;
footerHeight = footer->GetHeight();
height += footerHeight;
}
void cRecMenu::ClearMenuItems(bool destructor) {
for (std::list<cRecMenuItem*>::iterator it = menuItems.begin(); it != menuItems.end(); it++) {
if (deleteMenuItems)
delete *it;
else if (!destructor)
(*it)->Hide();
}
menuItems.clear();
};
2013-07-09 00:17:42 +02:00
void cRecMenu::InitMenu(bool complete) {
currentHeight = 0;
numItems = 0;
if (scrollable) {
width -= scrollbarWidth + border;
2019-11-10 15:37:28 +01:00
osdManager.DestroyPixmap(pixmapScrollBar);
pixmapScrollBar = NULL;
DELETENULL(imgScrollBar);
2013-07-09 00:17:42 +02:00
}
2019-11-10 15:37:28 +01:00
osdManager.DestroyPixmap(pixmap);
pixmap = NULL;
for (std::list<cRecMenuItem*>::iterator it = menuItems.begin(); it != menuItems.end(); it++) {
if (deleteMenuItems)
delete *it;
else
(*it)->Hide();
}
menuItems.clear();
if (complete) {
startIndex = 0;
stopIndex = 0;
scrollable = false;
} else {
stopIndex = startIndex;
}
2013-07-09 00:17:42 +02:00
}
void cRecMenu::AddMenuItem(cRecMenuItem *item, bool inFront) {
item->Show();
if (!inFront)
menuItems.push_back(item);
else
menuItems.push_front(item);
}
bool cRecMenu::AddMenuItemInitial(cRecMenuItem *item, bool inFront) {
currentHeight += item->GetHeight();
int totalHeight = headerHeight + footerHeight + currentHeight + 2*border;
2019-06-16 14:01:22 +02:00
if (totalHeight >= geoManager.osdHeight - 80) {
scrollable = true;
currentHeight -= item->GetHeight();
if (deleteMenuItems) {
delete item;
2013-07-09 00:17:42 +02:00
}
return false;
2013-07-09 00:17:42 +02:00
}
numItems++;
if (!inFront) {
stopIndex++;
menuItems.push_back(item);
} else {
startIndex--;
menuItems.push_front(item);
}
return true;
}
void cRecMenu::Activate(cRecMenuItem *itemOld, cRecMenuItem *item) {
itemOld->setInactive();
itemOld->setBackground();
itemOld->Draw();
2019-11-10 13:54:35 +01:00
item->SetActive();
item->setBackground();
item->Draw();
2013-07-09 00:17:42 +02:00
}
bool cRecMenu::ActivatePrev(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
2019-11-10 13:52:16 +01:00
if (!scrollable && footer && footer->IsActive()) {
if (menuItems.size() > 0) {
cRecMenuItem *itemLast = menuItems.back();
Activate(footer, itemLast);
return true;
}
2013-07-09 00:17:42 +02:00
} else if (activeItem) {
cRecMenuItem *prev = NULL;
bool foundActive = false;
for (std::list<cRecMenuItem*>::iterator item = menuItems.end(); item != menuItems.begin(); ) {
item--;
if (*item == activeItem) {
foundActive = true;
continue;
}
if (!foundActive)
continue;
if ((*item)->isSelectable()) {
prev = *item;
2013-07-09 00:17:42 +02:00
break;
}
}
if (prev) {
Activate(activeItem , prev);
return true;
}
}
return false;
}
bool cRecMenu::ScrollUp(void) {
2019-11-10 13:52:16 +01:00
if (footer && footer->IsActive()) {
if (menuItems.size() > 0)
Activate(footer, menuItems.back());
2013-07-09 00:17:42 +02:00
} else {
//get perv x items
int numNewItems = numItems / 2;
int numAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(startIndex-1)) {
AddMenuItem(newItem, true);
cRecMenuItem *last = menuItems.back();
if (deleteMenuItems) {
delete last;
} else {
last->setInactive();
last->Hide();
}
menuItems.pop_back();
2013-07-09 00:17:42 +02:00
stopIndex--;
startIndex--;
numAdded++;
if (numAdded >= numNewItems)
break;
}
if (numAdded != 0) {
scrollable = true;
if (CalculateHeight(true))
CreatePixmap();
Arrange(deleteMenuItems);
Display(deleteMenuItems);
2013-07-09 00:17:42 +02:00
ActivatePrev();
} else {
return false;
2013-07-09 00:17:42 +02:00
}
}
return true;
2013-07-09 00:17:42 +02:00
}
bool cRecMenu::ActivateNext(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (activeItem) {
cRecMenuItem *next = NULL;
bool foundActive = false;
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
if (*item == activeItem) {
foundActive = true;
continue;
}
if (!foundActive)
continue;
if ((*item)->isSelectable()) {
next = *item;
break;
}
}
if (next) {
Activate(activeItem , next);
return true;
2019-11-10 13:52:16 +01:00
} else if (!scrollable && footer && footer->isSelectable() && !footer->IsActive()) {
Activate(activeItem , footer);
return true;
}
}
return false;
}
bool cRecMenu::ScrollDown(void) {
2013-07-09 00:17:42 +02:00
//get next x items
int numNewItems = numItems / 2;
int numAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(stopIndex)) {
menuItems.push_back(newItem);
cRecMenuItem *first = menuItems.front();
if (deleteMenuItems) {
delete first;
} else {
first->setInactive();
first->Hide();
}
menuItems.pop_front();
2013-07-09 00:17:42 +02:00
startIndex++;
stopIndex++;
2013-07-09 00:17:42 +02:00
numAdded++;
if (numAdded >= numNewItems)
break;
}
if (numAdded != 0) {
scrollable = true;
if (CalculateHeight(true))
CreatePixmap();
Arrange(deleteMenuItems);
Display(deleteMenuItems);
2013-07-09 00:17:42 +02:00
ActivateNext();
} else {
//last item reached, activate footer if not already active
2019-11-10 13:52:16 +01:00
if ((footer) && !(footer->IsActive())) {
2013-07-09 00:17:42 +02:00
cRecMenuItem *activeItem = GetActiveMenuItem();
Activate(activeItem , footer);
} else {
return false;
2013-07-09 00:17:42 +02:00
}
}
return true;
2013-07-09 00:17:42 +02:00
}
void cRecMenu::PageUp(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!activeItem)
return;
if (!scrollable) {
JumpBegin();
return;
}
if (footer && activeItem == footer) {
Activate(footer, menuItems.front());
return;
}
2019-11-10 13:24:22 +01:00
int newActive = GetNumActive() - numItems;
if (newActive < 0)
newActive = 0;
activeItem->setInactive();
activeItem->setBackground();
ClearMenuItems();
currentHeight = 0;
stopIndex = startIndex;
numItems = 0;
cRecMenuItem *newItem = NULL;
bool spaceLeft = true;
while (newItem = GetMenuItem(startIndex-1)) {
if (startIndex-1 == newActive)
2019-11-10 13:54:35 +01:00
newItem->SetActive();
spaceLeft = AddMenuItemInitial(newItem, true);
if (!spaceLeft)
break;
}
if (spaceLeft) {
while (newItem = GetMenuItem(stopIndex)) {
spaceLeft = AddMenuItemInitial(newItem);
if (!spaceLeft)
break;
}
}
2019-11-10 13:24:22 +01:00
if (GetNumActive() == numItems)
2019-11-10 13:54:35 +01:00
menuItems.front()->SetActive();
if (CalculateHeight(true))
CreatePixmap();
Arrange(deleteMenuItems);
Display(deleteMenuItems);
}
void cRecMenu::PageDown(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!activeItem)
return;
if (footer && activeItem == footer) {
return;
}
if (!scrollable) {
JumpEnd();
return;
}
2019-11-10 13:24:22 +01:00
int newActive = GetNumActive() + numItems;
activeItem->setInactive();
activeItem->setBackground();
ClearMenuItems();
currentHeight = 0;
numItems = 0;
startIndex = stopIndex;
cRecMenuItem *newItem = NULL;
bool spaceLeft = true;
while (newItem = GetMenuItem(stopIndex)) {
if (stopIndex == newActive)
2019-11-10 13:54:35 +01:00
newItem->SetActive();
spaceLeft = AddMenuItemInitial(newItem);
if (!spaceLeft)
break;
}
if (spaceLeft) {
while (newItem = GetMenuItem(startIndex-1)) {
spaceLeft = AddMenuItemInitial(newItem, true);
if (!spaceLeft)
break;
}
}
2019-11-10 13:24:22 +01:00
if (GetNumActive() == GetTotalNumMenuItems())
2019-11-10 13:54:35 +01:00
menuItems.back()->SetActive();
if (CalculateHeight(true))
CreatePixmap();
Arrange(deleteMenuItems);
Display(deleteMenuItems);
}
2013-07-09 00:17:42 +02:00
void cRecMenu::JumpBegin(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!scrollable) {
cRecMenuItem *firstSelectable= NULL;
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
if ((*item)->isSelectable()) {
firstSelectable = *item;
2013-07-09 00:17:42 +02:00
break;
}
}
if (activeItem && firstSelectable) {
Activate(activeItem , firstSelectable);
}
} else {
activeItem->setInactive();
activeItem->setBackground();
if (footer)
footer->Draw();
ClearMenuItems();
2013-07-09 00:17:42 +02:00
int currentItem = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(currentItem)) {
AddMenuItem(newItem);
currentItem++;
if (currentItem >= numItems)
break;
}
2019-06-16 14:01:22 +02:00
if (CalculateHeight(true))
CreatePixmap();
Arrange(false);
2013-07-09 00:17:42 +02:00
startIndex = 0;
2020-03-05 15:18:48 +01:00
stopIndex = currentItem;
cRecMenuItem *first = menuItems.front();
2019-11-10 13:54:35 +01:00
first->SetActive();
first->setBackground();
first->Draw();
2019-06-16 14:01:22 +02:00
Display(false);
2013-07-09 00:17:42 +02:00
}
}
void cRecMenu::JumpEnd(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!activeItem)
return;
if (!scrollable) {
cRecMenuItem *lastSelectable= NULL;
if (footer && footer->isSelectable()) {
lastSelectable = footer;
} else {
for (std::list<cRecMenuItem*>::iterator item = menuItems.end(); item != menuItems.begin(); ) {
item--;
if ((*item)->isSelectable()) {
lastSelectable = *item;
2013-07-09 00:17:42 +02:00
break;
}
}
}
if (lastSelectable) {
Activate(activeItem , lastSelectable);
}
} else {
activeItem->setInactive();
activeItem->setBackground();
ClearMenuItems();
2013-07-09 00:17:42 +02:00
int totalNumItems = GetTotalNumMenuItems();
2019-06-16 14:01:22 +02:00
int currentItem = totalNumItems - 1;
2013-07-09 00:17:42 +02:00
int itemsAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(currentItem)) {
AddMenuItem(newItem, true);
2013-07-09 00:17:42 +02:00
currentItem--;
itemsAdded++;
if (itemsAdded >= numItems)
break;
}
2019-06-16 14:01:22 +02:00
if (CalculateHeight(true))
CreatePixmap();
Arrange(false);
2013-07-09 00:17:42 +02:00
stopIndex = totalNumItems;
startIndex = stopIndex - numItems;
if (footer) {
2019-11-10 13:54:35 +01:00
footer->SetActive();
2013-07-09 00:17:42 +02:00
footer->setBackground();
footer->Draw();
} else {
cRecMenuItem *last = menuItems.back();
2019-11-10 13:54:35 +01:00
last->SetActive();
last->setBackground();
last->Draw();
2013-07-09 00:17:42 +02:00
}
2019-06-16 14:01:22 +02:00
Display(false);
2013-07-09 00:17:42 +02:00
}
}
void cRecMenu::Arrange(bool scroll) {
int xElement = x + border;
int yElement = y + border;
int widthElement = width - 2 * border;
if (scrollable)
widthElement -= scrollbarWidth + border;
if (header) {
if (!scroll) {
header->SetGeometry(xElement, yElement, widthElement);
header->SetPixmaps();
header->setBackground();
2013-07-09 00:17:42 +02:00
}
yElement += header->GetHeight();
}
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
(*item)->SetGeometry(xElement, yElement, widthElement);
(*item)->SetPixmaps();
yElement += (*item)->GetHeight();
2013-07-09 00:17:42 +02:00
}
if (footer && !scroll) {
footer->SetGeometry(xElement, yElement, widthElement);
footer->SetPixmaps();
footer->setBackground();
2013-07-09 00:17:42 +02:00
}
}
void cRecMenu::Display(bool scroll) {
2019-07-11 11:28:11 +02:00
if (config.style == eStyleGraphical) {
2013-12-21 11:25:03 +01:00
drawBackgroundGraphical(bgRecMenuBack);
} else {
pixmap->Fill(theme.Color(clrBackground));
drawBorder();
}
2013-07-09 00:17:42 +02:00
if (header && !scroll) {
header->setBackground();
header->Draw();
}
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
(*item)->setBackground();
(*item)->Show();
(*item)->Draw();
2013-07-09 00:17:42 +02:00
}
if (footer && !scroll) {
footer->setBackground();
footer->Draw();
}
if (scrollable)
DrawScrollBar();
}
void cRecMenu::Hide(void) {
pixmap->SetLayer(-1);
if (pixmapScrollBar)
pixmapScrollBar->SetLayer(-1);
if (header)
header->Hide();
if (footer)
footer->Hide();
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
(*item)->Hide();
2013-07-09 00:17:42 +02:00
}
}
void cRecMenu::Show(void) {
pixmap->SetLayer(3);
if (pixmapScrollBar)
pixmapScrollBar->SetLayer(3);
if (header)
header->Show();
if (footer)
footer->Show();
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
(*item)->Show();
2013-07-09 00:17:42 +02:00
}
}
void cRecMenu::UpdateActiveMenuItem(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (activeItem)
activeItem->Draw();
}
2013-07-09 00:17:42 +02:00
void cRecMenu::DrawScrollBar(void) {
if (!pixmapScrollBar)
return;
2013-07-09 00:17:42 +02:00
pixmapScrollBar->Fill(theme.Color(clrBorder));
pixmapScrollBar->DrawRectangle(cRect(2, 2, pixmapScrollBar->ViewPort().Width() - 4, pixmapScrollBar->ViewPort().Height() - 4), theme.Color(clrBackground));
2013-07-09 00:17:42 +02:00
int totalNumItems = GetTotalNumMenuItems();
if (!totalNumItems)
return;
if (!imgScrollBar) {
2013-07-09 00:17:42 +02:00
int scrollBarImgHeight = (pixmapScrollBar->ViewPort().Height() - 8) * numItems / totalNumItems;
imgScrollBar = createScrollbar(pixmapScrollBar->ViewPort().Width() - 8, scrollBarImgHeight, theme.Color(clrHighlight), theme.Color(clrHighlightBlending));
2013-07-09 00:17:42 +02:00
}
int offset = (pixmapScrollBar->ViewPort().Height() - 8) * startIndex / totalNumItems;
pixmapScrollBar->DrawImage(cPoint(4, 2 + offset), *imgScrollBar);
}
cRecMenuItem *cRecMenu::GetActiveMenuItem(void) {
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
2019-11-10 13:52:16 +01:00
if ((*item)->IsActive())
return *item;
2013-07-09 00:17:42 +02:00
}
2019-11-10 13:52:16 +01:00
if (footer && footer->IsActive())
return footer;
return NULL;
2013-07-09 00:17:42 +02:00
}
cRecMenuItem *cRecMenu::GetMenuItemAt(int num) {
int current = 0;
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
if (current == num)
return *item;
current++;
2013-07-09 00:17:42 +02:00
}
return NULL;
}
2019-11-10 13:24:22 +01:00
int cRecMenu::GetNumActive(void) {
int numActive = startIndex;
for (std::list<cRecMenuItem*>::iterator item = menuItems.begin(); item != menuItems.end(); item++) {
2019-11-10 13:52:16 +01:00
if ((*item)->IsActive()) {
break;
}
numActive++;
2014-01-03 11:56:45 +01:00
}
return numActive;
2014-01-03 11:56:45 +01:00
}
2013-07-09 00:17:42 +02:00
eRecMenuState cRecMenu::ProcessKey(eKeys Key) {
cRecMenuItem *activeItem = GetActiveMenuItem();
eRecMenuState state = rmsContinue;
if (!activeItem)
return state;
state = activeItem->ProcessKey(Key);
if (state == rmsRefresh) {
CreateMenuItems();
Display();
} else if (state == rmsNotConsumed) {
switch (Key & ~k_Repeat) {
case kUp:
if (!ActivatePrev())
if (!ScrollUp())
JumpEnd();
state = rmsConsumed;
2013-07-09 00:17:42 +02:00
break;
case kDown:
if (!ActivateNext())
if (!ScrollDown())
JumpBegin();
state = rmsConsumed;
2013-07-09 00:17:42 +02:00
break;
case kLeft:
PageUp();
2013-07-09 00:17:42 +02:00
state = rmsConsumed;
break;
case kRight:
PageDown();
2013-07-09 00:17:42 +02:00
state = rmsConsumed;
break;
default:
break;
}
}
return state;
}
cImage *cRecMenu::createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend) {
cImage *image = new cImage(cSize(width, height));
image->Fill(clrBgr);
if (height >= 32 && config.style != eStyleFlat) {
2013-07-09 00:17:42 +02:00
int numSteps = 64;
int alphaStep = 0x03;
if (height < 100) {
2013-07-09 00:17:42 +02:00
numSteps = 32;
alphaStep = 0x06;
}
int stepY = std::max(1, (int)(0.5 * height / numSteps));
2013-07-09 00:17:42 +02:00
int alpha = 0x40;
tColor clr;
for (int i = 0; i < numSteps; i++) {
2013-07-09 00:17:42 +02:00
clr = AlphaBlend(clrBgr, clrBlend, alpha);
for (int y = i * stepY; y < (i + 1) * stepY; y++) {
for (int x = 0; x < width; x++) {
image->SetPixel(cPoint(x, y), clr);
2013-07-09 00:17:42 +02:00
}
}
alpha += alphaStep;
}
}
return image;
2019-06-16 14:01:22 +02:00
}