mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 17:34:58 +03:00
add screen positioning to some Composites
This commit is contained in:
parent
d9a68332e5
commit
56285a7b30
@ -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)]
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
},
|
||||
))))
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user