]> Shamusworld >> Repos - apple2/blob - src/gui/diskselector.cpp
ac3ec44682f8b3993bc8137f13491bc3b71a0cab
[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 static bool entered = false;
56 static int driveNumber;
57 static int diskSelectorState = DSS_HIDDEN;
58 static int diskSelected = -1;
59 static int lastDiskSelected = -1;
60 static int numColumns;
61 static int colStart = 0;
62 static int dxLeft = 0;
63 static int dxRight = 0;
64 static int rsbPos = DS_WIDTH;
65 static int lsbPos = -40;
66 static int textScrollCount = 0;
67 static 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 uint32_t windowPixels[DS_WIDTH * DS_HEIGHT];
114 SDL_Texture * scrollLeftIcon = NULL;
115 SDL_Texture * scrollRightIcon = NULL;
116 bool DiskSelector::showWindow = false;
117 std::vector<FileStruct> fsList;
118 std::vector<FileStruct> hdList;
119
120
121 void DiskSelector::Init(SDL_Renderer * renderer)
122 {
123         window = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
124                 SDL_TEXTUREACCESS_TARGET, DS_WIDTH, DS_HEIGHT);
125
126         if (!window)
127         {
128                 WriteLog("GUI (DiskSelector): Could not create window!\n");
129                 return;
130         }
131
132         if (SDL_SetTextureBlendMode(window, SDL_BLENDMODE_BLEND) == -1)
133                 WriteLog("GUI (DiskSelector): Could not set blend mode for window.\n");
134
135         scrollLeftIcon  = GUI::CreateTexture(renderer, &scroll_left);
136         scrollRightIcon = GUI::CreateTexture(renderer, &scroll_right);
137
138         for(uint32_t i=0; i<DS_WIDTH*DS_HEIGHT; i++)
139                 windowPixels[i] = 0xEF007F00;
140
141         SDL_UpdateTexture(window, NULL, windowPixels, DS_WIDTH * sizeof(Uint32));
142         FindDisks();
143         FindHardDisks();
144         DrawFilenames(renderer);
145 }
146
147
148 //
149 // Find all disks images top level call
150 //
151 void DiskSelector::FindDisks(void)
152 {
153         fsList.clear();
154         FindDisks(settings.disksPath);
155         std::sort(fsList.begin(), fsList.end(), FileStruct());
156         // Calculate the number of columns in the file selector...
157         numColumns = (int)ceilf((float)fsList.size() / 27.0f);
158         WriteLog("GUI (DiskSelector)::FindDisks(): # of columns is %i (%i files)\n", numColumns, fsList.size());
159 }
160
161
162 /*
163 OK, so the way that you can determine if a file is a directory in a cross-
164 platform way is to do an opendir() call on a discovered filename.  If it
165 returns NULL, then it's a regular file and not a directory.  Though I think the
166 Linux method is more elegant.  :-P
167 */
168 //
169 // Find all disks images within path (recursive call does depth first search)
170 //
171 void DiskSelector::FindDisks(const char * path)
172 {
173         DIR * dir = opendir(path);
174
175         if (!dir)
176         {
177                 WriteLog("GUI (DiskSelector)::FindDisks: Could not open directory \"%s\%!\n", path);
178                 return;
179         }
180
181         dirent * ent;
182
183         while ((ent = readdir(dir)) != NULL)
184         {
185                 char buf[0x10000];
186                 sprintf(buf, "%s/%s", path, ent->d_name);
187
188                 // Cross-platform way to test if it's a directory...
189                 DIR * test = opendir(buf);
190
191 //              if ((ent->d_type == DT_REG) && HasLegalExtension(ent->d_name))
192                 if (test == NULL)
193                 {
194                         if (HasLegalExtension(ent->d_name))
195                         {
196                                 FileStruct fs;
197                                 fs.image = ent->d_name;
198                                 fs.fullPath = buf;
199                                 fsList.push_back(fs);
200                         }
201                 }
202 //              else if (ent->d_type == DT_DIR)
203                 else
204                 {
205                         // Make sure we close the thing, since it's a bona-fide dir!
206                         closedir(test);
207
208                         // Only recurse if the directory is not one of the special ones...
209                         if ((strcmp(ent->d_name, "..") != 0)
210                                 && (strcmp(ent->d_name, ".") != 0))
211                         {
212                                 // Check to see if this is a special directory with a manifest
213                                 char buf2[0x10000];
214                                 sprintf(buf2, "%s/manifest.txt", buf);
215                                 FILE * fp = fopen(buf2, "r");
216
217                                 // No manifest means it's just a regular directory...
218                                 if (fp == NULL)
219                                         FindDisks(buf);
220                                 else
221                                 {
222                                         // Read the manifest and all that good stuff
223                                         FileStruct fs;
224                                         ReadManifest(fp, &fs.diskSet);
225                                         fclose(fp);
226
227                                         // Finally, check that the stuff in the manifest is
228                                         // actually in the directory...
229                                         if (CheckManifest(buf, &fs.diskSet) == true)
230                                         {
231                                                 fs.fullPath = buf;
232                                                 fs.image = fs.diskSet.name;
233                                                 fsList.push_back(fs);
234                                         }
235                                         else
236                                                 WriteLog("Manifest for '%s' failed check phase.\n", fs.diskSet.name.c_str());
237 #if 0
238                                         printf("Name found: \"%s\" (%d)\nDisks:\n", fs.diskSet.name.c_str(), fs.diskSet.num);
239                                         for(int i=0; i<fs.diskSet.num; i++)
240                                                 printf("%s (CRC: %08X)\n", fs.diskSet.image[i].c_str(), fs.diskSet.crc[i]);
241 #endif
242
243                                 }
244                         }
245                 }
246         }
247
248         closedir(dir);
249 }
250
251
252 void DiskSelector::ReadManifest(FILE * fp, DiskSet * ds)
253 {
254         char line[0x10000];
255         int disksFound = 0;
256         int lineNo = 0;
257
258         while (!feof(fp))
259         {
260                 fgets(line, 0x10000, fp);
261                 lineNo++;
262
263                 if ((line[0] == '#') || (line[0] == '\n'))
264                         ; // Do nothing with comments or blank lines...
265                 else
266                 {
267                         char buf[1024];
268                         char crcbuf[16];
269                         char altName[1024];
270
271                         if (strncmp(line, "diskset", 7) == 0)
272                         {
273                                 sscanf(line, "diskset=\"%[^\"]\"", buf);
274                                 ds->name = buf;
275                         }
276                         else if (strncmp(line, "disks", 5) == 0)
277                         {
278                                 sscanf(line, "disks=%hhd", &ds->num);
279                         }
280                         else if (strncmp(line, "disk", 4) == 0)
281                         {
282                                 int n = sscanf(line, "disk=%s %s (%s)", buf, crcbuf, altName);
283
284                                 if ((n == 2) || (n == 3))
285                                 {
286                                         ds->image[disksFound] = buf;
287                                         ds->crc[disksFound] = strtoul(crcbuf, NULL, 16);
288                                         disksFound++;
289
290                                         if (n == 3)
291                                                 ds->imgName[disksFound] = altName;
292                                         else
293                                         {
294                                                 // Find the file's extension, if any
295                                                 char * ext = strrchr(buf, '.');
296
297                                                 // Kill the disk extension, if it exists
298                                                 if (ext != NULL)
299                                                         *ext = 0;
300
301                                                 ds->imgName[disksFound] = buf;
302                                         }
303                                 }
304                                 else
305                                         WriteLog("Malformed disk descriptor in manifest at line %d\n", lineNo);
306                         }
307                 }
308         }
309
310         if (disksFound != ds->num)
311                 WriteLog("Found only %d entries in manifest, expected %hhd\n", disksFound, ds->num);
312 }
313
314
315 bool DiskSelector::CheckManifest(const char * path, DiskSet * ds)
316 {
317         uint8_t found = 0;
318
319         for(int i=0; i<ds->num; i++)
320         {
321                 std::string filename = path;
322                 filename += "/";
323                 filename += ds->image[i];
324                 uint32_t size;
325                 uint8_t * buf = ReadFile(filename.c_str(), &size);
326
327                 if (buf != NULL)
328                 {
329                         ds->crcFound[i] = CRC32(buf, size);
330                         free(buf);
331                         found++;
332
333                         if (ds->crc[i] != ds->crcFound[i])
334                         {
335                                 WriteLog("Warning: Bad CRC32 for '%s'. Expected: %08X, found: %08X\n", ds->image[i], ds->crc[i], ds->crcFound[i]);
336                         }
337                 }
338         }
339
340         return (found == ds->num ? true : false);
341 }
342
343
344 bool DiskSelector::HasLegalExtension(const char * name)
345 {
346         // Find the file's extension, if any
347         const char * ext = strrchr(name, '.');
348
349         // No extension, so fuggetaboutit
350         if (ext == NULL)
351                 return false;
352
353         // Otherwise, look for a legal extension
354         // We should be smarter than this, and look at headers & file sizes instead
355         if ((strcasecmp(ext, ".dsk") == 0)
356                 || (strcasecmp(ext, ".do") == 0)
357                 || (strcasecmp(ext, ".po") == 0)
358                 || (strcasecmp(ext, ".woz") == 0))
359                 return true;
360
361         return false;
362 }
363
364
365 //
366 // Find all disks images top level call
367 //
368 void DiskSelector::FindHardDisks(void)
369 {
370         hdList.clear();
371         FindHardDisks(settings.disksPath);
372         std::sort(hdList.begin(), hdList.end(), FileStruct());
373         WriteLog("GUI (DiskSelector)::FindHardDisks(): # of HDs is %i\n", hdList.size());
374 }
375
376
377 //
378 // Find all hard disk images within path (recursive call does depth first search)
379 //
380 void DiskSelector::FindHardDisks(const char * path)
381 {
382         DIR * dir = opendir(path);
383
384         if (!dir)
385         {
386                 WriteLog("GUI (DiskSelector)::FindHardDisks: Could not open directory \"%s\%!\n", path);
387                 return;
388         }
389
390         dirent * ent;
391
392         while ((ent = readdir(dir)) != NULL)
393         {
394                 char buf[0x10000];
395                 sprintf(buf, "%s/%s", path, ent->d_name);
396
397                 // Cross-platform way to test if it's a directory (test = NULL -> file)
398                 DIR * test = opendir(buf);
399
400                 if (test == NULL)
401                 {
402                         const char * ext = strrchr(ent->d_name, '.');
403
404                         if ((ext != NULL) && (strcasecmp(ext, ".2mg") == 0))
405                         {
406                                 FileStruct fs;
407                                 fs.image = ent->d_name;
408                                 fs.fullPath = buf;
409                                 hdList.push_back(fs);
410                         }
411                 }
412                 else
413                 {
414                         // Make sure we close the thing, since it's a bona-fide dir!
415                         closedir(test);
416
417                         // Only recurse if the directory is not one of the special ones...
418                         if ((strcmp(ent->d_name, "..") != 0)
419                                 && (strcmp(ent->d_name, ".") != 0))
420                         {
421                                 FindHardDisks(buf);
422                         }
423                 }
424         }
425
426         closedir(dir);
427 }
428
429
430 void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
431 {
432         if (SDL_SetRenderTarget(renderer, window) < 0)
433         {
434                 WriteLog("GUI: Could not set Render Target to overlay... (%s)\n", SDL_GetError());
435                 return;
436         }
437
438         // 3 columns of 16 chars apiece (with 8X16 font), 18 rows
439         // 3 columns of 18 chars apiece (with 7X12 font), 24 rows
440         // 3 columns of 21 chars apiece (with 6X11 font), 27 rows
441
442         unsigned int count = 0;
443         unsigned int fsStart = colStart * 27;
444         int offset = 0;
445
446         // Draw partial columns (for scrolling left/right)
447         // [could probably combine these...]
448         if (textScrollCount < 0)
449         {
450                 int partialColStart = (colStart - 1) * 27;
451                 offset = -1 * textScrollCount;
452
453                 for(unsigned int y=0; y<27; y++)
454                 {
455                         for(unsigned int i=22+textScrollCount, x=0; i<21; i++, x++)
456                         {
457                                 if (i >= fsList[partialColStart + y].image.length())
458                                         break;
459
460                                 GUI::DrawCharacter(renderer, x + 1, y + 1, fsList[partialColStart + y].image[i], false);
461                         }
462                 }
463         }
464         else if (textScrollCount > 0)
465         {
466                 offset = 22 - textScrollCount;
467
468                 for(unsigned int y=0; y<27; y++)
469                 {
470                         for(unsigned int i=textScrollCount, x=0; i<21; i++, x++)
471                         {
472                                 if (i >= fsList[fsStart + y].image.length())
473                                         break;
474
475                                 GUI::DrawCharacter(renderer, x + 1, y + 1, fsList[fsStart + y].image[i], false);
476                         }
477                 }
478
479                 fsStart += 27;
480         }
481
482         while (fsStart < fsList.size())
483         {
484 //              int currentX = (count / 18) * 17;
485 //              int currentY = (count % 18);
486 //              int currentX = (count / 24) * 19;
487 //              int currentY = (count % 24);
488                 int currentX = (count / 27) * 22;
489                 int currentY = (count % 27);
490
491 //              for(unsigned int i=0; i<16; i++)
492 //              for(unsigned int i=0; i<18; i++)
493                 for(unsigned int i=0; i<21; i++)
494                 {
495                         if (i >= fsList[fsStart].image.length())
496                                 break;
497
498                         bool invert = (diskSelected == (int)fsStart ? true : false);
499                         GUI::DrawCharacter(renderer, currentX + i + 1 + offset, currentY + 1, fsList[fsStart].image[i], invert);
500                 }
501
502                 count++;
503                 fsStart++;
504
505 //              if (count >= (18 * 3))
506 //              if (count >= (24 * 3))
507                 if (count >= (27 * 3))
508                         break;
509         }
510
511         // If a disk is selected, show it on the top line in inverse video
512         if (diskSelected > -1)
513         {
514                 for(unsigned int i=0; i<65; i++)
515                 {
516                         if (i >= fsList[diskSelected].image.length())
517                                 break;
518
519                         GUI::DrawCharacter(renderer, i + 1, 0, fsList[diskSelected].image[i], true);
520                 }
521         }
522
523         // Set render target back to default
524         SDL_SetRenderTarget(renderer, NULL);
525 }
526
527
528 void DiskSelector::ShowWindow(int drive)
529 {
530         diskSelectorState = DSS_SHOWN;
531         entered = false;
532         showWindow = true;
533         driveNumber = drive;
534 }
535
536
537 void DiskSelector::HideWindow(void)
538 {
539         diskSelectorState = DSS_HIDDEN;
540         dxLeft = 0;
541         dxRight = 0;
542         rsbPos = DS_WIDTH;
543         lsbPos = -40;
544         showWindow = false;
545         refresh = true;
546 }
547
548
549 void DiskSelector::MouseDown(int32_t x, int32_t y, uint32_t buttons)
550 {
551         if (!showWindow || !entered)
552                 return;
553
554         if ((diskSelectorState == DSS_LSB_SHOWING) || (diskSelectorState == DSS_LSB_SHOWN))
555         {
556                 colStart--;
557                 textScrollCount = 21;
558
559                 if (colStart == 0)
560                 {
561                         diskSelectorState = DSS_LSB_HIDING;
562                         dxLeft = -8;
563                 }
564
565                 return;
566         }
567
568         if ((diskSelectorState == DSS_RSB_SHOWING) || (diskSelectorState == DSS_RSB_SHOWN))
569         {
570                 colStart++;
571                 textScrollCount = -21;
572
573                 if ((colStart + 3) == numColumns)
574                 {
575                         diskSelectorState = DSS_RSB_HIDING;
576                         dxRight = 8;
577                 }
578
579                 return;
580         }
581
582         if (diskSelected != -1)
583         {
584                 floppyDrive[0].LoadImage(fsList[diskSelected].fullPath.c_str(), driveNumber);
585         }
586
587         showWindow = false;
588 }
589
590
591 void DiskSelector::MouseUp(int32_t x, int32_t y, uint32_t buttons)
592 {
593         if (!showWindow)
594                 return;
595
596 }
597
598
599 void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
600 {
601         if (!showWindow)
602                 return;
603
604         // Check to see if DS has been hovered yet, and, if so, set a flag to show
605         // that it has
606         if (!entered && ((x >= DS_XPOS) && (x <= (DS_XPOS + DS_WIDTH))
607                 && (y >= DS_YPOS) && (y <= (DS_YPOS + DS_HEIGHT))))
608                 entered = true;
609
610         // Check to see if the DS, since being hovered, is now no longer being
611         // hovered
612 //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...
613         if (entered && ((x < DS_XPOS) || (x > (DS_XPOS + DS_WIDTH))
614                 || (y < DS_YPOS) || (y > (DS_YPOS + DS_HEIGHT))))
615         {
616                 diskSelectorState = DSS_HIDDEN;
617                 dxLeft = 0;
618                 dxRight = 0;
619                 rsbPos = DS_WIDTH;
620                 lsbPos = -40;
621                 showWindow = false;
622                 refresh = true;
623                 return;
624         }
625
626         // Bail out if the DS hasn't been entered yet
627         if (!entered)
628                 return;
629
630 /*
631 states:
632 +-----+---------------------+-----+
633 |     |                     |     |
634 |     |                     |     |
635 +-----+---------------------+-----+
636  ^           ^                ^
637  |           |                x is here and state is DSS_SHOWN
638  |           x is here and state is DSS_LSB_SHOWING or DSS_RSB_SHOWING
639  x is here and state is DSS_SHOWN
640
641 */
642         if (x < (DS_XPOS + SCROLL_HOT_WIDTH))
643         {
644                 if ((colStart > 0) && (diskSelectorState == DSS_SHOWN))
645                 {
646                         diskSelectorState = DSS_LSB_SHOWING;
647                         dxLeft = 8;
648                 }
649         }
650         else if (x > (DS_XPOS + DS_WIDTH - SCROLL_HOT_WIDTH))
651         {
652                 if (((colStart + 3) < numColumns) && (diskSelectorState == DSS_SHOWN))
653                 {
654                         diskSelectorState = DSS_RSB_SHOWING;
655                         dxRight = -8;
656                 }
657         }
658         else
659         {
660                 // Handle the excluded middle  :-P
661                 if ((diskSelectorState == DSS_LSB_SHOWING)
662                         || (diskSelectorState == DSS_LSB_SHOWN))
663                 {
664                         diskSelectorState = DSS_LSB_HIDING;
665                         dxLeft = -8;
666                 }
667                 else if ((diskSelectorState == DSS_RSB_SHOWING)
668                         || (diskSelectorState == DSS_RSB_SHOWN))
669                 {
670                         diskSelectorState = DSS_RSB_HIDING;
671                         dxRight = 8;
672                 }
673         }
674
675         // The -1 terms move the origin to the upper left corner (from 1 in, and 1
676         // down)
677         int xChar = ((x - DS_XPOS) / FONT_WIDTH) - 1;
678         int yChar = ((y - DS_YPOS) / FONT_HEIGHT) - 1;
679         diskSelected = ((xChar / 22) * 27) + yChar + (colStart * 27);
680
681         if ((yChar < 0) || (yChar >= 27)
682                 || (diskSelected >= (int)fsList.size())
683                 || (diskSelectorState == DSS_LSB_SHOWING)
684                 || (diskSelectorState == DSS_LSB_SHOWN)
685                 || (diskSelectorState == DSS_RSB_SHOWING)
686                 || (diskSelectorState == DSS_RSB_SHOWN))
687                 diskSelected = -1;
688
689         if (diskSelected != lastDiskSelected)
690         {
691                 HandleSelection(sdlRenderer);
692                 lastDiskSelected = diskSelected;
693         }
694 }
695
696
697 void DiskSelector::HandleGUIState(void)
698 {
699         lsbPos += dxLeft;
700         rsbPos += dxRight;
701
702         if ((lsbPos > (SCROLL_HOT_WIDTH - 40)) && (diskSelectorState == DSS_LSB_SHOWING))
703         {
704                 diskSelectorState = DSS_LSB_SHOWN;
705                 lsbPos = SCROLL_HOT_WIDTH - 40;
706                 dxLeft = 0;
707         }
708         else if ((lsbPos < -40) && (diskSelectorState == DSS_LSB_HIDING))
709         {
710                 diskSelectorState = DSS_SHOWN;
711                 lsbPos = -40;
712                 dxLeft = 0;
713         }
714         else if ((rsbPos < (DS_WIDTH - SCROLL_HOT_WIDTH)) && (diskSelectorState == DSS_RSB_SHOWING))
715         {
716                 diskSelectorState = DSS_RSB_SHOWN;
717                 rsbPos = DS_WIDTH - SCROLL_HOT_WIDTH;
718                 dxRight = 0;
719         }
720         else if ((rsbPos > DS_WIDTH) && (diskSelectorState == DSS_RSB_HIDING))
721         {
722                 diskSelectorState = DSS_SHOWN;
723                 rsbPos = DS_WIDTH;
724                 dxRight = 0;
725         }
726
727         if (textScrollCount < 0)
728         {
729                 textScrollCount += 2;
730
731                 if (textScrollCount > 0)
732                 {
733                         textScrollCount = 0;
734                         refresh = true;
735                 }
736         }
737         else if (textScrollCount > 0)
738         {
739                 textScrollCount -= 2;
740
741                 if (textScrollCount < 0)
742                 {
743                         textScrollCount = 0;
744                         refresh = true;
745                 }
746         }
747 }
748
749
750 void DiskSelector::HandleSelection(SDL_Renderer * renderer)
751 {
752         SDL_UpdateTexture(window, NULL, windowPixels, DS_WIDTH * sizeof(Uint32));
753         DrawFilenames(renderer);
754         refresh = false;
755 }
756
757
758 void DiskSelector::Render(SDL_Renderer * renderer)
759 {
760         if (!(window && showWindow))
761                 return;
762
763         HandleGUIState();
764
765         if (((diskSelectorState != DSS_LSB_SHOWN)
766                 && (diskSelectorState != DSS_RSB_SHOWN)
767                 && (diskSelectorState != DSS_SHOWN))
768                 || (textScrollCount != 0) || refresh)
769                 HandleSelection(renderer);
770
771         // Render scroll arrows (need to figure out why no alpha!)
772         SDL_SetRenderTarget(renderer, window);
773         SDL_Rect dst2 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
774         dst2.x = lsbPos;
775         SDL_RenderCopy(renderer, scrollLeftIcon, NULL, &dst2);
776         SDL_Rect dst3 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
777         dst3.x = rsbPos;
778         SDL_RenderCopy(renderer, scrollRightIcon, NULL, &dst3);
779         SDL_SetRenderTarget(renderer, NULL);
780
781         SDL_Rect dst = { DS_XPOS, DS_YPOS, DS_WIDTH, DS_HEIGHT };
782         SDL_RenderCopy(renderer, window, NULL, &dst);
783 }
784