]> Shamusworld >> Repos - apple2/blob - src/gui/config.cpp
First steps towards making config window/settings stick.
[apple2] / src / gui / config.cpp
1 //
2 // config.cpp
3 //
4 // Configuration GUI
5 // by James Hammons
6 // © 2019 Underground Software
7 //
8
9 #include "config.h"
10 #include <vector>
11 #include "elements.h"
12 #include "font10pt.h"
13 #include "gui.h"
14 #include "log.h"
15 #include "settings.h"
16 #include "video.h"
17
18
19 #define C_WIDTH         402
20 #define C_HEIGHT        322
21 #define C_XPOS          ((VIRTUAL_SCREEN_WIDTH - C_WIDTH) / 2)
22 #define C_YPOS          ((VIRTUAL_SCREEN_HEIGHT - C_HEIGHT) / 2)
23
24 static SDL_Texture * window = NULL;
25 //static uint32_t windowPixels[C_WIDTH * C_HEIGHT];
26 static SDL_Texture * cardTex[3] = { 0 };
27 static SDL_Texture * cardBay = NULL;
28 bool Config::showWindow = false;
29
30 std::vector<void *> objList;
31
32 static bool dragging = false;
33 static bool entered = false;
34 static bool refresh = false;
35 //static bool cb1Checked = false;
36 static bool cb2Checked = false;
37 //static bool cb3Checked = false;
38 static bool cb4Checked = false;
39 static bool cbnChecked = false;
40 static char le1[512] = { 0 };
41
42 static const char cb1Text[] = "Automatically save state on exit";
43 static const char cb2Text[] = "Enable hard drive";
44 static const char cb3Text[] = "Run Apple2 in full screen mode";
45 static const char cb4Text[] = "Automatically switch to Apple ][ mode for games that require it";
46 static const char cbnText[] = "Don't check this box";
47 static const char le1Text[] = "HD1 location:";
48
49 static const char cbChecked[(9 * 11) + 1] =
50         "       @@"
51         "       @@"
52         "      @@ "
53         "      @@ "
54         "     @@  "
55         "  @@ @@  "
56         "@@  @@   "
57         " @@ @@   "
58         "  @@@ @  "
59         " @ @@ @  "
60         " @@  @@  ";
61
62 static const char cbUnchecked[(9 * 11) + 1] =
63         "         "
64         "         "
65         "         "
66         "         "
67         "         "
68         " @@@@@@  "
69         " @    @  "
70         " @    @  "
71         " @    @  "
72         " @    @  "
73         " @@@@@@  ";
74
75 static const char slotNum[7][(5 * 5) + 1] =
76 {
77         "  @  "
78         "@@@  "
79         "  @  "
80         "  @  "
81         "@@@@@",
82
83         "@@@@ "
84         "    @"
85         " @@@ "
86         "@    "
87         "@@@@@",
88
89         "@@@@ "
90         "    @"
91         " @@@ "
92         "    @"
93         "@@@@ ",
94
95         "@  @ "
96         "@  @ "
97         "@@@@@"
98         "   @ "
99         "   @ ",
100
101         "@@@@@"
102         "@    "
103         "@@@@ "
104         "    @"
105         "@@@@",
106
107         " @@@@"
108         "@    "
109         "@@@@ "
110         "@   @"
111         " @@@ ",
112
113         "@@@@@"
114         "    @"
115         "   @ "
116         "  @  "
117         " @   "
118 };
119
120 //static uint8_t card1[(96 * 11) + 1] = { 0 };
121 /*
122 0123456789ABCDEF
123 ----------------
124 @ABCDEFGHIJKLMNO
125 PQRSTUVWXYZ
126
127 m zorched to D ($6D -> $44) [0110 1101 -> 0100 0100]
128
129 */
130
131 void Config::Init(SDL_Renderer * renderer)
132 {
133         window = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
134                 SDL_TEXTUREACCESS_TARGET, C_WIDTH, C_HEIGHT);
135
136         if (!window)
137         {
138                 WriteLog("GUI (Config): Could not create window!\n");
139                 return;
140         }
141
142         if (SDL_SetTextureBlendMode(window, SDL_BLENDMODE_BLEND) == -1)
143                 WriteLog("GUI (Config): Could not set blend mode for window.\n");
144
145         for(int t=0; t<3; t++)
146         {
147                 cardTex[t] = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
148                         SDL_TEXTUREACCESS_TARGET, 96, 11);
149                 SDL_SetTextureBlendMode(cardTex[t], SDL_BLENDMODE_BLEND);
150
151                 SDL_SetRenderTarget(renderer, cardTex[t]);
152                 SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
153                 SDL_RenderClear(renderer);
154
155                 SDL_SetRenderDrawColor(renderer, 0x00, 0xAA, 0x00, 0xFF);
156
157                 for(int j=3; j<8; j++)
158                         for(int i=0; i<96; i++)
159                                 SDL_RenderDrawPoint(renderer, i, j);
160         }
161
162         SDL_SetRenderTarget(renderer, cardTex[0]);
163         GUI::DrawString(renderer, 4, 0, "Disk ][");
164         SDL_SetRenderTarget(renderer, cardTex[1]);
165         GUI::DrawString(renderer, 2, 0, "Mockingboard");
166         SDL_SetRenderTarget(renderer, cardTex[2]);
167         GUI::DrawString(renderer, 6, 0, "SCSI");
168
169         cardBay = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 123, 99);
170         SDL_SetTextureBlendMode(cardBay, SDL_BLENDMODE_BLEND);
171         SDL_SetRenderTarget(renderer, cardBay);
172         SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
173         SDL_RenderClear(renderer);
174
175         GUI::DrawBox(renderer, 5, 5, 118, 88, 0xFF, 0xFF, 0xFF);
176         GUI::DrawStringVert(renderer, 5, 33 + 21, " SLOTS ");
177
178         for(int t=0; t<7; t++)
179         {
180                 GUI::DrawBox(renderer, FONT_WIDTH * 2, (FONT_HEIGHT * (t + 1)) + 3, 96, 5, 0xFF, 0xFF, 0xFF);
181                 GUI::DrawCharArray(renderer, slotNum[t], 112, (FONT_HEIGHT * (t + 1)) + 3, 5, 5, 0xFF, 0xFF, 0xFF);
182         }
183
184         SDL_SetRenderTarget(renderer, NULL);
185
186         objList.push_back(new CheckBox(1, 1, &settings.autoStateSaving, cb1Text));
187         objList.push_back(new CheckBox(1, 2, &cb2Checked, cb2Text));
188         objList.push_back(new CheckBox(1, 3, &settings.fullscreen, cb3Text));
189         objList.push_back(new CheckBox(1, 4, &cb4Checked, cb4Text));
190
191         objList.push_back(new CheckBox(1, 27, &cbnChecked, cbnText));
192
193         objList.push_back(new LineEdit(1, 6, le1, 48, le1Text));
194         objList.push_back(new Draggable(1 * FONT_WIDTH, 8 * FONT_HEIGHT, 96, 11, &settings.cardSlot[0], cardTex[0]));
195         objList.push_back(new Draggable(1 * FONT_WIDTH, 9 * FONT_HEIGHT, 96, 11, &settings.cardSlot[1], cardTex[0]));
196         objList.push_back(new Draggable(1 * FONT_WIDTH, 10 * FONT_HEIGHT, 96, 11, &settings.cardSlot[2], cardTex[1]));
197         objList.push_back(new Draggable(1 * FONT_WIDTH, 11 * FONT_HEIGHT, 96, 11, &settings.cardSlot[3], cardTex[1]));
198         objList.push_back(new Draggable(1 * FONT_WIDTH, 12 * FONT_HEIGHT, 96, 11, &settings.cardSlot[4], cardTex[2]));
199 }
200
201
202 void Config::ShowWindow(void)
203 {
204         entered = false;
205         showWindow = true;
206         refresh = true;
207 }
208
209
210 void Config::HideWindow(void)
211 {
212         showWindow = false;
213         refresh = true;
214 }
215
216
217 void Config::MouseDown(int32_t x, int32_t y, uint32_t buttons)
218 {
219         if (!showWindow || !entered)
220                 return;
221
222         dragging = true;
223         std::vector<void *>::iterator i;
224
225         for(i=objList.begin(); i!=objList.end(); i++)
226         {
227                 Object * obj = (Object *)(*i);
228
229                 switch (obj->type)
230                 {
231                 case OTCheckBox:
232                 {
233                         CheckBox * cb = (CheckBox *)obj;
234
235                         if (cb->hovered)
236                         {
237                                 *(cb->state) = !(*(cb->state));
238                                 refresh = true;
239                         }
240
241                         break;
242                 }
243
244                 case OTDraggable:
245                 {
246                         Draggable * d = (Draggable *)obj;
247
248                         if (d->hovered)
249                         {
250                                 d->dragging = true;
251                                 refresh = true;
252                         }
253
254                         break;
255                 }
256
257                 default:
258                         break;
259                 }
260         }
261 }
262
263
264 void Config::MouseUp(int32_t x, int32_t y, uint32_t buttons)
265 {
266         if (!showWindow)
267                 return;
268
269         dragging = false;
270         std::vector<void *>::iterator i;
271
272         for(i=objList.begin(); i!=objList.end(); i++)
273         {
274                 Object * obj = (Object *)(*i);
275
276                 switch (obj->type)
277                 {
278                 case OTDraggable:
279                 {
280                         Draggable * d = (Draggable *)obj;
281
282                         if (d->dragging)
283                         {
284                                 d->dragging = false;
285
286                                 if ((d->r.x > 120) && (d->r.x < 220)
287                                         && (d->r.y > (8 * FONT_HEIGHT))
288                                         && (d->r.y < (15 * FONT_HEIGHT)))
289                                 {
290                                         *(d->spot) = ((d->r.y - (8 * FONT_HEIGHT)) / FONT_HEIGHT) + 1;
291                                         d->r.x = 120;
292                                         d->r.y = (7 + *(d->spot)) * FONT_HEIGHT;
293                                 }
294                                 else
295                                 {
296                                         d->r.x = d->homex;
297                                         d->r.y = d->homey;
298                                         *(d->spot) = 0;
299                                 }
300
301                                 refresh = true;
302                         }
303
304                         break;
305                 }
306                 }
307         }
308 }
309
310
311 static int32_t oldx, oldy;
312 void Config::MouseMove(int32_t x, int32_t y, uint32_t buttons)
313 {
314         if (!showWindow)
315                 return;
316
317         int32_t nx = x - C_XPOS, ny = y - C_YPOS;
318
319         // Check to see if C has been hovered yet, and, if so, set a flag to show
320         // that it has
321         if (!entered && ((nx >= 0) && (nx <= C_WIDTH) && (ny >= 0)
322                 && (ny <= C_HEIGHT)))
323                 entered = true;
324
325         // Check to see if the C, since being hovered, is now no longer being
326         // hovered
327 //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...
328         if (entered && ((nx < 0) || (nx > C_WIDTH) || (ny < 0) || (ny > C_HEIGHT)))
329         {
330                 showWindow = false;
331                 refresh = true;
332                 return;
333         }
334
335         // Bail out if the C hasn't been entered yet
336         if (!entered)
337                 return;
338
339         std::vector<void *>::iterator i;
340
341         for(i=objList.begin(); i!=objList.end(); i++)
342         {
343                 Object * obj = (Object *)(*i);
344
345                 switch (obj->type)
346                 {
347                 case OTCheckBox:
348                 {
349                         CheckBox * cb = (CheckBox *)obj;
350                         bool oldHover = cb->hovered;
351                         cb->hovered = (((nx >= ((cb->r.x * FONT_WIDTH) + 1))
352                                 && (nx <= ((cb->r.x * FONT_WIDTH) + 6))
353                                 && (ny >= ((cb->r.y * FONT_HEIGHT) + 3))
354                                 && (ny <= ((cb->r.y * FONT_HEIGHT) + 8))) ? true : false);
355
356                         if (oldHover != cb->hovered)
357                                 refresh = true;
358
359                         break;
360                 }
361
362                 case OTLineEdit:
363                 {
364                         LineEdit * le = (LineEdit *)obj;
365                         uint32_t labelLen = strlen(le->label);
366                         bool oldHover = le->hovered;
367                         le->hovered = (((nx >= ((le->r.x + labelLen + 1) * FONT_WIDTH))
368                                 && (nx <= ((le->r.x + labelLen + 1 + le->size) * FONT_WIDTH))
369                                 && (ny >= ((le->r.y * FONT_HEIGHT)))
370                                 && (ny <= ((le->r.y + 1) * FONT_HEIGHT))) ? true : false);
371
372                         if (oldHover != le->hovered)
373                                 refresh = true;
374
375                         break;
376                 }
377
378                 case OTDraggable:
379                 {
380                         Draggable * d = (Draggable *)obj;
381
382                         if (!d->dragging)
383                         {
384                                 bool oldHover = d->hovered;
385                                 d->hovered = (((nx >= d->r.x) && (nx < (d->r.x + d->r.w))
386                                         && (ny >= d->r.y) && (ny < (d->r.y + d->r.h)))
387                                         ? true : false);
388
389                                 if (oldHover != d->hovered)
390                                         refresh = true;
391                         }
392                         else
393                         {
394                                 d->r.x += (nx - oldx);
395                                 d->r.y += (ny - oldy);
396                                 refresh = true;
397                         }
398
399                         break;
400                 }
401
402                 default:
403                         break;
404                 }
405         }
406
407         oldx = nx;
408         oldy = ny;
409 }
410
411
412 bool Config::KeyDown(uint32_t key)
413 {
414         if (!showWindow)
415                 return false;
416
417 //      bool response = false;
418         std::vector<void *>::iterator i;
419
420         for(i=objList.begin(); i!=objList.end(); i++)
421         {
422                 Object * obj = (Object *)(*i);
423
424                 switch (obj->type)
425                 {
426                 case OTLineEdit:
427                 {
428                         LineEdit * le = (LineEdit *)obj;
429
430                         if (le->hovered)
431                         {
432                                 uint32_t textLen = strlen(le->text);
433                                 le->text[textLen] = key;
434                                 refresh = true;
435 WriteLog("Config: textLen=%u, key=%02X\n", textLen, key);
436                                 return true;
437                         }
438
439                         break;
440                 }
441
442                 default:
443                         break;
444                 }
445         }
446
447         return false;
448 }
449
450
451 void Config::DrawElements(SDL_Renderer * renderer)
452 {
453         SDL_SetRenderDrawColor(renderer, 0x7F, 0x3F, 0x00, 0xEF);
454         SDL_RenderClear(renderer);
455
456         SDL_Rect cbRect = { 108, FONT_HEIGHT * 7, 123, 99 };
457         SDL_RenderCopy(renderer, cardBay, NULL, &cbRect);
458
459         std::vector<void *>::iterator i;
460
461         for(i=objList.begin(); i!=objList.end(); i++)
462         {
463                 Object * obj = (Object *)(*i);
464
465                 switch (obj->type)
466                 {
467                 case OTCheckBox:
468                 {
469                         CheckBox * cb = (CheckBox *)obj;
470                         uint8_t r = 0x00, g = 0xAA, b = 0x00;
471
472                         if (cb->hovered)
473                                 r = 0x20, g = 0xFF, b = 0x20;
474
475                         GUI::DrawCharArray(renderer, (*(cb->state) ? cbChecked : cbUnchecked), cb->r.x * FONT_WIDTH, (cb->r.y * FONT_HEIGHT) - 2, 9, 11, r, g, b);
476                         GUI::DrawString(renderer, cb->r.x + 2, cb->r.y, cb->text);
477                         break;
478                 }
479
480                 case OTLineEdit:
481                 {
482                         LineEdit * le = (LineEdit *)obj;
483                         GUI::DrawString(renderer, le->r.x, le->r.y, le->label);
484                         uint32_t labelLen = strlen(le->label);
485                         uint8_t r = 0x00, g = 0xAA, b = 0x00;
486
487                         if (le->hovered)
488                                 r = 0x20, g = 0xFF, b = 0x20;
489
490                         GUI::DrawBox(renderer, FONT_WIDTH * (le->r.x + labelLen + 1), FONT_HEIGHT * le->r.y, FONT_WIDTH * le->size, FONT_HEIGHT, r, g, b);
491                         GUI::DrawString(renderer, le->r.x + labelLen + 1, le->r.y, le->text);
492                         break;
493                 }
494
495                 case OTDraggable:
496                 {
497                         Draggable * d = (Draggable *)obj;
498                         SDL_RenderCopy(renderer, d->img, NULL, &d->r);
499                         break;
500                 }
501
502                 default:
503                         break;
504                 }
505         }
506 }
507
508
509 void Config::Render(SDL_Renderer * renderer)
510 {
511         if (!(window && showWindow))
512                 return;
513
514         if (refresh)
515         {
516                 SDL_SetRenderTarget(renderer, window);
517                 DrawElements(renderer);
518                 refresh = false;
519         }
520
521         SDL_SetRenderTarget(renderer, NULL);
522
523         SDL_Rect dst = { C_XPOS, C_YPOS, C_WIDTH, C_HEIGHT };
524         SDL_RenderCopy(renderer, window, NULL, &dst);
525 }
526