]> Shamusworld >> Repos - apple2/commitdiff
Added initial emulator configuration window, cleanup of settings code.
authorShamus Hammons <jlhamm@acm.org>
Wed, 17 Apr 2019 03:29:58 +0000 (22:29 -0500)
committerShamus Hammons <jlhamm@acm.org>
Wed, 17 Apr 2019 03:29:58 +0000 (22:29 -0500)
The settings code now actually saves updated settings to the config
file.  Also wrote the beginnings of a proper Config window, and a few
of the options actually work (which ones work is left as an exercise
for the reader).

23 files changed:
Makefile
apple2.cfg
src/apple2.cpp
src/fileio.cpp
src/fileio.h
src/gui/diskselector.cpp
src/gui/diskselector.h
src/gui/gui.cpp
src/gui/gui.h
src/harddrive.cpp
src/sdlemu_config.cpp [deleted file]
src/sdlemu_config.h [deleted file]
src/settings.cpp
src/settings.h
src/video.cpp
web/apple2.css
web/img/a2-icon-64x64.png
web/img/ss-01s.png
web/img/ss-02s.png
web/img/ss-03s.png
web/img/ss-04.png
web/img/ss-04s.png
web/index.html

index ac00d109507ef137c96716e7ed4301bb67752af2..819bcc9be91c56f9d642aa0aac1bc394ac0d10da 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -101,6 +101,7 @@ LIBS = $(SDL_LIBS) -lstdc++ -lz -lm $(GLLIB) -pg
 INCS = -I. -I./src
 
 OBJS = \
+       obj/config.o          \
        obj/diskselector.o    \
        obj/font10pt.o        \
        obj/font12pt.o        \
@@ -122,7 +123,6 @@ OBJS = \
        obj/log.o             \
        obj/mmu.o             \
        obj/mockingboard.o    \
-       obj/sdlemu_config.o   \
        obj/settings.o        \
        obj/sound.o           \
        obj/timing.o          \
index e1e024c505ab6347f1e11eeb8dccf89808e30ea3..c861df75c74ce437032afce4549953df83f8322d 100644 (file)
@@ -3,22 +3,28 @@
 #
 
 # Apple ROM paths
-
-#default
+#Not used anymore
 #BIOSROM = ./ROMs/apple2e-enhanced.rom
 #BIOSROM = ./ROMs/apple2e.rom
-#Not used anymore
 #diskROM = ./ROMs/disk.rom
 #ROMs = ./ROMs
-#default
-#disks = ./disks
-#harddrive = ./disks/Pitch-Dark-20180731.2mg
 
-# Auto state loading/saving upon starting/quitting Apple2 (1 - use, 0 - don't use)
+# Defaults
+disks = ./disks/
+
+harddrive1 = Pitch-Dark-20180731.2mg
+harddrive2 = 
+harddrive3 = 
+harddrive4 = 
+harddrive5 = 
+harddrive6 = 
+harddrive7 = 
 
-#These are the defaults--we don't advertise it just yet... ;-)
-autoSaveState = 0
-#autoStateFilename = ./apple2auto.state
+# Auto state loading/saving upon starting/quitting Apple2 (1-use, 0-don't use)
+# These are the defaults--we don't advertise it just yet... ;-)
+
+autoSaveState = 1
+autoStateFilename = ./apple2auto.state
 
 # OpenGL filtering type: 1 - blurry, 0 - sharp
 
@@ -36,3 +42,10 @@ useJoystick = 0
 
 joyport = 0
 
+windowX = 770
+windowY = 146
+
+hardwareTypeNTSC = 1
+renderType = 0
+useOpenGL = 1
+
index 6d893fa63f5d4be9517f06a5be87f5d594a6cb90..e97363afdf68a4ea4555c383645fdc4b81e20f70 100644 (file)
@@ -57,8 +57,9 @@
 #include "sound.h"
 #include "timing.h"
 #include "video.h"
-#include "gui/gui.h"
 #include "gui/diskselector.h"
+#include "gui/config.h"
+#include "gui/gui.h"
 
 // Debug and misc. defines
 
@@ -673,9 +674,9 @@ while (pc < 0x9FF)
 }
 #endif
 
+       SaveSettings();
        SoundDone();
        VideoDone();
-       SaveSettings();
        LogDone();
 
        return 0;
@@ -752,6 +753,10 @@ static void FrameCallback(void)
                        if (event.key.repeat != 0)
                                break;
 
