use std::sync::Arc; use app::App; use arboard::Clipboard; use cosmic_text::Family; use render::Renderer; use ui::prelude::*; use winit::{event::WindowEvent, event_loop::ActiveEventLoop, window::Window}; use crate::testing::input::Input; use len_fns::*; mod app; mod input; mod render; pub fn main() { App::run(); } pub struct Client { renderer: Renderer, input: Input, ui: Ui, info: WidgetId, focus: Option>, clipboard: Clipboard, } #[derive(Eq, PartialEq, Hash, Clone)] struct Submit; impl DefaultEvent for Submit { type Data = (); } impl Client { pub fn new(window: Arc) -> Self { let renderer = Renderer::new(window); let mut ui = Ui::new(); let rrect = rect(Color::WHITE).radius(20); let pad_test = ( rrect.color(Color::BLUE), ( rrect .color(Color::RED) .sized((100, 100)) .center() .width(rest(2)), ( rrect.color(Color::ORANGE), rrect.color(Color::LIME).pad(10.0), ) .span(Dir::RIGHT) .width(rest(2)), rrect.color(Color::YELLOW), ) .span(Dir::RIGHT) .pad(10) .width(rest(3)), ) .span(Dir::RIGHT) .add_static(&mut ui); let span_test = ( rrect.color(Color::GREEN).width(100), rrect.color(Color::ORANGE), rrect.color(Color::CYAN), rrect.color(Color::BLUE).width(rel(0.5)), rrect.color(Color::MAGENTA).width(100), rrect.color(Color::RED).width(100), ) .span(Dir::LEFT) .add_static(&mut ui); let span_add = Span::empty(Dir::RIGHT).add_static(&mut ui); let add_button = rect(Color::LIME) .radius(30) .on(CursorSense::click(), move |ctx: &mut Client, _| { let child = ctx .ui .add(image(include_bytes!("assets/sungals.png")).center()) .any(); ctx.ui[span_add].children.push(child); }) .sized((150, 150)) .align(Align::BotRight); let del_button = rect(Color::RED) .radius(30) .on(CursorSense::click(), move |ctx: &mut Client, _| { ctx.ui[span_add].children.pop(); }) .sized((150, 150)) .align(Align::BotLeft); let span_add_test = (span_add, add_button, del_button) .stack() .add_static(&mut ui); let main = pad_test.pad(10).add_static(&mut ui); let btext = |content| text(content).size(30); let text_test = ( btext("this is a").align(Align::Left), btext("teeeeeeeest").align(Align::Right), btext("okkk\nokkkkkk!").align(Align::Left), btext("hmm"), btext("a"), ( btext("'").family(Family::Monospace).align(Align::Top), btext("'").family(Family::Monospace), btext(":gamer mode").family(Family::Monospace), rect(Color::CYAN).sized((10, 10)).center(), rect(Color::RED).sized((100, 100)).center(), rect(Color::PURPLE).sized((50, 50)).align(Align::Top), ) .span(Dir::RIGHT) .center(), text("pretty cool right?").size(50), ) .span(Dir::DOWN) .add_static(&mut ui); let texts = Span::empty(Dir::DOWN).spacing(10).add_static(&mut ui); let msg_area = (Rect::new(Color::SKY), texts.scroll().masked()).stack(); let add_text = text("add") .editable() .text_align(Align::Left) .size(30) .id_on(CursorSense::click(), |id, client: &mut Client, ctx| { client.ui.text(id).select(ctx.cursor, ctx.size); client.focus = Some(id.clone()); }) .id_on(Submit, move |id, client: &mut Client, _| { let content = client.ui.text(id).take(); let text = text(content) .editable() .size(30) .text_align(Align::Left) .wrap(true) .id_on(CursorSense::click(), |id, client: &mut Client, ctx| { client.ui.text(id).select(ctx.cursor, ctx.size); client.focus = Some(id.clone()); }); let msg_box = (rect(Color::WHITE.darker(0.5)), text) .stack() .size(StackSize::Child(1)) .add(&mut client.ui); client.ui[texts].children.push(msg_box.any()); }) .add(&mut ui); let text_edit_scroll = ( msg_area, ( Rect::new(Color::WHITE.darker(0.9)), ( add_text.clone().width(rest(1)), Rect::new(Color::GREEN) .on(CursorSense::click(), move |client: &mut Client, _| { client.run_event(&add_text, Submit, ()); }) .sized((40, 40)), ) .span(Dir::RIGHT) .pad(10), ) .stack() .size(StackSize::Child(1)) .offset_layer(1) .align(Align::Bot), ) .span(Dir::DOWN) .add_static(&mut ui); let switch_button = |color, to, label| { let rect = rect(color) .id_on(CursorSense::click(), move |id, ui: &mut Ui, _| { ui[main].inner.set_static(to); ui[id].color = color.darker(0.3); }) .edit_on( CursorSense::HoverStart | CursorSense::unclick(), move |r, _| { r.color = color.brighter(0.2); }, ) .edit_on(CursorSense::HoverEnd, move |r, _| { r.color = color; }); (rect, text(label).size(30)).stack() }; let tabs = ( switch_button(Color::RED, pad_test.any(), "pad"), switch_button(Color::GREEN, span_test.any(), "span"), switch_button(Color::BLUE, span_add_test.any(), "image span"), switch_button(Color::MAGENTA, text_test.any(), "text layout"), switch_button( Color::YELLOW.mul_rgb(0.5), text_edit_scroll.any(), "text edit scroll", ), ) .span(Dir::RIGHT); let info = text("").add(&mut ui); let info_sect = info.clone().pad(10).align(Align::Right); ((tabs.height(40), main).span(Dir::DOWN), info_sect) .stack() .set_root(&mut ui); Self { renderer, input: Input::default(), ui, info, focus: None, clipboard: Clipboard::new().unwrap(), } } pub fn event(&mut self, event: WindowEvent, event_loop: &ActiveEventLoop) { let input_changed = self.input.event(&event); let cursor_state = self.cursor_state().clone(); if let Some(focus) = &self.focus && cursor_state.buttons.left.is_start() { self.ui.text(focus).deselect(); self.focus = None; } if input_changed { let window_size = self.window_size(); self.run_sensors(&cursor_state, window_size); self.ui.run_sensors(&cursor_state, window_size); } match event { WindowEvent::CloseRequested => event_loop.exit(), WindowEvent::RedrawRequested => { self.ui.update(); self.renderer.update(&mut self.ui); self.renderer.draw() } WindowEvent::Resized(size) => { self.ui.resize((size.width, size.height)); self.renderer.resize(&size) } WindowEvent::KeyboardInput { event, .. } => { if let Some(sel) = &self.focus && event.state.is_pressed() { let mut text = self.ui.text(sel); match text.apply_event(&event, &self.input.modifiers) { TextInputResult::Unfocus => { self.focus = None; } TextInputResult::Submit => { self.run_event(&sel.clone(), Submit, ()); } TextInputResult::Paste => { if let Ok(t) = self.clipboard.get_text() { text.insert(&t); } } TextInputResult::Unused | TextInputResult::Used => (), } } } _ => (), } let new = format!( "widgets: {}\nactive:{}\nviews: {}", self.ui.num_widgets(), self.ui.active_widgets(), self.renderer.ui.view_count() ); if new != *self.ui[&self.info].content { *self.ui[&self.info].content = new; } if self.ui.needs_redraw() { self.renderer.window().request_redraw(); } self.input.end_frame(); } } impl UiCtx for Client { fn ui(&mut self) -> &mut Ui { &mut self.ui } }