2019-11-24 18:21:23 +03:00
|
|
|
use crate::game::{State, Transition};
|
|
|
|
use crate::ui::UI;
|
2019-11-30 20:15:51 +03:00
|
|
|
use ezgui::layout::Widget;
|
2019-12-09 00:44:43 +03:00
|
|
|
use ezgui::{
|
2019-12-16 05:42:14 +03:00
|
|
|
Button, Color, DrawBoth, Drawable, EventCtx, GeomBatch, GfxCtx, JustDraw, Line, MultiKey,
|
|
|
|
RewriteColor, ScreenDims, ScreenPt, ScreenRectangle, Text,
|
2019-12-09 00:44:43 +03:00
|
|
|
};
|
2019-12-16 04:09:41 +03:00
|
|
|
use geom::{Distance, Polygon};
|
|
|
|
use stretch::geometry::{Rect, Size};
|
2019-11-30 20:15:51 +03:00
|
|
|
use stretch::node::{Node, Stretch};
|
2019-11-30 21:09:31 +03:00
|
|
|
use stretch::style::{AlignItems, Dimension, FlexDirection, FlexWrap, JustifyContent, Style};
|
2019-11-24 18:21:23 +03:00
|
|
|
|
2019-12-16 20:42:12 +03:00
|
|
|
pub type Callback = Box<dyn Fn(&mut EventCtx, &mut UI) -> Option<Transition>>;
|
2019-11-24 18:21:23 +03:00
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
pub struct ManagedWidget {
|
|
|
|
widget: WidgetType,
|
|
|
|
style: LayoutStyle,
|
|
|
|
rect: Option<ScreenRectangle>,
|
|
|
|
bg: Option<Drawable>,
|
|
|
|
}
|
|
|
|
|
|
|
|
enum WidgetType {
|
2019-11-30 20:15:51 +03:00
|
|
|
Draw(JustDraw),
|
|
|
|
Btn(Button, Callback),
|
2019-12-16 04:09:41 +03:00
|
|
|
Row(Vec<ManagedWidget>),
|
|
|
|
Column(Vec<ManagedWidget>),
|
2019-11-30 21:09:31 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
struct LayoutStyle {
|
|
|
|
bg_color: Option<Color>,
|
|
|
|
align_items: Option<AlignItems>,
|
|
|
|
justify_content: Option<JustifyContent>,
|
|
|
|
flex_wrap: Option<FlexWrap>,
|
|
|
|
padding: Option<Rect<Dimension>>,
|
2019-12-16 20:42:12 +03:00
|
|
|
min_size: Option<Size<Dimension>>,
|
2019-11-30 21:09:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LayoutStyle {
|
|
|
|
fn apply(&self, style: &mut Style) {
|
2019-12-16 04:09:41 +03:00
|
|
|
if let Some(x) = self.align_items {
|
|
|
|
style.align_items = x;
|
|
|
|
}
|
|
|
|
if let Some(x) = self.justify_content {
|
|
|
|
style.justify_content = x;
|
|
|
|
}
|
|
|
|
if let Some(x) = self.flex_wrap {
|
|
|
|
style.flex_wrap = x;
|
|
|
|
}
|
|
|
|
if let Some(x) = self.padding {
|
|
|
|
style.padding = x;
|
2019-11-30 21:09:31 +03:00
|
|
|
}
|
2019-12-16 20:42:12 +03:00
|
|
|
if let Some(x) = self.min_size {
|
|
|
|
style.min_size = x;
|
|
|
|
}
|
2019-11-30 21:09:31 +03:00
|
|
|
}
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
impl ManagedWidget {
|
2019-12-16 04:09:41 +03:00
|
|
|
fn new(widget: WidgetType) -> ManagedWidget {
|
|
|
|
ManagedWidget {
|
|
|
|
widget,
|
|
|
|
style: LayoutStyle {
|
|
|
|
bg_color: None,
|
|
|
|
align_items: None,
|
|
|
|
justify_content: None,
|
|
|
|
flex_wrap: None,
|
|
|
|
padding: None,
|
2019-12-16 20:42:12 +03:00
|
|
|
min_size: None,
|
2019-12-16 04:09:41 +03:00
|
|
|
},
|
|
|
|
rect: None,
|
|
|
|
bg: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn centered(mut self) -> ManagedWidget {
|
|
|
|
self.style.align_items = Some(AlignItems::Center);
|
|
|
|
self.style.justify_content = Some(JustifyContent::SpaceAround);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-16 05:42:14 +03:00
|
|
|
pub fn evenly_spaced(mut self) -> ManagedWidget {
|
|
|
|
self.style.justify_content = Some(JustifyContent::SpaceBetween);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
pub fn flex_wrap(mut self) -> ManagedWidget {
|
|
|
|
self.style.flex_wrap = Some(FlexWrap::Wrap);
|
|
|
|
self.style.justify_content = Some(JustifyContent::SpaceAround);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn bg(mut self, color: Color) -> ManagedWidget {
|
|
|
|
self.style.bg_color = Some(color);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn padding(mut self, pixels: usize) -> ManagedWidget {
|
|
|
|
self.style.padding = Some(Rect {
|
|
|
|
start: Dimension::Points(pixels as f32),
|
|
|
|
end: Dimension::Points(pixels as f32),
|
|
|
|
top: Dimension::Points(pixels as f32),
|
|
|
|
bottom: Dimension::Points(pixels as f32),
|
|
|
|
});
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-16 20:42:12 +03:00
|
|
|
pub fn min_width(mut self, pixels: usize) -> ManagedWidget {
|
|
|
|
self.style.min_size = Some(Size {
|
|
|
|
width: Dimension::Points(pixels as f32),
|
|
|
|
height: Dimension::Undefined,
|
|
|
|
});
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-12-16 05:42:14 +03:00
|
|
|
pub fn draw_batch(ctx: &EventCtx, batch: GeomBatch) -> ManagedWidget {
|
|
|
|
ManagedWidget::new(WidgetType::Draw(JustDraw::wrap(DrawBoth::new(
|
|
|
|
ctx,
|
|
|
|
batch,
|
|
|
|
Vec::new(),
|
|
|
|
))))
|
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
// TODO Helpers that should probably be written differently
|
|
|
|
pub fn draw_text(ctx: &EventCtx, txt: Text) -> ManagedWidget {
|
2019-12-16 04:09:41 +03:00
|
|
|
ManagedWidget::new(WidgetType::Draw(JustDraw::text(txt, ctx)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw_svg(ctx: &EventCtx, filename: &str) -> ManagedWidget {
|
|
|
|
ManagedWidget::new(WidgetType::Draw(JustDraw::svg(filename, ctx)))
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 20:42:12 +03:00
|
|
|
pub fn btn(btn: Button, onclick: Callback) -> ManagedWidget {
|
|
|
|
ManagedWidget::new(WidgetType::Btn(btn, onclick))
|
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
pub fn img_button(
|
|
|
|
ctx: &EventCtx,
|
|
|
|
filename: &str,
|
|
|
|
hotkey: Option<MultiKey>,
|
|
|
|
onclick: Callback,
|
|
|
|
) -> ManagedWidget {
|
2019-12-16 20:42:12 +03:00
|
|
|
ManagedWidget::btn(Button::rectangle_img(filename, hotkey, ctx), onclick)
|
2019-11-24 18:21:27 +03:00
|
|
|
}
|
|
|
|
|
2019-12-08 21:24:01 +03:00
|
|
|
pub fn svg_button(
|
2019-11-30 20:15:51 +03:00
|
|
|
ctx: &EventCtx,
|
2019-11-24 18:21:27 +03:00
|
|
|
filename: &str,
|
2019-11-28 20:55:56 +03:00
|
|
|
tooltip: &str,
|
2019-11-24 18:21:27 +03:00
|
|
|
hotkey: Option<MultiKey>,
|
|
|
|
onclick: Callback,
|
2019-11-30 20:15:51 +03:00
|
|
|
) -> ManagedWidget {
|
2019-12-16 20:42:12 +03:00
|
|
|
ManagedWidget::btn(
|
|
|
|
Button::rectangle_svg(
|
|
|
|
filename,
|
|
|
|
tooltip,
|
|
|
|
hotkey,
|
|
|
|
RewriteColor::Change(Color::WHITE, Color::ORANGE),
|
|
|
|
ctx,
|
|
|
|
),
|
|
|
|
onclick,
|
|
|
|
)
|
2019-11-24 18:21:27 +03:00
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
pub fn text_button(
|
|
|
|
ctx: &EventCtx,
|
|
|
|
label: &str,
|
|
|
|
hotkey: Option<MultiKey>,
|
|
|
|
onclick: Callback,
|
|
|
|
) -> ManagedWidget {
|
|
|
|
ManagedWidget::detailed_text_button(
|
|
|
|
ctx,
|
|
|
|
Text::from(Line(label).fg(Color::BLACK)),
|
|
|
|
hotkey,
|
|
|
|
onclick,
|
|
|
|
)
|
2019-11-24 18:21:30 +03:00
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
pub fn detailed_text_button(
|
|
|
|
ctx: &EventCtx,
|
|
|
|
txt: Text,
|
|
|
|
hotkey: Option<MultiKey>,
|
|
|
|
onclick: Callback,
|
|
|
|
) -> ManagedWidget {
|
2019-11-24 18:21:27 +03:00
|
|
|
// TODO Default style. Lots of variations.
|
2019-12-16 20:42:12 +03:00
|
|
|
ManagedWidget::btn(
|
|
|
|
Button::text(txt, Color::WHITE, Color::ORANGE, hotkey, "", ctx),
|
|
|
|
onclick,
|
|
|
|
)
|
2019-12-16 04:09:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn row(widgets: Vec<ManagedWidget>) -> ManagedWidget {
|
|
|
|
ManagedWidget::new(WidgetType::Row(widgets))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn col(widgets: Vec<ManagedWidget>) -> ManagedWidget {
|
|
|
|
ManagedWidget::new(WidgetType::Column(widgets))
|
2019-11-30 20:15:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO Maybe just inline this code below, more clear
|
|
|
|
|
|
|
|
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transition> {
|
2019-12-16 04:09:41 +03:00
|
|
|
match self.widget {
|
|
|
|
WidgetType::Draw(_) => {}
|
|
|
|
WidgetType::Btn(ref mut btn, ref onclick) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
btn.event(ctx);
|
|
|
|
if btn.clicked() {
|
|
|
|
if let Some(t) = (onclick)(ctx, ui) {
|
|
|
|
return Some(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Row(ref mut widgets) | WidgetType::Column(ref mut widgets) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
for w in widgets {
|
|
|
|
if let Some(t) = w.event(ctx, ui) {
|
|
|
|
return Some(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-11-30 20:15:51 +03:00
|
|
|
fn draw(&self, g: &mut GfxCtx) {
|
2019-12-16 04:09:41 +03:00
|
|
|
if let Some(ref bg) = self.bg {
|
|
|
|
g.fork_screenspace();
|
|
|
|
g.redraw(bg);
|
|
|
|
g.unfork();
|
|
|
|
}
|
|
|
|
|
|
|
|
match self.widget {
|
|
|
|
WidgetType::Draw(ref j) => j.draw(g),
|
|
|
|
WidgetType::Btn(ref btn, _) => btn.draw(g),
|
|
|
|
WidgetType::Row(ref widgets) | WidgetType::Column(ref widgets) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
for w in widgets {
|
|
|
|
w.draw(g);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
pub struct Composite {
|
2019-11-30 20:15:51 +03:00
|
|
|
top_level: ManagedWidget,
|
2019-12-16 04:09:41 +03:00
|
|
|
pos: CompositePosition,
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
enum CompositePosition {
|
|
|
|
FillScreen,
|
|
|
|
MinimalTopLeft(ScreenPt),
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
impl Composite {
|
|
|
|
pub fn minimal_size(top_level: ManagedWidget, top_left: ScreenPt) -> Composite {
|
|
|
|
Composite {
|
|
|
|
top_level,
|
|
|
|
pos: CompositePosition::MinimalTopLeft(top_left),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn fill_screen(top_level: ManagedWidget) -> Composite {
|
|
|
|
Composite {
|
|
|
|
top_level,
|
|
|
|
pos: CompositePosition::FillScreen,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Option<Transition> {
|
2019-11-24 18:21:30 +03:00
|
|
|
// TODO If this ever gets slow, only run if window size has changed.
|
2019-11-30 20:15:51 +03:00
|
|
|
let mut stretch = Stretch::new();
|
|
|
|
let root = stretch
|
|
|
|
.new_node(
|
2019-12-16 04:09:41 +03:00
|
|
|
match self.pos {
|
|
|
|
CompositePosition::FillScreen => Style {
|
|
|
|
size: Size {
|
|
|
|
width: Dimension::Points(ctx.canvas.window_width as f32),
|
|
|
|
height: Dimension::Points(ctx.canvas.window_height as f32),
|
|
|
|
},
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
CompositePosition::MinimalTopLeft(_) => Style {
|
|
|
|
// TODO There a way to encode the offset in stretch?
|
|
|
|
..Default::default()
|
2019-11-30 20:15:51 +03:00
|
|
|
},
|
|
|
|
},
|
|
|
|
Vec::new(),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let mut nodes = vec![];
|
|
|
|
flexbox(root, &self.top_level, &mut stretch, &mut nodes);
|
|
|
|
nodes.reverse();
|
|
|
|
|
|
|
|
stretch.compute_layout(root, Size::undefined()).unwrap();
|
2019-12-16 04:09:41 +03:00
|
|
|
let top_left = match self.pos {
|
|
|
|
CompositePosition::FillScreen => ScreenPt::new(0.0, 0.0),
|
|
|
|
CompositePosition::MinimalTopLeft(pt) => pt,
|
|
|
|
};
|
|
|
|
apply_flexbox(
|
|
|
|
&mut self.top_level,
|
|
|
|
&stretch,
|
|
|
|
&mut nodes,
|
|
|
|
top_left.x,
|
|
|
|
top_left.y,
|
|
|
|
ctx,
|
|
|
|
);
|
2019-11-30 20:15:51 +03:00
|
|
|
assert!(nodes.is_empty());
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
self.top_level.event(ctx, ui)
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
pub fn draw(&self, g: &mut GfxCtx) {
|
2019-12-16 05:42:14 +03:00
|
|
|
// The order the very first round is a bit weird.
|
|
|
|
if let Some(ref rect) = self.top_level.rect {
|
|
|
|
g.canvas.mark_covered_area(rect.clone());
|
|
|
|
}
|
2019-11-30 20:15:51 +03:00
|
|
|
self.top_level.draw(g);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 04:09:41 +03:00
|
|
|
// TODO Put these two inside ManagedWidget
|
2019-11-30 20:15:51 +03:00
|
|
|
// Populate a flattened list of Nodes, matching the traversal order
|
|
|
|
fn flexbox(parent: Node, w: &ManagedWidget, stretch: &mut Stretch, nodes: &mut Vec<Node>) {
|
2019-12-16 04:09:41 +03:00
|
|
|
match w.widget {
|
|
|
|
WidgetType::Draw(ref widget) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
let dims = widget.get_dims();
|
2019-12-16 04:09:41 +03:00
|
|
|
let mut style = Style {
|
|
|
|
size: Size {
|
|
|
|
width: Dimension::Points(dims.width as f32),
|
|
|
|
height: Dimension::Points(dims.height as f32),
|
|
|
|
},
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
w.style.apply(&mut style);
|
|
|
|
let node = stretch.new_node(style, Vec::new()).unwrap();
|
2019-11-30 20:15:51 +03:00
|
|
|
stretch.add_child(parent, node).unwrap();
|
|
|
|
nodes.push(node);
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Btn(ref widget, _) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
let dims = widget.get_dims();
|
2019-12-16 04:09:41 +03:00
|
|
|
let mut style = Style {
|
|
|
|
size: Size {
|
|
|
|
width: Dimension::Points(dims.width as f32),
|
|
|
|
height: Dimension::Points(dims.height as f32),
|
|
|
|
},
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
w.style.apply(&mut style);
|
|
|
|
let node = stretch.new_node(style, Vec::new()).unwrap();
|
2019-11-30 20:15:51 +03:00
|
|
|
stretch.add_child(parent, node).unwrap();
|
|
|
|
nodes.push(node);
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Row(ref widgets) => {
|
2019-11-30 21:09:31 +03:00
|
|
|
let mut style = Style {
|
|
|
|
flex_direction: FlexDirection::Row,
|
|
|
|
..Default::default()
|
|
|
|
};
|
2019-12-16 04:09:41 +03:00
|
|
|
w.style.apply(&mut style);
|
2019-11-30 21:09:31 +03:00
|
|
|
let row = stretch.new_node(style, Vec::new()).unwrap();
|
2019-11-30 20:15:51 +03:00
|
|
|
nodes.push(row);
|
|
|
|
for widget in widgets {
|
|
|
|
flexbox(row, widget, stretch, nodes);
|
|
|
|
}
|
|
|
|
stretch.add_child(parent, row).unwrap();
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Column(ref widgets) => {
|
2019-11-30 21:09:31 +03:00
|
|
|
let mut style = Style {
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
..Default::default()
|
|
|
|
};
|
2019-12-16 04:09:41 +03:00
|
|
|
w.style.apply(&mut style);
|
2019-11-30 21:09:31 +03:00
|
|
|
let col = stretch.new_node(style, Vec::new()).unwrap();
|
2019-11-30 20:15:51 +03:00
|
|
|
nodes.push(col);
|
|
|
|
for widget in widgets {
|
|
|
|
flexbox(col, widget, stretch, nodes);
|
|
|
|
}
|
|
|
|
stretch.add_child(parent, col).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_flexbox(
|
|
|
|
w: &mut ManagedWidget,
|
|
|
|
stretch: &Stretch,
|
|
|
|
nodes: &mut Vec<Node>,
|
|
|
|
dx: f64,
|
|
|
|
dy: f64,
|
2019-12-16 04:09:41 +03:00
|
|
|
ctx: &mut EventCtx,
|
2019-11-30 20:15:51 +03:00
|
|
|
) {
|
2019-12-16 04:09:41 +03:00
|
|
|
let result = stretch.layout(nodes.pop().unwrap()).unwrap();
|
|
|
|
let x: f64 = result.location.x.into();
|
|
|
|
let y: f64 = result.location.y.into();
|
|
|
|
let width: f64 = result.size.width.into();
|
|
|
|
let height: f64 = result.size.height.into();
|
|
|
|
w.rect = Some(ScreenRectangle::top_left(
|
|
|
|
ScreenPt::new(x + dx, y + dy),
|
|
|
|
ScreenDims::new(width, height),
|
|
|
|
));
|
|
|
|
if let Some(color) = w.style.bg_color {
|
|
|
|
let mut batch = GeomBatch::new();
|
|
|
|
batch.push(
|
|
|
|
color,
|
|
|
|
Polygon::rounded_rectangle(
|
|
|
|
Distance::meters(width),
|
|
|
|
Distance::meters(height),
|
|
|
|
Distance::meters(5.0),
|
|
|
|
)
|
|
|
|
.translate(x + dx, y + dy),
|
|
|
|
);
|
|
|
|
w.bg = Some(batch.upload(ctx));
|
|
|
|
}
|
|
|
|
|
|
|
|
match w.widget {
|
|
|
|
WidgetType::Draw(ref mut widget) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
widget.set_pos(ScreenPt::new(x + dx, y + dy));
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Btn(ref mut widget, _) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
widget.set_pos(ScreenPt::new(x + dx, y + dy));
|
2019-11-24 18:21:27 +03:00
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Row(ref mut widgets) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
// layout() doesn't return absolute position; it's relative to the container.
|
|
|
|
for widget in widgets {
|
2019-12-16 04:09:41 +03:00
|
|
|
apply_flexbox(widget, stretch, nodes, x + dx, y + dy, ctx);
|
2019-11-30 20:15:51 +03:00
|
|
|
}
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
WidgetType::Column(ref mut widgets) => {
|
2019-11-30 20:15:51 +03:00
|
|
|
for widget in widgets {
|
2019-12-16 04:09:41 +03:00
|
|
|
apply_flexbox(widget, stretch, nodes, x + dx, y + dy, ctx);
|
2019-11-30 20:15:51 +03:00
|
|
|
}
|
2019-11-24 18:21:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-16 04:09:41 +03:00
|
|
|
|
|
|
|
pub struct ManagedGUIState {
|
|
|
|
composite: Composite,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ManagedGUIState {
|
|
|
|
pub fn new(top_level: ManagedWidget) -> Box<dyn State> {
|
|
|
|
Box::new(ManagedGUIState {
|
|
|
|
composite: Composite::fill_screen(top_level),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State for ManagedGUIState {
|
|
|
|
fn event(&mut self, ctx: &mut EventCtx, ui: &mut UI) -> Transition {
|
|
|
|
if let Some(t) = self.composite.event(ctx, ui) {
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
Transition::Keep
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw_default_ui(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
|
|
|
|
fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
|
|
|
// Happens to be a nice background color too ;)
|
|
|
|
g.clear(ui.cs.get("grass"));
|
|
|
|
self.composite.draw(g);
|
|
|
|
}
|
|
|
|
}
|