bsnes/higan/target-bsnes/settings/input.cpp

160 lines
5.2 KiB
C++
Raw Normal View History

Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
auto InputSettings::create() -> void {
setIcon(Icon::Device::Joypad);
setText("Input");
Update to v106r47 release. byuu says: This is probably the largest code-change diff I've done in years. I spent four days working 10-16 hours a day reworking layouts in hiro completely. The result is we now have TableLayout, which will allow for better horizontal+vertical combined alignment. Windows, GTK2, and now GTK3 are fully supported. Windows is getting the initial window geometry wrong by a bit. GTK2 and GTK3 work perfectly. I basically abandoned trying to detect resize signals, and instead keep a list of all hiro windows that are allocated, and every time the main loop runs, it will query all of them to see if they've been resized. I'm disgusted that I have to do this, but after fighting with GTK for years, I'm about sick of it. GTK was doing this crazy thing where it would trigger another size-allocate inside of a previous size-allocate, and so my layouts would be halfway through resizing all the widgets, and then the size-allocate would kick off another one. That would end up leaving the rest of the first layout loop with bad widget sizes. And if I detected a second re-entry and blocked it, then the entire window would end up with the older geometry. I started trying to build a message queue system to allow the second layout resize to occur after the first one completed, but this was just too much madness, so I went with the simpler solution. Qt4 has some geometry problems, and doesn't show tab frame layouts properly yet. Qt5 causes an ICE error and tanks my entire Xorg display server, so ... something is seriously wrong there, and it's not hiro's fault. Creating a dummy Qt5 application without even using hiro, just int main() { TestObject object; } with object performing a dynamic\_cast to a derived type segfaults. Memory is getting corrupted where GCC allocates the vtables for classes, just by linking in Qt. Could be somehow related to the -fPIC requirement that only Qt5 has ... could just be that FreeBSD 10.1 has a buggy implementation of Qt5. I don't know. It's beyond my ability to debug, so this one's going to stay broken. The Cocoa port is busted. I'll fix it up to compile again, but that's about all I'm going to do. Many optimizations mean bsnes and higan open faster. GTK2 and GTK3 both resize windows very quickly now. higan crashes when you load a game, so that's not good. bsnes works though. bsnes also has the start of a localization engine now. Still a long way to go. The makefiles received a rather substantial restructuring. Including the ruby and hiro makefiles will add the necessary compilation rules for you, which also means that moc will run for the qt4 and qt5 targets, and windres will run for the Windows targets.
2018-07-14 03:59:29 +00:00
layout.setPadding(5);
portLabel.setText("Port:");
portList.onChange([&] { reloadDevices(); });
deviceLabel.setText("Device:");
deviceList.onChange([&] { reloadMappings(); });
turboLabel.setText("Turbo rate:");
for(uint frequency : range(1, 9)) {
ComboButtonItem item{&turboList};
item.setText(frequency);
if(frequency == settings["Input/Turbo/Frequency"].natural()) item.setSelected();
}
turboList.onChange([&] {
uint frequency = turboList.selected().text().natural();
settings["Input/Turbo/Frequency"].setValue(frequency);
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
inputManager.turboCounter = 0;
inputManager.turboFrequency = frequency;
});
mappingList.setBatchable();
mappingList.setHeadered();
mappingList.onActivate([&] { if(assignButton.enabled()) assignButton.doActivate(); });
mappingList.onChange([&] { updateControls(); });
assignMouse1.onActivate([&] { assignMouseInput(0); });
assignMouse2.onActivate([&] { assignMouseInput(1); });
assignMouse3.onActivate([&] { assignMouseInput(2); });
assignButton.setText("Assign").onActivate([&] {
assignMapping();
});
clearButton.setText("Clear").onActivate([&] {
for(auto mapping : mappingList.batched()) {
activeDevice().mappings[mapping.offset()].unbind();
}
refreshMappings();
});
}
auto InputSettings::updateControls() -> void {
auto batched = mappingList.batched();
assignButton.setEnabled(batched.size() == 1);
clearButton.setEnabled(batched.size() >= 1);
assignMouse1.setVisible(false);
assignMouse2.setVisible(false);
assignMouse3.setVisible(false);
if(batched.size() == 1) {
auto& input = activeDevice().mappings[batched.left().offset()];
if(input.isDigital()) {
assignMouse1.setVisible().setText("Mouse Left");
assignMouse2.setVisible().setText("Mouse Middle");
assignMouse3.setVisible().setText("Mouse Right");
} else if(input.isAnalog()) {
assignMouse1.setVisible().setText("Mouse X-axis");
assignMouse2.setVisible().setText("Mouse Y-axis");
}
}
}
auto InputSettings::activePort() -> InputPort& {
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
return inputManager.ports[portList.selected().offset()];
}
auto InputSettings::activeDevice() -> InputDevice& {
auto index = deviceList.selected().property("index").natural();
return activePort().devices[index];
}
auto InputSettings::reloadPorts() -> void {
portList.reset();
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
for(auto& port : inputManager.ports) {
if(port.name == "Expansion Port") continue;
portList.append(ComboButtonItem().setText(port.name));
}
reloadDevices();
}
auto InputSettings::reloadDevices() -> void {
deviceList.reset();
uint index = 0;
for(auto& device : activePort().devices) {
if(device.mappings) { //only display devices that have configurable inputs
deviceList.append(ComboButtonItem().setText(device.name).setProperty("index", index));
}
index++;
}
reloadMappings();
}
auto InputSettings::reloadMappings() -> void {
mappingList.reset();
mappingList.append(TableViewColumn().setText("Name"));
mappingList.append(TableViewColumn().setText("Mapping").setExpandable());
for(auto& mapping : activeDevice().mappings) {
mappingList.append(TableViewItem()
.append(TableViewCell().setText(mapping.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255}))
.append(TableViewCell())
);
}
refreshMappings();
updateControls();
}
auto InputSettings::refreshMappings() -> void {
uint index = 0;
for(auto& mapping : activeDevice().mappings) {
mappingList.item(index++).cell(1).setText(mapping.displayName());
}
Application::processEvents();
mappingList.resizeColumns();
}
auto InputSettings::assignMapping() -> void {
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
inputManager.poll(); //clear any pending events first
for(auto mapping : mappingList.batched()) {
activeMapping = activeDevice().mappings[mapping.offset()];
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
settingsWindow.layout.setEnabled(false);
settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."});
settingsWindow.setDismissable(false);
}
}
auto InputSettings::cancelMapping() -> void {
activeMapping.reset();
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
settingsWindow.statusBar.setText();
settingsWindow.layout.setEnabled();
settingsWindow.doSize();
settingsWindow.setDismissable(true);
}
auto InputSettings::assignMouseInput(uint id) -> void {
if(auto mapping = mappingList.selected()) {
activeMapping = activeDevice().mappings[mapping.offset()];
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
if(auto mouse = inputManager.findMouse()) {
if(activeMapping->isDigital()) {
return inputEvent(mouse, HID::Mouse::GroupID::Button, id, 0, 1, true);
} else if(activeMapping->isAnalog()) {
return inputEvent(mouse, HID::Mouse::GroupID::Axis, id, 0, +32767, true);
}
}
}
}
auto InputSettings::inputEvent(shared_pointer<HID::Device> device, uint group, uint input, int16 oldValue, int16 newValue, bool allowMouseInput) -> void {
if(!activeMapping) return;
if(device->isMouse() && !allowMouseInput) return;
if(activeMapping->bind(device, group, input, oldValue, newValue)) {
activeMapping.reset();
Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer<T>` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things.
2018-07-31 10:56:45 +00:00
settingsWindow.statusBar.setText("Mapping assigned.");
refreshMappings();
timer.onActivate([&] {
timer.setEnabled(false);
cancelMapping();
}).setInterval(200).setEnabled();
}
}