68 _cursor_pos = std::min(_cursor_pos, value.size());
80 _cursor_pos = value.size();
84 value.insert(_cursor_pos, e.
text);
85 _cursor_pos += e.
text.size();
93 if (_cursor_pos > 0) {
95 const auto start = prev_char(value, _cursor_pos);
96 value.erase(start, _cursor_pos - start);
105 if (_cursor_pos < value.size()) {
106 value.erase(_cursor_pos, next_char(value, _cursor_pos) - _cursor_pos);
115 if (_cursor_pos == 0) {
118 _cursor_pos = prev_char(value, _cursor_pos);
122 if (_cursor_pos >= value.size()) {
125 _cursor_pos = next_char(value, _cursor_pos);
133 _cursor_pos = value.size();
146 constexpr float text_padding = 4.0F;
148 const auto& s = get_style(ctx);
155 if (s.border_width > 0.0F) {
157 transform, (_hovered && enabled) ? s.border_hover : s.border, s.border_width);
163 const bool had_clip = SDL_RenderClipEnabled(renderer);
164 SDL_Rect old_clip {};
166 SDL_GetRenderClipRect(renderer, &old_clip);
169 const SDL_Rect box_clip {
170 static_cast<int>(transform.position.x + text_padding),
171 static_cast<int>(transform.position.y),
172 static_cast<int>(transform.size.x - (text_padding * 2)),
173 static_cast<int>(transform.size.y),
175 SDL_Rect clip = box_clip;
176 const bool text_visible = !had_clip || SDL_GetRectIntersection(&box_clip, &old_clip, &clip);
177 SDL_SetRenderClipRect(renderer, &clip);
180 _cursor_pos = std::min(_cursor_pos, value.size());
181 float caret_offset = 0.0F;
182 if (_focused && _cursor_pos > 0 && f !=
nullptr) {
184 const std::string_view before_caret = std::string_view(value).substr(0, _cursor_pos);
190 const float visible_width = std::max(transform.size.x - (text_padding * 2) - 1.0F, 0.0F);
191 if (!_focused || value.empty() || f ==
nullptr) {
195 _scroll = std::clamp(_scroll, caret_offset - visible_width, caret_offset);
196 _scroll = std::clamp(_scroll, 0.0F, std::max(text_width - visible_width, 0.0F));
199 const float text_x = transform.position.x + text_padding - _scroll;
202 const auto& display_text = value.empty() ? placeholder : value;
203 const auto display_color = value.empty() ? s.placeholder : s.text;
205 if (text_visible && !display_text.empty() && f !=
nullptr) {
207 const float text_y = transform.position.y + ((transform.size.y - text_size.y) / 2.0F);
208 const asw::Vec2 text_pos { text_x, text_y };
214 if (text_visible && _focused && f !=
nullptr) {
215 const float cursor_x = text_x + caret_offset;
218 const float cursor_y = transform.position.y
219 + ((transform.size.y -
static_cast<float>(text_height.y)) / 2.0F);
222 { cursor_x, cursor_y +
static_cast<float>(text_height.y) }, s.caret);
226 SDL_SetRenderClipRect(renderer, had_clip ? &old_clip :
nullptr);
Shared state for the UI system.
void text(const asw::Font &font, const std::string &text, const asw::Vec2< float > &position, asw::Color color, asw::TextJustify justify=asw::TextJustify::Left)
Draw text. The position is rounded to whole pixels after justification so glyphs stay sharp....
const asw::Font & pick_font(const asw::Font &own, const Theme &theme)
The font a widget draws with: its own, or the theme font.