Copy in the new GUI code. Builds but will not work now.

This commit is contained in:
simon.kagstrom 2010-01-25 13:01:22 +00:00
parent 4e70ae6205
commit 328c6db22e
67 changed files with 5109 additions and 414 deletions

View File

@ -24,7 +24,7 @@ datadir = ${PREFIX}/share
#GCOV=-fprofile-arcs -ftest-coverage #GCOV=-fprofile-arcs -ftest-coverage
CFLAGS ?=-ggdb -Iinclude -Wall `sdl-config --cflags` CFLAGS ?=-ggdb -Wall `sdl-config --cflags` -ISrc
DEFINES =-DFRODO_SC -DHAVE_CONFIG_H -DDATADIR=\"$(datadir)/frodo/\" -DBINDIR=\"$(bindir)/\" -DHAVE_SDL DEFINES =-DFRODO_SC -DHAVE_CONFIG_H -DDATADIR=\"$(datadir)/frodo/\" -DBINDIR=\"$(bindir)/\" -DHAVE_SDL
LDFLAGS ?= $(GCOV) `sdl-config --libs` -lSDL_ttf -lSDL_image LDFLAGS ?= $(GCOV) `sdl-config --libs` -lSDL_ttf -lSDL_image
@ -32,11 +32,13 @@ LDFLAGS ?= $(GCOV) `sdl-config --libs` -lSDL_ttf -lSDL_image
CPP_SRCS=Src/C64_SC.cpp Src/main.cpp Src/Display.cpp Src/Prefs.cpp Src/SID.cpp \ CPP_SRCS=Src/C64_SC.cpp Src/main.cpp Src/Display.cpp Src/Prefs.cpp Src/SID.cpp \
Src/REU.cpp Src/IEC.cpp Src/1541fs.cpp Src/1541d64.cpp Src/1541t64.cpp \ Src/REU.cpp Src/IEC.cpp Src/1541fs.cpp Src/1541d64.cpp Src/1541t64.cpp \
Src/1541job.cpp Src/SAM.cpp Src/CPUC64_SC.cpp Src/VIC_SC.cpp Src/menu.cpp\ Src/1541job.cpp Src/SAM.cpp Src/CPUC64_SC.cpp Src/VIC_SC.cpp \
Src/CIA_SC.cpp Src/CPU1541_SC.cpp Src/CPU_common.cpp Src/Network.cpp \ Src/CIA_SC.cpp Src/CPU1541_SC.cpp Src/CPU_common.cpp Src/Network.cpp \
Src/VirtualKeyboard.cpp Src/gui/menu_messages.cpp Src/gui/dialogue_box.cpp Src/gui/widget.cpp \
Src/gui/game_info.cpp Src/gui/status_bar.cpp Src/gui/gui.cpp Src/gui/listener.cpp \
C_SRCS=Src/d64-read.c Src/menutexts.c Src/gui/timer.cpp Src/gui/utils.cpp Src/gui/virtual_keyboard.cpp Src/gui/menu.cpp
C_SRCS=Src/d64-read.c
OBJS=$(patsubst %.cpp,objs-host/%.o,$(CPP_SRCS)) $(patsubst %.c,objs-host/%.o,$(C_SRCS)) OBJS=$(patsubst %.cpp,objs-host/%.o,$(CPP_SRCS)) $(patsubst %.c,objs-host/%.o,$(C_SRCS))

View File

