aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Domke <tmbinc@elitedvb.net>2005-01-23 23:14:14 +0000
committerFelix Domke <tmbinc@elitedvb.net>2005-01-23 23:14:14 +0000
commit4c9d04cb33fb06dfa075b431e36e7ea938a5f963 (patch)
treec2c74af99bbece5f62c4577beca11f27c2539ec3
parent9202d4248dd7df2f6e5eb53b4154c8297ec9b1d1 (diff)
downloadenigma2-4c9d04cb33fb06dfa075b431e36e7ea938a5f963.tar.gz
enigma2-4c9d04cb33fb06dfa075b431e36e7ea938a5f963.zip
- allow close of dialog
- some eWidget fixes - background for eWidgetDesktop - introduce "session" object
-rw-r--r--components.py89
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/gui/ewidget.cpp16
-rw-r--r--lib/gui/ewidgetdesktop.cpp26
-rw-r--r--lib/gui/ewidgetdesktop.h4
-rw-r--r--main/Makefile.am1
-rw-r--r--main/enigma.cpp1
-rw-r--r--mytest.py70
-rw-r--r--screens.py8
9 files changed, 183 insertions, 34 deletions
diff --git a/components.py b/components.py
index 8ae48068..4c26c0a0 100644
--- a/components.py
+++ b/components.py
@@ -1,5 +1,6 @@
from enigma import *
import time
+import sys
# some helper classes first:
class HTMLComponent:
@@ -20,12 +21,72 @@ class HTMLSkin:
return res
class GUISkin:
- data = { }
+ def __init__(self):
+ self.data = { }
+
def createGUIScreen(self, parent):
for (name, val) in self.items():
self.data[name] = { }
val.GUIcreate(self.data[name], parent, None)
+
+ def deleteGUIScreen(self):
+ for (name, val) in self.items():
+ w = self.data[name]["instance"]
+ val.GUIdelete(self.data[name])
+ del self.data[name]
+
+ # note: you'll probably run into this assert. if this happens, don't panic!
+ # yes, it's evil. I told you that programming in python is just fun, and
+ # suddently, you have to care about things you don't even know.
+ #
+ # but calm down, the solution is easy, at least on paper:
+ #
+ # Each Component, which is a GUIComponent, owns references to each
+ # instantiated eWidget (namely in screen.data[name]["instance"], in case
+ # you care.)
+ # on deleteGUIscreen, all eWidget *must* (!) be deleted (otherwise,
+ # well, problems appear. I don't want to go into details too much,
+ # but this would be a memory leak anyway.)
+ # The assert beyond checks for that. It asserts that the corresponding
+ # eWidget is about to be removed (i.e., that the refcount becomes 0 after
+ # running deleteGUIscreen).
+ # (You might wonder why the refcount is checked for 2 and not for 1 or 0 -
+ # one reference is still hold by the local variable 'w', another one is
+ # hold be the function argument to sys.getrefcount itself. So only if it's
+ # 2 at this point, the object will be destroyed after leaving deleteGUIscreen.)
+ #
+ # Now, how to fix this problem? You're holding a reference somewhere. (References
+ # can only be hold from Python, as eWidget itself isn't related to the c++
+ # way of having refcounted objects. So it must be in python.)
+ #
+ # It could be possible that you're calling deleteGUIscreen trough a call of
+ # a PSignal. For example, you could try to call session.close() in response
+ # to a Button::click. This will fail. (It wouldn't work anyway, as you would
+ # remove a dialog while running it. It never worked - enigma1 just set a
+ # per-mainloop variable on eWidget::close() to leave the exec()...)
+ # That's why Session supports delayed closes. Just call Session.close() and
+ # it will work.
+ #
+ # Another reason is that you just stored the data["instance"] somewhere. or
+ # added it into a notifier list and didn't removed it.
+ #
+ # If you can't help yourself, just ask me. I'll be glad to help you out.
+ # Sorry for not keeping this code foolproof. I really wanted to archive
+ # that, but here I failed miserably. All I could do was to add this assert.
+ assert sys.getrefcount(w) == 2, "too many refs hold to " + str(w)
+
+ def close(self):
+ self.deleteGUIScreen()
+ del self.data
+
+# note: components can be used in multiple screens, so we have kind of
+# two contexts: first the per-component one (self), then the per-screen (i.e.:
+# per eWidget one), called "priv". In "priv", for example, the instance
+# of the eWidget is stored.
+
+# GUI components have a "notifier list" of associated eWidgets to one component
+# (as said - one component instance can be used at multiple screens)
class GUIComponent:
""" GUI component """
@@ -38,6 +99,16 @@ class GUIComponent:
self.notifier.append(i)
if self.notifierAdded:
self.notifierAdded(i)
+
+ # GUIdelete must delete *all* references to the current component!
+ def GUIdelete(self, priv):
+ g = priv["instance"]
+ self.notifier.remove(g)
+ self.GUIdeleteInstance(g)
+ del priv["instance"]
+
+ def GUIdeleteInstance(self, priv):
+ pass
class VariableText:
"""VariableText can be used for components which have a variable text, based on any widget with setText call"""
@@ -107,19 +178,11 @@ class Button(HTMLComponent, GUIComponent, VariableText):
self.setText(text)
self.onClick = [ ]
- def clicked(self):
+ def push(self):
for x in self.onClick:
x()
return 0
-
- def GUIcreate(self, priv, parent, skindata):
- GUIComponent.GUIcreate(self, priv,parent, skindata)
- priv["instance"].selected.get().append(self.clicked)
- def click(self):
- for x in self.onClick:
- x()
-
# html:
def produceHTML(self):
return "<input type=\"submit\" text=\"" + self.getText() + "\">\n"
@@ -127,8 +190,11 @@ class Button(HTMLComponent, GUIComponent, VariableText):
# GUI:
def GUIcreateInstance(self, priv, parent, skindata):
g = eButton(parent)
-# g.clicked = [ self.click ]
+ g.selected.get().append(self.push)
return g
+
+ def GUIdeleteInstance(self, g):
+ g.selected.get().remove(self.push)
class Header(HTMLComponent, GUIComponent, VariableText):
@@ -155,4 +221,3 @@ class VolumeBar(HTMLComponent, GUIComponent, VariableValue):
g = eSlider(parent)
g.setRange(0, 100)
return g
-
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f33133b8..a09b9bc1 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1 +1 @@
-SUBDIRS = base dvb dvb_si gdi network service driver nav content gui python
+SUBDIRS = base dvb dvb_si gdi network service driver nav gui python
diff --git a/lib/gui/ewidget.cpp b/lib/gui/ewidget.cpp
index 3ebac357..7f089361 100644
--- a/lib/gui/ewidget.cpp
+++ b/lib/gui/ewidget.cpp
@@ -10,7 +10,7 @@ eWidget::eWidget(eWidget *parent): m_parent(parent ? parent->child() : 0)
if (m_parent)
m_vis = wVisShow;
-
+
if (m_parent)
{
m_parent->m_childs.push_back(this);
@@ -109,7 +109,17 @@ void eWidget::show()
void eWidget::hide()
{
+ /* TODO: when hiding an upper level widget, widgets get hidden but keep the */
+ /* wVisShow flag (because when the widget is shown again, the widgets must */
+ /* become visible again. */
+ if (!(m_vis & wVisShow))
+ return;
m_vis &= ~wVisShow;
+
+ /* this is a workaround to the above problem. when we are in the delete phase,
+ don't hide childs. */
+ if (!(m_parent || m_desktop))
+ return;
/* TODO: optimize here to only recalc what's required. possibly merge with show. */
eWidget *root = this;
@@ -137,9 +147,13 @@ void eWidget::destruct()
eWidget::~eWidget()
{
+ hide();
+
if (m_parent)
m_parent->m_childs.remove(this);
+ m_parent = 0;
+
/* destroy all childs */
ePtrList<eWidget>::iterator i(m_childs.begin());
while (i != m_childs.end())
diff --git a/lib/gui/ewidgetdesktop.cpp b/lib/gui/ewidgetdesktop.cpp
index bb6c7c39..1b5cf9b2 100644
--- a/lib/gui/ewidgetdesktop.cpp
+++ b/lib/gui/ewidgetdesktop.cpp
@@ -42,11 +42,10 @@ void eWidgetDesktop::calcWidgetClipRegion(eWidget *widget, gRegion &parent_visib
void eWidgetDesktop::recalcClipRegions()
{
- gRegion screen = gRegion(eRect(ePoint(0, 0), m_screen_size));
+ m_background_region = gRegion(eRect(ePoint(0, 0), m_screen_size));
for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
- calcWidgetClipRegion(*i, screen);
-// dumpRegion(screen);
+ calcWidgetClipRegion(*i, m_background_region);
}
void eWidgetDesktop::invalidate(const gRegion &region)
@@ -56,12 +55,33 @@ void eWidgetDesktop::invalidate(const gRegion &region)
m_dirty_region |= region;
}
+void eWidgetDesktop::setBackgroundColor(gColor col)
+{
+ m_background_color = col;
+
+ /* if there's something visible from the background, redraw it with the new color. */
+ if (m_dc && m_background_region.valid() && !m_background_region.empty())
+ {
+ /* todo: split out "setBackgroundColor / clear"... maybe? */
+ gPainter painter(m_dc);
+ painter.resetClip(m_background_region);
+ painter.setBackgroundColor(m_background_color);
+ painter.clear();
+ }
+}
+
void eWidgetDesktop::paint()
{
gPainter painter(m_dc);
/* walk all root windows. */
for (ePtrList<eWidget>::iterator i(m_root.begin()); i != m_root.end(); ++i)
i->doPaint(painter, m_dirty_region);
+ m_dirty_region &= m_background_region;
+
+ painter.resetClip(m_dirty_region);
+ painter.setBackgroundColor(m_background_color);
+ painter.clear();
+
m_dirty_region = gRegion();
}
diff --git a/lib/gui/ewidgetdesktop.h b/lib/gui/ewidgetdesktop.h
index 1354a86b..f76baf60 100644
--- a/lib/gui/ewidgetdesktop.h
+++ b/lib/gui/ewidgetdesktop.h
@@ -13,7 +13,9 @@ class eWidgetDesktop: public Object
public: // weil debug
eSize m_screen_size;
gRegion m_dirty_region;
+ gRegion m_background_region;
ePtr<gDC> m_dc;
+ gColor m_background_color;
public:
eWidgetDesktop(eSize screen);
~eWidgetDesktop();
@@ -25,6 +27,8 @@ public:
void paint();
void setDC(gDC *dc);
+ void setBackgroundColor(gColor col);
+
void setRedrawTask(eMainloop &ml);
private:
ePtrList<eWidget> m_root;
diff --git a/main/Makefile.am b/main/Makefile.am
index 46ce98b1..e0e7e79b 100644
--- a/main/Makefile.am
+++ b/main/Makefile.am
@@ -9,7 +9,6 @@ enigma2_SOURCES = \
enigma2_LDADD_WHOLE = \
$(top_builddir)/lib/base/libenigma_base.a \
- $(top_builddir)/lib/content/libenigma_content.a \
$(top_builddir)/lib/driver/libenigma_driver.a \
$(top_builddir)/lib/dvb/libenigma_dvb.a \
$(top_builddir)/lib/dvb_si/libenigma_dvb_si.a \
diff --git a/main/enigma.cpp b/main/enigma.cpp
index faff4d89..92982e5b 100644
--- a/main/enigma.cpp
+++ b/main/enigma.cpp
@@ -105,6 +105,7 @@ int main(int argc, char **argv)
eWidgetDesktop dsk(eSize(720, 576));
wdsk = &dsk;
+ dsk.setBackgroundColor(gColor(0));
dsk.setDC(my_dc);
#endif
diff --git a/mytest.py b/mytest.py
index 0cbeac02..54f0f862 100644
--- a/mytest.py
+++ b/mytest.py
@@ -29,7 +29,6 @@ screens["global"](components)
# test our screens
components["$001"] = screens["testDialog"]()
-components["$002"] = screens["clockDisplay"](components["clock"])
print "*** classes:"
dump(screens)
@@ -55,24 +54,65 @@ class GUIOutputDevice(OutputDevice):
def create(self, comp):
comp.createGUIScreen(self.parent)
-def runScreenTest():
- desktop = getDesktop()
-
- wnd = eWindow(desktop)
- mainwnd = wnd
- wnd.setTitle("Screen from python!")
- wnd.move(ePoint(300, 100))
- wnd.resize(eSize(300, 300))
+class Session:
+ def __init__(self):
+ self.desktop = None
+ self.delayTimer = eTimer()
+ self.delayTimer.timeout.get().append(self.processDelay)
+
+ def processDelay(self):
+ components[self.screenname].close()
+ if self.currentWindow != None:
+ self.currentWindow.hide()
+
+ del components[self.screenname]
+ del self.currentWindow
+
+
+ def open(self, screenname, screen):
+ components[screenname] = screen
+ self.screenname = screenname
+ screen.session = self
+
+ if self.desktop != None:
+ self.currentWindow = wnd = eWindow(self.desktop)
+ wnd.setTitle("Screen from python!")
+ wnd.move(ePoint(300, 100))
+ wnd.resize(eSize(300, 300))
+
+ gui = GUIOutputDevice()
+ gui.parent = wnd
+ gui.create(components["$002"])
+
+ applyGUIskin(components["$002"], None, "clockDialog")
+
+ wnd.show()
+ else:
+ self.currentWindow = None
+
+ def close(self):
+ self.delayTimer.start(0, 1)
- gui = GUIOutputDevice()
- gui.parent = wnd
- gui.create(components["$002"])
+def runScreenTest():
+ session = Session()
+ session.desktop = getDesktop()
+
+# components["$002"] = screens["clockDisplay"](components["clock"])
- applyGUIskin(components["$002"], None, "clockDialog")
+ session.open("$002", screens["clockDisplay"](components["clock"]))
- wnd.show()
-# components["$002"].data["okbutton"]["instance"].push()
+ def blub():
+# x = components["$002"]
+ components["$002"].data["okbutton"]["instance"].push()
+# dump(components)
+# print "session, close screen " + str(sys.getrefcount(x))
+# session.close()
+
+ tmr = eTimer()
+ tmr.timeout.get().append(blub)
+ tmr.start(4000, 1)
+
runMainloop()
return 0
diff --git a/screens.py b/screens.py
index 7287898d..b68f669e 100644
--- a/screens.py
+++ b/screens.py
@@ -1,4 +1,5 @@
from components import *
+import sys
# some screens
def doGlobal(screen):
@@ -7,6 +8,9 @@ def doGlobal(screen):
class Screen(dict, HTMLSkin, GUISkin):
""" bla """
+ def close(self):
+ GUISkin.close(self)
+
# a test dialog
class testDialog(Screen):
def testDialogClick(self):
@@ -24,9 +28,11 @@ class testDialog(Screen):
class clockDisplay(Screen):
def okbutton(self):
print "clockDisplay close"
+
+ self.session.close()
def __init__(self, clock):
- HTMLSkin.__init__(self, ("title", "theClock", "okbutton"))
+ GUISkin.__init__(self)
self["theClock"] = clock
b = Button("bye")
b.onClick = [ self.okbutton ]