diff --git a/include/core/project.hpp b/include/core/project.hpp index 65d58904..de3eb410 100644 --- a/include/core/project.hpp +++ b/include/core/project.hpp @@ -13,6 +13,7 @@ class memwatch_set; class controller_state; class button_mapping; class emulator_dispatch; +class input_queue; namespace command { class group; @@ -169,7 +170,7 @@ class project_state public: project_state(voice_commentary& _commentary, memwatch_set& _mwatch, command::group& _command, controller_state& _controls, settingvar::cache& _setcache, button_mapping& _buttons, - emulator_dispatch& _edispatch); + emulator_dispatch& _edispatch, input_queue& _iqueue); ~project_state(); /** * Get currently active project. @@ -223,6 +224,49 @@ 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& namemap, + std::map>& childmap); +/** + * Arrange current project to be flushed later. + * + * Notes: Safe to call from another thread. + */ + void F_call_flush(std::function 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 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 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 onerror); +/** + * Arrage branch to be deleted. + * + * Notes: Safe to call from another thread. + */ + void F_delete_branch(uint64_t id, std::function onerror); +/** + * Arrage branch to be switched. + * + * Notes: Safe to call from another thread. + */ + void F_switch_branch(uint64_t id, std::function onerror); private: project_info* active_project; voice_commentary& commentary; @@ -232,6 +276,7 @@ private: settingvar::cache& setcache; button_mapping& buttons; emulator_dispatch& edispatch; + input_queue& iqueue; }; #endif diff --git a/include/platform/wxwidgets/platform.hpp b/include/platform/wxwidgets/platform.hpp index fe2c1de9..e2ae731b 100644 --- a/include/platform/wxwidgets/platform.hpp +++ b/include/platform/wxwidgets/platform.hpp @@ -107,6 +107,7 @@ void show_message_ok(wxWindow* parent, const std::string& title, const std::stri bool run_show_error(wxWindow* parent, const std::string& title, const std::string& text, std::function fn); void show_exception(wxWindow* parent, const std::string& title, const std::string& text, std::exception& e); +void show_exception_any(wxWindow* parent, const std::string& title, const std::string& text, std::exception& e); //Some important windows (if open). extern wxwin_messages* msg_window; diff --git a/src/core/instance.cpp b/src/core/instance.cpp index b8e01253..1de8943b 100644 --- a/src/core/instance.cpp +++ b/src/core/instance.cpp @@ -68,6 +68,8 @@ emulator_instance::emulator_instance() D.prealloc(buttons); D.init(dispatch); + D.init(command); + D.init(iqueue, *command); D.init(mlogic); D.init(memory); D.init(lua); @@ -79,7 +81,6 @@ emulator_instance::emulator_instance() D.init(mbranch, *mlogic, *dispatch); D.init(controls, *project, *mlogic, *buttons, *dispatch); D.init(keyboard); - D.init(command); D.init(mapper, *keyboard, *command); D.init(fbuf, *subtitles, *settings, *mwatch, *keyboard, *dispatch); D.init(buttons, *controls, *mapper, *keyboard, *fbuf, *dispatch); @@ -91,10 +92,9 @@ emulator_instance::emulator_instance() D.init(abindmanager, *mapper, *command); D.init(nrrdata); D.init(cmapper, *memory, *mlogic); - D.init(project, *commentary, *mwatch, *command, *controls, *setcache, *buttons, *dispatch); + D.init(project, *commentary, *mwatch, *command, *controls, *setcache, *buttons, *dispatch, *iqueue); D.init(dbg, *dispatch); D.init(framerate); - D.init(iqueue, *command); D.init(mdumper); status_A->valid = false; diff --git a/src/core/project.cpp b/src/core/project.cpp index c490a7dc..63fd2f52 100644 --- a/src/core/project.cpp +++ b/src/core/project.cpp @@ -9,6 +9,7 @@ #include "core/moviedata.hpp" #include "core/moviefile.hpp" #include "core/project.hpp" +#include "core/queue.hpp" #include "library/directory.hpp" #include "library/minmax.hpp" #include "library/string.hpp" @@ -24,6 +25,16 @@ void do_flush_slotinfo(); namespace { + void fill_namemap(project_info& p, uint64_t id, std::map& namemap, + std::map>& 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& data, const std::vector& app) { size_t dsize = data.size(); @@ -188,9 +199,9 @@ namespace project_state::project_state(voice_commentary& _commentary, memwatch_set& _mwatch, command::group& _command, controller_state& _controls, settingvar::cache& _setcache, button_mapping& _buttons, - emulator_dispatch& _edispatch) + emulator_dispatch& _edispatch, input_queue& _iqueue) : commentary(_commentary), mwatch(_mwatch), command(_command), controls(_controls), setcache(_setcache), - buttons(_buttons), edispatch(_edispatch) + buttons(_buttons), edispatch(_edispatch), iqueue(_iqueue) { active_project = NULL; } @@ -479,6 +490,80 @@ 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& namemap, + std::map>& 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 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 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 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 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 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 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) { @@ -530,6 +615,8 @@ void project_info::set_parent_branch(uint64_t bid, uint64_t pbid) throw std::runtime_error("Invalid branch ID"); if(pbid && !branches.count(pbid)) throw std::runtime_error("Invalid parent branch ID"); + if(bid == pbid) + throw std::runtime_error("Branch can't be its own parent"); for(auto& i : branches) { uint64_t j = i.first; while(j) { diff --git a/src/platform/wxwidgets/branchesmenu.cpp b/src/platform/wxwidgets/branchesmenu.cpp index 2b6b56cc..6fa4bc9b 100644 --- a/src/platform/wxwidgets/branchesmenu.cpp +++ b/src/platform/wxwidgets/branchesmenu.cpp @@ -13,16 +13,6 @@ void update_movie_state(); namespace { - void fill_namemap(project_info& p, uint64_t id, std::map& namemap, - std::map>& 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; - } - //Tree of branches. class branches_tree : public wxTreeCtrl { @@ -68,12 +58,7 @@ namespace std::map namemap; std::map> childmap; uint64_t cur = 0; - lsnes_instance.iqueue->run([&cur, &namemap, &childmap]() { - auto p = lsnes_instance.project->get(); - if(!p) return; - fill_namemap(*p, 0, namemap, childmap); - cur = p->get_current_branch(); - }); + lsnes_instance.project->F_get_branch_map(cur, namemap, childmap); current = cur; selection cursel = get_selection(); std::set expanded; @@ -103,13 +88,6 @@ namespace return names[id]; return ""; } - void call_project_flush() - { - lsnes_instance.iqueue->run_async([] { - auto p = CORE().project->get(); - if(p) p->flush(); - }, [](std::exception& e) {}); - } private: void build_tree(uint64_t id, wxTreeItemId parent, std::map>& childmap, std::map& namemap) @@ -236,26 +214,17 @@ namespace } catch(canceled_exception& e) { return; } - lsnes_instance.iqueue->run([this, id, newname]() { - run_show_error(this, "Error creating branch", "Can't create branch", [id, newname]() { - auto p = CORE().project->get(); - if(p) p->create_branch(id, newname); - }); + lsnes_instance.project->F_create_branch(id, newname, [this](std::exception& e) { + show_exception_any(this, "Error creating branch", "Can't create branch", e); }); - branches->call_project_flush(); } void on_select(wxCommandEvent& e) { uint64_t id = get_selected_id(); if(id == 0xFFFFFFFFFFFFFFFFULL) return; - lsnes_instance.iqueue->run([this, id]() { - run_show_error(this, "Error setting branch", "Can't set branch", [id]() { - auto p = CORE().project->get(); - if(p) p->set_current_branch(id); - }); + lsnes_instance.project->F_switch_branch(id, [this](std::exception& e) { + show_exception_any(this, "Error setting branch", "Can't set branch", e); }); - branches->call_project_flush(); - update_movie_state(); } void on_rename(wxCommandEvent& e) { @@ -268,14 +237,9 @@ namespace } catch(canceled_exception& e) { return; } - lsnes_instance.iqueue->run([this, id, newname]() { - run_show_error(this, "Error renaming branch", "Can't rename branch", [id, newname]() { - auto p = CORE().project->get(); - if(p) p->set_branch_name(id, newname); - }); + lsnes_instance.project->F_rename_branch(id, newname, [this](std::exception& e) { + show_exception_any(this, "Error renaming branch", "Can't rename branch", e); }); - branches->call_project_flush(); - update_movie_state(); } void on_reparent(wxCommandEvent& e) { @@ -291,27 +255,17 @@ namespace pid = bsel->get_selection(); if(pid == 0xFFFFFFFFFFFFFFFFULL) return; bsel->Destroy(); - lsnes_instance.iqueue->run([this, id, pid]() { - run_show_error(this, "Error reparenting branch", "Can't reparent branch", - [id, pid]() { - auto p = CORE().project->get(); - if(p) p->set_parent_branch(id, pid); - }); + lsnes_instance.project->F_reparent_branch(id, pid, [this](std::exception& e) { + show_exception_any(this, "Error reparenting branch", "Can't reparent branch", e); }); - branches->call_project_flush(); - update_movie_state(); } void on_delete(wxCommandEvent& e) { uint64_t id = get_selected_id(); if(id == 0xFFFFFFFFFFFFFFFFULL) return; - lsnes_instance.iqueue->run([this, id]() { - run_show_error(this, "Error deleting branch", "Can't delete branch", [id]() { - auto p = CORE().project->get(); - if(p) p->delete_branch(id); - }); + lsnes_instance.project->F_delete_branch(id, [this](std::exception& e) { + show_exception_any(this, "Error deleting branch", "Can't delete branch", e); }); - branches->call_project_flush(); } void on_close(wxCommandEvent& e) { @@ -407,13 +361,8 @@ void branches_menu::on_select(wxCommandEvent& e) if(!branch_ids.count(id)) return; uint64_t bid = branch_ids[id]; std::string err; - lsnes_instance.iqueue->run_async([this, bid]() { - auto p = CORE().project->get(); - if(p) p->set_current_branch(bid); - if(p) p->flush(); - update_movie_state(); - }, [this](std::exception& e) { - show_exception(this->pwin, "Error changing branch", "Can't change branch", e); + lsnes_instance.project->F_switch_branch(bid, [this](std::exception& e) { + show_exception_any(this->pwin, "Error changing branch", "Can't change branch", e); }); } @@ -421,11 +370,8 @@ void branches_menu::update() { std::map namemap; std::map> childmap; - lsnes_instance.iqueue->run([&namemap, &childmap]() { - auto p = CORE().project->get(); - if(!p) return; - fill_namemap(*p, 0, namemap, childmap); - }); + uint64_t cur; + lsnes_instance.project->F_get_branch_map(cur, namemap, childmap); //First destroy everything that isn't a menu. for(auto i : otheritems) i.parent->Delete(i.item); diff --git a/src/platform/wxwidgets/main.cpp b/src/platform/wxwidgets/main.cpp index a33f1d9e..3ea2fbe5 100644 --- a/src/platform/wxwidgets/main.cpp +++ b/src/platform/wxwidgets/main.cpp @@ -753,3 +753,13 @@ void show_exception(wxWindow* parent, const std::string& title, const std::strin std::string _text = (text == "") ? err : (text + ": " + err); show_message_ok(parent, _title, _text, wxICON_EXCLAMATION); } + +void show_exception_any(wxWindow* parent, const std::string& title, const std::string& text, std::exception& e) +{ + std::string err = e.what(); + std::string _title = title; + std::string _text = (text == "") ? err : (text + ": " + err); + runuifun([parent, _title, _text]() { + show_message_ok(parent, _title, _text, wxICON_EXCLAMATION); + }); +}