]> Shamusworld >> Repos - apple2/blob - src/gui/diskselector.cpp
Added WOZ 2 support.
[apple2] / src / gui / diskselector.cpp
1 //
2 // diskselector.cpp
3 //
4 // Floppy disk selector GUI
5 // by James Hammons
6 // © 2014-2018 Underground Software
7 //
8 // JLH = James Hammons <jlhamm@acm.org>
9 //
10 // WHO  WHEN        WHAT
11 // ---  ----------  -----------------------------------------------------------
12 // JLH  10/13/2013  Created this file
13 //
14 // STILL TO DO:
15 //
16 // - Fix bug where hovering on scroll image causes it to fly across the screen
17 //   [DONE]
18 //
19
20 #include "diskselector.h"
21 #include <dirent.h>
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25 #include "crc32.h"
26 #include "fileio.h"
27 #include "floppydrive.h"
28 #include "font10pt.h"
29 #include "gui.h"
30 #include "log.h"
31 #include "settings.h"
32 #include "video.h"
33
34 // Icons, in GIMP "C" format
35 #include "gfx/scroll-left.c"
36 #include "gfx/scroll-right.c"
37
38
39 struct Bitmap {
40         unsigned int width;
41         unsigned int height;
42         unsigned int bytesPerPixel;                                     // 3:RGB, 4:RGBA
43         unsigned char pixelData[];
44 };
45
46 enum { DSS_SHOWING, DSS_HIDING, DSS_SHOWN, DSS_HIDDEN, DSS_LSB_SHOWING, DSS_LSB_SHOWN, DSS_LSB_HIDING, DSS_RSB_SHOWING, DSS_RSB_SHOWN, DSS_RSB_HIDING, DSS_TEXT_SCROLLING };
47
48 #define DS_WIDTH                        402
49 #define DS_HEIGHT                       322
50 #define SCROLL_HOT_WIDTH        48
51 #define DS_XPOS ((VIRTUAL_SCREEN_WIDTH - DS_WIDTH) / 2)
52 #define DS_YPOS ((VIRTUAL_SCREEN_HEIGHT - DS_HEIGHT) / 2)
53
54
55 bool entered = false;
56 int driveNumber;
57 int diskSelectorState = DSS_HIDDEN;
58 int diskSelected = -1;
59 int lastDiskSelected = -1;
60 int numColumns;
61 int colStart = 0;
62 int dxLeft = 0;
63 int dxRight = 0;
64 int rsbPos = DS_WIDTH;
65 int lsbPos = -40;
66 int textScrollCount = 0;
67 bool refresh = false;
68
69 /*
70 So, how this will work for multiple columns, where the number of columns is greater than 3, is to have an arrow button pop up on the left or right hand side (putting the mouse on the left or right side of the disk selector activates (shows) the button, if such a move can be made. Button hides when the mouse moves out of the hot zone or when it has no more effect.
71 */
72
73
74 // We make provision for sets of 32 or less...
75 /*
76 The way the manifests are laid out, we make the assumption that the boot disk of a set is always listed first.  Therefore, image[0] will always be the boot disk.
77 */
78 struct DiskSet
79 {
80         uint8_t num;                    // # of disks in this set
81         std::string name;               // The name of this disk set
82 //      std::string fullPath;   // The path to the containing folder
83         std::string image[32];  // List of disk images in this set
84         std::string imgName[32];// List of human readable names of disk images
85         uint32_t crc[32];               // List of CRC32s of the disk images in the set
86         uint32_t crcFound[32];  // List of CRC32s actually discovered on filesystem
87
88         DiskSet(): num(0) {}
89 };
90
91
92 //
93 // Struct to hold filenames & full paths to same
94 //
95 struct FileStruct
96 {
97         std::string image;
98         std::string fullPath;
99         DiskSet diskSet;
100
101 //      FileStruct(): diskSet(NULL) {}
102 //      ~FileStruct() { if (diskSet != NULL) delete diskSet; }
103
104         // Functor, to presumably make the std::sort go faster
105         bool operator()(const FileStruct & a, const FileStruct & b) const
106         {
107                 return (strcasecmp(a.image.c_str(), b.image.c_str()) < 0 ? true : false);
108         }
109 };
110
111
112 static SDL_Texture * window = NULL;
113 static SDL_Texture * charStamp = NULL;
114 static uint32_t windowPixels[DS_WIDTH * DS_HEIGHT];
115 static uint32_t stamp[FONT_WIDTH * FONT_HEIGHT];
116 SDL_Texture * scrollLeftIcon = NULL;
117 SDL_Texture * scrollRightIcon = NULL;
118 bool DiskSelector::showWindow = false;
119 std::vector<FileStruct> fsList;
120
121
122 void DiskSelector::Init(SDL_Renderer * renderer)
123 {
124         window = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
125                 SDL_TEXTUREACCESS_TARGET, DS_WIDTH, DS_HEIGHT);
126         charStamp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
127                 SDL_TEXTUREACCESS_TARGET, FONT_WIDTH, FONT_HEIGHT);
128
129         if (!window)
130         {
131                 WriteLog("GUI (DiskSelector): Could not create window!\n");
132                 return;
133         }
134
135         if (SDL_SetTextureBlendMode(window, SDL_BLENDMODE_BLEND) == -1)
136                 WriteLog("GUI (DiskSelector): Could not set blend mode for window.\n");
137
138         if (SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_BLEND) == -1)
139                 WriteLog("GUI (DiskSelector): Could not set blend mode for charStamp.\n");
140
141         scrollLeftIcon  = GUI::CreateTexture(renderer, &scroll_left);
142         scrollRightIcon = GUI::CreateTexture(renderer, &scroll_right);
143
144         for(uint32_t i=0; i<DS_WIDTH*DS_HEIGHT; i++)
145                 windowPixels[i] = 0xEF007F00;
146
147         SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
148         FindDisks();
149         DrawFilenames(renderer);
150 }
151
152
153 //
154 // Find all disks images top level call
155 //
156 void DiskSelector::FindDisks(void)
157 {
158         fsList.clear();
159         FindDisks(settings.disksPath);
160         std::sort(fsList.begin(), fsList.end(), FileStruct());
161         // Calculate the number of columns in the file selector...
162         numColumns = (int)ceilf((float)fsList.size() / 27.0f);
163         WriteLog("GUI (DiskSelector)::FindDisks(): # of columns is %i (%i files)\n", numColumns, fsList.size());
164 }
165
166 /*
167 OK, so the way that you can determine if a file is a directory in a cross-platform way is to do an opendir() call on a discovered filename.  If it returns NULL, then it's a regular file and not a directory.  Though I think the Linux method is more elegant.  :-P
168 */
169 //
170 // Find all disks images within path (recursive call does depth first search)
171 //
172 void DiskSelector::FindDisks(const char * path)
173 {
174         DIR * dir = opendir(path);
175
176         if (!dir)
177         {
178                 WriteLog("GUI (DiskSelector)::FindDisks: Could not open directory \"%s\%!\n", path);
179                 return;
180         }
181
182         dirent * ent;
183
184         while ((ent = readdir(dir)) != NULL)
185         {
186                 char buf[0x10000];
187                 sprintf(buf, "%s/%s", path, ent->d_name);
188
189                 // Cross-platform way to test if it's a directory...
190                 DIR * test = opendir(buf);
191
192 //              if ((ent->d_type == DT_REG) && HasLegalExtension(ent->d_name))
193                 if (test == NULL)
194                 {
195                         if (HasLegalExtension(ent->d_name))
196                         {
197                                 FileStruct fs;
198                                 fs.image = ent->d_name;
199                                 fs.fullPath = buf;
200                                 fsList.push_back(fs);
201                         }
202                 }
203 //              else if (ent->d_type == DT_DIR)
204                 else
205                 {
206                         // Make sure we close the thing, since it's a bona-fide dir!
207                         closedir(test);
208
209                         // Only recurse if the directory is not one of the special ones...
210                         if ((strcmp(ent->d_name, "..") != 0)
211                                 && (strcmp(ent->d_name, ".") != 0))
212                         {
213                                 // Check to see if this is a special directory with a manifest
214                                 char buf2[0x10000];
215                                 sprintf(buf2, "%s/manifest.txt", buf);
216                                 FILE * fp = fopen(buf2, "r");
217
218                                 // No manifest means it's just a regular directory...
219                                 if (fp == NULL)
220                                         FindDisks(buf);
221                                 else
222                                 {
223                                         // Read the manifest and all that good stuff
224                                         FileStruct fs;
225                                         ReadManifest(fp, &fs.diskSet);
226                                         fclose(fp);
227
228                                         // Finally, check that the stuff in the manifest is
229                                         // actually in the directory...
230                                         if (CheckManifest(buf, &fs.diskSet) == true)
231                                         {
232                                                 fs.fullPath = buf;
233                                                 fs.image = fs.diskSet.name;
234                                                 fsList.push_back(fs);
235                                         }
236                                         else
237                                                 WriteLog("Manifest for '%s' failed check phase.\n", fs.diskSet.name.c_str());
238 #if 0
239                                         printf("Name found: \"%s\" (%d)\nDisks:\n", fs.diskSet.name.c_str(), fs.diskSet.num);
240                                         for(int i=0; i<fs.diskSet.num; i++)
241                                                 printf("%s (CRC: %08X)\n", fs.diskSet.image[i].c_str(), fs.diskSet.crc[i]);
242 #endif
243
244                                 }
245                         }
246                 }
247         }
248
249         closedir(dir);
250 }
251
252
253 void DiskSelector::ReadManifest(FILE * fp, DiskSet * ds)
254 {
255         char line[0x10000];
256         int disksFound = 0;
257         int lineNo = 0;
258
259         while (!feof(fp))
260         {
261                 fgets(line, 0x10000, fp);
262                 lineNo++;
263
264                 if ((line[0] == '#') || (line[0] == '\n'))
265                         ; // Do nothing with comments or blank lines...
266                 else
267                 {
268                         char buf[1024];
269                         char crcbuf[16];
270                         char altName[1024];
271
272                         if (strncmp(line, "diskset", 7) == 0)
273                         {
274                                 sscanf(line, "diskset=\"%[^\"]\"", buf);
275                                 ds->name = buf;
276                         }
277                         else if (strncmp(line, "disks", 5) == 0)
278                         {
279                                 sscanf(line, "disks=%hhd", &ds->num);
280                         }
281                         else if (strncmp(line, "disk", 4) == 0)
282                         {
283                                 int n = sscanf(line, "disk=%s %s (%s)", buf, crcbuf, altName);
284
285                                 if ((n == 2) || (n == 3))
286                                 {
287                                         ds->image[disksFound] = buf;
288                                         ds->crc[disksFound] = strtoul(crcbuf, NULL, 16);
289                                         disksFound++;
290
291                                         if (n == 3)
292                                                 ds->imgName[disksFound] = altName;
293                                         else
294                                         {
295                                                 // Find the file's extension, if any
296                                                 char * ext = strrchr(buf, '.');
297
298                                                 // Kill the disk extension, if it exists
299                                                 if (ext != NULL)
300                                                         *ext = 0;
301
302                                                 ds->imgName[disksFound] = buf;
303                                         }
304                                 }
305                                 else
306                                         WriteLog("Malformed disk descriptor in manifest at line %d\n", lineNo);
307                         }
308                 }
309         }
310
311         if (disksFound != ds->num)
312                 WriteLog("Found only %d entries in manifest, expected %hhd\n", disksFound, ds->num);
313 }
314
315
316 bool DiskSelector::CheckManifest(const char * path, DiskSet * ds)
317 {
318         uint8_t found = 0;
319
320         for(int i=0; i<ds->num; i++)
321         {
322                 std::string filename = path;
323                 filename += "/";
324                 filename += ds->image[i];
325                 uint32_t size;
326                 uint8_t * buf = ReadFile(filename.c_str(), &size);
327
328                 if (buf != NULL)
329                 {
330                         ds->crcFound[i] = CRC32(buf, size);
331                         free(buf);
332                         found++;
333
334                         if (ds->crc[i] != ds->crcFound[i])
335                         {
336                                 WriteLog("Warning: Bad CRC32 for '%s'. Expected: %08X, found: %08X\n", ds->image[i], ds->crc[i], ds->crcFound[i]);
337                         }
338                 }
339         }
340
341         return (found == ds->num ? true : false);
342 }
343
344
345 bool DiskSelector::HasLegalExtension(const char * name)
346 {
347         // Find the file's extension, if any
348         const char * ext = strrchr(name, '.');
349
350         // No extension, so fuggetaboutit
351         if (ext == NULL)
352                 return false;
353
354         // Otherwise, look for a legal extension
355         // We should be smarter than this, and look at headers & file sizes instead
356         if ((strcasecmp(ext, ".dsk") == 0)
357                 || (strcasecmp(ext, ".do") == 0)
358                 || (strcasecmp(ext, ".po") == 0)
359                 || (strcasecmp(ext, ".woz") == 0))
360                 return true;
361
362         return false;
363 }
364
365
366 void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
367 {
368         if (SDL_SetRenderTarget(renderer, window) < 0)
369         {
370                 WriteLog("GUI: Could not set Render Target to overlay... (%s)\n", SDL_GetError());
371                 return;
372         }
373
374         // 3 columns of 16 chars apiece (with 8X16 font), 18 rows
375         // 3 columns of 18 chars apiece (with 7X12 font), 24 rows
376         // 3 columns of 21 chars apiece (with 6X11 font), 27 rows
377
378         unsigned int count = 0;
379         unsigned int fsStart = colStart * 27;
380         int offset = 0;
381
382         // Draw partial columns (for scrolling left/right)
383         // [could probably combine these...]
384         if (textScrollCount < 0)
385         {
386                 int partialColStart = (colStart - 1) * 27;
387                 offset = -1 * textScrollCount;
388
389                 for(unsigned int y=0; y<27; y++)
390                 {
391                         for(unsigned int i=22+textScrollCount, x=0; i<21; i++, x++)
392                         {
393                                 if (i >= fsList[partialColStart + y].image.length())
394                                         break;
395
396                                 DrawCharacter(renderer, x + 1, y + 1, fsList[partialColStart + y].image[i], false);
397                         }
398                 }
399         }
400         else if (textScrollCount > 0)
401         {
402                 offset = 22 - textScrollCount;
403
404                 for(unsigned int y=0; y<27; y++)
405                 {
406                         for(unsigned int i=textScrollCount, x=0; i<21; i++, x++)
407                         {
408                                 if (i >= fsList[fsStart + y].image.length())
409                                         break;
410
411                                 DrawCharacter(renderer, x + 1, y + 1, fsList[fsStart + y].image[i], false);
412                         }
413                 }
414
415                 fsStart += 27;
416         }
417
418         while (fsStart < fsList.size())
419         {
420 //              int currentX = (count / 18) * 17;
421 //              int currentY = (count % 18);
422 //              int currentX = (count / 24) * 19;
423 //              int currentY = (count % 24);
424                 int currentX = (count / 27) * 22;
425                 int currentY = (count % 27);
426
427 //              for(unsigned int i=0; i<16; i++)
428 //              for(unsigned int i=0; i<18; i++)
429                 for(unsigned int i=0; i<21; i++)
430                 {
431                         if (i >= fsList[fsStart].image.length())
432                                 break;
433
434                         bool invert = (diskSelected == (int)fsStart ? true : false);
435                         DrawCharacter(renderer, currentX + i + 1 + offset, currentY + 1, fsList[fsStart].image[i], invert);
436                 }
437
438                 count++;
439                 fsStart++;
440
441 //              if (count >= (18 * 3))
442 //              if (count >= (24 * 3))
443                 if (count >= (27 * 3))
444                         break;
445         }
446
447         // If a disk is selected, show it on the top line in inverse video
448         if (diskSelected > -1)
449         {
450                 for(unsigned int i=0; i<65; i++)
451                 {
452                         if (i >= fsList[diskSelected].image.length())
453                                 break;
454
455                         DrawCharacter(renderer, i + 1, 0, fsList[diskSelected].image[i], true);
456                 }
457         }
458
459         // Set render target back to default
460         SDL_SetRenderTarget(renderer, NULL);
461 }
462
463
464 void DiskSelector::DrawCharacter(SDL_Renderer * renderer, int x, int y, uint8_t c, bool invert/*=false*/)
465 {
466         uint32_t inv = (invert ? 0x000000FF : 0x00000000);
467         uint32_t pixel = 0xFFFFC000;    // RRGGBBAA
468         uint8_t * ptr = (uint8_t *)&font10pt[(c - 0x20) * FONT_WIDTH * FONT_HEIGHT];
469         SDL_Rect dst;
470         dst.x = x * FONT_WIDTH, dst.y = y * FONT_HEIGHT, dst.w = FONT_WIDTH, dst.h = FONT_HEIGHT;
471
472         for(int i=0; i<FONT_WIDTH*FONT_HEIGHT; i++)
473                 stamp[i] = (pixel | ptr[i]) ^ inv;
474
475         SDL_UpdateTexture(charStamp, NULL, stamp, FONT_WIDTH * sizeof(Uint32));
476         SDL_RenderCopy(renderer, charStamp, NULL, &dst);
477 }
478
479
480 void DiskSelector::ShowWindow(int drive)
481 {
482         diskSelectorState = DSS_SHOWN;
483         entered = false;
484         showWindow = true;
485         driveNumber = drive;
486 }
487
488
489 void DiskSelector::MouseDown(int32_t x, int32_t y, uint32_t buttons)
490 {
491         if (!showWindow || !entered)
492                 return;
493
494         if ((diskSelectorState == DSS_LSB_SHOWING) || (diskSelectorState == DSS_LSB_SHOWN))
495         {
496                 colStart--;
497                 textScrollCount = 21;
498
499                 if (colStart == 0)
500                 {
501                         diskSelectorState = DSS_LSB_HIDING;
502                         dxLeft = -8;
503                 }
504
505                 return;
506         }
507
508         if ((diskSelectorState == DSS_RSB_SHOWING) || (diskSelectorState == DSS_RSB_SHOWN))
509         {
510                 colStart++;
511                 textScrollCount = -21;
512
513                 if ((colStart + 3) == numColumns)
514                 {
515                         diskSelectorState = DSS_RSB_HIDING;
516                         dxRight = 8;
517                 }
518
519                 return;
520         }
521
522         if (diskSelected != -1)
523         {
524                 floppyDrive[0].LoadImage(fsList[diskSelected].fullPath.c_str(), driveNumber);
525         }
526
527         showWindow = false;
528 }
529
530
531 void DiskSelector::MouseUp(int32_t x, int32_t y, uint32_t buttons)
532 {
533         if (!showWindow)
534                 return;
535
536 }
537
538
539 void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
540 {
541         if (!showWindow)
542                 return;
543
544         // Check to see if DS has been hovered yet, and, if so, set a flag to show
545         // that it has
546         if (!entered && ((x >= DS_XPOS) && (x <= (DS_XPOS + DS_WIDTH))
547                 && (y >= DS_YPOS) && (y <= (DS_YPOS + DS_HEIGHT))))
548                 entered = true;
549
550         // Check to see if the DS, since being hovered, is now no longer being
551         // hovered
552 //N.B.: Should probably make like a 1/2 to 1 second timeout to allow for overshooting the edge of the thing, maybe have the window fade out gradually and let it come back if you enter before it leaves...
553         if (entered && ((x < DS_XPOS) || (x > (DS_XPOS + DS_WIDTH))
554                 || (y < DS_YPOS) || (y > (DS_YPOS + DS_HEIGHT))))
555         {
556                 diskSelectorState = DSS_HIDDEN;
557                 dxLeft = 0;
558                 dxRight = 0;
559                 rsbPos = DS_WIDTH;
560                 lsbPos = -40;
561                 showWindow = false;
562                 refresh = true;
563                 return;
564         }
565
566         // Bail out if the DS hasn't been entered yet
567         if (!entered)
568                 return;
569
570 /*
571 states:
572 +-----+---------------------+-----+
573 |     |                     |     |
574 |     |                     |     |
575 +-----+---------------------+-----+
576  ^           ^                ^
577  |           |                x is here and state is DSS_SHOWN
578  |           x is here and state is DSS_LSB_SHOWING or DSS_RSB_SHOWING
579  x is here and state is DSS_SHOWN
580
581 */
582         if (x < (DS_XPOS + SCROLL_HOT_WIDTH))
583         {
584                 if ((colStart > 0) && (diskSelectorState == DSS_SHOWN))
585                 {
586                         diskSelectorState = DSS_LSB_SHOWING;
587                         dxLeft = 8;
588                 }
589         }
590         else if (x > (DS_XPOS + DS_WIDTH - SCROLL_HOT_WIDTH))
591         {
592                 if (((colStart + 3) < numColumns) && (diskSelectorState == DSS_SHOWN))
593                 {
594                         diskSelectorState = DSS_RSB_SHOWING;
595                         dxRight = -8;
596                 }
597         }
598         else
599         {
600                 // Handle the excluded middle  :-P
601                 if ((diskSelectorState == DSS_LSB_SHOWING)
602                         || (diskSelectorState == DSS_LSB_SHOWN))
603                 {
604                         diskSelectorState = DSS_LSB_HIDING;
605                         dxLeft = -8;
606                 }
607                 else if ((diskSelectorState == DSS_RSB_SHOWING)
608                         || (diskSelectorState == DSS_RSB_SHOWN))
609                 {
610                         diskSelectorState = DSS_RSB_HIDING;
611                         dxRight = 8;
612                 }
613         }
614
615         // The -1 terms move the origin to the upper left corner (from 1 in, and 1
616         // down)
617         int xChar = ((x - DS_XPOS) / FONT_WIDTH) - 1;
618         int yChar = ((y - DS_YPOS) / FONT_HEIGHT) - 1;
619         diskSelected = ((xChar / 22) * 27) + yChar + (colStart * 27);
620
621         if ((yChar < 0) || (yChar >= 27)
622                 || (diskSelected >= (int)fsList.size())
623                 || (diskSelectorState == DSS_LSB_SHOWING)
624                 || (diskSelectorState == DSS_LSB_SHOWN)
625                 || (diskSelectorState == DSS_RSB_SHOWING)
626                 || (diskSelectorState == DSS_RSB_SHOWN))
627                 diskSelected = -1;
628
629         if (diskSelected != lastDiskSelected)
630         {
631                 HandleSelection(sdlRenderer);
632                 lastDiskSelected = diskSelected;
633         }
634 }
635
636
637 void DiskSelector::HandleGUIState(void)
638 {
639         lsbPos += dxLeft;
640         rsbPos += dxRight;
641
642         if ((lsbPos > (SCROLL_HOT_WIDTH - 40)) && (diskSelectorState == DSS_LSB_SHOWING))
643         {
644                 diskSelectorState = DSS_LSB_SHOWN;
645                 lsbPos = SCROLL_HOT_WIDTH - 40;
646                 dxLeft = 0;
647         }
648         else if ((lsbPos < -40) && (diskSelectorState == DSS_LSB_HIDING))
649         {
650                 diskSelectorState = DSS_SHOWN;
651                 lsbPos = -40;
652                 dxLeft = 0;
653         }
654         else if ((rsbPos < (DS_WIDTH - SCROLL_HOT_WIDTH)) && (diskSelectorState == DSS_RSB_SHOWING))
655         {
656                 diskSelectorState = DSS_RSB_SHOWN;
657                 rsbPos = DS_WIDTH - SCROLL_HOT_WIDTH;
658                 dxRight = 0;
659         }
660         else if ((rsbPos > DS_WIDTH) && (diskSelectorState == DSS_RSB_HIDING))
661         {
662                 diskSelectorState = DSS_SHOWN;
663                 rsbPos = DS_WIDTH;
664                 dxRight = 0;
665         }
666
667         if (textScrollCount < 0)
668         {
669                 textScrollCount += 2;
670
671                 if (textScrollCount > 0)
672                 {
673                         textScrollCount = 0;
674                         refresh = true;
675                 }
676         }
677         else if (textScrollCount > 0)
678         {
679                 textScrollCount -= 2;
680
681                 if (textScrollCount < 0)
682                 {
683                         textScrollCount = 0;
684                         refresh = true;
685                 }
686         }
687 }
688
689
690 void DiskSelector::HandleSelection(SDL_Renderer * renderer)
691 {
692         SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
693         DrawFilenames(renderer);
694         refresh = false;
695 }
696
697
698 void DiskSelector::Render(SDL_Renderer * renderer)
699 {
700         if (!(window && showWindow))
701                 return;
702
703         HandleGUIState();
704
705         if (((diskSelectorState != DSS_LSB_SHOWN)
706                 && (diskSelectorState != DSS_RSB_SHOWN)
707                 && (diskSelectorState != DSS_SHOWN))
708                 || (textScrollCount != 0) || refresh)
709                 HandleSelection(renderer);
710
711         // Render scroll arrows (need to figure out why no alpha!)
712         SDL_SetRenderTarget(renderer, window);
713         SDL_Rect dst2 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
714         dst2.x = lsbPos;
715         SDL_RenderCopy(renderer, scrollLeftIcon, NULL, &dst2);
716         SDL_Rect dst3 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
717         dst3.x = rsbPos;
718         SDL_RenderCopy(renderer, scrollRightIcon, NULL, &dst3);
719         SDL_SetRenderTarget(renderer, NULL);
720
721         SDL_Rect dst = { DS_XPOS, DS_YPOS, DS_WIDTH, DS_HEIGHT };
722         SDL_RenderCopy(renderer, window, NULL, &dst);
723 }
724