]> Shamusworld >> Repos - apple2/commitdiff
Improvements to timing, disk selector; added Double LoRes.
authorShamus Hammons <jlhamm@acm.org>
Thu, 22 Jun 2017 03:57:57 +0000 (22:57 -0500)
committerShamus Hammons <jlhamm@acm.org>
Thu, 22 Jun 2017 03:57:57 +0000 (22:57 -0500)
Having taken a good look at "Understanding the Apple IIe", I've fixed
the timing of one frame now that I know how much time it's supposed to
take. Also added the ability to recurse into subdirectories of the disks
directory, and the ability to page through the disk list when there are
more than three columns of disks. Another thing I did not know about was
Double LoRes, that has been added as well; also, did not know that the
video bus appeared at memory mapped locations that weren't attached to
anything. This quirk is now properly emulated.

13 files changed:
Makefile
src/apple2.cpp
src/apple2.h
src/gui/diskselector.cpp
src/gui/diskselector.h
src/gui/gfx/scroll-left.c [new file with mode: 0644]
src/gui/gfx/scroll-right.c [new file with mode: 0644]
src/gui/gui.cpp
src/gui/gui.h
src/mmu.cpp
src/sound.cpp
src/v65c02.h
src/video.cpp

index 9006897c5233b0eab07861e90c89eb80a50e6e48..11e3fd8e13c5eda7b539dc954651384d30d6d04b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -94,7 +94,7 @@ LDFLAGS =
 # Link in the gprof lib
 #LIBS = -L/usr/local/lib -L/usr/lib `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz $(GLLIB) -pg
 #LIBS = -L/usr/local/lib -L/usr/lib $(SDL_LIBS) -lstdc++ -lz $(GLLIB) -pg
-LIBS = $(SDL_LIBS) -lstdc++ -lz $(GLLIB) -pg
+LIBS = $(SDL_LIBS) -lstdc++ -lz -lm $(GLLIB) -pg
 
 #INCS = -I. -I./src -I/usr/local/include -I/usr/include
 INCS = -I. -I./src
index 1ef3ff6251c3599f20b03880af41dbecadc93227..246c737c377f7ca077b3acd6873f6a23ba61e0c4 100644 (file)
@@ -4,10 +4,11 @@
 // by James Hammons
 // © 2017 Underground Software
 //
-// Loosely based on AppleWin by Tom Charlesworth which was based on AppleWin by
-// Oliver Schmidt which was based on AppleWin by Michael O'Brien. :-) Parts are
-// also derived from ApplePC. Too bad it was closed source--it could have been
-// *the* premier Apple II emulator out there.
+// Parts loosely inspired by AppleWin by Tom Charlesworth which was based on
+// AppleWin by Oliver Schmidt which was based on AppleWin by Michael O'Brien.
+// :-) Some parts (mainly TV rendering) are derived from ApplePC. Too bad it
+// was closed source--it could have been *the* premier Apple II emulator out
+// there.
 //
 // JLH = James Hammons <jlhamm@acm.org>
 //
 // - 128K IIe related stuff [DONE]
 // - State loading/saving
 //
+// BUGS:
+//
+// - Having a directory in the ${disks} directory causes a segfault in floppy
+//
 
 #include "apple2.h"
 
@@ -47,9 +52,9 @@
 #include "settings.h"
 #include "sound.h"
 #include "timing.h"
-#include "v65c02.h"
 #include "video.h"
 #include "gui/gui.h"
+#include "gui/diskselector.h"
 
 // Debug and misc. defines
 
@@ -68,8 +73,9 @@ V65C02REGS mainCPU;                                                   // v65C02 execution context
 uint8_t appleType = APPLE_TYPE_IIE;
 FloppyDrive floppyDrive;
 bool powerStateChangeRequested = false;
+uint64_t frameCycleStart;
 
-// Local variables (actually, they're global since they're not static)
+// Exported variables
 
 uint8_t lastKeyPressed = 0;
 bool keyDown = false;
@@ -121,6 +127,8 @@ static SDL_sem * mainSem = NULL;
 static bool cpuFinished = false;
 
 // NB: Apple //e Manual sez 6502 is running @ 1,022,727 Hz
+//     This is a lie. At the end of each 65 cycle line, there is an elongated
+//     cycle (the so-called 'long' cycle) that throws the calcs out of whack.
 
 // Let's try a thread...
 //
@@ -147,13 +155,20 @@ WriteLog("CPU: SDL_SemWait(mainSem);\n");
 
                // There are exactly 800 slices of 21.333 cycles per frame, so it works
                // out evenly.
+               // [Actually, seems it's 786 slices of 21.666 cycles per frame]
+
+               // Set our frame cycle counter to the correct # of cycles at the start
+               // of this frame
+               frameCycleStart = mainCPU.clock - mainCPU.overflow;
 #ifdef THREAD_DEBUGGING
 WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n");
 #endif
-               for(int i=0; i<800; i++)
+//             for(int i=0; i<800; i++)
+               for(int i=0; i<786; i++)
                {
                        uint32_t cycles = 21;
-                       overflow += 0.333333334;
+//                     overflow += 0.333333334;
+                       overflow += 0.666666667;
 
                        if (overflow > 1.0)
                        {
@@ -169,9 +184,64 @@ WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n");
                        Execute65C02(&mainCPU, cycles);
                        WriteSampleToBuffer();
 
-                       // Dunno if this is correct (seems to be close enough)...
-                       vbl = (i < 670 ? true : false);
+                       // According to "Understanding The Apple IIe", VBL asserted after
+                       // the last byte of the screen is read and let go on the first read
+                       // of the first byte of the screen. We now know that the screen
+                       // starts on line #6 and ends on line #197 (of the vertical
+                       // counter--actual VBLANK happens on lines 230 thru 233).
+                       vbl = ((i > 17) && (i < 592) ? true : false);
                }
+/*
+Other timings from UTA2E:
+Power-up reset                         32.6 msec / 512 horizontal scans
+Flash cycle                                    1.87 Hz / Vertical freq./32
+Delay before auto repeat       534-801 msec / 32-48 vertical scans
+Auto repeat frequency          15 Hz / Vertical freq./4
+Vertical frequency                     59.94 Hz
+Horizontal frequency           15,734 Hz
+1 NTSC frame = 17030 cycles
+1 line = 65 cycles
+70 blank lines for top margin, 192 lines for screen, (35 & 35?)
+VA-C,V0-5 is upcounter starting at 011111010 ($FA) to 111111111 ($1FF)
+Horizontal counter is upcounter resets to 0000000, then jumps to 1000000 &
+counts up to 1111111 (bit 7 is Horizontal Preset Enable, which resets the counter when it goes low, the rest are H0-5)
+
+pg. 3-24 says one cycle before VBL the counters will be at
+010111111/1111111 (that doesn't look right to me...)
+
+Video address bits:
+
+A0 <- H0
+A1 <- H1
+A2 <- H2
+A3 <- SUM-A3
+A4 <- SUM-A4
+A5 <- SUM-A5
+A6 <- SUM-A6
+A7 <- V0
+A8 <- V1
+A9 <- V2
+
+SUMS are calculated like so:
+
+  1        1       0       1
+          H5      H4      H3
+  V4      V3      V4      V3
+------------------------------
+SUM-A6  SUM-A5  SUM-A4  SUM-A3
+
+In TEXT mode, A10 == (80STORE' * PAGE2)', A11 == 80STORE' * PAGE2
+A12-A15 == 0
+
+In HIRES mode, A13 == (PAGE2 * 80STORE')', A14 == PAGE2 * 80STORE'
+A10 == VA, A11 == VB, A12 == VC, A15 == 0
+
+N.B.: VA-C are lower bits than V5-0
+
+HC, from 00, 0 to 23 is the HBL interval, with horizontal retrace occuring between cycles 8 and 11.
+VC, from line 0-5 and 198-261 is the VBL interval, with vertical retrace occuring between lines 230-233
+
+*/
 
 #ifdef THREAD_DEBUGGING
 WriteLog("CPU: SDL_mutexP(cpuMutex);\n");
@@ -361,6 +431,7 @@ static void ResetApple2State(void)
 
        // Without this, you can wedge the system :-/
        memset(ram, 0, 0x10000);
+       memset(ram2, 0, 0x10000);
        mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET;
 }
 
