1 #include "platform/wxwidgets/settings-common.hpp"
2 #include "platform/wxwidgets/settings-keyentry.hpp"
3 #include "platform/wxwidgets/menu_branches.hpp"
4 #include "platform/wxwidgets/platform.hpp"
5 #include "platform/wxwidgets/loadsave.hpp"
6 #include "core/debug.hpp"
7 #include "core/dispatch.hpp"
8 #include "core/instance.hpp"
9 #include "core/project.hpp"
10 #include "core/moviedata.hpp"
11 #include "core/ui-services.hpp"
16 class branches_tree
: public wxTreeCtrl
19 branches_tree(wxWindow
* parent
, emulator_instance
& _inst
, int id
, bool _nosels
)
20 : wxTreeCtrl(parent
, id
), inst(_inst
), nosels(_nosels
)
23 SetMinSize(wxSize(400, 300));
24 branchchange
.set(inst
.dispatch
->branch_change
, [this]() { runuifun([this]() {
25 this->update(); }); });
37 selection
get_selection()
41 s
.item
= GetSelection();
43 if(s
.item
.IsOk() && i
.second
== s
.item
) {
44 s
.isroot
= (i
.first
== 0);
45 s
.haschildren
= with_children
.count(i
.first
);
47 s
.iscurrent
= (i
.first
== current
);
52 s
.haschildren
= false;
54 s
.id
= 0xFFFFFFFFFFFFFFFFULL
;
60 std::map
<uint64_t, std::string
> namemap
;
61 std::map
<uint64_t, std::set
<uint64_t>> childmap
;
63 UI_get_branch_map(inst
, cur
, namemap
, childmap
);
65 selection cursel
= get_selection();
66 std::set
<uint64_t> expanded
;
68 if(IsExpanded(i
.second
))
69 expanded
.insert(i
.first
);
72 with_children
.clear();
73 if(namemap
.empty()) return;
76 ids
[0] = AddRoot(towxstring(namemap
[0] + ((!nosels
&& current
== 0) ? " <selected>" : "")));
77 build_tree(0, ids
[0], childmap
, namemap
);
78 for(auto i
: expanded
)
82 if(i
.first
== cursel
.id
) {
87 std::string
get_name(uint64_t id
)
94 void build_tree(uint64_t id
, wxTreeItemId parent
, std::map
<uint64_t, std::set
<uint64_t>>& childmap
,
95 std::map
<uint64_t, std::string
>& namemap
)
98 if(!childmap
.count(id
) || childmap
[id
].empty())
100 for(auto i
: childmap
[id
]) {
101 ids
[i
] = AppendItem(ids
[id
], towxstring(namemap
[i
] + ((!nosels
&& current
== i
) ?
102 " <selected>" : "")));
103 build_tree(i
, ids
[i
], childmap
, namemap
);
106 emulator_instance
& inst
;
108 std::map
<uint64_t, std::string
> names
;
109 std::map
<uint64_t, wxTreeItemId
> ids
;
110 std::set
<uint64_t> with_children
;
111 struct dispatch::target
<> branchchange
;
115 class branch_select
: public wxDialog
118 branch_select(wxWindow
* parent
, emulator_instance
& _inst
)
119 : wxDialog(parent
, wxID_ANY
, towxstring("lsnes: Select new parent branch"))
123 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
127 top_s
->Add(branches
= new branches_tree(this, _inst
, wxID_ANY
, true), 1, wxGROW
);
128 branches
->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED
,
129 wxCommandEventHandler(branch_select::on_change
), NULL
, this);
131 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
132 pbutton_s
->AddStretchSpacer();
133 pbutton_s
->Add(okbutton
= new wxButton(this, wxID_OK
, wxT("OK")), 0, wxGROW
);
134 pbutton_s
->Add(cancelbutton
= new wxButton(this, wxID_OK
, wxT("Cancel")), 0, wxGROW
);
135 okbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
136 wxCommandEventHandler(branch_select::on_ok
), NULL
, this);
137 cancelbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
138 wxCommandEventHandler(branch_select::on_cancel
), NULL
, this);
139 top_s
->Add(pbutton_s
, 0, wxGROW
);
141 top_s
->SetSizeHints(this);
147 void on_ok(wxCommandEvent
& e
)
152 void on_cancel(wxCommandEvent
& e
)
155 EndModal(wxID_CANCEL
);
157 uint64_t get_selection()
159 return branches
->get_selection().id
;
161 void on_change(wxCommandEvent
& e
)
164 okbutton
->Enable(get_selection() != 0xFFFFFFFFFFFFFFFFULL
);
168 wxButton
* cancelbutton
;
169 branches_tree
* branches
;
172 class branch_config
: public wxDialog
175 branch_config(wxWindow
* parent
, emulator_instance
& _inst
)
176 : wxDialog(parent
, wxID_ANY
, towxstring("lsnes: Edit slot branches")), inst(_inst
)
180 wxBoxSizer
* top_s
= new wxBoxSizer(wxVERTICAL
);
184 top_s
->Add(branches
= new branches_tree(this, inst
, wxID_ANY
, false), 1, wxGROW
);
185 branches
->Connect(wxEVT_COMMAND_TREE_SEL_CHANGED
,
186 wxCommandEventHandler(branch_config::on_change
), NULL
, this);
188 wxBoxSizer
* pbutton_s
= new wxBoxSizer(wxHORIZONTAL
);
189 pbutton_s
->Add(createbutton
= new wxButton(this, wxID_OK
, wxT("Create")), 0, wxGROW
);
190 pbutton_s
->Add(selectbutton
= new wxButton(this, wxID_OK
, wxT("Select")), 0, wxGROW
);
191 pbutton_s
->Add(renamebutton
= new wxButton(this, wxID_OK
, wxT("Rename")), 0, wxGROW
);
192 pbutton_s
->Add(reparentbutton
= new wxButton(this, wxID_OK
, wxT("Reparent")), 0, wxGROW
);
193 pbutton_s
->Add(deletebutton
= new wxButton(this, wxID_OK
, wxT("Delete")), 0, wxGROW
);
194 pbutton_s
->AddStretchSpacer();
195 pbutton_s
->Add(okbutton
= new wxButton(this, wxID_OK
, wxT("Close")), 0, wxGROW
);
196 createbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
197 wxCommandEventHandler(branch_config::on_create
), NULL
, this);
198 selectbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
199 wxCommandEventHandler(branch_config::on_select
), NULL
, this);
200 renamebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
201 wxCommandEventHandler(branch_config::on_rename
), NULL
, this);
202 reparentbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
203 wxCommandEventHandler(branch_config::on_reparent
), NULL
, this);
204 deletebutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
205 wxCommandEventHandler(branch_config::on_delete
), NULL
, this);
206 okbutton
->Connect(wxEVT_COMMAND_BUTTON_CLICKED
,
207 wxCommandEventHandler(branch_config::on_close
), NULL
, this);
208 top_s
->Add(pbutton_s
, 0, wxGROW
);
210 top_s
->SetSizeHints(this);
215 void on_create(wxCommandEvent
& e
)
218 uint64_t id
= get_selected_id();
219 if(id
== 0xFFFFFFFFFFFFFFFFULL
) return;
222 newname
= pick_text(this, "Enter new branch name", "Enter name for new branch:",
224 } catch(canceled_exception
& e
) {
227 UI_create_branch(inst
, id
, newname
, [this](std::exception
& e
) {
228 show_exception_any(this, "Error creating branch", "Can't create branch", e
);
231 void on_select(wxCommandEvent
& e
)
234 uint64_t id
= get_selected_id();
235 if(id
== 0xFFFFFFFFFFFFFFFFULL
) return;
236 UI_switch_branch(inst
, id
, [this](std::exception
& e
) {
237 show_exception_any(this, "Error setting branch", "Can't set branch", e
);
240 void on_rename(wxCommandEvent
& e
)
243 uint64_t id
= get_selected_id();
244 if(id
== 0xFFFFFFFFFFFFFFFFULL
) return;
245 std::string newname
= branches
->get_name(id
);
247 newname
= pick_text(this, "Enter new branch name", "Rename this branch to:",
249 } catch(canceled_exception
& e
) {
252 UI_rename_branch(inst
, id
, newname
, [this](std::exception
& e
) {
253 show_exception_any(this, "Error renaming branch", "Can't rename branch", e
);
256 void on_reparent(wxCommandEvent
& e
)
259 uint64_t id
= get_selected_id();
260 if(id
== 0xFFFFFFFFFFFFFFFFULL
) return;
262 branch_select
* bsel
= new branch_select(this, inst
);
263 int r
= bsel
->ShowModal();
268 pid
= bsel
->get_selection();
269 if(pid
== 0xFFFFFFFFFFFFFFFFULL
) return;
271 UI_reparent_branch(inst
, id
, pid
, [this](std::exception
& e
) {
272 show_exception_any(this, "Error reparenting branch", "Can't reparent branch", e
);
275 void on_delete(wxCommandEvent
& e
)
278 uint64_t id
= get_selected_id();
279 if(id
== 0xFFFFFFFFFFFFFFFFULL
) return;
280 UI_delete_branch(inst
, id
, [this](std::exception
& e
) {
281 show_exception_any(this, "Error deleting branch", "Can't delete branch", e
);
284 void on_close(wxCommandEvent
& e
)
289 void on_change(wxCommandEvent
& e
)
291 set_enabled(branches
->get_selection());
294 uint64_t get_selected_id()
296 return branches
->get_selection().id
;
298 void set_enabled(branches_tree::selection id
)
301 createbutton
->Enable(id
.item
.IsOk());
302 selectbutton
->Enable(id
.item
.IsOk());
303 renamebutton
->Enable(id
.item
.IsOk() && !id
.isroot
);
304 reparentbutton
->Enable(id
.item
.IsOk() && !id
.isroot
);
305 deletebutton
->Enable(id
.item
.IsOk() && !id
.isroot
&& !id
.haschildren
&& !id
.iscurrent
);
307 wxButton
* createbutton
;
308 wxButton
* selectbutton
;
309 wxButton
* renamebutton
;
310 wxButton
* reparentbutton
;
311 wxButton
* deletebutton
;
313 branches_tree
* branches
;
314 emulator_instance
& inst
;
317 void build_menus(wxMenu
* root
, uint64_t id
, std::list
<branches_menu::miteminfo
>& otheritems
,
318 std::list
<wxMenu
*>& menus
, std::map
<uint64_t, std::string
>& namemap
,
319 std::map
<uint64_t, std::set
<uint64_t>>& childmap
, std::map
<int, uint64_t>& branch_ids
, int& nextid
,
323 auto& children
= childmap
[id
];
325 otheritems
.push_back(branches_menu::miteminfo(root
->AppendCheckItem(mid
, towxstring(namemap
[id
])),
327 branch_ids
[mid
] = id
;
328 root
->FindItem(mid
)->Check(id
== curbranch
);
329 if(!children
.empty())
330 otheritems
.push_back(branches_menu::miteminfo(root
->AppendSeparator(), false, root
));
331 for(auto i
: children
) {
332 bool has_children
= !childmap
[i
].empty();
334 //No children, just put the item there.
336 otheritems
.push_back(branches_menu::miteminfo(root
->AppendCheckItem(mid2
,
337 towxstring(namemap
[i
])), false, root
));
338 branch_ids
[mid2
] = i
;
339 root
->FindItem(mid2
)->Check(i
== curbranch
);
341 //Has children. Make a menu.
342 wxMenu
* m
= new wxMenu();
343 otheritems
.push_back(branches_menu::miteminfo(root
->AppendSubMenu(m
,
344 towxstring(namemap
[i
])), true, root
));
346 build_menus(m
, i
, otheritems
, menus
, namemap
, childmap
, branch_ids
, nextid
,
353 branches_menu::branches_menu(wxWindow
* win
, emulator_instance
& _inst
, int wxid_low
, int wxid_high
)
358 wxid_range_low
= wxid_low
;
359 wxid_range_high
= wxid_high
;
360 win
->Connect(wxid_low
, wxid_high
, wxEVT_COMMAND_MENU_SELECTED
,
361 wxCommandEventHandler(branches_menu::on_select
), NULL
, this);
362 branchchange
.set(inst
.dispatch
->branch_change
, [this]() { runuifun([this]() { this->update(); }); });
365 branches_menu::~branches_menu()
369 void branches_menu::on_select(wxCommandEvent
& e
)
373 if(id
< wxid_range_low
|| id
> wxid_range_high
) return;
374 if(id
== wxid_range_low
) {
376 branch_config
* bcfg
= new branch_config(pwin
, inst
);
381 if(!branch_ids
.count(id
)) return;
382 uint64_t bid
= branch_ids
[id
];
384 UI_switch_branch(inst
, bid
, [this](std::exception
& e
) {
385 show_exception_any(this->pwin
, "Error changing branch", "Can't change branch", e
);
389 void branches_menu::update()
392 std::map
<uint64_t, std::string
> namemap
;
393 std::map
<uint64_t, std::set
<uint64_t>> childmap
;
395 UI_get_branch_map(inst
, cur
, namemap
, childmap
);
396 //First destroy everything that isn't a menu.
397 for(auto i
: otheritems
)
398 i
.parent
->Delete(i
.item
);
399 //Then kill all menus.
405 if(namemap
.empty()) {
406 if(disabler_fn
) disabler_fn(false);
409 //Okay, cleared. Rebuild things.
410 otheritems
.push_back(miteminfo(Append(wxid_range_low
, towxstring("Edit branches")), false, this));
411 otheritems
.push_back(miteminfo(AppendSeparator(), false, this));
412 int ass_id
= wxid_range_low
+ 1;
413 build_menus(this, 0, otheritems
, menus
, namemap
, childmap
, branch_ids
, ass_id
, cur
);
414 if(disabler_fn
) disabler_fn(true);
417 bool branches_menu::any_enabled()
419 return UI_in_project_context(inst
);