]> git.vomp.tv Git - vompclient.git/blob - viewman.cc
Fix line endings
[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 /////////////////////////////////////////////////////////////////////////////
334 // END NEW STUFF
335 /////////////////////////////////////////////////////////////////////////////
336
337 // ---------------------------------------------------- END OF REMOVE CODE
338
339
340 void ViewMan::removeAll()
341 {
342   // 1.. Don't delete wallpaper. No point.
343   for (; numViews > 1; --numViews)
344   {
345     delete views[numViews-1];
346   }
347 }
348
349 int ViewMan::handleCommand(UCHAR command)
350 {
351   int retVal;
352   int retVal2 = 0;
353   int i;
354
355   if (command != Remote::NA_NONE)
356   {
357     // handle command return values
358     // 0 - drop through to next view
359     // 1 - dont drop to next view, but not handled
360     // 2 - handled - stop command here
361     // 4 - handled - delete this view
362
363     for (i=numViews-1; i>=0; i--)
364     {
365 //      Log::getInstance()->log("ViewMan", Log::DEBUG, "Giving command to i=%i", i);
366       retVal = views[i]->handleCommand(command);
367       if (retVal == 1)
368       {
369         // not handled but don't give to any more views
370         return 0;
371       }
372
373       if (retVal == 2)
374       {
375         // command handled
376         retVal2 = 1;
377         break;
378       }
379       else if (retVal == 4)
380       {
381 //        Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
382         removeView(views[i]);
383         retVal2 = 1;
384         break;
385       }
386     }
387   }
388   else
389   {
390     // fake the return code
391     retVal2 = 2;
392   }
393
394 //  Log::getInstance()->log("ViewMan", Log::DEBUG, "out of handlecommand code, now on to messages");
395
396 //  processMessageQueue();
397
398   return retVal2;
399 }
400
401 void ViewMan::processMessage(Message* m)
402 {
403   if (m->to != this)
404   {
405     for (int i = numViews-1; i >= 0; i--)
406     {
407       if (views[i] == m->to)
408       {
409         Log::getInstance()->log("ViewMan", Log::DEBUG, "sending message from view %p to view %p %lu", m->from, m->to, m->message);
410         views[i]->processMessage(m);
411         return;
412       }
413     }
414     return;
415   }
416
417   /* Handle mouse events*/
418   // They come in with m->to = NULL? and just need to be delivered to top view?
419   if (numViews && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)))
420   {
421     views[numViews-1]->processMessage(m);
422     return;
423   }
424
425   Log::getInstance()->log("ViewMan", Log::DEBUG, "it's for meeee!");
426
427   switch(m->message)
428   {
429     case Message::CLOSE_ME:
430     {
431       removeView((View*)m->from);
432       break;
433     }
434     case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
435     {
436       View* toAdd = (View*)m->parameter;
437       add(toAdd);
438       toAdd->draw();
439       updateView(toAdd);
440       break;
441     }
442   }
443 }