@@ -379,6 +450,48 @@ int main(int /*argc*/, char * /*argv*/[])
        LoadSettings();
        srand(time(NULL));                      // Initialize RNG
 
+#if 0
+// Make some timing/address tables
+
+       for(uint32_t line=0; line<262; line++)
+       {
+               WriteLog("LINE %03i: ", line);
+
+               for(uint32_t col=0; col<65; col++)
+               {
+                       // Convert these to H/V counters
+                       uint32_t hcount = col - 1;
+
+                       // HC sees zero twice:
+                       if (hcount == 0xFFFFFFFF)
+                               hcount = 0;
+
+                       uint32_t vcount = line + 0xFA;
+
+                       // Now do the address calculations
+                       uint32_t sum = 0xD + ((hcount & 0x38) >> 3)
+                               + (((vcount & 0xC0) >> 6) | ((vcount & 0xC0) >> 4));
+                       uint32_t address = ((vcount & 0x38) << 4) | ((sum & 0x0F) << 3) | (hcount & 0x07);
+
+                       // Add in particulars for the gfx mode we're in...
+                       if (false)
+                               // non hires
+                               address |= (!(!store80Mode && displayPage2) ? 0x400 : 0)
+                                       | (!store80Mode && displayPage2 ? 0x800 : 0);
+                       else
+                               // hires
+                               address |= (!(!store80Mode && displayPage2) ? 0x2000: 0)
+                                       | (!store80Mode && displayPage2 ? 0x4000 : 0)
+                                       | ((vcount & 0x07) << 10);
+
+                       WriteLog("$%04X ", address);
+               }
+
+               WriteLog("\n");
+       }
+
+#endif
+
        // Zero out memory
        memset(ram, 0, 0x10000);
        memset(rom, 0, 0x10000);
@@ -826,7 +939,7 @@ static void FrameCallback(void)
 
        // 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)
+       if ((hideMouseTimeout > 0) && !(GUI::sidebarState == SBS_SHOWN || DiskSelector::showWindow == true))
                hideMouseTimeout--;
        else if (hideMouseTimeout == 0)
        {
@@ -836,6 +949,8 @@ static void FrameCallback(void)
 
        // Stuff the Apple keyboard buffer, if any keys are pending
        // N.B.: May have to simulate the key repeat delay too [yup, sure do]
+       //       According to "Understanding the Apple IIe", the initial delay is
+       //       between 32 & 48 jiffies and the repeat is every 4 jiffies.
        if (keyDownCount > 0)
        {
                keyDelay--;
index 57e284c134050d96e73995c98c5d8ebbc69cc9a0..6627bbef73420022bb892cf52a12264fa89f492b 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <stdint.h>
 #include "floppy.h"
+#include "v65c02.h"
 
 enum { APPLE_TYPE_II, APPLE_TYPE_IIE, APPLE_TYPE_IIC };
 
@@ -16,6 +17,7 @@ bool LoadImg(char * filename, uint8_t * ram, int size);
 
 extern uint8_t ram[0x10000], rom[0x10000];             // RAM & ROM pointers
 extern uint8_t ram2[0x10000];                                  // Auxillary RAM
+extern V65C02REGS mainCPU;                                             // v65C02 execution context
 extern uint8_t appleType;
 extern FloppyDrive floppyDrive;
 extern uint8_t lastKeyPressed;
@@ -32,4 +34,5 @@ extern bool altzp;
 extern bool ioudis;
 extern bool dhires;
 extern uint8_t lcState;
+extern uint64_t frameCycleStart;
 
index dfdbd572d37098eae16bce72a49c2c28cb6c235f..d13d9bb7d112537b013f74affb6e229f5e891363 100644 (file)
 #include <vector>
 #include "apple2.h"
 #include "font10pt.h"
+#include "gui.h"
 #include "log.h"
 #include "settings.h"
 #include "video.h"
 
+// Icons, in GIMP "C" format
+#include "gfx/scroll-left.c"
+#include "gfx/scroll-right.c"
 
-enum { DSS_SHOWING, DSS_HIDING, DSS_SHOWN, DSS_HIDDEN };
 
-#define DS_WIDTH       400
-#define DS_HEIGHT      300
+struct Bitmap {
+       unsigned int width;
+       unsigned int height;
+       unsigned int bytesPerPixel;                                     // 3:RGB, 4:RGBA
+       unsigned char pixelData[];
+};
+
+enum { DSS_SHOWING, DSS_HIDING, DSS_SHOWN, DSS_HIDDEN, DSS_LSB_SHOWING, DSS_LSB_SHOWN, DSS_LSB_HIDING, DSS_RSB_SHOWING, DSS_RSB_SHOWN, DSS_RSB_HIDING, DSS_TEXT_SCROLLING };
+
+#define DS_WIDTH                       402
+#define DS_HEIGHT                      322
+#define SCROLL_HOT_WIDTH       48
+// Need to add logic for left/right scroll buttons (they show when the mouse
+// is in the left or right hand portion of the rect).
+#define DS_XPOS        ((VIRTUAL_SCREEN_WIDTH - DS_WIDTH) / 2)
+#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;
+
+/*
+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.
+*/
 
 
 //
-// Case insensitve string comparison voodoo
+// Struct to hold filenames & full paths to same
 //
-struct ci_char_traits : public std::char_traits<char>
+struct FileStruct
 {
-       static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
-       static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
-       static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
-       static int compare(const char * s1, const char * s2, size_t n)
-       {
-               while (n-- != 0)
-               {
-                       if (toupper(*s1) < toupper(*s2)) return -1;
-                       if (toupper(*s1) > toupper(*s2)) return 1;
-                       ++s1; ++s2;
-               }
-               return 0;
-       }
-       static const char * find(const char * s, int n, char a)
+       std::string image;
+       std::string fullPath;
+
+       // Functor, to presumably make the std::sort go faster
+       bool operator()(const FileStruct & a, const FileStruct & b) const
        {
-               while (n-- > 0 && toupper(*s) != toupper(a))
-               {
-                       ++s;
-               }
-               return s;
+               return (strcasecmp(a.image.c_str(), b.image.c_str()) < 0 ? true : false);
        }
 };
 
-typedef std::basic_string<char, ci_char_traits> ci_string;
-//
-// END Case insensitve string comparison voodoo
-//
-
 
 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;
-std::vector<ci_string> imageList;
+std::vector<FileStruct> fsList;
 
 
 void DiskSelector::Init(SDL_Renderer * renderer)
@@ -100,45 +114,87 @@ void DiskSelector::Init(SDL_Renderer * renderer)
        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));
