Bug Summary

File:Source/Core/DolphinWX/Src/InputConfigDiag.cpp
Location:line 242, column 43
Description:Value stored to 'r' during its initialization is never read

Annotated Source Code

1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "InputConfigDiag.h"
6#include "UDPConfigDiag.h"
7#include "WxUtils.h"
8#include "HW/Wiimote.h"
9
10void GamepadPage::ConfigUDPWii(wxCommandEvent &event)
11{
12 UDPWrapper* const wrp = ((UDPConfigButton*)event.GetEventObject())->wrapper;
13 UDPConfigDiag diag(this, wrp);
14 diag.ShowModal();
15}
16
17void GamepadPage::ConfigExtension(wxCommandEvent& event)
18{
19 ControllerEmu::Extension* const ex = ((ExtensionButton*)event.GetEventObject())->extension;
20
21 // show config diag, if "none" isn't selected
22 if (ex->switch_extension)
23 {
24 wxDialog dlg(this, -1,
25 wxGetTranslation(StrToWxStr(ex->attachments[ex->switch_extension]->GetName())),
26 wxDefaultPosition, wxDefaultSize);
27
28 wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
29 const std::size_t orig_size = control_groups.size();
30
31 ControlGroupsSizer* const szr =
32 new ControlGroupsSizer(ex->attachments[ex->switch_extension], &dlg, this, &control_groups);
33 main_szr->Add(szr, 0, wxLEFT, 5);
34 main_szr->Add(dlg.CreateButtonSizer(wxOK0x00000004), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
35 dlg.SetSizerAndFit(main_szr);
36 dlg.Center();
37
38 dlg.ShowModal();
39
40 // remove the new groups that were just added, now that the window closed
41 control_groups.resize(orig_size);
42 }
43}
44
45PadSettingExtension::PadSettingExtension(wxWindow* const parent, ControllerEmu::Extension* const ext)
46 : PadSetting(new wxChoice(parent, -1))
47 , extension(ext)
48{
49
50 std::vector<ControllerEmu*>::const_iterator
51 i = extension->attachments.begin(),
52 e = extension->attachments.end();
53
54 for (; i!=e; ++i)
55 ((wxChoice*)wxcontrol)->Append(wxGetTranslation(StrToWxStr((*i)->GetName())));
56
57 UpdateGUI();
58}
59
60void PadSettingExtension::UpdateGUI()
61{
62 ((wxChoice*)wxcontrol)->Select(extension->switch_extension);
63}
64
65void PadSettingExtension::UpdateValue()
66{
67 extension->switch_extension = ((wxChoice*)wxcontrol)->GetSelection();
68}
69
70PadSettingCheckBox::PadSettingCheckBox(wxWindow* const parent, ControlState& _value, const char* const label)
71 : PadSetting(new wxCheckBox(parent, -1, wxGetTranslation(StrToWxStr(label)), wxDefaultPosition))
72 , value(_value)
73{
74 UpdateGUI();
75}
76
77void PadSettingCheckBox::UpdateGUI()
78{
79 ((wxCheckBox*)wxcontrol)->SetValue(value > 0);
80}
81
82void PadSettingCheckBox::UpdateValue()
83{
84 // 0.01 so its saved to the ini file as just 1. :(
85 value = 0.01 * ((wxCheckBox*)wxcontrol)->GetValue();
86}
87
88void PadSettingSpin::UpdateGUI()
89{
90 ((wxSpinCtrl*)wxcontrol)->SetValue((int)(value * 100));
91}
92
93void PadSettingSpin::UpdateValue()
94{
95 value = float(((wxSpinCtrl*)wxcontrol)->GetValue()) / 100;
96}
97
98ControlDialog::ControlDialog(GamepadPage* const parent, InputPlugin& plugin, ControllerInterface::ControlReference* const ref)
99 : wxDialog(parent, -1, _("Configure Control")wxGetTranslation(("Configure Control")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE(0x20000000 | 0x0800 | 0x1000) | wxRESIZE_BORDER0x0040)
100 , control_reference(ref)
101 , m_plugin(plugin)
102 , m_parent(parent)
103{
104 m_devq = m_parent->controller->default_device;
105
106 // GetStrings() sounds slow :/
107 //device_cbox = new wxComboBox(this, -1, StrToWxStr(ref->device_qualifier.ToString()), wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER);
108 device_cbox = new wxComboBox(this, -1, StrToWxStr(m_devq.ToString()), wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER0x0400);
109
110 device_cbox->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &ControlDialog::SetDevice, this);
111 device_cbox->Bind(wxEVT_COMMAND_TEXT_ENTER, &ControlDialog::SetDevice, this);
112
113 wxStaticBoxSizer* const control_chooser = CreateControlChooser(parent);
114
115 wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer(wxVERTICAL, this, _("Device")wxGetTranslation(("Device")));
116 d_szr->Add(device_cbox, 0, wxEXPAND|wxALL, 5);
117
118 wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
119 szr->Add(d_szr, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5);
120 szr->Add(control_chooser, 1, wxEXPAND|wxALL, 5);
121
122 SetSizerAndFit(szr); // needed
123
124 UpdateGUI();
125 SetFocus();
126}
127
128ControlButton::ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref, const unsigned int width, const std::string& label)
129: wxButton(parent, -1, wxT("")L"", wxDefaultPosition, wxSize(width,20))
130, control_reference(_ref)
131{
132 if (label.empty())
133 SetLabel(StrToWxStr(_ref->expression));
134 else
135 SetLabel(StrToWxStr(label));
136}
137
138void InputConfigDialog::UpdateProfileComboBox()
139{
140 std::string pname(File::GetUserPath(D_CONFIG_IDX));
141 pname += PROFILES_PATH"Profiles/";
142 pname += m_plugin.profile_name;
143
144 CFileSearch::XStringVector exts;
145 exts.push_back("*.ini");
146 CFileSearch::XStringVector dirs;
147 dirs.push_back(pname);
148 CFileSearch cfs(exts, dirs);
149 const CFileSearch::XStringVector& sv = cfs.GetFileNames();
150
151 wxArrayString strs;
152 CFileSearch::XStringVector::const_iterator si = sv.begin(),
153 se = sv.end();
154 for (; si!=se; ++si)
155 {
156 std::string str(si->begin() + si->find_last_of('/') + 1 , si->end() - 4) ;
157 strs.push_back(StrToWxStr(str));
158 }
159
160 std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
161 e = m_padpages.end();
162 for (; i != e; ++i)
163 {
164 (*i)->profile_cbox->Clear();
165 (*i)->profile_cbox->Append(strs);
166 }
167}
168
169void InputConfigDialog::UpdateControlReferences()
170{
171 std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
172 e = m_padpages.end();
173 for (; i != e; ++i)
174 (*i)->controller->UpdateReferences(g_controller_interface);
175}
176
177void InputConfigDialog::ClickSave(wxCommandEvent& event)
178{
179 m_plugin.SaveConfig();
180 event.Skip();
181}
182
183void ControlDialog::UpdateListContents()
184{
185 control_lbox->Clear();
186
187 Device* const dev = g_controller_interface.FindDevice(m_devq);
188 if (dev)
189 {
190 if (control_reference->is_input)
191 {
192 // for inputs
193 std::vector<Device::Input*>::const_iterator
194 i = dev->Inputs().begin(),
195 e = dev->Inputs().end();
196 for (; i!=e; ++i)
197 control_lbox->Append(StrToWxStr((*i)->GetName()));
198 }
199 else
200 {
201 // for outputs
202 std::vector<Device::Output*>::const_iterator
203 i = dev->Outputs().begin(),
204 e = dev->Outputs().end();
205 for (; i!=e; ++i)
206 control_lbox->Append(StrToWxStr((*i)->GetName()));
207 }
208 }
209}
210
211void ControlDialog::SelectControl(const std::string& name)
212{
213 //UpdateGUI();
214
215 const int f = control_lbox->FindString(StrToWxStr(name));
216 if (f >= 0)
217 control_lbox->Select(f);
218}
219
220void ControlDialog::UpdateGUI()
221{
222 // update textbox
223 textctrl->SetValue(StrToWxStr(control_reference->expression));
224
225 // updates the "bound controls:" label
226 m_bound_label->SetLabel(wxString::Format(_("Bound Controls: %lu")wxGetTranslation(("Bound Controls: %lu")),
227 (unsigned long)control_reference->BoundCount()));
228};
229
230void GamepadPage::UpdateGUI()
231{
232 device_cbox->SetValue(StrToWxStr(controller->default_device.ToString()));
233
234 std::vector< ControlGroupBox* >::const_iterator g = control_groups.begin(),
235 ge = control_groups.end();
236 for (; g!=ge; ++g)
237 {
238 // buttons
239 std::vector<ControlButton*>::const_iterator i = (*g)->control_buttons.begin()
240 , e = (*g)->control_buttons.end();
241 for (; i!=e; ++i) {
242 ControllerInterface::ControlReference *r = (*i)->control_reference;
Value stored to 'r' during its initialization is never read
243 wxString expr = StrToWxStr((*i)->control_reference->expression);
244 expr.Replace("&", "&&");
245 (*i)->SetLabel(expr);
246 }
247
248 // cboxes
249 std::vector<PadSetting*>::const_iterator si = (*g)->options.begin()
250 , se = (*g)->options.end();
251 for (; si!=se; ++si)
252 (*si)->UpdateGUI();
253 }
254}
255
256void GamepadPage::ClearAll(wxCommandEvent&)
257{
258 // just load an empty ini section to clear everything :P
259 IniFile::Section section;
260 controller->LoadConfig(&section);
261
262 // no point in using the real ControllerInterface i guess
263 ControllerInterface face;
264
265 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
266 controller->UpdateReferences(face);
267
268 UpdateGUI();
269}
270
271void GamepadPage::LoadDefaults(wxCommandEvent&)
272{
273 controller->LoadDefaults(g_controller_interface);
274
275 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
276 controller->UpdateReferences(g_controller_interface);
277
278 UpdateGUI();
279}
280
281void ControlDialog::SetControl(wxCommandEvent&)
282{
283 control_reference->expression = WxStrToStr(textctrl->GetValue());
284
285 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
286 g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device);
287
288 UpdateGUI();
289}
290
291void GamepadPage::SetDevice(wxCommandEvent&)
292{
293 controller->default_device.FromString(WxStrToStr(device_cbox->GetValue()));
294
295 // show user what it was validated as
296 device_cbox->SetValue(StrToWxStr(controller->default_device.ToString()));
297
298 // this will set all the controls to this default device
299 controller->UpdateDefaultDevice();
300
301 // update references
302 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
303 controller->UpdateReferences(g_controller_interface);
304}
305
306void ControlDialog::SetDevice(wxCommandEvent&)
307{
308 m_devq.FromString(WxStrToStr(device_cbox->GetValue()));
309
310 // show user what it was validated as
311 device_cbox->SetValue(StrToWxStr(m_devq.ToString()));
312
313 // update gui
314 UpdateListContents();
315}
316
317void ControlDialog::ClearControl(wxCommandEvent&)
318{
319 control_reference->expression.clear();
320
321 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
322 g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device);
323
324 UpdateGUI();
325}
326
327inline bool IsAlphabetic(wxString &str)
328{
329 for (wxString::const_iterator it = str.begin(); it != str.end(); ++it)
330 if (!isalpha(*it))
331 return false;
332 return true;
333}
334
335inline void GetExpressionForControl(wxString &expr,
336 wxString &control_name,
337 DeviceQualifier *control_device = NULL__null,
338 DeviceQualifier *default_device = NULL__null)
339{
340 expr = "";
341
342 // non-default device
343 if (control_device && default_device && !(*control_device == *default_device))
344 {
345 expr += control_device->ToString();
346 expr += ":";
347 }
348
349 // append the control name
350 expr += control_name;
351
352 if (!IsAlphabetic(expr))
353 expr = wxString::Format("`%s`", expr);
354}
355
356bool ControlDialog::GetExpressionForSelectedControl(wxString &expr)
357{
358 const int num = control_lbox->GetSelection();
359
360 if (num < 0)
361 return false;
362
363 wxString control_name = control_lbox->GetString(num);
364 GetExpressionForControl(expr,
365 control_name,
366 &m_devq,
367 &m_parent->controller->default_device);
368
369 return true;
370}
371
372void ControlDialog::SetSelectedControl(wxCommandEvent&)
373{
374 wxString expr;
375
376 if (!GetExpressionForSelectedControl(expr))
377 return;
378
379 textctrl->WriteText(expr);
380 control_reference->expression = textctrl->GetValue();
381
382 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
383 g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device);
384
385 UpdateGUI();
386}
387
388void ControlDialog::AppendControl(wxCommandEvent& event)
389{
390 wxString device_expr, expr;
391
392 const wxString lbl = ((wxButton*)event.GetEventObject())->GetLabel();
393 char op = lbl[0];
394
395 if (!GetExpressionForSelectedControl(device_expr))
396 return;
397
398 // Unary ops (that is, '!') are a special case. When there's a selection,
399 // put parens around it and prepend it with a '!', but when there's nothing,
400 // just add a '!device'.
401 if (op == '!')
402 {
403 wxString selection = textctrl->GetStringSelection();
404 if (selection == "")
405 expr = wxString::Format("%c%s", op, device_expr);
406 else
407 expr = wxString::Format("%c(%s)", op, selection);
408 }
409 else
410 expr = wxString::Format(" %c %s", op, device_expr);
411
412 textctrl->WriteText(expr);
413 control_reference->expression = textctrl->GetValue();
414
415 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
416 g_controller_interface.UpdateReference(control_reference, m_parent->controller->default_device);
417
418 UpdateGUI();
419}
420
421void GamepadPage::AdjustSetting(wxCommandEvent& event)
422{
423 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
424 ((PadSetting*)((wxControl*)event.GetEventObject())->GetClientData())->UpdateValue();
425}
426
427void GamepadPage::AdjustControlOption(wxCommandEvent&)
428{
429 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
430 m_control_dialog->control_reference->range = (ControlState)(m_control_dialog->range_slider->GetValue()) / SLIDER_TICK_COUNT100;
431}
432
433void GamepadPage::ConfigControl(wxEvent& event)
434{
435 m_control_dialog = new ControlDialog(this, m_plugin, ((ControlButton*)event.GetEventObject())->control_reference);
436 m_control_dialog->ShowModal();
437 m_control_dialog->Destroy();
438
439 // update changes that were made in the dialog
440 UpdateGUI();
441}
442
443void GamepadPage::ClearControl(wxEvent& event)
444{
445 ControlButton* const btn = (ControlButton*)event.GetEventObject();
446 btn->control_reference->expression.clear();
447 btn->control_reference->range = 1.0f;
448
449 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
450 controller->UpdateReferences(g_controller_interface);
451
452 // update changes
453 UpdateGUI();
454}
455
456void ControlDialog::DetectControl(wxCommandEvent& event)
457{
458 wxButton* const btn = (wxButton*)event.GetEventObject();
459 const wxString lbl = btn->GetLabel();
460
461 Device* const dev = g_controller_interface.FindDevice(m_devq);
462 if (dev)
463 {
464 btn->SetLabel(_("[ waiting ]")wxGetTranslation(("[ waiting ]")));
465
466 // apparently, this makes the "waiting" text work on Linux
467 wxTheAppstatic_cast<wxApp*>(wxApp::GetInstance())->Yield();
468
469 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
470 Device::Control* const ctrl = control_reference->Detect(DETECT_WAIT_TIME1500, dev);
471
472 // if we got input, select it in the list
473 if (ctrl)
474 SelectControl(ctrl->GetName());
475
476 btn->SetLabel(lbl);
477 }
478}
479
480void GamepadPage::DetectControl(wxCommandEvent& event)
481{
482 ControlButton* btn = (ControlButton*)event.GetEventObject();
483
484 // find device :/
485 Device* const dev = g_controller_interface.FindDevice(controller->default_device);
486 if (dev)
487 {
488 btn->SetLabel(_("[ waiting ]")wxGetTranslation(("[ waiting ]")));
489
490 // apparently, this makes the "waiting" text work on Linux
491 wxTheAppstatic_cast<wxApp*>(wxApp::GetInstance())->Yield();
492
493 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
494 Device::Control* const ctrl = btn->control_reference->Detect(DETECT_WAIT_TIME1500, dev);
495
496 // if we got input, update expression and reference
497 if (ctrl)
498 {
499 wxString control_name = ctrl->GetName();
500 wxString expr;
501 GetExpressionForControl(expr, control_name);
502 btn->control_reference->expression = expr;
503 g_controller_interface.UpdateReference(btn->control_reference, controller->default_device);
504 }
505 }
506
507 UpdateGUI();
508}
509
510wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
511{
512 wxStaticBoxSizer* const main_szr = new wxStaticBoxSizer(wxVERTICAL, this, control_reference->is_input ? _("Input")wxGetTranslation(("Input")) : _("Output")wxGetTranslation(("Output")));
513
514 textctrl = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(-1, 48), wxTE_MULTILINE0x0020 | wxTE_RICH20x8000);
515 wxFont font = textctrl->GetFont();
516 font.SetFamily(wxFONTFAMILY_MODERN);
517 textctrl->SetFont(font);
518
519 wxButton* const detect_button = new wxButton(this, -1, control_reference->is_input ? _("Detect")wxGetTranslation(("Detect")) : _("Test")wxGetTranslation(("Test")));
520
521 wxButton* const clear_button = new wxButton(this, -1, _("Clear")wxGetTranslation(("Clear")));
522 wxButton* const set_button = new wxButton(this, -1, _("Set")wxGetTranslation(("Set")));
523
524 wxButton* const select_button = new wxButton(this, -1, _("Select")wxGetTranslation(("Select")));
525 select_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::SetSelectedControl, this);
526
527 wxButton* const not_button = new wxButton(this, -1, _("! NOT")wxGetTranslation(("! NOT")), wxDefaultPosition);
528 not_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::AppendControl, this);
529
530 wxButton* const or_button = new wxButton(this, -1, _("| OR")wxGetTranslation(("| OR")), wxDefaultPosition);
531 or_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::AppendControl, this);
532
533 control_lbox = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
534
535 wxBoxSizer* const button_sizer = new wxBoxSizer(wxVERTICAL);
536 button_sizer->Add(detect_button, 1, 0, 5);
537 button_sizer->Add(select_button, 1, 0, 5);
538 button_sizer->Add(or_button, 1, 0, 5);
539
540 if (control_reference->is_input)
541 {
542 // TODO: check if && is good on other OS
543 wxButton* const and_button = new wxButton(this, -1, _("&& AND")wxGetTranslation(("&& AND")), wxDefaultPosition);
544 wxButton* const add_button = new wxButton(this, -1, _("+ ADD")wxGetTranslation(("+ ADD")), wxDefaultPosition);
545
546 and_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::AppendControl, this);
547 add_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::AppendControl, this);
548
549 button_sizer->Add(and_button, 1, 0, 5);
550 button_sizer->Add(not_button, 1, 0, 5);
551 button_sizer->Add(add_button, 1, 0, 5);
552 }
553
554 range_slider = new wxSlider(this, -1, SLIDER_TICK_COUNT100, -SLIDER_TICK_COUNT100 * 5, SLIDER_TICK_COUNT100 * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP0x0080 | wxSL_LABELS(0x2000|0x4000) /*| wxSL_AUTOTICKS*/);
555
556 range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT100));
557
558 detect_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::DetectControl, this);
559 clear_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::ClearControl, this);
560 set_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &ControlDialog::SetControl, this);
561
562 range_slider->Bind(wxEVT_SCROLL_CHANGED, &GamepadPage::AdjustControlOption, parent);
563 wxStaticText* const range_label = new wxStaticText(this, -1, _("Range")wxGetTranslation(("Range")));
564 m_bound_label = new wxStaticText(this, -1, wxT("")L"");
565
566 wxBoxSizer* const range_sizer = new wxBoxSizer(wxHORIZONTAL);
567 range_sizer->Add(range_label, 0, wxCENTER|wxLEFT, 5);
568 range_sizer->Add(range_slider, 1, wxEXPAND|wxLEFT, 5);
569
570 wxBoxSizer* const ctrls_sizer = new wxBoxSizer(wxHORIZONTAL);
571 ctrls_sizer->Add(control_lbox, 1, wxEXPAND, 0);
572 ctrls_sizer->Add(button_sizer, 0, wxEXPAND, 0);
573
574 wxSizer* const bottom_btns_sizer = CreateButtonSizer(wxOK0x00000004);
575 bottom_btns_sizer->Prepend(set_button, 0, wxRIGHT, 5);
576 bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, 5);
577
578 main_szr->Add(range_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5);
579 main_szr->Add(ctrls_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5);
580 main_szr->Add(textctrl, 1, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5);
581 main_szr->Add(bottom_btns_sizer, 0, wxEXPAND|wxBOTTOM|wxRIGHT, 5);
582 main_szr->Add(m_bound_label, 0, wxCENTER, 0);
583
584 UpdateListContents();
585
586 return main_szr;
587}
588
589void GamepadPage::GetProfilePath(std::string& path)
590{
591 const wxString& name = profile_cbox->GetValue();
592 if (false == name.empty())
593 {
594 // TODO: check for dumb characters maybe
595
596 path = File::GetUserPath(D_CONFIG_IDX);
597 path += PROFILES_PATH"Profiles/";
598 path += m_plugin.profile_name;
599 path += '/';
600 path += WxStrToStr(profile_cbox->GetValue());
601 path += ".ini";
602 }
603}
604
605void GamepadPage::LoadProfile(wxCommandEvent&)
606{
607 std::string fname;
608 GamepadPage::GetProfilePath(fname);
609
610 if (false == File::Exists(fname))
611 return;
612
613 IniFile inifile;
614 inifile.Load(fname);
615
616 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
617 controller->LoadConfig(inifile.GetOrCreateSection("Profile"));
618 controller->UpdateReferences(g_controller_interface);
619
620 UpdateGUI();
621}
622
623void GamepadPage::SaveProfile(wxCommandEvent&)
624{
625 std::string fname;
626 GamepadPage::GetProfilePath(fname);
627 File::CreateFullPath(fname);
628
629 if (false == fname.empty())
630 {
631 IniFile inifile;
632 controller->SaveConfig(inifile.GetOrCreateSection("Profile"));
633 inifile.Save(fname);
634
635 m_config_dialog->UpdateProfileComboBox();
636 }
637 else
638 {
639 PanicAlertT("You must enter a valid profile name.")MsgAlert(false, WARNING, "You must enter a valid profile name."
)
;
640 }
641}
642
643void GamepadPage::DeleteProfile(wxCommandEvent&)
644{
645 std::string fname;
646 GamepadPage::GetProfilePath(fname);
647
648 const char* const fnamecstr = fname.c_str();
649
650 if (File::Exists(fnamecstr) &&
651 AskYesNoT("Are you sure you want to delete \"%s\"?",MsgAlert(true, QUESTION, "Are you sure you want to delete \"%s\"?"
, WxStrToStr(profile_cbox->GetValue()).c_str())
652 WxStrToStr(profile_cbox->GetValue()).c_str())MsgAlert(true, QUESTION, "Are you sure you want to delete \"%s\"?"
, WxStrToStr(profile_cbox->GetValue()).c_str())
)
653 {
654 File::Delete(fnamecstr);
655
656 m_config_dialog->UpdateProfileComboBox();
657 }
658}
659
660void InputConfigDialog::UpdateDeviceComboBox()
661{
662 std::vector< GamepadPage* >::iterator i = m_padpages.begin(),
663 e = m_padpages.end();
664 DeviceQualifier dq;
665 for (; i != e; ++i)
666 {
667 (*i)->device_cbox->Clear();
668 std::vector<Device*>::const_iterator
669 di = g_controller_interface.Devices().begin(),
670 de = g_controller_interface.Devices().end();
671 for (; di!=de; ++di)
672 {
673 dq.FromDevice(*di);
674 (*i)->device_cbox->Append(StrToWxStr(dq.ToString()));
675 }
676 (*i)->device_cbox->SetValue(StrToWxStr((*i)->controller->default_device.ToString()));
677 }
678}
679
680void GamepadPage::RefreshDevices(wxCommandEvent&)
681{
682 std::lock_guard<std::recursive_mutex> lk(m_plugin.controls_lock);
683
684 // refresh devices
685 g_controller_interface.Shutdown();
686 g_controller_interface.Initialize();
687
688 // update all control references
689 m_config_dialog->UpdateControlReferences();
690
691 // update device cbox
692 m_config_dialog->UpdateDeviceComboBox();
693}
694
695ControlGroupBox::~ControlGroupBox()
696{
697 std::vector<PadSetting*>::const_iterator
698 i = options.begin(),
699 e = options.end();
700 for (; i!=e; ++i)
701 delete *i;
702}
703
704ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent, GamepadPage* const eventsink)
705 : wxBoxSizer(wxVERTICAL)
706 , control_group(group)
707{
708 static_bitmap = NULL__null;
709
710 wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
711 std::vector<ControllerEmu::ControlGroup::Control*>::iterator
712 ci = group->controls.begin(),
713 ce = group->controls.end();
714 for (; ci != ce; ++ci)
715 {
716
717 wxStaticText* const label = new wxStaticText(parent, -1, wxGetTranslation(StrToWxStr((*ci)->name)));
718
719 ControlButton* const control_button = new ControlButton(parent, (*ci)->control_ref, 80);
720 control_button->SetFont(m_SmallFont);
721
722 control_buttons.push_back(control_button);
723
724 if ((*ci)->control_ref->is_input)
725 {
726 control_button->SetToolTip(_("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options.")wxGetTranslation(("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options."
))
);
727 control_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::DetectControl, eventsink);
728 }
729 else
730 {
731 control_button->SetToolTip(_("Left/Right-click for more options.\nMiddle-click to clear.")wxGetTranslation(("Left/Right-click for more options.\nMiddle-click to clear."
))
);
732 control_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::ConfigControl, eventsink);
733 }
734
735 control_button->Bind(wxEVT_MIDDLE_DOWN, &GamepadPage::ClearControl, eventsink);
736 control_button->Bind(wxEVT_RIGHT_UP, &GamepadPage::ConfigControl, eventsink);
737
738 wxBoxSizer* const control_sizer = new wxBoxSizer(wxHORIZONTAL);
739 control_sizer->AddStretchSpacer(1);
740 control_sizer->Add(label, 0, wxCENTER | wxRIGHT, 3);
741 control_sizer->Add(control_button, 0, 0, 0);
742
743 Add(control_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 3);
744
745 }
746
747 wxMemoryDC dc;
748
749 switch (group->type)
750 {
751 case GROUP_TYPE_STICK:
752 case GROUP_TYPE_TILT:
753 case GROUP_TYPE_CURSOR:
754 case GROUP_TYPE_FORCE:
755 {
756 wxBitmap bitmap(64, 64);
757 dc.SelectObject(bitmap);
758 dc.Clear();
759 static_bitmap = new wxStaticBitmap(parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP);
760
761 std::vector< ControllerEmu::ControlGroup::Setting* >::const_iterator
762 i = group->settings.begin(),
763 e = group->settings.end();
764
765 wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
766 for (; i!=e; ++i)
767 {
768 PadSettingSpin* setting = new PadSettingSpin(parent, *i);
769 setting->wxcontrol->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &GamepadPage::AdjustSetting, eventsink);
770 options.push_back(setting);
771 szr->Add(new wxStaticText(parent, -1, wxGetTranslation(StrToWxStr((*i)->name))));
772 szr->Add(setting->wxcontrol, 0, wxLEFT, 0);
773 }
774
775 wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
776 h_szr->Add(szr, 1, 0, 5);
777 h_szr->Add(static_bitmap, 0, wxALL|wxCENTER, 3);
778
779 Add(h_szr, 0, wxEXPAND|wxLEFT|wxCENTER|wxTOP, 3);
780 }
781 break;
782 case GROUP_TYPE_BUTTONS:
783 {
784 wxBitmap bitmap(int(12*group->controls.size()+1), 12);
785 dc.SelectObject(bitmap);
786 dc.Clear();
787 static_bitmap = new wxStaticBitmap(parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP);
788
789 PadSettingSpin* const threshold_cbox = new PadSettingSpin(parent, group->settings[0]);
790 threshold_cbox->wxcontrol->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &GamepadPage::AdjustSetting, eventsink);
791
792 threshold_cbox->wxcontrol->SetToolTip(_("Adjust the analog control pressure required to activate buttons.")wxGetTranslation(("Adjust the analog control pressure required to activate buttons."
))
);
793
794 options.push_back(threshold_cbox);
795
796 wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
797 szr->Add(new wxStaticText(parent, -1, wxGetTranslation(StrToWxStr(group->settings[0]->name))),
798 0, wxCENTER|wxRIGHT, 3);
799 szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, 3);
800
801 Add(szr, 0, wxALL|wxCENTER, 3);
802 Add(static_bitmap, 0, wxALL|wxCENTER, 3);
803 }
804 break;
805 case GROUP_TYPE_MIXED_TRIGGERS:
806 case GROUP_TYPE_TRIGGERS:
807 case GROUP_TYPE_SLIDER:
808 {
809 int height = (int)(12 * group->controls.size());
810 int width = 64;
811
812 if (GROUP_TYPE_MIXED_TRIGGERS == group->type)
813 width = 64+12+1;
814
815 if (GROUP_TYPE_TRIGGERS != group->type)
816 height /= 2;
817
818 wxBitmap bitmap(width, height+1);
819 dc.SelectObject(bitmap);
820 dc.Clear();
821 static_bitmap = new wxStaticBitmap(parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP);
822
823 std::vector<ControllerEmu::ControlGroup::Setting*>::const_iterator
824 i = group->settings.begin(),
825 e = group->settings.end();
826 for (; i!=e; ++i)
827 {
828 PadSettingSpin* setting = new PadSettingSpin(parent, *i);
829 setting->wxcontrol->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &GamepadPage::AdjustSetting, eventsink);
830 options.push_back(setting);
831 wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
832 szr->Add(new wxStaticText(parent, -1, wxGetTranslation(StrToWxStr((*i)->name))), 0, wxCENTER|wxRIGHT, 3);
833 szr->Add(setting->wxcontrol, 0, wxRIGHT, 3);
834 Add(szr, 0, wxALL|wxCENTER, 3);
835 }
836
837 Add(static_bitmap, 0, wxALL|wxCENTER, 3);
838 }
839 break;
840 case GROUP_TYPE_EXTENSION:
841 {
842 PadSettingExtension* const attachments = new PadSettingExtension(parent, (ControllerEmu::Extension*)group);
843 wxButton* const configure_btn = new ExtensionButton(parent, (ControllerEmu::Extension*)group);
844
845 options.push_back(attachments);
846
847 attachments->wxcontrol->Bind(wxEVT_COMMAND_CHOICE_SELECTED, &GamepadPage::AdjustSetting, eventsink);
848 configure_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::ConfigExtension, eventsink);
849
850 Add(attachments->wxcontrol, 0, wxTOP|wxLEFT|wxRIGHT|wxEXPAND, 3);
851 Add(configure_btn, 0, wxALL|wxEXPAND, 3);
852 }
853 break;
854 case GROUP_TYPE_UDPWII:
855 {
856 wxButton* const btn = new UDPConfigButton(parent, (UDPWrapper*)group);
857 btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::ConfigUDPWii, eventsink);
858 Add(btn, 0, wxALL|wxEXPAND, 3);
859 }
860 break;
861 default:
862 {
863 //options
864
865 std::vector<ControllerEmu::ControlGroup::Setting*>::const_iterator
866 i = group->settings.begin(),
867 e = group->settings.end();
868 for (; i!=e; ++i)
869 {
870 PadSettingCheckBox* setting_cbox = new PadSettingCheckBox(parent, (*i)->value, (*i)->name);
871 setting_cbox->wxcontrol->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &GamepadPage::AdjustSetting, eventsink);
872 options.push_back(setting_cbox);
873
874 Add(setting_cbox->wxcontrol, 0, wxALL|wxLEFT, 5);
875
876 }
877 }
878 break;
879 }
880
881 dc.SelectObject(wxNullBitmap);
882
883 //AddStretchSpacer(0);
884}
885
886ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent, GamepadPage* const eventsink, std::vector<ControlGroupBox*>* groups)
887 : wxBoxSizer(wxHORIZONTAL)
888{
889 size_t col_size = 0;
890
891 wxBoxSizer* stacked_groups = NULL__null;
892 for (unsigned int i = 0; i < controller->groups.size(); ++i)
893 {
894 ControlGroupBox* control_group_box = new ControlGroupBox(controller->groups[i], parent, eventsink);
895 wxStaticBoxSizer *control_group =
896 new wxStaticBoxSizer(wxVERTICAL, parent, wxGetTranslation(StrToWxStr(controller->groups[i]->name)));
897 control_group->Add(control_group_box);
898
899 const size_t grp_size = controller->groups[i]->controls.size() + controller->groups[i]->settings.size();
900 col_size += grp_size;
901 if (col_size > 8 || NULL__null == stacked_groups)
902 {
903 if (stacked_groups)
904 Add(stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5);
905
906 stacked_groups = new wxBoxSizer(wxVERTICAL);
907 stacked_groups->Add(control_group, 0, wxEXPAND);
908
909 col_size = grp_size;
910 }
911 else
912 {
913 stacked_groups->Add(control_group, 0, wxEXPAND);
914 }
915
916 if (groups)
917 groups->push_back(control_group_box);
918 }
919
920 if (stacked_groups)
921 Add(stacked_groups, 0, /*wxEXPAND|*/wxBOTTOM|wxRIGHT, 5);
922}
923
924GamepadPage::GamepadPage(wxWindow* parent, InputPlugin& plugin, const unsigned int pad_num, InputConfigDialog* const config_dialog)
925 : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
926 ,controller(plugin.controllers[pad_num])
927 , m_config_dialog(config_dialog)
928 , m_plugin(plugin)
929{
930
931 wxBoxSizer* control_group_sizer = new ControlGroupsSizer(m_plugin.controllers[pad_num], this, this, &control_groups);
932
933 wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Profile")wxGetTranslation(("Profile")));
934
935 // device chooser
936
937 wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Device")wxGetTranslation(("Device")));
938
939 device_cbox = new wxComboBox(this, -1, wxT("")L"", wxDefaultPosition, wxSize(64,-1));
940 device_cbox->ToggleWindowStyle(wxTE_PROCESS_ENTER0x0400);
941
942 wxButton* refresh_button = new wxButton(this, -1, _("Refresh")wxGetTranslation(("Refresh")), wxDefaultPosition, wxSize(60,-1));
943
944 device_cbox->Bind(wxEVT_COMMAND_COMBOBOX_SELECTED, &GamepadPage::SetDevice, this);
945 device_cbox->Bind(wxEVT_COMMAND_TEXT_ENTER, &GamepadPage::SetDevice, this);
946 refresh_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::RefreshDevices, this);
947
948 device_sbox->Add(device_cbox, 1, wxLEFT|wxRIGHT, 3);
949 device_sbox->Add(refresh_button, 0, wxRIGHT|wxBOTTOM, 3);
950
951 wxButton* const default_button = new wxButton(this, -1, _("Default")wxGetTranslation(("Default")), wxDefaultPosition, wxSize(48,-1));
952 wxButton* const clearall_button = new wxButton(this, -1, _("Clear")wxGetTranslation(("Clear")), wxDefaultPosition, wxSize(58,-1));
953
954 wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reset")wxGetTranslation(("Reset")));
955 clear_sbox->Add(default_button, 1, wxLEFT, 3);
956 clear_sbox->Add(clearall_button, 1, wxRIGHT, 3);
957
958 clearall_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::ClearAll, this);
959 default_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::LoadDefaults, this);
960
961 profile_cbox = new wxComboBox(this, -1, wxT("")L"", wxDefaultPosition, wxSize(64,-1));
962
963 wxButton* const pload_btn = new wxButton(this, -1, _("Load")wxGetTranslation(("Load")), wxDefaultPosition, wxSize(48,-1));
964 wxButton* const psave_btn = new wxButton(this, -1, _("Save")wxGetTranslation(("Save")), wxDefaultPosition, wxSize(48,-1));
965 wxButton* const pdelete_btn = new wxButton(this, -1, _("Delete")wxGetTranslation(("Delete")), wxDefaultPosition, wxSize(60,-1));
966
967 pload_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::LoadProfile, this);
968 psave_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::SaveProfile, this);
969 pdelete_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GamepadPage::DeleteProfile, this);
970
971 profile_sbox->Add(profile_cbox, 1, wxLEFT, 3);
972 profile_sbox->Add(pload_btn, 0, wxLEFT, 3);
973 profile_sbox->Add(psave_btn, 0, 0, 3);
974 profile_sbox->Add(pdelete_btn, 0, wxRIGHT|wxBOTTOM, 3);
975
976 wxBoxSizer* const dio = new wxBoxSizer(wxHORIZONTAL);
977 dio->Add(device_sbox, 1, wxEXPAND|wxRIGHT, 5);
978 dio->Add(clear_sbox, 0, wxEXPAND|wxRIGHT, 5);
979 dio->Add(profile_sbox, 1, wxEXPAND|wxRIGHT, 5);
980
981 wxBoxSizer* const mapping = new wxBoxSizer(wxVERTICAL);
982
983 mapping->Add(dio, 1, wxEXPAND|wxLEFT|wxTOP|wxBOTTOM, 5);
984 mapping->Add(control_group_sizer, 0, wxLEFT|wxEXPAND, 5);
985
986 UpdateGUI();
987
988 SetSizerAndFit(mapping); // needed
989 Layout();
990};
991
992
993InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputPlugin& plugin, const std::string& name, const int tab_num)
994 : wxDialog(parent, wxID_ANY, wxGetTranslation(StrToWxStr(name)), wxPoint(128,-1), wxDefaultSize)
995 , m_plugin(plugin)
996{
997 m_pad_notebook = new wxNotebook(this, -1, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT0x0000);
998 for (unsigned int i = 0; i < std::min(plugin.controllers.size(), (size_t)MAX_WIIMOTES); ++i)
999 {
1000 GamepadPage* gp = new GamepadPage(m_pad_notebook, m_plugin, i, this);
1001 m_padpages.push_back(gp);
1002 m_pad_notebook->AddPage(gp, wxString::Format(wxT("%s %u")L"%s %u", wxGetTranslation(StrToWxStr(m_plugin.gui_name)), 1+i));
1003 }
1004
1005 m_pad_notebook->SetSelection(tab_num);
1006
1007 UpdateDeviceComboBox();
1008 UpdateProfileComboBox();
1009
1010 Bind(wxEVT_COMMAND_BUTTON_CLICKED, &InputConfigDialog::ClickSave, this, wxID_OK);
1011
1012 wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
1013 szr->Add(m_pad_notebook, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5);
1014 szr->Add(CreateButtonSizer(wxOK0x00000004 | wxCANCEL0x00000010 | wxNO_DEFAULT0x00000080), 0, wxEXPAND|wxALL, 5);
1015
1016 SetSizerAndFit(szr);
1017 Center();
1018
1019 // live preview update timer
1020 m_update_timer = new wxTimer(this, -1);
1021 Bind(wxEVT_TIMER, &InputConfigDialog::UpdateBitmaps, this);
1022 m_update_timer->Start(PREVIEW_UPDATE_TIME25, wxTIMER_CONTINUOUSfalse);
1023}
1024
1025bool InputConfigDialog::Destroy()
1026{
1027 m_update_timer->Stop();
1028 return true;
1029}