draw menus centered in the screen, with highlighted lines

This commit is contained in:
Dustin Carlino 2018-09-19 16:26:58 -07:00
parent 96994eb9bd
commit c7f2c50e25
5 changed files with 73 additions and 37 deletions

View File

@ -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);

View File

@ -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;
}
};

View File

@ -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) {

View File

@ -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<String> {
// 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
}
}

View File

@ -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<String>,
lines: Vec<String>,
// (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<usize>,
}
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)
}