diff options
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 |
commit | 051c380fd14040c83a0d5b919e6289e70fef9df8 (patch) | |
tree | e247a309f4d1c66c07803c02d67ac89837211bd1 /src/frontend/mame/ui | |
parent | 67f129e31518a50a801413f732991972d2c3538a (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.cpp | 25 | ||||
-rw-r--r-- | src/frontend/mame/ui/dirmenu.cpp | 110 | ||||
-rw-r--r-- | src/frontend/mame/ui/filecreate.cpp | 13 | ||||
-rw-r--r-- | src/frontend/mame/ui/filesel.cpp | 62 | ||||
-rw-r--r-- | src/frontend/mame/ui/filesel.h | 2 | ||||
-rw-r--r-- | src/frontend/mame/ui/inputdevices.cpp | 15 | ||||
-rw-r--r-- | src/frontend/mame/ui/selector.cpp | 5 | ||||
-rw-r--r-- | src/frontend/mame/ui/selmenu.cpp | 10 | ||||
-rw-r--r-- | src/frontend/mame/ui/selsoft.cpp | 2 | ||||
-rw-r--r-- | src/frontend/mame/ui/simpleselgame.cpp | 6 | ||||
-rw-r--r-- | src/frontend/mame/ui/swlist.cpp | 97 | ||||
-rw-r--r-- | src/frontend/mame/ui/swlist.h | 1 | ||||
-rw-r--r-- | src/frontend/mame/ui/ui.cpp | 3 | ||||
-rw-r--r-- | src/frontend/mame/ui/utils.h | 84 |
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 |