@ -530,7 +530,7 @@ bool C64::Load1541JobState(FILE *f)
* snapshot is loaded into FrodoSC again. * snapshot is loaded into FrodoSC again.
*/ */
void C64::SaveSnapshot(char *filename) void C64::SaveSnapshot(const char *filename)
{ {
FILE *f; FILE *f;
uint8 flags; uint8 flags;
@ -595,7 +595,7 @@ void C64::SaveSnapshot(char *filename)
* Load snapshot (emulation must be paused and in VBlank) * Load snapshot (emulation must be paused and in VBlank)
*/ */
bool C64::LoadSnapshot(char *filename) bool C64::LoadSnapshot(const char *filename)
{ {
FILE *f; FILE *f;

View File

@ -21,9 +21,6 @@
#define _C64_H #define _C64_H
#if defined(HAVE_SDL) #if defined(HAVE_SDL)
/* SDL menu */
#include "menu.h"
#include "VirtualKeyboard.h"
#include "Network.h" #include "Network.h"
#include "Prefs.h" #include "Prefs.h"
#endif #endif
@ -90,16 +87,24 @@ public:
void Run(void); void Run(void);
void Quit(void); void Quit(void);
void Pause(void); void Pause(void)
void Resume(void); {
this->have_a_break = true;
}
void Resume(void)
{
this->have_a_break = false;
}
void Reset(void); void Reset(void);
void NMI(void); void NMI(void);
void VBlank(bool draw_frame); void VBlank(bool draw_frame);
void NewPrefs(Prefs *prefs); void NewPrefs(Prefs *prefs);
void PatchKernal(bool fast_reset, bool emul_1541_proc); void PatchKernal(bool fast_reset, bool emul_1541_proc);
void SaveRAM(char *filename); void SaveRAM(char *filename);
void SaveSnapshot(char *filename); void SaveSnapshot(const char *filename);
bool LoadSnapshot(char *filename); bool LoadSnapshot(const char *filename);
int SaveCPUState(FILE *f); int SaveCPUState(FILE *f);
int Save1541State(FILE *f); int Save1541State(FILE *f);
bool Save1541JobState(FILE *f); bool Save1541JobState(FILE *f);
@ -133,6 +138,11 @@ public:
#ifdef FRODO_SC #ifdef FRODO_SC
uint32 CycleCounter; uint32 CycleCounter;
#endif #endif
bool IsPaused()
{
return this->have_a_break;
}
void enter_menu() { void enter_menu() {
this->have_a_break = true; this->have_a_break = true;
} }
@ -201,12 +211,10 @@ public:
double speed_index; double speed_index;
#endif #endif
#ifdef HAVE_SDL #ifdef HAVE_SDL
VirtualKeyboard *virtual_keyboard;
char server_hostname[255]; char server_hostname[255];
int server_port; int server_port;
int network_connection_type; int network_connection_type;
Network *peer; Network *peer;
TTF_Font *menu_font;
int linecnt; int linecnt;
bool fake_key_sequence; bool fake_key_sequence;
@ -219,16 +227,8 @@ public:
void network_vblank(); void network_vblank();
void select_disc(Prefs *np, bool start); void startFakeKeySequence(const char *str);
void start_fake_key_sequence(const char *str);
void run_fake_key_sequence(); void run_fake_key_sequence();
char * bind_one_key(Prefs *np, int which);
void bind_keys(Prefs *np);
void select_fake_key_sequence(Prefs *np);
void advanced_options(Prefs *np);
void other_options(Prefs *np);
void networking_menu(Prefs *np);
void save_load_state(Prefs *np, int do_what);
#endif #endif
#ifdef WIN32 #ifdef WIN32

View File

@ -1,3 +1,4 @@
/* /*
* C64_SC.cpp - Put the pieces together (Frodo SC) * C64_SC.cpp - Put the pieces together (Frodo SC)
* *

View File

@ -10,6 +10,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <dirent.h> #include <dirent.h>
#include "gui/gui.hh"
#include "gui/virtual_keyboard.hh"
#if defined(GEKKO) #if defined(GEKKO)
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
#include <ogc/lwp_watchdog.h> #include <ogc/lwp_watchdog.h>
@ -24,8 +27,6 @@
#define C64_NETWORK_BROKER "c64-network.game-host.org" #define C64_NETWORK_BROKER "c64-network.game-host.org"
#include "menutexts.h"
/* TODO: */ /* TODO: */
extern char *fixme_tmp_network_server; extern char *fixme_tmp_network_server;
@ -54,9 +55,6 @@ void C64::c64_ctor1(void)
memset(this->save_game_name, 0, sizeof(this->save_game_name)); memset(this->save_game_name, 0, sizeof(this->save_game_name));
strcpy(this->save_game_name, "unknown"); strcpy(this->save_game_name, "unknown");
this->virtual_keyboard = new VirtualKeyboard(real_screen, this->menu_font);
virtual_keyboard = this->virtual_keyboard;
strncpy(this->server_hostname, C64_NETWORK_BROKER, strncpy(this->server_hostname, C64_NETWORK_BROKER,
sizeof(this->server_hostname)); sizeof(this->server_hostname));
this->server_port = 46214; this->server_port = 46214;
@ -85,265 +83,11 @@ void C64::c64_dtor(void)
{ {
} }
void C64::select_disc(Prefs *np, bool start)
{
const char *name;
const char *d64_name = NULL;
if (!start)
name = menu_select_file(IMAGE_PATH);
else
name = menu_select_file_start(IMAGE_PATH, &d64_name);
if (name== NULL)
return;
if (strcmp(name, "None") == 0)
{
strcpy(np->DrivePath[0], "\0");
strcpy(this->save_game_name, "unknown");
}
else
{
const char *save_game = strrchr(name, '/');
if (!save_game)
save_game = name;
else
save_game = save_game + 1; /* Skip '/' */
strncpy(np->DrivePath[0], name, 255);
strncpy(this->save_game_name, save_game, 255);
if (strstr(name, ".prg") || strstr(name, ".PRG") ||
strstr(name, ".p00") || strstr(name, ".P00") ||
strstr(name, ".s00") || strstr(name, ".S00")) {
FILE *src, *dst;
/* Clean temp dir first (we only want one file) */
unlink(TMP_PATH"/a");
src = fopen(np->DrivePath[0], "r");
if (src != NULL)
{
snprintf(np->DrivePath[0], 255, "%s", TMP_PATH);
/* Special handling of .prg: Copy to TMP_PATH and
* load that as a dir */
dst = fopen(TMP_PATH"/a", "w");
if (dst)
{
Uint8 buf[1024];
size_t v;
do {
v = fread(buf, 1, 1024, src);
fwrite(buf, 1, v, dst);
} while (v > 0);
fclose(dst);
}
fclose(src);
}
}
NewPrefs(np);
ThePrefs = *np;
}
this->prefs_changed = true;
/* Cleanup*/
free((void*)name);
/* And maybe start the game */
if (d64_name)
{
static char buf[255];
snprintf(buf, 255, "\nLOAD \"%s\",8,1\nRUN\n", d64_name);
this->start_fake_key_sequence((const char*)buf);
free((void*)d64_name);
}
else if (start)
this->start_fake_key_sequence("\nLOAD \"*\",8,1\nRUN\n");
}
char *C64::bind_one_key(Prefs *np, int which)
{
static const char *which_to_button_name[N_WIIMOTE_BINDINGS] = {
"up", "down", "left", "right",
"2", "1", "A", "B", "+", "-",
"classic up", "classic down", "classic left", "classic right", "classic a",
"classic b", "classic X", "classic Y", "classic L",
"classic R", "classic ZR", "classic ZL" };
static char strs[N_WIIMOTE_BINDINGS][255];
char *out = strs[which];
int cur = np->JoystickKeyBinding[which];
snprintf(out, 255, "Bind to %s (now %s)", which_to_button_name[which],
this->virtual_keyboard->keycode_to_string(cur));
return out;
}
void C64::bind_keys(Prefs *np)
{
const char *bind_key_messages[N_WIIMOTE_BINDINGS + 1];
bool has_classic_controller = false;
#if defined(GEKKO)
WPADData *wpad, *wpad_other;
wpad = WPAD_Data(0);
wpad_other = WPAD_Data(1);
if (wpad->exp.type == WPAD_EXP_CLASSIC ||
wpad_other->exp.type == WPAD_EXP_CLASSIC)
has_classic_controller = true;
#endif
memset(bind_key_messages, 0, sizeof(const char*) * (N_WIIMOTE_BINDINGS + 1));
for (int i = 0; i < (has_classic_controller ? N_WIIMOTE_BINDINGS : CLASSIC_UP); i++)
bind_key_messages[i] = this->bind_one_key(np, i);
int opt = menu_select(bind_key_messages, NULL);
if (opt >= 0)
{
int key;
bool shifted;
key = this->virtual_keyboard->get_key();
/* -2 means abort */
if (key != np->JoystickKeyBinding[opt] && key != -2)
{
this->prefs_changed = true;
np->JoystickKeyBinding[opt] = key;
}
}
}
void C64::networking_menu(Prefs *np)
{
int opt;
do
{
char buf[3][255];
const char *network_client_messages[] = {
buf[0], /* 0 */
buf[1], /* 1 */
buf[2], /* 2 */
"#2 ", /* 3 */
"Connect to the C64 network!", /* 4 */
NULL,
};
snprintf(buf[0], 255, "Set username (%s)",
np->NetworkName);
snprintf(buf[1], 255, "Server hostname (%s)",
this->server_hostname);
snprintf(buf[2], 255, "Port (%d)",
this->server_port);
opt = menu_select("Networking", network_client_messages, NULL);
if (opt >= 0 && opt <= 2)
{
const char *m = this->virtual_keyboard->get_string();
if (m)
{
if (opt == 0)
{
memset(np->NetworkName, 0,
sizeof(np->NetworkName));
strncpy(np->NetworkName, m,
sizeof(np->NetworkName));
} else if (opt == 1)
strncpy(this->server_hostname, m,
sizeof(this->server_hostname));
if (opt == 2)
this->server_port = atoi(m);
}
}
else if (opt == 4) {
if (strncmp(np->NetworkName, "Unset", 5) == 0)
{
char *msg = "Select name first";
msgYesNo(msg, false, 160, 160);
continue;
}
this->peer = new Network(this->server_hostname, this->server_port);
this->network_connection_type = CONNECT;
}
} while (opt >= 0 && opt <= 2);
this->prefs_changed = true;
}
void C64::advanced_options(Prefs *np)
{
int submenus[4] = { np->DisplayOption, 0,
np->SpriteCollisions, 0 };
#define SPEED_95 30
#define SPEED_100 20
#define SPEED_110 18
switch (np->MsPerFrame)
{
case SPEED_95:
submenus[1] = 0; break;
case SPEED_110:
submenus[1] = 2; break;
default:
/* If it has some other value... */
submenus[1] = 1; break;
}
int opt = menu_select("Advanced options",
new_advanced_options_menu_messages,
submenus);
if (opt >= 0)
{
np->DisplayOption = submenus[0];
np->SpriteCollisions = submenus[2];
switch(submenus[1])
{
case 0:
np->MsPerFrame = SPEED_95; break;
case 1:
np->MsPerFrame = SPEED_100; break;
case 2:
default:
np->MsPerFrame = SPEED_110; break;
}
this->prefs_changed = true;
}
}
void C64::other_options(Prefs *np)
{
int old_swap = np->JoystickSwap == true ? 1 : 0;
int submenus[3] = { old_swap, !np->Emul1541Proc, 0 };
int opt = menu_select("Options", new_options_menu_messages,
submenus);
if (opt >= 0)
{
np->Emul1541Proc = submenus[1] == 0 ? true : false;
np->JoystickSwap = submenus[0] == 0 ? false : true;
this->prefs_changed = true;
}
}
/* From dreamcast port but heavily modified */ /* From dreamcast port but heavily modified */
void C64::run_fake_key_sequence() void C64::run_fake_key_sequence()
{ {
int kc = this->virtual_keyboard->char_to_keycode(this->fake_key_str[this->fake_key_index]); int kc = Gui::gui->kbd->charToKeycode(this->fake_key_str[this->fake_key_index]);
TheDisplay->FakeKeyPress(kc, TheCIA1->KeyMatrix, TheCIA1->RevMatrix); TheDisplay->FakeKeyPress(kc, TheCIA1->KeyMatrix, TheCIA1->RevMatrix);
@ -363,80 +107,12 @@ void C64::run_fake_key_sequence()
} }
} }
void C64::start_fake_key_sequence(const char *str) void C64::startFakeKeySequence(const char *str)
{ {
this->fake_key_str = str; this->fake_key_str = str;
this->fake_key_sequence = true; this->fake_key_sequence = true;
} }
void C64::select_fake_key_sequence(Prefs *np)
{
static const char *fake_key_sequences[] = {
"\nLOAD \"*\",8,1\nRUN\n",
"\nLOAD \"$\",8\n",
"\nLIST\n",
NULL};
const char *fake_key_messages[] = {
"LOAD \"*\",8,1 and RUN",
"LOAD \"$\",8",
"LIST",
NULL};
int opt;
opt = menu_select("Keyboard macros", fake_key_messages, NULL);
if (opt < 0)
return;
this->start_fake_key_sequence(fake_key_sequences[opt]);
}
void C64::save_load_state(Prefs *np, int opt)
{
switch(opt)
{
case 1: /* save */
{
char save_buf[255];
char prefs_buf[255];
snprintf(save_buf, 255, "%s/%s.sav", SAVES_PATH,
this->save_game_name);
snprintf(prefs_buf, 255, "%s.prefs", save_buf);
this->SaveSnapshot(save_buf);
np->Save(prefs_buf);
} break;
case 0: /* load/delete */
case 2:
{
const char *name = menu_select_file(SAVES_PATH);
char save_buf[255];
char prefs_buf[255];
if (name == NULL)
break;
snprintf(save_buf, 255, "%s", name);
snprintf(prefs_buf, 255, "%s.prefs", save_buf);
if (opt == 2)
{
unlink(save_buf);
unlink(prefs_buf);
}
else /* Load the snapshot */
{
this->LoadSnapshot(save_buf);
np->Load(prefs_buf);
this->prefs_changed = true;
}
free((void*)name);
} break;
default:
break;
}
}
/* /*
* Start main emulation thread * Start main emulation thread
*/ */
@ -642,63 +318,11 @@ void C64::VBlank(bool draw_frame)
} }
if (this->have_a_break) { if (this->have_a_break) {
int submenus[3] = {1, 0, 0};
int opt;
Prefs np = ThePrefs; Prefs np = ThePrefs;
this->prefs_changed = false; this->prefs_changed = false;
TheSID->PauseSound(); TheSID->PauseSound();
opt = menu_select("Main menu", new_main_menu_messages, submenus);
switch(opt)
{
case 0: /* Insert disc/tape */
this->select_disc(&np, submenus[0] == 1);
break;
case 2: /* Save / load game */
this->save_load_state(&np, submenus[1]);
break;
case 4: /* Bind keys to joystick */
switch (submenus[2])
{
case 0: /* type */
{
const char *seq = this->virtual_keyboard->get_string();
if (seq != NULL)
this->start_fake_key_sequence(seq);
} break;
case 1: /* Macro */
this->select_fake_key_sequence(&np); break;
default:
case 2: /* Bind to controller */
this->bind_keys(&np); break;
}
break;
case 7: /* Reset the C64 */
Reset();
break;
case 8: /* Networking */
this->networking_menu(&np);
break;
case 9: /* Other options */
this->other_options(&np);
break;
case 10: /* Advanced options */
this->advanced_options(&np);
break;
case 11:
{
menu_select("Frodo help", welcome, NULL);
} break;
case 12: /* Quit */
quit_thyself = true;
break;
case -1:
default:
break;
}
if (this->prefs_changed) if (this->prefs_changed)
{ {

View File

@ -24,6 +24,8 @@
#include "Version.h" #include "Version.h"
#include "CIA.h" #include "CIA.h"
#include "gui/gui.hh"
#include "gui/virtual_keyboard.hh"
#include <SDL.h> #include <SDL.h>
#if defined(GEKKO) #if defined(GEKKO)
@ -626,7 +628,7 @@ void C64Display::TranslateKey(SDLKey key, bool key_up, uint8 *key_matrix,
shift_on = false; shift_on = false;
else if (!key_up && this->entering_text_message) else if (!key_up && this->entering_text_message)
{ {
char c = virtual_keyboard->keycode_to_char(c64_key | (shift_on ? 0x80 : 0) ); char c = Gui::gui->kbd->keycodeToChar(c64_key | (shift_on ? 0x80 : 0) );
if (this->text_message_idx >= sizeof(this->text_message) - 2 || if (this->text_message_idx >= sizeof(this->text_message) - 2 ||
c == '\n') c == '\n')

View File

@ -24,7 +24,6 @@
#include "Prefs.h" #include "Prefs.h"
#include "main.h" #include "main.h"
#include "C64.h" #include "C64.h"
#include "menu.h"
#if defined(GEKKO) #if defined(GEKKO)
# include <wiiuse/wpad.h> # include <wiiuse/wpad.h>
@ -1088,7 +1087,7 @@ network_connection_error_t Network::WaitForPeerList()
return VERSION_ERROR; return VERSION_ERROR;
} }
#endif #endif
int sel = menu_select_peer(pi->peers, pi->n_peers); int sel = 0; // FIXME! menu_select_peer(pi->peers, pi->n_peers);
/* FIXME! What to do here??? */ /* FIXME! What to do here??? */
if (sel < 0) if (sel < 0)

View File

@ -21,6 +21,10 @@
#ifndef _PREFS_H #ifndef _PREFS_H
#define _PREFS_H #define _PREFS_H
#define SPEED_95 30
#define SPEED_100 20
#define SPEED_110 18
#define MAX_JOYSTICK_AXES 32 #define MAX_JOYSTICK_AXES 32
#define MAX_JOYSTICK_BUTTONS 32 #define MAX_JOYSTICK_BUTTONS 32
#define MAX_JOYSTICK_HATS 8 #define MAX_JOYSTICK_HATS 8
@ -165,9 +169,13 @@ private:
uint32 MsPerFrame; uint32 MsPerFrame;
#endif #endif
int JoystickAxes[MAX_JOYSTICK_AXES]; int JoystickAxes[MAX_JOYSTICK_AXES];
int JoystickHats[MAX_JOYSTICK_AXES];
int JoystickButtons[MAX_JOYSTICK_BUTTONS]; int JoystickButtons[MAX_JOYSTICK_BUTTONS];
char NetworkName[32]; char NetworkName[32];
char NetworkServer[64];
int NetworkPort;
int NetworkKey; int NetworkKey;
uint32 NetworkAvatar; uint32 NetworkAvatar;
}; };

44
Src/gui/Makefile Normal file
View File

@ -0,0 +1,44 @@
CXX = g++
CC = gcc
LD = g++
CPP = cpp
ERROR_FILTER := 2>&1 | sed -e 's/\(.[a-zA-Z]\+\):\([0-9]\+\):/\1(\2):/g'
CFLAGS ?=-ggdb -Iinclude -Wall `sdl-config --cflags` -Imocks
DEFINES =
LDFLAGS ?= $(GCOV) `sdl-config --libs` -lSDL_ttf -lSDL_image
CPP_SRCS=menu.cpp main.cpp utils.cpp gui.cpp dialogue_box.cpp menu_messages.cpp \
timer.cpp game_info.cpp widget.cpp virtual_keyboard.cpp listener.cpp \
status_bar.cpp
OBJS=$(patsubst %.cpp,objs/%.o,$(CPP_SRCS)) $(patsubst %.c,objs/%.o,$(C_SRCS))
DEPS=$(patsubst %.cpp,deps/%.d,$(CPP_SRCS)) $(patsubst %.c,deps/%.d,$(C_SRCS))
TARGET=menu
all: $(DEPS) $(TARGET)
deps/%.d: %.cpp
@echo makedep $(notdir $<)
@install -d deps/$(dir $<)
@$(CPP) -M -MT objs/$(patsubst %.cpp,%.o,$<) $(DEFINES) $(CFLAGS) -o $@ $<
objs/%.o: %.cpp
@echo CXX $(notdir $<)
@install -d objs/$(dir $<)
@$(CXX) $(CFLAGS) $(DEFINES) -c -o $@ $< $(ERROR_FILTER)
clean:
rm -rf $(TARGET) *~ objs deps
$(TARGET): $(OBJS)
@echo LD $@
@$(LD) $(LDFLAGS) -o $@ $+
-include $(DEPS)

468
Src/gui/bind_keys_menu.cpp Normal file
View File

@ -0,0 +1,468 @@
#include "gui.hh"
#include "menu.hh"
#include "help_box.hh"
#include "dialogue_box.hh"
#include "virtual_keyboard.hh"
class BindKeysMenu;
class AnalogueBindListener : public DialogueListener
{
public:
AnalogueBindListener(BindKeysMenu *menu)
{
this->menu = menu;
}
void escapeCallback(DialogueBox *which, int selected)
{
delete this;
}
void selectCallback(DialogueBox *which, int selected);
private:
BindKeysMenu *menu;
};
class BindKeysView;
class BindKeysMenu : public Menu, public KeyboardListener
{
/* This is a very popular class with many friends */
friend class BindKeysView;
friend class AnalogueBindListener;
public:
BindKeysMenu(Font *font, HelpBox *help) : Menu(font)
{
this->help = help;
memset(this->hm, 0, sizeof(this->hm));
this->setText(bind_key_menu_messages);
}
~BindKeysMenu()
{
this->freeHelpMessages();
}
virtual void selectCallback(int which)
{
int *ck = NULL;
/* Either the virtual keyboard or the analogue menu */
bool use_virtkbd = true;
switch(which)
{
case 0: /* Classic */
switch (this->p_submenus[0].sel)
{
case 0: ck = &Gui::gui->np->JoystickHats[0]; break;
case 1: ck = &Gui::gui->np->JoystickHats[1]; break;
case 2: ck = &Gui::gui->np->JoystickHats[2]; break;
case 3: ck = &Gui::gui->np->JoystickHats[3]; break;
case 4: ck = &Gui::gui->np->JoystickButtons[0]; break;
case 5: ck = &Gui::gui->np->JoystickButtons[1]; break;
case 6: ck = &Gui::gui->np->JoystickButtons[2]; break;
case 7: ck = &Gui::gui->np->JoystickButtons[3]; break;
case 8: ck = &Gui::gui->np->JoystickButtons[4]; break;
default:
panic("Classic: impossible selection %d", this->p_submenus[0].sel); break;
}
break;
case 2: /* Nunchuk */
switch (this->p_submenus[1].sel)
{
case 0: ck = &Gui::gui->np->JoystickAxes[0]; use_virtkbd = false; break;
case 1: ck = &Gui::gui->np->JoystickAxes[1]; use_virtkbd = false; break;
case 2: ck = &Gui::gui->np->JoystickButtons[7]; break;
case 3: ck = &Gui::gui->np->JoystickButtons[8]; break;
default:
panic("Nunchuk: impossible selection %d", this->p_submenus[1].sel); break;
}
break;
case 4: /* Classic */
switch (this->p_submenus[2].sel)
{
case 0: ck = &Gui::gui->np->JoystickHats[0]; break;
case 1: ck = &Gui::gui->np->JoystickHats[1]; break;
case 2: ck = &Gui::gui->np->JoystickHats[2]; break;
case 3: ck = &Gui::gui->np->JoystickHats[3]; break;
case 4: ck = &Gui::gui->np->JoystickButtons[9]; break;
case 5: ck = &Gui::gui->np->JoystickButtons[10]; break;
case 6: ck = &Gui::gui->np->JoystickButtons[11]; break;
case 7: ck = &Gui::gui->np->JoystickButtons[12]; break;
case 8: ck = &Gui::gui->np->JoystickButtons[13]; break;
case 9: ck = &Gui::gui->np->JoystickButtons[14]; break;
case 10: ck = &Gui::gui->np->JoystickButtons[15]; break;
case 11: ck = &Gui::gui->np->JoystickButtons[16]; break;
case 12: ck = &Gui::gui->np->JoystickButtons[17]; break;
case 13: ck = &Gui::gui->np->JoystickButtons[18]; break;
default:
panic("Classic: impossible selection %d", this->p_submenus[2].sel); break;
}
break;
case 6:
switch (this->p_submenus[3].sel)
{
case 0: ck = &Gui::gui->np->JoystickAxes[0]; use_virtkbd = false; break;
case 1: ck = &Gui::gui->np->JoystickAxes[1]; use_virtkbd = false; break;
default:
panic("Classic: impossible selection %d", this->p_submenus[3].sel); break;
}
break;
case 8:
switch (this->p_submenus[4].sel)
{
case 0: ck = &Gui::gui->np->JoystickAxes[2]; use_virtkbd = false; break;
case 1: ck = &Gui::gui->np->JoystickAxes[3]; use_virtkbd = false; break;
default:
panic("Classic: impossible selection %d", this->p_submenus[4].sel); break;
}
break;
case 11:
printf("Resetting joystick setup to defaults\n");
Gui::gui->popView();
return;
default:
panic("Impossible menu option\n");
break;
}
this->cur_key = ck;
if (use_virtkbd)
{
VirtualKeyboard::kbd->activate();
VirtualKeyboard::kbd->registerListener(this);
}
else
{
AnalogueBindListener *bl = new AnalogueBindListener(this);
DialogueBox *dlg = new DialogueBox(select_analogue_dlg);
dlg->registerListener(bl);
Gui::gui->pushDialogueBox(dlg);
}
}
virtual void hoverCallback(int which)
{
this->help->updateHelpMessage(which);
}
virtual void escapeCallback(int which)
{
Gui::gui->popView();
}
virtual void keyCallback(bool shift, const char *str)
{
panic_if(!this->cur_key, "No key selected but keyboard active???\n");
*this->cur_key = this->stringToKeycode(str);
this->updateHelpMessages();
this->help->updateHelpMessage(this->cur_sel);
VirtualKeyboard::kbd->deactivate();
this->cur_key = NULL;
}
void updateHelpMessages()
{
this->freeHelpMessages();
this->hm[0] = this->addOne(this->hm[0], this->allocOne("Up: %s", stringToPtr_Wiimote("Up")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("Down: %s", stringToPtr_Wiimote("Down")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("Left: %s", stringToPtr_Wiimote("Left")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("Right: %s", stringToPtr_Wiimote("Right")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("A: %s", stringToPtr_Wiimote("A")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("B: %s", stringToPtr_Wiimote("B")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("+: %s", stringToPtr_Wiimote("+")));
this->hm[0] = this->addOne(this->hm[0], this->allocOne("-: %s", stringToPtr_Wiimote("-")));
/* Nunchuk */
this->hm[2] = this->addOne(this->hm[2], this->allocOne("Horiz: %s", stringToPtr_Nunchuk("Horiz")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("Vert: %s", stringToPtr_Nunchuk("Vert")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("Z: %s", stringToPtr_Nunchuk("Z")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("C: %s", stringToPtr_Nunchuk("C")));
/* Classic */
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Up: %s", stringToPtr_Classic("Up")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Down: %s", stringToPtr_Classic("Down")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Left: %s", stringToPtr_Classic("Left")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Right: %s", stringToPtr_Classic("Right")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("a: %s", stringToPtr_Classic("a")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("b: %s", stringToPtr_Classic("b")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("x: %s", stringToPtr_Classic("x")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("y: %s", stringToPtr_Classic("y")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zl: %s", stringToPtr_Classic("Zl")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("Zr: %s", stringToPtr_Classic("Zr")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("+: %s", stringToPtr_Classic("+")));
this->hm[4] = this->addOne(this->hm[4], this->allocOne("-: %s", stringToPtr_Classic("-")));
/*
this->hm[2] = this->addOne(this->hm[2], this->allocOne("l: %s", stringToPtr_Classic("l")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("r: %s", stringToPtr_Classic("r")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("R-toggle: %s", stringToPtr_Classic("RA")));
this->hm[2] = this->addOne(this->hm[2], this->allocOne("L-toggle: %s", stringToPtr_Classic("LA")));
*/
this->hm[6] = this->addOne(this->hm[6], this->allocOne("Horiz: %s", stringToPtr_Classic("LAH")));
this->hm[6] = this->addOne(this->hm[6], this->allocOne("Vert: %s", stringToPtr_Classic("LAV")));
this->hm[8] = this->addOne(this->hm[8], this->allocOne("Horiz: %s", stringToPtr_Classic("RAH")));
this->hm[8] = this->addOne(this->hm[8], this->allocOne("Vert: %s", stringToPtr_Classic("RAV")));
this->hm[11] = this->addOne(this->hm[11], "Revert to defaults");
this->help->setHelpMessages(this->hm);
}
private:
void freeHelpMessages()
{
for (unsigned i = 0; i < ARRAY_SIZE(this->hm); i++)
{
if (this->hm[i])
{
for (int j = 0; this->hm[i][j]; j++)
free((void*)this->hm[i][j]);
free(this->hm[i]);
}
this->hm[i] = NULL;
}
}
#define EQ(b) (strcmp(str, b) == 0)
int *stringToPtr_Classic(const char *str)
{
if (EQ("Up"))
return &Gui::gui->np->JoystickHats[0];
if (EQ("Down"))
return &Gui::gui->np->JoystickHats[1];
if (EQ("Left"))
return &Gui::gui->np->JoystickHats[2];
if (EQ("Right"))
return &Gui::gui->np->JoystickHats[3];
if (EQ("LAH"))
return &Gui::gui->np->JoystickAxes[0];
if (EQ("LAV"))
return &Gui::gui->np->JoystickAxes[1];
if (EQ("RAH"))
return &Gui::gui->np->JoystickAxes[2];
if (EQ("RAV"))
return &Gui::gui->np->JoystickAxes[3];
if (EQ("RA"))
return &Gui::gui->np->JoystickAxes[4];
if (EQ("LA"))
return &Gui::gui->np->JoystickAxes[5];
if (EQ("a"))
return &Gui::gui->np->JoystickButtons[9];
if (EQ("b"))
return &Gui::gui->np->JoystickButtons[10];
if (EQ("x"))
return &Gui::gui->np->JoystickButtons[11];
if (EQ("y"))
return &Gui::gui->np->JoystickButtons[12];
if (EQ("L"))
return &Gui::gui->np->JoystickButtons[13];
if (EQ("R"))
return &Gui::gui->np->JoystickButtons[14];
if (EQ("Zl"))
return &Gui::gui->np->JoystickButtons[15];
if (EQ("Zr"))
return &Gui::gui->np->JoystickButtons[16];
if (EQ("-"))
return &Gui::gui->np->JoystickButtons[17];
if (EQ("+"))
return &Gui::gui->np->JoystickButtons[18];
if (EQ("Home"))
return &Gui::gui->np->JoystickButtons[19];
/* Shound never happen! */
panic("Illegal string %s\n", str);
return NULL;
}
int *stringToPtr_Nunchuk(const char *str)
{
if (EQ("Horiz"))
return &Gui::gui->np->JoystickAxes[0];
if (EQ("Vert"))
return &Gui::gui->np->JoystickAxes[1];
if (EQ("Z"))
return &Gui::gui->np->JoystickButtons[7];
if (EQ("C"))
return &Gui::gui->np->JoystickButtons[8];
/* Shound never happen! */
panic("Illegal string %s\n", str);
return NULL;
}
int *stringToPtr_Wiimote(const char *str)
{
if (EQ("Up"))
return &Gui::gui->np->JoystickHats[0];
if (EQ("Down"))
return &Gui::gui->np->JoystickHats[1];
if (EQ("Left"))
return &Gui::gui->np->JoystickHats[2];
if (EQ("Right"))
return &Gui::gui->np->JoystickHats[3];
if (EQ("A"))
return &Gui::gui->np->JoystickButtons[0];
if (EQ("B"))
return &Gui::gui->np->JoystickButtons[1];
if (EQ("1"))
return &Gui::gui->np->JoystickButtons[2];
if (EQ("2"))
return &Gui::gui->np->JoystickButtons[3];
if (EQ("+"))
return &Gui::gui->np->JoystickButtons[4];
if (EQ("-"))
return &Gui::gui->np->JoystickButtons[5];
if (EQ("Home"))
return &Gui::gui->np->JoystickButtons[6];
/* Shound never happen! */
panic("Illegal string %s\n", str);
return NULL;
}
#undef EQ
const char **addOne(const char **dst, const char *what)
{
int cur;
int n = 0;
if (dst != NULL)
{
for (n = 0; dst[n]; n++)
;
}
cur = n;
n++;
dst = (const char **)xrealloc(dst, (n+1) * sizeof(const char*));
dst[cur] = what;
dst[n] = NULL;
return dst;
}
const char *allocOne(const char *fmt, int *what)
{
const char *str = this->bindingToString(*what);
size_t len = strlen(str) + strlen(fmt) + 2;
char *out = (char *)xmalloc(len);
sprintf(out, fmt, str);
return out;
}
int stringToKeycode(const char *str)
{
if (strcmp(str, "None") == 0)
return 0;
/* default: */
return VirtualKeyboard::kbd->stringToKeycode(str);
}
const char *bindingToString(int val)
{
switch(val)
{
case JOY_NONE:
return "None";
case JOY_HORIZ:
return "Horizontal";
case JOY_VERT:
return "Vertical";
case JOY_FIRE:
return "Fire";
default:
break;
}
/* default: */
return VirtualKeyboard::kbd->keycodeToString(val);
}
HelpBox *help;
int *cur_key;
const char **hm[12];
};
void AnalogueBindListener::selectCallback(DialogueBox *which, int selected)
{
switch(selected)
{
case 1:
*menu->cur_key = JOY_HORIZ; break;
case 2:
*menu->cur_key = JOY_VERT; break;
case 0:
default:
*menu->cur_key = JOY_NONE; break;
}
this->menu->updateHelpMessages();
this->menu->help->updateHelpMessage(this->menu->cur_sel);
delete this;
}
class BindKeysView : public GuiView
{
public:
BindKeysView() : GuiView()
{
this->help = new HelpBox(Gui::gui->small_font, NULL);
this->menu = new BindKeysMenu(Gui::gui->small_font, this->help);
}
~BindKeysView()
{
delete this->help;
delete this->menu;
}
void viewPushCallback()
{
this->menu->updateHelpMessages();
this->help->updateHelpMessage(0);
}
void runLogic()
{
this->menu->runLogic();
}
void pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->disc_info, NULL, where, &dst);
this->menu->draw(where, 50, 70, 300, 400);
this->help->draw(where, 354, 24, 264, 210);
}
protected:
BindKeysMenu *menu;
HelpBox *help;
};

72
Src/gui/dialogue_box.cpp Normal file
View File

@ -0,0 +1,72 @@
#include "dialogue_box.hh"
void DialogueListener::escapeCallback(DialogueBox *which, int selected)
{
Gui::gui->popDialogueBox();
}
void DialogueListener::selectCallback(DialogueBox *which, int selected)
{
Gui::gui->popDialogueBox();
}
DialogueBox::DialogueBox(const char *msgs[], bool delete_on_action) : Menu(NULL), ListenerManager()
{
this->setFont(Gui::gui->default_font);
this->setSelectedBackground(NULL, NULL, NULL,
Gui::gui->bg_left, Gui::gui->bg_middle,
Gui::gui->bg_right);
this->setText(msgs, NULL);
/* Place on the second to last entry */
this->cur_sel = this->n_entries - 2;
this->delete_on_action = delete_on_action;
}
int DialogueBox::selectNext(event_t ev)
{
/* No up/down movement please! */
if (ev == KEY_UP || ev == KEY_DOWN)
return this->cur_sel;
return Menu::selectNext(ev);
}
void DialogueBox::selectCallback(int which)
{
for (int i = 0; i < this->nListeners(); i++)
if (this->listeners[i])
((DialogueListener*)this->listeners[i])->selectCallback(this,
this->p_submenus[0].sel);
Gui::gui->popDialogueBox();
if (this->delete_on_action)
delete this;
}
void DialogueBox::hoverCallback(int which)
{
}
void DialogueBox::escapeCallback(int which)
{
for (int i = 0; i < this->nListeners(); i++)
if (this->listeners[i])
((DialogueListener*)this->listeners[i])->selectCallback(this,
this->p_submenus[0].sel);
Gui::gui->popDialogueBox();
if (this->delete_on_action)
delete this;
}
void DialogueBox::draw(SDL_Surface *where)
{
int d_x = where->w / 2 - Gui::gui->dialogue_bg->w / 2;
int d_y = where->h / 2 - Gui::gui->dialogue_bg->h / 2;
SDL_Rect dst = (SDL_Rect){d_x, d_y,
Gui::gui->dialogue_bg->w, Gui::gui->dialogue_bg->h};
SDL_BlitSurface(Gui::gui->dialogue_bg, NULL, where, &dst);
Menu::draw(where, d_x + 10, d_y + 10,
Gui::gui->dialogue_bg->w - 10, Gui::gui->dialogue_bg->h - 10);
}

38
Src/gui/dialogue_box.hh Normal file
View File

@ -0,0 +1,38 @@
#ifndef __DIALOGUE_BOX_HH__
#define __DIALOGUE_BOX_HH__
#include "menu.hh"
#include "listener.hh"
#include "gui_view.hh"
#include "gui.hh"
class DialogueBox;
class DialogueListener : public Listener
{
public:
virtual void selectCallback(DialogueBox *which, int selected);
virtual void escapeCallback(DialogueBox *which, int selected);
};
class DialogueBox : public Menu, public ListenerManager
{
public:
DialogueBox(const char *msgs[], bool delete_on_action = true);
virtual void selectCallback(int which);
virtual void escapeCallback(int which);
virtual void hoverCallback(int which);
virtual int selectNext(event_t ev);
virtual void draw(SDL_Surface *where);
protected:
bool delete_on_action;
};
#endif /* __DIALOGUE_BOX_HH__ */

186
Src/gui/disc_menu.cpp Normal file
View File

@ -0,0 +1,186 @@
#include <unistd.h> /* unlink */
#include <C64.h>
#include "menu.hh"
#include "file_browser.hh"
#include "game_info.hh"
#include "game_info_box.hh"
#include "utils.hh"
static const char *game_exts[] = {".d64", ".D64", ".t64", ".T64",
".prg",".PRG", ".p00", ".P00", NULL};
static const char *prg_exts[] = {".prg",".PRG", ".p00", ".P00", NULL};
class DiscMenu;
class DiscView : public GuiView
{
public:
DiscView();
~DiscView();
void pushEvent(SDL_Event *ev);
void loadGameInfo(const char *what);
void setDirectory(const char *path);
void runStartSequence(bool what);
/* Inherited */
void runLogic();
void draw(SDL_Surface *where);
DiscMenu *menu;
GameInfoBox *gameInfo;
};
class DiscMenu : public FileBrowser, TimeoutHandler
{
friend class DiscView;
public:
DiscMenu(Font *font) :
FileBrowser(game_exts, font), TimeoutHandler()
{
this->runStartSequence = false;
}
~DiscMenu()
{
}
virtual void selectCallback(int which)
{
const char *fileName = this->pp_msgs[this->cur_sel];
const char *save_game = strrchr(fileName, '/');
if (!save_game)
save_game = fileName;
else
save_game = save_game + 1; /* Skip '/' */
strncpy(Gui::gui->np->DrivePath[0], fileName, sizeof(Gui::gui->np->DrivePath[0]));
if (ext_matches_list(fileName, prg_exts)) {
char tmp_filename[255];
FILE *src, *dst;
snprintf(tmp_filename, sizeof(tmp_filename), "%s/a", Gui::gui->tmp_path);
/* Clean temp dir first (we only want one file) */
unlink(tmp_filename);
src = fopen(Gui::gui->np->DrivePath[0], "r");
if (src != NULL)
{
snprintf(Gui::gui->np->DrivePath[0], sizeof(Gui::gui->np->DrivePath[0]),
"%s", Gui::gui->tmp_path);
/* Special handling of .prg: Copy to TMP_PATH and
* load that as a dir */
dst = fopen(tmp_filename, "w");
if (dst)
{
Uint8 buf[1024];
size_t v;
do {
v = fread(buf, 1, sizeof(buf), src);
fwrite(buf, 1, v, dst);
} while (v > 0);
fclose(dst);
}
fclose(src);
}
}
Gui::gui->timerController->disarm(this);
Gui::gui->dv->loadGameInfo(fileName);
if (Gui::gui->dv->gameInfo->gi)
Gui::gui->updateGameInfo(Gui::gui->dv->gameInfo->gi);
else
Gui::gui->updateGameInfo(new GameInfo(fileName));
Gui::gui->popView();
if (this->runStartSequence)
TheC64->startFakeKeySequence("\nLOAD \"*\",8,1\nRUN\n");
}
virtual void hoverCallback(int which)
{
Gui::gui->timerController->arm(this, 100);
}
virtual void timeoutCallback()
{
printf("Hovering timed out over %s\n",
this->pp_msgs[this->cur_sel]);
Gui::gui->dv->loadGameInfo(this->pp_msgs[this->cur_sel]);
}
virtual void escapeCallback(int which)
{
Gui::gui->timerController->disarm(this);
Gui::gui->popView();
}
bool runStartSequence;
};
DiscView::DiscView() : GuiView()
{
this->menu = new DiscMenu(Gui::gui->default_font);
this->gameInfo = new GameInfoBox(Gui::gui->default_font);
}
DiscView::~DiscView()
{
delete this->menu;
delete this->gameInfo;
}
void DiscView::loadGameInfo(const char *what)
{
this->gameInfo->loadGameInfo(what);
}
void DiscView::setDirectory(const char *path)
{
this->menu->setDirectory(path);
}
void DiscView::runStartSequence(bool what)
{
this->menu->runStartSequence = what;
}
void DiscView::runLogic()
{
this->menu->runLogic();
}
void DiscView::pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void DiscView::draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->disc_info, NULL, where, &dst);
this->menu->draw(where, 50, 70, 280, 375);
this->gameInfo->draw(where, 360, 55, 262, 447);
}

57
Src/gui/file_browser.hh Normal file
View File

@ -0,0 +1,57 @@
#ifndef __FILE_BROWSER_HH__
#define __FILE_BROWSER_HH__
#include "menu.hh"
#include "gui.hh"
class FileBrowser : public Menu
{
public:
FileBrowser(const char **exts, Font *font) : Menu(font)
{
this->path = NULL;
this->exts = exts;
if (!this->exts)
this->exts = (const char **){ NULL };
/* If nothing else: Set the default list */
this->setDefaultFileList();
}
~FileBrowser()
{
this->freeFileList();
}
void setDirectory(const char *path)
{
this->freeFileList();
this->file_list = get_file_list(path, this->exts);
if (!this->file_list)
this->setDefaultFileList();
this->setText(this->file_list);
}
protected:
void setDefaultFileList()
{
this->file_list = (const char **)xmalloc(2 * sizeof(char*));
this->file_list[0] = xstrdup("None");
}
void freeFileList()
{
if (!this->file_list)
return;
for (int i = 0; this->file_list[i]; i++)
free((void*)this->file_list[i]);
free(this->file_list);
}
const char *path;
const char **file_list;
const char **exts;
};
#endif /* __FILE_BROWSER_HH__ */

35
Src/gui/font.hh Normal file
View File

@ -0,0 +1,35 @@
#ifndef __FONT_HH__
#define __FONT_HH__
#include <SDL.h>
class Font
{
public:
virtual ~Font()
{
}
virtual int getHeight(const char *str) = 0;
virtual int getHeight(const char c)
{
char buf[2] = {c, '\0'};
return this->getHeight(buf);
}
virtual int getWidth(const char *str) = 0;
virtual int getWidth(const char c)
{
char buf[2] = {c, '\0'};
return this->getWidth(buf);
}
virtual void draw(SDL_Surface *where, const char *msg,
int x, int y, int w, int h) = 0;
};
#endif /* __FONT_HH__ */

200
Src/gui/game_info.cpp Normal file
View File

@ -0,0 +1,200 @@
#include <arpa/inet.h>
#include <sys/stat.h>
#include <SDL.h>
#include <SDL_image.h>
#include "game_info.hh"
#include "utils.hh"
#define VERSION_BASE (0x1978)
#define VERSION_MAGIC (VERSION_BASE + 0)
struct game_info_v0
{
uint32_t sz;
uint16_t version_magic;
uint16_t author_off;
uint16_t name_off;
uint16_t screenshot_off; /* In PNG format */
uint16_t filename_off;
uint16_t flags;
uint8_t data[]; /* 4-byte aligned */
};
GameInfo::GameInfo(const char *filename,
const char *name, const char *author,
SDL_Surface *image)
{
this->filename = filename;
this->name = name;
this->author = author;
this->screenshot = image;
}
GameInfo::GameInfo(GameInfo *gi)
{
if (!gi)
{
this->filename = NULL;
this->name = NULL;
this->author = NULL;
this->screenshot = NULL;
return;
}
this->name = gi->name ? xstrdup(gi->name) : NULL;
this->author = gi->author ? xstrdup(gi->author) : NULL;
this->filename = gi->filename ? xstrdup(gi->filename) : NULL;
this->screenshot = NULL;
if (gi->screenshot)
this->screenshot = SDL_DisplayFormatAlpha(gi->screenshot);
}
GameInfo::~GameInfo()
{
this->resetDefaults();
}
void GameInfo::resetDefaults()
{
free((void*)this->name);
free((void*)this->author);
SDL_FreeSurface(this->screenshot);
this->name = NULL;
this->author = NULL;
this->screenshot = NULL;
}
struct game_info *GameInfo::dump()
{
size_t total_sz = sizeof(struct game_info);
size_t png_sz;
struct game_info *out;
void *png_data;
if (!this->screenshot)
return NULL;
/* Convert surface to PNG */
png_data = sdl_surface_to_png(this->screenshot, &png_sz);
panic_if(!png_data, "Cannot create PNG from surface\n");
total_sz += strlen(this->author) + 1;
total_sz += strlen(this->name) + 1;
total_sz += png_sz;
/* 4-byte align */
total_sz += 4 - (total_sz & 3);
/* Allocate everything */
out = (struct game_info*)xmalloc(total_sz);
out->sz = total_sz;
out->version_magic = VERSION_MAGIC;
out->author_off = 0; /* Starts AFTER the header */
out->name_off = out->author_off + strlen(this->author) + 1;
out->screenshot_off = out->name_off + strlen(this->name) + 1;
memcpy(out->data + out->author_off, this->author, strlen(this->author) + 1);
memcpy(out->data + out->name_off, this->name, strlen(this->name) + 1);
memcpy(out->data + out->screenshot_off, png_data, png_sz);
out->sz = htonl(out->sz);
out->author_off = htons(out->author_off);
out->version_magic = htons(out->version_magic);
out->name_off = htons(out->name_off);
out->screenshot_off = htons(out->screenshot_off);
return out;
}
bool GameInfo::fromDump(struct game_info *gi)
{
SDL_RWops *rw;
gi->sz = ntohl(gi->sz);
gi->version_magic = ntohs(gi->version_magic);
gi->author_off = ntohs(gi->author_off);
gi->name_off = ntohs(gi->name_off);
gi->screenshot_off = ntohs(gi->screenshot_off);
this->author = xstrdup((char*)gi->data + gi->author_off);
this->name = xstrdup((char*)gi->data + gi->name_off);
rw = SDL_RWFromMem(gi->data + gi->screenshot_off,
gi->sz - gi->screenshot_off);
if (!rw)
goto bail_out;
this->screenshot = IMG_Load_RW(rw, 0);
SDL_FreeRW(rw);
if (!this->screenshot)
goto bail_out;
return true;
bail_out:
this->resetDefaults();
return false;
}
GameInfo *GameInfo::loadFromFile(const char *fileName)
{
struct stat st;
struct game_info *p;
GameInfo *out = NULL;
FILE *fp;
printf("Woho! I'll load %s\n", fileName);
if (stat(fileName, &st) < 0)
return NULL;
if (st.st_size <= (signed)sizeof(struct game_info))
{
warning("Size of %s is too small: %d vs minimum %d bytes\n",
fileName, (int)st.st_size, (signed)sizeof(struct game_info) + 4);
return NULL;
}
if (st.st_size % 4 != 0)
{
warning("Size of %s is unreasonable: %d\n", fileName, (int)st.st_size);
return NULL;
}
fp = fopen(fileName, "r");
if (!fp)
return NULL;
p = (struct game_info*)xmalloc(st.st_size);
if (fread(p, 1, st.st_size, fp) == (unsigned)st.st_size)
{
out = new GameInfo();
if (out->fromDump(p) == false)
{
warning("Converting %s to GameInfo failed\n",
fileName);
delete out;
out = NULL;
}
}
else
warning("Could not read %s\n", fileName);
free(p);
fclose(fp);
return out;
}
void GameInfo::setAuthor(const char *author)
{
free((void*)this->author);
this->author = xstrdup(author);
}
void GameInfo::setName(const char *name)
{
free((void*)this->name);
this->name = xstrdup(name);
}

53
Src/gui/game_info.hh Normal file
View File

@ -0,0 +1,53 @@
#ifndef __GAME_INFO_HH__
#define __GAME_INFO_HH__
#include <SDL.h>
struct game_info
{
/* These two MUST stay the same */
uint32_t sz;
uint16_t version_magic;
uint16_t author_off;
uint16_t name_off;
uint16_t screenshot_off; /* In PNG format */
uint16_t filename_off;
uint16_t flags;
uint8_t data[]; /* 4-byte aligned */
};
class GameInfo
{
public:
GameInfo(const char *filename = NULL, const char *name = NULL,
const char *author = NULL,
SDL_Surface *image = NULL);
GameInfo(GameInfo *gi);
~GameInfo();
void setAuthor(const char *author);
void setName(const char *name);
void resetDefaults();
/** Returns an allocated dump structure */
struct game_info *dump();
/** Fill in this game info object from a structure */
bool fromDump(struct game_info *data);
static GameInfo *loadFromFile(const char *fileName);
/* Should perhaps be protected but I trust you - just be careful! */
const char *name;
const char *author;
const char *filename;
SDL_Surface *screenshot;
};
#endif /*__GAME_INFO_HH__ */

102
Src/gui/game_info_box.hh Normal file
View File

@ -0,0 +1,102 @@
#ifndef _GAME_INFO_BOX_H_
#define _GAME_INFO_BOX_H_
#include "menu.hh"
#include "game_info.hh"
class GameInfoBox : public Menu
{
public:
GameInfoBox(Font *font) : Menu(font)
{
this->gi = NULL;
memset(this->gi_messages, 0, sizeof(this->gi_messages));
this->setSelectedBackground(NULL, NULL, NULL, NULL, NULL, NULL);
}
void setGameInfo(GameInfo *gi)
{
/* Make a copy */
if (this->gi)
delete this->gi;
this->gi = new GameInfo(gi);
this->updateMessages();
}
void loadGameInfo(const char *what)
{
/* Reset the current game info */
if (this->gi)
{
delete this->gi;
this->gi = NULL;
}
/* No need to do this for directories or the special "None" field */
if ( !(strcmp(what, "None") == 0 ||
what[0] == '[') )
{
size_t len = strlen(Gui::gui->metadata_base_path) + strlen(what) + 6;
char *tmp = (char*)xmalloc(len);
sprintf(tmp, "%s/%s.lra", Gui::gui->metadata_base_path, what);
/* Might return NULL, but that's OK */
this->gi = GameInfo::loadFromFile(tmp);
free(tmp);
}
this->updateMessages();
}
virtual void selectCallback(int which)
{
}
virtual void hoverCallback(int which)
{
}
virtual void escapeCallback(int which)
{
}
void draw(SDL_Surface *where, int x, int y, int w, int h)
{
if (!this->gi)
return;
if (this->gi->screenshot)
{
SDL_Rect dst;
/* Blit the screenshot */
dst = (SDL_Rect){x + w / 2 - this->gi->screenshot->w / 2, y, w, h};
SDL_BlitSurface(this->gi->screenshot, NULL, where, &dst);
Menu::draw(where, x, y + this->gi->screenshot->h + 10,
w, h - this->gi->screenshot->h - 10);
}
else
Menu::draw(where, x, y + 10, w, h - 10);
}
void updateMessages()
{
this->setText(NULL);
memset(this->gi_messages, 0, sizeof(this->gi_messages));
this->gi_messages[0] = "Game:";
this->gi_messages[1] = " ";
this->gi_messages[2] = "Author:";
this->gi_messages[3] = " ";
if (this->gi)
{
this->gi_messages[1] = this->gi->name ? this->gi->name : " ";
this->gi_messages[3] = this->gi->author ? this->gi->author : " ";
}
this->setText(this->gi_messages);
}
const char *gi_messages[6];
GameInfo *gi;
};
#endif /* _GAME_INFO_BOX_H_ */

115
Src/gui/game_info_menu.cpp Normal file
View File

@ -0,0 +1,115 @@
#include "gui.hh"
#include "menu.hh"
#include "game_info_box.hh"
#include "virtual_keyboard.hh"
class GameInfoView;
class GameInfoMenu : public Menu, public KeyboardListener
{
friend class GameInfoView;
public:
GameInfoMenu(Font *font, GameInfoBox *box) : Menu(font)
{
this->box = box;
this->setText(game_info_menu_messages);
}
virtual void stringCallback(const char *str)
{
switch (this->cur_sel)
{
case 2:
this->box->gi->setName(str);
break;
case 3:
this->box->gi->setAuthor(str);
break;
default:
panic("Cur sel is %d, not possible!\n", this->cur_sel);
break;
}
this->box->updateMessages();
}
virtual void selectCallback(int which)
{
switch (which)
{
case 0:
break;
case 2:
case 3:
VirtualKeyboard::kbd->activate();
VirtualKeyboard::kbd->registerListener(this);
break;
default:
panic("Impossible menu option\n");
break;
}
}
virtual void hoverCallback(int which)
{
}
virtual void escapeCallback(int which)
{
Gui::gui->popView();
}
private:
GameInfoBox *box;
};
class GameInfoView : public GuiView
{
public:
GameInfoView() : GuiView()
{
this->gameInfo = new GameInfoBox(Gui::gui->default_font);;
this->menu = new GameInfoMenu(Gui::gui->default_font, this->gameInfo);
}
~GameInfoView()
{
delete this->gameInfo;
delete this->menu;
}
void runLogic()
{
this->menu->runLogic();
}
void pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void viewPushCallback()
{
this->gameInfo->setGameInfo(Gui::gui->cur_gameInfo);
}
void draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->disc_info, NULL, where, &dst);
this->menu->draw(where, 50, 70, 280, 375);
this->gameInfo->draw(where, 360, 55, 262, 447);
}
protected:
GameInfoMenu *menu;
GameInfoBox *gameInfo;
};

414
Src/gui/gui.cpp Normal file
View File

@ -0,0 +1,414 @@
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <arpa/inet.h>
#include "menu.hh"
#include "gui.hh"
#include "menu_messages.hh"
#include "help_box.hh"
#include "dialogue_box.hh"
#include "sdl_ttf_font.hh"
#include "utils.hh"
#include "virtual_keyboard.hh"
extern SDL_Surface *screen;
#define THEME_ROOT_PATH "themes"
#define METADATA_ROOT_PATH "metadata"
#define GAME_ROOT_PATH "discs"
#define TMP_ROOT_PATH "tmp"
#define SAVE_GAME_ROOT_PATH "saves"
static const char *get_theme_path(const char *dir, const char *what)
{
static char buf[255];
memset(buf, 0, sizeof(buf));
snprintf(buf, 254, "%s/%s/%s",
THEME_ROOT_PATH, dir, what);
return buf;
}
/* These are a bit of special cases... */
#include "disc_menu.cpp"
#include "save_game_menu.cpp"
#include "bind_keys_menu.cpp"
#include "theme_menu.cpp"
#include "options_menu.cpp"
#include "network_menu.cpp"
#include "game_info_menu.cpp"
#include "main_menu.cpp"
GuiView::GuiView()
{
}
void GuiView::updateTheme()
{
}
void GuiView::viewPushCallback()
{
}
void GuiView::viewPopCallback()
{
}
Gui::Gui()
{
this->np = NULL;
this->focus = NULL;
this->bg_left = NULL;
this->bg_middle = NULL;
this->bg_right = NULL;
this->bg_submenu_left = NULL;
this->bg_submenu_middle = NULL;
this->bg_submenu_right = NULL;
this->background = NULL;
this->main_menu_bg = NULL;
this->infobox = NULL;
this->textbox = NULL;
this->status_bar_bg = NULL;
this->default_font = NULL;
this->dialogue_bg = NULL;
this->small_font = NULL;
this->n_views = 0;
this->views = NULL;
this->timerController = new TimerController();
VirtualKeyboard::kbd = new VirtualKeyboard(NULL);
this->theme_base_path = THEME_ROOT_PATH;
this->metadata_base_path = METADATA_ROOT_PATH;
this->game_base_path = GAME_ROOT_PATH;
this->tmp_path = TMP_ROOT_PATH;
this->save_game_path = SAVE_GAME_ROOT_PATH;
this->cur_gameInfo = new GameInfo();
this->gameInfoChanged = false;
this->dlg = NULL;
this->kbd = NULL;
this->mv = NULL;
this->dv = NULL;
this->sgv = NULL;
this->ov = NULL;
this->nv = NULL;
this->tv = NULL;
this->giv = NULL;
this->bkv = NULL;
}
Gui::~Gui()
{
delete this->mv;
delete this->dv;
delete this->sgv;
delete this->ov;
delete this->nv;
delete this->tv;
delete this->giv;
delete this->bkv;
delete this->cur_gameInfo;
delete this->timerController;
if (this->status_bar)
delete this->status_bar;
if (this->dlg)
delete this->dlg;
if (VirtualKeyboard::kbd)
delete VirtualKeyboard::kbd;
SDL_FreeSurface(this->bg_left);
SDL_FreeSurface(this->bg_middle);
SDL_FreeSurface(this->bg_right);
SDL_FreeSurface(this->bg_submenu_left);
SDL_FreeSurface(this->bg_submenu_middle);
SDL_FreeSurface(this->bg_submenu_right);
SDL_FreeSurface(this->background);
SDL_FreeSurface(this->main_menu_bg);
SDL_FreeSurface(this->infobox);
SDL_FreeSurface(this->dialogue_bg);
SDL_FreeSurface(this->disc_info);
SDL_FreeSurface(this->textbox);
SDL_FreeSurface(this->selected_key);
SDL_FreeSurface(this->highlighted_key);
SDL_FreeSurface(this->status_bar_bg);
if (this->default_font)
delete this->default_font;
if (this->small_font)
delete this->small_font;
}
bool Gui::setTheme(const char *path)
{
this->bg_left = this->loadThemeImage(path, "bg_left.png");
this->bg_middle = this->loadThemeImage(path, "bg_middle.png");
this->bg_right = this->loadThemeImage(path, "bg_right.png");
this->bg_submenu_left = this->loadThemeImage(path, "bg_submenu_left.png");
this->bg_submenu_middle = this->loadThemeImage(path, "bg_submenu_middle.png");
this->bg_submenu_right = this->loadThemeImage(path, "bg_submenu_right.png");
this->background = this->loadThemeImage(path, "background.png");
this->main_menu_bg = this->loadThemeImage(path, "main_menu_bg.png");
this->status_bar_bg = this->loadThemeImage(path, "status_bar.png");
this->infobox = this->loadThemeImage(path, "infobox.png");
this->textbox = this->loadThemeImage(path, "textbox.png");
this->dialogue_bg = this->loadThemeImage(path, "dialogue_box.png");
this->disc_info = this->loadThemeImage(path, "disc_info.png");
this->highlighted_key = this->loadThemeImage(path, "highlighted_key.png");
this->selected_key = this->loadThemeImage(path, "selected_key.png");
this->default_font = this->loadThemeFont(path, "font.ttf", 18);
this->small_font = this->loadThemeFont(path, "font.ttf", 16);
if (!this->bg_left || !this->bg_right || !this->bg_middle ||
!this->bg_submenu_left || !this->bg_submenu_right ||
!this->bg_submenu_middle ||
!this->dialogue_bg ||
!this->disc_info ||
!this->selected_key ||
!this->highlighted_key ||
!this->status_bar_bg ||
!this->default_font ||
!this->small_font)
{
SDL_FreeSurface(this->bg_left);
SDL_FreeSurface(this->bg_middle);
SDL_FreeSurface(this->bg_right);
SDL_FreeSurface(this->bg_submenu_left);
SDL_FreeSurface(this->bg_submenu_middle);
SDL_FreeSurface(this->bg_submenu_right);
SDL_FreeSurface(this->background);
SDL_FreeSurface(this->main_menu_bg);
SDL_FreeSurface(this->infobox);
SDL_FreeSurface(this->dialogue_bg);
SDL_FreeSurface(this->disc_info);
SDL_FreeSurface(this->textbox);
SDL_FreeSurface(this->selected_key);
SDL_FreeSurface(this->highlighted_key);
SDL_FreeSurface(this->status_bar_bg);
if (this->default_font)
delete this->default_font;
if (this->small_font)
delete this->small_font;
return false;
}
/* Create the views */
if (!this->mv)
{
this->status_bar = new StatusBar();
this->mv = new MainView();
this->dv = new DiscView();
this->sgv = new SaveGameView();
this->ov = new OptionsView();
this->nv = new NetworkView();
this->tv = new ThemeView();
this->bkv = new BindKeysView();
this->giv = new GameInfoView();
this->pushView(mv);
}
VirtualKeyboard::kbd->updateTheme();
return true;
}
void Gui::runLogic(void)
{
GuiView *cur_view = this->peekView();
this->status_bar->runLogic();
this->timerController->tick();
if (!this->is_active || !cur_view)
return;
if (this->dlg)
this->dlg->runLogic();
else if (this->kbd)
this->kbd->runLogic();
else
cur_view->runLogic();
}
void Gui::pushView(GuiView *view)
{
int cur = this->n_views;
this->n_views++;
this->views = (GuiView**)xrealloc(this->views,
sizeof(GuiView*) * this->n_views);
this->views[cur] = view;
view->viewPushCallback();
}
void Gui::pushDialogueBox(DialogueBox *dlg)
{
this->dlg = dlg;
}
DialogueBox *Gui::popDialogueBox()
{
DialogueBox *out = this->dlg;
this->dlg = NULL;
return out;
}
GuiView *Gui::popView()
{
GuiView *cur = this->peekView();
if (!cur)
return NULL;
cur->viewPopCallback();
this->n_views--;
if (this->n_views <= 0)
{
free(this->views);
this->views = NULL;
this->n_views = 0;
/* Deactivate when no views are left */
this->is_active = false;
return NULL;
}
this->views = (GuiView**)xrealloc(this->views,
sizeof(GuiView*) * this->n_views);
return cur;
}
void Gui::exitMenu()
{
printf("Exiting the menu system\n");
/* Pop all views */
while (this->popView())
;
}
void Gui::pushEvent(SDL_Event *ev)
{
GuiView *cur_view = this->peekView();
if (!this->is_active || !cur_view)
return;
if (this->dlg)
this->dlg->pushEvent(ev);
else if (this->kbd)
this->kbd->pushEvent(ev);
else
cur_view->pushEvent(ev);
}
void Gui::draw(SDL_Surface *where)
{
GuiView *cur_view = this->peekView();
if (!this->is_active || !cur_view)
{
this->status_bar->draw(where);
return;
}
SDL_BlitSurface(this->background, NULL, where, NULL);
cur_view->draw(where);
if (this->kbd)
this->kbd->draw(where);
if (this->dlg)
this->dlg->draw(where);
this->status_bar->draw(where);
}
void Gui::activate()
{
this->is_active = true;
/* FIXME! TMP! TMP! */
this->np = new Prefs();
}
void Gui::deActivate()
{
/* FIXME! TMP! TMP! */
delete this->np;
this->is_active = false;
}
SDL_Surface *Gui::loadThemeImage(const char *dir, const char *what)
{
return IMG_Load(get_theme_path(dir, what));
}
Font *Gui::loadThemeFont(const char *dir, const char *what, int size)
{
TTF_Font *fnt;
fnt = read_and_alloc_font(get_theme_path(dir, what), size);
if (!fnt)
return NULL;
return new Font_TTF(fnt, 255,255,255);
}
void Gui::updateGameInfo(GameInfo *gi)
{
panic_if(!gi, "gi must be set\n");
delete this->cur_gameInfo;
this->cur_gameInfo = gi;
this->gameInfoChanged = true;
}
void Gui::saveGameInfo()
{
struct game_info *p = this->cur_gameInfo->dump();
if (p)
{
char buf[255];
FILE *fp;
snprintf(buf, sizeof(buf), "%s/%s",
METADATA_ROOT_PATH, this->cur_gameInfo->filename);
fp = fopen(buf, "w");
if (!fp)
{
warning("Could not open %s for writing\n", buf);
return;
}
int n = fwrite((const void*)p, 1, p->sz, fp);
if (n != (int)p->sz)
warning("Could only write %d bytes of %s\n", n, buf);
fclose(fp);
}
this->gameInfoChanged = false;
}
/* The singleton/factory stuff */
Gui *Gui::gui;
void Gui::init()
{
Gui::gui = new Gui();
/* Set the default theme */
panic_if(!Gui::gui->setTheme("default"),
"Setting default theme failed\n");
}

134
Src/gui/gui.hh Normal file
View File

@ -0,0 +1,134 @@
#ifndef __GUI_HH__
#define __GUI_HH__
#include <SDL.h>
#include "menu.hh"
#include "font.hh"
#include "timer.hh"
#include "gui_view.hh"
/* Frodo stuff */
#include <sysdeps.h>
#include <main.h>
#include <Prefs.h>
class DialogueBox;
class StatusBar;
class GameInfo;
class MainView;
class BindKeysView;
class DiscView;
class SaveGameView;
class OptionsView;
class NetworkView;
class ThemeView;
class GameInfoView;
class VirtualKeyboard;
class Gui
{
public:
Gui();
~Gui();
bool setTheme(const char *path);
void activate();
void deActivate();
void runLogic(void);
void pushEvent(SDL_Event *ev);
void draw(SDL_Surface *where);
void pushView(GuiView *view);
void pushVirtualKeyboard(VirtualKeyboard *kbd);
void pushDialogueBox(DialogueBox *dlg);
DialogueBox *popDialogueBox();
GuiView *popView();
GuiView *peekView()
{
if (!this->views)
return NULL;
return this->views[this->n_views-1];
}
void updateGameInfo(GameInfo *gi);
void saveGameInfo();
void exitMenu();
/* These are private, keep off! */
const char *getThemePath(const char *dir, const char *what);
SDL_Surface *loadThemeImage(const char *dir, const char *what);
Font *loadThemeFont(const char *dir, const char *what, int size);
bool is_active;
Menu *focus; /* Where the focus goes */
Menu *main_menu;
SDL_Surface *background;
SDL_Surface *main_menu_bg;
SDL_Surface *status_bar_bg;
SDL_Surface *infobox;
SDL_Surface *textbox;
SDL_Surface *dialogue_bg;
SDL_Surface *disc_info;
SDL_Surface *bg_left, *bg_right, *bg_middle,
*bg_submenu_left, *bg_submenu_right, *bg_submenu_middle;
SDL_Surface *highlighted_key;
SDL_Surface *selected_key;
Font *default_font;
Font *small_font;
TimerController *timerController;
/* Handled specially */
VirtualKeyboard *kbd;
DialogueBox *dlg;
StatusBar *status_bar;
MainView *mv;
DiscView *dv;
SaveGameView *sgv;
OptionsView *ov;
NetworkView *nv;
GameInfoView *giv;
ThemeView *tv;
BindKeysView *bkv;
GuiView **views;
int n_views;
const char *metadata_base_path;
const char *theme_base_path;
const char *game_base_path;
const char *tmp_path;
const char *save_game_path;
GameInfo *cur_gameInfo;
bool gameInfoChanged;
/* New preferences */
Prefs *np;
/* Singleton */
static void init();
static Gui *gui;
};
#endif /* GUI_HH */

22
Src/gui/gui_view.hh Normal file
View File

@ -0,0 +1,22 @@
#ifndef __GUI_VIEW_HH__
#define __GUI_VIEW_HH__
#include <SDL.h>
#include "widget.hh"
class GuiView : public Widget
{
public:
GuiView();
virtual void updateTheme();
virtual void viewPushCallback();
virtual void viewPopCallback();
virtual void draw(SDL_Surface *where) = 0;
};
#endif /* __GUI_VIEW_HH__ */

41
Src/gui/help_box.hh Normal file
View File

@ -0,0 +1,41 @@
#ifndef __HELP_BOX_HH__
#define __HELP_BOX_HH__
#include "menu.hh"
class HelpBox : public Menu
{
public:
HelpBox(Font *font, const char ***all_messages) : Menu(font)
{
this->setHelpMessages(all_messages);
this->setSelectedBackground(NULL, NULL, NULL, NULL, NULL, NULL);
}
void setHelpMessages(const char ***all_messages)
{
this->all_messages = all_messages;
}
void updateHelpMessage(int which)
{
if (!this->all_messages)
return;
this->setText(this->all_messages[which]);
}
virtual void selectCallback(int which)
{
}
virtual void hoverCallback(int which)
{
}
virtual void escapeCallback(int which)
{
}
protected:
const char ***all_messages;
};
#endif /* __HELP_BOX_HH__ */

38
Src/gui/listener.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "listener.hh"
#include "utils.hh"
ListenerManager::ListenerManager()
{
printf("Flushing listeners\n");
this->flushListeners();
}
void ListenerManager::registerListener(Listener *kl)
{
int n_listeners = sizeof(this->listeners) / sizeof(*this->listeners);
int i;
/* Don't register already registered listeners */
for (i = 0; i < n_listeners; i++)
if (this->listeners[i] == kl)
return;
/* Find a free spot */
for (i = 0; i < n_listeners; i++)
if (!this->listeners[i])
break;
panic_if(i == n_listeners,
"No free listeners!\n");
this->listeners[i] = kl;
}
void ListenerManager::unregisterListener(Listener *kl)
{
int n_listeners = sizeof(this->listeners) / sizeof(*this->listeners);
for (int i = 0; i < n_listeners; i++)
{
if (this->listeners[i] == kl)
this->listeners[i] = NULL;
}
}

34
Src/gui/listener.hh Normal file
View File

@ -0,0 +1,34 @@
#ifndef __LISTENER_HH__
#define __LISTENER_HH__
#include <string.h>
class Listener
{
/* Implemented by the child */
};
class ListenerManager
{
public:
ListenerManager();
void registerListener(Listener *l);
void unregisterListener(Listener *l);
void flushListeners()
{
memset(this->listeners, 0, sizeof(this->listeners));
}
int nListeners()
{
return sizeof(this->listeners) / sizeof(*this->listeners);
}
protected:
Listener *listeners[8];
};
#endif /* __LISTENER_HH__ */

69
Src/gui/main.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <SDL_image.h>
#include <SDL_ttf.h>
#include "gui.hh"
#include "utils.hh"
#include <C64.h>
SDL_Surface *screen;
C64 *TheC64;
#define MS_PER_FRAME 28
static void run(void)
{
Uint32 last_frame = SDL_GetTicks();
while(1)
{
SDL_Event ev;
Uint32 now = SDL_GetTicks();
if (!Gui::gui->is_active)
break;
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT)
exit(1);
Gui::gui->pushEvent(&ev);
}
Gui::gui->runLogic();
Gui::gui->draw(screen);
SDL_Flip(screen);
if ( (now - last_frame) < MS_PER_FRAME)
SDL_Delay( MS_PER_FRAME - (now - last_frame));
}
}
static void init(void)
{
/* Creation of the mocks */
TheC64 = new C64();
screen = SDL_SetVideoMode(640, 480, 16,
SDL_DOUBLEBUF);
panic_if(!screen, "Cannot initialize video: %s\n", SDL_GetError());
TTF_Init();
Gui::init();
Gui::gui->activate();
}
static void fini(void)
{
delete Gui::gui;
}
int main(int argc, char *argv[])
{
init();
run();
fini();
SDL_Quit();
return 0;
}

182
Src/gui/main_menu.cpp Normal file
View File

@ -0,0 +1,182 @@
#include "menu.hh"
#include "dialogue_box.hh"
class KeyboardTypingListener : public KeyboardListener
{
virtual void stringCallback(const char *str)
{
printf("string: %s\n", str);
/* Remove thyself! */
delete this;
}
virtual void keyCallback(bool shift, const char *str)
{
printf("Vobb: %d: %s\n", shift, str);
}
};
class ExitListener : public DialogueListener
{
void escapeCallback(DialogueBox *which, int selected)
{
}
void selectCallback(DialogueBox *which, int selected)
{
/* Cancel? */
if (selected != 1)
exit(0);
}
};
class MainView;
class MainMenu : public Menu
{
friend class MainView;
public:
MainMenu(Font *font, HelpBox *help) : Menu(font)
{
this->help = help;
this->updatePauseState();
}
virtual void selectCallback(int which)
{
printf("entry %d selected: %s\n", which, this->pp_msgs[which]);
switch (which)
{
case 0:
TheC64->IsPaused() ? TheC64->Resume() : TheC64->Pause();
if (TheC64->IsPaused())
Gui::gui->status_bar->queueMessage("C64 emulation paused");
else
Gui::gui->status_bar->queueMessage("C64 emulation resumed");
this->updatePauseState();
break;
case 2: /* Insert disc */
Gui::gui->dv->setDirectory(Gui::gui->game_base_path);
Gui::gui->pushView(Gui::gui->dv);
Gui::gui->dv->runStartSequence(this->p_submenus[0].sel == 1);
break;
case 4: /* Load/save states */
if (this->p_submenus[1].sel == 1)
Gui::gui->sgv->saveSnapshot();
else
{
Gui::gui->sgv->setDirectory(Gui::gui->save_game_path);
Gui::gui->pushView(Gui::gui->sgv);
Gui::gui->sgv->setLoadSnapshot(this->p_submenus[1].sel == 0);
}
break;
case 6: /* Keyboard */
switch(this->p_submenus[2].sel)
{
case 0:
VirtualKeyboard::kbd->activate();
VirtualKeyboard::kbd->registerListener(new KeyboardTypingListener());
break;
case 1:
break;
case 2:
Gui::gui->pushView(Gui::gui->bkv);
break;
default:
panic("Illegal selection\n");
}
break;
case 9: /* Game info */
Gui::gui->pushView(Gui::gui->giv);
break;
case 10: /* Networking */
Gui::gui->pushView(Gui::gui->nv);
break;
case 11: /* Options */
Gui::gui->pushView(Gui::gui->ov);
break;
case 12: /* Exit */
DialogueBox *exit_dialogue = new DialogueBox(exit_dialogue_messages);
exit_dialogue->registerListener(new ExitListener());
Gui::gui->pushDialogueBox(exit_dialogue);
break;
}
}
virtual void hoverCallback(int which)
{
this->help->updateHelpMessage(which);
}
virtual void escapeCallback(int which)
{
Gui::gui->exitMenu();
}
private:
void updatePauseState()
{
if (TheC64->IsPaused())
main_menu_messages[0] = "Resume";
else
main_menu_messages[0] = "Pause";
this->setText(main_menu_messages);
}
HelpBox *help;
};
class MainView : public GuiView
{
public:
MainView() : GuiView()
{
panic_if(!Gui::gui->default_font,
"Theme does not seem correctly loaded\n");
this->help = new HelpBox(Gui::gui->small_font, main_menu_help);
this->menu = new MainMenu(Gui::gui->default_font, this->help);
}
~MainView()
{
delete this->help;
delete this->menu;
}
void runLogic()
{
this->menu->runLogic();
}
void pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->infobox, NULL, where, &dst);
dst = (SDL_Rect){350,242,0,0};
SDL_BlitSurface(Gui::gui->textbox, NULL, where, &dst);
this->menu->draw(where, 50, 70, 300, 400);
this->help->draw(where, 354, 24, 264, 210);
}
protected:
MainMenu *menu;
HelpBox *help;
};

373
Src/gui/menu.cpp Normal file
View File

@ -0,0 +1,373 @@
/*********************************************************************
*
* Copyright (C) 2004-2009, Simon Kagstrom
*
* Filename: menu.c
* Author: Simon Kagstrom <simon.kagstrom@gmail.com>
* Description: Code for menus (originally for Mophun)
*
* $Id$
*
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "menu.hh"
#include "font.hh"
#include "utils.hh"
#include "gui.hh"
#define IS_SUBMENU(p_msg) ( (p_msg)[0] == '^' )
#define IS_EMPTY(p_msg) ( (p_msg)[0] == '#' )
void Menu::printText(SDL_Surface *where, const char *msg, SDL_Color clr,
int x, int y, int w, int h)
{
char *buf;
unsigned int i;
int tw;
buf = xstrdup(msg);
tw = this->font->getWidth(buf);
/* Crop text */
if (tw > w)
{
int pixels_per_char = tw / strlen(buf);
int last_char = (w / pixels_per_char) - 1;
if ((unsigned)last_char > strlen(buf))
last_char = strlen(buf) - 3;
/* FIXME! Handle some corner cases here (short strings etc) */
if (last_char > 3)
{
buf[last_char - 2] = '.';
buf[last_char - 1] = '.';
buf[last_char] = '\0';
}
}
/* Fixup multi-menu option look */
for (i = 0; i < strlen(buf) ; i++)
{
if (buf[i] == '^' || buf[i] == '|')
buf[i] = ' ';
}
if (IS_EMPTY(buf))
buf[0] = ' ';
this->font->draw(where, buf, x, y, w, h);
free(buf);
}
void Menu::draw(SDL_Surface *where, int x, int y, int w, int h)
{
int font_height = this->font->getHeight("X");
int line_height = (font_height + font_height / 4);
int x_start = x;
int entries_visible = h / line_height - 1;
int start_entry_visible = 0;
/* No messages - nothing to draw */
if (!this->pp_msgs)
return;
if (this->cur_sel - start_entry_visible > entries_visible)
{
while (this->cur_sel - start_entry_visible > entries_visible)
{
start_entry_visible++;
if (start_entry_visible > this->n_entries)
{
start_entry_visible = 0;
break;
}
}
}
else if ( this->cur_sel < start_entry_visible )
start_entry_visible = this->cur_sel;
if (start_entry_visible + entries_visible > this->n_entries)
entries_visible = this->n_entries - start_entry_visible;
for (int i = start_entry_visible;
i <= start_entry_visible + entries_visible; i++)
{
const char *msg = this->pp_msgs[i];
int cur_y;
if (i >= this->n_entries)
break;
cur_y = y + (i - start_entry_visible) * line_height;
/* Draw the background for the selected entry */
if (this->cur_sel == i) {
int tw, th;
tw = this->font->getWidth(msg);
th = this->font->getHeight(msg);
highlight_background(where, this->font,
this->text_bg_left, this->text_bg_middle, this->text_bg_right,
x_start, cur_y, tw, th);
}
if (IS_SUBMENU(msg))
{
submenu_t *p_submenu = this->findSubmenu(i);
int n_pipe = 0;
int total_chars = 0;
int tw, th, tw_first;
int n_chars;
char *p;
int n;
for (n = 0; msg[n] != '\0'; n++)
{
if (msg[n] != '|')
continue;
/* msg[n] == '|' */
/* Count the number of chars until next pipe */
for (n_chars = 1; msg[n+n_chars] && msg[n+n_chars] != '|'; n_chars++);
total_chars += n_chars;
n_pipe++;
/* Found the selection yet? */
if (p_submenu->sel == n_pipe-1)
break;
}
p = (char*)xmalloc(total_chars + 1);
strncpy(p, msg, n + 1);
tw_first = this->font->getWidth(p);
memset(p, 0, total_chars + 1);
strncpy(p, msg + n, n_chars - 1);
tw = this->font->getWidth(p);
th = this->font->getHeight(p);
highlight_background(where, this->font,
this->submenu_bg_left, this->submenu_bg_middle, this->submenu_bg_right,
x_start + tw_first, cur_y, tw, th);
free(p);
}
/* And print the text on top */
this->printText(where, msg, this->text_color,
x_start, cur_y, w, h);
}
}
int Menu::getNextEntry(int dy)
{
if (this->cur_sel + dy < 0)
return this->n_entries - 1;
if (this->cur_sel + dy > this->n_entries - 1)
return 0;
return this->cur_sel + dy;
}
submenu_t *Menu::findSubmenu(int index)
{
int i;
for (i = 0; i < this->n_submenus; i++)
{
if (this->p_submenus[i].index == index)
return &this->p_submenus[i];
}
return NULL;
}
int Menu::selectOne(int which)
{
panic_if(!this->pp_msgs,
"Can't select a message without any messages!");
if (which >= this->n_entries)
which = 0;
this->cur_sel = which;
if (this->pp_msgs[this->cur_sel][0] == ' ' ||
IS_SUBMENU(this->pp_msgs[this->cur_sel]))
this->selectNext(0, 1);
this->hoverCallback(this->cur_sel);
return this->cur_sel;
}
int Menu::selectNext(int dx, int dy)
{
int next;
panic_if(!this->pp_msgs,
"Can't select the next message without any messages!");
this->cur_sel = this->getNextEntry(dy);
next = this->getNextEntry(dy + 1);
/* We want to skip this for some reason */
if (this->pp_msgs[this->cur_sel][0] == ' ' ||
IS_SUBMENU(this->pp_msgs[this->cur_sel]) ) {
return this->selectNext(dx, dy);
}
/* If the next is a submenu */
if (dx != 0 && IS_SUBMENU(this->pp_msgs[next]))
{
submenu_t *p_submenu = findSubmenu(next);
panic_if(!p_submenu, "submenu in the menu text but no actual submenu\n");
p_submenu->sel = (p_submenu->sel + dx) < 0 ? p_submenu->n_entries - 1 :
(p_submenu->sel + dx) % p_submenu->n_entries;
}
return this->cur_sel;
}
int Menu::selectNext(event_t ev)
{
int now = this->cur_sel;
int next;
switch (ev)
{
case KEY_UP:
next = this->selectNext(0, -1); break;
case KEY_DOWN:
next = this->selectNext(0, 1); break;
case KEY_LEFT:
next = this->selectNext(-1, 0); break;
case KEY_RIGHT:
next = this->selectNext(1, 0); break;
default:
panic("selectNext(ev) called with event %d\n", ev);
}
if (now != next)
this->hoverCallback(this->cur_sel);
return this->cur_sel;
}
void Menu::runLogic()
{
event_t ev;
while ( (ev = this->popEvent()) != EVENT_NONE )
{
switch (ev)
{
case KEY_UP:
case KEY_DOWN:
case KEY_LEFT:
case KEY_RIGHT:
this->selectNext(ev);
break;
case KEY_SELECT:
this->selectCallback(this->cur_sel);
/* Might be deleted */
return;
case KEY_ESCAPE:
this->escapeCallback(this->cur_sel);
/* Might be deleted */
return;
default:
break;
}
}
}
void Menu::setText(const char **messages, int *submenu_defaults)
{
int submenu;
/* Free the old stuff */
this->n_submenus = 0;
free(this->p_submenus);
free(this->pp_msgs);
/* Empty messages are allowed */
this->p_submenus = NULL;
this->pp_msgs = NULL;
if (!messages)
return;
for (this->n_entries = 0; messages[this->n_entries]; this->n_entries++)
{
/* Is this a submenu? */
if (IS_SUBMENU(messages[this->n_entries]))
{
this->n_submenus++;
continue; /* Length of submenus is unimportant */
}
}
this->pp_msgs = (const char **)xmalloc(this->n_entries * sizeof(const char *));
if (this->n_submenus)
this->p_submenus = (submenu_t *)xmalloc(this->n_submenus * sizeof(submenu_t));
for (int i = 0; i < this->n_entries; i++)
this->pp_msgs[i] = xstrdup(messages[i]);
submenu = 0;
for (int i = 0; i < this->n_entries; i++)
{
if (IS_SUBMENU(this->pp_msgs[i]))
{
int n;
this->p_submenus[submenu].index = i;
this->p_submenus[submenu].sel = submenu_defaults ? submenu_defaults[submenu] : 0;
this->p_submenus[submenu].n_entries = 0;
for (n = 0; this->pp_msgs[i][n] != '\0'; n++)
{
if (this->pp_msgs[i][n] == '|')
this->p_submenus[submenu].n_entries++;
}
submenu++;
}
}
/* Move selection to the first entry */
this->selectOne(0);
}
Menu::Menu(Font *font) : Widget()
{
this->setTextColor((SDL_Color){0xff,0xff,0xff,0});
this->font = font;
this->pp_msgs = NULL;
this->n_entries = 0;
this->p_submenus = NULL;
this->n_submenus = 0;
this->cur_sel = 0;
this->mouse_x = -1;
this->mouse_y = -1;
this->setSelectedBackground(Gui::gui->bg_left, Gui::gui->bg_middle,
Gui::gui->bg_right, Gui::gui->bg_submenu_left,
Gui::gui->bg_submenu_middle, Gui::gui->bg_submenu_right);
}
void Menu::setTextColor(SDL_Color clr)
{
this->text_color = clr;
}
Menu::~Menu()
{
for (int i = 0; i < this->n_entries; i++)
free((void*)this->pp_msgs[i]);
free(this->pp_msgs);
free(this->p_submenus);
}

108
Src/gui/menu.hh Normal file
View File

@ -0,0 +1,108 @@
/*********************************************************************
*
* Copyright (C) 2004, 2008, Simon Kagstrom
*
* Filename: menu.h
* Author: Simon Kagstrom <simon.kagstrom@gmail.com>
* Description:
*
* $Id$
*
********************************************************************/
#ifndef __MENU_H__
#define __MENU_H__
#include <SDL.h>
#include <SDL_ttf.h>
#include <stdint.h>
#include "font.hh"
#include "widget.hh"
typedef struct
{
int n_entries;
int index;
int sel;
} submenu_t;
class Menu : public Widget
{
public:
Menu(Font *font);
~Menu();
void setFont(Font *font)
{
this->font = font;
}
void setTextColor(SDL_Color clr);
void setSelectedBackground(SDL_Surface *left, SDL_Surface *middle, SDL_Surface *right,
SDL_Surface *submenu_left, SDL_Surface *submenu_middle, SDL_Surface *submenu_right)
{
this->text_bg_left = left;
this->text_bg_middle = middle;
this->text_bg_right = right;
this->submenu_bg_left = submenu_left;
this->submenu_bg_middle = submenu_middle;
this->submenu_bg_right = submenu_right;
}
void setText(const char **messages, int *submenu_defaults = NULL);
virtual void runLogic();
void draw(SDL_Surface *where,
int x, int y, int w, int h);
protected:
void printText(SDL_Surface *where, const char *msg, SDL_Color clr,
int x, int y, int w, int h);
virtual void hoverCallback(int which) = 0;
virtual void selectCallback(int which) = 0;
virtual void escapeCallback(int which) = 0;
submenu_t *findSubmenu(int index);
public:
virtual int getNextEntry(int dy);
virtual int selectOne(int which);
virtual int selectNext(int dx, int dy);
virtual int selectNext(event_t ev);
protected:
const char **pp_msgs;
Font *font;
SDL_Color text_color;
SDL_Surface *text_bg_left;
SDL_Surface *text_bg_right;
SDL_Surface *text_bg_middle;
SDL_Surface *submenu_bg_left;
SDL_Surface *submenu_bg_right;
SDL_Surface *submenu_bg_middle;
/* Relative to this menu */
int mouse_x, mouse_y;
int n_submenus;
submenu_t *p_submenus;
int cur_sel; /* Main selection */
int n_entries;
};
#endif /* !__MENU_H__ */

258
Src/gui/menu_messages.cpp Normal file
View File

@ -0,0 +1,258 @@
#include <stdlib.h>
#include "menu_messages.hh"
const char **exit_dialogue_messages = (const char*[]){
/*00*/ "Do you really want to exit",
/*01*/ "Frodo?",
/*02*/ "#", /* Empty line */
/*03*/ "#",
/*04*/ "#",
/*05*/ "#",
/*06*/ "^|Yes|Cancel",
NULL
};
const char **network_port_dialogue_messages = (const char*[]){
/*00*/ "Please supply a number as",
/*01*/ "network port.",
/*02*/ "#", /* Empty line */
/*03*/ "#",
/*04*/ "#",
/*05*/ "#",
/*06*/ "^|OK",
NULL
};
const char **network_unset_name_dlg = (const char*[]){
/*00*/ "Please setup a name to use",
/*01*/ "on network connections.",
/*02*/ "#", /* Empty line */
/*03*/ "#",
/*04*/ "#",
/*05*/ "#",
/*06*/ "^|OK",
NULL
};
const char **broken_theme_dlg = (const char*[]){
/*00*/ "The selected theme cannot be",
/*01*/ "loaded, probably some file",
/*02*/ "is missing or broken in it.",
/*03*/ "The default theme has been",
/*04*/ "reverted.",
/*05*/ "#",
/*06*/ "^|OK",
NULL
};
const char **select_analogue_dlg = (const char*[]){
/*00*/ "Select axis of analogue",
/*01*/ "joystick to bind.",
/*02*/ "#",
/*03*/ "#",
/*04*/ "#",
/*05*/ "#",
/*06*/ "^|None|Horiz|Vert",
NULL
};
const char **main_menu_messages = (const char*[]){
/*00*/ NULL, /* Setup dynamically */
/*01*/ " ",
/*02*/ "File",
/*03*/ "^|Insert|Start",
/*04*/ "States",
/*05*/ "^|Load|Save|Delete",
/*06*/ "Keyboard",
/*07*/ "^|Type|Macro|Bind",
/*08*/ " ",
/*09*/ "Game info",
/*10*/ "Networking",
/*11*/ "Options",
/*12*/ "Quit",
NULL
};
const char **main_menu_help[] = {
(const char*[]){
"Pause or resume the C64",
"emulation. Not available",
"when running in networked",
"mode.",
NULL,
},
NULL,
(const char*[]){
"Insert a disc/tape or",
"start it",
NULL,
},
NULL,
(const char*[]){
"Load/save or delete game",
"states",
NULL,
},
NULL,
(const char*[]){
"Bind keyboard keys to the",
"joysticks, use pre-defined",
"macros, or type with the",
"virtual keyboard",
NULL,
},
NULL,
NULL,
(const char*[]){
"View and configure game",
"information (author,",
"screenshots etc)",
NULL,
},
(const char*[]){
"Network setup for playing",
"C64 games against other",
"players online.",
NULL,
},
(const char*[]){
"Configure Frodo",
NULL,
},
(const char*[]){
"Quit Frodo",
NULL,
},
NULL,
};
const char **options_menu_messages = (const char*[]){
/*00*/ "Map Controller 1 to:",
/*01*/ "^|Port 1|Port 2",
/*02*/ "True 1541 emulation",
/*03*/ "^|ON|OFF",
/*04*/ "1541 Floppy Drive LED",
/*05*/ "^|ON|OFF",
/*06*/ "Display resolution",
/*07*/ "^|double-center|stretched",
/*08*/ "Speed (approx. %)",
/*09*/ "^|95|100|110",
/*10*/ "Reset the C=64",
/*11*/ " ",
/*12*/ "Setup GUI theme",
NULL
};
const char **bind_key_menu_messages = (const char*[]){
/*00*/ "Wiimote",
/*01*/ "^|Up|Down|Left|Right|A|B|1|2|+|-",
/*02*/ "Nunchuk",
/*03*/ "^|Horiz|Vert|Z|C",
/*04*/ "Classic",
/*05*/ "^|Up|Down|Left|a|b|x|y|Zl|Zr|+|-",
/*06*/ "Classic (left analogue)",
/*07*/ "^|Horiz|Vert",
/*08*/ "Classic(right analogue)",
/*09*/ "^|Horiz|Vert",
/*10*/ " ",
/*11*/ "Reset to defaults",
NULL
};
const char **options_menu_help[] = {
(const char*[]){
"Switch controller to",
"C64 joystick port",
"mapping.",
NULL,
},
NULL,
(const char*[]){
"Turn on or off true 1541",
"floppy emulation. Might",
"be needed in some games",
"but slows down emulation.",
NULL,
},
NULL,
(const char*[]){
"Display 1541 drive LED to",
"show if the emulation got",
"stuck or is running.",
NULL,
},
NULL,
(const char*[]){
"Select display resolution",
"mapping. Double-center",
"removes some pixels on the",
"borders, stretched fills",
"the display but is slower.",
NULL,
},
NULL,
(const char*[]){
"Setup speed factor (in %).",
"Should normally be 100",
"unless Simon did some bad",
"mistake.",
NULL,
},
NULL,
NULL,
(const char*[]){
"Setup theme for the Frodo",
"menus.",
NULL,
},
NULL,
};
const char **network_menu_help[] = {
(const char*[]){
"Setup username to use on",
"the C64 network. Must be",
"set before connceting.",
NULL,
},
(const char*[]){
"Setup server hostname.",
"Only for debugging, so",
"leave as it is.",
NULL,
},
(const char*[]){
"UDP port to use. Only for",
"debugging, so leave as",
"it is",
NULL,
},
NULL,
(const char*[]){
"Connect to the C64",
"network, or disconnect if",
"you are already connected.",
NULL,
},
NULL,
(const char*[]){
"Post message to the C64",
"network server. You must",
"be connected to use this.",
NULL,
},
NULL,
};
const char **game_info_menu_messages = (const char*[]){
/*00*/ "Capture game screenshot",
/*01*/ " ",
/*02*/ "Set game name",
/*02*/ "Set game author",
NULL
};

21
Src/gui/menu_messages.hh Normal file
View File

@ -0,0 +1,21 @@
#ifndef MENU_MESSAGES_HH
#define MENU_MESSAGES_HH
extern const char **main_menu_messages;
extern const char **exit_dialogue_messages;
extern const char **main_menu_help[];
extern const char **bind_key_menu_messages;
extern const char **options_menu_messages;
extern const char **options_menu_help[];
extern const char **game_info_menu_messages;
/* The menu messages are dynamically generated */
extern const char **network_menu_help[];
extern const char **network_port_dialogue_messages;
extern const char **network_unset_name_dlg;
extern const char **broken_theme_dlg;
extern const char **select_analogue_dlg;
#endif

59
Src/gui/mocks/C64.h Normal file
View File

@ -0,0 +1,59 @@
#ifndef __MOCKS_C64_H__
#define __MOCKS_C64_H__
/* Network connection type */
enum
{
NONE,
CONNECT,
MASTER,
CLIENT
};
class C64
{
public:
C64()
{
this->have_a_break = false;
}
void Pause()
{
this->have_a_break = true;
}
void Resume()
{
this->have_a_break = false;
}
bool IsPaused()
{
return this->have_a_break;
}
void startFakeKeySequence(const char *what)
{
printf("Faking %s\n", what);
}
void LoadSnapshot(const char *name)
{
printf("Loading savegame %s\n", name);
}
void SaveSnapshot(const char *name)
{
printf("Saving savegame %s\n", name);
}
int network_connection_type;
private:
bool have_a_break;
};
extern C64 *TheC64;
#endif /*__MOCKS_C64_H__ */

9
Src/gui/mocks/Network.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __MOCKS_NETWORK_H__
#define __MOCKS_NETWORK_H__
class Network
{
public:
};
#endif /*__MOCKS_NETWORK_H__ */

61
Src/gui/mocks/Prefs.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef __MOCK_PREFS_HH__
#define __MOCK_PREFS_HH__
#include <string.h>
#define SPEED_95 30
#define SPEED_100 20
#define SPEED_110 18
enum
{
/* ASCII values before these */
JOY_NONE = 0,
JOY_HORIZ = 256,
JOY_VERT = 258,
JOY_FIRE = 259,
};
/* Insanely high, but the Wii has insanely many of these */
#define MAX_JOYSTICK_AXES 32
#define MAX_JOYSTICK_BUTTONS 32
#define MAX_JOYSTICK_HATS 8
class Prefs
{
public:
Prefs()
{
/* Set to NONE by default */
memset(this->JoystickAxes, 0, sizeof(this->JoystickAxes));
memset(this->JoystickButtons, 0, sizeof(this->JoystickButtons));
memset(this->JoystickHats, 0, sizeof(this->JoystickHats));
strcpy(this->NetworkName, "Unset name");
strcpy(this->NetworkServer, "play.c64-network.org");
this->NetworkPort = 46214;
this->Emul1541Proc = 0;
this->ShowLEDs = 0;
this->DisplayOption = 0;
this->MsPerFrame = SPEED_100;
memset(this->DrivePath, 0, sizeof(this->DrivePath));
}
char DrivePath[4][256]; // Path for drive 8..11
char NetworkName[32];
char NetworkServer[128];
int NetworkPort;
int Emul1541Proc;
int ShowLEDs;
int DisplayOption;
unsigned int MsPerFrame;
/* This is borrowed from UAE */
int JoystickAxes[MAX_JOYSTICK_AXES];
int JoystickHats[MAX_JOYSTICK_HATS];
int JoystickButtons[MAX_JOYSTICK_BUTTONS];
};
#endif /* __MOCK_PREFS_HH__ */

174
Src/gui/network_menu.cpp Normal file
View File

@ -0,0 +1,174 @@
#include "gui.hh"
#include "menu.hh"
#include "help_box.hh"
#include "virtual_keyboard.hh"
#include <sysdeps.h>
#include <C64.h>
class NetworkView;
class NetworkMenu : public Menu, public KeyboardListener
{
friend class NetworkView;
public:
NetworkMenu(Font *font, HelpBox *help) : Menu(font)
{
this->help = help;
memset(this->messages, 0, sizeof(this->messages));
memset(this->strs, 0, sizeof(this->strs));
}
~NetworkMenu()
{
}
virtual void stringCallback(const char *str)
{
switch (this->cur_sel)
{
case 0:
strncpy(Gui::gui->np->NetworkName, str, sizeof(Gui::gui->np->NetworkName));
break;
case 1:
strncpy(Gui::gui->np->NetworkServer, str, sizeof(Gui::gui->np->NetworkName));
break;
case 2:
{
char *endp;
unsigned long v;
v = strtoul(str, &endp, 0);
if (endp == str)
{
DialogueBox *error_dialogue = new DialogueBox(network_port_dialogue_messages);
Gui::gui->pushDialogueBox(error_dialogue);
}
else
Gui::gui->np->NetworkPort = v;
} break;
default:
panic("Cur sel is %d, not possible!\n", this->cur_sel);
break;
}
this->updateMessages();
}
virtual void selectCallback(int which)
{
printf("option entry %d selected: %s\n", which, this->pp_msgs[which]);
switch (which)
{
case 0:
case 1:
case 2:
VirtualKeyboard::kbd->activate();
VirtualKeyboard::kbd->registerListener(this);
break;
case 4:
if ( strncmp(Gui::gui->np->NetworkName, "Unset", strlen("Unset")) == 0)
Gui::gui->pushDialogueBox(new DialogueBox(network_unset_name_dlg));
else
TheC64->network_connection_type = CONNECT;
break;
case 6:
printf("Send message NYI\n"); // FIXME! Send message
break;
default:
break;
}
}
virtual void hoverCallback(int which)
{
this->help->updateHelpMessage(which);
}
virtual void escapeCallback(int which)
{
Gui::gui->popView();
}
private:
void updateMessages()
{
memset(this->strs, 0, sizeof(this->strs));
snprintf(this->strs[0], sizeof(this->strs[0]) - 1, "Set username (%s)",
Gui::gui->np->NetworkName);
snprintf(this->strs[1], sizeof(this->strs[1]) - 1, "Server (%s)",
Gui::gui->np->NetworkServer);
snprintf(this->strs[2], sizeof(this->strs[2]) - 1, "Server port (%d)",
Gui::gui->np->NetworkPort);
this->messages[0] = this->strs[0];
this->messages[1] = this->strs[1];
this->messages[2] = this->strs[2];
this->messages[3] = " ";
this->messages[4] = "Connect to the network!";
this->messages[5] = " ";
this->messages[6] = "Post network message";
this->messages[7] = NULL;
this->setText(this->messages);
}
char strs[3][255];
const char *messages[8];
HelpBox *help;
};
class NetworkView : public GuiView
{
public:
NetworkView() : GuiView()
{
this->help = new HelpBox(Gui::gui->small_font, network_menu_help);
this->menu = new NetworkMenu(Gui::gui->default_font, this->help);
}
~NetworkView()
{
delete this->help;
delete this->menu;
}
void runLogic()
{
this->menu->runLogic();
}
void pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void viewPushCallback()
{
this->menu->updateMessages();
}
void draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->infobox, NULL, where, &dst);
dst = (SDL_Rect){350,242,0,0};
SDL_BlitSurface(Gui::gui->textbox, NULL, where, &dst);
this->menu->draw(where, 50, 70, 300, 400);
this->help->draw(where, 354, 24, 264, 210);
}
protected:
NetworkMenu *menu;
HelpBox *help;
};

154
Src/gui/options_menu.cpp Normal file
View File

@ -0,0 +1,154 @@
#include "gui.hh"
#include "menu.hh"
#include "help_box.hh"
#include "status_bar.hh"
#include <Prefs.h>
class OptionsView;
class OptionsMenu : public Menu
{
friend class OptionsView;
public:
OptionsMenu(Font *font, HelpBox *help) : Menu(font)
{
this->help = help;
this->setText(options_menu_messages);
}
~OptionsMenu()
{
}
virtual void selectCallback(int which)
{
if (which == 9) /* Game info */
{
Gui::gui->status_bar->queueMessage("Resetting the C64");
Gui::gui->popView();
return;
}
/* Select theme */
if (which == 12)
{
Gui::gui->tv->setDirectory(Gui::gui->theme_base_path);
Gui::gui->pushView(Gui::gui->tv);
return;
}
/* Doesn't matter which otherwise, it's just selection */
this->updatePrefs();
Gui::gui->popView();
}
virtual void hoverCallback(int which)
{
this->help->updateHelpMessage(which);
}
virtual void escapeCallback(int which)
{
this->updatePrefs();
Gui::gui->popView();
}
void updatePrefs()
{
Gui::gui->np->Emul1541Proc = !this->p_submenus[1].sel;
Gui::gui->np->ShowLEDs = !this->p_submenus[2].sel;
Gui::gui->np->DisplayOption = this->p_submenus[3].sel;
switch (this->p_submenus[4].sel)
{
case 0:
Gui::gui->np->MsPerFrame = SPEED_95; break;
case 1:
Gui::gui->np->MsPerFrame = SPEED_100; break;
case 2:
Gui::gui->np->MsPerFrame = SPEED_110; break;
default:
panic("Impossible submenu value: %d\n", this->p_submenus[4].sel);
}
}
void updateSubmenus()
{
int submenu_defs[5];
submenu_defs[0] = 0;
submenu_defs[1] = !Gui::gui->np->Emul1541Proc;
submenu_defs[2] = !Gui::gui->np->ShowLEDs;
submenu_defs[3] = Gui::gui->np->DisplayOption;
switch (Gui::gui->np->MsPerFrame)
{
case SPEED_95:
submenu_defs[4] = 0; break;
case SPEED_110:
submenu_defs[4] = 2; break;
default:
/* If it has some other value... */
submenu_defs[4] = 1; break;
}
this->setText(options_menu_messages, submenu_defs);
}
private:
HelpBox *help;
};
class OptionsView : public GuiView
{
public:
OptionsView() : GuiView()
{
this->help = new HelpBox(Gui::gui->small_font, options_menu_help);
this->menu = new OptionsMenu(Gui::gui->default_font, this->help);
}
~OptionsView()
{
delete this->help;
delete this->menu;
}
void viewPushCallback()
{
this->menu->updateSubmenus();
}
void runLogic()
{
this->menu->runLogic();
}
void pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->infobox, NULL, where, &dst);
dst = (SDL_Rect){350,242,0,0};
SDL_BlitSurface(Gui::gui->textbox, NULL, where, &dst);
this->menu->draw(where, 50, 70, 300, 400);
this->help->draw(where, 354, 24, 264, 210);
}
protected:
OptionsMenu *menu;
HelpBox *help;
};

143
Src/gui/save_game_menu.cpp Normal file
View File

@ -0,0 +1,143 @@
#include <unistd.h> /* unlink */
#include <C64.h>
#include "menu.hh"
#include "file_browser.hh"
#include "game_info.hh"
#include "game_info_box.hh"
#include "utils.hh"
static const char *save_exts[] = {".sav", ".SAV", NULL};
class SaveGameMenu;
class SaveGameView : public GuiView
{
public:
SaveGameView();
~SaveGameView();
void pushEvent(SDL_Event *ev);
void loadGameInfo(const char *what);
void setDirectory(const char *path);
void setLoadSnapshot(bool which);
void saveSnapshot();
/* Inherited */
void runLogic();
void draw(SDL_Surface *where);
SaveGameMenu *menu;
GameInfoBox *gameInfo;
};
class SaveGameMenu : public FileBrowser
{
friend class SaveGameView;
public:
SaveGameMenu(Font *font) :
FileBrowser(save_exts, font)
{
this->loadSnapshot = true;
}
~SaveGameMenu()
{
}
virtual void selectCallback(int which)
{
const char *fileName = this->pp_msgs[this->cur_sel];
if (this->loadSnapshot)
TheC64->LoadSnapshot(fileName);
else
unlink(fileName);
Gui::gui->popView();
}
virtual void hoverCallback(int which)
{
}
virtual void escapeCallback(int which)
{
Gui::gui->popView();
}
bool loadSnapshot;
};
SaveGameView::SaveGameView() : GuiView()
{
this->menu = new SaveGameMenu(Gui::gui->default_font);
this->gameInfo = new GameInfoBox(Gui::gui->default_font);
}
SaveGameView::~SaveGameView()
{
delete this->menu;
delete this->gameInfo;
}
void SaveGameView::loadGameInfo(const char *what)
{
this->gameInfo->loadGameInfo(what);
}
void SaveGameView::setDirectory(const char *path)
{
this->menu->setDirectory(path);
}
void SaveGameView::setLoadSnapshot(bool what)
{
this->menu->loadSnapshot = what;
}
void SaveGameView::saveSnapshot()
{
const char *name = "unknown";
char buf[255];
if (strlen(Gui::gui->np->DrivePath[0]) != 0)
name = Gui::gui->np->DrivePath[0];
snprintf(buf, sizeof(buf), "%s/%s.sav", Gui::gui->save_game_path, name);
TheC64->SaveSnapshot(buf);
}
void SaveGameView::runLogic()
{
this->menu->runLogic();
}
void SaveGameView::pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void SaveGameView::draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->disc_info, NULL, where, &dst);
this->menu->draw(where, 50, 70, 280, 375);
this->gameInfo->draw(where, 360, 55, 262, 447);
}

