suggestion
Wraps a textEntry to provide an attached menu (dropdown) of choices.
Use after TextEntryWidget handles events, so don't call TextEntryWidget.processEvents().
Only valid between Window.beginand Window.end.
Parameters
- te:*TextEntryWidget
- *TextEntryWidget
- init_opts:SuggestionInitOptions
- SuggestionInitOptions
Source
Implementation
pub fn suggestion(te: *TextEntryWidget, init_opts: SuggestionInitOptions) *SuggestionWidget {
var button_clicked = false;
const src = @src();
const button_id = dvui.parentGet().extendId(src, 0);
if (init_opts.button) {
if (dvui.buttonIcon(
src,
"combobox_triangle",
entypo.chevron_small_down,
.{},
.{},
.{ .expand = .ratio, .margin = dvui.Rect.all(2), .gravity_x = 1.0, .tab_index = 0 },
)) {
button_clicked = true;
}
if (button_id == dvui.focusedWidgetIdInCurrentSubwindow()) {
dvui.focusWidget(te.data().id, null, null);
}
}
const min_width = te.textLayout.data().backgroundRect().w;
var sug = widgetAlloc(SuggestionWidget);
sug.init(@src(), .{
.rs = te.data().borderRectScale(),
.text_entry_id = te.data().id,
}, .{ .label = .{ .text = te.getText() }, .min_size_content = .{ .w = min_width }, .padding = .{}, .border = te.data().options.borderGet() });
if (button_clicked) {
if (sug.willOpen()) sug.close() else sug.open();
}
// process events from textEntry
const evts = dvui.events();
for (evts) |*e| {
if (!te.matchEvent(e)) {
continue;
}
if (e.evt == .key and (e.evt.key.action == .down or e.evt.key.action == .repeat)) {
switch (e.evt.key.code) {
.up => {
e.handle(@src(), sug.menu.data());
if (sug.willOpen()) {
sug.selected_index -|= 1;
} else {
sug.open();
}
},
.down => {
e.handle(@src(), sug.menu.data());
if (sug.willOpen()) {
sug.selected_index += 1;
} else {
sug.open();
}
},
.escape => {
e.handle(@src(), sug.menu.data());
sug.close();
},
.enter => {
if (sug.willOpen()) {
e.handle(@src(), sug.menu.data());
sug.activate_selected = true;
}
},
else => {
if (sug.willOpen() and e.evt.key.action == .down) {
if (e.evt.key.matchBind("next_widget")) {
e.handle(@src(), sug.menu.data());
sug.close();
} else if (e.evt.key.matchBind("prev_widget")) {
e.handle(@src(), sug.menu.data());
sug.close();
}
}
},
}
}
if (!e.handled) {
te.processEvent(e);
}
}
if (init_opts.open_on_text_change and te.text_changed) {
sug.open();
}
const focused_now = dvui.focusedWidgetIdInCurrentSubwindow() == te.data().id;
if (init_opts.open_on_focus) {
const focused_last_frame = dvui.dataGet(null, te.data().id, "_focused_last_frame", bool) orelse false;
if (!focused_last_frame and focused_now) {
sug.open();
}
dvui.dataSet(null, te.data().id, "_focused_last_frame", focused_now);
}
if (!focused_now) {
sug.close();
}
return sug;
}