Cleanup direct emulation thread references in editor-authors.cpp

This commit is contained in:
Ilari Liusvaara 2014-05-31 21:48:57 +03:00
parent a2f6ba2b6f
commit aa7e15aa27
6 changed files with 278 additions and 204 deletions

View file

@ -224,49 +224,6 @@ public:
* Copy macros to project.
*/
void copy_macros(project_info& p, controller_state& s);
/**
* Fill branch name map.
*
* Notes: Safe to call from another thread.
*/
void F_get_branch_map(uint64_t& cur, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap);
/**
* Arrange current project to be flushed later.
*
* Notes: Safe to call from another thread.
*/
void F_call_flush(std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be created.
*
* Notes: Safe to call from another thread.
*/
void F_create_branch(uint64_t id, const std::string& name, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be renamed.
*
* Notes: Safe to call from another thread.
*/
void F_rename_branch(uint64_t id, const std::string& name, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be reparented.
*
* Notes: Safe to call from another thread.
*/
void F_reparent_branch(uint64_t id, uint64_t pid, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be deleted.
*
* Notes: Safe to call from another thread.
*/
void F_delete_branch(uint64_t id, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be switched.
*
* Notes: Safe to call from another thread.
*/
void F_switch_branch(uint64_t id, std::function<void(std::exception&)> onerror);
private:
project_info* active_project;
voice_commentary& commentary;

View file

@ -0,0 +1,81 @@
#ifndef _ui_services__hpp__included__
#define _ui_services__hpp__included__
#include <map>
#include <set>
#include <functional>
#include <list>
#include <string>
/*********************************************************************************************************************
UI services.
- All functions here are safe to call from another thread.
- If function takes onerror parameter, that function is asynchronous.
- The onerror handler is called from arbitrary thread.
*********************************************************************************************************************/
class emulator_instance;
struct project_author_info
{
//True if this is a project, false if not. Ignored when saving.
bool is_project;
//Lua scripts. Ignored when saving if not in project context.
std::list<std::string> luascripts;
//Autorun new lua scripts. Ignored when saving if not in project context, always loaded as false.
bool autorunlua;
//Authors. First of each pair is full name, second is nickname.
std::list<std::pair<std::string, std::string>> authors;
//Name of the game.
std::string gamename;
//Project Directory. Ignored if not in project context.
std::string directory;
//Project name. Ignored if not in project context.
std::string projectname;
//Save prefix.
std::string prefix;
};
/**
* Fill branch name map.
*/
void UI_get_branch_map(emulator_instance& instance, uint64_t& cur, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap);
/**
* Arrange current project to be flushed.
*/
void UI_call_flush(emulator_instance& instance, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be created.
*/
void UI_create_branch(emulator_instance& instance, uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be renamed.
*/
void UI_rename_branch(emulator_instance& instance, uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be reparented.
*/
void UI_reparent_branch(emulator_instance& instance, uint64_t id, uint64_t pid,
std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be deleted.
*/
void UI_delete_branch(emulator_instance& instance, uint64_t id, std::function<void(std::exception&)> onerror);
/**
* Arrage branch to be switched.
*/
void UI_switch_branch(emulator_instance& instance, uint64_t id, std::function<void(std::exception&)> onerror);
/**
* Load project author info.
*/
project_author_info UI_load_author_info(emulator_instance& instance);
/**
* Save project author info.
*/
void UI_save_author_info(emulator_instance& instance, project_author_info& info);
#endif

View file

@ -25,16 +25,6 @@ void do_flush_slotinfo();
namespace
{
void fill_namemap(project_info& p, uint64_t id, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap)
{
namemap[id] = p.get_branch_name(id);
auto s = p.branch_children(id);
for(auto i : s)
fill_namemap(p, i, namemap, childmap);
childmap[id] = s;
}
void concatenate(std::vector<char>& data, const std::vector<char>& app)
{
size_t dsize = data.size();
@ -490,80 +480,6 @@ void project_state::copy_macros(project_info& p, controller_state& s)
p.macros[i] = s.get_macro(i).serialize();
}
void project_state::F_get_branch_map(uint64_t& cur, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap)
{
iqueue.run([this, &cur, &namemap, &childmap]() {
auto p = this->get();
if(!p) return;
fill_namemap(*p, 0, namemap, childmap);
cur = p->get_current_branch();
});
}
void project_state::F_call_flush(std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this]() {
auto p = this->get();
if(p) p->flush();
}, onerror);
}
void project_state::F_create_branch(uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this, id, name]() {
auto p = this->get();
if(!p) return;
p->create_branch(id, name);
p->flush();
}, onerror);
}
void project_state::F_rename_branch(uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this, id, name]() {
auto p = this->get();
if(!p) return;
p->set_branch_name(id, name);
p->flush();
update_movie_state();
}, onerror);
}
void project_state::F_reparent_branch(uint64_t id, uint64_t pid, std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this, id, pid]() {
auto p = this->get();
if(!p) return;
p->set_parent_branch(id, pid);
p->flush();
update_movie_state();
}, onerror);
}
void project_state::F_delete_branch(uint64_t id, std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this, id]() {
auto p = this->get();
if(!p) return;
p->delete_branch(id);
p->flush();
}, onerror);
}
void project_state::F_switch_branch(uint64_t id, std::function<void(std::exception&)> onerror)
{
iqueue.run_async([this, id]() {
auto p = this->get();
if(!p) return;
p->set_current_branch(id);
p->flush();
update_movie_state();
}, onerror);
}
project_info::project_info(emulator_dispatch& _dispatch)
: edispatch(_dispatch)
{

162
src/core/ui-services.cpp Normal file
View file

@ -0,0 +1,162 @@
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/instance.hpp"
#include "core/moviedata.hpp"
#include "core/project.hpp"
#include "core/queue.hpp"
#include "core/ui-services.hpp"
namespace
{
void fill_namemap(project_info& p, uint64_t id, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap)
{
namemap[id] = p.get_branch_name(id);
auto s = p.branch_children(id);
for(auto i : s)
fill_namemap(p, i, namemap, childmap);
childmap[id] = s;
}
}
void update_movie_state();
void do_flush_slotinfo();
void UI_get_branch_map(emulator_instance& inst, uint64_t& cur, std::map<uint64_t, std::string>& namemap,
std::map<uint64_t, std::set<uint64_t>>& childmap)
{
auto project = inst.project;
inst.iqueue->run([project, &cur, &namemap, &childmap]() {
auto p = project->get();
if(!p) return;
fill_namemap(*p, 0, namemap, childmap);
cur = p->get_current_branch();
});
}
void UI_call_flush(emulator_instance& inst, std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project]() {
auto p = project->get();
if(p) p->flush();
}, onerror);
}
void UI_create_branch(emulator_instance& inst, uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project, id, name]() {
auto p = project->get();
if(!p) return;
p->create_branch(id, name);
p->flush();
}, onerror);
}
void UI_rename_branch(emulator_instance& inst, uint64_t id, const std::string& name,
std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project, id, name]() {
auto p = project->get();
if(!p) return;
p->set_branch_name(id, name);
p->flush();
update_movie_state();
}, onerror);
}
void UI_reparent_branch(emulator_instance& inst, uint64_t id, uint64_t pid,
std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project, id, pid]() {
auto p = project->get();
if(!p) return;
p->set_parent_branch(id, pid);
p->flush();
update_movie_state();
}, onerror);
}
void UI_delete_branch(emulator_instance& inst, uint64_t id, std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project, id]() {
auto p = project->get();
if(!p) return;
p->delete_branch(id);
p->flush();
}, onerror);
}
void UI_switch_branch(emulator_instance& inst, uint64_t id, std::function<void(std::exception&)> onerror)
{
auto project = inst.project;
inst.iqueue->run_async([project, id]() {
auto p = project->get();
if(!p) return;
p->set_current_branch(id);
p->flush();
update_movie_state();
}, onerror);
}
project_author_info UI_load_author_info(emulator_instance& inst)
{
project_author_info x;
inst.iqueue->run([&inst, &x]() {
project_info* proj = inst.project->get();
x.is_project = (proj != NULL);
x.autorunlua = false;
if(proj) {
x.projectname = proj->name;
x.directory = proj->directory;
x.prefix = proj->prefix;
x.luascripts = proj->luascripts;
x.gamename = proj->gamename;
for(auto i : proj->authors)
x.authors.push_back(i);
} else {
x.prefix = get_mprefix_for_project();
x.gamename = inst.mlogic->get_mfile().gamename;
for(auto i : inst.mlogic->get_mfile().authors)
x.authors.push_back(i);
}
});
return x;
}
void UI_save_author_info(emulator_instance& inst, project_author_info& info)
{
inst.iqueue->run([&inst, info]() {
project_info* proj = inst.project->get();
std::set<std::string> oldscripts;
std::vector<std::pair<std::string, std::string>> _authors(info.authors.begin(), info.authors.end());
if(proj) {
for(auto i : proj->luascripts)
oldscripts.insert(i);
proj->gamename = info.gamename;
proj->authors = _authors;
proj->prefix = info.prefix;
proj->directory = info.directory;
proj->name = info.projectname;
proj->luascripts = info.luascripts;
proj->flush();
//For save status to immediately update.
do_flush_slotinfo();
update_movie_state();
inst.dispatch->title_change();
} else {
inst.mlogic->get_mfile().gamename = info.gamename;
inst.mlogic->get_mfile().authors = _authors;
set_mprefix_for_project(info.prefix);
}
if(proj && info.autorunlua)
for(auto i : info.luascripts)
if(!oldscripts.count(i))
inst.command->invoke("run-lua " + i);
});
}