-       FindDisks(NULL);
+       FindDisks();
        DrawFilenames(renderer);
 }
 
 
+//
+// Find all disks images top level call
+//
+void DiskSelector::FindDisks(void)
+{
+       fsList.clear();
+       FindDisks(settings.disksPath);
+       std::sort(fsList.begin(), fsList.end(), FileStruct());
+       // Calculate the number of columns in the file selector...
+       numColumns = (int)ceilf((float)fsList.size() / 27.0f);
+       WriteLog("GUI (DiskSelector)::FindDisks(): # of columns is %i (%i files)\n", numColumns, fsList.size());
+}
+
+
+//
+// Find all disks images within path (recursive call does depth first search)
+//
 void DiskSelector::FindDisks(const char * path)
 {
-       DIR * dir = opendir(settings.disksPath);
+       DIR * dir = opendir(path);
 
        if (!dir)
        {
-               WriteLog("GUI (DiskSelector)::FindDisks: Could not open directory \"%s\%!\n", settings.disksPath);
+               WriteLog("GUI (DiskSelector)::FindDisks: Could not open directory \"%s\%!\n", path);
                return;
        }
 
-       imageList.clear();
        dirent * ent;
 
        while ((ent = readdir(dir)) != NULL)
        {
-               if (HasLegalExtension(ent->d_name))
-                       imageList.push_back(ci_string(ent->d_name));
+               char buf[0x10000];
+               sprintf(buf, "%s/%s", path, ent->d_name);
+
+               if ((ent->d_type == DT_REG) && HasLegalExtension(ent->d_name))
+               {
+                       FileStruct fs;
+                       fs.image = ent->d_name;
+                       fs.fullPath = buf;
+                       fsList.push_back(fs);
+               }
+               else if (ent->d_type == DT_DIR)
+               {
+                       // Only recurse if the directory is not one of the special ones...
+                       if ((strcmp(ent->d_name, "..") != 0)
+                               && (strcmp(ent->d_name, ".") != 0))
+                               FindDisks(buf);
+               }
        }
 
        closedir(dir);
-       std::sort(imageList.begin(), imageList.end());
 }
 
 
 bool DiskSelector::HasLegalExtension(const char * name)
 {
+       // Find the file's extension, if any
        const char * ext = strrchr(name, '.');
 
-       if ((strcasecmp(ext, ".dsk") == 0) || (strcasecmp(ext, ".do") == 0)
-               || (strcasecmp(ext, ".po") == 0) || (strcasecmp(ext, ".nib") == 0))
+       // No extension, so fuggetaboutit
+       if (ext == NULL)
+               return false;
+
+       // Otherwise, look for a legal extension
+       // We should be smarter than this, and look at headers & file sizes instead
+       if ((strcasecmp(ext, ".dsk") == 0)
+               || (strcasecmp(ext, ".do") == 0)
+               || (strcasecmp(ext, ".po") == 0)
+               || (strcasecmp(ext, ".nib") == 0))
                return true;
 
        return false;
@@ -158,8 +214,46 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
        // 3 columns of 21 chars apiece (with 6X11 font), 27 rows
 
        unsigned int count = 0;
+       unsigned int fsStart = colStart * 27;
+       int offset = 0;
+
+       // Draw partial columns (for scrolling left/right)
+       // [could probably combine these...]
+       if (textScrollCount < 0)
+       {
+               int partialColStart = (colStart - 1) * 27;
+               offset = -1 * textScrollCount;
 
-       while (count < imageList.size())
+               for(unsigned int y=0; y<27; y++)
+               {
+                       for(unsigned int i=22+textScrollCount, x=0; i<21; i++, x++)
+                       {
+                               if (i >= fsList[partialColStart + y].image.length())
+                                       break;
+
+                               DrawCharacter(renderer, x + 1, y + 1, fsList[partialColStart + y].image[i], false);
+                       }
+               }
+       }
+       else if (textScrollCount > 0)
+       {
+               offset = 22 - textScrollCount;
+
+               for(unsigned int y=0; y<27; y++)
+               {
+                       for(unsigned int i=textScrollCount, x=0; i<21; i++, x++)
+                       {
+                               if (i >= fsList[fsStart + y].image.length())
+                                       break;
+
+                               DrawCharacter(renderer, x + 1, y + 1, fsList[fsStart + y].image[i], false);
+                       }
+               }
+
+               fsStart += 27;
+       }
+
+       while (fsStart < fsList.size())
        {
 //             int currentX = (count / 18) * 17;
 //             int currentY = (count % 18);
@@ -172,14 +266,15 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
 //             for(unsigned int i=0; i<18; i++)
                for(unsigned int i=0; i<21; i++)
                {
-                       if (i >= imageList[count].length())
+                       if (i >= fsList[fsStart].image.length())
                                break;
 
-                       bool invert = (diskSelected == (int)count ? true : false);
-                       DrawCharacter(renderer, currentX + i, currentY, imageList[count][i], invert);
+                       bool invert = (diskSelected == (int)fsStart ? true : false);
+                       DrawCharacter(renderer, currentX + i + 1 + offset, currentY + 1, fsList[fsStart].image[i], invert);
                }
 
                count++;
+               fsStart++;
 
 //             if (count >= (18 * 3))
 //             if (count >= (24 * 3))
@@ -187,6 +282,18 @@ void DiskSelector::DrawFilenames(SDL_Renderer * renderer)
                        break;
        }
 
+       // If a disk is selected, show it on the top line in inverse video
+       if (diskSelected > -1)
+       {
+               for(unsigned int i=0; i<65; i++)
+               {
+                       if (i >= fsList[diskSelected].image.length())
+                               break;
+
+                       DrawCharacter(renderer, i + 1, 0, fsList[diskSelected].image[i], true);
+               }
+       }
+
        // Set render target back to default
        SDL_SetRenderTarget(renderer, NULL);
 }
@@ -224,11 +331,43 @@ void DiskSelector::MouseDown(int32_t x, int32_t y, uint32_t buttons)
        if (!entered)
                return;
 
