]> git.vomp.tv Git - vompclient.git/blob - voptions.cc
Fix for possible crash when removing bar
[vompclient.git] / voptions.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 "voptions.h"
22
23 VOptions::VOptions(void* tparent, const char* title, const OPTIONDATA* toptionData, const int tnumOptions)
24 {
25   viewman = ViewMan::getInstance();
26
27   parent = tparent;
28   optionData = toptionData;
29   numOptions = tnumOptions;
30
31   UINT newHeight = 85;
32   if (numOptions < 4) newHeight += (4 * 30);
33   else newHeight += (numOptions * 30);
34
35   create(530, newHeight);
36
37   setBackgroundColour(Colour::VIEWBACKGROUND);
38   setTitleBarOn(1);
39   setTitleBarColour(Colour::TITLEBARBACKGROUND);
40   setTitleText(title);
41
42   int fontHeight = surface->getFontHeight();
43
44   optionBoxes = new WOptionBox[numOptions];
45
46   UINT i, j;
47   char* config;
48   vdr = VDR::getInstance();
49   // After setup, save all current indexes
50   optionsAtStart = new int[numOptions];
51
52   for (i = 0; i < numOptions; i++)
53   {
54     optionBoxes[i].setSurface(surface);
55     optionBoxes[i].setSurfaceOffset(346, 45 + (i * 30));
56     optionBoxes[i].setDimensions(150, fontHeight);
57
58     if (optionData[i].optionType == OPTIONTYPE_TEXT)
59     {
60       for (j = 0; j < optionData[i].optionCount; j++)
61       {
62         Log::getInstance()->log("Options", Log::DEBUG, "Add option: %s", optionData[i].options[j]);
63         optionBoxes[i].addOption(tr((char*)optionData[i].options[j]));
64       }
65
66       // Set the built in default
67       optionBoxes[i].setSelected(tr((char*)optionData[i].options[optionData[i].defaultOption]));
68     }
69     else
70     {
71       // int mode
72       optionBoxes[i].setIntMode(optionData[i].startInt, optionData[i].optionCount);
73       optionBoxes[i].setSelected(optionData[i].defaultOption);
74     }
75
76     // Now see if there is a config option for it
77     config = vdr->configLoad(optionData[i].configSection, optionData[i].configParam);
78     if (config)
79     {
80       if (optionData[i].optionType == OPTIONTYPE_TEXT)
81       {
82         for (j = 0; j < optionData[i].optionCount; j++)
83         {
84           if (!STRCASECMP(config, optionData[i].options[j]))
85           {
86             optionBoxes[i].setSelected(tr((char*)optionData[i].options[j]));
87           }
88         }
89       }
90       else
91       {
92         optionBoxes[i].setSelected(atoi(config));
93       }
94       delete[] config;
95     }
96
97     // After setup, save initial option
98     optionsAtStart[i] = optionBoxes[i].getSelectedIndex();
99   }
100
101   selectedOption = numOptions;
102   //optionBoxes[0].setActive(1);
103
104   int voff = 0;
105   if ((numOptions < 8) && (numOptions >= 4))
106   {
107     voff = (8 - numOptions) * 10;
108   }
109   else if (numOptions < 4)
110   {
111     voff = 40; //(4 * 10)
112   }
113
114   if (Video::getInstance()->getFormat() == Video::PAL)
115   {
116     setScreenPos(104, 130 + voff);
117   }
118   else
119   {
120     setScreenPos(94, 70 + voff);
121   }
122
123   if (!vdr->isConnected()) Command::getInstance()->connectionLost();
124 }
125
126 VOptions::~VOptions()
127 {
128   delete[] optionsAtStart;
129   delete[] optionBoxes;
130 }
131
132 void VOptions::draw()
133 {
134   View::draw();
135
136   WSymbol wsy;
137   Colour cl;
138
139   drawText(tr("Press back to exit, <, > or [ok] to change"), 10, area.h - 30, Colour::LIGHTTEXT);
140
141   wsy.setSurface(surface);
142   UINT ystart=titleBarOn ? 45 : 15;
143
144   for (UINT i = 0; i < numOptions; i++)
145   {
146     drawText(tr(optionData[i].title), 10, ystart + i*30, Colour::LIGHTTEXT);
147
148     if (i == selectedOption) cl = Colour::SELECTHIGHLIGHT;
149     else cl = Colour::BUTTONBACKGROUND;
150
151     wsy.nextSymbol = WSymbol::LEFTARROW;
152     wsy.nextColour = cl;
153
154     wsy.setSurfaceOffset(328, ystart + 2 + (i * 30));
155     wsy.draw();
156     wsy.nextSymbol = WSymbol::RIGHTARROW;
157     wsy.setSurfaceOffset(498, ystart + 2 + (i * 30));
158     wsy.draw();
159     optionBoxes[i].setSurfaceOffset(346, ystart + (i * 30));
160     optionBoxes[i].draw();
161   }
162 }
163
164 int VOptions::handleCommand(int command)
165 {
166   switch(command)
167   {
168     case Remote::DF_UP:
169     case Remote::UP:
170     {
171       if (selectedOption > 0)
172       {
173         if (selectedOption < numOptions) optionBoxes[selectedOption].setActive(0);
174         --selectedOption;
175         optionBoxes[selectedOption].setActive(1);
176         draw();
177         viewman->updateView(this);
178       }
179       else
180       {
181         if (selectedOption < numOptions) optionBoxes[selectedOption].setActive(0);
182         selectedOption = numOptions;
183         return 0; //Control to tab view
184       }
185       return 2;
186     }
187     case Remote::DF_DOWN:
188     case Remote::DOWN:
189     {
190       if (selectedOption < (numOptions - 1))
191       {
192         if (selectedOption < numOptions) optionBoxes[selectedOption].setActive(0);
193         ++selectedOption;
194         optionBoxes[selectedOption].setActive(1);
195         draw();
196         viewman->updateView(this);
197       }
198       else if (selectedOption == numOptions)
199       {
200         selectedOption = 0;
201         optionBoxes[selectedOption].setActive(1);
202         draw();
203         viewman->updateView(this);
204       }
205       return 2;
206     }
207     case Remote::DF_LEFT:
208     case Remote::LEFT:
209     {
210       if (selectedOption == numOptions) return 2;
211       optionBoxes[selectedOption].left();
212       draw();
213       viewman->updateView(this);
214       return 2;
215     }
216     case Remote::DF_RIGHT:
217     case Remote::RIGHT:
218     {
219       if (selectedOption == numOptions) return 2;
220       optionBoxes[selectedOption].right();
221       draw();
222       viewman->updateView(this);
223       return 2;
224     }
225     case Remote::BACK:
226     {
227       doSave();
228
229       // Instead of returning 4 here which would delete this view
230       // before the doSave message is processed, let the message queue
231       // do the doSave then this close message. That will make the options menu
232       // disappear before this view
233
234       Message* m = new Message();
235       m->message = Message::CLOSE_ME;
236       m->from = this;
237       m->to = viewman;
238       Command::getInstance()->postMessageNoLock(m);
239
240       return 2;
241     }
242     case Remote::OK:
243     {
244       if (selectedOption == numOptions) return 2;
245       optionBoxes[selectedOption].cycle();
246       draw();
247       viewman->updateView(this);
248     }
249   }
250
251   return 1;
252 }
253
254 void VOptions::doSave()
255 {
256   UINT i;
257   int* result = new int[numOptions];
258
259   for (i = 0; i < numOptions; i++)
260   {
261     result[i] = optionBoxes[i].getSelectedIndex();
262
263     if (result[i] != optionsAtStart[i])
264     {
265       Log::getInstance()->log("Options", Log::DEBUG, "Option %i has changed", i);
266
267       if (optionData[i].optionType == OPTIONTYPE_TEXT)
268       {
269         vdr->configSave(optionData[i].configSection, optionData[i].configParam,
270           optionData[i].options[result[i]]);
271       }
272       else
273       {
274         char buffer[20];
275         sprintf(buffer, "%i", result[i]);
276         vdr->configSave(optionData[i].configSection, optionData[i].configParam,
277           buffer);
278       }
279     }
280   }
281
282   // Save a vector of option IDs that have changed
283
284   map<int, int>* optionChanges = new map<int, int>;
285
286   for (i = 0; i < numOptions; i++)
287   {
288     if (result[i] != optionsAtStart[i])
289     {
290       (*optionChanges)[optionData[i].id] = result[i];
291     }
292   }
293
294   delete[] result;
295
296   // Send it to parent for changes to be applied
297   Message* m = new Message();
298   m->message = Message::CHANGED_OPTIONS;
299   m->to = parent;
300   m->parameter = (ULONG)optionChanges;
301   Command::getInstance()->postMessageNoLock(m);
302 }
303
304 void VOptions::processMessage(Message* m)
305 {
306   if (m->message == Message::MOUSE_MOVE)
307   {
308     int x=(m->parameter>>16)-getScreenX();
309     int y=(m->parameter&0xFFFF)-getScreenY();
310     UINT i;
311     for (i = 0; i < numOptions; i++)
312     {
313       if (optionBoxes[i].mouseMove(x,y))
314       {
315         if (selectedOption != numOptions) optionBoxes[selectedOption].setActive(0);
316         optionBoxes[i].setActive(1);
317         selectedOption=i;
318         draw();
319         viewman->updateView(this);
320         break;
321       }
322     }
323   }
324   else if (m->message == Message::MOUSE_LBDOWN)
325   {
326     int x=(m->parameter>>16)-getScreenX();
327     int y=(m->parameter&0xFFFF)-getScreenY();
328     UINT i;
329     bool butpress=false;
330     for (i = 0; i < numOptions; i++)
331     {
332       if (optionBoxes[i].mouseLBDOWN(x,y))
333       {
334         ViewMan::getInstance()->handleCommand(Remote::OK); //simulate OK press
335         butpress=true;
336         break;
337       }
338     }
339     if (!butpress)
340     {
341       //check if press is outside this view! then simulate cancel
342       if (x<0 || y <0 || x>getWidth() || y>getHeight())
343       {
344         ViewMan::getInstance()->handleCommand(Remote::BACK); //simulate cancel press
345       }
346     }
347   }
348 }