]> git.vomp.tv Git - vompclient.git/blob - wselectlist.cc
Fix a Boxx log line. Switch some WSelectList code to std::string/fmt::format
[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 int WSelectList::addOption(const std::string& text, void* data, int selected, TVMediaInfo* pict) // FIXME convert WSelectList wslo to use std::string
89 {
90   int thisNewOption = options.size();
91
92   wsloption wslo;
93   wslo.text = new char[text.length() + 1];
94   strcpy(wslo.text, text.c_str());
95   wslo.data = data;
96   wslo.pict = pict;
97   options.push_back(wslo);
98   if (selected) selectedOption = thisNewOption;
99   return thisNewOption;
100 }
101
102 void WSelectList::draw()
103 {
104   int fontHeight = getFontHeight();
105   int ySeparation = static_cast<int>(static_cast<float>(fontHeight) * linesPerOption) + gap;
106
107   numOptionsDisplayable = (area.h - 5) / ySeparation;
108
109   if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
110   if (selectedOption == (topOption - 1)) topOption--;
111   // if still not visible...
112   if ((selectedOption < topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
113   {
114     topOption = selectedOption - (numOptionsDisplayable / 2);
115   }
116
117   if (topOption < 0) topOption = 0;
118
119   fillColour(backgroundColour);
120
121   UINT ypos = 5;
122   for (int i = topOption; i < (topOption + numOptionsDisplayable); i++)
123   {
124     if (i == static_cast<int>(options.size())) return;
125     if ((ypos + ySeparation) > area.h) break;
126
127     if (i == selectedOption && showseloption)
128     {
129       rectangle(0, ypos, area.w, static_cast<UINT>(static_cast<float>(fontHeight) * linesPerOption) - 1, darkseloption ? DrawStyle::SELECTDARKHIGHLIGHT : DrawStyle::SELECTHIGHLIGHT);
130       drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::DARKTEXT, options[i].pict);
131     }
132     else
133     {
134       rectangle(0, ypos, area.w, static_cast<UINT>(static_cast<float>(fontHeight) * linesPerOption) - 1, DrawStyle::SELECTBACKGROUND);
135       drawOptionLine(options[i].text, 5, ypos, area.w - 5, DrawStyle::LIGHTTEXT, options[i].pict);
136     }
137     ypos += ySeparation;
138   }
139 }
140
141 void WSelectList::addColumn(int x)
142 {
143   if (numColumns == 10) return;
144   columns[numColumns++] = x;
145 }
146
147 int WSelectList::getColumn(int x)
148 {
149   if (x >= numColumns) return 0;
150   return columns[x];
151 }
152
153 void WSelectList::drawOptionLine(char* text, int xpos, int ypos, int width, const DrawStyle& colour, TVMediaInfo* pict)
154 {
155   UINT curline = 0;
156   UINT taboffset = 0;
157   int fontHeight = getFontHeight();
158   float ypos_mod = static_cast<float>(ypos) + (linesPerOption - floor(linesPerOption)) * static_cast<float>(fontHeight) * 0.5f;
159
160   int imagewidth = 0;
161   int xposmod = xpos;
162   if (numColumns > 1) imagewidth = columns[1] - columns[0];
163   if (pict)
164   {
165     drawTVMedia(*pict, static_cast<float>(xpos), static_cast<float>(ypos), static_cast<float>(imagewidth),
166                 static_cast<float>(fontHeight) * linesPerOption, TopLeftLimited);
167     taboffset++;
168     xposmod += xpos;
169   }
170
171   if (!numColumns && linesPerOption == 1)
172   {
173     drawText(text, xpos, ypos, width, colour);
174   }
175   else
176   {
177     char buffer[200];
178     strncpy(buffer, text, 199);
179     int currentColumn = taboffset;
180     char* pointer;
181     char* savepointer;
182
183     pointer = STRTOKR(buffer, "\t\n", &savepointer);
184     while(pointer)
185     {
186       drawText(pointer, xposmod + columns[currentColumn], (fontHeight * curline) + static_cast<int>(ypos_mod), width - columns[currentColumn], colour);
187
188       pointer = STRTOKR(NULL, "\t\n", &savepointer);
189       if (pointer)
190       {
191         char delimiter = text[pointer - buffer - 1];
192         if (delimiter == '\t') currentColumn++;
193         else if (delimiter == '\n')
194         {
195           currentColumn = taboffset;
196           curline++;
197         }
198       }
199       if (static_cast<float>(curline) >= linesPerOption) return;
200
201       if (currentColumn == 10) return;
202     }
203   }
204 }
205
206 void WSelectList::up()
207 {
208   if (selectedOption > 0)
209   {
210     selectedOption--;
211   }
212   else
213   {
214     if (!noLoop) selectedOption = options.size() - 1;
215   }
216 }
217
218 void WSelectList::down()
219 {
220   if (selectedOption < (static_cast<int>(options.size()) - 1))
221   {
222     selectedOption++;
223   }
224   else
225   {
226     if (!noLoop) selectedOption = 0;
227   }
228 }
229
230 void WSelectList::pageUp()
231 {
232   topOption -= numOptionsDisplayable;
233   if (topOption < 0) topOption = 0;
234
235   selectedOption = topOption;
236 }
237
238 void WSelectList::pageDown()
239 {
240   if ((topOption + numOptionsDisplayable) >= static_cast<int>(options.size()))
241   {
242     selectedOption = options.size() - 1;
243   }
244   else
245   {
246     topOption += numOptionsDisplayable;
247     selectedOption = topOption;
248   }
249 }
250
251 int WSelectList::getTopOption()
252 {
253   return topOption;
254 }
255
256 int WSelectList::getNumOptions()
257 {
258   return options.size();
259 }
260
261 int WSelectList::getBottomOption()
262 {
263   UINT retval = topOption + numOptionsDisplayable;
264   if (retval > options.size()) return options.size();
265   else return retval;
266 }
267
268 int WSelectList::getCurrentOption()
269 {
270   return selectedOption;
271 }
272
273 void* WSelectList::getCurrentOptionData()
274 {
275   if (!options.size()) return 0;
276   return options[selectedOption].data;
277 }
278
279 int WSelectList::getNumOptionsDisplayable()
280 {
281   return numOptionsDisplayable;
282 }
283
284 bool WSelectList::mouseAndroidScroll(int /* x */, int /* y */, int /* sx */, int /* sy */)
285 {
286 /*
287  *  int fontHeight = getFontHeight();
288  *  int movelines= sy/fontHeight;
289  *
290  *  int seloption=selectedOption+movelines;
291  *  if (seloption<0) seloption=0;
292  *  else if (seloption>options.size()-1) seloption=options.size()-1;
293  *  selectedOption=seloption;
294 */
295   return false;
296 }
297
298 bool WSelectList::mouseMove(int x, int y)
299 {
300   int ml = getMouseLine(x - getRootBoxOffsetX(), y - getRootBoxOffsetY());
301   if (ml >= 0 && ml != selectedOption)
302   {
303     selectedOption = ml;
304     return true;
305   }
306   return false;
307 }
308
309 bool WSelectList::mouseLBDOWN(int x, int y)
310 {
311   int ml = getMouseLine(x - getRootBoxOffsetX(), y - getRootBoxOffsetY());
312   if (ml == selectedOption)
313   {
314     /* caller should generate a OK message*/
315     return true;
316   }
317   return false;
318 }
319
320 int WSelectList::getMouseLine(int x, int y)
321 {
322   int fontHeight = getFontHeight();
323   int ySeparation = static_cast<int>(static_cast<float>(fontHeight) * linesPerOption) + gap;
324
325   if (y < 0) return -1;
326   if (x < 0 || x > static_cast<int>(area.w)) return -1;
327   if (y > (10 + numOptionsDisplayable * ySeparation)) return -1;
328
329   int cy = y - 5;
330
331   int selected = cy / ySeparation;
332   if (y < 5) selected = -1;
333   if (selected > numOptionsDisplayable) return -1;
334   /* Important: should be the same algorithm used in draw! */
335   if (selectedOption == (topOption + numOptionsDisplayable)) topOption++;
336   if (selectedOption == (topOption - 1)) topOption--;
337   // if still not visible...
338   if ((selectedOption < topOption) || (selectedOption > (topOption + numOptionsDisplayable)))
339   {
340     topOption = selectedOption - (numOptionsDisplayable / 2);
341   }
342
343   if (topOption < 0) topOption = 0;
344   if ((selected + topOption >= static_cast<int>(options.size())) || (selected + topOption < 0)) return -1;
345   return selected + topOption;
346 }