Files
sphaira/sphaira/source/ui/scrollable_text.cpp

110 lines
3.7 KiB
C++

#include "ui/scrollable_text.hpp"
#include "app.hpp"
#include "ui/nvg_util.hpp"
#include "log.hpp"
#include <cstring>
namespace sphaira::ui {
ScrollableText::ScrollableText(const std::string& text, float x, float y, float y_clip, float w, float font_size)
: m_font_size{font_size}
, m_y_off_base{y}
, m_clip_y{y_clip}
, m_end_w{w}
, m_y_off{y}
{
SetActions(
std::make_pair(Button::LS_DOWN, Action{[this](){
const auto bound = m_bounds[3];
if (bound < m_clip_y) {
return;
}
const auto a = m_y_off_base + m_clip_y;
const auto norm = m_bounds[3] - m_bounds[1];
const auto b = m_y_off + norm;
if (b <= a) {
return;
}
m_y_off -= m_step;
m_index++;
App::PlaySoundEffect(SoundEffect_Scroll);
}}),
std::make_pair(Button::LS_UP, Action{[this](){
if (m_y_off == m_y_off_base) {
return;
}
m_y_off += m_step;
m_index--;
App::PlaySoundEffect(SoundEffect_Scroll);
}})
);
#if 1
// converts '\''n' to '\n' without including <regex> because it bloats
// the binary by over 400 KiB lol
const auto mini_regex = [](std::string_view str, std::string_view regex, std::string_view replace) -> std::string {
std::string out;
out.reserve(str.size());
u32 i{};
while (i < str.size()) {
if ((i + regex.size()) <= str.size() && !std::memcmp(str.data() + i, regex.data(), regex.size())) {
out.append(replace.data(), replace.size());
i += regex.size();
} else {
out.push_back(str[i]);
i++;
}
}
return out;
};
m_text = mini_regex(text, "\r", "");
m_text = mini_regex(m_text, "\\n", "\n");
#else
m_text = std::regex_replace(text, std::regex("\\\\n"), "\n");
#endif
if (m_text.size() > 4096) {
m_text.resize(4096);
m_text += "...";
}
nvgFontSize(App::GetVg(), m_font_size);
nvgTextLineHeight(App::GetVg(), 1.7);
nvgTextBoxBounds(App::GetVg(), 110.0F, m_y_off_base, m_end_w, m_text.c_str(), nullptr, m_bounds);
// log_write("bounds x: %.2f y: %.2f w: %.2f h: %.2f\n", m_bounds[0], m_bounds[1], m_bounds[2], m_bounds[3]);
}
// void ScrollableText::Update(Controller* controller, TouchInfo* touch) {
// }
void ScrollableText::Draw(NVGcontext* vg, Theme* theme) {
Widget::Draw(vg, theme);
const Vec4 line_vec(30, 86, 1220, 646);
// const Vec4 banner_vec(70, line_vec.y + 20, 848.f, 208.f);
const Vec4 banner_vec(70, line_vec.y + 20, m_end_w + (110.0F), 208.f);
// only draw scrollbar if needed
if ((m_bounds[3] - m_bounds[1]) > m_clip_y) {
const auto scrollbar_size = m_clip_y;
const auto max_index = (m_bounds[3] - m_bounds[1]) / m_step;
const auto sb_h = 1.f / max_index * scrollbar_size;
const auto in_clip = m_clip_y / m_step - 1;
const auto sb_y = m_index;
gfx::drawRect(vg, banner_vec.w, m_y_off_base, 10, scrollbar_size, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND));
gfx::drawRect(vg, banner_vec.w+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->GetColour(ThemeEntryID_SCROLLBAR));
}
nvgSave(vg);
nvgIntersectScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip
nvgTextLineHeight(App::GetVg(), 1.7);
gfx::drawTextBox(vg, banner_vec.x + 40, m_y_off, m_font_size, m_bounds[2] - m_bounds[0], theme->GetColour(ThemeEntryID_TEXT), m_text.c_str());
nvgRestore(vg);
}
} // namespace sphaira::ui