summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/ui
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2022-09-02 08:55:16 +1000
committer Vas Crabb <vas@vastheman.com>2022-09-02 08:55:16 +1000
commit051c380fd14040c83a0d5b919e6289e70fef9df8 (patch)
treee247a309f4d1c66c07803c02d67ac89837211bd1 /src/frontend/mame/ui
parent67f129e31518a50a801413f732991972d2c3538a (diff)
Patched up some gaps in functionality and fixed some bugs.
ui: Added some missing functionality: * Added an option to copy input device IDs to the relevant menus. * Added an item for setting the software lists files path (-hashpath) to the folder setup menu. * Allow pasting text from clipboard in most places that allow typing (searching, entering filenames, entering barcodes). * Changed the software selection menu heading to be a bit less misleading. * Made barcode menu less eager to rebuild itself unnecessarily, and removed some confusing and apparently pointless code. Exposed more Lua bindings: * Added low-level palette objects. * Added indexed bitmap types. * Added a bitmap method for extracting pixels from a rectangular area as a packed binary string. * Changed screen device pixels method to return width and height in addition to the pixels. osd: Added some functionality and cleaned up a little: * Added a function for copying text to the clipboard. * Moved function for converting Windows error codes to standard error conditions to winutil.cpp so it can be used from more places. * Removed duplicate declaration of osd_get_clipboard_text and made the function noexcept (including fixing implementations). * Made macOS implementation of osd_get_clipboard_text skip the encoding conversion if it finds UTF-8 text first. * Changed the default -uimodekey setting so it doesn't lose the "not shift" that stops the default from interfering with UI paste. Various bug fixes: * util/unicode.cpp: Fixed the version of utf8_from_uchar that returns std::string blowing up on invalid codepoints. * util/bitmap.h: Fixed wrapping constructors for indexed bitmaps taking the wrong parameter type (nothing was using them before). * util/bitmap.cpp: Fixed potential use-after-free issues with bitmap palettes. * emu/input.cpp, emu/inputdev.cpp: Log 1-based device numbers, matching what's shown in the internal UI and used in tokens in CFG files. * emu/emumem.cpp: Added the bank tag to a fatal error message where it was missing. docs: Reworked and expanded documentation on configuring stable controller IDs. For translators, the changes are quite minor: * There's a menu item for copying a device ID to the clipboard, and associated success/failure messages. * There's the menu item for setting the software list file search path. * One of the lines in the software selection menu heading has changes as it could be interpreted as implying it showed a software list name.
Diffstat (limited to 'src/frontend/mame/ui')
-rw-r--r--src/frontend/mame/ui/barcode.cpp25
-rw-r--r--src/frontend/mame/ui/dirmenu.cpp110
-rw-r--r--src/frontend/mame/ui/filecreate.cpp13
-rw-r--r--src/frontend/mame/ui/filesel.cpp62
-rw-r--r--src/frontend/mame/ui/filesel.h2
-rw-r--r--src/frontend/mame/ui/inputdevices.cpp15
-rw-r--r--src/frontend/mame/ui/selector.cpp5
-rw-r--r--src/frontend/mame/ui/selmenu.cpp10
-rw-r--r--src/frontend/mame/ui/selsoft.cpp2
-rw-r--r--src/frontend/mame/ui/simpleselgame.cpp6
-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.cpp3
-rw-r--r--src/frontend/mame/ui/utils.h84
14 files changed, 280 insertions, 155 deletions
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/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..44d50108b8c 100644
--- a/src/frontend/mame/ui/filecreate.cpp
+++ b/src/frontend/mame/ui/filecreate.cpp
@@ -208,13 +208,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..704aaba3686 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();
+ }
}
}
@@ -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/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/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..9b1b3f1e74d 100644
--- a/src/frontend/mame/ui/selmenu.cpp
+++ b/src/frontend/mame/ui/selmenu.cpp
@@ -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..c15fcff7a26 100644
--- a/src/frontend/mame/ui/selsoft.cpp
+++ b/src/frontend/mame/ui/selsoft.cpp
@@ -704,7 +704,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/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..3299448a1f4 100644
--- a/src/frontend/mame/ui/ui.cpp
+++ b/src/frontend/mame/ui/ui.cpp
@@ -42,6 +42,8 @@
#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 <chrono>
@@ -1116,6 +1118,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.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