]> git.vomp.tv Git - vompclient.git/commitdiff
EPG & vvideolive clean up (inc new bugs!)
authorChris Tallon <chris@vomp.tv>
Thu, 1 Dec 2005 19:21:21 +0000 (19:21 +0000)
committerChris Tallon <chris@vomp.tv>
Thu, 1 Dec 2005 19:21:21 +0000 (19:21 +0000)
20 files changed:
Makefile
colour.cc
colour.h
event.cc
event.h
vchannellist.cc
vdr.cc
vdr.h
vepg.cc [new file with mode: 0644]
vepg.h [new file with mode: 0644]
viewman.cc
vlivebanner.cc
vlivebanner.h
vrecordinglist.cc
vvideolive.cc
vvideolive.h
widget.cc
widget.h
wtextbox.cc [new file with mode: 0644]
wtextbox.h [new file with mode: 0644]

index dd29a01de77e7c2d495698f6d5a55f49d6645f43..0b7c21c23b4a758efe5a143f06e08c1e2eacde45 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,8 +16,8 @@ OBJECTS = main.o command.o log.o remote.o led.o mtd.o video.o audio.o tcp.o dire
           recording.o channel.o message.o playervideo.o playerradio.o messagequeue.o \
           view.o vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o \
           vrecordingmenu.o vquestion.o vchannellist.o vwelcome.o vvideolive.o vvideorec.o vradiolive.o \
-          vchannelselect.o vserverselect.o colour.o vconnect.o voptions.o region.o \
-          widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o woptionbox.o i18n.o \
+          vchannelselect.o vserverselect.o colour.o vconnect.o voptions.o vepg.o region.o \
+          widget.o wselectlist.o wjpeg.o wsymbol.o wbutton.o woptionbox.o wtextbox.o i18n.o \
           fonts/helvB24.o fonts/helvB18.o
 
 .PHONY: clean fresh all install strip
index 44722293b18b4c104d5a5bfd0dd75646adda442d..cf1d38a7dac639e0ac9a6a5568665c59da282b2c 100644 (file)
--- a/colour.cc
+++ b/colour.cc
@@ -33,6 +33,9 @@ Colour Colour::LIGHTTEXT(255, 255, 255);
 Colour Colour::DARKTEXT(0, 0, 100);
 Colour Colour::DANGER(200, 0, 0);
 Colour Colour::BUTTONBACKGROUND(0, 0, 150);
