diff --git a/TODO.md b/TODO.md index 78cb53b8..3b380942 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,8 @@ TODO-list for the Egui project. If you looking for something to do, look here. ## Top priority -* Refactor graphics layers and areas so one don't have to register LayerId:s. +* Egui-web copy-paste +* Egui-web fetch ## Other @@ -13,14 +14,6 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [ ] Tooltip widget: Something that looks like this: (?) :that shows text on hover. * [ ] ui.info_button().on_hover_text("More info here"); * [ ] Allow adding multiple tooltips to the same widget, showing them all one after the other. - * [ ] Text input - * [x] Input - * [x] Text focus - * [x] Cursor movement - * [x] Text selection - * [x] Clipboard copy/paste - * [ ] Text edit undo - * [ ] Move focus with tab * [ ] Vertical slider * [/] Color picker * [x] linear rgb <-> sRGB @@ -32,21 +25,13 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [ ] Additive blending aware color picker * [ ] Premultiplied alpha is a bit of a pain in the ass. Maybe rethink this a bit. * [ ] Hue wheel -* Containers - * [ ] Scroll areas - * [x] Vertical scrolling - * [x] Scroll-wheel input - * [x] Drag background to scroll - * [x] Kinetic scrolling - * [ ] Horizontal scrolling * Input * [x] Distinguish between clicks and drags * [x] Double-click * [x] Text - * [x] Get modifier keys + * [x] Modifier keys * [ ] Support all mouse buttons * [ ] Distinguish between touch input and mouse input - * [ ] Keyboard shortcuts (copy, paste, undo, select-all, ...?) * Text * [/] Unicode * [x] Shared mutable expanding texture map @@ -91,26 +76,14 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [ ] Ask Egui if an event requires repainting * [ ] Only repaint when mouse is over a Egui window (or is pressed and there is an active widget) -## Backends - -* [ ] Extract egui_app as egui_backend - -* egui_glium -* egui_web - * [ ] async HTTP requests -* [ ] egui_bitmap: slow reference rasterizer for tests - * Port https://github.com/emilk/imgui_software_renderer - * Less important: fast rasterizer for embedded 🤷‍♀️ -* [ ] egui_terminal (think ncurses) - * [ ] replace `round_to_pixel` with `round_to_X` where user can select X to be e.g. width of a letter -* [ ] egui_svg: No idea what this would be for :) +## Integrations ### egui_web - * [x] Scroll input * [x] Change to resize cursor on hover * [x] Port most code to Rust * [x] Read url fragment and redirect to a subpage (e.g. different examples apps)] +* [ ] Copy/paste support * [ ] Async HTTP requests * [ ] Fix WebGL colors/blending (try EXT_sRGB) * [ ] Embeddability @@ -121,6 +94,17 @@ TODO-list for the Egui project. If you looking for something to do, look here. * Different Egui instances, same app * Allows very nice web integration +### Other + +* [ ] Extract egui::app as own library (egui_framework ?) +* [ ] egui_bitmap: slow reference rasterizer for tests + * Port https://github.com/emilk/imgui_software_renderer + * Less important: fast rasterizer for embedded 🤷‍♀️ +* [ ] egui_terminal (think ncurses) + * [ ] replace `round_to_pixel` with `round_to_X` where user can select X to be e.g. width of a letter +* [ ] egui_svg: No idea what this would be for :) + + ## Modularity * [x] `trait Widget` (`Label`, `Slider`, `Checkbox`, ...) @@ -163,13 +147,24 @@ Ability to do a search for any widget. The search works even for collapsed regio * [x] Collapsing header region * [x] Tooltip * [x] Movable/resizable windows - * [x] Kinetic windows * [x] Add support for clicking hyperlinks +* [x] Text input + * [x] Input + * [x] Text focus + * [x] Cursor movement + * [x] Text selection + * [x] Clipboard copy/paste + * [x] Move focus with tab + * [x] Text edit undo * Containers * [x] Vertical slider * [x] Resize any side and corner on windows * [x] Fix autoshrink * [x] Automatic positioning of new windows + * [x] Vertical scroll areas + * [x] Scroll-wheel input + * [x] Drag background to scroll + * [x] Kinetic scrolling * Simple animations * Clip rects * [x] Separate Ui::clip_rect from Ui::rect diff --git a/egui/src/context.rs b/egui/src/context.rs index afa2055d..41bfc6ea 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -205,7 +205,7 @@ impl Context { } fn begin_frame_mut(&mut self, new_raw_input: RawInput) { - self.memory().begin_frame(&self.input); + self.memory().begin_frame(&self.input, &new_raw_input); self.input = std::mem::take(&mut self.input).begin_frame(new_raw_input); *self.available_rect.lock() = Some(self.input.screen_rect()); diff --git a/egui/src/memory.rs b/egui/src/memory.rs index a1dcafcd..993848d5 100644 --- a/egui/src/memory.rs +++ b/egui/src/memory.rs @@ -83,6 +83,18 @@ pub(crate) struct Interaction { /// What had keyboard focus previous frame? pub kb_focus_id_previous_frame: Option, + /// If set, the next widget that is interested in kb_focus will automatically get it. + /// Probably because the user pressed Tab. + pub kb_focus_give_to_next: bool, + + /// The last widget interested in kb focus. + pub kb_focus_last_interested: Option, + + /// Set at the beginning of the frame, set to `false` when "used". + pressed_tab: bool, + /// Set at the beginning of the frame, set to `false` when "used". + pressed_shift_tab: bool, + /// HACK: windows have low priority on dragging. /// This is so that if you drag a slider in a window, /// the slider will steal the drag away from the window. @@ -104,7 +116,11 @@ impl Interaction { self.click_id.is_some() || self.drag_id.is_some() } - fn begin_frame(&mut self, prev_input: &crate::input::InputState) { + fn begin_frame( + &mut self, + prev_input: &crate::input::InputState, + new_input: &crate::input::RawInput, + ) { self.kb_focus_id_previous_frame = self.kb_focus_id; self.click_interest = false; self.drag_interest = false; @@ -118,13 +134,34 @@ impl Interaction { self.click_id = None; self.drag_id = None; } + + self.pressed_tab = false; + self.pressed_shift_tab = false; + for event in &new_input.events { + if let crate::input::Event::Key { + key: crate::input::Key::Tab, + pressed: true, + modifiers, + } = event + { + if modifiers.shift { + self.pressed_shift_tab = true; + } else { + self.pressed_tab = true; + } + } + } } } impl Memory { - pub(crate) fn begin_frame(&mut self, prev_input: &crate::input::InputState) { + pub(crate) fn begin_frame( + &mut self, + prev_input: &crate::input::InputState, + new_input: &crate::input::RawInput, + ) { self.used_ids.clear(); - self.interaction.begin_frame(prev_input); + self.interaction.begin_frame(prev_input, new_input); if !prev_input.mouse.down { self.window_interaction = None; @@ -169,6 +206,26 @@ impl Memory { } } + /// Register this widget as being interested in getting keyboard focus. + /// This will allow the user to select it with tab and shift-tab. + pub fn interested_in_kb_focus(&mut self, id: Id) { + if self.interaction.kb_focus_give_to_next { + self.interaction.kb_focus_id = Some(id); + self.interaction.kb_focus_give_to_next = false; + } else if self.has_kb_focus(id) { + if self.interaction.pressed_tab { + self.interaction.kb_focus_id = None; + self.interaction.kb_focus_give_to_next = true; + self.interaction.pressed_tab = false; + } else if self.interaction.pressed_shift_tab { + self.interaction.kb_focus_id = self.interaction.kb_focus_last_interested; + self.interaction.pressed_shift_tab = false; + } + } + + self.interaction.kb_focus_last_interested = Some(id); + } + /// Stop editing of active `TextEdit` (if any). pub fn stop_text_input(&mut self) { self.interaction.kb_focus_id = None; diff --git a/egui/src/widgets/text_edit.rs b/egui/src/widgets/text_edit.rs index 2a8378e4..bf50aae6 100644 --- a/egui/src/widgets/text_edit.rs +++ b/egui/src/widgets/text_edit.rs @@ -252,6 +252,10 @@ impl<'t> Widget for TextEdit<'t> { }; let response = ui.interact(rect, id, sense); + if enabled { + ui.memory().interested_in_kb_focus(id); + } + if enabled { if let Some(mouse_pos) = ui.input().mouse.pos { // TODO: triple-click to select whole paragraph