+                       // This breaks IMEs and the like, but we'll do simple for now
+                       if (GUI::KeyDown(event.key.keysym.sym))
+                               break;
+
                        // Use CTRL+SHIFT+Q to exit, as well as the usual window decoration
                        // method
                        if ((event.key.keysym.mod & KMOD_CTRL)
@@ -1033,7 +1038,7 @@ else if (event.key.keysym.sym == SDLK_F9)
 
        // Hide the mouse if it's been 1s since the last time it was moved
        // N.B.: Should disable mouse hiding if it's over the GUI...
-       if ((hideMouseTimeout > 0) && !(GUI::sidebarState == SBS_SHOWN || DiskSelector::showWindow == true))
+       if ((hideMouseTimeout > 0) && !(GUI::sidebarState == SBS_SHOWN || DiskSelector::showWindow == true || Config::showWindow == true))
                hideMouseTimeout--;
        else if (hideMouseTimeout == 0)
        {
index efa4c61b6d9c2dd9c0ceb9fd449497957a8ee958..ccda0d71369582574fa3c27e2f6624a2bd4953cf 100644 (file)
@@ -31,9 +31,9 @@ uint8_t standardTMAP[160] = {
 
 
 //
-// Note that size *must* be a valid pointer, otherwise this will go BOOM
+// sizePtr is optional
 //
-uint8_t * ReadFile(const char * filename, uint32_t * size)
+uint8_t * ReadFile(const char * filename, uint32_t * sizePtr/*= NULL*/)
 {
        FILE * fp = fopen(filename, "rb");
 
@@ -41,13 +41,16 @@ uint8_t * ReadFile(const char * filename, uint32_t * size)
                return NULL;
 
        fseek(fp, 0, SEEK_END);
-       *size = ftell(fp);
+       uint32_t size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
 
-       uint8_t * buffer = (uint8_t *)malloc(*size);
-       fread(buffer, 1, *size, fp);
+       uint8_t * buffer = (uint8_t *)malloc(size);
+       fread(buffer, 1, size, fp);
        fclose(fp);
 
+       if (sizePtr != NULL)
+               *sizePtr = size;
+
        return buffer;
 }
 
index db11d87edbfdb47aaba6e8a370117192e5772093..e7a15bc4127b8b26e14dc6701aeb16ea2229ebc2 100644 (file)
@@ -99,7 +99,7 @@ struct WOZ2
 };
 
 // Exported functions
-uint8_t * ReadFile(const char * filename, uint32_t * size);
+uint8_t * ReadFile(const char * filename, uint32_t * sizePtr = NULL);
 void InitWOZ2Headers(WOZ2 &);
 uint8_t * InitWOZ(uint32_t * pSize = NULL);
 uint8_t * UpconvertWOZ1ToWOZ2(uint8_t * woz1Data, uint32_t woz1Size, uint32_t * newSize);
index 211cae767cb47a87eb3532e27795b807e6aa3a16..8e7820fdc9a7d4dde1a567cfa34f7cda4bfe8d97 100644 (file)
@@ -52,19 +52,19 @@ enum { DSS_SHOWING, DSS_HIDING, DSS_SHOWN, DSS_HIDDEN, DSS_LSB_SHOWING, DSS_LSB_
 #define DS_YPOS        ((VIRTUAL_SCREEN_HEIGHT - DS_HEIGHT) / 2)
 
 
-bool entered = false;
-int driveNumber;
-int diskSelectorState = DSS_HIDDEN;
-int diskSelected = -1;
-int lastDiskSelected = -1;
-int numColumns;
-int colStart = 0;
-int dxLeft = 0;
-int dxRight = 0;
-int rsbPos = DS_WIDTH;
-int lsbPos = -40;
-int textScrollCount = 0;
-bool refresh = false;
+static bool entered = false;
+static int driveNumber;
+static int diskSelectorState = DSS_HIDDEN;
+static int diskSelected = -1;
+static int lastDiskSelected = -1;
+static int numColumns;
+static int colStart = 0;
+static int dxLeft = 0;
+static int dxRight = 0;
+static int rsbPos = DS_WIDTH;
+static int lsbPos = -40;
+static int textScrollCount = 0;
+static bool refresh = false;
 
 /*
 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.
@@ -110,9 +110,7 @@ struct FileStruct
 
 
 static SDL_Texture * window = NULL;
-static SDL_Texture * charStamp = NULL;
 static uint32_t windowPixels[DS_WIDTH * DS_HEIGHT];
-static uint32_t stamp[FONT_WIDTH * FONT_HEIGHT];
 SDL_Texture * scrollLeftIcon = NULL;
 SDL_Texture * scrollRightIcon = NULL;
 bool DiskSelector::showWindow = false;
@@ -123,8 +121,6 @@ void DiskSelector::Init(SDL_Renderer * renderer)
 {
        window = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
                SDL_TEXTUREACCESS_TARGET, DS_WIDTH, DS_HEIGHT);
-       charStamp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
-               SDL_TEXTUREACCESS_TARGET, FONT_WIDTH, FONT_HEIGHT);
 
        if (!window)
        {
@@ -135,16 +131,13 @@ void DiskSelector::Init(SDL_Renderer * renderer)
        if (SDL_SetTextureBlendMode(window, SDL_BLENDMODE_BLEND) == -1)
                WriteLog("GUI (DiskSelector): Could not set blend mode for window.\n");
 
-       if (SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_BLEND) == -1)
-               WriteLog("GUI (DiskSelector): Could not set blend mode for charStamp.\n");
-
        scrollLeftIcon  = GUI::CreateTexture(renderer, &scroll_left);
        scrollRightIcon = GUI::CreateTexture(renderer, &scroll_right);
 
        for(uint32_t i=0; i<DS_WIDTH*DS_HEIGHT; i++)
                windowPixels[i] = 0xEF007F00;
 
-       SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
+       SDL_UpdateTexture(window, NULL, windowPixels, DS_WIDTH * sizeof(Uint32));
        FindDisks();
        DrawFilenames(renderer);
 }
@@ -393,7 +386,7 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
                                if (i >= fsList[partialColStart + y].image.length())
                                        break;
 
-                               DrawCharacter(renderer, x + 1, y + 1, fsList[partialColStart + y].image[i], false);
+                               GUI::DrawCharacter(renderer, x + 1, y + 1, fsList[partialColStart + y].image[i], false);
                        }
                }
        }
@@ -408,7 +401,7 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
                                if (i >= fsList[fsStart + y].image.length())
                                        break;
 
-                               DrawCharacter(renderer, x + 1, y + 1, fsList[fsStart + y].image[i], false);
+                               GUI::DrawCharacter(renderer, x + 1, y + 1, fsList[fsStart + y].image[i], false);
                        }
                }
 
@@ -432,7 +425,7 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
                                break;
 
                        bool invert = (diskSelected == (int)fsStart ? true : false);
-                       DrawCharacter(renderer, currentX + i + 1 + offset, currentY + 1, fsList[fsStart].image[i], invert);
+                       GUI::DrawCharacter(renderer, currentX + i + 1 + offset, currentY + 1, fsList[fsStart].image[i], invert);
                }
 
                count++;
@@ -452,7 +445,7 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
                        if (i >= fsList[diskSelected].image.length())
                                break;
 
-                       DrawCharacter(renderer, i + 1, 0, fsList[diskSelected].image[i], true);
+                       GUI::DrawCharacter(renderer, i + 1, 0, fsList[diskSelected].image[i], true);
                }
        }
 
@@ -461,22 +454,6 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
 }
 
 
-void DiskSelector::DrawCharacter(SDL_Renderer * renderer, int x, int y, uint8_t c, bool invert/*=false*/)
-{
-       uint32_t inv = (invert ? 0x000000FF : 0x00000000);
-       uint32_t pixel = 0xFFFFC000;    // RRGGBBAA
-       uint8_t * ptr = (uint8_t *)&font10pt[(c - 0x20) * FONT_WIDTH * FONT_HEIGHT];
-       SDL_Rect dst;
-       dst.x = x * FONT_WIDTH, dst.y = y * FONT_HEIGHT, dst.w = FONT_WIDTH, dst.h = FONT_HEIGHT;
-
-       for(int i=0; i<FONT_WIDTH*FONT_HEIGHT; i++)
-               stamp[i] = (pixel | ptr[i]) ^ inv;
-
-       SDL_UpdateTexture(charStamp, NULL, stamp, FONT_WIDTH * sizeof(Uint32));
-       SDL_RenderCopy(renderer, charStamp, NULL, &dst);
-}
-
-
 void DiskSelector::ShowWindow(int drive)
 {
        diskSelectorState = DSS_SHOWN;
@@ -486,6 +463,18 @@ void DiskSelector::ShowWindow(int drive)
 }
 
 
+void DiskSelector::HideWindow(void)
+{
+       diskSelectorState = DSS_HIDDEN;
+       dxLeft = 0;
+       dxRight = 0;
+       rsbPos = DS_WIDTH;
+       lsbPos = -40;
+       showWindow = false;
+       refresh = true;
+}
+
+
 void DiskSelector::MouseDown(int32_t x, int32_t y, uint32_t buttons)
 {
        if (!showWindow || !entered)
@@ -689,7 +678,7 @@ void DiskSelector::HandleGUIState(void)
 
 void DiskSelector::HandleSelection(SDL_Renderer * renderer)
 {
-       SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
+       SDL_UpdateTexture(window, NULL, windowPixels, DS_WIDTH * sizeof(Uint32));
        DrawFilenames(renderer);
        refresh = false;
 }
index 658fab6b2602db170c1167961645602fc768d787..00086a5e6b22cb87710a929ef58dbccd9460e8bc 100644 (file)
@@ -21,8 +21,8 @@ class DiskSelector
                static bool CheckManifest(const char *, DiskSet *);
                static bool HasLegalExtension(const char *);
                static void DrawFilenames(SDL_Renderer *);
-               static void DrawCharacter(SDL_Renderer *, int, int, uint8_t, bool inv=false);
                static void ShowWindow(int);
+               static void HideWindow(void);
                static void MouseDown(int32_t, int32_t, uint32_t);
                static void MouseUp(int32_t, int32_t, uint32_t);
                static void MouseMove(int32_t, int32_t, uint32_t);
index 022c2fdbb53f3288a86b9b6343091d1193d9afe8..6960a9675cf87f4b8d5916f8a666507069730654 100644 (file)
@@ -3,7 +3,7 @@
 //
 // Graphical User Interface support
 // by James Hammons
-// Â© 2014 Underground Software
+// Â© 2014-2019 Underground Software
 //
 // JLH = James Hammons <jlhamm@acm.org>
 //
 //
 
 #include "gui.h"
+#include <vector>
 #include "apple2.h"
+#include "config.h"
 #include "diskselector.h"
+#include "elements.h"
 #include "floppydrive.h"
+#include "font10pt.h"
 #include "log.h"
 #include "video.h"
 
@@ -80,6 +84,14 @@ const char ejectIcon[(8 * 7) + 1] =
        "@@@@@@@@"
        "@@@@@@@@";
 
+const char newDiskIcon[(30 * 6) + 1] =
+       "@@   @@ @@@@@ @@   @@     @@  "
+       "@@@  @@ @@    @@   @@    @@@@ "
+       "@@@@ @@ @@@@  @@ @ @@   @@@@@@"
+       "@@ @@@@ @@    @@@@@@@     @@  "
+       "@@  @@@ @@    @@@@@@@  @@@@@  "
+       "@@   @@ @@@@@ @@   @@  @@@@   ";
+
 const char driveLight[(5 * 5) + 1] =
        " @@@ "
        "@@@@@"
@@ -88,7 +100,6 @@ const char driveLight[(5 * 5) + 1] =
        " @@@ ";
 
 
-
 SDL_Texture * GUI::overlay = NULL;
 SDL_Rect GUI::olDst;
 int GUI::sidebarState = SBS_HIDDEN;
@@ -117,10 +128,16 @@ const char iconHelp[7][80] = { "Turn emulated Apple off/on",
        "Configure Apple2" };
 bool disk1EjectHovered = false;
 bool disk2EjectHovered = false;
+bool disk1NewDiskHovered = false;
+bool disk2NewDiskHovered = false;
 
+SDL_Texture * GUI::charStamp = NULL;
+uint32_t GUI::stamp[FONT_WIDTH * FONT_HEIGHT];
 
 #define SIDEBAR_X_POS  (VIRTUAL_SCREEN_WIDTH - 80)
 
+//std::vector<void *> objList;
+
 
 GUI::GUI(void)
 {
@@ -136,6 +153,8 @@ void GUI::Init(SDL_Renderer * renderer)
 {
        overlay = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888,
                SDL_TEXTUREACCESS_TARGET, 128, 380);
+       charStamp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
+               SDL_TEXTUREACCESS_TARGET, FONT_WIDTH, FONT_HEIGHT);
 
        if (!overlay)
        {
@@ -146,6 +165,9 @@ void GUI::Init(SDL_Renderer * renderer)
        if (SDL_SetTextureBlendMode(overlay, SDL_BLENDMODE_BLEND) == -1)
                WriteLog("GUI: Could not set blend mode for overlay.\n");
 
+       if (SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_BLEND) == -1)
+               WriteLog("GUI: Could not set blend mode for charStamp.\n");
+
        for(uint32_t i=0; i<128*380; i++)
                texturePointer[i] = 0xB0A000A0;
 
@@ -185,6 +207,7 @@ void GUI::Init(SDL_Renderer * renderer)
        }
 
        DiskSelector::Init(renderer);
+       Config::Init(renderer);
        WriteLog("GUI: Successfully initialized.\n");
 }
 
@@ -206,6 +229,7 @@ SDL_Texture * GUI::CreateTexture(SDL_Renderer * renderer, const void * source)
 void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
 {
        DiskSelector::MouseDown(x, y, buttons);
+       Config::MouseDown(x, y, buttons);
 
        if (sidebarState != SBS_SHOWN)
                return;
@@ -231,9 +255,10 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
                        SpawnMessage("*** DISK #1 EJECTED ***");
                }
 
-               if (!disk1EjectHovered)
+               if (!disk1EjectHovered && !disk1NewDiskHovered)
                {
                        // Load the disk selector
+                       Config::HideWindow();
                        DiskSelector::ShowWindow(0);
                }
 
@@ -248,9 +273,10 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
                        SpawnMessage("*** DISK #2 EJECTED ***");
                }
 
