]> Shamusworld >> Repos - virtualjaguar/blob - src/gui.cpp
Added directory sorting and first letter seeking
[virtualjaguar] / src / gui.cpp
1 //
2 // GUI.CPP
3 //
4 // Graphical User Interface support
5 // by James L. Hammons
6 //
7
8 #include <string.h>
9 #include <dirent.h>
10 #include <SDL.h>
11 #include "types.h"
12 #include "tom.h"
13 #include "font1.h"
14 #include "gui.h"
15
16 // Private function prototypes
17
18 uint32 CountROMFiles(char * path);
19
20
21 void InitGUI(void)
22 {
23 }
24
25 void GUIDone(void)
26 {
27 }
28
29 //
30 // Render the backbuffer to the primary screen surface
31 //
32 void BlitBackbuffer(void)
33 {
34         extern SDL_Surface * surface, * mainSurface;
35         extern int16 * backbuffer;
36
37         if (SDL_MUSTLOCK(surface))
38                 while (SDL_LockSurface(surface) < 0)
39                         SDL_Delay(10);
40
41         memcpy(surface->pixels, backbuffer, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
42
43         if (SDL_MUSTLOCK(surface))
44                 SDL_UnlockSurface(surface);
45
46         SDL_Rect srcrect, dstrect;
47         srcrect.x = srcrect.y = 0, srcrect.w = surface->w, srcrect.h = surface->h;
48         dstrect.x = dstrect.y = 0, dstrect.w = surface->w, dstrect.h = surface->h;
49         SDL_BlitSurface(surface, &srcrect, mainSurface, &dstrect);
50     SDL_Flip(mainSurface);      
51 }
52
53 //
54 // Draw text at the given x/y coordinates. Can invert text as well.
55 //
56 void DrawText(int16 * screen, uint32 x, uint32 y, bool invert, const char * text, ...)
57 {
58         char string[4096];
59         va_list arg;
60
61         va_start(arg, text);
62         vsprintf(string, text, arg);
63         va_end(arg);
64
65         uint32 pitch = TOMGetSDLScreenPitch() / 2;              // Returns pitch in bytes but we need words...
66         uint32 length = strlen(string), address = x + (y * pitch);
67
68         for(uint32 i=0; i<length; i++)
69         {
70                 uint32 fontAddr = (uint32)string[i] * 64;
71
72                 for(uint32 yy=0; yy<8; yy++)
73                 {
74                         for(uint32 xx=0; xx<8; xx++)
75                         {
76                                 if ((font1[fontAddr] && !invert) || (!font1[fontAddr] && invert))
77                                         *(screen + address + xx + (yy * pitch)) = 0xFE00;
78                                 fontAddr++;
79                         }
80                 }
81
82                 address += 8;
83         }
84 }
85
86 //
87 // Very very crude GUI file selector
88 //
89 #ifndef FILENAME_MAX
90 #define FILENAME_MAX    2048
91 #endif
92 bool UserSelectFile(char * path, char * filename)
93 {
94         extern int16 * backbuffer;
95         uint32 numFiles = CountROMFiles(path);
96
97         if (numFiles == 0)
98                 return false;
99
100         char * names = (char *)malloc(numFiles * FILENAME_MAX);
101
102         if (names == NULL)
103         {
104                 WriteLog("Could not allocate memory for %u files!\nAborting!\n", numFiles);
105                 return false;
106         }
107
108         int i = 0;
109         DIR * dp = opendir(path);
110         dirent * de;
111
112         while ((de = readdir(dp)) != NULL)
113         {
114                 char * ext = strrchr(de->d_name, '.');
115                 if (ext != NULL)
116                 {
117                         if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
118                         {
119                                 // Do a QnD insertion sort...
120                                 // (Yeah, it's n^2/2 time, but there aren't that many items...)
121                                 uint32 pos = 0;
122
123                                 for(int k=0; k<i; k++)
124                                 {
125                                         if (stricmp(&names[k * FILENAME_MAX], de->d_name) < 0)
126                                                 pos++;
127                                         else
128                                                 break;
129                                 }
130
131                                 uint32 blockSize = (i - pos) * FILENAME_MAX;
132
133                                 if (blockSize)
134 //This only works on Win32 for some reason...
135 //                                      memcpy(&names[(pos + 1) * FILENAME_MAX], &names[pos * FILENAME_MAX], blockSize);
136                                         for(int k=blockSize-1; k>=0; k--)
137                                                 names[((pos + 1) * FILENAME_MAX) + k] = names[(pos * FILENAME_MAX) + k];
138
139                                 strcpy(&names[pos * FILENAME_MAX], de->d_name);
140                                 i++;
141                         }
142                 }
143         }
144
145         closedir(dp);
146
147         // Main GUI selection loop
148
149         uint32 cursor = 0, startFile = 0;
150
151         if (numFiles > 1)       // Only go GUI if more than one possibility!
152         {
153                 bool done = false;
154                 uint32 limit = (numFiles > 24 ? 24 : numFiles);
155                 SDL_Event event;
156
157                 while (!done)
158                 {
159                         while (SDL_PollEvent(&event))
160                         {
161                                 // Draw the GUI...
162                                 memset(backbuffer, 0x11, tom_getVideoModeWidth() * tom_getVideoModeHeight() * 2);
163
164                                 for(uint32 i=0; i<limit; i++)
165                                 {
166                                         bool invert = (cursor == i ? true : false);
167                                         char buf[41];
168                                         // Guarantee that we clip our strings to fit in the screen...
169                                         memcpy(buf, &names[(startFile + i) * FILENAME_MAX], 38);
170                                         buf[38] = 0;
171                                         DrawText(backbuffer, 0, i*8, invert, " %s ", buf);
172                                 }
173
174                                 BlitBackbuffer();
175
176                                 if (event.type == SDL_KEYDOWN)
177                                 {
178                                         SDLKey key = event.key.keysym.sym;
179
180                                         if (key == SDLK_DOWN)
181                                         {
182                                                 if (cursor != limit - 1)        // Cursor is within its window
183                                                         cursor++;
184                                                 else                                            // Otherwise, scroll the window...
185                                                 {
186                                                         if (cursor + startFile != numFiles - 1)
187                                                                 startFile++;
188                                                 }
189                                         }
190                                         if (key == SDLK_UP)
191                                         {
192                                                 if (cursor != 0)
193                                                         cursor--;
194                                                 else
195                                                 {
196                                                         if (startFile != 0)
197                                                                 startFile--;
198                                                 }
199                                         }
200                                         if (key == SDLK_PAGEDOWN)
201                                         {
202                                         }
203                                         if (key == SDLK_PAGEUP)
204                                         {
205                                         }
206                                         if (key == SDLK_RETURN)
207                                                 done = true;
208                                         if (key == SDLK_ESCAPE)
209                                         {
210                                                 WriteLog("GUI: Aborting VJ by user request.\n");
211                                                 return false;                                           // Bail out!
212                                         }
213                                         if (key >= SDLK_a && key <= SDLK_z)
214                                         {
215                                                 // Advance cursor to filename with first letter pressed...
216                                                 uint8 which = (key - SDLK_a) + 65;      // Convert key to A-Z char
217                                                 for(uint32 i=0; i<numFiles; i++)
218                                                 {
219                                                         if ((names[i * FILENAME_MAX] & 0xDF) == which)
220                                                         {
221                                                                 cursor = i - startFile;
222                                                                 if (i > startFile + limit - 1)
223                                                                         startFile = i - limit + 1,
224                                                                         cursor = limit - 1;
225                                                                 if (i < startFile)
226                                                                         startFile = i,
227                                                                         cursor = 0;
228                                                                 break;
229                                                         }
230                                                 }
231                                         }
232                                 }
233                         }
234                 }
235         }
236
237         strcpy(filename, path);
238         // Potential GPF here: If length of dir is zero, then this will cause a page fault!
239         if (path[strlen(path) - 1] != '/')
240                 strcat(filename, "/");
241         strcat(filename, &names[(cursor + startFile) * FILENAME_MAX]);
242         free(names);
243
244         return true;
245 }
246
247 //
248 // Count # of possible ROM files in the current directory
249 //
250 uint32 CountROMFiles(char * path)
251 {
252         uint32 numFiles = 0;
253         DIR * dp = opendir(path);
254
255         if (dp == NULL)
256         {
257                 WriteLog("VJ: Could not open directory \"%s\"!\nAborting!\n", path);
258                 return 0;
259         }
260         else
261         {
262                 dirent * de;
263
264                 while ((de = readdir(dp)) != NULL)
265                 {
266                         char * ext = strrchr(de->d_name, '.');
267                         if (ext != NULL)
268                                 if (stricmp(ext, ".zip") == 0 || stricmp(ext, ".jag") == 0)
269                                         numFiles++;
270                 }
271
272                 closedir(dp);
273         }
274
275         return numFiles;
276 }