View file

@ -8,6 +8,7 @@
#include "core/instance.hpp"
#include "core/project.hpp"
#include "core/moviedata.hpp"
#include "core/ui-services.hpp"
void update_movie_state();
@ -58,7 +59,7 @@ namespace
std::map<uint64_t, std::string> namemap;
std::map<uint64_t, std::set<uint64_t>> childmap;
uint64_t cur = 0;
lsnes_instance.project->F_get_branch_map(cur, namemap, childmap);
UI_get_branch_map(lsnes_instance, cur, namemap, childmap);
current = cur;
selection cursel = get_selection();
std::set<uint64_t> expanded;
@ -214,7 +215,7 @@ namespace
} catch(canceled_exception& e) {
return;
}
lsnes_instance.project->F_create_branch(id, newname, [this](std::exception& e) {
UI_create_branch(lsnes_instance, id, newname, [this](std::exception& e) {
show_exception_any(this, "Error creating branch", "Can't create branch", e);
});
}
@ -222,7 +223,7 @@ namespace
{
uint64_t id = get_selected_id();
if(id == 0xFFFFFFFFFFFFFFFFULL) return;
lsnes_instance.project->F_switch_branch(id, [this](std::exception& e) {
UI_switch_branch(lsnes_instance, id, [this](std::exception& e) {
show_exception_any(this, "Error setting branch", "Can't set branch", e);
});
}
@ -237,7 +238,7 @@ namespace
} catch(canceled_exception& e) {
return;
}
lsnes_instance.project->F_rename_branch(id, newname, [this](std::exception& e) {
UI_rename_branch(lsnes_instance, id, newname, [this](std::exception& e) {
show_exception_any(this, "Error renaming branch", "Can't rename branch", e);
});
}
@ -255,7 +256,7 @@ namespace
pid = bsel->get_selection();
if(pid == 0xFFFFFFFFFFFFFFFFULL) return;
bsel->Destroy();
lsnes_instance.project->F_reparent_branch(id, pid, [this](std::exception& e) {
UI_reparent_branch(lsnes_instance, id, pid, [this](std::exception& e) {
show_exception_any(this, "Error reparenting branch", "Can't reparent branch", e);
});
}
@ -263,7 +264,7 @@ namespace
{
uint64_t id = get_selected_id();
if(id == 0xFFFFFFFFFFFFFFFFULL) return;
lsnes_instance.project->F_delete_branch(id, [this](std::exception& e) {
UI_delete_branch(lsnes_instance, id, [this](std::exception& e) {
show_exception_any(this, "Error deleting branch", "Can't delete branch", e);
});
}
@ -361,7 +362,7 @@ void branches_menu::on_select(wxCommandEvent& e)
if(!branch_ids.count(id)) return;
uint64_t bid = branch_ids[id];
std::string err;
lsnes_instance.project->F_switch_branch(bid, [this](std::exception& e) {
UI_switch_branch(lsnes_instance, bid, [this](std::exception& e) {
show_exception_any(this->pwin, "Error changing branch", "Can't change branch", e);
});
}
@ -371,7 +372,7 @@ void branches_menu::update()
std::map<uint64_t, std::string> namemap;
std::map<uint64_t, std::set<uint64_t>> childmap;
uint64_t cur;
lsnes_instance.project->F_get_branch_map(cur, namemap, childmap);
UI_get_branch_map(lsnes_instance, cur, namemap, childmap);
//First destroy everything that isn't a menu.
for(auto i : otheritems)
i.parent->Delete(i.item);

View file

@ -1,9 +1,6 @@
#include "core/command.hpp"
#include "core/dispatch.hpp"
#include "core/instance.hpp"
#include "core/mainloop.hpp"
#include "core/moviedata.hpp"
#include "core/project.hpp"
#include "core/ui-services.hpp"
#include "library/zip.hpp"
#include "platform/wxwidgets/platform.hpp"
@ -32,7 +29,7 @@ public:
void on_luasel(wxCommandEvent& e);
private:
void reorder_scripts(int delta);
wxTextCtrl* projectname;
wxTextCtrl* gamename;
wxTextCtrl* pname;
wxTextCtrl* directory;
wxTextCtrl* authors;
@ -51,21 +48,21 @@ private:
wxeditor_authors::wxeditor_authors(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("lsnes: Edit game name & authors"), wxDefaultPosition, wxSize(-1, -1))
{
project_info* proj = lsnes_instance.project->get();
project_author_info ainfo = UI_load_author_info(lsnes_instance);
Centre();
wxFlexGridSizer* top_s = new wxFlexGridSizer(proj ? 12 : 5, 1, 0, 0);
wxFlexGridSizer* top_s = new wxFlexGridSizer(ainfo.is_project ? 12 : 5, 1, 0, 0);
SetSizer(top_s);
if(proj) {
if(ainfo.is_project) {
wxFlexGridSizer* c4_s = new wxFlexGridSizer(1, 2, 0, 0);
c4_s->Add(new wxStaticText(this, wxID_ANY, wxT("Project:")), 0, wxGROW);
c4_s->Add(pname = new wxTextCtrl(this, wxID_ANY, towxstring(proj->name),
c4_s->Add(pname = new wxTextCtrl(this, wxID_ANY, towxstring(ainfo.projectname),
wxDefaultPosition, wxSize(400, -1)), 1, wxGROW);
top_s->Add(c4_s);
wxFlexGridSizer* c2_s = new wxFlexGridSizer(1, 3, 0, 0);
c2_s->Add(new wxStaticText(this, wxID_ANY, wxT("Directory:")), 0, wxGROW);
c2_s->Add(directory = new wxTextCtrl(this, wxID_ANY, towxstring(proj->directory),
c2_s->Add(directory = new wxTextCtrl(this, wxID_ANY, towxstring(ainfo.directory),
wxDefaultPosition, wxSize(350, -1)), 1, wxGROW);
wxButton* pdir;
c2_s->Add(pdir = new wxButton(this, wxID_ANY, wxT("...")), 1, wxGROW);
@ -75,24 +72,23 @@ wxeditor_authors::wxeditor_authors(wxWindow* parent)
wxFlexGridSizer* c3_s = new wxFlexGridSizer(1, 2, 0, 0);
c3_s->Add(new wxStaticText(this, wxID_ANY, wxT("Prefix:")), 0, wxGROW);
c3_s->Add(projectpfx = new wxTextCtrl(this, wxID_ANY, towxstring(proj->prefix),
c3_s->Add(projectpfx = new wxTextCtrl(this, wxID_ANY, towxstring(ainfo.prefix),
wxDefaultPosition, wxSize(300, -1)), 1, wxGROW);
top_s->Add(c3_s);
} else {
directory = NULL;
pname = NULL;
wxFlexGridSizer* c2_s = new wxFlexGridSizer(1, 2, 0, 0);
c2_s->Add(new wxStaticText(this, wxID_ANY, wxT("Save slot prefix:")), 0, wxGROW);
c2_s->Add(projectpfx = new wxTextCtrl(this, wxID_ANY, towxstring(get_mprefix_for_project()),
c2_s->Add(projectpfx = new wxTextCtrl(this, wxID_ANY, towxstring(ainfo.prefix),
wxDefaultPosition, wxSize(300, -1)), 1, wxGROW);
top_s->Add(c2_s);
}
wxFlexGridSizer* c_s = new wxFlexGridSizer(1, 2, 0, 0);
c_s->Add(new wxStaticText(this, wxID_ANY, wxT("Game name:")), 0, wxGROW);
c_s->Add(projectname = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)), 1,
wxGROW);
c_s->Add(gamename = new wxTextCtrl(this, wxID_ANY, towxstring(ainfo.gamename), wxDefaultPosition,
wxSize(400, -1)), 1, wxGROW);
top_s->Add(c_s);
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Authors (one per line):")), 0, wxGROW);
@ -101,7 +97,7 @@ wxeditor_authors::wxeditor_authors(wxWindow* parent)
authors->Connect(wxEVT_COMMAND_TEXT_UPDATED,
wxCommandEventHandler(wxeditor_authors::on_authors_change), NULL, this);
if(proj) {
if(ainfo.is_project) {
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Autoload lua scripts:")), 0, wxGROW);
top_s->Add(luascripts = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(400, 100)), 1,
wxEXPAND);
@ -150,25 +146,11 @@ wxeditor_authors::wxeditor_authors(wxWindow* parent)
top_s->SetSizeHints(this);
Fit();
std::list<std::string> luascriptlist;
std::string gamename;
std::string x;
lsnes_instance.iqueue->run([&gamename, &x, &luascriptlist, proj]() {
if(proj) {
luascriptlist = proj->luascripts;
gamename = proj->gamename;
for(auto i : proj->authors)
x = x + i.first + "|" + i.second + "\n";
} else {
gamename = lsnes_instance.mlogic->get_mfile().gamename;
for(auto i : lsnes_instance.mlogic->get_mfile().authors)
x = x + i.first + "|" + i.second + "\n";
}
});
for(auto i : luascriptlist)
for(auto i : ainfo.authors)
x = x + i.first + "|" + i.second + "\n";
for(auto i : ainfo.luascripts)
luascripts->Append(towxstring(i));
projectname->SetValue(towxstring(gamename));
authors->SetValue(towxstring(x));
}
@ -199,50 +181,25 @@ void wxeditor_authors::on_cancel(wxCommandEvent& e)
void wxeditor_authors::on_ok(wxCommandEvent& e)
{
project_info* proj = lsnes_instance.project->get();
std::string gamename = tostdstring(projectname->GetValue());
std::string pfx = tostdstring(projectpfx->GetValue());
std::string dir = directory ? tostdstring(directory->GetValue()) : std::string("");
std::string prjname = pname ? tostdstring(pname->GetValue()) : std::string("");
std::vector<std::pair<std::string, std::string>> newauthors;
std::list<std::string> luascriptlist;
project_author_info ainfo;
ainfo.gamename = tostdstring(gamename->GetValue());
ainfo.prefix = tostdstring(projectpfx->GetValue());
ainfo.directory = directory ? tostdstring(directory->GetValue()) : std::string("");
ainfo.projectname = pname ? tostdstring(pname->GetValue()) : std::string("");
size_t lines = authors->GetNumberOfLines();
for(size_t i = 0; i < lines; i++) {
std::string l = tostdstring(authors->GetLineText(i));
if(l != "" && l != "|")
newauthors.push_back(split_author(l));
ainfo.authors.push_back(split_author(l));
}
if(luascripts)
for(unsigned i = 0; i < luascripts->GetCount(); i++)
luascriptlist.push_back(tostdstring(luascripts->GetString(i)));
bool run_new = autorunlua ? autorunlua->GetValue() : false;
ainfo.luascripts.push_back(tostdstring(luascripts->GetString(i)));
ainfo.autorunlua = autorunlua ? autorunlua->GetValue() : false;
lsnes_instance.iqueue->run([gamename, newauthors, pfx, dir, prjname, luascriptlist, run_new, proj]() {
std::set<std::string> oldscripts;
if(proj) {
for(auto i : proj->luascripts)
oldscripts.insert(i);
proj->gamename = gamename;
proj->authors = newauthors;
proj->prefix = pfx;
proj->directory = dir;
proj->name = prjname;
proj->luascripts = luascriptlist;
proj->flush();
//For save status to immediately update.
do_flush_slotinfo();
update_movie_state();
CORE().dispatch->title_change();
} else {
lsnes_instance.mlogic->get_mfile().gamename = gamename;
lsnes_instance.mlogic->get_mfile().authors = newauthors;
set_mprefix_for_project(pfx);
}
if(run_new)
for(auto i : luascriptlist)
if(!oldscripts.count(i))
lsnes_instance.command->invoke("run-lua " + i);
});
UI_save_author_info(lsnes_instance, ainfo);
EndModal(wxID_OK);
}