summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2007-02-16 01:10:41 +0000
committerIan C <ianc@noddybox.co.uk>2007-02-16 01:10:41 +0000
commitb369f37c6244b5d56742b56f745219fb2544efe2 (patch)
treea838093b033d302e6c7f64e7e255594d490d093a /source
parent284d8dec91155107f04ad4e2c02338bcb6263abc (diff)
Some hi-res support. Added new config page and averaging touchscreen reads.
In process of writing file selector.
Diffstat (limited to 'source')
-rw-r--r--source/config.c130
-rw-r--r--source/framebuffer.c15
-rw-r--r--source/gui.c428
-rw-r--r--source/keyboard.c48
-rw-r--r--source/main.c21
-rw-r--r--source/touchwrap.c55
-rw-r--r--source/zx81.c71
7 files changed, 698 insertions, 70 deletions
diff --git a/source/config.c b/source/config.c
new file mode 100644
index 0000000..b2abec8
--- /dev/null
+++ b/source/config.c
@@ -0,0 +1,130 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include <nds.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+/* ---------------------------------------- PRIVATE DATA
+*/
+const char *conf_filename = "DS81.CFG";
+
+const char *conf_entry[DS81_NUM_CONFIG_ITEMS]=
+{
+ "sticky_shift",
+ "average_touchscreen"
+};
+
+
+/* ---------------------------------------- GLOBAL DATA
+*/
+int DS81_Config[DS81_NUM_CONFIG_ITEMS]=
+{
+ TRUE,
+ FALSE
+};
+
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+int LoadConfig(void)
+{
+ FILE *fp = NULL;
+
+#ifndef DS81_DISABLE_FAT
+ fp=fopen(conf_filename,"r");
+#endif
+
+ if (fp)
+ {
+ char line[80];
+
+ while(fgets(line, sizeof line, fp))
+ {
+ char *p;
+
+ if ((p = strchr(line, '=')))
+ {
+ int f;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ if (strncmp(line, conf_entry[f],
+ strlen(conf_entry[f])) == 0)
+ {
+ DS81_Config[f] = (*(p+1) == '1');
+ }
+ }
+
+ }
+ }
+
+ fclose(fp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int SaveConfig(void)
+{
+ FILE *fp = NULL;
+
+#ifndef DS81_DISABLE_FAT
+ fp=fopen(conf_filename,"w");
+#endif
+
+ if (fp)
+ {
+ int f;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ fprintf(fp,"%s=%d\n",conf_entry[f],DS81_Config[f]);
+ }
+
+ fclose(fp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const char *ConfigDesc(DS81_ConfigItem item)
+{
+ switch(item)
+ {
+ case DS81_STICKY_SHIFT:
+ return "STICKY SHIFT";
+
+ case DS81_AVERAGE_TOUCHSCREEN:
+ return "AVERAGE TOUCHSCREEN";
+
+ default:
+ return "UNKNOWN";
+ }
+}
+
diff --git a/source/framebuffer.c b/source/framebuffer.c
index ef66235..691862e 100644
--- a/source/framebuffer.c
+++ b/source/framebuffer.c
@@ -21,6 +21,8 @@
*/
#include <nds.h>
+#include <stdio.h>
+#include <stdarg.h>
#include <string.h>
/* ---------------------------------------- STATIC DATA
@@ -183,6 +185,19 @@ void FB_Centre(const char *text, int y, int colour, int paper)
}
+void FB_printf(int x, int y, int colour, int paper, const char *format, ...)
+{
+ char buff[80];
+ va_list va;
+
+ va_start(va,format);
+ vsnprintf(buff,sizeof buff,format,va);
+ va_end(va);
+
+ FB_Print(buff,x,y,colour,paper);
+}
+
+
void FB_HLine(int x1, int x2, int y, int colour)
{
uint16 *line;
diff --git a/source/gui.c b/source/gui.c
index 713ad02..7e55b97 100644
--- a/source/gui.c
+++ b/source/gui.c
@@ -20,10 +20,160 @@
$Id$
*/
-#include <nds.h>
+#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
+#include <nds.h>
+
+#include <sys/dir.h>
#include "framebuffer.h"
+#include "config.h"
+
+
+/* ---------------------------------------- PRIVATE INTERFACES - PATH HANDLING
+*/
+#define FSEL_FILENAME_LEN 20
+#define FSEL_LINES 15
+#define FSEL_MAX_FILES 512
+
+#define FSEL_LIST_Y 12
+#define FSEL_LIST_H FSEL_LINES*8
+
+typedef struct
+{
+ char name[FSEL_FILENAME_LEN+1];
+ int is_dir;
+ int size;
+} FSEL_File;
+
+static FSEL_File fsel[FSEL_MAX_FILES];
+
+
+static void CheckPath(char *path)
+{
+ size_t l;
+
+ l = strlen(path);
+
+ if (l == 1)
+ {
+ path[0] = '/';
+ }
+ else
+ {
+ if (path[l-1] != '/')
+ {
+ path[l] = '/';
+ path[l+1] = 0;
+ }
+ }
+}
+
+
+static void AddPath(char *path, const char *dir)
+{
+ if (strcmp(dir,"..") == 0)
+ {
+ char *p;
+
+ p = strrchr(path,'/');
+
+ if (p && p!=path)
+ {
+ *p = 0;
+ }
+ }
+ else
+ {
+ strcat(path,dir);
+ strcat(path,"/");
+ }
+}
+
+
+
+
+static int SortFiles(const void *a, const void *b)
+{
+ const FSEL_File *f1;
+ const FSEL_File *f2;
+
+ f1 = (const FSEL_File *)a;
+ f2 = (const FSEL_File *)b;
+
+ if (f1->is_dir == f1->is_dir)
+ {
+ return strcmp(f1->name, f2->name);
+ }
+ else if (f1->is_dir)
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+static int ValidFilename(const char *name, int is_dir, const char *filter)
+{
+ size_t l;
+ size_t f;
+
+ l = strlen(name);
+
+ if (l > FSEL_FILENAME_LEN)
+ return 0;
+
+ if (strcmp(name,".") == 0)
+ return 0;
+
+ if (is_dir || !filter)
+ return 1;
+
+ f = strlen(filter);
+
+ if (l > f)
+ {
+ if (strcmp(name+l-f,filter) == 0)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int LoadDir(const char *path, const char *filter)
+{
+ DIR_ITER *dir;
+ struct stat st;
+ char name[FILENAME_MAX];
+ int no = 0;
+
+ if ((dir = diropen(path)))
+ {
+ while(no < FSEL_MAX_FILES && dirnext(dir,name,&st) == 0)
+ {
+ if (ValidFilename(name, (st.st_mode & S_IFDIR), filter))
+ {
+ strcpy(fsel[no].name,name);
+ fsel[no].is_dir = (st.st_mode & S_IFDIR);
+ fsel[no].size = (int)st.st_size;
+ no++;
+ }
+ }
+
+ dirclose(dir);
+
+ qsort(fsel,no,sizeof fsel[0],SortFiles);
+ }
+
+ return no;
+}
/* ---------------------------------------- PUBLIC INTERFACES
@@ -189,3 +339,279 @@ void GUI_Alert(int fatal, const char *text)
}
}
}
+
+
+void GUI_Config(void)
+{
+ int sel;
+ DS81_ConfigItem f;
+ bool done;
+ bool save;
+
+ sel = 0;
+ done = false;
+ save = false;
+
+ FB_Clear();
+
+ FB_Centre("Up/Down to select",140,FB_RGB(31,31,0),-1);
+ FB_Centre("A to toggle",150,FB_RGB(31,31,0),-1);
+ FB_Centre("Or use touchscreen",160,FB_RGB(31,31,0),-1);
+ FB_Centre("START to finish",170,FB_RGB(31,31,0),-1);
+
+#ifndef DS81_DISABLE_FAT
+ FB_Centre("SELECT to save to \\DS81.CFG",180,FB_RGB(31,31,0),-1);
+#endif
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ FB_Print(ConfigDesc(f),14,20+f*14,FB_RGB(31,31,31),-1);
+ }
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ for(f=0;f<DS81_NUM_CONFIG_ITEMS;f++)
+ {
+ FB_FillBox(2,20+f*14-1,10,10,
+ DS81_Config[f] ? FB_RGB(31,31,31):FB_RGB(0,0,0));
+
+ FB_Box(2,20+f*14-1,10,10,FB_RGB(18,18,18));
+ }
+
+ FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,FB_RGB(18,18,31));
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!(key=keysDownRepeat()));
+
+ FB_Box(0,20+sel*14-3,SCREEN_WIDTH-1,14,FB_RGB(0,0,0));
+
+ if (key & KEY_START)
+ {
+ done=true;
+ }
+#ifndef DS81_DISABLE_FAT
+ else if (key & KEY_SELECT)
+ {
+ done=true;
+ save=true;
+ }
+#endif
+ else if (key & KEY_A)
+ {
+ DS81_Config[sel] = !DS81_Config[sel];
+ }
+ else if ((key & KEY_UP) && sel)
+ {
+ sel--;
+ }
+ else if ((key & KEY_DOWN) && sel<DS81_NUM_CONFIG_ITEMS-1)
+ {
+ sel++;
+ }
+ else if (key & KEY_TOUCH)
+ {
+ touchPosition tp = touchReadXY();
+ int nsel;
+
+ nsel = (tp.py-18)/14;
+
+ if (nsel>=0 && nsel<DS81_NUM_CONFIG_ITEMS)
+ {
+ sel = nsel;
+ DS81_Config[sel] = !DS81_Config[sel];
+ }
+ }
+ }
+
+ if (save)
+ {
+ SaveConfig();
+ }
+}
+
+
+bool GUI_FileSelect(char pwd[], char selected_file[], const char *filter)
+{
+ int no;
+ int sel;
+ int top;
+ int bar_size;
+ double bar_step;
+ bool done;
+ bool ret;
+ int pen;
+ int paper;
+ int off;
+ int f;
+
+ CheckPath(pwd);
+
+ FB_Clear();
+
+ FB_printf(0,0,FB_RGB(0,0,0),FB_RGB(22,22,22),"%-31.31s",pwd);
+
+ no = LoadDir(pwd,filter);
+
+ sel = 0;
+ top = 0;
+ done = false;
+ ret = false;
+
+ if (no<=FSEL_LINES)
+ {
+ bar_step = 0;
+ bar_size = FSEL_LIST_H;
+ }
+ else
+ {
+ bar_step = FSEL_LIST_H/(double)no;
+ bar_size = bar_step*FSEL_LINES;
+ }
+
+ while(!done)
+ {
+ uint32 key=0;
+
+ for (f=0;f<FSEL_LINES;f++)
+ {
+ off = f + top;
+
+ if (off<no)
+ {
+ if (off == sel)
+ {
+ pen = FB_RGB(0,0,0);
+ paper = FB_RGB(31,31,31);
+ }
+ else
+ {
+ pen = FB_RGB(31,31,31);
+ paper = FB_RGB(0,0,0);
+ }
+
+ FB_printf(8,FSEL_LIST_Y+f*8,pen,paper,
+ "%-*s %s",
+ FSEL_FILENAME_LEN,
+ fsel[off].name,
+ fsel[off].is_dir ? "DIR" : " ");
+ }
+ else
+ {
+ FB_printf(8,FSEL_LIST_Y+f*8,FB_RGB(31,31,31),FB_RGB(0,0,0),
+ "%-*s %s",
+ FSEL_FILENAME_LEN,
+ off==0 ? "No Files!" : "",
+ "");
+ }
+ }
+
+ FB_FillBox(240,FSEL_LIST_Y,16,FSEL_LIST_H,FB_RGB(10,10,10));
+ FB_FillBox(240,FSEL_LIST_Y+top*bar_step,16,bar_size,FB_RGB(31,31,31));
+
+ do
+ {
+ swiWaitForVBlank();
+ } while(!(key=keysDownRepeat()));
+
+ if (key & KEY_UP)
+ {
+ if (sel)
+ {
+ sel--;
+
+ if (sel<top)
+ {
+ top--;
+ }
+ }
+ }
+ else if (key & KEY_DOWN)
+ {
+ if (sel < (no-1))
+ {
+ sel++;
+
+ if (sel >= (top+FSEL_LINES))
+ {
+ top++;
+ }
+ }
+ }
+ else if (key & KEY_L)
+ {
+ if (sel)
+ {
+ sel-=FSEL_LINES;
+
+ if (sel < 0)
+ {
+ sel = 0;
+ }
+
+ top = sel;
+ }
+ }
+ else if (key & KEY_R)
+ {
+ if (sel < (no-1))
+ {
+ sel+=FSEL_LINES;
+
+ if (sel > (no-1))
+ {
+ sel = no-1;
+ }
+
+ top = sel - FSEL_LINES + 1;
+
+ if (top < 0)
+ {
+ top = 0;
+ }
+ }
+ }
+ else if (key & KEY_A)
+ {
+ if (fsel[sel].is_dir)
+ {
+ AddPath(pwd,fsel[sel].name);
+
+ no = LoadDir(pwd,filter);
+
+ sel = 0;
+ top = 0;
+
+ if (no<=FSEL_LINES)
+ {
+ bar_step = 0;
+ bar_size = FSEL_LIST_H;
+ }
+ else
+ {
+ bar_step = FSEL_LIST_H/(double)no;
+ bar_size = bar_step*FSEL_LINES;
+ }
+ }
+ else
+ {
+ done = true;
+ ret = true;
+
+ strcpy(selected_file,pwd);
+ strcat(selected_file,fsel[sel].name);
+ }
+ }
+ else if (key & KEY_START)
+ {
+ done=true;
+ }
+ }
+
+ while (keysHeld());
+
+ return ret;
+}
diff --git a/source/keyboard.c b/source/keyboard.c
index cb6a932..37ae4ef 100644
--- a/source/keyboard.c
+++ b/source/keyboard.c
@@ -24,6 +24,7 @@
#include "keyboard.h"
#include "framebuffer.h"
+#include "touchwrap.h"
#include "keyb_bin.h"
/* ---------------------------------------- STATIC DATA
@@ -166,36 +167,39 @@ static int GetEvent(SoftKeyEvent *ev, int map)
*/
if (keys & KEY_TOUCH)
{
- touchPosition tp=touchReadXY();
+ touchPosition tp;
- if (tp.py<21 || tp.py>165)
+ if (AllowTouch(&tp))
{
- key_state[SK_CONFIG].new_state = TRUE;
- }
- else
- {
- SoftKey press;
-
- press = LocatePress(&tp);
-
- if (press != NUM_SOFT_KEYS)
+ if (tp.py<21 || tp.py>165)
+ {
+ key_state[SK_CONFIG].new_state = TRUE;
+ }
+ else
{
- key_state[press].handled = TRUE;
+ SoftKey press;
+
+ press = LocatePress(&tp);
- if (key_state[press].is_sticky)
+ if (press != NUM_SOFT_KEYS)
{
- if (last != press)
+ key_state[press].handled = TRUE;
+
+ if (key_state[press].is_sticky)
{
- key_state[press].new_state =
- !key_state[press].state;
+ if (last != press)
+ {
+ key_state[press].new_state =
+ !key_state[press].state;
+ }
+ }
+ else
+ {
+ key_state[press].new_state = TRUE;
}
- }
- else
- {
- key_state[press].new_state = TRUE;
- }
- last = press;
+ last = press;
+ }
}
}
}
diff --git a/source/main.c b/source/main.c
index aed05f5..f2b0e70 100644
--- a/source/main.c
+++ b/source/main.c
@@ -32,6 +32,7 @@
#include "z80.h"
#include "zx81.h"
#include "tapes.h"
+#include "config.h"
#include "splashimg_bin.h"
#include "rom_font_bin.h"
@@ -42,8 +43,7 @@ static const char *main_menu[]=
{
"Reset ZX81",
"Select Tape",
- "Sticky Shift On",
- "Sticky Shift Off",
+ "Configure",
"Map Joypad to Keys",
"Cancel",
NULL
@@ -53,8 +53,7 @@ typedef enum
{
MenuReset,
MenuSelectTape,
- MenuStickyOn,
- MenuStickyOff,
+ MenuConfigure,
MenuMapJoypad,
} MenuOpt;
@@ -301,9 +300,11 @@ int main(int argc, char *argv[])
Splash();
+ LoadConfig();
+
SK_DisplayKeyboard(BG_GFX_SUB);
- SK_SetSticky(SK_SHIFT,1);
+ SK_SetSticky(SK_SHIFT,DS81_Config[DS81_STICKY_SHIFT]);
while(1)
{
@@ -329,12 +330,10 @@ int main(int argc, char *argv[])
SelectTape();
break;
- case MenuStickyOn:
- SK_SetSticky(SK_SHIFT,1);
- break;
-
- case MenuStickyOff:
- SK_SetSticky(SK_SHIFT,0);
+ case MenuConfigure:
+ GUI_Config();
+ SK_SetSticky(SK_SHIFT,
+ DS81_Config[DS81_STICKY_SHIFT]);
break;
case MenuMapJoypad:
diff --git a/source/touchwrap.c b/source/touchwrap.c
new file mode 100644
index 0000000..4fa373b
--- /dev/null
+++ b/source/touchwrap.c
@@ -0,0 +1,55 @@
+/*
+ ds81 - Nintendo DS ZX81 emulator.
+
+ Copyright (C) 2006 Ian Cowburn <ianc@noddybox.co.uk>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ $Id$
+*/
+
+#include <nds.h>
+#include <stdlib.h>
+
+#include "touchwrap.h"
+#include "config.h"
+
+/* ---------------------------------------- PUBLIC INTERFACES
+*/
+int AllowTouch(touchPosition *tp)
+{
+ static touchPosition last;
+ int16 dx;
+ int16 dy;
+ int res;
+
+ *tp = touchReadXY();
+
+ if (DS81_Config[DS81_AVERAGE_TOUCHSCREEN])
+ {
+ dx = last.px - tp->px;
+ dy = last.py - tp->py;
+
+ res = (abs(dx) < 5 && abs(dy) < 5);
+ }
+ else
+ {
+ res = TRUE;
+ }
+
+ last = *tp;
+
+ return res;
+}
diff --git a/source/zx81.c b/source/zx81.c
index 9a053b5..7964ed1 100644
--- a/source/zx81.c
+++ b/source/zx81.c
@@ -41,9 +41,6 @@
#define FALSE 0
#endif
-#define MAX_FNAME_LEN 30
-
-
/* ---------------------------------------- STATICS
*/
#define ROMLEN 0x2000
@@ -99,6 +96,8 @@ static int enable_filesystem;
static const Z80Byte *tape_image;
static int tape_len;
+static char last_dir[FILENAME_MAX] = "/";
+
/* GFX vars
*/
static uint16 *txt_screen;
@@ -259,58 +258,58 @@ static Z80Byte FromASCII(char c)
*/
static FILE *OpenTapeFile(Z80Word addr)
{
+ static const char zx_chars[] = "\"#$:?()><=+-*/;,."
+ "0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
FILE *fp;
- char fn[MAX_FNAME_LEN];
+ char fn[FILENAME_MAX];
int f;
int done;
- f=0;
- done=FALSE;
+ fp = NULL;
+ f = 0;
+ done = FALSE;
- while(f<(MAX_FNAME_LEN-3) && !done)
+ while(f<(FILENAME_MAX-3) && !done)
{
int ch;
- ch=mem[addr++];
+ ch = mem[addr++];
if (ch&0x80)
{
- done=TRUE;
- ch&=0x7f;
+ done = TRUE;
+ ch &= 0x7f;
}
- switch(ch)
+ if (ch>=11 && ch<=63)
{
- case 22:
- fn[f++]='-';
- break;
-
- case 27:
- fn[f++]='.';
-
- default:
- if (ch>=28 && ch<=37)
- {
- fn[f++]='0'+(ch-28);
- }
- else if (ch>=38 && ch<=63)
- {
- fn[f++]='A'+(ch-38);
- }
- break;
+ fn[f++] = zx_chars[ch-11];
}
}
- fn[f++]='.';
- fn[f++]='P';
- fn[f]=0;
+ if (fn[0] == '*')
+ {
+ if (GUI_FileSelect(last_dir,fn,".P"))
+ {
+ fp = fopen(fn,"rb");
+ }
- if (!(fp=fopen(fn,"rb")))
+ SK_DisplayKeyboard(BG_GFX_SUB);
+ }
+ else
{
- char full_fn[MAX_FNAME_LEN+11]="\\ZX81SNAP\\";
+ fn[f++] = '.';
+ fn[f++] = 'P';
+ fn[f] = 0;
- strcat(full_fn,fn);
- fp=fopen(full_fn,"rb");
+ if (!(fp = fopen(fn,"rb")))
+ {
+ char full_fn[FILENAME_MAX+11] = "/ZX81SNAP/";
+
+ strcat(full_fn,fn);
+ fp = fopen(full_fn,"rb");
+ }
}
return fp;
@@ -378,7 +377,7 @@ static void DrawScreen_HIRES(Z80 *z80)
bmp = bmp_screen;
table = z80->I << 8;
- /* scr is increment in both loops so that it can skip of the end-of-line
+ /* scr is increment in both loops so that it can skip the end-of-line
character
*/
for(y=0; y<192; y++)