]> Shamusworld >> Repos - apple2/blobdiff - src/gui/gui.cpp
Miscellaneous bugfixes.
[apple2] / src / gui / gui.cpp
index 91ce920ef799125c8d4f8a9fdb617457fd81f2f3..b0386acc1cfbac55e516119d47a19f8fde0e2b32 100644 (file)
@@ -3,12 +3,12 @@
 //
 // Graphical User Interface support
 // by James Hammons
-// © 2014 Underground Software
+// © 2014-2019 Underground Software
 //
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // WHO  WHEN        WHAT
-// ---  ----------  ------------------------------------------------------------
+// ---  ----------  -----------------------------------------------------------
 // JLH  02/03/2006  Created this file
 // JLH  03/13/2006  Added functions to allow shutting down GUI externally
 // JLH  03/22/2006  Finalized basic multiple window support
 //
 
 #include "gui.h"
+#include <vector>
 #include "apple2.h"
-#include "applevideo.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,15 +100,14 @@ const char driveLight[(5 * 5) + 1] =
        " @@@ ";
 
 
-enum { SBS_SHOWING, SBS_HIDING, SBS_SHOWN, SBS_HIDDEN };
-
-
 SDL_Texture * GUI::overlay = NULL;
 SDL_Rect GUI::olDst;
 int GUI::sidebarState = SBS_HIDDEN;
 int32_t GUI::dx = 0;
 int32_t GUI::iconSelected = -1;
 bool GUI::hasKeyboardFocus = false;
+bool GUI::powerOnState = true;
+
 int32_t lastIconSelected = -1;
 SDL_Texture * iconSelection = NULL;
 SDL_Texture * diskIcon = NULL;
@@ -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,8 +207,7 @@ void GUI::Init(SDL_Renderer * renderer)
        }
 
        DiskSelector::Init(renderer);
-       DiskSelector::showWindow = true;
-
+       Config::Init(renderer);
        WriteLog("GUI: Successfully initialized.\n");
 }
 
@@ -207,6 +228,9 @@ 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;
 
@@ -214,27 +238,80 @@ void GUI::MouseDown(int32_t x, int32_t y, uint32_t buttons)
        {
        // Power
        case 0:
-               SpawnMessage("*** POWER ***");
+               powerOnState = !powerOnState;
+               SetPowerState();
+
+               if (!powerOnState)
+                       SpawnMessage("*** POWER OFF ***");
+
                break;
        // Disk #1
        case 1:
                SpawnMessage("*** DISK #1 ***");
 
-               if (disk1EjectHovered && !floppyDrive.IsEmpty(0))
-                       SpawnMessage("*** EJECT DISK #1 ***");
+#if 0
+               if (disk1EjectHovered && !floppyDrive[0].IsEmpty(0))
+               {
+                       floppyDrive[0].EjectImage(0);
+                       SpawnMessage("*** DISK #1 EJECTED ***");
+               }
+
+               if (!disk1EjectHovered && !disk1NewDiskHovered)
+               {
+                       // Load the disk selector
+                       Config::HideWindow();
+                       DiskSelector::ShowWindow(0);
+               }
+#else
+               if (disk1EjectHovered)
+               {
+                       if (!floppyDrive[0].IsEmpty(0))
+                       {
+                               floppyDrive[0].EjectImage(0);
+                               SpawnMessage("*** DISK #1 EJECTED ***");
+                       }
+               }
+               else
+               {
+                       if (disk1NewDiskHovered)
+                       {
+                               if (!floppyDrive[0].IsEmpty(0))
+                                       floppyDrive[0].EjectImage(0);
+
+                               floppyDrive[0].CreateBlankImage(0);
+                       }
+                       else
+                       {
+                               // Load the disk selector
+                               Config::HideWindow();
+                               DiskSelector::ShowWindow(0);
+                       }
+               }
+#endif
 
                break;
        // Disk #2
        case 2:
                SpawnMessage("*** DISK #2 ***");
 
-               if (disk2EjectHovered && !floppyDrive.IsEmpty(1))
-                       SpawnMessage("*** EJECT DISK #2 ***");
+               if (disk2EjectHovered && !floppyDrive[0].IsEmpty(1))
+               {
+                       floppyDrive[0].EjectImage(1);
+                       SpawnMessage("*** DISK #2 EJECTED ***");
+               }
+
+               if (!disk2EjectHovered && !disk2NewDiskHovered)
+               {
+                       // Load the disk selector
+                       Config::HideWindow();
+                       DiskSelector::ShowWindow(1);
+               }
 
                break;
        // Swap disks
        case 3:
-               SpawnMessage("*** SWAP DISKS ***");
+               floppyDrive[0].SwapImages();
+               SpawnMessage("*** DISKS SWAPPED ***");
                break;
        // Save state
        case 4:
@@ -247,6 +324,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;
        }
 }
