more concise Text / tooltip()

This commit is contained in:
Michael Kirk 2021-03-19 16:02:43 -07:00 committed by Dustin Carlino
parent 2bebd8a2c9
commit affd582093
65 changed files with 259 additions and 272 deletions

View File

@ -405,9 +405,9 @@ impl HoverOnBuilding {
HoverOnBuilding {
tooltip: if let Some(time) = isochrone.time_to_reach_building.get(&hover_id) {
Text::from(Line(format!("{} away", time)))
Text::from(format!("{} away", time))
} else {
Text::from(Line("This is more than 15 minutes away"))
Text::from("This is more than 15 minutes away")
},
drawn_route: ctx.upload(batch),
}
@ -469,7 +469,7 @@ impl ExploreAmenities {
);
table.column(
"Type",
Box::new(|ctx, _, x| Text::from(Line(&x.amenity_type)).render(ctx)),
Box::new(|ctx, _, x| Text::from(&x.amenity_type).render(ctx)),
Col::Sortable(Box::new(|rows| {
rows.sort_by_key(|x| x.amenity_type.clone())
})),
@ -479,7 +479,7 @@ impl ExploreAmenities {
table.column(
"Time to reach",
Box::new(|ctx, app, x| {
Text::from(Line(x.duration_away.to_string(&app.opts.units))).render(ctx)
Text::from(x.duration_away.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.duration_away))),
);

View File

@ -211,7 +211,7 @@ impl ChallengesPicker {
let challenge = Challenge::all().remove(name).unwrap().remove(current);
let mut txt = Text::new();
for l in &challenge.description {
txt.add(Line(l));
txt.add(l);
}
let mut inner_col = vec![
@ -224,14 +224,14 @@ impl ChallengesPicker {
];
if let Some(scores) = app.session.high_scores.get(&challenge.gameplay) {
let mut txt = Text::from(Line(format!("{} high scores:", scores.len())));
txt.add(Line(format!("Goal: {}", scores[0].goal)));
let mut txt = Text::from(format!("{} high scores:", scores.len()));
txt.add(format!("Goal: {}", scores[0].goal));
let mut idx = 1;
for score in scores {
txt.add(Line(format!(
txt.add(format!(
"{}) {}, using proposal: {}",
idx, score.score, score.edits_name
)));
));
idx += 1;
}
inner_col.push(txt.into_widget(ctx));

View File

@ -267,7 +267,7 @@ impl CommonState {
);
if app.opts.dev && !g.is_screencap() {
let dev_batch = Text::from(Line("DEV")).bg(Color::RED).render(g);
let dev_batch = Text::from("DEV").bg(Color::RED).render(g);
let dims = dev_batch.get_dims();
batch.append(dev_batch.translate(
g.canvas.window_width - dims.width - 10.0,

View File

@ -42,7 +42,7 @@ impl Viewer {
.into_widget(ctx),
ctx.style().btn_close_widget(ctx),
]),
Text::from(Line("Root causes"))
Text::from("Root causes")
.into_widget(ctx)
.named("root causes"),
]))

View File

@ -157,19 +157,16 @@ impl DebugMode {
fn reset_info(&mut self, ctx: &mut EventCtx) {
let mut txt = Text::new();
if !self.hidden.is_empty() {
txt.add(Line(format!("Hiding {} things", self.hidden.len())));
txt.add(format!("Hiding {} things", self.hidden.len()));
}
if let Some(ref results) = self.search_results {
txt.add(Line(format!(
txt.add(format!(
"Search for {} has {} results",
results.query, results.num_matches
)));
));
}
if let Some((n, _)) = self.all_routes {
txt.add(Line(format!(
"Showing {} routes",
abstutil::prettyprint_usize(n)
)));
txt.add(format!("Showing {} routes", abstutil::prettyprint_usize(n)));
}
self.panel
.replace(ctx, "current info", txt.into_widget(ctx));

View File

@ -1,7 +1,7 @@
use map_gui::ID;
use map_model::{Map, PathConstraints};
use sim::{AgentID, Sim};
use widgetry::{GfxCtx, Key, Line, Text};
use widgetry::{GfxCtx, Key, Text};
use crate::app::App;
@ -12,16 +12,14 @@ impl ObjectDebugger {
if g.is_key_down(Key::LeftControl) {
if let Some(pt) = g.canvas.get_cursor_in_map_space() {
let mut txt = Text::new();
txt.add(Line(pt.to_string()));
txt.add(Line(
pt.to_gps(app.primary.map.get_gps_bounds()).to_string(),
));
txt.add(Line(format!("{:?}", g.canvas.get_cursor())));
txt.add(Line(format!("zoom: {}", g.canvas.cam_zoom)));
txt.add(Line(format!(
txt.add(pt.to_string());
txt.add(pt.to_gps(app.primary.map.get_gps_bounds()).to_string());
txt.add(format!("{:?}", g.canvas.get_cursor()));
txt.add(format!("zoom: {}", g.canvas.cam_zoom));
txt.add(format!(
"cam_x = {}, cam_y = {}",
g.canvas.cam_x, g.canvas.cam_y
)));
));
g.draw_mouse_tooltip(txt);
}
}

View File

@ -95,7 +95,7 @@ impl State<App> for PathCounter {
} {
let n = self.cnt.get(r);
if n > 0 {
self.tooltip = Some(Text::from(Line(abstutil::prettyprint_usize(n))));
self.tooltip = Some(Text::from(abstutil::prettyprint_usize(n)));
}
} else {
app.primary.current_selection = None;

View File

@ -102,7 +102,7 @@ impl State<App> for PolygonDebugger {
match &self.items[self.idx] {
Item::Point(pt) => {
batch.append(
Text::from(Line(self.idx.to_string()))
Text::from(self.idx.to_string())
.bg(app.cs.panel_bg)
.render(g)
.centered_on(g.canvas.map_to_screen(*pt).to_pt()),
@ -111,7 +111,7 @@ impl State<App> for PolygonDebugger {
Item::Triangle(ref tri) => {
for pt in &[tri.pt1, tri.pt2, tri.pt3] {
batch.append(
Text::from(Line(self.idx.to_string()))
Text::from(self.idx.to_string())
.bg(app.cs.panel_bg)
.render(g)
.centered_on(g.canvas.map_to_screen(*pt).to_pt()),
@ -122,7 +122,7 @@ impl State<App> for PolygonDebugger {
Item::Polygon(ref poly) => {
g.draw_polygon(app.cs.selected, poly.clone());
batch.append(
Text::from(Line(self.idx.to_string()))
Text::from(self.idx.to_string())
.bg(app.cs.panel_bg)
.render(g)
.centered_on(g.canvas.map_to_screen(poly.center()).to_pt()),
@ -131,7 +131,7 @@ impl State<App> for PolygonDebugger {
}
if let Some(pt) = self.center {
batch.append(
Text::from(Line("c"))
Text::from("c")
.bg(app.cs.panel_bg)
.render(g)
.centered_on(g.canvas.map_to_screen(pt).to_pt()),

View File

@ -407,8 +407,8 @@ impl State<App> for AllRoutesExplorer {
let current = self.current_counts.get(r);
let mut txt = Text::new();
txt.append_all(cmp_count(current, baseline));
txt.add(Line(format!("{} baseline", prettyprint_usize(baseline))));
txt.add(Line(format!("{} now", prettyprint_usize(current))));
txt.add(format!("{} baseline", prettyprint_usize(baseline)));
txt.add(format!("{} now", prettyprint_usize(current)));
self.tooltip = Some(txt);
}
}

View File

@ -198,13 +198,13 @@ impl Dataviz {
for (r, cnt) in per_road.borrow() {
tooltips.push((
map.get_r(*r).get_thick_polygon(map),
Text::from(Line(format!("{} collisions", prettyprint_usize(*cnt)))),
Text::from(format!("{} collisions", prettyprint_usize(*cnt))),
));
}
for (i, cnt) in per_intersection.borrow() {
tooltips.push((
map.get_i(*i).polygon.clone(),
Text::from(Line(format!("{} collisions", prettyprint_usize(*cnt)))),
Text::from(format!("{} collisions", prettyprint_usize(*cnt))),
));
}
let tooltips = MapspaceTooltips::new(

View File

@ -74,19 +74,19 @@ impl PopularDestinations {
by_type.add(None, *cnt);
}
}
let mut breakdown = Text::from(Line("Breakdown by type"));
let mut breakdown = Text::from("Breakdown by type");
let mut list = by_type.consume().into_iter().collect::<Vec<_>>();
list.sort_by_key(|(_, cnt)| *cnt);
list.reverse();
let sum = per_bldg.sum() as f64;
for (category, cnt) in list {
breakdown.add(Line(format!(
breakdown.add(format!(
"{}: {}%",
category
.map(|x| x.to_string())
.unwrap_or("other".to_string()),
((cnt as f64) / sum * 100.0) as usize
)));
));
}
Box::new(PopularDestinations {
@ -151,16 +151,16 @@ impl State<App> for PopularDestinations {
if let Some(ID::Building(b)) = app.primary.current_selection {
let mut txt = Text::new();
txt.add(Line(format!(
txt.add(format!(
"{} trips to here",
abstutil::prettyprint_usize(self.per_bldg.get(b))
)));
));
for a in &app.primary.map.get_b(b).amenities {
txt.add(Line(format!(
txt.add(format!(
" {} ({})",
a.names.get(app.opts.language.as_ref()),
a.amenity_type
)));
));
}
g.draw_mouse_tooltip(txt);
}

View File

@ -199,7 +199,7 @@ impl State<App> for ViewKML {
g.draw_polygon(Color::BLUE, obj.polygon.clone());
let mut txt = Text::new();
for (k, v) in &obj.attribs {
txt.add(Line(format!("{} = {}", k, v)));
txt.add(format!("{} = {}", k, v));
}
g.draw_mouse_tooltip(txt);

View File

@ -136,11 +136,7 @@ impl State<App> for PolygonEditor {
self.panel.draw(g);
if self.mouseover_pt.is_some() {
CommonState::draw_custom_osd(
g,
app,
Text::from(Line("hold left Control to move point")),
);
CommonState::draw_custom_osd(g, app, Text::from("hold left Control to move point"));
} else {
CommonState::draw_osd(g, app);
}

View File

@ -425,7 +425,7 @@ impl Marker {
)),
);
batch.append(
Text::from(Line(&event))
Text::from(&event)
.with_bg()
.render_autocropped(ctx)
.scale(0.5)
@ -440,7 +440,7 @@ impl Marker {
}
// TODO Refactor
batch.append(
Text::from(Line(&event))
Text::from(&event)
.with_bg()
.render_autocropped(ctx)
.scale(0.5)
@ -466,7 +466,7 @@ impl Marker {
.color(RewriteColor::Change(Color::hex("#5B5B5B"), Color::RED)),
);
batch.append(
Text::from(Line(&self.event))
Text::from(&self.event)
.with_bg()
.render_autocropped(g)
.scale(0.75)
@ -476,7 +476,7 @@ impl Marker {
batch.push(Color::RED, Ring::must_new(self.pts.clone()).to_polygon());
// TODO Refactor plz
batch.append(
Text::from(Line(&self.event))
Text::from(&self.event)
.with_bg()
.render_autocropped(g)
.scale(0.75)

View File

@ -122,7 +122,7 @@ impl ShowRelative {
} else {
let offset = app.primary.map.get_traffic_signal(*i).offset - base_offset;
batch.append(
Text::from(Line(offset.to_string(&app.opts.units)))
Text::from(offset.to_string(&app.opts.units))
.bg(Color::PURPLE)
.render_autocropped(ctx)
.color(RewriteColor::ChangeAlpha(0.8))

View File

@ -219,10 +219,10 @@ fn draw_zone(
fn make_instructions(ctx: &mut EventCtx, allow_through_traffic: &BTreeSet<TripMode>) -> Widget {
if allow_through_traffic == &TripMode::all().into_iter().collect() {
Text::from(Line(
Text::from(
"Through-traffic is allowed for everyone, meaning this is just a normal public road. \
Would you like to restrict it?",
))
)
.wrap_to_pct(ctx, 30)
.into_widget(ctx)
} else {

View File

@ -54,23 +54,23 @@ pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID
let mut txt = Text::new();
if !b.amenities.is_empty() {
txt.add(Line(""));
txt.add("");
if b.amenities.len() == 1 {
txt.add(Line("1 amenity:"));
txt.add("1 amenity:");
} else {
txt.add(Line(format!("{} amenities:", b.amenities.len())));
txt.add(format!("{} amenities:", b.amenities.len()));
}
for a in &b.amenities {
txt.add(Line(format!(
txt.add(format!(
" {} ({})",
a.names.get(app.opts.language.as_ref()),
a.amenity_type
)));
));
}
}
if !app.primary.sim.infinite_parking() {
txt.add(Line(""));
txt.add("");
if let Some(pl) = app
.primary
.sim
@ -97,7 +97,7 @@ pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID
),
);
} else {
txt.add(Line("No nearby parking available"))
txt.add("No nearby parking available")
}
}

View File

@ -67,7 +67,7 @@ pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID)
}
}
let mut txt = Text::new();
txt.add(Line("Total"));
txt.add("Total");
txt.append(
Line(format!(
": {} boardings, {} alightings",
@ -77,7 +77,7 @@ pub fn stop(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusStopID)
.secondary(),
);
for r in app.primary.map.get_routes_serving_stop(id) {
txt.add(Line(format!("Route {}", r.short_name)));
txt.add(format!("Route {}", r.short_name));
txt.append(
Line(format!(
": {} boardings, {} alightings",
@ -178,7 +178,7 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
header_btns(ctx),
]));
rows.push(
Text::from(Line(&route.full_name))
Text::from(&route.full_name)
.wrap_to_pct(ctx, 20)
.into_widget(ctx),
);
@ -354,11 +354,11 @@ pub fn route(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BusRouteI
// TODO Unit test
fn describe_schedule(route: &BusRoute) -> Text {
let mut txt = Text::new();
txt.add(Line(format!(
txt.add(format!(
"{} {}s run this route daily",
route.spawn_times.len(),
route.plural_noun()
)));
));
if false {
// Compress the times
@ -371,12 +371,12 @@ fn describe_schedule(route: &BusRoute) -> Text {
if Some(new_dt) == dt {
last = Some(*t);
} else {
txt.add(Line(format!(
txt.add(format!(
"Every {} from {} to {}",
dt.unwrap(),
start.ampm_tostring(),
l.ampm_tostring()
)));
));
start = l;
last = Some(*t);
dt = Some(new_dt);
@ -387,16 +387,16 @@ fn describe_schedule(route: &BusRoute) -> Text {
}
}
// Handle end
txt.add(Line(format!(
txt.add(format!(
"Every {} from {} to {}",
dt.unwrap(),
start.ampm_tostring(),
last.unwrap().ampm_tostring()
)));
));
} else {
// Just list the times
for t in &route.spawn_times {
txt.add(Line(t.ampm_tostring()));
txt.add(t.ampm_tostring());
}
}
txt

View File

@ -19,7 +19,7 @@ pub fn info(ctx: &EventCtx, app: &App, details: &mut Details, id: IntersectionID
let mut rows = header(ctx, app, details, id, Tab::IntersectionInfo(id));
let i = app.primary.map.get_i(id);
let mut txt = Text::from(Line("Connecting"));
let mut txt = Text::from("Connecting");
let mut road_names = BTreeSet::new();
for r in &i.roads {
road_names.insert(
@ -30,7 +30,7 @@ pub fn info(ctx: &EventCtx, app: &App, details: &mut Details, id: IntersectionID
);
}
for r in road_names {
txt.add(Line(format!(" {}", r)));
txt.add(format!(" {}", r));
}
rows.push(txt.into_widget(ctx));
@ -63,7 +63,7 @@ pub fn traffic(
let mut txt = Text::new();
txt.add(Line(format!(
txt.add(format!(
"Since midnight: {} commuters and vehicles crossed",
prettyprint_usize(
app.primary
@ -72,7 +72,7 @@ pub fn traffic(
.intersection_thruput
.total_for(id)
)
)));
));
rows.push(txt.into_widget(ctx));
rows.push(opts.to_controls(ctx, app));
@ -179,7 +179,7 @@ pub fn current_demand(
outlines.push(p);
}
batch.push(Color::hex("#A3A3A3"), arrow.clone());
tooltips.push((arrow, Text::from(Line(prettyprint_usize(demand)))));
tooltips.push((arrow, Text::from(prettyprint_usize(demand))));
}
batch.extend(Color::WHITE, outlines);
@ -278,14 +278,14 @@ pub fn traffic_signal(
{
let mut txt = Text::new();
txt.add(Line(format!("{} stages", signal.stages.len())).small_heading());
txt.add(Line(format!("Signal offset: {}", signal.offset)));
txt.add(format!("Signal offset: {}", signal.offset));
{
let mut total = Duration::ZERO;
for s in &signal.stages {
total += s.stage_type.simple_duration();
}
// TODO Say "normally" or something?
txt.add(Line(format!("One cycle lasts {}", total)));
txt.add(format!("One cycle lasts {}", total));
}
rows.push(txt.into_widget(ctx));
}

View File

@ -178,8 +178,8 @@ pub fn debug(ctx: &EventCtx, app: &App, details: &mut Details, id: LaneID) -> Ve
.build_widget(ctx, format!("open {}", r.orig_id.osm_way_id)),
);
let mut txt = Text::from(Line(""));
txt.add(Line("Raw OpenStreetMap data"));
let mut txt = Text::from("");
txt.add("Raw OpenStreetMap data");
rows.push(txt.into_widget(ctx));
rows.extend(make_table(
@ -207,11 +207,11 @@ pub fn traffic(
let r = map.get_r(l.parent);
// Since this applies to the entire road, ignore lane type.
let mut txt = Text::from(Line("Traffic over entire road, not just this lane"));
txt.add(Line(format!(
let mut txt = Text::from("Traffic over entire road, not just this lane");
txt.add(format!(
"Since midnight: {} commuters and vehicles crossed",
prettyprint_usize(app.primary.sim.get_analytics().road_thruput.total_for(r.id))
)));
));
rows.push(txt.into_widget(ctx));
rows.push(opts.to_controls(ctx, app));

View File

@ -409,12 +409,7 @@ pub fn schedule(
TripEndpoint::SuddenlyAppear(_) => "suddenly appear".to_string(),
};
rows.push(
Text::from(Line(format!(
" Spends {} at {}",
trip.departure - last_t,
at
)))
.into_widget(ctx),
Text::from(format!(" Spends {} at {}", trip.departure - last_t, at)).into_widget(ctx),
);
// TODO Ideally end time if we know
last_t = trip.departure;

View File

@ -596,7 +596,7 @@ fn make_timeline(
norm_color,
build_text(app, &msgs, norm_distance),
));
let mut display_txt = Text::from(Line(&p.phase_type.describe(map)));
let mut display_txt = Text::from(&p.phase_type.describe(map));
display_txt.add(Line(format!(
" Road: {}",
map.get_r(lane_detail.parent)
@ -624,7 +624,7 @@ fn make_timeline(
build_text(app, &msgs, norm_distance),
));
let mut display_txt = Text::from(Line(&p.phase_type.describe(map)));
let mut display_txt = Text::from(&p.phase_type.describe(map));
display_txt.add(Line(format!(" Intersection: {}", id.parent)));
display_txt.add(Line(format!(
" Delay: {}",
@ -706,7 +706,7 @@ fn make_trip_details(
ctx.style()
.btn_plain
.icon("system/assets/timeline/start_pos.svg")
.tooltip(Text::from(Line(name)))
.tooltip(name)
.build_widget(ctx, format!("jump to start of {}", trip_id))
};
@ -739,7 +739,7 @@ fn make_trip_details(
ctx.style()
.btn_plain
.icon("system/assets/timeline/goal_pos.svg")
.tooltip(Text::from(Line(name)))
.tooltip(name)
.build_widget(ctx, format!("jump to goal of {}", trip_id))
};
@ -814,10 +814,10 @@ fn make_trip_details(
.btn_plain
.icon("system/assets/speed/jump_to_time.svg")
.tooltip({
let mut txt = Text::from(Line("This will jump to "));
let mut txt = Text::from("This will jump to ");
txt.append(Line(trip.departure.ampm_tostring()).fg(Color::hex("#F9EC51")));
txt.add(Line("The simulation will continue, and your score"));
txt.add(Line("will be calculated at this new time."));
txt.add("The simulation will continue, and your score");
txt.add("will be calculated at this new time.");
txt
})
.build_widget(ctx, format!("jump to {}", trip.departure))
@ -833,10 +833,10 @@ fn make_trip_details(
.btn_plain
.icon("system/assets/speed/jump_to_time.svg")
.tooltip({
let mut txt = Text::from(Line("This will jump to "));
let mut txt = Text::from("This will jump to ");
txt.append(Line(t.ampm_tostring()).fg(Color::hex("#F9EC51")));
txt.add(Line("The simulation will continue, and your score"));
txt.add(Line("will be calculated at this new time."));
txt.add("The simulation will continue, and your score");
txt.add("will be calculated at this new time.");
txt
})
.build_widget(ctx, format!("jump to {}", t))

View File

@ -42,7 +42,7 @@ impl Layer for BikeActivity {
.road_thruput
.total_for_with_agent_types(r, btreeset! { AgentType::Bike });
if cnt > 0 {
self.tooltip = Some(Text::from(Line(prettyprint_usize(cnt))));
self.tooltip = Some(Text::from(prettyprint_usize(cnt)));
}
}
}

View File

@ -129,7 +129,7 @@ impl Layer for Throughput {
.road_thruput
.total_for_with_agent_types(r, self.agent_types.clone());
if cnt > 0 {
self.tooltip = Some(Text::from(Line(prettyprint_usize(cnt))));
self.tooltip = Some(Text::from(prettyprint_usize(cnt)));
}
}
Some(ID::Intersection(i)) => {
@ -140,7 +140,7 @@ impl Layer for Throughput {
.intersection_thruput
.total_for_with_agent_types(i, self.agent_types.clone());
if cnt > 0 {
self.tooltip = Some(Text::from(Line(prettyprint_usize(cnt))));
self.tooltip = Some(Text::from(prettyprint_usize(cnt)));
}
}
_ => {}

View File

@ -92,7 +92,7 @@ impl MainMenu {
let col = vec![
{
let mut txt = Text::from(Line("A/B STREET").display_title());
txt.add(Line("Created by Dustin Carlino, Yuwen Li, & Michael Kirk"));
txt.add("Created by Dustin Carlino, Yuwen Li, & Michael Kirk");
txt.into_widget(ctx).centered_horiz()
},
Widget::row({

View File

@ -31,7 +31,7 @@ impl Proposals {
let mut txt = Text::new();
txt.add(Line(&edits.proposal_description[0]).small_heading());
for l in edits.proposal_description.iter().skip(1) {
txt.add(Line(l));
txt.add(l);
}
current_tab.push(
txt.wrap_to_pct(ctx, 70)
@ -83,11 +83,9 @@ impl Proposals {
{
let mut txt = Text::from(Line("A/B STREET").display_title());
txt.add(Line("PROPOSALS").big_heading_styled());
txt.add(Line(""));
txt.add(Line(
"These are proposed changes to Seattle made by community members.",
));
txt.add(Line("Contact dabreegster@gmail.com to add your idea here!"));
txt.add("");
txt.add("These are proposed changes to Seattle made by community members.");
txt.add("Contact dabreegster@gmail.com to add your idea here!");
txt.into_widget(ctx).centered_horiz().margin_below(20)
},
Widget::custom_row(buttons).flex_wrap(ctx, Percent::int(80)),

View File

@ -307,14 +307,14 @@ impl CommuterPatterns {
fn redraw_panel(&mut self, state: Option<&PanelState>, ctx: &mut EventCtx, app: &App) {
if let Some(state) = state {
let mut txt = Text::new();
txt.add(Line(format!(
txt.add(format!(
"Total: {} trips",
abstutil::prettyprint_usize(state.total_trips)
)));
));
for (name, cnt) in &state.building_counts {
if *cnt != 0 {
txt.add(Line(format!("{}: {}", name, cnt)));
txt.add(format!("{}: {}", name, cnt));
}
}

View File

@ -211,29 +211,27 @@ fn make_table(app: &App) -> Table<App, Entry, Filters> {
table.static_col("Trip ID", Box::new(|x| x.trip.0.to_string()));
table.column(
"Total duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.total_duration.to_string(&app.opts.units))).render(ctx)
}),
Box::new(|ctx, app, x| Text::from(x.total_duration.to_string(&app.opts.units)).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.total_duration))),
);
table.column(
"Driving duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.driving_duration.to_string(&app.opts.units))).render(ctx)
Text::from(x.driving_duration.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.driving_duration))),
);
table.column(
"Parking duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.parking_duration.to_string(&app.opts.units))).render(ctx)
Text::from(x.parking_duration.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.parking_duration))),
);
table.column(
"Walking duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.walking_duration.to_string(&app.opts.units))).render(ctx)
Text::from(x.walking_duration.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.walking_duration))),
);

View File

@ -52,7 +52,7 @@ impl TripTable {
prettyprint_usize(finished),
percent(finished),
))
.tooltip(Text::from(Line("Finished Trips")));
.tooltip("Finished Trips");
let finished_trips_table = make_table_finished_trips(app);
let finished_trips_content = Widget::col(vec![
@ -68,7 +68,7 @@ impl TripTable {
.style()
.btn_tab
.text(format!("Cancelled Trips: {}", prettyprint_usize(cancelled)))
.tooltip(Text::from(Line("Cancelled Trips")));
.tooltip("Cancelled Trips");
let cancelled_trips_content = Widget::col(vec![
cancelled_trips_table.render(ctx, app),
Filler::square_width(ctx, 0.15)
@ -86,7 +86,7 @@ impl TripTable {
prettyprint_usize(unfinished),
percent(unfinished)
))
.tooltip(Text::from(Line("Unfinished Trips")));
.tooltip("Unfinished Trips");
let unfinished_trips_content = Widget::col(vec![
unfinished_trips_table.render(ctx, app),
Filler::square_width(ctx, 0.15)
@ -448,14 +448,12 @@ fn make_table_finished_trips(app: &App) -> Table<App, FinishedTrip, Filters> {
);
table.column(
"Departure",
Box::new(|ctx, _, x| Text::from(Line(x.departure.ampm_tostring())).render(ctx)),
Box::new(|ctx, _, x| Text::from(x.departure.ampm_tostring()).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.departure))),
);
table.column(
"Duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.duration_after.to_string(&app.opts.units))).render(ctx)
}),
Box::new(|ctx, app, x| Text::from(x.duration_after.to_string(&app.opts.units)).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.duration_after))),
);
@ -500,12 +498,12 @@ fn make_table_finished_trips(app: &App) -> Table<App, FinishedTrip, Filters> {
table.column(
"Time spent waiting",
Box::new(|ctx, app, x| Text::from(Line(x.waiting.to_string(&app.opts.units))).render(ctx)),
Box::new(|ctx, app, x| Text::from(x.waiting.to_string(&app.opts.units)).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.waiting))),
);
table.column(
"Percent waiting",
Box::new(|ctx, _, x| Text::from(Line(x.percent_waiting.to_string())).render(ctx)),
Box::new(|ctx, _, x| Text::from(x.percent_waiting.to_string()).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.percent_waiting))),
);
@ -582,14 +580,14 @@ fn make_table_cancelled_trips(app: &App) -> Table<App, CancelledTrip, Filters> {
);
table.column(
"Departure",
Box::new(|ctx, _, x| Text::from(Line(x.departure.ampm_tostring())).render(ctx)),
Box::new(|ctx, _, x| Text::from(x.departure.ampm_tostring()).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.departure))),
);
if app.has_prebaked().is_some() {
table.column(
"Estimated duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.duration_before.to_string(&app.opts.units))).render(ctx)
Text::from(x.duration_before.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.duration_before))),
);
@ -683,14 +681,14 @@ fn make_table_unfinished_trips(app: &App) -> Table<App, UnfinishedTrip, Filters>
);
table.column(
"Departure",
Box::new(|ctx, _, x| Text::from(Line(x.departure.ampm_tostring())).render(ctx)),
Box::new(|ctx, _, x| Text::from(x.departure.ampm_tostring()).render(ctx)),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.departure))),
);
if app.has_prebaked().is_some() {
table.column(
"Estimated duration",
Box::new(|ctx, app, x| {
Text::from(Line(x.duration_before.to_string(&app.opts.units))).render(ctx)
Text::from(x.duration_before.to_string(&app.opts.units)).render(ctx)
}),
Col::Sortable(Box::new(|rows| rows.sort_by_key(|x| x.duration_before))),
);

View File

@ -124,11 +124,11 @@ impl GameplayState for Actdev {
Line("Created by Dustin Carlino, Yuwen Li, & Michael Kirk")
.small()
.into_widget(ctx),
Text::from(Line(
Text::from(
"A/B Street is a traffic simulation game based on OpenStreetMap. You \
can modify roads and intersections, measure the effects on different \
groups, and advocate for your proposal.",
))
)
.wrap_to_pct(ctx, 50)
.into_widget(ctx),
"This is a simplified version. Check out the full version below."

View File

@ -145,11 +145,11 @@ impl GameplayState for OptimizeCommute {
}
"hint" => {
// TODO Multiple hints. Point to follow button.
let mut txt = Text::from(Line("Hints"));
txt.add(Line(""));
txt.add(Line("Use the locator at the top right to find the VIP."));
txt.add(Line("You can wait for one of their trips to begin or end."));
txt.add(Line("Focus on trips spent mostly waiting"));
let mut txt = Text::from("Hints");
txt.add("");
txt.add("Use the locator at the top right to find the VIP.");
txt.add("You can wait for one of their trips to begin or end.");
txt.add("Focus on trips spent mostly waiting");
let contents = txt.into_widget(ctx);
return Some(Transition::Push(FYI::new(ctx, contents, app.cs.panel_bg)));
}
@ -175,7 +175,7 @@ impl GameplayState for OptimizeCommute {
fn recreate_panels(&mut self, ctx: &mut EventCtx, app: &App) {
let (before, after, done) = get_score(app, &self.trips);
let mut txt = Text::from(Line(format!("Total time: {} (", after)));
let mut txt = Text::from(format!("Total time: {} (", after));
txt.append_all(cmp_duration_shorter(app, after, before));
txt.append(Line(")"));

View File

@ -165,8 +165,8 @@ impl GameplayState for FixTrafficSignals {
}
"hint" => {
// TODO Multiple hints. Point to layers.
let mut txt = Text::from(Line("Hint"));
txt.add(Line(""));
let mut txt = Text::from("Hint");
txt.add("");
txt.add_appended(vec![
Line("Press "),
Key::L.txt(ctx),

View File

@ -221,11 +221,11 @@ impl EditScenarioModifiers {
Line("Modify traffic patterns")
.small_heading()
.into_widget(ctx),
Text::from(Line(
Text::from(
"This scenario determines the exact trips everybody takes, when they leave, where \
they go, and how they choose to get there. You can modify those patterns here. \
The modifications apply in order.",
))
)
.wrap_to_pct(ctx, 50)
.into_widget(ctx),
];

View File

@ -464,7 +464,7 @@ impl Task {
Task::Nil => unreachable!(),
Task::Camera => "Put out the fire at the fire station",
Task::InspectObjects => {
let mut txt = Text::from(Line("Find one of each:"));
let mut txt = Text::from("Find one of each:");
for (name, done) in vec![
("bike lane", state.inspected_bike_lane),
("building", state.inspected_building),
@ -474,14 +474,14 @@ impl Task {
if done {
txt.add(Line(format!("[X] {}", name)).fg(Color::GREEN));
} else {
txt.add(Line(format!("[ ] {}", name)));
txt.add(format!("[ ] {}", name));
}
}
return txt;
}
Task::TimeControls => "Wait until after 5pm",
Task::PauseResume => {
let mut txt = Text::from(Line("[ ] Pause/resume "));
let mut txt = Text::from("[ ] Pause/resume ");
txt.append(Line(format!("{} times", 3 - state.num_pauses)).fg(Color::GREEN));
return txt;
}
@ -491,17 +491,17 @@ impl Task {
if state.following_car {
txt.add(Line("[X] follow the target car").fg(Color::GREEN));
} else {
txt.add(Line("[ ] follow the target car"));
txt.add("[ ] follow the target car");
}
if state.car_parked {
txt.add(Line("[X] wait for them to park").fg(Color::GREEN));
} else {
txt.add(Line("[ ] wait for them to park"));
txt.add("[ ] wait for them to park");
}
if state.prank_done {
txt.add(Line("[X] click car and press c to draw WASH ME").fg(Color::GREEN));
} else {
txt.add(Line("[ ] click car and press "));
txt.add("[ ] click car and press ");
// TODO ctx.style().hotkey_color
txt.append(Line(Key::C.describe()).fg(Color::GREEN));
txt.append(Line(" to draw WASH ME"));
@ -512,7 +512,7 @@ impl Task {
let mut txt = Text::from(Line(
"1) Find a road with almost no parking spots available",
));
txt.add(Line("2) Click it and press "));
txt.add("2) Click it and press ");
// TODO ctx.style().hotkey_color
txt.append(Line(Key::C.describe()).fg(Color::GREEN));
txt.append(Line(" to check the occupancy"));
@ -520,14 +520,14 @@ impl Task {
}
Task::WatchBikes => "Watch for 3 minutes",
Task::FixBikes => {
return Text::from(Line(format!(
return Text::from(format!(
"[ ] Complete all trips {} faster",
CAR_BIKE_CONTENTION_GOAL
)));
));
}
Task::Done => "Tutorial complete!",
};
Text::from(Line(simple))
Text::from(simple)
}
fn label(self) -> &'static str {
@ -736,7 +736,7 @@ impl TutorialState {
.disabled(self.current.stage == 0)
.build_widget(ctx, "previous tutorial"),
{
let mut txt = Text::from(Line(format!("Task {}", self.current.stage + 1)));
let mut txt = Text::from(format!("Task {}", self.current.stage + 1));
// TODO Smaller font and use alpha for the "/9" part
txt.append(Line(format!("/{}", self.stages.len())).fg(Color::grey(0.7)));
txt.into_widget(ctx)
@ -815,10 +815,10 @@ impl TutorialState {
let mut col = vec![{
let mut txt = Text::new();
txt.add(Line(self.stage().task.label()).small_heading());
txt.add(Line(""));
txt.add("");
for l in lines {
txt.add(Line(l));
txt.add(l);
}
txt.wrap_to_pct(ctx, 30).into_widget(ctx)
}];

View File

@ -254,12 +254,12 @@ impl TimePanel {
}
use widgetry::DrawWithTooltips;
let mut tooltip_text = Text::from(Line("Finished Trips"));
tooltip_text.add(Line(format!(
let mut tooltip_text = Text::from("Finished Trips");
tooltip_text.add(format!(
"{} ({}% of total)",
prettyprint_usize(finished),
(ratio * 100.0) as usize
)));
));
if let Some(baseline_finished) = self.baseline_finished_trips {
// TODO: up/down icons
let line = if baseline_finished > finished {

View File

@ -36,7 +36,7 @@ impl JumpToTime {
.btn_tab
.text("Jump to time")
.hotkey(Key::T)
.tooltip(Text::from(Line("Jump to time")));
.tooltip("Jump to time");
let jump_to_time_content = {
// TODO Auto-fill width?
let slider_width = 500.0;
@ -75,7 +75,7 @@ impl JumpToTime {
.btn_tab
.text("Jump to delay")
.hotkey(Key::D)
.tooltip(Text::from(Line("Jump to delay")));
.tooltip("Jump to delay");
let jump_to_delay_content = Widget::col(vec![
Widget::row(vec![
Line("Jump to next").small_heading().into_widget(ctx),

View File

@ -81,7 +81,7 @@ impl MainState {
Key::I.txt(ctx),
Line(" to create a new intersection"),
]);
instructions.add(Line("Hover on an intersection, then..."));
instructions.add("Hover on an intersection, then...");
instructions.add_appended(vec![
Line("- Press "),
Key::R.txt(ctx),

View File

@ -255,7 +255,7 @@ mod wasm_loader {
Box::new(FileLoader {
response: rx,
on_load: Some(on_load),
panel: ctx.make_loading_screen(Text::from(Line(format!("Loading {}...", url)))),
panel: ctx.make_loading_screen(Text::from(format!("Loading {}...", url))),
started: Instant::now(),
url,
})
@ -374,7 +374,7 @@ mod wasm_loader {
Box::new(RawFileLoader {
response: rx,
on_load: Some(on_load),
panel: ctx.make_loading_screen(Text::from(Line(format!("Loading {}...", url)))),
panel: ctx.make_loading_screen(Text::from(format!("Loading {}...", url))),
started: Instant::now(),
url,
})
@ -478,7 +478,7 @@ where
Box::new(FutureLoader {
loading_title: loading_title.to_string(),
started: Instant::now(),
panel: ctx.make_loading_screen(Text::from(Line(loading_title))),
panel: ctx.make_loading_screen(Text::from(loading_title)),
receiver,
on_load: Some(on_load),
})
@ -500,7 +500,7 @@ where
Box::new(FutureLoader {
loading_title: loading_title.to_string(),
started: Instant::now(),
panel: ctx.make_loading_screen(Text::from(Line(loading_title))),
panel: ctx.make_loading_screen(Text::from(loading_title)),
receiver,
on_load: Some(on_load),
runtime,

View File

@ -245,7 +245,7 @@ fn draw_time_left(
Circle::new(center, radius).to_partial_polygon(percent),
);
batch.append(
Text::from(Line(format!("{}", idx + 1)))
Text::from(format!("{}", idx + 1))
.render_autocropped(prerender)
.scale(0.1)
.centered_on(center),

View File

@ -311,7 +311,7 @@ impl<A: AppLike + 'static> State<A> for CityPicker<A> {
g.draw_polygon(color.alpha(0.5), poly.clone());
g.unfork();
g.draw_mouse_tooltip(Text::from(Line(nice_map_name(name))));
g.draw_mouse_tooltip(Text::from(nice_map_name(name)));
}
}
}

View File

@ -100,7 +100,7 @@ impl<'a> ColorDiscrete<'a> {
pub struct ColorLegend {}
impl ColorLegend {
pub fn row<S: Into<String>>(ctx: &mut EventCtx, color: Color, label: S) -> Widget {
pub fn row(ctx: &mut EventCtx, color: Color, label: impl AsRef<str>) -> Widget {
let radius = 15.0;
Widget::row(vec![
GeomBatch::from(vec![(
@ -109,9 +109,7 @@ impl ColorLegend {
)])
.into_widget(ctx)
.centered_vert(),
Text::from(Line(label))
.wrap_to_pct(ctx, 35)
.into_widget(ctx),
Text::from(label).wrap_to_pct(ctx, 35).into_widget(ctx),
])
}

View File

@ -45,7 +45,7 @@ impl<A: AppLike + 'static> RunCommand<A> {
p.communicate_start(None)
.limit_time(Duration::from_millis(0)),
);
let panel = ctx.make_loading_screen(Text::from(Line("Starting command...")));
let panel = ctx.make_loading_screen(Text::from("Starting command..."));
let max_capacity =
(0.8 * ctx.canvas.window_height / ctx.default_line_height()) as usize;
Box::new(RunCommand {
@ -120,7 +120,7 @@ impl<A: AppLike + 'static> State<A> for RunCommand<A> {
.small_heading(),
);
for line in &self.lines {
txt.add(Line(line));
txt.add(line);
}
self.panel = ctx.make_loading_screen(txt);

View File

@ -111,10 +111,10 @@ impl CrossStreet {
{
let mut txt = Text::from(Line("What cross street?").small_heading());
// TODO This isn't so clear...
txt.add(Line(format!(
txt.add(format!(
"(Or just quit to go to {})",
map.get_r(first[0]).get_name(app.opts().language.as_ref()),
)));
));
txt.into_widget(ctx)
},
ctx.style().btn_close_widget(ctx),

View File

@ -133,10 +133,10 @@ pub struct PopupMsg {
}
impl PopupMsg {
pub fn new<A: AppLike, I: Into<String>>(
pub fn new<A: AppLike>(
ctx: &mut EventCtx,
title: &str,
lines: Vec<I>,
lines: Vec<impl AsRef<str>>,
) -> Box<dyn State<A>> {
PopupMsg::also_draw(
ctx,
@ -147,17 +147,17 @@ impl PopupMsg {
)
}
pub fn also_draw<A: AppLike, I: Into<String>>(
pub fn also_draw<A: AppLike>(
ctx: &mut EventCtx,
title: &str,
lines: Vec<I>,
lines: Vec<impl AsRef<str>>,
unzoomed: Drawable,
zoomed: Drawable,
) -> Box<dyn State<A>> {
let mut txt = Text::new();
txt.add(Line(title).small_heading());
for l in lines {
txt.add(Line(l));
txt.add(l);
}
Box::new(PopupMsg {
panel: Panel::new(Widget::col(vec![

View File

@ -167,26 +167,26 @@ impl Viewer {
);
let mut txt = Text::new();
txt.add(Line(format!("Address: {}", b.address)));
txt.add(format!("Address: {}", b.address));
if let Some(ref names) = b.name {
txt.add(Line(format!(
txt.add(format!(
"Name: {}",
names.get(app.opts.language.as_ref()).to_string()
)));
));
}
if !b.amenities.is_empty() {
txt.add(Line(""));
txt.add("");
if b.amenities.len() == 1 {
txt.add(Line("1 amenity:"));
txt.add("1 amenity:");
} else {
txt.add(Line(format!("{} amenities:", b.amenities.len())));
txt.add(format!("{} amenities:", b.amenities.len()));
}
for a in &b.amenities {
txt.add(Line(format!(
txt.add(format!(
" {} ({})",
a.names.get(app.opts.language.as_ref()),
a.amenity_type
)));
));
}
}
col.push(txt.into_widget(ctx));

View File

@ -228,7 +228,7 @@ impl State<App> for ParkingMapper {
self.selected = Some((ids, ctx.upload(batch)));
let mut txt = Text::new();
txt.add(Line(format!("Click to map parking for OSM way {}", way)));
txt.add(format!("Click to map parking for OSM way {}", way));
txt.add_appended(vec![
Line("Shortcut: press "),
Key::N.txt(ctx),
@ -250,7 +250,7 @@ impl State<App> for ParkingMapper {
}
if k.contains("parking") {
if !road.osm_tags.contains_key(osm::INFERRED_PARKING) {
txt.add(Line(format!("{} = {}", k, v)));
txt.add(format!("{} = {}", k, v));
}
} else if k == "sidewalk" {
if !road.osm_tags.contains_key(osm::INFERRED_SIDEWALKS) {

View File

@ -39,14 +39,14 @@ impl Strategize {
let mut txt = Text::new();
txt.add(Line(format!("Results for {}", level.title)).small_heading());
txt.add(Line(format!(
txt.add(format!(
"You delivered {} presents",
prettyprint_usize(score)
)));
txt.add(Line(""));
txt.add(Line("High scores:"));
));
txt.add("");
txt.add("High scores:");
for (idx, score) in app.session.high_scores[&level.title].iter().enumerate() {
txt.add(Line(format!("{}) {}", idx + 1, prettyprint_usize(*score))));
txt.add(format!("{}) {}", idx + 1, prettyprint_usize(*score)));
}
// Partly duplicated with Buildings::new, but we want to label upzones and finished houses
@ -168,29 +168,29 @@ impl Results {
let mut txt = Text::new();
if score < level.goal {
txt.add(Line("Not quite...").small_heading());
txt.add(Line(format!(
txt.add(format!(
"You only delivered {} / {} presents",
prettyprint_usize(score),
prettyprint_usize(level.goal)
)));
txt.add(Line("Review your route and try again."));
txt.add(Line(""));
txt.add(Line("Hint: look for any apartments you missed!"));
));
txt.add("Review your route and try again.");
txt.add("");
txt.add("Hint: look for any apartments you missed!");
} else {
txt.add(Line("Thank you, Santa!").small_heading());
txt.add(Line(format!(
txt.add(format!(
"You delivered {} presents, more than the goal of {}!",
prettyprint_usize(score),
prettyprint_usize(level.goal)
)));
));
let high_score = app.session.high_scores[&level.title][0];
if high_score == score {
txt.add(Line("Wow, a new high score!"));
txt.add("Wow, a new high score!");
} else {
txt.add(Line(format!(
txt.add(format!(
"But can you beat the high score of {}?",
prettyprint_usize(high_score)
)));
));
}
}

View File

@ -56,11 +56,11 @@ impl Picker {
let mut txt = Text::new();
txt.add(Line(format!("Ready for {}?", level.title)).small_heading());
txt.add(Line(format!(
txt.add(format!(
"Goal: deliver {} presents",
prettyprint_usize(level.goal)
)));
txt.add(Line(format!("Time limit: {}", level.time_limit)));
));
txt.add(format!("Time limit: {}", level.time_limit));
txt.add_appended(vec![
Line("Deliver presents to "),
Line("single-family homes").fg(app.cs.residential_building),

View File

@ -37,7 +37,7 @@ impl Buildings {
buildings.insert(b.id, BldgState::Store);
batch.push(colors.store, b.polygon.clone());
batch.append(
Text::from(Line("Upzoned"))
Text::from("Upzoned")
.render_autocropped(ctx)
.scale(0.1)
.centered_on(b.label_center),
@ -83,7 +83,7 @@ impl Buildings {
buildings.insert(b.id, BldgState::Store);
batch.push(colors.store, b.polygon.clone());
batch.append(
Text::from(Line(amenity.names.get(app.opts.language.as_ref())))
Text::from(amenity.names.get(app.opts.language.as_ref()))
.render_autocropped(ctx)
.scale(0.1)
.centered_on(b.label_center),

View File

@ -175,9 +175,9 @@ impl Game {
app.session.colors.boost,
self.state.boost / MAX_BOOST,
if self.state.boost == Duration::ZERO {
Text::from(Line("Find a bike or bus lane"))
Text::from("Find a bike or bus lane")
} else {
Text::from(Line("Hold space to boost"))
Text::from("Hold space to boost")
},
);
self.minimap.mut_panel().replace(ctx, "boost", boost_bar);
@ -228,7 +228,7 @@ impl Game {
Effect::Scale {
lerp_scale: (1.0, 4.0),
center: app.map.get_b(b).label_center,
orig: Text::from(Line(format!("+{}", prettyprint_usize(increase))))
orig: Text::from(format!("+{}", prettyprint_usize(increase)))
.bg(app.session.colors.score)
.render_autocropped(ctx)
.scale(0.1),
@ -257,13 +257,10 @@ impl Game {
Effect::Scale {
lerp_scale: (1.0, 4.0),
center: app.map.get_b(b).label_center,
orig: Text::from(Line(format!(
"Refilled {}",
prettyprint_usize(refill)
)))
.bg(app.session.colors.energy)
.render_autocropped(ctx)
.scale(0.1),
orig: Text::from(format!("Refilled {}", prettyprint_usize(refill)))
.bg(app.session.colors.energy)
.render_autocropped(ctx)
.scale(0.1),
},
);
}
@ -368,7 +365,7 @@ impl State<App> for Game {
Effect::Scale {
lerp_scale: (1.0, 4.0),
center: self.player.get_pos(),
orig: Text::from(Line("Time's up!"))
orig: Text::from("Time's up!")
.bg(Color::RED)
.render_autocropped(ctx)
.scale(0.1),
@ -402,7 +399,7 @@ impl State<App> for Game {
let pt = ctx.canvas.center_to_screen_pt();
Pt2D::new(pt.x, pt.y / 2.0)
},
orig: Text::from(Line("Almost out of time!"))
orig: Text::from("Almost out of time!")
.bg(Color::RED)
.render_autocropped(ctx),
},
@ -432,7 +429,7 @@ impl State<App> for Game {
let pt = ctx.canvas.center_to_screen_pt();
Pt2D::new(pt.x, pt.y / 2.0)
},
orig: Text::from(Line("Low on blood sugar, refill soon!"))
orig: Text::from("Low on blood sugar, refill soon!")
.bg(Color::RED)
.render_autocropped(ctx),
},

View File

@ -1,6 +1,6 @@
use abstutil::prettyprint_usize;
use geom::Polygon;
use widgetry::{Color, EventCtx, GeomBatch, Line, Text, Widget};
use widgetry::{Color, EventCtx, GeomBatch, Text, Widget};
pub fn custom_bar(ctx: &mut EventCtx, filled_color: Color, pct_full: f64, txt: Text) -> Widget {
let total_width = 300.0;
@ -30,10 +30,10 @@ pub fn make_bar(ctx: &mut EventCtx, filled_color: Color, value: usize, max: usiz
} else {
(value as f64) / (max as f64)
};
let txt = Text::from(Line(format!(
let txt = Text::from(format!(
"{} / {}",
prettyprint_usize(value),
prettyprint_usize(max)
)));
));
custom_bar(ctx, filled_color, pct_full, txt)
}

View File

@ -100,7 +100,7 @@ fn level_btn(ctx: &mut EventCtx, app: &App, level: &Level, idx: usize) -> GeomBa
let mut txt = Text::new();
txt.add(Line(format!("LEVEL {}", idx + 1)).small_heading());
txt.add(Line(&level.title).small_heading());
txt.add(Line(&level.description));
txt.add(&level.description);
let batch = txt.wrap_to_pct(ctx, 15).render_autocropped(ctx);
// Add padding

View File

@ -253,7 +253,7 @@ impl<'a> LoadingScreen<'a> {
let mut txt = Text::from(Line(&self.title).small_heading());
for l in &self.lines {
txt.add(Line(l));
txt.add(l);
}
let panel = ctx.make_loading_screen(txt);

View File

@ -51,6 +51,12 @@ pub struct TextSpan {
underlined: bool,
}
impl<AsStrRef: AsRef<str>> From<AsStrRef> for TextSpan {
fn from(line: AsStrRef) -> Self {
Line(line.as_ref())
}
}
impl TextSpan {
pub fn fg(mut self, color: Color) -> TextSpan {
assert_eq!(self.fg_color, None);
@ -167,6 +173,22 @@ pub struct Text {
bg_color: Option<Color>,
}
impl From<TextSpan> for Text {
fn from(line: TextSpan) -> Text {
let mut txt = Text::new();
txt.add(line);
txt
}
}
impl<AsStrRef: AsRef<str>> From<AsStrRef> for Text {
fn from(line: AsStrRef) -> Text {
let mut txt = Text::new();
txt.add(Line(line.as_ref()));
txt
}
}
impl Text {
pub fn new() -> Text {
Text {
@ -175,12 +197,6 @@ impl Text {
}
}
pub fn from(line: TextSpan) -> Text {
let mut txt = Text::new();
txt.add(line);
txt
}
pub fn from_all(lines: Vec<TextSpan>) -> Text {
let mut txt = Text::new();
for l in lines {
@ -244,8 +260,8 @@ impl Text {
self
}
pub fn add(&mut self, line: TextSpan) {
self.lines.push((None, vec![line]));
pub fn add(&mut self, line: impl Into<TextSpan>) {
self.lines.push((None, vec![line.into()]));
}
pub fn add_highlighted(&mut self, line: TextSpan, highlight: Color) {
@ -542,7 +558,7 @@ impl TextSpan {
write!(&mut svg, "\" />").unwrap();
// We need to subtract and account for the length of the text
let start_offset = (path.length() / 2.0).inner_meters()
- (Text::from(Line(&self.text)).dims(assets).width * scale) / 2.0;
- (Text::from(&self.text).dims(assets).width * scale) / 2.0;
let fg_color = self.fg_color_for_style(&assets.style.borrow());
write!(

View File

@ -420,8 +420,8 @@ impl<'b, 'a: 'b, 'c> ButtonBuilder<'a, 'c> {
/// Set a non-default tooltip [`Text`] to appear when hovering over the button.
///
/// If a `tooltip` is not specified, a default tooltip will be applied.
pub fn tooltip(mut self, tooltip: Text) -> Self {
self.tooltip = Some(tooltip);
pub fn tooltip(mut self, tooltip: impl Into<Text>) -> Self {
self.tooltip = Some(tooltip.into());
self
}

View File

@ -100,7 +100,7 @@ impl CompareTimes {
.collect(),
)
.evenly_spaced();
let y_label = Text::from(Line(format!("{} (minutes)", y_name.as_ref())))
let y_label = Text::from(format!("{} (minutes)", y_name.as_ref()))
.render(ctx)
.rotate(Angle::degrees(90.0))
.autocrop()

View File

@ -6,8 +6,8 @@ use geom::{
use crate::widgets::line_plot::{make_legend, thick_lineseries, Yvalue};
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, PlotOptions, ScreenDims, ScreenPt, Series,
Text, TextExt, Widget, WidgetImpl, WidgetOutput,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, PlotOptions, ScreenDims, ScreenPt, Series, Text,
TextExt, Widget, WidgetImpl, WidgetOutput,
};
// The X is always time
@ -152,7 +152,7 @@ impl FanChart {
let percent_x = (i as f64) / ((num_x_labels - 1) as f64);
let t = max_x.percent_of(percent_x);
// TODO Need ticks now to actually see where this goes
let batch = Text::from(Line(t.to_string()))
let batch = Text::from(t.to_string())
.render(ctx)
.rotate(Angle::degrees(-15.0))
.autocrop();

View File

@ -143,8 +143,8 @@ impl<'a, 'c> Image<'a, 'c> {
}
/// Add a tooltip to appear when hovering over the image.
pub fn tooltip(mut self, tooltip: Text) -> Self {
self.tooltip = Some(tooltip);
pub fn tooltip(mut self, tooltip: impl Into<Text>) -> Self {
self.tooltip = Some(tooltip.into());
self
}

View File

@ -7,8 +7,8 @@ use geom::{
};
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, ScreenDims, ScreenPt, ScreenRectangle,
Text, TextExt, Toggle, Widget, WidgetImpl, WidgetOutput,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, ScreenDims, ScreenPt, ScreenRectangle, Text,
TextExt, Toggle, Widget, WidgetImpl, WidgetOutput,
};
// The X is always time
@ -176,7 +176,7 @@ impl<T: Yvalue<T>> LinePlot<T> {
let percent_x = (i as f64) / ((num_x_labels - 1) as f64);
let t = max_x.percent_of(percent_x);
// TODO Need ticks now to actually see where this goes
let batch = Text::from(Line(t.to_string()))
let batch = Text::from(t.to_string())
.render(ctx)
.rotate(Angle::degrees(-15.0))
.autocrop();
@ -230,12 +230,12 @@ impl<T: Yvalue<T>> WidgetImpl for LinePlot<T> {
let y_percent = 1.0 - (pt.y() / self.dims.height);
// TODO Draw this info in the ColorLegend
txt.add(Line(format!(
txt.add(format!(
"{}: at {}, {}",
label,
t.ampm_tostring(),
self.max_y.from_percent(y_percent).prettyprint()
)));
));
}
if !txt.is_empty() {
g.fork_screenspace();

View File

@ -193,7 +193,7 @@ impl<T: 'static> WidgetImpl for Menu<T> {
if let Some(pt) = g.canvas.get_cursor_in_screen_space() {
if rect.contains(pt) {
g.draw_mouse_tooltip(
Text::from(Line(info))
Text::from(info)
.inner_wrap_to_pct(0.3 * g.canvas.window_width, &g.prerender.assets),
);
}

View File

@ -2,8 +2,8 @@ use geom::{Angle, Circle, Distance, Duration, PolyLine, Pt2D, Time};
use crate::widgets::line_plot::{make_legend, Yvalue};
use crate::{
Color, Drawable, EventCtx, GeomBatch, GfxCtx, Line, PlotOptions, ScreenDims, ScreenPt, Series,
Text, TextExt, Widget, WidgetImpl, WidgetOutput,
Color, Drawable, EventCtx, GeomBatch, GfxCtx, PlotOptions, ScreenDims, ScreenPt, Series, Text,
TextExt, Widget, WidgetImpl, WidgetOutput,
};
// The X is always time
@ -132,7 +132,7 @@ impl ScatterPlot {
),
);
let txt = Text::from(Line("avg")).render(ctx).autocrop();
let txt = Text::from("avg").render(ctx).autocrop();
let width = txt.get_dims().width;
batch.append(txt.centered_on(Pt2D::new(-width / 2.0, (1.0 - avg) * height)));
}
@ -150,7 +150,7 @@ impl ScatterPlot {
let percent_x = (i as f64) / ((num_x_labels - 1) as f64);
let t = max_x.percent_of(percent_x);
// TODO Need ticks now to actually see where this goes
let batch = Text::from(Line(t.to_string()))
let batch = Text::from(t.to_string())
.render(ctx)
.rotate(Angle::degrees(-15.0))
.autocrop();

View File

@ -1,7 +1,7 @@
use geom::{CornerRadii, Distance, Polygon, Pt2D};
use crate::{
include_labeled_bytes, text, Button, Drawable, EdgeInsets, EventCtx, GeomBatch, GfxCtx, Line,
include_labeled_bytes, text, Button, Drawable, EdgeInsets, EventCtx, GeomBatch, GfxCtx,
Outcome, OutlineStyle, Prerender, ScreenDims, ScreenPt, ScreenRectangle, Style, Text, Widget,
WidgetImpl, WidgetOutput,
};
@ -113,7 +113,7 @@ impl Spinner {
Polygon::rounded_rectangle(self.dims.width, self.dims.height, 5.0),
)]);
batch.append(
Text::from(Line(self.current.to_string()))
Text::from(self.current.to_string())
.render_autocropped(prerender)
.centered_on(Pt2D::new(TEXT_WIDTH / 2.0, self.dims.height / 2.0)),
);

View File

@ -197,7 +197,7 @@ impl<A, T: 'static, F> Table<A, T, F> {
pub fn static_col(&mut self, name: &str, to_str: Box<dyn Fn(&T) -> String>) {
self.column(
name,
Box::new(move |ctx, _, x| Text::from(Line((to_str)(x))).render(ctx)),
Box::new(move |ctx, _, x| Text::from((to_str)(x)).render(ctx)),
Col::Static,
);
}

View File

@ -42,7 +42,7 @@ impl TextBox {
}
fn calculate_text(&self, style: &Style) -> Text {
let mut txt = Text::from(Line(&self.line[0..self.cursor_x]));
let mut txt = Text::from(&self.line[0..self.cursor_x]);
if self.cursor_x < self.line.len() {
// TODO This "cursor" looks awful!
txt.append_all(vec![

View File

@ -396,10 +396,10 @@ fn make_tabs(ctx: &mut EventCtx) -> TabController {
.padding(20)
.dims(ScreenDims::new(50.0, 100.0))
.content_mode(ContentMode::ScaleAspectFit)
.tooltip(Text::from(Line(
.tooltip(
"With ScaleAspectFit content grows, without distorting its aspect ratio, \
until it reaches its padding bounds.",
)))
)
.into_widget(ctx),
Image::from_path("system/assets/tools/home.svg")
.color(Color::GREEN)
@ -407,9 +407,7 @@ fn make_tabs(ctx: &mut EventCtx) -> TabController {
.padding(20)
.dims(ScreenDims::new(50.0, 100.0))
.content_mode(ContentMode::ScaleToFill)
.tooltip(Text::from(Line(
"With ScaleToFill content can stretches to fill its size (less padding)",
)))
.tooltip("With ScaleToFill content can stretches to fill its size (less padding)")
.into_widget(ctx),
Image::from_path("system/assets/tools/home.svg")
.color(Color::BLUE)
@ -417,9 +415,7 @@ fn make_tabs(ctx: &mut EventCtx) -> TabController {
.padding(20)
.dims(ScreenDims::new(50.0, 100.0))
.content_mode(ContentMode::ScaleAspectFill)
.tooltip(Text::from(Line(
"With ScaleAspectFill content can exceed its visible bounds",
)))
.tooltip("With ScaleAspectFill content can exceed its visible bounds")
.into_widget(ctx),
]),
Text::from(Line("Spinner").big_heading_styled().size(18)).into_widget(ctx),
@ -510,9 +506,9 @@ fn make_controls(ctx: &mut EventCtx, tabs: &mut TabController) -> Panel {
Panel::new(Widget::col(vec![
Text::from(Line("widgetry demo").big_heading_styled()).into_widget(ctx),
Widget::col(vec![
Text::from(Line(
Text::from(
"Click and drag the background to pan, use touchpad or scroll wheel to zoom",
))
)
.into_widget(ctx),
Widget::row(vec![
ctx.style()