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