+       if ((diskSelectorState == DSS_LSB_SHOWING) || (diskSelectorState == DSS_LSB_SHOWN))
+       {
+               if (colStart > 0)
+               {
+                       colStart--;
+                       textScrollCount = 21;
+
+                       if (colStart == 0)
+                       {
+                               diskSelectorState = DSS_LSB_HIDING;
+                               dxLeft = -8;
+                       }
+               }
+
+               return;
+       }
+
+       if ((diskSelectorState == DSS_RSB_SHOWING) || (diskSelectorState == DSS_RSB_SHOWN))
+       {
+               if (colStart + 3 < numColumns)
+               {
+                       colStart++;
+                       textScrollCount = -21;
+
+                       if ((colStart + 3) == numColumns)
+                       {
+                               diskSelectorState = DSS_RSB_HIDING;
+                               dxRight = 8;
+                       }
+               }
+
+               return;
+       }
+
        if (diskSelected != -1)
        {
-               char buffer[2048];
-               sprintf(buffer, "%s/%s", settings.disksPath, &imageList[diskSelected][0]);
-               floppyDrive.LoadImage(buffer, driveNumber);
+               floppyDrive.LoadImage(fsList[diskSelected].fullPath.c_str(), driveNumber);
        }
 
        showWindow = false;
@@ -243,17 +382,19 @@ void DiskSelector::MouseUp(int32_t x, int32_t y, uint32_t buttons)
 }
 
 
-#define DS_XPOS        ((VIRTUAL_SCREEN_WIDTH - DS_WIDTH) / 2)
-#define DS_YPOS        ((VIRTUAL_SCREEN_HEIGHT - DS_HEIGHT) / 2)
 void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
 {
        if (!showWindow)
                return;
 
+       // Check to see if DS has been hovered yet, and, if so, set a flag to show
+       // that it has
        if (!entered && ((x >= DS_XPOS) && (x <= (DS_XPOS + DS_WIDTH))
                && (y >= DS_YPOS) && (y <= (DS_YPOS + DS_HEIGHT))))
                entered = true;
 
+       // Check to see if the DS, since being hovered, is now no longer being
+       // hovered
        if (entered && ((x < DS_XPOS) || (x > (DS_XPOS + DS_WIDTH))
                || (y < DS_YPOS) || (y > (DS_YPOS + DS_HEIGHT))))
        {
@@ -261,11 +402,68 @@ void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
                return;
        }
 
-       int xChar = (x - DS_XPOS) / FONT_WIDTH;
-       int yChar = (y - DS_YPOS) / FONT_HEIGHT;
-       diskSelected = ((xChar / 22) * 27) + yChar;
+       if (entered && (colStart > 0))
+       {
+               if (diskSelectorState != DSS_LSB_SHOWN)
+               {
+                       if (x < (DS_XPOS + SCROLL_HOT_WIDTH))
+                       {
+                               diskSelectorState = DSS_LSB_SHOWING;
+                               dxLeft = 8;
+                       }
+                       else
+                       {
+                               diskSelectorState = DSS_LSB_HIDING;
+                               dxLeft = -8;
+                       }
+               }
+               else
+               {
+                       if (x >= (DS_XPOS + SCROLL_HOT_WIDTH))
+                       {
+                               diskSelectorState = DSS_LSB_HIDING;
+                               dxLeft = -8;
+                       }
+               }
+       }
+
+       if (entered && ((colStart + 3) < numColumns))
+       {
+               if (diskSelectorState != DSS_RSB_SHOWN)
+               {
+                       if (x > (DS_XPOS + DS_WIDTH - SCROLL_HOT_WIDTH))
+                       {
+                               diskSelectorState = DSS_RSB_SHOWING;
+                               dxRight = -8;
+                       }
+                       else
+                       {
+                               diskSelectorState = DSS_RSB_HIDING;
+                               dxRight = 8;
+                       }
+               }
+               else
+               {
+                       if (x <= (DS_XPOS + DS_WIDTH - SCROLL_HOT_WIDTH))
+                       {
+                               diskSelectorState = DSS_RSB_HIDING;
+                               dxRight = 8;
+                       }
+               }
+       }
 
-       if ((yChar >= 27) || (diskSelected >= (int)imageList.size()))
+       // The -1 terms move the origin to the upper left corner (from 1 in, and 1
+       // down)
+       int xChar = ((x - DS_XPOS) / FONT_WIDTH) - 1;
+       int yChar = ((y - DS_YPOS) / FONT_HEIGHT) - 1;
+       diskSelected = ((xChar / 22) * 27) + yChar + (colStart * 27);
+
+       if ((yChar < 0) || (yChar >= 27)
+               || (diskSelected >= (int)fsList.size())
+               || (diskSelectorState == DSS_LSB_SHOWING)
+               || (diskSelectorState == DSS_LSB_SHOWN)
+               || (diskSelectorState == DSS_RSB_SHOWING)
+               || (diskSelectorState == DSS_RSB_SHOWN))
                diskSelected = -1;
 
        if (diskSelected != lastDiskSelected)
@@ -276,10 +474,64 @@ void DiskSelector::MouseMove(int32_t x, int32_t y, uint32_t buttons)
 }
 
 
+void DiskSelector::HandleGUIState(void)
+{
+       lsbPos += dxLeft;
+       rsbPos += dxRight;
+
+       if ((lsbPos > (SCROLL_HOT_WIDTH - 40)) && (diskSelectorState == DSS_LSB_SHOWING))
+       {
+               diskSelectorState = DSS_LSB_SHOWN;
+               lsbPos = SCROLL_HOT_WIDTH - 40;
+               dxLeft = 0;
+       }
+       else if ((lsbPos < -40) && (diskSelectorState == DSS_LSB_HIDING))
+       {
+               diskSelectorState = DSS_SHOWN;
+               lsbPos = -40;
+               dxLeft = 0;
+       }
+       else if ((rsbPos < (DS_WIDTH - SCROLL_HOT_WIDTH)) && (diskSelectorState == DSS_RSB_SHOWING))
+       {
+               diskSelectorState = DSS_RSB_SHOWN;
+               rsbPos = DS_WIDTH - SCROLL_HOT_WIDTH;
+               dxRight = 0;
+       }
+       else if ((rsbPos > DS_WIDTH) && (diskSelectorState == DSS_RSB_HIDING))
+       {
+               diskSelectorState = DSS_SHOWN;
+               rsbPos = DS_WIDTH;
+               dxRight = 0;
+       }
+
+       if (textScrollCount < 0)
+       {
+               textScrollCount += 2;
+
+               if (textScrollCount > 0)
+               {
+                       textScrollCount = 0;
+                       refresh = true;
+               }
+       }
+       else if (textScrollCount > 0)
+       {
+               textScrollCount -= 2;
+
+               if (textScrollCount < 0)
+               {
+                       textScrollCount = 0;
+                       refresh = true;
+               }
+       }
+}
+
+
 void DiskSelector::HandleSelection(SDL_Renderer * renderer)
 {
        SDL_UpdateTexture(window, NULL, windowPixels, 128 * sizeof(Uint32));
        DrawFilenames(renderer);
+       refresh = false;
 }
 
 
@@ -288,6 +540,24 @@ void DiskSelector::Render(SDL_Renderer * renderer)
        if (!(window && showWindow))
                return;
 
