Add saving/loading configuration
LaiNES now can save and load configuration. At the moment, it's the size of the window, and the key bindings. Instead of cluttering the gui, I broke the config out to its own file. Also added "home config directory" support, which is the standard for *nix I suppose.
This commit is contained in:
parent
db56e638d2
commit
48f85a4323
|
@ -9,7 +9,7 @@ env = Environment(ENV = environ,
|
|||
CPPFLAGS = ['-Wno-unused-value'],
|
||||
CXXFLAGS = flags,
|
||||
LINKFLAGS = flags,
|
||||
CPPPATH = ['#lib/include', '#src/include'],
|
||||
CPPPATH = ['#simpleini', '#lib/include', '#src/include'],
|
||||
LIBS = ['SDL2', 'SDL2_image', 'SDL2_ttf'])
|
||||
|
||||
env.Program('laines', Glob('build/*/*.cpp') + Glob('build/*/*/*.cpp'))
|
||||
|
|
155
src/config.cpp
Normal file
155
src/config.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include <cstdlib>
|
||||
#include <SimpleIni.h>
|
||||
#include "config.hpp"
|
||||
#include "gui.hpp"
|
||||
|
||||
namespace GUI {
|
||||
|
||||
/* Settings */
|
||||
CSimpleIniA ini(true, false, false);
|
||||
|
||||
/* Window settings */
|
||||
int last_window_size = 1;
|
||||
|
||||
/* Controls settings */
|
||||
SDL_Scancode KEY_A [] = { SDL_SCANCODE_A, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_B [] = { SDL_SCANCODE_S, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_SELECT[] = { SDL_SCANCODE_SPACE, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_START [] = { SDL_SCANCODE_RETURN, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_UP [] = { SDL_SCANCODE_UP, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_DOWN [] = { SDL_SCANCODE_DOWN, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_LEFT [] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_RIGHT [] = { SDL_SCANCODE_RIGHT, SDL_SCANCODE_ESCAPE };
|
||||
int BTN_UP [] = { -1, -1 };
|
||||
int BTN_DOWN [] = { -1, -1 };
|
||||
int BTN_LEFT [] = { -1, -1 };
|
||||
int BTN_RIGHT [] = { -1, -1 };
|
||||
int BTN_A [] = { -1, -1 };
|
||||
int BTN_B [] = { -1, -1 };
|
||||
int BTN_SELECT[] = { -1, -1 };
|
||||
int BTN_START [] = { -1, -1 };
|
||||
bool useJoystick[] = { false, false };
|
||||
|
||||
|
||||
|
||||
/* Ensure config directory exists */
|
||||
const char* get_config_path(char * buf, int buflen)
|
||||
{
|
||||
/* Bail on the complex stuff if we don't need it */
|
||||
if (!USE_CONFIG_DIR)
|
||||
{
|
||||
return CONFIG_FALLBACK;
|
||||
}
|
||||
|
||||
/* First, get the home directory */
|
||||
char homepath[CONFIG_PATH_MAX];
|
||||
char path[CONFIG_PATH_MAX];
|
||||
char * home = getenv("HOME");
|
||||
if (home == NULL)
|
||||
return CONFIG_FALLBACK;
|
||||
|
||||
snprintf(homepath, sizeof(homepath), "%s/.config", home);
|
||||
|
||||
/* Then, .config as a folder */
|
||||
int res = mkdir(homepath, CONFIG_DIR_DEFAULT_MODE);
|
||||
int err = errno;
|
||||
|
||||
if (res == -1 && err != EEXIST)
|
||||
return CONFIG_FALLBACK;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", homepath, CONFIG_DIR_NAME);
|
||||
|
||||
/* Finally, CONFIG_DIR_NAME as a sub-folder */
|
||||
res = mkdir(path, CONFIG_DIR_DEFAULT_MODE);
|
||||
err = errno;
|
||||
|
||||
if (res == -1 && err != EEXIST)
|
||||
return CONFIG_FALLBACK;
|
||||
|
||||
snprintf(buf, buflen, "%s/settings", path);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* Load settings */
|
||||
void load_settings()
|
||||
{
|
||||
/* Files */
|
||||
char path[CONFIG_PATH_MAX];
|
||||
ini.LoadFile(get_config_path(path, sizeof(path)));
|
||||
|
||||
/* Screen settings */
|
||||
int screen_size = atoi(ini.GetValue("screen", "size", "1"));
|
||||
if (screen_size < 1 || screen_size > 4)
|
||||
screen_size = 1;
|
||||
|
||||
set_size(screen_size);
|
||||
|
||||
/* Control settings */
|
||||
for (int p = 0; p < 1; p++)
|
||||
{
|
||||
const char* section = p==0?"controls p1":"controls p2";
|
||||
|
||||
useJoystick[p] = (ini.GetValue(section, "usejoy", "no"))[0] == 'y';
|
||||
if (useJoystick[p])
|
||||
{
|
||||
BTN_UP[p] = atoi(ini.GetValue(section, "UP", "-1"));
|
||||
BTN_DOWN[p] = atoi(ini.GetValue(section, "DOWN", "-1"));
|
||||
BTN_LEFT[p] = atoi(ini.GetValue(section, "LEFT", "-1"));
|
||||
BTN_RIGHT[p] = atoi(ini.GetValue(section, "RIGHT", "-1"));
|
||||
BTN_A[p] = atoi(ini.GetValue(section, "A", "-1"));
|
||||
BTN_B[p] = atoi(ini.GetValue(section, "B", "-1"));
|
||||
BTN_SELECT[p] = atoi(ini.GetValue(section, "SELECT", "-1"));
|
||||
BTN_START[p] = atoi(ini.GetValue(section, "START", "-1"));
|
||||
} else {
|
||||
KEY_UP[p] = (SDL_Scancode)atoi(ini.GetValue(section, "UP", "82"));
|
||||
KEY_DOWN[p] = (SDL_Scancode)atoi(ini.GetValue(section, "DOWN", "81"));
|
||||
KEY_LEFT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "LEFT", "80"));
|
||||
KEY_RIGHT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "RIGHT", "79"));
|
||||
KEY_A[p] = (SDL_Scancode)atoi(ini.GetValue(section, "A", "4"));
|
||||
KEY_B[p] = (SDL_Scancode)atoi(ini.GetValue(section, "B", "22"));
|
||||
KEY_SELECT[p] = (SDL_Scancode)atoi(ini.GetValue(section, "SELECT", "44"));
|
||||
KEY_START[p] = (SDL_Scancode)atoi(ini.GetValue(section, "START", "40"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Save settings */
|
||||
void save_settings()
|
||||
{
|
||||
/* Screen settings */
|
||||
char buf[2] = {0};
|
||||
sprintf(buf, "%d", last_window_size);
|
||||
ini.SetValue("screen", "size", buf);
|
||||
|
||||
/* Control settings */
|
||||
for (int p = 0; p < 1; p++)
|
||||
{
|
||||
const char* section = p==0?"controls p1":"controls p2";
|
||||
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_UP[p]:KEY_UP[p]);
|
||||
ini.SetValue("section", "UP", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_DOWN[p]:KEY_DOWN[p]);
|
||||
ini.SetValue("section", "DOWN", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_LEFT[p]:KEY_LEFT[p]);
|
||||
ini.SetValue("section", "LEFT", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_RIGHT[p]:KEY_RIGHT[p]);
|
||||
ini.SetValue("section", "RIGHT", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_A[p]:KEY_A[p]);
|
||||
ini.SetValue("section", "A", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_B[p]:KEY_B[p]);
|
||||
ini.SetValue("section", "B", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_SELECT[p]:KEY_SELECT[p]);
|
||||
ini.SetValue("section", "SELECT", buf);
|
||||
sprintf(buf, "%d", useJoystick[p]?BTN_START[p]:KEY_START[p]);
|
||||
ini.SetValue("section", "START", buf);
|
||||
ini.SetValue("section", "usejoy", useJoystick[p]?"yes":"no");
|
||||
}
|
||||
|
||||
char path[CONFIG_PATH_MAX];
|
||||
ini.SaveFile(get_config_path(path, sizeof(path)));
|
||||
}
|
||||
|
||||
}
|
26
src/gui.cpp
26
src/gui.cpp
|
@ -7,10 +7,10 @@
|
|||
#include "cpu.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "config.hpp"
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
||||
// Screen size:
|
||||
const unsigned WIDTH = 256;
|
||||
const unsigned HEIGHT = 240;
|
||||
|
@ -36,28 +36,10 @@ FileMenu* fileMenu;
|
|||
|
||||
bool pause = true;
|
||||
|
||||
// Controls settings:
|
||||
SDL_Scancode KEY_A [] = { SDL_SCANCODE_A, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_B [] = { SDL_SCANCODE_S, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_SELECT[] = { SDL_SCANCODE_SPACE, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_START [] = { SDL_SCANCODE_RETURN, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_UP [] = { SDL_SCANCODE_UP, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_DOWN [] = { SDL_SCANCODE_DOWN, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_LEFT [] = { SDL_SCANCODE_LEFT, SDL_SCANCODE_ESCAPE };
|
||||
SDL_Scancode KEY_RIGHT [] = { SDL_SCANCODE_RIGHT, SDL_SCANCODE_ESCAPE };
|
||||
int BTN_UP [] = { -1, -1 };
|
||||
int BTN_DOWN [] = { -1, -1 };
|
||||
int BTN_LEFT [] = { -1, -1 };
|
||||
int BTN_RIGHT [] = { -1, -1 };
|
||||
int BTN_A [] = { -1, -1 };
|
||||
int BTN_B [] = { -1, -1 };
|
||||
int BTN_SELECT[] = { -1, -1 };
|
||||
int BTN_START [] = { -1, -1 };
|
||||
bool useJoystick[] = { false, false };
|
||||
|
||||
/* Set the window size multiplier */
|
||||
void set_size(int mul)
|
||||
{
|
||||
last_window_size = mul;
|
||||
SDL_SetWindowSize(window, WIDTH * mul, HEIGHT * mul);
|
||||
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
|
||||
}
|
||||
|
@ -80,7 +62,7 @@ void init()
|
|||
// Initialize graphics structures:
|
||||
window = SDL_CreateWindow ("LaiNES",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
WIDTH, HEIGHT, 0);
|
||||
WIDTH * last_window_size, HEIGHT * last_window_size, 0);
|
||||
|
||||
renderer = SDL_CreateRenderer(window, -1,
|
||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
|
@ -110,12 +92,14 @@ void init()
|
|||
settingsMenu->add(new Entry("Video", []{ menu = videoMenu; }));
|
||||
settingsMenu->add(new Entry("Controller 1", []{ menu = useJoystick[0] ? joystickMenu[0] : keyboardMenu[0]; }));
|
||||
settingsMenu->add(new Entry("Controller 2", []{ menu = useJoystick[1] ? joystickMenu[1] : keyboardMenu[1]; }));
|
||||
settingsMenu->add(new Entry("Save Settings", []{ save_settings(); menu = mainMenu; }));
|
||||
|
||||
videoMenu = new Menu;
|
||||
videoMenu->add(new Entry("<", []{ menu = settingsMenu; }));
|
||||
videoMenu->add(new Entry("Size 1x", []{ set_size(1); }));
|
||||
videoMenu->add(new Entry("Size 2x", []{ set_size(2); }));
|
||||
videoMenu->add(new Entry("Size 3x", []{ set_size(3); }));
|
||||
videoMenu->add(new Entry("Size 4x", []{ set_size(4); }));
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
|
|
39
src/include/config.hpp
Normal file
39
src/include/config.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include <cerrno>
|
||||
#include <sys/stat.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#define CONFIG_DIR_DEFAULT_MODE S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH
|
||||
#define USE_CONFIG_DIR true
|
||||
#define CONFIG_DIR_NAME "LaiNES"
|
||||
#define CONFIG_FALLBACK ".laines-settings"
|
||||
/* PATH_MAX is a portability nightmare. */
|
||||
#define CONFIG_PATH_MAX 1024
|
||||
|
||||
namespace GUI {
|
||||
|
||||
/* Loading and saving */
|
||||
void load_settings();
|
||||
void save_settings();
|
||||
const char* get_config_path(char * buf, int buflen);
|
||||
|
||||
extern int last_window_size;
|
||||
extern SDL_Scancode KEY_A [];
|
||||
extern SDL_Scancode KEY_B [];
|
||||
extern SDL_Scancode KEY_SELECT[];
|
||||
extern SDL_Scancode KEY_START [];
|
||||
extern SDL_Scancode KEY_UP [];
|
||||
extern SDL_Scancode KEY_DOWN [];
|
||||
extern SDL_Scancode KEY_LEFT [];
|
||||
extern SDL_Scancode KEY_RIGHT [];
|
||||
extern int BTN_UP [];
|
||||
extern int BTN_DOWN [];
|
||||
extern int BTN_LEFT [];
|
||||
extern int BTN_RIGHT [];
|
||||
extern int BTN_A [];
|
||||
extern int BTN_B [];
|
||||
extern int BTN_SELECT[];
|
||||
extern int BTN_START [];
|
||||
extern bool useJoystick[];
|
||||
|
||||
}
|
|
@ -23,6 +23,6 @@ void render_texture(SDL_Texture* texture, int x, int y);
|
|||
u8 get_joypad_state(int n);
|
||||
void new_frame(u32* pixels);
|
||||
void new_samples(const blip_sample_t* samples, size_t count);
|
||||
|
||||
void set_size(int mul);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#include "gui.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
GUI::load_settings();
|
||||
GUI::init();
|
||||
GUI::run();
|
||||
|
||||
|
|
Reference in a new issue