summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame')
-rw-r--r--src/frontend/mame/clifront.cpp1
-rw-r--r--src/frontend/mame/luaengine.cpp205
-rw-r--r--src/frontend/mame/luaengine.h2
-rw-r--r--src/frontend/mame/luaengine.ipp45
-rw-r--r--src/frontend/mame/luaengine_render.cpp536
-rw-r--r--src/frontend/mame/mameopts.cpp4
-rw-r--r--src/frontend/mame/media_ident.cpp1
-rw-r--r--src/frontend/mame/ui/barcode.cpp25
-rw-r--r--src/frontend/mame/ui/custui.cpp13
-rw-r--r--src/frontend/mame/ui/devopt.cpp2
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp110
-rw-r--r--src/frontend/mame/ui/filecreate.cpp14
-rw-r--r--src/frontend/mame/ui/filesel.cpp64
-rw-r--r--src/frontend/mame/ui/filesel.h2
-rw-r--r--src/frontend/mame/ui/info.cpp5
-rw-r--r--src/frontend/mame/ui/inifile.cpp30
-rw-r--r--src/frontend/mame/ui/inputdevices.cpp15
-rw-r--r--src/frontend/mame/ui/mainmenu.cpp1
-rw-r--r--src/frontend/mame/ui/menu.cpp6
-rw-r--r--src/frontend/mame/ui/miscmenu.cpp13
-rw-r--r--src/frontend/mame/ui/selector.cpp5
-rw-r--r--src/frontend/mame/ui/selmenu.cpp12
-rw-r--r--src/frontend/mame/ui/selsoft.cpp6
-rw-r--r--src/frontend/mame/ui/simpleselgame.cpp6
-rw-r--r--src/frontend/mame/ui/state.cpp62
-rw-r--r--src/frontend/mame/ui/state.h5
-rw-r--r--src/frontend/mame/ui/swlist.cpp97
-rw-r--r--src/frontend/mame/ui/swlist.h1
-rw-r--r--src/frontend/mame/ui/ui.cpp5
-rw-r--r--src/frontend/mame/ui/utils.cpp5
-rw-r--r--src/frontend/mame/ui/utils.h84
-rw-r--r--src/frontend/mame/ui/videoopt.cpp2
32 files changed, 1107 insertions, 277 deletions
diff --git a/src/frontend/mame/clifront.cpp b/src/frontend/mame/clifront.cpp
index 9e04f1ed77b..6faa41dec41 100644
--- a/src/frontend/mame/clifront.cpp
+++ b/src/frontend/mame/clifront.cpp
@@ -31,6 +31,7 @@
#include "chd.h"
#include "corestr.h"
+#include "path.h"
#include "unzip.h"
#include "xmlfile.h"
diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp
index 43449a62184..386d6dc841d 100644
--- a/src/frontend/mame/luaengine.cpp
+++ b/src/frontend/mame/luaengine.cpp
@@ -720,6 +720,9 @@ void lua_engine::initialize()
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["palette_enumerator"] = sol::overload(
+ [] (device_t &dev) { return devenum<palette_interface_enumerator>(dev); },
+ [] (device_t &dev, int maxdepth) { return devenum<palette_interface_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); });
@@ -1271,6 +1274,7 @@ void lua_engine::initialize()
machine_type["exit_pending"] = sol::property(&running_machine::exit_pending);
machine_type["hard_reset_pending"] = sol::property(&running_machine::hard_reset_pending);
machine_type["devices"] = sol::property([] (running_machine &m) { return devenum<device_enumerator>(m.root_device()); });
+ machine_type["palettes"] = sol::property([] (running_machine &m) { return devenum<palette_interface_enumerator>(m.root_device()); });
machine_type["screens"] = sol::property([] (running_machine &m) { return devenum<screen_device_enumerator>(m.root_device()); });
machine_type["cassettes"] = sol::property([] (running_machine &m) { return devenum<cassette_device_enumerator>(m.root_device()); });
machine_type["images"] = sol::property([] (running_machine &m) { return devenum<image_interface_enumerator>(m.root_device()); });
@@ -1432,11 +1436,67 @@ void lua_engine::initialize()
});
+ auto dipalette_type = sol().registry().new_usertype<device_palette_interface>("dipalette", sol::no_constructor);
+ dipalette_type.set_function("pen", &device_palette_interface::pen);
+ dipalette_type.set_function(
+ "pen_color",
+ [] (device_palette_interface const &pal, pen_t pen)
+ {
+ return uint32_t(pal.pen_color(pen));
+ });
+ dipalette_type.set_function("pen_contrast", &device_palette_interface::pen_contrast);
+ dipalette_type.set_function("pen_indirect", &device_palette_interface::pen_indirect);
+ dipalette_type.set_function(
+ "indirect_color",
+ [] (device_palette_interface const &pal, int index)
+ {
+ return uint32_t(pal.indirect_color(index));
+ });
+ dipalette_type["set_pen_color"] = sol::overload(
+ [] (device_palette_interface &pal, pen_t pen, uint32_t color)
+ {
+ pal.set_pen_color(pen, rgb_t(color));
+ },
+ static_cast<void (device_palette_interface::*)(pen_t, uint8_t, uint8_t, uint8_t)>(&device_palette_interface::set_pen_color));
+ dipalette_type.set_function("set_pen_red_level", &device_palette_interface::set_pen_red_level);
+ dipalette_type.set_function("set_pen_green_level", &device_palette_interface::set_pen_green_level);
+ dipalette_type.set_function("set_pen_blue_level", &device_palette_interface::set_pen_blue_level);
+ dipalette_type.set_function("set_pen_contrast", &device_palette_interface::set_pen_contrast);
+ dipalette_type.set_function("set_pen_indirect", &device_palette_interface::set_pen_indirect);
+ dipalette_type["set_indirect_color"] = sol::overload(
+ [] (device_palette_interface &pal, int index, uint32_t color)
+ {
+ pal.set_indirect_color(index, rgb_t(color));
+ },
+ [] (device_palette_interface &pal, int index, uint8_t r, uint8_t g, uint8_t b)
+ {
+ pal.set_indirect_color(index, rgb_t(r, g, b));
+ });
+ dipalette_type.set_function("set_shadow_factor", &device_palette_interface::set_shadow_factor);
+ dipalette_type.set_function("set_highlight_factor", &device_palette_interface::set_highlight_factor);
+ dipalette_type.set_function("set_shadow_mode", &device_palette_interface::set_shadow_mode);
+ dipalette_type["palette"] = sol::property(
+ [] (device_palette_interface &pal)
+ {
+ return pal.palette()
+ ? std::optional<palette_wrapper>(std::in_place, *pal.palette())
+ : std::optional<palette_wrapper>();
+ });
+ dipalette_type["entries"] = sol::property(&device_palette_interface::entries);
+ dipalette_type["indirect_entries"] = sol::property(&device_palette_interface::indirect_entries);
+ dipalette_type["black_pen"] = sol::property(&device_palette_interface::black_pen);
+ dipalette_type["white_pen"] = sol::property(&device_palette_interface::white_pen);
+ dipalette_type["shadows_enabled"] = sol::property(&device_palette_interface::shadows_enabled);
+ dipalette_type["highlights_enabled"] = sol::property(&device_palette_interface::hilights_enabled);
+ dipalette_type["device"] = sol::property(static_cast<device_t & (device_palette_interface::*)()>(&device_palette_interface::device));
+
+
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"] =
+ screen_dev_type.set_function(
+ "draw_box",
[] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
float const sc_width(sdev.visible_area().width());
@@ -1451,8 +1511,9 @@ void lua_engine::initialize()
if (!bgcolor)
bgcolor = ui.colors().background_color();
ui.draw_outlined_box(sdev.container(), x1, y1, x2, y2, *fgcolor, *bgcolor);
- };
- screen_dev_type["draw_line"] =
+ });
+ screen_dev_type.set_function(
+ "draw_line",
[] (screen_device &sdev, float x1, float y1, float x2, float y2, std::optional<uint32_t> color)
{
float const sc_width(sdev.visible_area().width());
@@ -1464,8 +1525,9 @@ void lua_engine::initialize()
if (!color)
color = mame_machine_manager::instance()->ui().colors().text_color();
sdev.container().add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- };
- screen_dev_type["draw_text"] =
+ });
+ screen_dev_type.set_function(
+ "draw_text",
[this] (screen_device &sdev, sol::object xobj, float y, char const *msg, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
float const sc_width(sdev.visible_area().width());
@@ -1503,78 +1565,80 @@ void lua_engine::initialize()
x, y, (1.0f - x),
justify, ui::text_layout::word_wrapping::WORD,
mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor);
- };
- screen_dev_type["orientation"] =
- [] (screen_device &sdev)
- {
- uint32_t flags = sdev.orientation();
- int rotation_angle = 0;
- switch (flags)
+ });
+ screen_dev_type.set_function(
+ "orientation",
+ [] (screen_device &sdev)
{
- 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);
- };
+ 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
- {
- // FIXME: this shouldn't be a member of the screen device
- // the screen is only used as a hint when configured for native snapshots and may be ignored
- std::string snapstr;
- bool is_absolute_path = false;
- if (filename)
+ screen_dev_type.set_function("time_until_vblank_start", &screen_device::time_until_vblank_start);
+ screen_dev_type.set_function("time_until_vblank_end", &screen_device::time_until_vblank_end);
+ screen_dev_type.set_function(
+ "snapshot",
+ [this] (screen_device &sdev, char const *filename) -> sol::object
{
- // 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);
- }
+ // FIXME: this shouldn't be a member of the screen device
+ // the screen is only used as a hint when configured for native snapshots and may be ignored
+ 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);
- std::error_condition filerr;
- if (!snapstr.empty())
- filerr = file.open(snapstr);
- else
- filerr = machine().video().open_next(file, "png");
- if (filerr)
- return sol::make_object(sol(), filerr);
+ // open the file
+ emu_file file(is_absolute_path ? "" : machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
+ std::error_condition filerr;
+ if (!snapstr.empty())
+ filerr = file.open(snapstr);
+ else
+ filerr = machine().video().open_next(file, "png");
+ if (filerr)
+ return sol::make_object(sol(), filerr);
- // and save the snapshot
- machine().video().save_snapshot(&sdev, file);
- return 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)
- {
- // TODO: would be better if this could return a tuple of (buffer, width, height)
- const rectangle &visarea = sdev.visible_area();
- luaL_Buffer buff;
- int size = visarea.height() * visarea.width() * 4;
- u32 *ptr = (u32 *)luaL_buffinitsize(s, &buff, size);
- sdev.pixels(ptr);
- luaL_pushresultsize(&buff, size);
- return sol::make_reference(s, sol::stack_reference(s, -1));
- };
+ // and save the snapshot
+ machine().video().save_snapshot(&sdev, file);
+ return sol::lua_nil;
+ });
+ screen_dev_type.set_function("pixel", &screen_device::pixel);
+ screen_dev_type.set_function(
+ "pixels",
+ [] (screen_device &sdev, sol::this_state s)
+ {
+ const rectangle &visarea = sdev.visible_area();
+ luaL_Buffer buff;
+ int size = visarea.height() * visarea.width() * 4;
+ u32 *const ptr = reinterpret_cast<u32 *>(luaL_buffinitsize(s, &buff, size));
+ sdev.pixels(ptr);
+ luaL_pushresultsize(&buff, size);
+ return std::make_tuple(sol::make_reference(s, sol::stack_reference(s, -1)), visarea.width(), visarea.height());
+ });
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(); });
@@ -1589,6 +1653,7 @@ void lua_engine::initialize()
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);
+ screen_dev_type["palette"] = sol::property([] (screen_device const &sdev) { return sdev.has_palette() ? &sdev.palette() : nullptr; });
auto cass_type = sol().registry().new_usertype<cassette_image_device>(
diff --git a/src/frontend/mame/luaengine.h b/src/frontend/mame/luaengine.h
index 27761eb85b5..e188c186e11 100644
--- a/src/frontend/mame/luaengine.h
+++ b/src/frontend/mame/luaengine.h
@@ -144,6 +144,8 @@ private:
class buffer_helper;
struct addr_space;
+ class palette_wrapper;
+ template <typename T> class bitmap_helper;
class tap_helper;
class addr_space_change_notif;
class symbol_table_wrapper;
diff --git a/src/frontend/mame/luaengine.ipp b/src/frontend/mame/luaengine.ipp
index 91e4b9d0b4f..4b20e39cdb1 100644
--- a/src/frontend/mame/luaengine.ipp
+++ b/src/frontend/mame/luaengine.ipp
@@ -128,6 +128,51 @@ public:
};
+class lua_engine::palette_wrapper
+{
+public:
+ palette_wrapper(uint32_t numcolors, uint32_t numgroups) : m_palette(palette_t::alloc(numcolors, numgroups))
+ {
+ }
+
+ palette_wrapper(palette_t &pal) : m_palette(&pal)
+ {
+ m_palette->ref();
+ }
+
+ palette_wrapper(palette_wrapper const &that) : m_palette(that.m_palette)
+ {
+ m_palette->ref();
+ }
+
+ ~palette_wrapper()
+ {
+ m_palette->deref();
+ }
+
+ palette_wrapper &operator=(palette_wrapper const &that)
+ {
+ that.m_palette->ref();
+ m_palette->deref();
+ m_palette = that.m_palette;
+ return *this;
+ }
+
+ palette_t const &palette() const
+ {
+ return *m_palette;
+ }
+
+ palette_t &palette()
+ {
+ return *m_palette;
+ }
+
+private:
+ palette_t *m_palette;
+};
+
+
namespace sol {
// don't convert core_options to a table directly
diff --git a/src/frontend/mame/luaengine_render.cpp b/src/frontend/mame/luaengine_render.cpp
index 893412a4b30..d6369b27bc3 100644
--- a/src/frontend/mame/luaengine_render.cpp
+++ b/src/frontend/mame/luaengine_render.cpp
@@ -17,11 +17,90 @@
#include "render.h"
#include "rendlay.h"
+#include <algorithm>
+#include <atomic>
#include <iterator>
namespace {
+class render_texture_helper
+{
+public:
+ render_texture_helper(render_texture_helper const &) = delete;
+
+ render_texture_helper(render_texture_helper &&that)
+ : texture(that.texture)
+ , bitmap(that.bitmap)
+ , manager(that.manager)
+ , storage_lock_count(that.storage_lock_count)
+ , palette_lock_count(that.palette_lock_count)
+ {
+ that.texture = nullptr;
+ that.bitmap.reset();
+ }
+
+ template <typename T>
+ render_texture_helper(sol::this_state s, render_manager &m, std::shared_ptr<T> const &b, texture_format f)
+ : texture(nullptr)
+ , bitmap(b)
+ , manager(m)
+ , storage_lock_count(b->storage_lock_count)
+ , palette_lock_count(b->palette_lock_count)
+ {
+ if (bitmap)
+ {
+ texture = manager.texture_alloc();
+ if (texture)
+ {
+ ++storage_lock_count;
+ ++palette_lock_count;
+ texture->set_bitmap(*bitmap, bitmap->cliprect(), f);
+ }
+ else
+ {
+ luaL_error(s, "Error allocating texture");
+ }
+ }
+ }
+
+ ~render_texture_helper()
+ {
+ free();
+ }
+
+ bool valid() const
+ {
+ return texture && bitmap;
+ }
+
+ void free()
+ {
+ if (texture)
+ {
+ manager.texture_free(texture);
+ texture = nullptr;
+ }
+ if (bitmap)
+ {
+ assert(storage_lock_count);
+ assert(palette_lock_count);
+ --storage_lock_count;
+ --palette_lock_count;
+ bitmap.reset();
+ }
+ }
+
+ render_texture *texture;
+ std::shared_ptr<bitmap_t> bitmap;
+
+private:
+ render_manager &manager;
+ std::atomic<unsigned> &storage_lock_count;
+ std::atomic<unsigned> &palette_lock_count;
+};
+
+
struct layout_file_views
{
layout_file_views(layout_file &f) : file(f) { }
@@ -54,6 +133,57 @@ struct render_target_view_names
int count;
};
+
+template <typename T>
+auto get_bitmap_pixels(T const &bitmap, sol::this_state s, rectangle const &bounds)
+{
+ if (!bitmap.cliprect().contains(bounds))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ luaL_Buffer buff;
+ size_t const size(bounds.width() * bounds.height() * sizeof(typename T::pixel_t));
+ auto ptr = reinterpret_cast<typename T::pixel_t *>(luaL_buffinitsize(s, &buff, size));
+ for (auto y = bounds.top(); bounds.bottom() >= y; ++y, ptr += bounds.width())
+ std::copy_n(&bitmap.pix(y, bounds.left()), bounds.width(), ptr);
+ luaL_pushresultsize(&buff, size);
+ return std::make_tuple(sol::make_reference(s, sol::stack_reference(s, -1)), bounds.width(), bounds.height());
+}
+
+
+template <typename T>
+auto make_bitmap_specific_type(sol::table registry, char const *name)
+{
+ auto result = registry.new_usertype<T>(
+ name,
+ sol::no_constructor,
+ sol::base_classes, sol::bases<bitmap_t>());
+ result.set_function("pix", [] (T &bitmap, int32_t x, int32_t y) { return bitmap.pix(y, x); });
+ result["pixels"] = sol::overload(
+ [] (T const &bitmap, sol::this_state s)
+ {
+ return get_bitmap_pixels(bitmap, s, bitmap.cliprect());
+ },
+ [] (T const &bitmap, sol::this_state s, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ return get_bitmap_pixels(bitmap, s, rectangle(minx, maxx, miny, maxy));
+ });
+ result["fill"] = sol::overload(
+ static_cast<void (T::*)(typename T::pixel_t)>(&T::fill),
+ [] (T &bitmap, typename T::pixel_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ bitmap.fill(color, rectangle(minx, maxx, miny, maxy));
+ });
+ result.set_function(
+ "plot",
+ [] (T &bitmap, int32_t x, int32_t y, typename T::pixel_t color)
+ {
+ if (bitmap.cliprect().contains(x, y))
+ bitmap.pix(y, x) = color;
+ });
+ result.set_function("plot_box", &T::plot_box);
+ result["bpp"] = sol::property(&T::bpp);
+ return result;
+}
+
} // anonymous namespace
@@ -214,6 +344,231 @@ public:
} // namespace sol
+template <typename T>
+class lua_engine::bitmap_helper : public T
+{
+public:
+ using ptr = std::shared_ptr<bitmap_helper>;
+
+ bitmap_helper(bitmap_helper const &) = delete;
+ bitmap_helper(bitmap_helper &&) = delete;
+ bitmap_helper &operator=(bitmap_helper const &) = delete;
+ bitmap_helper &operator=(bitmap_helper &&) = delete;
+
+ bitmap_helper(sol::this_state s, int width, int height, int xslop, int yslop)
+ : T(width, height, xslop, yslop)
+ , storage_lock_count(0)
+ , palette_lock_count(0)
+ , storage()
+ {
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ bitmap_helper(ptr const &source, rectangle const &subrect)
+ : T(*source, subrect)
+ , storage_lock_count(0)
+ , palette_lock_count(0)
+ , storage(source->storage ? source->storage : source)
+ {
+ ++storage->storage_lock_count;
+ this->set_palette(source->palette());
+ }
+
+ ~bitmap_helper()
+ {
+ assert(!storage_lock_count);
+ assert(!palette_lock_count);
+ release_storage();
+ }
+
+ void reset(sol::this_state s)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot reset bitmap while in use");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::reset();
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ }
+
+ void allocate(sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot reallocate bitmap while in use");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::allocate(width, height, xslop, yslop);
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ void resize(sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ if (storage_lock_count)
+ luaL_error(s, "Cannot resize bitmap while in use");
+ T::resize(width, height, xslop, yslop);
+ release_storage();
+ if ((0 < width) && (0 < height) && !this->valid())
+ luaL_error(s, "Error allocating bitmap storage");
+ }
+
+ void wrap(sol::this_state s, ptr const &source, rectangle const &subrect)
+ {
+ if (source.get() == this)
+ luaL_error(s, "Bitmap cannot wrap itself");
+ if (storage_lock_count)
+ luaL_error(s, "Cannot free bitmap storage while in use");
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ palette_t *const p(this->palette());
+ if (p)
+ p->ref();
+ T::wrap(*source, subrect);
+ this->set_palette(p);
+ if (p)
+ p->deref();
+ release_storage();
+ storage = source->storage ? source->storage : source;
+ ++storage->storage_lock_count;
+ }
+
+ std::atomic<unsigned> storage_lock_count;
+ std::atomic<unsigned> palette_lock_count;
+
+ template <typename B>
+ static auto make_type(sol::table &registry, char const *name)
+ {
+ auto result = registry.new_usertype<bitmap_helper>(
+ name,
+ sol::call_constructor, sol::factories(
+ [] (sol::this_state s)
+ {
+ return std::make_shared<bitmap_helper>(s, 0, 0, 0, 0);
+ },
+ [] (sol::this_state s, int width, int height)
+ {
+ return std::make_shared<bitmap_helper>(s, width, height, 0, 0);
+ },
+ [] (sol::this_state s, int width, int height, int xslop, int yslop)
+ {
+ return std::make_shared<bitmap_helper>(s, width, height, xslop, yslop);
+ },
+ [] (ptr const &source)
+ {
+ return std::make_shared<bitmap_helper>(source, source->cliprect());
+ },
+ [] (sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ rectangle const subrect(minx, maxx, miny, maxy);
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ return std::make_shared<bitmap_helper>(source, subrect);
+ }),
+ sol::base_classes, sol::bases<B, bitmap_t>());
+ add_bitmap_members(result);
+ return result;
+ }
+
+ template <typename B>
+ static auto make_indexed_type(sol::table &registry, char const *name)
+ {
+ auto result = registry.new_usertype<bitmap_helper>(
+ name,
+ sol::call_constructor, sol::factories(
+ [] (sol::this_state s, palette_wrapper &p)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, 0, 0, 0, 0);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (sol::this_state s, palette_wrapper &p, int width, int height)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, width, height, 0, 0);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (sol::this_state s, palette_wrapper &p, int width, int height, int xslop, int yslop)
+ {
+ ptr result = std::make_shared<bitmap_helper>(s, width, height, xslop, yslop);
+ result->set_palette(&p.palette());
+ return result;
+ },
+ [] (ptr const &source)
+ {
+ return std::make_shared<bitmap_helper>(source, source->cliprect());
+ },
+ [] (sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ rectangle const subrect(minx, maxx, miny, maxy);
+ if (!source->cliprect().contains(subrect))
+ luaL_error(s, "Bounds exceed source clipping rectangle");
+ return std::make_shared<bitmap_helper>(source, subrect);
+ }),
+ sol::base_classes, sol::bases<B, bitmap_t>());
+ result["palette"] = sol::property(
+ [] (bitmap_helper const &b)
+ {
+ return b.palette()
+ ? std::optional<palette_wrapper>(std::in_place, *b.palette())
+ : std::optional<palette_wrapper>();
+ },
+ [] (bitmap_helper &b, sol::this_state s, palette_wrapper &p)
+ {
+ if (b.palette_lock_count)
+ luaL_error(s, "Cannot set palette while in use");
+ b.set_palette(&p.palette());
+ });
+ add_bitmap_members(result);
+ return result;
+ }
+
+private:
+ void release_storage()
+ {
+ if (storage)
+ {
+ assert(storage->storage_lock_count);
+ --storage->storage_lock_count;
+ storage.reset();
+ }
+ }
+
+ template <typename U>
+ static void add_bitmap_members(U &type)
+ {
+ type.set_function("reset", &bitmap_helper::reset);
+ type["allocate"] = sol::overload(
+ &bitmap_helper::allocate,
+ [] (bitmap_helper &bitmap, sol::this_state s, int width, int height) { bitmap.allocate(s, width, height, 0, 0); });
+ type["resize"] = sol::overload(
+ &bitmap_helper::resize,
+ [] (bitmap_helper &bitmap, sol::this_state s, int width, int height) { bitmap.resize(s, width, height, 0, 0); });
+ type["wrap"] = sol::overload(
+ [] (bitmap_helper &bitmap, sol::this_state s, ptr const &source)
+ {
+ bitmap.wrap(s, source, source->cliprect());
+ },
+ [] (bitmap_helper &bitmap, sol::this_state s, ptr const &source, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ bitmap.wrap(s, source, rectangle(minx, maxx, miny, maxy));
+ });
+ type["locked"] = sol::property([] (bitmap_helper const &b) { return bool(b.storage_lock_count); });
+ }
+
+ ptr storage;
+};
+
+
//-------------------------------------------------
// initialize_render - register render user types
//-------------------------------------------------
@@ -226,9 +581,9 @@ void lua_engine::initialize_render(sol::table &emu)
sol::call_constructor, sol::initializers(
[] (render_bounds &b) { new (&b) render_bounds{ 0.0F, 0.0F, 1.0F, 1.0F }; },
[] (render_bounds &b, float x0, float y0, float x1, float y1) { new (&b) render_bounds{ x0, y0, x1, y1 }; }));
- bounds_type["includes"] = &render_bounds::includes;
- bounds_type["set_xy"] = &render_bounds::set_xy;
- bounds_type["set_wh"] = &render_bounds::set_wh;
+ bounds_type.set_function("includes", &render_bounds::includes);
+ bounds_type.set_function("set_xy", &render_bounds::set_xy);
+ bounds_type.set_function("set_wh", &render_bounds::set_wh);
bounds_type["x0"] = &render_bounds::x0;
bounds_type["y0"] = &render_bounds::y0;
bounds_type["x1"] = &render_bounds::x1;
@@ -243,13 +598,148 @@ void lua_engine::initialize_render(sol::table &emu)
sol::call_constructor, sol::initializers(
[] (render_color &c) { new (&c) render_color{ 1.0F, 1.0F, 1.0F, 1.0F }; },
[] (render_color &c, float a, float r, float g, float b) { new (&c) render_color{ a, r, g, b }; }));
- color_type["set"] = &render_color::set;
+ color_type.set_function("set", &render_color::set);
color_type["a"] = &render_color::a;
color_type["r"] = &render_color::r;
color_type["g"] = &render_color::g;
color_type["b"] = &render_color::b;
+ auto palette_type = emu.new_usertype<palette_wrapper>(
+ "palette",
+ sol::call_constructor, sol::initializers(
+ [] (palette_wrapper &pal, uint32_t colors) { new (&pal) palette_wrapper(colors, 1); },
+ [] (palette_wrapper &pal, uint64_t colors, uint32_t groups) { new (&pal) palette_wrapper(colors, groups); }));
+ palette_type.set_function(
+ "entry_color",
+ [] (palette_wrapper const &pal, uint32_t index) { return uint32_t(pal.palette().entry_color(index)); });
+ palette_type.set_function(
+ "entry_contrast",
+ [] (palette_wrapper const &pal, uint32_t index) { return pal.palette().entry_contrast(index); });
+ palette_type.set_function(
+ "entry_adjusted_color",
+ [] (palette_wrapper const &pal, uint32_t index, std::optional<uint32_t> group)
+ {
+ if (group)
+ {
+ if ((pal.palette().num_colors() <= index) || (pal.palette().num_groups() <= *group))
+ return uint32_t(rgb_t::black());
+ index += *group * pal.palette().num_colors();
+ }
+ return uint32_t(pal.palette().entry_adjusted_color(index));
+ });
+ palette_type["entry_set_color"] = sol::overload(
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint32_t color)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_color(index, rgb_t(color));
+ },
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t red, uint8_t green, uint8_t blue)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_color(index, rgb_t(red, green, blue));
+ });
+ palette_type.set_function(
+ "entry_set_red_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_red_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_green_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_green_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_blue_level",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, uint8_t level)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_blue_level(index, level);
+ });
+ palette_type.set_function(
+ "entry_set_contrast",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t index, float contrast)
+ {
+ if (pal.palette().num_colors() <= index)
+ luaL_error(s, "Color index out of range");
+ pal.palette().entry_set_contrast(index, contrast);
+ });
+ palette_type.set_function(
+ "group_set_brightness",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t group, float brightness)
+ {
+ if (pal.palette().num_colors() <= group)
+ luaL_error(s, "Group index out of range");
+ pal.palette().group_set_brightness(group, brightness);
+ });
+ palette_type.set_function(
+ "group_set_contrast",
+ [] (palette_wrapper &pal, sol::this_state s, uint32_t group, float contrast)
+ {
+ if (pal.palette().num_colors() <= group)
+ luaL_error(s, "Group index out of range");
+ pal.palette().group_set_contrast(group, contrast);
+ });
+ palette_type["colors"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().num_colors(); });
+ palette_type["groups"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().num_groups(); });
+ palette_type["max_index"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().max_index(); });
+ palette_type["black_entry"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().black_entry(); });
+ palette_type["white_entry"] = sol::property([] (palette_wrapper const &pal) { return pal.palette().white_entry(); });
+ palette_type["brightness"] = sol::property([] (palette_wrapper &pal, float brightness) { pal.palette().set_brightness(brightness); });
+ palette_type["contrast"] = sol::property([] (palette_wrapper &pal, float contrast) { pal.palette().set_contrast(contrast); });
+ palette_type["gamma"] = sol::property([] (palette_wrapper &pal, float gamma) { pal.palette().set_gamma(gamma); });
+
+
+ auto bitmap_type = sol().registry().new_usertype<bitmap_t>("bitmap", sol::no_constructor);
+ bitmap_type.set_function(
+ "cliprect",
+ [] (bitmap_t const &bitmap)
+ {
+ rectangle const &result(bitmap.cliprect());
+ return std::make_tuple(result.left(), result.top(), result.right(), result.bottom());
+ });
+ bitmap_type["fill"] = sol::overload(
+ static_cast<void (bitmap_t::*)(uint64_t)>(&bitmap_t::fill),
+ [] (bitmap_t &bitmap, uint64_t color, int32_t minx, int32_t miny, int32_t maxx, int32_t maxy)
+ {
+ bitmap.fill(color, rectangle(minx, maxx, miny, maxy));
+ });
+ bitmap_type.set_function("plot_box", &bitmap_t::plot_box);
+ bitmap_type["width"] = sol::property(&bitmap_t::width);
+ bitmap_type["height"] = sol::property(&bitmap_t::height);
+ bitmap_type["rowpixels"] = sol::property(&bitmap_t::rowpixels);
+ bitmap_type["rowbytes"] = sol::property(&bitmap_t::rowbytes);
+ bitmap_type["bpp"] = sol::property(&bitmap_t::bpp);
+ bitmap_type["valid"] = sol::property(&bitmap_t::valid);
+
+ make_bitmap_specific_type<bitmap8_t>(sol().registry(), "bitmap8");
+ make_bitmap_specific_type<bitmap16_t>(sol().registry(), "bitmap16");
+ make_bitmap_specific_type<bitmap32_t>(sol().registry(), "bitmap32");
+ make_bitmap_specific_type<bitmap64_t>(sol().registry(), "bitmap64");
+
+ bitmap_helper<bitmap_ind8>::make_indexed_type<bitmap8_t>(emu, "bitmap_ind8");
+ bitmap_helper<bitmap_ind16>::make_indexed_type<bitmap16_t>(emu, "bitmap_ind16");
+ bitmap_helper<bitmap_ind32>::make_indexed_type<bitmap32_t>(emu, "bitmap_ind32");
+ bitmap_helper<bitmap_ind64>::make_indexed_type<bitmap64_t>(emu, "bitmap_ind64");
+
+ bitmap_helper<bitmap_yuy16>::make_type<bitmap16_t>(emu, "bitmap_yuy16");
+ bitmap_helper<bitmap_rgb32>::make_type<bitmap32_t>(emu, "bitmap_rgb32");
+ bitmap_helper<bitmap_argb32>::make_type<bitmap32_t>(emu, "bitmap_argb32");
+
+ auto render_texture_type = emu.new_usertype<render_texture_helper>("render_texture", sol::no_constructor);
+ render_texture_type.set_function("free", &render_texture_helper::free);
+ render_texture_type["valid"] = sol::property(&render_texture_helper::valid);
+
+
auto layout_view_type = sol().registry().new_usertype<layout_view>("layout_view", sol::no_constructor);
layout_view_type["has_screen"] = &layout_view::has_screen;
layout_view_type["set_prepare_items_callback"] =
@@ -392,7 +882,8 @@ void lua_engine::initialize_render(sol::table &emu)
auto render_container_type = sol().registry().new_usertype<render_container>("render_container", sol::no_constructor);
- render_container_type["draw_box"] =
+ render_container_type.set_function(
+ "draw_box",
[] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
x1 = std::clamp(x1, 0.0f, 1.0f);
@@ -405,8 +896,9 @@ void lua_engine::initialize_render(sol::table &emu)
if (!bgcolor)
bgcolor = ui.colors().background_color();
ui.draw_outlined_box(ctnr, x1, y1, x2, y2, *fgcolor, *bgcolor);
- };
- render_container_type["draw_line"] =
+ });
+ render_container_type.set_function(
+ "draw_line",
[] (render_container &ctnr, float x1, float y1, float x2, float y2, std::optional<uint32_t> color)
{
x1 = std::clamp(x1, 0.0f, 1.0f);
@@ -416,8 +908,15 @@ void lua_engine::initialize_render(sol::table &emu)
if (!color)
color = mame_machine_manager::instance()->ui().colors().text_color();
ctnr.add_line(x1, y1, x2, y2, UI_LINE_WIDTH, rgb_t(*color), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
- };
- render_container_type["draw_text"] =
+ });
+ render_container_type.set_function(
+ "draw_quad",
+ [] (render_container &cntr, render_texture_helper const &tex, float x1, float y1, float x2, float y2, std::optional<uint32_t> color)
+ {
+ cntr.add_quad(x1, y1, x2, y2, color ? *color : uint32_t(0xffffffff), tex.texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
+ });
+ render_container_type.set_function(
+ "draw_text",
[] (render_container &ctnr, sol::this_state s, sol::object xobj, float y, char const *msg, std::optional<uint32_t> fgcolor, std::optional<uint32_t> bgcolor)
{
auto justify = ui::text_layout::text_justify::LEFT;
@@ -453,7 +952,7 @@ void lua_engine::initialize_render(sol::table &emu)
x, y, (1.0f - x),
justify, ui::text_layout::word_wrapping::WORD,
mame_ui_manager::OPAQUE_, *fgcolor, *bgcolor);
- };
+ });
render_container_type["user_settings"] = sol::property(&render_container::get_user_settings, &render_container::set_user_settings);
render_container_type["orientation"] = sol::property(
&render_container::orientation,
@@ -510,6 +1009,23 @@ void lua_engine::initialize_render(sol::table &emu)
auto render_type = sol().registry().new_usertype<render_manager>("render", sol::no_constructor);
+ render_type["texture_alloc"] = sol::overload(
+ [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_ind16>::ptr const &bitmap)
+ {
+ return render_texture_helper(s, manager, bitmap, TEXFORMAT_PALETTE16);
+ },
+ [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_yuy16>::ptr const &bitmap)
+ {
+ return render_texture_helper(s, manager, bitmap, TEXFORMAT_YUY16);
+ },
+ [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_rgb32>::ptr const &bitmap)
+ {
+ return render_texture_helper(s, manager, bitmap, TEXFORMAT_RGB32);
+ },
+ [] (render_manager &manager, sol::this_state s, bitmap_helper<bitmap_argb32>::ptr const &bitmap)
+ {
+ return render_texture_helper(s, manager, bitmap, TEXFORMAT_ARGB32);
+ });
render_type["max_update_rate"] = sol::property(&render_manager::max_update_rate);
render_type["ui_target"] = sol::property(&render_manager::ui_target);
render_type["ui_container"] = sol::property(&render_manager::ui_container);
diff --git a/src/frontend/mame/mameopts.cpp b/src/frontend/mame/mameopts.cpp
index bbdf8a692b4..c6031308592 100644
--- a/src/frontend/mame/mameopts.cpp
+++ b/src/frontend/mame/mameopts.cpp
@@ -15,10 +15,12 @@
#include "fileio.h"
#include "screen.h"
#include "softlist_dev.h"
-#include "zippath.h"
#include "hashfile.h"
#include "clifront.h"
+#include "path.h"
+#include "zippath.h"
+
#include <cctype>
#include <stack>
diff --git a/src/frontend/mame/media_ident.cpp b/src/frontend/mame/media_ident.cpp
index 7e6665bc765..d09858198ea 100644
--- a/src/frontend/mame/media_ident.cpp
+++ b/src/frontend/mame/media_ident.cpp
@@ -14,6 +14,7 @@
#include "softlist_dev.h"
#include "jedparse.h"
+#include "path.h"
#include "unzip.h"
diff --git a/src/frontend/mame/ui/barcode.cpp b/src/frontend/mame/ui/barcode.cpp
index a06e4b99673..a0e4791dfb6 100644
--- a/src/frontend/mame/ui/barcode.cpp
+++ b/src/frontend/mame/ui/barcode.cpp
@@ -58,24 +58,11 @@ void menu_barcode_reader::populate(float &customtop, float &custombottom)
{
if (current_device())
{
- std::string buffer;
- const char *new_barcode;
-
// selected device
item_append(std::string(current_display_name()), std::string(current_device()->tag() + 1), current_display_flags(), ITEMREF_SELECT_READER);
// append the "New Barcode" item
- if (get_selection_ref() == ITEMREF_NEW_BARCODE)
- {
- buffer.append(m_barcode_buffer);
- new_barcode = buffer.c_str();
- }
- else
- {
- new_barcode = m_barcode_buffer.c_str();
- }
-
- item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE);
+ item_append(_("New Barcode:"), m_barcode_buffer, 0, ITEMREF_NEW_BARCODE);
// finish up the menu
item_append(_("Enter Code"), 0, ITEMREF_ENTER_BARCODE);
@@ -131,11 +118,19 @@ void menu_barcode_reader::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (get_selection_ref() == ITEMREF_NEW_BARCODE)
+ {
+ if (paste_text(m_barcode_buffer, uchar_is_digit))
+ ev->item->set_subtext(m_barcode_buffer);
+ }
+ break;
+
case IPT_SPECIAL:
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
{
if (input_character(m_barcode_buffer, ev->unichar, uchar_is_digit))
- reset(reset_options::REMEMBER_POSITION);
+ ev->item->set_subtext(m_barcode_buffer);
}
break;
}
diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp
index 08cad10ccdd..febb6a89472 100644
--- a/src/frontend/mame/ui/custui.cpp
+++ b/src/frontend/mame/ui/custui.cpp
@@ -22,6 +22,7 @@
#include "corestr.h"
#include "osdepend.h"
+#include "path.h"
#include <algorithm>
#include <iterator>
@@ -250,7 +251,7 @@ void menu_custom_ui::find_languages()
std::sort(
std::next(m_languages.begin()),
m_languages.end(),
- [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
+ [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x, y); });
char const *const lang = machine().options().language();
if (*lang)
@@ -259,8 +260,8 @@ void menu_custom_ui::find_languages()
std::next(m_languages.begin()),
m_languages.end(),
lang,
- [] (std::string const &x, char const *y) { return 0 > core_stricmp(x.c_str(), y); });
- if ((m_languages.end() != found) && !core_stricmp(found->c_str(), lang))
+ [] (std::string const &x, char const *y) { return 0 > core_stricmp(x, y); });
+ if ((m_languages.end() != found) && !core_stricmp(*found, lang))
m_currlang = std::distance(m_languages.begin(), found);
}
else
@@ -292,7 +293,7 @@ void menu_custom_ui::find_sysnames()
std::sort(
m_sysnames.begin(),
m_sysnames.end(),
- [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x.c_str(), y.c_str()); });
+ [] (std::string const &x, std::string const &y) { return 0 > core_stricmp(x, y); });
char const *const names = ui().options().system_names();
if (*names)
@@ -301,9 +302,9 @@ void menu_custom_ui::find_sysnames()
std::next(m_sysnames.begin()),
m_sysnames.end(),
names,
- [] (std::string const &x, char const *y) { return 0 > core_stricmp(x.c_str(), y); });
+ [] (std::string const &x, char const *y) { return 0 > core_stricmp(x, y); });
m_currsysnames = std::distance(m_sysnames.begin(), found);
- if ((m_sysnames.end() == found) || core_stricmp(found->c_str(), names))
+ if ((m_sysnames.end() == found) || core_stricmp(*found, names))
m_sysnames.emplace(found, names);
}
else
diff --git a/src/frontend/mame/ui/devopt.cpp b/src/frontend/mame/ui/devopt.cpp
index 0f20c35486f..1fc1e83564f 100644
--- a/src/frontend/mame/ui/devopt.cpp
+++ b/src/frontend/mame/ui/devopt.cpp
@@ -15,6 +15,8 @@
#include "romload.h"
#include "screen.h"
+#include "utf8.h"
+
namespace ui {
diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp
index 1aa4cb6a8fe..ab55b742054 100644
--- a/src/frontend/mame/ui/dirmenu.cpp
+++ b/src/frontend/mame/ui/dirmenu.cpp
@@ -49,6 +49,7 @@ const folders_entry f_folders[] =
{ N_p("path-option", "Cheat Files"), OPTION_CHEATPATH, ADDING },
{ N_p("path-option", "Plugins"), OPTION_PLUGINSPATH, ADDING },
{ N_p("path-option", "UI Translations"), OPTION_LANGUAGEPATH, CHANGE },
+ { N_p("path-option", "Software Lists"), OPTION_HASHPATH, ADDING },
{ N_p("path-option", "INIs"), OPTION_INIPATH, ADDING },
{ N_p("path-option", "UI Settings"), OPTION_UI_PATH, CHANGE },
{ N_p("path-option", "Plugin Data"), OPTION_PLUGINDATAPATH, CHANGE },
@@ -176,6 +177,8 @@ private:
virtual void populate(float &customtop, float &custombottom) override;
virtual void handle(event const *ev) override;
+ void update_search();
+
int const m_ref;
std::string m_current_path;
std::string m_search;
@@ -241,10 +244,13 @@ void menu_add_change_folder::handle(event const *ev)
m_search.clear();
reset(reset_options::SELECT_FIRST);
}
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_search, uchar_is_printable))
+ update_search();
+ }
else if (ev->iptkey == IPT_SPECIAL)
{
- bool update_selected = false;
-
if (ev->unichar == 0x09)
{
// Tab key, save current path
@@ -276,56 +282,10 @@ void menu_add_change_folder::handle(event const *ev)
reset_parent(reset_options::SELECT_FIRST);
stack_pop();
}
- else
+ else if (input_character(m_search, ev->unichar, uchar_is_printable))
{
// if it's any other key and we're not maxed out, update
- update_selected = input_character(m_search, ev->unichar, uchar_is_printable);
- }
-
- // check for entries which matches our search buffer
- if (update_selected)
- {
- const int cur_selected = selected_index();
- int entry, bestmatch = 0;
-
- // from current item to the end
- for (entry = cur_selected; entry < item_count(); entry++)
- if (item(entry).ref() && !m_search.empty())
- {
- int match = 0;
- for (int i = 0; i < m_search.size() + 1; i++)
- {
- if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
- match = i;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- set_selected_index(entry);
- }
- }
-
- // and from the first item to current one
- for (entry = 0; entry < cur_selected; entry++)
- {
- if (item(entry).ref() && !m_search.empty())
- {
- int match = 0;
- for (int i = 0; i < m_search.size() + 1; i++)
- {
- if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
- match = i;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- set_selected_index(entry);
- }
- }
- }
- centre_selection();
+ update_search();
}
}
else if (ev->iptkey == IPT_UI_CANCEL)
@@ -408,6 +368,56 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b
ui().colors().text_color(), ui().colors().background_color(), 1.0f);
}
+//-------------------------------------------------
+// update search
+//-------------------------------------------------
+
+void menu_add_change_folder::update_search()
+{
+ // check for entries which matches our search buffer
+ const int cur_selected = selected_index();
+ int entry, bestmatch = 0;
+
+ // from current item to the end
+ for (entry = cur_selected; entry < item_count(); entry++)
+ if (item(entry).ref() && !m_search.empty())
+ {
+ int match = 0;
+ for (int i = 0; i < m_search.size() + 1; i++)
+ {
+ if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ set_selected_index(entry);
+ }
+ }
+
+ // and from the first item to current one
+ for (entry = 0; entry < cur_selected; entry++)
+ {
+ if (item(entry).ref() && !m_search.empty())
+ {
+ int match = 0;
+ for (int i = 0; i < m_search.size() + 1; i++)
+ {
+ if (core_strnicmp(item(entry).text().c_str(), m_search.data(), i) == 0)
+ match = i;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ set_selected_index(entry);
+ }
+ }
+ }
+ centre_selection();
+}
+
/**************************************************
MENU DISPLAY PATH
diff --git a/src/frontend/mame/ui/filecreate.cpp b/src/frontend/mame/ui/filecreate.cpp
index 3ecb44f9b62..675ddc93ea6 100644
--- a/src/frontend/mame/ui/filecreate.cpp
+++ b/src/frontend/mame/ui/filecreate.cpp
@@ -17,6 +17,7 @@
#include "ui/ui.h"
#include "ui/utils.h"
+#include "path.h"
#include "zippath.h"
#include <cstring>
@@ -208,13 +209,22 @@ void menu_file_create::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (get_selection_ref() == ITEMREF_NEW_IMAGE_NAME)
+ {
+ if (paste_text(m_filename, &osd_is_valid_filename_char))
+ reset(reset_options::REMEMBER_POSITION);
+ }
+ break;
+
case IPT_SPECIAL:
if (get_selection_ref() == ITEMREF_NEW_IMAGE_NAME)
{
- input_character(m_filename, ev->unichar, &osd_is_valid_filename_char);
- reset(reset_options::REMEMBER_POSITION);
+ if (input_character(m_filename, ev->unichar, &osd_is_valid_filename_char))
+ reset(reset_options::REMEMBER_POSITION);
}
break;
+
case IPT_UI_CANCEL:
m_ok = false;
break;
diff --git a/src/frontend/mame/ui/filesel.cpp b/src/frontend/mame/ui/filesel.cpp
index 36f18005409..664bd699c47 100644
--- a/src/frontend/mame/ui/filesel.cpp
+++ b/src/frontend/mame/ui/filesel.cpp
@@ -304,45 +304,41 @@ void menu_file_selector::select_item(const file_selector_entry &entry)
// type_search_char
//-------------------------------------------------
-void menu_file_selector::type_search_char(char32_t ch)
+void menu_file_selector::update_search()
{
- std::string const current(m_filename);
- if (input_character(m_filename, ch, uchar_is_printable))
- {
- ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename);
+ ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename);
- file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
+ file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
- // if it's a perfect match for the current selection, don't move it
- if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size()))
+ // if it's a perfect match for the current selection, don't move it
+ if (!cur_selected || core_strnicmp(cur_selected->basename.c_str(), m_filename.c_str(), m_filename.size()))
+ {
+ std::string::size_type bestmatch(0);
+ file_selector_entry const *selected_entry(cur_selected);
+ for (auto &entry : m_entrylist)
{
- std::string::size_type bestmatch(0);
- file_selector_entry const *selected_entry(cur_selected);
- for (auto &entry : m_entrylist)
+ // TODO: more efficient "common prefix" code
+ std::string::size_type match(0);
+ for (std::string::size_type i = 1; m_filename.size() >= i; ++i)
{
- // TODO: more efficient "common prefix" code
- std::string::size_type match(0);
- for (std::string::size_type i = 1; m_filename.size() >= i; ++i)
- {
- if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i))
- match = i;
- else
- break;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- selected_entry = &entry;
- }
+ if (!core_strnicmp(entry.basename.c_str(), m_filename.c_str(), i))
+ match = i;
+ else
+ break;
}
- if (selected_entry && (selected_entry != cur_selected))
+ if (match > bestmatch)
{
- set_selection((void *)selected_entry);
- centre_selection();
+ bestmatch = match;
+ selected_entry = &entry;
}
}
+
+ if (selected_entry && (selected_entry != cur_selected))
+ {
+ set_selection((void *)selected_entry);
+ centre_selection();
+ }
}
}
@@ -401,7 +397,7 @@ void menu_file_selector::populate(float &customtop, float &custombottom)
selected_entry = entry;
// do we have to select this file?
- if (!core_stricmp(m_current_file.c_str(), dirent->name))
+ if (!core_stricmp(m_current_file, dirent->name))
selected_entry = entry;
}
}
@@ -448,7 +444,13 @@ void menu_file_selector::handle(event const *ev)
if (ev->iptkey == IPT_SPECIAL)
{
// if it's any other key and we're not maxed out, update
- type_search_char(ev->unichar);
+ if (input_character(m_filename, ev->unichar, uchar_is_printable))
+ update_search();
+ }
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_filename, uchar_is_printable))
+ update_search();
}
else if (ev->iptkey == IPT_UI_CANCEL)
{
diff --git a/src/frontend/mame/ui/filesel.h b/src/frontend/mame/ui/filesel.h
index 3b09244ca20..8fa309c2fb9 100644
--- a/src/frontend/mame/ui/filesel.h
+++ b/src/frontend/mame/ui/filesel.h
@@ -91,7 +91,7 @@ private:
file_selector_entry *append_dirent_entry(const osd::directory::entry *dirent);
void append_entry_menu_item(const file_selector_entry *entry);
void select_item(const file_selector_entry &entry);
- void type_search_char(char32_t ch);
+ void update_search();
};
diff --git a/src/frontend/mame/ui/info.cpp b/src/frontend/mame/ui/info.cpp
index f6fa969bbb4..5c031d1fe01 100644
--- a/src/frontend/mame/ui/info.cpp
+++ b/src/frontend/mame/ui/info.cpp
@@ -19,6 +19,9 @@
#include "romload.h"
#include "screen.h"
#include "softlist.h"
+#include "speaker.h"
+
+#include "utf8.h"
#include <set>
#include <sstream>
@@ -208,7 +211,7 @@ machine_static_info::machine_static_info(const ui_options &options, machine_conf
for (device_t &device : device_enumerator(config.root_device()))
{
// the "no sound hardware" warning doesn't make sense when you plug in a sound card
- if (dynamic_cast<device_sound_interface *>(&device))
+ if (dynamic_cast<speaker_device *>(&device))
m_flags &= ~::machine_flags::NO_SOUND_HW;
// build overall emulation status
diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp
index 6cf9886324d..c4217f93fa3 100644
--- a/src/frontend/mame/ui/inifile.cpp
+++ b/src/frontend/mame/ui/inifile.cpp
@@ -20,10 +20,12 @@
#include "softlist_dev.h"
#include "corestr.h"
+#include "path.h"
#include <algorithm>
#include <cstring>
#include <iterator>
+#include <locale>
namespace {
@@ -56,7 +58,17 @@ inifile_manager::inifile_manager(ui_options &options)
}
}
}
- std::stable_sort(m_ini_index.begin(), m_ini_index.end(), [] (auto const &x, auto const &y) { return 0 > core_stricmp(x.first.c_str(), y.first.c_str()); });
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
+ std::stable_sort(
+ m_ini_index.begin(),
+ m_ini_index.end(),
+ [&coll] (auto const &x, auto const &y)
+ {
+ std::wstring const wx = wstring_from_utf8(x.first);
+ std::wstring const wy = wstring_from_utf8(y.first);
+ return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
+ }
+ );
}
//-------------------------------------------------
@@ -118,9 +130,21 @@ void inifile_manager::init_category(std::string &&filename, util::core_file &fil
}
}
}
- std::stable_sort(index.begin(), index.end(), [] (auto const &x, auto const &y) { return 0 > core_stricmp(x.first.c_str(), y.first.c_str()); });
if (!index.empty())
+ {
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
+ std::stable_sort(
+ index.begin(),
+ index.end(),
+ [&coll] (auto const &x, auto const &y)
+ {
+ std::wstring const wx = wstring_from_utf8(x.first);
+ std::wstring const wy = wstring_from_utf8(y.first);
+ return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
+ }
+ );
m_ini_index.emplace_back(std::move(filename), std::move(index));
+ }
}
@@ -509,7 +533,7 @@ void favorite_manager::update_sorted()
int cmp;
- cmp = core_stricmp(lhs.longname.c_str(), rhs.longname.c_str());
+ cmp = core_stricmp(lhs.longname, rhs.longname);
if (0 > cmp)
return true;
else if (0 < cmp)
diff --git a/src/frontend/mame/ui/inputdevices.cpp b/src/frontend/mame/ui/inputdevices.cpp
index 6dba1d49f92..d5c993bd075 100644
--- a/src/frontend/mame/ui/inputdevices.cpp
+++ b/src/frontend/mame/ui/inputdevices.cpp
@@ -13,6 +13,9 @@
#include "inputdev.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
namespace ui {
@@ -82,6 +85,9 @@ protected:
private:
virtual void populate(float &customtop, float &custombottom) override
{
+ item_append(_("menu-inputdev", "Copy Device ID"), 0U, nullptr);
+ item_append(menu_item_type::SEPARATOR);
+
bool haveanalog = false;
for (input_item_id itemid = ITEM_ID_FIRST_VALID; m_device.maxitem() >= itemid; ++itemid)
{
@@ -109,6 +115,15 @@ private:
virtual void handle(event const *ev) override
{
+ // FIXME: hacky, depending on first item being "copy ID", but need a better model for item reference values
+ if (ev && ev->item && (IPT_UI_SELECT == ev->iptkey) && (&item(0) == ev->item))
+ {
+ if (!osd_set_clipboard_text(m_device.id()))
+ machine().popmessage(_("menu-inputdev", "Copied device ID to clipboard"));
+ else
+ machine().popmessage(_("menu-inputdev", "Error copying device ID to clipboard"));
+ }
+
for (int i = 0; item_count() > i; ++i)
{
void *const ref(item(i).ref());
diff --git a/src/frontend/mame/ui/mainmenu.cpp b/src/frontend/mame/ui/mainmenu.cpp
index aebe9a5886b..0ef893dfd1c 100644
--- a/src/frontend/mame/ui/mainmenu.cpp
+++ b/src/frontend/mame/ui/mainmenu.cpp
@@ -37,6 +37,7 @@
#include "machine/bcreader.h"
#include "crsshair.h"
+#include "dinetwork.h"
#include "dipty.h"
#include "emuopts.h"
diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp
index dbe1b29a813..0ad1ad0b379 100644
--- a/src/frontend/mame/ui/menu.cpp
+++ b/src/frontend/mame/ui/menu.cpp
@@ -719,13 +719,13 @@ void menu::draw(uint32_t flags)
}
// customize subitem text color
- if (!core_stricmp(pitem.subtext().c_str(), _("On")))
+ if (!core_stricmp(pitem.subtext(), _("On")))
fgcolor2 = rgb_t(0x00,0xff,0x00);
- if (!core_stricmp(pitem.subtext().c_str(), _("Off")))
+ if (!core_stricmp(pitem.subtext(), _("Off")))
fgcolor2 = rgb_t(0xff,0x00,0x00);
- if (!core_stricmp(pitem.subtext().c_str(), _("Auto")))
+ if (!core_stricmp(pitem.subtext(), _("Auto")))
fgcolor2 = rgb_t(0xff,0xff,0x00);
// draw the subitem right-justified
diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp
index 55a2aab986f..d043157dbea 100644
--- a/src/frontend/mame/ui/miscmenu.cpp
+++ b/src/frontend/mame/ui/miscmenu.cpp
@@ -23,17 +23,19 @@
#include "osdnet.h"
#include "mameopts.h"
#include "pluginopts.h"
+#include "dinetwork.h"
#include "drivenum.h"
#include "fileio.h"
#include "romload.h"
#include "uiinput.h"
-#include "corestr.h"
+#include "path.h"
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iterator>
+#include <locale>
namespace ui {
@@ -445,10 +447,17 @@ void menu_crosshair::populate(float &customtop, float &custombottom)
if ((length > 4) && core_filename_ends_with(dir->name, ".png"))
m_pics.emplace_back(dir->name, length - 4);
}
+ std::collate<wchar_t> const &coll = std::use_facet<std::collate<wchar_t>>(std::locale());
std::stable_sort(
m_pics.begin(),
m_pics.end(),
- [] (std::string const &a, std::string const &b) { return 0 > core_stricmp(a.c_str(), b.c_str()); });
+ [&coll] (auto const &x, auto const &y)
+ {
+ std::wstring const wx = wstring_from_utf8(x);
+ std::wstring const wy = wstring_from_utf8(y);
+ return 0 > coll.compare(wx.data(), wx.data() + wx.size(), wy.data(), wy.data() + wy.size());
+ }
+ );
}
// Make sure to keep these matched to the CROSSHAIR_VISIBILITY_xxx types
diff --git a/src/frontend/mame/ui/selector.cpp b/src/frontend/mame/ui/selector.cpp
index f8791a37887..93e3ce326d3 100644
--- a/src/frontend/mame/ui/selector.cpp
+++ b/src/frontend/mame/ui/selector.cpp
@@ -69,6 +69,11 @@ void menu_selector::handle(event const *ev)
}
break;
+ case IPT_UI_PASTE:
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ break;
+
case IPT_SPECIAL:
if (input_character(m_search, ev->unichar, uchar_is_printable))
reset(reset_options::SELECT_FIRST);
diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp
index bc43ee4b4b8..a37b7215918 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -278,7 +278,7 @@ void menu_select_launch::software_parts::populate(float &customtop, float &custo
parts.reserve(m_parts.size());
for (s_parts::const_iterator it = m_parts.begin(); m_parts.end() != it; ++it)
parts.push_back(it);
- std::sort(parts.begin(), parts.end(), [] (auto const &left, auto const &right) { return 0 > core_stricmp(left->first.c_str(), right->first.c_str()); });
+ std::sort(parts.begin(), parts.end(), [] (auto const &left, auto const &right) { return 0 > core_stricmp(left->first, right->first); });
for (auto const &elem : parts)
item_append(elem->first, elem->second, 0, (void *)&*elem);
@@ -1583,6 +1583,16 @@ void menu_select_launch::handle_keys(uint32_t flags, int &iptkey)
if (!m_ui_error && machine().ui_input().pressed_repeat(IPT_UI_TOGGLE_CHEAT, 0))
mame_machine_manager::instance()->cheat().set_enable(!mame_machine_manager::instance()->cheat().enabled());
+ // handle pasting text into the search
+ if (exclusive_input_pressed(iptkey, IPT_UI_PASTE, 0))
+ {
+ if (!m_ui_error && accept_search())
+ {
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ }
+ }
+
// see if any other UI keys are pressed
if (iptkey == IPT_INVALID)
{
diff --git a/src/frontend/mame/ui/selsoft.cpp b/src/frontend/mame/ui/selsoft.cpp
index 051b09b4fcf..7255db8427f 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -16,7 +16,6 @@
#include "ui/inifile.h"
#include "ui/selector.h"
-#include "corestr.h"
#include "drivenum.h"
#include "emuopts.h"
#include "fileio.h"
@@ -25,6 +24,9 @@
#include "softlist_dev.h"
#include "uiinput.h"
#include "luaengine.h"
+
+#include "corestr.h"
+#include "path.h"
#include "unicode.h"
#include <algorithm>
@@ -704,7 +706,7 @@ void menu_select_software::make_topbox_text(std::string &line0, std::string &lin
// determine the text for the header
int vis_item = !m_search.empty() ? m_available_items : (m_available_items - 1);
line0 = string_format(_("%1$s %2$s ( %3$d / %4$d software packages )"), emulator_info::get_appname(), bare_build_version, vis_item, m_data->swinfo().size() - 1);
- line1 = string_format(_("System: \"%1$s\" software list "), m_system.description);
+ line1 = string_format(_("%1$s - select software"), m_system.description);
software_filter const *const it(m_data->current_filter());
char const *const filter(it ? it->filter_text() : nullptr);
diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp
index 9cd8dd26fbe..9db5ac2218d 100644
--- a/src/frontend/mame/ui/simpleselgame.cpp
+++ b/src/frontend/mame/ui/simpleselgame.cpp
@@ -132,6 +132,10 @@ void simple_menu_select_game::handle(event const *ev)
case IPT_UI_CANCEL:
inkey_cancel();
break;
+ case IPT_UI_PASTE:
+ if (paste_text(m_search, uchar_is_printable))
+ reset(reset_options::SELECT_FIRST);
+ break;
case IPT_SPECIAL:
inkey_special(*ev);
break;
@@ -218,7 +222,7 @@ void simple_menu_select_game::inkey_cancel()
void simple_menu_select_game::inkey_special(const event &menu_event)
{
// typed characters append to the buffer
- size_t old_size = m_search.size();
+ size_t const old_size = m_search.size();
if (input_character(m_search, menu_event.unichar, uchar_is_printable))
{
if (m_search.size() < old_size)
diff --git a/src/frontend/mame/ui/state.cpp b/src/frontend/mame/ui/state.cpp
index 9f4e6a40ab2..635b980c6ba 100644
--- a/src/frontend/mame/ui/state.cpp
+++ b/src/frontend/mame/ui/state.cpp
@@ -14,6 +14,8 @@
#include "emuopts.h"
#include "inputdev.h"
+#include "path.h"
+
namespace ui {
@@ -95,6 +97,7 @@ menu_load_save_state_base::menu_load_save_state_base(
, m_confirm_delete(nullptr)
, m_must_exist(must_exist)
, m_keys_released(false)
+ , m_slot_selected(INPUT_CODE_INVALID)
{
set_one_shot(one_shot);
set_needs_prev_menu_item(!one_shot);
@@ -237,7 +240,12 @@ void menu_load_save_state_base::populate(float &customtop, float &custombottom)
void menu_load_save_state_base::handle(event const *ev)
{
// process the event
- if (ev && (ev->iptkey == IPT_UI_SELECT))
+ if (INPUT_CODE_INVALID != m_slot_selected)
+ {
+ if (!machine().input().code_pressed(m_slot_selected))
+ stack_pop();
+ }
+ else if (ev && (ev->iptkey == IPT_UI_SELECT))
{
if (ev->itemref)
{
@@ -245,10 +253,7 @@ void menu_load_save_state_base::handle(event const *ev)
file_entry const &entry = file_entry_from_itemref(ev->itemref);
slot_selected(std::string(entry.file_name()));
}
- else
- {
- stack_pop();
- }
+ stack_pop();
}
else if (ev && (ev->iptkey == IPT_UI_CLEAR))
{
@@ -266,9 +271,13 @@ void menu_load_save_state_base::handle(event const *ev)
else if (!m_confirm_delete)
{
// poll inputs
- std::string name = poll_inputs();
- if (!name.empty())
- try_select_slot(std::move(name));
+ input_code code;
+ std::string name = poll_inputs(code);
+ if (!name.empty() && try_select_slot(std::move(name)))
+ {
+ m_switch_poller.reset();
+ m_slot_selected = code;
+ }
}
}
@@ -292,25 +301,32 @@ std::string menu_load_save_state_base::get_visible_name(const std::string &file_
// poll_inputs
//-------------------------------------------------
-std::string menu_load_save_state_base::poll_inputs()
+std::string menu_load_save_state_base::poll_inputs(input_code &code)
{
- input_code const code = m_switch_poller.poll();
- if (INPUT_CODE_INVALID == code)
+ input_code const result = m_switch_poller.poll();
+ if (INPUT_CODE_INVALID == result)
{
m_keys_released = true;
}
else if (m_keys_released)
{
- input_item_id const id = code.item_id();
+ input_item_id const id = result.item_id();
// keyboard A-Z and 0-9
if (((ITEM_ID_A <= id) && (ITEM_ID_Z >= id)) || ((ITEM_ID_0 <= id) && (ITEM_ID_9 >= id)))
+ {
+ code = result;
return keyboard_input_item_name(id);
+ }
// joystick buttons
- if ((DEVICE_CLASS_JOYSTICK == code.device_class()) && (ITEM_CLASS_SWITCH == code.item_class()) && (ITEM_MODIFIER_NONE == code.item_modifier()) && (ITEM_ID_BUTTON1 <= id) && (ITEM_ID_BUTTON32 >= id))
- return util::string_format("joy%i-%i", code.device_index(), id - ITEM_ID_BUTTON1 + 1);
+ if ((DEVICE_CLASS_JOYSTICK == result.device_class()) && (ITEM_CLASS_SWITCH == result.item_class()) && (ITEM_MODIFIER_NONE == result.item_modifier()) && (ITEM_ID_BUTTON1 <= id) && (ITEM_ID_BUTTON32 >= id))
+ {
+ code = result;
+ return util::string_format("joy%i-%i", result.device_index(), id - ITEM_ID_BUTTON1 + 1);
+ }
}
+ code = INPUT_CODE_INVALID;
return "";
}
@@ -319,10 +335,17 @@ std::string menu_load_save_state_base::poll_inputs()
// try_select_slot
//-------------------------------------------------
-void menu_load_save_state_base::try_select_slot(std::string &&name)
+bool menu_load_save_state_base::try_select_slot(std::string &&name)
{
if (!m_must_exist || is_present(name))
+ {
slot_selected(std::move(name));
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
@@ -337,9 +360,6 @@ void menu_load_save_state_base::slot_selected(std::string &&name)
// record the last slot touched
s_last_file_selected = std::move(name);
-
- // no matter what, pop out
- menu::stack_pop();
}
@@ -391,6 +411,10 @@ void menu_load_save_state_base::handle_keys(uint32_t flags, int &iptkey)
}
iptkey = IPT_INVALID;
}
+ else if (INPUT_CODE_INVALID != m_slot_selected)
+ {
+ iptkey = IPT_INVALID;
+ }
else
{
menu::handle_keys(flags, iptkey);
@@ -415,7 +439,7 @@ void menu_load_save_state_base::custom_render(void *selectedref, float top, floa
if (selected_item().ref())
{
if (m_delete_prompt.empty())
- m_delete_prompt = util::string_format(_("Press %1$s to delete"), machine().input().seq_name(machine().ioport().type_seq(IPT_UI_CLEAR)));
+ m_delete_prompt = util::string_format(_("Press %1$s to delete"), ui().get_general_input_setting(IPT_UI_CLEAR));
text[count++] = m_delete_prompt;
}
diff --git a/src/frontend/mame/ui/state.h b/src/frontend/mame/ui/state.h
index a4dc107b1fc..c9594cf25cf 100644
--- a/src/frontend/mame/ui/state.h
+++ b/src/frontend/mame/ui/state.h
@@ -73,15 +73,16 @@ private:
file_entry const * m_confirm_delete;
bool const m_must_exist;
bool m_keys_released;
+ input_code m_slot_selected;
static void *itemref_from_file_entry(const file_entry &entry);
static const file_entry &file_entry_from_itemref(void *itemref);
- void try_select_slot(std::string &&name);
+ bool try_select_slot(std::string &&name);
void slot_selected(std::string &&name);
std::string state_directory() const;
bool is_present(const std::string &name) const;
- std::string poll_inputs();
+ std::string poll_inputs(input_code &code);
std::string get_visible_name(const std::string &file_name);
};
diff --git a/src/frontend/mame/ui/swlist.cpp b/src/frontend/mame/ui/swlist.cpp
index 70c9471da56..5d3c74f8676 100644
--- a/src/frontend/mame/ui/swlist.cpp
+++ b/src/frontend/mame/ui/swlist.cpp
@@ -192,6 +192,54 @@ void menu_software_list::append_software_entry(const software_info &swinfo)
//-------------------------------------------------
+// update_search - update meunu for new search text
+//-------------------------------------------------
+
+void menu_software_list::update_search(void *selectedref)
+{
+ // display the popup
+ ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_search);
+
+ // identify the selected entry
+ entry_info const *const cur_selected = (uintptr_t(selectedref) != 1)
+ ? reinterpret_cast<entry_info const *>(get_selection_ref())
+ : nullptr;
+
+ // if it's a perfect match for the current selection, don't move it
+ if (!cur_selected || core_strnicmp((m_ordered_by_shortname ? cur_selected->short_name : cur_selected->long_name).c_str(), m_search.c_str(), m_search.size()))
+ {
+ std::string::size_type bestmatch(0);
+ entry_info const *selected_entry(cur_selected);
+ for (auto &entry : m_entrylist)
+ {
+ // TODO: more efficient "common prefix" code
+ auto const &compare_name = m_ordered_by_shortname ? entry.short_name : entry.long_name;
+ std::string::size_type match(0);
+ for (std::string::size_type i = 1; m_search.size() >= i; ++i)
+ {
+ if (!core_strnicmp(compare_name.c_str(), m_search.c_str(), i))
+ match = i;
+ else
+ break;
+ }
+
+ if (match > bestmatch)
+ {
+ bestmatch = match;
+ selected_entry = &entry;
+ }
+ }
+
+ if (selected_entry && (selected_entry != cur_selected))
+ {
+ set_selection((void *)selected_entry);
+ centre_selection();
+ }
+ }
+}
+
+
+//-------------------------------------------------
// populate
//-------------------------------------------------
@@ -267,50 +315,15 @@ void menu_software_list::handle(event const *ev)
stack_pop();
}
}
+ else if (ev->iptkey == IPT_UI_PASTE)
+ {
+ if (paste_text(m_search, m_ordered_by_shortname ? is_valid_softlist_part_char : uchar_is_printable))
+ update_search(ev->itemref);
+ }
else if (ev->iptkey == IPT_SPECIAL)
{
- if (input_character(m_search, ev->unichar, m_ordered_by_shortname ? is_valid_softlist_part_char : [] (char32_t ch) { return true; }))
- {
- // display the popup
- ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_search);
-
- // identify the selected entry
- entry_info const *const cur_selected = (uintptr_t(ev->itemref) != 1)
- ? reinterpret_cast<entry_info const *>(get_selection_ref())
- : nullptr;
-
- // if it's a perfect match for the current selection, don't move it
- if (!cur_selected || core_strnicmp((m_ordered_by_shortname ? cur_selected->short_name : cur_selected->long_name).c_str(), m_search.c_str(), m_search.size()))
- {
- std::string::size_type bestmatch(0);
- entry_info const *selected_entry(cur_selected);
- for (auto &entry : m_entrylist)
- {
- // TODO: more efficient "common prefix" code
- auto const &compare_name = m_ordered_by_shortname ? entry.short_name : entry.long_name;
- std::string::size_type match(0);
- for (std::string::size_type i = 1; m_search.size() >= i; ++i)
- {
- if (!core_strnicmp(compare_name.c_str(), m_search.c_str(), i))
- match = i;
- else
- break;
- }
-
- if (match > bestmatch)
- {
- bestmatch = match;
- selected_entry = &entry;
- }
- }
-
- if (selected_entry && (selected_entry != cur_selected))
- {
- set_selection((void *)selected_entry);
- centre_selection();
- }
- }
- }
+ if (input_character(m_search, ev->unichar, m_ordered_by_shortname ? is_valid_softlist_part_char : uchar_is_printable))
+ update_search(ev->itemref);
}
else if (ev->iptkey == IPT_UI_CANCEL)
{
diff --git a/src/frontend/mame/ui/swlist.h b/src/frontend/mame/ui/swlist.h
index 36e5d3c6eaf..b77d8090d7b 100644
--- a/src/frontend/mame/ui/swlist.h
+++ b/src/frontend/mame/ui/swlist.h
@@ -93,6 +93,7 @@ private:
// functions
void append_software_entry(const software_info &swinfo);
+ void update_search(void *selectedref);
};
diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp
index e0c0de0d4ab..878e175d22a 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -42,8 +42,12 @@
#include "screen.h"
#include "uiinput.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
#include "../osd/modules/lib/osdobj_common.h"
+#include "utf8.h"
+
#include <chrono>
#include <functional>
#include <type_traits>
@@ -1116,6 +1120,7 @@ void mame_ui_manager::decrease_frameskip()
bool mame_ui_manager::can_paste()
{
// check to see if the clipboard is not empty
+ // FIXME: this is expensive - need a cheaper way to check if clipboard contains suitable content
return !osd_get_clipboard_text().empty();
}
diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp
index 6c399f9c924..fe5f3b0c138 100644
--- a/src/frontend/mame/ui/utils.cpp
+++ b/src/frontend/mame/ui/utils.cpp
@@ -1028,9 +1028,10 @@ private:
}
}
- static bool include_clones_default(std::string const &name)
+ static bool include_clones_default(std::string_view name)
{
- return !core_stricmp(name.c_str(), "category.ini") || !core_stricmp(name.c_str(), "alltime.ini");
+ using namespace std::literals;
+ return util::streqlower(name, "category.ini"sv) || util::streqlower(name, "alltime.ini"sv);
}
unsigned m_ini, m_group;
diff --git a/src/frontend/mame/ui/utils.h b/src/frontend/mame/ui/utils.h
index 098588086f2..02e88a73b65 100644
--- a/src/frontend/mame/ui/utils.h
+++ b/src/frontend/mame/ui/utils.h
@@ -15,12 +15,17 @@
#include "softlist.h"
#include "unicode.h"
+// FIXME: allow OSD module headers to be included in a less ugly way
+#include "../osd/modules/lib/osdlib.h"
+
#include <algorithm>
#include <functional>
#include <limits>
#include <memory>
#include <string>
+#include <string_view>
#include <unordered_map>
+#include <utility>
#include <vector>
@@ -406,6 +411,8 @@ int getprecisionchr(const char* s);
std::vector<std::string> tokenize(const std::string &text, char sep);
+namespace ui {
+
//-------------------------------------------------
// input_character - inputs a typed character
// into a buffer
@@ -414,31 +421,30 @@ std::vector<std::string> tokenize(const std::string &text, char sep);
template <typename F>
bool input_character(std::string &buffer, std::string::size_type size, char32_t unichar, F &&filter)
{
- bool result = false;
- auto buflen = buffer.size();
-
+ auto const buflen(buffer.length());
if ((unichar == 8) || (unichar == 0x7f))
{
// backspace
if (0 < buflen)
{
- auto buffer_oldend = buffer.c_str() + buflen;
- auto buffer_newend = utf8_previous_char(buffer_oldend);
+ auto const buffer_oldend(buffer.c_str() + buflen);
+ auto const buffer_newend(utf8_previous_char(buffer_oldend));
buffer.resize(buffer_newend - buffer.c_str());
- result = true;
+ return true;
}
}
else if ((unichar >= ' ') && filter(unichar))
{
// append this character - check against the size first
- std::string utf8_char = utf8_from_uchar(unichar);
- if ((buffer.size() + utf8_char.size()) <= size)
+ char utf8char[UTF8_CHAR_MAX];
+ auto const utf8len(utf8_from_uchar(utf8char, std::size(utf8char), unichar));
+ if ((0 < utf8len) && (size >= utf8len) && ((size - utf8len) >= buflen))
{
- buffer += utf8_char;
- result = true;
+ buffer.append(utf8char, utf8len);
+ return true;
}
}
- return result;
+ return false;
}
@@ -450,9 +456,61 @@ bool input_character(std::string &buffer, std::string::size_type size, char32_t
template <typename F>
bool input_character(std::string &buffer, char32_t unichar, F &&filter)
{
- auto size = std::numeric_limits<std::string::size_type>::max();
- return input_character(buffer, size, unichar, filter);
+ auto const size(std::numeric_limits<std::string::size_type>::max());
+ return input_character(buffer, size, unichar, std::forward<F>(filter));
}
+//-------------------------------------------------
+// paste_text - paste text from clipboard into a
+// buffer, ignoring invalid characters
+//-------------------------------------------------
+
+template <typename F>
+bool paste_text(std::string &buffer, std::string::size_type size, F &&filter)
+{
+ std::string const clip(osd_get_clipboard_text());
+ std::string_view text(clip);
+ bool updated(false);
+ int codelength;
+ char32_t unichar;
+ while ((codelength = uchar_from_utf8(&unichar, text)) != 0)
+ {
+ text.remove_prefix((0 < codelength) ? codelength : 1);
+ if ((0 < codelength) && filter(unichar))
+ {
+ char utf8char[UTF8_CHAR_MAX];
+ auto const utf8len(utf8_from_uchar(utf8char, std::size(utf8char), unichar));
+ if (0 < utf8len)
+ {
+ if ((size < utf8len) || ((size - utf8len) < buffer.length()))
+ {
+ return updated;
+ }
+ else
+ {
+ buffer.append(utf8char, utf8len);
+ updated = true;
+ }
+ }
+ }
+ }
+ return updated;
+}
+
+
+//-------------------------------------------------
+// paste_text - paste text from clipboard into a
+// buffer, ignoring invalid characters
+//-------------------------------------------------
+
+template <typename F>
+bool paste_text(std::string &buffer, F &&filter)
+{
+ auto const size(std::numeric_limits<std::string::size_type>::max());
+ return paste_text(buffer, size, std::forward<F>(filter));
+}
+
+} // namespace ui
+
#endif // MAME_FRONTEND_UI_UTILS_H
diff --git a/src/frontend/mame/ui/videoopt.cpp b/src/frontend/mame/ui/videoopt.cpp
index 253271beb4f..67881db6cd0 100644
--- a/src/frontend/mame/ui/videoopt.cpp
+++ b/src/frontend/mame/ui/videoopt.cpp
@@ -14,6 +14,8 @@
#include "rendlay.h"
#include "rendutil.h"
+#include "utf8.h"
+
namespace ui {