63
Src/gui/sdl_ttf_font.hh Normal file
View File

@ -0,0 +1,63 @@
#include <SDL.h>
#include <SDL_ttf.h>
#include "font.hh"
#include "utils.hh"
#ifndef __SDL_TTF_FONT_HH__
#define __SDL_TTF_FONT_HH__
class Font_TTF : public Font
{
public:
Font_TTF(TTF_Font *font,
int r, int g, int b)
{
this->clr = (SDL_Color){r, g, b};
this->font = font;
}
~Font_TTF()
{
TTF_CloseFont(this->font);
}
int getHeight(const char *str)
{
int tw, th;
TTF_SizeText(this->font, str, &tw, &th);
return th;
}
int getWidth(const char *str)
{
int tw, th;
TTF_SizeText(this->font, str, &tw, &th);
return tw;
}
void draw(SDL_Surface *where, const char *msg,
int x, int y, int w, int h)
{
SDL_Surface *p;
SDL_Rect dst;
p = TTF_RenderText_Blended(this->font, msg, this->clr);
panic_if(!p, "TTF error for '%s': %s\n", msg, TTF_GetError());
dst = (SDL_Rect){x, y, w, h};
SDL_BlitSurface(p, NULL, where, &dst);
SDL_FreeSurface(p);
}
protected:
TTF_Font *font;
SDL_Color clr;
};
#endif