+       HandleGUIState();
+
+       if (((diskSelectorState != DSS_LSB_SHOWN)
+               && (diskSelectorState != DSS_RSB_SHOWN)
+               && (diskSelectorState != DSS_SHOWN))
+               || (textScrollCount != 0) || refresh)
+               HandleSelection(renderer);
+
+       // Render scroll arrows (need to figure out why no alpha!)
+       SDL_SetRenderTarget(renderer, window);
+       SDL_Rect dst2 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
+       dst2.x = lsbPos;
+       SDL_RenderCopy(renderer, scrollLeftIcon, NULL, &dst2);
+       SDL_Rect dst3 = { 0, ((DS_HEIGHT - 40) / 2), 40, 40 };
+       dst3.x = rsbPos;
+       SDL_RenderCopy(renderer, scrollRightIcon, NULL, &dst3);
+       SDL_SetRenderTarget(renderer, NULL);
+
        SDL_Rect dst = { DS_XPOS, DS_YPOS, DS_WIDTH, DS_HEIGHT };
        SDL_RenderCopy(renderer, window, NULL, &dst);
 }
index c784e218b25c0c22b4841395600dbf3292ab84b6..961e99a99fc88a35818fa3d4fd56efce95bb96c7 100644 (file)
@@ -12,6 +12,7 @@ class DiskSelector
 
                // Everything is class methods/variables
                static void Init(SDL_Renderer *);
+               static void FindDisks();
                static void FindDisks(const char *);
                static bool HasLegalExtension(const char *);
                static void DrawFilenames(SDL_Renderer *);
@@ -21,6 +22,7 @@ class DiskSelector
                static void MouseUp(int32_t, int32_t, uint32_t);
                static void MouseMove(int32_t, int32_t, uint32_t);
                static void HandleSelection(SDL_Renderer *);
+               static void HandleGUIState(void);
                static void Render(SDL_Renderer *);
 
        public:
diff --git a/src/gui/gfx/scroll-left.c b/src/gui/gfx/scroll-left.c
new file mode 100644 (file)
index 0000000..dfcd34c
--- /dev/null
@@ -0,0 +1,208 @@
+/* GIMP RGBA C-Source image dump (scroll-left.c) */
+
+static const struct {
+  unsigned int          width;
+  unsigned int          height;
+  unsigned int          bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ 
+  unsigned char         pixel_data[40 * 40 * 4 + 1];
+} scroll_left = {
+  40, 40, 4,
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\231\000\000\000\356\000\000"
+  "\000\356\000\000\000\216\000\000\000\006\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040"
+  "\000\000\000\232\000\000\000\372\000\007\001\377\000O\011\377\000L\011\377\000\001\000\377\000\000\000\217\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000"
+  "\276\026\377\000\324\031\377\000\324\031\377\000M\011\377\000\000\000\355\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040"
+  "\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000\276\026\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000M\011\377\000\000\000\355\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372"
+  "\000\007\001\377\000[\013\377\000\276\026\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\324\031\377\000\276\026\377\000X\012\377\000\001\000\377\000\000\000\217\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000"
+  "c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\372\000\000\000\220\000\000\000\006\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302"
+  "\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377"
+  "\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005"
+  "\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000"
+  "\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000"
+  "\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221"
+  "\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001"
+  "\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377"
+  "\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026"
+  "\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377"
+  "\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000"
+  "\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000"
+  "\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242"
+  "\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221"
+  "\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007"
+  "\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000[\013\377"
+  "\000\276\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\276\026"
+  "\377\000[\013\377\000\007\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000\276\026\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\276\026\377\000[\013\377"
+  "\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\232\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377"
+  "\000\005\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000[\013"
+  "\377\000\276\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\276"
+  "\026\377\000[\013\377\000\007\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000"
+  "\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031"
+  "\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\372\000\000\000\232\000"
+  "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000"
+  "\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000"
+  "\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027"
+  "\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U"
+  "\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377"
+  "\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000"
+  "\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221"
+  "\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377"
+  "\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302"
+  "\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377"
+  "\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001"
+  "\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000$\000\000\000"
+  "\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324\031\377\000\324\031\377"
+  "\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005\001\377\000\000\000\370\000\000"
+  "\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000$\000\000\000\242\000\000\000\372\000\007\001\377\000c\014\377\000\302\027\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026\377\000U\012\377\000\005"
+  "\001\377\000\000\000\370\000\000\000\221\000\000\000\036\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000c\014\377"
+  "\000\302\027\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\275\026"
+  "\377\000U\012\377\000\005\001\377\000\000\000\372\000\000\000\220\000\000\000\006\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372"
+  "\000\007\001\377\000[\013\377\000\276\026\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\324\031\377\000\276\026\377\000X\012\377\000\001\000\377\000\000\000\217\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040"
+  "\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000\276\026\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000M\011\377\000\000\000\355\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000\276\026\377\000\324"
+  "\031\377\000\324\031\377\000M\011\377\000\000\000\355\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000O\011\377\000L\011\377\000\001\000"
+  "\377\000\000\000\217\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\040\000\000\000\231\000\000\000\356\000\000\000\356\000\000\000\216\000\000\000\006\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+};
+
diff --git a/src/gui/gfx/scroll-right.c b/src/gui/gfx/scroll-right.c
new file mode 100644 (file)
index 0000000..641521b
--- /dev/null
@@ -0,0 +1,208 @@
+/* GIMP RGBA C-Source image dump (scroll-right.c) */
+
+static const struct {
+  unsigned int          width;
+  unsigned int          height;
+  unsigned int          bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ 
+  unsigned char         pixel_data[40 * 40 * 4 + 1];
+} scroll_right = {
+  40, 40, 4,
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\006\000\000\000\216\000\000\000\356\000\000\000\356\000\000\000\231\000\000\000\040\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\217\000\001\000\377\000L\011\377\000"
+  "O\011\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\355\000M\011\377\000\324\031\377\000\324\031\377\000\276\026\377"
+  "\000[\013\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\355\000M\011\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\276\026\377\000[\013\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\217\000\001\000\377\000X\012\377\000\276\026\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\276\026\377\000[\013\377\000\007\001\377\000\000\000\372\000\000\000\232"
+  "\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\006\000\000\000\220\000\000\000\372\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377"
+  "\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275"
+  "\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377"
+  "\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001"
+  "\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000"
+  "\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377"
+  "\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000"
+  "\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007"
+  "\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377"
+  "\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027"
+  "\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000"
+  "\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000"
+  "\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000"
+  "\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031"
+  "\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372"
+  "\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000"
+  "\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377"
+  "\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012"
+  "\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302"
+  "\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372"
+  "\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377"
+  "\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000"
+  "\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\036\000\000\000\221\000\000\000\370\000\007\001\377\000[\013\377\000\276\026\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\276\026\377\000[\013\377\000\007\001\377\000\000\000"
+  "\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\007\001\377\000[\013\377\000\276\026\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\276\026\377\000[\013\377"
+  "\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\040\000\000\000\232\000\000\000\372\000\005\001\377\000U\012\377\000\275\026"
+  "\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c"
+  "\014\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\007\001\377\000[\013\377\000\276\026\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\276\026\377\000[\013\377\000\007"
+  "\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040"
+  "\000\000\000\232\000\000\000\372\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000"
+  "\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221"
+  "\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242"
+  "\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001"
+  "\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377"
+  "\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027"
+  "\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377"
+  "\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000"
+  "\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000"
+  "\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221"
+  "\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242"
+  "\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001"
+  "\377\000U\012\377\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324"
+  "\031\377\000\302\027\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377"
+  "\000\275\026\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027"
+  "\377\000c\014\377\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\036\000\000\000\221\000\000\000\370\000\005\001\377\000U\012\377\000\275\026\377"
+  "\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377"
+  "\000\007\001\377\000\000\000\372\000\000\000\242\000\000\000$\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\006\000\000\000\220\000\000\000\372\000\005\001\377\000U\012\377\000\275\026\377\000\324\031\377\000"
+  "\324\031\377\000\324\031\377\000\324\031\377\000\302\027\377\000c\014\377\000\007\001\377\000"
+  "\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\217\000\001\000\377\000X\012\377\000\276\026\377\000\324\031\377\000\324\031\377\000"
+  "\324\031\377\000\324\031\377\000\276\026\377\000[\013\377\000\007\001\377\000\000\000\372\000\000\000"
+  "\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\355\000M\011\377\000\324\031\377\000\324\031\377\000\324\031\377\000\324\031"
+  "\377\000\276\026\377\000[\013\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\355\000M\011\377\000\324\031\377\000\324\031\377\000\276\026\377\000[\013\377\000"
+  "\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\217\000"
+  "\001\000\377\000L\011\377\000O\011\377\000\007\001\377\000\000\000\372\000\000\000\232\000\000\000\040\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\006\000\000\000\216\000\000\000\356\000\000\000\356"
+  "\000\000\000\231\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
+  "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
+};
+
index 3f29a204e2fa19a2256a5ef5bbb625581597de27..78d4a7471d6a456d1da84da1d84e02d604a7076c 100644 (file)
@@ -87,8 +87,6 @@ const char driveLight[(5 * 5) + 1] =
        " @@@ ";
 
 
-enum { SBS_SHOWING, SBS_HIDING, SBS_SHOWN, SBS_HIDDEN };
-
 
 SDL_Texture * GUI::overlay = NULL;
 SDL_Rect GUI::olDst;
@@ -186,8 +184,6 @@ void GUI::Init(SDL_Renderer * renderer)
        }
 
        DiskSelector::Init(renderer);
