semi working
This commit is contained in:
+9
-1
@@ -4,6 +4,14 @@ pub struct Rect;
|
|||||||
|
|
||||||
impl Element for Rect {
|
impl Element for Rect {
|
||||||
fn render(&mut self, scope: &mut crate::render::RenderScope) {
|
fn render(&mut self, scope: &mut crate::render::RenderScope) {
|
||||||
scope.draw_rect();
|
scope.draw_rect(300, 300, 0xffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
pub mod tick;
|
||||||
|
pub mod velocity;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::widget::Widget;
|
||||||
|
|
||||||
|
pub trait Extension {
|
||||||
|
fn init(&self, _widgets: &Vec<Arc<Widget>>) {}
|
||||||
|
fn render(&self, _widget: &Arc<Widget>) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{component, extensions::Extension, widget::Widget};
|
||||||
|
|
||||||
|
pub struct TickExtension(pub usize);
|
||||||
|
|
||||||
|
impl Extension for TickExtension {
|
||||||
|
fn init(&self, widgets: &Vec<Arc<Widget>>) {
|
||||||
|
let rate_dur = 1000 / self.0 as u64;
|
||||||
|
std::thread::spawn({
|
||||||
|
let widgets = widgets.clone();
|
||||||
|
move || loop {
|
||||||
|
for w in &widgets {
|
||||||
|
if let Some(on_tick) = w.get::<OnTick>() {
|
||||||
|
(on_tick.0)(&w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(rate_dur));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component!(OnTick(pub fn(&Arc<Widget>)));
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
component,
|
||||||
|
extensions::Extension,
|
||||||
|
style::{Position, Transform},
|
||||||
|
widget::Widget,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct VelocityExtension;
|
||||||
|
|
||||||
|
impl VelocityExtension {
|
||||||
|
fn apply_velocity(ticks: usize, velocity: i32, x: &mut usize) {
|
||||||
|
if velocity.abs() != 0 && ticks as i32 % (1000 / velocity.abs()) == 0 {
|
||||||
|
if velocity > 0 {
|
||||||
|
*x += 1;
|
||||||
|
} else if velocity < 0 {
|
||||||
|
*x -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VelocityExtension {
|
||||||
|
fn apply_velocity_xy(ticks: usize, widget: &Arc<Widget>) {
|
||||||
|
if let Some(velocity) = widget.get::<Velocity>() {
|
||||||
|
if let Some(mut t) = widget.get::<Transform>() {
|
||||||
|
match &mut t.x {
|
||||||
|
Position::Const(x) => Self::apply_velocity(ticks, velocity.0, x),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
match &mut t.y {
|
||||||
|
Position::Const(y) => Self::apply_velocity(ticks, velocity.1, y),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
widget.set_component(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Extension for VelocityExtension {
|
||||||
|
fn init(&self, widgets: &Vec<Arc<Widget>>) {
|
||||||
|
std::thread::spawn({
|
||||||
|
let widgets = widgets.clone();
|
||||||
|
move || {
|
||||||
|
let mut tick = 0;
|
||||||
|
loop {
|
||||||
|
for widget in &widgets {
|
||||||
|
Self::apply_velocity_xy(tick, widget);
|
||||||
|
}
|
||||||
|
if tick > 1000 {
|
||||||
|
tick = 0;
|
||||||
|
} else {
|
||||||
|
tick += 1;
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component!(Velocity(pub i32, pub i32));
|
||||||
+51
-17
@@ -1,46 +1,80 @@
|
|||||||
pub mod elements;
|
use std::sync::Arc;
|
||||||
pub mod render;
|
|
||||||
pub mod widget;
|
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
|
|
||||||
use minifb::Window;
|
use minifb::Window;
|
||||||
|
|
||||||
use crate::{render::RenderScope, widget::Element};
|
use crate::{
|
||||||
|
extensions::Extension,
|
||||||
|
render::RenderScope,
|
||||||
|
style::Transform,
|
||||||
|
widget::{Element, Widget},
|
||||||
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub mod elements;
|
||||||
|
pub mod extensions;
|
||||||
|
pub mod macros;
|
||||||
|
pub mod render;
|
||||||
|
pub mod style;
|
||||||
|
pub mod widget;
|
||||||
|
|
||||||
|
pub struct Screen {
|
||||||
window: Window,
|
window: Window,
|
||||||
elements: Vec<Arc<Mutex<Box<dyn Element>>>>,
|
pub widgets: Vec<Arc<Widget>>,
|
||||||
|
extensions: Vec<Arc<Box<dyn Extension>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl Screen {
|
||||||
pub fn new(win: Window) -> Self {
|
pub fn new(win: Window) -> Screen {
|
||||||
Self {
|
Screen {
|
||||||
window: win,
|
window: win,
|
||||||
elements: Vec::new(),
|
widgets: Vec::new(),
|
||||||
|
extensions: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element<E: Element + 'static>(&mut self, e: E) {
|
pub fn draw<E: Element + 'static>(&mut self, element: E) -> &Arc<Widget> {
|
||||||
self.elements.push(Arc::new(Mutex::new(Box::new(e))));
|
self.widgets.push(Arc::new(Widget::new(Box::new(element))));
|
||||||
|
self.widgets.last().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) {
|
pub fn extension<E: Extension + 'static>(&mut self, ext: E) {
|
||||||
|
self.extensions.push(Arc::new(Box::new(ext)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) -> std::io::Result<()> {
|
||||||
|
for elem in &mut self.widgets {
|
||||||
|
elem.component(Transform::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
for ext in &self.extensions {
|
||||||
|
ext.init(&self.widgets);
|
||||||
|
}
|
||||||
|
|
||||||
while self.window.is_open() {
|
while self.window.is_open() {
|
||||||
self.render();
|
self.render();
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(28));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self) {
|
fn render(&mut self) {
|
||||||
let (w, h) = self.window.get_size();
|
let (w, h) = self.window.get_size();
|
||||||
let mut scope = RenderScope::new(w, h);
|
let mut scope = RenderScope::new(w, h);
|
||||||
|
|
||||||
for e in &self.elements {
|
for e in &self.widgets {
|
||||||
e.lock().unwrap().render(&mut scope);
|
e.0.lock().unwrap().render(&mut scope);
|
||||||
|
scope.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window
|
self.window
|
||||||
.update_with_buffer(&scope.get_buffer(), w, h)
|
.update_with_buffer(&scope.get_buffer(), w, h)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_extension(&self, wi: Arc<Widget>) -> std::io::Result<()> {
|
||||||
|
for ext in &self.extensions {
|
||||||
|
ext.render(&wi);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! event {
|
||||||
|
($name:ident) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name;
|
||||||
|
|
||||||
|
impl $crate::events::Event for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident {$($inner:tt)*}) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name {
|
||||||
|
$($inner)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::events::Event for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident ($($inner:tt)*)) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name ($($inner)*);
|
||||||
|
|
||||||
|
impl $crate::events::Event for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! component {
|
||||||
|
($name:ident) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name;
|
||||||
|
|
||||||
|
impl $crate::widget::Component for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident {$($inner:tt)*}) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name {
|
||||||
|
$($inner)*
|
||||||
|
}
|
||||||
|
|
||||||
|
impl $crate::widget::Component for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
($name:ident ($($inner:tt)*)) => {
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct $name ($($inner)*);
|
||||||
|
|
||||||
|
impl $crate::widget::Component for $name {
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro to create an event handler closure that calls a method on `self`
|
||||||
|
///
|
||||||
|
/// This macro automates the pattern of capturing `self` as a raw pointer,
|
||||||
|
/// then passing an event to a method on `self` inside an unsafe closure.
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `$self_ty`: The self type.
|
||||||
|
/// - `$self`: The instance variable (usually `self`) to call the method on.
|
||||||
|
/// - `$events`: The event source which has an `.on` method to register the handler.
|
||||||
|
/// - `$method`: The method name on `self` to call when an event occurs.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// ```rust
|
||||||
|
/// event_handler!(self, events, on_keypress);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This expands roughly to:
|
||||||
|
/// ```rust
|
||||||
|
/// let self_ref = self as *mut Self;
|
||||||
|
/// events.on(move |event| unsafe { (*self_ref).on_keypress(event) });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// This macro uses `unsafe` code because it dereferences a raw pointer inside the closure.
|
||||||
|
/// Ensure that the `self` reference lives at least as long as the closure to avoid undefined behavior.
|
||||||
|
///
|
||||||
|
/// # Why use raw pointers here?
|
||||||
|
/// Often, event handlers require `'static` closures, but `self` is a stack reference.
|
||||||
|
/// Capturing `self` directly is not possible, so this workaround uses a raw pointer.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! event_handler {
|
||||||
|
($self_ty:ty, $self:ident, $events:ident, $method:ident) => {{
|
||||||
|
let self_ref = $self as *mut $self_ty;
|
||||||
|
$events.on(move |es, e| unsafe { (*self_ref).$method(es, e) });
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! rsx {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
+19
-5
@@ -1,12 +1,26 @@
|
|||||||
use minifb::{Window, WindowOptions};
|
use minifb::{Window, WindowOptions};
|
||||||
use osgui::{elements::Rect, App};
|
use osgui::{
|
||||||
|
elements::Rect,
|
||||||
|
extensions::velocity::{Velocity, VelocityExtension},
|
||||||
|
Screen,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let window = Window::new("minifb example", 500, 500, WindowOptions::default()).unwrap();
|
let window = Window::new(
|
||||||
|
"minifb example",
|
||||||
|
500,
|
||||||
|
500,
|
||||||
|
WindowOptions {
|
||||||
|
resize: false,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let mut app = App::new(window);
|
let mut app = Screen::new(window);
|
||||||
|
app.extension(VelocityExtension);
|
||||||
|
|
||||||
app.element(Rect);
|
app.draw(Rect).component(Velocity(100, 0));
|
||||||
|
|
||||||
app.run();
|
app.run().unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
+58
-8
@@ -1,26 +1,76 @@
|
|||||||
|
use crate::style::{RawTransform, Transform};
|
||||||
|
|
||||||
|
enum RenderMethod {
|
||||||
|
// Text(String),
|
||||||
|
Rectangle(usize, usize, u32),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct RenderScope {
|
pub struct RenderScope {
|
||||||
|
transform: RawTransform,
|
||||||
|
render_stack: Vec<RenderMethod>,
|
||||||
|
parent_width: usize,
|
||||||
|
parent_height: usize,
|
||||||
buffer: Vec<u32>,
|
buffer: Vec<u32>,
|
||||||
width: usize,
|
|
||||||
height: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderScope {
|
impl RenderScope {
|
||||||
pub fn new(w: usize, h: usize) -> Self {
|
pub fn new(w: usize, h: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer: vec![0; w * h],
|
buffer: vec![0; w * h],
|
||||||
width: w,
|
render_stack: Vec::new(),
|
||||||
height: h,
|
parent_width: w,
|
||||||
|
parent_height: h,
|
||||||
|
transform: RawTransform::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_rect(&mut self) {
|
pub fn set_transform(&mut self, transform: &Transform) {
|
||||||
for y in 0..200 {
|
transform.use_dimensions(&mut self.transform);
|
||||||
for x in 0..200 {
|
transform.use_position(self.parent_width, self.parent_height, &mut self.transform);
|
||||||
self.buffer[y * self.height + x] = 0xFF00FF;
|
}
|
||||||
|
|
||||||
|
// pub fn draw_text(&mut self, text: &str) {
|
||||||
|
// self.render_stack.push(RenderMethod::Text(text.to_string()));
|
||||||
|
// let (w, h) = utils::str_size(text);
|
||||||
|
// self.transform.width = self.transform.width.max(w);
|
||||||
|
// self.transform.height = self.transform.height.max(h);
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn draw_rect(&mut self, width: usize, height: usize, color: u32) {
|
||||||
|
self.render_stack
|
||||||
|
.push(RenderMethod::Rectangle(width, height, color));
|
||||||
|
self.transform.width = self.transform.width.max(width);
|
||||||
|
self.transform.height = self.transform.height.max(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
for m in &self.render_stack {
|
||||||
|
match m {
|
||||||
|
&RenderMethod::Rectangle(width, height, color) => {
|
||||||
|
for y in 0..height {
|
||||||
|
for x in 0..width {
|
||||||
|
self.buffer[y * self.parent_height + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.render_stack.clear();
|
||||||
|
self.transform.width = 0;
|
||||||
|
self.transform.height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_size(&self) -> (usize, usize) {
|
||||||
|
(self.transform.width, self.transform.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_parent_size(&self) -> (usize, usize) {
|
||||||
|
(self.parent_width, self.parent_height)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_buffer(&self) -> Vec<u32> {
|
pub fn get_buffer(&self) -> Vec<u32> {
|
||||||
self.buffer.clone()
|
self.buffer.clone()
|
||||||
}
|
}
|
||||||
|
|||||||
+119
@@ -0,0 +1,119 @@
|
|||||||
|
use crate::component;
|
||||||
|
|
||||||
|
pub struct RawTransform {
|
||||||
|
pub x: usize,
|
||||||
|
pub y: usize,
|
||||||
|
pub width: usize,
|
||||||
|
pub height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Position {
|
||||||
|
Const(usize),
|
||||||
|
Center,
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Dimension {
|
||||||
|
Auto,
|
||||||
|
Const(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
component!(Transform {
|
||||||
|
pub x: Position,
|
||||||
|
pub y: Position,
|
||||||
|
pub mx: i32,
|
||||||
|
pub my: i32,
|
||||||
|
pub width: Dimension,
|
||||||
|
pub height: Dimension,
|
||||||
|
});
|
||||||
|
|
||||||
|
impl Transform {
|
||||||
|
pub fn new() -> Transform {
|
||||||
|
Transform {
|
||||||
|
x: Position::Const(0),
|
||||||
|
y: Position::Const(0),
|
||||||
|
mx: 0,
|
||||||
|
my: 0,
|
||||||
|
width: Dimension::Auto,
|
||||||
|
height: Dimension::Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn center() -> Transform {
|
||||||
|
Transform {
|
||||||
|
x: Position::Center,
|
||||||
|
y: Position::Center,
|
||||||
|
mx: 0,
|
||||||
|
my: 0,
|
||||||
|
width: Dimension::Auto,
|
||||||
|
height: Dimension::Auto,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bottom(mut self) -> Self {
|
||||||
|
self.y = Position::End;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn margin(mut self, x: i32, y: i32) -> Self {
|
||||||
|
self.mx = x;
|
||||||
|
self.my = y;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dimensions(mut self, width: usize, height: usize) -> Self {
|
||||||
|
self.width = Dimension::Const(width);
|
||||||
|
self.height = Dimension::Const(height);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_dimensions(&self, raw: &mut RawTransform) {
|
||||||
|
self.width.use_dimension(&mut raw.width);
|
||||||
|
self.height.use_dimension(&mut raw.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn use_position(&self, parent_width: usize, parent_height: usize, raw: &mut RawTransform) {
|
||||||
|
self.x
|
||||||
|
.use_position(raw.width, parent_width, self.mx, &mut raw.x);
|
||||||
|
self.y
|
||||||
|
.use_position(raw.height, parent_height, self.my, &mut raw.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RawTransform {
|
||||||
|
pub fn new() -> RawTransform {
|
||||||
|
RawTransform {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dimension {
|
||||||
|
pub fn use_dimension(&self, r: &mut usize) {
|
||||||
|
match self {
|
||||||
|
Self::Auto => {}
|
||||||
|
Self::Const(n) => *r = *n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Position {
|
||||||
|
pub fn use_position(&self, size: usize, parent: usize, m: i32, r: &mut usize) {
|
||||||
|
match self {
|
||||||
|
Self::Center => *r = (parent - size) / 2,
|
||||||
|
Self::Const(n) => *r = *n,
|
||||||
|
Self::End => *r = parent - size,
|
||||||
|
}
|
||||||
|
|
||||||
|
if m > 0 {
|
||||||
|
*r += m as usize;
|
||||||
|
} else {
|
||||||
|
*r -= -m as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+53
-2
@@ -1,5 +1,56 @@
|
|||||||
|
use std::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::render::RenderScope;
|
use crate::render::RenderScope;
|
||||||
|
|
||||||
pub trait Element {
|
pub type BoxedElement = Box<dyn Element + Send + Sync>;
|
||||||
fn render(&mut self, scope: &mut RenderScope);
|
pub type BoxedComponent = Box<dyn Component + Send + Sync>;
|
||||||
|
|
||||||
|
pub trait Element: Send + Sync {
|
||||||
|
#[allow(unused)]
|
||||||
|
fn render(&mut self, scope: &mut RenderScope) {}
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Component: Send + Sync {
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Widget(
|
||||||
|
pub Mutex<BoxedElement>,
|
||||||
|
Mutex<HashMap<TypeId, BoxedComponent>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl Widget {
|
||||||
|
pub fn new(e: Box<dyn Element>) -> Self {
|
||||||
|
Self(Mutex::new(e), Mutex::new(HashMap::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
|
||||||
|
self.1
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.entry(c.type_id())
|
||||||
|
.or_insert_with(|| Box::new(c));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_component<C: Component + 'static>(self: &Arc<Self>, c: C) -> &Arc<Self> {
|
||||||
|
self.1.lock().unwrap().insert(c.type_id(), Box::new(c));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<C: Component + 'static + Clone>(&self) -> Option<C> {
|
||||||
|
self.1
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&TypeId::of::<C>())
|
||||||
|
.and_then(|c| c.as_any().downcast_ref::<C>())
|
||||||
|
.map(|c| c.clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user