mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
Implemented 'skins' and 'themes'
This commit is contained in:
833
osdbase.c
833
osdbase.c
@@ -4,495 +4,410 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: osdbase.c 1.12 2004/01/31 10:31:13 kls Exp $
|
||||
* $Id: osdbase.c 1.13 2004/05/01 10:51:43 kls Exp $
|
||||
*/
|
||||
|
||||
#include "osdbase.h"
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/unistd.h>
|
||||
#include "tools.h"
|
||||
#include <string.h>
|
||||
#include "device.h"
|
||||
#include "i18n.h"
|
||||
#include "remote.h"
|
||||
#include "status.h"
|
||||
|
||||
// --- cPalette --------------------------------------------------------------
|
||||
// --- cOsdItem --------------------------------------------------------------
|
||||
|
||||
cPalette::cPalette(int Bpp)
|
||||
cOsdItem::cOsdItem(eOSState State)
|
||||
{
|
||||
maxColors = 1 << Bpp;
|
||||
numColors = 0;
|
||||
full = false;
|
||||
text = NULL;
|
||||
offset = -1;
|
||||
state = State;
|
||||
selectable = true;
|
||||
fresh = true;
|
||||
}
|
||||
|
||||
void cPalette::SetColor(int Index, eDvbColor Color)
|
||||
cOsdItem::cOsdItem(const char *Text, eOSState State)
|
||||
{
|
||||
if (Index < maxColors) {
|
||||
if (numColors < Index)
|
||||
numColors = Index + 1;
|
||||
used[Index] = true;
|
||||
color[Index] = Color;
|
||||
fetched[Index] = false;
|
||||
text = NULL;
|
||||
offset = -1;
|
||||
state = State;
|
||||
selectable = true;
|
||||
fresh = true;
|
||||
SetText(Text);
|
||||
}
|
||||
|
||||
cOsdItem::~cOsdItem()
|
||||
{
|
||||
free(text);
|
||||
}
|
||||
|
||||
void cOsdItem::SetText(const char *Text, bool Copy)
|
||||
{
|
||||
free(text);
|
||||
text = Copy ? strdup(Text) : (char *)Text; // text assumes ownership!
|
||||
}
|
||||
|
||||
void cOsdItem::SetSelectable(bool Selectable)
|
||||
{
|
||||
selectable = Selectable;
|
||||
}
|
||||
|
||||
void cOsdItem::SetFresh(bool Fresh)
|
||||
{
|
||||
fresh = Fresh;
|
||||
}
|
||||
|
||||
eOSState cOsdItem::ProcessKey(eKeys Key)
|
||||
{
|
||||
return Key == kOk ? state : osUnknown;
|
||||
}
|
||||
|
||||
// --- cOsdMenu --------------------------------------------------------------
|
||||
|
||||
cSkinDisplayMenu *cOsdMenu::displayMenu = NULL;
|
||||
int cOsdMenu::displayMenuCount = 0;
|
||||
int cOsdMenu::displayMenuItems = 0;//XXX dynamic???
|
||||
|
||||
cOsdMenu::cOsdMenu(const char *Title, int c0, int c1, int c2, int c3, int c4)
|
||||
{
|
||||
isMenu = true;
|
||||
digit = 0;
|
||||
hasHotkeys = false;
|
||||
title = NULL;
|
||||
SetTitle(Title);
|
||||
cols[0] = c0;
|
||||
cols[1] = c1;
|
||||
cols[2] = c2;
|
||||
cols[3] = c3;
|
||||
cols[4] = c4;
|
||||
first = 0;
|
||||
current = marked = -1;
|
||||
subMenu = NULL;
|
||||
helpRed = helpGreen = helpYellow = helpBlue = NULL;
|
||||
status = NULL;
|
||||
if (!displayMenuCount++) {
|
||||
displayMenu = Skins.Current()->DisplayMenu();
|
||||
displayMenuItems = displayMenu->MaxItems();
|
||||
}
|
||||
}
|
||||
|
||||
int cPalette::Index(eDvbColor Color)
|
||||
cOsdMenu::~cOsdMenu()
|
||||
{
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
Color = eDvbColor(((Color & 0xFF) << 24) | ((Color & 0xFF00) << 8) | ((Color & 0xFF0000) >> 8) | ((Color & 0xFF000000) >> 24));
|
||||
#endif
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
if (color[i] == Color) {
|
||||
used[i] = true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (!full) {
|
||||
if (numColors < maxColors) {
|
||||
color[numColors++] = Color;
|
||||
used[numColors - 1] = true;
|
||||
fetched[numColors - 1] = false;
|
||||
return numColors - 1;
|
||||
free(title);
|
||||
delete subMenu;
|
||||
free(status);
|
||||
displayMenu->Clear();
|
||||
cStatus::MsgOsdClear();
|
||||
if (!--displayMenuCount)
|
||||
DELETENULL(displayMenu);
|
||||
}
|
||||
|
||||
const char *cOsdMenu::hk(const char *s)
|
||||
{
|
||||
static char buffer[64];
|
||||
if (s && hasHotkeys) {
|
||||
if (digit == 0 && '1' <= *s && *s <= '9' && *(s + 1) == ' ')
|
||||
digit = -1; // prevents automatic hotkeys - input already has them
|
||||
if (digit >= 0) {
|
||||
digit++;
|
||||
snprintf(buffer, sizeof(buffer), " %c %s", (digit < 10) ? '0' + digit : ' ' , s);
|
||||
s = buffer;
|
||||
}
|
||||
for (int i = maxColors; --i >= 0; ) {
|
||||
if (!used[i]) {
|
||||
color[i] = Color;
|
||||
used[i] = true;
|
||||
fetched[i] = false;
|
||||
return i;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void cOsdMenu::SetHasHotkeys(void)
|
||||
{
|
||||
hasHotkeys = true;
|
||||
digit = 0;
|
||||
}
|
||||
|
||||
void cOsdMenu::SetStatus(const char *s)
|
||||
{
|
||||
free(status);
|
||||
status = s ? strdup(s) : NULL;
|
||||
displayMenu->SetMessage(mtStatus, s);
|
||||
}
|
||||
|
||||
void cOsdMenu::SetTitle(const char *Title)
|
||||
{
|
||||
free(title);
|
||||
title = strdup(Title);
|
||||
}
|
||||
|
||||
void cOsdMenu::SetHelp(const char *Red, const char *Green, const char *Yellow, const char *Blue)
|
||||
{
|
||||
// strings are NOT copied - must be constants!!!
|
||||
helpRed = Red;
|
||||
helpGreen = Green;
|
||||
helpYellow = Yellow;
|
||||
helpBlue = Blue;
|
||||
displayMenu->SetButtons(helpRed, helpGreen, helpYellow, helpBlue);
|
||||
cStatus::MsgOsdHelpKeys(helpRed, helpGreen, helpYellow, helpBlue);
|
||||
}
|
||||
|
||||
void cOsdMenu::Del(int Index)
|
||||
{
|
||||
cList<cOsdItem>::Del(Get(Index));
|
||||
if (current == Count())
|
||||
current--;
|
||||
if (Index == first && first > 0)
|
||||
first--;
|
||||
}
|
||||
|
||||
void cOsdMenu::Add(cOsdItem *Item, bool Current, cOsdItem *After)
|
||||
{
|
||||
cList<cOsdItem>::Add(Item, After);
|
||||
if (Current)
|
||||
current = Item->Index();
|
||||
}
|
||||
|
||||
void cOsdMenu::Ins(cOsdItem *Item, bool Current, cOsdItem *Before)
|
||||
{
|
||||
cList<cOsdItem>::Ins(Item, Before);
|
||||
if (Current)
|
||||
current = Item->Index();
|
||||
}
|
||||
|
||||
void cOsdMenu::Display(void)
|
||||
{
|
||||
if (subMenu) {
|
||||
subMenu->Display();
|
||||
return;
|
||||
}
|
||||
displayMenu->Clear();
|
||||
cStatus::MsgOsdClear();
|
||||
displayMenu->SetTabs(cols[0], cols[1], cols[2], cols[3], cols[4]);//XXX
|
||||
displayMenu->SetTitle(title);
|
||||
cStatus::MsgOsdTitle(title);
|
||||
displayMenu->SetButtons(helpRed, helpGreen, helpYellow, helpBlue);
|
||||
cStatus::MsgOsdHelpKeys(helpRed, helpGreen, helpYellow, helpBlue);
|
||||
int count = Count();
|
||||
if (count > 0) {
|
||||
int ni = 0;
|
||||
for (cOsdItem *item = First(); item; item = Next(item))
|
||||
cStatus::MsgOsdItem(item->Text(), ni++);
|
||||
if (current < 0)
|
||||
current = 0; // just for safety - there HAS to be a current item!
|
||||
if (current - first >= displayMenuItems || current < first) {
|
||||
first = current - displayMenuItems / 2;
|
||||
if (first + displayMenuItems > count)
|
||||
first = count - displayMenuItems;
|
||||
if (first < 0)
|
||||
first = 0;
|
||||
}
|
||||
int i = first;
|
||||
int n = 0;
|
||||
for (cOsdItem *item = Get(first); item; item = Next(item)) {
|
||||
displayMenu->SetItem(item->Text(), i - first, i == current, item->Selectable());
|
||||
if (i == current)
|
||||
cStatus::MsgOsdCurrentItem(item->Text());
|
||||
if (++n == displayMenuItems)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (!isempty(status))
|
||||
displayMenu->SetMessage(mtStatus, status);
|
||||
}
|
||||
|
||||
void cOsdMenu::SetCurrent(cOsdItem *Item)
|
||||
{
|
||||
current = Item ? Item->Index() : -1;
|
||||
}
|
||||
|
||||
void cOsdMenu::RefreshCurrent(void)
|
||||
{
|
||||
cOsdItem *item = Get(current);
|
||||
if (item)
|
||||
item->Set();
|
||||
}
|
||||
|
||||
void cOsdMenu::DisplayCurrent(bool Current)
|
||||
{
|
||||
cOsdItem *item = Get(current);
|
||||
if (item) {
|
||||
displayMenu->SetItem(item->Text(), current - first, Current, item->Selectable());
|
||||
if (Current)
|
||||
cStatus::MsgOsdCurrentItem(item->Text());
|
||||
if (!Current)
|
||||
item->SetFresh(true); // leaving the current item resets 'fresh'
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdMenu::Clear(void)
|
||||
{
|
||||
first = 0;
|
||||
current = marked = -1;
|
||||
cList<cOsdItem>::Clear();
|
||||
}
|
||||
|
||||
bool cOsdMenu::SelectableItem(int idx)
|
||||
{
|
||||
cOsdItem *item = Get(idx);
|
||||
return item && item->Selectable();
|
||||
}
|
||||
|
||||
void cOsdMenu::CursorUp(void)
|
||||
{
|
||||
if (current > 0) {
|
||||
int tmpCurrent = current;
|
||||
while (--tmpCurrent >= 0 && !SelectableItem(tmpCurrent));
|
||||
if (tmpCurrent < 0)
|
||||
return;
|
||||
if (tmpCurrent >= first)
|
||||
DisplayCurrent(false);
|
||||
current = tmpCurrent;
|
||||
if (current < first) {
|
||||
first = first > displayMenuItems - 1 ? first - (displayMenuItems - 1) : 0;
|
||||
if (Setup.MenuScrollPage)
|
||||
current = !SelectableItem(first) ? first + 1 : first;
|
||||
Display();
|
||||
}
|
||||
else
|
||||
DisplayCurrent(true);
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdMenu::CursorDown(void)
|
||||
{
|
||||
int last = Count() - 1;
|
||||
int lastOnScreen = first + displayMenuItems - 1;
|
||||
|
||||
if (current < last) {
|
||||
int tmpCurrent = current;
|
||||
while (++tmpCurrent <= last && !SelectableItem(tmpCurrent));
|
||||
if (tmpCurrent > last)
|
||||
return;
|
||||
if (tmpCurrent <= lastOnScreen)
|
||||
DisplayCurrent(false);
|
||||
current = tmpCurrent;
|
||||
if (current > lastOnScreen) {
|
||||
first += displayMenuItems - 1;
|
||||
lastOnScreen = first + displayMenuItems - 1;
|
||||
if (lastOnScreen > last) {
|
||||
first = last - (displayMenuItems - 1);
|
||||
lastOnScreen = last;
|
||||
}
|
||||
if (Setup.MenuScrollPage)
|
||||
current = !SelectableItem(lastOnScreen) ? lastOnScreen - 1 : lastOnScreen;
|
||||
Display();
|
||||
}
|
||||
else
|
||||
DisplayCurrent(true);
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdMenu::PageUp(void)
|
||||
{
|
||||
current -= displayMenuItems;
|
||||
first -= displayMenuItems;
|
||||
if (first < 0)
|
||||
first = current = 0;
|
||||
if (!SelectableItem(current)) {
|
||||
current -= (current > 0) ? 1 : -1;
|
||||
first = min(first, current - 1);
|
||||
}
|
||||
Display();
|
||||
DisplayCurrent(true);
|
||||
}
|
||||
|
||||
void cOsdMenu::PageDown(void)
|
||||
{
|
||||
current += displayMenuItems;
|
||||
first += displayMenuItems;
|
||||
int count = Count();
|
||||
if (current > count - 1) {
|
||||
current = count - 1;
|
||||
first = max(0, count - displayMenuItems);
|
||||
}
|
||||
if (!SelectableItem(current)) {
|
||||
current += (current < count - 1) ? 1 : -1;
|
||||
first = max(first, current - displayMenuItems);
|
||||
}
|
||||
Display();
|
||||
DisplayCurrent(true);
|
||||
}
|
||||
|
||||
void cOsdMenu::Mark(void)
|
||||
{
|
||||
if (Count() && marked < 0) {
|
||||
marked = current;
|
||||
SetStatus(tr("Up/Dn for new location - OK to move"));
|
||||
}
|
||||
}
|
||||
|
||||
eOSState cOsdMenu::HotKey(eKeys Key)
|
||||
{
|
||||
for (cOsdItem *item = First(); item; item = Next(item)) {
|
||||
const char *s = item->Text();
|
||||
if (s && (s = skipspace(s)) != NULL) {
|
||||
if (*s == Key - k1 + '1') {
|
||||
current = item->Index();
|
||||
cRemote::Put(kOk, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
esyslog("ERROR: too many different colors used in palette");
|
||||
full = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cPalette::Reset(void)
|
||||
{
|
||||
for (int i = 0; i < numColors; i++)
|
||||
used[i] = fetched[i] = false;
|
||||
full = false;
|
||||
}
|
||||
|
||||
const eDvbColor *cPalette::NewColors(int &FirstColor, int &LastColor)
|
||||
{
|
||||
for (FirstColor = 0; FirstColor < numColors; FirstColor++) {
|
||||
if (!fetched[FirstColor]) {
|
||||
for (LastColor = FirstColor; LastColor < numColors && !fetched[LastColor]; LastColor++)
|
||||
fetched[LastColor] = true;
|
||||
LastColor--; // the loop ended one past the last one!
|
||||
return &color[FirstColor];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
const eDvbColor *cPalette::AllColors(int &NumColors)
|
||||
eOSState cOsdMenu::AddSubMenu(cOsdMenu *SubMenu)
|
||||
{
|
||||
NumColors = numColors;
|
||||
return numColors ? color : NULL;
|
||||
delete subMenu;
|
||||
subMenu = SubMenu;
|
||||
subMenu->Display();
|
||||
return osContinue; // convenience return value
|
||||
}
|
||||
|
||||
void cPalette::Take(const cPalette &Palette, tIndexes *Indexes)
|
||||
eOSState cOsdMenu::CloseSubMenu()
|
||||
{
|
||||
for (int i = 0; i < Palette.numColors; i++) {
|
||||
if (Palette.used[i]) {
|
||||
int n = Index(Palette.color[i]);
|
||||
if (Indexes)
|
||||
(*Indexes)[i] = n;
|
||||
}
|
||||
}
|
||||
delete subMenu;
|
||||
subMenu = NULL;
|
||||
RefreshCurrent();
|
||||
Display();
|
||||
return osContinue; // convenience return value
|
||||
}
|
||||
|
||||
// --- cBitmap ---------------------------------------------------------------
|
||||
|
||||
cBitmap::cBitmap(int Width, int Height, int Bpp, bool ClearWithBackground)
|
||||
:cPalette(Bpp)
|
||||
eOSState cOsdMenu::ProcessKey(eKeys Key)
|
||||
{
|
||||
width = Width;
|
||||
height = Height;
|
||||
clearWithBackground = ClearWithBackground;
|
||||
bitmap = NULL;
|
||||
fontType = fontOsd;
|
||||
font = NULL;
|
||||
if (width > 0 && height > 0) {
|
||||
bitmap = MALLOC(u_char, width * height);
|
||||
if (bitmap) {
|
||||
Clean();
|
||||
memset(bitmap, 0x00, width * height);
|
||||
SetFont(fontOsd);
|
||||
}
|
||||
else
|
||||
esyslog("ERROR: can't allocate bitmap!");
|
||||
if (subMenu) {
|
||||
eOSState state = subMenu->ProcessKey(Key);
|
||||
if (state == osBack)
|
||||
return CloseSubMenu();
|
||||
return state;
|
||||
}
|
||||
else
|
||||
esyslog("ERROR: illegal bitmap parameters (%d, %d)!", width, height);
|
||||
}
|
||||
|
||||
cBitmap::~cBitmap()
|
||||
{
|
||||
free(bitmap);
|
||||
}
|
||||
|
||||
eDvbFont cBitmap::SetFont(eDvbFont Font)
|
||||
{
|
||||
eDvbFont oldFont = fontType;
|
||||
if (fontType != Font || !font) {
|
||||
font = cFont::GetFont(Font);
|
||||
fontType = Font;
|
||||
}
|
||||
return oldFont;
|
||||
}
|
||||
|
||||
bool cBitmap::Dirty(int &x1, int &y1, int &x2, int &y2)
|
||||
{
|
||||
if (dirtyX2 >= 0) {
|
||||
//XXX Workaround: apparently the bitmap sent to the driver always has to be a multiple
|
||||
//XXX of 8 bits wide, and (dx * dy) also has to be a multiple of 8.
|
||||
//TODO Fix driver (should be able to handle any size bitmaps!)
|
||||
while ((dirtyX1 > 0 || dirtyX2 < width - 1) && ((dirtyX2 - dirtyX1) & 7) != 7) {
|
||||
if (dirtyX2 < width - 1)
|
||||
dirtyX2++;
|
||||
else if (dirtyX1 > 0)
|
||||
dirtyX1--;
|
||||
}
|
||||
//XXX "... / 2" <==> Bpp???
|
||||
while ((dirtyY1 > 0 || dirtyY2 < height - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) {
|
||||
if (dirtyY2 < height - 1)
|
||||
dirtyY2++;
|
||||
else if (dirtyY1 > 0)
|
||||
dirtyY1--;
|
||||
}
|
||||
while ((dirtyX1 > 0 || dirtyX2 < width - 1) && (((dirtyX2 - dirtyX1 + 1) * (dirtyY2 - dirtyY1 + 1) / 2) & 7) != 0) {
|
||||
if (dirtyX2 < width - 1)
|
||||
dirtyX2++;
|
||||
else if (dirtyX1 > 0)
|
||||
dirtyX1--;
|
||||
}
|
||||
x1 = dirtyX1;
|
||||
y1 = dirtyY1;
|
||||
x2 = dirtyX2;
|
||||
y2 = dirtyY2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cBitmap::Clean(void)
|
||||
{
|
||||
dirtyX1 = width;
|
||||
dirtyY1 = height;
|
||||
dirtyX2 = -1;
|
||||
dirtyY2 = -1;
|
||||
}
|
||||
|
||||
void cBitmap::SetIndex(int x, int y, u_char Index)
|
||||
{
|
||||
if (bitmap) {
|
||||
if (0 <= x && x < width && 0 <= y && y < height) {
|
||||
if (bitmap[width * y + x] != Index) {
|
||||
bitmap[width * y + x] = Index;
|
||||
if (dirtyX1 > x) dirtyX1 = x;
|
||||
if (dirtyY1 > y) dirtyY1 = y;
|
||||
if (dirtyX2 < x) dirtyX2 = x;
|
||||
if (dirtyY2 < y) dirtyY2 = y;
|
||||
}
|
||||
cOsdItem *item = Get(current);
|
||||
if (marked < 0 && item) {
|
||||
eOSState state = item->ProcessKey(Key);
|
||||
if (state != osUnknown) {
|
||||
DisplayCurrent(true);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cBitmap::SetPixel(int x, int y, eDvbColor Color)
|
||||
{
|
||||
SetIndex(x, y, Index(Color));
|
||||
}
|
||||
|
||||
void cBitmap::SetBitmap(int x, int y, const cBitmap &Bitmap)
|
||||
{
|
||||
if (bitmap && Bitmap.bitmap) {
|
||||
tIndexes Indexes;
|
||||
Take(Bitmap, &Indexes);
|
||||
for (int ix = 0; ix < Bitmap.width; ix++) {
|
||||
for (int iy = 0; iy < Bitmap.height; iy++)
|
||||
SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cBitmap::Width(unsigned char c)
|
||||
{
|
||||
return font ? font->Width(c) : -1;
|
||||
}
|
||||
|
||||
int cBitmap::Width(const char *s)
|
||||
{
|
||||
return font ? font->Width(s) : -1;
|
||||
}
|
||||
|
||||
void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg)
|
||||
{
|
||||
if (bitmap) {
|
||||
u_char fg = Index(ColorFg);
|
||||
u_char bg = Index(ColorBg);
|
||||
int h = font->Height(s);
|
||||
while (s && *s) {
|
||||
const cFont::tCharData *CharData = font->CharData(*s++);
|
||||
if (int(x + CharData->width) > width)
|
||||
break;
|
||||
for (int row = 0; row < h; row++) {
|
||||
cFont::tPixelData PixelData = CharData->lines[row];
|
||||
for (int col = CharData->width; col-- > 0; ) {
|
||||
SetIndex(x + col, y + row, (PixelData & 1) ? fg : bg);
|
||||
PixelData >>= 1;
|
||||
switch (Key) {
|
||||
case k1...k9: return hasHotkeys ? HotKey(Key) : osUnknown;
|
||||
case kUp|k_Repeat:
|
||||
case kUp: CursorUp(); break;
|
||||
case kDown|k_Repeat:
|
||||
case kDown: CursorDown(); break;
|
||||
case kLeft|k_Repeat:
|
||||
case kLeft: PageUp(); break;
|
||||
case kRight|k_Repeat:
|
||||
case kRight: PageDown(); break;
|
||||
case kBack: return osBack;
|
||||
case kOk: if (marked >= 0) {
|
||||
SetStatus(NULL);
|
||||
if (marked != current)
|
||||
Move(marked, current);
|
||||
marked = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
x += CharData->width;
|
||||
}
|
||||
}
|
||||
// else run into default
|
||||
default: if (marked < 0)
|
||||
return osUnknown;
|
||||
}
|
||||
return osContinue;
|
||||
}
|
||||
|
||||
void cBitmap::Fill(int x1, int y1, int x2, int y2, eDvbColor Color)
|
||||
{
|
||||
if (bitmap) {
|
||||
u_char c = Index(Color);
|
||||
for (int y = y1; y <= y2; y++)
|
||||
for (int x = x1; x <= x2; x++)
|
||||
SetIndex(x, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
void cBitmap::Clear(void)
|
||||
{
|
||||
Reset();
|
||||
if (clearWithBackground)
|
||||
Fill(0, 0, width - 1, height - 1, clrBackground);
|
||||
}
|
||||
|
||||
const u_char *cBitmap::Data(int x, int y)
|
||||
{
|
||||
return &bitmap[y * width + x];
|
||||
}
|
||||
|
||||
// --- cWindow ---------------------------------------------------------------
|
||||
|
||||
cWindow::cWindow(int Handle, int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled)
|
||||
:cBitmap(w, h, Bpp, ClearWithBackground)
|
||||
{
|
||||
handle = Handle;
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
bpp = Bpp;
|
||||
tiled = Tiled;
|
||||
shown = false;
|
||||
}
|
||||
|
||||
bool cWindow::Contains(int x, int y)
|
||||
{
|
||||
x -= x0;
|
||||
y -= y0;
|
||||
return x >= 0 && y >= 0 && x < width && y < height;
|
||||
}
|
||||
|
||||
void cWindow::Relocate(int x, int y)
|
||||
{
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
}
|
||||
|
||||
void cWindow::Fill(int x1, int y1, int x2, int y2, eDvbColor Color)
|
||||
{
|
||||
if (tiled) {
|
||||
x1 -= x0;
|
||||
y1 -= y0;
|
||||
x2 -= x0;
|
||||
y2 -= y0;
|
||||
}
|
||||
cBitmap::Fill(x1, y1, x2, y2, Color);
|
||||
}
|
||||
|
||||
void cWindow::SetBitmap(int x, int y, const cBitmap &Bitmap)
|
||||
{
|
||||
if (tiled) {
|
||||
x -= x0;
|
||||
y -= y0;
|
||||
}
|
||||
cBitmap::SetBitmap(x, y, Bitmap);
|
||||
}
|
||||
|
||||
void cWindow::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg)
|
||||
{
|
||||
if (tiled) {
|
||||
x -= x0;
|
||||
y -= y0;
|
||||
}
|
||||
cBitmap::Text(x, y, s, ColorFg, ColorBg);
|
||||
}
|
||||
|
||||
const u_char *cWindow::Data(int x, int y)
|
||||
{
|
||||
return cBitmap::Data(x, y);
|
||||
}
|
||||
|
||||
// --- cOsdBase --------------------------------------------------------------
|
||||
|
||||
cOsdBase::cOsdBase(int x, int y)
|
||||
{
|
||||
numWindows = 0;
|
||||
x0 = x;
|
||||
y0 = y;
|
||||
}
|
||||
|
||||
cOsdBase::~cOsdBase()
|
||||
{
|
||||
for (int i = 0; i < numWindows; i++)
|
||||
delete window[i];
|
||||
}
|
||||
|
||||
tWindowHandle cOsdBase::Create(int x, int y, int w, int h, int Bpp, bool ClearWithBackground, bool Tiled)
|
||||
{
|
||||
if (numWindows < MAXNUMWINDOWS) {
|
||||
if (x >= 0 && y >= 0 && w > 0 && h > 0 && (Bpp == 1 || Bpp == 2 || Bpp == 4 || Bpp == 8)) {
|
||||
if ((w & 0x03) != 0) {
|
||||
w += 4 - (w & 0x03);
|
||||
dsyslog("OSD window width must be a multiple of 4 - increasing to %d", w);
|
||||
}
|
||||
cWindow *win = new cWindow(numWindows, x, y, w, h, Bpp, ClearWithBackground, Tiled);
|
||||
if (OpenWindow(win)) {
|
||||
window[win->Handle()] = win;
|
||||
numWindows++;
|
||||
return win->Handle();
|
||||
}
|
||||
else
|
||||
delete win;
|
||||
}
|
||||
else
|
||||
esyslog("ERROR: illegal OSD parameters");
|
||||
}
|
||||
else
|
||||
esyslog("ERROR: too many OSD windows");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cOsdBase::AddColor(eDvbColor Color, tWindowHandle Window)
|
||||
{
|
||||
cWindow *w = GetWindow(Window);
|
||||
if (w) {
|
||||
w->Index(Color);
|
||||
w->Reset();
|
||||
}
|
||||
}
|
||||
|
||||
cWindow *cOsdBase::GetWindow(int x, int y)
|
||||
{
|
||||
for (int i = 0; i < numWindows; i++) {
|
||||
if (window[i]->Tiled() && window[i]->Contains(x, y))
|
||||
return window[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cWindow *cOsdBase::GetWindow(tWindowHandle Window)
|
||||
{
|
||||
if (0 <= Window && Window < numWindows)
|
||||
return window[Window];
|
||||
if (Window == LAST_CREATED_WINDOW && numWindows > 0)
|
||||
return window[numWindows - 1];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void cOsdBase::Flush(void)
|
||||
{
|
||||
for (int i = 0; i < numWindows; i++) {
|
||||
CommitWindow(window[i]);
|
||||
window[i]->Clean();
|
||||
}
|
||||
// Showing the windows in a separate loop to avoid seeing them come up one after another
|
||||
for (int i = 0; i < numWindows; i++) {
|
||||
if (!window[i]->Shown())
|
||||
ShowWindow(window[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdBase::Clear(tWindowHandle Window)
|
||||
{
|
||||
if (Window == ALL_TILED_WINDOWS || Window == ALL_WINDOWS) {
|
||||
for (int i = 0; i < numWindows; i++)
|
||||
if (Window == ALL_WINDOWS || window[i]->Tiled())
|
||||
window[i]->Clear();
|
||||
}
|
||||
else {
|
||||
cWindow *w = GetWindow(Window);
|
||||
if (w)
|
||||
w->Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdBase::Fill(int x1, int y1, int x2, int y2, eDvbColor Color, tWindowHandle Window)
|
||||
{
|
||||
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x1, y1) : GetWindow(Window);
|
||||
if (w)
|
||||
w->Fill(x1, y1, x2, y2, Color);
|
||||
}
|
||||
|
||||
void cOsdBase::SetBitmap(int x, int y, const cBitmap &Bitmap, tWindowHandle Window)
|
||||
{
|
||||
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window);
|
||||
if (w)
|
||||
w->SetBitmap(x, y, Bitmap);
|
||||
}
|
||||
|
||||
int cOsdBase::Width(unsigned char c)
|
||||
{
|
||||
return numWindows ? window[0]->Width(c) : 0;
|
||||
}
|
||||
|
||||
int cOsdBase::Width(const char *s)
|
||||
{
|
||||
return numWindows ? window[0]->Width(s) : 0;
|
||||
}
|
||||
|
||||
eDvbFont cOsdBase::SetFont(eDvbFont Font)
|
||||
{
|
||||
eDvbFont oldFont = Font;
|
||||
for (int i = 0; i < numWindows; i++)
|
||||
oldFont = window[i]->SetFont(Font);
|
||||
return oldFont;
|
||||
}
|
||||
|
||||
void cOsdBase::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg, tWindowHandle Window)
|
||||
{
|
||||
cWindow *w = (Window == ALL_TILED_WINDOWS) ? GetWindow(x, y) : GetWindow(Window);
|
||||
if (w)
|
||||
w->Text(x, y, s, ColorFg, ColorBg);
|
||||
}
|
||||
|
||||
void cOsdBase::Relocate(tWindowHandle Window, int x, int y, int NewWidth, int NewHeight)
|
||||
{
|
||||
cWindow *w = GetWindow(Window);
|
||||
if (w) {
|
||||
if (NewWidth > 0 && NewHeight > 0) {
|
||||
if ((NewWidth & 0x03) != 0) {
|
||||
NewWidth += 4 - (NewWidth & 0x03);
|
||||
dsyslog("OSD window width must be a multiple of 4 - increasing to %d", NewWidth);
|
||||
}
|
||||
CloseWindow(w);
|
||||
cWindow *NewWindow = new cWindow(w->Handle(), x, y, NewWidth, NewHeight, w->Bpp(), w->ClearWithBackground(), w->Tiled());
|
||||
window[w->Handle()] = NewWindow;
|
||||
delete w;
|
||||
OpenWindow(NewWindow);
|
||||
}
|
||||
else {
|
||||
MoveWindow(w, x, y);
|
||||
w->Relocate(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cOsdBase::Hide(tWindowHandle Window)
|
||||
{
|
||||
HideWindow(GetWindow(Window), true);
|
||||
}
|
||||
|
||||
void cOsdBase::Show(tWindowHandle Window)
|
||||
{
|
||||
HideWindow(GetWindow(Window), false);
|
||||
}
|
||||
|
Reference in New Issue
Block a user