From 7bc4a59528ab13f3062dc1520e76f9ecedd87400 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Sat, 14 May 2005 15:23:23 +0000 Subject: [PATCH] - work on timers - add eInput widget - add python/Tools - add flexible listbox content --- RecordTimer.py | 109 ++++++++++++++----- keymap.xml | 9 ++ lib/gdi/font.h | 7 ++ lib/gui/Makefile.am | 3 +- lib/gui/einput.cpp | 208 +++++++++++++++++++++++++++++++++++++ lib/gui/einput.h | 80 ++++++++++++++ lib/gui/elabel.h | 2 +- lib/gui/elistbox.cpp | 12 ++- lib/gui/elistbox.h | 2 + lib/gui/elistboxcontent.cpp | 118 ++++++++++++++++++++- lib/gui/elistboxcontent.h | 12 ++- lib/python/Components/TimeInput.py | 18 ++++ lib/python/Components/TimerList.py | 57 ++++++++++ lib/python/Components/__init__.py | 2 +- lib/python/Screens/Menu.py | 4 +- lib/python/Screens/Screen.py | 1 - lib/python/Screens/TimerEdit.py | 54 ++++++++++ lib/python/Screens/__init__.py | 3 +- lib/python/Tools/.cvsignore | 1 + lib/python/Tools/FuzzyDate.py | 39 +++++++ lib/python/Tools/XMLTools.py | 17 +++ lib/python/Tools/__init__.py | 1 + lib/python/enigma_python.i | 3 + lib/service/iservice.h | 3 + mytest.py | 77 ++------------ skin.py | 27 +++-- timer.py | 52 +++++----- 27 files changed, 774 insertions(+), 147 deletions(-) create mode 100644 lib/gui/einput.cpp create mode 100644 lib/gui/einput.h create mode 100644 lib/python/Components/TimeInput.py create mode 100644 lib/python/Components/TimerList.py create mode 100644 lib/python/Screens/TimerEdit.py create mode 100644 lib/python/Tools/.cvsignore create mode 100644 lib/python/Tools/FuzzyDate.py create mode 100644 lib/python/Tools/XMLTools.py create mode 100644 lib/python/Tools/__init__.py diff --git a/RecordTimer.py b/RecordTimer.py index ad7fa56..0d3d53d 100644 --- a/RecordTimer.py +++ b/RecordTimer.py @@ -1,66 +1,123 @@ -from timer import * import time +import codecs + +from timer import * +import xml.dom.minidom + +import NavigationInstance + +from Tools.XMLTools import elementsWithTag +from ServiceReference import ServiceReference class RecordTimerEntry(TimerEntry): - def __init__(self, begin, end, nav, serviceref, epg): - TimerEntry.__init__(self, begin, end) - self.ServiceRef = serviceref - self.EpgData = epg - self.Timer = None - self.Nav = nav - self.RecordService = None + def __init__(self, begin, end, serviceref, epg): + TimerEntry.__init__(self, int(begin), int(end)) + + assert isinstance(serviceref, ServiceReference) + + self.service_ref = serviceref + + print self.service_ref.getServiceName() + self.epg_data = epg + self.timer = None + self.record_service = None # build filename from epg # pff das geht noch nicht... - if epg == None: - self.Filename = "recording.ts" - else: - self.Filename = "record_" + str(epg.m_event_name) + ".ts" - - print "------------ record filename: %s" % (self.Filename) +# if epg == None: +# self.Filename = "recording.ts" +# else: +# self.Filename = "record_" + str(epg.m_event_name) + ".ts" +# +# print "------------ record filename: %s" % (self.Filename) def activate(self, event): if event == self.EventPrepare: - self.RecordService = self.Nav.recordService(self.ServiceRef) - if self.RecordService == None: + self.record_service = NavigationInstance.instance.recordService(self.service_ref) + if self.record_service == None: print "timer record failed." else: - self.RecordService.prepare() - elif self.RecordService == None: + self.record_service.prepare() + elif self.record_service == None: if event != self.EventAbort: print "timer record start failed, can't finish recording." elif event == self.EventStart: - self.RecordService.start() + self.record_service.start() print "timer started!" elif event == self.EventEnd or event == self.EventAbort: - self.RecordService.stop() - self.RecordService = None + self.record_service.stop() + self.record_service = None print "Timer successfully ended" + +def createTimer(xml): + begin = int(xml.getAttribute("begin")) + end = int(xml.getAttribute("end")) + serviceref = ServiceReference(str(xml.getAttribute("serviceref"))) + epgdata = xml.getAttribute("epgdata") + #filename = xml.getAttribute("filename") + return RecordTimerEntry(begin, end, serviceref, epgdata) + class RecordTimer(Timer): def __init__(self): Timer.__init__(self) + self.Filename = "timers.xml" + +# try: + self.loadTimer() +# except: +# print "unable to load timers from file!" + def loadTimer(self): - print "TODO: load timers from xml" + + # TODO: PATH! + doc = xml.dom.minidom.parse(self.Filename) + + root = doc.childNodes[0] + for timer in elementsWithTag(root.childNodes, "timer"): + self.record(createTimer(timer)) def saveTimer(self): - print "TODO: save timers to xml" + doc = xml.dom.minidom.Document() + root_element = doc.createElement('timers') + doc.appendChild(root_element) + root_element.appendChild(doc.createTextNode("\n")) + + for timer in self.timer_list + self.processed_timers: + t = doc.createTextNode("\t") + root_element.appendChild(t) + t = doc.createElement('timer') + t.setAttribute("begin", str(timer.begin)) + t.setAttribute("end", str(timer.end)) + t.setAttribute("serviceref", str(timer.service_ref)) + #t.setAttribute("epgdata", timer.) + root_element.appendChild(t) + t = doc.createTextNode("\n") + root_element.appendChild(t) + + file = open(self.Filename, "w") + doc.writexml(codecs.getwriter('UTF-8')(file)) + file.close() def record(self, entry): entry.Timer = self self.addTimerEntry(entry) def removeEntry(self, entry): - if entry.State == TimerEntry.StateRunning: + if entry.state == TimerEntry.StateRunning: entry.End = time.time() print "aborting timer" - elif entry.State != TimerEntry.StateEnded: + elif entry.state != TimerEntry.StateEnded: entry.activate(TimerEntry.EventAbort) - self.TimerList.remove(entry) + self.timer_list.remove(entry) print "timer did not yet start - removing" else: print "timer did already end - doing nothing." self.calcNextActivation() + + + def shutdown(self): + self.saveTimer() diff --git a/keymap.xml b/keymap.xml index 2b5f92c..7b6e5fd 100644 --- a/keymap.xml +++ b/keymap.xml @@ -9,6 +9,15 @@ + + + + + + + + + diff --git a/lib/gdi/font.h b/lib/gdi/font.h index ff2a88c..c55b8f4 100644 --- a/lib/gdi/font.h +++ b/lib/gdi/font.h @@ -130,9 +130,16 @@ public: return boundBox; } + + const int size() const + { + return glyphs.size(); + } const eRect& getGlyphBBox(int num) const { + assert(num >= 0); + assert(num < (int)glyphs.size()); return glyphs[num].bbox; } }; diff --git a/lib/gui/Makefile.am b/lib/gui/Makefile.am index 44f5a16..24f7067 100644 --- a/lib/gui/Makefile.am +++ b/lib/gui/Makefile.am @@ -7,6 +7,7 @@ noinst_LIBRARIES = libenigma_gui.a libenigma_gui_a_SOURCES = \ ebutton.cpp elabel.cpp eslider.cpp ewidget.cpp ewidgetdesktop.cpp \ ewindow.cpp ewindowstyle.cpp elistbox.cpp elistboxcontent.cpp \ - epixmap.cpp ewindowstyleskinned.cpp + epixmap.cpp ewindowstyleskinned.cpp einput.cpp + diff --git a/lib/gui/einput.cpp b/lib/gui/einput.cpp new file mode 100644 index 0000000..b2c8ad1 --- /dev/null +++ b/lib/gui/einput.cpp @@ -0,0 +1,208 @@ +#include +#include +#include + +eInput::eInput(eWidget *parent): eLabel(parent) +{ + /* default to center alignment */ + m_valign = alignCenter; + m_halign = alignCenter; + + ePtr ptr; + eActionMap::getInstance(ptr); + ptr->bindAction("InputActions", 0, 0, this); +} + +eInput::~eInput() +{ + ePtr ptr; + eActionMap::getInstance(ptr); + ptr->unbindAction(this, 0); +} + +void eInput::setContent(eInputContent *content) +{ + if (m_content) + m_content->setInput(0); + m_content = content; + if (m_content) + m_content->setInput(this); +} + +int eInput::event(int event, void *data, void *data2) +{ + switch (event) + { + case evtPaint: + { + gPainter &painter = *(gPainter*)data2; + ePtr style; + + getStyle(style); + + eWidget::event(event, data, data2); + + ePtr para = new eTextPara(eRect(0, 0, size().width(), size().height())); + + std::string text; + int cursor = -1; + + if (m_content) + m_content->getDisplay(text, cursor); + + eDebug("cursor is %d", cursor); + para->setFont(m_font); + para->renderString(text, 0); + + int glyphs = para->size(); + eRect bbox; + if (cursor < glyphs) + { + bbox = para->getGlyphBBox(cursor); + bbox = eRect(bbox.left()-1, 0, 2, size().height()); + } else + { + bbox = para->getGlyphBBox(cursor - 1); + bbox = eRect(bbox.right(), 0, 2, size().height()); + } + painter.fill(bbox); + + painter.renderPara(para, ePoint(0, 0)); + + return 0; + } + case evtAction: + if (isVisible()) + { + switch((int)data2) + { + case moveLeft: + m_content->moveCursor(eInputContent::dirLeft); + break; + case moveRight: + m_content->moveCursor(eInputContent::dirRight); + break; + case moveHome: + m_content->moveCursor(eInputContent::dirHome); + break; + case moveEnd: + m_content->moveCursor(eInputContent::dirEnd); + break; + case deleteChar: + // not yet + break; + } + return 1; + } + return 0; + default: + break; + } + return eLabel::event(event, data, data2); +} + +int eInput::getNumber() +{ + return atoi(m_text.c_str()); +} + +DEFINE_REF(eInputContentNumber); + +void eInputContent::setInput(eInput *widget) +{ + m_input = widget; +} + +eInputContentNumber::eInputContentNumber(int cur, int min, int max) +{ + m_min = min; + m_max = max; + m_value = cur; + m_cursor = 0; + m_input = 0; + recalcLen(); +} + +void eInputContentNumber::getDisplay(std::string &res, int &cursor) +{ + // TODO + char r[128]; + sprintf(r, "%d", m_value); + res = r; + cursor = m_cursor; +} + +void eInputContentNumber::moveCursor(int dir) +{ + eDebug("move cursor.."); + int old_cursor = m_cursor; + + switch (dir) + { + case dirLeft: + --m_cursor; + break; + case dirRight: + ++m_cursor; + break; + case dirHome: + m_cursor = 0; + break; + case dirEnd: + m_cursor = m_len; + break; + } + + if (m_cursor < 0) + m_cursor = 0; + if (m_cursor > m_len) + m_cursor = m_len; + + if (m_cursor != old_cursor) + if (m_input) + m_input->invalidate(); +} + +int eInputContentNumber::haveKey(int code) +{ + insertDigit(m_cursor, code); + recalcLen(); + return 0; +} + +int eInputContentNumber::isValid() +{ + return m_value >= m_min && m_value <= m_max; +} + +void eInputContentNumber::recalcLen() +{ + int v = m_value; + m_len = 0; + while (v) + { + ++m_len; + v /= 10; + } + + if (!m_len) /* zero */ + m_len = 1; +} + +void eInputContentNumber::insertDigit(int pos, int dig) +{ + /* get stuff left from cursor */ + int exp = 1; + int i; + for (i = 0; i < (m_len - pos - 1); ++i) + exp *= 10; + + /* now it's 1...max */ + int left = m_value / exp; + int right = m_value % exp; + left *= 10; + left += dig; + left *= exp; + left += right; + m_value = left; +} diff --git a/lib/gui/einput.h b/lib/gui/einput.h new file mode 100644 index 0000000..b742a6d --- /dev/null +++ b/lib/gui/einput.h @@ -0,0 +1,80 @@ +#ifndef __lib_gui_einput_h +#define __lib_gui_einput_h + +#include +#include + +class eInputContent; + +class eInput: public eLabel +{ +public: + eInput(eWidget *parent); + virtual ~eInput(); + PSignal0 changed; + + int m_cursor; + + enum InputActions { + moveLeft, + moveRight, + moveHome, + moveEnd, + deleteChar + }; + + void setContent(eInputContent *cnt); + + int getNumber(); +protected: + ePtr m_content; + int event(int event, void *data=0, void *data2=0); +}; + +class eInputContent: public iObject +{ +public: + /* management stuff */ + void setInput(eInput *widget); + /* display stuff */ + virtual void getDisplay(std::string &res, int &cursor)=0; + + /* movement / user actions */ + enum { + dirLeft, dirRight, + dirHome, dirEnd, + /* contents can define their own directions */ + dirUser + }; + virtual void moveCursor(int dir)=0; + /* no movement keys except stuff like '.' or so*/ + virtual int haveKey(int code)=0; + + virtual int isValid()=0; +protected: + eInput *m_input; +}; + +class eInputContentNumber: public eInputContent +{ + DECLARE_REF(eInputContentNumber); +public: + eInputContentNumber(int cur, int min, int max); + + void getDisplay(std::string &res, int &cursor); + void moveCursor(int dir); + int haveKey(int code); + int isValid(); + +private: + void recalcLen(); + + void insertDigit(int pos, int dig); + + int m_value; + int m_cursor, m_len; + + int m_min, m_max; +}; + +#endif diff --git a/lib/gui/elabel.h b/lib/gui/elabel.h index 7e07f43..c19eb0a 100644 --- a/lib/gui/elabel.h +++ b/lib/gui/elabel.h @@ -25,6 +25,7 @@ public: protected: ePtr m_font; int m_valign, m_halign; + std::string m_text; int event(int event, void *data=0, void *data2=0); private: enum eLabelEvent @@ -33,7 +34,6 @@ private: evtChangedFont, evtChangedAlignment }; - std::string m_text; }; #endif diff --git a/lib/gui/elistbox.cpp b/lib/gui/elistbox.cpp index ba2e352..4598fa0 100644 --- a/lib/gui/elistbox.cpp +++ b/lib/gui/elistbox.cpp @@ -9,6 +9,8 @@ eListbox::eListbox(eWidget *parent): eWidget(parent) ePtr ptr; eActionMap::getInstance(ptr); + m_itemheight = 20; + ptr->bindAction("ListboxActions", 0, 0, this); } @@ -146,11 +148,19 @@ int eListbox::event(int event, void *data, void *data2) void eListbox::recalcSize() { - m_itemheight = 20; m_content->setSize(eSize(size().width(), m_itemheight)); m_items_per_page = size().height() / m_itemheight; } +void eListbox::setItemHeight(int h) +{ + if (h) + m_itemheight = h; + else + m_itemheight = 20; + recalcSize(); +} + void eListbox::entryAdded(int index) { /* manage our local pointers. when the entry was added before the current position, we have to advance. */ diff --git a/lib/gui/elistbox.h b/lib/gui/elistbox.h index 9e23bde..29349cb 100644 --- a/lib/gui/elistbox.h +++ b/lib/gui/elistbox.h @@ -73,6 +73,8 @@ public: pageDown, justCheck }; + + void setItemHeight(int h); #ifndef SWIG /* entryAdded: an entry was added *before* the given index. it's index is the given number. */ diff --git a/lib/gui/elistboxcontent.cpp b/lib/gui/elistboxcontent.cpp index d51729d..54e3a24 100644 --- a/lib/gui/elistboxcontent.cpp +++ b/lib/gui/elistboxcontent.cpp @@ -377,6 +377,11 @@ PyObject *eListboxPythonStringContent::getCurrentSelection() return r; } +void eListboxPythonStringContent::invalidateEntry(int index) +{ + m_listbox->entryChanged(index); +} + ////////////////////////////////////// void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) @@ -424,8 +429,117 @@ void eListboxPythonConfigContent::paint(gPainter &painter, eWindowStyle &style, painter.clippop(); } -void eListboxPythonConfigContent::invalidateEntry(int index) +////////////////////////////////////// + +void eListboxPythonMultiContent::paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected) { - m_listbox->entryChanged(index); + painter.clip(eRect(offset, m_itemsize)); + style.setStyle(painter, selected ? eWindowStyle::styleListboxSelected : eWindowStyle::styleListboxNormal); + painter.clear(); + + if (m_list && cursorValid()) + { + PyObject *items = PyList_GetItem(m_list, m_cursor); // borrowed reference! + + if (!items) + { + eDebug("eListboxPythonMultiContent: error getting item %d", m_cursor); + painter.clippop(); + return; + } + + if (!PyList_Check(items)) + { + eDebug("eListboxPythonMultiContent: list entry %d is not a list", m_cursor); + painter.clippop(); + return; + } + + int size = PyList_Size(items); + for (int i = 0; i < size; ++i) + { + PyObject *item = PyList_GetItem(items, i); // borrowed reference! + + if (!item) + { + eDebug("eListboxPythonMultiContent: ?"); + painter.clippop(); + return; + } + + + PyObject *px, *py, *pwidth, *pheight, *pfnt, *pstring, *pflags; + + /* + we have a list of tuples: + + (x, y, width, height, fnt, flags, "bla" ), + + */ + + if (!PyTuple_Check(item)) + { + eDebug("eListboxPythonMultiContent did not receive a tuple."); + painter.clippop(); + return; + } + + px = PyTuple_GetItem(item, 0); + py = PyTuple_GetItem(item, 1); + pwidth = PyTuple_GetItem(item, 2); + pheight = PyTuple_GetItem(item, 3); + pfnt = PyTuple_GetItem(item, 4); + pflags = PyTuple_GetItem(item, 5); + pstring = PyTuple_GetItem(item, 6); + + if (!(px && py && pwidth && pheight && pfnt && pstring)) + { + eDebug("eListboxPythonMultiContent received too small tuple (must be (x, y, width, height, fnt, flags, string[, ...])"); + painter.clippop(); + return; + } + + pstring = PyObject_Str(pstring); + + const char *string = (PyString_Check(pstring)) ? PyString_AsString(pstring) : ""; + + int x = PyInt_AsLong(px); + int y = PyInt_AsLong(py); + int width = PyInt_AsLong(pwidth); + int height = PyInt_AsLong(pheight); + int flags = PyInt_AsLong(pflags); + + int fnt = PyInt_AsLong(pfnt); + + if (m_font.find(fnt) == m_font.end()) + { + eDebug("eListboxPythonMultiContent: specified font %d was not found!", fnt); + Py_XDECREF(pstring); + painter.clippop(); + return; + } + + eRect r = eRect(x, y, width, height); + r.moveBy(offset); + + painter.setFont(m_font[fnt]); + + painter.renderText(r, string, flags); + + Py_XDECREF(pstring); + + if (selected) + style.drawFrame(painter, eRect(offset, m_itemsize), eWindowStyle::frameListboxEntry); + } + } + + painter.clippop(); } +void eListboxPythonMultiContent::setFont(int fnt, gFont *font) +{ + if (font) + m_font[fnt] = font; + else + m_font.erase(fnt); +} diff --git a/lib/gui/elistboxcontent.h b/lib/gui/elistboxcontent.h index 0c4cb00..6a4cdaa 100644 --- a/lib/gui/elistboxcontent.h +++ b/lib/gui/elistboxcontent.h @@ -103,6 +103,7 @@ protected: /* the following functions always refer to the selected item */ virtual void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected); + void invalidateEntry(int index); protected: PyObject *m_list; @@ -115,10 +116,19 @@ class eListboxPythonConfigContent: public eListboxPythonStringContent { public: void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected); - void invalidateEntry(int index); void setSeperation(int sep) { m_seperation = sep; } private: int m_seperation; }; +class eListboxPythonMultiContent: public eListboxPythonStringContent +{ +public: + void paint(gPainter &painter, eWindowStyle &style, const ePoint &offset, int selected); + + void setFont(int fnt, gFont *fnt); +private: + std::map > m_font; +}; + #endif diff --git a/lib/python/Components/TimeInput.py b/lib/python/Components/TimeInput.py new file mode 100644 index 0000000..c520fdf --- /dev/null +++ b/lib/python/Components/TimeInput.py @@ -0,0 +1,18 @@ +from HTMLComponent import * +from GUIComponent import * +from VariableText import * + +from enigma import eInput, eInputContentNumber + +class TimeInput(HTMLComponent, GUIComponent): + def __init__(self): + GUIComponent.__init__(self) + self.content = eInputContentNumber(12, 0, 15) + + def GUIcreate(self, parent, skindata): + self.instance = eInput(parent) + self.instance.setContent(self.content) + + def GUIdelete(self): + self.instance.setContent(None) + self.instance = None diff --git a/lib/python/Components/TimerList.py b/lib/python/Components/TimerList.py new file mode 100644 index 0000000..da005b0 --- /dev/null +++ b/lib/python/Components/TimerList.py @@ -0,0 +1,57 @@ +from HTMLComponent import * +from GUIComponent import * + +from Tools.FuzzyDate import FuzzyTime + +from enigma import eListboxPythonMultiContent, eListbox, gFont + + +RT_HALIGN_LEFT = 0 +RT_HALIGN_RIGHT = 1 +RT_HALIGN_CENTER = 2 +RT_HALIGN_BLOCK = 4 + +RT_VALIGN_TOP = 0 +RT_VALIGN_CENTER = 8 +RT_VALIGN_BOTTOM = 16 + +RT_WRAP = 32 + + +# +# | | +# | | +# +def TimerEntry(timer, processed): + res = [ ] + + res.append((0, 0, 400, 30, 0, RT_HALIGN_LEFT, timer.service_ref.getServiceName())) + res.append((0, 30, 200, 20, 1, RT_HALIGN_LEFT, "%s, %s" % FuzzyTime(timer.begin))) + + if processed: + res.append((200, 30, 200, 20, 1, RT_HALIGN_RIGHT, FuzzyTime(timer.end)[1])) + else: + res.append((200, 30, 200, 20, 1, RT_HALIGN_RIGHT, "done")) + return res + +class TimerList(HTMLComponent, GUIComponent): + def __init__(self, list): + GUIComponent.__init__(self) + self.l = eListboxPythonMultiContent() + self.l.setList(list) + self.l.setFont(0, gFont("Arial", 20)) + self.l.setFont(1, gFont("Arial", 18)) + + def getCurrent(self): + return self.l.getCurrentSelection() + + def GUIcreate(self, parent, skindata): + self.instance = eListbox(parent) + self.instance.setContent(self.l) + self.instance.setItemHeight(50) + + def GUIdelete(self): + self.instance.setContent(None) + self.instance = None + + diff --git a/lib/python/Components/__init__.py b/lib/python/Components/__init__.py index 8a064b2..d7cd406 100644 --- a/lib/python/Components/__init__.py +++ b/lib/python/Components/__init__.py @@ -3,5 +3,5 @@ __all__ = ["ActionMap", "Button", "Clock", "ConfigList", "EventInfo", "GUIComponent", "GUISkin", "HTMLComponent", "HTMLSkin", "Header", "Label", "MenuList", "PerServiceDisplay", "ProgressBar", "ServiceList", "ServiceName", "ServiceScan", "VariableText", "VariableValue", "VolumeBar", - "components", "config"] + "components", "config", "TimerList", "TimeInput" ] diff --git a/lib/python/Screens/Menu.py b/lib/python/Screens/Menu.py index ce73a95..c380931 100644 --- a/lib/python/Screens/Menu.py +++ b/lib/python/Screens/Menu.py @@ -11,6 +11,8 @@ from Components.Label import Label from Components.ProgressBar import ProgressBar from ConfigMenu import * +from TimerEdit import * + from enigma import quitMainloop import xml.dom.minidom @@ -32,7 +34,7 @@ mdom = xml.dom.minidom.parseString( self.setModeRadio() self.setModeFile() self.openDialog(ScartLoopThrough) - + self.openDialog(TimerEditList) diff --git a/lib/python/Screens/Screen.py b/lib/python/Screens/Screen.py index ef9b2bb..1b42141 100644 --- a/lib/python/Screens/Screen.py +++ b/lib/python/Screens/Screen.py @@ -29,7 +29,6 @@ class Screen(dict, HTMLSkin, GUISkin): del self.session for (name, val) in self.items(): - print "%s -> %d" % (name, sys.getrefcount(val)) del self[name] def close(self, retval=None): diff --git a/lib/python/Screens/TimerEdit.py b/lib/python/Screens/TimerEdit.py new file mode 100644 index 0000000..41b6a12 --- /dev/null +++ b/lib/python/Screens/TimerEdit.py @@ -0,0 +1,54 @@ +from Screen import Screen +from Components.TimerList import TimerList, TimerEntry +from Components.ActionMap import ActionMap +from Components.TimeInput import TimeInput +from Components.Label import Label +from Components.Button import Button + +class TimerEdit(Screen): + def __init__(self, session, entry): + Screen.__init__(self, session) + + self["actions"] = ActionMap(["OkCancelActions"], + { + "ok": self.apply, + "cancel": self.close + }) + + self.entry = entry + # begin, end, description, service + self["begin"] = TimeInput() + self["end"] = TimeInput() + + self["lbegin"] = Label("Begin") + self["lend"] = Label("End") + + self["description"] = Label("bla") +# TextInput() + self["apply"] = Button("Apply") + self["service"] = Button() + + def apply(self): + print "applied!" + +class TimerEditList(Screen): + def __init__(self, session): + Screen.__init__(self, session) + + list = [ ] + for timer in session.nav.RecordTimer.timer_list: + list.append(TimerEntry(timer, 0)) + + for timer in session.nav.RecordTimer.processed_timers: + list.append(TimerEntry(timer, 1)) + + self["timerlist"] = TimerList(list) + + self["actions"] = ActionMap(["OkCancelActions"], + { + "ok": self.openEdit, + "cancel": self.close + }) + + def openEdit(self): + self.session.open(TimerEdit, self["timerlist"].getCurrent()) diff --git a/lib/python/Screens/__init__.py b/lib/python/Screens/__init__.py index 90b22c2..fbd2c17 100644 --- a/lib/python/Screens/__init__.py +++ b/lib/python/Screens/__init__.py @@ -1,3 +1,4 @@ __all__ = ["ChannelSelection", "ClockDisplay", "ConfigMenu", - "InfoBar", "Menu", "ScartLoopThrough", "Screen", "ServiceScan"] + "InfoBar", "Menu", "ScartLoopThrough", "Screen", "ServiceScan", + "TimerEdit"] diff --git a/lib/python/Tools/.cvsignore b/lib/python/Tools/.cvsignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/lib/python/Tools/.cvsignore @@ -0,0 +1 @@ +*.pyc diff --git a/lib/python/Tools/FuzzyDate.py b/lib/python/Tools/FuzzyDate.py new file mode 100644 index 0000000..c5055ba --- /dev/null +++ b/lib/python/Tools/FuzzyDate.py @@ -0,0 +1,39 @@ +import time + +def FuzzyTime(t): + d = time.localtime(t) + nt = time.time() + n = time.localtime() + + if d[:3] == n[:3]: + # same day + date = "Today" + elif ((t - nt) < 7*86400) and (nt < t): + # same week + date = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")[d[6]] + elif d[0] == n[0]: + # same year + date = "%d.%d." % (d[2], d[1]) + else: + date = "%d.%d.%d" % (d[2], d[1], d[0]) + + timeres = "%d:%02d" % (d[3], d[4]) + + return (date, timeres) + +if __name__ == "__main__": + print "now: %s %s" % FuzzyDate(time.time()) + print "1 day: %s %s" % FuzzyDate(time.time() + 86400) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *2) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *3) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *4) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *5) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *6) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *7) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *8) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *9) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *10) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *11) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *12) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *13) + print "2 days: %s %s" % FuzzyDate(time.time() + 86400 *14) diff --git a/lib/python/Tools/XMLTools.py b/lib/python/Tools/XMLTools.py new file mode 100644 index 0000000..aaab467 --- /dev/null +++ b/lib/python/Tools/XMLTools.py @@ -0,0 +1,17 @@ +import xml.dom.minidom + +def elementsWithTag(el, tag): + + """filters all elements of childNode with the specified function + example: nodes = elementsWithTag(childNodes, lambda x: x == "bla")""" + + # fiiixme! (works but isn't nice) + if isinstance(tag, str): + s = tag + tag = lambda x: x == s + + for x in el: + if x.nodeType != xml.dom.minidom.Element.nodeType: + continue + if tag(x.tagName): + yield x diff --git a/lib/python/Tools/__init__.py b/lib/python/Tools/__init__.py new file mode 100644 index 0000000..4ff7ce3 --- /dev/null +++ b/lib/python/Tools/__init__.py @@ -0,0 +1 @@ +all = ["FuzzyDate.py", "XMLTools.py"] diff --git a/lib/python/enigma_python.i b/lib/python/enigma_python.i index 11faff1..6062c7d 100644 --- a/lib/python/enigma_python.i +++ b/lib/python/enigma_python.i @@ -48,6 +48,7 @@ is usually caused by not marking PSignals as immutable. #include #include +#include #include #include #include @@ -92,6 +93,7 @@ extern PSignal1 &keyPressedSignal(); // TODO: embed these... %immutable eButton::selected; +%immutable eInput::changed; %immutable eComponentScan::statusChanged; %immutable pNavigation::m_event; @@ -101,6 +103,7 @@ extern PSignal1 &keyPressedSignal(); %include %include %include +%include %include %include %include diff --git a/lib/service/iservice.h b/lib/service/iservice.h index 4379fbb..f7f6d5c 100644 --- a/lib/service/iservice.h +++ b/lib/service/iservice.h @@ -143,6 +143,9 @@ class iStaticServiceInformation: public iObject { public: virtual RESULT getName(const eServiceReference &ref, std::string &name)=0; + + // FOR SWIG + std::string getName(const eServiceReference &ref) { std::string temp; getName(ref, temp); return temp; } }; TEMPLATE_TYPEDEF(ePtr, iStaticServiceInformationPtr); diff --git a/mytest.py b/mytest.py index bfc015c..461fdfa 100644 --- a/mytest.py +++ b/mytest.py @@ -3,11 +3,13 @@ from tools import * import Screens.InfoBar -import RecordTimer - import sys import time +import ServiceReference + +from Navigation import Navigation + from skin import applyGUIskin # A screen is a function which instanciates all components of a screen into a temporary component. @@ -126,78 +128,11 @@ class Session: self.execBegin() def keyEvent(self, code): -# print "code " + str(code) - if code == 32: - self.currentDialog["okbutton"].instance.push() - - if code == 33: - self.currentDialog["channelSwitcher"].instance.push() - - if code >= 0x30 and code <= 0x39: - try: - self.currentDialog["menu"].instance.moveSelection(code - 0x31) - except: - self.currentDialog["list"].instance.moveSelection(code - 0x31) + print "code " + str(code) def close(self): self.delayTimer.start(0, 1) -# TODO: remove pNavgation, eNavigation and rewrite this stuff in python. -class Navigation: - def __init__(self): - self.pnav = pNavigation() - self.pnav.m_event.get().append(self.callEvent) - self.event = [ ] - self.currentlyPlayingService = None - - self.RecordTimer = RecordTimer.RecordTimer() - - def callEvent(self, i): - for x in self.event: - x(i) - - def playService(self, ref): - self.currentlyPlayingServiceReference = None - if not self.pnav.playService(ref): - self.currentlyPlayingServiceReference = ref - return 0 - return 1 - - def getCurrentlyPlayingServiceReference(self): - return self.currentlyPlayingServiceReference - - def recordService(self, ref): - service = iRecordableServicePtr() - print "recording service: %s" % (str(ref)) - if self.pnav.recordService(ref, service): - print "record returned non-zero" - return None - else: - print "ok, recordService didn't fail" - return service - - def enqueueService(self, ref): - return self.pnav.enqueueService(ref) - - def getCurrentService(self): - service = iPlayableServicePtr() - if self.pnav.getCurrentService(service): - return None - return service - - def getPlaylist(self): - playlist = ePlaylistPtr() - if self.pnav.getPlaylist(playlist): - return None - return playlist - - def pause(self, p): - return self.pnav.pause(p) - - def recordWithTimer(self, begin, end, ref, epg): - entry = RecordTimer.RecordTimerEntry(begin, end, self, ref, epg) - self.RecordTimer.record(entry) - return entry def runScreenTest(): session = Session() @@ -211,6 +146,8 @@ def runScreenTest(): runMainloop() + session.nav.shutdown() + return 0 import keymapparser diff --git a/skin.py b/skin.py index dc01e34..72cef1a 100644 --- a/skin.py +++ b/skin.py @@ -2,6 +2,7 @@ from enigma import * import xml.dom.minidom from xml.dom import EMPTY_NAMESPACE +from Tools.XMLTools import elementsWithTag colorNames = dict() @@ -71,6 +72,9 @@ dom = xml.dom.minidom.parseString( + + + @@ -99,23 +103,16 @@ dom = xml.dom.minidom.parseString( + + + + + + + + """) -# filters all elements of childNode with the specified function -# example: nodes = elementsWithTag(childNodes, lambda x: x == "bla") -def elementsWithTag(el, tag): - - # fiiixme! (works but isn't nice) - if tag.__class__ == "".__class__: - str = tag - tag = lambda x: x == str - - for x in el: - if x.nodeType != xml.dom.minidom.Element.nodeType: - continue - if tag(x.tagName): - yield x - def parsePosition(str): x, y = str.split(',') return ePoint(int(x), int(y)) diff --git a/timer.py b/timer.py index 294102b..023e4e3 100644 --- a/timer.py +++ b/timer.py @@ -14,47 +14,47 @@ class TimerEntry: StateEnded = 3 def __init__(self, begin, end): - self.Begin = begin - self.Prepare = 10 - self.End = end - self.State = 0 + self.begin = begin + self.prepare_time = 10 + self.end = end + self.state = 0 def getTime(self): - if self.State == 0: - return self.Begin - self.Prepare - elif self.State == 1: - return self.Begin + if self.state == 0: + return self.begin - self.prepare_time + elif self.state == 1: + return self.begin else: - return self.End + return self.end def __lt__(self, o): return self.getTime() < o.getTime() def activate(self, event): - print "timer %s got activated (%d)!" % (self.Description, event) + print "timer %s got activated (%d)!" % (self.description, event) class Timer: MaxWaitTime = 100 def __init__(self): - self.TimerList = [ ] - self.ProcessedTimers = [ ] + self.timer_list = [ ] + self.processed_timers = [ ] - self.Timer = eTimer() - self.Timer.timeout.get().append(self.calcNextActivation) + self.timer = eTimer() + self.timer.timeout.get().append(self.calcNextActivation) self.calcNextActivation() def addTimerEntry(self, entry): - bisect.insort(self.TimerList, entry) + bisect.insort(self.timer_list, entry) self.calcNextActivation() def setNextActivation(self, when): delay = int((when - time()) * 1000) print "next activation: %d (in %d seconds)" % (when, delay) - self.Timer.start(delay, 1) + self.timer.start(delay, 1) self.next = when def calcNextActivation(self): @@ -63,28 +63,28 @@ class Timer: min = int(time()) + self.MaxWaitTime # calculate next activation point - if len(self.TimerList): - w = self.TimerList[0].getTime() + if len(self.timer_list): + w = self.timer_list[0].getTime() if w < min: min = w self.setNextActivation(min) def doActivate(self, w): - w.activate(w.State) - self.TimerList.remove(w) - w.State += 1 - if w.State < TimerEntry.StateEnded: - bisect.insort(self.TimerList, w) + w.activate(w.state) + self.timer_list.remove(w) + w.state += 1 + if w.state < TimerEntry.StateEnded: + bisect.insort(self.timer_list, w) else: - bisect.insort(self.ProcessedTimers, w) + bisect.insort(self.processed_timers, w) def processActivation(self): t = int(time()) + 1 # we keep on processing the first entry until it goes into the future. - while len(self.TimerList) and self.TimerList[0].getTime() < t: - self.doActivate(self.TimerList[0]) + while len(self.timer_list) and self.timer_list[0].getTime() < t: + self.doActivate(self.timer_list[0]) #t = Timer() #base = time() + 5 -- 2.7.4