Copy in the new GUI code. Builds but will not work now.
@ -24,7 +24,7 @@ datadir = ${PREFIX}/share
|
||||
#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
|
||||
|
||||
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 \
|
||||
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/VirtualKeyboard.cpp
|
||||
|
||||
C_SRCS=Src/d64-read.c Src/menutexts.c
|
||||
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 \
|
||||
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))
|
||||
|
@ -530,7 +530,7 @@ bool C64::Load1541JobState(FILE *f)
|
||||
* snapshot is loaded into FrodoSC again.
|
||||
*/
|
||||
|
||||
void C64::SaveSnapshot(char *filename)
|
||||
void C64::SaveSnapshot(const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
uint8 flags;
|
||||
@ -595,7 +595,7 @@ void C64::SaveSnapshot(char *filename)
|
||||
* Load snapshot (emulation must be paused and in VBlank)
|
||||
*/
|
||||
|
||||
bool C64::LoadSnapshot(char *filename)
|
||||
bool C64::LoadSnapshot(const char *filename)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
|
36
Src/C64.h
@ -21,9 +21,6 @@
|
||||
#define _C64_H
|
||||
|
||||
#if defined(HAVE_SDL)
|
||||
/* SDL menu */
|
||||
#include "menu.h"
|
||||
#include "VirtualKeyboard.h"
|
||||
#include "Network.h"
|
||||
#include "Prefs.h"
|
||||
#endif
|
||||
@ -90,16 +87,24 @@ public:
|
||||
|
||||
void Run(void);
|
||||
void Quit(void);
|
||||
void Pause(void);
|
||||
void Resume(void);
|
||||
void Pause(void)
|
||||
{
|
||||
this->have_a_break = true;
|
||||
}
|
||||
|
||||
void Resume(void)
|
||||
{
|
||||
this->have_a_break = false;
|
||||
}
|
||||
|
||||
void Reset(void);
|
||||
void NMI(void);
|
||||
void VBlank(bool draw_frame);
|
||||
void NewPrefs(Prefs *prefs);
|
||||
void PatchKernal(bool fast_reset, bool emul_1541_proc);
|
||||
void SaveRAM(char *filename);
|
||||
void SaveSnapshot(char *filename);
|
||||
bool LoadSnapshot(char *filename);
|
||||
void SaveSnapshot(const char *filename);
|
||||
bool LoadSnapshot(const char *filename);
|
||||
int SaveCPUState(FILE *f);
|
||||
int Save1541State(FILE *f);
|
||||
bool Save1541JobState(FILE *f);
|
||||
@ -133,6 +138,11 @@ public:
|
||||
#ifdef FRODO_SC
|
||||
uint32 CycleCounter;
|
||||
#endif
|
||||
bool IsPaused()
|
||||
{
|
||||
return this->have_a_break;
|
||||
}
|
||||
|
||||
void enter_menu() {
|
||||
this->have_a_break = true;
|
||||
}
|
||||
@ -201,12 +211,10 @@ public:
|
||||
double speed_index;
|
||||
#endif
|
||||
#ifdef HAVE_SDL
|
||||
VirtualKeyboard *virtual_keyboard;
|
||||
char server_hostname[255];
|
||||
int server_port;
|
||||
int network_connection_type;
|
||||
Network *peer;
|
||||
TTF_Font *menu_font;
|
||||
int linecnt;
|
||||
|
||||
bool fake_key_sequence;
|
||||
@ -219,16 +227,8 @@ public:
|
||||
|
||||
void network_vblank();
|
||||
|
||||
void select_disc(Prefs *np, bool start);
|
||||
void start_fake_key_sequence(const char *str);
|
||||
void startFakeKeySequence(const char *str);
|
||||
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
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* C64_SC.cpp - Put the pieces together (Frodo SC)
|
||||
*
|
||||
|
386
Src/C64_SDL.h
@ -10,6 +10,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "gui/gui.hh"
|
||||
#include "gui/virtual_keyboard.hh"
|
||||
|
||||
#if defined(GEKKO)
|
||||
#include <wiiuse/wpad.h>
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
@ -24,8 +27,6 @@
|
||||
|
||||
#define C64_NETWORK_BROKER "c64-network.game-host.org"
|
||||
|
||||
#include "menutexts.h"
|
||||
|
||||
/* TODO: */
|
||||
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));
|
||||
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,
|
||||
sizeof(this->server_hostname));
|
||||
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 */
|
||||
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);
|
||||
|
||||
@ -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_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
|
||||
*/
|
||||
@ -642,63 +318,11 @@ void C64::VBlank(bool draw_frame)
|
||||
}
|
||||
|
||||
if (this->have_a_break) {
|
||||
int submenus[3] = {1, 0, 0};
|
||||
int opt;
|
||||
|
||||
Prefs np = ThePrefs;
|
||||
this->prefs_changed = false;
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "Version.h"
|
||||
|
||||
#include "CIA.h"
|
||||
#include "gui/gui.hh"
|
||||
#include "gui/virtual_keyboard.hh"
|
||||
|
||||
#include <SDL.h>
|
||||
#if defined(GEKKO)
|
||||
@ -626,7 +628,7 @@ void C64Display::TranslateKey(SDLKey key, bool key_up, uint8 *key_matrix,
|
||||
shift_on = false;
|
||||
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 ||
|
||||
c == '\n')
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "Prefs.h"
|
||||
#include "main.h"
|
||||
#include "C64.h"
|
||||
#include "menu.h"
|
||||
|
||||
#if defined(GEKKO)
|
||||
# include <wiiuse/wpad.h>
|
||||
@ -1088,7 +1087,7 @@ network_connection_error_t Network::WaitForPeerList()
|
||||
return VERSION_ERROR;
|
||||
}
|
||||
#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??? */
|
||||
if (sel < 0)
|
||||
|
@ -21,6 +21,10 @@
|
||||
#ifndef _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_BUTTONS 32
|
||||
#define MAX_JOYSTICK_HATS 8
|
||||
@ -165,9 +169,13 @@ private:
|
||||
uint32 MsPerFrame;
|
||||
#endif
|
||||
int JoystickAxes[MAX_JOYSTICK_AXES];
|
||||
int JoystickHats[MAX_JOYSTICK_AXES];
|
||||
int JoystickButtons[MAX_JOYSTICK_BUTTONS];
|
||||
|
||||
char NetworkName[32];
|
||||
char NetworkServer[64];
|
||||
int NetworkPort;
|
||||
|
||||
int NetworkKey;
|
||||
uint32 NetworkAvatar;
|
||||
};
|
||||
|
44
Src/gui/Makefile
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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);
|
||||
}
|
BIN
Src/gui/themes/default/background.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
Src/gui/themes/default/bg_left.png
Normal file
After Width: | Height: | Size: 289 B |
BIN
Src/gui/themes/default/bg_middle.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
Src/gui/themes/default/bg_right.png
Normal file
After Width: | Height: | Size: 321 B |
BIN
Src/gui/themes/default/bg_submenu_left.png
Normal file
After Width: | Height: | Size: 312 B |
BIN
Src/gui/themes/default/bg_submenu_middle.png
Normal file
After Width: | Height: | Size: 207 B |
BIN
Src/gui/themes/default/bg_submenu_right.png
Normal file
After Width: | Height: | Size: 341 B |
BIN
Src/gui/themes/default/dialogue_box.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Src/gui/themes/default/disc_info.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
Src/gui/themes/default/font.ttf
Normal file
BIN
Src/gui/themes/default/highlighted_key.png
Normal file
After Width: | Height: | Size: 413 B |
BIN
Src/gui/themes/default/infobox.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
Src/gui/themes/default/main_menu_bg.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
Src/gui/themes/default/selected_key.png
Normal file
After Width: | Height: | Size: 331 B |
BIN
Src/gui/themes/default/status_bar.png
Normal file
After Width: | Height: | Size: 473 B |
BIN
Src/gui/themes/default/textbox.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
68
Src/gui/timer.cpp
Normal 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
@ -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
@ -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
@ -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__ */
|
440
Src/gui/virtual_keyboard.cpp
Normal 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
@ -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
@ -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
@ -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
|
@ -11,8 +11,6 @@
|
||||
#include <wiiuse/wpad.h>
|
||||
#include <network.h>
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
extern int init_graphics(void);
|
||||
|
||||
/*
|
||||
|
@ -31,10 +31,10 @@ extern "C" int main(int argc, char *argv[]);
|
||||
#endif
|
||||
#if defined(HAVE_SDL)
|
||||
#include <SDL.h>
|
||||
#include <SDL_ttf.h>
|
||||
#include "gui/gui.hh"
|
||||
#endif
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
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() );
|
||||
return 1;
|
||||
}
|
||||
menu_init();
|
||||
Gui::gui = new Gui();
|
||||
Gui::gui->setTheme("default");
|
||||
#endif
|
||||
if (!init_graphics())
|
||||
return 1;
|
||||
|