Refactor emulator status reporting (and fix the statusbar doesn't update bug)
[lsnes.git] / src / platform / wxwidgets / dumpmenu.cpp
blob523d448c1f4557ef415e9703ab6a6f5abc67f410
1 #include "core/advdumper.hpp"
2 #include "core/dispatch.hpp"
3 #include "core/project.hpp"
5 #include "platform/wxwidgets/menu_dump.hpp"
6 #include "platform/wxwidgets/platform.hpp"
8 struct dumper_info
10 adv_dumper* instance;
11 std::string name;
12 bool active;
13 std::map<std::string, std::string> modes;
16 namespace
18 std::map<std::string, dumper_info> existing_dumpers;
20 struct dumper_menu_struct
22 int end_wxid;
23 wxMenuItem* end_item;
24 std::map<int, std::string> start_wxids;
25 std::map<int, wxMenuItem*> start_items;
26 wxMenuItem* sep;
28 std::map<std::string, dumper_menu_struct> menustructure;
29 std::string last_processed;
30 bool first;
32 void update_dumperinfo(std::map<std::string, dumper_info>& new_dumpers, adv_dumper* d)
34 struct dumper_info inf;
35 inf.instance = d;
36 inf.name = d->name();
37 std::set<std::string> mset = d->list_submodes();
38 for(auto i : mset)
39 inf.modes[i] = d->modename(i);
40 inf.active = d->busy();
41 new_dumpers[d->id()] = inf;
45 class dumper_menu_monitor : public information_dispatch
47 public:
48 dumper_menu_monitor(dumper_menu* dmenu)
49 : information_dispatch("wxwidgets-dumpmenu")
51 linked = dmenu;
54 ~dumper_menu_monitor() throw()
58 void on_dumper_update()
60 new_dumpers.clear();
61 std::set<adv_dumper*> dset = adv_dumper::get_dumper_set();
62 for(auto i : dset)
63 update_dumperinfo(new_dumpers, i);
64 runuifun([this]() { if(this->linked) this->linked->update(this->new_dumpers); });
66 private:
67 dumper_menu* linked;
68 std::map<std::string, dumper_info> new_dumpers;
73 dumper_menu::dumper_menu(wxWindow* win, int wxid_low, int wxid_high)
75 pwin = win;
76 win->Connect(wxid_low, wxid_high, wxEVT_COMMAND_MENU_SELECTED,
77 wxCommandEventHandler(dumper_menu::on_select), NULL, this);
78 wxid_range_low = wxid_low;
79 wxid_range_high = wxid_high;
80 monitor = new dumper_menu_monitor(this);
81 std::map<std::string, dumper_info> new_dumpers;
82 runemufn([&new_dumpers]() {
83 std::set<adv_dumper*> dset = adv_dumper::get_dumper_set();
84 for(auto i : dset)
85 update_dumperinfo(new_dumpers, i);
86 });
87 update(new_dumpers);
90 dumper_menu::~dumper_menu()
92 delete monitor;
95 void dumper_menu::on_select(wxCommandEvent& e)
97 int id = e.GetId();
98 if(id < wxid_range_low || id > wxid_range_high)
99 return;
100 for(auto i : menustructure) {
101 std::string error_str;
102 adv_dumper* t = existing_dumpers[i.first].instance;
103 if(i.second.end_wxid == id) {
104 //Execute end of dump operation.
105 runemufn([t, &error_str]() {
106 try {
107 t->end();
108 } catch(std::exception& e) {
109 error_str = e.what();
110 }});
111 if(error_str != "")
112 wxMessageBox(towxstring(error_str), _T("Error ending dump"), wxICON_EXCLAMATION | wxOK,
113 pwin);
114 return;
116 if(i.second.start_wxids.count(id)) {
117 //Execute start of dump operation.
118 std::string mode = i.second.start_wxids[id];
119 unsigned d = t->mode_details(mode);
120 std::string prefix;
121 if((d & adv_dumper::target_type_mask) == adv_dumper::target_type_file) {
122 wxFileDialog* d = new wxFileDialog(pwin, wxT("Choose file"),
123 towxstring(project_otherpath()), wxT(""), wxT("*.*"), wxFD_SAVE);
124 std::string modext = t->mode_extension(mode);
125 d->SetWildcard(towxstring(modext + " files|*." + modext));
126 auto p = project_get();
127 if(p)
128 d->SetFilename(towxstring(p->prefix + "." + modext));
129 if(d->ShowModal() == wxID_OK)
130 prefix = tostdstring(d->GetPath());
131 d->Destroy();
132 } else if((d & adv_dumper::target_type_mask) == adv_dumper::target_type_prefix) {
133 wxFileDialog* d = new wxFileDialog(pwin, wxT("Choose prefix"),
134 towxstring(project_otherpath()), wxT(""), wxT("*.*"), wxFD_SAVE);
135 auto p = project_get();
136 if(p)
137 d->SetFilename(towxstring(p->prefix));
138 if(d->ShowModal() == wxID_OK)
139 prefix = tostdstring(d->GetPath());
140 d->Destroy();
141 } else if((d & adv_dumper::target_type_mask) == adv_dumper::target_type_special) {
142 try {
143 prefix = pick_text(pwin, "Choose target", "Enter target to dump to", "");
144 } catch(...) {
145 return;
147 } else {
148 wxMessageBox(wxT("Unsupported target type"), _T("Dumper error"), wxICON_EXCLAMATION |
149 wxOK, pwin);
150 return;
152 if(prefix == "")
153 return;
154 runemufn([t, mode, prefix, &error_str]() {
155 try {
156 t->start(mode, prefix);
157 } catch(std::exception& e) {
158 error_str = e.what();
159 }});
160 if(error_str != "")
161 wxMessageBox(towxstring(error_str), _T("Error starting dump"), wxICON_EXCLAMATION |
162 wxOK, pwin);
163 return;
168 void dumper_menu::update(const std::map<std::string, dumper_info>& new_dumpers)
170 //Destroy all old entries.
171 for(auto i : menustructure) {
172 struct dumper_menu_struct& m = i.second;
173 if(m.end_item)
174 Remove(m.end_item);
175 for(auto mi : m.start_items)
176 Remove(mi.second);
177 if(m.sep)
178 Remove(m.sep);
180 //And create new ones.
181 int id = wxid_range_low;
182 first = true;
183 menustructure.clear();
184 for(auto i : new_dumpers) {
185 if(!first)
186 menustructure[last_processed].sep = AppendSeparator();
187 last_processed = i.first;
188 first = false;
189 menustructure[i.first].end_item = NULL;
190 menustructure[i.first].end_wxid = wxID_ANY;
191 if(!i.second.active) {
192 if(i.second.modes.empty()) {
193 menustructure[i.first].start_items[id] = Append(id, towxstring("Dump " +
194 i.second.name + "..."));
195 menustructure[i.first].start_wxids[id++] = "";
197 for(auto j : i.second.modes) {
198 menustructure[i.first].start_items[id] = Append(id, towxstring("Dump " +
199 i.second.name + " (" + j.second + ")..."));
200 menustructure[i.first].start_wxids[id++] = j.first;
202 } else {
203 menustructure[i.first].end_item = Append(id, towxstring("End " + i.second.name));
204 menustructure[i.first].end_wxid = id++;
207 existing_dumpers = new_dumpers;