70
Src/gui/status_bar.cpp Normal file
View File

@ -0,0 +1,70 @@
#include "status_bar.hh"
#include "gui.hh"
StatusBar::StatusBar() : Menu(Gui::gui->small_font), TimeoutHandler()
{
memset(this->messages, 0, sizeof(this->messages));
this->head = this->tail = 0;
this->cur_message = NULL;
this->setSelectedBackground(NULL, NULL, NULL, NULL, NULL, NULL);
}
void StatusBar::queueMessage(const char *message)
{
this->messages[this->head] = message;
/* If this is the first message, display it as soon as possible */
if (this->head == this->tail)
Gui::gui->timerController->arm(this, 1);
this->head = (this->head + 1) % N_STATUS_MESSAGES;
if (this->head == this->tail)
this->tail = (this->tail + 1) % N_STATUS_MESSAGES;
}
const char *StatusBar::dequeueMessage()
{
const char *out = this->messages[this->tail];
if (this->head == this->tail)
return NULL;
this->tail = (this->tail + 1) % N_STATUS_MESSAGES;
return out;
}
void StatusBar::timeoutCallback()
{
static const char *text[2];
this->cur_message = this->dequeueMessage();
text[0] = this->cur_message;
text[1] = NULL;
if (this->cur_message)
{
Gui::gui->timerController->arm(this, 500);
this->setText(text);
}
else
this->setText(NULL);
}
void StatusBar::draw(SDL_Surface *where)
{
SDL_Rect dst;
int x = 130;
int y = 12;
int w = 496;
int h = 56;
if (!this->cur_message)
return;
/* Blit the backgrounds */
dst = (SDL_Rect){x,y,0,0};
SDL_BlitSurface(Gui::gui->status_bar_bg, NULL, where, &dst);
Menu::draw(where, x+4, y+4, w, h);
}

