From 4aa7219d4955418fc021a1fad9e4a493f36bd3ea Mon Sep 17 00:00:00 2001 From: shadow cat Date: Mon, 8 Dec 2025 00:12:30 -0500 Subject: [PATCH] finally usable state stuff ig --- iris | 2 +- src/bin/client/main.rs | 11 +- src/bin/client/ui/color.rs | 4 + src/bin/client/ui/login.rs | 225 +++++++++++++++++++------------------ src/bin/client/ui/main.rs | 18 +-- src/bin/client/ui/misc.rs | 93 ++++++++++----- src/bin/client/ui/mod.rs | 8 +- 7 files changed, 205 insertions(+), 156 deletions(-) create mode 100644 src/bin/client/ui/color.rs diff --git a/iris b/iris index b66d4da..434e3c3 160000 --- a/iris +++ b/iris @@ -1 +1 @@ -Subproject commit b66d4da5d7dfc7ac3ca8e0cd0fc4e1a5b0322f04 +Subproject commit 434e3c3af7c726ec869ce9ed4a1fcd7a4adc2afc diff --git a/src/bin/client/main.rs b/src/bin/client/main.rs index 44b230f..2b0a165 100644 --- a/src/bin/client/main.rs +++ b/src/bin/client/main.rs @@ -54,9 +54,16 @@ impl DefaultAppState for Client { let dir = DataDir::default(); let notif = WidgetPtr::default().add(ui); let main_ui = WidgetPtr::default().add(ui); + let bg = ( + image(include_bytes!("./assets/fuit.jpg")), + rect(Color::BLACK.alpha((0.8 * 255.0) as u8)), + ) + .stack(); + ( - notif.clone().pad(Padding::top(10)).align(Align::TOP_CENTER), + bg, main_ui.clone(), + notif.clone().pad(Padding::top(10)).align(Align::TOP_CENTER), ) .stack() .set_root(ui); @@ -86,7 +93,7 @@ impl DefaultAppState for Client { thread: th, }, }); - login_screen(self, ui).set_ptr(&self.main_ui, ui); + // login_screen(self, ui).set_ptr(&self.main_ui, ui); } ClientEvent::ServerMsg(msg) => match msg { ServerMsg::SendMsg(msg) => { diff --git a/src/bin/client/ui/color.rs b/src/bin/client/ui/color.rs new file mode 100644 index 0000000..2176e51 --- /dev/null +++ b/src/bin/client/ui/color.rs @@ -0,0 +1,4 @@ +use super::*; + +pub const MODAL_BG: UiColor = UiColor::BLACK.brighter(0.05); +pub const GREEN: UiColor = UiColor::rgb(0, 150, 0); diff --git a/src/bin/client/ui/login.rs b/src/bin/client/ui/login.rs index 168e4c4..39fb2bb 100644 --- a/src/bin/client/ui/login.rs +++ b/src/bin/client/ui/login.rs @@ -1,8 +1,3 @@ -use iris::winit::{UiState, event::Edited}; -use openworm::net::ClientMsg; - -use crate::{net::AppHandle, state::ClientState}; - use super::*; pub fn start_screen(client: &mut Client, ui: &mut Ui) -> WidgetRef { @@ -18,118 +13,134 @@ pub fn start_screen(client: &mut Client, ui: &mut Ui) -> WidgetRef { .any(), ); + let connect = Button::submit("connect", ui); + let create = Button::submit("create", ui); + let connect_ = connect.clone(); + let create_ = create.clone(); + ui.on(connect.view(), Submit, move |_| { + connect_.disable(); + create_.disable(); + }); + ( wtext("Select Account").text_align(Align::CENTER).size(30), accounts, - ( - submit_button("connect", |_, _| {}), - submit_button("create", |_, _| {}), - ) - .span(Dir::RIGHT) - .gap(10), + (connect, create).span(Dir::RIGHT).gap(10), ) .span(Dir::DOWN) - .gap(10) + .gap(30) .pad(15) - .background(rect(Color::BLACK.brighter(0.2)).radius(15)) + .background(rect(color::MODAL_BG).radius(15)) .width(400) .align(Align::CENTER) .add(ui) .any() } -pub fn connect_screen(client: &mut Client, ui: &mut Ui, state: &UiState) -> WidgetRef { - let Client { data, proxy, .. } = client; - let ip = field_widget(&data.ip, "ip", ui); - let ip_ = ip.clone(); - let handle = AppHandle { - proxy: proxy.clone(), - window: state.window.clone(), - }; - let submit = submit_button("connect", move |client, _ui| { - let ClientState::Connect(state) = &mut client.state else { - return; - }; - let ip = ip_.get().content(); - state.handle = Some(connect(handle.clone(), ConnectInfo { ip })); - }); - ( - wtext("connect to a server") - .text_align(Align::CENTER) - .size(30), - field_box( - // NOTE: should probably do this on submit - ip.on(Edited, |ctx| { - ctx.state.data.ip = ctx.widget.get().content(); - }) - .add(ui), - ui, - ), - submit, - ) - .span(Dir::DOWN) - .gap(10) - .pad(15) - .background(rect(Color::BLACK.brighter(0.2)).radius(15)) - .width(400) - .align(Align::CENTER) - .add(ui) - .any() -} +// pub fn connect_screen(client: &mut Client, ui: &mut Ui, state: &UiState) -> WidgetRef { +// let Client { data, proxy, .. } = client; +// let ip = field_widget(&data.ip, "ip", ui); +// let ip_ = ip.clone(); +// let handle = AppHandle { +// proxy: proxy.clone(), +// window: state.window.clone(), +// }; +// +// let submit = Button::submit("connect", ui); +// +// submit.on(Submit, move |ctx| { +// let ClientState::Connect(state) = &mut ctx.state.state else { +// return; +// }; +// let ip = ip_.get().content(); +// state.handle = Some(connect(handle.clone(), ConnectInfo { ip })); +// }); +// +// ( +// wtext("connect to a server") +// .text_align(Align::CENTER) +// .size(30), +// field_box( +// // NOTE: should probably do this on submit +// ip.on(Edited, |ctx| { +// ctx.state.data.ip = ctx.widget.get().content(); +// }) +// .add(ui), +// ui, +// ), +// submit, +// ) +// .span(Dir::DOWN) +// .gap(10) +// .pad(15) +// .background(rect(Color::BLACK.brighter(0.2)).radius(15)) +// .width(400) +// .align(Align::CENTER) +// .add(ui) +// .any() +// } -pub fn login_screen(client: &mut Client, ui: &mut Ui) -> WidgetRef { - let Client { data, .. } = client; - let username = field_widget(&data.username, "username", ui); - let password = field_widget(&data.password, "password", ui); - let username_ = username.clone(); - let password_ = password.clone(); - let submit = submit_button("login", move |client, _ui| { - let ClientState::Login(state) = &mut client.state else { - return; - }; - let username = username_.get().content(); - let password = password_.get().content(); - state.handle.send(ClientMsg::Login { username, password }); - }); - let username_ = username.clone(); - let password_ = password.clone(); - let create_button = submit_button("create account", move |client, _ui| { - let ClientState::Login(state) = &mut client.state else { - return; - }; - let username = username_.get().content(); - let password = password_.get().content(); - state - .handle - .send(ClientMsg::CreateAccount { username, password }); - }); - ( - wtext("login to server").text_align(Align::CENTER).size(30), - field_box( - username - .on(Edited, |ctx| { - ctx.state.data.username = ctx.widget.get().content(); - }) - .add(ui), - ui, - ), - field_box( - password - .on(Edited, |ctx| { - ctx.state.data.password = ctx.widget.get().content(); - }) - .add(ui), - ui, - ), - submit, - create_button, - ) - .span(Dir::DOWN) - .gap(10) - .pad(15) - .background(rect(Color::BLACK.brighter(0.2)).radius(15)) - .width(400) - .align(Align::CENTER) - .add(ui) - .any() -} +// pub fn login_screen(client: &mut Client, ui: &mut Ui) -> WidgetRef { +// let Client { data, .. } = client; +// let username = field_widget(&data.username, "username", ui); +// let password = field_widget(&data.password, "password", ui); +// let username_ = username.clone(); +// let password_ = password.clone(); +// let submit = Button::submit("login", ui); +// submit +// .on(move |client, _ui| { +// let ClientState::Login(state) = &mut client.state else { +// return; +// }; +// let username = username_.get().content(); +// let password = password_.get().content(); +// state.handle.send(ClientMsg::Login { username, password }); +// }) +// .add(ui); +// let username_ = username.clone(); +// let password_ = password.clone(); +// let create_button = Button::submit( +// "create account", +// move |client, _ui| { +// let ClientState::Login(state) = &mut client.state else { +// return; +// }; +// let username = username_.get().content(); +// let password = password_.get().content(); +// state +// .handle +// .send(ClientMsg::CreateAccount { username, password }); +// }, +// ui, +// ); +// create_button.on() +// ( +// wtext("login to server").text_align(Align::CENTER).size(30), +// field_box( +// username +// .on(Edited, |ctx| { +// ctx.state.data.username = ctx.widget.get().content(); +// }) +// .add(ui), +// ui, +// ), +// field_box( +// password +// .on(Edited, |ctx| { +// ctx.state.data.password = ctx.widget.get().content(); +// }) +// .add(ui), +// ui, +// ), +// submit, +// create_button, +// ) +// .span(Dir::DOWN) +// .gap(10) +// .pad(15) +// .background(rect(Color::BLACK.brighter(0.2)).radius(15)) +// .width(400) +// .align(Align::CENTER) +// .add(ui) +// .any() +// } diff --git a/src/bin/client/ui/main.rs b/src/bin/client/ui/main.rs index c8505a2..f82d7a1 100644 --- a/src/bin/client/ui/main.rs +++ b/src/bin/client/ui/main.rs @@ -1,12 +1,5 @@ use super::*; use crate::state::{ClientState, LoggedIn}; -use iris::{ - layout::len_fns::*, - winit::{ - attr::{Selectable, Selector}, - event::Submit, - }, -}; use openworm::net::{ClientMsg, NetClientMsg}; pub const SIZE: u32 = 20; @@ -18,16 +11,7 @@ pub fn main_view(client: &mut Client, ui: &mut Ui) -> WidgetRef { let msg_panel = msg_panel(ui, state); let side_bar = rect(Color::BLACK.brighter(0.05)).width(80); - let bg = ( - image(include_bytes!("../assets/fuit.jpg")), - rect(Color::BLACK.alpha((0.8 * 255.0) as u8)), - ) - .stack(); - (side_bar, msg_panel) - .span(Dir::RIGHT) - .background(bg) - .add(ui) - .any() + (side_bar, msg_panel).span(Dir::RIGHT).add(ui).any() } pub fn msg_widget(username: &str, content: &str) -> impl WidgetRet { diff --git a/src/bin/client/ui/misc.rs b/src/bin/client/ui/misc.rs index ecd89a2..afc175a 100644 --- a/src/bin/client/ui/misc.rs +++ b/src/bin/client/ui/misc.rs @@ -1,5 +1,3 @@ -use iris::winit::attr::Selector; - use super::*; pub fn werror(ui: &mut Ui, msg: &str) -> WidgetRef { @@ -33,27 +31,72 @@ pub fn field_box(field: WidgetRef, ui: &mut Ui) -> WidgetRef { .any() } -pub fn submit_button( - text: &str, - on_submit: impl Fn(&mut Client, &mut Ui) + 'static, -) -> impl WidgetRet { - let color = Color::rgb(0, 200, 0); - rect(color) - .radius(15) - .on(CursorSense::click(), move |ctx| { - ctx.widget.get_mut().color = color.darker(0.2); - on_submit(ctx.state, ctx.ui); - }) - .on( - CursorSense::HoverStart | CursorSense::unclick(), - move |ctx| { - ctx.widget.get_mut().color = color.brighter(0.1); - }, - ) - .on(CursorSense::HoverEnd, move |ctx| { - ctx.widget.get_mut().color = color; - }) - .height(60) - .foreground(wtext(text).size(25).text_align(Align::CENTER)) - .to_any() +#[derive(Clone)] +pub struct Button { + color: UiColor, + root: WidgetRef, + rect: WidgetRef, + enabled: Handle, +} + +impl WidgetView for Button { + fn view(&self) -> &WidgetRef { + &self.root + } +} + +impl Button { + pub fn new(text: &str, color: UiColor, ui: &mut Ui) -> Self { + let rect = rect(color).radius(15).add(ui); + let enabled = Handle::from(true); + let enabled_ = enabled.clone(); + let enabled__ = enabled.clone(); + let root = rect + .clone() + .on( + CursorSense::HoverStart | CursorSense::unclick(), + move |ctx| { + if !*enabled_.get() { + return; + } + ctx.widget.get_mut().color = color.brighter(0.1); + }, + ) + .on(CursorSense::HoverEnd, move |ctx| { + if !*enabled__.get() { + return; + } + ctx.widget.get_mut().color = color; + }) + .height(60) + .foreground(wtext(text).size(25).text_align(Align::CENTER)) + .add(ui) + .any(); + let root_ = root.clone(); + let enabled_ = enabled.clone(); + rect.clone() + .on(CursorSense::click(), move |ctx| { + if !*enabled_.get() { + return; + } + ctx.widget.get_mut().color = color.darker(0.2); + ctx.ui.run_event(ctx.state, &root_, Submit, ()); + }) + .add(ui); + Self { + root, + rect, + color, + enabled, + } + } + + pub fn submit(text: &str, ui: &mut Ui) -> Self { + Self::new(text, color::GREEN, ui) + } + + pub fn disable(&self) { + *self.enabled.get_mut() = false; + self.rect.get_mut().color = self.color.darker(0.8); + } } diff --git a/src/bin/client/ui/mod.rs b/src/bin/client/ui/mod.rs index 6188c36..bfaf085 100644 --- a/src/bin/client/ui/mod.rs +++ b/src/bin/client/ui/mod.rs @@ -1,12 +1,12 @@ -use crate::{ - Client, - net::{ConnectInfo, connect}, -}; +use crate::Client; use iris::prelude::*; +use len_fns::*; mod login; mod main; mod misc; +pub mod color; + pub use login::*; pub use main::*; pub use misc::*;