From 0ea17abfeaf52b2c078d96aa0e981cb25cc4ac94 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 16 Apr 2018 18:58:13 +1000 Subject: [PATCH] Update to v106r15 release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit byuu says: Changelog: - Super Game Boy: fixed loading of boot ROM - hiro: added ComboEdit::setEditable(bool = true); - tomoko: added new systems settings panel Note!!: this release will not compile on Windows or macOS due to the missing ComboEdit control! I'll try to merge in hex's implementation for the Windows release here soon. macOS users will probably be out of luck for a while, sorry. The new systems panel is an idea I've been meaning to implement for quite a while, but finally got around to starting on it. It's still fairly unpolished, but the basic idea is there for Linux/BSD users to try out now. So imagine the Super Game Boy, BS-X Satellaview, Sufami Turbo, and the associated BS Memory Pack-slotted SNES cartridges. To play any of those, you needed to choose Nintendo→Super Famicom, and then select the relevant cartridge, and then select any slotted cartridges to play with it. This was acceptable-ish, if not ideal. But now imagine in the future if we wanted to support the Famicom Disk System, which is technically a cartridge that plugs into the Famicom deck. Or the PC Engine CD, which has one of three special HuCards that must be inserted (ignoring the Turbo Duo where it's built-in—I'm going to be emulating the Super CD as if you're using a stock PCE CD.) Or the Mega CD, where there are probably a half dozen or more BIOS + hardware revisions that are region-specific, which connect to an expansion port that is identical to the cartridge port save for the Mega Drive seeing an I/O register bit toggled here. In all of these cases, it's going to be a real pain to have to choose the 'BIOS' every time you want to play a game for them. I can't distribute these BIOSes with higan due to copyright restrictions, and trying to ship dummy folders for every possible combination would become quite odious, and difficult for people to use (compare to setting up the Game Boy Advance system BIOS.) And so I've created the new systems settings panel. Here, you can manage a list of systems that show up under the higan library menu (now renamed to “System”), where each entry contains name, boot, and hidden parameters. The name parameter is what shows up in the system menu. You can call any system higan emulates whatever you like here. Don't like “Super Famicom”? Change it to “SNES”, then. The boot parameter is a combo edit with a dropdown for all of the systems higan emulates. If you choose one of these, then the higan system menu option will work exactly like in previous releases, and prompt you for a cartridge. But if you choose the browse button next to the combo edit control, you'll get to pick any gamepak from the higan library of your choosing. So you could choose the SGB2 BIOS, and name the menu option “Super Game Boy 2”, and when you choose the menu option, it will load the SFC core, load the SGB2 BIOS, and only prompt you for the Game Boy game you wish to play on it. The same deal goes for the FDS, PCE-CD, Mega CD, Mega Drive Sonic & Knuckles lock-on cartridge, BS-X Satellaview, SD Gundam G-Next, etc. Whatever you want to be in the menu, you can put in there by pointing higan at the appropriate 'BIOS' gamepak to load. Astute readers have probably already noticed, but you can technically use this on non-slotted games as well, thus creating instant boot options for your absolute favorite games, if you so wanted. Point it at Zelda 3, and you can boot it instantly from the main menu, without any need for file selection. The hidden option is a way to hide the system entries from the system menu. Primarily this would be a fast way for users to disable emulation cores they never use in higan, without having to remove the options. The major concession with this change is the collapsing of the per-manufacturer submenus. What this means is you will now have all twelve higan emulated systems in the main menu by default. This makes the list rather long, but ... oh well. I may try to offer some form of grouping in the future, but the grouping defeats the “list order = display order” design, and I'm not willing to auto-sort the list. I want people to be able to control the ordering of the system menu, and have added (as yet non-functional) sorting arrows for that purpose. I also don't have a combined tree+table view widget in higan to try to and group things. But ... we'll see how things go in the future. Another idea is to add a specialty load option that opens up the user's Emulation library path, and lets you pick a gamepak for any system, which would boot the same way as when you drop a gamepak onto the higan executable or main window. So say you almost never play Wonderswan games, this would be a way to play them without them cluttering your system menu list. The “import ROM files” option has been removed. All it does is launch icarus directly. I would rather users become familiar with using icarus. The “load ROM file” option remains. Anyway, this is all still a work in progress, so please give it time and don't overload me with too many suggested changes right now, thanks :3 --- higan/emulator/emulator.hpp | 2 +- higan/gb/system/system.cpp | 4 +- .../configuration/configuration.cpp | 2 + .../presentation/presentation.cpp | 84 +++++++++--------- .../presentation/presentation.hpp | 2 + higan/target-tomoko/program/program.cpp | 1 + higan/target-tomoko/settings/settings.cpp | 5 ++ higan/target-tomoko/settings/settings.hpp | 38 +++++++++ .../settings/system-properties.cpp | 50 +++++++++++ higan/target-tomoko/settings/systems.cpp | 85 +++++++++++++++++++ higan/target-tomoko/tools/tools.cpp | 4 +- hiro/core/core.hpp | 3 + hiro/core/shared.hpp | 2 + hiro/core/widget/combo-edit.cpp | 10 +++ hiro/gtk/widget/combo-edit.cpp | 5 ++ hiro/gtk/widget/combo-edit.hpp | 1 + nall/string/markup/node.hpp | 8 +- 17 files changed, 258 insertions(+), 48 deletions(-) create mode 100644 higan/target-tomoko/settings/system-properties.cpp create mode 100644 higan/target-tomoko/settings/systems.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 9e8fdbee..fb166825 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.14"; + static const string Version = "106.15"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp index a9302192..b02e3457 100644 --- a/higan/gb/system/system.cpp +++ b/higan/gb/system/system.cpp @@ -57,8 +57,8 @@ auto System::load(Emulator::Interface* interface, Model model_, maybe syst } else return false; auto document = BML::unserialize(information.manifest); - if(auto name = document["game/memory[1]/name"].text()) { - if(auto fp = platform->open(systemID(), name, File::Read, File::Required)) { + if(auto memory = Emulator::Game::Memory{document["game/board/memory(type=ROM,content=Boot,architecture=LR35902)"]}) { + if(auto fp = platform->open(systemID(), memory.name(), File::Read, File::Required)) { fp->read(bootROM.sgb, 256); } } diff --git a/higan/target-tomoko/configuration/configuration.cpp b/higan/target-tomoko/configuration/configuration.cpp index a7220038..e67efc1a 100644 --- a/higan/target-tomoko/configuration/configuration.cpp +++ b/higan/target-tomoko/configuration/configuration.cpp @@ -59,6 +59,8 @@ Settings::Settings() { set("Emulation/AutoSaveMemory/Enable", true); set("Emulation/AutoSaveMemory/Interval", 30); + set("Systems", ""); + set("Crashed", false); } diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index 423d1835..f89a1183 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -6,42 +6,9 @@ unique_pointer presentation; Presentation::Presentation() { presentation = this; - libraryMenu.setText("Library"); - string_vector manufacturers; - for(auto& emulator : program->emulators) { - if(!manufacturers.find(emulator->information.manufacturer)) { - manufacturers.append(emulator->information.manufacturer); - } - } - for(auto& manufacturer : manufacturers) { - Menu manufacturerMenu{&libraryMenu}; - manufacturerMenu.setText(manufacturer); - for(auto& emulator : program->emulators) { - if(emulator->information.manufacturer != manufacturer) continue; - for(auto& medium : emulator->media) { - auto item = new MenuItem{&manufacturerMenu}; - item->setText({medium.name, " ..."}).onActivate([=] { - program->loadMedium(*emulator, medium); - }); - } - } - } - //add icarus menu options -- but only if icarus binary is present - if(execute("icarus", "--name").output.strip() == "icarus") { - libraryMenu.append(MenuSeparator()); - libraryMenu.append(MenuItem().setText("Load ROM File ...").onActivate([&] { - audio->clear(); - if(auto location = execute("icarus", "--import")) { - program->mediumQueue.append(location.output.strip()); - program->loadMedium(); - } - })); - libraryMenu.append(MenuItem().setText("Import ROM Files ...").onActivate([&] { - invoke("icarus"); - })); - } + libraryMenu.setText("System"); - systemMenu.setText("System").setVisible(false); + systemMenu.setVisible(false); resetSystem.setText("Soft Reset").onActivate([&] { program->softReset(); }); powerSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); }); unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); }); @@ -100,8 +67,9 @@ Presentation::Presentation() { statusBar.setVisible(showStatusBar.checked()); if(visible()) resizeViewport(); }); - showVideoSettings.setText("Video ...").onActivate([&] { settingsManager->show(0); }); - showAudioSettings.setText("Audio ...").onActivate([&] { settingsManager->show(1); }); + showSystemSettings.setText("Systems ...").onActivate([&] { settingsManager->show(0); }); + showVideoSettings.setText("Video ...").onActivate([&] { settingsManager->show(1); }); + showAudioSettings.setText("Audio ...").onActivate([&] { settingsManager->show(2); }); showInputSettings.setText("Input ...").onActivate([&] { if(emulator) { //default input panel to current core's input settings @@ -113,10 +81,10 @@ Presentation::Presentation() { } } } - settingsManager->show(2); + settingsManager->show(3); }); - showHotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsManager->show(3); }); - showAdvancedSettings.setText("Advanced ...").onActivate([&] { settingsManager->show(4); }); + showHotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsManager->show(4); }); + showAdvancedSettings.setText("Advanced ...").onActivate([&] { settingsManager->show(5); }); toolsMenu.setText("Tools").setVisible(false); saveQuickStateMenu.setText("Save Quick State"); @@ -335,6 +303,42 @@ auto Presentation::toggleFullScreen() -> void { resizeViewport(); } +auto Presentation::loadSystems() -> void { + libraryMenu.reset(); + for(auto system : settings.find("Systems/System")) { + if(system["Hidden"].boolean()) continue; + MenuItem item; + string boot = system["Boot"].text(); + item.setText({system["Name"].text(), " ..."}).onActivate([=] { + bool booted = false; + for(auto& emulator : program->emulators) { + if(boot == emulator->information.name) { + program->loadMedium(*emulator, emulator->media(0)); + booted = true; + break; + } + } + if(!booted && directory::exists(boot)) { + program->mediumQueue.append(boot); + program->loadMedium(); + } + }); + libraryMenu.append(item); + } + + //add icarus menu option -- but only if icarus binary is present + if(execute("icarus", "--name").output.strip() == "icarus") { + libraryMenu.append(MenuSeparator()); + libraryMenu.append(MenuItem().setText("Load ROM File ...").onActivate([&] { + audio->clear(); + if(auto location = execute("icarus", "--import")) { + program->mediumQueue.append(location.output.strip()); + program->loadMedium(); + } + })); + } +} + auto Presentation::loadShaders() -> void { auto pathname = locate("Video Shaders/"); diff --git a/higan/target-tomoko/presentation/presentation.hpp b/higan/target-tomoko/presentation/presentation.hpp index 9557623d..f790818c 100644 --- a/higan/target-tomoko/presentation/presentation.hpp +++ b/higan/target-tomoko/presentation/presentation.hpp @@ -14,6 +14,7 @@ struct Presentation : Window { auto clearViewport() -> void; auto resizeViewport(bool resizeWindow = true) -> void; auto toggleFullScreen() -> void; + auto loadSystems() -> void; auto loadShaders() -> void; MenuBar menuBar{this}; @@ -45,6 +46,7 @@ struct Presentation : Window { MenuCheckItem muteAudio{&settingsMenu}; MenuCheckItem showStatusBar{&settingsMenu}; MenuSeparator settingsSeparator{&settingsMenu}; + MenuItem showSystemSettings{&settingsMenu}; MenuItem showVideoSettings{&settingsMenu}; MenuItem showAudioSettings{&settingsMenu}; MenuItem showInputSettings{&settingsMenu}; diff --git a/higan/target-tomoko/program/program.cpp b/higan/target-tomoko/program/program.cpp index 76554146..a25b4c23 100644 --- a/higan/target-tomoko/program/program.cpp +++ b/higan/target-tomoko/program/program.cpp @@ -51,6 +51,7 @@ Program::Program(string_vector args) { settings.save(); new InputManager; + new SystemProperties; new SettingsManager; new CheatDatabase; new ToolsManager; diff --git a/higan/target-tomoko/settings/settings.cpp b/higan/target-tomoko/settings/settings.cpp index de6fb420..f8bfaa12 100644 --- a/higan/target-tomoko/settings/settings.cpp +++ b/higan/target-tomoko/settings/settings.cpp @@ -1,4 +1,9 @@ #include "../tomoko.hpp" + +#include "system-properties.cpp" +unique_pointer systemProperties; + +#include "systems.cpp" #include "video.cpp" #include "audio.cpp" #include "input.cpp" diff --git a/higan/target-tomoko/settings/settings.hpp b/higan/target-tomoko/settings/settings.hpp index 19c61135..e3092186 100644 --- a/higan/target-tomoko/settings/settings.hpp +++ b/higan/target-tomoko/settings/settings.hpp @@ -1,3 +1,39 @@ +struct SystemProperties : Window { + SystemProperties(); + auto append() -> void; + auto modify(Markup::Node) -> void; + + VerticalLayout layout{this}; + HorizontalLayout nameLayout{&layout, Size{~0, 0}}; + Label nameLabel{&nameLayout, Size{40, 0}}; + LineEdit nameEdit{&nameLayout, Size{~0, 0}}; + HorizontalLayout bootLayout{&layout, Size{~0, 0}}; + Label bootLabel{&bootLayout, Size{40, 0}}; + ComboEdit bootEdit{&bootLayout, Size{~0, 0}}; + Button bootBrowse{&bootLayout, Size{80, 0}}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + Widget spacer{&controlLayout, Size{40, 0}}; + CheckLabel hiddenOption{&controlLayout, Size{~0, 0}}; + Button acceptButton{&controlLayout, Size{80, 0}}; + Button cancelButton{&controlLayout, Size{80, 0}}; +}; + +struct SystemSettings : TabFrameItem { + SystemSettings(TabFrame*); + auto reload() -> void; + auto acceptProperties() -> void; + + VerticalLayout layout{this}; + TableView systemList{&layout, Size{~0, ~0}}; + HorizontalLayout controlLayout{&layout, Size{~0, 0}}; + Button upButton{&controlLayout, Size{0, 0}}; + Button downButton{&controlLayout, Size{0, 0}}; + Widget spacer{&controlLayout, Size{~0, 0}}; + Button appendButton{&controlLayout, Size{80, 0}}; + Button modifyButton{&controlLayout, Size{80, 0}}; + Button removeButton{&controlLayout, Size{80, 0}}; +}; + struct VideoSettings : TabFrameItem { VideoSettings(TabFrame*); @@ -150,6 +186,7 @@ struct SettingsManager : Window { VerticalLayout layout{this}; TabFrame panel{&layout, Size{~0, ~0}}; + SystemSettings systems{&panel}; VideoSettings video{&panel}; AudioSettings audio{&panel}; InputSettings input{&panel}; @@ -161,4 +198,5 @@ struct SettingsManager : Window { auto show(uint setting) -> void; }; +extern unique_pointer systemProperties; extern unique_pointer settingsManager; diff --git a/higan/target-tomoko/settings/system-properties.cpp b/higan/target-tomoko/settings/system-properties.cpp new file mode 100644 index 00000000..b6fa54dc --- /dev/null +++ b/higan/target-tomoko/settings/system-properties.cpp @@ -0,0 +1,50 @@ +SystemProperties::SystemProperties() { + systemProperties = this; + + layout.setMargin(5); + nameLabel.setText("Name:"); + bootLabel.setText("Boot:"); + bootEdit.setEditable(false); + for(auto& emulator : program->emulators) { + bootEdit.append(ComboEditItem().setText(emulator->information.name)); + } + bootBrowse.setText("Browse ...").onActivate([&] { + if(auto location = BrowserDialog().setTitle("Select Boot Game").setPath(settings["Library/Location"].text()).selectFolder()) { + bootEdit.setText(location); + } + }); + hiddenOption.setText("Hidden"); + acceptButton.onActivate([&] { + setVisible(false); + settingsManager->systems.acceptProperties(); + }); + cancelButton.setText("Cancel").onActivate([&] { + setVisible(false); + }); + + setTitle("System Properties"); + setSize({480, layout.minimumSize().height()}); + setDismissable(); +} + +auto SystemProperties::append() -> void { + setCentered(*settingsManager); + nameEdit.setText(""); + bootEdit.setText(""); + hiddenOption.setChecked(false); + acceptButton.setText("Append"); + setFocused(); + setVisible(); + nameEdit.setFocused(); +} + +auto SystemProperties::modify(Markup::Node system) -> void { + setCentered(*settingsManager); + nameEdit.setText(system["Name"].text()); + bootEdit.setText(system["Boot"].text()); + hiddenOption.setChecked(system["Hidden"].boolean()); + acceptButton.setText("Modify"); + setFocused(); + setVisible(); + nameEdit.setFocused(); +} diff --git a/higan/target-tomoko/settings/systems.cpp b/higan/target-tomoko/settings/systems.cpp new file mode 100644 index 00000000..278fe597 --- /dev/null +++ b/higan/target-tomoko/settings/systems.cpp @@ -0,0 +1,85 @@ +SystemSettings::SystemSettings(TabFrame* parent) : TabFrameItem(parent) { + setIcon(Icon::Device::Storage); + setText("Systems"); + + layout.setMargin(5); + + systemList.onActivate([&] { + modifyButton.doActivate(); + }); + + systemList.onChange([&] { + auto selected = (bool)systemList.selected(); + upButton.setEnabled(selected); + downButton.setEnabled(selected); + modifyButton.setEnabled(selected); + removeButton.setEnabled(selected); + }); + + upButton.setIcon(Icon::Go::Up); + downButton.setIcon(Icon::Go::Down); + + appendButton.setText("Append").onActivate([&] { + systemProperties->append(); + }); + + modifyButton.setText("Modify").onActivate([&] { + if(auto item = systemList.selected()) { + if(auto system = settings.find("Systems/System")[item.offset()]) { + systemProperties->modify(system); + } + } + }); + + removeButton.setText("Remove").onActivate([&] { + if(auto item = systemList.selected()) { + if(auto system = settings.find("Systems/System")[item.offset()]) { + if(MessageDialog().setParent(*settingsManager).setText({ + "Are you sure you want to delete this system?\n\n" + "Name: ", system["Name"].text() + }).question() == "Yes") { + settings["Systems"].remove(system); + reload(); + } + } + } + }); + + reload(); +} + +auto SystemSettings::reload() -> void { + systemList.reset(); + systemList.append(TableViewHeader().setVisible() + .append(TableViewColumn().setText("Name")) + .append(TableViewColumn().setText("Boot").setExpandable()) + ); + for(auto system : settings.find("Systems/System")) { + systemList.append(TableViewItem() + .append(TableViewCell().setText(system["Name"].text())) + .append(TableViewCell().setText(Location::base(system["Boot"].text()).trimRight("/", 1L))) + .setForegroundColor(system["Hidden"].boolean() ? Color{160, 160, 160} : Color{}) + ); + } + systemList.resizeColumns().doChange(); + presentation->loadSystems(); +} + +auto SystemSettings::acceptProperties() -> void { + if(systemProperties->acceptButton.text() == "Append") { + Markup::Node system{"System"}; + system.append({"Name", systemProperties->nameEdit.text()}); + system.append({"Boot", systemProperties->bootEdit.text()}); + system.append({"Hidden", systemProperties->hiddenOption.checked()}); + settings["Systems"].append(system); + } else if(systemProperties->acceptButton.text() == "Modify") { + if(auto item = systemList.selected()) { + if(auto system = settings.find("Systems/System")[item.offset()]) { + system("Name").setValue(systemProperties->nameEdit.text()); + system("Boot").setValue(systemProperties->bootEdit.text()); + system("Hidden").setValue(systemProperties->hiddenOption.checked()); + } + } + } + reload(); +} diff --git a/higan/target-tomoko/tools/tools.cpp b/higan/target-tomoko/tools/tools.cpp index 62b73af1..f9cba80e 100644 --- a/higan/target-tomoko/tools/tools.cpp +++ b/higan/target-tomoko/tools/tools.cpp @@ -1,10 +1,12 @@ #include "../tomoko.hpp" + #include "cheat-database.cpp" +unique_pointer cheatDatabase; + #include "cheat-editor.cpp" #include "state-manager.cpp" #include "manifest-viewer.cpp" #include "game-notes.cpp" -unique_pointer cheatDatabase; unique_pointer toolsManager; ToolsManager::ToolsManager() { diff --git a/hiro/core/core.hpp b/hiro/core/core.hpp index 97073687..0a6c627b 100644 --- a/hiro/core/core.hpp +++ b/hiro/core/core.hpp @@ -1144,6 +1144,7 @@ struct mComboEdit : mWidget { auto backgroundColor() const -> Color; auto doActivate() const -> void; auto doChange() const -> void; + auto editable() const -> bool; auto foregroundColor() const -> Color; auto item(uint position) const -> ComboEditItem; auto itemCount() const -> uint; @@ -1153,6 +1154,7 @@ struct mComboEdit : mWidget { auto remove(sComboEditItem item) -> type&; auto reset() -> type&; auto setBackgroundColor(Color color = {}) -> type&; + auto setEditable(bool editable = true) -> type&; auto setForegroundColor(Color color = {}) -> type&; auto setParent(mObject* parent = nullptr, int offset = -1) -> type& override; auto setText(const string& text = "") -> type&; @@ -1161,6 +1163,7 @@ struct mComboEdit : mWidget { //private: struct State { Color backgroundColor; + bool editable = true; Color foregroundColor; vector items; function onActivate; diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index 2dcec6f1..1b2fe228 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -342,6 +342,7 @@ struct ComboEdit : sComboEdit { auto backgroundColor() const { return self().backgroundColor(); } auto doActivate() const { return self().doActivate(); } auto doChange() const { return self().doChange(); } + auto editable() const { return self().editable(); } auto foregroundColor() const { return self().foregroundColor(); } auto item(uint position) const { return self().item(position); } auto itemCount() const { return self().itemCount(); } @@ -351,6 +352,7 @@ struct ComboEdit : sComboEdit { auto remove(sComboEditItem item) { return self().remove(item), *this; } auto reset() { return self().reset(), *this; } auto setBackgroundColor(Color color = {}) { return self().setBackgroundColor(color), *this; } + auto setEditable(bool editable = true) { return self().setEditable(editable), *this; } auto setForegroundColor(Color color = {}) { return self().setForegroundColor(color), *this; } auto setText(const string& text = "") { return self().setText(text), *this; } auto text() const { return self().text(); } diff --git a/hiro/core/widget/combo-edit.cpp b/hiro/core/widget/combo-edit.cpp index 1071cd00..1a457c2c 100644 --- a/hiro/core/widget/combo-edit.cpp +++ b/hiro/core/widget/combo-edit.cpp @@ -29,6 +29,10 @@ auto mComboEdit::doChange() const -> void { if(state.onChange) return state.onChange(); } +auto mComboEdit::editable() const -> bool { + return state.editable; +} + auto mComboEdit::foregroundColor() const -> Color { return state.foregroundColor; } @@ -81,6 +85,12 @@ auto mComboEdit::setBackgroundColor(Color color) -> type& { return *this; } +auto mComboEdit::setEditable(bool editable) -> type& { + state.editable = editable; + signal(setEditable, editable); + return *this; +} + auto mComboEdit::setForegroundColor(Color color) -> type& { state.foregroundColor = color; signal(setForegroundColor, color); diff --git a/hiro/gtk/widget/combo-edit.cpp b/hiro/gtk/widget/combo-edit.cpp index 49fe7551..f90dae4f 100644 --- a/hiro/gtk/widget/combo-edit.cpp +++ b/hiro/gtk/widget/combo-edit.cpp @@ -32,6 +32,7 @@ auto pComboEdit::construct() -> void { close(stdErr); setBackgroundColor(state().backgroundColor); + setEditable(state().editable); setForegroundColor(state().foregroundColor); for(auto& item : state().items) append(item); @@ -86,6 +87,10 @@ auto pComboEdit::setBackgroundColor(Color color) -> void { gtk_widget_modify_base(gtk_bin_get_child(GTK_BIN(gtkComboBox)), GTK_STATE_NORMAL, color ? &gdkColor : nullptr); } +auto pComboEdit::setEditable(bool editable) -> void { + gtk_editable_set_editable(GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(gtkComboBox))), editable); +} + auto pComboEdit::setForegroundColor(Color color) -> void { GdkColor gdkColor = CreateColor(color); gtk_widget_modify_text(gtk_bin_get_child(GTK_BIN(gtkComboBox)), GTK_STATE_NORMAL, color ? &gdkColor : nullptr); diff --git a/hiro/gtk/widget/combo-edit.hpp b/hiro/gtk/widget/combo-edit.hpp index 78808bbc..f5d48116 100644 --- a/hiro/gtk/widget/combo-edit.hpp +++ b/hiro/gtk/widget/combo-edit.hpp @@ -10,6 +10,7 @@ struct pComboEdit : pWidget { auto remove(sComboEditItem item) -> void; auto reset() -> void; auto setBackgroundColor(Color color) -> void; + auto setEditable(bool editable) -> void; auto setForegroundColor(Color color) -> void; auto setFont(const Font& font) -> void override; auto setText(const string& text) -> void; diff --git a/nall/string/markup/node.hpp b/nall/string/markup/node.hpp index c29b8d50..fdf95973 100644 --- a/nall/string/markup/node.hpp +++ b/nall/string/markup/node.hpp @@ -8,8 +8,8 @@ using SharedNode = shared_pointer; struct ManagedNode { ManagedNode() = default; - explicit ManagedNode(const string& name) : _name(name) {} - explicit ManagedNode(const string& name, const string& value) : _name(name), _value(value) {} + ManagedNode(const string& name) : _name(name) {} + ManagedNode(const string& name, const string& value) : _name(name), _value(value) {} auto clone() const -> SharedNode { SharedNode clone{new ManagedNode(_name, _value)}; @@ -46,8 +46,8 @@ protected: struct Node { Node() : shared(new ManagedNode) {} Node(const SharedNode& source) : shared(source ? source : new ManagedNode) {} - explicit Node(const string& name) : shared(new ManagedNode(name)) {} - explicit Node(const string& name, const string& value) : shared(new ManagedNode(name, value)) {} + Node(const string& name) : shared(new ManagedNode(name)) {} + Node(const string& name, const string& value) : shared(new ManagedNode(name, value)) {} auto unique() const -> bool { return shared.unique(); } auto clone() const -> Node { return shared->clone(); }