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