]> git.vomp.tv Git - vompclient.git/blob - vtabsviewman.cc
Fix for possible crash when removing bar
[vompclient.git] / vtabsviewman.cc
1 /*
2     Copyright 2004-2007 Chris Tallon, Marten Richter
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 #include "vtabsviewman.h"
21 #include "video.h"
22 #include "wsymbol.h"
23 #include "remote.h"
24 #include "command.h"
25 #include "viewman.h"
26
27 VTabsViewMan::VTabsViewMan()
28 {
29     numViews = 0;
30     selectedView = 0;
31     backgroundColour = Colour::VIEWBACKGROUND;
32     tabHasControl = true;
33 }
34
35 VTabsViewMan::~VTabsViewMan()
36 {
37     removeAll();
38 }
39
40 int VTabsViewMan::add(View* v)
41 {
42     if (numViews == 16) return 0;
43
44     v->setTitleBarOn(0); //No Title Bar
45     v->setViewMan(this); //For this view, we are the viewman
46     v->setBackgroundColour(Colour::TABVIEWBACKGROUND);
47
48     views[numViews++] = v;
49
50     if (surface!=NULL) create(); //Recreating surface
51
52     return 1;
53 }
54
55 int VTabsViewMan::removeView(View* toDelete)
56 {
57     if (numViews == 0) return 0;
58
59     int i;
60
61     if (toDelete == NULL)
62     {
63         toDelete = views[numViews-1];
64         i = numViews - 1;
65     }
66     else
67     {
68         // to be deleted view is more likely to be at the top
69         for (i = numViews-1; i >= 0; i--)
70         {
71             if (views[i] == toDelete) break;
72         }
73         if (i == -1)
74         {
75             // not a View we have!
76             return 0;
77         }
78     }
79 //    deleteView(i);
80
81     // Shift the views on top down one
82     --numViews;
83     for(int j = i; j < numViews; j++) views[j] = views[j+1];
84
85     // Delete the view
86     delete toDelete;
87
88     if (surface!=NULL) create(); //Recreating surface, if we are initted
89     if (selectedView >= numViews) selectedView = numViews-1;
90
91     return 1;
92 }
93
94 void VTabsViewMan::removeAll()
95 {
96     for (; numViews > 0; --numViews)
97     {
98         delete views[numViews-1];
99     }
100 }
101
102 void VTabsViewMan::updateView(View* toUpdate, Region* regionToUpdate)
103 {
104     draw();
105     ViewMan::getInstance()->updateView(this,regionToUpdate);
106 }
107
108 void VTabsViewMan::create()
109 {
110     if (surface!=NULL)
111     {
112         delete surface;//destroy old surface
113         surface=NULL;
114     }
115     Region newarea;
116     int i;
117     if (numViews == 0)
118     {
119         newarea.h=200;
120         newarea.w=200;
121     }
122     else
123     {
124         for (i = 0; i < numViews; i++)
125         {
126             newarea.h=max(views[i]->getHeight(),newarea.h);
127             newarea.w=max(views[i]->getWidth(),newarea.w);
128         }
129     }
130     newarea.h += 30; //Title Bar
131     newarea.h += 30; //Tab bar
132     newarea.h += 2; //Border
133     newarea.w += 2;
134
135     //centering
136
137     newarea.y = Video::getInstance()->getScreenHeight()/2-newarea.h/2;
138     newarea.x = Video::getInstance()->getScreenWidth()/2-newarea.w/2;
139     setScreenPos(newarea.x,newarea.y);
140
141     //Now iterate through the views and set the position
142
143     for (i = 0; i < numViews; i++)
144     {
145         views[i]->setScreenPos(newarea.x+1,newarea.y+1+30+30);
146     }
147     View::create(newarea.w,newarea.h);
148
149 }
150
151
152 void VTabsViewMan::draw()
153 {
154     if (surface==NULL) return;
155     View::draw();
156     //Now Drawing the tabs bar
157     int xpos=1;
158     WSymbol wsy;
159     wsy.setSurface(surface);
160
161     if (selectedView>=2)
162     {
163         wsy.nextSymbol = WSymbol::LEFTARROW;
164         wsy.nextColour = Colour::BUTTONBACKGROUND;
165         wsy.setSurfaceOffset(xpos, 40);
166         wsy.draw();
167         xpos+=20;
168     }
169     int i;
170     UINT textypos=30+30-2-surface->getFontHeight();
171     for (i = max(selectedView-1,0); i < numViews && xpos+150+20 < (int)area.w; i++)
172     {
173         if (i == selectedView)
174         {
175             rectangle(xpos+1,30+1,150,30,Colour::TABVIEWBACKGROUND);
176         }
177         else
178         {
179              rectangle(xpos+1,30+1,150,28,Colour::TABVIEWBACKGROUND);
180         }
181         if (i == selectedView && tabHasControl)
182             drawText(views[i]->getTitleText(),xpos+5,textypos,Colour::SELECTHIGHLIGHT);
183         else
184             drawText(views[i]->getTitleText(),xpos+5,textypos,Colour::LIGHTTEXT);
185
186         xpos+=151;
187     }
188     if (i < numViews)
189     {
190         wsy.nextSymbol = WSymbol::RIGHTARROW;
191         wsy.nextColour = Colour::BUTTONBACKGROUND;
192         wsy.setSurfaceOffset(xpos+5, 40);
193         wsy.draw();
194         xpos+=20;
195     }
196
197
198     if (selectedView < numViews) views[selectedView]->draw();
199 }
200
201 void VTabsViewMan::blt(Region& r)
202 {
203     Box::blt(r);
204
205     if (selectedView < numViews) {
206         Region helper=r;
207         helper.x = max(helper.x,views[selectedView]->area.x);
208         helper.w -= helper.x-r.x;
209         helper.y = max(helper.y,views[selectedView]->area.y);
210         helper.h -= helper.y-r.y;
211         helper.w = min(helper.w,views[selectedView]->area.w);
212         helper.h = min(helper.h,views[selectedView]->area.h);
213         views[selectedView]->blt(helper);
214     }
215 }
216
217
218 int VTabsViewMan::handleCommand(int command)
219 {
220   int retVal;
221   int i;
222   if (command == Remote::BACK)
223   {
224       for (i=0;i<numViews;i++)
225       {
226           views[i]->handleCommand(Remote::BACK);
227       }
228       // Instead of returning 4 here which would delete this view
229       // before the doSave messages are processed, let the message queue
230       // do the doSave then this close message. That will make the options menu
231       // disappear before this view
232
233       Message* m = new Message();
234       m->message = Message::CLOSE_ME;
235       m->from = this;
236       m->to = ViewMan::getInstance();
237       Command::getInstance()->postMessageNoLock(m);
238       return 2;
239   }
240   else if (tabHasControl) //our control bar is selected, we are the master of the universe
241   {
242       switch (command)
243       {
244       case Remote::DF_DOWN:
245       case Remote::DOWN:
246       {
247           tabHasControl = false; //loose control
248           if (selectedView < numViews)
249           {
250               views[selectedView]->handleCommand(command);
251               draw();
252               viewman->updateView(this);
253               return 2;
254           }
255           else
256             return 2;
257       }break;
258       case Remote::DF_LEFT:
259       case Remote::LEFT:
260       {
261         selectedView=max(0,selectedView-1);
262         draw();
263         viewman->updateView(this);
264         return 2;
265       }break;
266       case Remote::DF_RIGHT:
267       case Remote::RIGHT:
268       {
269         selectedView=min(numViews-1,selectedView+1);
270         draw();
271         viewman->updateView(this);
272         return 2;
273       }break;
274       }
275       return 1;
276   }
277   else if (command != Remote::NA_NONE)
278   {
279     // handle command return values
280     // 0 - drop through to next view //this means me
281     // 1 - dont drop to next view, but not handled
282     // 2 - handled - stop command here
283     // 4 - handled - delete this view //delete me too
284
285
286       if (selectedView < numViews)
287       {
288           retVal = views[selectedView]->handleCommand(command);
289           if (retVal == 1)
290           {
291               // not handled but don't give to any more views
292               return 1;
293           }
294           if (retVal == 2)
295           {
296               // command handled
297               return 2;
298           }
299           else if (retVal == 4)
300           {
301               //        Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
302
303               return 1;
304           } else if (retVal == 0) {
305               tabHasControl = true;
306               draw(); // I have control
307               viewman->updateView(this);
308               return 2;
309           }
310
311       }
312   }
313   else
314   {
315     // fake the return code
316     return  2;
317   }
318
319   return 0;
320
321 }
322
323 void VTabsViewMan::processMessage(Message* m)
324 {
325     /* Handle mouse events*/
326   // They come in with m->to = ViewMan and just need to be delivered to selectedView?
327   if ((numViews > 0) && ((m->message == Message::MOUSE_MOVE) || (m->message == Message::MOUSE_LBDOWN)))
328   {
329       //TODO, add Tab bar interaction
330     int x=(m->parameter>>16)-getScreenX();
331     int y=(m->parameter&0xFFFF)-getScreenY();
332     if (x<0 || y <0 || x>getWidth() || y>getHeight())
333     {
334         if (m->message == Message::MOUSE_LBDOWN)
335         {
336             Message *newm=new Message();
337             newm->from=NULL;
338             newm->to=Command::getInstance();
339             newm->message=Message::UDP_BUTTON;
340             newm->parameter=Remote::BACK;
341             Command::getInstance()->postMessage(newm);
342         }
343     } else {
344         if ( y <= 60)
345         { //my area
346             if (y >= 30 && m->message == Message::MOUSE_LBDOWN)
347             {
348                  int xpos=1;
349                  if (selectedView>=2)
350                  {
351                      if (xpos < x && x <=xpos+20)
352                      {
353                          tabHasControl=true;
354                          Message *newm=new Message();
355                          newm->from=NULL;
356                          newm->to=Command::getInstance();
357                          newm->message=Message::UDP_BUTTON;
358                          newm->parameter=Remote::LEFT;
359                          Command::getInstance()->postMessage(newm);
360                          return;
361                      }
362                      xpos+=20;
363                  }
364                  int i;
365                  for (i = max(selectedView-1,0);i < numViews && xpos+150+20 < (int)area.w; i++)
366                  {
367                      if (xpos < x && x <=xpos+150)
368                      {
369                          tabHasControl=true;
370                          selectedView = i;
371                          draw();
372                          ViewMan::getInstance()->updateView(this);
373                          return;
374                      }
375                      xpos+=151;
376                  }
377                  if (i < numViews)
378                  {
379                      if (xpos < x && x <=xpos+20)
380                      {
381                          tabHasControl=true;
382                          Message *newm=new Message();
383                          newm->from=NULL;
384                          newm->to=Command::getInstance();
385                          newm->message=Message::UDP_BUTTON;
386                          newm->parameter=Remote::RIGHT;
387                          Command::getInstance()->postMessage(newm);
388                          return;
389                      }
390                  }
391             }
392         }
393         else //tabs area
394         {
395             tabHasControl=false;
396             views[selectedView]->processMessage(m);
397         }
398     }
399     return;
400   }
401
402   if (m->to != this)
403   {
404     for (int i = numViews-1; i >= 0; i--)
405     {
406       if (views[i] == m->to)
407       {
408         Log::getInstance()->log("VTabsViewMan", Log::DEBUG, "sending message from view %p to view %p %lu", m->from, m->to, m->message);
409         views[i]->processMessage(m);
410         return;
411       }
412     }
413     return;
414   }
415
416
417
418   Log::getInstance()->log("VTabsViewMan", Log::DEBUG, "it's for meeee!");
419
420   switch(m->message)
421   {
422     case Message::CLOSE_ME:
423     {
424       removeView((View*)m->from);
425       break;
426     }
427     case Message::ADD_VIEW: // currently not used by anything but it might come in useful again
428     {
429       View* toAdd = (View*)m->parameter;
430       add(toAdd);
431       toAdd->draw();
432       ViewMan::getInstance()->updateView(this);
433       break;
434     }
435   }
436 }