-               if (!disk2EjectHovered)
+               if (!disk2EjectHovered && !disk2NewDiskHovered)
                {
                        // Load the disk selector
+                       Config::HideWindow();
                        DiskSelector::ShowWindow(1);
                }
 
@@ -271,6 +297,9 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
        // Configuration
        case 6:
                SpawnMessage("*** CONFIGURATION ***");
+               // Load the configuration window
+               DiskSelector::HideWindow();
+               Config::ShowWindow();
                break;
        }
 }
@@ -279,12 +308,14 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
 void GUI::MouseUp(int32_t x, int32_t y, uint32_t buttons)
 {
        DiskSelector::MouseUp(x, y, buttons);
+       Config::MouseUp(x, y, buttons);
 }
 
 
 void GUI::MouseMove(int32_t x, int32_t y, uint32_t buttons)
 {
        DiskSelector::MouseMove(x, y, buttons);
+       Config::MouseMove(x, y, buttons);
 
        if (sidebarState != SBS_SHOWN)
        {
@@ -335,6 +366,16 @@ void GUI::MouseMove(int32_t x, int32_t y, uint32_t buttons)
                                && (y >= (117 + 31 + 2))
                                && (y < (117 + 31 + 2 + 7)) ? true : false);
 
+                       disk1NewDiskHovered = ((x >= (SIDEBAR_X_POS + 24 + 6))
+                               && (x < (SIDEBAR_X_POS + 24 + 6 + 30))
+                               && (y >= (63 + 31 + 2))
+                               && (y < (63 + 31 + 2 + 6)) ? true : false);
+
+                       disk2NewDiskHovered = ((x >= (SIDEBAR_X_POS + 24 + 6))
+                               && (x < (SIDEBAR_X_POS + 24 + 6 + 30))
+                               && (y >= (117 + 31 + 2))
+                               && (y < (117 + 31 + 2 + 6)) ? true : false);
+
                        if (iconSelected != lastIconSelected)
                        {
                                HandleIconSelection(sdlRenderer);
@@ -355,6 +396,12 @@ void GUI::MouseMove(int32_t x, int32_t y, uint32_t buttons)
 }
 
 
+bool GUI::KeyDown(uint32_t key)
+{
+       return Config::KeyDown(key);
+}
+
+
 void GUI::HandleIconSelection(SDL_Renderer * renderer)
 {
        // Set up drive icons in their current states
@@ -409,6 +456,7 @@ void GUI::AssembleDriveIcon(SDL_Renderer * renderer, int driveNumber)
        DrawCharArray(renderer, number[driveNumber], 30, 20, 7, 7, 0xD0, 0xE0, 0xF0);
        DrawDriveLight(renderer, driveNumber);
        DrawEjectButton(renderer, driveNumber);
+       DrawNewDiskButton(renderer, driveNumber);
 
        // Set render target back to default
        SDL_SetRenderTarget(renderer, NULL);
@@ -430,6 +478,21 @@ void GUI::DrawEjectButton(SDL_Renderer * renderer, int driveNumber)
 }
 
 
+void GUI::DrawNewDiskButton(SDL_Renderer * renderer, int driveNumber)
+{
+       if (!floppyDrive[0].IsEmpty(driveNumber))
+               return;
+
+       uint8_t r = 0x00, g = 0xAA, b = 0x00;
+
+       if ((driveNumber == 0 && disk1NewDiskHovered)
+               || (driveNumber == 1 && disk2NewDiskHovered))
+               r = 0x20, g = 0xFF, b = 0x20;
+
+       DrawCharArray(renderer, newDiskIcon, 6, 31, 30, 6, r, g, b);
+}
+
+
 void GUI::DrawDriveLight(SDL_Renderer * renderer, int driveNumber)
 {
        int lightState = floppyDrive[0].DriveLightStatus(driveNumber);
@@ -463,6 +526,85 @@ void GUI::DrawCharArray(SDL_Renderer * renderer, const char * array, int x,
 }
 
 
+void GUI::DrawCharacter(SDL_Renderer * renderer, int x, int y, uint8_t c, bool invert/*= false*/)
+{
+       uint32_t inv = (invert ? 0x000000FF : 0x00000000);
+       uint32_t pixel = 0xFFFFC000;    // RRGGBBAA
+       uint8_t * ptr = (uint8_t *)&font10pt[(c - 0x20) * FONT_WIDTH * FONT_HEIGHT];
+       SDL_Rect dst;
+       dst.x = x * FONT_WIDTH, dst.y = y * FONT_HEIGHT, dst.w = FONT_WIDTH, dst.h = FONT_HEIGHT;
+
+       for(int i=0; i<FONT_WIDTH*FONT_HEIGHT; i++)
+               stamp[i] = (pixel | ptr[i]) ^ inv;
+
+       SDL_UpdateTexture(charStamp, NULL, stamp, FONT_WIDTH * sizeof(Uint32));
+       SDL_RenderCopy(renderer, charStamp, NULL, &dst);
+}
+
+
+//
+// N.B.: This draws a char at an abosulte X/Y position, not on a grid
+//
+void GUI::DrawCharacterVert(SDL_Renderer * renderer, int x, int y, uint8_t c, bool invert/*= false*/)
+{
+       uint32_t inv = (invert ? 0x000000FF : 0x00000000);
+       uint32_t pixel = 0xFFFFC000;    // RRGGBBAA
+       uint8_t * ptr = (uint8_t *)&font10pt[(c - 0x20) * FONT_WIDTH * FONT_HEIGHT];
+       SDL_Rect dst;
+       dst.x = x, dst.y = y, dst.w = FONT_WIDTH, dst.h = FONT_HEIGHT;
+       SDL_Point pt = { FONT_WIDTH - 1, FONT_HEIGHT - 1 };
+
+       for(int i=0; i<FONT_WIDTH*FONT_HEIGHT; i++)
+               stamp[i] = (pixel | ptr[i]) ^ inv;
+
+       SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_NONE);
+       SDL_UpdateTexture(charStamp, NULL, stamp, FONT_WIDTH * sizeof(Uint32));
+       SDL_RenderCopyEx(renderer, charStamp, NULL, &dst, 270.0, &pt, SDL_FLIP_NONE);
+       SDL_SetTextureBlendMode(charStamp, SDL_BLENDMODE_BLEND);
+}
+
+
+void GUI::DrawString(SDL_Renderer * renderer, int x, int y, const char * s, bool invert/*= false*/)
+{
+       int len = strlen(s);
+
+       for(int i=0; i<len; i++)
+               DrawCharacter(renderer, x + i, y, s[i], invert);
+}
+
+
+//
+// N.B.: This draws a char at an abosulte X/Y position, not on a grid
+//
+void GUI::DrawStringVert(SDL_Renderer * renderer, int x, int y, const char * s, bool invert/*= false*/)
+{
+       int len = strlen(s);
+
+       for(int i=0; i<len; i++)
+               DrawCharacterVert(renderer, x, y - (FONT_WIDTH * i), s[i], invert);
+}
+
+
+void GUI::DrawBox(SDL_Renderer * renderer, int x, int y, int w, int h, int r/*= 0x00*/, int g/*= 0xAA*/, int b/*= 0x00*/)
+{
+       SDL_SetRenderDrawColor(renderer, r, g, b, 0xFF);
+
+       for(int i=0; i<w; i++)
+       {
+               SDL_RenderDrawPoint(renderer, x + i, y);
+               SDL_RenderDrawPoint(renderer, x + i, y + h - 1);
+       }
+
+       for(int i=0; i<h; i++)
+       {
+               SDL_RenderDrawPoint(renderer, x, y + i);
+               SDL_RenderDrawPoint(renderer, x + w - 1, y + i);
+       }
+
+       SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
+}
+
+
 void GUI::HandleGUIState(void)
 {
        olDst.x += dx;
@@ -500,6 +642,7 @@ void GUI::DrawSidebarIcons(SDL_Renderer * renderer)
 
 void GUI::Render(SDL_Renderer * renderer)
 {
+       // Sanity check
        if (!overlay)
                return;
 
@@ -512,6 +655,7 @@ void GUI::Render(SDL_Renderer * renderer)
 
        // Hmm.
        DiskSelector::Render(renderer);
+       Config::Render(renderer);
 }
 
 
index 625b20c9ee0e536b54a5fb6d62444704e7ec0ecb..0dbf0dfffb8089e4ef544e4c15186fab63b241f4 100644 (file)
@@ -23,12 +23,19 @@ class GUI
                static void MouseDown(int32_t, int32_t, uint32_t);
                static void MouseUp(int32_t, int32_t, uint32_t);
                static void MouseMove(int32_t, int32_t, uint32_t);
+               static bool KeyDown(uint32_t);
                static void HandleIconSelection(SDL_Renderer *);
                static void AssembleDriveIcon(SDL_Renderer *, int);
                static void DrawEjectButton(SDL_Renderer *, int);
+               static void DrawNewDiskButton(SDL_Renderer *, int);
                static void DrawDriveLight(SDL_Renderer *, int);
                static void DrawCharArray(SDL_Renderer *, const char *, int x,
                        int y, int w, int h, int r, int g, int b);
+               static void DrawCharacter(SDL_Renderer *, int, int, uint8_t, bool inv = false);
+               static void DrawCharacterVert(SDL_Renderer *, int, int, uint8_t, bool inv = false);
+               static void DrawString(SDL_Renderer *, int, int, const char *, bool inv = false);
+               static void DrawStringVert(SDL_Renderer *, int, int, const char *, bool inv = false);
+               static void DrawBox(SDL_Renderer *, int, int, int, int, int r = 0x00, int g = 0xAA, int b = 0x00);
                static void HandleGUIState(void);
                static void DrawSidebarIcons(SDL_Renderer *);
                static void Render(SDL_Renderer *);
@@ -41,6 +48,10 @@ class GUI
                static int32_t iconSelected;
                static bool hasKeyboardFocus;
                static bool powerOnState;
+
+       private:
+               static SDL_Texture * charStamp;
+               static uint32_t stamp[];
 };
 
 #endif // __GUI_H__
index ca90a28d5b129ca44b9e61cbe0e6a197ba19acb1..0f06a500eafe85375a3d2ff055df1803c0881c47 100644 (file)
@@ -618,10 +618,12 @@ void InstallHardDrive(uint8_t slot)
 {
        SlotData hd = { SlotIOR, SlotIOW, SlotROM, 0, SlotIOExtraR, SlotIOExtraW };
        InstallSlotHandler(slot, &hd);
+       char fnBuf[MAX_PATH + 1];
 
        // If this fails to read the file, the pointer is set to NULL
        uint32_t size = 0;
-       hdData = ReadFile(settings.hdPath, &size);
+       sprintf(fnBuf, "%s%s", settings.disksPath, settings.hd[0]);
+       hdData = ReadFile(fnBuf, &size);
 
        if (hdData)
                WriteLog("HD: Read Hard Drive image file, %u bytes ($%X)\n", size - 0x40, size - 0x40);
diff --git a/src/sdlemu_config.cpp b/src/sdlemu_config.cpp
deleted file mode 100644 (file)
index 77fd67a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * SDLEMU library - Free sdl related functions library
- * Copyrigh(c) 1999-2002 sdlemu development crew
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <string>
-#include <list>
-#include "sdlemu_config.h"
-
-using namespace std;
-
-class token_list
-{
-public:
-       token_list(const string &name) : m_name(name), m_value(""), m_token("") {}
-       void add_token_variable(const string &var) { m_token = var; }
-       void add_token_value(const string &value) { m_value = value; }
-       const string &LineName() const { return m_name; }
-       const string &Token() const { return m_token; }
-       const string &Value() const { return m_value; }
-private:
-       std::string m_name;
-       std::string m_value;
-       std::string m_token;
-};
-
-std::list<token_list> vec;
-
-void string_tokenize_variable()
-{
-       list<token_list>::iterator p;
-       const string delim = " ";
-       for(p = vec.begin(); p != vec.end(); p++) {
-               string::size_type lastPos = (*p).LineName().find_first_not_of(delim, 0);
-               string::size_type pos     = (*p).LineName().find_first_of(delim, lastPos);
-
-               if(string::npos != pos && string::npos != lastPos) {
-                       string s = (*p).LineName().substr(lastPos, pos - lastPos);
-                       (*p).add_token_variable(s);
-               }
-       }
-}
-
-void string_tokenize_value()
-{
-       list<token_list>::iterator p;
-       const string delim = " =\n\t\r";                // "\r" needed for Win32 compatibility...
-
-       for(p = vec.begin(); p != vec.end(); p++) {
-               string::size_type lastPos = (*p).LineName().find_first_of(delim, 0);
-               string::size_type pos     = (*p).LineName().find_first_not_of(delim, lastPos);
-
-               if(string::npos != pos && string::npos != lastPos) {
-                       string s = (*p).LineName().substr(pos);
-                       (*p).add_token_value(s);
-               }
-       }
-}
-
-int sdlemu_init_config(const char *filename)
-{
-       FILE *f = fopen(filename, "r");
-       if(!f) return 0;
-
-       fseek(f, 0, SEEK_END);
-       int len = ftell(f);
-       fseek(f, 0, SEEK_SET);
-
-       char *s = new char[len];
-       fread(s, 1, len, f);
-       string str(s);
-
-       const string delim = "\n\r";            // "\r" needed for Win32 compatibility...
-       string::size_type lastPos = str.find_first_not_of(delim, 0);
-       string::size_type pos     = str.find_first_of(delim, lastPos);
-
-       while (string::npos != pos || string::npos != lastPos) {
-               string string = str.substr(lastPos, pos - lastPos);
-               if(string[0] == '#')
-               {
-               }
-               else if(string[0] == '[')
-               {
-               }
-               else
-               {
-                       vec.push_back(string);
-               }
-               lastPos = str.find_first_not_of(delim, pos);
-               pos = str.find_first_of(delim, lastPos);
-       }
-       string_tokenize_variable();
-       string_tokenize_value();
-       delete [] s;
-       fclose(f);
-       return 1;
-}
-
-const char *sdlemu_getval_string(const char *key_string, const char *default_string)
-{
-       list<token_list>::iterator p;
-       for(p = vec.begin(); p != vec.end(); p++) {
-
-               if(strcmp((*p).Token().c_str(), key_string) == 0)
-                       return (*p).Value().c_str();
-       }
-       return default_string;
-}
-
-int sdlemu_getval_int(const char *key_string, int default_int)
-{
-       list<token_list>::iterator p;
-       for(p = vec.begin(); p != vec.end(); p++) {
-
-               if(strcmp((*p).Token().c_str(), key_string) == 0) {
-                       const char *ret = (*p).Value().c_str();
-                       if(ret) return atoi(ret);
-               }
-       }
-       return default_int;
-}
-
-int sdlemu_getval_bool(const char *key_string, int default_int)
-{
-       list<token_list>::iterator p;
-       for(p = vec.begin(); p != vec.end(); p++) {
-
-               if(strcmp((*p).Token().c_str(), key_string) == 0) {
-                       const char *ret = (*p).Value().c_str();
-                       if(ret) return atoi(ret)>0;
-               }
-       }
-       return default_int;
-}
diff --git a/src/sdlemu_config.h b/src/sdlemu_config.h
deleted file mode 100644 (file)
index 2c2e6d5..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __SDL_CONFIG_H__
-#define __SDL_CONFIG_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int sdlemu_init_config(const char * filename);
-const char * sdlemu_getval_string(const char * key_string, const char * default_string);
-int sdlemu_getval_int(const char * key_string, int default_int);
-int sdlemu_getval_bool(const char * key_string, int default_int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
index 81b4d1df26f9742267f513df21b72f8fb1e9ada7..cb287d9b946f4a7a742095ee046fdfffe6929a4c 100644 (file)
@@ -1,36 +1,50 @@
 //
-// SETTINGS.CPP: Game configuration loading/saving support
+// settings.cpp: Apple2 configuration loading/saving support
 //
 // by James Hammons
-// (C) 2005 Underground Software
-//
-// JLH = James Hammons <jlhamm@acm.org>
-//
-// WHO  WHEN        WHAT
-// ---  ----------  -----------------------------------------------------------
-// JLH  01/04/2006  Added changelog ;-)
+// (C) 2019 Underground Software
 //
 
 #include "settings.h"
 
 #include <stdlib.h>
+#include <map>
 #include <string>
 #include <SDL2/SDL.h>
-#include "sdlemu_config.h"
+#include "fileio.h"
 #include "log.h"
 #include "video.h"
 
-using namespace std;
-
-
 // Global variables
 
 Settings settings;
 
+// Private variables
+
+static const char configPath[5][32] = {
+       "./apple2.cfg",                 // CWD
+       "~/apple2.cfg",                 // Home directory
+       "~/.apple2/apple2.cfg", // Home under .apple2 directory
+       "/etc/apple2.cfg",              // /etc
+       "apple2.cfg"                    // Somewhere in the path
+};
+
+static int8_t configLoc = -1;
+static std::map<std::string, std::string> keystore;
 
 // Private function prototypes
 
+static int8_t FindConfig(void);
+static void ParseConfigFile(void);
+static bool GetValue(const char *, bool);
+static int GetValue(const char *, int);
+static const char * GetValue(const char *, const char *);
+static void SetValue(const char * key, bool value);
+static void SetValue(const char * key, int value);
+static void SetValue(const char * key, unsigned int value);
+static void SetValue(const char * key, const char * value);
 static void CheckForTrailingSlash(char * path);
+static void UpdateConfigFile(void);
 
 
 //
@@ -38,74 +52,31 @@ static void CheckForTrailingSlash(char * path);
 //
 void LoadSettings(void)
 {
-       if (sdlemu_init_config("./apple2.cfg") == 0                     // CWD
-               && sdlemu_init_config("~/apple2.cfg") == 0              // Home
-               && sdlemu_init_config("~/.apple2/apple2.cfg") == 0      // Home under .apple2 directory
-               && sdlemu_init_config("apple2.cfg") == 0)               // Somewhere in the path
-               WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
+       ParseConfigFile();
+
+       settings.useJoystick = GetValue("useJoystick", false);
+       settings.joyport = GetValue("joyport", 0);
+       settings.hardwareTypeNTSC = GetValue("hardwareTypeNTSC", true);
+       settings.fullscreen = GetValue("fullscreen", false);
+       settings.useOpenGL = GetValue("useOpenGL", true);
+       settings.glFilter = GetValue("glFilterType", 0);
+       settings.renderType = GetValue("renderType", 0);
+       settings.autoStateSaving = GetValue("autoSaveState", true);
+
+       settings.winX = GetValue("windowX", 250);
+       settings.winY = GetValue("windowY", 100);
+
+//     strcpy(settings.BIOSPath, sdlemu_getval_string("BIOSROM", "./ROMs/apple2e-enhanced.rom"));
+       strcpy(settings.disksPath, GetValue("disks", "./disks/"));
+       strcpy(settings.hd[0], GetValue("harddrive1", "./disks/Pitch-Dark-20180731.2mg"));
+       strcpy(settings.hd[1], GetValue("harddrive2", ""));
+       strcpy(settings.hd[2], GetValue("harddrive3", ""));
+       strcpy(settings.hd[3], GetValue("harddrive4", ""));
+       strcpy(settings.hd[4], GetValue("harddrive5", ""));
+       strcpy(settings.hd[5], GetValue("harddrive6", ""));
+       strcpy(settings.hd[6], GetValue("harddrive7", ""));
+       strcpy(settings.autoStatePath, GetValue("autoStateFilename", "./apple2auto.state"));
 
-       settings.useJoystick = sdlemu_getval_bool("useJoystick", false);
-       settings.joyport = sdlemu_getval_int("joyport", 0);
-       settings.hardwareTypeNTSC = sdlemu_getval_bool("hardwareTypeNTSC", true);
-       settings.frameSkip = sdlemu_getval_int("frameSkip", 0);
-       settings.fullscreen = sdlemu_getval_bool("fullscreen", false);
-       settings.useOpenGL = sdlemu_getval_bool("useOpenGL", true);
-       settings.glFilter = sdlemu_getval_int("glFilterType", 0);
-       settings.renderType = sdlemu_getval_int("renderType", 0);
-       settings.autoStateSaving = sdlemu_getval_bool("autoSaveState", true);
-
-       settings.winX = sdlemu_getval_int("windowX", 250);
-       settings.winY = sdlemu_getval_int("windowY", 100);
-
-       // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
-       settings.p1KeyBindings[0] = sdlemu_getval_int("p1k_up", SDL_SCANCODE_UP);
-       settings.p1KeyBindings[1] = sdlemu_getval_int("p1k_down", SDL_SCANCODE_DOWN);
-       settings.p1KeyBindings[2] = sdlemu_getval_int("p1k_left", SDL_SCANCODE_LEFT);
-       settings.p1KeyBindings[3] = sdlemu_getval_int("p1k_right", SDL_SCANCODE_RIGHT);
-       settings.p1KeyBindings[4] = sdlemu_getval_int("p1k_c", SDL_SCANCODE_Z);
-       settings.p1KeyBindings[5] = sdlemu_getval_int("p1k_b", SDL_SCANCODE_X);
-       settings.p1KeyBindings[6] = sdlemu_getval_int("p1k_a", SDL_SCANCODE_C);
-       settings.p1KeyBindings[7] = sdlemu_getval_int("p1k_option", SDL_SCANCODE_APOSTROPHE);
-       settings.p1KeyBindings[8] = sdlemu_getval_int("p1k_pause", SDL_SCANCODE_RETURN);
-       settings.p1KeyBindings[9] = sdlemu_getval_int("p1k_0", SDL_SCANCODE_KP_0);
-       settings.p1KeyBindings[10] = sdlemu_getval_int("p1k_1", SDL_SCANCODE_KP_1);
-       settings.p1KeyBindings[11] = sdlemu_getval_int("p1k_2", SDL_SCANCODE_KP_2);
-       settings.p1KeyBindings[12] = sdlemu_getval_int("p1k_3", SDL_SCANCODE_KP_3);
-       settings.p1KeyBindings[13] = sdlemu_getval_int("p1k_4", SDL_SCANCODE_KP_4);
-       settings.p1KeyBindings[14] = sdlemu_getval_int("p1k_5", SDL_SCANCODE_KP_5);
-       settings.p1KeyBindings[15] = sdlemu_getval_int("p1k_6", SDL_SCANCODE_KP_6);
-       settings.p1KeyBindings[16] = sdlemu_getval_int("p1k_7", SDL_SCANCODE_KP_7);
-       settings.p1KeyBindings[17] = sdlemu_getval_int("p1k_8", SDL_SCANCODE_KP_8);
-       settings.p1KeyBindings[18] = sdlemu_getval_int("p1k_9", SDL_SCANCODE_KP_9);
-       settings.p1KeyBindings[19] = sdlemu_getval_int("p1k_pound", SDL_SCANCODE_KP_DIVIDE);
-       settings.p1KeyBindings[20] = sdlemu_getval_int("p1k_star", SDL_SCANCODE_KP_MULTIPLY);
-
-       settings.p2KeyBindings[0] = sdlemu_getval_int("p2k_up", SDL_SCANCODE_UP);
-       settings.p2KeyBindings[1] = sdlemu_getval_int("p2k_down", SDL_SCANCODE_DOWN);
-       settings.p2KeyBindings[2] = sdlemu_getval_int("p2k_left", SDL_SCANCODE_LEFT);
-       settings.p2KeyBindings[3] = sdlemu_getval_int("p2k_right", SDL_SCANCODE_RIGHT);
-       settings.p2KeyBindings[4] = sdlemu_getval_int("p2k_c", SDL_SCANCODE_Z);
-       settings.p2KeyBindings[5] = sdlemu_getval_int("p2k_b", SDL_SCANCODE_X);
-       settings.p2KeyBindings[6] = sdlemu_getval_int("p2k_a", SDL_SCANCODE_C);
-       settings.p2KeyBindings[7] = sdlemu_getval_int("p2k_option", SDL_SCANCODE_APOSTROPHE);
-       settings.p2KeyBindings[8] = sdlemu_getval_int("p2k_pause", SDL_SCANCODE_RETURN);
-       settings.p2KeyBindings[9] = sdlemu_getval_int("p2k_0", SDL_SCANCODE_KP_0);
-       settings.p2KeyBindings[10] = sdlemu_getval_int("p2k_1", SDL_SCANCODE_KP_1);
-       settings.p2KeyBindings[11] = sdlemu_getval_int("p2k_2", SDL_SCANCODE_KP_2);
-       settings.p2KeyBindings[12] = sdlemu_getval_int("p2k_3", SDL_SCANCODE_KP_3);
-       settings.p2KeyBindings[13] = sdlemu_getval_int("p2k_4", SDL_SCANCODE_KP_4);
-       settings.p2KeyBindings[14] = sdlemu_getval_int("p2k_5", SDL_SCANCODE_KP_5);
-       settings.p2KeyBindings[15] = sdlemu_getval_int("p2k_6", SDL_SCANCODE_KP_6);
-       settings.p2KeyBindings[16] = sdlemu_getval_int("p2k_7", SDL_SCANCODE_KP_7);
-       settings.p2KeyBindings[17] = sdlemu_getval_int("p2k_8", SDL_SCANCODE_KP_8);
-       settings.p2KeyBindings[18] = sdlemu_getval_int("p2k_9", SDL_SCANCODE_KP_9);
-       settings.p2KeyBindings[19] = sdlemu_getval_int("p2k_pound", SDL_SCANCODE_KP_DIVIDE);
-       settings.p2KeyBindings[20] = sdlemu_getval_int("p2k_star", SDL_SCANCODE_KP_MULTIPLY);
-
-       strcpy(settings.BIOSPath, sdlemu_getval_string("BIOSROM", "./ROMs/apple2e-enhanced.rom"));
-       strcpy(settings.disksPath, sdlemu_getval_string("disks", "./disks"));
-       strcpy(settings.hdPath, sdlemu_getval_string("harddrive", "./disks/Pitch-Dark-20180731.2mg"));
-       strcpy(settings.autoStatePath, sdlemu_getval_string("autoStateFilename", "./apple2auto.state"));
        CheckForTrailingSlash(settings.disksPath);
 }
 
@@ -116,6 +87,148 @@ void LoadSettings(void)
 void SaveSettings(void)
 {
        SDL_GetWindowPosition(sdlWindow, &settings.winX, &settings.winY);
+
+       SetValue("autoSaveState", settings.autoStateSaving);
+       SetValue("autoStateFilename", settings.autoStatePath);
+       SetValue("useJoystick", settings.useJoystick);
+       SetValue("joyport", settings.joyport);
+       SetValue("hardwareTypeNTSC", settings.hardwareTypeNTSC);
+       SetValue("fullscreen", settings.fullscreen);
+       SetValue("useOpenGL", settings.useOpenGL);
+       SetValue("glFilterType", settings.glFilter);
+       SetValue("renderType", settings.renderType);
+       SetValue("windowX", settings.winX);
+       SetValue("windowY", settings.winY);
+       SetValue("disks", settings.disksPath);
+       SetValue("harddrive1", settings.hd[0]);
+       SetValue("harddrive2", settings.hd[1]);
+       SetValue("harddrive3", settings.hd[2]);
+       SetValue("harddrive4", settings.hd[3]);
+       SetValue("harddrive5", settings.hd[4]);
+       SetValue("harddrive6", settings.hd[5]);
+       SetValue("harddrive7", settings.hd[6]);
+
+       UpdateConfigFile();
+}
+
+
+static int8_t FindConfig()
+{
+       for(uint8_t i=0; i<5; i++)
+       {
+               FILE * f = fopen(configPath[i], "r");
+
+               if (f != NULL)
+               {
+                       fclose(f);
+                       return i;
+               }
+       }
+
+       return -1;
+}
+
+
+//
+// Read & parse the configuration file into our keystore
+//
+static void ParseConfigFile(void)
+{
+       configLoc = FindConfig();
+
+       if (configLoc == -1)
+       {
+               WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
+               return;
+       }
+
+       char * buf = (char *)ReadFile(configPath[configLoc]);
+       std::string s(buf);
+
+       const std::string delim = "\n\r";
+       std::string::size_type start = s.find_first_not_of(delim, 0);
+       std::string::size_type end   = s.find_first_of(delim, start);
+
+       while ((start != std::string::npos) || (end != std::string::npos))
+       {
+               std::string sub = s.substr(start, end - start);
+
+               if ((sub[0] != '#') && (sub[0] != '['))
+               {
+                       std::string::size_type kStart = sub.find_first_not_of(" ", 0);
+                       std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
+                       std::string::size_type vStart = sub.find_first_of(" =\t\n\r", 0);
+                       std::string::size_type vEnd   = sub.find_first_not_of(" =\t\n\r", vStart);
+
+                       if ((kStart != std::string::npos) && (kEnd != std::string::npos)
+                               && (vStart != std::string::npos) && (vEnd != std::string::npos))
+                       {
+                               keystore[sub.substr(kStart, kEnd - kStart)] = sub.substr(vEnd);
+                       }
+               }
+
+               start = s.find_first_not_of(delim, end);
+               end   = s.find_first_of(delim, start);
+       }
+
+       free(buf);
+}
+
+
+static bool GetValue(const char * key, bool def)
+{
+       if (keystore.find(key) == keystore.end())
+               return def;
+
+       return (atoi(keystore[key].c_str()) == 0 ? false : true);
+}
+
+
+static int GetValue(const char * key, int def)
+{
+       if (keystore.find(key) == keystore.end())
+               return def;
+
+       return atoi(keystore[key].c_str());
+}
+
+
+static const char * GetValue(const char * key, const char * def)
+{
+       if (keystore.find(key) == keystore.end())
+               return def;
+
+       return keystore[key].c_str();
+}
+
+
+static void SetValue(const char * key, bool value)
+{
+       keystore[key] = (value ? "1" : "0");
+}
+
+
+static void SetValue(const char * key, int value)
+{
+       char buf[64];
+
+       sprintf(buf, "%i", value);
+       keystore[key] = buf;
+}
+
+
+static void SetValue(const char * key, unsigned int value)
+{
+       char buf[64];
+
+       sprintf(buf, "%u", value);
+       keystore[key] = buf;
+}
+
+
+static void SetValue(const char * key, const char * value)
+{
+       keystore[key] = value;
 }
 
 
@@ -124,8 +237,85 @@ void SaveSettings(void)
 //
 static void CheckForTrailingSlash(char * path)
 {
-       if (strlen(path) > 0)
-               if (path[strlen(path) - 1] != '/')
-                       strcat(path, "/");      // NOTE: Possible buffer overflow
+       uint32_t len = strlen(path);
+
+       // If the length is greater than zero, and the last char in the string is
+       // not a forward slash, and there's room for one more character, then add a
+       // trailing slash.
+       if ((len > 0) && (path[len - 1] != '/') && (len < MAX_PATH))
+               strcat(path, "/");
+}
+
+
+//
+// Update the values in the config file (if one exists) with updated values in
+// the keystore.
+//
+static void UpdateConfigFile(void)
+{
+       // Sanity check
+       if (configLoc == -1)
+       {
+               WriteLog("Settings: Creating default config...\n");
+               configLoc = 0;
+       }
+
+       char * buf = (char *)ReadFile(configPath[configLoc]);
+
+       FILE * f = fopen(configPath[configLoc], "w");
+
+       if (f == NULL)
+       {
+               WriteLog("Settings: Could not open config file for writing!\n");
+               free(buf);
+               return;
+       }
+
+       std::string s(buf);
+
+       const std::string delim = "\n\r";
+       std::string::size_type start = 0;
+       std::string::size_type end   = s.find_first_of(delim, start);
+
+       while (end != std::string::npos)
+       {
+               if (end > start)
+               {
+                       std::string sub = s.substr(start, end - start);
+
+                       if ((sub[0] != '#') && (sub[0] != '['))
+                       {
+                               std::string::size_type kStart = sub.find_first_not_of(" ", 0);
+                               std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
+
+                               if ((kStart != std::string::npos)
+                                       && (kEnd != std::string::npos))
+                               {
+                                       std::string key = sub.substr(kStart, kEnd - kStart);
+
+                                       if (keystore.find(key) != keystore.end())
+                                       {
+                                               sub = key + " = " + keystore[key];
+                                               keystore.erase(key);
+                                       }
+                               }
+                       }
+
+                       fprintf(f, "%s\n", sub.c_str());
+               }
+               else
+                       fprintf(f, "\n");
+
+               start = end + 1;
+               end   = s.find_first_of(delim, start);
+       }
+
+       std::map<std::string, std::string>::iterator i;
+
+       for(i=keystore.begin(); i!=keystore.end(); i++)
+               fprintf(f, "%s = %s\n", i->first.c_str(), i->second.c_str());
+
+       fclose(f);
+       free(buf);
 }
 
index e97dcdf1de44666f959add5542b8b3b1ef15b99a..41be54d8c8b26ca9fd27f3d7b403179c116508a2 100644 (file)
@@ -10,7 +10,7 @@
 #include <limits.h>
 #define MAX_PATH               _POSIX_PATH_MAX
 #else
-#include <stdlib.h>                                                            // for MAX_PATH on MinGW/Darwin
+#include <stdlib.h>                                            // for MAX_PATH on MinGW/Darwin
 // Win64 kludge
 #ifndef MAX_PATH
 #define MAX_PATH               _MAX_PATH               // Ugh.
@@ -28,26 +28,19 @@ struct Settings
        bool fullscreen;
        bool useOpenGL;
        uint32_t glFilter;
-       uint32_t frameSkip;
        uint32_t renderType;
        bool autoStateSaving;           // Auto-state loading/saving on entry/exit
 
        // Window settings
 
-       int winX;
-       int winY;
-
-       // Keybindings in order of U, D, L, R, C, B, A, Op, Pa, 0-9, #, *
-
-       uint16_t p1KeyBindings[21];
-       uint16_t p2KeyBindings[21];
+       int winX, winY;
 
        // Paths
 
-       char BIOSPath[MAX_PATH];
-       char disksPath[MAX_PATH];
-       char hdPath[MAX_PATH];
-       char autoStatePath[MAX_PATH];
+       char BIOSPath[MAX_PATH + 1];
+       char disksPath[MAX_PATH + 1];
+       char autoStatePath[MAX_PATH + 1];
+       char hd[7][MAX_PATH + 1];
 };
 
 // Render types
index e027dfa1485d0fb964114d45a5f23e07524270cb..7309910e24b89848a9f36a2dbc18f3f36712c4c0 100644 (file)
@@ -1197,6 +1197,12 @@ bool InitVideo(void)
                SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING,
                VIRTUAL_SCREEN_WIDTH, VIRTUAL_SCREEN_HEIGHT);
 
+       // Start in fullscreen, if user requested it via config file
+       int response = SDL_SetWindowFullscreen(sdlWindow, (settings.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
+
+       if (response != 0)
+               WriteLog("Video::FullScreen: SDL error = %s\n", SDL_GetError());
+
        SetupBlurTable();
 
        WriteLog("Video: Successfully initialized.\n");
index 99c736259f94fc005c77a71c484c5e4ff30a8c3c..4f6f972a30fb585de710861723b4ccc1053f9dad 100644 (file)
@@ -29,43 +29,63 @@ h1.title
        margin-top: 45px;
 }
 
-img.flt-l
+.flt-l
 {
        float: left;
-       margin-right: 8px;
+       padding-right: 8px;
 }
 
-img.flt-r
+.flt-r
 {
        float: right;
-       margin-left: 8px;
+       padding-left: 8px;
 }
 
-figure.flt-r
+.clr-l
+{
+       clear: left;
+}
+
+.clr-r
+{
+       clear: right;
+}
+
+figure
 {
-       float: right;
        margin-top: 0;
-       margin-left: 8px;
+       margin-left: 0;
        margin-right: 0;
        font-style: italic;
        font-size: 90%;
 }
 
-figure.small33
+img
 {
-       width: 33%;
+       max-width: 100%;
+       object-fit: contain;
 }
 
-img.small50
+img.border
 {
-       width: 50%;
-       height: 50%;
+       margin: 5px;
+       border: 1px solid #CF5F00;
+       border-radius: 4px;
+       padding: 5px;
+       background-color: #FFAF00;
+       box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
 }
 
-img.small33
+.small33
 {
        width: 33%;
-       height: 33%;
+       height: auto;
+}
+
+.small50
+{
+       width: 50%;
+       height: auto;
 }
 
 #title
index cc7ade3eb20937b60b7d3f6268168d73612c02ae..8cf0f946a545e1ab76f74b37e34fd09f9c157a17 100644 (file)
Binary files a/web/img/a2-icon-64x64.png and b/web/img/a2-icon-64x64.png differ
index b05e38e5c635549f7945029a0e9e0b49c5f49742..445a27b7ce94128ce87bcfb3a03ec25b2e3295a4 100644 (file)
Binary files a/web/img/ss-01s.png and b/web/img/ss-01s.png differ
index 4078a3aae35aa3ebf6a59f5a89435e81b84175c3..1f6337c52c33d1523a39ce6134a56ed7bd961e84 100644 (file)
Binary files a/web/img/ss-02s.png and b/web/img/ss-02s.png differ
index 3703aeffd3b3147dc0a68eb5abaddbd1bc4abc55..b4d1a767f6a2d3db102e4019f742ef3a1b210d16 100644 (file)
Binary files a/web/img/ss-03s.png and b/web/img/ss-03s.png differ
index 638832cc367a71e4f67e2dfdcd4ca2b9c3a2218d..7e58b633934bb3208837b19b95247dbbb90f7fea 100644 (file)
Binary files a/web/img/ss-04.png and b/web/img/ss-04.png differ
index 9801ac89dd8f85f584142b0fc231ffc4f6f0ca0d..faecb8026a8a9ff0bc59d48fa475f18c5ee761c4 100644 (file)
Binary files a/web/img/ss-04s.png and b/web/img/ss-04s.png differ
index 9310b4634c64a229583d7c7eee67797da49f3aed..b6dae4f6ed4b18cca17e03bd1ff66ed11549d527 100644 (file)
@@ -21,7 +21,7 @@
 <p><img class="flt-l" src="img/a2-icon-64x64.png">This is the home of the Apple2 portable Apple //e emulator.&ensp;It&rsquo;s based on GCC and SDL2, and runs on Linux, Windows, and MacOS X.&ensp;It&rsquo;s powered by Virtual 65C02&trade;, and sports an easy to use yet powerful interface.&ensp;It also has WOZ support!&ensp;The source is licensed under the GPL version 3.</p>
 
 <figure class="flt-r">
-<img src="img/ss-04s.png">
+<img class="border" src="img/ss-04s.png">
 <figcaption>Apple2 running &ldquo;The Bard&rsquo;s Tale&rdquo;</figcaption>
 </figure>
 
 
 <h3>How to Use It</h3>
 
-<figure class="flt-r small33">
-<img src="img/ss-01s.png" width="100%">
+<figure class="clr-r flt-r small33">
+<img class="border" src="img/ss-01s.png" width="100%">
 <figcaption>Apple2&rsquo;s Control Bar</figcaption>
 </figure>
 
+<figure class="clr-r flt-r small33">
+<img class="border" src="img/ss-02s.png">
+<figcaption>Apple2&rsquo;s Disk Selector</figcaption>
+</figure>
+
+<figure class="clr-r flt-r small33">
+<img class="border" src="img/ss-03s.png">
+<figcaption>Scrolling in the Disk Selector</figcaption>
+</figure>
+
 <p>By mousing over the right side of the screen, the emulator control bar will appear; moving the mouse off of the bar will cause it to disappear.&ensp;On the bar are seven icons, labeled (from top to bottom): power, disk one, disk two, swap disks, save state, load state, and configure.&ensp;Here&rsquo;s what they do:</p>
 
 <ul>
 <li>Configure: configure various behaviors of the Apple2 emulator</li>
 </ul>
 
-<img class="flt-l small33" src="img/ss-02s.png">
-
-<img class="flt-l small33" src="img/ss-03s.png">
-
 <p>In addition to the aforementioned control bar, Apple2 also supports the following function keys:</p>
 
 <ul>