diff --git a/editor/src/plugins/color_picker.rs b/editor/src/plugins/color_picker.rs index b654bc392e..95f662de6c 100644 --- a/editor/src/plugins/color_picker.rs +++ b/editor/src/plugins/color_picker.rs @@ -86,10 +86,7 @@ impl ColorPicker { match self { ColorPicker::Inactive => {} ColorPicker::Choosing(menu) => { - // TODO sloppy to use a mouse tooltip. ideally should be easy to figure out how - // many lines to display and center it. - // TODO would be nice to display the text in the current color - canvas.draw_mouse_tooltip(g, &menu.lines_to_display()); + canvas.draw_centered_text(g, menu.get_osd()); } ColorPicker::PickingColor(_, _) => { let (start_x, start_y) = get_screen_offset(canvas); diff --git a/editor/src/plugins/draw_polygon.rs b/editor/src/plugins/draw_polygon.rs index 9f5a1de38b..e3e37eb5d9 100644 --- a/editor/src/plugins/draw_polygon.rs +++ b/editor/src/plugins/draw_polygon.rs @@ -164,8 +164,8 @@ impl DrawPolygonState { return; } DrawPolygonState::ListingPolygons(menu) => { - // TODO urgh, dont do this - canvas.draw_mouse_tooltip(g, &menu.lines_to_display()); + canvas.draw_centered_text(g, menu.get_osd()); + // TODO display the current polygon return; } }; diff --git a/ezgui/src/canvas.rs b/ezgui/src/canvas.rs index 1d0c2b01eb..d9c7723631 100644 --- a/ezgui/src/canvas.rs +++ b/ezgui/src/canvas.rs @@ -81,10 +81,15 @@ impl Canvas { } pub fn draw_mouse_tooltip(&self, g: &mut GfxCtx, lines: &[String]) { - let (width, height) = text::dims(g, lines); + let mut osd = TextOSD::new(); + for l in lines { + osd.add_line(l.clone()); + } + + let (width, height) = osd.dims(g); let x1 = self.cursor_x - (width / 2.0); let y1 = self.cursor_y - (height / 2.0); - text::draw_text_bubble(g, lines, (x1, y1), None); + text::draw_text_bubble(g, (x1, y1), osd); } // at the bottom-left of the screen @@ -92,13 +97,27 @@ impl Canvas { if osd.is_empty() { return; } - let (_, height) = text::dims(g, &osd.lines); + let (_, height) = osd.dims(g); let y1 = f64::from(self.window_size.height) - height; - text::draw_text_bubble(g, &osd.lines, (0.0, y1), osd.highlight_char); + text::draw_text_bubble(g, (0.0, y1), osd); + } + + pub fn draw_centered_text(&self, g: &mut GfxCtx, osd: TextOSD) { + if osd.is_empty() { + return; + } + let (width, height) = osd.dims(g); + let x1 = (f64::from(self.window_size.width) - width) / 2.0; + let y1 = (f64::from(self.window_size.height) - height) / 2.0; + text::draw_text_bubble(g, (x1, y1), osd); } pub fn draw_text_at(&self, g: &mut GfxCtx, lines: &[String], pt: Pt2D) { - text::draw_text_bubble(g, lines, self.map_to_screen(pt), None); + let mut osd = TextOSD::new(); + for l in lines { + osd.add_line(l.clone()); + } + text::draw_text_bubble(g, self.map_to_screen(pt), osd); } fn zoom_towards_mouse(&mut self, delta_zoom: f64) { diff --git a/ezgui/src/menu.rs b/ezgui/src/menu.rs index e11b4c3e56..bd4726e1ed 100644 --- a/ezgui/src/menu.rs +++ b/ezgui/src/menu.rs @@ -1,6 +1,5 @@ -// Copyright 2018 Google LLC, licensed under http://www.apache.org/licenses/LICENSE-2.0 - use piston::input::{Button, Event, Key, PressEvent}; +use TextOSD; pub enum MenuResult { Canceled, @@ -45,10 +44,17 @@ impl Menu { MenuResult::StillActive } - pub fn lines_to_display(&self) -> Vec { - // TODO dont copy - let mut copy = self.choices.clone(); - copy[self.current_idx] = format!("---> {}", copy[self.current_idx]); - copy + // TODO different API... handle menus bigger than the screen, actually do scroll. maybe always + // display one size for the menu, just dont fill everything out + pub fn get_osd(&self) -> TextOSD { + let mut osd = TextOSD::new(); + for (idx, line) in self.choices.iter().enumerate() { + if self.current_idx == idx { + osd.add_highlighted_line(line.clone()); + } else { + osd.add_line(line.clone()); + } + } + osd } } diff --git a/ezgui/src/text.rs b/ezgui/src/text.rs index 674d93b7ed..f30857a4d4 100644 --- a/ezgui/src/text.rs +++ b/ezgui/src/text.rs @@ -16,9 +16,11 @@ const LINE_HEIGHT: f64 = 22.0; // TODO I kind of want general HTMLish markup options here -- bold, italic, underline, color, etc pub struct TextOSD { - pub(crate) lines: Vec, + lines: Vec, // (Line, character) indices - pub(crate) highlight_char: Option<(usize, usize)>, + // Can have one of each, sure, why not + highlight_char: Option<(usize, usize)>, + highlight_line: Option, } impl TextOSD { @@ -26,6 +28,7 @@ impl TextOSD { TextOSD { lines: Vec::new(), highlight_char: None, + highlight_line: None, } } @@ -47,18 +50,26 @@ impl TextOSD { self.lines.push(line); } + pub fn add_highlighted_line(&mut self, line: String) { + assert!(self.highlight_line.is_none()); + self.highlight_line = Some(self.lines.len()); + self.lines.push(line); + } + pub(crate) fn is_empty(&self) -> bool { self.lines.is_empty() } + + pub fn dims(&self, g: &mut GfxCtx) -> (f64, f64) { + let longest_line = self.lines.iter().max_by_key(|l| l.len()).unwrap(); + let width = g.glyphs.width(FONT_SIZE, longest_line).unwrap(); + let height = (self.lines.len() as f64) * LINE_HEIGHT; + (width, height) + } } -pub fn draw_text_bubble( - g: &mut GfxCtx, - lines: &[String], - (x1, y1): (f64, f64), - highlight_char: Option<(usize, usize)>, -) { - let (width, height) = dims(g, lines); +pub fn draw_text_bubble(g: &mut GfxCtx, (x1, y1): (f64, f64), osd: TextOSD) { + let (width, height) = osd.dims(g); graphics::Rectangle::new(TEXT_BG_COLOR).draw( [x1, y1, width, height], &g.orig_ctx.draw_state, @@ -68,15 +79,25 @@ pub fn draw_text_bubble( let fg_text = Image::new_color(TEXT_FG_COLOR); let mut y = y1 + LINE_HEIGHT; - for (line_idx, line) in lines.iter().enumerate() { + for (line_idx, line) in osd.lines.iter().enumerate() { let mut x = x1; + + if Some(line_idx) == osd.highlight_line { + graphics::Rectangle::new(TEXT_HIGHLIGHT_COLOR).draw( + [x, y - LINE_HEIGHT, width, LINE_HEIGHT], + &g.orig_ctx.draw_state, + g.orig_ctx.transform, + g.gfx, + ); + } + for (char_idx, ch) in line.chars().enumerate() { if let Ok(draw_ch) = g.glyphs.character(FONT_SIZE, ch) { let char_ctx = g .orig_ctx .transform .trans(x + draw_ch.left(), y - draw_ch.top()); - if Some((line_idx, char_idx)) == highlight_char { + if Some((line_idx, char_idx)) == osd.highlight_char { graphics::Rectangle::new(TEXT_HIGHLIGHT_COLOR).draw( [0.0, 0.0, draw_ch.width(), LINE_HEIGHT], &g.orig_ctx.draw_state, @@ -90,7 +111,7 @@ pub fn draw_text_bubble( panic!("Couldn't get glyph for {}", ch); } } - if Some((line_idx, line.len())) == highlight_char { + if Some((line_idx, line.len())) == osd.highlight_char { graphics::Rectangle::new(TEXT_HIGHLIGHT_COLOR).draw( [x, y - LINE_HEIGHT, END_OF_LINE_CURSOR_WIDTH, LINE_HEIGHT], &g.orig_ctx.draw_state, @@ -101,10 +122,3 @@ pub fn draw_text_bubble( y += LINE_HEIGHT; } } - -pub fn dims(g: &mut GfxCtx, lines: &[String]) -> (f64, f64) { - let longest_line = lines.iter().max_by_key(|l| l.len()).unwrap(); - let width = g.glyphs.width(FONT_SIZE, longest_line).unwrap(); - let height = (lines.len() as f64) * LINE_HEIGHT; - (width, height) -}