-//     DiskSelector::showWindow = true;
-
        WriteLog("GUI: Successfully initialized.\n");
 }
 
@@ -491,9 +487,7 @@ void GUI::DrawSidebarIcons(SDL_Renderer * renderer)
                stateSaveIcon, stateLoadIcon, configIcon };
 
        icons[0] = (powerOnState ? powerOnIcon : powerOffIcon);
-
-       SDL_Rect dst;
-       dst.w = dst.h = 40, dst.x = 24, dst.y = 2 + 7;
+       SDL_Rect dst = { 24, 2 + 7, 40, 40 };
 
        for(int i=0; i<7; i++)
        {
index f79011a0a69a349a86e600308367c0c0137ad14e..625b20c9ee0e536b54a5fb6d62444704e7ec0ecb 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <SDL2/SDL.h>
 
+enum { SBS_SHOWING, SBS_HIDING, SBS_SHOWN, SBS_HIDDEN };
+
 class GUI
 {
        public:
index 5019b9de05b7169f0b004f861d44cac700170ea5..8a5b36f8547b3297b6967097a13b121665e94f31 100644 (file)
@@ -131,6 +131,7 @@ uint8_t ReadButton1(uint16_t);
 uint8_t ReadPaddle0(uint16_t);
 uint8_t ReadIOUDIS(uint16_t);
 uint8_t ReadDHIRES(uint16_t);
+uint8_t ReadFloatingBus(uint16_t);
 //uint8_t SwitchR(uint16_t);
 //void SwitchW(uint16_t, uint8_t);
 
@@ -168,6 +169,14 @@ AddressMap memoryMap[] = {
        { 0xC01D, 0xC01D, AM_READ_WRITE, 0, 0, ReadHIRES, WriteKeyStrobe },
        { 0xC01E, 0xC01E, AM_READ_WRITE, 0, 0, ReadALTCHARSET, WriteKeyStrobe },
        { 0xC01F, 0xC01F, AM_READ_WRITE, 0, 0, Read80COL, WriteKeyStrobe },
+       // $C020 is "Cassette Out (RO)"
+       { 0xC020, 0xC02F, AM_READ, 0, 0, ReadFloatingBus, 0 },
+       // May have to put a "floating bus" read there... :-/
+       // Apparently, video RAM is put on 'non-responding address'. So will
+       // need to time those out.
+       // So... $C020-$C08F, when read, return video data.
+       // $C090-$C7FF do also, as long as the slot the range refers to is empty
+       // and last and least is $CFFF, which is the Expansion ROM disable.
        { 0xC030, 0xC03F, AM_READ_WRITE, 0, 0, ReadSpeaker, WriteSpeaker },
        { 0xC050, 0xC051, AM_READ_WRITE, 0, 0, SwitchTEXTR, SwitchTEXTW },
        { 0xC052, 0xC053, AM_READ_WRITE, 0, 0, SwitchMIXEDR, SwitchMIXEDW },
@@ -887,3 +896,46 @@ uint8_t ReadDHIRES(uint16_t)
 }
 
 
+// Whenever a read is done to a MMIO location that is unconnected to anything,
+// it actually sees the RAM access done by the video generation hardware. Some
+// programs exploit this, so we emulate it here.
+
+// N.B.: frameCycles will be off by the true amount because this only increments
+//       by the amount of a speaker cycle, not the cycle count when the access
+//       happens... !!! FIX !!!
+uint8_t ReadFloatingBus(uint16_t)
+{
+       // Get the currently elapsed cycle count for this frame
+       uint32_t frameCycles = mainCPU.clock - frameCycleStart;
+
+       // Make counters out of the cycle count. There are 65 cycles per line.
+       uint32_t numLines = frameCycles / 65;
+       uint32_t numHTicks = frameCycles - (numLines * 65);
+
+       // Convert these to H/V counters
+       uint32_t hcount = numHTicks - 1;
+
+       // HC sees zero twice:
+       if (hcount == 0xFFFFFFFF)
+               hcount = 0;
+
+       uint32_t vcount = numLines + 0xFA;
+
+       // Now do the address calculations
+       uint32_t sum = 0xD + ((hcount & 0x38) >> 3)
+               + (((vcount & 0xC0) >> 6) | ((vcount & 0xC0) >> 4));
+       uint32_t address = ((vcount & 0x38) << 4) | ((sum & 0x0F) << 3) | (hcount & 0x07);
+
+       // Add in particulars for the gfx mode we're in...
+       if (textMode || (!textMode && !hiRes))
+               address |= (!(!store80Mode && displayPage2) ? 0x400 : 0)
+                       | (!store80Mode && displayPage2 ? 0x800 : 0);
+       else
+               address |= (!(!store80Mode && displayPage2) ? 0x2000: 0)
+                       | (!store80Mode && displayPage2 ? 0x4000 : 0)
+                       | ((vcount & 0x07) << 10);
+
+       // The address so read is *always* in main RAM, not alt RAM
+       return ram[address];
+}
+
index 10e8b8141b36ee2e553cfb76e11ec242c7d99513..a68956788fa118e84150efcaf95477809230ba1d 100644 (file)
 
 #include "sound.h"
 
-#include <string.h>                                                            // For memset, memcpy
+#include <string.h>                    // For memset, memcpy
 #include <SDL2/SDL.h>
 #include "log.h"
 
 // Useful defines
 
 //#define DEBUG
-//#define WRITE_OUT_WAVE
 
-//#define SAMPLE_RATE                  (44100.0)
 #define SAMPLE_RATE                    (48000.0)
 #define SAMPLES_PER_FRAME      (SAMPLE_RATE / 60.0)
 #define CYCLES_PER_SAMPLE      (1024000.0 / SAMPLE_RATE)
-//#define SOUND_BUFFER_SIZE    (8192)
 // 32K ought to be enough for anybody
 #define SOUND_BUFFER_SIZE      (32768)
 
@@ -56,11 +53,8 @@ static SDL_mutex * mutex = NULL;
 static SDL_mutex * mutex2 = NULL;
 static int16_t sample;
 static uint8_t ampPtr = 12;                                            // Start with -2047 - +2047
-static int16_t amplitude[17] = { 0, 1, 2, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047,
-       4095, 8191, 16383, 32767 };
-#ifdef WRITE_OUT_WAVE
-static FILE * fp = NULL;
-#endif
+static int16_t amplitude[17] = { 0, 1, 2, 3, 7, 15, 31, 63, 127, 255,
+       511, 1023, 2047, 4095, 8191, 16383, 32767 };
 
 // Private function prototypes
 
@@ -72,10 +66,6 @@ static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
 //
 void SoundInit(void)
 {
-#if 0
-// To weed out problems for now...
-return;
-#endif
        SDL_zero(desired);
        desired.freq = SAMPLE_RATE;                                     // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
        desired.format = AUDIO_S16SYS;                          // This uses the native endian (for portability)...
@@ -101,10 +91,6 @@ return;
        SDL_PauseAudioDevice(device, 0);                        // Start playback!
        soundInitialized = true;
        WriteLog("Sound: Successfully initialized.\n");
-
-#ifdef WRITE_OUT_WAVE
-       fp = fopen("./apple2.wav", "wb");
-#endif
 }
 
 
@@ -121,10 +107,6 @@ void SoundDone(void)
                SDL_DestroyMutex(mutex);
                SDL_DestroyMutex(mutex2);
                WriteLog("Sound: Done.\n");
-
-#ifdef WRITE_OUT_WAVE
-               fclose(fp);
-#endif
        }
 }
 