37
Src/gui/status_bar.hh Normal file
View File

@ -0,0 +1,37 @@
#ifndef __STATUS_BAR_HH__
#define __STATUS_BAR_HH__
#include "menu.hh"
#include "gui.hh"
#include "timer.hh"
#define N_STATUS_MESSAGES 8
class StatusBar : public Menu, TimeoutHandler
{
public:
StatusBar();
void queueMessage(const char *message);
virtual void draw(SDL_Surface *where);
virtual void hoverCallback(int which) {};
virtual void selectCallback(int which) {};
virtual void escapeCallback(int which) {};
protected:
virtual void timeoutCallback();
const char *dequeueMessage();
const char *messages[N_STATUS_MESSAGES];
const char *cur_message;
int head, tail;
int x;
int y;
};
#endif /* __DIALOGUE_BOX_HH__ */

99
Src/gui/theme_menu.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "menu.hh"
#include "file_browser.hh"
class ThemeMenu;
class ThemeView : public GuiView
{
public:
ThemeView();
~ThemeView();
void pushEvent(SDL_Event *ev);
void setDirectory(const char *path);
/* Inherited */
void runLogic();
void draw(SDL_Surface *where);
protected:
ThemeMenu *menu;
};
class ThemeMenu : public FileBrowser
{
friend class ThemeView;
public:
ThemeMenu(Font *font) :
FileBrowser(NULL, font)
{
}
virtual void selectCallback(int which)
{
char *p = xstrdup(this->pp_msgs[this->cur_sel]);
p[strlen(p) - 1] = '\0';
if (!Gui::gui->setTheme(p + 1))
{
/* Something is wrong, reset to default */
Gui::gui->setTheme("default");
Gui::gui->pushDialogueBox(new DialogueBox(broken_theme_dlg));
}
free(p);
Gui::gui->popView();
}
virtual void hoverCallback(int which)
{
}
virtual void escapeCallback(int which)
{
}
};
ThemeView::ThemeView() : GuiView()
{
this->menu = new ThemeMenu(Gui::gui->default_font);
}
ThemeView::~ThemeView()
{
delete this->menu;
}
void ThemeView::setDirectory(const char *path)
{
this->menu->setDirectory(path);
}
void ThemeView::runLogic()
{
this->menu->runLogic();
}
void ThemeView::pushEvent(SDL_Event *ev)
{
this->menu->pushEvent(ev);
}
void ThemeView::draw(SDL_Surface *where)
{
SDL_Rect dst;
/* Blit the backgrounds */
dst = (SDL_Rect){20,45,300,400};
SDL_BlitSurface(Gui::gui->main_menu_bg, NULL, where, &dst);
dst = (SDL_Rect){350,13,0,0};
SDL_BlitSurface(Gui::gui->infobox, NULL, where, &dst);
this->menu->draw(where, 50, 70, 280, 375);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

68
Src/gui/timer.cpp Normal file
View File

@ -0,0 +1,68 @@
#include "timer.hh"
#include "utils.hh"
// FIXME!
#define MS_TO_TICKS(x) ((x) / 28)
TimerController::TimerController()
{
this->n_handlers = 0;
this->handlers = NULL;
}
int TimerController::arm(TimeoutHandler *which, int ms)
{
int i;
/* Set the timeout */
which->timeout = MS_TO_TICKS(ms);
if (which->timeout == 0)
which->timeout = 1;
/* Re-register? */
for (i = 0; i < this->n_handlers; i++)
if (this->handlers[i] == which)
return i;
/* Not already there */
for (i = 0; i < this->n_handlers; i++)
if (this->handlers[i] == NULL)
break;
if (i == this->n_handlers)
{
this->n_handlers++;
this->handlers = (TimeoutHandler**)xrealloc(this->handlers,
this->n_handlers * sizeof(TimeoutHandler*));
}
this->handlers[i] = which;
which->timer_id = i;
return i;
}
void TimerController::disarm(TimeoutHandler *which)
{
panic_if(which->timer_id >= this->n_handlers,
"timer_id %d is too out of bounds (max %d)\n",
which->timer_id, this->n_handlers);
this->handlers[which->timer_id] = NULL;
which->timer_id = -1;
}
void TimerController::tick()
{
for (int i = 0; i < this->n_handlers; i++)
{
TimeoutHandler *cur = this->handlers[i];
if (!cur)
continue;
cur->tick();
if (cur->timeout == 0)
this->disarm(cur);
}
}

46
Src/gui/timer.hh Normal file
View File

@ -0,0 +1,46 @@
#ifndef __TIMER_HH__
#define __TIMER_HH__
class TimeoutHandler;
class TimerController
{
public:
TimerController();
int arm(TimeoutHandler *which, int ms);
void disarm(TimeoutHandler *which);
void tick();
private:
int n_handlers;
TimeoutHandler **handlers;
};
class TimeoutHandler
{
friend class TimerController;
public:
TimeoutHandler()
{
this->timeout = 0;
this->timer_id = -1;
}
void tick()
{
this->timeout--;
if (this->timeout == 0)
this->timeoutCallback();
}
virtual void timeoutCallback() = 0;
protected:
int timeout;
int timer_id;
};
#endif /* __TIMER_HH__ */

273
Src/gui/utils.cpp Normal file
View File

@ -0,0 +1,273 @@
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <png.h>
#include <sys/stat.h>
#include <SDL_ttf.h>
#include "utils.hh"
#include "font.hh"
TTF_Font *read_and_alloc_font(const char *path, int pt_size)
{
TTF_Font *out;
SDL_RWops *rw;
Uint8 *data;
FILE *fp = fopen(path, "r");
if (!fp) {
fprintf(stderr, "Could not open font %s\n", path);
return NULL;
}
data = (Uint8*)xmalloc(1 * 1024*1024);
fread(data, 1, 1 * 1024 * 1024, fp);
rw = SDL_RWFromMem(data, 1 * 1024 * 1024);
if (!rw)
{
fprintf(stderr, "Could not create RW: %s\n", SDL_GetError());
free(data);
return NULL;
}
out = TTF_OpenFontRW(rw, 1, pt_size);
if (!out)
{
fprintf(stderr, "TTF: Unable to create font %s (%s)\n",
path, TTF_GetError());
}
fclose(fp);
return out;
}
static int cmpstringp(const void *p1, const void *p2)
{
const char *p1_s = *(const char**)p1;
const char *p2_s = *(const char**)p2;
/* Put directories first and handle some special cases */
if (*p1_s == '[' && *p2_s != '[')
return -1;
if (*p1_s != '[' && *p2_s == '[')
return 1;
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
/* Return true if name ends with ext (for filenames) */
static bool ext_matches(const char *name, const char *ext)
{
int len = strlen(name);
int ext_len = strlen(ext);
if (len <= ext_len)
return false;
return (strcmp(name + len - ext_len, ext) == 0);
}
bool ext_matches_list(const char *name, const char **exts)
{
for (const char **p = exts; *p; p++)
{
if (ext_matches(name, *p))
return true;
}
return false;
}
const char **get_file_list(const char *base_dir, const char *exts[])
{
DIR *d = opendir(base_dir);
const char **file_list;
int cur = 0;
struct dirent *de;
int cnt = 16;
if (!d)
return NULL;
file_list = (const char**)malloc(cnt * sizeof(char*));
file_list[cur++] = strdup("None");
file_list[cur] = NULL;
for (de = readdir(d);
de;
de = readdir(d))
{
char buf[255];
struct stat st;
snprintf(buf, 255, "%s/%s", base_dir, de->d_name);
if (stat(buf, &st) < 0)
continue;
if (S_ISDIR(st.st_mode))
{
char *p;
size_t len = strlen(de->d_name) + 4;
/* We don't need the current dir */
if (strcmp(de->d_name, ".") == 0)
continue;
p = (char*)malloc( len );
snprintf(p, len, "[%s]", de->d_name);
file_list[cur++] = p;
file_list[cur] = NULL;
}
else if (ext_matches_list(de->d_name, exts))
{
char *p;
p = strdup(de->d_name);
file_list[cur++] = p;
file_list[cur] = NULL;
}
if (cur > cnt - 2)
{
cnt = cnt + 32;
file_list = (const char**)realloc(file_list, cnt * sizeof(char*));
if (!file_list)
return NULL;
}
}
closedir(d);
qsort(&file_list[1], cur-1, sizeof(const char *), cmpstringp);
return file_list;
}
/* PNG writing */
struct png_write_user_struct
{
size_t sz;
void *data;
};
static void user_write_fn(png_structp png_ptr, png_bytep bytes, png_size_t sz)
{
struct png_write_user_struct *out = (struct png_write_user_struct *)png_ptr->io_ptr;
out->data = xrealloc(out->data, out->sz + sz);
memcpy((uint8_t*)out->data + out->sz, bytes, sz);
out->sz += sz;
}
static int png_colortype_from_surface(SDL_Surface *surface)
{
int colortype = PNG_COLOR_MASK_COLOR; /* grayscale not supported */
if (surface->format->palette)
colortype |= PNG_COLOR_MASK_PALETTE;
else if (surface->format->Amask)
colortype |= PNG_COLOR_MASK_ALPHA;
return colortype;
}
static void png_user_warn(png_structp ctx, png_const_charp str)
{
fprintf(stderr, "libpng: warning: %s\n", str);
}
static void png_user_error(png_structp ctx, png_const_charp str)
{
fprintf(stderr, "libpng: error: %s\n", str);
}
/* This is taken from http://encelo.netsons.org/programming/sdl (GPLed) */
void *sdl_surface_to_png(SDL_Surface *surf, size_t *out_sz)
{
png_structp png_ptr;
png_infop info_ptr;
int i, colortype;
png_bytep *row_pointers;
struct png_write_user_struct out;
out.sz = 0;
out.data = NULL;
/* Initializing png structures and callbacks */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, png_user_error, png_user_warn);
if (png_ptr == NULL) {
printf("png_create_write_struct error!\n");
return NULL;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
printf("png_create_info_struct error!\n");
exit(-1);
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
exit(-1);
}
png_set_write_fn(png_ptr, (void *)&out, user_write_fn, NULL);
colortype = png_colortype_from_surface(surf);
png_set_IHDR(png_ptr, info_ptr, surf->w, surf->h, 8, colortype, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
/* Writing the image */
png_write_info(png_ptr, info_ptr);
png_set_packing(png_ptr);
row_pointers = (png_bytep*) malloc(sizeof(png_bytep)*surf->h);
for (i = 0; i < surf->h; i++)
row_pointers[i] = (png_bytep)(Uint8 *)surf->pixels + i*surf->pitch;
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
/* Cleaning out... */
free(row_pointers);
png_destroy_write_struct(&png_ptr, &info_ptr);
*out_sz = out.sz;
return out.data;
}
void highlight_background(SDL_Surface *where, Font *font,
SDL_Surface *bg_left, SDL_Surface *bg_middle, SDL_Surface *bg_right,
int x, int y, int w, int h)
{
SDL_Rect dst;
/* Can't highlight without images */
if (!bg_left || !bg_middle || !bg_right)
return;
int font_height = font->getHeight("X");
int bg_y_start = y + font_height / 2 -
bg_left->h / 2;
int bg_x_start = x - bg_left->w / 3;
int bg_x_end = x + w - (2 * bg_right->w) / 3;
int n_mid = (bg_x_end - bg_x_start) / bg_middle->w;
/* Left */
dst = (SDL_Rect){bg_x_start, bg_y_start, 0,0};
SDL_BlitSurface(bg_left, NULL, where, &dst);
/* Middle */
for (int i = 1; i < n_mid; i++)
{
dst = (SDL_Rect){bg_x_start + i * bg_middle->w, bg_y_start, 0,0};
SDL_BlitSurface(bg_middle, NULL, where, &dst);
}
dst = (SDL_Rect){bg_x_end - bg_middle->w, bg_y_start, 0,0};
SDL_BlitSurface(bg_middle, NULL, where, &dst);
/* Right */
dst = (SDL_Rect){bg_x_end, bg_y_start, 0,0};
SDL_BlitSurface(bg_right, NULL, where, &dst);
}

82
Src/gui/utils.hh Normal file
View File

@ -0,0 +1,82 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <SDL.h>
#include <SDL_ttf.h>
class Font;
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
#define BUG_ON(cond)
#define panic(x...) do \
{ \
fprintf(stderr, "=============PANIC PANIC PANIC===========\n"); \
fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); fprintf(stderr, x); \
fprintf(stderr, "=========================================\n"); \
assert(0); \
exit(1); \
} while(0)
#define warning(x...) do \
{ \
fprintf(stderr, "==============WARNING WARNING============\n"); \
fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); fprintf(stderr, x); \
fprintf(stderr, "=========================================\n"); \
} while(0)
#define panic_if(cond, x...) \
do { if ((cond)) panic(x); } while(0)
static inline char *xstrdup(const char *s)
{
char *out = strdup(s);
panic_if(!out, "strdup failed");
return out;
}
static inline void *xmalloc(size_t sz)
{
void *out = malloc(sz);
panic_if(!out, "malloc failed");
memset(out, 0, sz);
return out;
}
static inline void *xrealloc(void *ptr, size_t sz)
{
void *out = realloc(ptr, sz);
panic_if(!out, "malloc failed");
return out;
}
#define xsnprintf(buf, size, fmt, x...) do { \
int r = snprintf(buf, size, fmt, x); \
panic_if(r < 0 || r >= (int)(size), "snprintf failed for %s with %d\n", fmt, r); \
} while(0)
TTF_Font *read_and_alloc_font(const char *path, int pt_size);
bool ext_matches_list(const char *name, const char **exts);
const char **get_file_list(const char *base_dir, const char *exts[]);
void *sdl_surface_to_png(SDL_Surface *src, size_t *out_sz);
void highlight_background(SDL_Surface *where, Font *font,
SDL_Surface *bg_left, SDL_Surface *bg_middle, SDL_Surface *bg_right,
int x, int y, int w, int h);
#endif /* __UTILS_H__ */