+Colour Colour::PROGRAMMEB(80, 80, 240); // two colours used as alterating backgrounds for individual programmes in EPG
+Colour Colour::PROGRAMMEA(40, 40, 120); // TODO fit epg style (colours) in with rest of application
+Colour Colour::NOPROGRAMME(180, 180, 180); // no programme details colour
 
 
 /*
index 3abb27fcd800fea4c8a988b37ecbcbbc7bd5c6f7..84de2d66efdf040d8c565997a102f86368dd220c 100644 (file)
--- a/colour.h
+++ b/colour.h
@@ -41,6 +41,9 @@ class Colour
 
     static Colour BLACK;
     static Colour RED;
+    static Colour GREEN;
+    static Colour YELLOW;
+    static Colour BLUE;
     static Colour VIDEOBLUE;
     static Colour VIEWBACKGROUND;
     static Colour TITLEBARBACKGROUND;
@@ -49,6 +52,10 @@ class Colour
     static Colour DARKTEXT;
     static Colour DANGER;
     static Colour BUTTONBACKGROUND;
+    static Colour PROGRAMMEA;
+    static Colour PROGRAMMEB;
+    static Colour NOPROGRAMME;
+
 
 };
 
index 614eaa113ff3ad839963748c27109a643ac5f5fd..e37a0f638b513645460b6bb8484fd46c6a388a01 100644 (file)
--- a/event.cc
+++ b/event.cc
@@ -39,3 +39,25 @@ Event::~Event()
   if (subtitle) delete[] subtitle;
   if (description) delete[] description;
 }
+
+void Event::settitle(char* s)
+{
+  delete title;
+  title = new char[strlen(s) + 1];
+  strcpy(title, s);
+}
+
+void Event::setdescription(char* s)
+{
+  delete description;
+  description = new char[strlen(s) + 1];
+  strcpy(description, s);
+}
+
+void Event::setsubtitle(char* s)
+{
+  delete subtitle;
+  subtitle = new char[strlen(s) + 1];
+  strcpy(subtitle, s);
+}
+
diff --git a/event.h b/event.h
index 3d595bc57465701c2c328744ba9cf4cdc1cf95c6..f73f1a679a6571bb9d61ca9335600bac50ca204c 100644 (file)
--- a/event.h
+++ b/event.h
@@ -31,6 +31,10 @@ class Event
     Event();
     ~Event();
 
+    void settitle(char* title);
+    void setsubtitle(char* subtitle);
+    void setdescription(char* description);
+
     ULONG id;
     ULONG time;
     ULONG duration;
index 82d0e05c96e236956dbf1c6fc9bead7754854ed9..83ae18b98aceb6545593fed76a02f8272eae8746 100644 (file)
@@ -201,7 +201,7 @@ int VChannelList::handleCommand(int command)
    //   if (chan->type == VDR::RADIO) return 2;
 
       VVideoLive* v = new VVideoLive(chanList, chan->type);
-      v->setChannel(chan->number);
+      v->channelChange(VVideoLive::NUMBER, chan->number);
 
       ViewMan::getInstance()->addNoLock(v);
       v->draw();
diff --git a/vdr.cc b/vdr.cc
index 3776d044641d43ac8539660ca137219eca6b35f5..696750b1eaff243927c0c69fa0216172ed436f21 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
@@ -628,18 +628,28 @@ ULLONG VDR::rescanRecording()
 
 EventList* VDR::getChannelSchedule(ULONG number)
 {
+  time_t now;
+  time(&now);
+  return getChannelSchedule(number, now, 24 * 60 * 60);
+}
+
+EventList* VDR::getChannelSchedule(ULONG number, time_t start, ULONG duration)
+{ 
+// retrieve event list (vector of events) from vdr within filter window. duration is in seconds
   if (!connected) return 0;
 
-  UCHAR buffer[12];
+  UCHAR buffer[20];
 
-  *(unsigned long*)&buffer[0] = htonl(8);
+  *(unsigned long*)&buffer[0] = htonl(16);
   *(unsigned long*)&buffer[4] = htonl(VDR_GETCHANNELSCHEDULE);
   *(unsigned long*)&buffer[8] = htonl(number);
+  *(unsigned long*)&buffer[12] = htonl(start);
+  *(unsigned long*)&buffer[16] = htonl(duration);
 
   pthread_mutex_lock(&mutex);
-  int a = tcp->sendPacket(buffer, 12);
+  int a = tcp->sendPacket(buffer, 20);
 
-  if (a != 12)
+  if (a != 20)
   {
     pthread_mutex_unlock(&mutex);
     return NULL;
diff --git a/vdr.h b/vdr.h
index 72322931011c19f01fc4c0be1153e5b7d00834b6..48c4c6eb300f8ff071c3f6cd8f6d94db719cc6e8 100644 (file)
--- a/vdr.h
+++ b/vdr.h
@@ -76,6 +76,7 @@ class VDR
     UCHAR*     getBlock(ULLONG position, UINT maxAmount, UINT* amountReceived);
     int        stopStreaming();
     EventList* getChannelSchedule(ULONG number);
+    EventList* getChannelSchedule(ULONG number, time_t start, ULONG duration);
     int        configSave(char* section, char* key, const char* value);
     char*      configLoad(char* section, char* key);
 
diff --git a/vepg.cc b/vepg.cc
new file mode 100644 (file)
index 0000000..4bb9fa7
--- /dev/null
+++ b/vepg.cc
@@ -0,0 +1,550 @@
+/*\r
+    Copyright 2004-2005 Brian Walton\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+/*\r
+    vepg presents a 2 dimensional electronic programme guide with channels down \r
+    the y axis and time along the x axis.\r
+    Programmes are layed on the x axis as alterate coloured blocks with as much \r
+    of the programme title as will fit inside the block shown as text.\r
+    Up and down commands step through the channels whilst left and right commands \r
+    move through the programmes of the currently selected channel.\r
+    When a programme is selected, it highlights in the grid and full programe details \r
+    (start time, title and description) are displayed in an area at te top left of the screen.\r
+    Any currently programmed timers will display in the grid and in the orogramme detail window as red\r
+    It is possible to select a programme to be recorded by pressing the record button.\r
+    The video stream currently being viewed is shown as quarter screen in the top right.\r
+*/\r
+    \r
+#include "vepg.h"\r
+\r
+VEpg::VEpg(VVideoLive* v, UINT currentChannel)\r
+{\r
+  for(UINT listIndex = 0; listIndex < 7; listIndex++)\r
+  {\r
+    // initialise array of pointers to eventlist structures\r
+    eventLista[listIndex] = NULL;\r
+  }\r
+  \r
+\r
+// Create pallet on which to paint our epg view and position it in centre of screen.\r
+// Need to reduce size to deal with overscanning TVs.\r
+  videoLive = v;\r
+//  create(640, 530);\r
+//TODO: have size for ntsc\r
+  if (Video::getInstance()->getFormat() == Video::PAL)\r
+  {\r
+    create(632, 520);\r
+    setScreenPos(44, 30);\r
+  }\r
+  else\r
+  {\r
+  // what can we do about poor ntsc?\r
+    create(512, 384);\r
+    setScreenPos(64, 51);\r
+  }\r
+  \r
+// beautify\r
+  Colour transparent = Colour(0, 0, 0, 0);\r
+  setBackgroundColour(transparent);\r
+// initialise variables and pointers\r
+  eventList = NULL;\r
+  chanList = VDR::getInstance()->getChannelsList(VDR::VIDEO); //TODO want to be able to display video and radio together\r
+  e = 0;\r
+  progTitle.setSurface(surface);\r
+  progTitle.setSurfaceOffset(0,0);\r
+  progTitle.setDimensions(300,(Surface::getFontHeight() + 6) * 2 + 2); //paragraph line seperation is 6 pixels\r
+  progTitle.setBackgroundColour(Colour::TITLEBARBACKGROUND);\r
+  progInfo.setSurface(surface);\r
+  progInfo.setSurfaceOffset(0, progTitle.getOffsetY() + progTitle.getHeight());\r
+  progInfo.setDimensions(300,(Surface::getFontHeight() + 6) * 8 + 2);\r
+  chanName.setSurface(surface);\r
+  chanName.setDimensions(510, (Surface::getFontHeight() + 4));\r
+  chanName.setSurfaceOffset(305,230);\r
+  chanName.setBackgroundColour(Colour(0, 0, 0, 90));\r
+// create area to display list of channels\r
+  chanListbox.setSurface(surface); // add channel list\r
+  chanListbox.setSurfaceOffset(0, progInfo.getOffsetY() + progInfo.getHeight() + Surface::getFontHeight() + 8); // position channel list\r
+  chanListbox.setDimensions(150, (Surface::getFontHeight() + 1) * 7 + 5); //listbox line seperation is 1 pixel\r
+// populate channel list\r
+  Channel* chan;\r
+  int first = 1;\r
+  for (UINT i = 0; i < chanList->size(); i++)\r
+  {\r
+    chan = (*chanList)[i];\r
+    if (i == currentChannel)\r
+      first = 1;\r
+    chan->index = chanListbox.addOption(chan->name, first);\r
+    first = 0;\r
+  }\r
+  listTop = chanListbox.getTopOption();\r
+  chanListbox.draw(); // doing this to allow chanListbox.getBottomOption() in updateEventList() to work\r
+  chanName.setText((*chanList)[chanListbox.getCurrentOption()]->name);\r
+  time(&ltime); // set ltime to now\r
+  ltime = prevHour(&ltime); // set ltime to previous hour TODO make this half hour?\r
+  time(&selTime); // set selTime to now\r
+  updateEventList(); // get list of programmes\r
+}\r
+\r
+VEpg::~VEpg()\r
+{\r
+   for(int listIndex = 0; listIndex < 7; listIndex++)\r
+   {\r
+     if (eventLista[listIndex])\r
+     {\r
+       (eventLista)[listIndex]->clear();\r
+       delete eventLista[listIndex];\r
+     }\r
+   }\r
+//  delete [] eventLista;\r
+\r
+// destroy dynamically allocated memory\r
+}\r
+\r
+void VEpg::setInfo(Event* event)\r
+{\r
+  time_t t;\r
+  struct tm* btime; // to hold programme start and end time\r
+  char* timeString = new char[9]; // to hold programme start and end time\r
+  int length = strlen(event->title); // calculate length of programme title string\r
+  char* title = new char[length + 15]; // create string to hold start time, end time and programme title\r
+  btime = localtime((time_t*)&event->time); //get programme start time\r
+  strftime(timeString, 9, "%0H:%0M - ", btime); // and format it as hh:mm -\r
+  strcpy(title, timeString); // put it in our buffer\r
+  t = event->time + event->duration; //get programme end time\r
+  btime = localtime(&t);\r
+  strftime(timeString, 7, "%0H:%0M ", btime); // and format it as hh:mm -\r
+  strcat(title, timeString); // put it in our buffer\r
+  strcat(title, event->title); // then add the programme title\r
+  progTitle.setText(title); // sput this sring in our text box\r
+  length = strlen(event->description);\r
+  char* info = new char[length + 1]; // create programme detail string\r
+  strcpy(info, event->description);\r
+  progInfo.setText(info); // show programme detail string\r
+// destroy dynamically allocated memory\r
+  delete info;\r
+  delete title;\r
+  delete timeString;\r
+}\r
+\r
+void VEpg::draw()\r
+{\r
+  View::draw(); // draw pallet\r
+  chanListbox.draw();\r
+  drawgrid();\r
+  chanName.draw(); // TODO this should be dealt with by vvideolive\r
+  progTitle.draw();\r
+  progInfo.draw();\r
+\r
+// Display the status and key stuff at the bottom\r
+  int keyx = chanListbox.getOffsetX();\r
+  int keyy = chanListbox.getOffsetY() + chanListbox.getHeight() + 2;\r
+  surface->fillblt(keyx, keyy, 610, Surface::getFontHeight() * 2 + 14, surface->rgba(100, 100, 100, 255));\r
+  \r
+  WSymbol w;\r
+  w.setSurface(surface);\r
+  \r
+  w.nextSymbol = WSymbol::LEFTARROW;\r
+  w.setSurfaceOffset(keyx + 1, keyy + 20);\r
+  w.draw();\r
+  \r
+  w.nextSymbol = WSymbol::UP;\r
+  w.setSurfaceOffset(keyx + 26, keyy + 3);\r
+  w.draw();\r
+\r
+  w.nextSymbol = WSymbol::DOWN;\r
+  w.setSurfaceOffset(keyx + 26, keyy + 36);\r
+  w.draw();\r
+  \r
+  w.nextSymbol = WSymbol::RIGHTARROW;\r
+  w.setSurfaceOffset(keyx + 50, keyy + 20);\r
+  w.draw();\r
+  \r
+  drawText("OK", keyx + 18, keyy + 20, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 72, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 0, 0, 255));\r
+  drawText("Page up", keyx + 74, keyy + 5, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 72, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba(0, 200, 0, 255));\r
+  drawText("Page down", keyx + 74, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 180, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 200, 0, 255));\r
+  drawText("-24 hours", keyx + 182, keyy + 5, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 180, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba( 0, 0, 200, 255));\r
+  drawText("+24 hours", keyx + 182, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 290, keyy + 4, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
+  drawText("Guide / Back: Close", keyx + 292 , keyy + 5, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 290, keyy + Surface::getFontHeight() + 8, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
+  Colour red = Colour(130, 0, 0);\r
+  drawText("Rec: Set timer", keyx + 292, keyy + Surface::getFontHeight() + 9, red);\r
+  \r
+  surface->fillblt(keyx + 474, keyy + 4, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
+  w.nextSymbol = WSymbol::PLAY;\r
+  w.setSurfaceOffset(keyx + 476, keyy + 5);\r
+  w.draw();\r
+  drawText("Sel channel", keyx + 496, keyy + 5, Colour::LIGHTTEXT);\r
+  \r
+  surface->fillblt(keyx + 474, keyy + Surface::getFontHeight() + 8, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
+  drawText("Go: Preview", keyx + 476, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
+}\r
+\r
+int VEpg::handleCommand(int command)\r
+{\r
+  switch(command)\r
+  {\r
+    case Remote::DF_UP:\r
+    case Remote::UP:\r
+    { // cursor up the channel list\r
+      chanListbox.up();\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::DF_DOWN:\r
+    case Remote::DOWN:\r
+    { // cursor down the channel list\r
+      chanListbox.down();\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::DF_LEFT:\r
+    case Remote::LEFT:\r
+    { // cursor left through time\r
+      selTime = thisEvent.time - 1;\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::DF_RIGHT:\r
+    case Remote::RIGHT:\r
+    { \r
+    // cursor right through time\r
+      selTime = thisEvent.time + thisEvent.duration;\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::RED:\r
+    { \r
+    // cursor up one page\r
+      chanListbox.pageUp();\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::GREEN:\r
+    { \r
+    // cursor down one page\r
+      chanListbox.pageDown();\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::BLUE:\r
+    { \r
+    // step forward 24 hours\r
+      selTime += 24 * 60 * 60;\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::YELLOW:\r
+    { \r
+    // step forward 24 hours\r
+      selTime -= 24 * 60 * 60;\r
+      draw();\r
+      show();\r
+      return 2;\r
+    }\r
+    case Remote::RECORD:\r
+    {\r
+      //TODO\r
+      return 2;\r
+    }\r
+    case Remote::PLAY:\r
+    case Remote::GO:\r
+    case Remote::OK:\r
+    { // select programme and display menu TODO currently just changes to selected channel\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = videoLive;\r
+      m->message = Message::CHANNEL_CHANGE;\r
+      m->parameter = (*chanList)[chanListbox.getCurrentOption()]->number;\r
+      ViewMan::getInstance()->postMessage(m);\r
+      if(command == Remote::GO)\r
+        return 2;\r
+      // GO just changes channel in preview, PLAY changes channel and returns to normal TV\r
+    }\r
+    case Remote::BACK:\r
+    case Remote::GUIDE:\r
+    {\r
+    // return to normal TV mode TODO vvideolive should handle this (via message?)\r
+      Video::getInstance()->setMode(Video::NORMAL);\r
+      videoLive->setEpgMode(FALSE);\r
+      return 4;\r
+    }\r
+    case Remote::CHANNELUP:\r
+    {\r
+    // change up channel on live TV TODO vvideolive should handle this\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = videoLive;\r
+      m->message = Message::CHANNEL_UP;\r
+      ViewMan::getInstance()->postMessage(m);\r
+      return 2;\r
+    }\r
+    case Remote::CHANNELDOWN:\r
+    { // change down channel on live TV TODO vvideolive should handle this\r
+      Message* m = new Message();\r
+      m->from = this;\r
+      m->to = videoLive;\r
+      m->message = Message::CHANNEL_DOWN;\r
+      ViewMan::getInstance()->postMessage(m);\r
+      return 2;\r
+    }\r
+  }\r
+  // stop command getting to any more views\r
+  return 1;\r
+}\r
+\r
+void VEpg::drawgrid() // redraws grid and select programme\r
+{\r
+// draw the grid of programmes\r
+  char timeString[20];\r
+  time_t t;\r
+  time(&t); // set t = now\r
+  if(selTime < t)\r
+    selTime = t; // don't allow cursor in the past\r
+  if(listTop != chanListbox.getTopOption())\r
+  {\r
+  // chanListbox has scrolled TODO speed up by changing only rows that have changed\r
+    listTop = chanListbox.getTopOption();\r
+    updateEventList();\r
+  }\r
+  if ((selTime >= ltime + WINDOW_WIDTH * 60) || (selTime <= ltime))\r
+  {\r
+  // we have cursored back before left time of window\r
+  //TODO check that this and above don't happen together\r
+    ltime = prevHour(&selTime);\r
+    updateEventList();\r
+  }\r
+  // draw time scale\r
+  t = ltime;\r
+  struct tm* tms;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%a %e %b", tms);\r
+  int timey = chanListbox.getOffsetY() - Surface::getFontHeight() - 3;\r
+  int timex = 135;\r
+  drawTextRJ(timeString, timex - 10, timey, Colour::LIGHTTEXT); // print date\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex, timey, Colour::LIGHTTEXT); // print left time\r
+  surface->fillblt(155, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 255, 255, 255));\r
+  t = t + 3600;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex + 180, timey, Colour::LIGHTTEXT); // print middle time\r
+  surface->fillblt(335, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 255, 255, 255));\r
+  t = t + 3600;\r
+  tms = localtime(&t);\r
+  strftime(timeString, 19, "%H:%M", tms);\r
+  drawText(timeString, timex + 360, timey, Colour::LIGHTTEXT); // print right time\r
+  surface->fillblt(515, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 255, 255, 255));\r
+  // pointer to selTime\r
+  surface->fillblt(155 + (selTime - ltime) / 20, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 50, 50, 255));\r
+  \r
+  // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?\r
+  Event* event;\r
+  Event noevent; // an event to use if there are gaps in the epg\r
+  thisEvent.setdescription("There are no programme details available for this period");\r
+  thisEvent.duration = WINDOW_WIDTH * 60;\r
+  thisEvent.time = ltime;\r
+  thisEvent.settitle("No programme details");\r
+  thisEvent.id = 0;\r
+  bool swapColour = FALSE; // alternate cell colour\r
+  bool currentRow = FALSE;\r
+  int y = chanListbox.getOffsetY() + 5; // vertical position of cell\r
+  Colour bg, fg; // background colour of cells in grid\r
+  // for each displayed channel, find programmes that fall in 2.5 hour time window\r
+  for(int listIndex = 0; listIndex < 7; listIndex++)\r
+  {\r
+    if (listTop + listIndex >= chanListbox.getBottomOption())\r
+      continue; // ensure nothing populates grid below last channel\r
+    currentRow = (listTop + listIndex == chanListbox.getCurrentOption());\r
+    noevent.time = ltime;\r
+    noevent.duration = WINDOW_WIDTH * 60;\r
+    noevent.settitle("");\r
+    paintCell(&noevent, y, Colour::NOPROGRAMME, Colour::LIGHTTEXT); // fill row with no programme colour to be painted ove with valid programmes\r
+    if (currentRow)\r
+    {\r
+      thisEvent.setdescription("There are no programme details available for this period");\r
+      thisEvent.duration = WINDOW_WIDTH * 60;\r
+      thisEvent.time = ltime;\r
+      thisEvent.settitle("No programme details");\r
+      thisEvent.id = 0;\r
+    }\r
+    if (eventLista[listIndex])\r
+    {\r
+      sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());\r
+      for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel\r
+      {\r
+       fg = Colour::LIGHTTEXT;\r
+        event = (*eventLista[listIndex])[e];\r
+       if (event)\r
+       {\r
+         UINT end = event->time + event->duration; // programme end time\r
+         if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window\r
+           continue; // that's enough of this channel's events\r
+         if(end <= UINT(ltime)) // programme ends before LHS of window\r
+           continue; // this event is before the window - let's try the next event\r
+         // this event is one we are interested in\r
+         bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour\r
+         swapColour = !swapColour; // it wil be the other colour next time\r
+         if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)\r
+         {\r
+         // this is the selected programme\r
+           thisEvent.setdescription(event->description);\r
+           thisEvent.duration = event->duration;\r
+           thisEvent.time = event->time;\r
+           thisEvent.settitle(event->title);\r
+           thisEvent.id = event->id;\r
+           if(thisEvent.id == 0)\r
+             thisEvent.id = 1;\r
+           bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+           fg = Colour::DARKTEXT;\r
+         }\r
+         else\r
+         {\r
+           if (currentRow && thisEvent.id == 0)\r
+           {\r
+             if (end <= UINT(selTime) && end > UINT(thisEvent.time))\r
+               thisEvent.time = end;\r
+             if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)\r
+               thisEvent.duration = event->time - thisEvent.time;\r
+           } \r
+         }\r
+         paintCell(event, y, bg, fg);\r
+       }\r
+      }\r
+    }\r
+    else\r
+    {\r
+    // no event list for this channel. Already painted noevent colour so just highlight if selected\r
+      if (currentRow)\r
+      {\r
+        bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+        fg = Colour::DARKTEXT;\r
+        paintCell(&thisEvent, y, bg, fg);\r
+      }\r
+      else\r
+      {\r
+        bg = Colour::NOPROGRAMME;\r
+       fg = Colour::LIGHTTEXT;\r
+        noevent.settitle("No programme details");\r
+       paintCell(&noevent, y, bg, fg);\r
+      }\r
+    }\r
+    y += Surface::getFontHeight() + 1;\r
+  }\r
+  setInfo(&thisEvent);\r
+}\r
+\r
+void VEpg::updateEventList() \r
+{\r
+  Channel* chan;\r
+  for(UINT listIndex = 0; listIndex < 7; listIndex++)\r
+  {\r
+    if (eventLista[listIndex])\r
+    {\r
+      if ((eventLista[listIndex])->empty())\r
+        (eventLista)[listIndex]->clear();\r
+    }\r
+    if(listTop + listIndex >= UINT(chanListbox.getBottomOption()))\r
+      continue;\r
+    chan = (*chanList)[listTop + listIndex];\r
+    eventLista[listIndex] = VDR::getInstance()->getChannelSchedule(chan->number, ltime - 1, WINDOW_WIDTH * 60 + 2); // ltime - 1 to get prog before window (allows cursor left past ltime). + 2 to get prog after window\r
+  }\r
+}\r
+\r
+void VEpg::setCurrentChannel(char* chname)\r
+{\r
+  chanName.setText(chname);\r
+  chanName.draw();\r
+  show();\r
+}\r
+\r
+void VEpg::paintCell(Event* event, int yOffset, Colour bg, Colour fg)\r
+{\r
+  int w, x, y, h;\r
+  y =yOffset;\r
+  h = Surface::getFontHeight(); // TODO if want border around text, need to increae this and wselectlist line height\r
+  UINT end = event->time + event->duration; // programme end time\r
+  if(event->time <= UINT(ltime) && end > UINT(ltime)) // spans start of displayed window\r
+  {\r
+    x = 155; // LHS of window\r
+    if (end > (UINT(ltime) + (WINDOW_WIDTH * 60)))\r
+      w = WINDOW_WIDTH * MINUTE_SCALE; // spans full 2 hour window\r
+    else\r
+      w = MINUTE_SCALE * (event->time + event->duration - ltime ) / 60; // get width of remaining programme\r
+  }\r
+  if((event->time >= UINT(ltime)) && (event->time <= UINT(ltime) + (WINDOW_WIDTH * 60))) // starts within window\r
+  {\r
+    x = 155 + (MINUTE_SCALE * (event->time - ltime) / 60);\r
+    w = MINUTE_SCALE * event->duration / 60;\r
+    //if (w > 155 + MINUTE_SCALE * WINDOW_WIDTH -x)\r
+     // w = w + x - 155 - MINUTE_SCALE * WINDOW_WIDTH; // ends outside window\r
+  }\r
+  if (w > 155 + WINDOW_WIDTH * MINUTE_SCALE - x)\r
+    w = 155 + WINDOW_WIDTH * MINUTE_SCALE -x; // limit cells to RHS of window\r
+  surface->fillblt(x, y, w, h, surface->rgba(bg.red, bg.green, bg.blue, bg.alpha));\r
+  char* tt = new char[strlen(event->title) + 1];\r
+  strcpy (tt, event->title);\r
+  int textWidth = 0;\r
+  for (UINT textPos = 0; textPos < strlen(tt); textPos++)\r
+  {\r
+    int thisCharWidth = surface->getCharWidth(tt[textPos]);\r
+    if (textWidth + thisCharWidth > w) // text will not fit in cell\r
+    {\r
+      textWidth = textPos;\r
+      break;\r
+    }\r
+    textWidth += thisCharWidth;\r
+  }\r
+  char* tT = new char[textWidth];\r
+  if(textWidth > 1)\r
+  {\r
+    strncpy(tT, tt, textWidth - 1);\r
+    tT[textWidth - 1] =  '\0';\r
+    surface->drawText(tT, x+2, y, fg.red, fg.green, fg.blue);\r
+  }\r
+  delete tT;\r
+  \r
+}\r
+\r
+time_t VEpg::prevHour(time_t* t)\r
+{\r
+  struct tm* tms;\r
+  tms = localtime(t);\r
+  tms->tm_sec = 0;\r
+  tms->tm_min = 0;\r
+  return mktime(tms);\r
+}\r
+\r
diff --git a/vepg.h b/vepg.h
new file mode 100644 (file)
index 0000000..b4e5a0b
--- /dev/null
+++ b/vepg.h
@@ -0,0 +1,82 @@
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+#ifndef VEPG_H\r
+#define VEPG_H\r
+#define WINDOW_WIDTH (150)\r
+#define MINUTE_SCALE (3)\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include "view.h"\r
+#include "remote.h"\r
+#include "wselectlist.h"\r
+#include "viewman.h"\r
+#include "vdr.h"\r
+#include "vchannellist.h"\r
+#include "command.h"\r
+#include "message.h"\r
+#include "colour.h"\r
+#include "video.h"\r
+#include "wtextbox.h"\r
+#include "event.h"\r
+#include "message.h"\r
+#include "vvideolive.h"\r
+\r
+class VVideoLive;\r
+\r
+class VEpg : public View\r
+{\r
+  public:\r
+    VEpg(VVideoLive* v, UINT currentChannel = 0);\r
+    ~VEpg();\r
+\r
+    int handleCommand(int command); // deal with commands (from remote control)\r
+    void draw(); // draw epg view\r
+    void setCurrentChannel(char* chname);\r
+\r
+  private:\r
+    void setInfo(Event* event); // display details of selected programme\r
+    void drawgrid(); // redraws grid and select programme\r
+    \r
+    WSelectList chanListbox; // listbox to display available channels\r
+    WTextbox progTitle; // area to display time and title of selected programme\r
+    WTextbox progInfo; // area to display details of selected programme\r
+    EventList* eventList; // list of events (programmes) for a channel\r
+    Event thisEvent; // the selected event\r
+    time_t selTime; // current selection time \r
+    UINT e; // temp used to point to an event\r
+    ChannelList* chanList; // list of available channels\r
+    tm* epgtime; // selected time within epg\r
+    tm* Ltime; // time of LHS of epg view\r
+    time_t ltime; // time of LHS of epg view\r
+    time_t lastEnd; // end time of last painted cell - used to look for gaps in epg\r
+    WTextbox chanName;\r
+    EventList* eventLista[7];\r
+    int listTop;\r
+    int listWindowSize;\r
+    void updateChanList();\r
+    void updateEventList();\r
+    void paintCell(Event* event, int yOffset, Colour bg, Colour fg);\r
+    time_t prevHour(time_t* t);\r
+    VVideoLive* videoLive;\r
+};\r
+\r
+#endif\r
index 703788f3dec82f01b96875bf76c114b9104f692e..c10a8fdc4d57d9496635233f2927fcf92aca2daf 100644 (file)
@@ -637,7 +637,7 @@ void ViewMan::startAutoDeleteThread3()
     if (resetThreadFlag) continue;
 
     // timer ran out
-    Log::getInstance()->log("ViewMan", Log::DEBUG, "About to remove %p", nextToDelete);
+    Log::getInstance()->log("ViewMan", Log::DEBUG, "AutoDel: About to remove %p", nextToDelete);
     removeView(nextToDelete, 1);  // enter this method with mutex locked
 
     resetThreadFlag = 1;
index 8c7cc9bcbff825823f242af842ece5d48058b7e6..3d3639e3272ba5ba8c6510e6af6b944c6cc6a1dd 100644 (file)
 
 #include "vlivebanner.h"
 
-VLiveBanner::VLiveBanner(View* tparent, Channel* channel)
+VLiveBanner::VLiveBanner(View* tparent, Channel* channel, bool bannerTakesCommands)
 {
   eventList = NULL;
   parent = tparent;
+  takeCommands = bannerTakesCommands;
 
   create(500, 120);
   if (Video::getInstance()->getFormat() == Video::PAL)
@@ -131,6 +132,9 @@ int VLiveBanner::handleCommand(int command)
       return 4;
     }
     case Remote::DF_UP:
+    {
+      if (!takeCommands) return 0; // banner was auto, old remote
+    } // else drop through
     case Remote::UP:
     {
       sl.up();
@@ -140,6 +144,9 @@ int VLiveBanner::handleCommand(int command)
       return 2;
     }
     case Remote::DF_DOWN:
+    {
+      if (!takeCommands) return 0; // banner was auto, old remote
+    } // else drop through
     case Remote::DOWN:
     {
       sl.down();
@@ -150,6 +157,8 @@ int VLiveBanner::handleCommand(int command)
     }
     case Remote::CHANNELUP:
     {
+      ViewMan::getInstance()->timedDelete(this, 0, 0); // cancel timer so this view is still here later
+
       Message* m = new Message();
       m->from = this;
       m->to = parent;
@@ -159,6 +168,8 @@ int VLiveBanner::handleCommand(int command)
     }
     case Remote::CHANNELDOWN:
     {
+      ViewMan::getInstance()->timedDelete(this, 0, 0);
+
       Message* m = new Message();
       m->from = this;
       m->to = parent;
index 9bb8741ad7e07be7ec31d8722767fd6af8cd3e28..d719f26de61f2395c532b3f03fa700d7885cab53 100644 (file)
@@ -40,7 +40,7 @@
 class VLiveBanner : public View
 {
   public:
-    VLiveBanner(View* parent, Channel* channel);
+    VLiveBanner(View* parent, Channel* channel, bool bannerTakesCommands);
     ~VLiveBanner();
     void delData();
 
@@ -54,6 +54,7 @@ class VLiveBanner : public View
     WSelectList sl;
     Channel* currentChannel;
     EventList* eventList;
+    bool takeCommands;
 
 };
 
index c0b5443cd3941aef300b964696072676ea0fed7c..c7f2b7bcf3a4e52e708297dd92c08df148e6ffcf 100644 (file)
@@ -418,7 +418,7 @@ int VRecordingList::handleCommand(int command)
     }
     case Remote::PLAY:
     {
-      if (doPlay()) return 2;
+      if (doResume()) return 2;
       return 1;
     }
 
index e0475c729f69869b3cb03c45a9f2b73ef789d134..95694dc385a2889d2e033e8722b89dfa6604b417 100644 (file)
@@ -29,9 +29,12 @@ VVideoLive::VVideoLive(ChannelList* tchanList, ULONG tstreamType)
   viewman = ViewMan::getInstance();
   chanList = tchanList;
   currentChannel = 0;
+  previousChannel = 0;
   unavailable = 0;
   unavailableView = NULL;
   streamType = tstreamType;
+  vlb = (VLiveBanner*)1; // Can't be NULL because then that is sent to ViewMan::remove and it takes the top view off .. FIXME!
+  epgmode=false;
   if (streamType == VDR::RADIO) player = new PlayerVideo(Command::getInstance(), 0, 1);
   else                          player = new PlayerVideo(Command::getInstance(), 0, 0);
 
@@ -83,8 +86,7 @@ int VVideoLive::handleCommand(int command)
     {
       if (unavailable) showUnavailable(0);
       else stop();
-      upChannel();
-      play();
+      channelChange(OFFSET, UP);
       return 2;
     }
     case Remote::DF_DOWN:
@@ -92,13 +94,22 @@ int VVideoLive::handleCommand(int command)
     {
       if (unavailable) showUnavailable(0);
       else stop();
-      downChannel();
-      play();
+      channelChange(OFFSET, DOWN);
       return 2;
     }
     case Remote::OK:
     {
-      doBanner();
+      doBanner(true);
+      return 2;
+    }
+    case Remote::GUIDE:
+    case Remote::RED:
+    {
+      if (!epgmode)
+      {
+        showEPG();
+      }
+      epgmode=!epgmode;
       return 2;
     }
 
@@ -115,37 +126,70 @@ int VVideoLive::handleCommand(int command)
   return 1;
 }
 
+void VVideoLive::channelChange(UCHAR changeType, UINT newData)
+{
+  UINT newChannel = 0;
+
+  if (changeType == INDEX)
+  {
+    newChannel = newData;
+  }
+  else if (changeType == NUMBER)
+  {
+    newChannel = channelIndexFromNumber(newData);
+  }
+  else if (changeType == OFFSET)
+  {
+    if (newData == UP) newChannel = upChannel();
+    else newChannel = downChannel();
+  }
+  else if (changeType == PREVIOUS)
+  {
+    newChannel = previousChannel;
+  }
+  else
+  {
+    return; // bad input!
+  }
+
+  previousChannel = currentChannel;
+  currentChannel = newChannel;
+
+  if (unavailable) showUnavailable(0);
+  else stop(1);
+  if(epgmode)
+    if(vepg)
+      vepg->setCurrentChannel((*chanList)[currentChannel]->name);
+  play();
+}
+
 void VVideoLive::processMessage(Message* m)
 {
   if (m->message == Message::CHANNEL_CHANGE)
   {
-    // check channel number is valid
-    currentChannel = channelIndexFromNumber(m->parameter);
-    if (unavailable) showUnavailable(0);
-    else stop();
-    play();
+    channelChange(NUMBER, m->parameter);
   }
   else if (m->message == Message::CHANNEL_UP)
   {
-    // from vlivebanner
-    if (unavailable) showUnavailable(0);
-    else stop(1);
-    upChannel();
-    play(1);
-    vlb->setChannel((*chanList)[currentChannel]);
-    vlb->draw();
-    vlb->show();
+    // this message is from vlivebanner
+    channelChange(OFFSET, UP);
+    if(!epgmode)
+    {
+      vlb->setChannel((*chanList)[currentChannel]);
+      vlb->draw();
+      vlb->show();
+    }
   }
   else if (m->message == Message::CHANNEL_DOWN)
   {
-    // from vlivebanner
-    if (unavailable) showUnavailable(0);
-    else stop(1);
-    downChannel();
-    play(1);
-    vlb->setChannel((*chanList)[currentChannel]);
-    vlb->draw();
-    vlb->show();
+    // this message is from vlivebanner
+    channelChange(OFFSET, DOWN);
+    if(!epgmode)
+    {
+      vlb->setChannel((*chanList)[currentChannel]);
+      vlb->draw();
+      vlb->show();
+    }
   }
   else if (m->message == Message::STREAM_END)
   {
@@ -155,9 +199,11 @@ void VVideoLive::processMessage(Message* m)
   }
 }
 
-void VVideoLive::doBanner()
+void VVideoLive::doBanner(bool bannerTakesCommands)
 {
-  vlb = new VLiveBanner(this, (*chanList)[currentChannel]);
+  if(epgmode)
+    return;
+  vlb = new VLiveBanner(this, (*chanList)[currentChannel], bannerTakesCommands);
   viewman->timedDelete(vlb, 4, 0);
 
   Message* m = new Message();
@@ -207,12 +253,6 @@ void VVideoLive::showUnavailable(int active)
   }
 }
 
-void VVideoLive::setChannel(int number)
-{
-  currentChannel = channelIndexFromNumber(number);
-  play();
-}
-
 void VVideoLive::play(int noShowVLB)
 {
   showUnavailable(0);
@@ -222,38 +262,43 @@ void VVideoLive::play(int noShowVLB)
   if (!available)
   {
     showUnavailable(1);
-    if (!noShowVLB) doBanner();
+    if (!noShowVLB) doBanner(false);
   }
   else
   {
-    if (!noShowVLB) doBanner();
+    if (!noShowVLB) doBanner(false);
     player->play();
   }
 }
 
 void VVideoLive::stop(int noRemoveVLB)
 {
+printf("1\n");
   if (unavailable) return;
+printf("2\n");
   if (!noRemoveVLB) viewman->removeView(vlb, 1); // if live banner is present, remove it. won't cause damage if its not present
+printf("3\n");
 
   player->stop();
+printf("4\n");
   vdr->stopStreaming();
+printf("5\n");
 }
 
-int VVideoLive::upChannel()
+UINT VVideoLive::upChannel()
 {
-  if (currentChannel == (chanList->size() - 1)) return 0; // at the end
-
-  ++currentChannel;
-  return 1;
+  if (currentChannel == (chanList->size() - 1)) // at the end
+    return 0; // so go to start
+  else
+    return currentChannel + 1;
 }
 
-int VVideoLive::downChannel()
+UINT VVideoLive::downChannel()
 {
-  if (currentChannel == 0) return 0; // at the start
-
-  --currentChannel;
-  return 1;
+  if (currentChannel == 0) // at the start
+    return chanList->size() - 1; // so go to end
+  else
+    return currentChannel - 1;
 }
 
 UINT VVideoLive::channelIndexFromNumber(int number)
@@ -265,3 +310,24 @@ UINT VVideoLive::channelIndexFromNumber(int number)
   return 0;
 }
 
