Clean up various small TODOs

This commit is contained in:
Emil Ernerfeldt 2020-10-01 22:40:49 +02:00
parent 6fcfb52aa0
commit 5cba44eaa8
9 changed files with 56 additions and 26 deletions

48
TODO.md
View file

@ -3,6 +3,10 @@
TODO-list for the Egui project. If you looking for something to do, look here. TODO-list for the Egui project. If you looking for something to do, look here.
* Widgets * Widgets
* [ ] Tooltips:
* [ ] Tooltip widget: Something that looks like this: (?) :that shows text on hover.
* [ ] ui.info_button().tooltip_text("More info here");
* [ ] Allow adding multiple tooltips to the same widget, showing them all one after the other.
* [ ] Text input * [ ] Text input
* [x] Input * [x] Input
* [x] Text focus * [x] Text focus
@ -37,16 +41,17 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* [ ] Get modifier keys * [ ] Get modifier keys
* [ ] Keyboard shortcuts * [ ] Keyboard shortcuts
* [ ] Copy, paste, undo, ... * [ ] Copy, paste, undo, ...
* [ ] Text * Text
* [/] Unicode * [/] Unicode
* [x] Shared mutable expanding texture map * [x] Shared mutable expanding texture map
* [ ] Text editing of unicode * [ ] Text editing of unicode
* [ ] Change text style/color and continue in same layout * [ ] Change text style/color and continue in same layout
* [ ] Menu bar (File, Edit, etc) * Menu bar (File, Edit, etc)
* [ ] Sub-menus * [ ] Sub-menus
* [ ] Keyboard shortcuts * [ ] Keyboard shortcuts
* [ ] Layout * Layout
* [x] Generalize Layout (separate from Ui) * [x] Generalize Layout (separate from Ui)
* [ ] Break out `Region` with min_size + max_size + cursor + layout
* [ ] Table with resizable columns * [ ] Table with resizable columns
* [ ] Grid layout * [ ] Grid layout
* [ ] Point list * [ ] Point list
@ -54,9 +59,6 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* [ ] Positioning preference: `window.preference(Top, Right)` * [ ] Positioning preference: `window.preference(Top, Right)`
* [ ] Keeping right/bottom on expand. Maybe cover jitteryness with quick animation? * [ ] Keeping right/bottom on expand. Maybe cover jitteryness with quick animation?
* [ ] Make auto-positioning of windows respect permanent side-bars. * [ ] Make auto-positioning of windows respect permanent side-bars.
* [x] Image support
* [x] Show user textures
* [x] API for creating a texture managed by `egui::app::Backend`
* Visuals * Visuals
* [x] Pixel-perfect painting (round positions to nearest pixel). * [x] Pixel-perfect painting (round positions to nearest pixel).
* [x] Fix `aa_size`: should be 1, currently fudged at 1.5 * [x] Fix `aa_size`: should be 1, currently fudged at 1.5
@ -66,9 +68,7 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* [x] sRGBA decode in fragment shader * [x] sRGBA decode in fragment shader
* [ ] Fix alpha blending / sRGB weirdness in WebGL (EXT_sRGB) * [ ] Fix alpha blending / sRGB weirdness in WebGL (EXT_sRGB)
* [ ] Thin circles look bad * [ ] Thin circles look bad
* [ ] Allow adding multiple tooltips to the same widget, showing them all one after the other. * [ ] Optimize small filled circles with the global texture.
* Math
* [x] Change `width.min(max_width)` to `width.at_most(max_width)`
* Id * Id
* struct TempId(u64); struct StateId(u64); * struct TempId(u64); struct StateId(u64);
* `TempId` is count-based. Only good for interaction. Can't be used for storing state. * `TempId` is count-based. Only good for interaction. Can't be used for storing state.
@ -79,14 +79,32 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* Manual layout example: * Manual layout example:
* ui.child_ui_pos(pos).label("Label at specific position"); * ui.child_ui_pos(pos).label("Label at specific position");
* ui.child_ui_rect(rect).label("Label in a rectangle"); * ui.child_ui_rect(rect).label("Label in a rectangle");
* Reactive mode
* [ ] 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)
## egui_web ## 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 :)
### egui_web
* [x] Scroll input * [x] Scroll input
* [x] Change to resize cursor on hover * [x] Change to resize cursor on hover
* [x] Port most code to Rust * [x] Port most code to Rust
* [x] Read url fragment and redirect to a subpage (e.g. different examples apps)] * [x] Read url fragment and redirect to a subpage (e.g. different examples apps)]
* [ ] Fix WebGL colors/beldning (try EXT_sRGB) * [ ] Async HTTP requests
* [ ] Fix WebGL colors/blending (try EXT_sRGB)
* [ ] Embeddability * [ ] Embeddability
* [ ] Support canvas that does NOT cover entire screen. * [ ] Support canvas that does NOT cover entire screen.
* [ ] Support multiple eguis in one web page. * [ ] Support multiple eguis in one web page.
@ -101,7 +119,7 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* [ ] `trait Container` (`Frame`, `Resize`, `ScrollArea`, ...) * [ ] `trait Container` (`Frame`, `Resize`, `ScrollArea`, ...)
* [ ] `widget::TextButton` implemented as a `container::Button` which contains a `widget::Label`. * [ ] `widget::TextButton` implemented as a `container::Button` which contains a `widget::Label`.
* [ ] Easily chain `Container`s without nested closures. * [ ] Easily chain `Container`s without nested closures.
* e.g. `ui.containers((Frame::new(), Resize::new(), ScrollArea::new()), |ui| ...)` * e.g. `ui.wrap(Frame::new()).wrap(Resize::new()).wrap(ScrollArea::new()).show(|ui| ...)`
* [ ] Attach labels to checkboxes, radio buttons and sliders with a separate wrapper-widget ? * [ ] Attach labels to checkboxes, radio buttons and sliders with a separate wrapper-widget ?
### Refactor space allocation ### Refactor space allocation
@ -112,6 +130,8 @@ When painting a widget, you want to allocate space. On that space you sometimes
* `ui.canvas(size) -> Paint` * `ui.canvas(size) -> Paint`
* `ui.child_ui(size) -> Ui` * `ui.child_ui(size) -> Ui`
This is a good place to support whole-widget culling. If a swidget is not visible, the above functions should maybe return `None` so that the widget code can early-out.
## Other ## Other
* [x] Persist UI state in external storage * [x] Persist UI state in external storage
@ -120,6 +140,7 @@ When painting a widget, you want to allocate space. On that space you sometimes
* [ ] Build in a profiler which tracks which `Ui` in which window takes up CPU. * [ ] Build in a profiler which tracks which `Ui` in which window takes up CPU.
* [ ] Draw as flame graph * [ ] Draw as flame graph
* [ ] Draw as hotmap * [ ] Draw as hotmap
* [ ] Integrate puffin?
* [ ] Windows should open from `UI`s and be boxed by parent ui. * [ ] Windows should open from `UI`s and be boxed by parent ui.
* Then we could open the example app inside a window in the example app, recursively. * Then we could open the example app inside a window in the example app, recursively.
* [ ] Implement a minimal markdown viewer * [ ] Implement a minimal markdown viewer
@ -157,3 +178,6 @@ Ability to do a search for any widget. The search works even for collapsed regio
* [x] Use clip rectangles when interacting * [x] Use clip rectangles when interacting
* [x] Adjust clip rects so edges of child widgets aren't clipped * [x] Adjust clip rects so edges of child widgets aren't clipped
* [x] Use HW clip rects * [x] Use HW clip rects
* [x] Image support
* [x] Show user textures
* [x] API for creating a texture managed by `egui::app::Backend`

