mirror of
https://github.com/holub/mame
synced 2025-07-07 02:50:50 +03:00
Merge pull request #949 from npwoods/make_filesel_current_path_clickable
Make filesel current path clickable [Nathan Woods]
This commit is contained in:
commit
f3a11b6fd2
@ -75,6 +75,8 @@ files {
|
||||
MAME_DIR .. "src/frontend/mame/pluginopts.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/ui.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/ui.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/text.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/text.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/devctrl.h",
|
||||
MAME_DIR .. "src/frontend/mame/ui/menu.cpp",
|
||||
MAME_DIR .. "src/frontend/mame/ui/menu.h",
|
||||
|
@ -319,13 +319,63 @@ menu_file_selector::~menu_file_selector()
|
||||
|
||||
void menu_file_selector::custom_render(void *selectedref, float top, float bottom, float origx1, float origy1, float origx2, float origy2)
|
||||
{
|
||||
extra_text_render(top, bottom,
|
||||
origx1, origy1, origx2, origy2,
|
||||
m_current_directory.c_str(),
|
||||
nullptr);
|
||||
// lay out extra text
|
||||
auto layout = ui().create_layout(container);
|
||||
layout.add_text(m_current_directory.c_str());
|
||||
|
||||
// position this extra text
|
||||
float x1, y1, x2, y2;
|
||||
extra_text_position(origx1, origx2, origy1, top, layout, -1, x1, y1, x2, y2);
|
||||
|
||||
// draw a box
|
||||
ui().draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);
|
||||
|
||||
// take off the borders
|
||||
x1 += UI_BOX_LR_BORDER;
|
||||
y1 += UI_BOX_TB_BORDER;
|
||||
|
||||
size_t hit_start = 0, hit_span = 0;
|
||||
if (mouse_hit
|
||||
&& layout.hit_test(mouse_x - x1, mouse_y - y1, hit_start, hit_span)
|
||||
&& m_current_directory.substr(hit_start, hit_span) != PATH_SEPARATOR)
|
||||
{
|
||||
// we're hovering over a directory! highlight it
|
||||
auto target_dir_start = m_current_directory.rfind(PATH_SEPARATOR, hit_start) + 1;
|
||||
auto target_dir_end = m_current_directory.find(PATH_SEPARATOR, hit_start + hit_span);
|
||||
m_hover_directory = m_current_directory.substr(0, target_dir_end);
|
||||
|
||||
// highlight the text in question
|
||||
rgb_t fgcolor = UI_MOUSEOVER_COLOR;
|
||||
rgb_t bgcolor = UI_MOUSEOVER_BG_COLOR;
|
||||
layout.restyle(target_dir_start, target_dir_end - target_dir_start, &fgcolor, &bgcolor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we are not hovering over anything
|
||||
m_hover_directory.clear();
|
||||
}
|
||||
|
||||
// draw the text within it
|
||||
layout.emit(container, x1, y1);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// custom_mouse_down - perform our special mouse down
|
||||
//-------------------------------------------------
|
||||
|
||||
bool menu_file_selector::custom_mouse_down()
|
||||
{
|
||||
if (m_hover_directory.length() > 0)
|
||||
{
|
||||
m_current_directory = m_hover_directory;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// compare_file_selector_entries - sorting proc
|
||||
|
@ -69,6 +69,9 @@ public:
|
||||
virtual void handle() override;
|
||||
virtual void custom_render(void *selectedref, float top, float bottom, float x, float y, float x2, float y2) override;
|
||||
|
||||
protected:
|
||||
virtual bool custom_mouse_down() override;
|
||||
|
||||
private:
|
||||
enum file_selector_entry_type
|
||||
{
|
||||
@ -98,6 +101,7 @@ private:
|
||||
bool m_has_create;
|
||||
int * m_result;
|
||||
file_selector_entry * m_entrylist;
|
||||
std::string m_hover_directory;
|
||||
char m_filename_buffer[1024];
|
||||
|
||||
// methods
|
||||
|
@ -514,8 +514,6 @@ void menu::draw(UINT32 flags, float origx0, float origy0)
|
||||
|
||||
bool selected_subitem_too_big = false;
|
||||
int itemnum, linenum;
|
||||
bool mouse_hit, mouse_button;
|
||||
float mouse_x = -1, mouse_y = -1;
|
||||
|
||||
if (ui().options().use_background_image() && &machine().system() == &GAME_NAME(___empty) && bgrnd_bitmap->valid() && !noimage)
|
||||
container->add_quad(0.0f, 0.0f, 1.0f, 1.0f, rgb_t::white, bgrnd_texture, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
|
||||
@ -916,6 +914,9 @@ void menu::handle_events(UINT32 flags)
|
||||
{
|
||||
// if we are hovering over a valid item, select it with a single click
|
||||
case UI_EVENT_MOUSE_DOWN:
|
||||
if (custom_mouse_down())
|
||||
return;
|
||||
|
||||
if ((flags & PROCESS_ONLYCHAR) == 0)
|
||||
{
|
||||
if (hover >= 0 && hover < item.size())
|
||||
@ -2957,24 +2958,13 @@ void menu::set_pressed()
|
||||
|
||||
void menu::extra_text_draw_box(float origx1, float origx2, float origy, float yspan, const char *text, int direction)
|
||||
{
|
||||
float text_width, text_height;
|
||||
float width, maxwidth;
|
||||
float x1, y1, x2, y2;
|
||||
|
||||
// get the size of the text
|
||||
ui().draw_text_full(container,text, 0.0f, 0.0f, 1.0f, JUSTIFY_LEFT, WRAP_WORD,
|
||||
DRAW_NONE, rgb_t::white, rgb_t::black, &text_width, &text_height);
|
||||
width = text_width + (2 * UI_BOX_LR_BORDER);
|
||||
maxwidth = MAX(width, origx2 - origx1);
|
||||
auto layout = ui().create_layout(container);
|
||||
layout.add_text(text);
|
||||
|
||||
// compute our bounds
|
||||
x1 = 0.5f - 0.5f * maxwidth;
|
||||
x2 = x1 + maxwidth;
|
||||
y1 = origy + (yspan * direction);
|
||||
y2 = origy + (UI_BOX_TB_BORDER * direction);
|
||||
|
||||
if (y1 > y2)
|
||||
std::swap(y1, y2);
|
||||
// position this extra text
|
||||
float x1, y1, x2, y2;
|
||||
extra_text_position(origx1, origx2, origy, yspan, layout, direction, x1, y1, x2, y2);
|
||||
|
||||
// draw a box
|
||||
ui().draw_outlined_box(container,x1, y1, x2, y2, UI_BACKGROUND_COLOR);
|
||||
@ -2984,8 +2974,29 @@ void menu::extra_text_draw_box(float origx1, float origx2, float origy, float ys
|
||||
y1 += UI_BOX_TB_BORDER;
|
||||
|
||||
// draw the text within it
|
||||
ui().draw_text_full(container,text, x1, y1, text_width, JUSTIFY_LEFT, WRAP_WORD,
|
||||
DRAW_NORMAL, rgb_t::white, rgb_t::black, nullptr, nullptr);
|
||||
layout.emit(container, x1, y1);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// extra_text_position - given extra text that has
|
||||
// been put into a layout, position it
|
||||
//-------------------------------------------------
|
||||
|
||||
void menu::extra_text_position(float origx1, float origx2, float origy, float yspan, text_layout &layout,
|
||||
int direction, float &x1, float &y1, float &x2, float &y2)
|
||||
{
|
||||
float width = layout.actual_width() + (2 * UI_BOX_LR_BORDER);
|
||||
float maxwidth = MAX(width, origx2 - origx1);
|
||||
|
||||
// compute our bounds
|
||||
x1 = 0.5f - 0.5f * maxwidth;
|
||||
x2 = x1 + maxwidth;
|
||||
y1 = origy + (yspan * direction);
|
||||
y2 = origy + (UI_BOX_TB_BORDER * direction);
|
||||
|
||||
if (y1 > y2)
|
||||
std::swap(y1, y2);
|
||||
}
|
||||
|
||||
|
||||
|
@ -284,6 +284,11 @@ protected:
|
||||
|
||||
// draw header and footer text
|
||||
void extra_text_render(float top, float bottom, float origx1, float origy1, float origx2, float origy2, const char *header, const char *footer);
|
||||
void extra_text_position(float origx1, float origx2, float origy, float yspan, text_layout &layout,
|
||||
int direction, float &x1, float &y1, float &x2, float &y2);
|
||||
|
||||
// custom events
|
||||
virtual bool custom_mouse_down() { return false; }
|
||||
|
||||
template <typename T>
|
||||
static T *topmost_menu() { return dynamic_cast<T *>(menu_stack.get()); }
|
||||
|
539
src/frontend/mame/ui/text.cpp
Normal file
539
src/frontend/mame/ui/text.cpp
Normal file
@ -0,0 +1,539 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
|
||||
/*********************************************************************
|
||||
|
||||
text.cpp
|
||||
|
||||
Text functionality for MAME's crude user interface
|
||||
|
||||
*********************************************************************/
|
||||
|
||||
#include "text.h"
|
||||
#include "rendfont.h"
|
||||
#include "render.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
//-------------------------------------------------
|
||||
// is_space_character
|
||||
//-------------------------------------------------
|
||||
|
||||
inline bool is_space_character(unicode_char ch)
|
||||
{
|
||||
return ch == ' ';
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// is_breakable_char - is a given unicode
|
||||
// character a possible line break?
|
||||
//-------------------------------------------------
|
||||
|
||||
inline bool is_breakable_char(unicode_char ch)
|
||||
{
|
||||
// regular spaces and hyphens are breakable
|
||||
if (is_space_character(ch) || ch == '-')
|
||||
return true;
|
||||
|
||||
// In the following character sets, any character is breakable:
|
||||
// Hiragana (3040-309F)
|
||||
// Katakana (30A0-30FF)
|
||||
// Bopomofo (3100-312F)
|
||||
// Hangul Compatibility Jamo (3130-318F)
|
||||
// Kanbun (3190-319F)
|
||||
// Bopomofo Extended (31A0-31BF)
|
||||
// CJK Strokes (31C0-31EF)
|
||||
// Katakana Phonetic Extensions (31F0-31FF)
|
||||
// Enclosed CJK Letters and Months (3200-32FF)
|
||||
// CJK Compatibility (3300-33FF)
|
||||
// CJK Unified Ideographs Extension A (3400-4DBF)
|
||||
// Yijing Hexagram Symbols (4DC0-4DFF)
|
||||
// CJK Unified Ideographs (4E00-9FFF)
|
||||
if (ch >= 0x3040 && ch <= 0x9fff)
|
||||
return true;
|
||||
|
||||
// Hangul Syllables (AC00-D7AF) are breakable
|
||||
if (ch >= 0xac00 && ch <= 0xd7af)
|
||||
return true;
|
||||
|
||||
// CJK Compatibility Ideographs (F900-FAFF) are breakable
|
||||
if (ch >= 0xf900 && ch <= 0xfaff)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CORE IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
//-------------------------------------------------
|
||||
// ctor
|
||||
//-------------------------------------------------
|
||||
|
||||
text_layout::text_layout(render_font &font, float xscale, float yscale, float width, text_layout::text_justify justify, text_layout::word_wrapping wrap)
|
||||
: m_font(font), m_xscale(xscale), m_yscale(yscale), m_width(width), m_justify(justify), m_wrap(wrap), m_current_line(nullptr), m_last_break(0), m_text_position(0)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// ctor (move)
|
||||
//-------------------------------------------------
|
||||
|
||||
text_layout::text_layout(text_layout &&that)
|
||||
: m_font(that.m_font), m_xscale(that.m_xscale), m_yscale(that.m_yscale), m_width(that.m_width), m_justify(that.m_justify), m_wrap(that.m_wrap), m_lines(std::move(that.m_lines)),
|
||||
m_current_line(that.m_current_line), m_last_break(that.m_last_break), m_text_position(that.m_text_position)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// dtor
|
||||
//-------------------------------------------------
|
||||
|
||||
text_layout::~text_layout()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// add_text
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::add_text(const char *text, const char_style &style)
|
||||
{
|
||||
int position = 0;
|
||||
int text_length = strlen(text);
|
||||
|
||||
while(position < text_length)
|
||||
{
|
||||
// do we need to create a new line?
|
||||
if (m_current_line == nullptr)
|
||||
{
|
||||
// get the current character
|
||||
unicode_char schar;
|
||||
int scharcount;
|
||||
scharcount = uchar_from_utf8(&schar, &text[position], text_length - position);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
// if the line starts with a tab character, center it regardless
|
||||
text_justify line_justify = justify();
|
||||
if (schar == '\t')
|
||||
{
|
||||
position += scharcount;
|
||||
line_justify = text_layout::CENTER;
|
||||
}
|
||||
|
||||
// start a new line
|
||||
start_new_line(line_justify, style.size);
|
||||
}
|
||||
|
||||
// get the current character
|
||||
int scharcount;
|
||||
unicode_char ch;
|
||||
scharcount = uchar_from_utf8(&ch, &text[position], text_length - position);
|
||||
if (scharcount < 0)
|
||||
break;
|
||||
position += scharcount;
|
||||
|
||||
// set up source information
|
||||
source_info source = { 0, };
|
||||
source.start = m_text_position;
|
||||
source.span = scharcount;
|
||||
m_text_position += scharcount;
|
||||
|
||||
// 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
|
||||
update_maximum_line_width();
|
||||
m_current_line = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we hit a space, remember the location and width *without* the space
|
||||
if (is_space_character(ch))
|
||||
m_last_break = m_current_line->character_count();
|
||||
|
||||
// append the character
|
||||
m_current_line->add_character(ch, style, source);
|
||||
|
||||
// do we have to wrap?
|
||||
if (wrap() != NEVER && m_current_line->width() > m_width)
|
||||
{
|
||||
switch (wrap())
|
||||
{
|
||||
case TRUNCATE:
|
||||
truncate_wrap();
|
||||
break;
|
||||
|
||||
case WORD:
|
||||
word_wrap();
|
||||
break;
|
||||
|
||||
default:
|
||||
fatalerror("invalid word wrapping value");
|
||||
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))
|
||||
m_last_break = m_current_line->character_count();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// update_maximum_line_width
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::update_maximum_line_width()
|
||||
{
|
||||
m_maximum_line_width = actual_width();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// actual_width
|
||||
//-------------------------------------------------
|
||||
|
||||
float text_layout::actual_width() const
|
||||
{
|
||||
float current_line_width = m_current_line ? m_current_line->width() : 0;
|
||||
return MAX(m_maximum_line_width, current_line_width);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// actual_height
|
||||
//-------------------------------------------------
|
||||
|
||||
float text_layout::actual_height() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// start_new_line
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::start_new_line(text_layout::text_justify justify, float height)
|
||||
{
|
||||
// create a new line
|
||||
std::unique_ptr<line> new_line(global_alloc_clear<line>(*this, justify, actual_height(), height * yscale()));
|
||||
|
||||
// update the current line
|
||||
update_maximum_line_width();
|
||||
m_current_line = new_line.get();
|
||||
m_last_break = 0;
|
||||
|
||||
// append it
|
||||
m_lines.push_back(std::move(new_line));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// get_char_width
|
||||
//-------------------------------------------------
|
||||
|
||||
float text_layout::get_char_width(unicode_char ch, float size)
|
||||
{
|
||||
return font().char_width(size * yscale(), xscale() / yscale(), ch);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// truncate_wrap
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::truncate_wrap()
|
||||
{
|
||||
// for now, lets assume that we're only truncating the last character
|
||||
size_t truncate_position = m_current_line->character_count() - 1;
|
||||
const auto& truncate_char = m_current_line->character(truncate_position);
|
||||
|
||||
// copy style information
|
||||
char_style style = truncate_char.style;
|
||||
|
||||
// copy source information
|
||||
source_info source = { 0, };
|
||||
source.start = truncate_char.source.start + truncate_char.source.span;
|
||||
source.span = 0;
|
||||
|
||||
// figure out how wide an elipsis is
|
||||
float elipsis_width = 3 * get_char_width('.', style.size);
|
||||
|
||||
// where should we really truncate from?
|
||||
while (truncate_position > 0 && m_current_line->character(truncate_position).xoffset + elipsis_width < width())
|
||||
truncate_position--;
|
||||
|
||||
// truncate!!!
|
||||
m_current_line->truncate(truncate_position);
|
||||
|
||||
// and append the elipsis
|
||||
m_current_line->add_character('.', style, source);
|
||||
|
||||
// finally start a new line
|
||||
start_new_line(m_current_line->justify(), style.size);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// word_wrap
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::word_wrap()
|
||||
{
|
||||
// keep track of the last line and break
|
||||
line *last_line = m_current_line;
|
||||
size_t last_break = m_last_break;
|
||||
|
||||
// start a new line with the same justification
|
||||
start_new_line(last_line->justify(), last_line->character(last_line->character_count() - 1).style.size);
|
||||
|
||||
// find the begining 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))
|
||||
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);
|
||||
}
|
||||
|
||||
// and finally, truncate the last line
|
||||
last_line->truncate(last_break);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// hit_test
|
||||
//-------------------------------------------------
|
||||
|
||||
bool text_layout::hit_test(float x, float y, size_t &start, size_t &span) const
|
||||
{
|
||||
for (const auto &line : m_lines)
|
||||
{
|
||||
if (y >= line->yoffset() && y < line->yoffset() + line->height())
|
||||
{
|
||||
float line_xoffset = line->xoffset();
|
||||
if (x >= line_xoffset && x < line_xoffset + line->width())
|
||||
{
|
||||
for (size_t i = 0; i < line->character_count(); i++)
|
||||
{
|
||||
const auto &ch = line->character(i);
|
||||
if (x >= ch.xoffset && x < ch.xoffset + ch.xwidth)
|
||||
{
|
||||
start = ch.source.start;
|
||||
span = ch.source.span;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
start = 0;
|
||||
span = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// restyle
|
||||
//-------------------------------------------------
|
||||
|
||||
void text_layout::restyle(size_t start, size_t span, rgb_t *fgcolor, rgb_t *bgcolor)
|
||||
{
|
||||
for (const auto &line : m_lines)
|
||||
{
|
||||
for (size_t i = 0; i < line->character_count(); i++)
|
||||
{
|
||||
auto &ch = line->character(i);
|
||||
if (ch.source.start >= start && ch.source.start + ch.source.span <= start + span)
|
||||
{
|
||||
if (fgcolor != nullptr)
|
||||
ch.style.fgcolor = *fgcolor;
|
||||
if (bgcolor != nullptr)
|
||||
ch.style.bgcolor = *bgcolor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// get_wrap_info
|
||||
//-------------------------------------------------
|
||||
|
||||
int text_layout::get_wrap_info(std::vector<int> &xstart, std::vector<int> &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)
|
||||
{
|
||||
float line_xoffset = line->xoffset();
|
||||
|
||||
// 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();
|
||||
|
||||
// render the background of the character (if present)
|
||||
if (ch.style.bgcolor.a() != 0)
|
||||
container->add_rect(char_x, char_y, char_x + char_width, char_y + char_height, ch.style.bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
|
||||
|
||||
// render the foreground
|
||||
container->add_char(
|
||||
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(unicode_char 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 = 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
|
160
src/frontend/mame/ui/text.h
Normal file
160
src/frontend/mame/ui/text.h
Normal file
@ -0,0 +1,160 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Nicola Salmoria, Aaron Giles, Nathan Woods
|
||||
/***************************************************************************
|
||||
|
||||
text.h
|
||||
|
||||
Text functionality for MAME's crude user interface
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MAME_FRONTEND_UI_TEXT_H
|
||||
#define MAME_FRONTEND_UI_TEXT_H
|
||||
|
||||
#include "palette.h"
|
||||
#include "unicode.h"
|
||||
|
||||
class render_font;
|
||||
class render_container;
|
||||
|
||||
namespace ui {
|
||||
|
||||
/***************************************************************************
|
||||
TYPE DEFINITIONS
|
||||
***************************************************************************/
|
||||
|
||||
class text_layout
|
||||
{
|
||||
public:
|
||||
// justification options for text
|
||||
enum text_justify
|
||||
{
|
||||
LEFT = 0,
|
||||
CENTER,
|
||||
RIGHT
|
||||
};
|
||||
|
||||
// word wrapping options
|
||||
enum word_wrapping
|
||||
{
|
||||
NEVER,
|
||||
TRUNCATE,
|
||||
WORD
|
||||
};
|
||||
|
||||
// ctor/dtor
|
||||
text_layout(render_font &font, float xscale, float yscale, float width, text_justify justify, word_wrapping wrap);
|
||||
text_layout(text_layout &&that);
|
||||
~text_layout();
|
||||
|
||||
// accessors
|
||||
render_font &font() const { return m_font; }
|
||||
float xscale() const { return m_xscale; }
|
||||
float yscale() const { return m_yscale; }
|
||||
float width() const { return m_width; }
|
||||
text_justify justify() const { return m_justify; }
|
||||
word_wrapping wrap() const { return m_wrap; }
|
||||
|
||||
// methods
|
||||
float actual_width() const;
|
||||
float actual_height() const;
|
||||
bool hit_test(float x, float y, size_t &start, size_t &span) const;
|
||||
void restyle(size_t start, size_t span, rgb_t *fgcolor, rgb_t *bgcolor);
|
||||
int get_wrap_info(std::vector<int> &xstart, std::vector<int> &xend) const;
|
||||
void emit(render_container *container, float x, float y);
|
||||
void add_text(const char *text, rgb_t fgcolor = rgb_t::white, rgb_t bgcolor = rgb_t(0,0,0,0), 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);
|
||||
}
|
||||
|
||||
private:
|
||||
// text style information - in a struct to facilitate copying
|
||||
struct char_style
|
||||
{
|
||||
rgb_t fgcolor;
|
||||
rgb_t bgcolor;
|
||||
float size;
|
||||
};
|
||||
|
||||
// information about the "source" of a chracter - 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
|
||||
{
|
||||
unicode_char 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(unicode_char 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<positioned_char> m_characters;
|
||||
text_layout &m_layout;
|
||||
text_justify m_justify;
|
||||
float m_yoffset;
|
||||
float m_width;
|
||||
float m_height;
|
||||
};
|
||||
|
||||
// instance variables
|
||||
render_font &m_font;
|
||||
float m_xscale;
|
||||
float m_yscale;
|
||||
float m_width;
|
||||
float m_maximum_line_width;
|
||||
text_justify m_justify;
|
||||
word_wrapping m_wrap;
|
||||
std::vector<std::unique_ptr<line>> m_lines;
|
||||
line *m_current_line;
|
||||
size_t m_last_break;
|
||||
size_t m_text_position;
|
||||
|
||||
// methods
|
||||
void add_text(const char *text, const char_style &style);
|
||||
void start_new_line(text_justify justify, float height);
|
||||
float get_char_width(unicode_char ch, float size);
|
||||
void truncate_wrap();
|
||||
void word_wrap();
|
||||
void update_maximum_line_width();
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
||||
#endif // MAME_FRONTEND_UI_TEXT_H
|
@ -125,51 +125,6 @@ std::vector<ui::menu_item> mame_ui_manager::slider_list;
|
||||
slider_state *mame_ui_manager::slider_current;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
INLINE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
//-------------------------------------------------
|
||||
// is_breakable_char - is a given unicode
|
||||
// character a possible line break?
|
||||
//-------------------------------------------------
|
||||
|
||||
static inline int is_breakable_char(unicode_char ch)
|
||||
{
|
||||
// regular spaces and hyphens are breakable
|
||||
if (ch == ' ' || ch == '-')
|
||||
return TRUE;
|
||||
|
||||
// In the following character sets, any character is breakable:
|
||||
// Hiragana (3040-309F)
|
||||
// Katakana (30A0-30FF)
|
||||
// Bopomofo (3100-312F)
|
||||
// Hangul Compatibility Jamo (3130-318F)
|
||||
// Kanbun (3190-319F)
|
||||
// Bopomofo Extended (31A0-31BF)
|
||||
// CJK Strokes (31C0-31EF)
|
||||
// Katakana Phonetic Extensions (31F0-31FF)
|
||||
// Enclosed CJK Letters and Months (3200-32FF)
|
||||
// CJK Compatibility (3300-33FF)
|
||||
// CJK Unified Ideographs Extension A (3400-4DBF)
|
||||
// Yijing Hexagram Symbols (4DC0-4DFF)
|
||||
// CJK Unified Ideographs (4E00-9FFF)
|
||||
if (ch >= 0x3040 && ch <= 0x9fff)
|
||||
return TRUE;
|
||||
|
||||
// Hangul Syllables (AC00-D7AF) are breakable
|
||||
if (ch >= 0xac00 && ch <= 0xd7af)
|
||||
return TRUE;
|
||||
|
||||
// CJK Compatibility Ideographs (F900-FAFF) are breakable
|
||||
if (ch >= 0xf900 && ch <= 0xfaff)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
CORE IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
@ -600,204 +555,25 @@ void mame_ui_manager::draw_text(render_container *container, const char *buf, fl
|
||||
|
||||
void mame_ui_manager::draw_text_full(render_container *container, const char *origs, float x, float y, float origwrapwidth, int justify, int wrap, int draw, rgb_t fgcolor, rgb_t bgcolor, float *totalwidth, float *totalheight, float text_size)
|
||||
{
|
||||
float lineheight = get_line_height() * text_size;
|
||||
const char *ends = origs + strlen(origs);
|
||||
float wrapwidth = origwrapwidth;
|
||||
const char *s = origs;
|
||||
const char *linestart;
|
||||
float cury = y;
|
||||
float maxwidth = 0;
|
||||
float aspect = machine().render().ui_aspect(container);
|
||||
// create the layout
|
||||
auto layout = create_layout(container, origwrapwidth, (ui::text_layout::text_justify)justify, (ui::text_layout::word_wrapping)wrap);
|
||||
|
||||
// if we don't want wrapping, guarantee a huge wrapwidth
|
||||
if (wrap == WRAP_NEVER)
|
||||
wrapwidth = 1000000.0f;
|
||||
if (wrapwidth <= 0)
|
||||
return;
|
||||
// append text to it
|
||||
layout.add_text(
|
||||
origs,
|
||||
fgcolor,
|
||||
draw == DRAW_OPAQUE ? bgcolor : rgb_t(0, 0, 0, 0),
|
||||
text_size);
|
||||
|
||||
// loop over lines
|
||||
while (*s != 0)
|
||||
{
|
||||
const char *lastbreak = nullptr;
|
||||
int line_justify = justify;
|
||||
unicode_char schar;
|
||||
int scharcount;
|
||||
float lastbreak_width = 0;
|
||||
float curwidth = 0;
|
||||
float curx = x;
|
||||
// and emit it (if we are asked to do so)
|
||||
if (draw != DRAW_NONE)
|
||||
layout.emit(container, x, y);
|
||||
|
||||
// get the current character
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
// if the line starts with a tab character, center it regardless
|
||||
if (schar == '\t')
|
||||
{
|
||||
s += scharcount;
|
||||
line_justify = JUSTIFY_CENTER;
|
||||
}
|
||||
|
||||
// remember the starting position of the line
|
||||
linestart = s;
|
||||
|
||||
// loop while we have characters and are less than the wrapwidth
|
||||
while (*s != 0 && curwidth <= wrapwidth)
|
||||
{
|
||||
float chwidth;
|
||||
|
||||
// get the current chcaracter
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
// if we hit a newline, stop immediately
|
||||
if (schar == '\n')
|
||||
break;
|
||||
|
||||
// get the width of this character
|
||||
chwidth = get_font()->char_width(lineheight, aspect, schar);
|
||||
|
||||
// if we hit a space, remember the location and width *without* the space
|
||||
if (schar == ' ')
|
||||
{
|
||||
lastbreak = s;
|
||||
lastbreak_width = curwidth;
|
||||
}
|
||||
|
||||
// add the width of this character and advance
|
||||
curwidth += chwidth;
|
||||
s += scharcount;
|
||||
|
||||
// if we hit any non-space breakable character, remember the location and width
|
||||
// *with* the breakable character
|
||||
if (schar != ' ' && is_breakable_char(schar) && curwidth <= wrapwidth)
|
||||
{
|
||||
lastbreak = s;
|
||||
lastbreak_width = curwidth;
|
||||
}
|
||||
}
|
||||
|
||||
// if we accumulated too much for the current width, we need to back off
|
||||
if (curwidth > wrapwidth)
|
||||
{
|
||||
// if we're word wrapping, back up to the last break if we can
|
||||
if (wrap == WRAP_WORD)
|
||||
{
|
||||
// if we hit a break, back up to there with the appropriate width
|
||||
if (lastbreak != nullptr)
|
||||
{
|
||||
s = lastbreak;
|
||||
curwidth = lastbreak_width;
|
||||
}
|
||||
|
||||
// if we didn't hit a break, back up one character
|
||||
else if (s > linestart)
|
||||
{
|
||||
// get the previous character
|
||||
s = (const char *)utf8_previous_char(s);
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
curwidth -= get_font()->char_width(lineheight, aspect, schar);
|
||||
// if back to 0, there is no space to draw even a single char
|
||||
if (curwidth <= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're truncating, make sure we have enough space for the ...
|
||||
else if (wrap == WRAP_TRUNCATE)
|
||||
{
|
||||
// add in the width of the ...
|
||||
curwidth += 3.0f * get_font()->char_width(lineheight, aspect, '.');
|
||||
|
||||
// while we are above the wrap width, back up one character
|
||||
while (curwidth > wrapwidth && s > linestart)
|
||||
{
|
||||
// get the previous character
|
||||
s = (const char *)utf8_previous_char(s);
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
curwidth -= get_font()->char_width(lineheight, aspect, schar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// align according to the justfication
|
||||
if (line_justify == JUSTIFY_CENTER)
|
||||
curx += (origwrapwidth - curwidth) * 0.5f;
|
||||
else if (line_justify == JUSTIFY_RIGHT)
|
||||
curx += origwrapwidth - curwidth;
|
||||
|
||||
// track the maximum width of any given line
|
||||
if (curwidth > maxwidth)
|
||||
maxwidth = curwidth;
|
||||
|
||||
// if opaque, add a black box
|
||||
if (draw == DRAW_OPAQUE)
|
||||
container->add_rect(curx, cury, curx + curwidth, cury + lineheight, bgcolor, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
|
||||
|
||||
// loop from the line start and add the characters
|
||||
while (linestart < s)
|
||||
{
|
||||
// get the current character
|
||||
unicode_char linechar;
|
||||
int linecharcount = uchar_from_utf8(&linechar, linestart, ends - linestart);
|
||||
if (linecharcount == -1)
|
||||
break;
|
||||
|
||||
if (draw != DRAW_NONE)
|
||||
{
|
||||
container->add_char(curx, cury, lineheight, aspect, fgcolor, *get_font(), linechar);
|
||||
curx += get_font()->char_width(lineheight, aspect, linechar);
|
||||
}
|
||||
linestart += linecharcount;
|
||||
}
|
||||
|
||||
// append ellipses if needed
|
||||
if (wrap == WRAP_TRUNCATE && *s != 0 && draw != DRAW_NONE)
|
||||
{
|
||||
container->add_char(curx, cury, lineheight, aspect, fgcolor, *get_font(), '.');
|
||||
curx += get_font()->char_width(lineheight, aspect, '.');
|
||||
container->add_char(curx, cury, lineheight, aspect, fgcolor, *get_font(), '.');
|
||||
curx += get_font()->char_width(lineheight, aspect, '.');
|
||||
container->add_char(curx, cury, lineheight, aspect, fgcolor, *get_font(), '.');
|
||||
curx += get_font()->char_width(lineheight, aspect, '.');
|
||||
}
|
||||
|
||||
// if we're not word-wrapping, we're done
|
||||
if (wrap != WRAP_WORD)
|
||||
break;
|
||||
|
||||
// advance by a row
|
||||
cury += lineheight;
|
||||
|
||||
// skip past any spaces at the beginning of the next line
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
if (schar == '\n')
|
||||
s += scharcount;
|
||||
else
|
||||
while (*s && isspace(schar))
|
||||
{
|
||||
s += scharcount;
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// report the width and height of the resulting space
|
||||
// return width/height
|
||||
if (totalwidth)
|
||||
*totalwidth = maxwidth;
|
||||
*totalwidth = layout.actual_width();
|
||||
if (totalheight)
|
||||
*totalheight = cury - y;
|
||||
*totalheight = layout.actual_height();
|
||||
}
|
||||
|
||||
|
||||
@ -2536,136 +2312,40 @@ void mame_ui_manager::set_use_natural_keyboard(bool use_natural_keyboard)
|
||||
assert(error.empty());
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// wrap_text
|
||||
//-------------------------------------------------
|
||||
|
||||
ui::text_layout mame_ui_manager::create_layout(render_container *container, float width, ui::text_layout::text_justify justify, ui::text_layout::word_wrapping wrap)
|
||||
{
|
||||
// determine scale factors
|
||||
float yscale = get_line_height();
|
||||
float xscale = yscale * machine().render().ui_aspect(container);
|
||||
|
||||
// create the layout
|
||||
return ui::text_layout(*get_font(), xscale, yscale, width, justify, wrap);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// wrap_text
|
||||
//-------------------------------------------------
|
||||
|
||||
int mame_ui_manager::wrap_text(render_container *container, const char *origs, float x, float y, float origwrapwidth, std::vector<int> &xstart, std::vector<int> &xend, float text_size)
|
||||
{
|
||||
float lineheight = get_line_height() * text_size;
|
||||
const char *ends = origs + strlen(origs);
|
||||
float wrapwidth = origwrapwidth;
|
||||
const char *s = origs;
|
||||
const char *linestart;
|
||||
float maxwidth = 0;
|
||||
float aspect = machine().render().ui_aspect(container);
|
||||
int count = 0;
|
||||
// create the layout
|
||||
auto layout = create_layout(container, origwrapwidth, ui::text_layout::LEFT, ui::text_layout::WORD);
|
||||
|
||||
// loop over lines
|
||||
while (*s != 0)
|
||||
{
|
||||
const char *lastbreak = nullptr;
|
||||
unicode_char schar;
|
||||
int scharcount;
|
||||
float lastbreak_width = 0;
|
||||
float curwidth = 0;
|
||||
// add the text
|
||||
layout.add_text(
|
||||
origs,
|
||||
rgb_t::black,
|
||||
rgb_t::black,
|
||||
text_size);
|
||||
|
||||
// get the current character
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
// remember the starting position of the line
|
||||
linestart = s;
|
||||
|
||||
// loop while we have characters and are less than the wrapwidth
|
||||
while (*s != 0 && curwidth <= wrapwidth)
|
||||
{
|
||||
float chwidth;
|
||||
|
||||
// get the current chcaracter
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
// if we hit a newline, stop immediately
|
||||
if (schar == '\n')
|
||||
break;
|
||||
|
||||
// get the width of this character
|
||||
chwidth = get_font()->char_width(lineheight, aspect, schar);
|
||||
|
||||
// if we hit a space, remember the location and width *without* the space
|
||||
if (schar == ' ')
|
||||
{
|
||||
lastbreak = s;
|
||||
lastbreak_width = curwidth;
|
||||
}
|
||||
|
||||
// add the width of this character and advance
|
||||
curwidth += chwidth;
|
||||
s += scharcount;
|
||||
|
||||
// if we hit any non-space breakable character, remember the location and width
|
||||
// *with* the breakable character
|
||||
if (schar != ' ' && is_breakable_char(schar) && curwidth <= wrapwidth)
|
||||
{
|
||||
lastbreak = s;
|
||||
lastbreak_width = curwidth;
|
||||
}
|
||||
}
|
||||
|
||||
// if we accumulated too much for the current width, we need to back off
|
||||
if (curwidth > wrapwidth)
|
||||
{
|
||||
// if we hit a break, back up to there with the appropriate width
|
||||
if (lastbreak != nullptr)
|
||||
{
|
||||
s = lastbreak;
|
||||
curwidth = lastbreak_width;
|
||||
}
|
||||
|
||||
// if we didn't hit a break, back up one character
|
||||
else if (s > linestart)
|
||||
{
|
||||
// get the previous character
|
||||
s = (const char *)utf8_previous_char(s);
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
curwidth -= get_font()->char_width(lineheight, aspect, schar);
|
||||
}
|
||||
}
|
||||
|
||||
// track the maximum width of any given line
|
||||
if (curwidth > maxwidth)
|
||||
maxwidth = curwidth;
|
||||
|
||||
xstart.push_back(linestart - origs);
|
||||
xend.push_back(s - origs);
|
||||
|
||||
// loop from the line start and add the characters
|
||||
while (linestart < s)
|
||||
{
|
||||
// get the current character
|
||||
unicode_char linechar;
|
||||
int linecharcount = uchar_from_utf8(&linechar, linestart, ends - linestart);
|
||||
if (linecharcount == -1)
|
||||
break;
|
||||
linestart += linecharcount;
|
||||
}
|
||||
|
||||
// advance by a row
|
||||
count++;
|
||||
|
||||
// skip past any spaces at the beginning of the next line
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
|
||||
if (schar == '\n')
|
||||
s += scharcount;
|
||||
else
|
||||
while (*s && isspace(schar))
|
||||
{
|
||||
s += scharcount;
|
||||
scharcount = uchar_from_utf8(&schar, s, ends - s);
|
||||
if (scharcount == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
// and get the wrapping info
|
||||
return layout.get_wrap_info(xstart, xend);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "ui/uimain.h"
|
||||
#include "ui/menuitem.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/text.h"
|
||||
|
||||
namespace ui {
|
||||
|
||||
@ -256,6 +257,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, const char *origs, float x, float y, float origwrapwidth, std::vector<int> &xstart, std::vector<int> &xend, float text_size = 1.0f);
|
||||
|
Loading…
Reference in New Issue
Block a user