+UINT VVideoLive::getCurrentChannelIndex()
+{
+  return channelIndexFromNumber(currentChannel);
+}
+
+void VVideoLive::showEPG()
+{
+  if (unavailable) showUnavailable(0);
+  vepg = new VEpg(this, currentChannel);
+  ViewMan::getInstance()->addNoLock(vepg);
+  Video::getInstance()->setMode(Video::QUARTER);
+  Video::getInstance()->setPosition(170, 5); //TODO need to deal with 4:3 switching
+  vepg->draw();
+  vepg->show();
+}
+
+void VVideoLive::setEpgMode(bool mode)
+{
+  epgmode = mode;
+}
+
index 7ef9cb530f34059efa5c9622536385f31e4974de..60e7e738ef238f08e132ab71777bb08d095b2292 100644 (file)
 #include "vinfo.h"
 #include "command.h"
 #include "i18n.h"
+#include "vepg.h"
+#include "wtextbox.h"
+
+class VEpg;
 
 class VVideoLive : public View
 {
@@ -48,10 +52,22 @@ class VVideoLive : public View
     int handleCommand(int command);
     void processMessage(Message* m);
 
-    void setChannel(int number);
+    void channelChange(UCHAR changeType, UINT newData);
+    // changeType = INDEX = (newData is a channel index in the list)
+    //            = NUMBER = (newData is a real channel number)
+    //            = OFFSET = (newData is UP or DOWN)
 
     void play(int noShowVLB = 0);
     void stop(int noRemoveVLB = 0);
+    UINT getCurrentChannelIndex();
+    void setEpgMode(bool mode);
+
+    const static UCHAR INDEX = 1;
+    const static UCHAR NUMBER = 2;
+    const static UCHAR OFFSET = 3;
+    const static UCHAR PREVIOUS = 4;
+    const static UCHAR UP = 1;
+    const static UCHAR DOWN = 2;
 
   private:
     static VVideoLive* instance;
@@ -60,16 +76,21 @@ class VVideoLive : public View
     Player* player;
     ChannelList* chanList;
     UINT currentChannel;
+    UINT previousChannel;
     int unavailable;
     VInfo* unavailableView;
     ULONG streamType;
     VLiveBanner* vlb;
 
-    int upChannel();
-    int downChannel();
-    void doBanner();
+    UINT upChannel();
+    UINT downChannel();
+    void doBanner(bool takesCommands);
     void showUnavailable(int active);
     UINT channelIndexFromNumber(int number);
+    VEpg* vepg;
+    int xpos;
+    bool epgmode;
+    void showEPG();
 };
 
 #endif
