mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
starting a slider widget, using in easy places where the range is usize
This commit is contained in:
parent
83f62631e9
commit
28b2734d59
@ -2,13 +2,13 @@ use crate::helpers::ID;
|
||||
use crate::render::calculate_corners;
|
||||
use crate::ui::UI;
|
||||
use abstutil::Timer;
|
||||
use ezgui::{EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||
use ezgui::{EventCtx, GfxCtx, Key, ModalMenu, Slider, Text};
|
||||
use geom::{Polygon, Pt2D, Triangle};
|
||||
|
||||
pub struct PolygonDebugger {
|
||||
menu: ModalMenu,
|
||||
items: Vec<Item>,
|
||||
current: usize,
|
||||
slider: Slider,
|
||||
center: Option<Pt2D>,
|
||||
}
|
||||
|
||||
@ -44,57 +44,57 @@ impl PolygonDebugger {
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: pts.iter().map(|pt| Item::Point(*pt)).collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, pts.len() - 1),
|
||||
center: Some(Pt2D::center(&pts_without_last)),
|
||||
});
|
||||
} else if ctx
|
||||
.input
|
||||
.contextual_action(Key::F2, "debug sidewalk corners")
|
||||
{
|
||||
let items: Vec<Item> =
|
||||
calculate_corners(i, &ui.primary.map, &mut Timer::new("calculate corners"))
|
||||
.into_iter()
|
||||
.map(Item::Polygon)
|
||||
.collect();
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: calculate_corners(
|
||||
i,
|
||||
&ui.primary.map,
|
||||
&mut Timer::new("calculate corners"),
|
||||
)
|
||||
.into_iter()
|
||||
.map(Item::Polygon)
|
||||
.collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, items.len() - 1),
|
||||
items,
|
||||
center: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
Some(ID::Lane(id)) => {
|
||||
if ctx.input.contextual_action(Key::X, "debug lane geometry") {
|
||||
let items: Vec<Item> = ui
|
||||
.primary
|
||||
.map
|
||||
.get_l(id)
|
||||
.lane_center_pts
|
||||
.points()
|
||||
.iter()
|
||||
.map(|pt| Item::Point(*pt))
|
||||
.collect();
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: ui
|
||||
.primary
|
||||
.map
|
||||
.get_l(id)
|
||||
.lane_center_pts
|
||||
.points()
|
||||
.iter()
|
||||
.map(|pt| Item::Point(*pt))
|
||||
.collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, items.len() - 1),
|
||||
items,
|
||||
center: None,
|
||||
});
|
||||
} else if ctx.input.contextual_action(Key::F2, "debug lane triangles") {
|
||||
let items: Vec<Item> = ui
|
||||
.primary
|
||||
.draw_map
|
||||
.get_l(id)
|
||||
.polygon
|
||||
.triangles()
|
||||
.into_iter()
|
||||
.map(Item::Triangle)
|
||||
.collect();
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: ui
|
||||
.primary
|
||||
.draw_map
|
||||
.get_l(id)
|
||||
.polygon
|
||||
.triangles()
|
||||
.into_iter()
|
||||
.map(Item::Triangle)
|
||||
.collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, items.len() - 1),
|
||||
items,
|
||||
center: None,
|
||||
});
|
||||
}
|
||||
@ -112,22 +112,23 @@ impl PolygonDebugger {
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: pts.iter().map(|pt| Item::Point(*pt)).collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, pts.len() - 1),
|
||||
center: Some(center),
|
||||
});
|
||||
} else if ctx.input.contextual_action(Key::F2, "debug area triangles") {
|
||||
let items: Vec<Item> = ui
|
||||
.primary
|
||||
.map
|
||||
.get_a(id)
|
||||
.polygon
|
||||
.triangles()
|
||||
.into_iter()
|
||||
.map(Item::Triangle)
|
||||
.collect();
|
||||
return Some(PolygonDebugger {
|
||||
menu,
|
||||
items: ui
|
||||
.primary
|
||||
.map
|
||||
.get_a(id)
|
||||
.polygon
|
||||
.triangles()
|
||||
.into_iter()
|
||||
.map(Item::Triangle)
|
||||
.collect(),
|
||||
current: 0,
|
||||
slider: Slider::new(0, items.len() - 1),
|
||||
items,
|
||||
center: None,
|
||||
});
|
||||
}
|
||||
@ -139,44 +140,52 @@ impl PolygonDebugger {
|
||||
|
||||
// True when done
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
||||
let current = self.slider.get_value();
|
||||
|
||||
let mut txt = Text::prompt("Polygon Debugger");
|
||||
txt.add_line(format!("Item {}/{}", self.current + 1, self.items.len()));
|
||||
txt.add_line(format!("Item {}/{}", current + 1, self.items.len()));
|
||||
self.menu.handle_event(ctx, Some(txt));
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
|
||||
if self.menu.action("quit") {
|
||||
return true;
|
||||
} else if self.current != self.items.len() - 1 && self.menu.action("next item") {
|
||||
self.current += 1;
|
||||
} else if self.current != self.items.len() - 1 && self.menu.action("last item") {
|
||||
self.current = self.items.len() - 1;
|
||||
} else if self.current != 0 && self.menu.action("prev item") {
|
||||
self.current -= 1;
|
||||
} else if self.current != 0 && self.menu.action("first item") {
|
||||
self.current = 0;
|
||||
} else if current != self.items.len() - 1 && self.menu.action("next item") {
|
||||
self.slider.set_value(ctx, current + 1);
|
||||
} else if current != self.items.len() - 1 && self.menu.action("last item") {
|
||||
self.slider.set_value(ctx, self.items.len() - 1);
|
||||
} else if current != 0 && self.menu.action("prev item") {
|
||||
self.slider.set_value(ctx, current - 1);
|
||||
} else if current != 0 && self.menu.action("first item") {
|
||||
self.slider.set_value(ctx, 0);
|
||||
}
|
||||
|
||||
self.slider.event(ctx);
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
match self.items[self.current] {
|
||||
let current = self.slider.get_value();
|
||||
|
||||
match self.items[current] {
|
||||
Item::Point(pt) => {
|
||||
g.draw_text_at(&Text::from_line(format!("{}", self.current)), pt);
|
||||
g.draw_text_at(&Text::from_line(format!("{}", current)), pt);
|
||||
}
|
||||
Item::Triangle(ref tri) => {
|
||||
for pt in &[tri.pt1, tri.pt2, tri.pt3] {
|
||||
g.draw_text_at(&Text::from_line(format!("{}", self.current)), *pt);
|
||||
g.draw_text_at(&Text::from_line(format!("{}", current)), *pt);
|
||||
}
|
||||
g.draw_polygon(ui.cs.get("selected"), &Polygon::from_triangle(tri));
|
||||
}
|
||||
Item::Polygon(ref poly) => {
|
||||
g.draw_polygon(ui.cs.get("selected"), poly);
|
||||
g.draw_text_at(&Text::from_line(format!("{}", self.current)), poly.center());
|
||||
g.draw_text_at(&Text::from_line(format!("{}", current)), poly.center());
|
||||
}
|
||||
}
|
||||
if let Some(pt) = self.center {
|
||||
g.draw_text_at(&Text::from_line("c".to_string()), pt);
|
||||
}
|
||||
self.menu.draw(g);
|
||||
self.slider.draw(g);
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,14 @@ use crate::common::CommonState;
|
||||
use crate::mission::{clip_trips, Trip};
|
||||
use crate::ui::{ShowEverything, UI};
|
||||
use abstutil::{prettyprint_usize, Timer};
|
||||
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Slider, Text};
|
||||
use geom::{Circle, Distance, Speed};
|
||||
use popdat::PopDat;
|
||||
|
||||
pub struct TripsVisualizer {
|
||||
menu: ModalMenu,
|
||||
trips: Vec<Trip>,
|
||||
current: usize,
|
||||
slider: Slider,
|
||||
}
|
||||
|
||||
impl TripsVisualizer {
|
||||
@ -17,7 +17,8 @@ impl TripsVisualizer {
|
||||
let mut timer = Timer::new("initialize popdat");
|
||||
let popdat: PopDat = abstutil::read_binary("../data/shapes/popdat", &mut timer)
|
||||
.expect("Couldn't load popdat");
|
||||
|
||||
// TODO We'll break if there are no matching trips
|
||||
let trips = clip_trips(&popdat, ui, 10_000, &mut timer);
|
||||
TripsVisualizer {
|
||||
menu: ModalMenu::new(
|
||||
"Trips Visualizer",
|
||||
@ -30,21 +31,22 @@ impl TripsVisualizer {
|
||||
],
|
||||
ctx,
|
||||
),
|
||||
trips: clip_trips(&popdat, ui, 10_000, &mut timer),
|
||||
// TODO We'll break if there are no matching trips
|
||||
current: 0,
|
||||
slider: Slider::new(0, trips.len() - 1),
|
||||
trips,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the we're done
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> bool {
|
||||
let current = self.slider.get_value();
|
||||
|
||||
let mut txt = Text::prompt("Trips Visualizer");
|
||||
txt.add_line(format!(
|
||||
"Trip {}/{}",
|
||||
prettyprint_usize(self.current),
|
||||
prettyprint_usize(current + 1),
|
||||
prettyprint_usize(self.trips.len())
|
||||
));
|
||||
let trip = &self.trips[self.current];
|
||||
let trip = &self.trips[current];
|
||||
txt.add_line(format!("Leave at {}", trip.depart_at));
|
||||
txt.add_line(format!(
|
||||
"Purpose: {:?} -> {:?}",
|
||||
@ -65,21 +67,23 @@ impl TripsVisualizer {
|
||||
|
||||
if self.menu.action("quit") {
|
||||
return true;
|
||||
} else if self.current != self.trips.len() - 1 && self.menu.action("next trip") {
|
||||
self.current += 1;
|
||||
} else if self.current != self.trips.len() - 1 && self.menu.action("last trip") {
|
||||
self.current = self.trips.len() - 1;
|
||||
} else if self.current != 0 && self.menu.action("prev trip") {
|
||||
self.current -= 1;
|
||||
} else if self.current != 0 && self.menu.action("first trip") {
|
||||
self.current = 0;
|
||||
} else if current != self.trips.len() - 1 && self.menu.action("next trip") {
|
||||
self.slider.set_value(ctx, current + 1);
|
||||
} else if current != self.trips.len() - 1 && self.menu.action("last trip") {
|
||||
self.slider.set_value(ctx, self.trips.len() - 1);
|
||||
} else if current != 0 && self.menu.action("prev trip") {
|
||||
self.slider.set_value(ctx, current - 1);
|
||||
} else if current != 0 && self.menu.action("first trip") {
|
||||
self.slider.set_value(ctx, 0);
|
||||
}
|
||||
|
||||
self.slider.event(ctx);
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
let trip = &self.trips[self.current];
|
||||
let trip = &self.trips[self.slider.get_value()];
|
||||
let from = ui.primary.map.get_b(trip.from);
|
||||
let to = ui.primary.map.get_b(trip.to);
|
||||
|
||||
@ -97,6 +101,7 @@ impl TripsVisualizer {
|
||||
);
|
||||
|
||||
self.menu.draw(g);
|
||||
self.slider.draw(g);
|
||||
CommonState::draw_osd(g, ui, ui.primary.current_selection);
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::common::Warper;
|
||||
use crate::helpers::ID;
|
||||
use crate::render::DrawTurn;
|
||||
use crate::ui::UI;
|
||||
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Text};
|
||||
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, ModalMenu, Slider, Text};
|
||||
use geom::{Distance, Polygon};
|
||||
use map_model::{Traversable, LANE_THICKNESS};
|
||||
use sim::AgentID;
|
||||
@ -12,8 +12,8 @@ pub struct RouteExplorer {
|
||||
agent: AgentID,
|
||||
steps: Vec<Traversable>,
|
||||
entire_trace: Option<Polygon>,
|
||||
current: usize,
|
||||
warper: Option<Warper>,
|
||||
slider: Slider,
|
||||
}
|
||||
|
||||
impl RouteExplorer {
|
||||
@ -62,7 +62,6 @@ impl RouteExplorer {
|
||||
ctx,
|
||||
),
|
||||
agent,
|
||||
current: 0,
|
||||
warper: Some(Warper::new(
|
||||
ctx,
|
||||
steps[0]
|
||||
@ -73,6 +72,7 @@ impl RouteExplorer {
|
||||
Traversable::Turn(t) => ID::Turn(t),
|
||||
},
|
||||
)),
|
||||
slider: Slider::new(0, steps.len() - 1),
|
||||
steps,
|
||||
entire_trace,
|
||||
})
|
||||
@ -80,47 +80,54 @@ impl RouteExplorer {
|
||||
|
||||
// Done when None
|
||||
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<EventLoopMode> {
|
||||
if let Some(ref warper) = self.warper {
|
||||
// Don't block while we're warping
|
||||
let ev_mode = if let Some(ref warper) = self.warper {
|
||||
if let Some(mode) = warper.event(ctx, ui) {
|
||||
return Some(mode);
|
||||
mode
|
||||
} else {
|
||||
self.warper = None;
|
||||
EventLoopMode::InputOnly
|
||||
}
|
||||
self.warper = None;
|
||||
}
|
||||
} else {
|
||||
EventLoopMode::InputOnly
|
||||
};
|
||||
|
||||
let current = self.slider.get_value();
|
||||
|
||||
let mut txt = Text::prompt(&format!("Route Explorer for {:?}", self.agent));
|
||||
txt.add_line(format!("Step {}/{}", self.current + 1, self.steps.len()));
|
||||
txt.add_line(format!("{:?}", self.steps[self.current]));
|
||||
txt.add_line(format!("Step {}/{}", current + 1, self.steps.len()));
|
||||
txt.add_line(format!("{:?}", self.steps[current]));
|
||||
self.menu.handle_event(ctx, Some(txt));
|
||||
ctx.canvas.handle_event(ctx.input);
|
||||
|
||||
if self.menu.action("quit") {
|
||||
return None;
|
||||
} else if self.current != self.steps.len() - 1 && self.menu.action("next step") {
|
||||
self.current += 1;
|
||||
} else if self.current != self.steps.len() - 1 && self.menu.action("last step") {
|
||||
self.current = self.steps.len() - 1;
|
||||
} else if self.current != 0 && self.menu.action("prev step") {
|
||||
self.current -= 1;
|
||||
} else if self.current != 0 && self.menu.action("first step") {
|
||||
self.current = 0;
|
||||
} else if current != self.steps.len() - 1 && self.menu.action("next step") {
|
||||
self.slider.set_value(ctx, current + 1);
|
||||
} else if current != self.steps.len() - 1 && self.menu.action("last step") {
|
||||
self.slider.set_value(ctx, self.steps.len() - 1);
|
||||
} else if current != 0 && self.menu.action("prev step") {
|
||||
self.slider.set_value(ctx, current - 1);
|
||||
} else if current != 0 && self.menu.action("first step") {
|
||||
self.slider.set_value(ctx, 0);
|
||||
} else if self.slider.event(ctx) {
|
||||
// Cool, the value changed, so fall-through
|
||||
} else {
|
||||
return Some(EventLoopMode::InputOnly);
|
||||
return Some(ev_mode);
|
||||
}
|
||||
|
||||
let step = self.steps[self.slider.get_value()];
|
||||
self.warper = Some(Warper::new(
|
||||
ctx,
|
||||
self.steps[self.current]
|
||||
.dist_along(
|
||||
self.steps[self.current].length(&ui.primary.map) / 2.0,
|
||||
&ui.primary.map,
|
||||
)
|
||||
step.dist_along(step.length(&ui.primary.map) / 2.0, &ui.primary.map)
|
||||
.0,
|
||||
match self.steps[self.current] {
|
||||
match step {
|
||||
Traversable::Lane(l) => ID::Lane(l),
|
||||
Traversable::Turn(t) => ID::Turn(t),
|
||||
},
|
||||
));
|
||||
|
||||
Some(EventLoopMode::InputOnly)
|
||||
// We just created a new warper, so...
|
||||
Some(EventLoopMode::Animation)
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||
@ -129,7 +136,7 @@ impl RouteExplorer {
|
||||
}
|
||||
|
||||
let color = ui.cs.get_def("current step", Color::RED);
|
||||
match self.steps[self.current] {
|
||||
match self.steps[self.slider.get_value()] {
|
||||
Traversable::Lane(l) => {
|
||||
g.draw_polygon(color, &ui.primary.draw_map.get_l(l).polygon);
|
||||
}
|
||||
@ -138,5 +145,6 @@ impl RouteExplorer {
|
||||
}
|
||||
}
|
||||
self.menu.draw(g);
|
||||
self.slider.draw(g);
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ pub use crate::runner::{run, EventLoopMode, GUI};
|
||||
pub use crate::screen_geom::ScreenPt;
|
||||
pub use crate::text::{Text, HOTKEY_COLOR};
|
||||
pub use crate::widgets::{
|
||||
Autocomplete, LogScroller, ModalMenu, ScrollingMenu, TextBox, Wizard, WrappedWizard,
|
||||
Autocomplete, LogScroller, ModalMenu, ScrollingMenu, Slider, TextBox, Wizard, WrappedWizard,
|
||||
};
|
||||
|
||||
pub enum InputResult<T: Clone> {
|
||||
|
@ -4,6 +4,7 @@ mod menu;
|
||||
mod modal_menu;
|
||||
mod screenshot;
|
||||
mod scrolling_menu;
|
||||
mod slider;
|
||||
mod text_box;
|
||||
mod wizard;
|
||||
|
||||
@ -13,5 +14,6 @@ pub use self::menu::{Menu, Position};
|
||||
pub use self::modal_menu::ModalMenu;
|
||||
pub(crate) use self::screenshot::{screenshot_current, screenshot_everything};
|
||||
pub use self::scrolling_menu::ScrollingMenu;
|
||||
pub use self::slider::Slider;
|
||||
pub use self::text_box::TextBox;
|
||||
pub use self::wizard::{Wizard, WrappedWizard};
|
||||
|
157
ezgui/src/widgets/slider.rs
Normal file
157
ezgui/src/widgets/slider.rs
Normal file
@ -0,0 +1,157 @@
|
||||
use crate::screen_geom::ScreenRectangle;
|
||||
use crate::{Color, EventCtx, GfxCtx};
|
||||
use geom::{Distance, Polygon, Pt2D};
|
||||
|
||||
// Pixels
|
||||
const BAR_WIDTH: f64 = 300.0;
|
||||
const BAR_HEIGHT: f64 = 100.0;
|
||||
const SLIDER_WIDTH: f64 = 50.0;
|
||||
const SLIDER_HEIGHT: f64 = 120.0;
|
||||
|
||||
const HORIZ_PADDING: f64 = 60.0;
|
||||
const VERT_PADDING: f64 = 20.0;
|
||||
|
||||
pub struct Slider {
|
||||
min: usize,
|
||||
max: usize,
|
||||
current_percent: f64,
|
||||
mouse_on_slider: bool,
|
||||
dragging: bool,
|
||||
}
|
||||
|
||||
impl Slider {
|
||||
pub fn new(min: usize, max: usize) -> Slider {
|
||||
Slider {
|
||||
min,
|
||||
max,
|
||||
current_percent: 0.0,
|
||||
mouse_on_slider: false,
|
||||
dragging: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> usize {
|
||||
self.min + (self.current_percent * (self.max - self.min) as f64) as usize
|
||||
}
|
||||
|
||||
pub fn set_value(&mut self, ctx: &mut EventCtx, value: usize) {
|
||||
self.current_percent = (value - self.min) as f64 / (self.max - self.min) as f64;
|
||||
|
||||
// Just reset dragging, to prevent chaos
|
||||
self.dragging = false;
|
||||
let pt = ctx.canvas.get_cursor_in_screen_space();
|
||||
self.mouse_on_slider = self.slider_geom().contains_pt(Pt2D::new(pt.x, pt.y));
|
||||
}
|
||||
|
||||
// Returns true if the value changed.
|
||||
pub fn event(&mut self, ctx: &mut EventCtx) -> bool {
|
||||
if self.dragging {
|
||||
if ctx.input.get_moved_mouse().is_some() {
|
||||
let percent =
|
||||
(ctx.canvas.get_cursor_in_screen_space().x - HORIZ_PADDING) / BAR_WIDTH;
|
||||
let old_value = self.get_value();
|
||||
self.current_percent = percent.min(1.0).max(0.0);
|
||||
if self.get_value() != old_value {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if ctx.input.left_mouse_button_released() {
|
||||
self.dragging = false;
|
||||
}
|
||||
} else {
|
||||
if !ctx.canvas.is_dragging() && ctx.input.get_moved_mouse().is_some() {
|
||||
let pt = ctx.canvas.get_cursor_in_screen_space();
|
||||
self.mouse_on_slider = self.slider_geom().contains_pt(Pt2D::new(pt.x, pt.y));
|
||||
}
|
||||
if ctx.input.left_mouse_button_pressed() {
|
||||
if self.mouse_on_slider {
|
||||
self.dragging = true;
|
||||
} else {
|
||||
// Did we click somewhere else on the bar?
|
||||
let pt = ctx.canvas.get_cursor_in_screen_space();
|
||||
if Polygon::rectangle_topleft(
|
||||
Pt2D::new(HORIZ_PADDING, VERT_PADDING),
|
||||
Distance::meters(BAR_WIDTH),
|
||||
Distance::meters(BAR_HEIGHT),
|
||||
)
|
||||
.contains_pt(Pt2D::new(pt.x, pt.y))
|
||||
{
|
||||
// TODO Argh, some code duplication
|
||||
let percent = (pt.x - HORIZ_PADDING) / BAR_WIDTH;
|
||||
let old_value = self.get_value();
|
||||
self.current_percent = percent.min(1.0).max(0.0);
|
||||
self.mouse_on_slider = true;
|
||||
self.dragging = true;
|
||||
if self.get_value() != old_value {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn draw(&self, g: &mut GfxCtx) {
|
||||
g.fork_screenspace();
|
||||
|
||||
// A nice background for the entire thing
|
||||
g.draw_polygon(
|
||||
Color::grey(0.3),
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(0.0, 0.0),
|
||||
Distance::meters(BAR_WIDTH + 2.0 * HORIZ_PADDING),
|
||||
Distance::meters(BAR_HEIGHT + 2.0 * VERT_PADDING),
|
||||
),
|
||||
);
|
||||
g.canvas.mark_covered_area(ScreenRectangle {
|
||||
x1: 0.0,
|
||||
y1: 0.0,
|
||||
x2: BAR_WIDTH + 2.0 * HORIZ_PADDING,
|
||||
y2: BAR_HEIGHT + 2.0 * VERT_PADDING,
|
||||
});
|
||||
|
||||
// The bar
|
||||
g.draw_polygon(
|
||||
Color::WHITE,
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(HORIZ_PADDING, VERT_PADDING),
|
||||
Distance::meters(BAR_WIDTH),
|
||||
Distance::meters(BAR_HEIGHT),
|
||||
),
|
||||
);
|
||||
|
||||
// Show the progress
|
||||
if self.current_percent != 0.0 {
|
||||
g.draw_polygon(
|
||||
Color::GREEN,
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(HORIZ_PADDING, VERT_PADDING),
|
||||
Distance::meters(self.current_percent * BAR_WIDTH),
|
||||
Distance::meters(BAR_HEIGHT),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// The actual slider
|
||||
g.draw_polygon(
|
||||
if self.mouse_on_slider {
|
||||
Color::YELLOW
|
||||
} else {
|
||||
Color::grey(0.7)
|
||||
},
|
||||
&self.slider_geom(),
|
||||
);
|
||||
}
|
||||
|
||||
fn slider_geom(&self) -> Polygon {
|
||||
Polygon::rectangle_topleft(
|
||||
Pt2D::new(
|
||||
HORIZ_PADDING + self.current_percent * BAR_WIDTH - (SLIDER_WIDTH / 2.0),
|
||||
VERT_PADDING - (SLIDER_HEIGHT - BAR_HEIGHT) / 2.0,
|
||||
),
|
||||
Distance::meters(SLIDER_WIDTH),
|
||||
Distance::meters(SLIDER_HEIGHT),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user