View File

@ -0,0 +1,440 @@
/*********************************************************************
*
* Copyright (C) 2009, Simon Kagstrom
*
* Filename: VirtualKeyboard.c
* Author: Simon Kagstrom <simon.kagstrom@gmail.com>
* Description: A virtual keyboard
*
* $Id$
*
********************************************************************/
#include <SDL.h>
#include "virtual_keyboard.hh"
#include "utils.hh"
#include "gui.hh"
typedef struct virtkey
{
const char *name;
int kc;
bool is_shift;
bool is_done;
} virtkey_t;
#define INVALID_VIRTKEY ((struct virtkey){NULL, -1, false, false})
static inline bool IS_INVALID_VIRTKEY(virtkey_t *k)
{
return k->name == NULL && k->kc == -1 &&
k->is_done == false && k->is_shift == false;
}
/*
C64 keyboard matrix:
Bit 7 6 5 4 3 2 1 0
0 CUD F5 F3 F1 F7 CLR RET DEL
1 SHL E S Z 4 A W 3
2 X T F C 6 D R 5
3 V U H B 8 G Y 7
4 N O K M 0 J I 9
5 , @ : . - L P +
6 / ^ = SHR HOM ; * <EFBFBD>
7 R/S Q C= SPC 2 CTL <- 1
*/
#define MATRIX(a,b) (((a) << 3) | (b))
#define K(name, a,b) \
{ name, MATRIX(a,b), false, false }
#define S(name, a,b) \
{ name, MATRIX(a,b), true, false }
#define N(name) \
{ name, -1, false, false }
#define D(name) \
{ name, -1, false, true }
#define J(name, v) \
{ name, 0x40 | (v), false, false }
#define KEY_COLS 15
#define KEY_ROWS 8
static virtkey_t keys[KEY_COLS * KEY_ROWS] = {
K("<-",7,1), K("1", 7,0), K("2", 7,3), K("3", 1,0), K("4", 1,3), K("5", 2,0), K("6", 2,3), K("7", 3,0), K("8", 3,3), K("9", 4,0), K("0", 4,3), K("+", 5,0), K("-", 5,3), K("£", 6,0), K("Hom", 6,3),
K("Cr", 7,2), K("Q", 7,6), K("W", 1,1), K("E", 1,6), K("R", 2,1), K("T", 2,6), K("Y", 3,1), K("U", 3,6), K("I", 4,1), K("O", 4,6), K("P", 5,1), K("@", 5,6), K("*", 6,1), K("Au", 6,6),K("Rstr",4,0),
K("R/Stp", 7,7), K(NULL,0,0), K("A", 1,2), K("S", 1,5), K("D", 2,2), K("F", 2,5), K("G", 3,2), K("H", 3,5), K("J", 4,2), K("K", 4,5), K("L", 5,2), K(":", 5,5), K(";", 6,2), K("=", 6,5), K("Ret", 0,1),
K("C=", 7,5), S("Shft",1,7),K(NULL,0,0),K("Z", 1,4), K("X", 2,7), K("C", 2,4), K("V", 3,7), K("B", 3,4), K("N", 4,7), K("M", 4,4), K(",", 5,7), K(".", 5,4), K("/", 6,7), K("Dwn",0,7),K("Rgt", 0,2),
N("None"), K(NULL,0,0), K(NULL,0,0), K("space", 7,4),K(0, 0,0),K(NULL,0,0), K("f1",0,4), K("f3",0,5), K("f5",0,6), K("f7",0,3), K("Del",0,0),K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), D("DONE"),
K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(0, 0,0),K(0, 0,0),J("Joy up",1),K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(NULL, 0,0),K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(NULL, 0,0),
K(0, 0,0), K(NULL,0,0), K(NULL,0,0), J("Joy left",4), K(0,0,0),K(0,0,0),J("Joy fire",0x10),K(0,0,0), K(NULL,0,0),J("Joy right",8),K(0,0,0),K(0, 0,0),K(0, 0,0), K(NULL,0,0), K(NULL,0,0),
K(NULL,0,0), K(0, 0,0), K(NULL,0,0), K(NULL,0,0), K(0,0,0),K(0,0,0),J("Joy down",2),K(NULL,0,0),K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(NULL,0,0), K(NULL, 0,0),K(NULL,0,0), K(NULL, 0,0),
};
static const char *shifted_names[KEY_COLS * KEY_ROWS] = {
NULL, "!", "\"", "#", "$", "%", "&", "'", "(", ")", NULL, NULL, NULL, NULL, "Clr",
NULL, "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", NULL, NULL, NULL, NULL,
NULL, NULL, "a", "s", "d", "f", "g", "h", "j", "k", "l", "[", "]", NULL, NULL,
NULL, NULL, NULL, "z", "x", "c", "v", "b", "n", "m", "<", ">", "?", "Up", "Lft",
NULL, NULL, NULL, NULL, NULL, NULL, "f2", "f4", "f6", "f8", "Ins", NULL, NULL, NULL, NULL,
};
VirtualKeyboard::VirtualKeyboard(Font *font) : GuiView(), ListenerManager()
{
this->font = font;
this->sel_x = 0;
this->sel_y = 0;
this->shift_on = false;
this->kbd_only_input = false;
this->is_active = false;
this->buf_head = 0;
this->buf_len = 255;
this->buf = (struct virtkey*)xmalloc(sizeof(struct virtkey) * this->buf_len);
memset(this->buf, 0, sizeof(struct virtkey) * this->buf_len);
}
VirtualKeyboard::~VirtualKeyboard()
{
free(this->buf);
}
void VirtualKeyboard::draw(SDL_Surface *where, int x_base, int y_base, int w, int h)
{
int key_w = w / KEY_COLS;
int key_h = h / KEY_ROWS;
SDL_Rect bg_rect = {x_base, y_base,
key_w * KEY_COLS, key_h * KEY_ROWS};
SDL_FillRect(where, &bg_rect,
SDL_MapRGB(where->format, 0x00, 0x80, 0x80));
for (int y = 0; y < KEY_ROWS; y++ )
{
for (int x = 0; x < KEY_COLS; x++ )
{
int which = y * KEY_COLS + x;
virtkey_t key = keys[which];
const char *what = key.name;
/* Skip empty positions */
if (key.name == NULL)
continue;
if (this->shift_on && shifted_names[which])
what = shifted_names[which];
if (this->sel_x == x && this->sel_y == y)
highlight_background(where, Gui::gui->small_font,
Gui::gui->bg_left, Gui::gui->bg_middle, Gui::gui->bg_right,
x * key_w + x_base, y * key_h + y_base,
this->font->getWidth(what), h);
this->font->draw(where, what,
x * key_w + x_base, y * key_h + y_base, w, h);
}
}
}
void VirtualKeyboard::selectNext(int dx, int dy)
{
int next_x = (this->sel_x + dx) % KEY_COLS;
int next_y = (this->sel_y + dy) % KEY_ROWS;
virtkey_t key;
if (next_x < 0)
next_x = KEY_COLS + next_x;
if (next_y < 0)
next_y = KEY_ROWS + next_y;
this->sel_x = next_x;
this->sel_y = next_y;
key = keys[ next_y * KEY_COLS + next_x ];
/* Skip the empty spots */
if (key.name == NULL)
{
if (dy != 0) /* Look left */
this->selectNext(-1, 0);
else
this->selectNext(dx, dy);
}
}
void VirtualKeyboard::toggleShift()
{
this->shift_on = !this->shift_on;
}
const char *VirtualKeyboard::keycodeToString(int kc)
{
bool shifted = kc & 0x80;
int kc_raw = kc & ~0x80;
const char *out = "Unknown";
if (kc < 0)
return "None";
/* Just loop through all of them */
for (int i = 0; i < KEY_COLS * KEY_ROWS; i++)
{
virtkey_t key = keys[i];
if (key.kc == kc_raw && key.name != NULL)
{
out = key.name;
if (shifted && shifted_names[i])
out = shifted_names[i];
break;
}
}
return out;
}
int VirtualKeyboard::charToKeycode(char c)
{
for (int i = 0; i < KEY_COLS * KEY_ROWS; i++)
{
virtkey_t key = keys[i];
if (key.name != NULL)
{
if (strlen(key.name) == 1)
{
if (key.name[0] == c)
return key.kc;
if (shifted_names[i] && strlen(shifted_names[i]) == 1 &&
shifted_names[i][0] == c)
return key.kc | 0x80;
}
/* OK, ugly special cases, but these are pretty important */
if (c == ' ' && strcmp(key.name, "space") == 0)
return key.kc;
if (c == '\n' && strcmp(key.name, "Ret") == 0)
return key.kc;
}
}
return -1;
}
virtkey_t VirtualKeyboard::eventToVirtkey(event_t ev)
{
char c = (char)ev;
for (int i = 0; i < KEY_COLS * KEY_ROWS; i++)
{
virtkey_t key = keys[i];
if (key.name != NULL)
{
if (strlen(key.name) == 1)
{
if (key.name[0] == c)
return key;
if (shifted_names[i] && strlen(shifted_names[i]) == 1 &&
shifted_names[i][0] == c)
return key;
}
/* OK, ugly special cases, but these are pretty important */
if ( (c == ' ' && strcmp(key.name, "space") == 0) ||
(c == '\n' && strcmp(key.name, "Ret") == 0) )
return key;
}
}
return INVALID_VIRTKEY;
}
int VirtualKeyboard::stringToKeycode(const char *str)
{
for (int i = 0; i < KEY_COLS * KEY_ROWS; i++)
{
virtkey_t key = keys[i];
if (key.name != NULL)
{
if (strcmp(key.name, str) == 0)
return key.kc;
}
}
return 0;
}
const char VirtualKeyboard::keycodeToChar(int kc)
{
const char *s = this->keycodeToString(kc);
if (strcmp(s, "space") == 0)
return ' ';
if (strcmp(s, "Ret") == 0)
return '\n';
if (strcmp(s, "Del") == 0)
return '\b';
/* NULL is never, ever returned */
return s[0];
}
void VirtualKeyboard::activate()
{
Gui::gui->kbd = this;
this->is_active = true;
memset(this->buf, 0, sizeof(struct virtkey) * this->buf_len);
this->buf_head = 0;
this->kbd_only_input = false;
}
void VirtualKeyboard::runLogic()
{
event_t ev;
virtkey_t ev_key;
if (!this->is_active)
return;
ev = this->popEvent();
if (ev == EVENT_NONE)
return;
/* Something was typed on the keyboard */
ev_key = this->eventToVirtkey(ev);
if ( !IS_INVALID_VIRTKEY(&ev_key) ) {
this->pushKey(&ev_key);
}
if (ev & KEY_UP)
this->selectNext(0, -1);
else if (ev & KEY_DOWN)
this->selectNext(0, 1);
else if (ev & KEY_LEFT)
this->selectNext(-1, 0);
else if (ev & KEY_RIGHT)
this->selectNext(1, 0);
else if (ev & KEY_ESCAPE)
this->deactivate();
else if (ev & KEY_SELECT)
{
virtkey_t *key = &keys[ this->sel_y * KEY_COLS + this->sel_x ];
if (!key)
return;
if (key->is_shift == true)
this->toggleShift();
else if (key->is_done) /* We're done! */
this->done();
else if (strcmp(key->name, "Del") == 0)
{
if (this->buf_head > 1)
{
this->buf[this->buf_head - 1] = (struct virtkey){NULL, -1, false, false};
this->buf_head -= 2;
}
}
else
this->pushKey(key);
}
}
void VirtualKeyboard::pushKey(struct virtkey *vk)
{
int n_listeners = sizeof(this->listeners) / sizeof(*this->listeners);
/* Add to buf */
this->buf[this->buf_head] = *vk;
this->buf_head++;
if (this->buf_head >= this->buf_len - 1)
this->buf_head = 0; /* OK, not good, but well... */
for (int i = 0; i < n_listeners; i++)
{
if (this->listeners[i])
((KeyboardListener*)this->listeners[i])->keyCallback(this->shift_on,
vk->name);
}
}
void VirtualKeyboard::deactivate()
{
this->is_active = false;
this->flushListeners();
Gui::gui->kbd = NULL;
}
void VirtualKeyboard::done()
{
int n_listeners = sizeof(this->listeners) / sizeof(*this->listeners);
char *buf = (char *)xmalloc(this->buf_head + 1);
for (unsigned i = 0; i < this->buf_head; i++)
buf[i] = this->keycodeToChar(this->buf[i].kc);
for (int i = 0; i < n_listeners; i++)
{
if (this->listeners[i])
((KeyboardListener*)this->listeners[i])->stringCallback(buf);
}
free(buf);
this->deactivate();
}
void VirtualKeyboard::draw(SDL_Surface *where)
{
this->draw(where, 20, 240, 600, 240);
}
void VirtualKeyboard::updateTheme()
{
this->setFont(Gui::gui->small_font);
}
void VirtualKeyboard::pushEvent(SDL_Event *ev)
{
switch(ev->type)
{
case SDL_KEYDOWN:
switch (ev->key.keysym.sym)
{
case SDLK_UP:
case SDLK_DOWN:
case SDLK_LEFT:
case SDLK_RIGHT:
case SDLK_PAGEDOWN:
case SDLK_PAGEUP:
case SDLK_HOME:
case SDLK_ESCAPE:
/* Handle via the standard widget implementation (except for space) */
this->kbd_only_input = false;
Widget::pushEvent(ev);
return;
case SDLK_RETURN:
if (this->kbd_only_input)
this->done();
else
Widget::pushEvent(ev);
return;
case SDLK_SPACE ... SDLK_z:
Widget::pushEvent((event_t)(ev->key.keysym.sym));
this->kbd_only_input = true;
default:
break;
}
default:
break;
}
}
/* The singleton */
VirtualKeyboard *VirtualKeyboard::kbd;
KeyboardListener::~KeyboardListener()
{
VirtualKeyboard::kbd->unregisterListener(this);
}

