From 25f085cc267760a43d2294406d3fdd6d14dc6e7f Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Wed, 1 Nov 2000 11:45:05 +0100 Subject: [PATCH] Improved Schedules menus --- dvbapi.c | 20 ++++- dvbapi.h | 4 +- dvbosd.c | 7 +- dvbosd.h | 3 +- interface.c | 86 ++++++++++++++++++-- interface.h | 6 +- menu.c | 222 ++++++++++++++++++++++++++++++++-------------------- osd.c | 5 +- osd.h | 6 +- 9 files changed, 257 insertions(+), 102 deletions(-) diff --git a/dvbapi.c b/dvbapi.c index f7272f76..cc246d2f 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.33 2000/10/29 10:39:57 kls Exp $ + * $Id: dvbapi.c 1.34 2000/11/01 09:19:27 kls Exp $ */ #include "dvbapi.h" @@ -1598,6 +1598,24 @@ void cDvbApi::ClrEol(int x, int y, eDvbColor color) Fill(x, y, cols - x, 1, color); } +int cDvbApi::CellWidth(void) +{ +#ifdef DEBUG_OSD + return 1; +#else + return charWidth; +#endif +} + +int cDvbApi::Width(unsigned char c) +{ +#ifdef DEBUG_OSD + return 1; +#else + return osd->Width(c); +#endif +} + void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg) { if (x < 0) x = cols + x; diff --git a/dvbapi.h b/dvbapi.h index 2a67585d..16a2b7a7 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.19 2000/10/29 12:11:16 kls Exp $ + * $Id: dvbapi.h 1.20 2000/11/01 09:18:50 kls Exp $ */ #ifndef __DVBAPI_H @@ -122,6 +122,8 @@ public: void Clear(void); void Fill(int x, int y, int w, int h, eDvbColor color = clrBackground); void ClrEol(int x, int y, eDvbColor color = clrBackground); + int CellWidth(void); + int Width(unsigned char c); void Text(int x, int y, const char *s, eDvbColor colorFg = clrWhite, eDvbColor colorBg = clrBackground); void Flush(void); diff --git a/dvbosd.c b/dvbosd.c index 97c79322..c0150e26 100644 --- a/dvbosd.c +++ b/dvbosd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.c 1.3 2000/10/07 14:42:48 kls Exp $ + * $Id: dvbosd.c 1.4 2000/11/01 09:13:32 kls Exp $ */ #include "dvbosd.h" @@ -76,6 +76,11 @@ void cBitmap::SetPixel(int x, int y, eDvbColor Color) } } +int cBitmap::Width(unsigned char c) +{ + return font ? font->Width(c) : -1; +} + void cBitmap::Text(int x, int y, const char *s, eDvbColor ColorFg, eDvbColor ColorBg) { if (bitmap) { diff --git a/dvbosd.h b/dvbosd.h index f7a53635..149dc6cb 100644 --- a/dvbosd.h +++ b/dvbosd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbosd.h 1.1 2000/10/01 15:00:00 kls Exp $ + * $Id: dvbosd.h 1.2 2000/11/01 09:13:44 kls Exp $ */ #ifndef __DVBOSD_H @@ -56,6 +56,7 @@ public: void SetFont(eDvbFont Font); bool Dirty(void); void SetPixel(int x, int y, eDvbColor Color); + int Width(unsigned char c); void Text(int x, int y, const char *s, eDvbColor ColorFg = clrWhite, eDvbColor ColorBg = clrBackground); void Fill(int x1, int y1, int x2, int y2, eDvbColor Color); void Clear(void); diff --git a/interface.c b/interface.c index 3e1232f0..c0554ca3 100644 --- a/interface.c +++ b/interface.c @@ -4,10 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.c 1.26 2000/10/29 12:53:55 kls Exp $ + * $Id: interface.c 1.27 2000/11/01 11:25:25 kls Exp $ */ #include "interface.h" +#include #include cInterface *Interface = NULL; @@ -16,6 +17,7 @@ cInterface::cInterface(int SVDRPport) { open = 0; cols[0] = 0; + width = height = 0; keyFromWait = kNone; rcIo = NULL; SVDRP = NULL; @@ -40,15 +42,17 @@ cInterface::~cInterface() void cInterface::Open(int NumCols, int NumLines) { if (!open++) - cDvbApi::PrimaryDvbApi->Open(NumCols, NumLines); + cDvbApi::PrimaryDvbApi->Open(width = NumCols, height = NumLines); } void cInterface::Close(void) { if (open == 1) Clear(); - if (!--open) + if (!--open) { cDvbApi::PrimaryDvbApi->Close(); + width = height = 0; + } } unsigned int cInterface::GetCh(bool Wait, bool *Repeat, bool *Release) @@ -120,6 +124,74 @@ void cInterface::SetCols(int *c) } } +char *cInterface::WrapText(const char *Text, int Width, int *Height) +{ + // Wraps the Text to make it fit into the area defined by the given Width + // (which is given in character cells). + // The actual number of lines resulting from this operation is returned in + // Height. + // The returned string is newly created on the heap and the caller + // is responsible for deleting it once it is no longer used. + // Wrapping is done by inserting the necessary number of newline + // characters into the string. + + int Lines = 1; + char *t = strdup(Text); + char *Blank = NULL; + char *Delim = NULL; + int w = 0; + + Width *= cDvbApi::PrimaryDvbApi->CellWidth(); + + while (*t && t[strlen(t) - 1] == '\n') + t[strlen(t) - 1] = 0; // skips trailing newlines + + for (char *p = t; *p; ) { + if (*p == '\n') { + Lines++; + w = 0; + Blank = Delim = NULL; + p++; + continue; + } + else if (isspace(*p)) + Blank = p; + int cw = cDvbApi::PrimaryDvbApi->Width(*p); + if (w + cw > Width) { + if (Blank) { + *Blank = '\n'; + p = Blank; + continue; + } + else { + // Here's the ugly part, where we don't have any whitespace to + // punch in a newline, so we need to make room for it: + if (Delim) + p = Delim + 1; // let's fall back to the most recent delimiter + char *s = new char[strlen(t) + 2]; // The additional '\n' plus the terminating '\0' + int l = p - t; + strncpy(s, t, l); + s[l] = '\n'; + strcpy(s + l + 1, p); + delete t; + t = s; + p = t + l; + continue; + } + } + else + w += cw; + if (strchr("-.,:;!?_", *p)) { + Delim = p; + Blank = NULL; + } + p++; + } + + *Height = Lines; + return t; +} + void cInterface::Write(int x, int y, const char *s, eDvbColor FgColor, eDvbColor BgColor) { if (open) @@ -154,7 +226,7 @@ void cInterface::WriteText(int x, int y, const char *s, eDvbColor FgColor, eDvbC void cInterface::Title(const char *s) { - int x = (MenuColumns - strlen(s)) / 2; + int x = (Width() - strlen(s)) / 2; if (x < 0) x = 0; ClearEol(0, 0, clrCyan); @@ -203,7 +275,7 @@ bool cInterface::Confirm(const char *s) void cInterface::HelpButton(int Index, const char *Text, eDvbColor FgColor, eDvbColor BgColor) { if (open && Text) { - const int w = MenuColumns / 4; + const int w = Width() / 4; int l = (w - strlen(Text)) / 2; if (l < 0) l = 0; @@ -460,7 +532,7 @@ eKeys cInterface::DisplayDescription(const cEventInfo *EventInfo) int cInterface::WriteParagraph(int Line, const char *Text) { - if (Line < MenuLines && Text) { + if (Line < Height() && Text) { Line++; char *s = strdup(Text); char *pStart = s, *pEnd; @@ -479,7 +551,7 @@ int cInterface::WriteParagraph(int Line, const char *Text) //XXX need to scroll if text is longer *pEnd = 0; Write(1, Line++, pStart, clrCyan); - if (Line >= MenuLines) + if (Line >= Height()) return Line; pStart = pEnd + 1; } diff --git a/interface.h b/interface.h index 684adfec..2c9344cc 100644 --- a/interface.h +++ b/interface.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: interface.h 1.17 2000/10/29 12:32:12 kls Exp $ + * $Id: interface.h 1.18 2000/11/01 11:18:23 kls Exp $ */ #ifndef __INTERFACE_H @@ -19,6 +19,7 @@ class cInterface { public: enum { MaxCols = 5 }; private: + int width, height; int open; int cols[MaxCols]; eKeys keyFromWait; @@ -35,11 +36,14 @@ public: ~cInterface(); void Open(int NumCols = MenuColumns, int NumLines = MenuLines); void Close(void); + int Width(void) { return width; } + int Height(void) { return height; } eKeys GetKey(bool Wait = true); void PutKey(eKeys Key); void Clear(void); void ClearEol(int x, int y, eDvbColor Color = clrBackground); void SetCols(int *c); + char *WrapText(const char *Text, int Width, int *Height); void Write(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void WriteText(int x, int y, const char *s, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); void Title(const char *s); diff --git a/menu.c b/menu.c index d5b0a32f..06d3dd4e 100644 --- a/menu.c +++ b/menu.c @@ -4,11 +4,10 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.37 2000/10/29 11:23:33 kls Exp $ + * $Id: menu.c 1.38 2000/11/01 11:45:05 kls Exp $ */ #include "menu.h" -#include #include #include #include @@ -727,7 +726,107 @@ eOSState cMenuChannels::ProcessKey(eKeys Key) return state; } -// --- cMenuSummary -------------------------------------------------------- +// --- cMenuTextItem --------------------------------------------------------- + +class cMenuTextItem : public cOsdItem { +private: + char *text; + int x, y, w, h, lines, offset; + eDvbColor fgColor, bgColor; +public: + cMenuTextItem(const char *Text, int X, int Y, int W, int H = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + ~cMenuTextItem(); + int Height(void) { return h; } + void Clear(void); + virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + bool CanScrollUp(void) { return offset > 0; } + bool CanScrollDown(void) { return h + offset < lines; } + void ScrollUp(void); + void ScrollDown(void); + virtual eOSState ProcessKey(eKeys Key); + }; + +cMenuTextItem::cMenuTextItem(const char *Text, int X, int Y, int W, int H, eDvbColor FgColor, eDvbColor BgColor) +{ + x = X; + y = Y; + w = W; + h = H; + fgColor = FgColor; + bgColor = BgColor; + offset = 0; + text = Interface->WrapText(Text, w - 1, &lines); + if (h < 0) + h = lines; +} + +cMenuTextItem::~cMenuTextItem() +{ + delete text; +} + +void cMenuTextItem::Clear(void) +{ + cDvbApi::PrimaryDvbApi->Fill(x, y, w, h, bgColor); +} + +void cMenuTextItem::Display(int Offset, eDvbColor FgColor, eDvbColor BgColor) +{ + int l = 0; + char *t = text; + while (*t) { + char *n = strchr(t, '\n'); + if (l >= offset) { + if (n) + *n = 0; + Interface->Write(x, y + l - offset, t, fgColor, bgColor); + if (n) + *n = '\n'; + else + break; + } + if (!n) + break; + t = n + 1; + if (++l >= h + offset) + break; + } + // scroll indicators use inverted color scheme! + if (CanScrollUp()) Interface->Write(x + w - 1, y, "^", bgColor, fgColor); + if (CanScrollDown()) Interface->Write(x + w - 1, y + h - 1, "v", bgColor, fgColor); +} + +void cMenuTextItem::ScrollUp(void) +{ + if (CanScrollUp()) { + Clear(); + offset--; + Display(); + } +} + +void cMenuTextItem::ScrollDown(void) +{ + if (CanScrollDown()) { + Clear(); + offset++; + Display(); + } +} + +eOSState cMenuTextItem::ProcessKey(eKeys Key) +{ + switch (Key) { + case kUp|k_Repeat: + case kUp: ScrollUp(); break; + case kDown|k_Repeat: + case kDown: ScrollDown(); break; + default: return osUnknown; + } + return osContinue; +} + +// --- cMenuSummary ---------------------------------------------------------- class cMenuSummary : public cOsdMenu { public: @@ -738,29 +837,7 @@ public: cMenuSummary::cMenuSummary(const char *Text) :cOsdMenu("Summary") { - while (*Text) { - char line[MenuColumns + 1]; - char *p = line; - const char *b = NULL; - *p++ = ' '; - while (*Text && p - line < MenuColumns - 2) { - if (isspace(*Text)) - b = Text; // remember the blank - if (*Text == '\n') - break; - *p++ = *Text++; - } - if (*Text) { - if (b && Text - b > 0) { - p -= Text - b; - Text = b + 1; - } - else - Text++; - } - *p = 0; - Add(new cOsdItem(line, osBack)); - } + Add(new cMenuTextItem(Text, 1, 2, MenuColumns - 2, MAXOSDITEMS)); } eOSState cMenuSummary::ProcessKey(eKeys Key) @@ -975,84 +1052,55 @@ eOSState cMenuTimers::ProcessKey(eKeys Key) return state; } -// --- cMenuEventItem -------------------------------------------------------- - -class cMenuEventItem : public cOsdItem { -public: - cMenuEventItem(const char *Text); -}; - -cMenuEventItem::cMenuEventItem(const char *Text) -:cOsdItem(Text, osBack) -{ -} - // --- cMenuEvent ------------------------------------------------------------ class cMenuEvent : public cOsdMenu { private: - void AddParagraph(const char *text); const cEventInfo *eventInfo; public: cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch = false); + virtual eOSState ProcessKey(eKeys Key); }; cMenuEvent::cMenuEvent(const cEventInfo *EventInfo, bool CanSwitch) -:cOsdMenu("Event", 1) +:cOsdMenu("Event") { - const char *p; - char buffer[MenuColumns + 1]; - eventInfo = EventInfo; - - cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID()); - - snprintf(buffer, sizeof(buffer), "\t%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); - Add(new cMenuEventItem(buffer)); - if ((p = eventInfo->GetTitle()) != NULL && *p) { - Add(new cMenuEventItem("")); - AddParagraph(p); + if (eventInfo) { + cChannel *channel = Channels.GetByServiceID(eventInfo->GetServiceID()); + if (channel) { + const char *p; + char *buffer; + asprintf(&buffer, "%-17.*s %.*s %s - %s", 17, channel->name, 5, eventInfo->GetDate(), eventInfo->GetTimeString(), eventInfo->GetEndTimeString()); + SetTitle(buffer, false); + int Line = 2; + cMenuTextItem *item; + if (!isempty(p = eventInfo->GetTitle())) { + Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrCyan)); + Line += item->Height() + 1; + } + if (!isempty(p = eventInfo->GetSubtitle())) { + Add(item = new cMenuTextItem(p, 1, Line, MenuColumns - 2, -1, clrYellow)); + Line += item->Height() + 1; + } + if (!isempty(p = eventInfo->GetExtendedDescription())) + Add(new cMenuTextItem(p, 1, Line, MenuColumns - 2, Height() - Line - 2, clrCyan), true); + SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL); + } } - if ((p = eventInfo->GetSubtitle()) != NULL && *p) { - Add(new cMenuEventItem("")); - AddParagraph(p); - } - if ((p = eventInfo->GetExtendedDescription()) != NULL && *p) { - Add(new cMenuEventItem("")); - AddParagraph(p); - } - SetHelp("Record", NULL, NULL, CanSwitch ? "Switch" : NULL); } -void cMenuEvent::AddParagraph(const char *text) +eOSState cMenuEvent::ProcessKey(eKeys Key) { - char *ptextsave = strdup(text); + eOSState state = cOsdMenu::ProcessKey(Key); - if (ptextsave) { - - int column = 1; - char buffer[MenuColumns + 1]; - char *pStart = ptextsave; - char *pEndText = &ptextsave[strlen(text) - 1]; - - while (pStart < pEndText) { - char *pEnd; - if (strlen(pStart) > (unsigned)(MenuColumns - column - 2)) - pEnd = &pStart[MenuColumns - column - 2]; - else - pEnd = &pStart[strlen(pStart)]; - - while (*pEnd && *pEnd != ' ' && pEnd > pStart) - pEnd--; - - *pEnd = 0; - sprintf(buffer, "\t%s", pStart); - Add(new cMenuEventItem(buffer)); - pStart = pEnd + 1; - } + if (state == osUnknown) { + switch (Key) { + case kOk: return osBack; + default: break; + } } - - delete ptextsave; + return state; } // --- cMenuWhatsOnItem ------------------------------------------------------ @@ -1266,6 +1314,8 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key) default: break; } } + else if (!HasSubMenu()) + now = next = false; return state; } diff --git a/osd.c b/osd.c index 3225e681..f3458274 100644 --- a/osd.c +++ b/osd.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.c 1.10 2000/10/28 09:33:47 kls Exp $ + * $Id: osd.c 1.11 2000/11/01 11:21:51 kls Exp $ */ #include "osd.h" @@ -170,7 +170,8 @@ void cOsdMenu::Display(void) break; } } - Interface->Status(status); + if (!isempty(status)) + Interface->Status(status); } void cOsdMenu::RefreshCurrent(void) diff --git a/osd.h b/osd.h index 5e2ad300..2b9359a6 100644 --- a/osd.h +++ b/osd.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: osd.h 1.12 2000/10/28 09:32:59 kls Exp $ + * $Id: osd.h 1.13 2000/11/01 11:20:15 kls Exp $ */ #ifndef __OSD_H @@ -50,7 +50,7 @@ public: void SetText(const char *Text, bool Copy = true); void SetColor(eDvbColor FgColor, eDvbColor BgColor = clrBackground); const char *Text(void) { return text; } - void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); + virtual void Display(int Offset = -1, eDvbColor FgColor = clrWhite, eDvbColor BgColor = clrBackground); virtual void Set(void) {} virtual eOSState ProcessKey(eKeys Key); }; @@ -90,6 +90,8 @@ protected: public: cOsdMenu(const char *Title, int c0 = 0, int c1 = 0, int c2 = 0, int c3 = 0, int c4 = 0); virtual ~cOsdMenu(); + int Width(void) { return Interface->Width(); } + int Height(void) { return Interface->Height(); } int Current(void) { return current; } void Add(cOsdItem *Item, bool Current = false); void Display(void);