]> git.vomp.tv Git - vompclient.git/blob - wselectlist.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / wselectlist.cc
1 /*
2     Copyright 2004-2020 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <math.h>
21 #include <string.h>
22
23 #include "colour.h"
24 #include "log.h"
25
26 #include "wselectlist.h"
27
28 WSelectList::WSelectList():
29 backgroundColour(DrawStyle::VIEWBACKGROUND)
30 {
31 }
32
33 WSelectList::~WSelectList()
34 {
35   clear();
36 }
37
38 void WSelectList::clear()
39 {
40   int vsize = options.size();
41   for (int i = 0; i < vsize; i++)
42   {
43     delete[] options[i].text;
44     if (options[i].pict) delete options[i].pict;
45   }
46   options.clear();
47
48   selectedOption = 0;
49   topOption = 0;
50   numOptionsDisplayable = 0;
51   numColumns = 0;
52 }
53
54 void WSelectList::setNoLoop()
55 {
56   noLoop = 1;
57 }
58
59 void WSelectList::setBackgroundColour(const DrawStyle& colour)
60 {
61   backgroundColour = colour;
62 }
63
64 void WSelectList::hintSetCurrent(int idx)
65 {
66   selectedOption = idx;
67   if (selectedOption >= static_cast<int>(options.size())) selectedOption = options.size() - 1;
68 }
69
70 void WSelectList::hintSetTop(int idx)
71 {
72   topOption = idx;
73 }
74
75 int WSelectList::addOption(const char* text, void* data, int selected, TVMediaInfo* pict)
76 {
77   int thisNewOption = options.size();
78
79   wsloption wslo;
80   wslo.text = new char[strlen(text) + 1];
81   strcpy(wslo.text, text);
82   wslo.data = data;
83   wslo.pict = pict;
84   options.push_back(wslo);
85   if (selected) selectedOption = thisNewOption;
86   return thisNewOption;
87 }
88
89 void WSelectList::draw()
90 {
91   int fontHeight = getFontHeight();
92   int ySeparation = static_cast<int>(static_cast<float>(fontHeight) * linesPerOption) + gap;
93
94   numOptionsDisplayable = (area.h - 5) / ySeparation;
95
96   if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
97   if (selectedOption == (topOption - 1)) topOption--;
98   // if still not visible...
99   if ((selectedOption < topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
100   {
101     topOption = selectedOption - (numOptionsDisplayable / 2);
102   }
103
104   if (topOption < 0) topOption = 0;
105
106   fillColour(backgroundColour);
107
108   UINT ypos = 5;
109   for (int i = topOption; i < (topOption + numOptionsDisplayable); i++)
110   {
111     if (i == static_cast<int>(options.size())) return;
112     if ((ypos + ySeparation) > area.h) break;
113
114     if (i == selectedOption && showseloption)
115     {
116       rectangle(0, ypos, area.w, static_cast<UINT>(static_cast<float>(fontHeight) * linesPerOption) - 1, darkseloption ? DrawStyle::SELECTDARKHIGHLIGHT : DrawStyle::SELECTHIGHLIGHT);
117       drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT, options[i].pict);
118     }
119     else
120     {
121       rectangle(0, ypos, area.w, static_cast<UINT>(static_cast<float>(fontHeight) * linesPerOption) - 1, DrawStyle::SELECTBACKGROUND);
122       drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT, options[i].pict);
123     }
124     ypos += ySeparation;
125   }
126 }
127
128 void WSelectList::addColumn(int x)
129 {
130   if (numColumns == 10) return;
131   columns[numColumns++] = x;
132 }
133
134 int WSelectList::getColumn(int x)
135 {
136   if (x >= numColumns) return 0;
137   return columns[x];
138 }
139
140 void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour, TVMediaInfo* pict)
141 {
142   UINT curline = 0;
143   UINT taboffset = 0;
144   int fontHeight = getFontHeight();
145   float ypos_mod = static_cast<float>(ypos) + (linesPerOption - floor(linesPerOption)) * static_cast<float>(fontHeight) * 0.5f;
146
147   int imagewidth = 0;
148   int xposmod = xpos;
149   if (numColumns > 1) imagewidth = columns[1] - columns[0];
150   if (pict)
151   {
152     drawTVMedia(*pict, static_cast<float>(xpos), static_cast<float>(ypos), static_cast<float>(imagewidth),
153                 static_cast<float>(fontHeight) * linesPerOption, TopLeftLimited);
154     taboffset++;
155     xposmod += xpos;
156   }
157
158   if (!numColumns && linesPerOption == 1)
159   {
160     drawText(text, xpos, ypos, width, colour);
161   }
162   else
163   {
164     char buffer[200];
165     strncpy(buffer, text, 199);
166     int currentColumn = taboffset;
167     char* pointer;
168     char* savepointer;
169
170     pointer = STRTOKR(buffer, "\t\n", &savepointer);
171     while(pointer)
172     {
173       drawText(pointer, xposmod + columns[currentColumn], (fontHeight * curline) + static_cast<int>(ypos_mod), width - columns[currentColumn], colour);
174
175       pointer = STRTOKR(NULL, "\t\n", &savepointer);
176       if (pointer)
177       {
178         char delimiter = text[pointer - buffer - 1];
179         if (delimiter == '\t') currentColumn++;
180         else if (delimiter == '\n')
181         {
182           currentColumn = taboffset;
183           curline++;
184         }
185       }
186       if (static_cast<float>(curline) >= linesPerOption) return;
187
188       if (currentColumn == 10) return;
189     }
190   }
191 }
192
193 void WSelectList::up()
194 {
195   if (selectedOption > 0)
196   {
197     selectedOption--;
198   }
199   else
200   {
201     if (!noLoop) selectedOption = options.size() - 1;
202   }
203 }
204
205 void WSelectList::down()
206 {
207   if (selectedOption < (static_cast<int>(options.size()) - 1))
208   {
209     selectedOption++;
210   }
211   else
212   {
213     if (!noLoop) selectedOption = 0;
214   }
215 }
216
217 void WSelectList::pageUp()
218 {
219   topOption -= numOptionsDisplayable;
220   if (topOption < 0) topOption = 0;
221
222   selectedOption = topOption;
223 }
224
225 void WSelectList::pageDown()
226 {
227   if ((topOption + numOptionsDisplayable) >= static_cast<int>(options.size()))
228   {
229     selectedOption = options.size() - 1;
230   }
231   else
232   {
233     topOption += numOptionsDisplayable;
234     selectedOption = topOption;
235   }
236 }
237
238 int WSelectList::getTopOption()
239 {
240   return topOption;
241 }
242
243 int WSelectList::getNumOptions()
244 {
245   return options.size();
246 }
247
248 int WSelectList::getBottomOption()
249 {
250   UINT retval = topOption + numOptionsDisplayable;
251   if (retval > options.size()) return options.size();
252   else return retval;
253 }
254
255 int WSelectList::getCurrentOption()
256 {
257   return selectedOption;
258 }
259
260 void* WSelectList::getCurrentOptionData()
261 {
262   if (!options.size()) return 0;
263   return options[selectedOption].data;
264 }
265
266 int WSelectList::getNumOptionsDisplayable()
267 {
268   return numOptionsDisplayable;
269 }
270
271 bool WSelectList::mouseAndroidScroll(int /* x */, int /* y */, int /* sx */, int /* sy */)
272 {
273 /*
274  *  int fontHeight = getFontHeight();
275  *  int movelines= sy/fontHeight;
276  *
277  *  int seloption=selectedOption+movelines;
278  *  if (seloption<0) seloption=0;
279  *  else if (seloption>options.size()-1) seloption=options.size()-1;
280  *  selectedOption=seloption;
281 */
282   return false;
283 }
284
285 bool WSelectList::mouseMove(int x, int y)
286 {
287   int ml = getMouseLine(x - getRootBoxOffsetX(), y - getRootBoxOffsetY());
288   if (ml >= 0 && ml != selectedOption)
289   {
290     selectedOption = ml;
291     return true;
292   }
293   return false;
294 }
295
296 bool WSelectList::mouseLBDOWN(int x, int y)
297 {
298   int ml = getMouseLine(x - getRootBoxOffsetX(), y - getRootBoxOffsetY());
299   if (ml == selectedOption)
300   {
301     /* caller should generate a OK message*/
302     return true;
303   }
304   return false;
305 }
306
307 int WSelectList::getMouseLine(int x, int y)
308 {
309   int fontHeight = getFontHeight();
310   int ySeparation = static_cast<int>(static_cast<float>(fontHeight) * linesPerOption) + gap;
311
312   if (y < 0) return -1;
313   if (x < 0 || x > static_cast<int>(area.w)) return -1;
314   if (y > (10 + numOptionsDisplayable * ySeparation)) return -1;
315
316   int cy = y - 5;
317
318   int selected = cy / ySeparation;
319   if (y < 5) selected = -1;
320   if (selected > numOptionsDisplayable) return -1;
321   /* Important: should be the same algorithm used in draw! */
322   if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
323   if (selectedOption == (topOption - 1)) topOption--;
324   // if still not visible...
325   if ((selectedOption < topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
326   {
327     topOption = selectedOption - (numOptionsDisplayable / 2);
328   }
329
330   if (topOption < 0) topOption = 0;
331   if ((selected + topOption >= static_cast<int>(options.size())) || (selected + topOption < 0)) return -1;
332   return selected + topOption;
333 }