mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-24 15:02:59 +03:00
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:
parent
4e79d19765
commit
eb4060b071
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user