Rename "kb_focus" to just "focus" everywhere

This commit is contained in:
Emil Ernerfeldt 2021-03-09 20:55:24 +01:00
parent 3fbc07659c
commit 017d602fe5
14 changed files with 75 additions and 69 deletions

View file

@ -214,7 +214,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
* Much improved text editing, with better navigation and selection. * Much improved text editing, with better navigation and selection.
* Move focus between `TextEdit` widgets with tab and shift-tab. * Move focus between `TextEdit` widgets with tab and shift-tab.
* Undo edtis in a `TextEdit`. * Undo edtis in a `TextEdit`.
* You can now check if a `TextEdit` lost keyboard focus with `response.lost_kb_focus`. * You can now check if a `TextEdit` lost keyboard focus with `response.lost_focus`.
* Added `ui.text_edit_singleline` and `ui.text_edit_multiline`. * Added `ui.text_edit_singleline` and `ui.text_edit_multiline`.
* You can now debug why your `Ui` is unexpectedly wide with `ui.style_mut().visuals.debug_expand_width = true;` * You can now debug why your `Ui` is unexpectedly wide with `ui.style_mut().visuals.debug_expand_width = true;`

View file

@ -198,16 +198,16 @@ impl CtxRef {
if !enabled || !sense.focusable || !layer_id.allow_interaction() { if !enabled || !sense.focusable || !layer_id.allow_interaction() {
// Not interested or allowed input: // Not interested or allowed input:
self.memory().surrender_kb_focus(id); self.memory().surrender_focus(id);
return response; return response;
} }
if sense.focusable { if sense.focusable {
self.memory().interested_in_kb_focus(id); self.memory().interested_in_focus(id);
} }
if sense.click if sense.click
&& response.has_kb_focus() && response.has_focus()
&& (self.input().key_pressed(Key::Space) || self.input().key_pressed(Key::Enter)) && (self.input().key_pressed(Key::Space) || self.input().key_pressed(Key::Enter))
{ {
// Space/enter works like a primary click for e.g. selected buttons // Space/enter works like a primary click for e.g. selected buttons
@ -280,8 +280,8 @@ impl CtxRef {
response.hovered &= response.is_pointer_button_down_on; // we don't hover widgets while interacting with *other* widgets response.hovered &= response.is_pointer_button_down_on; // we don't hover widgets while interacting with *other* widgets
} }
if response.has_kb_focus() && response.clicked_elsewhere() { if response.has_focus() && response.clicked_elsewhere() {
self.memory().surrender_kb_focus(id); self.memory().surrender_focus(id);
} }
response response
@ -657,7 +657,7 @@ impl Context {
/// If `true`, egui is currently listening on text input (e.g. typing text in a [`TextEdit`]). /// If `true`, egui is currently listening on text input (e.g. typing text in a [`TextEdit`]).
pub fn wants_keyboard_input(&self) -> bool { pub fn wants_keyboard_input(&self) -> bool {
self.memory().interaction.kb_focus.focused().is_some() self.memory().interaction.focus.focused().is_some()
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -756,7 +756,7 @@ impl Context {
"keyboard focus widget: {}", "keyboard focus widget: {}",
self.memory() self.memory()
.interaction .interaction
.kb_focus .focus
.focused() .focused()
.as_ref() .as_ref()
.map(Id::short_debug_format) .map(Id::short_debug_format)

View file

@ -91,7 +91,7 @@ pub(crate) struct Interaction {
/// A widget interested in drags that has a mouse press on it. /// A widget interested in drags that has a mouse press on it.
pub drag_id: Option<Id>, pub drag_id: Option<Id>,
pub kb_focus: KbFocus, pub focus: Focus,
/// HACK: windows have low priority on dragging. /// HACK: windows have low priority on dragging.
/// This is so that if you drag a slider in a window, /// This is so that if you drag a slider in a window,
@ -111,7 +111,7 @@ pub(crate) struct Interaction {
/// Keeps tracks of what widget has keyboard focus /// Keeps tracks of what widget has keyboard focus
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub(crate) struct KbFocus { pub(crate) struct Focus {
/// The widget with keyboard focus (i.e. a text input field). /// The widget with keyboard focus (i.e. a text input field).
id: Option<Id>, id: Option<Id>,
@ -121,11 +121,11 @@ pub(crate) struct KbFocus {
/// Give focus to this widget next frame /// Give focus to this widget next frame
id_next_frame: Option<Id>, id_next_frame: Option<Id>,
/// If set, the next widget that is interested in kb_focus will automatically get it. /// If set, the next widget that is interested in focus will automatically get it.
/// Probably because the user pressed Tab. /// Probably because the user pressed Tab.
give_to_next: bool, give_to_next: bool,
/// The last widget interested in kb focus. /// The last widget interested in focus.
last_interested: Option<Id>, last_interested: Option<Id>,
/// Set at the beginning of the frame, set to `false` when "used". /// Set at the beginning of the frame, set to `false` when "used".
@ -158,11 +158,11 @@ impl Interaction {
self.drag_id = None; self.drag_id = None;
} }
self.kb_focus.begin_frame(new_input); self.focus.begin_frame(new_input);
} }
} }
impl KbFocus { impl Focus {
/// Which widget currently has keyboard focus? /// Which widget currently has keyboard focus?
pub fn focused(&self) -> Option<Id> { pub fn focused(&self) -> Option<Id> {
self.id self.id
@ -206,22 +206,22 @@ impl KbFocus {
pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap<Id, Pos2>) { pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap<Id, Pos2>) {
if let Some(id) = self.id { if let Some(id) = self.id {
// Allow calling `request_kb_focus` one frame and not using it until next frame // Allow calling `request_focus` one frame and not using it until next frame
let recently_gained_kb_focus = self.id_previous_frame != Some(id); let recently_gained_focus = self.id_previous_frame != Some(id);
if !recently_gained_kb_focus && !used_ids.contains_key(&id) { if !recently_gained_focus && !used_ids.contains_key(&id) {
// Dead-mans-switch: the widget with kb focus has disappeared! // Dead-mans-switch: the widget with focus has disappeared!
self.id = None; self.id = None;
} }
} }
} }
pub(crate) fn had_kb_focus_last_frame(&self, id: Id) -> bool { pub(crate) fn had_focus_last_frame(&self, id: Id) -> bool {
self.id_previous_frame == Some(id) self.id_previous_frame == Some(id)
} }
fn interested_in_kb_focus(&mut self, id: Id) { fn interested_in_focus(&mut self, id: Id) {
if self.give_to_next && !self.had_kb_focus_last_frame(id) { if self.give_to_next && !self.had_focus_last_frame(id) {
self.id = Some(id); self.id = Some(id);
self.give_to_next = false; self.give_to_next = false;
} else if self.id == Some(id) { } else if self.id == Some(id) {
@ -261,7 +261,7 @@ impl Memory {
used_ids: &epaint::ahash::AHashMap<Id, Pos2>, used_ids: &epaint::ahash::AHashMap<Id, Pos2>,
) { ) {
self.areas.end_frame(); self.areas.end_frame();
self.interaction.kb_focus.end_frame(used_ids); self.interaction.focus.end_frame(used_ids);
self.drag_value.end_frame(input); self.drag_value.end_frame(input);
} }
@ -269,43 +269,44 @@ impl Memory {
self.areas.layer_id_at(pos, resize_interact_radius_side) self.areas.layer_id_at(pos, resize_interact_radius_side)
} }
pub(crate) fn had_kb_focus_last_frame(&self, id: Id) -> bool { pub(crate) fn had_focus_last_frame(&self, id: Id) -> bool {
self.interaction.kb_focus.id_previous_frame == Some(id) self.interaction.focus.id_previous_frame == Some(id)
} }
/// True if the given widget had keyboard focus last frame, but not this one. /// True if the given widget had keyboard focus last frame, but not this one.
pub fn lost_kb_focus(&self, id: Id) -> bool { pub(crate) fn lost_focus(&self, id: Id) -> bool {
self.had_kb_focus_last_frame(id) && !self.has_kb_focus(id) self.had_focus_last_frame(id) && !self.has_focus(id)
} }
/// True if the given widget has keyboard focus this frame, but didn't last frame. /// True if the given widget has keyboard focus this frame, but didn't last frame.
pub fn gained_kb_focus(&self, id: Id) -> bool { pub(crate) fn gained_focus(&self, id: Id) -> bool {
!self.had_kb_focus_last_frame(id) && self.has_kb_focus(id) !self.had_focus_last_frame(id) && self.has_focus(id)
} }
pub fn has_kb_focus(&self, id: Id) -> bool { pub(crate) fn has_focus(&self, id: Id) -> bool {
self.interaction.kb_focus.id == Some(id) self.interaction.focus.id == Some(id)
} }
pub fn request_kb_focus(&mut self, id: Id) { /// Give keyboard focus to a specific widget
self.interaction.kb_focus.id = Some(id); pub fn request_focus(&mut self, id: Id) {
self.interaction.focus.id = Some(id);
} }
pub fn surrender_kb_focus(&mut self, id: Id) { pub fn surrender_focus(&mut self, id: Id) {
if self.interaction.kb_focus.id == Some(id) { if self.interaction.focus.id == Some(id) {
self.interaction.kb_focus.id = None; self.interaction.focus.id = None;
} }
} }
/// Register this widget as being interested in getting keyboard focus. /// Register this widget as being interested in getting keyboard focus.
/// This will allow the user to select it with tab and shift-tab. /// This will allow the user to select it with tab and shift-tab.
pub fn interested_in_kb_focus(&mut self, id: Id) { pub(crate) fn interested_in_focus(&mut self, id: Id) {
self.interaction.kb_focus.interested_in_kb_focus(id); self.interaction.focus.interested_in_focus(id);
} }
/// Stop editing of active `TextEdit` (if any). /// Stop editing of active `TextEdit` (if any).
pub fn stop_text_input(&mut self) { pub fn stop_text_input(&mut self) {
self.interaction.kb_focus.id = None; self.interaction.focus.id = None;
} }
pub fn is_anything_being_dragged(&self) -> bool { pub fn is_anything_being_dragged(&self) -> bool {

View file

@ -151,13 +151,13 @@ impl Response {
} }
/// This widget has the keyboard focus (i.e. is receiving key presses). /// This widget has the keyboard focus (i.e. is receiving key presses).
pub fn has_kb_focus(&self) -> bool { pub fn has_focus(&self) -> bool {
self.ctx.memory().has_kb_focus(self.id) self.ctx.memory().has_focus(self.id)
} }
/// True if this widget has keyboard focus this frame, but didn't last frame. /// True if this widget has keyboard focus this frame, but didn't last frame.
pub fn gained_kb_focus(&self) -> bool { pub fn gained_focus(&self) -> bool {
self.ctx.memory().gained_kb_focus(self.id) self.ctx.memory().gained_focus(self.id)
} }
/// The widget had keyboard focus and lost it, /// The widget had keyboard focus and lost it,
@ -169,12 +169,17 @@ impl Response {
/// # let mut ui = egui::Ui::__test(); /// # let mut ui = egui::Ui::__test();
/// # let mut my_text = String::new(); /// # let mut my_text = String::new();
/// # fn do_request(_: &str) {} /// # fn do_request(_: &str) {}
/// if ui.text_edit_singleline(&mut my_text).lost_kb_focus() { /// if ui.text_edit_singleline(&mut my_text).lost_focus() {
/// do_request(&my_text); /// do_request(&my_text);
/// } /// }
/// ``` /// ```
pub fn lost_focus(&self) -> bool {
self.ctx.memory().lost_focus(self.id)
}
#[deprecated = "Renamed to lost_focus()"]
pub fn lost_kb_focus(&self) -> bool { pub fn lost_kb_focus(&self) -> bool {
self.ctx.memory().lost_kb_focus(self.id) self.lost_focus()
} }
/// The widgets is being dragged. /// The widgets is being dragged.
@ -340,7 +345,7 @@ impl Response {
/// ///
/// Call after interacting and potential calls to [`Self::mark_changed`]. /// Call after interacting and potential calls to [`Self::mark_changed`].
pub fn widget_info(&self, make_info: impl Fn() -> crate::WidgetInfo) { pub fn widget_info(&self, make_info: impl Fn() -> crate::WidgetInfo) {
if self.gained_kb_focus() { if self.gained_focus() {
use crate::output::{OutputEvent, WidgetEvent}; use crate::output::{OutputEvent, WidgetEvent};
let widget_info = make_info(); let widget_info = make_info();
let event = OutputEvent::WidgetEvent(WidgetEvent::Focus, widget_info); let event = OutputEvent::WidgetEvent(WidgetEvent::Focus, widget_info);

View file

@ -243,7 +243,7 @@ pub struct Widgets {
impl Widgets { impl Widgets {
pub fn style(&self, response: &Response) -> &WidgetVisuals { pub fn style(&self, response: &Response) -> &WidgetVisuals {
if response.is_pointer_button_down_on() || response.has_kb_focus() { if response.is_pointer_button_down_on() || response.has_focus() {
&self.active &self.active
} else if response.hovered() { } else if response.hovered() {
&self.hovered &self.hovered

View file

@ -840,7 +840,7 @@ impl Ui {
self.text_edit_multiline(text) self.text_edit_multiline(text)
} }
/// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_kb_focus`). /// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_focus`).
/// ///
/// Se also [`TextEdit`]. /// Se also [`TextEdit`].
pub fn text_edit_singleline(&mut self, text: &mut String) -> Response { pub fn text_edit_singleline(&mut self, text: &mut String) -> Response {

View file

@ -12,7 +12,7 @@ pub(crate) struct MonoState {
last_dragged_id: Option<Id>, last_dragged_id: Option<Id>,
last_dragged_value: Option<f64>, last_dragged_value: Option<f64>,
/// For temporary edit of a `DragValue` value. /// For temporary edit of a `DragValue` value.
/// Couples with [`Interaction::kb_focus_id`]. /// Couples with the current focus id.
edit_string: Option<String>, edit_string: Option<String>,
} }
@ -208,7 +208,7 @@ impl<'a> Widget for DragValue<'a> {
}; };
let kb_edit_id = ui.auto_id_with("edit"); let kb_edit_id = ui.auto_id_with("edit");
let is_kb_editing = ui.memory().has_kb_focus(kb_edit_id); let is_kb_editing = ui.memory().has_focus(kb_edit_id);
let mut response = if is_kb_editing { let mut response = if is_kb_editing {
let button_width = ui.spacing().interact_size.x; let button_width = ui.spacing().interact_size.x;
@ -229,7 +229,7 @@ impl<'a> Widget for DragValue<'a> {
set(&mut get_set_value, parsed_value) set(&mut get_set_value, parsed_value)
} }
if ui.input().key_pressed(Key::Enter) { if ui.input().key_pressed(Key::Enter) {
ui.memory().surrender_kb_focus(kb_edit_id); ui.memory().surrender_focus(kb_edit_id);
ui.memory().drag_value.edit_string = None; ui.memory().drag_value.edit_string = None;
} else { } else {
ui.memory().drag_value.edit_string = Some(value_text); ui.memory().drag_value.edit_string = Some(value_text);
@ -248,7 +248,7 @@ impl<'a> Widget for DragValue<'a> {
)); ));
if response.clicked() { if response.clicked() {
ui.memory().request_kb_focus(kb_edit_id); ui.memory().request_focus(kb_edit_id);
ui.memory().drag_value.edit_string = None; // Filled in next frame ui.memory().drag_value.edit_string = None; // Filled in next frame
} else if response.dragged() { } else if response.dragged() {
let mdelta = response.drag_delta(); let mdelta = response.drag_delta();
@ -281,7 +281,7 @@ impl<'a> Widget for DragValue<'a> {
drag_state.last_dragged_value = Some(stored_value); drag_state.last_dragged_value = Some(stored_value);
ui.memory().drag_value = drag_state; ui.memory().drag_value = drag_state;
} }
} else if response.has_kb_focus() { } else if response.has_focus() {
let change = ui.input().num_presses(Key::ArrowUp) as f64 let change = ui.input().num_presses(Key::ArrowUp) as f64
+ ui.input().num_presses(Key::ArrowRight) as f64 + ui.input().num_presses(Key::ArrowRight) as f64
- ui.input().num_presses(Key::ArrowDown) as f64 - ui.input().num_presses(Key::ArrowDown) as f64

View file

@ -69,7 +69,7 @@ impl Widget for Hyperlink {
let color = ui.visuals().hyperlink_color; let color = ui.visuals().hyperlink_color;
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
if response.hovered() || response.has_kb_focus() { if response.hovered() || response.has_focus() {
// Underline: // Underline:
for row in &galley.rows { for row in &galley.rows {
let rect = row.rect().translate(rect.min.to_vec2()); let rect = row.rect().translate(rect.min.to_vec2());

View file

@ -159,10 +159,10 @@ impl Label {
// This should be the easiest method of putting text anywhere. // This should be the easiest method of putting text anywhere.
pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Galley) { pub fn paint_galley(&self, ui: &mut Ui, pos: Pos2, galley: Galley) {
self.paint_galley_kb_focus(ui, pos, galley, false) self.paint_galley_focus(ui, pos, galley, false)
} }
fn paint_galley_kb_focus(&self, ui: &mut Ui, pos: Pos2, galley: Galley, kb_focus: bool) { fn paint_galley_focus(&self, ui: &mut Ui, pos: Pos2, galley: Galley, focus: bool) {
let Self { let Self {
mut background_color, mut background_color,
code, code,
@ -174,7 +174,7 @@ impl Label {
.. ..
} = *self; } = *self;
let underline = underline || kb_focus; let underline = underline || focus;
let text_color = if let Some(text_color) = self.text_color { let text_color = if let Some(text_color) = self.text_color {
text_color text_color
@ -287,13 +287,13 @@ impl Widget for Label {
response |= ui.interact(rect, id, sense); response |= ui.interact(rect, id, sense);
} }
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text)); response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
self.paint_galley_kb_focus(ui, pos, galley, response.has_kb_focus()); self.paint_galley_focus(ui, pos, galley, response.has_focus());
response response
} else { } else {
let galley = self.layout(ui); let galley = self.layout(ui);
let (rect, response) = ui.allocate_exact_size(galley.size, sense); let (rect, response) = ui.allocate_exact_size(galley.size, sense);
response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text)); response.widget_info(|| WidgetInfo::labeled(WidgetType::Label, &galley.text));
self.paint_galley_kb_focus(ui, rect.min, galley, response.has_kb_focus()); self.paint_galley_focus(ui, rect.min, galley, response.has_focus());
response response
} }
} }

View file

@ -66,7 +66,7 @@ impl Widget for SelectableLabel {
let visuals = ui.style().interact_selectable(&response, selected); let visuals = ui.style().interact_selectable(&response, selected);
if selected || response.hovered() || response.has_kb_focus() { if selected || response.hovered() || response.has_focus() {
let rect = rect.expand(visuals.expansion); let rect = rect.expand(visuals.expansion);
let corner_radius = 2.0; let corner_radius = 2.0;

View file

@ -325,7 +325,7 @@ impl<'a> Slider<'a> {
let value = self.get_value(); let value = self.get_value();
response.widget_info(|| WidgetInfo::slider(value, &self.text)); response.widget_info(|| WidgetInfo::slider(value, &self.text));
if response.has_kb_focus() { if response.has_focus() {
let kb_step = ui.input().num_presses(Key::ArrowRight) as f32 let kb_step = ui.input().num_presses(Key::ArrowRight) as f32
- ui.input().num_presses(Key::ArrowLeft) as f32; - ui.input().num_presses(Key::ArrowLeft) as f32;

View file

@ -114,7 +114,7 @@ impl CCursorPair {
/// # let mut ui = egui::Ui::__test(); /// # let mut ui = egui::Ui::__test();
/// # let mut my_string = String::new(); /// # let mut my_string = String::new();
/// let response = ui.add(egui::TextEdit::singleline(&mut my_string)); /// let response = ui.add(egui::TextEdit::singleline(&mut my_string));
/// if response.lost_kb_focus() { /// if response.lost_focus() {
/// // use my_string /// // use my_string
/// } /// }
/// ``` /// ```
@ -140,7 +140,7 @@ impl<'t> TextEdit<'t> {
Self::multiline(text) Self::multiline(text)
} }
/// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_kb_focus`). /// Now newlines (`\n`) allowed. Pressing enter key will result in the `TextEdit` loosing focus (`response.lost_focus`).
pub fn singleline(text: &'t mut String) -> Self { pub fn singleline(text: &'t mut String) -> Self {
TextEdit { TextEdit {
text, text,
@ -248,7 +248,7 @@ impl<'t> Widget for TextEdit<'t> {
if frame { if frame {
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
let frame_rect = response.rect.expand(visuals.expansion); let frame_rect = response.rect.expand(visuals.expansion);
let shape = if response.has_kb_focus() { let shape = if response.has_focus() {
Shape::Rect { Shape::Rect {
rect: frame_rect, rect: frame_rect,
corner_radius: visuals.corner_radius, corner_radius: visuals.corner_radius,
@ -347,7 +347,7 @@ impl<'t> TextEdit<'t> {
}); });
response.mark_changed(); response.mark_changed();
} else if response.hovered() && ui.input().pointer.any_pressed() { } else if response.hovered() && ui.input().pointer.any_pressed() {
ui.memory().request_kb_focus(id); ui.memory().request_focus(id);
if ui.input().modifiers.shift { if ui.input().modifiers.shift {
if let Some(cursorp) = &mut state.cursorp { if let Some(cursorp) = &mut state.cursorp {
cursorp.primary = cursor_at_pointer; cursorp.primary = cursor_at_pointer;
@ -371,7 +371,7 @@ impl<'t> TextEdit<'t> {
ui.output().cursor_icon = CursorIcon::Text; ui.output().cursor_icon = CursorIcon::Text;
} }
if ui.memory().has_kb_focus(id) && enabled { if ui.memory().has_focus(id) && enabled {
let mut cursorp = state let mut cursorp = state
.cursorp .cursorp
.map(|cursorp| { .map(|cursorp| {
@ -437,7 +437,7 @@ impl<'t> TextEdit<'t> {
insert_text(&mut ccursor, text, "\n"); insert_text(&mut ccursor, text, "\n");
Some(CCursorPair::one(ccursor)) Some(CCursorPair::one(ccursor))
} else { } else {
ui.memory().surrender_kb_focus(id); // End input with enter ui.memory().surrender_focus(id); // End input with enter
break; break;
} }
} }
@ -491,7 +491,7 @@ impl<'t> TextEdit<'t> {
.feed_state(ui.input().time, &(cursorp.as_ccursorp(), text.clone())); .feed_state(ui.input().time, &(cursorp.as_ccursorp(), text.clone()));
} }
if ui.memory().has_kb_focus(id) { if ui.memory().has_focus(id) {
if let Some(cursorp) = state.cursorp { if let Some(cursorp) = state.cursorp {
paint_cursor_selection(ui, response.rect.min, &galley, &cursorp); paint_cursor_selection(ui, response.rect.min, &galley, &cursorp);
paint_cursor_end(ui, response.rect.min, &galley, &cursorp.primary); paint_cursor_end(ui, response.rect.min, &galley, &cursorp.primary);

View file

@ -125,7 +125,7 @@ impl Widgets {
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("Single line text input:"); ui.label("Single line text input:");
let response = ui.text_edit_singleline(&mut self.single_line_text_input); let response = ui.text_edit_singleline(&mut self.single_line_text_input);
if response.lost_kb_focus() { if response.lost_focus() {
// The user pressed enter. // The user pressed enter.
} }
}); });

View file

@ -113,7 +113,7 @@ fn ui_url(ui: &mut egui::Ui, frame: &mut epi::Frame<'_>, url: &mut String) -> Op
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.label("URL:"); ui.label("URL:");
trigger_fetch |= ui.text_edit_singleline(url).lost_kb_focus(); trigger_fetch |= ui.text_edit_singleline(url).lost_focus();
trigger_fetch |= ui.button("GET").clicked(); trigger_fetch |= ui.button("GET").clicked();
}); });