~saiko/game

714607efc2a488aae86b3dbb0fbe9d17962223db — 2xsaiko 1 year, 15 days ago bbcb60b
3k partial ui rewrites, fml
M src/main.rs => src/main.rs +8 -31
@@ 42,11 42,8 @@ use crate::kb::Keyboard;
use crate::math::*;
use crate::res::{DataSource, ResourceLoader};
use crate::shader::ShaderManager;
use crate::ui::element::{Button, Element, Viewport};
use crate::ui::graphics::{Alignment, Graphics, StringDrawProps};
use crate::ui::layout::{BorderLayout, LayoutManager, StackLayout};
use crate::ui::panel::Panel;
use crate::ui::UiController;
use crate::ui::UiHost;
use crate::util::{AnySurface, Color, LogPipe};
use crate::res::merge::MergeModeTable;
use std::convert::TryInto;


@@ 61,7 58,9 @@ mod res;
mod shader;
mod tex;
mod util;
#[macro_use]
mod ui;
mod testui;

const GAME_NAME: &str = "Untitled Game";
const GAME_VERSION: &str = env!("CARGO_PKG_VERSION");


@@ 205,33 204,11 @@ fn start_game(env: Rc<Environment>) {

  let fr = load_fonts(&env.rl, &display, &mut sm);

  struct TestUi<T: LayoutManager> {
    panel: Panel<T>,
  }

  impl<T: LayoutManager> UiController for TestUi<T> {
    fn get_element(&mut self) -> &mut dyn Element {
      unimplemented!()
    }
  }

  let mut ui = Panel::new(BorderLayout::new(
    Button::new("Click Me! T", || ()),
    Button::new("Click Me! B", || ()),
    Button::new("Click Me! L", || ()),
    Button::new("Click Me! R", || ()),
    Viewport::new(camera.clone(), model.clone()),
  ));

  let mut ui2 = Panel::new(StackLayout::new(vec![
    box Viewport::new(camera.clone(), model.clone()),
  ]));
  let mut ui_host = UiHost::new();

  ui.resize(window.width(), window.height());
  ui2.resize(window.width(), window.height());
//  ui_host.open_ui(TestUi::new(camera.clone(), model.clone()));

  while running.load(Ordering::Relaxed) {
    let current_ui: &mut dyn Element = if gui_mode { &mut ui } else { &mut ui2 };
    let time_start = Instant::now();
    let mut frame = display.draw();
    frame.clear(None, Some((0.0, 0.0, 0.0, 0.0)), false, Some(1.0), None);


@@ 242,7 219,7 @@ fn start_game(env: Rc<Environment>) {
    let mut surface = AnySurface::Frame(&mut frame);
    let mut g = Graphics::new(&display, &mut surface, fr.choose((12, false, window.dpi)), &mut sm, gui_mat);

    current_ui.draw(&mut g);
    ui_host.draw(&mut g);

    let fr = fr.choose((14, false, window.dpi));



@@ 279,7 256,7 @@ fn start_game(env: Rc<Environment>) {
        }
        Event::WindowEvent { event: WindowEvent::Resized(LogicalSize { width, height }), .. } => {
          window.on_resize(width, height);
          current_ui.resize(window.width(), window.height());
          ui_host.resize(window.width(), window.height());
        }
        Event::WindowEvent { event: WindowEvent::KeyboardInput { input, .. }, .. } => {
          if input.scancode == 15 && input.state == ElementState::Pressed {


@@ 303,7 280,7 @@ fn start_game(env: Rc<Environment>) {
        }
        Event::WindowEvent { event: WindowEvent::HiDpiFactorChanged(f), .. } => {
          window.on_dpi_changed(f);
          current_ui.resize(window.width(), window.height());
          ui_host.resize(window.width(), window.height());
        }
        _ => ()
      };

A src/testui.rs => src/testui.rs +65 -0
@@ 0,0 1,65 @@
use crate::ui::element::Button;
use crate::ui::graphics::Graphics;
use crate::ui::panel::Container;

pub struct TestUi {
  elements: TestUiElements,
  controller: TestUiController,
}

impl TestUi {
  fn new(controller: TestUiController) -> Self {
    let elements = controller.create_elements();
    TestUi { elements, controller }
  }
}

impl Ui for TestUi {
  fn update(&mut self) {
    unimplemented!()
  }

  fn draw(&mut self, g: &mut Graphics) {
    unimplemented!()
  }

  fn resize(&mut self, width: u32, height: u32) {
    unimplemented!()
  }
}

struct TestUiElements {
  button: Container<Button>,
  button1: Container<Button>,
}

struct TestUiController;

impl UiController for TestUiController {
  type Elements = TestUiElements;

  fn create_elements(&self) -> Self::Elements {
    TestUiElements {
      button: Button::new(""),
      button1: Button::new(""),
    }
  }

  fn update(&mut self, elements: &mut TestUiElements) {}
}

pub trait UiController {
  type Elements;

  fn create_elements(&self) -> Self::Elements;

  fn update(&mut self, elements: &mut Self::Elements);
}

pub trait Ui {
  fn update(&mut self);

  fn draw(&mut self, g: &mut Graphics);

  fn resize(&mut self, width: u32, height: u32);
}

A src/ui/access.rs => src/ui/access.rs +66 -0
@@ 0,0 1,66 @@
use crate::ui::panel::ContainerAny;

#[macro_export]
macro_rules! ui_def {
    (impl for $ui_struct:ty as $ui_access:ident {
      $($variant:ident => $field:ident),* $(,)?
    }) => {
      #[derive(Copy, Clone, Eq, PartialEq, Debug)]
      pub enum $ui_access {
        $($variant),*
      }

      impl $crate::ui::access::Values for $ui_access {
        fn values() -> &'static [Self] {
          &[$(Self::$variant),*]
        }
      }

      impl $crate::ui::access::UiAccess for $ui_struct {
        type Access = $ui_access;

        fn by_name(name: &str) -> Option<Self::Access> {
          match name {
            $(stringify!($field) => Some(Self::Access::$variant),)+
            _ => None
          }
        }

        fn get_element(&self, ident: Self::Access) -> &dyn $crate::ui::panel::ContainerAny {
          match ident {
            $(Self::Access::$variant => &self.$field,)+
          }
        }

        fn get_element_mut(&mut self, ident: Self::Access) -> &mut dyn $crate::ui::panel::ContainerAny {
          match ident {
            $(Self::Access::$variant => &mut self.$field,)+
          }
        }
      }

      impl $crate::ui::layout::LayoutManager<$ui_struct> for $ui_access {
        fn relayout_at(&self, ui: &mut $ui_struct, g: &crate::ui::graphics::Graphics, x: i32, y: i32, width: u32, height: u32) {
          $crate::ui::access::UiAccess::get_element_mut(ui, *self).set_dimensions(x, y, width, height)
        }

        fn get_resize_capabilities(&self, ui: & $ui_struct, g: & $crate::ui::graphics::Graphics) -> $crate::ui::rescap::ResizeCapabilities {
          $crate::ui::access::UiAccess::get_element(ui, *self).drawable().get_resize_capabilities(g)
        }
      }
    };
}

pub trait Values {
  fn values() -> &'static [Self];
}

pub trait UiAccess {
  type Access: Values;

  fn by_name(name: &str) -> Option<Self::Access>;

  fn get_element(&self, access: Self::Access) -> &dyn ContainerAny;

  fn get_element_mut(&mut self, access: Self::Access) -> &mut dyn ContainerAny;
}

M src/ui/element/button.rs => src/ui/element/button.rs +21 -10
@@ 1,27 1,37 @@
use crate::ui::element::Element;
use crate::ui::event::EventQueue;
use crate::ui::graphics::{Alignment, Graphics, StringDrawProps};
use crate::ui::panel::Container;
use crate::ui::rescap::ResizeCapabilities;
use crate::util::Color;

pub struct Button<F: FnMut()> {
pub enum ButtonEvent {
  Pressed,
}

pub struct Button {
  text: String,
  width: i32,
  height: i32,
  click_callback: F,
  queue: EventQueue<ButtonEvent>,
}

impl<F: FnMut()> Button<F> {
  pub fn new(text: &str, click_callback: F) -> Self {
    Button {
impl Button {
  pub fn new(text: &str) -> Container<Self> {
    Container::new(Button {
      text: text.to_owned(),
      width: 0,
      height: 0,
      click_callback,
    }
      queue: EventQueue::new(),
    })
  }

  pub fn poll_events(&mut self, op: impl FnMut(ButtonEvent)) {
    self.queue.poll_events(op);
  }
}

impl<F: FnMut()> Element for Button<F> {
impl Element for Button {
  fn draw(&mut self, g: &mut Graphics) {
    g.draw_rect(1, 1, self.width - 2, self.height - 2, Color::from_packed_rgb(0x00ccff));
    g.draw_string(&self.text, self.width / 2, self.height / 2 - (g.font_renderer().get_height() / 2.0) as i32, StringDrawProps::default().with_alignment(Alignment::Center).with_color(Color::from_packed_rgb(0x7f7f7f)));


@@ 35,7 45,7 @@ impl<F: FnMut()> Element for Button<F> {
      None,
      None,
      None,
      None
      None,
    )
  }



@@ 45,6 55,7 @@ impl<F: FnMut()> Element for Button<F> {
  }

  fn click(&mut self, mouse_x: i32, mouse_y: i32) -> bool {
    unimplemented!()
    self.queue.push(ButtonEvent::Pressed);
    true
  }
}
\ No newline at end of file

M src/ui/element/mod.rs => src/ui/element/mod.rs +40 -1
@@ 1,9 1,12 @@
use std::ops::DerefMut;

pub use button::*;
pub use spacer::*;
pub use viewport::*;

use crate::ui::graphics::Graphics;
use crate::ui::rescap::ResizeCapabilities;
use crate::ui::UiController;

mod button;
mod spacer;


@@ 28,4 31,40 @@ impl Element for () {
  }

  fn resize(&mut self, width: u32, height: u32) {}
}
\ No newline at end of file
}

impl Element for &mut dyn Element {
  fn draw(&mut self, g: &mut Graphics) {
    self.draw(g);
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
    self.get_resize_capabilities(g)
  }

  fn resize(&mut self, width: u32, height: u32) {
    self.resize(width, height);
  }

  fn click(&mut self, mouse_x: i32, mouse_y: i32) -> bool {
    self.click(mouse_x, mouse_y)
  }
}

impl Element for Box<dyn Element> {
  fn draw(&mut self, g: &mut Graphics) {
    (**self).draw(g);
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
    (**self).get_resize_capabilities(g)
  }

  fn resize(&mut self, width: u32, height: u32) {
    (**self).resize(width, height);
  }

  fn click(&mut self, mouse_x: i32, mouse_y: i32) -> bool {
    (**self).click(mouse_x, mouse_y)
  }
}

M src/ui/element/viewport.rs => src/ui/element/viewport.rs +8 -7
@@ 11,29 11,30 @@ use crate::{Model, RenderProperties, Vertex};
use crate::cam::Camera;
use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::panel::Container;
use crate::ui::rescap::ResizeCapabilities;

pub struct Viewport<'a> {
pub struct Viewport {
  camera: Rc<RefCell<Camera>>,
  model: Rc<Model<Vertex>>,
  width: u32,
  height: u32,
  fb: Option<ViewportFb<'a>>,
  fb: Option<ViewportFb<'static>>,
}

impl Viewport<'_> {
  pub fn new(camera: Rc<RefCell<Camera>>, model: Rc<Model<Vertex>>) -> Self {
    Viewport {
impl Viewport {
  pub fn new(camera: Rc<RefCell<Camera>>, model: Rc<Model<Vertex>>) -> Container<Self> {
    Container::new(Viewport {
      camera,
      model,
      width: 0,
      height: 0,
      fb: None,
    }
    })
  }
}

impl Element for Viewport<'_> {
impl Element for Viewport {
  fn draw(&mut self, g: &mut Graphics) {
    let fb = match self.fb {
      Some(ref mut s) => s,

A src/ui/event.rs => src/ui/event.rs +19 -0
@@ 0,0 1,19 @@
pub struct EventQueue<E> {
  events: Vec<E>,
}

impl<E> EventQueue<E> {
  pub fn new() -> Self {
    EventQueue { events: vec![] }
  }

  pub fn push(&mut self, event: E) {
    self.events.push(event);
  }

  pub fn poll_events(&mut self, mut op: impl FnMut(E)) {
    for event in self.events.drain(..) {
      op(event);
    }
  }
}
\ No newline at end of file

M src/ui/layout/border.rs => src/ui/layout/border.rs +37 -45
@@ 1,10 1,10 @@
use std::cmp::max;
use std::marker::PhantomData;

use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::layout::LayoutManager;
use crate::ui::layout::util::layout_stack;
use crate::ui::panel::PanelElement;
use crate::ui::rescap::ResizeCapabilities;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]


@@ 30,39 30,41 @@ pub enum Position {
/// |                 Bottom                 |
/// +----------------------------------------+
/// ```
pub struct BorderLayout<T, B, L, R, C>
  where T: Element, B: Element, L: Element, R: Element, C: Element
pub struct BorderLayout<X, T, B, L, R, C>
  where T: LayoutManager<X>, B: LayoutManager<X>, L: LayoutManager<X>, R: LayoutManager<X>, C: LayoutManager<X>
{
  top: PanelElement<T>,
  bottom: PanelElement<B>,
  left: PanelElement<L>,
  right: PanelElement<R>,
  center: PanelElement<C>,
  top: T,
  bottom: B,
  left: L,
  right: R,
  center: C,
  _phantom_data: PhantomData<X>,
}

impl<T, B, L, R, C> BorderLayout<T, B, L, R, C>
  where T: Element, B: Element, L: Element, R: Element, C: Element
impl<X, T, B, L, R, C> BorderLayout<X, T, B, L, R, C>
  where T: LayoutManager<X>, B: LayoutManager<X>, L: LayoutManager<X>, R: LayoutManager<X>, C: LayoutManager<X>
{
  pub fn new(top: T, bottom: B, left: L, right: R, center: C) -> Self {
  pub fn of(top: T, bottom: B, left: L, right: R, center: C) -> Self {
    BorderLayout {
      top: PanelElement::new(top),
      bottom: PanelElement::new(bottom),
      left: PanelElement::new(left),
      center: PanelElement::new(center),
      right: PanelElement::new(right),
      top,
      bottom,
      left,
      center,
      right,
      _phantom_data: PhantomData::default(),
    }
  }
}

impl<T, B, L, R, C> LayoutManager for BorderLayout<T, B, L, R, C>
  where T: Element, B: Element, L: Element, R: Element, C: Element
impl<X, T, B, L, R, C> LayoutManager<X> for BorderLayout<X, T, B, L, R, C>
  where T: LayoutManager<X>, B: LayoutManager<X>, L: LayoutManager<X>, R: LayoutManager<X>, C: LayoutManager<X>
{
  fn relayout(&mut self, g: &Graphics, width: u32, height: u32) {
    let top_caps = self.top.drawable().get_resize_capabilities(g);
    let bottom_caps = self.bottom.drawable().get_resize_capabilities(g);
    let left_caps = self.left.drawable().get_resize_capabilities(g);
    let right_caps = self.right.drawable().get_resize_capabilities(g);
    let center_caps = self.center.drawable().get_resize_capabilities(g);
  fn relayout_at(&self, ui: &mut X, g: &Graphics, x: i32, y: i32, width: u32, height: u32) {
    let top_caps = self.top.get_resize_capabilities(ui, g);
    let bottom_caps = self.bottom.get_resize_capabilities(ui, g);
    let left_caps = self.left.get_resize_capabilities(ui, g);
    let right_caps = self.right.get_resize_capabilities(ui, g);
    let center_caps = self.center.get_resize_capabilities(ui, g);

    let lcr_caps = left_caps.stack_right(center_caps).stack_right(right_caps);
    let full_caps = top_caps.stack_down(lcr_caps).stack_down(bottom_caps);


@@ 82,30 84,20 @@ impl<T, B, L, R, C> LayoutManager for BorderLayout<T, B, L, R, C>
    let center_height = sizes[1];
    let bottom_height = sizes[2];

    self.top.set_dimensions(0, 0, width, top_height);
    self.bottom.set_dimensions(0, (top_height + center_height) as i32, width, bottom_height);
    self.left.set_dimensions(0, top_height as i32, left_width, center_height);
    self.right.set_dimensions((left_width + center_width) as i32, top_height as i32, right_width, center_height);
    self.center.set_dimensions(left_width as i32, top_height as i32, center_width, center_height);
    self.top.relayout_at(ui, g, x, y, width, top_height);
    self.bottom.relayout_at(ui, g, x, y + (top_height + center_height) as i32, width, bottom_height);
    self.left.relayout_at(ui, g, x, y + top_height as i32, left_width, center_height);
    self.right.relayout_at(ui, g, x + (left_width + center_width) as i32, y + top_height as i32, right_width, center_height);
    self.center.relayout_at(ui, g, x + left_width as i32, y + top_height as i32, center_width, center_height);
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
    let top_caps = self.top.drawable().get_resize_capabilities(g);
    let bottom_caps = self.bottom.drawable().get_resize_capabilities(g);
    let left_caps = self.left.drawable().get_resize_capabilities(g);
    let right_caps = self.right.drawable().get_resize_capabilities(g);
    let center_caps = self.center.drawable().get_resize_capabilities(g);
  fn get_resize_capabilities(&self, ui: &X, g: &Graphics) -> ResizeCapabilities {
    let top_caps = self.top.get_resize_capabilities(ui, g);
    let bottom_caps = self.bottom.get_resize_capabilities(ui, g);
    let left_caps = self.left.get_resize_capabilities(ui, g);
    let right_caps = self.right.get_resize_capabilities(ui, g);
    let center_caps = self.center.get_resize_capabilities(ui, g);

    top_caps.stack_down(left_caps.stack_right(center_caps).stack_right(right_caps)).stack_down(bottom_caps)
  }

  fn get_drawables(&mut self) -> Vec<PanelElement<&mut dyn Element>> {
    vec![
      self.top.as_any_element(),
      self.bottom.as_any_element(),
      self.left.as_any_element(),
      self.right.as_any_element(),
      self.center.as_any_element(),
    ]
  }
}
\ No newline at end of file

M src/ui/layout/mod.rs => src/ui/layout/mod.rs +14 -8
@@ 1,23 1,29 @@
pub use border::*;
pub use grid::*;
pub use noop::*;
pub use stack::*;

use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::panel::PanelElement;
use crate::ui::rescap::ResizeCapabilities;

mod border;
mod grid;
mod noop;
mod stack;
mod util;

pub trait LayoutManager {
  fn relayout(&mut self, g: &Graphics, width: u32, height: u32);
pub trait LayoutManager<T> {
  fn relayout(&self, ui: &mut T, g: &Graphics, width: u32, height: u32) {
    self.relayout_at(ui, g, 0, 0, width, height);
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities;
  fn relayout_at(&self, ui: &mut T, g: &Graphics, x: i32, y: i32, width: u32, height: u32);

  fn get_drawables(&mut self) -> Vec<PanelElement<&mut dyn Element>>;
  fn get_resize_capabilities(&self, ui: &T, g: &Graphics) -> ResizeCapabilities;
}

impl<T> LayoutManager<T> for () {
  fn relayout_at(&self, ui: &mut T, g: &Graphics, x: i32, y: i32, width: u32, height: u32) {}

  fn get_resize_capabilities(&self, ui: &T, g: &Graphics) -> ResizeCapabilities {
    ResizeCapabilities::zero_size()
  }
}
\ No newline at end of file

D src/ui/layout/noop.rs => src/ui/layout/noop.rs +0 -28
@@ 1,28 0,0 @@
use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::layout::LayoutManager;
use crate::ui::panel::PanelElement;
use crate::ui::rescap::ResizeCapabilities;

pub struct NoopLayout {
  elements: Vec<PanelElement<Box<dyn Element>>>,
}

impl NoopLayout {
  pub fn new(elements: Vec<Box<dyn Element>>) -> Self {
    NoopLayout {
      elements: elements.into_iter().map(PanelElement::new).collect()
    }
  }
}

impl LayoutManager for NoopLayout {
  fn relayout(&mut self, g: &Graphics, width: u32, height: u32) {}

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities { ResizeCapabilities::default() }


  fn get_drawables(&mut self) -> Vec<PanelElement<&mut dyn Element>> {
    self.elements.iter_mut().map(PanelElement::as_any_element).collect()
  }
}
\ No newline at end of file

M src/ui/layout/stack.rs => src/ui/layout/stack.rs +30 -34
@@ 1,34 1,30 @@
use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::layout::LayoutManager;
use crate::ui::panel::PanelElement;
use crate::ui::rescap::ResizeCapabilities;

pub struct StackLayout {
  elements: Vec<PanelElement<Box<dyn Element>>>,
}

impl StackLayout {
  pub fn new(elements: Vec<Box<dyn Element>>) -> Self {
    StackLayout {
      elements: elements.into_iter().map(PanelElement::new).collect()
    }
  }
}

impl LayoutManager for StackLayout {
  fn relayout(&mut self, g: &Graphics, width: u32, height: u32) {
    for el in self.elements.iter_mut() {
      el.set_dimensions(0, 0, width, height);
    }
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
    self.elements.iter()
      .fold(ResizeCapabilities::default(), |acc, a| acc.combine(a.drawable().get_resize_capabilities(g)))
  }

  fn get_drawables(&mut self) -> Vec<PanelElement<&mut dyn Element>> {
    self.elements.iter_mut().map(PanelElement::as_any_element).collect()
  }
}
\ No newline at end of file
//use crate::ui::element::Element;
//use crate::ui::graphics::Graphics;
//use crate::ui::layout::LayoutManager;
//use crate::ui::panel::PanelElement;
//use crate::ui::rescap::ResizeCapabilities;
//
//pub struct StackLayout<R> {
//  elements: Vec<PanelElement<R, Box<dyn Element<R>>>>,
//}
//
//impl<R> StackLayout<R> {
//  pub fn new(elements: Vec<Box<dyn Element<R>>>) -> Self {
//    StackLayout {
//      elements: elements.into_iter().map(PanelElement::new).collect()
//    }
//  }
//}
//
//impl<R> LayoutManager<R> for StackLayout<R> {
//  fn relayout(&mut self, g: &Graphics, width: u32, height: u32) {
//    for el in self.elements.iter_mut() {
//      el.set_dimensions(0, 0, width, height);
//    }
//  }
//
//  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
//    self.elements.iter()
//      .fold(ResizeCapabilities::default(), |acc, a| acc.combine(a.drawable().get_resize_capabilities(g)))
//  }
//}
\ No newline at end of file

M src/ui/mod.rs => src/ui/mod.rs +39 -9
@@ 1,29 1,57 @@
use crate::ui::element::Element;
use crate::ui::access::UiAccess;
use crate::ui::graphics::Graphics;
use crate::ui::rescap::ResizeCapabilities;

#[macro_use]
pub mod access;
pub mod console;
pub mod layout;
pub mod element;
pub mod panel;
pub mod rescap;
pub mod graphics;
pub mod event;

pub trait UiController {
  fn get_element(&mut self) -> &mut dyn Element;
  fn update(&mut self);

  fn resize(&mut self, width: u32, height: u32) {
    self.get_element().resize(width, height);
  fn draw(&mut self, g: &mut Graphics) {
    Self::Access::values()
  }

  fn resize(&mut self, g: &Graphics, width: u32, height: u32);

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities;

  fn click(&mut self, x: i32, y: i32) -> bool;

  fn open(&mut self) {}

  fn close(&mut self) {}
}

#[macro_export]
macro_rules! ui_impl {
  ($prop:ident) => {
    fn click(&mut self, x: i32, y: i32) {
      self.$prop.click(self, x, y);
    }

    fn draw(&mut self, g: &mut Graphics) {
      self.$prop.draw(g);
    }

    fn resize(&mut self, width: u32, height: u32) {
      self.$prop.resize(width, height);
    }
  }
}

pub struct UiHost {
  current_controller: Option<Box<dyn UiController>>,
  width: u32,
  height: u32,
  needs_resize: bool,
}

impl UiHost {


@@ 32,6 60,7 @@ impl UiHost {
      current_controller: None,
      width: 0,
      height: 0,
      needs_resize: false,
    }
  }



@@ 46,22 75,23 @@ impl UiHost {
  pub fn open_ui(&mut self, mut element: impl UiController + 'static) -> Option<Box<dyn UiController>> {
    let r = self.close_ui();
    element.open();
    element.resize(self.width, self.height);
    self.current_controller = Some(box element);
    self.needs_resize = true;
    r
  }

  pub fn resize(&mut self, width: u32, height: u32) {
    self.width = width;
    self.height = height;
    if let Some(ref mut c) = self.current_controller {
      c.resize(width, height);
    }
    self.needs_resize = true;
  }

  pub fn draw(&mut self, g: &mut Graphics) {
    if let Some(ref mut c) = self.current_controller {
      c.get_element().draw(g)
      if self.needs_resize {
        c.resize(g, self.width, self.height);
      }
      c.draw(g)
    }
  }
}
\ No newline at end of file

M src/ui/panel.rs => src/ui/panel.rs +65 -85
@@ 1,40 1,9 @@
use std::ops::{Deref, DerefMut};

use crate::ui::element::Element;
use crate::ui::graphics::Graphics;
use crate::ui::layout::LayoutManager;
use crate::ui::rescap::ResizeCapabilities;

pub trait AsMutElement {
  fn as_element(&self) -> &dyn Element;

  fn as_mut_element(&mut self) -> &mut dyn Element;
}

impl<T> AsMutElement for T where T: Element {
  fn as_element(&self) -> &dyn Element { self }

  fn as_mut_element(&mut self) -> &mut dyn Element { self }
}

impl AsMutElement for &mut dyn Element {
  fn as_element(&self) -> &dyn Element { *self }

  fn as_mut_element(&mut self) -> &mut dyn Element { *self }
}

impl AsMutElement for Box<dyn Element> {
  fn as_element(&self) -> &dyn Element { self.as_ref() }

  fn as_mut_element(&mut self) -> &mut dyn Element { self.as_mut() }
}

pub struct Panel<T: LayoutManager> {
  layout_manager: T,
  width: u32,
  height: u32,
  needs_relayout: bool,
}

pub struct PanelElement<T: AsMutElement> {
pub struct Container<T: Element> {
  drawable: T,
  x: i32,
  y: i32,


@@ 42,9 11,9 @@ pub struct PanelElement<T: AsMutElement> {
  height: u32,
}

impl<T: AsMutElement> PanelElement<T> {
impl<T: Element> Container<T> {
  pub fn new(el: T) -> Self {
    PanelElement {
    Container {
      drawable: el,
      x: 0,
      y: 0,


@@ 62,7 31,7 @@ impl<T: AsMutElement> PanelElement<T> {
    self.y = y;
    self.width = width;
    self.height = height;
    self.drawable.as_mut_element().resize(width, height);
    self.drawable.resize(width, height);
  }

  pub fn x(&self) -> i32 { self.x }


@@ 73,69 42,80 @@ impl<T: AsMutElement> PanelElement<T> {

  pub fn height(&self) -> u32 { self.height }

  pub fn as_any_element(&mut self) -> PanelElement<&mut dyn Element> {
    PanelElement {
      drawable: self.drawable.as_mut_element(),
      x: self.x,
      y: self.y,
      width: self.width,
      height: self.height,
    }
  pub fn draw(&mut self, g: &mut Graphics) {
    g.push_matrix(|g| {
      g.translatei(self.x, self.y, -1);
      self.drawable_mut().draw(g);
    });
  }
}

impl<T: LayoutManager> Panel<T> {
  pub fn new(lm: T) -> Self {
    Panel {
      layout_manager: lm,
      width: 0,
      height: 0,
      needs_relayout: false,
  pub fn click(&mut self, x: i32, y: i32) -> bool {
    if x >= self.x && y >= self.y && x < self.x + self.width as i32 && y < self.y - self.height as i32 {
      let i = self.x;
      let i1 = self.y;
      self.drawable_mut().click(x - i, y - i1)
    } else {
      false
    }
  }

  pub fn relayout(&mut self, g: &Graphics) {
    self.layout_manager.relayout(g, self.width, self.height);
  pub fn into_inner(self) -> T {
    self.drawable
  }
}

  pub fn schedule_relayout(&mut self) {
    self.needs_relayout = true;
  }
impl<T: Element> Deref for Container<T> {
  type Target = T;

  fn deref(&self) -> &Self::Target { &self.drawable }
}

impl<T: LayoutManager> Element for Panel<T> {
  fn draw(&mut self, g: &mut Graphics) {
    if self.needs_relayout {
      self.relayout(g);
      self.needs_relayout = false;
    }
impl<T: Element> DerefMut for Container<T> {
  fn deref_mut(&mut self) -> &mut Self::Target { &mut self.drawable }
}

    for mut el in self.layout_manager.get_drawables() {
      g.push_matrix(|g| {
        g.translatei(el.x(), el.y(), 1);
        el.drawable_mut().draw(g);
      });
    }
pub trait ContainerAny {
  fn drawable(&self) -> &dyn Element;

  fn drawable_mut(&mut self) -> &mut dyn Element;

  fn set_dimensions(&mut self, x: i32, y: i32, width: u32, height: u32);

  fn x(&self) -> i32;

  fn y(&self) -> i32;

  fn width(&self) -> u32;

  fn height(&self) -> u32;
}

impl<T: Element> ContainerAny for Container<T> {
  fn drawable(&self) -> &dyn Element {
    self.drawable()
  }

  fn get_resize_capabilities(&self, g: &Graphics) -> ResizeCapabilities {
    self.layout_manager.get_resize_capabilities(g)
  fn drawable_mut(&mut self) -> &mut dyn Element {
    self.drawable_mut()
  }

  fn resize(&mut self, width: u32, height: u32) {
    self.width = width;
    self.height = height;
    self.schedule_relayout();
  fn set_dimensions(&mut self, x: i32, y: i32, width: u32, height: u32) {
    self.set_dimensions(x, y, width, height)
  }

  fn x(&self) -> i32 {
    self.x()
  }

  fn y(&self) -> i32 {
    self.y()
  }

  fn width(&self) -> u32 {
    self.width()
  }

  fn click(&mut self, mouse_x: i32, mouse_y: i32) -> bool {
    self.layout_manager.get_drawables().iter_mut()
      .filter(|el|
        mouse_x >= el.x() && mouse_x < (el.x() + el.width() as i32) && mouse_y >= el.y() && mouse_y < (el.y() + el.height() as i32))
      .fold(false, |acc, a| {
        let x = a.x();
        let y = a.y();
        acc || a.drawable_mut().click(mouse_x - x, mouse_y - y)
      })
  fn height(&self) -> u32 {
    self.height()
  }
}
\ No newline at end of file

M src/util/mod.rs => src/util/mod.rs +1 -1
@@ 11,4 11,4 @@ mod logpipe;
mod math;
mod multiwrite;
mod rectmap;
pub mod single;
\ No newline at end of file
pub mod single;