remove unneeded test object,
[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_animation(this), m_parent(parent ? parent->child() : 0)
7 {
8         m_vis = 0;
9         m_desktop = 0;
10         m_have_background_color = 0;
11         m_z_position = 0;
12         
13         m_client_offset = eSize(0, 0);
14         
15         if (m_parent)
16                 m_vis = wVisShow;
17         
18         if (m_parent)
19         {
20                 insertIntoParent();
21                 m_parent->getStyle(m_style);
22         }
23
24         m_current_focus = 0;
25         m_focus_owner = 0;
26         
27         m_notify_child_on_position_change = 1;
28 }
29
30 void eWidget::move(ePoint pos)
31 {
32         pos = pos + m_client_offset;
33         
34         if (m_position == pos)
35                 return;
36
37                         /* ?? what about native move support? */
38         invalidate();
39
40         m_position = pos;
41         
42         event(evtChangedPosition);
43         
44         if (m_notify_child_on_position_change)
45                 for (ePtrList<eWidget>::iterator i(m_childs.begin()); i != m_childs.end(); ++i)
46                         i->event(evtParentChangedPosition);
47                 
48         recalcClipRegionsWhenVisible();
49         
50                 /* try native move if supported. */
51         if ((m_vis & wVisShow) && ((!m_desktop) || m_desktop->movedWidget(this)))
52                 invalidate();
53 }
54
55 void eWidget::resize(eSize size)
56 {
57                 /* same strategy as with move: we first check if
58                    the size changed at all, and if it did, we
59                    invalidate both the old and new area. 
60                    TODO: check if either the old or new area
61                    fits into the other completely, and invalidate
62                    only once. */
63         eSize old_size = m_size;
64         eSize old_offset = m_client_offset;
65         m_client_offset = eSize(0, 0);
66         event(evtWillChangeSize, &size, &m_client_offset);
67         if (old_size == m_size)
68                 return;
69         
70         move(position() - old_offset);
71         
72         invalidate();
73         event(evtChangedSize);
74
75         if (m_notify_child_on_position_change)
76                 for (ePtrList<eWidget>::iterator i(m_childs.begin()); i != m_childs.end(); ++i)
77                         i->event(evtParentChangedPosition); /* position/size is the same here */
78
79         recalcClipRegionsWhenVisible(); 
80         invalidate();
81 }
82
83 void eWidget::invalidate(const gRegion &region)
84 {
85                 /* we determine the area to redraw, and re-position this
86                    area to the absolute position, and then call the
87                    desktop's invalidate() with that, which adds this
88                    area into the dirty region. */
89         gRegion res = m_visible_with_childs;
90         if (region.valid())
91                 res &= region;
92
93         if (res.empty())
94                 return;
95         
96         eWidget *root = this;
97         ePoint abspos = position();
98         while (root && !root->m_desktop)
99         {
100                 root = root->m_parent;
101                 assert(root);
102                 abspos += root->position();
103         }
104         
105         res.moveBy(abspos);
106 //      eDebug("region to invalidate:");
107 //      dumpRegion(res);
108         root->m_desktop->invalidate(res);
109 }
110
111 void eWidget::show()
112 {
113         if (m_vis & wVisShow)
114                 return;
115
116         m_vis |= wVisShow;
117         
118                 /* TODO: optimize here to only recalc what's required. possibly merge with hide. */
119         eWidget *root = this;
120         ePoint abspos = position();
121         while (root && !root->m_desktop)
122         {
123                 root = root->m_parent;
124                 if (!root)
125                 {
126                                 /* oops: our root widget does not have a desktop associated. 
127                                         probably somebody already erased the root, but tries some
128                                         operations on a child window. 
129                                         
130                                         ignore them for now. */
131                         /* assert(root); */
132                         return;
133                 }
134                 abspos += root->position();
135         }
136
137         root->m_desktop->recalcClipRegions(root);
138
139         gRegion abs = m_visible_with_childs;
140         abs.moveBy(abspos);
141         root->m_desktop->invalidate(abs);
142 }
143
144 void eWidget::hide()
145 {
146                 /* TODO: when hiding an upper level widget, widgets get hidden but keep the */
147                 /* wVisShow flag (because when the widget is shown again, the widgets must */
148                 /* become visible again. */
149         if (!(m_vis & wVisShow))
150                 return;
151         m_vis &= ~wVisShow;
152         
153                 /* this is a workaround to the above problem. when we are in the delete phase, 
154                    don't hide childs. */
155         if (!(m_parent || m_desktop))
156                 return;
157
158                 /* TODO: optimize here to only recalc what's required. possibly merge with show. */
159         eWidget *root = this;
160         ePoint abspos = position();
161         while (root && !root->m_desktop)
162         {
163                 root = root->m_parent;
164                 if (!root)
165                         return;
166                 abspos += root->position();
167         }
168         assert(root->m_desktop);
169
170         gRegion abs = m_visible_with_childs;
171         abs.moveBy(abspos);
172
173         root->m_desktop->recalcClipRegions(root);
174         root->m_desktop->invalidate(abs);
175 }
176
177 void eWidget::destruct()
178 {
179         if (m_parent)
180                 m_parent->m_childs.remove(this);
181         delete this;
182 }
183
184 void eWidget::setBackgroundColor(const gRGB &col)
185 {
186         m_background_color = col;
187         m_have_background_color = 1;
188 }
189
190 void eWidget::clearBackgroundColor()
191 {
192         m_have_background_color = 0;
193 }
194
195 void eWidget::setZPosition(int z)
196 {
197         m_z_position = z;
198         if (!m_parent)
199                 return;
200         
201         m_parent->m_childs.remove(this);
202         
203         insertIntoParent(); /* now at the new Z position */
204 }
205
206 void eWidget::setTransparent(int transp)
207 {
208         if (transp)
209                 m_vis |= wVisTransparent;
210         else
211                 m_vis &=~wVisTransparent;
212 }
213
214 ePoint eWidget::getAbsolutePosition()
215 {
216         eWidget *root = this;
217         ePoint abspos = position();
218
219         while (root && !root->m_desktop)
220         {
221                 root = root->m_parent;
222                 assert(root);
223                 abspos += root->position();
224         }
225
226         return abspos;
227 }
228
229 void eWidget::mayKillFocus()
230 {
231         setFocus(0);
232                 /* when we have the focus, remove it first. */
233         if (m_focus_owner)
234                 m_focus_owner->setFocus(0);
235 }
236
237 eWidget::~eWidget()
238 {
239         hide();
240         
241         if (m_parent)
242                 m_parent->m_childs.remove(this);
243
244         m_parent = 0;
245
246                 /* tell all childs that the parent is not anymore existing */
247         ePtrList<eWidget>::iterator i(m_childs.begin());
248         while (i != m_childs.end())
249         {
250                 (*i)->parentRemoved();
251                 i = m_childs.erase(i);
252         }
253 }
254
255 void eWidget::insertIntoParent()
256 {
257         ePtrList<eWidget>::iterator i = m_parent->m_childs.begin();
258         
259         for(;;)
260         {
261                 if ((i == m_parent->m_childs.end()) || (i->m_z_position > m_z_position))
262                 {
263                         m_parent->m_childs.insert(i, this);
264                         return;
265                 }
266                 ++i;
267         }
268 }
269
270 void eWidget::doPaint(gPainter &painter, const gRegion &r)
271 {
272         if (m_visible_with_childs.empty())
273                 return;
274         
275         gRegion region = r, childs = r;
276                         /* we were in parent's space, now we are in local space */
277         region.moveBy(-position());
278         
279         painter.moveOffset(position());
280         
281                 /* check if there's anything for us to paint */
282         region &= m_visible_region;
283         
284         if (!region.empty())
285         {
286                 painter.resetClip(region);
287                 event(evtPaint, &region, &painter);
288         }
289
290         childs.moveBy(-position());
291                 /* walk all childs */
292         for (ePtrList<eWidget>::iterator i(m_childs.begin()); i != m_childs.end(); ++i)
293                 i->doPaint(painter, childs);
294         
295         painter.moveOffset(-position());
296 }
297
298 void eWidget::recalcClipRegionsWhenVisible()
299 {
300         eWidget *t = this;
301         do
302         {
303                 if (!(t->m_vis & wVisShow))
304                         break;
305                 if (t->m_desktop)
306                 {
307                         t->m_desktop->recalcClipRegions(t);
308                         break;
309                 }
310                 t = t->m_parent;
311                 assert(t);
312         } while(1);
313 }
314
315 void eWidget::parentRemoved()
316 {
317         m_parent = 0;
318 }
319
320 int eWidget::event(int event, void *data, void *data2)
321 {
322         switch (event)
323         {
324         case evtPaint:
325         {
326                 gPainter &painter = *(gPainter*)data2;
327                 
328 //              eDebug("eWidget::evtPaint");
329 //              dumpRegion(*(gRegion*)data);
330                 if (!isTransparent())
331                 {
332                         if (!m_have_background_color)
333                         {
334                                 ePtr<eWindowStyle> style;
335                                 if (!getStyle(style))
336                                         style->paintBackground(painter, ePoint(0, 0), size());
337                         } else
338                         {
339                                 painter.setBackgroundColor(m_background_color);
340                                 painter.clear();
341                         }
342                 } else
343                 {
344                         eWidget *w = this;
345                         
346                         while (w && !w->m_have_background_color)
347                                 w = w->m_parent;
348
349                         if (w)
350                                 painter.setBackgroundColor(w->m_background_color);
351                 }
352                 break;
353         }
354         case evtKey:
355                 break;
356         case evtWillChangeSize:
357                 m_size = *static_cast<eSize*>(data);
358                 break;
359         case evtChangedSize:
360                 m_clip_region = gRegion(eRect(ePoint(0, 0),  m_size));
361                 break;
362         case evtParentChangedPosition:
363                 for (ePtrList<eWidget>::iterator i(m_childs.begin()); i != m_childs.end(); ++i)
364                         i->event(evtParentChangedPosition);
365                 break;
366         case evtFocusGot:
367                 m_focus_owner = (eWidget*)data;
368                 break;
369         case evtFocusLost:
370                 m_focus_owner = 0;
371                 break;
372         default:
373                 return -1;
374         }
375         return 0;
376 }
377
378 void eWidget::setFocus(eWidget *focus)
379 {
380         if (m_current_focus)
381                 m_current_focus->event(evtFocusLost, this);
382         
383         m_current_focus = focus;
384
385         if (m_current_focus)
386                 m_current_focus->event(evtFocusGot, this);
387 }
388