2020-07-11 23:43:00 +00:00
# include <string.h>
2018-02-07 15:20:26 +00:00
# include "globals.h"
# include "bios.h"
# include "applevm.h"
# include "physicalkeyboard.h"
# include "physicaldisplay.h"
# include "cpu.h"
2021-01-09 12:14:14 +00:00
# include "appledisplay.h"
2018-02-07 15:20:26 +00:00
2020-07-07 01:31:37 +00:00
# ifdef TEENSYDUINO
2020-07-08 21:44:25 +00:00
# include <Bounce2.h>
2020-07-07 01:31:37 +00:00
# include "teensy-paddles.h"
2020-07-08 21:44:25 +00:00
extern Bounce resetButtonDebouncer ;
2020-07-15 00:43:41 +00:00
extern void runDebouncer ( ) ;
2020-07-07 01:31:37 +00:00
# endif
2018-02-07 15:20:26 +00:00
2020-12-28 19:23:47 +00:00
// using EXTMEM to cache all the filenames in a directory
2020-07-11 11:39:56 +00:00
# ifndef TEENSYDUINO
# define EXTMEM
# endif
struct _cacheEntry {
char fn [ BIOS_MAXPATH ] ;
} ;
# define BIOSCACHESIZE 1024 // hope that's enough files?
EXTMEM char cachedPath [ BIOS_MAXPATH ] = { 0 } ;
EXTMEM char cachedFilter [ BIOS_MAXPATH ] = { 0 } ;
EXTMEM struct _cacheEntry biosCache [ BIOSCACHESIZE ] ;
uint16_t numCacheEntries = 0 ;
2020-12-28 19:23:47 +00:00
// When selecting files...
char fileFilter [ 16 ] ; // FIXME length & Strcpy -> strncpy
uint16_t fileSelectionFor ; // define what the returned name is for
2021-01-09 12:14:14 +00:00
# define LINEHEIGHT 10
2021-01-09 15:48:15 +00:00
# define MENUINDENT 10
# define MAXFILESPERPAGE BIOS_MAXFILES
# define FILEMENUSTARTAT (LINEHEIGHT+1)
2021-01-09 12:14:14 +00:00
2020-12-28 19:23:47 +00:00
// menu screen enums
enum {
BIOS_AIIE = 0 ,
BIOS_VM = 1 ,
BIOS_HARDWARE = 2 ,
BIOS_DISKS = 3 ,
BIOS_ABOUT = 4 ,
BIOS_PADDLES = 5 ,
BIOS_SELECTFILE = 6 ,
BIOS_DONE = 99 ,
} ;
2020-07-11 11:39:56 +00:00
2018-02-07 15:20:26 +00:00
enum {
ACT_EXIT = 1 ,
ACT_RESET = 2 ,
2021-01-09 00:41:12 +00:00
ACT_REBOOT = 3 ,
ACT_REBOOTANDEJECT = 4 ,
ACT_MONITOR = 5 ,
ACT_DISPLAYTYPE = 6 ,
2021-01-19 23:40:13 +00:00
ACT_LUMINANCEUP = 7 ,
ACT_LUMINANCEDOWN = 8 ,
ACT_DEBUG = 9 ,
ACT_DISK1 = 10 ,
ACT_DISK2 = 11 ,
ACT_HD1 = 12 ,
ACT_HD2 = 13 ,
ACT_VOLPLUS = 14 ,
ACT_VOLMINUS = 15 ,
ACT_SUSPEND = 16 ,
ACT_RESTORE = 17 ,
ACT_PADX_INV = 18 ,
ACT_PADY_INV = 19 ,
ACT_PADDLES = 20 ,
ACT_SPEED = 21 ,
ACT_ABOUT = 22 ,
2018-02-07 15:20:26 +00:00
} ;
2018-02-07 18:13:07 +00:00
# define NUM_TITLES 4
const char * menuTitles [ NUM_TITLES ] = { " Aiie " , " VM " , " Hardware " , " Disks " } ;
2018-02-18 01:44:04 +00:00
const uint8_t titleWidths [ NUM_TITLES ] = { 45 , 28 , 80 , 45 } ;
2018-02-07 18:13:07 +00:00
const uint8_t aiieActions [ ] = { ACT_ABOUT } ;
2018-02-07 15:20:26 +00:00
2021-01-09 00:41:12 +00:00
const uint8_t vmActions [ ] = { ACT_EXIT , ACT_RESET , ACT_REBOOT , ACT_REBOOTANDEJECT ,
ACT_MONITOR ,
2018-02-07 15:20:26 +00:00
ACT_DEBUG , ACT_SUSPEND , ACT_RESTORE } ;
2021-01-19 23:40:13 +00:00
const uint8_t hardwareActions [ ] = { ACT_DISPLAYTYPE , ACT_LUMINANCEUP ,
ACT_LUMINANCEDOWN , ACT_SPEED ,
2020-07-09 06:50:56 +00:00
ACT_PADX_INV , ACT_PADY_INV ,
2020-07-07 01:31:37 +00:00
ACT_PADDLES , ACT_VOLPLUS , ACT_VOLMINUS } ;
2018-02-07 15:20:26 +00:00
const uint8_t diskActions [ ] = { ACT_DISK1 , ACT_DISK2 ,
ACT_HD1 , ACT_HD2 } ;
# define CPUSPEED_HALF 0
# define CPUSPEED_FULL 1
# define CPUSPEED_DOUBLE 2
# define CPUSPEED_QUAD 3
const char * staticPathConcat ( const char * rootPath , const char * filePath )
{
static char buf [ MAXPATH ] ;
strncpy ( buf , rootPath , sizeof ( buf ) - 1 ) ;
strncat ( buf , filePath , sizeof ( buf ) - strlen ( buf ) - 1 ) ;
return buf ;
}
BIOS : : BIOS ( )
{
2020-12-28 19:23:47 +00:00
selectedMenu = BIOS_VM ;
2018-02-07 15:20:26 +00:00
selectedMenuItem = 0 ;
selectedFile = - 1 ;
for ( int8_t i = 0 ; i < BIOS_MAXFILES ; i + + ) {
// Put end terminators in place; strncpy won't copy over them
fileDirectory [ i ] [ BIOS_MAXPATH ] = ' \0 ' ;
}
}
BIOS : : ~ BIOS ( )
{
}
void BIOS : : DrawMenuBar ( )
{
uint8_t xpos = 0 ;
if ( selectedMenu < 0 ) {
selectedMenu = NUM_TITLES - 1 ;
}
selectedMenu % = NUM_TITLES ;
# define XPADDING 2
for ( int i = 0 ; i < NUM_TITLES ; i + + ) {
for ( int x = 0 ; x < titleWidths [ i ] + 2 * XPADDING ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( xpos + x , 0 , 0xFFFF ) ;
g_display - > drawPixel ( xpos + x , LINEHEIGHT , 0xFFFF ) ;
2018-02-07 15:20:26 +00:00
}
2021-01-09 15:48:15 +00:00
for ( int y = 0 ; y < = LINEHEIGHT ; y + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( xpos , y , 0xFFFF ) ;
g_display - > drawPixel ( xpos + titleWidths [ i ] + 2 * XPADDING , y , 0xFFFF ) ;
2018-02-07 15:20:26 +00:00
}
xpos + = XPADDING ;
g_display - > drawString ( selectedMenu = = i ? M_SELECTDISABLED : M_DISABLED ,
xpos , 2 , menuTitles [ i ] ) ;
xpos + = titleWidths [ i ] + XPADDING ;
}
}
2020-12-28 19:23:47 +00:00
bool BIOS : : loop ( )
2018-02-07 15:20:26 +00:00
{
2020-12-28 19:23:47 +00:00
static bool needsinit = true ;
if ( needsinit ) {
g_filemanager - > getRootPath ( rootPath , sizeof ( rootPath ) ) ;
needsinit = false ;
}
2020-07-11 11:39:56 +00:00
2020-12-28 19:23:47 +00:00
static bool needsRedraw = true ;
2018-02-07 15:20:26 +00:00
2020-12-28 19:23:47 +00:00
if ( selectedMenu = = BIOS_DONE ) {
// We're returning to the bios a second time
selectedMenu = BIOS_VM ;
needsRedraw = true ;
}
2018-02-07 15:20:26 +00:00
2020-12-28 19:23:47 +00:00
# ifdef TEENSYDUINO
if ( resetButtonDebouncer . read ( ) = = LOW ) {
// wait until it's no longer pressed
while ( resetButtonDebouncer . read ( ) = = LOW )
runDebouncer ( ) ;
delay ( 100 ) ; // wait long enough for it to debounce
return BIOS_DONE ;
}
# endif
bool hitReturn = false ;
2021-01-20 03:26:50 +00:00
uint16_t rv = BIOS_DONE ;
2021-01-09 00:56:05 +00:00
bool changingMenu = false ;
2020-12-28 19:23:47 +00:00
if ( g_keyboard - > kbhit ( ) ) {
switch ( g_keyboard - > read ( ) ) {
case PK_DARR :
selectedMenuItem + + ; // modded by current action
needsRedraw = true ;
2018-02-07 15:20:26 +00:00
break ;
2020-12-28 19:23:47 +00:00
case PK_UARR :
selectedMenuItem - - ; // modded by current action
needsRedraw = true ;
2018-02-07 18:13:07 +00:00
break ;
2020-12-28 19:23:47 +00:00
case PK_RARR :
2021-01-21 02:10:56 +00:00
if ( selectedMenu < NUM_TITLES ) {
selectedMenuItem = 0 ;
selectedMenu + + ;
selectedMenu % = NUM_TITLES ;
changingMenu = true ;
needsRedraw = true ;
}
2020-12-28 19:23:47 +00:00
break ;
case PK_LARR :
2021-01-21 02:10:56 +00:00
if ( selectedMenu < NUM_TITLES ) {
selectedMenuItem = 0 ;
selectedMenu - - ;
changingMenu = true ;
if ( selectedMenu < 0 ) {
selectedMenu = NUM_TITLES - 1 ;
}
needsRedraw = true ;
2020-12-28 19:23:47 +00:00
}
break ;
case PK_RET :
hitReturn = true ;
needsRedraw = true ;
break ;
default :
break ;
}
}
2021-01-09 00:56:05 +00:00
if ( changingMenu & & selectedMenu = = BIOS_HARDWARE ) {
// Need to initialize the CPU speed from g_speed
switch ( g_speed ) {
case 1023000 :
currentCPUSpeedIndex = CPUSPEED_FULL ;
break ;
case 1023000 / 2 :
currentCPUSpeedIndex = CPUSPEED_HALF ;
break ;
case 1023000 * 2 :
currentCPUSpeedIndex = CPUSPEED_DOUBLE ;
break ;
case 1023000 * 4 :
currentCPUSpeedIndex = CPUSPEED_QUAD ;
break ;
default :
// Dunno what happened, but we'll default back to full (normal) speed
currentCPUSpeedIndex = CPUSPEED_FULL ;
g_speed = 1023000 ;
break ;
}
}
2020-12-28 19:23:47 +00:00
switch ( selectedMenu ) {
case BIOS_AIIE :
rv = AiieMenuHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_VM :
rv = VmMenuHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_HARDWARE :
rv = HardwareMenuHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_DISKS :
rv = DisksMenuHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_ABOUT :
rv = AboutScreenHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_PADDLES :
rv = PaddlesScreenHandler ( needsRedraw , hitReturn ) ;
break ;
case BIOS_SELECTFILE :
rv = SelectFileScreenHandler ( needsRedraw , hitReturn ) ;
break ;
}
if ( rv ! = selectedMenu ) {
2020-12-28 21:08:03 +00:00
selectedMenuItem = 0 ;
2020-12-28 19:23:47 +00:00
needsRedraw = true ;
selectedMenu = rv ;
}
else
needsRedraw = false ; // assume the handler drew
return ( ( selectedMenu = = BIOS_DONE ) ? false : true ) ;
}
uint16_t BIOS : : AiieMenuHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( aiieActions ) - 1 ;
selectedMenuItem % = sizeof ( aiieActions ) ;
if ( needsRedraw | | localRedraw ) {
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
DrawMenuBar ( ) ;
DrawAiieMenu ( ) ;
g_display - > flush ( ) ;
localRedraw = false ;
}
if ( performAction ) {
// there is only ACT_ABOUT
return BIOS_ABOUT ;
}
return BIOS_AIIE ;
}
uint16_t BIOS : : VmMenuHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( vmActions ) - 1 ;
selectedMenuItem % = sizeof ( vmActions ) ;
if ( needsRedraw | | localRedraw ) {
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
DrawMenuBar ( ) ;
DrawVMMenu ( ) ;
g_display - > flush ( ) ;
localRedraw = false ;
}
if ( performAction ) {
if ( isActionActive ( vmActions [ selectedMenuItem ] ) ) {
switch ( vmActions [ selectedMenuItem ] ) {
case ACT_EXIT :
return BIOS_DONE ;
case ACT_RESET :
WarmReset ( ) ;
return BIOS_DONE ;
2021-01-09 00:41:12 +00:00
case ACT_REBOOT :
// Reboot, but don't eject disks
RebootAsIs ( ) ;
return BIOS_DONE ;
case ACT_REBOOTANDEJECT :
// Power off and on, ejecting disks
2020-12-28 19:23:47 +00:00
ColdReboot ( ) ;
return BIOS_DONE ;
case ACT_MONITOR :
( ( AppleVM * ) g_vm ) - > Monitor ( ) ;
return BIOS_DONE ;
case ACT_DEBUG :
g_debugMode + + ;
g_debugMode % = 9 ; // FIXME: abstract max #
localRedraw = true ;
return BIOS_VM ;
case ACT_SUSPEND :
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
g_display - > drawString ( M_SELECTED , 80 , 100 , " Suspending VM... " ) ;
g_display - > flush ( ) ;
// CPU is already suspended, so this is safe...
( ( AppleVM * ) g_vm ) - > Suspend ( " suspend.vm " ) ;
localRedraw = true ;
return BIOS_VM ;
case ACT_RESTORE :
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
g_display - > drawString ( M_SELECTED , 80 , 100 , " Resuming VM... " ) ;
g_display - > flush ( ) ;
( ( AppleVM * ) g_vm ) - > Resume ( " suspend.vm " ) ;
return BIOS_DONE ;
}
}
}
return BIOS_VM ;
}
uint16_t BIOS : : HardwareMenuHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( hardwareActions ) - 1 ;
selectedMenuItem % = sizeof ( hardwareActions ) ;
if ( needsRedraw | | localRedraw ) {
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
DrawMenuBar ( ) ;
DrawHardwareMenu ( ) ;
g_display - > flush ( ) ;
localRedraw = false ;
}
if ( performAction ) {
if ( isActionActive ( hardwareActions [ selectedMenuItem ] ) ) {
switch ( hardwareActions [ selectedMenuItem ] ) {
case ACT_DISPLAYTYPE :
g_displayType + + ;
g_displayType % = 4 ; // FIXME: abstract max #
( ( AppleDisplay * ) g_display ) - > displayTypeChanged ( ) ;
localRedraw = true ;
2018-02-07 15:20:26 +00:00
break ;
2021-01-19 23:40:13 +00:00
case ACT_LUMINANCEUP :
if ( g_luminanceCutoff < 255 )
g_luminanceCutoff + + ;
( ( AppleDisplay * ) g_display ) - > displayTypeChanged ( ) ;
localRedraw = true ;
break ;
case ACT_LUMINANCEDOWN :
if ( g_luminanceCutoff > 0 )
g_luminanceCutoff - - ;
( ( AppleDisplay * ) g_display ) - > displayTypeChanged ( ) ;
localRedraw = true ;
break ;
2020-12-28 19:23:47 +00:00
case ACT_SPEED :
currentCPUSpeedIndex + + ;
currentCPUSpeedIndex % = 4 ;
switch ( currentCPUSpeedIndex ) {
case CPUSPEED_HALF :
g_speed = 1023000 / 2 ;
break ;
case CPUSPEED_DOUBLE :
g_speed = 1023000 * 2 ;
break ;
case CPUSPEED_QUAD :
g_speed = 1023000 * 4 ;
break ;
default :
g_speed = 1023000 ;
break ;
}
localRedraw = true ;
2018-02-07 15:20:26 +00:00
break ;
2020-12-28 19:23:47 +00:00
case ACT_PADX_INV :
g_invertPaddleX = ! g_invertPaddleX ;
# ifdef TEENSYDUINO
( ( TeensyPaddles * ) g_paddles ) - > setRev ( g_invertPaddleX , g_invertPaddleY ) ;
# endif
localRedraw = true ;
2018-02-07 15:20:26 +00:00
break ;
2020-12-28 19:23:47 +00:00
case ACT_PADY_INV :
g_invertPaddleY = ! g_invertPaddleY ;
# ifdef TEENSYDUINO
( ( TeensyPaddles * ) g_paddles ) - > setRev ( g_invertPaddleX , g_invertPaddleY ) ;
# endif
localRedraw = true ;
2018-02-07 15:20:26 +00:00
break ;
2020-12-28 19:23:47 +00:00
case ACT_PADDLES :
return BIOS_PADDLES ;
case ACT_VOLPLUS :
g_volume + + ;
if ( g_volume > 15 ) {
g_volume = 15 ;
}
localRedraw = true ;
break ;
case ACT_VOLMINUS :
g_volume - - ;
if ( g_volume < 0 ) {
g_volume = 0 ;
}
localRedraw = true ;
break ;
}
}
}
return BIOS_HARDWARE ;
}
uint16_t BIOS : : DisksMenuHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( diskActions ) - 1 ;
selectedMenuItem % = sizeof ( diskActions ) ;
if ( needsRedraw | | localRedraw ) {
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
DrawMenuBar ( ) ;
DrawDisksMenu ( ) ;
g_display - > flush ( ) ;
localRedraw = false ;
}
if ( performAction ) {
if ( isActionActive ( diskActions [ selectedMenuItem ] ) ) {
switch ( diskActions [ selectedMenuItem ] ) {
2018-02-07 15:20:26 +00:00
case ACT_DISK1 :
if ( ( ( AppleVM * ) g_vm ) - > DiskName ( 0 ) [ 0 ] ! = ' \0 ' ) {
( ( AppleVM * ) g_vm ) - > ejectDisk ( 0 ) ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
break ;
2018-02-07 15:20:26 +00:00
} else {
2020-12-28 19:23:47 +00:00
strcpy ( fileFilter , " dsk,.po,nib,woz " ) ;
fileSelectionFor = ACT_DISK1 ;
return BIOS_SELECTFILE ;
2018-02-07 15:20:26 +00:00
}
break ;
case ACT_DISK2 :
if ( ( ( AppleVM * ) g_vm ) - > DiskName ( 1 ) [ 0 ] ! = ' \0 ' ) {
( ( AppleVM * ) g_vm ) - > ejectDisk ( 1 ) ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
break ;
2018-02-07 15:20:26 +00:00
} else {
2020-12-28 19:23:47 +00:00
strcpy ( fileFilter , " dsk,.po,nib,woz " ) ;
fileSelectionFor = ACT_DISK2 ;
return BIOS_SELECTFILE ;
2018-02-07 15:20:26 +00:00
}
break ;
case ACT_HD1 :
if ( ( ( AppleVM * ) g_vm ) - > HDName ( 0 ) [ 0 ] ! = ' \0 ' ) {
( ( AppleVM * ) g_vm ) - > ejectHD ( 0 ) ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
break ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-19 13:52:58 +00:00
strcpy ( fileFilter , " img,hdv " ) ;
2020-12-28 19:23:47 +00:00
fileSelectionFor = ACT_HD1 ;
return BIOS_SELECTFILE ;
2018-02-07 15:20:26 +00:00
}
break ;
case ACT_HD2 :
if ( ( ( AppleVM * ) g_vm ) - > HDName ( 1 ) [ 0 ] ! = ' \0 ' ) {
( ( AppleVM * ) g_vm ) - > ejectHD ( 1 ) ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
break ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-20 03:56:52 +00:00
strcpy ( fileFilter , " img,hdv " ) ;
2020-12-28 19:23:47 +00:00
fileSelectionFor = ACT_HD2 ;
return BIOS_SELECTFILE ;
2018-02-07 15:20:26 +00:00
}
break ;
2020-12-28 19:23:47 +00:00
}
}
}
return BIOS_DISKS ;
} ;
2018-02-07 15:20:26 +00:00
2020-12-28 19:23:47 +00:00
uint16_t BIOS : : AboutScreenHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
selectedMenuItem = 0 ;
if ( needsRedraw | | localRedraw ) {
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
2021-01-09 17:15:12 +00:00
// Draw a black area where we're going to "boot" a fake //e for the about screen. Don't put the whole graphic around it so it's obvious it's not a //e.
for ( uint8_t y = 12 ; y < 12 + 192 ; y + + ) {
for ( uint16_t x = 20 ; x < 280 + 20 ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( x , y , 0x0000 ) ;
2021-01-09 17:15:12 +00:00
}
}
/*
2020-12-28 19:23:47 +00:00
g_display - > drawString ( M_SELECTED ,
0 ,
0 ,
" Aiie! - an Apple //e emulator " ) ;
g_display - > drawString ( M_NORMAL ,
15 , 20 ,
" (c) 2017-2020 Jorj Bauer " ) ;
g_display - > drawString ( M_NORMAL ,
15 , 38 ,
" https://github.com/JorjBauer/aiie/ " ) ;
g_display - > drawString ( M_NORMAL ,
0 ,
200 ,
" Press return " ) ;
2021-01-09 17:15:12 +00:00
*/
2020-12-28 19:23:47 +00:00
g_display - > flush ( ) ;
localRedraw = false ;
}
2021-01-09 17:15:12 +00:00
const char * str =
" "
" Aiie! "
" "
" "
" "
" "
" "
" "
" ... an Apple //e emulator "
" written by "
" Jorj Bauer <jorj@jorj.org> "
" "
" "
" "
" (c) 2017-2021 Jorj Bauer "
" "
" "
" Source code is available at "
" github.com/JorjBauer/aiie/ "
" "
" "
" "
" Press <Return>... " // intentionally short so cursor stays here
;
static uint16_t ptr = 0 ;
static bool didFinish = false ;
if ( ! didFinish ) {
// Draw the next character
bool didOne = false ;
while ( ! didOne | | ptr < 35 * 2 ) { // draw the first 2 lines in one go, no matter what
char charToDraw = str [ ptr ] ;
didOne = true ;
int xpos = ptr % 35 ;
int ypos = ( int ) ( ptr / 35 ) ;
if ( charToDraw ! = ' ' ) {
// First 2 lines have a blue background on any text; others are black
g_display - > drawCharacter ( ptr < 70 ? M_NORMAL : M_PLAIN , xpos * 8 + 20 , ypos * 8 + 12 , charToDraw ) ;
}
ptr + + ;
if ( ptr > = strlen ( str ) ) {
didFinish = true ;
} else {
if ( charToDraw = = ' ' ) {
// Just blep the spaces to the screen toot-sweet
didOne = false ;
}
}
}
} else {
// Flash the cursor until the user exits
static bool cursorOn = false ;
static bool flopTime = false ;
flopTime = ! flopTime ;
if ( flopTime ) {
cursorOn = ! cursorOn ;
}
int xpos = strlen ( str ) % 35 ;
int ypos = ( int ) ( strlen ( str ) / 35 ) ;
g_display - > drawCharacter ( M_PLAIN , xpos * 8 + 20 , ypos * 8 + 12 , cursorOn ? 127 : 32 ) ;
}
g_display - > flush ( ) ;
2020-12-28 19:23:47 +00:00
if ( performAction ) {
2021-01-09 17:15:12 +00:00
ptr = 0 ;
didFinish = false ;
2020-12-28 19:23:47 +00:00
return BIOS_AIIE ;
}
return BIOS_ABOUT ;
}
uint16_t BIOS : : PaddlesScreenHandler ( bool needsRedraw , bool performAction )
{
static bool localRedraw = true ;
selectedMenuItem = 0 ;
static uint8_t lastPaddleX = g_paddles - > paddle0 ( ) ;
static uint8_t lastPaddleY = g_paddles - > paddle1 ( ) ;
2021-01-21 03:05:50 +00:00
uint8_t paddle = g_paddles - > paddle0 ( ) ;
if ( paddle ! = lastPaddleX ) {
lastPaddleX = paddle ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
}
2021-01-21 03:05:50 +00:00
paddle = g_paddles - > paddle1 ( ) ;
if ( paddle ! = lastPaddleY ) {
lastPaddleY = paddle ;
2020-12-28 19:23:47 +00:00
localRedraw = true ;
}
if ( needsRedraw | | localRedraw ) {
char buf [ 50 ] ;
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-12-28 19:23:47 +00:00
sprintf ( buf , " Paddle X: %d " , lastPaddleX ) ;
g_display - > drawString ( M_NORMAL , 0 , 12 , buf ) ;
sprintf ( buf , " Paddle Y: %d " , lastPaddleY ) ;
g_display - > drawString ( M_NORMAL , 0 , 42 , buf ) ;
2021-01-21 03:05:50 +00:00
g_display - > drawString ( M_NORMAL , 0 , 132 , " Press return to exit " ) ;
// Draw the target for the paddle position
for ( uint16_t y = 10 ; y < = 110 ; y + + ) {
for ( uint16_t x = 160 ; x < = 260 ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( x , y , 0x0000 ) ;
g_display - > drawPixel ( x , 10 , 0xFFFF ) ;
g_display - > drawPixel ( x , 110 , 0xFFFF ) ;
2021-01-21 03:05:50 +00:00
}
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( 160 , y , 0xFFFF ) ;
g_display - > drawPixel ( 260 , y , 0xFFFF ) ;
2021-01-21 03:05:50 +00:00
}
for ( uint16_t y = 57 ; y < = 63 ; y + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( 207 , y , 0xFFFF ) ;
g_display - > drawPixel ( 213 , y , 0xFFFF ) ;
2021-01-21 03:05:50 +00:00
}
for ( uint16_t x = 207 ; x < = 213 ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( x , 57 , 0xFFFF ) ;
g_display - > drawPixel ( x , 63 , 0xFFFF ) ;
2021-01-21 03:05:50 +00:00
}
float drawX = ( ( float ) lastPaddleX / 255.0 ) * 100.0 ;
float drawY = ( ( float ) lastPaddleY / 255.0 ) * 100.0 ;
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( 160 + drawX , 10 + drawY , 0xFFFF ) ;
2021-01-21 03:05:50 +00:00
2020-12-28 19:23:47 +00:00
g_display - > flush ( ) ;
localRedraw = false ;
}
if ( performAction ) {
return BIOS_HARDWARE ;
}
return BIOS_PADDLES ;
}
2020-12-28 20:55:02 +00:00
static void insertDisk ( int forWhat , const char * path ,
const char * fileName )
{
// drawIt is false b/c we don't want to draw it immediately -- that
// would draw over the bios screen
if ( forWhat = = ACT_DISK1 | | forWhat = = ACT_DISK2 ) {
( ( AppleVM * ) g_vm ) - > insertDisk ( forWhat = = ACT_DISK1 ? 0 : 1 , staticPathConcat ( path , fileName ) , false ) ;
} else {
// must be a hard drive
( ( AppleVM * ) g_vm ) - > insertHD ( forWhat = = ACT_HD1 ? 0 : 1 , staticPathConcat ( path , fileName ) ) ;
}
}
2020-12-28 19:23:47 +00:00
uint16_t BIOS : : SelectFileScreenHandler ( bool needsRedraw , bool performAction )
{
if ( selectedMenuItem < 0 )
selectedMenuItem = BIOS_MAXFILES + 1 ;
selectedMenuItem % = BIOS_MAXFILES + 2 ;
static bool localRedraw = true ;
static int8_t page = 0 ;
static uint16_t fileCount = 0 ;
if ( needsRedraw | | localRedraw ) {
2020-12-28 20:55:02 +00:00
fileCount = DrawDiskNames ( page , selectedMenuItem , fileFilter ) ;
2020-12-28 19:23:47 +00:00
localRedraw = false ;
}
if ( performAction ) {
2020-12-28 20:55:02 +00:00
if ( selectedMenuItem = = 0 ) {
2020-12-28 19:23:47 +00:00
page - - ;
if ( page < 0 ) page = 0 ;
// else sel = BIOS_MAXFILES + 1;
localRedraw = true ;
}
2020-12-28 20:55:02 +00:00
else if ( selectedMenuItem = = BIOS_MAXFILES + 1 ) {
2021-01-23 03:09:16 +00:00
// FIXME what if there are no files on the next page? We
// shouldn't show a blank page.
2020-12-28 19:23:47 +00:00
if ( fileCount = = BIOS_MAXFILES ) { // don't let them select
// 'Next' if there were no
// files in the list or if the
// list isn't full
page + + ;
//sel = 0;
localRedraw = true ;
}
2020-12-28 20:55:02 +00:00
} else if ( strcmp ( fileDirectory [ selectedMenuItem - 1 ] , " ../ " ) = = 0 ) {
2020-12-28 19:23:47 +00:00
// Go up a directory (strip a directory name from rootPath)
stripDirectory ( ) ;
page = 0 ;
//sel = 0;
localRedraw = true ;
2020-12-28 20:55:02 +00:00
} else if ( fileDirectory [ selectedMenuItem - 1 ] [ strlen ( fileDirectory [ selectedMenuItem - 1 ] ) - 1 ] = = ' / ' ) {
2020-12-28 19:23:47 +00:00
// Descend in to the directory. FIXME: file path length?
2020-12-28 20:55:02 +00:00
strcat ( rootPath , fileDirectory [ selectedMenuItem - 1 ] ) ;
selectedMenuItem = 0 ;
2020-12-28 19:23:47 +00:00
page = 0 ;
localRedraw = true ;
} else {
2020-12-28 20:55:02 +00:00
selectedFile = selectedMenuItem - 1 ;
insertDisk ( fileSelectionFor , rootPath , fileDirectory [ selectedFile ] ) ;
2018-02-07 17:34:42 +00:00
g_display - > flush ( ) ;
2020-12-28 19:23:47 +00:00
return BIOS_DISKS ;
}
}
return BIOS_SELECTFILE ;
}
2018-02-07 15:20:26 +00:00
void BIOS : : WarmReset ( )
{
g_cpu - > Reset ( ) ;
}
2021-01-09 00:41:12 +00:00
void BIOS : : RebootAsIs ( )
{
// g_vm->Reset() will eject disks. We don't want to do that, so we need to
// grab the inserted disk names; reset the VM; then restore the disks.
2021-01-09 16:30:19 +00:00
char * disk6s1 = strdup ( ( ( AppleVM * ) g_vm ) - > DiskName ( 0 ) ? ( ( AppleVM * ) g_vm ) - > DiskName ( 0 ) : " " ) ;
char * disk6s2 = strdup ( ( ( AppleVM * ) g_vm ) - > DiskName ( 1 ) ? ( ( AppleVM * ) g_vm ) - > DiskName ( 1 ) : " " ) ;
char * hdd1 = strdup ( ( ( AppleVM * ) g_vm ) - > HDName ( 0 ) ? ( ( AppleVM * ) g_vm ) - > HDName ( 0 ) : " " ) ;
char * hdd2 = strdup ( ( ( AppleVM * ) g_vm ) - > HDName ( 1 ) ? ( ( AppleVM * ) g_vm ) - > HDName ( 1 ) : " " ) ;
2021-01-09 00:41:12 +00:00
g_vm - > Reset ( ) ;
g_cpu - > Reset ( ) ;
2021-01-09 16:30:19 +00:00
if ( disk6s1 [ 0 ] )
2021-01-09 00:41:12 +00:00
( ( AppleVM * ) g_vm ) - > insertDisk ( 0 , disk6s1 ) ;
2021-01-09 16:30:19 +00:00
if ( disk6s2 [ 0 ] )
2021-01-09 00:41:12 +00:00
( ( AppleVM * ) g_vm ) - > insertDisk ( 1 , disk6s2 ) ;
2021-01-09 16:30:19 +00:00
if ( hdd1 [ 0 ] )
2021-01-09 00:41:12 +00:00
( ( AppleVM * ) g_vm ) - > insertHD ( 0 , hdd1 ) ;
2021-01-09 16:30:19 +00:00
if ( hdd2 [ 0 ] )
2021-01-09 00:41:12 +00:00
( ( AppleVM * ) g_vm ) - > insertHD ( 2 , hdd2 ) ;
2021-01-09 16:30:19 +00:00
free ( disk6s1 ) ;
free ( disk6s2 ) ;
free ( hdd1 ) ;
free ( hdd2 ) ;
2021-01-09 00:41:12 +00:00
}
2018-02-07 15:20:26 +00:00
void BIOS : : ColdReboot ( )
{
g_vm - > Reset ( ) ;
g_cpu - > Reset ( ) ;
}
bool BIOS : : isActionActive ( int8_t action )
{
// don't return true for disk events that aren't valid
switch ( action ) {
case ACT_EXIT :
case ACT_RESET :
2021-01-09 00:41:12 +00:00
case ACT_REBOOT :
case ACT_REBOOTANDEJECT :
2018-02-07 15:20:26 +00:00
case ACT_MONITOR :
case ACT_DISPLAYTYPE :
case ACT_SPEED :
2018-02-07 18:13:07 +00:00
case ACT_ABOUT :
2018-02-07 15:20:26 +00:00
case ACT_DEBUG :
case ACT_DISK1 :
case ACT_DISK2 :
case ACT_HD1 :
case ACT_HD2 :
case ACT_SUSPEND :
case ACT_RESTORE :
2020-07-07 01:31:37 +00:00
case ACT_PADX_INV :
case ACT_PADY_INV :
case ACT_PADDLES :
2018-02-07 15:20:26 +00:00
return true ;
2021-01-19 23:40:13 +00:00
case ACT_LUMINANCEUP :
return ( g_luminanceCutoff < 255 ) ;
case ACT_LUMINANCEDOWN :
return ( g_luminanceCutoff > 0 ) ;
2018-02-07 15:20:26 +00:00
case ACT_VOLPLUS :
return ( g_volume < 15 ) ;
case ACT_VOLMINUS :
return ( g_volume > 0 ) ;
}
/* NOTREACHED */
return false ;
}
2018-02-07 18:13:07 +00:00
void BIOS : : DrawAiieMenu ( )
{
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( aiieActions ) - 1 ;
selectedMenuItem % = sizeof ( aiieActions ) ;
char buf [ 40 ] ;
for ( int i = 0 ; i < sizeof ( aiieActions ) ; i + + ) {
switch ( aiieActions [ i ] ) {
case ACT_ABOUT :
sprintf ( buf , " About... " ) ;
break ;
}
if ( isActionActive ( aiieActions [ i ] ) ) {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTED : M_NORMAL , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 18:13:07 +00:00
} else {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTDISABLED : M_DISABLED , MENUINDENT , 20 + LINEHEIGHT * i ,
2018-02-07 18:13:07 +00:00
buf ) ;
}
}
}
2018-02-07 15:20:26 +00:00
void BIOS : : DrawVMMenu ( )
{
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( vmActions ) - 1 ;
selectedMenuItem % = sizeof ( vmActions ) ;
char buf [ 40 ] ;
for ( int i = 0 ; i < sizeof ( vmActions ) ; i + + ) {
switch ( vmActions [ i ] ) {
case ACT_DEBUG :
{
const char * templateString = " Debug: %s " ;
switch ( g_debugMode ) {
case D_NONE :
sprintf ( buf , templateString , " off " ) ;
break ;
case D_SHOWFPS :
sprintf ( buf , templateString , " Show FPS " ) ;
break ;
case D_SHOWMEMFREE :
sprintf ( buf , templateString , " Show mem free " ) ;
break ;
case D_SHOWPADDLES :
sprintf ( buf , templateString , " Show paddles " ) ;
break ;
case D_SHOWPC :
sprintf ( buf , templateString , " Show PC " ) ;
break ;
case D_SHOWCYCLES :
sprintf ( buf , templateString , " Show cycles " ) ;
break ;
case D_SHOWBATTERY :
sprintf ( buf , templateString , " Show battery " ) ;
break ;
case D_SHOWTIME :
sprintf ( buf , templateString , " Show time " ) ;
break ;
2020-07-04 12:03:35 +00:00
case D_SHOWDSK :
sprintf ( buf , templateString , " Show Disk " ) ;
break ;
2018-02-07 15:20:26 +00:00
}
}
break ;
case ACT_EXIT :
strcpy ( buf , " Resume " ) ;
break ;
case ACT_RESET :
2021-01-09 00:41:12 +00:00
strcpy ( buf , " Reset (press Reset key) " ) ;
break ;
case ACT_REBOOT :
strcpy ( buf , " Reboot (reboot emulator) " ) ;
2018-02-07 15:20:26 +00:00
break ;
2021-01-09 00:41:12 +00:00
case ACT_REBOOTANDEJECT :
strcpy ( buf , " Reboot and eject disks " ) ;
2018-02-07 15:20:26 +00:00
break ;
case ACT_MONITOR :
strcpy ( buf , " Drop to Monitor " ) ;
break ;
case ACT_SUSPEND :
strcpy ( buf , " Suspend VM " ) ;
break ;
case ACT_RESTORE :
strcpy ( buf , " Restore VM " ) ;
break ;
}
if ( isActionActive ( vmActions [ i ] ) ) {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTED : M_NORMAL , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTDISABLED : M_DISABLED , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
}
}
}
void BIOS : : DrawHardwareMenu ( )
{
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( hardwareActions ) - 1 ;
selectedMenuItem % = sizeof ( hardwareActions ) ;
char buf [ 40 ] ;
for ( int i = 0 ; i < sizeof ( hardwareActions ) ; i + + ) {
switch ( hardwareActions [ i ] ) {
case ACT_DISPLAYTYPE :
{
const char * templateString = " Display: %s " ;
switch ( g_displayType ) {
case m_blackAndWhite :
sprintf ( buf , templateString , " B&W " ) ;
break ;
case m_monochrome :
sprintf ( buf , templateString , " Mono " ) ;
break ;
case m_ntsclike :
sprintf ( buf , templateString , " NTSC-like " ) ;
break ;
case m_perfectcolor :
sprintf ( buf , templateString , " RGB " ) ;
break ;
}
}
break ;
2021-01-19 23:40:13 +00:00
case ACT_LUMINANCEUP :
sprintf ( buf , " Luminance+: %d " , g_luminanceCutoff ) ;
break ;
case ACT_LUMINANCEDOWN :
sprintf ( buf , " Luminance-: %d " , g_luminanceCutoff ) ;
break ;
2018-02-07 15:20:26 +00:00
case ACT_SPEED :
{
const char * templateString = " CPU Speed: %s " ;
switch ( currentCPUSpeedIndex ) {
case CPUSPEED_HALF :
sprintf ( buf , templateString , " Half [511.5 kHz] " ) ;
break ;
case CPUSPEED_DOUBLE :
sprintf ( buf , templateString , " Double (2.046 MHz) " ) ;
break ;
case CPUSPEED_QUAD :
sprintf ( buf , templateString , " Quad (4.092 MHz) " ) ;
break ;
default :
sprintf ( buf , templateString , " Normal (1.023 MHz) " ) ;
break ;
}
}
break ;
2020-07-07 01:31:37 +00:00
case ACT_PADX_INV :
if ( g_invertPaddleX )
strcpy ( buf , " Paddle X inverted " ) ;
else
strcpy ( buf , " Paddle X normal " ) ;
break ;
case ACT_PADY_INV :
if ( g_invertPaddleY )
strcpy ( buf , " Paddle Y inverted " ) ;
else
strcpy ( buf , " Paddle Y normal " ) ;
break ;
case ACT_PADDLES :
strcpy ( buf , " Configure paddles " ) ;
break ;
2018-02-07 15:20:26 +00:00
case ACT_VOLPLUS :
strcpy ( buf , " Volume + " ) ;
break ;
case ACT_VOLMINUS :
strcpy ( buf , " Volume - " ) ;
break ;
}
if ( isActionActive ( hardwareActions [ i ] ) ) {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTED : M_NORMAL , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTDISABLED : M_DISABLED , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
}
}
// draw the volume bar
uint16_t volCutoff = 300.0 * ( float ) ( ( float ) g_volume / 15.0 ) ;
for ( uint8_t y = 234 ; y < = 235 ; y + + ) {
for ( uint16_t x = 0 ; x < 300 ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( x , y , x < = volCutoff ? 0xFFFF : 0x0010 ) ;
2018-02-07 15:20:26 +00:00
}
}
}
void BIOS : : DrawDisksMenu ( )
{
if ( selectedMenuItem < 0 )
selectedMenuItem = sizeof ( diskActions ) - 1 ;
selectedMenuItem % = sizeof ( diskActions ) ;
char buf [ 80 ] ;
for ( int i = 0 ; i < sizeof ( diskActions ) ; i + + ) {
switch ( diskActions [ i ] ) {
case ACT_DISK1 :
case ACT_DISK2 :
{
const char * insertedDiskName = ( ( AppleVM * ) g_vm ) - > DiskName ( diskActions [ i ] = = ACT_DISK2 ? 1 : 0 ) ;
// Get the name of the file; strip off the directory
const char * endPtr = & insertedDiskName [ strlen ( insertedDiskName ) - 1 ] ;
while ( endPtr ! = insertedDiskName & &
* endPtr ! = ' / ' ) {
endPtr - - ;
}
if ( * endPtr = = ' / ' ) {
endPtr + + ;
}
if ( insertedDiskName [ 0 ] ) {
snprintf ( buf , sizeof ( buf ) , " Eject Disk %d [%s] " , diskActions [ i ] = = ACT_DISK2 ? 2 : 1 , endPtr ) ;
} else {
sprintf ( buf , " Insert Disk %d " , diskActions [ i ] = = ACT_DISK2 ? 2 : 1 ) ;
}
}
break ;
case ACT_HD1 :
case ACT_HD2 :
{
const char * insertedDiskName = ( ( AppleVM * ) g_vm ) - > HDName ( diskActions [ i ] = = ACT_HD2 ? 1 : 0 ) ;
// Get the name of the file; strip off the directory
const char * endPtr = & insertedDiskName [ strlen ( insertedDiskName ) - 1 ] ;
while ( endPtr ! = insertedDiskName & &
* endPtr ! = ' / ' ) {
endPtr - - ;
}
if ( * endPtr = = ' / ' ) {
endPtr + + ;
}
if ( insertedDiskName [ 0 ] ) {
snprintf ( buf , sizeof ( buf ) , " Remove HD %d [%s] " , diskActions [ i ] = = ACT_HD2 ? 2 : 1 , endPtr ) ;
} else {
sprintf ( buf , " Connect HD %d " , diskActions [ i ] = = ACT_HD2 ? 2 : 1 ) ;
}
}
break ;
}
if ( isActionActive ( diskActions [ i ] ) ) {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTED : M_NORMAL , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( selectedMenuItem = = i ? M_SELECTDISABLED : M_DISABLED , MENUINDENT , 20 + LINEHEIGHT * i , buf ) ;
2018-02-07 15:20:26 +00:00
}
}
}
void BIOS : : DrawCurrentMenu ( )
{
switch ( selectedMenu ) {
2018-02-07 18:13:07 +00:00
case 0 : // Aiie
DrawAiieMenu ( ) ;
break ;
case 1 : // VM
2018-02-07 15:20:26 +00:00
DrawVMMenu ( ) ;
break ;
2018-02-07 18:13:07 +00:00
case 2 : // Hardware
2018-02-07 15:20:26 +00:00
DrawHardwareMenu ( ) ;
break ;
2018-02-07 18:13:07 +00:00
case 3 : // Disks
2018-02-07 15:20:26 +00:00
DrawDisksMenu ( ) ;
break ;
}
}
void BIOS : : stripDirectory ( )
{
rootPath [ strlen ( rootPath ) - 1 ] = ' \0 ' ; // remove the last character
while ( rootPath [ 0 ] & & rootPath [ strlen ( rootPath ) - 1 ] ! = ' / ' ) {
rootPath [ strlen ( rootPath ) - 1 ] = ' \0 ' ; // remove the last character again
}
// We're either at the previous directory, or we've nulled out the whole thing.
if ( rootPath [ 0 ] = = ' \0 ' ) {
// Never go beyond this
strcpy ( rootPath , " / " ) ;
}
}
2020-07-11 11:39:56 +00:00
uint16_t BIOS : : DrawDiskNames ( uint8_t page , int8_t selection , const char * filter )
2018-02-07 15:20:26 +00:00
{
2020-07-11 11:39:56 +00:00
uint16_t fileCount = GatherFilenames ( page , filter ) ;
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2021-01-09 15:48:15 +00:00
const char * title = " BIOS Configuration - pick disk image " ;
g_display - > drawString ( M_NORMAL , 0 , 0 , title ) ;
for ( int x = 0 ; x < strlen ( title ) * 8 ; x + + ) {
2022-01-31 01:26:12 +00:00
g_display - > drawPixel ( x , LINEHEIGHT - 1 , 0xFFFF ) ;
2018-02-07 15:20:26 +00:00
}
2021-01-09 15:48:15 +00:00
uint8_t vpos = FILEMENUSTARTAT ;
g_display - > drawString ( page = = 0 ? ( selection = = 0 ? M_SELECTDISABLED : M_DISABLED ) :
( selection = = 0 ? M_SELECTED : M_NORMAL ) ,
MENUINDENT , vpos , " <Prev> " ) ;
vpos + = LINEHEIGHT * 1.5 ;
bool endsHere = false ;
2018-02-07 15:20:26 +00:00
uint8_t i ;
2021-01-09 15:48:15 +00:00
2018-02-07 15:20:26 +00:00
for ( i = 0 ; i < BIOS_MAXFILES ; i + + ) {
2021-01-09 15:48:15 +00:00
// If the file name is less than 39 characters, it fits on one
// line; but if it's longer, we need to use two lines.
const char * name = " - " ;
2018-02-07 15:20:26 +00:00
if ( i < fileCount ) {
2021-01-09 15:48:15 +00:00
name = fileDirectory [ i ] ;
2018-02-07 15:20:26 +00:00
}
2021-01-09 15:48:15 +00:00
g_display - > drawString (
( i < fileCount ) ? ( ( i = = selection - 1 ) ? M_SELECTED : M_NORMAL ) :
( i = = selection - 1 ) ? M_SELECTDISABLED : M_DISABLED ,
MENUINDENT , vpos ,
name ) ;
vpos + = LINEHEIGHT ;
2021-01-23 03:09:16 +00:00
if ( strlen ( name ) > 39 ) {
2021-01-09 15:48:15 +00:00
// Break the string at 39 characters and start drawing the second line indented more
char restOfString [ BIOS_MAXPATH - 39 + 1 ] ;
strcpy ( restOfString , ( char * ) & name [ 39 ] ) ;
g_display - > drawString (
( i < fileCount ) ? ( ( i = = selection - 1 ) ? M_SELECTED : M_NORMAL ) :
( i = = selection - 1 ) ? M_SELECTDISABLED : M_DISABLED ,
MENUINDENT + 15 ,
vpos ,
restOfString ) ;
vpos + = LINEHEIGHT ;
}
2021-01-23 03:09:16 +00:00
if ( i + 1 > = fileCount ) {
2021-01-09 15:48:15 +00:00
endsHere = true ;
2021-01-23 03:09:16 +00:00
}
2018-02-07 15:20:26 +00:00
}
2021-01-09 15:48:15 +00:00
vpos + = LINEHEIGHT / 2 ;
if ( endsHere | | fileCount < BIOS_MAXFILES ) {
g_display - > drawString ( ( i + 1 = = selection ) ? M_SELECTDISABLED : M_DISABLED ,
MENUINDENT , vpos ,
" <Next> " ) ;
2018-02-07 15:20:26 +00:00
} else {
2021-01-09 15:48:15 +00:00
g_display - > drawString ( i + 1 = = selection ? M_SELECTED : M_NORMAL ,
MENUINDENT , vpos ,
" <Next> " ) ;
2018-02-07 15:20:26 +00:00
}
g_display - > flush ( ) ;
2020-07-11 11:39:56 +00:00
return fileCount ;
2018-02-07 15:20:26 +00:00
}
2020-07-11 23:43:00 +00:00
// Read a directory, cache all the entries
2020-07-11 11:39:56 +00:00
uint16_t BIOS : : cacheAllEntries ( const char * filter )
{
// If we've already cached this directory, then just return it
if ( numCacheEntries & & ! strcmp ( cachedPath , rootPath ) & & ! strcmp ( cachedFilter , filter ) )
return numCacheEntries ;
// Otherwise flush the cache and start over
numCacheEntries = 0 ;
strcpy ( cachedPath , rootPath ) ;
strcpy ( cachedFilter , filter ) ;
// This could be a lengthy process, so...
2021-01-09 12:14:14 +00:00
g_display - > clrScr ( c_darkblue ) ;
2020-07-11 11:39:56 +00:00
g_display - > drawString ( M_SELECTED ,
0 ,
0 ,
" Loading... " ) ;
g_display - > flush ( ) ;
// read all the entries we can find
int16_t idx = 0 ;
while ( 1 ) {
struct _cacheEntry * ce = & biosCache [ numCacheEntries ] ;
idx = g_filemanager - > readDir ( rootPath , filter , ce - > fn , idx , BIOS_MAXPATH ) ;
if ( idx = = - 1 ) {
2021-01-20 03:56:52 +00:00
// add a terminating entry
biosCache [ numCacheEntries ] . fn [ 0 ] = ' \0 ' ;
2020-07-11 11:39:56 +00:00
return numCacheEntries ;
}
idx + + ;
numCacheEntries + + ;
2021-01-20 03:56:52 +00:00
if ( numCacheEntries > = BIOSCACHESIZE - 2 ) {
// need a terminating entry
biosCache [ BIOSCACHESIZE - 1 ] . fn [ 0 ] = ' \0 ' ;
2020-07-11 11:39:56 +00:00
return numCacheEntries ;
}
}
/* NOTREACHED */
}
2018-02-07 15:20:26 +00:00
2020-07-11 23:43:00 +00:00
void BIOS : : swapCacheEntries ( int a , int b )
{
struct _cacheEntry tmpEntry ;
strcpy ( tmpEntry . fn , biosCache [ a ] . fn ) ;
strcpy ( biosCache [ a ] . fn , biosCache [ b ] . fn ) ;
strcpy ( biosCache [ b ] . fn , tmpEntry . fn ) ;
}
// Take all the entries in the cache and sort htem
void BIOS : : sortCachedEntries ( )
{
if ( numCacheEntries < = 1 )
return ;
bool changedAnything = true ;
while ( changedAnything ) {
changedAnything = false ;
for ( int i = 0 ; i < numCacheEntries - 1 ; i + + ) {
if ( strcmp ( biosCache [ i ] . fn , biosCache [ i + 1 ] . fn ) > 0 ) {
swapCacheEntries ( i , i + 1 ) ;
changedAnything = true ;
}
}
}
}
2020-07-11 11:39:56 +00:00
uint16_t BIOS : : GatherFilenames ( uint8_t pageOffset , const char * filter )
2018-02-07 15:20:26 +00:00
{
2021-01-09 15:48:15 +00:00
uint8_t startNum = MAXFILESPERPAGE * pageOffset ;
2018-02-07 15:20:26 +00:00
uint8_t count = 0 ; // number we're including in our listing
2020-07-11 11:39:56 +00:00
uint16_t numEntriesTotal = cacheAllEntries ( filter ) ;
2020-07-11 23:43:00 +00:00
sortCachedEntries ( ) ;
2020-07-11 11:39:56 +00:00
if ( numEntriesTotal > BIOSCACHESIZE ) {
// ... umm, this is a problem. FIXME?
}
struct _cacheEntry * nextEntry = biosCache ;
while ( startNum ) {
nextEntry + + ;
startNum - - ;
}
2018-02-07 15:20:26 +00:00
2020-07-11 11:39:56 +00:00
while ( 1 ) {
if ( nextEntry - > fn [ 0 ] = = 0 )
2018-02-07 15:20:26 +00:00
return count ;
2020-07-11 11:39:56 +00:00
strncpy ( fileDirectory [ count ] , nextEntry - > fn , BIOS_MAXPATH ) ;
2018-02-07 15:20:26 +00:00
count + + ;
if ( count > = BIOS_MAXFILES ) {
return count ;
}
2020-07-11 11:39:56 +00:00
nextEntry + + ;
2018-02-07 15:20:26 +00:00
}
}
2020-12-28 19:23:47 +00:00