18 text, { std::string* text; }
STATE {
int caret_pos = 0; };
19 ATTRIBUTE(on_enter, std::function<
void()>){[] {}};
20 ATTRIBUTE(on_escape, std::function<
void()>){[] {}};
22 cydui::provide_context<TextInputContext> text_input_ctx{};
26 text_input_ctx > with_context {
34 fragment.append(build_text(*props.text).fill(
"#FFFFFF"_color));
37 const auto [x, y, w, h] = build_text(props.text->substr(0, state.caret_pos)).get_footprint();
38 fragment.draw<vg::rectangle>().x(x + w - 1_px).y(y - 3_px).w(2_px).h(h + 3_px).fill(
"#FFFFFF"_color);
43 if (ev.keysym.code == SDLK_LEFT) {
44 state.caret_pos = advance_from(state.caret_pos, -1);
45 }
else if (ev.keysym.code == SDLK_RIGHT) {
46 state.caret_pos = advance_from(state.caret_pos);
47 }
else if (ev.keysym.code == SDLK_HOME) {
49 }
else if (ev.keysym.code == SDLK_END) {
50 state.caret_pos = props.text->size();
51 }
else if (ev.keysym.code == SDLK_RETURN) {
52 component.on_enter_();
53 }
else if (ev.keysym.code == SDLK_ESCAPE) {
54 component.on_escape_();
55 }
else if (ev.keysym.code == SDLK_BACKSPACE) {
56 if (state.caret_pos ==
static_cast<int>(props.text->size())) {
57 while (!props.text->empty()) {
58 const unsigned char c = (*props.text)[props.text->size() - 1];
59 props.text->pop_back();
61 if ((c & 0x80) == 0) {
63 }
else if ((c & 0xC0) == 0x80) {
71 while (!props.text->empty() && state.caret_pos > 0) {
72 const unsigned char c = (*props.text)[state.caret_pos - 1];
73 props.text->erase(state.caret_pos - 1, 1);
75 if ((c & 0x80) == 0) {
77 }
else if ((c & 0xC0) == 0x80) {
90 if (not ev.compositing_event) {
91 if (state.caret_pos ==
static_cast<int>(props.text->size())) {
92 props.text->append(ev.text);
94 props.text->insert(state.caret_pos, ev.text);
96 state.caret_pos +=
static_cast<int>(ev.text.size());
102 int min_distance = std::numeric_limits<int>::max();
103 auto prev = build_text(props.text->substr(0, advance_from(0))).get_footprint();
105 const auto d1 = std::abs(x.value_as_base_unit() - prev.x.value_as_base_unit());
106 const auto d2 = std::abs(x.value_as_base_unit() - (prev.x.value_as_base_unit() + prev.w.value_as_base_unit()));
115 for (
int i = 2; i < static_cast<int>(props.text->size()); i = advance_from(i)) {
116 const auto curr = build_text(props.text->substr(0, i)).get_footprint();
118 const auto d1 = std::abs(x.value_as_base_unit() - (prev.x + prev.w).value_as_base_unit());
119 const auto d2 = std::abs(x.value_as_base_unit() - (curr.x + curr.w).value_as_base_unit());
120 if (d1 > min_distance && d2 > min_distance) {
124 state.caret_pos = advance_from(i, -1);
137 int advance_from(
int index,
int n = 1)
const {
140 if (((*props.text)[index] & 0xC0) == 0xC0) {
142 while (((*props.text)[index] & 0xC0) == 0x80 && index <
static_cast<int>(props.text->size())
146 index = std::min(index,
static_cast<int>(props.text->size()));
149 index = std::min(index,
static_cast<int>(props.text->size()));
154 while (((*props.text)[index - 1] & 0xC0) == 0x80 && index > 0) {
158 index = std::max(index, 0);
165 vg::text build_text(
const std::string& s)
const {
166 return vg::text{s}.x(0).y(25).font_family(
"Helvetica");