From 22f52553f746c9ade11ecb8a0873507682d0f1cb Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sun, 17 Oct 2021 06:58:12 +1100 Subject: [PATCH] frontend: Cleaned up rendering of info views. Put the description for systems in the info box - it's useful for the fruit machines with very long names that are truncated in the list. Also stopped truncating manufactuer and parent name in the info box. Made the text layout class capable of handling lines containing combinatations of left/centre/right-justified text and got rid of the legacy UI manager text wrapping function. Made the system/software selection menus and the info viewer share the same code for formatting info text. This means the multi-column layout works properly in the info viewer now, and the code is a lot simpler. Also the system/software selection menus don't have to redo the text layout every frame now. Made the info viewer update the text layout if the output aspect ratio changes, and cleaned up more legacy code. The lines in the info viewer are no longer bogus "menu items", and there's a lot less special-case code to support it in the base menu class. This commit includes an update to the Chinese translations from YuiFAN. --- language/Chinese_Simplified/strings.po | 59 ++- language/Chinese_Traditional/strings.po | 61 ++- src/frontend/mame/cheat.cpp | 19 +- src/frontend/mame/luaengine.cpp | 10 +- src/frontend/mame/ui/analogipt.cpp | 3 +- src/frontend/mame/ui/auditmenu.cpp | 6 +- src/frontend/mame/ui/confswitch.cpp | 2 +- src/frontend/mame/ui/custui.cpp | 88 +++-- src/frontend/mame/ui/datmenu.cpp | 348 ++++++++++------- src/frontend/mame/ui/datmenu.h | 33 +- src/frontend/mame/ui/dirmenu.cpp | 12 +- src/frontend/mame/ui/inifile.cpp | 2 +- src/frontend/mame/ui/inputmap.cpp | 8 +- src/frontend/mame/ui/menu.cpp | 188 ++++++--- src/frontend/mame/ui/menu.h | 10 +- src/frontend/mame/ui/miscmenu.cpp | 4 +- src/frontend/mame/ui/optsmenu.cpp | 2 +- src/frontend/mame/ui/selector.cpp | 4 +- src/frontend/mame/ui/selmenu.cpp | 210 ++++------ src/frontend/mame/ui/selmenu.h | 2 + src/frontend/mame/ui/simpleselgame.cpp | 6 +- src/frontend/mame/ui/sliders.cpp | 24 +- src/frontend/mame/ui/slotopt.cpp | 2 +- src/frontend/mame/ui/sndmenu.cpp | 2 +- src/frontend/mame/ui/state.cpp | 4 +- src/frontend/mame/ui/submenu.cpp | 4 +- src/frontend/mame/ui/text.cpp | 496 ++++++++++++++---------- src/frontend/mame/ui/text.h | 95 ++--- src/frontend/mame/ui/ui.cpp | 70 ++-- src/frontend/mame/ui/ui.h | 5 +- src/frontend/mame/ui/utils.cpp | 6 +- 31 files changed, 972 insertions(+), 813 deletions(-) diff --git a/language/Chinese_Simplified/strings.po b/language/Chinese_Simplified/strings.po index 8b8187bc453..bf54a750cd6 100644 --- a/language/Chinese_Simplified/strings.po +++ b/language/Chinese_Simplified/strings.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: MAME\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-16 04:41+1100\n" -"PO-Revision-Date: 2021-10-14 21:22+0800\n" +"PO-Revision-Date: 2021-10-16 12:57+0800\n" "Last-Translator: YuiFAN\n" "Language-Team: MAME Language Team\n" "Language: zh_CN\n" @@ -1519,7 +1519,7 @@ msgstr "可见度延迟" #: src/frontend/mame/ui/miscmenu.cpp:639 #, c-format msgid "%s.xml saved in UI settings folder." -msgstr "" +msgstr "%s.xml 已保存于 UI 设定文件夹" #: src/frontend/mame/ui/miscmenu.cpp:665 msgid "Name: Description:\n" @@ -1528,7 +1528,7 @@ msgstr "名称: 描述:\n" #: src/frontend/mame/ui/miscmenu.cpp:676 #, c-format msgid "%s.txt saved in UI settings folder." -msgstr "" +msgstr "%s.txt 已保存于 UI 设定文件夹" #: src/frontend/mame/ui/miscmenu.cpp:693 msgid "Export list in XML format (like -listxml)" @@ -2126,6 +2126,10 @@ msgid "" "Press %1$s to cancel\n" "Press %2$s to continue" msgstr "" +"取消校验?\n" +"\n" +"按下 %1$s 取消\n" +"按下 %2$s 继续" #: src/frontend/mame/ui/auditmenu.cpp:135 #, c-format @@ -2300,7 +2304,7 @@ msgstr "鼠标按下背景颜色" #: src/frontend/mame/ui/custui.cpp:600 msgid "Restore default colors" -msgstr "" +msgstr "还原至缺省颜色" #: src/frontend/mame/ui/custui.cpp:612 msgid "UI Color Settings" @@ -2309,7 +2313,7 @@ msgstr "UI 色彩设定" #: src/frontend/mame/ui/custui.cpp:621 #, c-format msgid "Double-click or press %1$s to change color" -msgstr "" +msgstr "双击或按下 %1$s 改变颜色" #: src/frontend/mame/ui/custui.cpp:629 msgid "Menu Preview" @@ -3615,12 +3619,12 @@ msgstr "半押" #: src/emu/inpttype.ipp:119 msgctxt "input-name" msgid "High" -msgstr "" +msgstr "大" #: src/emu/inpttype.ipp:120 msgctxt "input-name" msgid "Low" -msgstr "" +msgstr "小" #: src/emu/inpttype.ipp:125 msgctxt "input-name" @@ -5225,42 +5229,42 @@ msgstr "P10 选择" #: src/emu/inpttype.ipp:497 msgctxt "input-name" msgid "1 Player Start" -msgstr "1 位玩家开始" +msgstr "玩家 1 开始" #: src/emu/inpttype.ipp:498 msgctxt "input-name" msgid "2 Players Start" -msgstr "2 位玩家开始" +msgstr "玩家 2 开始" #: src/emu/inpttype.ipp:499 msgctxt "input-name" msgid "3 Players Start" -msgstr "3 位玩家开始" +msgstr "玩家 3 开始" #: src/emu/inpttype.ipp:500 msgctxt "input-name" msgid "4 Players Start" -msgstr "4 位玩家开始" +msgstr "玩家 4 开始" #: src/emu/inpttype.ipp:501 msgctxt "input-name" msgid "5 Players Start" -msgstr "5 位玩家开始" +msgstr "玩家 5 开始" #: src/emu/inpttype.ipp:502 msgctxt "input-name" msgid "6 Players Start" -msgstr "6 位玩家开始" +msgstr "玩家 6 开始" #: src/emu/inpttype.ipp:503 msgctxt "input-name" msgid "7 Players Start" -msgstr "7 位玩家开始" +msgstr "玩家 7 开始" #: src/emu/inpttype.ipp:504 msgctxt "input-name" msgid "8 Players Start" -msgstr "8 位玩家开始" +msgstr "玩家 8 开始" #: src/emu/inpttype.ipp:509 msgctxt "input-name" @@ -5325,7 +5329,7 @@ msgstr "投币孔 12" #: src/emu/inpttype.ipp:521 msgctxt "input-name" msgid "Bill 1" -msgstr "" +msgstr "投钞孔 1" #: src/emu/inpttype.ipp:526 msgctxt "input-name" @@ -6305,7 +6309,7 @@ msgstr "鼠标 Y 10" #: src/emu/inpttype.ipp:806 msgctxt "input-name" msgid "Keypad" -msgstr "" +msgstr "小键盘" #: src/emu/inpttype.ipp:807 msgctxt "input-name" @@ -6350,7 +6354,7 @@ msgstr "重新启动机台" #: src/emu/inpttype.ipp:819 msgctxt "input-name" msgid "Soft Reset" -msgstr "" +msgstr "软体重新启动" #: src/emu/inpttype.ipp:820 msgctxt "input-name" @@ -6520,7 +6524,7 @@ msgstr "菜单 切换" #: src/emu/inpttype.ipp:853 msgctxt "input-name" msgid "UI Release Pointer" -msgstr "" +msgstr "菜单 解除指标锁定" #: src/emu/inpttype.ipp:854 msgctxt "input-name" @@ -6560,7 +6564,7 @@ msgstr "菜单 新增/移除最爱项目" #: src/emu/inpttype.ipp:861 msgctxt "input-name" msgid "UI Export List" -msgstr "菜单" +msgstr "菜单 汇出列表" #: src/emu/inpttype.ipp:862 msgctxt "input-name" @@ -7046,18 +7050,3 @@ msgstr "MESSinfo" #: plugins/data/data_mameinfo.lua:20 msgid "MAMEinfo" msgstr "MAMEinfo" - -#, c-format -#~ msgid "%s.xml saved under ui folder." -#~ msgstr "%s.xml 已保存于 ui 文件夹。" - -#, c-format -#~ msgid "%s.txt saved under ui folder." -#~ msgstr "%s.txt 已保存于 ui 资料夹下。" - -#, c-format -#~ msgid "Double-click or press %1$s to change the color value" -#~ msgstr "双击或按下 %1$s 以改变颜色值" - -#~ msgid "Restore originals colors" -#~ msgstr "还原至原本颜色" diff --git a/language/Chinese_Traditional/strings.po b/language/Chinese_Traditional/strings.po index 96ec4caa052..7a2bc6a2ffd 100644 --- a/language/Chinese_Traditional/strings.po +++ b/language/Chinese_Traditional/strings.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: MAME\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-10-16 04:41+1100\n" -"PO-Revision-Date: 2021-10-14 21:20+0800\n" +"PO-Revision-Date: 2021-10-16 12:55+0800\n" "Last-Translator: YuiFAN\n" "Language-Team: MAME Language Team\n" "Language: zh_TW\n" @@ -300,7 +300,7 @@ msgstr "搜尋: %1$s_" #: src/frontend/mame/ui/selsoft.cpp:723 #, c-format msgid "Software list/item: %1$s:%2$s" -msgstr "" +msgstr "軟體列表/項目: %1$s:%2$s" #: src/frontend/mame/ui/optsmenu.cpp:73 src/frontend/mame/ui/sndmenu.cpp:163 msgid "Sound Options" @@ -1519,7 +1519,7 @@ msgstr "可見度延遲" #: src/frontend/mame/ui/miscmenu.cpp:639 #, c-format msgid "%s.xml saved in UI settings folder." -msgstr "" +msgstr "%s.xml 已儲存於 UI 設定資料夾" #: src/frontend/mame/ui/miscmenu.cpp:665 msgid "Name: Description:\n" @@ -1528,7 +1528,7 @@ msgstr "名稱: 描述:\n" #: src/frontend/mame/ui/miscmenu.cpp:676 #, c-format msgid "%s.txt saved in UI settings folder." -msgstr "" +msgstr "%s.txt 已儲存於 UI 設定資料夾" #: src/frontend/mame/ui/miscmenu.cpp:693 msgid "Export list in XML format (like -listxml)" @@ -2126,6 +2126,10 @@ msgid "" "Press %1$s to cancel\n" "Press %2$s to continue" msgstr "" +"取消驗證?\n" +"\n" +"按下 %1$s 取消\n" +"按下 %2$s 繼續" #: src/frontend/mame/ui/auditmenu.cpp:135 #, c-format @@ -2300,7 +2304,7 @@ msgstr "滑鼠按下背景顏色" #: src/frontend/mame/ui/custui.cpp:600 msgid "Restore default colors" -msgstr "" +msgstr "還原至預設顏色" #: src/frontend/mame/ui/custui.cpp:612 msgid "UI Color Settings" @@ -2309,7 +2313,7 @@ msgstr "UI 色彩設定" #: src/frontend/mame/ui/custui.cpp:621 #, c-format msgid "Double-click or press %1$s to change color" -msgstr "" +msgstr "雙擊或按下 %1$s 改變顏色" #: src/frontend/mame/ui/custui.cpp:629 msgid "Menu Preview" @@ -3615,12 +3619,12 @@ msgstr "半押" #: src/emu/inpttype.ipp:119 msgctxt "input-name" msgid "High" -msgstr "" +msgstr "大" #: src/emu/inpttype.ipp:120 msgctxt "input-name" msgid "Low" -msgstr "" +msgstr "小" #: src/emu/inpttype.ipp:125 msgctxt "input-name" @@ -5225,42 +5229,42 @@ msgstr "P10 選擇" #: src/emu/inpttype.ipp:497 msgctxt "input-name" msgid "1 Player Start" -msgstr "1 位玩家開始" +msgstr "玩家 1 開始" #: src/emu/inpttype.ipp:498 msgctxt "input-name" msgid "2 Players Start" -msgstr "2 位玩家開始" +msgstr "玩家 2 開始" #: src/emu/inpttype.ipp:499 msgctxt "input-name" msgid "3 Players Start" -msgstr "3 位玩家開始" +msgstr "玩家 3 開始" #: src/emu/inpttype.ipp:500 msgctxt "input-name" msgid "4 Players Start" -msgstr "4 位玩家開始" +msgstr "玩家 4 開始" #: src/emu/inpttype.ipp:501 msgctxt "input-name" msgid "5 Players Start" -msgstr "5 位玩家開始" +msgstr "玩家 5 開始" #: src/emu/inpttype.ipp:502 msgctxt "input-name" msgid "6 Players Start" -msgstr "6 位玩家開始" +msgstr "玩家 6 開始" #: src/emu/inpttype.ipp:503 msgctxt "input-name" msgid "7 Players Start" -msgstr "7 位玩家開始" +msgstr "玩家 7 開始" #: src/emu/inpttype.ipp:504 msgctxt "input-name" msgid "8 Players Start" -msgstr "8 位玩家開始" +msgstr "玩家 8 開始" #: src/emu/inpttype.ipp:509 msgctxt "input-name" @@ -5325,7 +5329,7 @@ msgstr "投幣孔 12" #: src/emu/inpttype.ipp:521 msgctxt "input-name" msgid "Bill 1" -msgstr "" +msgstr "吸鈔口 1" #: src/emu/inpttype.ipp:526 msgctxt "input-name" @@ -6305,7 +6309,7 @@ msgstr "滑鼠 Y 10" #: src/emu/inpttype.ipp:806 msgctxt "input-name" msgid "Keypad" -msgstr "" +msgstr "小鍵盤" #: src/emu/inpttype.ipp:807 msgctxt "input-name" @@ -6350,7 +6354,7 @@ msgstr "重新啟動機台" #: src/emu/inpttype.ipp:819 msgctxt "input-name" msgid "Soft Reset" -msgstr "" +msgstr "軟體重新啟動" #: src/emu/inpttype.ipp:820 msgctxt "input-name" @@ -6520,7 +6524,7 @@ msgstr "選單 切換" #: src/emu/inpttype.ipp:853 msgctxt "input-name" msgid "UI Release Pointer" -msgstr "" +msgstr "選單 釋放指標" #: src/emu/inpttype.ipp:854 msgctxt "input-name" @@ -6560,7 +6564,7 @@ msgstr "選單 新增/移除最愛項目" #: src/emu/inpttype.ipp:861 msgctxt "input-name" msgid "UI Export List" -msgstr "選單" +msgstr "選單 匯出清單" #: src/emu/inpttype.ipp:862 msgctxt "input-name" @@ -7046,18 +7050,3 @@ msgstr "MESSinfo" #: plugins/data/data_mameinfo.lua:20 msgid "MAMEinfo" msgstr "MAMEinfo" - -#, c-format -#~ msgid "%s.xml saved under ui folder." -#~ msgstr "%s.xml 已儲存於 ui 資料夾下。" - -#, c-format -#~ msgid "%s.txt saved under ui folder." -#~ msgstr "%s.txt 已儲存於 ui 資料夾下。" - -#, c-format -#~ msgid "Double-click or press %1$s to change the color value" -#~ msgstr "雙擊或按下 %1$s 以改變顏色值" - -#~ msgid "Restore originals colors" -#~ msgstr "還原至原本顏色" diff --git a/src/frontend/mame/cheat.cpp b/src/frontend/mame/cheat.cpp index f4a567db28f..2946d2c2257 100644 --- a/src/frontend/mame/cheat.cpp +++ b/src/frontend/mame/cheat.cpp @@ -431,12 +431,12 @@ cheat_script::script_entry::script_entry( // extract other attributes m_line = entrynode.get_attribute_int("line", 0); - m_justify = ui::text_layout::LEFT; + m_justify = ui::text_layout::text_justify::LEFT; char const *const align(entrynode.get_attribute_string("align", "left")); if (!std::strcmp(align, "center")) - m_justify = ui::text_layout::CENTER; + m_justify = ui::text_layout::text_justify::CENTER; else if (!std::strcmp(align, "right")) - m_justify = ui::text_layout::RIGHT; + m_justify = ui::text_layout::text_justify::RIGHT; else if (std::strcmp(align, "left")) throw emu_fatalerror("%s.xml(%d): invalid alignment '%s' specified\n", filename, entrynode.line, align); @@ -547,9 +547,9 @@ void cheat_script::script_entry::save(emu_file &cheatfile) const if (m_line != 0) cheatfile.printf(" line=\"%d\"", m_line); - if (m_justify == ui::text_layout::CENTER) + if (m_justify == ui::text_layout::text_justify::CENTER) cheatfile.printf(" align=\"center\""); - else if (m_justify == ui::text_layout::RIGHT) + else if (m_justify == ui::text_layout::text_justify::RIGHT) cheatfile.printf(" align=\"right\""); if (m_arglist.size() == 0) @@ -1236,10 +1236,13 @@ void cheat_manager::render_text(mame_ui_manager &mui, render_container &containe if (!m_output[linenum].empty()) { // output the text - mui.draw_text_full(container, m_output[linenum], + mui.draw_text_full( + container, + m_output[linenum], 0.0f, float(linenum) * mui.get_line_height(), 1.0f, - m_justify[linenum], ui::text_layout::NEVER, mame_ui_manager::OPAQUE_, - rgb_t::white(), rgb_t::black(), nullptr, nullptr); + m_justify[linenum], ui::text_layout::word_wrapping::NEVER, + mame_ui_manager::OPAQUE_, rgb_t::white(), rgb_t::black(), + nullptr, nullptr); } } } diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 78521783541..a76c46fb1d5 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -85,7 +85,7 @@ void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, { float const sc_width(sdev.visible_area().width()); float const sc_height(sdev.visible_area().height()); - auto justify = ui::text_layout::LEFT; + auto justify = ui::text_layout::text_justify::LEFT; float x = 0; if (xobj.is()) { @@ -95,11 +95,11 @@ void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, { char const *const justifystr(xobj.as()); if (!strcmp(justifystr, "left")) - justify = ui::text_layout::LEFT; + justify = ui::text_layout::text_justify::LEFT; else if (!strcmp(justifystr, "right")) - justify = ui::text_layout::RIGHT; + justify = ui::text_layout::text_justify::RIGHT; else if (!strcmp(justifystr, "center")) - justify = ui::text_layout::CENTER; + justify = ui::text_layout::text_justify::CENTER; } else { @@ -111,7 +111,7 @@ void do_draw_text(lua_State *L, screen_device &sdev, sol::object &xobj, float y, sdev.container(), msg, x, y, (1.0f - x), - justify, ui::text_layout::WORD, + justify, ui::text_layout::word_wrapping::WORD, mame_ui_manager::OPAQUE_, fgcolor, bgcolor); } diff --git a/src/frontend/mame/ui/analogipt.cpp b/src/frontend/mame/ui/analogipt.cpp index d1df77c5647..2f1d1a7128d 100644 --- a/src/frontend/mame/ui/analogipt.cpp +++ b/src/frontend/mame/ui/analogipt.cpp @@ -90,7 +90,8 @@ void menu_analog::custom_render(void *selectedref, float top, float bottom, floa ui().draw_text_full( container(), data.field.get().name(), - nameleft, liney, namewidth, ui::text_layout::LEFT, ui::text_layout::NEVER, + nameleft, liney, namewidth, + text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, fgcolor, ui().colors().text_bg_color()); ioport_value cur(0U); diff --git a/src/frontend/mame/ui/auditmenu.cpp b/src/frontend/mame/ui/auditmenu.cpp index 717973d9cfc..afe54aeaf69 100644 --- a/src/frontend/mame/ui/auditmenu.cpp +++ b/src/frontend/mame/ui/auditmenu.cpp @@ -80,7 +80,7 @@ void menu_audit::custom_render(void *selectedref, float top, float bottom, float draw_text_box( &m_prompt, &m_prompt + 1, x, x2, y2 + ui().box_tb_border(), y2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } break; @@ -102,7 +102,7 @@ void menu_audit::custom_render(void *selectedref, float top, float bottom, float ui().draw_text_box( container(), std::move(text).str(), - ui::text_layout::CENTER, + text_layout::text_justify::CENTER, 0.5f, 0.5f, ui().colors().background_color()); } @@ -115,7 +115,7 @@ void menu_audit::custom_render(void *selectedref, float top, float bottom, float _("Cancel audit?\n\nPress %1$s to cancel\nPress %2$s to continue"), ui().get_general_input_setting(IPT_UI_SELECT), ui().get_general_input_setting(IPT_UI_CANCEL)), - ui::text_layout::CENTER, + text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR); break; diff --git a/src/frontend/mame/ui/confswitch.cpp b/src/frontend/mame/ui/confswitch.cpp index d45f8f0242c..be1346171d3 100644 --- a/src/frontend/mame/ui/confswitch.cpp +++ b/src/frontend/mame/ui/confswitch.cpp @@ -335,7 +335,7 @@ void menu_settings_dip_switches::custom_render(void *selectedref, float top, flo container(), group.name, nameleft, liney + (lineheight * (DIP_SWITCH_HEIGHT - 1.0f) / 2.0f), namewidth, - ui::text_layout::RIGHT, ui::text_layout::NEVER, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); // draw the group outline diff --git a/src/frontend/mame/ui/custui.cpp b/src/frontend/mame/ui/custui.cpp index 69b3a3b0b3b..76d5b282534 100644 --- a/src/frontend/mame/ui/custui.cpp +++ b/src/frontend/mame/ui/custui.cpp @@ -199,7 +199,7 @@ void menu_custom_ui::custom_render(void *selectedref, float top, float bottom, f draw_text_box( std::begin(text), std::end(text), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -491,7 +491,7 @@ void menu_font_ui::custom_render(void *selectedref, float top, float bottom, flo draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); if (uintptr_t(selectedref) == INFOS_SIZE) @@ -500,7 +500,7 @@ void menu_font_ui::custom_render(void *selectedref, float top, float bottom, flo draw_text_box( std::begin(bottomtext), std::end(bottomtext), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::LEFT, ui::text_layout::NEVER, false, + text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_GREEN_COLOR, m_info_size); } } @@ -613,7 +613,7 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); // bottom text @@ -622,7 +622,7 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f draw_text_box( std::begin(bottomtext), std::end(bottomtext), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); // compute maxwidth @@ -630,8 +630,12 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f const float lr_border = ui().box_lr_border() * machine().render().ui_aspect(&container()); float width; - ui().draw_text_full(container(), topbuf, 0.0f, 0.0f, 1.0f, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); + ui().draw_text_full( + container(), + topbuf, + 0.0f, 0.0f, 1.0f, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); float maxwidth = width + 2.0f * lr_border; std::string sampletxt[5]; @@ -644,8 +648,12 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f for (auto & elem: sampletxt) { - ui().draw_text_full(container(), elem, 0.0f, 0.0f, 1.0f, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); + ui().draw_text_full( + container(), + elem, + 0.0f, 0.0f, 1.0f, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); width += 2 * lr_border; maxwidth = std::max(maxwidth, width); } @@ -666,8 +674,12 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f y2 -= ui().box_tb_border(); // draw the text within it - ui().draw_text_full(container(), topbuf, x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), nullptr, nullptr); + ui().draw_text_full( + container(), + topbuf, + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), nullptr, nullptr); // compute our bounds for menu preview float line_height = ui().get_line_height(); @@ -685,30 +697,50 @@ void menu_colors_ui::custom_render(void *selectedref, float top, float bottom, f y1 += ui().box_tb_border(); // draw normal text - ui().draw_text_full(container(), sampletxt[0], x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, m_color_table[MUI_TEXT_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); + ui().draw_text_full( + container(), + sampletxt[0], + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, m_color_table[MUI_TEXT_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); y1 += line_height; // draw subitem text - ui().draw_text_full(container(), sampletxt[1], x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, m_color_table[MUI_SUBITEM_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); + ui().draw_text_full( + container(), + sampletxt[1], + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, m_color_table[MUI_SUBITEM_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); y1 += line_height; // draw selected text highlight(x1, y1, x2, y1 + line_height, m_color_table[MUI_SELECTED_BG_COLOR].color); - ui().draw_text_full(container(), sampletxt[2], x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, m_color_table[MUI_SELECTED_COLOR].color, m_color_table[MUI_SELECTED_BG_COLOR].color, nullptr, nullptr); + ui().draw_text_full( + container(), + sampletxt[2], + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, m_color_table[MUI_SELECTED_COLOR].color, m_color_table[MUI_SELECTED_BG_COLOR].color, nullptr, nullptr); y1 += line_height; // draw mouse over text highlight(x1, y1, x2, y1 + line_height, m_color_table[MUI_MOUSEOVER_BG_COLOR].color); - ui().draw_text_full(container(), sampletxt[3], x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, m_color_table[MUI_MOUSEOVER_COLOR].color, m_color_table[MUI_MOUSEOVER_BG_COLOR].color, nullptr, nullptr); + ui().draw_text_full( + container(), + sampletxt[3], + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, m_color_table[MUI_MOUSEOVER_COLOR].color, m_color_table[MUI_MOUSEOVER_BG_COLOR].color, nullptr, nullptr); y1 += line_height; // draw clone text - ui().draw_text_full(container(), sampletxt[4], x1, y1, x2 - x1, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, m_color_table[MUI_CLONE_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); + ui().draw_text_full( + container(), + sampletxt[4], + x1, y1, x2 - x1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, m_color_table[MUI_CLONE_COLOR].color, m_color_table[MUI_TEXT_BG_COLOR].color, nullptr, nullptr); } @@ -890,8 +922,12 @@ void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, floa float width, maxwidth = origx2 - origx1; // top text - ui().draw_text_full(container(), m_title, 0.0f, 0.0f, 1.0f, ui::text_layout::CENTER, ui::text_layout::NEVER, - mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width); + ui().draw_text_full( + container(), + m_title, + 0.0f, 0.0f, 1.0f, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width); const float lr_border = ui().box_lr_border() * machine().render().ui_aspect(&container()); width += 2 * lr_border; maxwidth = std::max(maxwidth, width); @@ -915,7 +951,7 @@ void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, floa container(), m_title, x1, y1, x2 - x1, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color()); std::string sampletxt(_("Color preview:")); @@ -923,7 +959,7 @@ void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, floa container(), sampletxt, 0.0f, 0.0f, 1.0f, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width); width += 2 * lr_border; @@ -947,7 +983,7 @@ void menu_rgb_ui::custom_render(void *selectedref, float top, float bottom, floa container(), sampletxt, x1, y1, width - lr_border, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, rgb_t::white(), rgb_t::black()); x1 += width + (lr_border * 2.0f); diff --git a/src/frontend/mame/ui/datmenu.cpp b/src/frontend/mame/ui/datmenu.cpp index a707c76459e..f25ece6015a 100644 --- a/src/frontend/mame/ui/datmenu.cpp +++ b/src/frontend/mame/ui/datmenu.cpp @@ -35,10 +35,11 @@ namespace ui { menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_system_info *system) : menu(mui, container) - , m_actual(0) , m_system(!system ? &system_list::instance().systems()[driver_list::find(mui.machine().system().name)] : system) , m_swinfo(nullptr) , m_issoft(false) + , m_layout() + , m_actual(0) { for (device_image_interface& image : image_interface_enumerator(mui.machine().root_device())) @@ -71,23 +72,24 @@ menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container menu_dats_view::menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_software_info *swinfo, const ui_system_info *system) : menu(mui, container) - , m_actual(0) , m_system(!system ? &system_list::instance().systems()[driver_list::find(mui.machine().system().name)] : system) , m_swinfo(swinfo) + , m_issoft(true) + , m_layout() + , m_actual(0) , m_list(swinfo->listname) , m_short(swinfo->shortname) , m_long(swinfo->longname) , m_parent(swinfo->parentname) - , m_issoft(true) { - if (swinfo != nullptr && !swinfo->infotext.empty()) + if (swinfo && !swinfo->infotext.empty()) m_items_list.emplace_back(_("Software List Info"), 0, ""); std::vector lua_list; if (mame_machine_manager::instance()->lua()->call_plugin("data_list", std::string(m_short).append(1, ',').append(m_list).c_str(), lua_list)) { int count = 1; - for(std::string &item : lua_list) + for (std::string &item : lua_list) { std::string version; mame_machine_manager::instance()->lua()->call_plugin("data_version", count - 1, version); @@ -105,25 +107,110 @@ menu_dats_view::~menu_dats_view() { } +//------------------------------------------------- +// add text to layout +//------------------------------------------------- + +void menu_dats_view::add_info_text(text_layout &layout, std::string_view text, rgb_t color, float size) +{ + char justify = 'l'; // left justify by default + if ((text.length() > 3) && (text[0] == '#') && (text[1] == 'j')) + { + auto const eol = text.find('\n'); + if ((std::string_view::npos != eol) && (2 < eol)) + { + justify = text[2]; + text.remove_prefix(eol + 1); + } + } + + if ('2' == justify) + { + while (!text.empty()) + { + // pop a line from the front + auto const eol = text.find('\n'); + std::string_view const line = (std::string_view::npos != eol) + ? text.substr(0, eol + 1) + : text; + text.remove_prefix(line.length()); + + // split on the first tab + auto const split = line.find('\t'); + if (std::string_view::npos != split) + { + layout.add_text(line.substr(0, split), text_layout::text_justify::LEFT, color, rgb_t::transparent(), size); + layout.add_text(" ", text_layout::text_layout::text_justify::LEFT, color, rgb_t::transparent(), size); + layout.add_text(line.substr(split + 1), text_layout::text_justify::RIGHT, color, rgb_t::transparent(), size); + } + else + { + layout.add_text(line, text_layout::text_justify::LEFT, color, rgb_t::transparent(), size); + } + } + } + else + { + // use the same alignment for all the text + auto const j = + ('c' == justify) ? text_layout::text_justify::CENTER : + ('r' == justify) ? text_layout::text_justify::RIGHT : + text_layout::text_justify::LEFT; + layout.add_text(text, j, color, rgb_t::transparent(), size); + } + +} + //------------------------------------------------- // handle //------------------------------------------------- void menu_dats_view::handle() { - const event *menu_event = process(FLAG_UI_DATS); - if (menu_event != nullptr) + event const *const menu_event = process(PROCESS_LR_ALWAYS | PROCESS_CUSTOM_NAV); + if (menu_event) { - if (menu_event->iptkey == IPT_UI_LEFT && m_actual > 0) + switch (menu_event->iptkey) { - m_actual--; - reset(reset_options::SELECT_FIRST); - } + case IPT_UI_LEFT: + if (m_actual > 0) + { + m_actual--; + reset(reset_options::SELECT_FIRST); + } + break; - if (menu_event->iptkey == IPT_UI_RIGHT && m_actual < m_items_list.size() - 1) - { - m_actual++; - reset(reset_options::SELECT_FIRST); + case IPT_UI_RIGHT: + if ((m_actual + 1) < m_items_list.size()) + { + m_actual++; + reset(reset_options::SELECT_FIRST); + } + break; + + case IPT_UI_UP: + --top_line; + break; + + case IPT_UI_DOWN: + ++top_line; + break; + + case IPT_UI_PAGE_UP: + top_line -= m_visible_lines - 3; + break; + + case IPT_UI_PAGE_DOWN: + top_line += m_visible_lines - 3; + break; + + case IPT_UI_HOME: + top_line = 0; + break; + + case IPT_UI_END: + top_line = m_layout->lines() - m_visible_lines; + break; } } } @@ -138,9 +225,8 @@ void menu_dats_view::populate(float &customtop, float &custombottom) if (!paused) machine().pause(); - (m_issoft == true) ? get_data_sw() : get_data(); + m_layout = std::nullopt; - item_append(menu_item_type::SEPARATOR, (FLAG_UI_DATS | FLAG_LEFT_ARROW | FLAG_RIGHT_ARROW)); customtop = 2.0f * ui().get_line_height() + 4.0f * ui().box_tb_border(); custombottom = ui().get_line_height() + 3.0f * ui().box_tb_border(); @@ -162,7 +248,6 @@ void menu_dats_view::draw(uint32_t flags) float const visible_left = (1.0f - visible_width) * 0.5f; float const extra_height = 2.0f * line_height; float const visible_extra_menu_height = get_customtop() + get_custombottom() + extra_height; - int const visible_items = item_count() - 2; // determine effective positions taking into account the hilighting arrows float const effective_width = visible_width - 2.0f * gutter_width; @@ -179,116 +264,104 @@ void menu_dats_view::draw(uint32_t flags) // compute top/left of inner menu area by centering, if the menu is at the bottom of the extra, adjust float const visible_top = ((1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f) + get_customtop(); - // compute left box size - float x1 = visible_left; - float y1 = visible_top - ui().box_tb_border(); - float x2 = x1 + visible_width; - float y2 = visible_top + visible_main_menu_height + ui().box_tb_border() + extra_height; - float line = visible_top + float(m_visible_lines) * line_height; + // compute text box size + float const x1 = visible_left; + float const y1 = visible_top - ui().box_tb_border(); + float const x2 = x1 + visible_width; + float const y2 = visible_top + visible_main_menu_height + ui().box_tb_border() + extra_height; + float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH; + float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH; + float const separator = visible_top + float(m_visible_lines) * line_height; ui().draw_outlined_box(container(), x1, y1, x2, y2, ui().colors().background_color()); + if (!m_layout || (m_layout->width() != effective_width)) + { + std::string buffer; + if (m_issoft) + get_data_sw(buffer); + else + get_data(buffer); + m_layout.emplace(ui().create_layout(container(), effective_width)); + add_info_text(*m_layout, buffer, ui().colors().text_color()); + } + int const visible_items = m_layout->lines(); m_visible_lines = (std::min)(visible_items, m_visible_lines); top_line = (std::max)(0, top_line); if (top_line + m_visible_lines >= visible_items) top_line = visible_items - m_visible_lines; clear_hover(); - int const n_loop = (std::min)(visible_items, m_visible_lines); - for (int linenum = 0; linenum < n_loop; linenum++) + if (top_line) { - float const line_y = visible_top + float(linenum) * line_height; - int const itemnum = top_line + linenum; - menu_item const &pitem = item(itemnum); - std::string_view const itemtext = pitem.text; - float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float const line_y0 = line_y; - float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float const line_y1 = line_y + line_height; - + // if we're on the top line, display the up arrow rgb_t fgcolor = ui().colors().text_color(); - rgb_t bgcolor = ui().colors().text_bg_color(); - - if (!linenum && top_line) + if (mouse_in_rect(line_x0, visible_top, line_x1, visible_top + line_height)) { - // if we're on the top line, display the up arrow - if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1)) - { - fgcolor = ui().colors().mouseover_color(); - bgcolor = ui().colors().mouseover_bg_color(); - highlight(line_x0, line_y0, line_x1, line_y1, bgcolor); - set_hover(HOVER_ARROW_UP); - } - draw_arrow( - 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, - fgcolor, ROT0); - } - else if ((linenum == m_visible_lines - 1) && (itemnum != visible_items - 1)) - { - // if we're on the bottom line, display the down arrow - if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1)) - { - fgcolor = ui().colors().mouseover_color(); - bgcolor = ui().colors().mouseover_bg_color(); - highlight(line_x0, line_y0, line_x1, line_y1, bgcolor); - set_hover(HOVER_ARROW_DOWN); - } - draw_arrow( - 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, - 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, - fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); - } - else if (pitem.subtext.empty()) - { - // draw dats text - ui().draw_text_full( - container(), itemtext, - effective_left, line_y, effective_width, - ui::text_layout::LEFT, ui::text_layout::NEVER, - mame_ui_manager::NORMAL, fgcolor, bgcolor, - nullptr, nullptr); + fgcolor = ui().colors().mouseover_color(); + highlight( + line_x0, visible_top, + line_x1, visible_top + line_height, + ui().colors().mouseover_bg_color()); + set_hover(HOVER_ARROW_UP); } + draw_arrow( + 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, visible_top + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, visible_top + 0.75f * line_height, + fgcolor, ROT0); } - - for (size_t count = visible_items; count < item_count(); count++) + if ((top_line + m_visible_lines) < visible_items) { - menu_item const &pitem = item(count); - std::string_view const itemtext = pitem.text; - float const line_x0 = x1 + 0.5f * UI_LINE_WIDTH; - float const line_y0 = line; - float const line_x1 = x2 - 0.5f * UI_LINE_WIDTH; - float const line_y1 = line + line_height; - rgb_t const fgcolor = ui().colors().selected_color(); - rgb_t const bgcolor = ui().colors().selected_bg_color(); - - if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem)) - set_hover(count); - - if (pitem.type == menu_item_type::SEPARATOR) + // if we're on the bottom line, display the down arrow + float const line_y = visible_top + float(m_visible_lines - 1) * line_height; + rgb_t fgcolor = ui().colors().text_color(); + if (mouse_in_rect(line_x0, line_y, line_x1, line_y + line_height)) { - container().add_line( - visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, - UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + fgcolor = ui().colors().mouseover_color(); + highlight( + line_x0, line_y, + line_x1, line_y + line_height, + ui().colors().mouseover_bg_color()); + set_hover(HOVER_ARROW_DOWN); } - else - { - highlight(line_x0, line_y0, line_x1, line_y1, bgcolor); - ui().draw_text_full( - container(), itemtext, - effective_left, line, effective_width, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, fgcolor, bgcolor, - nullptr, nullptr); - } - line += line_height; + draw_arrow( + 0.5f * (x1 + x2) - 0.5f * ud_arrow_width, line_y + 0.25f * line_height, + 0.5f * (x1 + x2) + 0.5f * ud_arrow_width, line_y + 0.75f * line_height, + fgcolor, ROT0 ^ ORIENTATION_FLIP_Y); } + // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow + m_visible_items = m_visible_lines - (top_line ? 1 : 0) - (top_line + m_visible_lines != visible_items); + m_layout->emit( + container(), + top_line ? (top_line + 1) : 0, m_visible_items, + effective_left, visible_top + (top_line ? line_height : 0.0f)); + + // add visual separator before the "return to prevous menu" item + container().add_line( + visible_left, separator + (0.5f * line_height), + visible_left + visible_width, separator + (0.5f * line_height), + UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + + menu_item const &pitem = item(0); + std::string_view const itemtext = pitem.text; + float const line_y0 = separator + line_height; + float const line_y1 = line_y0 + line_height; + + if (mouse_in_rect(line_x0, line_y0, line_x1, line_y1) && is_selectable(pitem)) + set_hover(0); + + highlight(line_x0, line_y0, line_x1, line_y1, ui().colors().selected_bg_color()); + ui().draw_text_full( + container(), itemtext, + effective_left, line_y0, effective_width, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, + ui().colors().selected_color(), ui().colors().selected_bg_color(), + nullptr, nullptr); + // if there is something special to add, do it by calling the virtual method custom_render(get_selection_ref(), get_customtop(), get_custombottom(), x1, y1, x2, y2); - - // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - m_visible_items = m_visible_lines - (top_line != 0) - (top_line + m_visible_lines != visible_items); } //------------------------------------------------- @@ -299,11 +372,15 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f { float maxwidth = origx2 - origx1; float width; - std::string_view driver = m_issoft ? m_swinfo->longname : m_system->description; + std::string_view const driver = m_issoft ? m_swinfo->longname : m_system->description; float const lr_border = ui().box_lr_border() * machine().render().ui_aspect(&container()); - ui().draw_text_full(container(), driver, 0.0f, 0.0f, 1.0f, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); + ui().draw_text_full( + container(), + driver, + 0.0f, 0.0f, 1.0f, + ui::text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); width += 2 * lr_border; maxwidth = std::max(maxwidth, width); @@ -325,7 +402,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f container(), driver, x1, y1, x2 - x1, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, ui::text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color()); maxwidth = 0; @@ -335,7 +412,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f container(), elem.label, 0.0f, 0.0f, 1.0f, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); maxwidth += width; @@ -369,7 +446,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f container(), elem.label, x1, y1, 1.0f, - ui::text_layout::LEFT, ui::text_layout::NEVER, + text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, mame_ui_manager::NONE, fcolor, bcolor, &width, nullptr); @@ -386,7 +463,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f container(), elem.label, x1, y1, 1.0f, - ui::text_layout::LEFT, ui::text_layout::NEVER, + text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, fcolor, bcolor, &width, nullptr); x1 += width + space; @@ -394,9 +471,14 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f } // bottom - std::string revision; - revision.assign(_("Revision: ")).append(m_items_list[m_actual].revision); - ui().draw_text_full(container(), revision, 0.0f, 0.0f, 1.0f, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &width, nullptr); + std::string const revision(util::string_format(_("Revision: %1$s"), m_items_list[m_actual].revision)); + ui().draw_text_full( + container(), + revision, + 0.0f, 0.0f, 1.0f, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), + &width, nullptr); width += 2 * lr_border; maxwidth = std::max(origx2 - origx1, width); @@ -419,7 +501,7 @@ void menu_dats_view::custom_render(void *selectedref, float top, float bottom, f container(), revision, x1, y1, x2 - x1, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color()); } @@ -448,43 +530,17 @@ bool menu_dats_view::custom_mouse_down() // load data from DATs //------------------------------------------------- -void menu_dats_view::get_data() +void menu_dats_view::get_data(std::string &buffer) { - std::vector xstart, xend; - std::string buffer; mame_machine_manager::instance()->lua()->call_plugin("data", m_items_list[m_actual].option, buffer); - - float const aspect = machine().render().ui_aspect(&container()); - float const line_height = ui().get_line_height(); - float const gutter_width = 0.52f * line_height * aspect; - float const visible_width = 1.0f - (2.0f * ui().box_lr_border() * aspect); - float const effective_width = visible_width - 2.0f * gutter_width; - - auto lines = ui().wrap_text(container(), buffer, 0.0f, 0.0f, effective_width, xstart, xend); - for (int x = 0; x < lines; ++x) - { - std::string tempbuf(buffer.substr(xstart[x], xend[x] - xstart[x])); - if ((tempbuf[0] != '#') || x) - item_append(std::move(tempbuf), (FLAG_UI_DATS | FLAG_DISABLE), (void *)(uintptr_t)(x + 1)); - } } -void menu_dats_view::get_data_sw() +void menu_dats_view::get_data_sw(std::string &buffer) { - std::vector xstart; - std::vector xend; - std::string buffer; if (m_items_list[m_actual].option == 0) buffer = m_swinfo->infotext; else mame_machine_manager::instance()->lua()->call_plugin("data", m_items_list[m_actual].option - 1, buffer); - - auto lines = ui().wrap_text(container(), buffer, 0.0f, 0.0f, 1.0f - (4.0f * ui().box_lr_border() * machine().render().ui_aspect(&container())), xstart, xend); - for (int x = 0; x < lines; ++x) - { - std::string tempbuf(buffer.substr(xstart[x], xend[x] - xstart[x])); - item_append(std::move(tempbuf), (FLAG_UI_DATS | FLAG_DISABLE), (void *)(uintptr_t)(x + 1)); - } } } // namespace ui diff --git a/src/frontend/mame/ui/datmenu.h b/src/frontend/mame/ui/datmenu.h index 45de4f423a5..33e3d160b84 100644 --- a/src/frontend/mame/ui/datmenu.h +++ b/src/frontend/mame/ui/datmenu.h @@ -15,8 +15,11 @@ #pragma once #include "ui/menu.h" +#include "ui/text.h" +#include #include +#include #include @@ -37,31 +40,37 @@ public: menu_dats_view(mame_ui_manager &mui, render_container &container, const ui_system_info *system = nullptr); virtual ~menu_dats_view() override; + static void add_info_text(text_layout &layout, std::string_view text, rgb_t color, float size = 1.0f); + protected: virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override; virtual bool custom_mouse_down() override; private: + struct list_items + { + list_items(std::string &&l, int i, std::string &&rev) : label(std::move(l)), option(i), revision(std::move(rev)) { } + + std::string label; + int option; + std::string revision; + }; + // draw dats menu virtual void draw(uint32_t flags) override; virtual void populate(float &customtop, float &custombottom) override; virtual void handle() override; + void get_data(std::string &buffer); + void get_data_sw(std::string &buffer); + + ui_system_info const *const m_system; + ui_software_info const *const m_swinfo; + bool const m_issoft; + std::optional m_layout; int m_actual; - const ui_system_info *m_system; - const ui_software_info *m_swinfo; std::string m_list, m_short, m_long, m_parent; - void get_data(); - void get_data_sw(); - bool m_issoft; - struct list_items - { - list_items(std::string l, int i, std::string rev) { label = l; option = i; revision = rev; } - std::string label; - int option; - std::string revision; - }; std::vector m_items_list; }; diff --git a/src/frontend/mame/ui/dirmenu.cpp b/src/frontend/mame/ui/dirmenu.cpp index a361bfd325f..f610189b771 100644 --- a/src/frontend/mame/ui/dirmenu.cpp +++ b/src/frontend/mame/ui/dirmenu.cpp @@ -122,7 +122,7 @@ void menu_directory::custom_render(void *selectedref, float top, float bottom, f draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -200,12 +200,12 @@ void menu_display_actual::custom_render(void *selectedref, float top, float bott float const maxwidth(draw_text_box( std::begin(m_folders), std::end(m_folders), origx1, origx2, origy1 - (3.0f * ui().box_tb_border()) - (m_folders.size() * lineheight), origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f)); draw_text_box( std::begin(m_heading), std::end(m_heading), 0.5f * (1.0f - maxwidth), 0.5f * (1.0f + maxwidth), origy1 - top, origy1 - top + lineheight + (2.0f * ui().box_tb_border()), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -426,7 +426,7 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); // bottom text @@ -434,7 +434,7 @@ void menu_add_change_folder::custom_render(void *selectedref, float top, float b draw_text_box( std::begin(bottomtext), std::end(bottomtext), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } @@ -518,7 +518,7 @@ void menu_remove_folder::custom_render(void *selectedref, float top, float botto draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } diff --git a/src/frontend/mame/ui/inifile.cpp b/src/frontend/mame/ui/inifile.cpp index 77b1cf47945..87cdd9329b1 100644 --- a/src/frontend/mame/ui/inifile.cpp +++ b/src/frontend/mame/ui/inifile.cpp @@ -268,7 +268,7 @@ favorite_manager::favorite_manager(ui_options &options) // need to populate this, it isn't displayed anywhere else tmpmatches.infotext.append(tmpmatches.longname); - tmpmatches.infotext.append("\t\n\n"); + tmpmatches.infotext.append(1, '\n'); tmpmatches.infotext.append(_("swlist-info", "Software list/item")); tmpmatches.infotext.append(1, '\n'); tmpmatches.infotext.append(tmpmatches.listname); diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp index 4d2c2c9bb8d..08cbab0facc 100644 --- a/src/frontend/mame/ui/inputmap.cpp +++ b/src/frontend/mame/ui/inputmap.cpp @@ -282,7 +282,7 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float draw_text_box( std::begin(text), std::end(text), x1, x2, y2 + ui().box_tb_border(), y2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } else @@ -299,7 +299,7 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float draw_text_box( std::begin(text), std::end(text), x1, x2, y2 + ui().box_tb_border(), y2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_RED_COLOR, 1.0f); } else if (selectedref) @@ -311,7 +311,7 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float draw_text_box( std::begin(text), std::end(text), x1, x2, y2 + ui().box_tb_border(), y2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } else @@ -322,7 +322,7 @@ void menu_input::custom_render(void *selectedref, float top, float bottom, float draw_text_box( std::begin(text), std::end(text), x1, x2, y2 + ui().box_tb_border(), y2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } } diff --git a/src/frontend/mame/ui/menu.cpp b/src/frontend/mame/ui/menu.cpp index 5b2bb73b7ad..ffbd52fa620 100644 --- a/src/frontend/mame/ui/menu.cpp +++ b/src/frontend/mame/ui/menu.cpp @@ -446,8 +446,13 @@ void menu::draw(uint32_t flags) // first draw the FPS counter if (ui().show_fps_counter()) { - ui().draw_text_full(container(), machine().video().speed_text(), 0.0f, 0.0f, 1.0f, - ui::text_layout::RIGHT, ui::text_layout::WORD, mame_ui_manager::OPAQUE_, rgb_t::white(), rgb_t::black(), nullptr, nullptr); + ui().draw_text_full( + container(), + machine().video().speed_text(), + 0.0f, 0.0f, 1.0f, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::WORD, + mame_ui_manager::OPAQUE_, rgb_t::white(), rgb_t::black(), + nullptr, nullptr); } bool const customonly = (flags & PROCESS_CUSTOM_ONLY); @@ -627,8 +632,13 @@ void menu::draw(uint32_t flags) container().add_line(visible_left, line_y0 + 0.5f * line_height, visible_left + ((visible_width - heading_width) / 2) - lr_border, line_y0 + 0.5f * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); container().add_line(visible_left + visible_width - ((visible_width - heading_width) / 2) + lr_border, line_y0 + 0.5f * line_height, visible_left + visible_width, line_y0 + 0.5f * line_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); } - ui().draw_text_full(container(), itemtext, effective_left, line_y0, effective_width, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); + ui().draw_text_full( + container(), + itemtext, + effective_left, line_y0, effective_width, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, + nullptr, nullptr); } else { @@ -637,8 +647,13 @@ void menu::draw(uint32_t flags) float item_width, subitem_width; // draw the left-side text - ui().draw_text_full(container(), itemtext, effective_left, line_y0, effective_width, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor, &item_width, nullptr); + ui().draw_text_full( + container(), + itemtext, + effective_left, line_y0, effective_width, + text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, + &item_width, nullptr); if (pitem.flags & FLAG_COLOR_BOX) { @@ -679,8 +694,13 @@ void menu::draw(uint32_t flags) fgcolor2 = rgb_t(0xff,0xff,0x00); // draw the subitem right-justified - ui().draw_text_full(container(), subitem_text, effective_left + item_width, line_y0, effective_width - item_width, - ui::text_layout::RIGHT, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, subitem_invert ? fgcolor3 : fgcolor2, bgcolor, &subitem_width, nullptr); + ui().draw_text_full( + container(), + subitem_text, + effective_left + item_width, line_y0, effective_width - item_width, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, subitem_invert ? fgcolor3 : fgcolor2, bgcolor, + &subitem_width, nullptr); } // apply arrows @@ -720,8 +740,13 @@ void menu::draw(uint32_t flags) float target_width, target_height; // compute the multi-line target width/height - ui().draw_text_full(container(), pitem.subtext, 0, 0, visible_width * 0.75f, - ui::text_layout::RIGHT, ui::text_layout::WORD, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &target_width, &target_height); + ui().draw_text_full( + container(), + pitem.subtext, + 0, 0, visible_width * 0.75f, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::WORD, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), + &target_width, &target_height); // determine the target location float const target_x = visible_left + visible_width - target_width - lr_border; @@ -730,14 +755,19 @@ void menu::draw(uint32_t flags) target_y = line_y - target_height - ui().box_tb_border(); // add a box around that - ui().draw_outlined_box(container(), target_x - lr_border, - target_y - ui().box_tb_border(), - target_x + target_width + lr_border, - target_y + target_height + ui().box_tb_border(), + ui().draw_outlined_box( + container(), + target_x - lr_border, target_y - ui().box_tb_border(), + target_x + target_width + lr_border, target_y + target_height + ui().box_tb_border(), subitem_invert ? ui().colors().selected_bg_color() : ui().colors().background_color()); - ui().draw_text_full(container(), pitem.subtext, target_x, target_y, target_width, - ui::text_layout::RIGHT, ui::text_layout::WORD, mame_ui_manager::NORMAL, ui().colors().selected_color(), ui().colors().selected_bg_color(), nullptr, nullptr); + ui().draw_text_full( + container(), + pitem.subtext, + target_x, target_y, target_width, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::WORD, + mame_ui_manager::NORMAL, ui().colors().selected_color(), ui().colors().selected_bg_color(), + nullptr, nullptr); } // if there is something special to add, do it by calling the virtual method @@ -767,8 +797,13 @@ void menu::draw_text_box() float target_x, target_y; // compute the multi-line target width/height - ui().draw_text_full(container(), text, 0, 0, 1.0f - 2.0f * lr_border - 2.0f * gutter_width, - ui::text_layout::LEFT, ui::text_layout::WORD, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &target_width, &target_height); + ui().draw_text_full( + container(), + text, + 0, 0, 1.0f - 2.0f * lr_border - 2.0f * gutter_width, + text_layout::text_justify::LEFT, text_layout::word_wrapping::WORD, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), + &target_width, &target_height); target_height += 2.0f * line_height; if (target_height > 1.0f - 2.0f * ui().box_tb_border()) target_height = floorf((1.0f - 2.0f * ui().box_tb_border()) / line_height) * line_height; @@ -792,23 +827,33 @@ void menu::draw_text_box() target_y = 1.0f - ui().box_tb_border() - target_height; // add a box around that - ui().draw_outlined_box(container(), target_x - lr_border - gutter_width, - target_y - ui().box_tb_border(), - target_x + target_width + gutter_width + lr_border, - target_y + target_height + ui().box_tb_border(), - (m_items[0].flags & FLAG_REDTEXT) ? UI_RED_COLOR : ui().colors().background_color()); - ui().draw_text_full(container(), text, target_x, target_y, target_width, - ui::text_layout::LEFT, ui::text_layout::WORD, mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), nullptr, nullptr); + ui().draw_outlined_box( + container(), + target_x - lr_border - gutter_width, target_y - ui().box_tb_border(), + target_x + target_width + gutter_width + lr_border, target_y + target_height + ui().box_tb_border(), + (m_items[0].flags & FLAG_REDTEXT) ? UI_RED_COLOR : ui().colors().background_color()); + ui().draw_text_full( + container(), + text, + target_x, target_y, target_width, + text_layout::text_justify::LEFT, text_layout::word_wrapping::WORD, + mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), + nullptr, nullptr); // draw the "return to prior menu" text with a hilight behind it highlight( - target_x + 0.5f * UI_LINE_WIDTH, - target_y + target_height - line_height, - target_x + target_width - 0.5f * UI_LINE_WIDTH, - target_y + target_height, - ui().colors().selected_bg_color()); - ui().draw_text_full(container(), backtext, target_x, target_y + target_height - line_height, target_width, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, ui().colors().selected_color(), ui().colors().selected_bg_color(), nullptr, nullptr); + target_x + 0.5f * UI_LINE_WIDTH, + target_y + target_height - line_height, + target_x + target_width - 0.5f * UI_LINE_WIDTH, + target_y + target_height, + ui().colors().selected_bg_color()); + ui().draw_text_full( + container(), + backtext, + target_x, target_y + target_height - line_height, target_width, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, ui().colors().selected_color(), ui().colors().selected_bg_color(), + nullptr, nullptr); // artificially set the hover to the last item so a double-click exits m_hover = m_items.size() - 1; @@ -875,27 +920,33 @@ void menu::handle_events(uint32_t flags, event &ev) } else if (m_hover == HOVER_ARROW_UP) { - if (flags & FLAG_UI_DATS) + if (flags & PROCESS_CUSTOM_NAV) { - top_line -= m_visible_items - (last_item_visible() ? 1 : 0); - return; + ev.iptkey = IPT_UI_PAGE_UP; + stop = true; + } + else + { + m_selected -= m_visible_items; + if (m_selected < 0) + m_selected = 0; + top_line -= m_visible_items - (last_item_visible() ? 1 : 0); } - m_selected -= m_visible_items; - if (m_selected < 0) - m_selected = 0; - top_line -= m_visible_items - (last_item_visible() ? 1 : 0); } else if (m_hover == HOVER_ARROW_DOWN) { - if ((flags & FLAG_UI_DATS) != 0) + if (flags & PROCESS_CUSTOM_NAV) { - top_line += m_visible_lines - 2; - return; + ev.iptkey = IPT_UI_PAGE_DOWN; + stop = true; + } + else + { + m_selected += m_visible_lines - 2 + is_first_selected(); + if (m_selected > m_items.size() - 1) + m_selected = m_items.size() - 1; + top_line += m_visible_lines - 2; } - m_selected += m_visible_lines - 2 + is_first_selected(); - if (m_selected > m_items.size() - 1) - m_selected = m_items.size() - 1; - top_line += m_visible_lines - 2; } else if (m_hover == HOVER_UI_LEFT) { @@ -931,13 +982,15 @@ void menu::handle_events(uint32_t flags, event &ev) { if (local_menu_event.zdelta > 0) { - if ((flags & FLAG_UI_DATS) != 0) + if (flags & PROCESS_CUSTOM_NAV) // FIXME: DAT menu logic - let the derived class handle this { top_line -= local_menu_event.num_lines; return; } - if (is_first_selected()) + else if (is_first_selected()) + { select_last_item(); + } else { m_selected -= local_menu_event.num_lines; @@ -949,13 +1002,15 @@ void menu::handle_events(uint32_t flags, event &ev) } else { - if ((flags & FLAG_UI_DATS)) + if (flags & PROCESS_CUSTOM_NAV) // FIXME: DAT menu logic - let the derived class handle this { top_line += local_menu_event.num_lines; return; } - if (is_last_selected()) + else if (is_last_selected()) + { select_first_item(); + } else { m_selected += local_menu_event.num_lines; @@ -1024,11 +1079,8 @@ void menu::handle_keys(uint32_t flags, int &iptkey) validate_selection(1); // swallow left/right keys if they are not appropriate - bool ignoreleft = !(flags & PROCESS_LR_ALWAYS) && !(selected_item().flags & FLAG_LEFT_ARROW); - bool ignoreright = !(flags & PROCESS_LR_ALWAYS) && !(selected_item().flags & FLAG_RIGHT_ARROW); - - if ((m_items[0].flags & FLAG_UI_DATS)) - ignoreleft = ignoreright = false; + bool const ignoreleft = !(flags & PROCESS_LR_ALWAYS) && !(selected_item().flags & FLAG_LEFT_ARROW); + bool const ignoreright = !(flags & PROCESS_LR_ALWAYS) && !(selected_item().flags & FLAG_RIGHT_ARROW); // accept left/right keys as-is with repeat if (!ignoreleft && exclusive_input_pressed(iptkey, IPT_UI_LEFT, (flags & PROCESS_LR_REPEAT) ? 6 : 0)) @@ -1039,13 +1091,14 @@ void menu::handle_keys(uint32_t flags, int &iptkey) // up backs up by one item if (exclusive_input_pressed(iptkey, IPT_UI_UP, 6)) { - if ((m_items[0].flags & FLAG_UI_DATS)) + if (flags & PROCESS_CUSTOM_NAV) { - top_line--; return; } - if (is_first_selected()) + else if (is_first_selected()) + { select_last_item(); + } else { --m_selected; @@ -1059,13 +1112,14 @@ void menu::handle_keys(uint32_t flags, int &iptkey) // down advances by one item if (exclusive_input_pressed(iptkey, IPT_UI_DOWN, 6)) { - if ((m_items[0].flags & FLAG_UI_DATS)) + if (flags & PROCESS_CUSTOM_NAV) { - top_line++; return; } - if (is_last_selected()) + else if (is_last_selected()) + { select_first_item(); + } else { ++m_selected; @@ -1079,6 +1133,8 @@ void menu::handle_keys(uint32_t flags, int &iptkey) // page up backs up by m_visible_items if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_UP, 6)) { + if (flags & PROCESS_CUSTOM_NAV) + return; m_selected -= m_visible_items; top_line -= m_visible_items - (last_item_visible() ? 1 : 0); if (m_selected < 0) @@ -1089,6 +1145,8 @@ void menu::handle_keys(uint32_t flags, int &iptkey) // page down advances by m_visible_items if (exclusive_input_pressed(iptkey, IPT_UI_PAGE_DOWN, 6)) { + if (flags & PROCESS_CUSTOM_NAV) + return; m_selected += m_visible_lines - 2 + is_first_selected(); top_line += m_visible_lines - 2; @@ -1099,11 +1157,19 @@ void menu::handle_keys(uint32_t flags, int &iptkey) // home goes to the start if (exclusive_input_pressed(iptkey, IPT_UI_HOME, 0)) + { + if (flags & PROCESS_CUSTOM_NAV) + return; select_first_item(); + } // end goes to the last if (exclusive_input_pressed(iptkey, IPT_UI_END, 0)) + { + if (flags & PROCESS_CUSTOM_NAV) + return; select_last_item(); + } // pause enables/disables pause if (!ignorepause && exclusive_input_pressed(iptkey, IPT_UI_PAUSE, 0)) diff --git a/src/frontend/mame/ui/menu.h b/src/frontend/mame/ui/menu.h index e0f5cbf9f0d..d8fcbcd25ea 100644 --- a/src/frontend/mame/ui/menu.h +++ b/src/frontend/mame/ui/menu.h @@ -45,7 +45,6 @@ public: FLAG_MULTILINE = 1U << 3, FLAG_REDTEXT = 1U << 4, FLAG_DISABLE = 1U << 5, - FLAG_UI_DATS = 1U << 6, FLAG_UI_HEADING = 1U << 7, FLAG_COLOR_BOX = 1U << 8 }; @@ -109,10 +108,11 @@ protected: PROCESS_NOKEYS = 1 << 0, PROCESS_LR_ALWAYS = 1 << 1, PROCESS_LR_REPEAT = 1 << 2, - PROCESS_CUSTOM_ONLY = 1 << 3, - PROCESS_ONLYCHAR = 1 << 4, - PROCESS_NOINPUT = 1 << 5, - PROCESS_NOIMAGE = 1 << 6 + PROCESS_CUSTOM_NAV = 1 << 3, + PROCESS_CUSTOM_ONLY = 1 << 4, + PROCESS_ONLYCHAR = 1 << 5, + PROCESS_NOINPUT = 1 << 6, + PROCESS_NOIMAGE = 1 << 7 }; // options for reset diff --git a/src/frontend/mame/ui/miscmenu.cpp b/src/frontend/mame/ui/miscmenu.cpp index 182094ddfa9..135963406ad 100644 --- a/src/frontend/mame/ui/miscmenu.cpp +++ b/src/frontend/mame/ui/miscmenu.cpp @@ -840,7 +840,7 @@ void menu_machine_configure::custom_render(void *selectedref, float top, float b draw_text_box( std::begin(text), std::end(text), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -963,7 +963,7 @@ void menu_plugins_configure::custom_render(void *selectedref, float top, float b draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } diff --git a/src/frontend/mame/ui/optsmenu.cpp b/src/frontend/mame/ui/optsmenu.cpp index 88486463ab9..998c8d17c23 100644 --- a/src/frontend/mame/ui/optsmenu.cpp +++ b/src/frontend/mame/ui/optsmenu.cpp @@ -149,7 +149,7 @@ void menu_simple_game_options::custom_render(void *selectedref, float top, float draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } diff --git a/src/frontend/mame/ui/selector.cpp b/src/frontend/mame/ui/selector.cpp index 4f7751713c3..bbc1bf357c5 100644 --- a/src/frontend/mame/ui/selector.cpp +++ b/src/frontend/mame/ui/selector.cpp @@ -119,7 +119,7 @@ void menu_selector::custom_render(void *selectedref, float top, float bottom, fl draw_text_box( std::begin(tempbuf), std::end(tempbuf), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); // get the text for 'UI Select' @@ -127,7 +127,7 @@ void menu_selector::custom_render(void *selectedref, float top, float bottom, fl draw_text_box( std::begin(tempbuf), std::end(tempbuf), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } diff --git a/src/frontend/mame/ui/selmenu.cpp b/src/frontend/mame/ui/selmenu.cpp index ba9facc7d25..11ddcf94ff0 100644 --- a/src/frontend/mame/ui/selmenu.cpp +++ b/src/frontend/mame/ui/selmenu.cpp @@ -321,7 +321,7 @@ void menu_select_launch::software_parts::custom_render(void *selectedref, float draw_text_box( std::begin(text), std::end(text), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -427,7 +427,7 @@ void menu_select_launch::bios_selection::custom_render(void *selectedref, float draw_text_box( std::begin(text), std::end(text), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -527,6 +527,7 @@ menu_select_launch::menu_select_launch(mame_ui_manager &mui, render_container &c , m_info_view(-1) , m_items_list() , m_info_buffer() + , m_info_layout() , m_cache(mui.get_session_data(machine())) , m_is_swlist(is_swlist) , m_focus(focused_menu::MAIN) @@ -653,7 +654,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto draw_text_box( tempbuf, tempbuf + 3, origx1, origx2, origy1 - top, y1, - ui::text_layout::CENTER, ui::text_layout::NEVER, true, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, true, ui().colors().text_color(), ui().colors().background_color(), 1.0f); // draw toolbar @@ -760,7 +761,7 @@ void menu_select_launch::custom_render(void *selectedref, float top, float botto draw_text_box( std::begin(tempbuf), std::end(tempbuf), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::NEVER, true, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, true, ui().colors().text_color(), color, 1.0f); // is favorite? draw the star @@ -948,7 +949,7 @@ void menu_select_launch::draw_info_arrow(int ub, float origx1, float origx2, flo bool menu_select_launch::draw_error_text() { if (m_ui_error) - ui().draw_text_box(container(), m_error_text, ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR); + ui().draw_text_box(container(), m_error_text, text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR); return m_ui_error; } @@ -1039,7 +1040,7 @@ float menu_select_launch::draw_left_panel( ui().draw_text_full( container(), str, x1t, y1, x2 - x1, - ui::text_layout::LEFT, ui::text_layout::NEVER, + text_layout::text_justify::LEFT, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); y1 += line_height_max; @@ -1276,7 +1277,7 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2) m_cache.cache_toolbar(machine(), x_size, y2 - y1); // add backtrack button - rgb_t color(0xefefefef); + rgb_t color(0xffcccccc); if (mouse_in_rect(backtrack_pos, y1, x2, y2)) { set_hover(HOVER_BACKTRACK); @@ -1285,7 +1286,7 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2) ui().draw_text_box( container(), have_parent ? _("Return to previous menu") : _("Exit"), - ui::text_layout::RIGHT, 1.0f - lr_border, ypos, + text_layout::text_justify::RIGHT, 1.0f - lr_border, ypos, ui().colors().background_color()); } container().add_quad( @@ -1299,7 +1300,7 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2) for (int z = 0; toolbar_count > z; ++z, x1 += x_spacing) { x2 = x1 + x_size; - color = rgb_t (0xefefefef); + color = rgb_t (0xffcccccc); if (mouse_in_rect(x1, y1, x2, y2)) { set_hover(HOVER_B_FAV + toolbar_bitmaps[z]); @@ -1308,7 +1309,7 @@ void menu_select_launch::draw_toolbar(float x1, float y1, float x2, float y2) ui().draw_text_box( container(), _(hover_msg[toolbar_bitmaps[z]]), - ui::text_layout::CENTER, (x1 + x2) * 0.5f, ypos, + text_layout::text_justify::CENTER, (x1 + x2) * 0.5f, ypos, ui().colors().background_color()); } container().add_quad( @@ -2064,7 +2065,7 @@ void menu_select_launch::draw(uint32_t flags) container(), itemtext, effective_left + icon_offset, line_y, effective_width - icon_offset, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, + text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); } @@ -2079,7 +2080,7 @@ void menu_select_launch::draw(uint32_t flags) container(), subitem_text, effective_left + icon_offset, line_y, ui().get_string_width(pitem.subtext), - ui::text_layout::RIGHT, ui::text_layout::NEVER, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::NEVER, mame_ui_manager::NONE, item_invert ? fgcolor3 : fgcolor, bgcolor, &subitem_width, nullptr); subitem_width += gutter_width; @@ -2091,7 +2092,7 @@ void menu_select_launch::draw(uint32_t flags) container(), itemtext, effective_left + icon_offset, line_y, effective_width - icon_offset - subitem_width, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, + text_layout::text_justify::LEFT, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, &item_width, nullptr); @@ -2100,7 +2101,7 @@ void menu_select_launch::draw(uint32_t flags) container(), subitem_text, effective_left + icon_offset + item_width, line_y, effective_width - icon_offset - item_width, - ui::text_layout::RIGHT, ui::text_layout::NEVER, + text_layout::text_justify::RIGHT, text_layout::word_wrapping::NEVER, mame_ui_manager::NORMAL, item_invert ? fgcolor3 : fgcolor, bgcolor, nullptr, nullptr); } @@ -2138,13 +2139,21 @@ void menu_select_launch::draw(uint32_t flags) if (pitem.type == menu_item_type::SEPARATOR) { - container().add_line(visible_left, line + 0.5f * line_height, visible_left + visible_width, line + 0.5f * line_height, - UI_LINE_WIDTH, ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); + container().add_line( + visible_left, line + 0.5f * line_height, + visible_left + visible_width, line + 0.5f * line_height, + UI_LINE_WIDTH, + ui().colors().text_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); } else { - ui().draw_text_full(container(), itemtext, effective_left, line, effective_width, ui::text_layout::CENTER, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr); + ui().draw_text_full( + container(), + itemtext, + effective_left, line, effective_width, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NORMAL, fgcolor, bgcolor, + nullptr, nullptr); } line += line_height; } @@ -2273,7 +2282,9 @@ float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, flo { fgcolor = rgb_t(0xff, 0xff, 0x00); bgcolor = rgb_t(0xff, 0xff, 0xff); - ui().draw_textured_box(container(), x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, + ui().draw_textured_box( + container(), + x1 + UI_LINE_WIDTH, y1 + UI_LINE_WIDTH, x1 + midl - UI_LINE_WIDTH, y1 + line_height, bgcolor, rgb_t(43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); } else if (bgcolor == ui().colors().mouseover_bg_color()) @@ -2282,8 +2293,12 @@ float menu_select_launch::draw_right_box_title(float x1, float y1, float x2, flo bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); } - ui().draw_text_full(container(), buffer[cells], x1 + UI_LINE_WIDTH, y1, midl - UI_LINE_WIDTH, - ui::text_layout::CENTER, ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); + ui().draw_text_full( + container(), + buffer[cells], + x1 + UI_LINE_WIDTH, y1, midl - UI_LINE_WIDTH, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, text_size); x1 += midl; } @@ -2386,7 +2401,7 @@ std::string menu_select_launch::arts_render_common(float origx1, float origy1, f float text_length; ui().draw_text_full(container(), _("selmenu-artwork", arts_info[x].first), origx1, origy1, origx2 - origx1, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), &text_length, nullptr); title_size = (std::max)(text_length + 0.01f, title_size); } @@ -2412,7 +2427,7 @@ std::string menu_select_launch::arts_render_common(float origx1, float origy1, f ui().draw_text_full(container(), snaptext, origx1, origy1 + ui().box_tb_border(), origx2 - origx1, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size); draw_common_arrow(origx1, origy1 + ui().box_tb_border(), origx2, origy2, m_image_view, FIRST_VIEW, LAST_VIEW, title_size); @@ -2682,8 +2697,6 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, { float const line_height = ui().get_line_height(); float text_size = ui().options().infos_size(); - std::vector xstart; - std::vector xend; const char *first = ""; ui_software_info const *software; ui_system_info const *system; @@ -2698,6 +2711,7 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, if ((m_info_software != software) || (m_info_view != ui_globals::cur_sw_dats_view)) { m_info_buffer.clear(); + m_info_layout = std::nullopt; if (software == m_info_software) { m_info_view = ui_globals::cur_sw_dats_view; @@ -2734,6 +2748,7 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, if (&driver != m_info_driver || ui_globals::curdats_view != m_info_view) { m_info_buffer.clear(); + m_info_layout = std::nullopt; if (&driver == m_info_driver) { m_info_view = ui_globals::curdats_view; @@ -2783,7 +2798,7 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, ui().draw_text_full( container(), name, origx1, origy1, origx2 - origx1, - ui::text_layout::CENTER, ui::text_layout::NEVER, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, mame_ui_manager::NONE, ui().colors().text_color(), ui().colors().text_bg_color(), &txt_length, nullptr); txt_length += 0.01f; @@ -2807,37 +2822,33 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, if (bgcolor != ui().colors().text_bg_color()) { - ui().draw_textured_box(container(), origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f), - origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); + ui().draw_textured_box( + container(), + origx1 + ((middle - title_size) * 0.5f), origy1, origx1 + ((middle + title_size) * 0.5f), + origy1 + line_height, bgcolor, rgb_t(255, 43, 43, 43), + hilight_main_texture(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(1)); } - ui().draw_text_full(container(), snaptext, origx1, origy1, origx2 - origx1, ui::text_layout::CENTER, - ui::text_layout::NEVER, mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size); + ui().draw_text_full( + container(), + snaptext, + origx1, origy1, origx2 - origx1, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, + mame_ui_manager::NORMAL, fgcolor, bgcolor, nullptr, nullptr, tmp_size); - char justify = 'l'; // left justify - if ((m_info_buffer.length() >= 3) && (m_info_buffer[0] == '#')) + sc = origx2 - origx1 - (2.0f * gutter_width); + if (!m_info_layout || (m_info_layout->width() != sc)) { - if (m_info_buffer[1] == 'j') - justify = m_info_buffer[2]; + m_info_layout.emplace( + ui().create_layout( + container(), + sc, + text_layout::text_justify::LEFT, text_layout::word_wrapping::WORD)); + menu_dats_view::add_info_text(*m_info_layout, m_info_buffer, ui().colors().text_color(), text_size); + m_total_lines = m_info_layout->lines(); } draw_common_arrow(origx1, origy1, origx2, origy2, m_info_view, 0, total - 1, title_size); - if (justify == 'f') - { - m_total_lines = ui().wrap_text( - container(), m_info_buffer, - 0.0f, 0.0f, 1.0f - (2.0f * gutter_width), - xstart, xend, - text_size); - } - else - { - m_total_lines = ui().wrap_text( - container(), m_info_buffer, - origx1, origy1, origx2 - origx1 - (2.0f * gutter_width), - xstart, xend, - text_size); - } int r_visible_lines = floor((origy2 - oy1) / (line_height * text_size)); if (m_total_lines < r_visible_lines) @@ -2847,82 +2858,23 @@ void menu_select_launch::infos_render(float origx1, float origy1, float origx2, if (m_topline_datsview + r_visible_lines >= m_total_lines) m_topline_datsview = m_total_lines - r_visible_lines; + // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow + m_right_visible_lines = r_visible_lines + - (m_topline_datsview ? 1 : 0) + - ((m_topline_datsview + r_visible_lines < m_total_lines) ? 1 : 0); + if (mouse_in_rect(origx1 + gutter_width, oy1, origx2 - gutter_width, origy2)) set_hover(HOVER_INFO_TEXT); - sc = origx2 - origx1 - (2.0f * gutter_width); - for (int r = 0; r < r_visible_lines; ++r) - { - int itemline = r + m_topline_datsview; - std::string_view const tempbuf(std::string_view(m_info_buffer).substr(xstart[itemline], xend[itemline] - xstart[itemline])); - if (!tempbuf.empty() && (tempbuf[0] == '#')) - continue; + if (m_topline_datsview) // up arrow + draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); + if (m_total_lines > (m_topline_datsview + r_visible_lines)) // bottom arrow + draw_info_arrow(1, origx1, origx2, oy1 + (float(r_visible_lines - 1) * line_height), line_height, text_size, ud_arrow_width); - if (r == 0 && m_topline_datsview != 0) // up arrow - { - draw_info_arrow(0, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); - } - else if (r == r_visible_lines - 1 && itemline != m_total_lines - 1) // bottom arrow - { - draw_info_arrow(1, origx1, origx2, oy1, line_height, text_size, ud_arrow_width); - } - else if (justify == '2') // two-column layout - { - // split at first tab - std::string_view::size_type const splitpos(tempbuf.find('\t')); - std::string_view const leftcol(tempbuf.substr(0, (std::string_view::npos == splitpos) ? 0U : splitpos)); - std::string_view const rightcol(tempbuf.substr((std::string_view::npos == splitpos) ? 0U : (splitpos + 1U))); - - // measure space needed, condense if necessary - float const leftlen(ui().get_string_width(leftcol, text_size)); - float const rightlen(ui().get_string_width(rightcol, text_size)); - float const textlen(leftlen + rightlen); - float const tmp_size3((textlen > sc) ? (text_size * (sc / textlen)) : text_size); - - // draw in two parts - ui().draw_text_full( - container(), leftcol, - origx1 + gutter_width, oy1, sc, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), - nullptr, nullptr, - tmp_size3); - ui().draw_text_full( - container(), rightcol, - origx1 + gutter_width, oy1, sc, - ui::text_layout::RIGHT, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), - nullptr, nullptr, - tmp_size3); - } - else if (justify == 'f' || justify == 'p') // full or partial justify - { - // check size - float const textlen = ui().get_string_width(tempbuf, text_size); - float tmp_size3 = (textlen > sc) ? text_size * (sc / textlen) : text_size; - ui().draw_text_full( - container(), tempbuf, - origx1 + gutter_width, oy1, origx2 - origx1, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), - nullptr, nullptr, - tmp_size3); - } - else - { - ui().draw_text_full( - container(), tempbuf, - origx1 + gutter_width, oy1, origx2 - origx1, - ui::text_layout::LEFT, ui::text_layout::TRUNCATE, - mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), - nullptr, nullptr, - text_size); - } - - oy1 += (line_height * text_size); - } - // return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow - m_right_visible_lines = r_visible_lines - (m_topline_datsview != 0) - (m_topline_datsview + r_visible_lines != m_total_lines); + m_info_layout->emit( + container(), + m_topline_datsview ? (m_topline_datsview + 1) : 0, m_right_visible_lines, + origx1 + gutter_width, oy1 + (m_topline_datsview ? line_height : 0.0f)); } @@ -2937,17 +2889,23 @@ void menu_select_launch::general_info(ui_system_info const *system, game_driver str << "#j2\n"; - util::stream_format(str, _("Romset\t%1$-.100s\n"), driver.name); + if (system) + str << system->description; + else + str << driver.type.fullname(); + str << "\t\n\n"; + + util::stream_format(str, _("Romset\t%1$s\n"), driver.name); util::stream_format(str, _("Year\t%1$s\n"), driver.year); - util::stream_format(str, _("Manufacturer\t%1$-.100s\n"), driver.manufacturer); + util::stream_format(str, _("Manufacturer\t%1$s\n"), driver.manufacturer); int cloneof = driver_list::non_bios_clone(driver); if (0 <= cloneof) { util::stream_format( str, - _("Driver is Clone of\t%1$-.100s\n"), - system ? system->parent : driver_list::driver(cloneof).type.fullname()); + _("Driver is Clone of\t%1$s\n"), + system ? std::string_view(system->parent) : std::string_view(driver_list::driver(cloneof).type.fullname())); } else { diff --git a/src/frontend/mame/ui/selmenu.h b/src/frontend/mame/ui/selmenu.h index 9a32b33b6db..12da4d2b1f9 100644 --- a/src/frontend/mame/ui/selmenu.h +++ b/src/frontend/mame/ui/selmenu.h @@ -20,6 +20,7 @@ #include #include +#include #include @@ -311,6 +312,7 @@ private: int m_info_view; std::vector m_items_list; std::string m_info_buffer; + std::optional m_info_layout; cache &m_cache; bool m_is_swlist; diff --git a/src/frontend/mame/ui/simpleselgame.cpp b/src/frontend/mame/ui/simpleselgame.cpp index 130434a74cf..9ad2fe62dc3 100644 --- a/src/frontend/mame/ui/simpleselgame.cpp +++ b/src/frontend/mame/ui/simpleselgame.cpp @@ -149,7 +149,7 @@ void simple_menu_select_game::handle() container(), _("The selected game is missing one or more required ROM or CHD images. " "Please select a different game.\n\nPress any key to continue."), - ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR); + text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR); } } @@ -314,7 +314,7 @@ void simple_menu_select_game::custom_render(void *selectedref, float top, float draw_text_box( tempbuf, tempbuf + 1, origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); // determine the text to render below @@ -396,7 +396,7 @@ void simple_menu_select_game::custom_render(void *selectedref, float top, float draw_text_box( tempbuf, tempbuf + 4, origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, true, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, true, ui().colors().text_color(), driver ? m_cached_color : ui().colors().background_color(), 1.0f); } diff --git a/src/frontend/mame/ui/sliders.cpp b/src/frontend/mame/ui/sliders.cpp index 4dba8969a90..99b3756bfec 100644 --- a/src/frontend/mame/ui/sliders.cpp +++ b/src/frontend/mame/ui/sliders.cpp @@ -9,14 +9,16 @@ *********************************************************************/ #include "emu.h" +#include "ui/sliders.h" + +#include "ui/slider.h" +#include "ui/ui.h" #include "osdepend.h" -#include "ui/ui.h" -#include "ui/sliders.h" -#include "ui/slider.h" namespace ui { + menu_sliders::menu_sliders(mame_ui_manager &mui, render_container &container, bool menuless_mode) : menu(mui, container) { m_menuless_mode = m_hidden = menuless_mode; @@ -244,8 +246,12 @@ void menu_sliders::custom_render(void *selectedref, float top, float bottom, flo y1 += ui().box_tb_border(); // determine the text height - ui().draw_text_full(container(), tempstring, 0, 0, x2 - x1 - 2.0f * lr_border, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), nullptr, &text_height); + ui().draw_text_full( + container(), + tempstring, + 0, 0, x2 - x1 - 2.0f * lr_border, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, + mame_ui_manager::NONE, rgb_t::white(), rgb_t::black(), nullptr, &text_height); // draw the thermometer bar_left = x1 + lr_border; @@ -271,8 +277,12 @@ void menu_sliders::custom_render(void *selectedref, float top, float bottom, flo container().add_line(default_x, bar_bottom, default_x, bar_area_top + bar_area_height, UI_LINE_WIDTH, ui().colors().border_color(), PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); // draw the actual text - ui().draw_text_full(container(), tempstring, x1 + lr_border, y1 + line_height, x2 - x1 - 2.0f * lr_border, - ui::text_layout::CENTER, ui::text_layout::WORD, mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), nullptr, &text_height); + ui().draw_text_full( + container(), + tempstring, + x1 + lr_border, y1 + line_height, x2 - x1 - 2.0f * lr_border, + text_layout::text_justify::CENTER, text_layout::word_wrapping::WORD, + mame_ui_manager::NORMAL, ui().colors().text_color(), ui().colors().text_bg_color(), nullptr, &text_height); } } diff --git a/src/frontend/mame/ui/slotopt.cpp b/src/frontend/mame/ui/slotopt.cpp index c6da9c7589f..b21a039f86a 100644 --- a/src/frontend/mame/ui/slotopt.cpp +++ b/src/frontend/mame/ui/slotopt.cpp @@ -221,7 +221,7 @@ void menu_slot_devices::custom_render(void *selectedref, float top, float bottom draw_text_box( std::begin(text), std::end(text), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } } diff --git a/src/frontend/mame/ui/sndmenu.cpp b/src/frontend/mame/ui/sndmenu.cpp index 52948c8bca2..8eff1ed1b92 100644 --- a/src/frontend/mame/ui/sndmenu.cpp +++ b/src/frontend/mame/ui/sndmenu.cpp @@ -164,7 +164,7 @@ void menu_sound_options::custom_render(void *selectedref, float top, float botto draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } diff --git a/src/frontend/mame/ui/state.cpp b/src/frontend/mame/ui/state.cpp index 98655ffa23e..af56b28e298 100644 --- a/src/frontend/mame/ui/state.cpp +++ b/src/frontend/mame/ui/state.cpp @@ -431,13 +431,13 @@ void menu_load_save_state_base::custom_render(void *selectedref, float top, floa draw_text_box( std::begin(text), std::next(std::begin(text), count), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + (count * ui().get_line_height()) + (3.0f * ui().box_tb_border()), - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } // draw the confirmation prompt if necessary if (!m_confirm_prompt.empty()) - ui().draw_text_box(container(), m_confirm_prompt, ui::text_layout::CENTER, 0.5f, 0.5f, ui().colors().background_color()); + ui().draw_text_box(container(), m_confirm_prompt, text_layout::text_justify::CENTER, 0.5f, 0.5f, ui().colors().background_color()); } diff --git a/src/frontend/mame/ui/submenu.cpp b/src/frontend/mame/ui/submenu.cpp index 382524b636c..e4bd44763d4 100644 --- a/src/frontend/mame/ui/submenu.cpp +++ b/src/frontend/mame/ui/submenu.cpp @@ -443,7 +443,7 @@ void submenu::custom_render(void *selectedref, float top, float bottom, float or draw_text_box( std::begin(toptext), std::end(toptext), origx1, origx2, origy1 - top, origy1 - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); if (selectedref) @@ -455,7 +455,7 @@ void submenu::custom_render(void *selectedref, float top, float bottom, float or draw_text_box( std::begin(bottomtext), std::end(bottomtext), origx1, origx2, origy2 + ui().box_tb_border(), origy2 + bottom, - ui::text_layout::CENTER, ui::text_layout::TRUNCATE, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::TRUNCATE, false, ui().colors().text_color(), ui().colors().background_color(), 1.0f); } } diff --git a/src/frontend/mame/ui/text.cpp b/src/frontend/mame/ui/text.cpp index 981e69b5380..f91f12517a0 100644 --- a/src/frontend/mame/ui/text.cpp +++ b/src/frontend/mame/ui/text.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +// copyright-holders:Nathan Woods, Vas Crabb /********************************************************************* text.cpp @@ -10,12 +10,15 @@ #include "emu.h" #include "text.h" -#include "rendfont.h" + #include "render.h" -#include "unicode.h" +#include "rendfont.h" + +#include "util/unicode.h" #include #include +#include namespace ui { @@ -75,6 +78,191 @@ inline bool is_breakable_char(char32_t ch) +/*************************************************************************** +CLASS TO REPRESENT A LINE +***************************************************************************/ + +// information about the "source" of a character - also in a struct +// to facilitate copying +struct text_layout::source_info +{ + size_t start; + size_t span; +}; + + +// this should really be "positioned glyph" as glyphs != characters, but +// we'll get there eventually +struct text_layout::positioned_char +{ + char32_t character; + char_style style; + source_info source; + float xoffset; + float xwidth; +}; + + +class text_layout::line +{ +public: + using size_type = size_t; + static constexpr size_type npos = ~size_type(0); + + line(float yoffset, float height) : m_yoffset(yoffset), m_height(height) + { + } + + // methods + void add_character(text_layout &layout, char32_t ch, char_style const &style, source_info const &source) + { + // get the width of this character + float const chwidth = layout.get_char_width(ch, style.size); + + // append the positioned character + m_characters.emplace_back(positioned_char{ ch, style, source, m_width, chwidth }); + m_width += chwidth; + + // we might be bigger + m_height = std::max(m_height, style.size * layout.yscale()); + } + + void truncate(size_t position) + { + assert(position <= m_characters.size()); + + // are we actually truncating? + if (position < m_characters.size()) + { + // set the width as appropriate + m_width = m_characters[position].xoffset; + + // and resize the array + m_characters.resize(position); + } + } + + void set_justification(text_justify justify) + { + switch (justify) + { + case text_justify::RIGHT: + if (npos == m_right_justify_start) + m_right_justify_start = m_characters.size(); + [[fallthrough]]; + case text_justify::CENTER: + if (npos == m_center_justify_start) + m_center_justify_start = m_characters.size(); + break; + case text_justify::LEFT: + break; + } + } + + void align_text(text_layout const &layout) + { + assert(m_right_justify_start >= m_center_justify_start); + + if (m_characters.empty() || m_center_justify_start) + { + // at least some of the text is left-justified - anchor to left + m_anchor_pos = 0.0f; + m_anchor_target = 0.0f; + if ((layout.width() > m_width) && (m_characters.size() > m_center_justify_start)) + { + // at least some text is not left-justified + if (m_right_justify_start == m_center_justify_start) + { + // all text that isn't left-justified is right-justified + float const right_offset = layout.width() - m_width; + for (size_t i = m_right_justify_start; m_characters.size() > i; ++i) + m_characters[i].xoffset += right_offset; + m_width = layout.width(); + } + else if (m_characters.size() <= m_right_justify_start) + { + // all text that isn't left-justified is center-justified + float const center_width = m_width - m_characters[m_center_justify_start].xoffset; + float const center_offset = ((layout.width() - center_width) * 0.5f) - m_characters[m_center_justify_start].xoffset; + if (0.0f < center_offset) + { + for (size_t i = m_center_justify_start; m_characters.size() > i; ++i) + m_characters[i].xoffset += center_offset; + m_width += center_offset; + } + } + else + { + // left, right and center-justified parts + float const center_width = m_characters[m_right_justify_start].xoffset - m_characters[m_center_justify_start].xoffset; + float const center_offset = ((layout.width() - center_width) * 0.5f) - m_characters[m_center_justify_start].xoffset; + float const right_offset = layout.width() - m_width; + if (center_offset > right_offset) + { + // right-justified text pushes centre-justified text to the left + for (size_t i = m_center_justify_start; m_right_justify_start > i; ++i) + m_characters[i].xoffset += right_offset; + } + else if (0.0f < center_offset) + { + // left-justified text doesn't push centre-justified text to the right + for (size_t i = m_center_justify_start; m_right_justify_start > i; ++i) + m_characters[i].xoffset += center_offset; + } + for (size_t i = m_right_justify_start; m_characters.size() > i; ++i) + m_characters[i].xoffset += right_offset; + m_width = layout.width(); + } + } + } + else if (m_characters.size() <= m_right_justify_start) + { + // all text is center-justified - anchor to center + m_anchor_pos = 0.5f; + m_anchor_target = 0.5f; + } + else + { + // at least some text is right-justified - anchor to right + m_anchor_pos = 1.0f; + m_anchor_target = 1.0f; + if ((layout.width() > m_width) && (m_right_justify_start > m_center_justify_start)) + { + // mixed center-justified and right-justified text + float const center_width = m_characters[m_right_justify_start].xoffset; + float const center_offset = (layout.width() - m_width + (center_width * 0.5f)) - (layout.width() * 0.5f); + if (0.0f < center_offset) + { + for (size_t i = m_right_justify_start; m_characters.size() > i; ++i) + m_characters[i].xoffset += center_offset; + m_width += center_offset; + } + } + } + } + + // accessors + float xoffset(text_layout const &layout) const { return (layout.width() * m_anchor_target) - (m_width * m_anchor_pos); } + float yoffset() const { return m_yoffset; } + float width() const { return m_width; } + float height() const { return m_height; } + size_t character_count() const { return m_characters.size(); } + const positioned_char &character(size_t index) const { return m_characters[index]; } + positioned_char &character(size_t index) { return m_characters[index]; } + +private: + std::vector m_characters; + size_type m_center_justify_start = npos; + size_type m_right_justify_start = npos; + float m_yoffset; + float m_height; + float m_width = 0.0f; + float m_anchor_pos = 0.0f; + float m_anchor_target = 0.0f; +}; + + + /*************************************************************************** CORE IMPLEMENTATION ***************************************************************************/ @@ -122,7 +310,7 @@ text_layout::~text_layout() // add_text //------------------------------------------------- -void text_layout::add_text(std::string_view text, const char_style &style) +void text_layout::add_text(std::string_view text, text_justify line_justify, char_style const &style) { while (!text.empty()) { @@ -130,25 +318,9 @@ void text_layout::add_text(std::string_view text, const char_style &style) invalidate_calculated_actual_width(); // do we need to create a new line? - if (m_current_line == nullptr) - { - // get the current character - char32_t schar; - int const scharcount = uchar_from_utf8(&schar, text); - if (scharcount < 0) - break; - - // if the line starts with a tab character, center it regardless - text_justify line_justify = justify(); - if (schar == '\t') - { - text.remove_prefix(scharcount); - line_justify = text_layout::CENTER; - } - - // start a new line - start_new_line(line_justify, style.size); - } + if (!m_current_line) + start_new_line(style.size); + m_current_line->set_justification(line_justify); // get the current character char32_t ch; @@ -166,45 +338,43 @@ void text_layout::add_text(std::string_view text, const char_style &style) // is this an endline? if (ch == '\n') { - // first, start a line if we have not already - if (m_current_line == nullptr) - start_new_line(LEFT, style.size); - - // and then close up the current line + // close up the current line + m_current_line->align_text(*this); m_current_line = nullptr; } else if (!m_truncating) { // if we hit a space, remember the location and width *without* the space - if (is_space_character(ch)) + bool const is_space = is_space_character(ch); + if (is_space) m_last_break = m_current_line->character_count(); // append the character - m_current_line->add_character(ch, style, source); + m_current_line->add_character(*this, ch, style, source); // do we have to wrap? - if (wrap() != NEVER && m_current_line->width() > m_width) + if ((wrap() != word_wrapping::NEVER) && (m_current_line->width() > m_width)) { switch (wrap()) { - case TRUNCATE: - truncate_wrap(); - break; + case word_wrapping::TRUNCATE: + truncate_wrap(); + break; - case WORD: - word_wrap(); - break; + case word_wrapping::WORD: + word_wrap(line_justify); + break; - default: - fatalerror("invalid word wrapping value"); - break; + case word_wrapping::NEVER: + // can't happen due to if condition, but compile warns about it + break; } } else { - // we didn't wrap - if we hit any non-space breakable character, remember the location and width - // *with* the breakable character - if (ch != ' ' && is_breakable_char(ch)) + // we didn't wrap - if we hit any non-space breakable character, + // remember the location and width *with* the breakable character + if (!is_space && is_breakable_char(ch)) m_last_break = m_current_line->character_count(); } } @@ -226,25 +396,26 @@ void text_layout::invalidate_calculated_actual_width() // actual_left //------------------------------------------------- -float text_layout::actual_left() const +float text_layout::actual_left() { + if (m_current_line) + { + // TODO: is there a sane way to allow an open line to be temporarily finalised and rolled back? + m_current_line->align_text(*this); + m_current_line = nullptr; + } + float result; if (empty()) { // degenerate scenario - result = 0; + result = 0.0f; } else { result = 1.0f; for (const auto &line : m_lines) - { - result = std::min(result, line->xoffset()); - - // take an opportunity to break out easily - if (result <= 0) - break; - } + result = std::min(result, line->xoffset(*this)); } return result; } @@ -254,8 +425,15 @@ float text_layout::actual_left() const // actual_width //------------------------------------------------- -float text_layout::actual_width() const +float text_layout::actual_width() { + if (m_current_line) + { + // TODO: is there a sane way to allow an open line to be temporarily finalised and rolled back? + m_current_line->align_text(*this); + m_current_line = nullptr; + } + // do we need to calculate the width? if (m_calculated_actual_width < 0) { @@ -275,14 +453,12 @@ float text_layout::actual_width() const // actual_height //------------------------------------------------- -float text_layout::actual_height() const +float text_layout::actual_height() { - line *last_line = (m_lines.size() > 0) - ? m_lines[m_lines.size() - 1].get() - : nullptr; - return last_line - ? last_line->yoffset() + last_line->height() - : 0; + if (!m_lines.empty()) + return m_lines.back()->yoffset() + m_lines.back()->height(); + else + return 0.0f; } @@ -290,18 +466,12 @@ float text_layout::actual_height() const // start_new_line //------------------------------------------------- -void text_layout::start_new_line(text_layout::text_justify justify, float height) +void text_layout::start_new_line(float height) { - // create a new line - std::unique_ptr new_line(std::make_unique(*this, justify, actual_height(), height * yscale())); - // update the current line - m_current_line = new_line.get(); + m_current_line = m_lines.emplace_back(std::make_unique(actual_height(), height * yscale())).get(); m_last_break = 0; m_truncating = false; - - // append it - m_lines.emplace_back(std::move(new_line)); } @@ -335,7 +505,7 @@ void text_layout::truncate_wrap() source.start = truncate_char.source.start + truncate_char.source.span; source.span = 0; - // figure out how wide an elipsis is + // figure out how wide an ellipsis is float elipsis_width = get_char_width(elipsis, style.size); // where should we really truncate from? @@ -345,10 +515,10 @@ void text_layout::truncate_wrap() // truncate!!! m_current_line->truncate(truncate_position); - // and append the elipsis - m_current_line->add_character(elipsis, style, source); + // and append the ellipsis + m_current_line->add_character(*this, elipsis, style, source); - // take note that we are truncating; supress new characters + // take note that we are truncating; suppress new characters m_truncating = true; } @@ -357,29 +527,31 @@ void text_layout::truncate_wrap() // word_wrap //------------------------------------------------- -void text_layout::word_wrap() +void text_layout::word_wrap(text_justify line_justify) { // keep track of the last line and break - line *last_line = m_current_line; - size_t last_break = m_last_break; + line *const last_line = m_current_line; + size_t const last_break = m_last_break ? m_last_break : (last_line->character_count() - 1); // start a new line with the same justification - start_new_line(last_line->justify(), last_line->character(last_line->character_count() - 1).style.size); + start_new_line(last_line->character(last_line->character_count() - 1).style.size); + m_current_line->set_justification(line_justify); - // find the begining of the word to wrap + // find the beginning of the word to wrap size_t position = last_break; - while (position + 1 < last_line->character_count() && is_space_character(last_line->character(position).character)) + while ((position + 1) < last_line->character_count() && is_space_character(last_line->character(position).character)) position++; // transcribe the characters for (size_t i = position; i < last_line->character_count(); i++) { auto &ch = last_line->character(i); - m_current_line->add_character(ch.character, ch.style, ch.source); + m_current_line->add_character(*this, ch.character, ch.style, ch.source); } - // and finally, truncate the last line + // and finally, truncate the previous line and adjust spacing last_line->truncate(last_break); + last_line->align_text(*this); } @@ -387,13 +559,20 @@ void text_layout::word_wrap() // hit_test //------------------------------------------------- -bool text_layout::hit_test(float x, float y, size_t &start, size_t &span) const +bool text_layout::hit_test(float x, float y, size_t &start, size_t &span) { + if (m_current_line) + { + // TODO: is there a sane way to allow an open line to be temporarily finalised and rolled back? + m_current_line->align_text(*this); + m_current_line = nullptr; + } + for (const auto &line : m_lines) { if (y >= line->yoffset() && y < line->yoffset() + line->height()) { - float line_xoffset = line->xoffset(); + float line_xoffset = line->xoffset(*this); if (x >= line_xoffset && x < line_xoffset + line->width()) { for (size_t i = 0; i < line->character_count(); i++) @@ -438,57 +617,40 @@ void text_layout::restyle(size_t start, size_t span, rgb_t *fgcolor, rgb_t *bgco } -//------------------------------------------------- -// get_wrap_info -//------------------------------------------------- - -int text_layout::get_wrap_info(std::vector &xstart, std::vector &xend) const -{ - // this is a hacky method (tailored to the need to implement - // mame_ui_manager::wrap_text) but so be it - int line_count = 0; - for (const auto &line : m_lines) - { - int start_pos = 0; - int end_pos = 0; - - auto line_character_count = line->character_count(); - if (line_character_count > 0) - { - start_pos = line->character(0).source.start; - end_pos = line->character(line_character_count - 1).source.start - + line->character(line_character_count - 1).source.span; - } - - line_count++; - xstart.push_back(start_pos); - xend.push_back(end_pos); - } - return line_count; -} - - //------------------------------------------------- // emit //------------------------------------------------- void text_layout::emit(render_container &container, float x, float y) { - for (const auto &line : m_lines) + emit(container, 0, m_lines.size(), x, y); +} + +void text_layout::emit(render_container &container, size_t start, size_t lines, float x, float y) +{ + if (m_current_line) { - float line_xoffset = line->xoffset(); + // TODO: is there a sane way to allow an open line to be temporarily finalised and rolled back? + m_current_line->align_text(*this); + m_current_line = nullptr; + } + + float const base_y = (m_lines.size() > start) ? m_lines[start]->yoffset() : 0.0f; + for (size_t l = start; ((start + lines) > l) && (m_lines.size() > l); ++l) + { + auto const &line = m_lines[l]; + float const line_xoffset = line->xoffset(*this); + float const char_y = y + line->yoffset() - base_y; + float const char_height = line->height(); // emit every single character for (auto i = 0; i < line->character_count(); i++) { auto &ch = line->character(i); - // position this specific character correctly (TODO - this doesn't - // handle differently sized text (yet) - float char_x = x + line_xoffset + ch.xoffset; - float char_y = y + line->yoffset(); - float char_width = ch.xwidth; - float char_height = line->height(); + // position this specific character correctly (TODO - this doesn't handle differently sized text (yet) + float const char_x = x + line_xoffset + ch.xoffset; + float const char_width = ch.xwidth; // render the background of the character (if present) if (ch.style.bgcolor.a() != 0) @@ -496,95 +658,15 @@ void text_layout::emit(render_container &container, float x, float y) // render the foreground container.add_char( - char_x, - char_y, - char_height, - xscale() / yscale(), - ch.style.fgcolor, - font(), - ch.character); + char_x, + char_y, + char_height, + xscale() / yscale(), + ch.style.fgcolor, + font(), + ch.character); } } } - -//------------------------------------------------- -// line::ctor -//------------------------------------------------- - -text_layout::line::line(text_layout &layout, text_justify justify, float yoffset, float height) - : m_layout(layout), m_justify(justify), m_yoffset(yoffset), m_width(0.0), m_height(height) -{ -} - - -//------------------------------------------------- -// line::add_character -//------------------------------------------------- - -void text_layout::line::add_character(char32_t ch, const char_style &style, const source_info &source) -{ - // get the width of this character - float chwidth = m_layout.get_char_width(ch, style.size); - - // create the positioned character - positioned_char positioned_char = { 0, }; - positioned_char.character = ch; - positioned_char.xoffset = m_width; - positioned_char.xwidth = chwidth; - positioned_char.style = style; - positioned_char.source = source; - - // append the character - m_characters.push_back(positioned_char); - m_width += chwidth; - - // we might be bigger - m_height = std::max(m_height, style.size * m_layout.yscale()); -} - - -//------------------------------------------------- -// line::xoffset -//------------------------------------------------- - -float text_layout::line::xoffset() const -{ - float result; - switch (justify()) - { - case LEFT: - default: - result = 0; - break; - case CENTER: - result = (m_layout.width() - width()) / 2; - break; - case RIGHT: - result = m_layout.width() - width(); - break; - } - return result; -} - - -//------------------------------------------------- -// line::truncate -//------------------------------------------------- - -void text_layout::line::truncate(size_t position) -{ - assert(position <= m_characters.size()); - - // are we actually truncating? - if (position < m_characters.size()) - { - // set the width as appropriate - m_width = m_characters[position].xoffset; - - // and resize the array - m_characters.resize(position); - } -} - } // namespace ui diff --git a/src/frontend/mame/ui/text.h b/src/frontend/mame/ui/text.h index 78f4905bbf4..e0d52b8a211 100644 --- a/src/frontend/mame/ui/text.h +++ b/src/frontend/mame/ui/text.h @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods +// copyright-holders:Nathan Woods, Vas Crabb /*************************************************************************** text.h @@ -12,11 +12,15 @@ #pragma once +#include #include +#include + class render_font; class render_container; + namespace ui { /*************************************************************************** @@ -27,7 +31,7 @@ class text_layout { public: // justification options for text - enum text_justify + enum class text_justify { LEFT = 0, CENTER, @@ -35,7 +39,7 @@ public: }; // word wrapping options - enum word_wrapping + enum class word_wrapping { NEVER, TRUNCATE, @@ -56,24 +60,22 @@ public: word_wrapping wrap() const { return m_wrap; } // methods - float actual_left() const; - float actual_width() const; - float actual_height() const; - bool empty() const { return m_lines.size() == 0; } - bool hit_test(float x, float y, size_t &start, size_t &span) const; + float actual_left(); + float actual_width(); + float actual_height(); + bool empty() const { return m_lines.empty(); } + size_t lines() const { return m_lines.size(); } + bool hit_test(float x, float y, size_t &start, size_t &span); void restyle(size_t start, size_t span, rgb_t *fgcolor, rgb_t *bgcolor); - int get_wrap_info(std::vector &xstart, std::vector &xend) const; void emit(render_container &container, float x, float y); + void emit(render_container &container, size_t start, size_t lines, float x, float y); void add_text(std::string_view text, rgb_t fgcolor = rgb_t::white(), rgb_t bgcolor = rgb_t::transparent(), float size = 1.0) { - // create the style - char_style style = { 0, }; - style.fgcolor = fgcolor; - style.bgcolor = bgcolor; - style.size = size; - - // and add the text - add_text(text, style); + add_text(text, justify(), char_style{ fgcolor, bgcolor, size }); + } + void add_text(std::string_view text, text_justify line_justify, rgb_t fgcolor = rgb_t::white(), rgb_t bgcolor = rgb_t::transparent(), float size = 1.0) + { + add_text(text, line_justify, char_style{ fgcolor, bgcolor, size }); } private: @@ -85,53 +87,10 @@ private: float size; }; - // information about the "source" of a character - also in a struct - // to facilitate copying - struct source_info - { - size_t start; - size_t span; - }; - - // this should really be "positioned glyph" as glyphs != characters, but - // we'll get there eventually - struct positioned_char - { - char32_t character; - char_style style; - source_info source; - float xoffset; - float xwidth; - }; - // class to represent a line - class line - { - public: - line(text_layout &layout, text_justify justify, float yoffset, float height); - - // methods - void add_character(char32_t ch, const char_style &style, const source_info &source); - void truncate(size_t position); - - // accessors - float xoffset() const; - float yoffset() const { return m_yoffset; } - float width() const { return m_width; } - float height() const { return m_height; } - text_justify justify() const { return m_justify; } - size_t character_count() const { return m_characters.size(); } - const positioned_char &character(size_t index) const { return m_characters[index]; } - positioned_char &character(size_t index) { return m_characters[index]; } - - private: - std::vector m_characters; - text_layout &m_layout; - text_justify m_justify; - float m_yoffset; - float m_width; - float m_height; - }; + struct source_info; + struct positioned_char; + class line; // instance variables render_font &m_font; @@ -141,21 +100,21 @@ private: mutable float m_calculated_actual_width; text_justify m_justify; word_wrapping m_wrap; - std::vector> m_lines; + std::vector > m_lines; line *m_current_line; size_t m_last_break; size_t m_text_position; bool m_truncating; // methods - void add_text(std::string_view text, const char_style &style); - void start_new_line(text_justify justify, float height); + void add_text(std::string_view text, text_justify line_justify, char_style const &style); + void start_new_line(float height); float get_char_width(char32_t ch, float size); void truncate_wrap(); - void word_wrap(); + void word_wrap(text_justify line_justify); void invalidate_calculated_actual_width(); }; } // namespace ui -#endif // MAME_FRONTEND_UI_TEXT_H +#endif // MAME_FRONTEND_UI_TEXT_H diff --git a/src/frontend/mame/ui/ui.cpp b/src/frontend/mame/ui/ui.cpp index c2f50d8c33a..fb3c437fb74 100644 --- a/src/frontend/mame/ui/ui.cpp +++ b/src/frontend/mame/ui/ui.cpp @@ -212,7 +212,7 @@ void mame_ui_manager::init() ui_callback_type::GENERAL, [this] (render_container &container) -> uint32_t { - draw_text_box(container, messagebox_text, ui::text_layout::LEFT, 0.5f, 0.5f, colors().background_color()); + draw_text_box(container, messagebox_text, ui::text_layout::text_justify::LEFT, 0.5f, 0.5f, colors().background_color()); return 0; }); m_non_char_keys_down = std::make_unique((std::size(non_char_keys) + 7) / 8); @@ -436,7 +436,7 @@ void mame_ui_manager::display_startup_screens(bool first_time) [this, &poller, &warning_text, &warning_color, &config_menu] (render_container &container) -> uint32_t { // draw a standard message window - draw_text_box(container, warning_text, ui::text_layout::LEFT, 0.5f, 0.5f, warning_color); + draw_text_box(container, warning_text, ui::text_layout::text_justify::LEFT, 0.5f, 0.5f, warning_color); if (machine().ui_input().pressed(IPT_UI_CANCEL)) { @@ -673,7 +673,7 @@ void mame_ui_manager::update_and_render(render_container &container) // display any popup messages if (osd_ticks() < m_popup_text_end) - draw_text_box(container, messagebox_poptext, ui::text_layout::CENTER, 0.5f, 0.9f, colors().background_color()); + draw_text_box(container, messagebox_poptext, ui::text_layout::text_justify::CENTER, 0.5f, 0.9f, colors().background_color()); else m_popup_text_end = 0; @@ -818,7 +818,12 @@ void mame_ui_manager::draw_outlined_box(render_container &container, float x0, f void mame_ui_manager::draw_text(render_container &container, std::string_view buf, float x, float y) { - draw_text_full(container, buf, x, y, 1.0f - x, ui::text_layout::LEFT, ui::text_layout::WORD, mame_ui_manager::NORMAL, colors().text_color(), colors().text_bg_color(), nullptr, nullptr); + draw_text_full( + container, + buf, + x, y, 1.0f - x, + ui::text_layout::text_justify::LEFT, ui::text_layout::word_wrapping::WORD, + mame_ui_manager::NORMAL, colors().text_color(), colors().text_bg_color(), nullptr, nullptr); } @@ -884,8 +889,8 @@ void mame_ui_manager::draw_text_box(render_container &container, ui::text_layout auto actual_left = layout.actual_left(); auto actual_width = layout.actual_width(); auto actual_height = layout.actual_height(); - auto x = std::min(std::max(xpos - actual_width / 2, box_lr_border()), 1.0f - actual_width - box_lr_border()); - auto y = std::min(std::max(ypos - actual_height / 2, box_tb_border()), 1.0f - actual_height - box_tb_border()); + auto x = std::clamp(xpos - actual_width / 2, box_lr_border(), 1.0f - actual_width - box_lr_border()); + auto y = std::clamp(ypos - actual_height / 2, box_tb_border(), 1.0f - actual_height - box_tb_border()); // add a box around that draw_outlined_box(container, @@ -1120,8 +1125,12 @@ bool mame_ui_manager::can_paste() void mame_ui_manager::draw_fps_counter(render_container &container) { - draw_text_full(container, machine().video().speed_text(), 0.0f, 0.0f, 1.0f, - ui::text_layout::RIGHT, ui::text_layout::WORD, OPAQUE_, rgb_t::white(), rgb_t::black(), nullptr, nullptr); + draw_text_full( + container, + machine().video().speed_text(), + 0.0f, 0.0f, 1.0f, + ui::text_layout::text_justify::RIGHT, ui::text_layout::word_wrapping::WORD, + OPAQUE_, rgb_t::white(), rgb_t::black(), nullptr, nullptr); } @@ -1132,8 +1141,12 @@ void mame_ui_manager::draw_fps_counter(render_container &container) void mame_ui_manager::draw_timecode_counter(render_container &container) { std::string tempstring; - draw_text_full(container, machine().video().timecode_text(tempstring), 0.0f, 0.0f, 1.0f, - ui::text_layout::RIGHT, ui::text_layout::WORD, OPAQUE_, rgb_t(0xf0, 0xf0, 0x10, 0x10), rgb_t::black(), nullptr, nullptr); + draw_text_full( + container, + machine().video().timecode_text(tempstring), + 0.0f, 0.0f, 1.0f, + ui::text_layout::text_justify::RIGHT, ui::text_layout::word_wrapping::WORD, + OPAQUE_, rgb_t(0xf0, 0xf0, 0x10, 0x10), rgb_t::black(), nullptr, nullptr); } @@ -1144,8 +1157,12 @@ void mame_ui_manager::draw_timecode_counter(render_container &container) void mame_ui_manager::draw_timecode_total(render_container &container) { std::string tempstring; - draw_text_full(container, machine().video().timecode_total_text(tempstring), 0.0f, 0.0f, 1.0f, - ui::text_layout::LEFT, ui::text_layout::WORD, OPAQUE_, rgb_t(0xf0, 0x10, 0xf0, 0x10), rgb_t::black(), nullptr, nullptr); + draw_text_full( + container, + machine().video().timecode_total_text(tempstring), + 0.0f, 0.0f, 1.0f, + ui::text_layout::text_justify::LEFT, ui::text_layout::word_wrapping::WORD, + OPAQUE_, rgb_t(0xf0, 0x10, 0xf0, 0x10), rgb_t::black(), nullptr, nullptr); } @@ -1156,7 +1173,12 @@ void mame_ui_manager::draw_timecode_total(render_container &container) void mame_ui_manager::draw_profiler(render_container &container) { std::string_view text = g_profiler.text(machine()); - draw_text_full(container, text, 0.0f, 0.0f, 1.0f, ui::text_layout::LEFT, ui::text_layout::WORD, OPAQUE_, rgb_t::white(), rgb_t::black(), nullptr, nullptr); + draw_text_full( + container, + text, + 0.0f, 0.0f, 1.0f, + ui::text_layout::text_justify::LEFT, ui::text_layout::word_wrapping::WORD, + OPAQUE_, rgb_t::white(), rgb_t::black(), nullptr, nullptr); } @@ -1467,7 +1489,7 @@ uint32_t mame_ui_manager::handler_confirm_quit(render_container &container) ui_select_text, ui_cancel_text); - draw_text_box(container, quit_message, ui::text_layout::CENTER, 0.5f, 0.5f, UI_RED_COLOR); + draw_text_box(container, quit_message, ui::text_layout::text_justify::CENTER, 0.5f, 0.5f, UI_RED_COLOR); machine().pause(); // if the user press ENTER, quit the game @@ -2100,26 +2122,6 @@ ui::text_layout mame_ui_manager::create_layout(render_container &container, floa } -//------------------------------------------------- -// wrap_text -//------------------------------------------------- - -int mame_ui_manager::wrap_text(render_container &container, std::string_view origs, float x, float y, float origwrapwidth, std::vector &xstart, std::vector &xend, float text_size) -{ - // create the layout - auto layout = create_layout(container, origwrapwidth, ui::text_layout::LEFT, ui::text_layout::WORD); - - // add the text - layout.add_text( - origs, - rgb_t::black(), - rgb_t::black(), - text_size); - - // and get the wrapping info - return layout.get_wrap_info(xstart, xend); -} - //------------------------------------------------- // draw_textured_box - add primitives to // draw an outlined box with the given diff --git a/src/frontend/mame/ui/ui.h b/src/frontend/mame/ui/ui.h index 4cd6292a764..a81278f3333 100644 --- a/src/frontend/mame/ui/ui.h +++ b/src/frontend/mame/ui/ui.h @@ -207,10 +207,7 @@ public: // other void process_natural_keyboard(); - ui::text_layout create_layout(render_container &container, float width = 1.0, ui::text_layout::text_justify justify = ui::text_layout::LEFT, ui::text_layout::word_wrapping wrap = ui::text_layout::WORD); - - // word wrap - int wrap_text(render_container &container, std::string_view origs, float x, float y, float origwrapwidth, std::vector &xstart, std::vector &xend, float text_size = 1.0f); + ui::text_layout create_layout(render_container &container, float width = 1.0, ui::text_layout::text_justify justify = ui::text_layout::text_justify::LEFT, ui::text_layout::word_wrapping wrap = ui::text_layout::word_wrapping::WORD); // draw an outlined box with given line color and filled with a texture void draw_textured_box(render_container &container, float x0, float y0, float x1, float y1, rgb_t backcolor, rgb_t linecolor, render_texture *texture = nullptr, uint32_t flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA)); diff --git a/src/frontend/mame/ui/utils.cpp b/src/frontend/mame/ui/utils.cpp index 95002ce6482..35aef723b13 100644 --- a/src/frontend/mame/ui/utils.cpp +++ b/src/frontend/mame/ui/utils.cpp @@ -396,7 +396,7 @@ private: draw_text_box( std::begin(text), std::end(text), x, x2, y - top, y - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -1002,7 +1002,7 @@ private: draw_text_box( std::begin(text), std::end(text), x, x2, y - top, y - ui().box_tb_border(), - ui::text_layout::CENTER, ui::text_layout::NEVER, false, + text_layout::text_justify::CENTER, text_layout::word_wrapping::NEVER, false, ui().colors().text_color(), UI_GREEN_COLOR, 1.0f); } @@ -2044,7 +2044,7 @@ ui_software_info::ui_software_info( { // show the list/item here infotext.append(longname); - infotext.append("\t\n\n"); + infotext.append(2, '\n'); infotext.append(_("swlist-info", "Software list/item")); infotext.append(1, '\n'); infotext.append(listname);