add screen positioning to some Composites

This commit is contained in:
Dustin Carlino 2019-12-19 10:59:39 -08:00
parent d9a68332e5
commit 56285a7b30
8 changed files with 96 additions and 64 deletions

View File

@ -1,4 +1,4 @@
use crate::{Color, ScreenPt, ScreenRectangle, Text, UserInput};
use crate::{Color, ScreenDims, ScreenPt, ScreenRectangle, Text, UserInput};
use abstutil::Timer;
use geom::{Bounds, Distance, Polygon, Pt2D};
use glium::texture::Texture2dArray;
@ -225,8 +225,31 @@ impl Canvas {
_ => false,
}
}
pub fn align_window(
&self,
dims: ScreenDims,
horiz: HorizontalAlignment,
vert: VerticalAlignment,
) -> ScreenPt {
let x1 = match horiz {
HorizontalAlignment::Left => 0.0,
HorizontalAlignment::Center => (self.window_width - dims.width) / 2.0,
HorizontalAlignment::Right => self.window_width - dims.width,
HorizontalAlignment::FillScreen => 0.0,
};
let y1 = match vert {
VerticalAlignment::Top => 0.0,
VerticalAlignment::Center => (self.window_height - dims.height) / 2.0,
VerticalAlignment::Bottom => self.window_height - dims.height,
// TODO Hack
VerticalAlignment::BottomAboveOSD => self.window_height - dims.height - 40.0,
};
ScreenPt::new(x1, y1)
}
}
#[derive(Clone, Copy)]
pub enum HorizontalAlignment {
Left,
Center,
@ -234,10 +257,12 @@ pub enum HorizontalAlignment {
FillScreen,
}
#[derive(Clone, Copy)]
pub enum VerticalAlignment {
Top,
Center,
Bottom,
BottomAboveOSD,
}
#[derive(Serialize, Deserialize, Debug)]

View File

@ -235,26 +235,12 @@ impl<'a> GfxCtx<'a> {
(horiz, vert): (HorizontalAlignment, VerticalAlignment),
) {
let mut dims = self.text_dims(&txt);
let x1 = match horiz {
HorizontalAlignment::Left => 0.0,
HorizontalAlignment::Center => (self.canvas.window_width - dims.width) / 2.0,
HorizontalAlignment::Right => self.canvas.window_width - dims.width,
HorizontalAlignment::FillScreen => {
dims.width = self.canvas.window_width;
0.0
}
};
let y1 = match vert {
VerticalAlignment::Top => 0.0,
VerticalAlignment::Center => (self.canvas.window_height - dims.height) / 2.0,
VerticalAlignment::Bottom => self.canvas.window_height - dims.height,
};
self.canvas.mark_covered_area(text::draw_text_bubble(
self,
ScreenPt::new(x1, y1),
txt,
dims,
));
let top_left = self.canvas.align_window(dims, horiz, vert);
if let HorizontalAlignment::FillScreen = horiz {
dims.width = self.canvas.window_width;
}
self.canvas
.mark_covered_area(text::draw_text_bubble(self, top_left, txt, dims));
}
pub fn get_screen_bounds(&self) -> Bounds {

View File

@ -5,7 +5,10 @@ use crate::managed::{Composite, ManagedWidget};
use crate::options;
use crate::sandbox::GameplayMode;
use crate::ui::UI;
use ezgui::{hotkey, lctrl, Button, Color, EventCtx, Key, Line, RewriteColor, ScreenPt, Text};
use ezgui::{
hotkey, lctrl, Button, Color, EventCtx, HorizontalAlignment, Key, Line, RewriteColor, Text,
VerticalAlignment,
};
// TODO Rethink this API.
pub fn tool_panel(ctx: &EventCtx, extra_buttons: Vec<ManagedWidget>) -> Composite {
@ -46,14 +49,15 @@ pub fn tool_panel(ctx: &EventCtx, extra_buttons: Vec<ManagedWidget>) -> Composit
];
row.extend(extra_buttons);
Composite::minimal_size(
Composite::aligned(
(HorizontalAlignment::Left, VerticalAlignment::BottomAboveOSD),
ManagedWidget::row(row.into_iter().map(|x| x.margin(10)).collect()).bg(Color::grey(0.4)),
ScreenPt::new(30.0, ctx.canvas.window_height - 80.0),
)
}
pub fn edit_map_panel(ctx: &EventCtx, ui: &UI, gameplay: GameplayMode) -> Composite {
Composite::minimal_size(
Composite::aligned(
(HorizontalAlignment::Center, VerticalAlignment::Top),
ManagedWidget::row(vec![
ManagedWidget::col(vec![
ManagedWidget::draw_text(ctx, Text::from(Line("Sandbox"))),
@ -84,6 +88,5 @@ pub fn edit_map_panel(ctx: &EventCtx, ui: &UI, gameplay: GameplayMode) -> Compos
]),
])
.bg(Color::grey(0.4)),
ScreenPt::new(ctx.canvas.window_width / 2.0, 5.0),
)
}

View File

@ -2,8 +2,9 @@ use crate::game::{State, Transition};
use crate::ui::UI;
use ezgui::layout::Widget;
use ezgui::{
Button, Color, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey,
RewriteColor, ScreenDims, ScreenPt, ScreenRectangle, Slider, Text,
Button, Color, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, JustDraw,
Line, MultiKey, RewriteColor, ScreenDims, ScreenPt, ScreenRectangle, Slider, Text,
VerticalAlignment,
};
use geom::{Distance, Polygon};
use std::collections::HashMap;
@ -433,6 +434,7 @@ pub enum Outcome {
enum CompositePosition {
FillScreen,
MinimalTopLeft(ScreenPt),
Aligned(HorizontalAlignment, VerticalAlignment),
}
impl Composite {
@ -450,6 +452,16 @@ impl Composite {
}
}
pub fn aligned(
(horiz, vert): (HorizontalAlignment, VerticalAlignment),
top_level: ManagedWidget,
) -> Composite {
Composite {
top_level,
pos: CompositePosition::Aligned(horiz, vert),
}
}
pub fn recompute_layout(&mut self, ctx: &EventCtx, sliders: &mut HashMap<String, &mut Slider>) {
// TODO If this ever gets slow, only run if window size has changed.
let mut stretch = Stretch::new();
@ -463,10 +475,12 @@ impl Composite {
},
..Default::default()
},
CompositePosition::MinimalTopLeft(_) => Style {
// TODO There a way to encode the offset in stretch?
..Default::default()
},
CompositePosition::MinimalTopLeft(_) | CompositePosition::Aligned(_, _) => {
Style {
// TODO There a way to encode the offset in stretch?
..Default::default()
}
}
},
Vec::new(),
)
@ -481,6 +495,14 @@ impl Composite {
let top_left = match self.pos {
CompositePosition::FillScreen => ScreenPt::new(0.0, 0.0),
CompositePosition::MinimalTopLeft(pt) => pt,
CompositePosition::Aligned(horiz, vert) => {
let result = stretch.layout(root).unwrap();
ctx.canvas.align_window(
ScreenDims::new(result.size.width.into(), result.size.height.into()),
horiz,
vert,
)
}
};
self.top_level
.apply_flexbox(sliders, &stretch, &mut nodes, top_left.x, top_left.y, ctx);

View File

@ -5,7 +5,10 @@ use crate::managed::{Composite, ManagedWidget};
use crate::sandbox::gameplay::{change_scenario, load_map, spawner, GameplayMode, GameplayState};
use crate::sandbox::overlays::Overlays;
use crate::ui::UI;
use ezgui::{hotkey, lctrl, Color, EventCtx, GfxCtx, Key, Line, ModalMenu, ScreenPt, Text};
use ezgui::{
hotkey, lctrl, Color, EventCtx, GfxCtx, HorizontalAlignment, Key, Line, ModalMenu, Text,
VerticalAlignment,
};
use map_model::IntersectionID;
use sim::Analytics;
use std::collections::BTreeSet;
@ -75,7 +78,8 @@ pub fn freeform_controller(
gameplay: GameplayMode,
scenario_name: &str,
) -> Composite {
Composite::minimal_size(
Composite::aligned(
(HorizontalAlignment::Center, VerticalAlignment::Top),
ManagedWidget::row(vec![
ManagedWidget::col(vec![
ManagedWidget::text_button(
@ -125,6 +129,5 @@ pub fn freeform_controller(
]),
])
.bg(Color::grey(0.4)),
ScreenPt::new(ctx.canvas.window_width / 2.0 - 300.0, 5.0),
)
}

View File

@ -232,13 +232,18 @@ fn change_scenario(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Option<
abstutil::list_all_objects(abstutil::path_all_scenarios(ui.primary.map.get_name()));
list.push(builtin.clone());
list.push("just buses".to_string());
list.push("empty".to_string());
list
})?;
ui.primary.clear_sim();
Some(Transition::PopThenReplace(Box::new(SandboxMode::new(
ctx,
ui,
GameplayMode::PlayScenario(scenario_name),
if scenario_name == "empty" {
GameplayMode::Freeform
} else {
GameplayMode::PlayScenario(scenario_name)
},
))))
}

View File

@ -15,8 +15,8 @@ use crate::pregame::main_menu;
use crate::ui::{ShowEverything, UI};
use abstutil::Timer;
use ezgui::{
hotkey, lctrl, Button, Choice, Color, EventCtx, EventLoopMode, GfxCtx, Key, Line, ScreenPt,
Text,
hotkey, lctrl, Button, Choice, Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment,
Key, Line, Text, VerticalAlignment,
};
pub use gameplay::spawner::spawn_agents_around;
pub use gameplay::GameplayMode;
@ -296,7 +296,8 @@ impl AgentMeter {
pub fn new(ctx: &EventCtx, ui: &UI) -> AgentMeter {
let (active, unfinished, by_mode) = ui.primary.sim.num_trips();
let composite = Composite::minimal_size(
let composite = Composite::aligned(
(HorizontalAlignment::Right, VerticalAlignment::Top),
ManagedWidget::col(vec![
{
let mut txt = Text::new();
@ -318,7 +319,6 @@ impl AgentMeter {
])
.bg(Color::grey(0.4))
.padding(20),
ScreenPt::new(ctx.canvas.window_width - 300.0, 5.0),
);
AgentMeter {

View File

@ -4,7 +4,7 @@ use crate::sandbox::{GameplayMode, SandboxMode};
use crate::ui::UI;
use ezgui::{
hotkey, Button, Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, HorizontalAlignment, Key,
Line, RewriteColor, ScreenPt, Slider, Text, VerticalAlignment, Wizard,
Line, RewriteColor, Slider, Text, VerticalAlignment, Wizard,
};
use geom::{Distance, Duration, Line, Pt2D, Time};
use std::collections::HashMap;
@ -15,7 +15,6 @@ const ADJUST_SPEED_PERCENT: f64 = 0.01;
pub struct SpeedControls {
time_panel: TimePanel,
top_left: ScreenPt,
composite: Composite,
slider: Slider,
@ -34,12 +33,7 @@ enum SpeedState {
}
impl SpeedControls {
fn make_panel(
ctx: &EventCtx,
paused: bool,
desired_speed: f64,
top_left: ScreenPt,
) -> Composite {
fn make_panel(ctx: &EventCtx, paused: bool, desired_speed: f64) -> Composite {
let mut row = Vec::new();
if paused {
row.push(ManagedWidget::btn_no_cb(Button::rectangle_svg(
@ -147,20 +141,17 @@ impl SpeedControls {
.bg(Color::grey(0.5)),
);
Composite::minimal_size(
Composite::aligned(
(
HorizontalAlignment::Center,
VerticalAlignment::BottomAboveOSD,
),
ManagedWidget::row(row.into_iter().map(|x| x.margin(5)).collect())
.bg(Color::hex("#4C4C4C")),
top_left,
)
}
pub fn new(ctx: &mut EventCtx, ui: &UI) -> SpeedControls {
// TODO Or fullscreen and align it?
let top_left = ScreenPt::new(
(ctx.canvas.window_width - 600.0) / 2.0,
ctx.canvas.window_height - 80.0,
);
// 10 sim minutes / real second normally, or 1 sim hour / real second for dev mode
let speed_cap: f64 = if ui.opts.dev { 3600.0 } else { 600.0 };
let mut slider = Slider::new(160.0, 15.0);
@ -171,8 +162,7 @@ impl SpeedControls {
SpeedControls {
time_panel: TimePanel::new(ctx, ui),
top_left,
composite: SpeedControls::make_panel(ctx, false, 1.0, top_left),
composite: SpeedControls::make_panel(ctx, false, 1.0),
slider,
state: SpeedState::Running {
@ -225,8 +215,7 @@ impl SpeedControls {
last_measurement: now,
last_measurement_sim: ui.primary.sim.time(),
};
self.composite =
SpeedControls::make_panel(ctx, false, desired_speed, self.top_left);
self.composite = SpeedControls::make_panel(ctx, false, desired_speed);
return None;
}
"pause" => {
@ -288,8 +277,7 @@ impl SpeedControls {
pub fn pause(&mut self, ctx: &EventCtx) {
if !self.is_paused() {
self.state = SpeedState::Paused;
self.composite =
SpeedControls::make_panel(ctx, true, self.desired_speed(), self.top_left);
self.composite = SpeedControls::make_panel(ctx, true, self.desired_speed());
}
}
@ -380,7 +368,8 @@ impl TimePanel {
fn new(ctx: &mut EventCtx, ui: &UI) -> TimePanel {
TimePanel {
time: ui.primary.sim.time(),
composite: Composite::minimal_size(
composite: Composite::aligned(
(HorizontalAlignment::Left, VerticalAlignment::Top),
ManagedWidget::col(vec![
ManagedWidget::draw_text(
ctx,
@ -419,7 +408,6 @@ impl TimePanel {
])
.bg(Color::hex("#4C4C4C"))
.padding(10),
ScreenPt::new(0.0, 0.0),
),
}
}