Improve LTN tool rendering when zoomed in. Outlines around selected

objects are less thick and opaque, to cover up less of the road.
This commit is contained in:
Dustin Carlino 2021-12-17 11:37:54 +00:00
parent 4e79d19765
commit eb4060b071
4 changed files with 54 additions and 30 deletions

View File

@ -2,10 +2,11 @@ use std::collections::{BTreeMap, BTreeSet};
use geom::Distance;
use map_model::{Block, Perimeter};
use widgetry::mapspace::ToggleZoomed;
use widgetry::mapspace::{ObjectID, World, WorldOutcome};
use widgetry::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Outcome, Panel, State,
TextExt, VerticalAlignment, Widget,
Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Outcome, Panel, State, TextExt,
VerticalAlignment, Widget,
};
use crate::app::{App, Transition};
@ -20,7 +21,7 @@ pub struct SelectBoundary {
blocks: BTreeMap<Obj, Block>,
world: World<Obj>,
selected: BTreeSet<Obj>,
draw_outline: Drawable,
draw_outline: ToggleZoomed,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -39,7 +40,7 @@ impl SelectBoundary {
blocks: BTreeMap::new(),
world: World::bounded(app.primary.map.get_bounds()),
selected: BTreeSet::new(),
draw_outline: Drawable::empty(ctx),
draw_outline: ToggleZoomed::empty(ctx),
};
ctx.loading_screen("calculate all blocks", |ctx, timer| {
@ -126,27 +127,28 @@ impl SelectBoundary {
// Draw the outline of the current blocks
let mut valid_blocks = 0;
let mut batch = GeomBatch::new();
let mut batch = ToggleZoomed::builder();
for perimeter in self.merge_selected() {
if let Ok(block) = perimeter.to_block(&app.primary.map) {
if let Ok(outline) = block.polygon.to_outline(Distance::meters(10.0)) {
// Alternate colors, to help people figure out where two disjoint boundaries
// exist
// TODO Ideally have more than 2 colors to cycle through
batch.push(
if valid_blocks % 2 == 0 {
Color::RED
} else {
Color::GREEN
},
outline,
);
}
// Alternate colors, to help people figure out where two disjoint boundaries exist
// TODO Ideally have more than 2 colors to cycle through
let color = if valid_blocks % 2 == 0 {
Color::RED
} else {
Color::GREEN
};
valid_blocks += 1;
if let Ok(outline) = block.polygon.to_outline(Distance::meters(10.0)) {
batch.unzoomed.push(color, outline);
}
if let Ok(outline) = block.polygon.to_outline(Distance::meters(5.0)) {
batch.zoomed.push(color.alpha(0.5), outline);
}
}
}
self.draw_outline = batch.upload(ctx);
self.draw_outline = batch.build(ctx);
self.panel = make_panel(ctx, app, valid_blocks == 1);
}
}
@ -212,7 +214,7 @@ impl State<App> for SelectBoundary {
fn draw(&self, g: &mut GfxCtx, _: &App) {
self.world.draw(g);
g.redraw(&self.draw_outline);
self.draw_outline.draw(g);
self.panel.draw(g);
}
}

View File

@ -114,6 +114,11 @@ impl Color {
Color::rgba_f(self.r, self.g, self.b, a)
}
/// Multiply the color's current alpha by the `factor`, returning a new color.
pub fn multiply_alpha(&self, factor: f32) -> Color {
Color::rgba_f(self.r, self.g, self.b, self.a * factor)
}
pub fn hex(raw: &str) -> Color {
// Skip the leading '#'
let r = usize::from_str_radix(&raw[1..3], 16).unwrap();

View File

@ -77,6 +77,16 @@ impl ToggleZoomedBuilder {
self
}
/// Mark that this object will be drawn differently when zoomed and unzoomed, undoing the
/// effects of converting from a single `GeomBatch`. Idempotent.
pub fn draw_differently_zoomed(mut self) -> Self {
if self.always_draw_unzoomed {
self.always_draw_unzoomed = false;
self.zoomed = self.unzoomed.clone();
}
self
}
pub fn build(self, ctx: &EventCtx) -> ToggleZoomed {
if self.always_draw_unzoomed {
assert!(self.zoomed.is_empty());

View File

@ -159,25 +159,32 @@ impl<'a, ID: ObjectID> ObjectBuilder<'a, ID> {
self.draw_hover_rewrite(RewriteColor::ChangeAlpha(alpha))
}
/// Draw the object in a hovered state by adding an outline to the normal drawing.
/// Draw the object in a hovered state by adding an outline to the normal drawing. The
/// specified `color` and `thickness` will be used when unzoomed. For the zoomed view, the
/// color's opacity and the thickness will be halved.
pub fn hover_outline(self, color: Color, thickness: Distance) -> Self {
let mut draw = self
.draw_normal
.clone()
.expect("first specify how to draw normally");
if let Ok(p) = self
.hitbox
.clone()
.expect("call hitbox first")
.to_outline(thickness)
{
draw = draw.push(color, p);
.expect("first specify how to draw normally")
.draw_differently_zoomed();
let hitbox = self.hitbox.as_ref().expect("call hitbox first");
if let (Ok(unzoomed), Ok(zoomed)) = (
hitbox.to_outline(thickness),
hitbox.to_outline(thickness / 2.0),
) {
draw.unzoomed.push(color, unzoomed);
draw.zoomed.push(color.multiply_alpha(0.5), zoomed);
} else {
warn!(
"Can't hover_outline for {:?}. Falling back to a colored polygon",
self.id
);
draw = GeomBatch::from(vec![(color, self.hitbox.clone().unwrap())]).into();
draw = GeomBatch::from(vec![(
color.multiply_alpha(0.5),
self.hitbox.clone().unwrap(),
)])
.into();
}
self.draw_hovered(draw)
}