diff options
author | Vas Crabb <vas@vastheman.com> | 2020-12-18 15:54:52 +1100 |
---|---|---|
committer | Vas Crabb <vas@vastheman.com> | 2020-12-18 15:54:52 +1100 |
commit | 1df245cb99882892678216c3d0c6e243611d627c (patch) | |
tree | a8f3563a74d58755f4a82d4cbfc2406cf79543b3 /src/frontend | |
parent | ff9c1a0ca91f925e5c23b22a92a53c83f9f655ba (diff) |
More Lua engine clean-up and documentation, resulting in core cleanup.
More Lua interface cleanup, additional properties and methods, and
documentation migration/expansion.
Emulated switch inputs can have "not" codes applied to host input axis
directions. It works the same way as host switch inputs - push twice
for a "not" prefix.
Input polling helpers no longer need to store state in the input device
items. There’s less leakage, and less chance of things interfering with
each other.
Allow snapshot view options to be configured through the internal UI via
the video options menu. Made video options menus place initial focus on
the currently selected view item. Removed some crud from the menu base
class.
Fixed the description of the "snapview" option. The value to get raw
screen pixels was changed to "native" a long time ago but the
description was never updated.
Re-arranged the Golden Poker button lamps so that the 6-button layouts
for Jolli Witch and Wild Witch make sense. In 6-button mode, the hold
buttons double as bonus game and bet buttons, but the lamp outputs don't
change. The simplest way to deal with this without requiring the user
to switch views or using layout scripting is to place the dedicated
buttons directly below the hold buttons that correspond to them.
Removed some software list data that was redundantly copied into
device_image_interface (m_supported was never even set, so it didn't
even work), and made crc() work better (previously it wasn't
recalculuated after unloading and loading another image).
Made strformat.h and devcb.h play nicer with C++17 and pre-standard
C++20. Format precision now correctly limits the length of string
views. Confirmed that strformat.{h,cpp} works with pre-standard C++20
support in GCC 9.
Removed an auto_alloc from cpu/arm7.
Diffstat (limited to 'src/frontend')
-rw-r--r-- | src/frontend/mame/iptseqpoll.cpp | 182 | ||||
-rw-r--r-- | src/frontend/mame/iptseqpoll.h | 4 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.cpp | 803 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.h | 2 | ||||
-rw-r--r-- | src/frontend/mame/luaengine.ipp | 85 | ||||
-rw-r--r-- | src/frontend/mame/luaengine_render.cpp | 150 | ||||
-rw-r--r-- | src/frontend/mame/ui/barcode.cpp | 18 | ||||
-rw-r--r-- | src/frontend/mame/ui/devctrl.h | 10 | ||||
-rw-r--r-- | src/frontend/mame/ui/devopt.cpp | 4 | ||||
-rw-r--r-- | src/frontend/mame/ui/info.cpp | 28 | ||||
-rw-r--r-- | src/frontend/mame/ui/inifile.cpp | 8 | ||||
-rw-r--r-- | src/frontend/mame/ui/mainmenu.cpp | 4 | ||||
-rw-r--r-- | src/frontend/mame/ui/menu.cpp | 57 | ||||
-rw-r--r-- | src/frontend/mame/ui/menu.h | 3 | ||||
-rw-r--r-- | src/frontend/mame/ui/miscmenu.cpp | 31 | ||||
-rw-r--r-- | src/frontend/mame/ui/tapectrl.cpp | 8 | ||||
-rw-r--r-- | src/frontend/mame/ui/videoopt.cpp | 111 | ||||
-rw-r--r-- | src/frontend/mame/ui/videoopt.h | 6 |
18 files changed, 722 insertions, 792 deletions
diff --git a/src/frontend/mame/iptseqpoll.cpp b/src/frontend/mame/iptseqpoll.cpp index 145c64f033a..83883e5d970 100644 --- a/src/frontend/mame/iptseqpoll.cpp +++ b/src/frontend/mame/iptseqpoll.cpp @@ -11,7 +11,8 @@ input_code_poller::input_code_poller(input_manager &manager) noexcept : - m_manager(manager) + m_manager(manager), + m_axis_memory() { } @@ -24,26 +25,31 @@ input_code_poller::~input_code_poller() void input_code_poller::reset() { // iterate over device classes and devices + m_axis_memory.clear(); for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) { input_class &devclass(m_manager.device_class(classno)); - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) + if (devclass.enabled()) { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) + for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) + // fetch the device; ignore if nullptr + input_device *const device(devclass.device(devnum)); + if (device) { - // for any non-switch items, set memory to the current value - input_device_item *const item(device->item(itemid)); - if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) - item->set_memory(m_manager.code_value(item->code())); + // iterate over items within each device + for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) + { + // for any non-switch items, set memory to the current value + input_device_item *const item(device->item(itemid)); + if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) + m_axis_memory.emplace_back(item, m_manager.code_value(item->code())); + } } } } } + std::sort(m_axis_memory.begin(), m_axis_memory.end()); } @@ -62,7 +68,7 @@ void switch_code_poller_base::reset() } -bool switch_code_poller_base::code_pressed_once(input_code code) +bool switch_code_poller_base::code_pressed_once(input_code code, bool moved) { // look for the code in the memory bool const pressed(m_manager.code_pressed(code)); @@ -78,7 +84,7 @@ bool switch_code_poller_base::code_pressed_once(input_code code) } // if we get here, we were not previously pressed; if still not pressed, return false - if (!pressed) + if (!pressed || !moved) return false; // otherwise, add the code to the memory and return true @@ -96,31 +102,14 @@ axis_code_poller::axis_code_poller(input_manager &manager) noexcept : input_code axis_code_poller::poll() { - // iterate over device classes and devices, skipping disabled classes - for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) + // iterate over the axis items we found + for (auto memory = m_axis_memory.begin(); m_axis_memory.end() != memory; ++memory) { - input_class &devclass(m_manager.device_class(classno)); - if (devclass.enabled()) + input_code const code = memory->first->code(); + if (memory->first->check_axis(code.item_modifier(), memory->second)) { - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) - { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) - { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) - { - input_device_item *const item(device->item(itemid)); - if (item && (item->itemclass() != ITEM_CLASS_SWITCH)) - { - input_code const code = item->code(); - if (item->check_axis(code.item_modifier())) - return code; - } - } - } - } + m_axis_memory.erase(memory); + return code; } } @@ -142,64 +131,73 @@ input_code switch_code_poller::poll() for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno) { input_class &devclass(m_manager.device_class(classno)); - if (devclass.enabled()) + if (!devclass.enabled()) + continue; + + for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) { - for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum) + // fetch the device; ignore if nullptr + input_device *const device(devclass.device(devnum)); + if (!device) + continue; + + // iterate over items within each device + for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) { - // fetch the device; ignore if nullptr - input_device *const device(devclass.device(devnum)); - if (device) + input_device_item *const item(device->item(itemid)); + if (!item) + continue; + + input_code code = item->code(); + if (item->itemclass() == ITEM_CLASS_SWITCH) { - // iterate over items within each device - for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid) - { - input_device_item *const item(device->item(itemid)); - if (item) - { - input_code code = item->code(); - if (item->itemclass() == ITEM_CLASS_SWITCH) - { - // item is natively a switch, poll it - if (code_pressed_once(code)) - return code; - } - else if (item->check_axis(code.item_modifier())) - { - // poll axes digitally - code.set_item_class(ITEM_CLASS_SWITCH); - if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS)) - { - // joystick X axis - check with left/right modifiers - code.set_item_modifier(ITEM_MODIFIER_LEFT); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_RIGHT); - if (code_pressed_once(code)) - return code; - } - else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS)) - { - // if this is a joystick Y axis, check with up/down modifiers - code.set_item_modifier(ITEM_MODIFIER_UP); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_DOWN); - if (code_pressed_once(code)) - return code; - } - else - { - // any other axis, check with pos/neg modifiers - code.set_item_modifier(ITEM_MODIFIER_POS); - if (code_pressed_once(code)) - return code; - code.set_item_modifier(ITEM_MODIFIER_NEG); - if (code_pressed_once(code)) - return code; - } - } - } - } + // item is natively a switch, poll it + if (code_pressed_once(code, true)) + return code; + else + continue; + } + + auto const memory(std::lower_bound( + m_axis_memory.begin(), + m_axis_memory.end(), + item, + [] (auto const &x, auto const &y) { return x.first < y; })); + if ((m_axis_memory.end() == memory) || (item != memory->first)) + continue; + + // poll axes digitally + bool const moved(item->check_axis(code.item_modifier(), memory->second)); + code.set_item_class(ITEM_CLASS_SWITCH); + if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS)) + { + // joystick X axis - check with left/right modifiers + code.set_item_modifier(ITEM_MODIFIER_LEFT); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_RIGHT); + if (code_pressed_once(code, moved)) + return code; + } + else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS)) + { + // if this is a joystick Y axis, check with up/down modifiers + code.set_item_modifier(ITEM_MODIFIER_UP); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_DOWN); + if (code_pressed_once(code, moved)) + return code; + } + else + { + // any other axis, check with pos/neg modifiers + code.set_item_modifier(ITEM_MODIFIER_POS); + if (code_pressed_once(code, moved)) + return code; + code.set_item_modifier(ITEM_MODIFIER_NEG); + if (code_pressed_once(code, moved)) + return code; } } } @@ -237,7 +235,7 @@ input_code keyboard_code_poller::poll() if (item && (item->itemclass() == ITEM_CLASS_SWITCH)) { input_code const code = item->code(); - if (code_pressed_once(code)) + if (code_pressed_once(code, true)) return code; } } diff --git a/src/frontend/mame/iptseqpoll.h b/src/frontend/mame/iptseqpoll.h index 13c0d9c6484..b9f31f70477 100644 --- a/src/frontend/mame/iptseqpoll.h +++ b/src/frontend/mame/iptseqpoll.h @@ -12,6 +12,7 @@ #pragma once +#include <utility> #include <vector> @@ -27,6 +28,7 @@ protected: input_code_poller(input_manager &manager) noexcept; input_manager &m_manager; + std::vector<std::pair<input_device_item *, s32> > m_axis_memory; }; @@ -38,7 +40,7 @@ public: protected: switch_code_poller_base(input_manager &manager) noexcept; - bool code_pressed_once(input_code code); + bool code_pressed_once(input_code code, bool moved); private: std::vector<input_code> m_switch_memory; diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 4e7fb5412da..98f00a219d0 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -47,7 +47,7 @@ int luaopen_lsqlite3(lua_State *L); template <typename T> struct lua_engine::devenum { - devenum(device_t &d) : device(d), iter(d) { } + template <typename... U> devenum(device_t &d, U &&... args) : device(d), iter(d, std::forward<U>(args)...) { } device_t &device; T iter; @@ -55,18 +55,85 @@ struct lua_engine::devenum }; -template <typename T> -struct lua_engine::object_ptr_vector_wrapper +namespace { + +void do_draw_box(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width; + y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height; + x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width; + y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height; + mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor); +} + +void do_draw_line(screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + x1 = std::min(std::max(0.0f, x1), sc_width) / sc_width; + y1 = std::min(std::max(0.0f, y1), sc_height) / sc_height; + x2 = std::min(std::max(0.0f, x2), sc_width) / sc_width; + y2 = std::min(std::max(0.0f, y2), sc_height) / sc_height; + sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); +} + +void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, const char *msg, rgb_t fgcolor, rgb_t bgcolor) +{ + float const sc_width(sdev.visible_area().width()); + float const sc_height(sdev.visible_area().height()); + auto justify = ui::text_layout::LEFT; + float x = 0; + if (xobj.is<float>()) + { + x = std::min(std::max(0.0f, xobj.as<float>()), sc_width) / sc_width; + } + else if (xobj.is<char const *>()) + { + char const *const justifystr(xobj.as<char const *>()); + if (!strcmp(justifystr, "left")) + justify = ui::text_layout::LEFT; + else if (!strcmp(justifystr, "right")) + justify = ui::text_layout::RIGHT; + else if (!strcmp(justifystr, "center")) + justify = ui::text_layout::CENTER; + } + else + { + luaL_error(L, "Error in param 1 to draw_text"); + return; + } + y = std::min(std::max(0.0f, y), sc_height) / sc_height; + mame_machine_manager::instance()->ui().draw_text_full( + sdev.container(), + msg, + x, y, (1.0f - x), + justify, ui::text_layout::WORD, + mame_ui_manager::OPAQUE_, fgcolor, bgcolor); +} + + +struct image_interface_formats { - object_ptr_vector_wrapper(std::vector<std::unique_ptr<T>> const &v) : vec(v) { } + image_interface_formats(device_image_interface &i) : image(i) { } + device_image_interface::formatlist_type const &items() { return image.formatlist(); } + + static image_device_format const &unwrap(device_image_interface::formatlist_type::const_iterator const &it) { return **it; } + static int push_key(lua_State *L, device_image_interface::formatlist_type::const_iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, (*it)->name()); } - std::vector<std::unique_ptr<T>> const &vec; + device_image_interface ℑ }; +} // anonymous namespace + namespace sol { +template <> struct is_container<image_interface_formats> : std::true_type { }; + + sol::buffer *sol_lua_get(sol::types<buffer *>, lua_State *L, int index, sol::stack::record &tracking) { return new sol::buffer(stack::get<int>(L, index), L); @@ -181,74 +248,30 @@ public: }; -template <typename T> -struct usertype_container<lua_engine::object_ptr_vector_wrapper<T> > : lua_engine::immutable_collection_helper<lua_engine::object_ptr_vector_wrapper<T>, std::vector<std::unique_ptr<T>> const, typename std::vector<std::unique_ptr<T>>::const_iterator> +template <> +struct usertype_container<image_interface_formats> : lua_engine::immutable_sequence_helper<image_interface_formats, device_image_interface::formatlist_type const, device_image_interface::formatlist_type::const_iterator> { private: - static int next_pairs(lua_State *L) - { - typename usertype_container::indexed_iterator &i(stack::unqualified_get<user<typename usertype_container::indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - result = stack::push(L, i.ix + 1); - result += stack::push_reference(L, i.it->get()); - ++i; - return result; - } + using format_list = device_image_interface::formatlist_type; public: - static int at(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.vec.size() < index)) - return stack::push(L, lua_nil); - return stack::push_reference(L, self.vec[index - 1].get()); - } - - static int get(lua_State *L) { return at(L); } - static int index_get(lua_State *L) { return at(L); } - - static int index_of(lua_State *L) + static int get(lua_State *L) { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - T &target(stack::unqualified_get<T>(L, 2)); - auto it(self.vec.begin()); - std::ptrdiff_t ix(0); - while ((self.vec.end() != it) && (it->get() != &target)) - { - ++it; - ++ix; - } - if (self.vec.end() == it) - return stack::push(L, lua_nil); + image_interface_formats &self(get_self(L)); + char const *const name(stack::unqualified_get<char const *>(L)); + auto const found(std::find_if( + self.image.formatlist().begin(), + self.image.formatlist().end(), + [&name] (std::unique_ptr<image_device_format> const &v) { return v->name() == name; })); + if (self.image.formatlist().end() != found) + return stack::push_reference(L, **found); else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - return stack::push(L, self.vec.size()); - } - - static int empty(lua_State *L) - { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - return stack::push(L, self.vec.empty()); + return stack::push(L, lua_nil); } - static int next(lua_State *L) { return stack::push(L, next_pairs); } - static int pairs(lua_State *L) { return ipairs(L); } - - static int ipairs(lua_State *L) + static int index_get(lua_State *L) { - lua_engine::object_ptr_vector_wrapper<T> &self(usertype_container::get_self(L)); - stack::push(L, next_pairs); - stack::push<user<typename usertype_container::indexed_iterator> >(L, self.vec, self.vec.begin()); - stack::push(L, lua_nil); - return 3; + return get(L); } }; @@ -300,6 +323,40 @@ bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler } +int sol_lua_push(sol::types<screen_type_enum>, lua_State *L, screen_type_enum &&value) +{ + switch (value) + { + case SCREEN_TYPE_INVALID: return sol::stack::push(L, "invalid"); + case SCREEN_TYPE_RASTER: return sol::stack::push(L, "raster"); + case SCREEN_TYPE_VECTOR: return sol::stack::push(L, "vector"); + case SCREEN_TYPE_LCD: return sol::stack::push(L, "svg"); + case SCREEN_TYPE_SVG: return sol::stack::push(L, "none"); + } + return sol::stack::push(L, "unknown"); +} + +int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value) +{ + switch (value) + { + case image_init_result::PASS: return sol::stack::push(L, "pass"); + case image_init_result::FAIL: return sol::stack::push(L, "fail"); + } + return sol::stack::push(L, "invalid"); +} + +int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value) +{ + switch (value) + { + case image_verify_result::PASS: return sol::stack::push(L, "pass"); + case image_verify_result::FAIL: return sol::stack::push(L, "fail"); + } + return sol::stack::push(L, "invalid"); +} + + //------------------------------------------------- // process_snapshot_filename - processes a snapshot // filename @@ -558,14 +615,6 @@ void lua_engine::initialize() }; - static const enum_parser<ui::text_layout::text_justify, 3> s_text_justify_parser = - { - { "left", ui::text_layout::LEFT }, - { "right", ui::text_layout::RIGHT }, - { "center", ui::text_layout::CENTER }, - }; - - static const enum_parser<int, 3> s_seek_parser = { { "set", SEEK_SET }, @@ -617,6 +666,7 @@ void lua_engine::initialize() * emu.device_enumerator(dev) - get device enumerator starting at arbitrary point in tree * emu.screen_enumerator(dev) - get screen device enumerator starting at arbitrary point in tree * emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree + * emu.image_enumerator(dev) - get image interface enumerator starting at arbitrary point in tree */ sol::table emu = sol().create_named_table("emu"); @@ -712,9 +762,21 @@ void lua_engine::initialize() osd_subst_env(result, str); return result; }; - emu["device_enumerator"] = [] (device_t &d) { return devenum<device_enumerator>(d); }; - emu["screen_enumerator"] = [] (device_t &d) { return devenum<screen_device_enumerator>(d); }; - emu["image_enumerator"] = [] (device_t &d) { return devenum<image_interface_enumerator>(d); }; + emu["device_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<device_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<device_enumerator>(dev, maxdepth); }); + emu["screen_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<screen_device_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<screen_device_enumerator>(dev, maxdepth); }); + emu["cassette_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<cassette_device_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<cassette_device_enumerator>(dev, maxdepth); }); + emu["image_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<image_interface_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<image_interface_enumerator>(dev, maxdepth); }); + emu["slot_enumerator"] = sol::overload( + [] (device_t &dev) { return devenum<slot_interface_enumerator>(dev); }, + [] (device_t &dev, int maxdepth) { return devenum<slot_interface_enumerator>(dev, maxdepth); }); /* emu_file library @@ -1313,33 +1375,6 @@ void lua_engine::initialize() game_driver_type["is_incomplete"] = sol::property([] (game_driver const &driver) { return (driver.flags & machine_flags::IS_INCOMPLETE) != 0; }); -/* device_t library - * - * manager:machine().devices[device_tag] - * - * device:subtag(tag) - get absolute tag relative to this device - * device:siblingtag(tag) - get absolute tag relative to this device - * device:memregion(tag) - get memory region - * device:memshare(tag) - get memory share - * device:membank(tag) - get memory bank - * device:ioport(tag) - get I/O port - * device:subdevice(tag) - get subdevice - * device:siblingdevice(tag) - get sibling device - * device:debug() - debug interface, CPUs only - * - * device.tag - device tree tag - * device.basetag - last component of tag ("root" for root device) - * device.name - device type full name - * device.shortname - device type short name - * device.owner - parent device (nil for root device) - * device.configured - whether configuration is complete - * device.started - whether the device has been started - * device.spaces[] - device address spaces table (k=name, v=addr_space) - * device.state[] - device state entries table (k=name, v=device_state_entry) - * device.items[] - device save state items table (k=name, v=index) - * device.roms[] - device rom entry table (k=name, v=rom_entry) - */ - auto device_type = sol().registry().new_usertype<device_t>("device", sol::no_constructor); device_type["subtag"] = &device_t::subtag; device_type["siblingtag"] = &device_t::siblingtag; @@ -1349,13 +1384,6 @@ void lua_engine::initialize() device_type["ioport"] = &device_t::ioport; device_type["subdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::subdevice); device_type["siblingdevice"] = static_cast<device_t *(device_t::*)(char const *) const>(&device_t::siblingdevice); - device_type["debug"] = - [this] (device_t &dev) -> sol::object - { - if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu - return sol::make_object(sol(), sol::lua_nil); - return sol::make_object(sol(), dev.debug()); - }; device_type["tag"] = sol::property(&device_t::tag); device_type["basetag"] = sol::property(&device_t::basetag); device_type["name"] = sol::property(&device_t::name); @@ -1363,20 +1391,28 @@ void lua_engine::initialize() device_type["owner"] = sol::property(&device_t::owner); device_type["configured"] = sol::property(&device_t::configured); device_type["started"] = sol::property(&device_t::started); + device_type["debug"] = sol::property( + [this] (device_t &dev) -> sol::object + { + if (!(dev.machine().debug_flags & DEBUG_FLAG_ENABLED) || !dynamic_cast<cpu_device *>(&dev)) // debugger not enabled or not cpu + return sol::make_object(sol(), sol::lua_nil); + return sol::make_object(sol(), dev.debug()); + }); device_type["spaces"] = sol::property( [this] (device_t &dev) { - device_memory_interface *memdev = dynamic_cast<device_memory_interface *>(&dev); + device_memory_interface *const memdev = dynamic_cast<device_memory_interface *>(&dev); sol::table sp_table = sol().create_table(); - if(!memdev) + if (!memdev) return sp_table; - for(int sp = 0; sp < memdev->max_space_count(); ++sp) + for (int sp = 0; sp < memdev->max_space_count(); ++sp) { - if(memdev->has_space(sp)) + if (memdev->has_space(sp)) sp_table[memdev->space(sp).name()] = addr_space(memdev->space(sp), *memdev); } return sp_table; }); + // FIXME: improve this device_type["state"] = sol::property( [this] (device_t &dev) { @@ -1388,41 +1424,246 @@ void lua_engine::initialize() st_table[s->symbol()] = s.get(); return st_table; }); + // FIXME: turn into a wrapper - it's stupid slow to walk on every property access + // also, this mixes up things like RAM areas with stuff saved by the device itself, so there's potential for key conflicts device_type["items"] = sol::property( [this] (device_t &dev) { sol::table table = sol().create_table(); - std::string tag = dev.tag(); - // 10000 is enough? - for(int i = 0; i < 10000; i++) + std::string const tag = dev.tag(); + for (int i = 0; ; i++) { - std::string name; - const char *item; + char const *item; void *base; uint32_t size, valcount, blockcount, stride; item = dev.machine().save().indexed_item(i, base, size, valcount, blockcount, stride); - if(!item) + if (!item) break; - name = &(strchr(item, '/')[1]); - if(name.substr(0, name.find('/')) == tag) - { - name = name.substr(name.find('/') + 1, std::string::npos); - table[name] = i; - } + + char const *name = &strchr(item, '/')[1]; + if (!strncmp(tag.c_str(), name, tag.length()) && (name[tag.length()] == '/')) + table[name + tag.length() + 1] = i; } return table; }); + // FIXME: this is useless in its current form device_type["roms"] = sol::property( [this] (device_t &dev) { sol::table table = sol().create_table(); - for(auto rom : dev.rom_region_vector()) - if(!rom.name().empty()) + for (auto rom : dev.rom_region_vector()) + if (!rom.name().empty()) table[rom.name()] = rom; return table; }); + auto screen_dev_type = sol().registry().new_usertype<screen_device>( + "screen_dev", + sol::no_constructor, + sol::base_classes, sol::bases<device_t>()); + screen_dev_type["draw_box"] = sol::overload( + [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor, uint32_t bgcolor) + { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, bgcolor); }, + [] (screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t fgcolor) + { do_draw_box(sdev, x1, y1, x2, y2, fgcolor, mame_machine_manager::instance()->ui().colors().background_color()); }, + [] (screen_device &sdev, float x1, float y1, float x2, float y2) + { auto const &colors(mame_machine_manager::instance()->ui().colors()); do_draw_box(sdev, x1, y1, x2, y2, colors.text_color(), colors.background_color()); }); + screen_dev_type["draw_line"] = sol::overload( + &do_draw_line, + [] (screen_device &sdev, float x1, float y1, float x2, float y2) + { do_draw_line(sdev, x1, y1, x2, y2, mame_machine_manager::instance()->ui().colors().text_color()); }); + screen_dev_type["draw_text"] = sol::overload( + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor, uint32_t bgcolor) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, bgcolor); }, + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg, uint32_t fgcolor) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, fgcolor, 0); }, + [this] (screen_device &sdev, sol::object xobj, float y, const char *msg) + { do_draw_text(m_lua_state, sdev, xobj, y, msg, mame_machine_manager::instance()->ui().colors().text_color(), 0); }); + screen_dev_type["orientation"] = + [] (screen_device &sdev) + { + uint32_t flags = sdev.orientation(); + int rotation_angle = 0; + switch (flags) + { + case ORIENTATION_SWAP_XY: + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X: + rotation_angle = 90; + flags ^= ORIENTATION_FLIP_X; + break; + case ORIENTATION_FLIP_Y: + case ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y: + rotation_angle = 180; + flags ^= ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y; + break; + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y: + case ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y: + rotation_angle = 270; + flags ^= ORIENTATION_FLIP_Y; + break; + } + return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y); + }; + screen_dev_type["time_until_pos"] = sol::overload( + [] (screen_device &sdev, int vpos) { return sdev.time_until_pos(vpos).as_double(); }, + [] (screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); }); + screen_dev_type["time_until_vblank_start"] = &screen_device::time_until_vblank_start; + screen_dev_type["time_until_vblank_end"] = &screen_device::time_until_vblank_end; + screen_dev_type["snapshot"] = + [this] (screen_device &sdev, char const *filename) -> sol::object + { + std::string snapstr; + bool is_absolute_path = false; + if (filename) + { + // a filename was specified; if it isn't absolute post-process it + snapstr = process_snapshot_filename(machine(), filename); + is_absolute_path = osd_is_absolute_path(snapstr); + } + + // open the file + emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); + osd_file::error filerr; + if (!snapstr.empty()) + filerr = file.open(snapstr); + else + filerr = machine().video().open_next(file, "png"); + if (filerr != osd_file::error::NONE) + return sol::make_object(sol(), filerr); + + // and save the snapshot + machine().video().save_snapshot(&sdev, file); + return sol::make_object(sol(), sol::lua_nil); + }; + screen_dev_type["pixel"] = [] (screen_device &sdev, s32 x, s32 y) { return sdev.pixel(x, y); }; + screen_dev_type["pixels"] = + [] (screen_device &sdev, sol::this_state s) + { + lua_State *L = s; + const rectangle &visarea = sdev.visible_area(); + luaL_Buffer buff; + int size = visarea.height() * visarea.width() * 4; + u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size); + sdev.pixels(ptr); + luaL_pushresultsize(&buff, size); + return sol::make_reference(L, sol::stack_reference(L, -1)); + }; + screen_dev_type["screen_type"] = sol::property(&screen_device::screen_type); + screen_dev_type["width"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().width(); }); + screen_dev_type["height"] = sol::property([] (screen_device &sdev) { return sdev.visible_area().height(); }); + screen_dev_type["refresh"] = sol::property([] (screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); }); + screen_dev_type["refresh_attoseconds"] = sol::property([] (screen_device &sdev) { return sdev.refresh_attoseconds(); }); + screen_dev_type["xofffset"] = sol::property(&screen_device::xoffset); + screen_dev_type["yofffset"] = sol::property(&screen_device::yoffset); + screen_dev_type["xscale"] = sol::property(&screen_device::xscale); + screen_dev_type["yscale"] = sol::property(&screen_device::yscale); + screen_dev_type["pixel_period"] = sol::property([] (screen_device &sdev) { return sdev.pixel_period().as_double(); }); + screen_dev_type["scan_period"] = sol::property([] (screen_device &sdev) { return sdev.scan_period().as_double(); }); + screen_dev_type["frame_period"] = sol::property([] (screen_device &sdev) { return sdev.frame_period().as_double(); }); + screen_dev_type["frame_number"] = &screen_device::frame_number; + screen_dev_type["container"] = sol::property(&screen_device::container); + + + auto cass_type = sol().registry().new_usertype<cassette_image_device>( + "cassette", + sol::no_constructor, + sol::base_classes, sol::bases<device_t, device_image_interface>()); + cass_type["stop"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); }; + cass_type["play"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); }; + cass_type["record"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); }; + cass_type["forward"] = &cassette_image_device::go_forward; + cass_type["reverse"] = &cassette_image_device::go_reverse; + cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); }; + cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped); + cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing); + cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording); + cass_type["motor_state"] = sol::property(&cassette_image_device::motor_on, &cassette_image_device::set_motor); + cass_type["speaker_state"] = sol::property(&cassette_image_device::speaker_on, &cassette_image_device::set_speaker); + cass_type["position"] = sol::property(&cassette_image_device::get_position); + cass_type["length"] = sol::property([] (cassette_image_device &c) { return c.exists() ? c.get_length() : 0.0; }); + + + auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor); + image_type["load"] = &device_image_interface::load; + image_type["load_software"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software); + image_type["unload"] = &device_image_interface::unload; + image_type["create"] = static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::create); + image_type["display"] = &device_image_interface::call_display; + image_type["is_readable"] = sol::property(&device_image_interface::is_readable); + image_type["is_writeable"] = sol::property(&device_image_interface::is_writeable); + image_type["is_creatable"] = sol::property(&device_image_interface::is_creatable); + image_type["must_be_loaded"] = sol::property(&device_image_interface::must_be_loaded); + image_type["is_reset_on_load"] = sol::property(&device_image_interface::is_reset_on_load); + image_type["image_type_name"] = sol::property(&device_image_interface::image_type_name); + image_type["instance_name"] = sol::property(&device_image_interface::instance_name); + image_type["brief_instance_name"] = sol::property(&device_image_interface::brief_instance_name); + image_type["formatlist"] = sol::property([] (device_image_interface &image) { return image_interface_formats(image); }); + image_type["exists"] = sol::property(&device_image_interface::exists); + image_type["readonly"] = sol::property(&device_image_interface::is_readonly); + image_type["filename"] = sol::property(&device_image_interface::filename); + image_type["crc"] = sol::property(&device_image_interface::crc); + image_type["loaded_through_softlist"] = sol::property(&device_image_interface::loaded_through_softlist); + image_type["software_list_name"] = sol::property(&device_image_interface::software_list_name); + image_type["software_longname"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->longname().c_str() : nullptr; + }); + image_type["software_publisher"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->publisher().c_str() : nullptr; + }); + image_type["software_year"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->year().c_str() : nullptr; + }); + image_type["software_parent"] = sol::property( + [] (device_image_interface &di) + { + software_info const *const si(di.software_entry()); + return si ? si->parentname().c_str() : nullptr; + }); + image_type["device"] = sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device)); + + + auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor); + format_type["name"] = sol::property(&image_device_format::name); + format_type["description"] = sol::property(&image_device_format::description); + format_type["extensions"] = sol::property( + [this] (image_device_format const &format) + { + int index = 1; + sol::table option_table = sol().create_table(); + for (std::string const &ext : format.extensions()) + option_table[index++] = ext; + return option_table; + }); + format_type["option_spec"] = sol::property(&image_device_format::optspec); + + + auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor); + slot_type["fixed"] = sol::property(&device_slot_interface::fixed); + slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options); + slot_type["default_option"] = sol::property(&device_slot_interface::default_option); + slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); }); + slot_type["device"] = sol::property(static_cast<device_t & (device_slot_interface::*)()>(&device_slot_interface::device)); + + + auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor); + dislot_option_type["name"] = sol::property(&device_slot_interface::slot_option::name); + dislot_option_type["device_fullname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().fullname(); }); + dislot_option_type["device_shortname"] = sol::property([] (device_slot_interface::slot_option &opt) { return opt.devtype().shortname(); }); + dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable); + dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios)); + dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock)); + + /* parameters_manager library * * manager:machine():parameters() @@ -1537,160 +1778,6 @@ void lua_engine::initialize() sound_type.set("attenuation", sol::property(&sound_manager::attenuation, &sound_manager::set_attenuation)); -/* screen_device library - * - * manager:machine().screens[screen_tag] - * - * screen:draw_box(x1, y1, x2, y2, fillcol, linecol) - draw box from (x1, y1)-(x2, y2) colored linecol - * filled with fillcol, color is 32bit argb - * screen:draw_line(x1, y1, x2, y2, linecol) - draw line from (x1, y1)-(x2, y2) colored linecol - * screen:draw_text(x || justify, y, message, [opt] fgcolor, [opt] bgcolor) - draw message at (x, y) or at line y - * with left/right/center justification - * screen:height() - screen height - * screen:width() - screen width - * screen:orientation() - screen angle, flipx, flipy - * screen:refresh() - screen refresh rate in Hz - * screen:refresh_attoseconds() - screen refresh rate in attoseconds - * screen:snapshot([opt] filename) - save snap shot - * screen:type() - screen drawing type - * screen:frame_number() - screen frame count - * screen:xscale() - screen x scale factor - * screen:yscale() - screen y scale factor - * screen:pixel(x, y) - get pixel at (x, y) as packed RGB in a u32 - * screen:pixels() - get whole screen binary bitmap as string - * screen:time_until_pos(vpos, hpos) - get the time until this screen pos is reached - */ - - auto screen_dev_type = sol().registry().new_usertype<screen_device>( - "screen_dev", - sol::no_constructor, - sol::base_classes, sol::bases<device_t>()); - screen_dev_type.set("container", sol::property(&screen_device::container)); - screen_dev_type.set("draw_box", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t bgcolor, uint32_t fgcolor) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width); - y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height); - x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width); - y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height); - mame_machine_manager::instance()->ui().draw_outlined_box(sdev.container(), x1, y1, x2, y2, fgcolor, bgcolor); - }); - screen_dev_type.set("draw_line", [](screen_device &sdev, float x1, float y1, float x2, float y2, uint32_t color) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - x1 = std::min(std::max(0.0f, x1), float(sc_width-1)) / float(sc_width); - y1 = std::min(std::max(0.0f, y1), float(sc_height-1)) / float(sc_height); - x2 = std::min(std::max(0.0f, x2), float(sc_width-1)) / float(sc_width); - y2 = std::min(std::max(0.0f, y2), float(sc_height-1)) / float(sc_height); - sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); - }); - screen_dev_type.set("draw_text", [this](screen_device &sdev, sol::object xobj, float y, const char *msg, sol::object color, sol::object bcolor) { - int sc_width = sdev.visible_area().width(); - int sc_height = sdev.visible_area().height(); - auto justify = ui::text_layout::LEFT; - float x = 0; - if(xobj.is<float>()) - { - x = std::min(std::max(0.0f, xobj.as<float>()), float(sc_width-1)) / float(sc_width); - y = std::min(std::max(0.0f, y), float(sc_height-1)) / float(sc_height); - } - else if(xobj.is<const char *>()) - { - justify = s_text_justify_parser(xobj.as<const char *>()); - } - else - { - luaL_error(m_lua_state, "Error in param 1 to draw_text"); - return; - } - rgb_t textcolor = mame_machine_manager::instance()->ui().colors().text_color(); - rgb_t bgcolor = 0; - if(color.is<uint32_t>()) - textcolor = rgb_t(color.as<uint32_t>()); - if(bcolor.is<uint32_t>()) - bgcolor = rgb_t(bcolor.as<uint32_t>()); - mame_machine_manager::instance()->ui().draw_text_full(sdev.container(), msg, x, y, (1.0f - x), - justify, ui::text_layout::WORD, mame_ui_manager::OPAQUE_, textcolor, bgcolor); - }); - screen_dev_type.set("height", [](screen_device &sdev) { return sdev.visible_area().height(); }); - screen_dev_type.set("width", [](screen_device &sdev) { return sdev.visible_area().width(); }); - screen_dev_type.set("orientation", [](screen_device &sdev) { - uint32_t flags = sdev.orientation(); - int rotation_angle = 0; - switch (flags) - { - case ORIENTATION_FLIP_X: - rotation_angle = 0; - break; - case ORIENTATION_SWAP_XY: - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X: - rotation_angle = 90; - break; - case ORIENTATION_FLIP_Y: - case ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - rotation_angle = 180; - break; - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_Y: - case ORIENTATION_SWAP_XY|ORIENTATION_FLIP_X|ORIENTATION_FLIP_Y: - rotation_angle = 270; - break; - } - return std::tuple<int, bool, bool>(rotation_angle, flags & ORIENTATION_FLIP_X, flags & ORIENTATION_FLIP_Y); - }); - screen_dev_type.set("refresh", [](screen_device &sdev) { return ATTOSECONDS_TO_HZ(sdev.refresh_attoseconds()); }); - screen_dev_type.set("refresh_attoseconds", [](screen_device &sdev) { return sdev.refresh_attoseconds(); }); - screen_dev_type.set("snapshot", [this](screen_device &sdev, sol::object filename) -> sol::object { - std::string snapstr; - bool is_absolute_path = false; - if (filename.is<const char *>()) - { - // a filename was specified; if it isn't absolute postprocess it - snapstr = process_snapshot_filename(machine(), filename.as<const char *>()); - is_absolute_path = osd_is_absolute_path(snapstr); - } - - // open the file - emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); - osd_file::error filerr; - if (!snapstr.empty()) - filerr = file.open(snapstr); - else - filerr = machine().video().open_next(file, "png"); - if (filerr != osd_file::error::NONE) - return sol::make_object(sol(), filerr); - - // and save the snapshot - machine().video().save_snapshot(&sdev, file); - return sol::make_object(sol(), sol::lua_nil); - }); - screen_dev_type.set("type", [](screen_device &sdev) { - switch (sdev.screen_type()) - { - case SCREEN_TYPE_RASTER: return "raster"; break; - case SCREEN_TYPE_VECTOR: return "vector"; break; - case SCREEN_TYPE_LCD: return "lcd"; break; - case SCREEN_TYPE_SVG: return "svg"; break; - default: break; - } - return "unknown"; - }); - screen_dev_type.set("frame_number", &screen_device::frame_number); - screen_dev_type.set("xscale", &screen_device::xscale); - screen_dev_type.set("yscale", &screen_device::yscale); - screen_dev_type.set("pixel", [](screen_device &sdev, float x, float y) { return sdev.pixel((s32)x, (s32)y); }); - screen_dev_type.set("pixels", [](screen_device &sdev, sol::this_state s) { - lua_State *L = s; - const rectangle &visarea = sdev.visible_area(); - luaL_Buffer buff; - int size = visarea.height() * visarea.width() * 4; - u32 *ptr = (u32 *)luaL_buffinitsize(L, &buff, size); - sdev.pixels(ptr); - luaL_pushresultsize(&buff, size); - return sol::make_reference(L, sol::stack_reference(L, -1)); - }); - screen_dev_type.set("time_until_pos", [](screen_device &sdev, int vpos, int hpos) { return sdev.time_until_pos(vpos, hpos).as_double(); }); - - /* mame_ui_manager library * * manager:ui() @@ -1799,160 +1886,6 @@ void lua_engine::initialize() output_type.set("id_to_name", &output_manager::id_to_name); -/* device_image_interface library - * - * manager:machine().images[image_type] - * - * image:exists() - * image:filename() - full path to the image file - * image:longname() - * image:manufacturer() - * image:year() - * image:software_list_name() - * image:image_type_name() - floppy/cart/cdrom/tape/hdd etc - * image:load(filename) - * image:load_software(softlist_name) - * image:unload() - * image:create() - * image:crc() - * image:display() - * - * image.device - get associated device_t - * image.instance_name - * image.brief_instance_name - * image.software_parent - * image.is_readable - * image.is_writeable - * image.is_creatable - * image.is_reset_on_load - * image.must_be_loaded - * image.formatlist - */ - - auto image_type = sol().registry().new_usertype<device_image_interface>("image", "new", sol::no_constructor); - image_type.set("exists", &device_image_interface::exists); - image_type.set("filename", &device_image_interface::filename); - image_type.set("longname", &device_image_interface::longname); - image_type.set("manufacturer", &device_image_interface::manufacturer); - image_type.set("year", &device_image_interface::year); - image_type.set("software_list_name", &device_image_interface::software_list_name); - image_type.set("software_parent", sol::property([](device_image_interface &di) { - const software_info *si = di.software_entry(); - return si ? si->parentname() : ""; - })); - image_type.set("image_type_name", &device_image_interface::image_type_name); - image_type.set("load", &device_image_interface::load); - image_type.set("load_software", static_cast<image_init_result (device_image_interface::*)(const std::string &)>(&device_image_interface::load_software)); - image_type.set("unload", &device_image_interface::unload); - image_type.set("create", [](device_image_interface &di, const std::string &filename) { return di.create(filename); }); - image_type.set("crc", &device_image_interface::crc); - image_type.set("display", [](device_image_interface &di) { return di.call_display(); }); - image_type.set("device", sol::property(static_cast<device_t & (device_image_interface::*)()>(&device_image_interface::device))); - image_type.set("instance_name", sol::property(&device_image_interface::instance_name)); - image_type.set("brief_instance_name", sol::property(&device_image_interface::brief_instance_name)); - image_type.set("is_readable", sol::property(&device_image_interface::is_readable)); - image_type.set("is_writeable", sol::property(&device_image_interface::is_writeable)); - image_type.set("is_creatable", sol::property(&device_image_interface::is_creatable)); - image_type.set("is_reset_on_load", sol::property(&device_image_interface::is_reset_on_load)); - image_type.set("must_be_loaded", sol::property(&device_image_interface::must_be_loaded)); - image_type.set("formatlist", sol::property([](const device_image_interface &image) { return object_ptr_vector_wrapper<image_device_format>(image.formatlist()); })); - - -/* image_device_format library - * - * manager:machine().images[tag].formatlist[index] - * - * format.name - name of the format (e.g. - "dsk") - * format.description - the description of the format - * format.extensions - all of the extensions, as an array - * format.optspec - the option spec associated with the format - * - */ - auto format_type = sol().registry().new_usertype<image_device_format>("image_format", sol::no_constructor); - format_type["name"] = sol::property(&image_device_format::name); - format_type["description"] = sol::property(&image_device_format::description); - format_type["optspec"] = sol::property(&image_device_format::optspec); - format_type["extensions"] = sol::property([this](const image_device_format &format) { - int index = 1; - sol::table option_table = sol().create_table(); - for (const std::string &ext : format.extensions()) - option_table[index++] = ext; - return option_table; - }); - - -/* device_slot_interface library - * - * manager:machine().slots[slot_name] - * - * slot.fixed - whether this slot is fixed, and hence not selectable by the user - * slot.has_selectable_options - does this slot have any selectable options at all? - * slot.default_option - returns the default option if one exists - * slot.options[] - get options table (k=name, v=device_slot_interface::slot_option) - */ - - auto slot_type = sol().registry().new_usertype<device_slot_interface>("slot", sol::no_constructor); - slot_type["fixed"] = sol::property(&device_slot_interface::fixed); - slot_type["has_selectable_options"] = sol::property(&device_slot_interface::has_selectable_options); - slot_type["default_option"] = sol::property(&device_slot_interface::default_option); - slot_type["options"] = sol::property([] (device_slot_interface const &slot) { return standard_tag_object_ptr_map<device_slot_interface::slot_option>(slot.option_list()); }); - - -/* device_slot_interface::slot_option library - * - * manager:machine().slots[slot_name].options[option_name] - * - * slot_option.selectable - is this item selectable by the user? - * slot_option.default_bios - the default bios for this option - * slot_option.clock - the clock speed associated with this option - */ - - auto dislot_option_type = sol().registry().new_usertype<device_slot_interface::slot_option>("dislot_option", sol::no_constructor); - dislot_option_type["selectable"] = sol::property(&device_slot_interface::slot_option::selectable); - dislot_option_type["default_bios"] = sol::property(static_cast<char const * (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::default_bios)); - dislot_option_type["clock"] = sol::property(static_cast<u32 (device_slot_interface::slot_option::*)() const>(&device_slot_interface::slot_option::clock)); - - -/* cassette_image_device library - * - * manager:machine().cassettes[cass_name] - * - * cass:play() - * cass:stop() - * cass:record() - * cass:forward() - forward play direction - * cass:reverse() - reverse play direction - * cass:seek(time, origin) - seek time sec from origin: "set", "cur", "end" - * - * cass.is_stopped - * cass.is_playing - * cass.is_recording - * cass.motor_state - * cass.speaker_state - * cass.position - * cass.length - * cass.image - get the device_image_interface for this cassette device - */ - - auto cass_type = sol().registry().new_usertype<cassette_image_device>( - "cassette", - sol::no_constructor, - sol::base_classes, sol::bases<device_t, device_image_interface>()); - cass_type["stop"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_STOPPED, CASSETTE_MASK_UISTATE); }; - cass_type["play"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_PLAY, CASSETTE_MASK_UISTATE); }; - cass_type["record"] = [] (cassette_image_device &c) { c.change_state(CASSETTE_RECORD, CASSETTE_MASK_UISTATE); }; - cass_type["forward"] = &cassette_image_device::go_forward; - cass_type["reverse"] = &cassette_image_device::go_reverse; - cass_type["seek"] = [] (cassette_image_device &c, double time, const char* origin) { if (c.exists()) c.seek(time, s_seek_parser(origin)); }; - cass_type["is_stopped"] = sol::property(&cassette_image_device::is_stopped); - cass_type["is_playing"] = sol::property(&cassette_image_device::is_playing); - cass_type["is_recording"] = sol::property(&cassette_image_device::is_recording); - cass_type["motor_state"] = sol::property(&cassette_image_device::motor_on, &cassette_image_device::set_motor); - cass_type["speaker_state"] = sol::property(&cassette_image_device::speaker_on, &cassette_image_device::set_speaker); - cass_type["position"] = sol::property(&cassette_image_device::get_position); - cass_type["length"] = sol::property([] (cassette_image_device &c) { return c.exists() ? c.get_length() : 0.0; }); - - /* mame_machine_manager library * * manager diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h index b0bbf2210c3..973dfedfd89 100644 --- a/src/frontend/mame/luaengine.h +++ b/src/frontend/mame/luaengine.h @@ -34,11 +34,11 @@ public: // helper structures template <typename T> struct devenum; template <typename T> struct simple_list_wrapper; - template <typename T> struct object_ptr_vector_wrapper; template <typename T> struct tag_object_ptr_map; template <typename T> using standard_tag_object_ptr_map = tag_object_ptr_map<std::unordered_map<std::string, std::unique_ptr<T> > >; template <typename T> struct immutable_container_helper; template <typename T, typename C, typename I = typename C::iterator> struct immutable_collection_helper; + template <typename T, typename C, typename I = typename C::iterator> struct immutable_sequence_helper; // construction/destruction lua_engine(); diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp index 8d51fb0a092..d532b8be1b4 100644 --- a/src/frontend/mame/luaengine.ipp +++ b/src/frontend/mame/luaengine.ipp @@ -89,7 +89,6 @@ int sol_lua_push(sol::types<buffer *>, lua_State *L, buffer *value); template <typename T> struct is_container<lua_engine::devenum<T> > : std::true_type { }; template <typename T> struct is_container<lua_engine::simple_list_wrapper<T> > : std::true_type { }; template <typename T> struct is_container<lua_engine::tag_object_ptr_map<T> > : std::true_type { }; -template <typename T> struct is_container<lua_engine::object_ptr_vector_wrapper<T> > : std::true_type { }; template <typename T> struct usertype_container<lua_engine::devenum<T> >; @@ -256,7 +255,6 @@ public: static int ipairs(lua_State *L) { return start_pairs<true>(L); } }; - } // namespace sol @@ -265,10 +263,10 @@ int sol_lua_push(sol::types<osd_file::error>, lua_State *L, osd_file::error &&va template <typename Handler> bool sol_lua_check(sol::types<osd_file::error>, lua_State *L, int index, Handler &&handler, sol::stack::record &tracking); -// map_handler_type customisation +// enums to automatically convert to strings int sol_lua_push(sol::types<map_handler_type>, lua_State *L, map_handler_type &&value); - -// endianness_t customisation +int sol_lua_push(sol::types<image_init_result>, lua_State *L, image_init_result &&value); +int sol_lua_push(sol::types<image_verify_result>, lua_State *L, image_verify_result &&value); int sol_lua_push(sol::types<endianness_t>, lua_State *L, endianness_t &&value); @@ -353,6 +351,83 @@ protected: }; +template <typename T, typename C, typename I> +struct lua_engine::immutable_sequence_helper : immutable_collection_helper<T, C, I> +{ +protected: + template <bool Indexed> + static int next_pairs(lua_State *L) + { + auto &i(sol::stack::unqualified_get<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, 1)); + if (i.src.end() == i.it) + return sol::stack::push(L, sol::lua_nil); + int result; + if constexpr (Indexed) + result = sol::stack::push(L, i.ix + 1); + else + result = T::push_key(L, i.it, i.ix); + result += sol::stack::push_reference(L, T::unwrap(i.it)); + ++i; + return result; + } + + template <bool Indexed> + static int start_pairs(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + sol::stack::push(L, next_pairs<Indexed>); + sol::stack::push<sol::user<typename immutable_sequence_helper::indexed_iterator> >(L, self.items(), self.items().begin()); + sol::stack::push(L, sol::lua_nil); + return 3; + } + +public: + static int at(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + std::ptrdiff_t const index(sol::stack::unqualified_get<std::ptrdiff_t>(L, 2)); + if ((0 >= index) || (self.items().size() < index)) + return sol::stack::push(L, sol::lua_nil); + else + return sol::stack::push_reference(L, T::unwrap(std::next(self.items().begin(), index - 1))); + } + + static int index_of(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + auto it(self.items().begin()); + std::ptrdiff_t ix(0); + auto const &item(sol::stack::unqualified_get<decltype(T::unwrap(it))>(L, 2)); + while ((self.items().end() != it) && (&item != &T::unwrap(it))) + { + ++it; + ++ix; + } + if (self.items().end() == it) + return sol::stack::push(L, sol::lua_nil); + else + return sol::stack::push(L, ix + 1); + } + + static int size(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + return sol::stack::push(L, self.items().size()); + } + + static int empty(lua_State *L) + { + T &self(immutable_sequence_helper::get_self(L)); + return sol::stack::push(L, self.items().empty()); + } + + static int next(lua_State *L) { return sol::stack::push(L, next_pairs<false>); } + static int pairs(lua_State *L) { return start_pairs<false>(L); } + static int ipairs(lua_State *L) { return start_pairs<true>(L); } +}; + + + struct lua_engine::addr_space { addr_space(address_space &s, device_memory_interface &d) : space(s), dev(d) { } diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp index ca472dba675..b910a717561 100644 --- a/src/frontend/mame/luaengine_render.cpp +++ b/src/frontend/mame/luaengine_render.cpp @@ -21,6 +21,10 @@ namespace { struct layout_file_views { layout_file_views(layout_file &f) : file(f) { } + layout_file::view_list &items() { return file.views(); } + + static layout_view &unwrap(layout_file::view_list::iterator const &it) { return *it; } + static int push_key(lua_State *L, layout_file::view_list::iterator const &it, std::size_t ix) { return sol::stack::push_reference(L, it->unqualified_name()); } layout_file &file; }; @@ -29,6 +33,10 @@ struct layout_file_views struct layout_view_items { layout_view_items(layout_view &v) : view(v) { } + layout_view::item_list &items() { return view.items(); } + + static layout_view::item &unwrap(layout_view::item_list::iterator const &it) { return *it; } + static int push_key(lua_State *L, layout_view::item_list::iterator const &it, std::size_t ix) { return sol::stack::push(L, ix + 1); } layout_view &view; }; @@ -53,48 +61,9 @@ template <> struct is_container<render_target_view_names> : std::true_type { }; template <> -struct usertype_container<layout_file_views> : lua_engine::immutable_collection_helper<layout_file_views, layout_file::view_list> +struct usertype_container<layout_file_views> : lua_engine::immutable_sequence_helper<layout_file_views, layout_file::view_list> { -private: - using view_list = layout_file::view_list; - - template <bool Indexed> - static int next_pairs(lua_State *L) - { - indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - if constexpr (Indexed) - result = stack::push(L, i.ix + 1); - else - result = stack::push_reference(L, i.it->unqualified_name()); - result += stack::push_reference(L, *i.it); - ++i; - return result; - } - - template <bool Indexed> - static int start_pairs(lua_State *L) - { - layout_file_views &self(get_self(L)); - stack::push(L, next_pairs<Indexed>); - stack::push<user<indexed_iterator> >(L, self.file.views(), self.file.views().begin()); - stack::push(L, lua_nil); - return 3; - } - public: - static int at(lua_State *L) - { - layout_file_views &self(get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.file.views().size() < index)) - return stack::push(L, lua_nil); - else - return stack::push_reference(L, *std::next(self.file.views().begin(), index - 1)); - } - static int get(lua_State *L) { layout_file_views &self(get_self(L)); @@ -113,72 +82,13 @@ public: { return get(L); } - - static int index_of(lua_State *L) - { - layout_file_views &self(get_self(L)); - layout_view &view(stack::unqualified_get<layout_view>(L, 2)); - auto it(self.file.views().begin()); - std::ptrdiff_t ix(0); - while ((self.file.views().end() != it) && (&view != &*it)) - { - ++it; - ++ix; - } - if (self.file.views().end() == it) - return stack::push(L, lua_nil); - else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - layout_file_views &self(get_self(L)); - return stack::push(L, self.file.views().size()); - } - - static int empty(lua_State *L) - { - layout_file_views &self(get_self(L)); - return stack::push(L, self.file.views().empty()); - } - - static int next(lua_State *L) { return stack::push(L, next_pairs<false>); } - static int pairs(lua_State *L) { return start_pairs<false>(L); } - static int ipairs(lua_State *L) { return start_pairs<true>(L); } }; template <> -struct usertype_container<layout_view_items> : lua_engine::immutable_collection_helper<layout_view_items, layout_view::item_list> +struct usertype_container<layout_view_items> : lua_engine::immutable_sequence_helper<layout_view_items, layout_view::item_list> { -private: - using item_list = layout_view::item_list; - - static int next_pairs(lua_State *L) - { - indexed_iterator &i(stack::unqualified_get<user<indexed_iterator> >(L, 1)); - if (i.src.end() == i.it) - return stack::push(L, lua_nil); - int result; - result = stack::push(L, i.ix + 1); - result += stack::push_reference(L, *i.it); - ++i.it; - ++i.ix; - return result; - } - public: - static int at(lua_State *L) - { - layout_view_items &self(get_self(L)); - std::ptrdiff_t const index(stack::unqualified_get<std::ptrdiff_t>(L, 2)); - if ((0 >= index) || (self.view.items().size() < index)) - return stack::push(L, lua_nil); - else - return stack::push_reference(L, *std::next(self.view.items().begin(), index - 1)); - } - static int get(lua_State *L) { layout_view_items &self(get_self(L)); @@ -195,50 +105,10 @@ public: return get(L); } - static int index_of(lua_State *L) - { - layout_view_items &self(get_self(L)); - layout_view::item &item(stack::unqualified_get<layout_view::item>(L, 2)); - auto it(self.view.items().begin()); - std::ptrdiff_t ix(0); - while ((self.view.items().end() != it) && (&item != &*it)) - { - ++it; - ++ix; - } - if (self.view.items().end() == it) - return stack::push(L, lua_nil); - else - return stack::push(L, ix + 1); - } - - static int size(lua_State *L) - { - layout_view_items &self(get_self(L)); - return stack::push(L, self.view.items().size()); - } - - static int empty(lua_State *L) - { - layout_view_items &self(get_self(L)); - return stack::push(L, self.view.items().empty()); - } - - static int next(lua_State *L) { return stack::push(L, next_pairs); } - static int pairs(lua_State *L) { return luaL_error(L, "sol: cannot call 'pairs' on type '%s': not iterable by ID", sol::detail::demangle<layout_view_items>().c_str()); } - - static int ipairs(lua_State *L) - { - layout_view_items &self(get_self(L)); - stack::push(L, next_pairs); - stack::push<user<indexed_iterator> >(L, self.view.items(), self.view.items().begin()); - stack::push(L, lua_nil); - return 3; - } }; diff --git a/src/frontend/mame/ui/barcode.cpp b/src/frontend/mame/ui/barcode.cpp index fad2af9ffc6..846f2cc97c5 100644 --- a/src/frontend/mame/ui/barcode.cpp +++ b/src/frontend/mame/ui/barcode.cpp @@ -74,8 +74,8 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom) item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE); // finish up the menu - item_append(menu_item_type::SEPARATOR); item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE); + item_append(menu_item_type::SEPARATOR); customtop = ui().get_line_height() + 3.0f * ui().box_tb_border(); } @@ -88,9 +88,6 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom) void menu_barcode_reader::handle() { - // rebuild the menu (so to update the selected device, if the user has pressed L or R) - repopulate(reset_options::REMEMBER_POSITION); - // process the menu const event *event = process(PROCESS_LR_REPEAT); @@ -127,6 +124,14 @@ void menu_barcode_reader::handle() } break; + case IPT_UI_CLEAR: + if (get_selection_ref() == ITEMREF_NEW_BARCODE) + { + m_barcode_buffer.clear(); + reset(reset_options::REMEMBER_POSITION); + } + break; + case IPT_SPECIAL: if (get_selection_ref() == ITEMREF_NEW_BARCODE) { @@ -134,11 +139,6 @@ void menu_barcode_reader::handle() reset(reset_options::REMEMBER_POSITION); } break; - - case IPT_UI_CANCEL: - // reset the char buffer also in this case - m_barcode_buffer.clear(); - break; } } } diff --git a/src/frontend/mame/ui/devctrl.h b/src/frontend/mame/ui/devctrl.h index 1be2385a66f..ec9dc0d2928 100644 --- a/src/frontend/mame/ui/devctrl.h +++ b/src/frontend/mame/ui/devctrl.h @@ -84,8 +84,8 @@ int menu_device_control<DeviceType>::current_index() template<class DeviceType> void menu_device_control<DeviceType>::previous() { - // left arrow - rotate left through cassette devices - if (m_device != nullptr) + // left arrow - rotate left through devices + if (m_device && (1 < m_count)) { enumerator iter(machine().root_device()); int index = iter.indexof(*m_device); @@ -94,6 +94,7 @@ void menu_device_control<DeviceType>::previous() else index = m_count - 1; m_device = iter.byindex(index); + reset(reset_options::REMEMBER_POSITION); } } @@ -106,7 +107,7 @@ template<class DeviceType> void menu_device_control<DeviceType>::next() { // right arrow - rotate right through cassette devices - if (m_device != nullptr) + if (m_device && (1 < m_count)) { enumerator iter(machine().root_device()); int index = iter.indexof(*m_device); @@ -115,6 +116,7 @@ void menu_device_control<DeviceType>::next() else index = 0; m_device = iter.byindex(index); + reset(reset_options::REMEMBER_POSITION); } } @@ -129,7 +131,7 @@ std::string menu_device_control<DeviceType>::current_display_name() std::string display_name; display_name.assign(current_device()->name()); if (count() > 1) - display_name.append(string_format("%d", current_index() + 1)); + display_name.append(string_format(" %d", current_index() + 1)); return display_name; } diff --git a/src/frontend/mame/ui/devopt.cpp b/src/frontend/mame/ui/devopt.cpp index e423bfd4370..f5e73f290e0 100644 --- a/src/frontend/mame/ui/devopt.cpp +++ b/src/frontend/mame/ui/devopt.cpp @@ -9,12 +9,14 @@ *********************************************************************/ #include "emu.h" -#include "ui/ui.h" #include "ui/devopt.h" + +#include "ui/ui.h" #include "romload.h" namespace ui { + /*------------------------------------------------- device_config - handle the game information menu diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp index 7d11970966f..3a57aac42c0 100644 --- a/src/frontend/mame/ui/info.cpp +++ b/src/frontend/mame/ui/info.cpp @@ -567,28 +567,30 @@ void menu_image_info::image_info(device_image_interface *image) // if image has been loaded through softlist, let's add some more info if (image->loaded_through_softlist()) { - // display long filename - item_append(image->longname(), FLAG_DISABLE, nullptr); + software_info const &swinfo(*image->software_entry()); - // display manufacturer and year - item_append(string_format("%s, %s", image->manufacturer(), image->year()), FLAG_DISABLE, nullptr); + // display full name, publisher and year + item_append(swinfo.longname(), FLAG_DISABLE, nullptr); + item_append(string_format("%1$s, %2$s", swinfo.publisher(), swinfo.year()), FLAG_DISABLE, nullptr); // display supported information, if available - switch (image->supported()) + switch (swinfo.supported()) { - case SOFTWARE_SUPPORTED_NO: - item_append(_("Not supported"), FLAG_DISABLE, nullptr); - break; - case SOFTWARE_SUPPORTED_PARTIAL: - item_append(_("Partially supported"), FLAG_DISABLE, nullptr); - break; - default: - break; + case SOFTWARE_SUPPORTED_NO: + item_append(_("Not supported"), FLAG_DISABLE, nullptr); + break; + case SOFTWARE_SUPPORTED_PARTIAL: + item_append(_("Partially supported"), FLAG_DISABLE, nullptr); + break; + default: + break; } } } else + { item_append(image->brief_instance_name(), _("[empty]"), 0, nullptr); + } item_append(std::string(), FLAG_DISABLE, nullptr); } diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp index 253c52c07f3..77dfd1088dc 100644 --- a/src/frontend/mame/ui/inifile.cpp +++ b/src/frontend/mame/ui/inifile.cpp @@ -298,11 +298,11 @@ void favorite_manager::add_favorite(running_machine &machine) // start with simple stuff that can just be copied info.shortname = software->shortname(); - info.longname = imagedev->longname(); + info.longname = software->longname(); info.parentname = software->parentname(); - info.year = imagedev->year(); - info.publisher = imagedev->manufacturer(); - info.supported = imagedev->supported(); + info.year = software->year(); + info.publisher = software->publisher(); + info.supported = software->supported(); info.part = part->name(); info.driver = &driver; info.listname = imagedev->software_list_name(); diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp index 23a68c979c5..1051b322d99 100644 --- a/src/frontend/mame/ui/mainmenu.cpp +++ b/src/frontend/mame/ui/mainmenu.cpp @@ -114,7 +114,7 @@ void menu_main::populate(float &customtop, float &custombottom) item_append(_("Slider Controls"), 0, (void *)SLIDERS); - item_append(_("Video Options"), 0, (machine().render().target_by_index(1) != nullptr) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS); + item_append(_("Video Options"), 0, (machine().render().target_by_index(1) || machine().video().snapshot_target().view_name(1)) ? (void *)VIDEO_TARGETS : (void *)VIDEO_OPTIONS); if (machine().crosshair().get_usage()) item_append(_("Crosshair Options"), 0, (void *)CROSSHAIR); @@ -229,7 +229,7 @@ void menu_main::handle() break; case VIDEO_OPTIONS: - menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target()); + menu::stack_push<menu_video_options>(ui(), container(), *machine().render().first_target(), false); break; case CROSSHAIR: diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 068780f2b6e..4fb9616c355 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -136,7 +136,6 @@ void menu::global_state::stack_push(std::unique_ptr<menu> &&menu) { menu->m_parent = std::move(m_stack); m_stack = std::move(menu); - m_stack->reset(reset_options::SELECT_FIRST); m_stack->machine().ui_input().reset(); } @@ -289,26 +288,6 @@ void menu::reset(reset_options options) m_items.clear(); m_visible_items = 0; m_selected = 0; - - // add an item to return - if (!m_parent) - { - item_append(_("Return to Machine"), 0, nullptr); - } - else if (m_parent->is_special_main_menu()) - { - if (machine().options().ui() == emu_options::UI_SIMPLE) - item_append(_("Exit"), 0, nullptr); - else - item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); - } - else - { - if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu()) - item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); - else - item_append(_("Return to Previous Menu"), 0, nullptr); - } } @@ -403,17 +382,6 @@ void menu::item_append_on_off(const std::string &text, bool state, uint32_t flag //------------------------------------------------- -// repopulate - repopulate menu items -//------------------------------------------------- - -void menu::repopulate(reset_options options) -{ - reset(options); - populate(m_customtop, m_custombottom); -} - - -//------------------------------------------------- // process - process a menu, drawing it // and returning any interesting events //------------------------------------------------- @@ -1201,8 +1169,31 @@ void menu::validate_selection(int scandir) void menu::do_handle() { - if (m_items.size() < 2) + if (m_items.empty()) + { + // add an item to return - this is a really hacky way of doing this + if (!m_parent) + { + item_append(_("Return to Machine"), 0, nullptr); + } + else if (m_parent->is_special_main_menu()) + { + if (machine().options().ui() == emu_options::UI_SIMPLE) + item_append(_("Exit"), 0, nullptr); + else + item_append(_("Exit"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + } + else + { + if (machine().options().ui() != emu_options::UI_SIMPLE && stack_has_special_main_menu()) + item_append(_("Return to Previous Menu"), FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, nullptr); + else + item_append(_("Return to Previous Menu"), 0, nullptr); + } + + // let implementation add other items populate(m_customtop, m_custombottom); + } handle(); } diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h index eacbae32609..8cd0057fc58 100644 --- a/src/frontend/mame/ui/menu.h +++ b/src/frontend/mame/ui/menu.h @@ -182,9 +182,6 @@ protected: void add_cleanup_callback(cleanup_callback &&callback) { m_global_state->add_cleanup_callback(std::move(callback)); } - // repopulate the menu items - void repopulate(reset_options options); - // process a menu, drawing it and returning any interesting events const event *process(uint32_t flags, float x0 = 0.0f, float y0 = 0.0f); void process_parent() { m_parent->process(PROCESS_NOINPUT); } diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 5de57de2ea6..dc5cc2ba9a3 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -176,33 +176,23 @@ void menu_network_devices::handle() information menu -------------------------------------------------*/ -void menu_bookkeeping::handle() +menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container) { - attotime curtime; - - /* if the time has rolled over another second, regenerate */ - curtime = machine().time(); - if (prevtime.seconds() != curtime.seconds()) - { - prevtime = curtime; - repopulate(reset_options::SELECT_FIRST); - } - - /* process the menu */ - process(0); } - -/*------------------------------------------------- - menu_bookkeeping - handle the bookkeeping - information menu --------------------------------------------------*/ -menu_bookkeeping::menu_bookkeeping(mame_ui_manager &mui, render_container &container) : menu(mui, container) +menu_bookkeeping::~menu_bookkeeping() { } -menu_bookkeeping::~menu_bookkeeping() +void menu_bookkeeping::handle() { + /* process the menu */ + process(0); + + /* if the time has rolled over another second, regenerate */ + attotime const curtime = machine().time(); + if (prevtime.seconds() != curtime.seconds()) + reset(reset_options::REMEMBER_POSITION); } void menu_bookkeeping::populate(float &customtop, float &custombottom) @@ -212,6 +202,7 @@ void menu_bookkeeping::populate(float &customtop, float &custombottom) int ctrnum; /* show total time first */ + prevtime = machine().time(); if (prevtime.seconds() >= (60 * 60)) util::stream_format(tempstring, _("Uptime: %1$d:%2$02d:%3$02d\n\n"), prevtime.seconds() / (60 * 60), (prevtime.seconds() / 60) % 60, prevtime.seconds() % 60); else diff --git a/src/frontend/mame/ui/tapectrl.cpp b/src/frontend/mame/ui/tapectrl.cpp index 75d62038931..720622f0e81 100644 --- a/src/frontend/mame/ui/tapectrl.cpp +++ b/src/frontend/mame/ui/tapectrl.cpp @@ -116,14 +116,11 @@ void menu_tape_control::populate(float &customtop, float &custombottom) void menu_tape_control::handle() { - // rebuild the menu (so to update the selected device, if the user has pressed L or R, and the tape counter) - repopulate(reset_options::REMEMBER_POSITION); - // process the menu const event *event = process(PROCESS_LR_REPEAT); if (event != nullptr) { - switch(event->iptkey) + switch (event->iptkey) { case IPT_UI_LEFT: if (event->itemref == TAPECMD_SLIDER) @@ -155,6 +152,9 @@ void menu_tape_control::handle() break; } } + + // hacky way to update the tape counter by repopulating every frame + reset(reset_options::REMEMBER_POSITION); } diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp index ccb39306208..21ba181ecb7 100644 --- a/src/frontend/mame/ui/videoopt.cpp +++ b/src/frontend/mame/ui/videoopt.cpp @@ -55,6 +55,10 @@ void menu_video_targets::populate(float &customtop, float &custombottom) // add a menu item item_append(util::string_format(_("Screen #%d"), targetnum), 0, target); } + + // add option for snapshot target if it has multiple views + if (machine().video().snapshot_target().view_name(1)) + item_append("Snapshot", 0, &machine().video().snapshot_target()); } /*------------------------------------------------- @@ -66,7 +70,15 @@ void menu_video_targets::handle() { event const *const menu_event = process(0); if (menu_event && (menu_event->iptkey == IPT_UI_SELECT)) - menu::stack_push<menu_video_options>(ui(), container(), *reinterpret_cast<render_target *>(menu_event->itemref)); + { + render_target *const target = reinterpret_cast<render_target *>(menu_event->itemref); + menu::stack_push<menu_video_options>( + ui(), + container(), + std::string(selected_item().text), + *target, + &machine().video().snapshot_target() == target); + } } @@ -75,10 +87,35 @@ void menu_video_targets::handle() video options menu -------------------------------------------------*/ -menu_video_options::menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target) +menu_video_options::menu_video_options( + mame_ui_manager &mui, + render_container &container, + render_target &target, + bool snapshot) : menu(mui, container) , m_target(target) + , m_title() + , m_show_title(false) + , m_snapshot(snapshot) { + set_selected_index(target.view()); + reset(reset_options::REMEMBER_POSITION); +} + +menu_video_options::menu_video_options( + mame_ui_manager &mui, + render_container &container, + std::string &&title, + render_target &target, + bool snapshot) + : menu(mui, container) + , m_target(target) + , m_title(std::move(title)) + , m_show_title(true) + , m_snapshot(snapshot) +{ + set_selected_index(target.view() + 2); + reset(reset_options::REMEMBER_POSITION); } menu_video_options::~menu_video_options() @@ -89,6 +126,13 @@ void menu_video_options::populate(float &customtop, float &custombottom) { uintptr_t ref; + // add title if requested + if (m_show_title) + { + item_append(m_title, FLAG_DISABLE, nullptr); + item_append(menu_item_type::SEPARATOR); + } + // add items for each view for (char const *name = m_target.view_name(ref = 0); name; name = m_target.view_name(++ref)) item_append(name, 0, reinterpret_cast<void *>(ITEM_VIEW_FIRST + ref)); @@ -127,33 +171,36 @@ void menu_video_options::populate(float &customtop, float &custombottom) // cropping item_append_on_off(_("Zoom to Screen Area"), m_target.zoom_to_screen(), 0, reinterpret_cast<void *>(ITEM_ZOOM)); - // uneven stretch - switch (m_target.scale_mode()) + if (!m_snapshot) { - case SCALE_FRACTIONAL: - subtext = _("On"); - break; + // uneven stretch + switch (m_target.scale_mode()) + { + case SCALE_FRACTIONAL: + subtext = _("On"); + break; + + case SCALE_FRACTIONAL_X: + subtext = _("X Only"); + break; - case SCALE_FRACTIONAL_X: - subtext = _("X Only"); - break; + case SCALE_FRACTIONAL_Y: + subtext = _("Y Only"); + break; - case SCALE_FRACTIONAL_Y: - subtext = _("Y Only"); - break; + case SCALE_FRACTIONAL_AUTO: + subtext = _("X or Y (Auto)"); + break; - case SCALE_FRACTIONAL_AUTO: - subtext = _("X or Y (Auto)"); - break; + case SCALE_INTEGER: + subtext = _("Off"); + break; + } + item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH)); - case SCALE_INTEGER: - subtext = _("Off"); - break; + // keep aspect + item_append_on_off(_("Maintain Aspect Ratio"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT)); } - item_append(_("Non-Integer Scaling"), subtext, FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW, reinterpret_cast<void *>(ITEM_UNEVENSTRETCH)); - - // keep aspect - item_append_on_off(_("Keep Aspect"), m_target.keepaspect(), 0, reinterpret_cast<void *>(ITEM_KEEPASPECT)); } @@ -164,6 +211,8 @@ void menu_video_options::populate(float &customtop, float &custombottom) void menu_video_options::handle() { + auto const lockout_popup([this] () { machine().popmessage(_("Cannot change options while recording!")); }); + bool const snap_lockout(m_snapshot && machine().video().is_recording()); bool changed(false); // process the menu @@ -176,6 +225,8 @@ void menu_video_options::handle() case ITEM_ROTATE: if (menu_event->iptkey == IPT_UI_LEFT || menu_event->iptkey == IPT_UI_RIGHT) { + if (snap_lockout) + return lockout_popup(); int const delta((menu_event->iptkey == IPT_UI_LEFT) ? ROT270 : ROT90); m_target.set_orientation(orientation_add(delta, m_target.orientation())); if (m_target.is_ui_target()) @@ -192,6 +243,8 @@ void menu_video_options::handle() case ITEM_ZOOM: if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { + if (snap_lockout) + return lockout_popup(); m_target.set_zoom_to_screen(menu_event->iptkey == IPT_UI_RIGHT); changed = true; } @@ -201,6 +254,8 @@ void menu_video_options::handle() case ITEM_UNEVENSTRETCH: if (menu_event->iptkey == IPT_UI_LEFT) { + if (snap_lockout) + return lockout_popup(); switch (m_target.scale_mode()) { case SCALE_FRACTIONAL: @@ -227,6 +282,8 @@ void menu_video_options::handle() } else if (menu_event->iptkey == IPT_UI_RIGHT) { + if (snap_lockout) + return lockout_popup(); switch (m_target.scale_mode()) { case SCALE_FRACTIONAL: @@ -257,6 +314,8 @@ void menu_video_options::handle() case ITEM_KEEPASPECT: if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { + if (snap_lockout) + return lockout_popup(); m_target.set_keepaspect(menu_event->iptkey == IPT_UI_RIGHT); changed = true; } @@ -266,6 +325,8 @@ void menu_video_options::handle() default: if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_VIEW_FIRST) { + if (snap_lockout) + return lockout_popup(); if (menu_event->iptkey == IPT_UI_SELECT) { m_target.set_view(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_VIEW_FIRST); @@ -274,6 +335,8 @@ void menu_video_options::handle() } else if (reinterpret_cast<uintptr_t>(menu_event->itemref) >= ITEM_TOGGLE_FIRST) { + if (snap_lockout) + return lockout_popup(); if ((menu_event->iptkey == IPT_UI_LEFT) || (menu_event->iptkey == IPT_UI_RIGHT)) { m_target.set_visibility_toggle(reinterpret_cast<uintptr_t>(menu_event->itemref) - ITEM_TOGGLE_FIRST, menu_event->iptkey == IPT_UI_RIGHT); @@ -284,7 +347,7 @@ void menu_video_options::handle() } } - /* if something changed, rebuild the menu */ + // if something changed, rebuild the menu if (changed) reset(reset_options::REMEMBER_REF); } diff --git a/src/frontend/mame/ui/videoopt.h b/src/frontend/mame/ui/videoopt.h index a70e7b8aa94..44a172cf8f5 100644 --- a/src/frontend/mame/ui/videoopt.h +++ b/src/frontend/mame/ui/videoopt.h @@ -32,7 +32,8 @@ private: class menu_video_options : public menu { public: - menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target); + menu_video_options(mame_ui_manager &mui, render_container &container, render_target &target, bool snapshot); + menu_video_options(mame_ui_manager &mui, render_container &container, std::string &&title, render_target &target, bool snapshot); virtual ~menu_video_options() override; private: @@ -40,6 +41,9 @@ private: virtual void handle() override; render_target &m_target; + std::string const m_title; + bool const m_show_title; + bool const m_snapshot; }; } // namespace ui |