blob: 04cd6809c48913ca1afe23b4462b8e0ce4240f51 [file] [log] [blame] [raw]
/*
YAPE - Yet Another Plus/4 Emulator
The program emulates the Commodore 264 family of 8 bit microcomputers
This program is free software, you are welcome to distribute it,
and/or modify it under certain conditions. For more information,
read 'Copying'.
(c) 2000, 2001, 2005 Attila Grósz
*/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "types.h"
#include "monitor.h"
#include "tedmem.h"
#include "interface.h"
#include "archdep.h"
#include "prg.h"
#include "tape.h"
#include "drive.h"
#include "roms.h"
#include "SaveState.h"
#ifndef SDL_CONTROLLERBUTTONDOWN // Emscripten
#define SDL_CONTROLLERBUTTONDOWN -1
#endif
extern bool autostart_file(const char *szFile, bool autostart = true);
extern bool start_file(const char *szFile, bool autostart = true);
extern bool openZipDisk(const char *fname, bool autostart);
extern void machineDoSomeFrames(unsigned int frames);
extern void machineEnable1551(bool enable);
extern bool machineIsTrueDriveEnabled(unsigned int dn);
extern void machineReset(bool hardreset);
extern void setMainLoop(int looptype);
#define COLOR(COL, SHADE) ((SHADE<<4)|COL|0x80)
#define MAX_LINES 25
#define MAX_INDEX (MAX_LINES - 1)
#define LISTOFFSET (ted8360->getCyclesPerRow() == 456 ? 52 : 112)
// TODO this is ugly and kludgy like hell but I don't have time for better
static menu_t main_menu = {
"Main menu",
"",
{
{"Load PRG file...", 0, UI_FILE_LOAD_PRG },
{"Attach disk image...", 0, UI_DRIVE_ATTACH_IMAGE },
{"Detach disk image", 0, UI_DRIVE_DETACH_IMAGE },
{"Emulator snapshot...", 0, UI_FILE_LOAD_FRE },
{ " ", 0, UI_MENUITEM_SEPARATOR },
{"Tape controls...", 0, UI_MENUITEM_MENULINK },
{" ", 0, UI_MENUITEM_SEPARATOR },
{"Options..." , 0, UI_MENUITEM_MENULINK },
{" ", 0, UI_MENUITEM_SEPARATOR },
{"Enter monitor" , 0, UI_EMULATOR_MONITOR },
{"Resume emulation" , 0, UI_EMULATOR_RESUME },
{ " ", 0, UI_MENUITEM_SEPARATOR },
{"Reset emulator", 0, UI_EMULATOR_RESET },
{ " ", 0, UI_MENUITEM_SEPARATOR },
{"Quit YAPE" , 0, UI_EMULATOR_EXIT }
},
0,
15,
0,
0,
0
};
static menu_t tape_menu = {
"Tape control menu",
"",
{
{"Attach TAP image...", 0, UI_TAPE_ATTACH_TAP },
{" ", 0, UI_MENUITEM_SEPARATOR },
{"Create TAP image", 0, UI_TAPE_CREATE_TAP },
{" ", 0, UI_MENUITEM_SEPARATOR },
{"Detach TAP image", 0, UI_TAPE_DETACH_TAP },
{" ", 0, UI_MENUITEM_SEPARATOR },
{"Press PLAY" , 0, UI_TAPE_PLAY },
{"Press RECORD" , 0, UI_TAPE_RECORD },
{"Press STOP" , 0, UI_TAPE_STOP },
{"Rewind tape" , 0, UI_TAPE_REWIND }
},
0,
10,
0,
0,
0
};
static menu_t snapshot_menu = {
"Emulator snapshot menu",
"",
{
{"Load snapshot...", 0, UI_SNAPSHOT_LOAD },
{"Save quicksnapshot...", 0, UI_SNAPSHOT_QUICKSAVE }
},
0,
2,
0,
0,
0
};
static menu_t options_menu = {
"Options menu",
"",
{
{"Dummy", 0, UI_MENUITEM_MENULINK },
},
0,
5,
0,
0,
0
};
static menu_t file_menu;
static menu_t tap_list;
static menu_t d64_list;
static menu_t fre_list;
static unsigned int pixels[512 * 312 * 2];
extern void frameUpdate(unsigned char *src, unsigned int *target);
static rvar_t *findRVar(char *name)
{
rvar_t **rv = settings;
while (*rv) {
rvar_t *item = *rv++;
while (item && item->value) {
if (!strcmp(name, item->menuName))
return item;
item++;
}
}
return NULL;
}
UI::UI(class TED *ted) :
display(ted->screen), charset(kernal + 0x1400), ted8360(ted)
{
// Link menu structure
main_menu.element[0].child = &file_menu;
main_menu.element[1].child = &d64_list;
main_menu.element[3].child = &fre_list;// snapshot_menu;
main_menu.element[5].child = &tape_menu;
main_menu.element[7].child = &options_menu;
tape_menu.element[0].child = &tap_list;
curr_menu = &main_menu;
strcpy( file_menu.title, "PRG file selection menu");
strcpy( tape_menu.title, "Tape controls menu");
strcpy( tap_list.title, "TAP image selection menu");
strcpy( d64_list.title, "Disk image selection menu");
strcpy(fre_list.title, "Emulator savestate selection menu");
file_menu.parent = curr_menu;
options_menu.parent = curr_menu;
tape_menu.parent = curr_menu;
tap_list.parent = &tape_menu;
d64_list.parent = curr_menu;
//snapshot_menu.parent = curr_menu;
fre_list.parent = curr_menu;
// initialize settings menu
unsigned int i = 0, j = 0;
rvar_t **rv = settings;
while (rv[i]) {
rvar_t *item = rv[i++];
while (item && item->value) { // FIXME
strcpy(options_menu.element[j].name, item->menuName);
options_menu.element[j].menufunction = UI_MENUITEM_CALLBACKS;
options_menu.element[j].type = (UI_MenuTypes) item->type;
item++;
j++;
}
}
options_menu.nr_of_elements = j;
}
void UI::screen_update()
{
const unsigned int cyclesPerRow = ted8360->getCyclesPerRow();
const int offset = cyclesPerRow == 504 ? -68 : 8;
frameUpdate(display + (cyclesPerRow - offset - 384) / 2 + 10 * cyclesPerRow, pixels);
}
void UI::clear(char color, char shade)
{
memset(display, COLOR(color, shade), 512 * SCR_VSIZE);
screen_update();
}
void UI::set_color(unsigned char foreground, unsigned char background)
{
bgcol = background;
fgcol = foreground;
}
void UI::texttoscreen(int x, int y, char *scrtxt, size_t len = 0)
{
int i = 0;
if (!len) len = strlen(scrtxt);
while (scrtxt[i] != 0 && len--) {
chrtoscreen(x + i*8, y, asc2pet(scrtxt[i]));
i++;
}
}
void UI::chrtoscreen(int x,int y, char scrchr)
{
int j, k;
unsigned char *cset;
const unsigned int CPR = ted8360->getCyclesPerRow();
cset = charset + (scrchr << 3);
for (j = 0; j<8; j++)
for (k = 0; k < 8; k++)
display[(y + j) * CPR + x + k] = (cset[j] & (0x80 >> k)) ? fgcol : bgcol;
}
void UI::hide_sel_bar(menu_t *menu)
{
if ( menu->element[ menu->curr_sel ].menufunction == UI_DIR_ITEM)
set_color( COLOR(2,1), COLOR(1,5) );
else
set_color( COLOR(0,0), COLOR(1,5) );
texttoscreen(LISTOFFSET, 64 + (curr_menu->curr_line<<3),
menu->element[ curr_menu->curr_sel ].name);
screen_update();
}
void UI::show_sel_bar(menu_t * menu)
{
set_color( COLOR(0,0), COLOR(15,7) );
texttoscreen(LISTOFFSET, 64 + (curr_menu->curr_line<<3),
menu->element[ curr_menu->curr_sel ].name);
screen_update();
}
void UI::show_settings_list(menu_t * menu, rvar_t *rvItems)
{
int nf = 0;
menu->nr_of_elements = 0;
rvar_t *rvPtr = *settings;
while (rvPtr) {
strcpy(menu->element[nf].name, rvPtr->menuName);
menu->element[nf].child = 0;
menu->element[nf].type = MENU_CALLBACK;
nf++;
rvPtr++;
}
menu->nr_of_elements = nf;
}
void UI::show_file_list(menu_t * menu, UI_MenuClass type)
{
int nf = 0, res;
char cfilename[512];
char *fileFoundName;
UI_FileTypes ft;
menu->nr_of_elements = 0;
res = ad_find_first_file("*");
fileFoundName = ad_return_current_filename();
ft = ad_return_current_filetype();
if (fileFoundName && !strcmp(fileFoundName, ".") )
res = ad_find_next_file();
if (!fileFoundName || strcmp(fileFoundName, "..") /*&& ft != UI_DRIVE_ITEM*/) {
strcpy( menu->element[nf++].name, "..");
menu->element[0].menufunction = UI_DIR_ITEM;
}
while (res) {
ft = ad_return_current_filetype();
// fprintf(stderr,"Parsed: %s\n", ad_return_current_filename());
if (ft != FT_FILE) {
strcpy(menu->element[nf].name, ad_return_current_filename());
menu->element[nf].menufunction = (ft == FT_DIR ? UI_DIR_ITEM : UI_DRIVE_ITEM);
++nf;
}
res = ad_find_next_file();
}
ad_find_file_close();
// populate file list
if (ft != FT_VOLUME) {
unsigned int nrOfExts = 1;
element_t ftypes[10];
switch ( type ) {
case UI_T64_ITEM:
case UI_PRG_ITEM:
nrOfExts = 3;
strcpy(ftypes[0].name, "*.prg");
strcpy(ftypes[1].name, "*.P00");
strcpy(ftypes[2].name, "*.T64");
ftypes[0].menufunction = UI_PRG_ITEM;
ftypes[1].menufunction = UI_PRG_ITEM;
ftypes[2].menufunction = UI_T64_ITEM;
break;
case UI_TAP_ITEM:
strcpy(ftypes[0].name, "*.tap");
ftypes[0].menufunction = UI_TAP_ITEM;
break;
case UI_D64_ITEM:
case UI_ZIP_ITEM:
strcpy(ftypes[0].name, "*.d64");
ftypes[0].menufunction = UI_D64_ITEM;
strcpy(ftypes[1].name, "*.zip");
ftypes[1].menufunction = UI_ZIP_ITEM;
#ifdef WIN32
nrOfExts = 2;
#else
nrOfExts = 3;
strcpy(ftypes[2].name, "*.D64");
ftypes[2].menufunction = UI_D64_ITEM;
#endif
break;
case UI_FRE_ITEM:
strcpy(ftypes[0].name, "*.yss");
ftypes[0].menufunction = UI_FRE_ITEM;
break;
case UI_DRIVE_SET_DIR:
menu->nr_of_elements = nf;
default:
return;
}
//
unsigned int k = nrOfExts - 1;
do {
strcpy(cfilename, ftypes[k].name);
type = ftypes[k].menufunction;
res = ad_find_first_file(cfilename);
while(res) {
strcpy(menu->element[nf].name, ad_return_current_filename());
menu->element[nf].menufunction = type;
++nf;
res = ad_find_next_file();
}
ad_find_file_close();
} while (k--);
//
}
menu->nr_of_elements = nf;
}
void UI::openD64Item(const char *name)
{
machineEnable1551(false);
if (CTrueDrive::GetRoot()) {
CTrueDrive::SwapDisk(name);
const Uint8 *state = SDL_GetKeyboardState(NULL);
if (state[SDL_SCANCODE_LSHIFT] || state[SDL_SCANCODE_RSHIFT]) {
autostart_file(name);
}
}
}
bool UI::handle_menu_command( struct element_t *element)
{
int menuSelection;
UI_MenuClass ptype = UI_MENUITEM_MENULINK;
// FIXME this must be nicer
if (!curr_menu->parent) {
menuSelection = element->menufunction;
} else {
ptype = curr_menu->parent->element[ curr_menu->parent->curr_sel ].menufunction;
menuSelection = element->menufunction;
}
switch ( menuSelection ) {
case UI_MENUITEM_MENULINK:
return false;
case UI_MENUITEM_CALLBACKS:
{ // find rvar and use callback
rvar_t *rv = findRVar(element->name);
if (rv) {
switch (rv->type) {
case RVAR_TOGGLE:
// if callback specified, call it otherwise toggle ourselves
if (rv->callback)
(rv->callback)(NULL);
else {
unsigned int *value = ((unsigned int*)(rv->value));
*value = !*value;
}
break;
case RVAR_HEX:
case RVAR_INT:
if (rv->callback)
(rv->callback)(NULL);
break;
case RVAR_STRING_FLIPLIST:
if (rv->callback) {
char text[64];
(rv->callback)(text);
}
break;
default:;
}
}
}
return false;
case UI_DRIVE_ITEM:
ad_exit_drive_selector();
case UI_DIR_ITEM:
if (ad_set_curr_dir(element->name)) {
ad_get_curr_dir( (char*)&(curr_menu->subtitle) );
if ( ptype == UI_FILE_LOAD_PRG )
show_file_list( &file_menu, UI_PRG_ITEM );
else if ( ptype == UI_TAPE_ATTACH_TAP )
show_file_list( &tap_list, UI_TAP_ITEM );
else if ( ptype == UI_DRIVE_ATTACH_IMAGE )
show_file_list( &d64_list, UI_D64_ITEM );
else if (ptype == UI_FILE_LOAD_FRE)
show_file_list(&fre_list, UI_FRE_ITEM);
curr_menu->curr_sel = 0;
curr_menu->curr_line = 0;
curr_menu->uppermost = 0;
}
/*if ( curr_menu->curr_sel >= file_menu.nr_of_elements )
curr_menu->curr_sel = file_menu.nr_of_elements - 1;*/
return false;
case UI_T64_ITEM:
case UI_PRG_ITEM:
{
const Uint8 *state = SDL_GetKeyboardState(NULL);
if (state[SDL_SCANCODE_LSHIFT] || state[SDL_SCANCODE_RSHIFT]) {
autostart_file(element->name);
} else {
if (menuSelection != UI_T64_ITEM)
PrgLoad(element->name, 0, ted8360);
else
prgLoadFromT64(element->name, 0, ted8360);
}
}
clear (0, 0);
break;
case UI_TAP_ITEM:
strcpy( ted8360->tap->tapefilename, element->name);
ted8360->tap->attach_tap();
break;
case UI_D64_ITEM:
openD64Item(element->name);
break;
case UI_ZIP_ITEM:
start_file(element->name, true);
break;
case UI_FRE_ITEM:
SaveState::openSnapshot(element->name, false);
//clear(0, 0);
break;
case UI_TAPE_DETACH_TAP:
ted8360->tap->detach_tap();
break;
case UI_TAPE_REWIND:
ted8360->tap->rewind();
break;
case UI_FILE_LOAD_PRG:
show_file_list( &file_menu, UI_PRG_ITEM );
return false;
case UI_TAPE_ATTACH_TAP:
show_file_list( &tap_list, UI_TAP_ITEM );
return false;
case UI_FILE_LOAD_FRE:
show_file_list(&fre_list, UI_FRE_ITEM);
return false;
case UI_DRIVE_ATTACH_IMAGE:
show_file_list( &d64_list, UI_D64_ITEM );
//ted8360->HookTCBM(0);
return false;
case UI_DRIVE_DETACH_IMAGE:
if (CTrueDrive::GetRoot()) {
CTrueDrive *d = CTrueDrive::GetRoot();
d->DetachDisk();
}
machineEnable1551(true);
return true;
case UI_SNAPSHOT_LOAD:
show_file_list( &snapshot_menu, UI_FRE_ITEM );
return false;
case UI_EMULATOR_MONITOR:
monitorEnter(ted8360->cpuptr);
return true;
case UI_EMULATOR_RESUME:
void ();
return true;
case UI_EMULATOR_RESET:
machineReset(true);
return true;
case UI_EMULATOR_EXIT:
exit(1);
break;
default:
break;
}
return true;
}
void UI::show_title(menu_t * menu)
{
const unsigned int CPR = ted8360->getCyclesPerRow() == 504 ? 576 : 456;
size_t titlen = strlen( menu->title ) << 3;
set_color( COLOR(8,7), COLOR(7,0) );
texttoscreen( (CPR - int(titlen))/2, 24, menu->title);
titlen = strlen( menu->subtitle );
set_color( COLOR(8,0), COLOR(1,5) );
int chunks = (int) titlen / (CPR / 8) + 1;
int startline = 40 - (chunks / 3) * 8;
char *subtitle = menu->subtitle;
do {
const int MAXLEN = 46;//55;
int chunklen = (int) (titlen > MAXLEN ? MAXLEN : titlen);
texttoscreen(CPR / 2 - int(chunklen) * 4, startline,
petstr2ascstr(subtitle), chunklen);
titlen -= MAXLEN;
subtitle += chunklen;
startline += 8;
} while (chunks--);
char helptxt[] = "Arrows: navigate, ENTER: select, ESC: resume";
texttoscreen( (CPR - int(strlen(helptxt)*8)) / 2 - 8, 312 - 32, petstr2ascstr(helptxt));
set_color( fgcol, bgcol );
}
void UI::show_menu(menu_t * menu)
{
int i;
int shown = menu->nr_of_elements - menu->uppermost;
show_title(menu);
if (shown > 0) {
if (shown > MAX_LINES)
shown = MAX_LINES + 1;
set_color( COLOR(0,0), COLOR(1,5) );
for (i = 0; i < shown; ++i) {
unsigned int ix = menu->uppermost + i;
element_t &elem = menu->element[ix];
if (elem.menufunction == UI_DIR_ITEM)
set_color( COLOR(2,1), COLOR(1,5) );
else
set_color( COLOR(0,0), COLOR(1,5) );
// display menu list element
texttoscreen(LISTOFFSET, 64+(i<<3), elem.name);
// if interactive menu, find out what to do
if (elem.menufunction == UI_MENUITEM_CALLBACKS) {
char valuetxt[256] = "";
unsigned int valuePos = LISTOFFSET + (43 << 3);
unsigned int valueTxtLen;
rvar_t *rv = findRVar(elem.name);
unsigned int type = (RvarTypes) elem.type;
switch (type) {
case RVAR_TOGGLE:
strcpy(valuetxt, *((unsigned int*)(rv->value)) ? "ON" : "OFF");
break;
case RVAR_INT:
sprintf(valuetxt, "%u", *((unsigned int*)(rv->value)));
break;
case RVAR_HEX:
sprintf(valuetxt, "$%04X", *((unsigned int*)(rv->value)));
break;
case RVAR_STRING_FLIPLIST:
if (rv->label)
sprintf(valuetxt, "%s", rv->label());
break;
default:;
}
valueTxtLen = (unsigned int) (strlen(valuetxt) << 3);
set_color(COLOR(2,1), COLOR(1,5));
texttoscreen(valuePos - valueTxtLen, 64 + (i << 3), valuetxt);
}
}
}
screen_update();
}
void UI::drawMenu()
{
ad_get_curr_dir(tap_list.subtitle);
ad_get_curr_dir(file_menu.subtitle);
ad_get_curr_dir(d64_list.subtitle);
ad_get_curr_dir(fre_list.subtitle);
clear (1, 5);
show_menu( curr_menu);
show_sel_bar( curr_menu );
}
int UI::enterMenu()
{
int retval;
drawMenu();
retval = wait_events();
clear (0, 0);
return retval;
}
void UI::menuMoveUp()
{
if (curr_menu->curr_sel > 0) {
int step = 0;
hide_sel_bar( curr_menu);
// Step and skip menu separators
do {
step++;
} while (curr_menu->element[curr_menu->curr_sel - step].menufunction
== UI_MENUITEM_SEPARATOR);
if (curr_menu->curr_line == 0) {
curr_menu->uppermost -= 1;
clear (1, 5);
show_menu( curr_menu );
} else
curr_menu->curr_line -= step;
curr_menu->curr_sel -= step;
show_sel_bar( curr_menu);
}
}
void UI::menuMoveDown()
{
if (curr_menu->curr_sel < curr_menu->nr_of_elements - 1) {
int step = 0;
hide_sel_bar( curr_menu);
// Step and skip menu separators
do {
step++;
} while (curr_menu->element[curr_menu->curr_sel + step].menufunction
== UI_MENUITEM_SEPARATOR);
if (curr_menu->curr_line==MAX_LINES) {
curr_menu->uppermost += 1;
clear (1, 5);
show_menu( curr_menu );
} else
curr_menu->curr_line += step;
curr_menu->curr_sel += step;
show_sel_bar( curr_menu);
}
}
int UI::menuEnter(bool forceAutoRun = false)
{
element_t *elem;
if ( curr_menu->element[ curr_menu->curr_sel ].child ) {
elem = &(curr_menu->element[ curr_menu->curr_sel ]);
curr_menu = elem->child;
} else {
elem = &(curr_menu->element[ curr_menu->curr_sel ]);
}
// returns zero if we have to get back to the main loop, 1 otherwise
if ( handle_menu_command( elem ) ) {
clear (0, 0);
return 0;
} else {
clear (1, 5);
show_menu( curr_menu );
show_sel_bar( curr_menu);
}
return 1;
}
int UI::wait_events()
{
SDL_Event event;
#ifdef __EMSCRIPTEN__
while (SDL_PollEvent(&event)) {
#else
while (SDL_WaitEvent(&event)) {
#endif
switch (event.type) {
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_RESIZED
|| event.window.event == SDL_WINDOWEVENT_RESTORED) {
screen_update();
}
break;
case SDL_JOYAXISMOTION:
//printf("joy: %u, button: %u was pressed!\n", event.jaxis.which, event.jaxis.axis);
break;
case (Uint32)SDL_CONTROLLERBUTTONDOWN:
case SDL_JOYBUTTONDOWN:
//printf("joy: %u, button: %u was pressed!\n", event.jbutton.which, event.jbutton.button);
break;
case SDL_JOYBUTTONUP:
switch (event.jbutton.button) { // START button
case 10:
if (!menuEnter())
return 1;
break;
case 14:
case 12:
case 5:
return 0;
case 0:
menuMoveUp();
break;
case 1:
menuMoveDown();
break;
default:
//printf("joy: %u, button: %u was pressed!\n", event.jbutton.which, event.jbutton.button);
break;
}
break;
case SDL_KEYDOWN:
//printf("key: %u, button was pressed!\n", event.key.keysym.scancode);
switch (event.key.keysym.sym) {
case SDLK_ESCAPE :
case SDLK_F8:
clear (0, 0);
return 1;
case SDLK_HOME:
hide_sel_bar( curr_menu);
clear (1, 5);
curr_menu->curr_sel = 0;
curr_menu->curr_line = 0;
curr_menu->uppermost = 0;
show_menu( curr_menu );
show_sel_bar( curr_menu);
break;
case SDLK_END:
break;
case SDLK_UP:
menuMoveUp();
break;
case SDLK_DOWN:
menuMoveDown();
break;
case SDLK_PAGEUP:
hide_sel_bar( curr_menu);
if (curr_menu->curr_line != 0 ) {
curr_menu->curr_sel = curr_menu->uppermost;
curr_menu->curr_line = 0;
} else {
curr_menu->curr_sel -= MAX_LINES;
if ( curr_menu->curr_sel < 0 )
curr_menu->curr_sel = 0;
curr_menu->uppermost = curr_menu->curr_sel;
clear (1, 5);
show_menu( curr_menu );
}
show_sel_bar( curr_menu);
break;
case SDLK_PAGEDOWN:
hide_sel_bar( curr_menu );
if (curr_menu->curr_line != MAX_LINES ) {
int nr_el = curr_menu->nr_of_elements - 1;
curr_menu->curr_sel = curr_menu->curr_line =
nr_el < MAX_LINES ? nr_el : MAX_LINES;
} else {
int nr_el = curr_menu->nr_of_elements - 1;
curr_menu->curr_sel += MAX_LINES;
if ( curr_menu->curr_sel > nr_el )
curr_menu->curr_sel = nr_el;
curr_menu->uppermost = curr_menu->curr_sel - MAX_LINES;
clear (1, 5);
show_menu( curr_menu );
}
show_sel_bar( curr_menu);
break;
case SDLK_LEFT:
if ( curr_menu->parent ) {
curr_menu = curr_menu->parent;
clear (1, 5);
show_menu( curr_menu );
show_sel_bar( curr_menu );
}
break;
case SDLK_RIGHT:
case SDLK_RETURN:
// return 1 if we get back to the main loop
if (!menuEnter())
return 1;
break;
default :
break;
};
break;
case SDL_QUIT:
//return 2;
exit(0);
}
}
return 0;
}
char UI::pet2asc(char c)
{
if (c == '\\')
return char(0x4D|0x80);
if (c == 0x5F)
return char(0x6F|0x80);
/*if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
return c ^ 0x20;*/
/*if ((c >= 0xc1) && (c <= 0xda))
return c ^ 0x80;*/
return c;
}
char *UI::petstr2ascstr(char *string)
{
char *p = string;
while (*p) {
*p = pet2asc( *p );
p++;
}
return string;
}
unsigned char UI::asc2pet(char c)
{
if ((c >= 'A') && (c <= 'Z'))
return c ;
if ((c >= 'a') && (c <= 'z'))
return c - 96;
if (c == '\\')
return 0x4D;
/*if ((c >= 0xc1) && (c <= 0xda))
return c ^ 0x80;*/
return c;
}
UI::~UI()
{
}
void interfaceLoop(void *arg)
{
UI *ui = (UI*) arg;
if (ui->wait_events()) {
setMainLoop(1);
}
}