rpcsx/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp

262 lines
6.3 KiB
C++
Raw Permalink Normal View History

2020-12-05 13:08:24 +01:00
#include "stdafx.h"
2021-05-26 20:29:03 +02:00
#include "overlay_edit_text.hpp"
2019-05-16 22:48:05 +02:00
namespace rsx
{
namespace overlays
{
static usz get_line_start(std::u32string_view text, usz pos)
{
if (pos == 0)
{
return 0;
}
2020-12-18 08:39:54 +01:00
const usz line_start = text.rfind('\n', pos - 1);
if (line_start == umax)
{
return 0;
}
return line_start + 1;
}
static usz get_line_end(std::u32string_view text, usz pos)
{
2020-12-18 08:39:54 +01:00
const usz line_end = text.find('\n', pos);
if (line_end == umax)
{
return text.length();
}
return line_end;
}
2019-05-16 22:48:05 +02:00
void edit_text::move_caret(direction dir)
{
2021-03-09 20:40:14 +01:00
m_reset_caret_pulse = true;
2019-05-16 22:48:05 +02:00
switch (dir)
{
case direction::left:
2019-05-16 22:48:05 +02:00
{
if (caret_position)
{
caret_position--;
refresh();
}
break;
}
case direction::right:
2019-05-16 22:48:05 +02:00
{
2021-04-12 15:14:13 +02:00
if (caret_position < value.length())
2019-05-16 22:48:05 +02:00
{
caret_position++;
refresh();
}
break;
}
case direction::up:
{
2021-04-12 15:14:13 +02:00
const usz current_line_start = get_line_start(value, caret_position);
if (current_line_start == 0)
{
// This is the first line, so caret moves to the very beginning
caret_position = 0;
refresh();
break;
}
2020-12-18 08:39:54 +01:00
const usz caret_pos_in_line = caret_position - current_line_start;
const usz prev_line_end = current_line_start - 1;
const usz prev_line_start = get_line_start(value, prev_line_end);
// TODO : Save caret position to some kind of buffer, so after switching back and forward, caret would be on initial position
caret_position = std::min(prev_line_end, prev_line_start + caret_pos_in_line);
refresh();
break;
}
case direction::down:
{
2021-04-12 15:14:13 +02:00
const usz current_line_end = get_line_end(value, caret_position);
if (current_line_end == value.length())
{
// This is the last line, so caret moves to the very end
caret_position = current_line_end;
refresh();
break;
}
2021-04-12 15:14:13 +02:00
const usz current_line_start = get_line_start(value, caret_position);
const usz caret_pos_in_line = caret_position - current_line_start;
const usz next_line_start = current_line_end + 1;
const usz next_line_end = get_line_end(value, next_line_start);
// TODO : Save caret position to some kind of buffer, so after switching back and forward, caret would be on initial position
caret_position = std::min(next_line_end, next_line_start + caret_pos_in_line);
refresh();
2019-05-16 22:48:05 +02:00
break;
}
}
2019-05-16 22:48:05 +02:00
}
2021-04-12 15:14:13 +02:00
void edit_text::set_text(const std::string& text)
{
set_unicode_text(utf8_to_u32string(text));
}
void edit_text::set_unicode_text(const std::u32string& text)
{
value = text;
if (value.empty())
{
overlay_element::set_unicode_text(placeholder);
}
2021-04-12 19:28:39 +02:00
else if (password_mode)
{
overlay_element::set_unicode_text(std::u32string(value.size(), U""[0]));
}
2021-04-12 15:14:13 +02:00
else
{
overlay_element::set_unicode_text(value);
}
}
void edit_text::set_placeholder(const std::u32string& placeholder_text)
{
placeholder = placeholder_text;
}
void edit_text::insert_text(const std::u32string& str)
2019-05-16 22:48:05 +02:00
{
if (caret_position == 0)
{
// Start
2021-04-12 15:14:13 +02:00
value = str + text;
2019-05-16 22:48:05 +02:00
}
else if (caret_position == text.length())
{
// End
2021-04-12 15:14:13 +02:00
value += str;
2019-05-16 22:48:05 +02:00
}
else
{
// Middle
2021-04-12 15:14:13 +02:00
value.insert(caret_position, str);
2019-05-16 22:48:05 +02:00
}
2021-09-02 19:00:30 +02:00
caret_position += str.length();
2021-03-09 20:40:14 +01:00
m_reset_caret_pulse = true;
2021-04-12 15:14:13 +02:00
set_unicode_text(value);
2019-05-16 22:48:05 +02:00
refresh();
}
void edit_text::erase()
{
if (!caret_position)
{
return;
}
if (caret_position == 1)
{
2021-04-12 15:14:13 +02:00
value = value.length() > 1 ? value.substr(1) : U"";
2019-05-16 22:48:05 +02:00
}
else if (caret_position == text.length())
{
2021-04-12 15:14:13 +02:00
value = value.substr(0, caret_position - 1);
2019-05-16 22:48:05 +02:00
}
else
{
2021-04-12 15:14:13 +02:00
value = value.substr(0, caret_position - 1) + value.substr(caret_position);
2019-05-16 22:48:05 +02:00
}
caret_position--;
2021-03-09 20:40:14 +01:00
m_reset_caret_pulse = true;
2021-04-12 15:14:13 +02:00
set_unicode_text(value);
2019-05-16 22:48:05 +02:00
refresh();
}
2022-10-29 22:17:24 +02:00
void edit_text::del()
{
if (caret_position >= text.length())
{
return;
}
if (caret_position == 0)
{
value = value.length() > 1 ? value.substr(1) : U"";
}
else
{
value = value.substr(0, caret_position) + value.substr(caret_position + 1);
}
m_reset_caret_pulse = true;
set_unicode_text(value);
refresh();
}
2019-05-16 22:48:05 +02:00
compiled_resource& edit_text::get_compiled()
{
if (!is_compiled())
2019-05-16 22:48:05 +02:00
{
auto renderer = get_font();
const auto [caret_x, caret_y] = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : -1, wrap_text);
2019-05-16 22:48:05 +02:00
overlay_element caret;
caret.set_pos(static_cast<u16>(caret_x) + padding_left + x, static_cast<u16>(caret_y) + padding_top + y);
caret.set_size(1, static_cast<u16>(renderer->get_size_px() + 2));
caret.fore_color = fore_color;
caret.back_color = fore_color;
2019-05-16 22:48:05 +02:00
caret.pulse_effect_enabled = true;
2021-03-09 20:40:14 +01:00
if (m_reset_caret_pulse)
{
// Reset the pulse slightly below 1 rising on each user interaction
caret.set_sinus_offset(1.6f);
m_reset_caret_pulse = false;
}
// Check if we have to scroll horizontally
// TODO: Vertical scrolling
const s32 available_width = w - padding_left - padding_right;
const f32 offset_right = caret_x + caret.w - available_width;
if (text.empty())
{
// Scroll to the beginning
horizontal_scroll_offset = 0.0f;
}
else if (horizontal_scroll_offset >= caret_x)
{
// Scroll to the left so that the entire caret is visible
horizontal_scroll_offset = caret_x;
}
else if (horizontal_scroll_offset <= offset_right && offset_right > 0.0f)
{
// Scroll to the right so that the entire caret is visible
horizontal_scroll_offset = offset_right;
}
else if (horizontal_scroll_offset > 0.0f && offset_right > 0.0f && caret_position >= text.size())
{
// Scroll to the left so that the entire caret is visible and reveal preceding text
horizontal_scroll_offset = offset_right;
}
horizontal_scroll_offset = std::max(0.0f, horizontal_scroll_offset);
auto& compiled = label::get_compiled();
compiled.add(caret.get_compiled(), -horizontal_scroll_offset, -vertical_scroll_offset);
2019-05-16 22:48:05 +02:00
for (auto& cmd : compiled.draw_commands)
{
cmd.config.clip_region = true;
cmd.config.clip_rect = {static_cast<f32>(x), static_cast<f32>(y), static_cast<f32>(x + w), static_cast<f32>(y + h)};
2019-05-16 22:48:05 +02:00
}
m_is_compiled = true;
2019-05-16 22:48:05 +02:00
}
return compiled_resources;
}
} // namespace overlays
} // namespace rsx