index 3e833fe80ed259770983e1c4ab4de45d34657d31..a5255192b9cbed83b23d37ba4ae759cc65a414e6 100644 (file)
--- a/widget.cc
+++ b/widget.cc
@@ -38,3 +38,13 @@ void Widget::setDimensions(int twidth, int theight)
   area.w = twidth;
   area.h = theight;
 }
+
+int Widget::getOffsetY()
+{
+  return offsetY;
+}
+
+int Widget::getOffsetX()
+{
+  return offsetX;
+}
index 29f12e51faaa995f867998d476dd1892ae0f4f61..fee77ddd46612f5f422670459ca6e0126843d8b4 100644 (file)
--- a/widget.h
+++ b/widget.h
@@ -34,6 +34,9 @@ class Widget : public Box
     virtual void draw()=0;
     void setSurface(Surface* tsurface);
     void setDimensions(int width, int height);
+    int getOffsetY();
+    int getOffsetX();
+
 
   private:
 
diff --git a/wtextbox.cc b/wtextbox.cc
new file mode 100644 (file)
index 0000000..d64f5e9
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+#include "wtextbox.h"\r
+\r
+WTextbox::WTextbox()\r
+{\r
+  int fontHeight = Surface::getFontHeight();\r
+  setDimensions(70, fontHeight);\r
+  setDimensions(100,100);\r
+  text = NULL;\r
+  foreColour = Colour::LIGHTTEXT;\r
+  backColour = Colour::VIEWBACKGROUND;\r
+}\r
+\r
+WTextbox::~WTextbox()\r
+{\r
+  if (text) delete[] text; //TODO is this needed?\r
+}\r
+\r
+void WTextbox::setText(char* takeText)\r
+{\r
+  int length = strlen(takeText);\r
+  text = new char[length + 1];\r
+  strcpy(text, takeText);\r
+}\r
+\r
+void WTextbox::setBackgroundColour(Colour bcolour)\r
+{\r
+  backColour = bcolour;\r
+}\r
+\r
+void WTextbox::setForegroundColour(Colour fcolour)\r
+{\r
+  foreColour = fcolour;\r
+}\r
+\r
+void WTextbox::draw()\r
+{\r
+  fillColour(backColour);\r
+  if (text)\r
+    drawPara(text, 5, 2, foreColour);\r
+}\r
+\r
diff --git a/wtextbox.h b/wtextbox.h
new file mode 100644 (file)
index 0000000..bfbf865
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+    Copyright 2004-2005 Chris Tallon\r
+\r
+    This file is part of VOMP.\r
+\r
+    VOMP is free software; you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation; either version 2 of the License, or\r
+    (at your option) any later version.\r
+\r
+    VOMP is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with VOMP; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+*/\r
+\r
+#ifndef WTEXTBOX_H\r
+#define WTEXTBOX_H\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#include "defines.h"\r
+#include "widget.h"\r
+#include "colour.h"\r
+\r
+class WTextbox : public Widget\r
+{\r
+  public:\r
+    WTextbox();\r
+    ~WTextbox();\r
+    void setText(char* text);\r
+    void draw();\r
+    void setBackgroundColour(Colour bcolour);\r
+    void setForegroundColour(Colour fcolour);\r
+\r
+  private:\r
+\r
+    char* text;\r
+    Colour foreColour;\r
+    Colour backColour;\r
+};\r
+\r
+#endif\r