@@ -254,11 +334,16 @@ 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)
        {
                iconSelected = -1;
@@ -308,17 +393,29 @@ 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);
                                lastIconSelected = iconSelected;
-                               SpawnMessage("%s", iconHelp[iconSelected]);
+
+                               if ((iconSelected >= 0) && (iconSelected <= 6))
+                                       SpawnMessage("%s", iconHelp[iconSelected]);
 
                                // Show what's in the selected drive
                                if (iconSelected >= 1 && iconSelected <= 2)
                                {
-                                       if (!floppyDrive.IsEmpty(iconSelected - 1))
-                                               SpawnMessage("\"%s\"", floppyDrive.ImageName(iconSelected - 1));
+                                       if (!floppyDrive[0].IsEmpty(iconSelected - 1))
+                                               SpawnMessage("\"%s\"", floppyDrive[0].ImageName(iconSelected - 1));
                                }
                        }
                }
@@ -326,6 +423,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
@@ -373,13 +476,14 @@ void GUI::AssembleDriveIcon(SDL_Renderer * renderer, int driveNumber)
        // Drive door @ (16, 7)
        SDL_Rect dst;
        dst.w = 8, dst.h = 10, dst.x = 16, dst.y = 7;
-       SDL_RenderCopy(renderer, (floppyDrive.IsEmpty(driveNumber) ?
+       SDL_RenderCopy(renderer, (floppyDrive[0].IsEmpty(driveNumber) ?
                doorOpen : doorClosed), NULL, &dst);
 
        // Numeral @ (30, 20)
        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);
@@ -388,7 +492,7 @@ void GUI::AssembleDriveIcon(SDL_Renderer * renderer, int driveNumber)
 
 void GUI::DrawEjectButton(SDL_Renderer * renderer, int driveNumber)
 {
-       if (floppyDrive.IsEmpty(driveNumber))
+       if (floppyDrive[0].IsEmpty(driveNumber))
                return;
 
        uint8_t r = 0x00, g = 0xAA, b = 0x00;
@@ -397,14 +501,28 @@ void GUI::DrawEjectButton(SDL_Renderer * renderer, int driveNumber)
                || (driveNumber == 1 && disk2EjectHovered))
                r = 0x20, g = 0xFF, b = 0x20;
 
-//     DrawCharArray(renderer, ejectIcon, 29, 31, 8, 7, 0x00, 0xAA, 0x00);
        DrawCharArray(renderer, ejectIcon, 29, 31, 8, 7, r, g, b);
 }
 
 
+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.DriveLightStatus(driveNumber);
+       int lightState = floppyDrive[0].DriveLightStatus(driveNumber);
        int r = 0x77, g = 0x00, b = 0x00;
 
        if (lightState == DLS_READ)
@@ -435,6 +553,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 absolute 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;
@@ -459,8 +656,8 @@ void GUI::DrawSidebarIcons(SDL_Renderer * renderer)
        SDL_Texture * icons[7] = { powerOnIcon, disk1Icon, disk2Icon, diskSwapIcon,
                stateSaveIcon, stateLoadIcon, configIcon };
 
-       SDL_Rect dst;
-       dst.w = dst.h = 40, dst.x = 24, dst.y = 2 + 7;
+       icons[0] = (powerOnState ? powerOnIcon : powerOffIcon);
+       SDL_Rect dst = { 24, 2 + 7, 40, 40 };
 
        for(int i=0; i<7; i++)
        {
@@ -472,6 +669,7 @@ void GUI::DrawSidebarIcons(SDL_Renderer * renderer)
 
 void GUI::Render(SDL_Renderer * renderer)
 {
+       // Sanity check
        if (!overlay)
                return;
 
@@ -484,6 +682,7 @@ void GUI::Render(SDL_Renderer * renderer)
 
        // Hmm.
        DiskSelector::Render(renderer);
+       Config::Render(renderer);
 }