]> git.vomp.tv Git - vompclient.git/blob - viewman.cc
Move EPG to the right a bit, timers fixes and improvements
[vompclient.git] / viewman.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "viewman.h"
22
23 ViewMan* ViewMan::instance = NULL;
24
25 ViewMan::ViewMan()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   numViews = 0;
31 }
32
33 ViewMan::~ViewMan()
34 {
35   instance = NULL;
36 }
37
38 ViewMan* ViewMan::getInstance()
39 {
40   return instance;
41 }
42
43 int ViewMan::init()
44 {
45   if (initted) return 0;
46   initted = 1;
47   return 1;
48 }
49
50 int ViewMan::shutdown()
51 {
52   if (!initted) return 0;
53
54   // FIXME don't think this can work properly, removeAll leaves the wallpaper there!
55   removeAll();
56
57   initted = 0;
58   return 1;
59 }
60
61 int ViewMan::add(View* v)
62 {
63   if (!initted) return 0;
64   if (numViews == 16) return 0;
65
66   views[numViews++] = v;
67
68   return 1;
69 }
70
71 // ---------------------------------------------------- REMOVE CODE
72
73 int ViewMan::removeView(View* toDelete)
74 {
75   if (!initted) return 0;
76   if (numViews == 0) return 0;
77
78   Log::getInstance()->log("ViewMan", Log::DEBUG, "entering remove, numViews=%i", numViews);
79
80   int i;
81
82   if (toDelete == NULL)
83   {
84     toDelete = views[numViews-1];
85     i = numViews - 1;
86   }
87   else
88   {
89     // to be deleted view is more likely to be at the top
90     for (i = numViews-1; i >= 0; i--)
91     {
92       Log::getInstance()->log("ViewMan", Log::DEBUG, "todel: %p, i=%i, views[i]=%p", toDelete, i, views[i]);
93       if (views[i] == toDelete) break;
94     }
95
96     if (i == -1)
97     {
98       // not a View we have!
99       return 0;
100     }
101   }
102
103   Log::getInstance()->log("ViewMan", Log::DEBUG, "Starting deleteView");
104   deleteView(i);
105   Log::getInstance()->log("ViewMan", Log::DEBUG, "Done deleteView");
106
107   // Shift the views on top down one
108   --numViews;
109   for(int j = i; j < numViews; j++) views[j] = views[j+1];
110
111   // Delete the view
112   delete toDelete;
113
114   return 1;
115 }
116
117 /////////////////////////////////////////////////////////////////////////////
118 // NEW STUFF
119 /////////////////////////////////////////////////////////////////////////////
120
121 void ViewMan::deleteView(int z)
122 {
123   Log::getInstance()->log("ViewMan", Log::DEBUG, "Delete view %i of %i", z, numViews);
124   RegionList rl;
125   boxSplit(views[z]->area, z + 1, numViews, 1, rl);
126   while(!rl.empty())
127   {
128     repaintRevealed(z, rl.front());
129     rl.pop_front();
130   }
131 }
132
133 void ViewMan::updateView(View* toUpdate, Region* regionToUpdate)
134 {
135   // Get the z index of the view
136
137   int z;
138   for (z = 0; z < numViews; z++)
139   {
140     if (views[z] == toUpdate) break;
141   }
142
143   if (z == numViews)
144   {
145     // not a View we have!
146     return;
147   }
148
149   // get the region for the whole view, could be less than that
150   // for smaller updates
151
152   Region r = views[z]->area;
153
154   if (regionToUpdate)
155   {
156     // Can be null if the whole view should be updated
157     // If this is given the numbers are relative to the size of the view, not the screen
158
159     r.x += regionToUpdate->x;
160     r.y += regionToUpdate->y;
161     r.w = regionToUpdate->w;
162     r.h = regionToUpdate->h;
163   }
164
165   RegionList rl;
166
167   Region r2;
168   boxSplit(r, z+1, numViews, 1, rl);
169   while(!rl.empty())
170   {
171     r2 = rl.front();
172     r2.z = z;
173     views[z]->show(r2);
174     rl.pop_front();
175   }
176 }
177
178 void ViewMan::repaintRevealed(int x, Region r)
179 {
180   RegionList rl;
181   boxSplit(r, x - 1, -1, -1, rl);
182
183   Region r2;
184   while(!rl.empty())
185   {
186     r2 = rl.front();
187     views[r2.z]->show(r2);
188     rl.pop_front();
189   }
190 }
191
192 void ViewMan::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
193 {
194 //  printf("Y=  S=%i E=%i D=%i: Boxsplit: %i %i %i %i\n", start, end, direction, r.x, r.y, r.w, r.h);
195
196   for(int z = start; z != end; z += direction)
197   {
198     if (r.overlappedBy(views[z]->area))
199     {
200 //      printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
201
202       int top = r.y;
203       int btm = r.y2();
204
205       if (views[z]->area.y > r.y)
206       {
207 //        printf("Z=%i S=%i E=%i D=%i: Case 1 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
208         top = views[z]->area.y;
209         Region newR;
210         newR.x = r.x;
211         newR.y = r.y;
212         newR.w = r.w;
213         newR.h = views[z]->area.y - r.y;
214         boxSplit(newR, z + direction, end, direction, rl);
215
216         if (direction == -1)
217         {
218           Region newR2;
219           newR2.x = r.x;
220           newR2.y = views[z]->area.y;
221           newR2.w = r.w;
222           newR2.h = r.h - newR.h;
223           boxSplit(newR2, z, end, -1, rl);
224           return;
225         }
226       }
227
228       if (views[z]->area.y2() < r.y2())
229       {
230 //        printf("Z=%i S=%i E=%i D=%i: Case 2 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
231         btm = views[z]->area.y2();
232         Region newR;
233         newR.x = r.x;
234         newR.y = views[z]->area.y2() + 1;
235         newR.w = r.w;
236         newR.h = r.y2() - newR.y + 1;
237         boxSplit(newR, z + direction, end, direction, rl);
238
239         if (direction == -1)
240         {
241           Region newR2;
242           newR2.x = r.x;
243           newR2.y = r.y;
244           newR2.w = r.w;
245           newR2.h = r.h - newR.h;
246           boxSplit(newR2, z, end, -1, rl);
247           return;
248         }
249       }
250
251       if (views[z]->area.x > r.x)
252       {
253 //        printf("Z=%i S=%i E=%i D=%i: Case 3 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
254         Region newR;
255         newR.x = r.x;
256         newR.y = top;
257         newR.w = views[z]->area.x - r.x;
258         newR.h = btm - top + 1;
259         boxSplit(newR, z + direction, end, direction, rl);
260
261         if (direction == -1)
262         {
263           Region newR2;
264           newR2.x = r.x + newR.w;
265           newR2.y = r.y;
266           newR2.w = r.w - newR.w;
267           newR2.h = r.h;
268           boxSplit(newR2, z, end, -1, rl);
269           return;
270         }
271       }
272
273       if (views[z]->area.x2() < r.x2())
274       {
275 //        printf("Z=%i S=%i E=%i D=%i: Case 4 for %i %i %i %i split by %i: %i %i %i %i\n", z, start, end, direction, r.x, r.y, r.w, r.h, z, views[z]->area.x, views[z]->area.y, views[z]->area.w, views[z]->area.h);
276         Region newR;
277         newR.x = views[z]->area.x2() + 1;
278         newR.y = top;
279         newR.w = r.x2() - newR.x + 1;
280         newR.h = btm - top + 1;
281         boxSplit(newR, z + direction, end, direction, rl);
282
283         if (direction == -1)
284         {
285           Region newR2;
286           newR2.x = r.x;
287           newR2.y = r.y;
288           newR2.w = r.w - newR.w;
289           newR2.h = r.h;
290           boxSplit(newR2, z, end, -1, rl);
291           return;
292         }
293       }
294
295       if (direction == -1)
296       {
297         // we are going down the stack
298         // r is underlapped by views[z]
299         // but we have not split
300         // Therefore this region under test is
301         // completely covering views[z]
302
303         // don't go any further down, generate a region and quit
304
305 //        printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
306         r.z = z;
307         rl.push_front(r);
308       }
309
310 //      printf("Returning from Z=%i\n", z);
311       return;
312     }
313     else
314     {
315 //      printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
316     }
317   }
318
319   // if direction = 1 then we have come to a region that is
320   // entirely clear of higher views and needs to be redrawn
321
322   // if direction = -1 then we have come to a region that is on
323   // the very bottom with nothing below it to repaint.
324   // do nothing. stale window data will be left on screen?
325
326   if (direction == 1)
327   {
328     rl.push_front(r);
329   }
330 }
331
332 // TEMP
333 void ViewMan::drawBlack(Region& r)
334 {
335   Surface* surface = Surface::getScreen();
336   surface->fillblt(r.x, r.y, r.w, r.h, surface->rgba(0, 0, 0, 255));
337 }
338
339 /////////////////////////////////////////////////////////////////////////////
340 // END NEW STUFF
341 /////////////////////////////////////////////////////////////////////////////
342
343 // ---------------------------------------------------- END OF REMOVE CODE
344
345
346 void ViewMan::removeAll()
347 {
348   // 1.. Don't delete wallpaper. No point.
349   for (; numViews > 1; --numViews)
350   {
351     delete views[numViews-1];
352   }
353 }
354
355 int ViewMan::handleCommand(UCHAR command)
356 {
357   int retVal;
358   int retVal2 = 0;
359   int i;
360
361   if (command != Remote::NA_NONE)
362   {
363     // handle command return values
364     // 0 - drop through to next view
365     // 1 - dont drop to next view, but not handled
366     // 2 - handled - stop command here
367     // 4 - handled - delete this view
368
369     for (i=numViews-1; i>=0; i--)
370     {
371       Log::getInstance()->log("ViewMan", Log::DEBUG, "Giving command to i=%i", i);
372       retVal = views[i]->handleCommand(command);
373       if (retVal == 1)
374       {
375         // not handled but don't give to any more views
376         return 0;
377       }
378
379       if (retVal == 2)
380       {
381         // command handled
382         retVal2 = 1;
383         break;
384       }
385       else if (retVal == 4)
386       {
387         Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
388         removeView(views[i]);
389         retVal2 = 1;
390         break;
391       }
392     }
393   }
394   else
395   {
396     // fake the return code
397     retVal2 = 2;
398   }
399
400   Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
401
402   processMessageQueue();
403
404   return retVal2;
405 }
406
407 void ViewMan::processMessage(Message* m)
408 {
409   if (m->to != this)
410   {
411     for (int i = numViews-1; i >= 0; i--)
412     {
413       if (views[i] == m->to)
414       {
415         Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view");
416         Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message);
417         views[i]->processMessage(m);
418         return;
419       }
420     }
421   }
422
423   Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
424
425   switch(m->message)
426   {
427     case Message::CLOSE_ME:
428     {
429       removeView((View*)m->from);
430       break;
431     }
432     case Message::ADD_VIEW:
433     {
434       View* toAdd = (View*)m->parameter;
435       add(toAdd);
436       toAdd->draw();
437       toAdd->show();
438     }
439   }
440 }