100
Src/gui/virtual_keyboard.hh Normal file
View File

@ -0,0 +1,100 @@
/*********************************************************************
*
* Copyright (C) 2009, Simon Kagstrom
*
* Filename: VirtualKeyboard.c
* Author: Simon Kagstrom <simon.kagstrom@gmail.com>
* Description: A virtual keyboard
*
* $Id$
*
********************************************************************/
#ifndef __VIRTUAL_KEYBORD_HH__
#define __VIRTUAL_KEYBORD_HH__
#include <SDL.h>
#include "widget.hh"
#include "gui_view.hh"
#include "font.hh"
#include "listener.hh"
struct virtkey;
class KeyboardListener : public Listener
{
public:
~KeyboardListener();
/* Each key is a string */
virtual void keyCallback(bool shift, const char *str)
{
}
virtual void stringCallback(const char *str)
{
}
};
class VirtualKeyboard : public GuiView, public ListenerManager
{
public:
VirtualKeyboard(Font *font);
~VirtualKeyboard();
/* Conversions */
const char *keycodeToString(int kc);
const char keycodeToChar(int kc);
int charToKeycode(char c);
int stringToKeycode(const char *str);
struct virtkey eventToVirtkey(event_t ev);
void activate();
void setFont(Font *font)
{
this->font = font;
}
void deactivate();
bool isActive()
{
return this->is_active;
}
virtual void updateTheme();
void draw(SDL_Surface *where);
void runLogic();
void draw(SDL_Surface *where, int x, int y, int w, int h);
void pushEvent(SDL_Event *ev);
/* Singleton object */
static VirtualKeyboard *kbd;
private:
void selectNext(int dx, int dy);
void toggleShift();
void pushKey(struct virtkey *vk);
void done();
Font *font;
int sel_x;
int sel_y;
bool shift_on;
bool kbd_only_input;
bool is_active;
struct virtkey *buf;
unsigned buf_head;
size_t buf_len;
};
#endif /* __VIRTUAL_KEYBORD_HH__ */