@@ -201,7 +183,7 @@ static void SDLSoundCallback(void * /*userdata*/, Uint8 * buffer8, int length8)
 }
 
 
-// This is called by the main CPU thread every ~21.333 cycles.
+// This is called by the main CPU thread every ~21.666 cycles.
 void WriteSampleToBuffer(void)
 {
 //WriteLog("WriteSampleToBuffer(): SDL_mutexP(mutex2)\n");
index 9b71d46260c9d8119d83b7b5e137cfe9a27b2b0f..95c7885d7ca0c16cd599c8bb45da5a8d94a4b45d 100644 (file)
 
 struct V65C02REGS
 {
-       uint16_t pc;                                            // 65C02 PC register
+       uint16_t pc;                                    // 65C02 PC register
        uint8_t cc;                                             // 65C02 Condition Code register
        uint8_t sp;                                             // 65C02 System stack pointer (bound to $01xx)
        uint8_t a;                                              // 65C02 A register
        uint8_t x;                                              // 65C02 X index register
        uint8_t y;                                              // 65C02 Y register
 //     uint32_t clock;                                 // 65C02 clock (@ 1 MHz, wraps at 71.5 minutes)
-       uint64_t clock;                                 // 65C02 clock (@ 1 MHz, wraps at 570842 years)
-       uint8_t (* RdMem)(uint16_t);            // Address of BYTE read routine
+       uint64_t clock;                                 // 65C02 clock (@ 1 MHz, wraps at 570,842 years)
+       uint8_t (* RdMem)(uint16_t);    // Address of BYTE read routine
        void (* WrMem)(uint16_t, uint8_t);      // Address of BYTE write routine
        uint16_t cpuFlags;                              // v65C02 IRQ/RESET flags
        uint64_t overflow;                              // # of cycles we went over last time through
@@ -51,7 +51,7 @@ extern bool dumpDis;
 
 // Function prototypes
 
-void Execute65C02(V65C02REGS *, uint32_t);     // Function to execute 65C02 instructions
-uint64_t GetCurrentV65C02Clock(void);                          // Get the clock of the currently executing CPU
+void Execute65C02(V65C02REGS *, uint32_t);     // Function to execute 65C02 instructions
+uint64_t GetCurrentV65C02Clock(void);          // Get the clock of the currently executing CPU
 
 #endif // __V65C02_H__
index 444b7e54620ab19065e55d9fccd3daa463017a4d..7a28cde86d5563e6c9313ec56f68501df5fde16e 100644 (file)
@@ -494,20 +494,12 @@ static void Render80ColumnTextLine(uint8_t line)
 
        for(int x=0; x<80; x++)
        {
-#if 0
-// This is wrong; it should grab from the alt bank if Page2 is set, not main RAM @ $0
-               uint8_t chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x];
-
-               if (x > 39)
-                       chr = ram2[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x - 40];
-#else
                uint8_t chr;
 
                if (x & 0x01)
                        chr = ram[lineAddrLoRes[line] + (x >> 1)];
                else
                        chr = ram2[lineAddrLoRes[line] + (x >> 1)];
-#endif
 
                // Render character at (x, y)
 
@@ -732,6 +724,169 @@ fb fb fb -> 15 [1111] -> 15               WHITE
 }
 
 
+//
+// Render the Double Lo Res screen (HIRES off, DHIRES on)
+//
+static void RenderDLoRes(void)
+{
+// NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!!
+//       Also, we could set up three different Render functions depending on
+//       which render type was set and call it with a function pointer. Would be
+//       faster then the nested ifs we have now.
+/*
+Note that these colors correspond to the bit patterns generated by the numbers 0-F in order:
+Color #s correspond to the bit patterns in reverse... Interesting! [It's because
+the video generator reads the bit patters from bit 0--which makes them backwards
+from the normal POV.]
+
+00 00 00 ->  0 [0000] -> 0 (lores color #)
+3C 4D 00 ->  8 [0001] -> 8?            BROWN
+00 5D 3C ->  4 [0010] -> 4?            DARK GREEN
+3C AA 3C -> 12 [0011] -> 12?   LIGHT GREEN (GREEN)
+41 30 7D ->  2 [0100] -> 2?            DARK BLUE
+7D 7D 7D -> 10 [0101] -> 10?   LIGHT GRAY (Grays are identical)
+41 8E BA ->  6 [0110] -> 6?            MEDIUM BLUE (BLUE)
+7D DB BA -> 14 [0111] -> 14?   AQUAMARINE (AQUA)
+7D 20 41 ->  1 [1000] -> 1?            DEEP RED (MAGENTA)
+BA 6D 41 ->  9 [1001] -> 9?            ORANGE
+7D 7D 7D ->  5 [1010] -> 5?            DARK GRAY (Grays are identical)
+BA CB 7D -> 13 [1011] -> 13?   YELLOW
+BE 51 BE ->  3 [1100] -> 3             PURPLE (VIOLET)
+FB 9E BE -> 11 [1101] -> 11?   PINK
+BE AE FB ->  7 [1110] -> 7?            LIGHT BLUE (CYAN)
+FB FB FB -> 15 [1111] -> 15            WHITE
+*/
+       uint8_t mirrorNybble[16] = { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
+       // Rotated one bit right (in the nybble)--right instead of left because
+       // these are backwards after all :-P
+       uint8_t mirrorNybble2[16] = { 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 };
+       uint32_t pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61);
+
+       for(uint16_t y=0; y<24; y++)
+       {
+               // Do top half of double lores screen bytes...
+
+               uint32_t previous3Bits = 0;
+
+               for(uint16_t x=0; x<40; x+=2)
+               {
+                       uint8_t scrByte3 = ram2[lineAddrLoRes[y] + x + 0] & 0x0F;
+                       uint8_t scrByte4 = ram2[lineAddrLoRes[y] + x + 1] & 0x0F;
+                       uint8_t scrByte1 = ram[lineAddrLoRes[y] + x + 0] & 0x0F;
+                       uint8_t scrByte2 = ram[lineAddrLoRes[y] + x + 1] & 0x0F;
+                       scrByte1 = mirrorNybble[scrByte1];
+                       scrByte2 = mirrorNybble[scrByte2];
+                       scrByte3 = mirrorNybble2[scrByte3];
+                       scrByte4 = mirrorNybble2[scrByte4];
+                       // This is just a guess, but it'll have to do for now...
+                       uint32_t pixels = previous3Bits | (scrByte3 << 24)
+                               | (scrByte3 << 20) | (scrByte1 << 16)
+                               | ((scrByte1 & 0x0C) << 12) | ((scrByte4 & 0x03) << 12)
+                               | (scrByte4 << 8) | (scrByte2 << 4) | scrByte2;
+
+                       // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
+                       // 0ppp 1111 1111 1111 11|11 1111 1111 1111
+                       // 31   27   23   19   15    11   7    3  0
+
+                       if (screenType == ST_COLOR_TV)
+                       {
+                               for(uint8_t i=0; i<7; i++)
+                               {
+                                       uint8_t bitPat = (pixels & 0x7F000000) >> 24;
+                                       pixels <<= 4;
+
+                                       for(uint8_t j=0; j<4; j++)
+                                       {
+                                               uint8_t color = blurTable[bitPat][j];
+
+                                               for(uint32_t cy=0; cy<8; cy++)
+                                               {
+                                                       scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+//                                                     scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+                                               }
+                                       }
+                               }
+
+                               previous3Bits = pixels & 0x70000000;
+                       }
+                       else
+                       {
+                               for(int j=0; j<28; j++)
+                               {
+                                       for(uint32_t cy=0; cy<8; cy++)
+                                       {
+                                               scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+                                       }
+
+                                       pixels <<= 1;
+                               }
+                       }
+               }
+
+               // Now do bottom half...
+
+               previous3Bits = 0;
+
+               for(uint16_t x=0; x<40; x+=2)
+               {
+                       uint8_t scrByte3 = ram2[lineAddrLoRes[y] + x + 0] >> 4;
+                       uint8_t scrByte4 = ram2[lineAddrLoRes[y] + x + 1] >> 4;
+                       uint8_t scrByte1 = ram[lineAddrLoRes[y] + x + 0] >> 4;
+                       uint8_t scrByte2 = ram[lineAddrLoRes[y] + x + 1] >> 4;
+                       scrByte1 = mirrorNybble[scrByte1];
+                       scrByte2 = mirrorNybble[scrByte2];
+                       scrByte3 = mirrorNybble2[scrByte3];
+                       scrByte4 = mirrorNybble2[scrByte4];
+                       // This is just a guess, but it'll have to do for now...
+//                     uint32_t pixels = previous3Bits | (scrByte1 << 24) | (scrByte1 << 20) | (scrByte1 << 16)
+//                             | ((scrByte1 & 0x0C) << 12) | ((scrByte2 & 0x03) << 12)
+//                             | (scrByte2 << 8) | (scrByte2 << 4) | scrByte2;
+                       uint32_t pixels = previous3Bits | (scrByte3 << 24)
+                               | (scrByte3 << 20) | (scrByte1 << 16)
+                               | ((scrByte1 & 0x0C) << 12) | ((scrByte4 & 0x03) << 12)
+                               | (scrByte4 << 8) | (scrByte2 << 4) | scrByte2;
+
+                       // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF
+                       // 0ppp 1111 1111 1111 11|11 1111 1111 1111
+                       // 31   27   23   19   15    11   7    3  0
+
+                       if (screenType == ST_COLOR_TV)
+                       {
+                               for(uint8_t i=0; i<7; i++)
+                               {
+                                       uint8_t bitPat = (pixels & 0x7F000000) >> 24;
+                                       pixels <<= 4;
+
+                                       for(uint8_t j=0; j<4; j++)
+                                       {
+                                               uint8_t color = blurTable[bitPat][j];
+
+                                               for(uint32_t cy=8; cy<16; cy++)
+                                               {
+                                                       scrBuffer[((x * 14) + (i * 4) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = palette[color];
+                                               }
+                                       }
+                               }
+
+                               previous3Bits = pixels & 0x70000000;
+                       }
+                       else
+                       {
+                               for(int j=0; j<28; j++)
+                               {
+                                       for(uint32_t cy=8; cy<16; cy++)
+                                       {
+                                               scrBuffer[((x * 14) + j) + (((y * 16) + cy) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000);
+                                       }
+
+                                       pixels <<= 1;
+                               }
+                       }
+               }
+       }
+}
+
+
 static void RenderHiRes(uint16_t toLine/*= 192*/)
 {
 //printf("RenderHiRes to line %u\n", toLine);
@@ -912,7 +1067,12 @@ void RenderVideoFrame(void)
                        else
                        {
                                if (dhires)
-                                       RenderDHiRes();
+                               {
+                                       if (hiRes)
+                                               RenderDHiRes();
+                                       else
+                                               RenderDLoRes();
+                               }
                                else if (hiRes)
                                        RenderHiRes();
                                else
@@ -946,6 +1106,7 @@ bool InitVideo(void)
 
 //     int retVal = SDL_CreateWindowAndRenderer(VIRTUAL_SCREEN_WIDTH * 2, VIRTUAL_SCREEN_HEIGHT * 2, SDL_WINDOW_OPENGL, &sdlWindow, &sdlRenderer);
        int retVal = SDL_CreateWindowAndRenderer(VIRTUAL_SCREEN_WIDTH * 2, VIRTUAL_SCREEN_HEIGHT * 2, 0, &sdlWindow, &sdlRenderer);
+//     int retVal = SDL_CreateWindowAndRenderer(VIRTUAL_SCREEN_WIDTH * 1, VIRTUAL_SCREEN_HEIGHT * 1, 0, &sdlWindow, &sdlRenderer);
 
        if (retVal != 0)
        {