first version of PythonSignals - need to be finalized a bit, but work basically
[enigma2.git] / lib / gui / ewidget.cpp
1 #include <lib/gui/ewidget.h>
2 #include <lib/gui/ewidgetdesktop.h>
3
4 extern void dumpRegion(const gRegion &region);
5
6 eWidget::eWidget(eWidget *parent): m_parent(parent ? parent->child() : 0)
7 {
8         m_vis = 0;
9         m_desktop = 0;
10         
11         if (m_parent)
12                 m_vis = wVisShow;
13         
14         if (m_parent)
15         {
16                 m_parent->m_childs.push_back(this);
17                 m_parent->getStyle(m_style);
18         }
19 }
20
21 void eWidget::move(ePoint pos)
22 {
23         if (m_position == pos)
24                 return;
25         
26         m_position = pos;
27         
28                 /* we invalidate before and after the move to
29                    cause a correct redraw. The area which is
30                    included both before and after isn't redrawn
31                    twice because a invalidate doesn't immediately
32                    redraws the region. */
33         invalidate();
34         event(evtChangedPosition);
35         recalcClipRegionsWhenVisible(); 
36         invalidate();
37 }
38
39 void eWidget::resize(eSize size)
40 {
41                 /* same strategy as with move: we first check if
42                    the size changed at all, and if it did, we
43                    invalidate both the old and new area. 
44                    TODO: check if either the old or new area
45                    fits into the other completely, and invalidate
46                    only once. */
47         eSize old_size = m_size;
48         event(evtWillChangeSize, &size);
49         if (old_size == m_size)
50                 return;
51
52         invalidate();
53         event(evtChangedSize);
54         recalcClipRegionsWhenVisible(); 
55         invalidate();
56 }
57
58 void eWidget::invalidate(const gRegion &region)
59 {
60                 /* we determine the area to redraw, and re-position this
61                    area to the absolute position, and then call the
62                    desktop's invalidate() with that, which adds this
63                    area into the dirty region. */
64         gRegion res = m_visible_with_childs;
65         if (region.valid())
66                 res &= region;
67
68         if (res.empty())
69                 return;
70         
71         eWidget *root = this;
72         ePoint abspos = position();
73         while (root && !root->m_desktop)
74         {
75                 root = root->m_parent;
76                 assert(root);
77                 abspos += root->position();
78         }
79         
80         res.moveBy(abspos);
81 //      eDebug("region to invalidate:");
82 //      dumpRegion(res);
83         root->m_desktop->invalidate(res);
84 }
85
86 void eWidget::show()
87 {
88         if (m_vis & wVisShow)
89                 return;
90         
91         m_vis |=  wVisShow;
92
93                 /* TODO: optimize here to only recalc what's required. possibly merge with hide. */
94         eWidget *root = this;
95         ePoint abspos = position();
96         while (root && !root->m_desktop)
97         {
98                 root = root->m_parent;
99                 assert(root);
100                 abspos += root->position();
101         }
102
103         root->m_desktop->recalcClipRegions();
104
105         gRegion abs = m_visible_with_childs;
106         abs.moveBy(abspos);
107         root->m_desktop->invalidate(abs);
108 }
109
110 void eWidget::hide()
111 {
112         m_vis &= ~wVisShow;
113
114                 /* TODO: optimize here to only recalc what's required. possibly merge with show. */
115         eWidget *root = this;
116         ePoint abspos = position();
117         while (root && !root->m_desktop)
118         {
119                 root = root->m_parent;
120                 abspos += root->position();
121         }
122         assert(root->m_desktop);
123
124         gRegion abs = m_visible_with_childs;
125         abs.moveBy(abspos);
126
127         root->m_desktop->recalcClipRegions();
128         root->m_desktop->invalidate(abs);
129 }
130
131 void eWidget::destruct()
132 {
133         if (m_parent)
134                 m_parent->m_childs.remove(this);
135         delete this;
136 }
137
138 eWidget::~eWidget()
139 {
140         if (m_parent)
141                 m_parent->m_childs.remove(this);
142
143                 /* destroy all childs */
144         ePtrList<eWidget>::iterator i(m_childs.begin());
145         while (i != m_childs.end())
146         {
147                 (*i)->m_parent = 0;
148                 delete *i;
149                 i = m_childs.erase(i);
150         }
151 }
152
153 void eWidget::doPaint(gPainter &painter, const gRegion &r)
154 {
155         if (m_visible_with_childs.empty())
156                 return;
157         
158         gRegion region = r;
159                         /* we were in parent's space, now we are in local space */
160         region.moveBy(-position());
161         
162         painter.moveOffset(position());
163                 /* walk all childs */
164         for (ePtrList<eWidget>::iterator i(m_childs.begin()); i != m_childs.end(); ++i)
165                 i->doPaint(painter, region);
166         
167                 /* check if there's anything for us to paint */
168         region &= m_visible_region;
169         
170         if (!region.empty())
171         {
172                 painter.resetClip(region);
173                 event(evtPaint, &region, &painter);
174         }
175         
176         painter.moveOffset(-position());
177 }
178
179 void eWidget::recalcClipRegionsWhenVisible()
180 {
181         eWidget *t = this;
182         do
183         {
184                 if (!(t->m_vis & wVisShow))
185                         break;
186                 if (t->m_desktop)
187                 {
188                         t->m_desktop->recalcClipRegions();
189                         break;
190                 }
191                 t = t->m_parent;
192                 assert(t);
193         } while(1);
194 }
195
196 int eWidget::event(int event, void *data, void *data2)
197 {
198         switch (event)
199         {
200         case evtPaint:
201         {
202                 gPainter &painter = *(gPainter*)data2;
203                 
204 //              eDebug("eWidget::evtPaint");
205 //              dumpRegion(*(gRegion*)data);
206                 ePtr<eWindowStyle> style;
207                 if (!getStyle(style))
208                         style->paintBackground(painter, ePoint(0, 0), size());
209                 break;
210         }
211         case evtKey:
212                 break;
213         case evtWillChangeSize:
214                 m_size = *static_cast<eSize*>(data);
215                 break;
216         case evtChangedSize:
217         {
218                 m_clip_region = gRegion(eRect(ePoint(0, 0),  m_size));
219                 break;
220         }
221         default:
222                 return -1;
223         }
224         return 0;
225 }
226