76
Src/gui/widget.cpp Normal file
View File

@ -0,0 +1,76 @@
#include "widget.hh"
Widget::Widget()
{
memset(this->event_stack, 0, sizeof(this->event_stack));
this->ev_head = this->ev_tail = 0;
}
event_t Widget::popEvent()
{
event_t out;
if (this->ev_head == this->ev_tail)
return EVENT_NONE;
out = this->event_stack[this->ev_tail];
this->ev_tail = (this->ev_tail + 1) % 8;
return out;
}
void Widget::pushEvent(event_t ev)
{
/* Push... */
this->event_stack[this->ev_head] = ev;
/* ... and update */
this->ev_head = (this->ev_head + 1) % 8;
if (this->ev_head == this->ev_tail)
this->ev_tail = (this->ev_tail + 1) % 8;
}
void Widget::pushEvent(SDL_Event *ev)
{
switch(ev->type)
{
case SDL_KEYDOWN:
switch (ev->key.keysym.sym)
{
case SDLK_UP:
this->pushEvent(KEY_UP);
break;
case SDLK_DOWN:
this->pushEvent(KEY_DOWN);
break;
case SDLK_LEFT:
this->pushEvent(KEY_LEFT);
break;
case SDLK_RIGHT:
this->pushEvent(KEY_RIGHT);
break;
case SDLK_PAGEDOWN:
this->pushEvent(KEY_PAGEDOWN);
break;
case SDLK_PAGEUP:
this->pushEvent(KEY_PAGEUP);
break;
case SDLK_RETURN:
case SDLK_SPACE:
this->pushEvent(KEY_SELECT);
break;
case SDLK_HOME:
case SDLK_ESCAPE:
this->pushEvent(KEY_ESCAPE);
break;
default:
break;
}
default:
break;
}
}
void Widget::draw(SDL_Surface *where, int x, int y, int w, int h)
{
}

42
Src/gui/widget.hh Normal file
View File

@ -0,0 +1,42 @@
#ifndef WIDGET_HH
#define WIDGET_HH
#include <SDL.h>
enum key_event {
EVENT_NONE = (1 << 8),
KEY_UP = (1 << 9),
KEY_DOWN = (1 << 10),
KEY_LEFT = (1 << 11),
KEY_RIGHT = (1 << 12),
KEY_SELECT = (1 << 13),
KEY_ESCAPE = (1 << 14),
KEY_PAGEDOWN = (1 << 15),
KEY_PAGEUP = (1 << 16),
KEY_HELP = (1 << 17),
};
typedef enum key_event event_t;
class Widget
{
public:
Widget();
virtual void pushEvent(event_t ev);
virtual void pushEvent(SDL_Event *ev);
virtual void runLogic() = 0;
virtual void draw(SDL_Surface *where,
int x, int y, int w, int h);
virtual event_t popEvent();
protected:
int ev_head, ev_tail;
event_t event_stack[8];
};
#endif

View File

@ -11,8 +11,6 @@
#include <wiiuse/wpad.h> #include <wiiuse/wpad.h>
#include <network.h> #include <network.h>
#include "menu.h"
extern int init_graphics(void); extern int init_graphics(void);
/* /*

View File

@ -31,10 +31,10 @@ extern "C" int main(int argc, char *argv[]);
#endif #endif
#if defined(HAVE_SDL) #if defined(HAVE_SDL)
#include <SDL.h> #include <SDL.h>
#include <SDL_ttf.h>
#include "gui/gui.hh"
#endif #endif
#include "menu.h"
extern int init_graphics(void); extern int init_graphics(void);
@ -75,7 +75,8 @@ int main(int argc, char **argv)
fprintf(stderr, "Unable to init TTF: %s\n", TTF_GetError() ); fprintf(stderr, "Unable to init TTF: %s\n", TTF_GetError() );
return 1; return 1;
} }
menu_init(); Gui::gui = new Gui();
Gui::gui->setTheme("default");
#endif #endif
if (!init_graphics()) if (!init_graphics())
return 1; return 1;