start dismantling DrawBoth, and make the JustDraw API nicer

This commit is contained in:
Dustin Carlino 2020-02-06 23:08:17 -08:00
parent 1371ed35ee
commit 12826fe118
10 changed files with 136 additions and 150 deletions

View File

@ -201,6 +201,12 @@ impl<'a> GfxCtx<'a> {
// println!("{:?}", backtrace::Backtrace::new());
}
pub fn redraw_at(&mut self, top_left: ScreenPt, obj: &Drawable) {
self.fork(Pt2D::new(0.0, 0.0), top_left, 1.0);
self.redraw(obj);
self.unfork();
}
// TODO Stateful API :(
pub fn enable_clipping(&mut self, rect: ScreenRectangle) {
assert!(self.params.scissor.is_none());

View File

@ -1,6 +1,6 @@
use crate::{
Canvas, Color, Event, GfxCtx, HorizontalAlignment, Line, Prerender, ScreenDims, Text,
UserInput, VerticalAlignment,
Canvas, Color, Drawable, Event, GeomBatch, GfxCtx, HorizontalAlignment, Line, Prerender,
ScreenDims, Text, UserInput, VerticalAlignment,
};
use abstutil::{elapsed_seconds, Timer, TimerSink};
use geom::Angle;
@ -156,6 +156,11 @@ impl<'a> EventCtx<'a> {
pub fn default_line_height(&self) -> f64 {
self.prerender.assets.default_line_height
}
// TODO I can't decide which way the API should go.
pub fn upload(&self, batch: GeomBatch) -> Drawable {
self.prerender.upload(batch)
}
}
pub struct LoadingScreen<'a> {

View File

@ -217,24 +217,21 @@ impl ManagedWidget {
}
}
// TODO dupe apis!
pub fn draw_batch(ctx: &EventCtx, batch: GeomBatch) -> ManagedWidget {
ManagedWidget::new(WidgetType::Draw(JustDraw::wrap(DrawBoth::new(
ctx,
batch,
Vec::new(),
))))
JustDraw::wrap(ctx, batch)
}
pub fn just_draw(j: JustDraw) -> ManagedWidget {
pub(crate) fn just_draw(j: JustDraw) -> ManagedWidget {
ManagedWidget::new(WidgetType::Draw(j))
}
pub fn draw_text(ctx: &EventCtx, txt: Text) -> ManagedWidget {
ManagedWidget::new(WidgetType::Draw(JustDraw::text(txt, ctx)))
JustDraw::text(ctx, txt)
}
pub fn draw_svg(ctx: &EventCtx, filename: &str) -> ManagedWidget {
ManagedWidget::new(WidgetType::Draw(JustDraw::svg(filename, ctx)))
JustDraw::svg(ctx, filename)
}
// TODO Argh uncomposable APIs
pub fn draw_svg_transform(
@ -242,9 +239,7 @@ impl ManagedWidget {
filename: &str,
rewrite: RewriteColor,
) -> ManagedWidget {
ManagedWidget::new(WidgetType::Draw(JustDraw::svg_transform(
filename, rewrite, ctx,
)))
JustDraw::svg_transform(ctx, filename, rewrite)
}
pub fn btn(btn: Button) -> ManagedWidget {

View File

@ -1,18 +1,18 @@
use crate::layout::Widget;
use crate::svg;
use crate::{
text, Color, DrawBoth, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, ManagedWidget, MultiKey,
text, Color, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, ManagedWidget, MultiKey,
RewriteColor, ScreenDims, ScreenPt, Text,
};
use geom::{Bounds, Polygon, Pt2D};
use geom::Polygon;
pub struct Button {
pub action: String,
// Both of these must have the same dimensions and are oriented with their top-left corner at
// 0, 0. Transformation happens later.
draw_normal: DrawBoth,
draw_hovered: DrawBoth,
draw_normal: Drawable,
draw_hovered: Drawable,
hotkey: Option<MultiKey>,
tooltip: Text,
@ -27,9 +27,10 @@ pub struct Button {
}
impl Button {
// TODO Take ctx and upload here, probably
pub fn new(
draw_normal: DrawBoth,
draw_hovered: DrawBoth,
draw_normal: Drawable,
draw_hovered: Drawable,
hotkey: Option<MultiKey>,
tooltip: &str,
hitbox: Polygon,
@ -104,9 +105,9 @@ impl Button {
pub(crate) fn draw(&self, g: &mut GfxCtx) {
if self.hovering {
self.draw_hovered.redraw(self.top_left, g);
g.redraw_at(self.top_left, &self.draw_hovered);
} else {
self.draw_normal.redraw(self.top_left, g);
g.redraw_at(self.top_left, &self.draw_normal);
}
}
}
@ -144,22 +145,14 @@ impl Button {
VERT_PADDING,
);
let normal = DrawBoth::new(
ctx,
GeomBatch::from(vec![
let normal = ctx.upload(GeomBatch::from(vec![
(Color::WHITE, bg.clone()),
(img_color, img_rect.clone()),
]),
vec![],
);
let hovered = DrawBoth::new(
ctx,
GeomBatch::from(vec![
]));
let hovered = ctx.upload(GeomBatch::from(vec![
(Color::ORANGE, bg.clone()),
(img_color, img_rect.clone()),
]),
vec![],
);
]));
Button::new(normal, hovered, key, label, bg)
}
@ -177,8 +170,8 @@ impl Button {
hovered.rewrite_color(hover);
Button::new(
DrawBoth::new(ctx, normal, Vec::new()),
DrawBoth::new(ctx, hovered, Vec::new()),
ctx.upload(normal),
ctx.upload(hovered),
key,
tooltip,
bounds.get_rectangle(),
@ -201,8 +194,8 @@ impl Button {
hovered.rewrite_color(hover);
Button::new(
DrawBoth::new(ctx, normal, Vec::new()),
DrawBoth::new(ctx, hovered, Vec::new()),
ctx.upload(normal),
ctx.upload(hovered),
key,
tooltip,
bounds.get_rectangle(),
@ -220,26 +213,27 @@ impl Button {
const HORIZ_PADDING: f64 = 30.0;
const VERT_PADDING: f64 = 10.0;
let dims = text.clone().dims(&ctx.prerender.assets);
let txt_batch = text.render(&ctx.prerender.assets);
let dims = txt_batch.get_dims();
let geom = Polygon::rounded_rectangle(
dims.width + 2.0 * HORIZ_PADDING,
dims.height + 2.0 * VERT_PADDING,
VERT_PADDING,
);
let draw_text = vec![(text, ScreenPt::new(HORIZ_PADDING, VERT_PADDING))];
let normal = DrawBoth::new(
ctx,
GeomBatch::from(vec![(unselected_bg_color, geom.clone())]),
draw_text.clone(),
);
let hovered = DrawBoth::new(
ctx,
GeomBatch::from(vec![(selected_bg_color, geom.clone())]),
draw_text.clone(),
);
let mut normal = GeomBatch::from(vec![(unselected_bg_color, geom.clone())]);
normal.add_translated(txt_batch.clone(), HORIZ_PADDING, VERT_PADDING);
Button::new(normal, hovered, hotkey, tooltip, geom)
let mut hovered = GeomBatch::from(vec![(selected_bg_color, geom.clone())]);
hovered.add_translated(txt_batch.clone(), HORIZ_PADDING, VERT_PADDING);
Button::new(
ctx.upload(normal),
ctx.upload(hovered),
hotkey,
tooltip,
geom,
)
}
pub fn text_no_bg(
@ -255,47 +249,49 @@ impl Button {
let horiz_padding = if padding { 15.0 } else { 0.0 };
let vert_padding = if padding { 8.0 } else { 0.0 };
let dims = unselected_text.clone().dims(&ctx.prerender.assets);
assert_eq!(dims, selected_text.clone().dims(&ctx.prerender.assets));
let unselected_batch = unselected_text.render(&ctx.prerender.assets);
let dims = unselected_batch.get_dims();
let selected_batch = selected_text.render(&ctx.prerender.assets);
assert_eq!(dims, selected_batch.get_dims());
let geom = Polygon::rectangle(
dims.width + 2.0 * horiz_padding,
dims.height + 2.0 * vert_padding,
);
let normal = DrawBoth::new(
ctx,
GeomBatch::new(),
vec![(unselected_text, ScreenPt::new(horiz_padding, vert_padding))],
);
let hovered = DrawBoth::new(
ctx,
GeomBatch::new(),
vec![(selected_text, ScreenPt::new(horiz_padding, vert_padding))],
);
let mut normal = GeomBatch::new();
normal.add_translated(unselected_batch, horiz_padding, vert_padding);
let mut hovered = GeomBatch::new();
hovered.add_translated(selected_batch, horiz_padding, vert_padding);
Button::new(normal, hovered, hotkey, tooltip, geom)
Button::new(
ctx.upload(normal),
ctx.upload(hovered),
hotkey,
tooltip,
geom,
)
}
// TODO Extreme wackiness.
pub fn inactive_btn(ctx: &EventCtx, mut txt: Text) -> ManagedWidget {
pub fn inactive_btn(ctx: &EventCtx, txt: Text) -> ManagedWidget {
let txt_batch = txt
.change_fg(Color::grey(0.5))
.render(&ctx.prerender.assets);
let dims = txt_batch.get_dims();
let horiz_padding = 15.0;
let vert_padding = 8.0;
txt = txt.change_fg(Color::grey(0.5));
let dims = txt.clone().dims(&ctx.prerender.assets);
let mut draw = DrawBoth::new(
ctx,
GeomBatch::new(),
vec![(txt, ScreenPt::new(horiz_padding, vert_padding))],
);
draw.override_bounds(Bounds::from(&vec![
Pt2D::new(0.0, 0.0),
Pt2D::new(
let mut batch = GeomBatch::new();
batch.add_translated(txt_batch, horiz_padding, vert_padding);
ManagedWidget::just_draw(JustDraw {
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
dims: ScreenDims::new(
dims.width + 2.0 * horiz_padding,
dims.height + 2.0 * vert_padding,
),
]));
ManagedWidget::just_draw(JustDraw::wrap(draw)).outline(2.0, Color::WHITE)
})
.outline(2.0, Color::WHITE)
}
pub fn inactive_button<S: Into<String>>(ctx: &mut EventCtx, label: S) -> ManagedWidget {
Button::inactive_btn(ctx, Text::from(Line(label)))
@ -305,18 +301,17 @@ impl Button {
const HORIZ_PADDING: f64 = 30.0;
const VERT_PADDING: f64 = 10.0;
let txt = Text::from(Line(label).fg(Color::BLACK));
let dims = txt.clone().dims(&ctx.prerender.assets);
let geom = Polygon::rounded_rectangle(
let txt = Text::from(Line(label).fg(Color::BLACK)).render(&ctx.prerender.assets);
let dims = txt.get_dims();
let mut batch = GeomBatch::from(vec![(
Color::WHITE,
Polygon::rounded_rectangle(
dims.width + 2.0 * HORIZ_PADDING,
dims.height + 2.0 * VERT_PADDING,
VERT_PADDING,
);
ManagedWidget::just_draw(JustDraw::wrap(DrawBoth::new(
ctx,
GeomBatch::from(vec![(Color::WHITE, geom)]),
vec![(txt, ScreenPt::new(HORIZ_PADDING, VERT_PADDING))],
)))
),
)]);
batch.add_translated(txt, HORIZ_PADDING, VERT_PADDING);
JustDraw::wrap(ctx, batch)
}
}

View File

@ -1,70 +1,66 @@
use crate::layout::Widget;
use crate::svg;
use crate::{DrawBoth, EventCtx, GeomBatch, GfxCtx, RewriteColor, ScreenDims, ScreenPt, Text};
use crate::{
Drawable, EventCtx, GeomBatch, GfxCtx, ManagedWidget, RewriteColor, ScreenDims, ScreenPt, Text,
};
// Just draw something. A widget just so layouting works.
pub struct JustDraw {
draw: DrawBoth,
pub(crate) draw: Drawable,
top_left: ScreenPt,
pub(crate) top_left: ScreenPt,
pub(crate) dims: ScreenDims,
}
impl JustDraw {
pub fn wrap(draw: DrawBoth) -> JustDraw {
JustDraw {
draw,
pub fn wrap(ctx: &EventCtx, batch: GeomBatch) -> ManagedWidget {
ManagedWidget::just_draw(JustDraw {
dims: batch.get_dims(),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
}
})
}
pub fn image(filename: &str, ctx: &EventCtx) -> JustDraw {
pub fn image(ctx: &EventCtx, filename: &str) -> ManagedWidget {
let (color, rect) = ctx.canvas.texture_rect(filename);
let batch = GeomBatch::from(vec![(color, rect)]);
JustDraw {
draw: DrawBoth::new(ctx, batch, vec![]),
top_left: ScreenPt::new(0.0, 0.0),
}
JustDraw::wrap(ctx, batch)
}
pub fn svg(filename: &str, ctx: &EventCtx) -> JustDraw {
pub fn svg(ctx: &EventCtx, filename: &str) -> ManagedWidget {
let mut batch = GeomBatch::new();
let bounds = svg::add_svg(&mut batch, filename);
let mut draw = DrawBoth::new(ctx, batch, vec![]);
// TODO The dims will be wrong; it'll only look at geometry, not the padding in the image.
draw.override_bounds(bounds);
JustDraw {
draw,
ManagedWidget::just_draw(JustDraw {
dims: ScreenDims::new(bounds.width(), bounds.height()),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
})
}
}
pub fn svg_transform(filename: &str, rewrite: RewriteColor, ctx: &EventCtx) -> JustDraw {
pub fn svg_transform(ctx: &EventCtx, filename: &str, rewrite: RewriteColor) -> ManagedWidget {
let mut batch = GeomBatch::new();
let bounds = svg::add_svg(&mut batch, filename);
batch.rewrite_color(rewrite);
let mut draw = DrawBoth::new(ctx, batch, vec![]);
// TODO The dims will be wrong; it'll only look at geometry, not the padding in the image.
draw.override_bounds(bounds);
JustDraw {
draw,
ManagedWidget::just_draw(JustDraw {
dims: ScreenDims::new(bounds.width(), bounds.height()),
draw: ctx.upload(batch),
top_left: ScreenPt::new(0.0, 0.0),
}
})
}
pub fn text(text: Text, ctx: &EventCtx) -> JustDraw {
JustDraw {
draw: DrawBoth::new(ctx, GeomBatch::new(), vec![(text, ScreenPt::new(0.0, 0.0))]),
top_left: ScreenPt::new(0.0, 0.0),
}
pub fn text(ctx: &EventCtx, text: Text) -> ManagedWidget {
JustDraw::wrap(ctx, text.render(&ctx.prerender.assets))
}
pub(crate) fn draw(&self, g: &mut GfxCtx) {
self.draw.redraw(self.top_left, g);
g.redraw_at(self.top_left, &self.draw);
}
}
impl Widget for JustDraw {
fn get_dims(&self) -> ScreenDims {
self.draw.get_dims()
self.dims
}
fn set_pos(&mut self, top_left: ScreenPt) {

View File

@ -6,7 +6,7 @@ use crate::render::{AgentColorScheme, MIN_ZOOM_FOR_DETAIL};
use crate::ui::UI;
use abstutil::clamp;
use ezgui::{
hotkey, Button, Choice, Color, Composite, DrawBoth, EventCtx, Filler, GeomBatch, GfxCtx,
hotkey, Button, Choice, Color, Composite, EventCtx, Filler, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, ScreenDims, ScreenPt,
Text, VerticalAlignment,
};
@ -297,16 +297,8 @@ fn make_minimap_panel(ctx: &mut EventCtx, acs: &AgentColorScheme, zoom_lvl: usiz
};
let rect = Polygon::rectangle(20.0, 8.0);
zoom_col.push(ManagedWidget::btn(Button::new(
DrawBoth::new(
ctx,
GeomBatch::from(vec![(color, rect.clone())]),
Vec::new(),
),
DrawBoth::new(
ctx,
GeomBatch::from(vec![(colors::HOVERING, rect.clone())]),
Vec::new(),
),
ctx.upload(GeomBatch::from(vec![(color, rect.clone())])),
ctx.upload(GeomBatch::from(vec![(colors::HOVERING, rect.clone())])),
None,
&format!("zoom to level {}", i + 1),
rect,

View File

@ -7,7 +7,7 @@ use crate::managed::{ManagedGUIState, WrappedComposite, WrappedOutcome};
use crate::ui::UI;
use abstutil::{prettyprint_usize, Counter};
use ezgui::{
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx, Histogram,
hotkey, Button, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx, Histogram,
HorizontalAlignment, JustDraw, Key, Line, ManagedWidget, Outcome, Plot, RewriteColor, Series,
Text, VerticalAlignment,
};
@ -723,8 +723,7 @@ impl Overlays {
.to_polygon(),
);
}
let timeline =
ManagedWidget::just_draw(JustDraw::wrap(DrawBoth::new(ctx, batch, Vec::new())));
let timeline = JustDraw::wrap(ctx, batch);
master_col.push(ManagedWidget::row(vec![
timeline.margin(5),

View File

@ -6,8 +6,8 @@ use crate::options::TrafficSignalStyle;
use crate::render::{dashed_lines, draw_signal_phase, DrawOptions, DrawTurn};
use crate::ui::{ShowEverything, UI};
use ezgui::{
hotkey, Button, Color, Composite, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, ManagedWidget, ModalMenu, Outcome, Text, VerticalAlignment,
hotkey, Button, Color, Composite, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment,
Key, Line, ManagedWidget, ModalMenu, Outcome, Text, VerticalAlignment,
};
use geom::{Distance, Polygon, Time};
use map_model::{IntersectionID, LaneID, Map, TurnType};
@ -325,8 +325,8 @@ fn make_diagram(i: IntersectionID, selected: usize, ui: &UI, ctx: &mut EventCtx)
col.push(
ManagedWidget::btn(Button::new(
DrawBoth::new(ctx, normal, Vec::new()),
DrawBoth::new(ctx, hovered, Vec::new()),
ctx.upload(normal),
ctx.upload(hovered),
None,
&format!("phase {}", idx + 1),
bbox.clone(),

View File

@ -10,9 +10,8 @@ use crate::sandbox::{spawn_agents_around, SpeedControls, TimePanel};
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, lctrl, Button, Choice, Color, Composite, DrawBoth, EventCtx, EventLoopMode, GeomBatch,
GfxCtx, HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, Text,
VerticalAlignment,
hotkey, lctrl, Button, Choice, Color, Composite, EventCtx, EventLoopMode, GeomBatch, GfxCtx,
HorizontalAlignment, Key, Line, ManagedWidget, Outcome, RewriteColor, Text, VerticalAlignment,
};
use geom::{Distance, Duration, Polygon};
use map_model::{ControlTrafficSignal, EditCmd, IntersectionID, Phase, TurnGroupID, TurnPriority};
@ -557,8 +556,8 @@ fn make_diagram(i: IntersectionID, selected: usize, ui: &UI, ctx: &mut EventCtx)
col.push(
ManagedWidget::row(vec![
ManagedWidget::btn(Button::new(
DrawBoth::new(ctx, normal, Vec::new()),
DrawBoth::new(ctx, hovered, Vec::new()),
ctx.upload(normal),
ctx.upload(hovered),
None,
&format!("phase {}", idx + 1),
bbox.clone(),

View File

@ -29,8 +29,7 @@ impl TitleScreen {
composite: WrappedComposite::new(
Composite::new(
ManagedWidget::col(vec![
ManagedWidget::just_draw(JustDraw::image("assets/pregame/logo.png", ctx))
.bg(Color::GREEN.alpha(0.2)),
JustDraw::image(ctx, "assets/pregame/logo.png").bg(Color::GREEN.alpha(0.2)),
// TODO that nicer font
// TODO Any key
ManagedWidget::btn(Button::text_bg(