aboutsummaryrefslogtreecommitdiff
path: root/src/game/components/statusline.cpp
blob: aac1c277e63c26ea2dd2ce75c094cbd68c056ba9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include "statusline.hpp"

#include <fmt/color.h>
#include <utility>

#include "engine/data/vector2.hpp"
#include "interfaces/matrix.hpp"
#include "util/ranges.hpp"
#include "util/ranges_impl.hpp"

StatusLine::StatusLine(std::shared_ptr<ComponentMatrix> 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<ComponentMatrix> &
{
	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 -> std::uint32_t
{
	return static_cast<std::uint32_t>(fmt::color::white);
}

auto StatusLine::get_background_color() const noexcept -> std::uint32_t
{
	return STATUSLINE_COLOR;
}

void StatusLine::set_section_status(
	StatusLineSection section,
	const std::string_view &status,
	std::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<std::int32_t>(_component_matrix->get_column_cnt());

	const auto section_length = _section_lengths[section];

	const auto status_len = static_cast<std::int32_t>(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<std::uint32_t>(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, std::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 -> std::int32_t
{
	std::int32_t section_start = 0;

	auto section_index = static_cast<std::int32_t>(section);

	while (section_index > 0)
	{
		const auto prev_section = static_cast<StatusLineSection>(section_index - 1);

		section_start += static_cast<std::int32_t>(_section_lengths.at(prev_section));

		section_index--;
	}

	return section_start;
}

void StatusLine::_clear_section(StatusLineSection section, std::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();
	}
}