]> git.vomp.tv Git - vompclient.git/blob - viewman.cc
New timers system. New program structure for handling buttons/timers
[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 /* For later...
134 void ViewMan::update(int z)
135 {
136   // get the region for the whole view, could be less than that
137   // for smaller updates
138
139   Region r = views[z]->area;
140   RegionList rl;
141
142   r.y += 10;
143
144   Region r2;
145   boxSplit(r, z+1, numViews, 1, rl);
146   while(!rl.empty())
147   {
148     r2 = rl.front();
149     r2.z = z;
150     views[z]->show(r2);
151     rl.pop_front();
152   }
153 }
154 */
155
156 void ViewMan::repaintRevealed(int x, Region r)
157 {
158   RegionList rl;
159   boxSplit(r, x - 1, -1, -1, rl);
160
161   Region r2;
162   while(!rl.empty())
163   {
164     r2 = rl.front();
165     views[r2.z]->show(r2);
166     rl.pop_front();
167   }
168 }
169
170 void ViewMan::boxSplit(Region r, int start, int end, int direction, RegionList& rl)
171 {
172 //  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);
173
174   for(int z = start; z != end; z += direction)
175   {
176     if (r.overlappedBy(views[z]->area))
177     {
178 //      printf("Z=%i S=%i E=%i D=%i: %i overlaps\n", z, start, end, direction, z);
179
180       int top = r.y;
181       int btm = r.y2();
182
183       if (views[z]->area.y > r.y)
184       {
185 //        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);
186         top = views[z]->area.y;
187         Region newR;
188         newR.x = r.x;
189         newR.y = r.y;
190         newR.w = r.w;
191         newR.h = views[z]->area.y - r.y;
192         boxSplit(newR, z + direction, end, direction, rl);
193
194         if (direction == -1)
195         {
196           Region newR2;
197           newR2.x = r.x;
198           newR2.y = views[z]->area.y;
199           newR2.w = r.w;
200           newR2.h = r.h - newR.h;
201           boxSplit(newR2, z, end, -1, rl);
202           return;
203         }
204       }
205
206       if (views[z]->area.y2() < r.y2())
207       {
208 //        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);
209         btm = views[z]->area.y2();
210         Region newR;
211         newR.x = r.x;
212         newR.y = views[z]->area.y2() + 1;
213         newR.w = r.w;
214         newR.h = r.y2() - newR.y + 1;
215         boxSplit(newR, z + direction, end, direction, rl);
216
217         if (direction == -1)
218         {
219           Region newR2;
220           newR2.x = r.x;
221           newR2.y = r.y;
222           newR2.w = r.w;
223           newR2.h = r.h - newR.h;
224           boxSplit(newR2, z, end, -1, rl);
225           return;
226         }
227       }
228
229       if (views[z]->area.x > r.x)
230       {
231 //        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);
232         Region newR;
233         newR.x = r.x;
234         newR.y = top;
235         newR.w = views[z]->area.x - r.x;
236         newR.h = btm - top + 1;
237         boxSplit(newR, z + direction, end, direction, rl);
238
239         if (direction == -1)
240         {
241           Region newR2;
242           newR2.x = r.x + newR.w;
243           newR2.y = r.y;
244           newR2.w = r.w - newR.w;
245           newR2.h = r.h;
246           boxSplit(newR2, z, end, -1, rl);
247           return;
248         }
249       }
250
251       if (views[z]->area.x2() < r.x2())
252       {
253 //        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);
254         Region newR;
255         newR.x = views[z]->area.x2() + 1;
256         newR.y = top;
257         newR.w = r.x2() - newR.x + 1;
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;
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 (direction == -1)
274       {
275         // we are going down the stack
276         // r is underlapped by views[z]
277         // but we have not split
278         // Therefore this region under test is
279         // completely covering views[z]
280
281         // don't go any further down, generate a region and quit
282
283 //        printf("Repaint region: %i %i %i %i\n", r.x, r.y, r.w, r.h);
284         r.z = z;
285         rl.push_front(r);
286       }
287
288 //      printf("Returning from Z=%i\n", z);
289       return;
290     }
291     else
292     {
293 //      printf("Z=%i S=%i E=%i D=%i: %i does not overlap\n", z, start, end, direction, z);
294     }
295   }
296
297   // if direction = 1 then we have come to a region that is
298   // entirely clear of higher views and needs to be redrawn
299
300   // if direction = -1 then we have come to a region that is on
301   // the very bottom with nothing below it to repaint.
302   // do nothing. stale window data will be left on screen?
303
304   if (direction == 1)
305   {
306     rl.push_front(r);
307   }
308 }
309
310 // TEMP
311 void ViewMan::drawBlack(Region& r)
312 {
313   Surface* surface = Surface::getScreen();
314   surface->fillblt(r.x, r.y, r.w, r.h, surface->rgba(0, 0, 0, 255));
315 }
316
317 /////////////////////////////////////////////////////////////////////////////
318 // END NEW STUFF
319 /////////////////////////////////////////////////////////////////////////////
320
321 // ---------------------------------------------------- END OF REMOVE CODE
322
323
324 void ViewMan::removeAll()
325 {
326   // 1.. Don't delete wallpaper. No point.
327   for (; numViews > 1; --numViews)
328   {
329     delete views[numViews-1];
330   }
331 }
332
333 int ViewMan::handleCommand(UCHAR command)
334 {
335   int retVal;
336   int retVal2 = 0;
337   int i;
338
339   if (command != Remote::NA_NONE)
340   {
341     // handle command return values
342     // 0 - drop through to next view
343     // 1 - dont drop to next view, but not handled
344     // 2 - handled - stop command here
345     // 4 - handled - delete this view
346
347     for (i=numViews-1; i>=0; i--)
348     {
349       Log::getInstance()->log("ViewMan", Log::DEBUG, "Giving command to i=%i", i);
350       retVal = views[i]->handleCommand(command);
351       if (retVal == 1)
352       {
353         // not handled but don't give to any more views
354         return 0;
355       }
356
357       if (retVal == 2)
358       {
359         // command handled
360         retVal2 = 1;
361         break;
362       }
363       else if (retVal == 4)
364       {
365         Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
366         removeView(views[i], 1);
367         retVal2 = 1;
368         break;
369       }
370     }
371   }
372   else
373   {
374     // fake the return code
375     retVal2 = 2;
376   }
377
378   Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
379
380   processMessageQueue();
381
382   return retVal2;
383 }
384
385 void ViewMan::processMessage(Message* m)
386 {
387   if (m->to != this)
388   {
389     for (int i = numViews-1; i >= 0; i--)
390     {
391       if (views[i] == m->to)
392       {
393         Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message to view");
394         Log::getInstance()->log("ViewMan", Log::DEBUG, "%p %p %lu", m->from, m->to, m->message);
395         views[i]->processMessage(m);
396         return;
397       }
398     }
399   }
400
401   Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
402
403   switch(m->message)
404   {
405     case Message::CLOSE_ME:
406     {
407       removeView((View*)m->from, 1);
408       break;
409     }
410     case Message::ADD_VIEW:
411     {
412       View* toAdd = (View*)m->parameter;
413       add(toAdd);
414       toAdd->draw();
415       toAdd->show();
416     }
417   }
418 }