mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
make a blend between ScrollingMenu and ContextMenu... don't use it yet
This commit is contained in:
parent
11945739bd
commit
671dad6b02
@ -32,11 +32,6 @@ impl UserInput {
|
|||||||
reserved_keys: HashMap::new(),
|
reserved_keys: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO Or left clicking outside of the menu
|
|
||||||
// TODO If the user left clicks on a menu item, then mark that action as selected, and
|
|
||||||
// ensure contextual_action is called this round.
|
|
||||||
// TODO If the user hovers on a menu item, mark it for later highlighting.
|
|
||||||
|
|
||||||
// Create the context menu here, even if one already existed.
|
// Create the context menu here, even if one already existed.
|
||||||
if input.right_mouse_button_pressed() {
|
if input.right_mouse_button_pressed() {
|
||||||
input.context_menu = Some(ContextMenu {
|
input.context_menu = Some(ContextMenu {
|
||||||
|
@ -5,6 +5,7 @@ mod color;
|
|||||||
mod event;
|
mod event;
|
||||||
mod input;
|
mod input;
|
||||||
mod log_scroller;
|
mod log_scroller;
|
||||||
|
mod menu;
|
||||||
mod runner;
|
mod runner;
|
||||||
mod scrolling_menu;
|
mod scrolling_menu;
|
||||||
mod text;
|
mod text;
|
||||||
|
133
ezgui/src/menu.rs
Normal file
133
ezgui/src/menu.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
use crate::{text, Canvas, Color, Event, GfxCtx, InputResult, Key, Text, UserInput};
|
||||||
|
use geom::{Polygon, Pt2D};
|
||||||
|
|
||||||
|
// Stores some associated data with each choice
|
||||||
|
pub struct Menu<T: Clone> {
|
||||||
|
prompt: Option<String>,
|
||||||
|
choices: Vec<(Key, String, T)>,
|
||||||
|
current_idx: Option<usize>,
|
||||||
|
|
||||||
|
origin: Pt2D,
|
||||||
|
// The rectangle representing the top row of the menu (not including the optional prompt), then
|
||||||
|
// the height of one row
|
||||||
|
// TODO Needing a separate call to initialize geometry sucks.
|
||||||
|
geometry: Option<(Polygon, f64)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Menu<T> {
|
||||||
|
/*pub fn new(prompt: &str, choices: Vec<(String, T)>) -> Menu<T> {
|
||||||
|
if choices.is_empty() {
|
||||||
|
panic!("Can't create a menu without choices for \"{}\"", prompt);
|
||||||
|
}
|
||||||
|
Menu {
|
||||||
|
prompt: prompt.to_string(),
|
||||||
|
choices,
|
||||||
|
current_idx: 0,
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn event(&mut self, input: &mut UserInput, canvas: &Canvas) -> InputResult<T> {
|
||||||
|
// We have to directly look at stuff here; all of input's methods lie and pretend nothing
|
||||||
|
// is happening.
|
||||||
|
let maybe_ev = input.use_event_directly();
|
||||||
|
if maybe_ev.is_none() {
|
||||||
|
return InputResult::StillActive;
|
||||||
|
}
|
||||||
|
let ev = maybe_ev.unwrap();
|
||||||
|
|
||||||
|
// Handle the mouse
|
||||||
|
if let Some((ref row, height)) = self.geometry {
|
||||||
|
if ev == Event::LeftMouseButtonDown {
|
||||||
|
if let Some(i) = self.current_idx {
|
||||||
|
let (_, choice, data) = self.choices[i].clone();
|
||||||
|
return InputResult::Done(choice, data);
|
||||||
|
} else {
|
||||||
|
return InputResult::Canceled;
|
||||||
|
}
|
||||||
|
} else if let Event::MouseMovedTo(x, y) = ev {
|
||||||
|
let cursor_pt = canvas.screen_to_map((x, y));
|
||||||
|
let mut matched = false;
|
||||||
|
for i in 0..self.choices.len() {
|
||||||
|
if row
|
||||||
|
.translate(0.0, (i as f64) * height)
|
||||||
|
.contains_pt(cursor_pt)
|
||||||
|
{
|
||||||
|
self.current_idx = Some(i);
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !matched {
|
||||||
|
self.current_idx = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle keys
|
||||||
|
if ev == Event::KeyPress(Key::Escape) {
|
||||||
|
return InputResult::Canceled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Disable arrow keys in context menus and the top menu?
|
||||||
|
if let Some(idx) = self.current_idx {
|
||||||
|
if ev == Event::KeyPress(Key::Enter) {
|
||||||
|
let (_, name, data) = self.choices[idx].clone();
|
||||||
|
return InputResult::Done(name, data);
|
||||||
|
} else if ev == Event::KeyPress(Key::UpArrow) {
|
||||||
|
if idx > 0 {
|
||||||
|
self.current_idx = Some(idx - 1);
|
||||||
|
}
|
||||||
|
} else if ev == Event::KeyPress(Key::DownArrow) {
|
||||||
|
if idx < self.choices.len() - 1 {
|
||||||
|
self.current_idx = Some(idx + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InputResult::StillActive
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn calculate_geometry(&mut self, g: &mut GfxCtx, canvas: &Canvas) {
|
||||||
|
if self.geometry.is_some() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut txt = Text::new();
|
||||||
|
// TODO prompt
|
||||||
|
for (hotkey, choice, _) in &self.choices {
|
||||||
|
txt.add_line(format!("{} - {}", hotkey.describe(), choice));
|
||||||
|
}
|
||||||
|
let (screen_width, screen_height) = txt.dims(g);
|
||||||
|
let map_width = screen_width / canvas.cam_zoom;
|
||||||
|
let map_height = screen_height / canvas.cam_zoom;
|
||||||
|
let top_left = Pt2D::new(
|
||||||
|
self.origin.x() - (map_width / 2.0),
|
||||||
|
self.origin.y() - (map_height / 2.0),
|
||||||
|
);
|
||||||
|
let row_height = map_height / (self.choices.len() as f64);
|
||||||
|
self.geometry = Some((
|
||||||
|
Polygon::rectangle_topleft(top_left, map_width, row_height),
|
||||||
|
row_height,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, g: &mut GfxCtx, canvas: &Canvas) {
|
||||||
|
let mut txt = Text::new();
|
||||||
|
// TODO prompt using Some(text::TEXT_QUERY_COLOR)
|
||||||
|
for (idx, (hotkey, choice, _)) in self.choices.iter().enumerate() {
|
||||||
|
let bg = if Some(idx) == self.current_idx {
|
||||||
|
Some(Color::WHITE)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
txt.add_styled_line(hotkey.describe(), Color::BLUE, bg);
|
||||||
|
txt.append(format!(" - {}", choice), text::TEXT_FG_COLOR, bg);
|
||||||
|
}
|
||||||
|
canvas.draw_text_at(g, txt, self.origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_choice(&self) -> Option<&T> {
|
||||||
|
let idx = self.current_idx?;
|
||||||
|
Some(&self.choices[idx].2)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user