View file

@ -286,7 +286,6 @@ impl<'open> Window<'open> {
let outer_rect = frame.end(&mut area_content_ui); let outer_rect = frame.end(&mut area_content_ui);
if possible.resizable { if possible.resizable {
// TODO: draw BEHIND contents ?
paint_resize_corner(&mut area_content_ui, outer_rect, frame_stroke); paint_resize_corner(&mut area_content_ui, outer_rect, frame_stroke);
} }

View file

@ -142,7 +142,7 @@ impl FrameHistory {
for (time, cpu_usage) in history.iter() { for (time, cpu_usage) in history.iter() {
let age = (right_side_time - time) as f32; let age = (right_side_time - time) as f32;
let x = remap(age, history.max_age()..=0.0, rect.range_x()); let x = remap(age, history.max_age()..=0.0, rect.x_range());
let y = remap_clamp(cpu_usage, 0.0..=graph_top_cpu_usage, rect.bottom_up_range()); let y = remap_clamp(cpu_usage, 0.0..=graph_top_cpu_usage, rect.bottom_up_range());
cmds.push(PaintCmd::line_segment( cmds.push(PaintCmd::line_segment(

View file

@ -269,7 +269,7 @@ fn vertex_gradient(ui: &mut Ui, bg_fill: Srgba, gradient: &Gradient) -> Response
let mut triangles = Triangles::default(); let mut triangles = Triangles::default();
for (i, &color) in gradient.0.iter().enumerate() { for (i, &color) in gradient.0.iter().enumerate() {
let t = i as f32 / (n as f32 - 1.0); let t = i as f32 / (n as f32 - 1.0);
let x = lerp(rect.range_x(), t); let x = lerp(rect.x_range(), t);
triangles.colored_vertex(pos2(x, rect.top()), color); triangles.colored_vertex(pos2(x, rect.top()), color);
triangles.colored_vertex(pos2(x, rect.bottom()), color); triangles.colored_vertex(pos2(x, rect.bottom()), color);
if i < n - 1 { if i < n - 1 {

View file

@ -32,8 +32,8 @@ impl Texture {
show_tooltip(ui.ctx(), |ui| { show_tooltip(ui.ctx(), |ui| {
let pos = ui.input().mouse.pos.unwrap_or_else(|| ui.left_top()); let pos = ui.input().mouse.pos.unwrap_or_else(|| ui.left_top());
let zoom_rect = ui.allocate_space(vec2(128.0, 128.0)); let zoom_rect = ui.allocate_space(vec2(128.0, 128.0));
let u = remap_clamp(pos.x, rect.range_x(), 0.0..=tex_w); let u = remap_clamp(pos.x, rect.x_range(), 0.0..=tex_w);
let v = remap_clamp(pos.y, rect.range_y(), 0.0..=tex_h); let v = remap_clamp(pos.y, rect.y_range(), 0.0..=tex_h);
let texel_radius = 32.0; let texel_radius = 32.0;
let u = u.at_least(texel_radius).at_most(tex_w - texel_radius); let u = u.at_least(texel_radius).at_most(tex_w - texel_radius);

View file

@ -139,14 +139,12 @@ impl Rect {
self.width() * self.height() self.width() * self.height()
} }
pub fn range_x(&self) -> RangeInclusive<f32> { pub fn x_range(&self) -> RangeInclusive<f32> {
self.min.x..=self.max.x self.min.x..=self.max.x
} }
pub fn y_range(&self) -> RangeInclusive<f32> {
pub fn range_y(&self) -> RangeInclusive<f32> {
self.min.y..=self.max.y self.min.y..=self.max.y
} }
pub fn bottom_up_range(&self) -> RangeInclusive<f32> { pub fn bottom_up_range(&self) -> RangeInclusive<f32> {
self.max.y..=self.min.y self.max.y..=self.min.y
} }

View file

@ -711,8 +711,13 @@ impl Ui {
} }
/// Start a ui with horizontal layout. /// Start a ui with horizontal layout.
/// Elements will be centered on the Y axis. /// After you have called this, the registers the contents as any other widget.
/// Initial height is `style.spacing.interact_size.y`. ///
/// Elements will be centered on the Y axis, i.e.
/// adjusted up and down to lie in the center of the horizontal layout.
/// The initial height is `style.spacing.interact_size.y`.
/// Centering is almost always what you want if you are
/// planning to to mix widgets or just different types of text.
pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) { pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
let initial_size = vec2( let initial_size = vec2(
self.available().width(), self.available().width(),

View file

@ -367,6 +367,7 @@ impl<'a> Widget for Checkbox<'a> {
let mut desired_size = let mut desired_size =
button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding; button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding;
desired_size = desired_size.at_least(spacing.interact_size); desired_size = desired_size.at_least(spacing.interact_size);
desired_size.y = desired_size.y.max(icon_width);
let rect = ui.allocate_space(desired_size); let rect = ui.allocate_space(desired_size);
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());
@ -450,6 +451,7 @@ impl Widget for RadioButton {
let mut desired_size = let mut desired_size =
button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding; button_padding + vec2(icon_width + icon_spacing, 0.0) + galley.size + button_padding;
desired_size = desired_size.at_least(ui.style().spacing.interact_size); desired_size = desired_size.at_least(ui.style().spacing.interact_size);
desired_size.y = desired_size.y.max(icon_width);
let rect = ui.allocate_space(desired_size); let rect = ui.allocate_space(desired_size);
let response = ui.interact(rect, id, Sense::click()); let response = ui.interact(rect, id, Sense::click());

View file

@ -63,8 +63,10 @@ pub fn input_to_egui(
} }
KeyboardInput { input, .. } => { KeyboardInput { input, .. } => {
if let Some(virtual_keycode) = input.virtual_keycode { if let Some(virtual_keycode) = input.virtual_keycode {
// TODO: If mac if cfg!(target_os = "macos")
if input.modifiers.logo() && virtual_keycode == VirtualKeyCode::Q { && input.modifiers.logo()
&& virtual_keycode == VirtualKeyCode::Q
{
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
} }
@ -174,7 +176,7 @@ pub fn handle_output(
) { ) {
if let Some(url) = output.open_url { if let Some(url) = output.open_url {
if let Err(err) = webbrowser::open(&url) { if let Err(err) = webbrowser::open(&url) {
eprintln!("Failed to open url: {}", err); // TODO show error in imgui eprintln!("Failed to open url: {}", err);
} }
} }