#include "statusline.hpp" #include "engine/data/bounds.hpp" #include "engine/data/vector2.hpp" #include "util/color.hpp" #include "util/ranges.hpp" #include #include StatusLine::StatusLine(std::shared_ptr component_matrix) noexcept : _component_matrix(std::move(component_matrix)), _need_render(false) { _component_matrix->fill(ComponentElement({.value = ' '})); } auto StatusLine::get() const noexcept -> const std::shared_ptr & { return _component_matrix; } auto StatusLine::get_need_render() const noexcept -> bool { return _need_render; } void StatusLine::set_need_render(bool need_render) noexcept { _need_render = need_render; } auto StatusLine::get_foreground_color() const noexcept -> uint32_t { return static_cast(fmt::color::white); } auto StatusLine::get_background_color() const noexcept -> uint32_t { return STATUSLINE_COLOR; } void StatusLine::set_section_status( StatusLineSection section, const std::string_view &status, int32_t start) noexcept { if (status.length() == 0U) { return; } _clear_section(section, start); auto section_start = _get_section_start_x(section); auto pos = Vector2({.x = section_start + start, .y = 0}); const auto column_cnt = static_cast(_component_matrix->get_column_cnt()); const auto section_length = _section_lengths[section]; const auto status_len = static_cast(status.length()); const auto section_style = _section_styles.contains(section) ? _section_styles.at(section) : Style(); auto is_style_applied = false; if (section_style.padding_left > 0U) { auto padding_remaining = section_style.padding_left; _component_matrix->set(pos, {.value = ' ', .style = section_style}); padding_remaining--; for (auto index : IotaView(0U, padding_remaining)) { pos += Vector2::right(); _component_matrix->set(pos, {.value = ' '}); } is_style_applied = true; } pos += Vector2::right(); auto status_offset_start = 0U; // Apply the section style to the first status character if it hasn't // already been applied if (!is_style_applied) { _component_matrix->set(pos, {.value = status[0], .style = section_style}); status_offset_start++; pos += Vector2::right(); is_style_applied = true; } const auto final_status_length = status_len <= section_length ? status_len : section_length; _matrix_write_string( pos, status.substr(status_offset_start, static_cast(final_status_length))); pos = pos.to_direction(Vector2::right(), final_status_length); for (auto index : IotaView(0U, section_style.padding_right)) { _component_matrix->set(pos, {.value = ' '}); pos += Vector2::right(); } _component_matrix->set(pos, {.value = ' ', .style = {.reset_before = true}}); set_need_render(true); } void StatusLine::set_section_length(StatusLineSection section, int32_t length) noexcept { _section_lengths[section] = length; } void StatusLine::set_section_style(StatusLineSection section, const Style &style) noexcept { _section_styles[section] = style; } void StatusLine::_matrix_write_string( const Vector2 &position, const std::string_view &str) noexcept { auto working_pos = position; for (const auto &character : str) { _component_matrix->set(working_pos, {.value = character}); working_pos += Vector2::right(); } } auto StatusLine::_get_section_start_x(StatusLineSection section) const noexcept -> int32_t { int32_t section_start = 0; auto section_index = static_cast(section); while (section_index > 0) { const auto prev_section = static_cast(section_index - 1); section_start += static_cast(_section_lengths.at(prev_section)); section_index--; } return section_start; } void StatusLine::_clear_section(StatusLineSection section, int32_t start) noexcept { auto section_start = _get_section_start_x(section); auto pos = Vector2({.x = section_start + start, .y = 0}); auto section_length = _section_lengths[section]; for (auto index : IotaView(0, section_length - start)) { _component_matrix->set(pos, ComponentElement({.value = ' '})); pos += Vector2::right(); } }