]> Shamusworld >> Repos - apple2/blob - src/gui/diskselector.cpp
c605b1359cca62ea1e0a80836f2c877d0730c191
[apple2] / src / gui / diskselector.cpp
1 //
2 // diskselector.cpp
3 //
4 // Floppy disk selector GUI
5 // by James Hammons
6 // © 2014 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 //
17
18 #include "diskselector.h"
19 #include <dirent.h>
20 #include <algorithm>
21 #include <string>
22 #include <vector>
23 #include "apple2.h"
24 #include "font10pt.h"
25 #include "log.h"
26 #include "settings.h"
27 #include "video.h"
28
29
30 enum { DSS_SHOWING, DSS_HIDING, DSS_SHOWN, DSS_HIDDEN };
31
32 #define DS_WIDTH        400
33 #define DS_HEIGHT       300
34
35 bool entered = false;
36 int driveNumber;
37 int diskSelectorState = DSS_HIDDEN;
38 int diskSelected = -1;
39 int lastDiskSelected = -1;
40
41
42 //
43 // Case insensitve string comparison voodoo
44 //
45 struct ci_char_traits : public std::char_traits<char>
46 {
47         static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
48         static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
49         static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
50         static int compare(const char * s1, const char * s2, size_t n)
51         {
52                 while (n-- != 0)
53                 {
54                         if (toupper(*s1) < toupper(*s2)) return -1;
55                         if (toupper(*s1) > toupper(*s2)) return 1;
56                         ++s1; ++s2;
57                 }
58                 return 0;
59         }
60         static const char * find(const char * s, int n, char a)
61         {
62                 while (n-- > 0 && toupper(*s) != toupper(a))
63                 {
64                         ++s;
65                 }
66                 return s;
67         }
68 };
69
70 typedef std::basic_string<char, ci_char_traits> ci_string;
71 //
72 // END Case insensitve string comparison voodoo
73 //
74
75
76 static SDL_Texture * window = NULL;
77 static SDL_Texture * charStamp = NULL;
78 static uint32_t windowPixels[DS_WIDTH * DS_HEIGHT];
79 static uint32_t stamp[FONT_WIDTH * FONT_HEIGHT];
80 bool DiskSelector::showWindow = false;
81 std::vector<ci_string> imageList;
82
83
84 void DiskSelector::Init(SDL_Renderer * renderer)
85 {
86         window = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
87                 SDL_TEXTUREACCESS_TARGET, DS_WIDTH, DS_HEIGHT);
88         charStamp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
89                 SDL_TEXTUREACCESS_TARGET, FONT_WIDTH, FONT_HEIGHT);
90
91         if (!window)
92         {
93                 WriteLog("GUI (DiskSelector): Could not create window!\n");
94                 return;
95         }
96
97         if (SDL_SetTextureBlendMode(window, SDL_BLENDMODE_BLEND) == -1)
98                 WriteLog("GUI (DiskSelector): Could not set blend mode for window.\n");
99
100         if (SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_BLEND) == -1)
101                 WriteLog("GUI (DiskSelector): Could not set blend mode for charStamp.\n");
102
103         for(uint32_t i=0; i<DS_WIDTH*DS_HEIGHT; i++)
104                 windowPixels[i] = 0xEF00FF00;
105
106         SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
107         FindDisks(NULL);
108         DrawFilenames(renderer);
109 }
110
111
112 void DiskSelector::FindDisks(const char * path)
113 {
114         DIR * dir = opendir(settings.disksPath);
115
116         if (!dir)
117         {
118                 WriteLog("GUI (DiskSelector)::FindDisks: Could not open directory \"%s\%!\n", settings.disksPath);
119                 return;
120         }
121
122         imageList.clear();
123         dirent * ent;
124
125         while ((ent = readdir(dir)) != NULL)
126         {
127                 if (HasLegalExtension(ent->d_name))
128                         imageList.push_back(ci_string(ent->d_name));
129         }
130
131         closedir(dir);
132         std::sort(imageList.begin(), imageList.end());
133 }
134
135
136 bool DiskSelector::HasLegalExtension(const char * name)
137 {
138         const char * ext = strrchr(name, '.');
139
140         if ((strcasecmp(ext, ".dsk") == 0) || (strcasecmp(ext, ".do") == 0)
141                 || (strcasecmp(ext, ".po") == 0) || (strcasecmp(ext, ".nib") == 0))
142                 return true;
143
144         return false;
145 }
146
147
148 void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
149 {
150         if (SDL_SetRenderTarget(renderer, window) < 0)
151         {
152                 WriteLog("GUI: Could not set Render Target to overlay... (%s)\n", SDL_GetError());
153                 return;
154         }
155
156         // 3 columns of 16 chars apiece (with 8X16 font), 18 rows
157         // 3 columns of 18 chars apiece (with 7X12 font), 24 rows
158         // 3 columns of 21 chars apiece (with 6X11 font), 27 rows
159
160         unsigned int count = 0;
161
162         while (count < imageList.size())
163         {
164 //              int currentX = (count / 18) * 17;
165 //              int currentY = (count % 18);
166 //              int currentX = (count / 24) * 19;
167 //              int currentY = (count % 24);
168                 int currentX = (count / 27) * 22;
169                 int currentY = (count % 27);
170
171 //              for(unsigned int i=0; i<16; i++)
172 //              for(unsigned int i=0; i<18; i++)
173                 for(unsigned int i=0; i<21; i++)
174                 {
175                         if (i >= imageList[count].length())
176                                 break;
177
178                         bool invert = (diskSelected == (int)count ? true : false);
179                         DrawCharacter(renderer, currentX + i, currentY, imageList[count][i], invert);
180                 }
181
182                 count++;
183
184 //              if (count >= (18 * 3))
185 //              if (count >= (24 * 3))
186                 if (count >= (27 * 3))
187                         break;
188         }
189
190         // Set render target back to default
191         SDL_SetRenderTarget(renderer, NULL);
192 }
193
194
195 void DiskSelector::DrawCharacter(SDL_Renderer * renderer, int x, int y, uint8_t c, bool invert/*=false*/)
196 {
197         uint32_t inv = (invert ? 0x000000FF : 0x00000000);
198         uint32_t pixel = 0xFFFFC000;    // RRGGBBAA
199         uint8_t * ptr = (uint8_t *)&font10pt[(c - 0x20) * FONT_WIDTH * FONT_HEIGHT];
200         SDL_Rect dst;
201         dst.x = x * FONT_WIDTH, dst.y = y * FONT_HEIGHT, dst.w = FONT_WIDTH, dst.h = FONT_HEIGHT;
202
203         for(int i=0; i<FONT_WIDTH*FONT_HEIGHT; i++)
204                 stamp[i] = (pixel | ptr[i]) ^ inv;
205
206         SDL_UpdateTexture(charStamp, NULL, stamp, FONT_WIDTH * sizeof(Uint32));
207         SDL_RenderCopy(renderer, charStamp, NULL, &dst);
208 }
209
210
211 void DiskSelector::ShowWindow(int drive)
212 {
213         entered = false;
214         showWindow = true;
215         driveNumber = drive;
216 }
217
218
219 void DiskSelector::MouseDown(int32_t x, int32_t y, uint32_t buttons)
220 {
221         if (!showWindow)
222                 return;
223
224         if (!entered)
225                 return;
226
227         if (diskSelected != -1)
228         {
229                 char buffer[2048];
230                 sprintf(buffer, "%s/%s", settings.disksPath, &imageList[diskSelected][0]);
231                 floppyDrive.LoadImage(buffer, driveNumber);
232         }
233
234         showWindow = false;
235 }
236
237
238 void DiskSelector::MouseUp(int32_t x, int32_t y, uint32_t buttons)
239 {
240         if (!showWindow)
241                 return;
242
243 }
244
245
246 #define DS_XPOS ((VIRTUAL_SCREEN_WIDTH - DS_WIDTH) / 2)
247 #define DS_YPOS ((VIRTUAL_SCREEN_HEIGHT - DS_HEIGHT) / 2)
248 void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
249 {
250         if (!showWindow)
251                 return;
252
253         if (!entered && ((x >= DS_XPOS) && (x <= (DS_XPOS + DS_WIDTH))
254                 && (y >= DS_YPOS) && (y <= (DS_YPOS + DS_HEIGHT))))
255                 entered = true;
256
257         if (entered && ((x < DS_XPOS) || (x > (DS_XPOS + DS_WIDTH))
258                 || (y < DS_YPOS) || (y > (DS_YPOS + DS_HEIGHT))))
259         {
260                 showWindow = false;
261                 return;
262         }
263
264         int xChar = (x - DS_XPOS) / FONT_WIDTH;
265         int yChar = (y - DS_YPOS) / FONT_HEIGHT;
266         diskSelected = ((xChar / 22) * 27) + yChar;
267
268         if ((yChar >= 27) || (diskSelected >= (int)imageList.size()))
269                 diskSelected = -1;
270
271         if (diskSelected != lastDiskSelected)
272         {
273                 HandleSelection(sdlRenderer);
274                 lastDiskSelected = diskSelected;
275         }
276 }
277
278
279 void DiskSelector::HandleSelection(SDL_Renderer * renderer)
280 {
281         SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
282         DrawFilenames(renderer);
283 }
284
285
286 void DiskSelector::Render(SDL_Renderer * renderer)
287 {
288         if (!(window && showWindow))
289                 return;
290
291         SDL_Rect dst = { DS_XPOS, DS_YPOS, DS_WIDTH, DS_HEIGHT };
292         SDL_RenderCopy(renderer, window, NULL, &dst);
293 }
294