diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 06658f28..d51360eb 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "094.22"; + static const char Version[] = "094.23"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 1cc98bac..c01090dd 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -6,6 +6,7 @@ struct BrowserDialogWindow { auto activate() -> void; auto change() -> void; auto isFolder(const string& name) -> bool; + auto isMatch(const string& name) -> bool; auto run() -> lstring; auto setPath(string path) -> void; @@ -25,6 +26,7 @@ private: Button cancelButton{&controlLayout, Size{80, 0}, 8}; BrowserDialog::State& state; + vector filters; }; //accept button clicked, or enter pressed on file name line edit @@ -45,12 +47,18 @@ auto BrowserDialogWindow::accept() -> void { } } + if(state.action == "openFolder" && selectedItems) { + string name = selectedItems.first()->text(0); + if(!isMatch(name)) return setPath({state.path, name}); + state.response.append(string{state.path, name, "/"}); + } + if(state.action == "saveFile") { string name = fileName.text(); if(!name && selectedItems) name = selectedItems.first()->text(0); if(!name || isFolder(name)) return; if(file::exists({state.path, name})) { - if(MessageDialog("File already exists; overwrite it?").question() != 0) return; + if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; } state.response.append(string{state.path, name}); } @@ -66,15 +74,18 @@ auto BrowserDialogWindow::accept() -> void { //list view item double-clicked, or enter pressed on selected list view item auto BrowserDialogWindow::activate() -> void { auto selectedItem = view.selected(); + if(state.action == "saveFile" && selectedItem) { string name = selectedItem->text(0); if(isFolder(name)) return setPath({state.path, name}); - fileName.setText(isFolder(name) ? "" : name); + fileName.setText(name); } + if(state.action == "selectFolder" && selectedItem) { string name = selectedItem->text(0); if(isFolder(name)) return setPath({state.path, name}); } + accept(); } @@ -93,34 +104,41 @@ auto BrowserDialogWindow::isFolder(const string& name) -> bool { return directory::exists({state.path, name}); } +auto BrowserDialogWindow::isMatch(const string& name) -> bool { + if(auto selectedItem = filterList.selected()) { + for(auto& filter : filters[selectedItem->offset()]) { + if(name.match(filter)) return true; + } + } + return false; +} + auto BrowserDialogWindow::run() -> lstring { state.response.reset(); layout.setMargin(8); pathName.onActivate([&] { setPath(pathName.text()); }); - pathHome.onActivate([&] { setPath(userpath()); }); - pathHome.setBordered(false).setIcon(Icon::Go::Home); - pathRefresh.onActivate([&] { setPath(state.path); }); - pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh); - pathUp.onActivate([&] { setPath(state.path.dirname()); }); - pathUp.setBordered(false).setIcon(Icon::Go::Up); - view.onActivate([&] { activate(); }); - view.onChange([&] { change(); }); - view.setMultiSelect(state.action == "openFiles"); - filterList.onChange([&] { setPath(state.path); }); + pathHome.setBordered(false).setIcon(Icon::Go::Home).onActivate([&] { setPath(userpath()); }); + pathRefresh.setBordered(false).setIcon(Icon::Action::Refresh).onActivate([&] { setPath(state.path); }); + pathUp.setBordered(false).setIcon(Icon::Go::Up).onActivate([&] { setPath(state.path.dirname()); }); + view.setMultiSelect(state.action == "openFiles").onActivate([&] { activate(); }).onChange([&] { change(); }); + filterList.setVisible(state.action != "selectFolder").onChange([&] { setPath(state.path); }); for(auto& filter : state.filters) { auto part = filter.split<1>("|"); filterList.append(ComboButtonItem().setText(part.first())); } - filterList.setVisible(state.action != "selectFolder"); - fileName.onActivate([&] { accept(); }); - fileName.setVisible(state.action == "saveFile"); + fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }); acceptButton.onActivate([&] { accept(); }); - if(state.action == "openFile" || state.action == "openFiles") acceptButton.setText("Open"); + if(state.action == "openFile" || state.action == "openFiles" || state.action == "openFolder") acceptButton.setText("Open"); if(state.action == "saveFile") acceptButton.setText("Save"); if(state.action == "selectFolder") acceptButton.setText("Select"); - cancelButton.onActivate([&] { window.setModal(false); }); - cancelButton.setText("Cancel"); + cancelButton.setText("Cancel").onActivate([&] { window.setModal(false); }); + + if(!state.filters) state.filters.append("All|*"); + for(auto& filter : state.filters) { + auto part = filter.split<1>("|"); + filters.append(part.last().split(":")); + } setPath(state.path); @@ -146,30 +164,30 @@ auto BrowserDialogWindow::setPath(string path) -> void { view.append(ListViewColumn().setWidth(~0)); view.append(ListViewColumn().setWidth( 0).setForegroundColor({192, 128, 128})); - for(auto& folder : directory::folders(path)) { + auto contents = directory::contents(path); + bool folderMode = state.action == "openFolder"; + + for(auto content : contents) { + if(!content.endsWith("/")) continue; + if(folderMode && isMatch(content.rtrim("/"))) continue; + ListViewItem item{&view}; item.setIcon(0, Icon::Emblem::Folder); - item.setText(0, folder.rtrim("/")); - item.setText(1, octal<3>(storage::mode({path, folder}) & 0777)); + item.setText(0, content.rtrim("/")); + item.setText(1, octal<3>(storage::mode({path, content}) & 0777)); } - if(state.action != "selectFolder") { //don't show files during folder selection - string filter = "*"; - if(auto selected = filterList.selected()) { - auto part = state.filters[selected->offset()].split<1>("|"); - filter = part.last(); - } + for(auto content : contents) { + if(content.endsWith("/") && !folderMode) continue; + if(!isMatch(content.rtrim("/"))) continue; - for(auto& file : directory::files(path)) { - if(!file.match(filter)) continue; - ListViewItem item{&view}; - item.setIcon(0, Icon::Emblem::File); - item.setText(0, file); - item.setText(1, octal<3>(storage::mode({path, file}) & 0777)); - } + ListViewItem item{&view}; + item.setIcon(0, folderMode ? Icon::Action::Open : Icon::Emblem::File); + item.setText(0, content.rtrim("/")); + item.setText(1, octal<3>(storage::mode({path, content}) & 0777)); } - if(view.items()) view.setSelected({0}); + if(view.items()) view.item(0)->setSelected(); Application::processEvents(); view.resizeColumns().setFocused().doChange(); } @@ -191,7 +209,14 @@ auto BrowserDialog::openFiles() -> lstring { if(!state.title) state.title = "Open Files"; if(auto result = _run()) return result; return {}; -}; +} + +auto BrowserDialog::openFolder() -> string { + state.action = "openFolder"; + if(!state.title) state.title = "Open Folder"; + if(auto result = _run()) return result.first(); + return {}; +} auto BrowserDialog::saveFile() -> string { state.action = "saveFile"; @@ -212,7 +237,7 @@ auto BrowserDialog::setFilters(const lstring& filters) -> type& { return *this; } -auto BrowserDialog::setParent(const shared_pointer& parent) -> type& { +auto BrowserDialog::setParent(const sWindow& parent) -> type& { state.parent = parent; return *this; } diff --git a/hiro/extension/browser-dialog.hpp b/hiro/extension/browser-dialog.hpp index 0f86b128..dee02878 100644 --- a/hiro/extension/browser-dialog.hpp +++ b/hiro/extension/browser-dialog.hpp @@ -6,26 +6,27 @@ struct BrowserDialog { using type = BrowserDialog; BrowserDialog(); - auto openFile() -> nall::string; //one existing file - auto openFiles() -> nall::lstring; //any existing files or folders - auto saveFile() -> nall::string; //one file - auto selectFolder() -> nall::string; //one existing folder - auto setFilters(const nall::lstring& filters = {"All|*"}) -> type&; - auto setParent(const nall::shared_pointer& parent) -> type&; - auto setPath(const nall::string& path = "") -> type&; - auto setTitle(const nall::string& title = "") -> type&; + auto openFile() -> string; //one existing file + auto openFiles() -> lstring; //any existing files or folders + auto openFolder() -> string; //one existing folder + auto saveFile() -> string; //one file + auto selectFolder() -> string; //one existing folder + auto setFilters(const lstring& filters = {}) -> type&; + auto setParent(const sWindow& parent) -> type&; + auto setPath(const string& path = "") -> type&; + auto setTitle(const string& title = "") -> type&; private: struct State { - nall::string action; - nall::lstring filters = {"*"}; - nall::shared_pointer parent; - nall::string path; - nall::lstring response; - nall::string title; + string action; + lstring filters = {"*"}; + sWindow parent; + string path; + lstring response; + string title; } state; - auto _run() -> nall::lstring; + auto _run() -> lstring; friend class BrowserDialogWindow; }; diff --git a/hiro/extension/message-dialog.cpp b/hiro/extension/message-dialog.cpp index e936bd82..3f180dc0 100644 --- a/hiro/extension/message-dialog.cpp +++ b/hiro/extension/message-dialog.cpp @@ -4,19 +4,19 @@ MessageDialog::MessageDialog(const string& text) { state.text = text; } -auto MessageDialog::error(const lstring& buttons) -> signed { +auto MessageDialog::error(const lstring& buttons) -> string { state.buttons = buttons; state.icon = Icon::Prompt::Error; return _run(); } -auto MessageDialog::information(const lstring& buttons) -> signed { +auto MessageDialog::information(const lstring& buttons) -> string { state.buttons = buttons; state.icon = Icon::Prompt::Information; return _run(); } -auto MessageDialog::question(const lstring& buttons) -> signed { +auto MessageDialog::question(const lstring& buttons) -> string { state.buttons = buttons; state.icon = Icon::Prompt::Question; return _run(); @@ -37,13 +37,13 @@ auto MessageDialog::setTitle(const string& title) -> type& { return *this; } -auto MessageDialog::warning(const lstring& buttons) -> signed { +auto MessageDialog::warning(const lstring& buttons) -> string { state.buttons = buttons; state.icon = Icon::Prompt::Warning; return _run(); } -auto MessageDialog::_run() -> signed { +auto MessageDialog::_run() -> string { Window window; VerticalLayout layout{&window}; HorizontalLayout messageLayout{&layout, Size{~0, 0}, 8}; @@ -57,7 +57,7 @@ auto MessageDialog::_run() -> signed { messageText.setText(state.text); for(auto n : range(state.buttons)) { Button button{&controlLayout, Size{80, 0}, 8}; - button.onActivate([&, n] { state.response = n; window.setModal(false); }); + button.onActivate([&, n] { state.response = state.buttons[n]; window.setModal(false); }); button.setText(state.buttons[n]); button.setFocused(); //the last button will have effective focus } @@ -66,7 +66,7 @@ auto MessageDialog::_run() -> signed { signed widthButtons = 8 + state.buttons.size() * 88; signed width = max(320, widthMessage, widthButtons); - window.onClose([&] { state.response = -1; window.setModal(false); }); + window.onClose([&] { window.setModal(false); }); window.setTitle(state.title); window.setResizable(false); window.setSize({width, layout.minimumSize().height()}); diff --git a/hiro/extension/message-dialog.hpp b/hiro/extension/message-dialog.hpp index b1b9006e..64f845a1 100644 --- a/hiro/extension/message-dialog.hpp +++ b/hiro/extension/message-dialog.hpp @@ -3,26 +3,26 @@ struct MessageDialog { using type = MessageDialog; - MessageDialog(const nall::string& text = ""); - auto error(const nall::lstring& buttons = {"Ok"}) -> signed; - auto information(const nall::lstring& buttons = {"Ok"}) -> signed; - auto question(const nall::lstring& buttons = {"Yes", "No"}) -> signed; - auto setParent(nall::shared_pointer parent = {}) -> type&; - auto setText(const nall::string& text = "") -> type&; - auto setTitle(const nall::string& title = "") -> type&; - auto warning(const nall::lstring& buttons = {"Ok"}) -> signed; + MessageDialog(const string& text = ""); + auto error(const lstring& buttons = {"Ok"}) -> string; + auto information(const lstring& buttons = {"Ok"}) -> string; + auto question(const lstring& buttons = {"Yes", "No"}) -> string; + auto setParent(sWindow parent = {}) -> type&; + auto setText(const string& text = "") -> type&; + auto setTitle(const string& title = "") -> type&; + auto warning(const lstring& buttons = {"Ok"}) -> string; private: struct State { - nall::lstring buttons; - nall::vector icon; - nall::shared_pointer parent; - signed response = -1; - nall::string text; - nall::string title; + lstring buttons; + vector icon; + sWindow parent; + string response; + string text; + string title; } state; - auto _run() -> signed; + auto _run() -> string; }; #endif diff --git a/nall/any.hpp b/nall/any.hpp index 8d6b638a..cbdad800 100644 --- a/nall/any.hpp +++ b/nall/any.hpp @@ -7,15 +7,36 @@ namespace nall { struct any { - bool empty() const { return container; } - void reset() { if(container) { delete container; container = nullptr; } } + any() = default; + any(const any& source) { operator=(source); } + any(any&& source) { operator=(move(source)); } + template any(const T& value) { operator=(value); } + ~any() { reset(); } - const std::type_info& type() const { + explicit operator bool() const { return container; } + auto empty() const -> bool { return !container; } + auto reset() -> void { if(container) { delete container; container = nullptr; } } + + auto type() const -> const std::type_info& { return container ? container->type() : typeid(void); } - template any& operator=(const T& value) { - using auto_t = type_if, typename std::remove_extent::type>::type*, T>; + template auto is() const -> bool { + return type() == typeid(typename remove_reference::type); + } + + template auto get() -> T& { + if(!is()) throw; + return static_cast::type>*>(container)->value; + } + + template auto get() const -> const T& { + if(!is()) throw; + return static_cast::type>*>(container)->value; + } + + template auto operator=(const T& value) -> any& { + using auto_t = type_if, typename remove_extent::type>::type*, T>; if(type() == typeid(auto_t)) { static_cast*>(container)->value = (auto_t)value; @@ -27,68 +48,35 @@ struct any { return *this; } - any& operator=(const any& source) { + auto operator=(const any& source) -> any& { if(container) { delete container; container = nullptr; } if(source.container) container = source.container->copy(); return *this; } - any& operator=(any&& source) { + auto operator=(any&& source) -> any& { if(container) delete container; container = source.container; source.container = nullptr; return *this; } - any() = default; - any(const any& source) { operator=(source); } - any(any&& source) { operator=(move(source)); } - template any(const T& value) { operator=(value); } - ~any() { reset(); } - private: struct placeholder { - virtual const std::type_info& type() const = 0; - virtual placeholder* copy() const = 0; - virtual ~placeholder() {} + virtual ~placeholder() = default; + virtual auto type() const -> const std::type_info& = 0; + virtual auto copy() const -> placeholder* = 0; }; placeholder* container = nullptr; template struct holder : placeholder { - T value; - const std::type_info& type() const { return typeid(T); } - placeholder* copy() const { return new holder(value); } holder(const T& value) : value(value) {} + auto type() const -> const std::type_info& { return typeid(T); } + auto copy() const -> placeholder* { return new holder(value); } + T value; }; - - template friend T any_cast(any&); - template friend T any_cast(const any&); - template friend T* any_cast(any*); - template friend const T* any_cast(const any*); }; -template T any_cast(any& value) { - typedef typename std::remove_reference::type nonref; - if(value.type() != typeid(nonref)) throw; - return static_cast*>(value.container)->value; -} - -template T any_cast(const any& value) { - typedef const typename std::remove_reference::type nonref; - if(value.type() != typeid(nonref)) throw; - return static_cast*>(value.container)->value; -} - -template T* any_cast(any* value) { - if(!value || value->type() != typeid(T)) return nullptr; - return &static_cast*>(value->container)->value; -} - -template const T* any_cast(const any* value) { - if(!value || value->type() != typeid(T)) return nullptr; - return &static_cast*>(value->container)->value; -} - } #endif diff --git a/nall/traits.hpp b/nall/traits.hpp index 039bb988..a64f80b8 100644 --- a/nall/traits.hpp +++ b/nall/traits.hpp @@ -19,6 +19,9 @@ namespace nall { template using is_array = std::is_array; template using is_function = std::is_function; template using is_integral = std::is_integral; + template using add_const = std::add_const; + template using remove_extent = std::remove_extent; + template using remove_reference = std::remove_reference; } namespace nall { diff --git a/ruby/audio/openal.cpp b/ruby/audio/openal.cpp index b066b99a..d4275a58 100644 --- a/ruby/audio/openal.cpp +++ b/ruby/audio/openal.cpp @@ -10,26 +10,30 @@ namespace ruby { struct pAudioOpenAL { struct { - ALCdevice* handle; - ALCcontext* context; - ALuint source; - ALenum format; - unsigned latency; - unsigned queueLength; + ALCdevice* handle = nullptr; + ALCcontext* context = nullptr; + ALuint source = 0; + ALenum format = AL_FORMAT_STEREO16; + unsigned latency = 0; + unsigned queueLength = 0; } device; struct { - uint32_t* data; - unsigned length; - unsigned size; + uint32_t* data = nullptr; + unsigned length = 0; + unsigned size = 0; } buffer; struct { - bool synchronize; - unsigned frequency; - unsigned latency; + bool synchronize = true; + unsigned frequency = 22050; + unsigned latency = 40; } settings; + ~pAudioOpenAL() { + term(); + } + auto cap(const string& name) -> bool { if(name == Audio::Synchronize) return true; if(name == Audio::Frequency) return true; @@ -41,23 +45,23 @@ struct pAudioOpenAL { if(name == Audio::Synchronize) return settings.synchronize; if(name == Audio::Frequency) return settings.frequency; if(name == Audio::Latency) return settings.latency; - return false; + return {}; } auto set(const string& name, const any& value) -> bool { - if(name == Audio::Synchronize) { - settings.synchronize = any_cast(value); + if(name == Audio::Synchronize && value.is()) { + settings.synchronize = value.get(); return true; } - if(name == Audio::Frequency) { - settings.frequency = any_cast(value); + if(name == Audio::Frequency && value.is()) { + settings.frequency = value.get(); return true; } - if(name == Audio::Latency) { - if(settings.latency != any_cast(value)) { - settings.latency = any_cast(value); + if(name == Audio::Latency && value.is()) { + if(settings.latency != value.get()) { + settings.latency = value.get(); updateLatency(); } return true; @@ -66,8 +70,8 @@ struct pAudioOpenAL { return false; } - auto sample(uint16_t sl, uint16_t sr) -> void { - buffer.data[buffer.length++] = sl + (sr << 16); + auto sample(uint16_t left, uint16_t right) -> void { + buffer.data[buffer.length++] = left << 0 | right << 16; if(buffer.length < buffer.size) return; ALuint albuffer = 0; @@ -171,26 +175,6 @@ struct pAudioOpenAL { } } - pAudioOpenAL() { - device.source = 0; - device.handle = 0; - device.context = 0; - device.format = AL_FORMAT_STEREO16; - device.queueLength = 0; - - buffer.data = 0; - buffer.length = 0; - buffer.size = 0; - - settings.synchronize = true; - settings.frequency = 22050; - settings.latency = 40; - } - - ~pAudioOpenAL() { - term(); - } - private: auto queryDevices() -> lstring { lstring result; diff --git a/ruby/audio/oss.cpp b/ruby/audio/oss.cpp index eb7c3648..f7e4b2ab 100644 --- a/ruby/audio/oss.cpp +++ b/ruby/audio/oss.cpp @@ -48,24 +48,24 @@ struct pAudioOSS { if(name == Audio::Device) return settings.device; if(name == Audio::Synchronize) return settings.synchronize; if(name == Audio::Frequency) return settings.frequency; - return false; + return {}; } auto set(const string& name, const any& value) -> bool { - if(name == Audio::Device) { - settings.device = any_cast(value); + if(name == Audio::Device && value.is()) { + settings.device = value.get(); if(!settings.device) settings.device = "/dev/dsp"; return true; } - if(name == Audio::Synchronize) { - settings.synchronize = any_cast(value); + if(name == Audio::Synchronize && value.is()) { + settings.synchronize = value.get(); updateSynchronization(); return true; } - if(name == Audio::Frequency) { - settings.frequency = any_cast(value); + if(name == Audio::Frequency && value.is()) { + settings.frequency = value.get(); if(device.fd >= 0) init(); return true; } diff --git a/ruby/input/sdl.cpp b/ruby/input/sdl.cpp index fad9af53..d5989511 100644 --- a/ruby/input/sdl.cpp +++ b/ruby/input/sdl.cpp @@ -27,12 +27,12 @@ struct pInputSDL { auto get(const string& name) -> any { if(name == Input::Handle) return (uintptr_t)settings.handle; - return false; + return {}; } auto set(const string& name, const any& value) -> bool { - if(name == Input::Handle) { - settings.handle = any_cast(value); + if(name == Input::Handle && value.is()) { + settings.handle = value.get(); return true; } diff --git a/ruby/input/xlib.cpp b/ruby/input/xlib.cpp index 607ac351..bc15d84f 100644 --- a/ruby/input/xlib.cpp +++ b/ruby/input/xlib.cpp @@ -25,12 +25,12 @@ struct pInputXlib { auto get(const string& name) -> any { if(name == Input::Handle) return (uintptr_t)settings.handle; - return false; + return {}; } auto set(const string& name, const any& value) -> bool { - if(name == Input::Handle) { - settings.handle = any_cast(value); + if(name == Input::Handle && value.is()) { + settings.handle = value.get(); return true; } diff --git a/ruby/video/glx.cpp b/ruby/video/glx.cpp index 3e6ff3db..f69afb7d 100644 --- a/ruby/video/glx.cpp +++ b/ruby/video/glx.cpp @@ -6,31 +6,36 @@ namespace ruby { struct pVideoGLX : OpenGL { - GLXContext (*glXCreateContextAttribs)(Display*, GLXFBConfig, GLXContext, int, const int*) = nullptr; - int (*glXSwapInterval)(int) = nullptr; + auto (*glXCreateContextAttribs)(Display*, GLXFBConfig, GLXContext, signed, const signed*) -> GLXContext = nullptr; + auto (*glXSwapInterval)(signed) -> signed = nullptr; - Display* display; - int screen; - Window xwindow; - Colormap colormap; - GLXContext glxcontext; - GLXWindow glxwindow; + Display* display = nullptr; + signed screen = 0; + Window xwindow = 0; + Colormap colormap = 0; + GLXContext glxcontext = nullptr; + GLXWindow glxwindow = 0; struct { - int version_major, version_minor; - bool double_buffer; - bool is_direct; + signed version_major = 0; + signed version_minor = 0; + bool doubleBuffer = false; + bool isDirect = false; } glx; struct { - Window handle; - bool synchronize; - unsigned depth; - unsigned filter; + Window handle = 0; + bool synchronize = false; + unsigned depth = 24; + unsigned filter = 1; //linear string shader; } settings; - bool cap(const string& name) { + ~pVideoGLX() { + term(); + } + + auto cap(const string& name) -> bool { if(name == Video::Handle) return true; if(name == Video::Synchronize) return true; if(name == Video::Depth) return true; @@ -39,30 +44,31 @@ struct pVideoGLX : OpenGL { return false; } - any get(const string& name) { + auto get(const string& name) -> any { if(name == Video::Handle) return (uintptr_t)settings.handle; if(name == Video::Synchronize) return settings.synchronize; if(name == Video::Depth) return settings.depth; if(name == Video::Filter) return settings.filter; - return false; + if(name == Video::Shader) return settings.shader; + return {}; } - bool set(const string& name, const any& value) { - if(name == Video::Handle) { - settings.handle = any_cast(value); + auto set(const string& name, const any& value) -> bool { + if(name == Video::Handle && value.is()) { + settings.handle = value.get(); return true; } - if(name == Video::Synchronize) { - if(settings.synchronize != any_cast(value)) { - settings.synchronize = any_cast(value); + if(name == Video::Synchronize && value.is()) { + if(settings.synchronize != value.get()) { + settings.synchronize = value.get(); if(glXSwapInterval) glXSwapInterval(settings.synchronize); return true; } } - if(name == Video::Depth) { - unsigned depth = any_cast(value); + if(name == Video::Depth && value.is()) { + unsigned depth = value.get(); if(depth > DefaultDepth(display, screen)) return false; switch(depth) { @@ -75,14 +81,14 @@ struct pVideoGLX : OpenGL { return true; } - if(name == Video::Filter) { - settings.filter = any_cast(value); + if(name == Video::Filter && value.is()) { + settings.filter = value.get(); if(settings.shader.empty()) OpenGL::filter = settings.filter ? GL_LINEAR : GL_NEAREST; return true; } - if(name == Video::Shader) { - settings.shader = any_cast(value); + if(name == Video::Shader && value.is()) { + settings.shader = value.get(); OpenGL::shader(settings.shader); if(settings.shader.empty()) OpenGL::filter = settings.filter ? GL_LINEAR : GL_NEAREST; return true; @@ -91,20 +97,20 @@ struct pVideoGLX : OpenGL { return false; } - bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { + auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { OpenGL::size(width, height); return OpenGL::lock(data, pitch); } - void unlock() { + auto unlock() -> void { } - void clear() { + auto clear() -> void { OpenGL::clear(); - if(glx.double_buffer) glXSwapBuffers(display, glxwindow); + if(glx.doubleBuffer) glXSwapBuffers(display, glxwindow); } - void refresh() { + auto refresh() -> void { //we must ensure that the child window is the same size as the parent window. //unfortunately, we cannot hook the parent window resize event notification, //as we did not create the parent window, nor have any knowledge of the toolkit used. @@ -118,12 +124,15 @@ struct pVideoGLX : OpenGL { outputWidth = parent.width, outputHeight = parent.height; OpenGL::refresh(); - if(glx.double_buffer) glXSwapBuffers(display, glxwindow); + if(glx.doubleBuffer) glXSwapBuffers(display, glxwindow); } - bool init() { + auto init() -> bool { term(); + display = XOpenDisplay(0); + screen = DefaultScreen(display); + glXQueryVersion(display, &glx.version_major, &glx.version_minor); //require GLX 1.2+ API if(glx.version_major < 1 || (glx.version_major == 1 && glx.version_minor < 2)) return false; @@ -133,7 +142,7 @@ struct pVideoGLX : OpenGL { //let GLX determine the best Visual to use for GL output; provide a few hints //note: some video drivers will override double buffering attribute - int attributeList[] = { + signed attributeList[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_DOUBLEBUFFER, True, @@ -143,7 +152,7 @@ struct pVideoGLX : OpenGL { None }; - int fbCount; + signed fbCount; GLXFBConfig* fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount); if(fbCount == 0) return false; @@ -174,12 +183,12 @@ struct pVideoGLX : OpenGL { glxcontext = glXCreateContext(display, vi, /* sharelist = */ 0, /* direct = */ GL_TRUE); glXMakeCurrent(display, glxwindow = xwindow, glxcontext); - glXCreateContextAttribs = (GLXContext (*)(Display*, GLXFBConfig, GLXContext, int, const int*))glGetProcAddress("glXCreateContextAttribsARB"); - glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI"); - if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA"); + glXCreateContextAttribs = (GLXContext (*)(Display*, GLXFBConfig, GLXContext, signed, const signed*))glGetProcAddress("glXCreateContextAttribsARB"); + glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI"); + if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA"); if(glXCreateContextAttribs) { - int attributes[] = { + signed attributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 2, None @@ -197,16 +206,16 @@ struct pVideoGLX : OpenGL { } //read attributes of frame buffer for later use, as requested attributes from above are not always granted - int value = 0; + signed value = 0; glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value); - glx.double_buffer = value; - glx.is_direct = glXIsDirect(display, glxcontext); + glx.doubleBuffer = value; + glx.isDirect = glXIsDirect(display, glxcontext); OpenGL::init(); return true; } - void term() { + auto term() -> void { OpenGL::term(); if(glxcontext) { @@ -223,26 +232,11 @@ struct pVideoGLX : OpenGL { XFreeColormap(display, colormap); colormap = 0; } - } - pVideoGLX() { - display = XOpenDisplay(0); - screen = DefaultScreen(display); - - settings.handle = 0; - settings.synchronize = false; - settings.depth = 24; - settings.filter = 1; //linear - - xwindow = 0; - colormap = 0; - glxcontext = nullptr; - glxwindow = 0; - } - - ~pVideoGLX() { - term(); - XCloseDisplay(display); + if(display) { + XCloseDisplay(display); + display = nullptr; + } } }; diff --git a/ruby/video/opengl/main.hpp b/ruby/video/opengl/main.hpp index 8334d02f..79613d5b 100644 --- a/ruby/video/opengl/main.hpp +++ b/ruby/video/opengl/main.hpp @@ -1,4 +1,4 @@ -void OpenGL::shader(const char* pathname) { +auto OpenGL::shader(const string& pathname) -> void { for(auto& program : programs) program.release(); programs.reset(); @@ -29,11 +29,11 @@ void OpenGL::shader(const char* pathname) { string text = node.text(); if(node.name() == "width") { if(text.endsWith("%")) relativeWidth = real(text.rtrim("%")) / 100.0; - else absoluteWidth = decimal(text); + else absoluteWidth = text.decimal(); } if(node.name() == "height") { if(text.endsWith("%")) relativeHeight = real(text.rtrim("%")) / 100.0; - else absoluteHeight = decimal(text); + else absoluteHeight = text.decimal(); } } @@ -51,7 +51,7 @@ void OpenGL::shader(const char* pathname) { allocateHistory(historySize); } -void OpenGL::allocateHistory(unsigned size) { +auto OpenGL::allocateHistory(unsigned size) -> void { for(auto& frame : history) glDeleteTextures(1, &frame.texture); history.reset(); while(size--) { @@ -65,12 +65,12 @@ void OpenGL::allocateHistory(unsigned size) { } } -bool OpenGL::lock(uint32_t*& data, unsigned& pitch) { +auto OpenGL::lock(uint32_t*& data, unsigned& pitch) -> bool { pitch = width * sizeof(uint32_t); return data = buffer; } -void OpenGL::clear() { +auto OpenGL::clear() -> void { for(auto& p : programs) { glUseProgram(p.program); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, p.framebuffer); @@ -83,7 +83,7 @@ void OpenGL::clear() { glClear(GL_COLOR_BUFFER_BIT); } -void OpenGL::refresh() { +auto OpenGL::refresh() -> void { clear(); glActiveTexture(GL_TEXTURE0); @@ -180,7 +180,7 @@ void OpenGL::refresh() { } } -bool OpenGL::init() { +auto OpenGL::init() -> bool { if(!OpenGLBind()) return false; glDisable(GL_ALPHA_TEST); @@ -199,13 +199,13 @@ bool OpenGL::init() { OpenGLSurface::allocate(); glrLinkProgram(program); - shader(nullptr); + shader(""); return initialized = true; } -void OpenGL::term() { +auto OpenGL::term() -> void { if(initialized == false) return; - shader(nullptr); //release shader resources (eg frame[] history) + shader(""); //release shader resources (eg frame[] history) OpenGLSurface::release(); if(buffer) { delete[] buffer; buffer = nullptr; } initialized = false; diff --git a/ruby/video/opengl/opengl.hpp b/ruby/video/opengl/opengl.hpp index 0d50f01a..ce3c72a3 100644 --- a/ruby/video/opengl/opengl.hpp +++ b/ruby/video/opengl/opengl.hpp @@ -22,18 +22,23 @@ namespace ruby { struct OpenGL; struct OpenGLTexture { + auto getFormat() const -> GLuint; + auto getType() const -> GLuint; + GLuint texture = 0; unsigned width = 0; unsigned height = 0; GLuint format = GL_RGBA8; GLuint filter = GL_LINEAR; GLuint wrap = GL_CLAMP_TO_BORDER; - - GLuint getFormat() const; - GLuint getType() const; }; struct OpenGLSurface : OpenGLTexture { + auto allocate() -> void; + auto size(unsigned width, unsigned height) -> void; + auto release() -> void; + auto render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight) -> void; + GLuint program = 0; GLuint framebuffer = 0; GLuint vao = 0; @@ -42,14 +47,13 @@ struct OpenGLSurface : OpenGLTexture { GLuint geometry = 0; GLuint fragment = 0; uint32_t* buffer = nullptr; - - void allocate(); - void size(unsigned width, unsigned height); - void release(); - void render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight); }; struct OpenGLProgram : OpenGLSurface { + auto bind(OpenGL* instance, const Markup::Node& node, const string& pathname) -> void; + auto parse(OpenGL* instance, string& source) -> void; + auto release() -> void; + unsigned phase = 0; //frame counter unsigned modulo = 0; //frame counter modulus unsigned absoluteWidth = 0; @@ -57,13 +61,17 @@ struct OpenGLProgram : OpenGLSurface { double relativeWidth = 0; double relativeHeight = 0; vector pixmaps; - - void bind(OpenGL* instance, const Markup::Node& node, const string& pathname); - void parse(OpenGL* instance, string& source); - void release(); }; struct OpenGL : OpenGLProgram { + auto shader(const string& pathname) -> void; + auto allocateHistory(unsigned size) -> void; + auto lock(uint32_t*& data, unsigned& pitch) -> bool; + auto clear() -> void; + auto refresh() -> void; + auto init() -> bool; + auto term() -> void; + vector programs; vector history; GLuint inputFormat = GL_RGBA8; @@ -72,22 +80,14 @@ struct OpenGL : OpenGLProgram { struct Setting { string name; string value; - bool operator< (const Setting& source) { return name < source.name; } - bool operator==(const Setting& source) { return name == source.name; } - Setting() {} + bool operator< (const Setting& source) const { return name < source.name; } + bool operator==(const Setting& source) const { return name == source.name; } + Setting() = default; Setting(const string& name) : name(name) {} Setting(const string& name, const string& value) : name(name), value(value) {} }; set settings; bool initialized = false; - - void shader(const char* pathname); - void allocateHistory(unsigned size); - bool lock(uint32_t*& data, unsigned& pitch); - void clear(); - void refresh(); - bool init(); - void term(); }; #include "texture.hpp" diff --git a/ruby/video/opengl/program.hpp b/ruby/video/opengl/program.hpp index c5837a0d..c4044c50 100644 --- a/ruby/video/opengl/program.hpp +++ b/ruby/video/opengl/program.hpp @@ -1,13 +1,13 @@ -void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const string& pathname) { +auto OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const string& pathname) -> void { filter = glrFilter(node["filter"].text()); wrap = glrWrap(node["wrap"].text()); modulo = glrModulo(node["modulo"].integer()); string w = node["width"].text(), h = node["height"].text(); if(w.endsWith("%")) relativeWidth = real(w.rtrim("%")) / 100.0; - else absoluteWidth = decimal(w); + else absoluteWidth = w.decimal(); if(h.endsWith("%")) relativeHeight = real(h.rtrim("%")) / 100.0; - else absoluteHeight = decimal(h); + else absoluteHeight = h.decimal(); format = glrFormat(node["format"].text()); @@ -71,7 +71,7 @@ void OpenGLProgram::bind(OpenGL* instance, const Markup::Node& node, const strin } //apply manifest settings to shader source #in tags -void OpenGLProgram::parse(OpenGL* instance, string& source) { +auto OpenGLProgram::parse(OpenGL* instance, string& source) -> void { lstring lines = source.split("\n"); for(auto& line : lines) { string s = line; @@ -89,7 +89,7 @@ void OpenGLProgram::parse(OpenGL* instance, string& source) { source = lines.merge("\n"); } -void OpenGLProgram::release() { +auto OpenGLProgram::release() -> void { OpenGLSurface::release(); for(auto& pixmap : pixmaps) glDeleteTextures(1, &pixmap.texture); pixmaps.reset(); diff --git a/ruby/video/opengl/surface.hpp b/ruby/video/opengl/surface.hpp index 9f368dec..7922c47c 100644 --- a/ruby/video/opengl/surface.hpp +++ b/ruby/video/opengl/surface.hpp @@ -1,10 +1,10 @@ -void OpenGLSurface::allocate() { +auto OpenGLSurface::allocate() -> void { glGenVertexArrays(1, &vao); glBindVertexArray(vao); glGenBuffers(3, &vbo[0]); } -void OpenGLSurface::size(unsigned w, unsigned h) { +auto OpenGLSurface::size(unsigned w, unsigned h) -> void { if(width == w && height == h) return; width = w, height = h; w = glrSize(w), h = glrSize(h); @@ -25,7 +25,7 @@ void OpenGLSurface::size(unsigned w, unsigned h) { } } -void OpenGLSurface::release() { +auto OpenGLSurface::release() -> void { if(vbo[0]) { glDeleteBuffers(3, &vbo[0]); for(auto &o : vbo) o = 0; } if(vao) { glDeleteVertexArrays(1, &vao); vao = 0; } if(vertex) { glDetachShader(program, vertex); glDeleteShader(vertex); vertex = 0; } @@ -37,7 +37,7 @@ void OpenGLSurface::release() { width = 0, height = 0; } -void OpenGLSurface::render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight) { +auto OpenGLSurface::render(unsigned sourceWidth, unsigned sourceHeight, unsigned targetWidth, unsigned targetHeight) -> void { glViewport(0, 0, targetWidth, targetHeight); float w = (float)sourceWidth / (float)glrSize(sourceWidth); diff --git a/ruby/video/opengl/texture.hpp b/ruby/video/opengl/texture.hpp index 8685bef7..d79a6a81 100644 --- a/ruby/video/opengl/texture.hpp +++ b/ruby/video/opengl/texture.hpp @@ -1,10 +1,10 @@ -GLuint OpenGLTexture::getFormat() const { +auto OpenGLTexture::getFormat() const -> GLuint { if(format == GL_R32I) return GL_RED_INTEGER; if(format == GL_R32UI) return GL_RED_INTEGER; return GL_BGRA; } -GLuint OpenGLTexture::getType() const { +auto OpenGLTexture::getType() const -> GLuint { if(format == GL_R32I) return GL_UNSIGNED_INT; if(format == GL_R32UI) return GL_UNSIGNED_INT; if(format == GL_RGB10_A2) return GL_UNSIGNED_INT_2_10_10_10_REV; diff --git a/ruby/video/opengl/utility.hpp b/ruby/video/opengl/utility.hpp index 83c8b0c2..6a632c17 100644 --- a/ruby/video/opengl/utility.hpp +++ b/ruby/video/opengl/utility.hpp @@ -1,9 +1,9 @@ -static unsigned glrSize(unsigned size) { +static auto glrSize(unsigned size) -> unsigned { return size; //return bit::round(size); //return nearest power of two } -static GLuint glrFormat(const string& format) { +static auto glrFormat(const string& format) -> GLuint { if(format == "r32i" ) return GL_R32I; if(format == "r32ui" ) return GL_R32UI; if(format == "rgba8" ) return GL_RGBA8; @@ -15,53 +15,53 @@ static GLuint glrFormat(const string& format) { return GL_RGBA8; } -static GLuint glrFilter(const string& filter) { +static auto glrFilter(const string& filter) -> GLuint { if(filter == "nearest") return GL_NEAREST; if(filter == "linear" ) return GL_LINEAR; return GL_LINEAR; } -static GLuint glrWrap(const string& wrap) { +static auto glrWrap(const string& wrap) -> GLuint { if(wrap == "border") return GL_CLAMP_TO_BORDER; if(wrap == "edge" ) return GL_CLAMP_TO_EDGE; if(wrap == "repeat") return GL_REPEAT; return GL_CLAMP_TO_BORDER; } -static unsigned glrModulo(unsigned modulo) { +static auto glrModulo(unsigned modulo) -> unsigned { if(modulo) return modulo; return 300; //divisible by 2, 3, 4, 5, 6, 10, 12, 15, 20, 25, 30, 50, 60, 100, 150 } -static GLuint glrProgram() { +static auto glrProgram() -> GLuint { GLuint program = 0; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&program); return program; } -static void glrUniform1i(const string& name, GLint value) { +static auto glrUniform1i(const string& name, GLint value) -> void { GLint location = glGetUniformLocation(glrProgram(), name); glUniform1i(location, value); } -static void glrUniform4f(const string& name, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3) { +static auto glrUniform4f(const string& name, GLfloat value0, GLfloat value1, GLfloat value2, GLfloat value3) -> void { GLint location = glGetUniformLocation(glrProgram(), name); glUniform4f(location, value0, value1, value2, value3); } -static void glrUniformMatrix4fv(const string& name, GLfloat *values) { +static auto glrUniformMatrix4fv(const string& name, GLfloat* values) -> void { GLint location = glGetUniformLocation(glrProgram(), name); glUniformMatrix4fv(location, 1, GL_FALSE, values); } -static void glrParameters(GLuint filter, GLuint wrap) { +static auto glrParameters(GLuint filter, GLuint wrap) -> void { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap); } -static GLuint glrCreateShader(GLuint program, GLuint type, const char* source) { +static auto glrCreateShader(GLuint program, GLuint type, const char* source) -> GLuint { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, 0); glCompileShader(shader); @@ -80,7 +80,7 @@ static GLuint glrCreateShader(GLuint program, GLuint type, const char* source) { return shader; } -static void glrLinkProgram(GLuint program) { +static auto glrLinkProgram(GLuint program) -> void { glLinkProgram(program); GLint result = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &result); diff --git a/ruby/video/sdl.cpp b/ruby/video/sdl.cpp index 4c63d237..776767a1 100644 --- a/ruby/video/sdl.cpp +++ b/ruby/video/sdl.cpp @@ -8,38 +8,43 @@ namespace ruby { struct pVideoSDL { - Display* display; - SDL_Surface* screen; - SDL_Surface* buffer; - unsigned iwidth, iheight; + Display* display = nullptr; + SDL_Surface* screen = nullptr; + SDL_Surface* buffer = nullptr; + unsigned iwidth = 0; + unsigned iheight = 0; struct { - uintptr_t handle; + uintptr_t handle = 0; - unsigned width; - unsigned height; + unsigned width = 0; + unsigned height = 0; } settings; - bool cap(const string& name) { + ~pVideoSDL() { + term(); + } + + auto cap(const string& name) -> bool { if(name == Video::Handle) return true; return false; } - any get(const string& name) { + auto get(const string& name) -> any { if(name == Video::Handle) return settings.handle; - return false; + return {}; } - bool set(const string& name, const any& value) { - if(name == Video::Handle) { - settings.handle = any_cast(value); + auto set(const string& name, const any& value) -> bool { + if(name == Video::Handle && value.is()) { + settings.handle = value.get(); return true; } return false; } - void resize(unsigned width, unsigned height) { + auto resize(unsigned width, unsigned height) -> void { if(iwidth >= width && iheight >= height) return; iwidth = max(width, iwidth); @@ -52,7 +57,7 @@ struct pVideoSDL { ); } - bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { + auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { if(width != settings.width || height != settings.height) { resize(settings.width = width, settings.height = height); } @@ -62,11 +67,11 @@ struct pVideoSDL { return data = (uint32_t*)buffer->pixels; } - void unlock() { + auto unlock() -> void { if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer); } - void clear() { + auto clear() -> void { if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); for(unsigned y = 0; y < iheight; y++) { uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2); @@ -76,13 +81,13 @@ struct pVideoSDL { refresh(); } - void refresh() { + auto refresh() -> void { //ruby input is X8R8G8B8, top 8-bits are ignored. //as SDL forces us to use a 32-bit buffer, we must set alpha to 255 (full opacity) //to prevent blending against the window beneath when X window visual is 32-bits. if(SDL_MUSTLOCK(buffer)) SDL_LockSurface(buffer); for(unsigned y = 0; y < settings.height; y++) { - uint32_t *data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2); + uint32_t* data = (uint32_t*)buffer->pixels + y * (buffer->pitch >> 2); for(unsigned x = 0; x < settings.width; x++) *data++ |= 0xff000000; } if(SDL_MUSTLOCK(buffer)) SDL_UnlockSurface(buffer); @@ -106,12 +111,12 @@ struct pVideoSDL { SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h); } - bool init() { + auto init() -> bool { display = XOpenDisplay(0); //todo: this causes a segfault inside SDL_SetVideoMode on FreeBSD (works under Linux) char env[512]; - sprintf(env, "SDL_WINDOWID=%ld", (long int)settings.handle); + sprintf(env, "SDL_WINDOWID=%ld", (long)settings.handle); putenv(env); SDL_InitSubSystem(SDL_INIT_VIDEO); @@ -126,15 +131,11 @@ struct pVideoSDL { return true; } - void term() { + auto term() -> void { XCloseDisplay(display); SDL_FreeSurface(buffer); SDL_QuitSubSystem(SDL_INIT_VIDEO); } - - pVideoSDL() { - settings.handle = 0; - } }; DeclareVideo(SDL) diff --git a/ruby/video/xshm.cpp b/ruby/video/xshm.cpp index f1592218..c9e61fbc 100644 --- a/ruby/video/xshm.cpp +++ b/ruby/video/xshm.cpp @@ -13,15 +13,16 @@ namespace ruby { struct pVideoXShm { struct Device { Display* display = nullptr; - int screen; - int depth; + signed screen = 0; + signed depth = 0; Visual* visual = nullptr; - Window window; + Window window = 0; XShmSegmentInfo shmInfo; XImage* image = nullptr; uint32_t* buffer = nullptr; - unsigned width, height; + unsigned width = 0; + unsigned height = 0; } device; struct Settings { @@ -29,34 +30,39 @@ struct pVideoXShm { unsigned filter = Video::FilterLinear; uint32_t* buffer = nullptr; - unsigned width, height; + unsigned width = 0; + unsigned height = 0; } settings; - bool cap(const string& name) { + ~pVideoXShm() { + term(); + } + + auto cap(const string& name) -> bool { if(name == Video::Handle) return true; if(name == Video::Filter) return true; return false; } - any get(const string& name) { + auto get(const string& name) -> any { if(name == Video::Handle) return settings.handle; if(name == Video::Filter) return settings.filter; - return false; + return {}; } - bool set(const string& name, const any& value) { - if(name == Video::Handle) { - settings.handle = any_cast(value); + auto set(const string& name, const any& value) -> bool { + if(name == Video::Handle && value.is()) { + settings.handle = value.get(); return true; } - if(name == Video::Filter) { - settings.filter = any_cast(value); + if(name == Video::Filter && value.is()) { + settings.filter = value.get(); return true; } return false; } - bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { + auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { if(settings.buffer == nullptr || settings.width != width || settings.height != height) { if(settings.buffer) delete[] settings.buffer; settings.width = width, settings.height = height; @@ -68,18 +74,18 @@ struct pVideoXShm { return true; } - void unlock() { + auto unlock() -> void { } - void clear() { + auto clear() -> void { if(settings.buffer == nullptr) return; uint32_t* dp = settings.buffer; unsigned length = settings.width * settings.height; - while(length--) *dp++ = (255u << 24); + while(length--) *dp++ = 255u << 24; refresh(); } - void refresh() { + auto refresh() -> void { if(settings.buffer == nullptr) return; size(); @@ -96,12 +102,12 @@ struct pVideoXShm { if(settings.filter == Video::FilterNearest) { for(unsigned x = 0; x < device.width; x++) { - *dp++ = (255u << 24) | sp[(unsigned)xstep]; + *dp++ = 255u << 24 | sp[(unsigned)xstep]; xstep += xratio; } } else { //settings.filter == Video::FilterLinear for(unsigned x = 0; x < device.width; x++) { - *dp++ = (255u << 24) | interpolate(xstep - (unsigned)xstep, sp[(unsigned)xstep], sp[(unsigned)xstep + 1]); + *dp++ = 255u << 24 | interpolate(xstep - (unsigned)xstep, sp[(unsigned)xstep], sp[(unsigned)xstep + 1]); xstep += xratio; } } @@ -116,7 +122,7 @@ struct pVideoXShm { XFlush(device.display); } - bool init() { + auto init() -> bool { device.display = XOpenDisplay(0); device.screen = DefaultScreen(device.display); @@ -151,18 +157,16 @@ struct pVideoXShm { return true; } - void term() { + auto term() -> void { free(); - - if(device.display) { XCloseDisplay(device.display); device.display = nullptr; } + if(device.display) { + XCloseDisplay(device.display); + device.display = nullptr; + } } - ~pVideoXShm() { - term(); - } - -//internal: - bool size() { +private: + auto size() -> bool { XWindowAttributes windowAttributes; XGetWindowAttributes(device.display, settings.handle, &windowAttributes); @@ -185,7 +189,7 @@ struct pVideoXShm { return true; } - void free() { + auto free() -> void { if(device.buffer == nullptr) return; device.buffer = nullptr; XShmDetach(device.display, &device.shmInfo); @@ -194,13 +198,13 @@ struct pVideoXShm { shmctl(device.shmInfo.shmid, IPC_RMID, 0); } - alwaysinline uint32_t interpolate(float mu, uint32_t a, uint32_t b) { - uint8_t ar = (a >> 16), ag = (a >> 8), ab = (a >> 0); - uint8_t br = (b >> 16), bg = (b >> 8), bb = (b >> 0); + alwaysinline auto interpolate(float mu, uint32_t a, uint32_t b) -> uint32_t { + uint8_t ar = a >> 16, ag = a >> 8, ab = a >> 0; + uint8_t br = b >> 16, bg = b >> 8, bb = b >> 0; uint8_t cr = ar * (1.0 - mu) + br * mu; uint8_t cg = ag * (1.0 - mu) + bg * mu; uint8_t cb = ab * (1.0 - mu) + bb * mu; - return (cr << 16) | (cg << 8) | (cb << 0); + return cr << 16 | cg << 8 | cb << 0; } }; diff --git a/ruby/video/xv.cpp b/ruby/video/xv.cpp index 2a73ea1b..9530a34c 100644 --- a/ruby/video/xv.cpp +++ b/ruby/video/xv.cpp @@ -4,54 +4,58 @@ #include #include -extern "C" XvImage* XvShmCreateImage(Display*, XvPortID, int, char*, int, int, XShmSegmentInfo*); +extern "C" auto XvShmCreateImage(Display*, XvPortID, signed, char*, signed, signed, XShmSegmentInfo*) -> XvImage*; namespace ruby { struct pVideoXv { - uint32_t* buffer; - uint8_t* ytable; - uint8_t* utable; - uint8_t* vtable; + uint32_t* buffer = nullptr; + uint8_t* ytable = nullptr; + uint8_t* utable = nullptr; + uint8_t* vtable = nullptr; - enum XvFormat { + enum XvFormat : unsigned { XvFormatRGB32, XvFormatRGB24, XvFormatRGB16, XvFormatRGB15, XvFormatYUY2, XvFormatUYVY, - XvFormatUnknown + XvFormatUnknown, }; struct { - Display* display; - GC gc; - Window window; - Colormap colormap; + Display* display = nullptr; + GC gc = 0; + Window window = 0; + Colormap colormap = 0; XShmSegmentInfo shminfo; - int port; - int depth; - int visualid; + signed port = -1; + signed depth = 0; + signed visualid = 0; - XvImage* image; - XvFormat format; - uint32_t fourcc; + XvImage* image = nullptr; + XvFormat format = XvFormatUnknown; + uint32_t fourcc = 0; - unsigned width; - unsigned height; + unsigned width = 0; + unsigned height = 0; } device; struct { - Window handle; - bool synchronize; + Window handle = 0; + bool synchronize = false; - unsigned width; - unsigned height; + unsigned width = 0; + unsigned height = 0; } settings; - bool cap(const string& name) { + ~pVideoXv() { + term(); + } + + auto cap(const string& name) -> bool { if(name == Video::Handle) return true; if(name == Video::Synchronize) { return XInternAtom(XOpenDisplay(0), "XV_SYNC_TO_VBLANK", true) != None; @@ -59,23 +63,23 @@ struct pVideoXv { return false; } - any get(const string& name) { + auto get(const string& name) -> any { if(name == Video::Handle) return settings.handle; if(name == Video::Synchronize) return settings.synchronize; - return false; + return {}; } - bool set(const string& name, const any& value) { - if(name == Video::Handle) { - settings.handle = any_cast(value); + auto set(const string& name, const any& value) -> bool { + if(name == Video::Handle && value.is()) { + settings.handle = value.get(); return true; } - if(name == Video::Synchronize) { + if(name == Video::Synchronize && value.is()) { Display* display = XOpenDisplay(0); Atom atom = XInternAtom(display, "XV_SYNC_TO_VBLANK", true); if(atom != None && device.port >= 0) { - settings.synchronize = any_cast(value); + settings.synchronize = value.get(); XvSetPortAttribute(display, device.port, atom, settings.synchronize); return true; } @@ -85,7 +89,7 @@ struct pVideoXv { return false; } - void resize(unsigned width, unsigned height) { + auto resize(unsigned width, unsigned height) -> void { if(device.width >= width && device.height >= height) return; device.width = max(width, device.width); device.height = max(height, device.height); @@ -106,7 +110,7 @@ struct pVideoXv { buffer = new uint32_t[device.width * device.height]; } - bool lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) { + auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool { if(width != settings.width || height != settings.height) { resize(settings.width = width, settings.height = height); } @@ -115,17 +119,17 @@ struct pVideoXv { return data = buffer; } - void unlock() { + auto unlock() -> void { } - void clear() { - memset(buffer, 0, device.width * device.height * sizeof(uint32_t)); + auto clear() -> void { + memory::fill(buffer, device.width * device.height * sizeof(uint32_t)); //clear twice in case video is double buffered ... refresh(); refresh(); } - void refresh() { + auto refresh() -> void { unsigned width = settings.width; unsigned height = settings.height; @@ -146,12 +150,12 @@ struct pVideoXv { XGetWindowAttributes(device.display, device.window, &target); switch(device.format) { - case XvFormatRGB32: render_rgb32(width, height); break; - case XvFormatRGB24: render_rgb24(width, height); break; - case XvFormatRGB16: render_rgb16(width, height); break; - case XvFormatRGB15: render_rgb15(width, height); break; - case XvFormatYUY2: render_yuy2 (width, height); break; - case XvFormatUYVY: render_uyvy (width, height); break; + case XvFormatRGB32: renderRGB32(width, height); break; + case XvFormatRGB24: renderRGB24(width, height); break; + case XvFormatRGB16: renderRGB16(width, height); break; + case XvFormatRGB15: renderRGB15(width, height); break; + case XvFormatYUY2: renderYUY2 (width, height); break; + case XvFormatUYVY: renderUYVY (width, height); break; } XvShmPutImage(device.display, device.port, device.window, device.gc, device.image, @@ -160,7 +164,7 @@ struct pVideoXv { true); } - bool init() { + auto init() -> bool { device.display = XOpenDisplay(0); if(!XShmQueryExtension(device.display)) { @@ -201,7 +205,7 @@ struct pVideoXv { visualtemplate.screen = DefaultScreen(device.display); visualtemplate.depth = device.depth; visualtemplate.visual = 0; - int visualmatches = 0; + signed visualmatches = 0; XVisualInfo *visualinfo = XGetVisualInfo(device.display, VisualIDMask | VisualScreenMask | VisualDepthMask, &visualtemplate, &visualmatches); if(visualmatches < 1 || !visualinfo->visual) { if(visualinfo) XFree(visualinfo); @@ -315,12 +319,12 @@ struct pVideoXv { buffer = new uint32_t[device.width * device.height]; settings.width = 256; settings.height = 256; - init_yuv_tables(); + initTables(); clear(); return true; } - void term() { + auto term() -> void { XShmDetach(device.display, &device.shminfo); shmdt(device.shminfo.shmaddr); shmctl(device.shminfo.shmid, IPC_RMID, NULL); @@ -336,13 +340,14 @@ struct pVideoXv { device.colormap = 0; } - if(buffer) { delete[] buffer; buffer = 0; } - if(ytable) { delete[] ytable; ytable = 0; } - if(utable) { delete[] utable; utable = 0; } - if(vtable) { delete[] vtable; vtable = 0; } + if(buffer) { delete[] buffer; buffer = nullptr; } + if(ytable) { delete[] ytable; ytable = nullptr; } + if(utable) { delete[] utable; utable = nullptr; } + if(vtable) { delete[] vtable; vtable = nullptr; } } - void render_rgb32(unsigned width, unsigned height) { +private: + auto renderRGB32(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint32_t* output = (uint32_t*)device.image->data; @@ -353,7 +358,7 @@ struct pVideoXv { } } - void render_rgb24(unsigned width, unsigned height) { + auto renderRGB24(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint8_t* output = (uint8_t*)device.image->data; @@ -370,7 +375,7 @@ struct pVideoXv { } } - void render_rgb16(unsigned width, unsigned height) { + auto renderRGB16(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint16_t* output = (uint16_t*)device.image->data; @@ -385,7 +390,7 @@ struct pVideoXv { } } - void render_rgb15(unsigned width, unsigned height) { + auto renderRGB15(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint16_t* output = (uint16_t*)device.image->data; @@ -400,7 +405,7 @@ struct pVideoXv { } } - void render_yuy2(unsigned width, unsigned height) { + auto renderYUY2(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint16_t* output = (uint16_t*)device.image->data; @@ -423,7 +428,7 @@ struct pVideoXv { } } - void render_uyvy(unsigned width, unsigned height) { + auto renderUYVY(unsigned width, unsigned height) -> void { uint32_t* input = (uint32_t*)buffer; uint16_t* output = (uint16_t*)device.image->data; @@ -446,7 +451,7 @@ struct pVideoXv { } } - void init_yuv_tables() { + auto initTables() -> void { ytable = new uint8_t[65536]; utable = new uint8_t[65536]; vtable = new uint8_t[65536]; @@ -475,23 +480,6 @@ struct pVideoXv { vtable[i] = v < 0 ? 0 : v > 255 ? 255 : v; } } - - pVideoXv() { - device.window = 0; - device.colormap = 0; - device.port = -1; - - ytable = 0; - utable = 0; - vtable = 0; - - settings.handle = 0; - settings.synchronize = false; - } - - ~pVideoXv() { - term(); - } }; DeclareVideo(Xv) diff --git a/target-tomoko/GNUmakefile b/target-tomoko/GNUmakefile index 8f8a278d..6bc1e364 100644 --- a/target-tomoko/GNUmakefile +++ b/target-tomoko/GNUmakefile @@ -9,7 +9,7 @@ include gb/GNUmakefile include gba/GNUmakefile ui_objects := ui-tomoko ui-program ui-configuration ui-input -ui_objects += ui-library ui-settings ui-tools ui-presentation +ui_objects += ui-settings ui-tools ui-presentation ui_objects += ruby hiro # platform diff --git a/target-tomoko/library/browser.cpp b/target-tomoko/library/browser.cpp deleted file mode 100644 index 964d30c8..00000000 --- a/target-tomoko/library/browser.cpp +++ /dev/null @@ -1,35 +0,0 @@ -LibraryBrowser::LibraryBrowser(TabFrame& parent, Emulator::Interface::Media& media) : TabFrameItem{&parent} { - this->media = media; - setText(media.name); - layout.setMargin(5); - gameList.onActivate([&] { - libraryManager->setVisible(false); - program->loadMedia({config().library.location, this->media.name, "/", gameList.selected()->text(), ".", this->media.type, "/"}); - }); -} - -auto LibraryBrowser::reload() -> void { - string path = {config().library.location, media.name}; - directory::create(path); - - gameList.reset(); - gameList.append(ListViewColumn()); - bool first = true; - auto folders = directory::folders(path, {"*.", media.type}); - for(auto& folder : folders) { - ListViewItem item; - item.setIcon(0, Icon::Emblem::Program); - item.setText(folder.rtrim({".", media.type, "/"})); - gameList.append(item); - if(first) { - first = false; - item.setFocused(); - } - } -} - -auto LibraryBrowser::select() -> void { - reload(); - setSelected(); - gameList.setFocused(); -} diff --git a/target-tomoko/library/library.cpp b/target-tomoko/library/library.cpp deleted file mode 100644 index 508041eb..00000000 --- a/target-tomoko/library/library.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "../tomoko.hpp" -#include "browser.cpp" -#include "manager.cpp" diff --git a/target-tomoko/library/library.hpp b/target-tomoko/library/library.hpp deleted file mode 100644 index c79383c6..00000000 --- a/target-tomoko/library/library.hpp +++ /dev/null @@ -1,21 +0,0 @@ -struct LibraryBrowser : TabFrameItem { - LibraryBrowser(TabFrame& parent, Emulator::Interface::Media& media); - auto reload() -> void; - auto select() -> void; - - Emulator::Interface::Media media; - - VerticalLayout layout{this}; - ListView gameList{&layout, Size{~0, ~0}}; -}; - -struct LibraryManager : Window { - LibraryManager(); - auto show(const string& type) -> void; - - VerticalLayout layout{this}; - TabFrame libraryFrame{&layout, Size{~0, ~0}}; - vector libraryBrowsers; -}; - -extern LibraryManager* libraryManager; diff --git a/target-tomoko/library/manager.cpp b/target-tomoko/library/manager.cpp deleted file mode 100644 index d611978e..00000000 --- a/target-tomoko/library/manager.cpp +++ /dev/null @@ -1,29 +0,0 @@ -LibraryManager* libraryManager = nullptr; - -LibraryManager::LibraryManager() { - libraryManager = this; - - layout.setMargin(5); - - for(auto& emulator : program->emulators) { - for(auto& media : emulator->media) { - if(media.bootable == false) continue; - auto browser = new LibraryBrowser(libraryFrame, media); - libraryBrowsers.append(browser); - } - } - - setSize({640, 800}); - setPlacement(0.0, 0.0); -} - -auto LibraryManager::show(const string& type) -> void { - for(auto& browser : libraryBrowsers) { - if(type != browser->media.type) continue; - browser->select(); - } - - setTitle({"Library (", config().library.location, ")"}); - setVisible(); - setFocused(); -} diff --git a/target-tomoko/presentation/presentation.cpp b/target-tomoko/presentation/presentation.cpp index 56bc03d4..5463839b 100644 --- a/target-tomoko/presentation/presentation.cpp +++ b/target-tomoko/presentation/presentation.cpp @@ -7,10 +7,18 @@ Presentation::Presentation() { libraryMenu.setText("Library"); for(auto& emulator : program->emulators) { for(auto& media : emulator->media) { - if(media.bootable == false) continue; + if(!media.bootable) continue; auto item = new MenuItem{&libraryMenu}; item->setText({media.name, " ..."}).onActivate([=] { - libraryManager->show(media.type); + directory::create({config().library.location, media.name}); + auto location = BrowserDialog() + .setTitle({"Load ", media.name}) + .setPath({config().library.location, media.name}) + .setFilters(string{media.name, "|*.", media.type}) + .openFolder(); + if(directory::exists(location)) { + program->loadMedia(location); + } }); loadBootableMedia.append(item); } @@ -73,7 +81,7 @@ Presentation::Presentation() { statusBar.setVisible(config().userInterface.showStatusBar); if(visible()) resizeViewport(); }); - showConfiguration.setText("Configuration ...").onActivate([&] { settingsManager->show(0); }); + showConfiguration.setText("Configuration ...").onActivate([&] { settingsManager->show(2); }); toolsMenu.setText("Tools").setVisible(false); saveStateMenu.setText("Save State"); @@ -98,7 +106,7 @@ Presentation::Presentation() { setTitle({"tomoko v", Emulator::Version}); setResizable(false); - setBackgroundColor({16, 16, 16}); + setBackgroundColor({0, 0, 0}); resizeViewport(); } @@ -130,24 +138,32 @@ auto Presentation::updateEmulator() -> void { } auto Presentation::resizeViewport() -> void { + signed scale = 1; + if(config().video.scale == "Small" ) scale = 1; + if(config().video.scale == "Normal") scale = 2; + if(config().video.scale == "Large" ) scale = 4; + signed width = 256; signed height = 240; - if(emulator) { width = emulator->information.width; height = emulator->information.height; } + bool arc = config().video.aspectCorrection; + if(fullScreen() == false) { - bool arc = config().video.aspectCorrection && emulator && emulator->information.aspectRatio != 1.0; + signed windowWidth = 256 * scale; + signed windowHeight = 240 * scale; + if(arc) windowWidth = windowWidth * 8 / 7; - if(config().video.scale == "Small" ) width *= 1, height *= 1; - if(config().video.scale == "Normal") width *= 2, height *= 2; - if(config().video.scale == "Large" ) width *= 4, height *= 4; - if(arc) width = width * 8 / 7; + double stretch = (arc && emulator && emulator->information.aspectRatio != 1.0) ? 8.0 / 7.0 : 1.0; + signed multiplier = min(windowWidth / (signed)(width * stretch), windowHeight / height); + width = width * multiplier * stretch; + height = height * multiplier; - setSize({width, height}); - viewport.setGeometry({0, 0, width, height}); + setSize({windowWidth, windowHeight}); + viewport.setGeometry({(windowWidth - width) / 2, (windowHeight - height) / 2, width, height}); setPlacement(0.5, 0.5); } else { auto desktop = Desktop::size(); diff --git a/target-tomoko/program/interface.cpp b/target-tomoko/program/interface.cpp index 4431bcd0..f557a7c8 100644 --- a/target-tomoko/program/interface.cpp +++ b/target-tomoko/program/interface.cpp @@ -1,11 +1,10 @@ //request from emulation core to load non-volatile media folder auto Program::loadRequest(unsigned id, string name, string type) -> void { string location = BrowserDialog() - .setParent(*presentation) .setTitle({"Load ", name}) .setPath({config().library.location, name}) .setFilters({string{name, "|*.", type}}) - .selectFolder(); + .openFolder(); if(!directory::exists(location)) return; mediaPaths(id) = location; diff --git a/target-tomoko/program/program.cpp b/target-tomoko/program/program.cpp index 7b01ee15..9bf69aac 100644 --- a/target-tomoko/program/program.cpp +++ b/target-tomoko/program/program.cpp @@ -22,7 +22,6 @@ Program::Program() { new ConfigurationManager; new InputManager; - new LibraryManager; new SettingsManager; new CheatDatabase; new ToolsManager; diff --git a/target-tomoko/settings/advanced.cpp b/target-tomoko/settings/advanced.cpp index d2837aab..8d36533c 100644 --- a/target-tomoko/settings/advanced.cpp +++ b/target-tomoko/settings/advanced.cpp @@ -34,7 +34,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) { libraryPrefix.setText("Location:"); libraryLocation.setEditable(false).setText(config().library.location); libraryChange.setText("Change ...").onActivate([&] { - if(auto location = BrowserDialog().setParent(*presentation).selectFolder()) { + if(auto location = BrowserDialog().setTitle("Select Library Location").selectFolder()) { libraryLocation.setText(config().library.location = location); } }); diff --git a/target-tomoko/settings/audio.cpp b/target-tomoko/settings/audio.cpp new file mode 100644 index 00000000..5cfa4185 --- /dev/null +++ b/target-tomoko/settings/audio.cpp @@ -0,0 +1,6 @@ +AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { + setIcon(Icon::Device::Speaker); + setText("Audio"); + + layout.setMargin(5); +} diff --git a/target-tomoko/settings/hotkeys.cpp b/target-tomoko/settings/hotkeys.cpp index 50f25710..a025e870 100644 --- a/target-tomoko/settings/hotkeys.cpp +++ b/target-tomoko/settings/hotkeys.cpp @@ -9,7 +9,7 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) { eraseButton.setEnabled((bool)mappingList.selected()); }); resetButton.setText("Reset").onActivate([&] { - if(MessageDialog("Are you sure you want to erase all hotkey mappings?").setParent(*settingsManager).question() == 0) { + if(MessageDialog("Are you sure you want to erase all hotkey mappings?").setParent(*settingsManager).question() == "Yes") { for(auto& mapping : inputManager->hotkeys) mapping->unbind(); refreshMappings(); } diff --git a/target-tomoko/settings/input.cpp b/target-tomoko/settings/input.cpp index e46ff460..3708d22f 100644 --- a/target-tomoko/settings/input.cpp +++ b/target-tomoko/settings/input.cpp @@ -16,7 +16,7 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { assignMouse2.setVisible(false).onActivate([&] { assignMouseInput(1); }); assignMouse3.setVisible(false).onActivate([&] { assignMouseInput(2); }); resetButton.setText("Reset").onActivate([&] { - if(MessageDialog("Are you sure you want to erase all mappings for this device?").setParent(*settingsManager).question() == 0) { + if(MessageDialog("Are you sure you want to erase all mappings for this device?").setParent(*settingsManager).question() == "Yes") { for(auto& mapping : activeDevice().mappings) mapping->unbind(); refreshMappings(); } diff --git a/target-tomoko/settings/settings.cpp b/target-tomoko/settings/settings.cpp index c7713866..233acc01 100644 --- a/target-tomoko/settings/settings.cpp +++ b/target-tomoko/settings/settings.cpp @@ -1,6 +1,9 @@ #include "../tomoko.hpp" +#include "video.cpp" +#include "audio.cpp" #include "input.cpp" #include "hotkeys.cpp" +#include "timing.cpp" #include "advanced.cpp" SettingsManager* settingsManager = nullptr; diff --git a/target-tomoko/settings/settings.hpp b/target-tomoko/settings/settings.hpp index cf421e67..4e8b738c 100644 --- a/target-tomoko/settings/settings.hpp +++ b/target-tomoko/settings/settings.hpp @@ -1,3 +1,15 @@ +struct VideoSettings : TabFrameItem { + VideoSettings(TabFrame*); + + VerticalLayout layout{this}; +}; + +struct AudioSettings : TabFrameItem { + AudioSettings(TabFrame*); + + VerticalLayout layout{this}; +}; + struct InputSettings : TabFrameItem { InputSettings(TabFrame*); auto updateControls() -> void; @@ -46,6 +58,12 @@ struct HotkeySettings : TabFrameItem { Button eraseButton{&controlLayout, Size{80, 0}}; }; +struct TimingSettings : TabFrameItem { + TimingSettings(TabFrame*); + + VerticalLayout layout{this}; +}; + struct AdvancedSettings : TabFrameItem { AdvancedSettings(TabFrame*); @@ -72,8 +90,11 @@ struct SettingsManager : Window { VerticalLayout layout{this}; TabFrame panel{&layout, Size{~0, ~0}}; + VideoSettings video{&panel}; + AudioSettings audio{&panel}; InputSettings input{&panel}; HotkeySettings hotkeys{&panel}; + TimingSettings timing{&panel}; AdvancedSettings advanced{&panel}; StatusBar statusBar{this}; diff --git a/target-tomoko/settings/timing.cpp b/target-tomoko/settings/timing.cpp new file mode 100644 index 00000000..0222a664 --- /dev/null +++ b/target-tomoko/settings/timing.cpp @@ -0,0 +1,6 @@ +TimingSettings::TimingSettings(TabFrame* parent) : TabFrameItem(parent) { + setIcon(Icon::Device::Clock); + setText("Timing"); + + layout.setMargin(5); +} diff --git a/target-tomoko/settings/video.cpp b/target-tomoko/settings/video.cpp new file mode 100644 index 00000000..0dafdb7d --- /dev/null +++ b/target-tomoko/settings/video.cpp @@ -0,0 +1,6 @@ +VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { + setIcon(Icon::Device::Display); + setText("Video"); + + layout.setMargin(5); +} diff --git a/target-tomoko/tomoko.hpp b/target-tomoko/tomoko.hpp index 4fe61724..5346eaa8 100644 --- a/target-tomoko/tomoko.hpp +++ b/target-tomoko/tomoko.hpp @@ -11,7 +11,6 @@ using namespace hiro; #include "program/program.hpp" #include "configuration/configuration.hpp" #include "input/input.hpp" -#include "library/library.hpp" #include "settings/settings.hpp" #include "tools/tools.hpp" #include "presentation/presentation.hpp" diff --git a/target-tomoko/tools/cheat-editor.cpp b/target-tomoko/tools/cheat-editor.cpp index ce260940..d249037e 100644 --- a/target-tomoko/tools/cheat-editor.cpp +++ b/target-tomoko/tools/cheat-editor.cpp @@ -62,7 +62,7 @@ auto CheatEditor::doRefresh() -> void { } auto CheatEditor::doReset(bool force) -> void { - if(force || MessageDialog().setParent(*toolsManager).setText("Permanently erase all slots?").question() == 0) { + if(force || MessageDialog().setParent(*toolsManager).setText("Permanently erase all slots?").question() == "Yes") { for(auto& cheat : cheats) { cheat.enabled = false; cheat.code = ""; diff --git a/target-tomoko/tools/state-manager.cpp b/target-tomoko/tools/state-manager.cpp index 0134e0b6..1d093de1 100644 --- a/target-tomoko/tools/state-manager.cpp +++ b/target-tomoko/tools/state-manager.cpp @@ -84,7 +84,7 @@ auto StateManager::doSave() -> void { } auto StateManager::doReset() -> void { - if(MessageDialog().setParent(*toolsManager).setText("Permanently erase all slots?").question() == 0) { + if(MessageDialog().setParent(*toolsManager).setText("Permanently erase all slots?").question() == "Yes") { for(auto slot : range(Slots)) file::remove(program->stateName(1 + slot, true)); doRefresh(); }