Revert "state: Turns the current state save feature to a menu [Nathan Woods]"

This breaks saving a state from a joystick button, e.g. the
joy%i-%i.sta states, which are rather useful when you don't have a
keyboard handy.
This commit is contained in:
Olivier Galibert 2017-06-01 18:41:21 +02:00
parent 472be8055f
commit cb29a590d0
5 changed files with 116 additions and 428 deletions

View File

@ -159,8 +159,6 @@ files {
MAME_DIR .. "src/frontend/mame/ui/sndmenu.cpp",
MAME_DIR .. "src/frontend/mame/ui/sndmenu.h",
MAME_DIR .. "src/frontend/mame/ui/starimg.ipp",
MAME_DIR .. "src/frontend/mame/ui/state.cpp",
MAME_DIR .. "src/frontend/mame/ui/state.h",
MAME_DIR .. "src/frontend/mame/ui/toolbar.ipp",
MAME_DIR .. "src/frontend/mame/ui/utils.cpp",
MAME_DIR .. "src/frontend/mame/ui/utils.h",

View File

@ -1,330 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nathan Woods
/***************************************************************************
ui/state.cpp
Menus for saving and loading state
***************************************************************************/
#include "emu.h"
#include "machine.h"
#include "emuopts.h"
#include "ui/state.h"
/***************************************************************************
ANONYMOUS NAMESPACE
***************************************************************************/
namespace {
//-------------------------------------------------
// is_valid_state_char - is the specified character
// a valid state filename character?
//-------------------------------------------------
bool is_valid_state_char(char32_t ch)
{
return uchar_is_printable(ch) && osd_is_valid_filename_char(ch);
}
//-------------------------------------------------
// get_entry_char
//-------------------------------------------------
char32_t get_entry_char(const osd::directory::entry &entry)
{
char32_t result = 0;
// first, is this a file that ends with *.sta?
if (entry.type == osd::directory::entry::entry_type::FILE
&& core_filename_ends_with(entry.name, ".sta"))
{
std::string basename = core_filename_extract_base(entry.name);
char32_t ch;
if (uchar_from_utf8(&ch, basename.c_str(), basename.length() == basename.length()) && is_valid_state_char(ch))
result = ch;
}
return result;
}
};
namespace ui {
/***************************************************************************
FILE ENTRY
***************************************************************************/
char32_t menu_load_save_state_base::s_last_file_selected;
//-------------------------------------------------
// file_entry ctor
//-------------------------------------------------
menu_load_save_state_base::file_entry::file_entry(char32_t entry_char, const std::chrono::system_clock::time_point &last_modified)
: m_entry_char(entry_char)
, m_last_modified(last_modified)
{
}
/***************************************************************************
BASE CLASS FOR LOAD AND SAVE
***************************************************************************/
//-------------------------------------------------
// ctor
//-------------------------------------------------
menu_load_save_state_base::menu_load_save_state_base(mame_ui_manager &mui, render_container &container, const char *header, const char *footer, bool must_exist)
: menu(mui, container)
, m_header(header)
, m_footer(footer)
, m_must_exist(must_exist)
, m_was_paused(false)
{
}
//-------------------------------------------------
// dtor
//-------------------------------------------------
menu_load_save_state_base::~menu_load_save_state_base()
{
// resume if appropriate (is the destructor really the right place
// to do this sort of activity?)
if (!m_was_paused)
machine().resume();
}
//-------------------------------------------------
// populate
//-------------------------------------------------
void menu_load_save_state_base::populate(float &customtop, float &custombottom)
{
// open the state directory
std::string statedir = state_directory();
osd::directory::ptr dir = osd::directory::open(statedir);
// create a separate vector, so we can add sorted entries to the menu
std::vector<const file_entry *> m_entries_vec;
// populate all file entries
m_file_entries.clear();
if (dir)
{
const osd::directory::entry *entry;
while ((entry = dir->read()) != nullptr)
{
char32_t entry_char = get_entry_char(*entry);
if (entry_char)
{
if (core_filename_ends_with(entry->name, ".sta"))
{
file_entry fileent(entry_char, entry->last_modified);
auto iter = m_file_entries.emplace(std::make_pair(entry_char, std::move(fileent))).first;
m_entries_vec.push_back(&iter->second);
}
}
}
}
// sort the vector; put recently modified state files at the top
std::sort(
m_entries_vec.begin(),
m_entries_vec.end(),
[this](const file_entry *a, const file_entry *b)
{
return a->last_modified() > b->last_modified();
});
// add the entries
for (const file_entry *entry : m_entries_vec)
{
// get the time as a local time string
char time_string[128];
auto last_modified_time_t = std::chrono::system_clock::to_time_t(entry->last_modified());
std::strftime(time_string, sizeof(time_string), "%c", std::localtime(&last_modified_time_t));
// format the text
std::string text = util::string_format("%s: %s",
utf8_from_uchar(entry->entry_char()),
time_string);
// append the menu item
void *itemref = itemref_from_file_entry(*entry);
item_append(std::move(text), std::string(), 0, itemref);
// is this item selected?
if (entry->entry_char() == s_last_file_selected)
set_selection(itemref);
}
// set up custom render proc
customtop = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER;
custombottom = ui().get_line_height() + 3.0f * UI_BOX_TB_BORDER;
// pause if appropriate
m_was_paused = machine().paused();
if (!m_was_paused)
machine().pause();
}
//-------------------------------------------------
// handle
//-------------------------------------------------
void menu_load_save_state_base::handle()
{
// process the menu
const event *event = process(0);
// process the event
if ((event != nullptr) && (event->iptkey == IPT_UI_SELECT))
{
// user selected one of the entries
const file_entry &entry = file_entry_from_itemref(event->itemref);
slot_selected(entry.entry_char());
}
else if ((event != nullptr) && (event->iptkey == IPT_SPECIAL)
&& is_valid_state_char(event->unichar)
&& (!m_must_exist || is_present(event->unichar)))
{
// user pressed a shortcut key
slot_selected(event->unichar);
}
}
//-------------------------------------------------
// slot_selected
//-------------------------------------------------
void menu_load_save_state_base::slot_selected(char32_t entry_char)
{
// handle it
process_file(utf8_from_uchar(entry_char));
// record the last slot touched
s_last_file_selected = entry_char;
// no matter what, pop out
menu::stack_pop(machine());
}
//-------------------------------------------------
// custom_render - perform our special rendering
//-------------------------------------------------
void menu_load_save_state_base::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
{
extra_text_render(top, bottom, origx1, origy1, origx2, origy2,
m_header,
m_footer);
}
//-------------------------------------------------
// itemref_from_file_entry
//-------------------------------------------------
void *menu_load_save_state_base::itemref_from_file_entry(const menu_load_save_state_base::file_entry &entry)
{
return (void *)&entry;
}
//-------------------------------------------------
// file_entry_from_itemref
//-------------------------------------------------
const menu_load_save_state_base::file_entry &menu_load_save_state_base::file_entry_from_itemref(void *itemref)
{
return *((const file_entry *)itemref);
}
//-------------------------------------------------
// is_present
//-------------------------------------------------
std::string menu_load_save_state_base::state_directory() const
{
return util::string_format("%s%s%s",
machine().options().state_directory(),
PATH_SEPARATOR,
machine().system().name);
}
//-------------------------------------------------
// is_present
//-------------------------------------------------
bool menu_load_save_state_base::is_present(char32_t entry_char) const
{
return m_file_entries.find(entry_char) != m_file_entries.end();
}
/***************************************************************************
LOAD STATE
***************************************************************************/
//-------------------------------------------------
// ctor
//-------------------------------------------------
menu_load_state::menu_load_state(mame_ui_manager &mui, render_container &container)
: menu_load_save_state_base(mui, container, _("Load State"), _("Select position to load from"), true)
{
}
//-------------------------------------------------
// process_file
//-------------------------------------------------
void menu_load_state::process_file(std::string &&file_name)
{
machine().schedule_load(std::move(file_name));
}
/***************************************************************************
SAVE STATE
***************************************************************************/
//-------------------------------------------------
// ctor
//-------------------------------------------------
menu_save_state::menu_save_state(mame_ui_manager &mui, render_container &container)
: menu_load_save_state_base(mui, container, _("Save State"), _("Select position to save to"), false)
{
}
//-------------------------------------------------
// process_file
//-------------------------------------------------
void menu_save_state::process_file(std::string &&file_name)
{
machine().schedule_save(std::move(file_name));
}
} // namespace ui

View File

@ -1,90 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nathan Woods
/***************************************************************************
ui/state.h
Menus for saving and loading state
***************************************************************************/
#pragma once
#ifndef MAME_FRONTEND_UI_STATE_H
#define MAME_FRONTEND_UI_STATE_H
#include "ui/menu.h"
namespace ui {
// ======================> menu_load_save_state_base
class menu_load_save_state_base : public menu
{
public:
virtual ~menu_load_save_state_base() override;
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle() override;
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
protected:
menu_load_save_state_base(mame_ui_manager &mui, render_container &container, const char *header, const char *footer, bool must_exist);
virtual void process_file(std::string &&file_name) = 0;
private:
class file_entry
{
public:
file_entry() = delete;
file_entry(const file_entry &) = delete;
file_entry(file_entry &&) = default;
file_entry(char32_t entry_char, const std::chrono::system_clock::time_point &last_modified);
char32_t entry_char() const { return m_entry_char; }
const std::chrono::system_clock::time_point &last_modified() const { return m_last_modified; }
private:
char32_t m_entry_char;
std::chrono::system_clock::time_point m_last_modified;
};
static char32_t s_last_file_selected;
std::unordered_map<char32_t, file_entry> m_file_entries;
const char * m_header;
const char * m_footer;
bool m_must_exist;
bool m_was_paused;
static void *itemref_from_file_entry(const file_entry &entry);
static const file_entry &file_entry_from_itemref(void *itemref);
void slot_selected(char32_t entry_char);
std::string state_directory() const;
bool is_present(char32_t entry_char) const;
};
// ======================> menu_load_state
class menu_load_state : public menu_load_save_state_base
{
public:
menu_load_state(mame_ui_manager &mui, render_container &container);
protected:
virtual void process_file(std::string &&file_name) override;
};
// ======================> menu_save_state
class menu_save_state : public menu_load_save_state_base
{
public:
menu_save_state(mame_ui_manager &mui, render_container &container);
protected:
virtual void process_file(std::string &&file_name) override;
};
};
#endif // MAME_FRONTEND_UI_STATE_H

View File

@ -27,7 +27,6 @@
#include "ui/mainmenu.h"
#include "ui/filemngr.h"
#include "ui/sliders.h"
#include "ui/state.h"
#include "ui/viewgfx.h"
#include "imagedev/cassette.h"
@ -184,7 +183,8 @@ mame_ui_manager::mame_ui_manager(running_machine &machine)
, m_show_profiler(false)
, m_popup_text_end(0)
, m_mouse_arrow_texture(nullptr)
, m_mouse_show(false) {}
, m_mouse_show(false)
, m_load_save_hold(false) {}
mame_ui_manager::~mame_ui_manager()
{
@ -988,8 +988,10 @@ void mame_ui_manager::draw_profiler(render_container &container)
void mame_ui_manager::start_save_state()
{
show_menu();
ui::menu::stack_push<ui::menu_save_state>(*this, machine().render().ui_container());
machine().pause();
m_load_save_hold = true;
using namespace std::placeholders;
set_handler(ui_callback_type::GENERAL, std::bind(&mame_ui_manager::handler_load_save, this, _1, uint32_t(LOADSAVE_SAVE)));
}
@ -999,8 +1001,10 @@ void mame_ui_manager::start_save_state()
void mame_ui_manager::start_load_state()
{
show_menu();
ui::menu::stack_push<ui::menu_load_state>(*this, machine().render().ui_container());
machine().pause();
m_load_save_hold = true;
using namespace std::placeholders;
set_handler(ui_callback_type::GENERAL, std::bind(&mame_ui_manager::handler_load_save, this, _1, uint32_t(LOADSAVE_LOAD)));
}
@ -1265,6 +1269,111 @@ uint32_t mame_ui_manager::handler_ingame(render_container &container)
}
//-------------------------------------------------
// handler_load_save - leads the user through
// specifying a game to save or load
//-------------------------------------------------
uint32_t mame_ui_manager::handler_load_save(render_container &container, uint32_t state)
{
std::string filename;
char file = 0;
// if we're not in the middle of anything, skip
if (state == LOADSAVE_NONE)
return 0;
// okay, we're waiting for a key to select a slot; display a message
if (state == LOADSAVE_SAVE)
draw_message_window(container, _("Select position to save to"));
else
draw_message_window(container, _("Select position to load from"));
// if load/save state sequence is still being pressed, do not read the filename yet
if (m_load_save_hold) {
bool seq_in_progress = false;
const input_seq &load_save_seq = state == LOADSAVE_SAVE ?
machine().ioport().type_seq(IPT_UI_SAVE_STATE) :
machine().ioport().type_seq(IPT_UI_LOAD_STATE);
for (int i = 0; i < load_save_seq.length(); i++)
if (machine().input().code_pressed_once(load_save_seq[i]))
seq_in_progress = true;
if (seq_in_progress)
return state;
else
m_load_save_hold = false;
}
// check for cancel key
if (machine().ui_input().pressed(IPT_UI_CANCEL))
{
// display a popup indicating things were cancelled
if (state == LOADSAVE_SAVE)
machine().popmessage(_("Save cancelled"));
else
machine().popmessage(_("Load cancelled"));
// reset the state
machine().resume();
return UI_HANDLER_CANCEL;
}
// check for A-Z or 0-9
for (input_item_id id = ITEM_ID_A; id <= ITEM_ID_Z; ++id)
if (machine().input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
file = id - ITEM_ID_A + 'a';
if (file == 0)
for (input_item_id id = ITEM_ID_0; id <= ITEM_ID_9; ++id)
if (machine().input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
file = id - ITEM_ID_0 + '0';
if (file == 0)
for (input_item_id id = ITEM_ID_0_PAD; id <= ITEM_ID_9_PAD; ++id)
if (machine().input().code_pressed_once(input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
file = id - ITEM_ID_0_PAD + '0';
if (file == 0)
{
bool found = false;
for (int joy_index = 0; joy_index <= MAX_SAVED_STATE_JOYSTICK; joy_index++)
for (input_item_id id = ITEM_ID_BUTTON1; id <= ITEM_ID_BUTTON32; ++id)
if (machine().input().code_pressed_once(input_code(DEVICE_CLASS_JOYSTICK, joy_index, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, id)))
{
filename = util::string_format("joy%i-%i", joy_index, id - ITEM_ID_BUTTON1 + 1);
found = true;
break;
}
if (!found)
return state;
}
else
{
filename = util::string_format("%c", file);
}
// display a popup indicating that the save will proceed
if (state == LOADSAVE_SAVE)
{
machine().popmessage(_("Save to position %s"), filename);
machine().schedule_save(std::move(filename));
}
else
{
machine().popmessage(_("Load from position %s"), filename);
machine().schedule_load(std::move(filename));
}
// avoid handling the name of the save state slot as a seperate input
machine().ui_input().mark_all_as_pressed();
// remove the pause and reset the state
machine().resume();
return UI_HANDLER_CANCEL;
}
//-------------------------------------------------
// request_quit
//-------------------------------------------------

View File

@ -245,6 +245,7 @@ private:
std::unique_ptr<uint8_t[]> m_non_char_keys_down;
render_texture * m_mouse_arrow_texture;
bool m_mouse_show;
bool m_load_save_hold;
ui_options m_ui_options;
std::unique_ptr<ui::machine_info> m_machine_info;