update iris & get button working again

This commit is contained in:
2026-01-19 21:26:59 -05:00
parent 040b70e1c5
commit e67c55d67d
8 changed files with 213 additions and 70 deletions

2
iris

Submodule iris updated: a9c76e4326...7bafb04a34

View File

@@ -1,9 +1,10 @@
use crate::{Client, Rsc}; use crate::{Client, Rsc};
use iris::core::UiRenderState;
use openworm::net::NetServerMsg; use openworm::net::NetServerMsg;
impl Client { impl Client {
pub fn debug(&mut self, rsc: &mut Rsc) { pub fn debug(&mut self, _rsc: &mut Rsc, render: &mut UiRenderState) {
rsc.ui.debug_layers(); render.debug_layers();
// let mut file = std::fs::OpenOptions::new() // let mut file = std::fs::OpenOptions::new()
// .write(true) // .write(true)
// .create(true) // .create(true)

View File

@@ -11,7 +11,10 @@ use openworm::{
net::{ClientMsg, ServerMsg, install_crypto_provider}, net::{ClientMsg, ServerMsg, install_crypto_provider},
rsc::DataDir, rsc::DataDir,
}; };
use winit::event::{ElementState, MouseButton, WindowEvent}; use winit::{
event::{ElementState, MouseButton, WindowEvent},
window::WindowAttributes,
};
mod account; mod account;
mod debug; mod debug;
@@ -31,8 +34,8 @@ pub struct Client {
dir: DataDir, dir: DataDir,
data: ClientData, data: ClientData,
state: ClientState, state: ClientState,
main_ui: WidgetRef<WidgetPtr>, main_ui: WeakWidget<WidgetPtr>,
notif: WidgetRef<WidgetPtr>, notif: WeakWidget<WidgetPtr>,
proxy: Proxy<ClientEvent>, proxy: Proxy<ClientEvent>,
} }
@@ -48,7 +51,7 @@ impl DefaultAppState for Client {
type Event = ClientEvent; type Event = ClientEvent;
fn new( fn new(
ui_state: DefaultUiState, mut ui_state: DefaultUiState,
rsc: &mut DefaultRsc<Self>, rsc: &mut DefaultRsc<Self>,
proxy: Proxy<Self::Event>, proxy: Proxy<Self::Event>,
) -> Self { ) -> Self {
@@ -67,9 +70,9 @@ impl DefaultAppState for Client {
notif.pad(Padding::top(10)).align(Align::TOP_CENTER), notif.pad(Padding::top(10)).align(Align::TOP_CENTER),
) )
.stack() .stack()
.set_root(rsc); .set_root(rsc, &mut ui_state);
main_view(rsc).set_ptr(main_ui, rsc); start_ui(rsc).set_ptr(main_ui, rsc);
Self { Self {
ui_state, ui_state,
@@ -82,7 +85,12 @@ impl DefaultAppState for Client {
} }
} }
fn event(&mut self, event: Self::Event, rsc: &mut DefaultRsc<Self>) { fn event(
&mut self,
event: Self::Event,
rsc: &mut DefaultRsc<Self>,
_render: &mut UiRenderState,
) {
match event { match event {
ClientEvent::Connect { send } => { ClientEvent::Connect { send } => {
let ClientState::Connect(connect) = self.state.take() else { let ClientState::Connect(connect) = self.state.take() else {
@@ -103,7 +111,7 @@ impl DefaultAppState for Client {
&& let Some(msg_area) = state.channel && let Some(msg_area) = state.channel
{ {
let msg = msg_widget(&msg.user, &msg.content).add_strong(rsc); let msg = msg_widget(&msg.user, &msg.content).add_strong(rsc);
rsc.ui[msg_area].children.push(msg); rsc[msg_area].children.push(msg);
} }
} }
ServerMsg::LoadMsgs(msgs) => { ServerMsg::LoadMsgs(msgs) => {
@@ -113,7 +121,7 @@ impl DefaultAppState for Client {
for msg in msgs { for msg in msgs {
state.msgs.push(msg.clone()); state.msgs.push(msg.clone());
let msg = msg_widget(&msg.user, &msg.content).add_strong(rsc); let msg = msg_widget(&msg.user, &msg.content).add_strong(rsc);
rsc.ui[msg_area].children.push(msg); rsc[msg_area].children.push(msg);
} }
} }
} }
@@ -132,28 +140,37 @@ impl DefaultAppState for Client {
} }
ServerMsg::Error(error) => { ServerMsg::Error(error) => {
let msg = format!("{error:?}"); let msg = format!("{error:?}");
rsc.ui[self.notif].inner = Some(werror(&msg, rsc)); rsc[self.notif].inner = Some(werror(&msg, rsc));
} }
}, },
ClientEvent::Err(msg) => { ClientEvent::Err(msg) => {
rsc.ui[self.notif].inner = Some(werror(&msg, rsc)); rsc[self.notif].inner = Some(werror(&msg, rsc));
} }
} }
} }
fn exit(&mut self, _: &mut DefaultRsc<Self>) { fn exit(&mut self, _rsc: &mut DefaultRsc<Self>, _render: &mut UiRenderState) {
self.state.exit(); self.state.exit();
self.dir.save(CLIENT_DATA, &self.data); self.dir.save(CLIENT_DATA, &self.data);
} }
fn window_event(&mut self, event: WindowEvent, rsc: &mut DefaultRsc<Self>) { fn window_event(
&mut self,
event: WindowEvent,
rsc: &mut DefaultRsc<Self>,
render: &mut UiRenderState,
) {
if let WindowEvent::MouseInput { if let WindowEvent::MouseInput {
state: ElementState::Pressed, state: ElementState::Pressed,
button: MouseButton::Middle, button: MouseButton::Middle,
.. ..
} = event } = event
{ {
self.debug(rsc); self.debug(rsc, render);
} }
} }
fn window_attributes() -> WindowAttributes {
WindowAttributes::default().with_title("OPENWORM")
}
} }

View File

@@ -15,7 +15,7 @@ pub struct Login {
pub struct LoggedIn { pub struct LoggedIn {
pub network: NetHandle, pub network: NetHandle,
pub msgs: Vec<NetServerMsg>, pub msgs: Vec<NetServerMsg>,
pub channel: Option<WidgetRef<Span>>, pub channel: Option<WeakWidget<Span>>,
pub username: String, pub username: String,
} }

View File

@@ -1,6 +1,6 @@
use super::*; use super::*;
pub fn start_ui(rsc: &mut Rsc) -> WidgetRef { pub fn start_ui(rsc: &mut Rsc) -> WeakWidget {
let mut accounts = Span::empty(Dir::DOWN); let mut accounts = Span::empty(Dir::DOWN);
accounts.push( accounts.push(
@@ -14,17 +14,15 @@ pub fn start_ui(rsc: &mut Rsc) -> WidgetRef {
let connect = Button::submit("connect", rsc); let connect = Button::submit("connect", rsc);
let create = Button::submit("create", rsc); let create = Button::submit("create", rsc);
connect.on(Submit, move |_, rsc| { rsc.events.register(connect.root(), Submit, move |_, rsc| {
connect.disable(); connect.disable(rsc);
create.disable(); create.disable(rsc);
}); });
let connect_ = connect.clone(); rsc.events.register(create.root(), Submit, move |ctx, rsc| {
let create_ = create.clone(); connect.disable(rsc);
ui.on(create.view(), Submit, move |ctx| { create.disable(rsc);
connect_.disable(); create_ui(rsc).set_ptr(ctx.state.main_ui, rsc);
create_.disable();
create_ui(ctx.ui).set_ptr(&ctx.state.main_ui, ctx.ui);
}); });
( (
@@ -35,14 +33,14 @@ pub fn start_ui(rsc: &mut Rsc) -> WidgetRef {
.span(Dir::DOWN) .span(Dir::DOWN)
.gap(30) .gap(30)
.modal(400) .modal(400)
.add(ui) .add(rsc)
} }
pub fn create_ui(ui: &mut Ui) -> WidgetRef { pub fn create_ui(rsc: &mut Rsc) -> WeakWidget {
wtext("hi").add(ui) wtext("hi").add(rsc)
} }
// pub fn connect_screen(client: &mut Client, ui: &mut Ui, state: &UiState) -> WidgetRef { // pub fn connect_screen(client: &mut Client, ui: &mut Ui, state: &UiState) -> WeakWidget {
// let Client { data, proxy, .. } = client; // let Client { data, proxy, .. } = client;
// let ip = field_widget(&data.ip, "ip", ui); // let ip = field_widget(&data.ip, "ip", ui);
// let ip_ = ip.clone(); // let ip_ = ip.clone();
@@ -84,7 +82,7 @@ pub fn create_ui(ui: &mut Ui) -> WidgetRef {
// .add(ui) // .add(ui)
// } // }
// pub fn login_screen(client: &mut Client, ui: &mut Ui) -> WidgetRef { // pub fn login_screen(client: &mut Client, ui: &mut Ui) -> WeakWidget {
// let Client { data, .. } = client; // let Client { data, .. } = client;
// let username = field_widget(&data.username, "username", ui); // let username = field_widget(&data.username, "username", ui);
// let password = field_widget(&data.password, "password", ui); // let password = field_widget(&data.password, "password", ui);

134
src/bin/client/ui/login.rs Normal file
View File

@@ -0,0 +1,134 @@
use iris::prelude::*;
use openworm::net::ClientMsg;
use crate::{net::AppHandle, state::ClientState};
use super::*;
pub fn start_screen(client: &mut Client, ui: &mut Ui) -> WidgetHandle {
let mut accounts = Span::empty(Dir::DOWN);
accounts.push(
wtext("no accounts")
.size(20)
.center_text()
.color(Color::GRAY)
.height(60)
.add(ui)
.any(),
);
(
wtext("Select Account").text_align(Align::CENTER).size(30),
accounts,
(
submit_button("connect", |_, _| {}),
submit_button("create", |_, _| {}),
)
.span(Dir::RIGHT)
.gap(10),
)
.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) -> WidgetHandle {
let Client { data, proxy, .. } = client;
let ip = field_widget(&data.ip, "ip", ui);
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 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()
}

View File

@@ -4,7 +4,7 @@ use super::*;
pub const SIZE: u32 = 20; pub const SIZE: u32 = 20;
pub fn main_view(rsc: &mut Rsc) -> WidgetRef { pub fn main_view(rsc: &mut Rsc) -> WeakWidget {
let msg_panel = msg_panel(rsc); let msg_panel = msg_panel(rsc);
let side_bar = rect(Color::BLACK.brighter(0.05)).width(80); let side_bar = rect(Color::BLACK.brighter(0.05)).width(80);
@@ -33,7 +33,7 @@ pub fn msg_widget(username: &str, content: &str) -> impl WidgetIdFn<Rsc> {
.to_any() .to_any()
} }
pub fn msg_panel(rsc: &mut Rsc) -> WidgetRef { pub fn msg_panel(rsc: &mut Rsc) -> WeakWidget {
let msg_area = Span::empty(Dir::DOWN).gap(15); let msg_area = Span::empty(Dir::DOWN).gap(15);
let send_text = wtext("") let send_text = wtext("")
@@ -54,7 +54,7 @@ pub fn msg_panel(rsc: &mut Rsc) -> WidgetRef {
.on(Submit, move |ctx, rsc| { .on(Submit, move |ctx, rsc| {
let content = ctx.widget.edit(rsc).take(); let content = ctx.widget.edit(rsc).take();
let msg = msg_widget("ur mothe:", &content).add_strong(rsc); let msg = msg_widget("ur mothe:", &content).add_strong(rsc);
rsc.ui[msg_area].children.push(msg); rsc[msg_area].children.push(msg);
}) })
.pad(15) .pad(15)
.attr::<Selector>(send_text) .attr::<Selector>(send_text)

View File

@@ -1,6 +1,6 @@
use super::*; use super::*;
pub fn werror(msg: &str, rsc: &mut Rsc) -> WidgetHandle { pub fn werror(msg: &str, rsc: &mut Rsc) -> StrongWidget {
wtext(msg) wtext(msg)
.size(20) .size(20)
.pad(10) .pad(10)
@@ -12,7 +12,7 @@ pub fn hint(msg: impl Into<String>) -> TextBuilder<Rsc> {
wtext(msg).size(20).color(Color::GRAY) wtext(msg).size(20).color(Color::GRAY)
} }
pub fn field_widget(name: &str, hint_text: &str, rsc: &mut Rsc) -> WidgetRef<TextEdit> { pub fn field_widget(name: &str, hint_text: &str, rsc: &mut Rsc) -> WeakWidget<TextEdit> {
wtext(name) wtext(name)
.editable(EditMode::SingleLine) .editable(EditMode::SingleLine)
.size(20) .size(20)
@@ -20,7 +20,7 @@ pub fn field_widget(name: &str, hint_text: &str, rsc: &mut Rsc) -> WidgetRef<Tex
.add(rsc) .add(rsc)
} }
pub fn field_box(field: WidgetRef<TextEdit>, rsc: &mut Rsc) -> WidgetRef { pub fn field_box(field: WeakWidget<TextEdit>, rsc: &mut Rsc) -> WeakWidget {
field field
.pad(10) .pad(10)
.background(rect(Color::BLACK.brighter(0.1)).radius(15)) .background(rect(Color::BLACK.brighter(0.1)).radius(15))
@@ -31,55 +31,48 @@ pub fn field_box(field: WidgetRef<TextEdit>, rsc: &mut Rsc) -> WidgetRef {
#[derive(Clone, Copy, WidgetView)] #[derive(Clone, Copy, WidgetView)]
pub struct Button { pub struct Button {
#[root] #[root]
root: WidgetRef, root: WeakWidget,
rect: WidgetRef<Rect>, rect: WeakWidget<Rect>,
enabled: Handle<bool>, color: UiColor,
enabled: WeakState<bool>,
} }
// impl WidgetView for Button {
// fn view(&self) -> &WidgetRef<Self::Widget> {
// &self.root
// }
// }
impl Button { impl Button {
pub fn new(text: &str, color: UiColor, rsc: &mut Rsc) -> Self { pub fn new(text: &str, color: UiColor, rsc: &mut Rsc) -> Self {
let rect = rect(color).radius(15).add(rsc); let rect = rect(color).radius(15).add(rsc);
// let enabled = Handle::from(true); let enabled = rsc.create_state(rect, true);
// let enabled_ = enabled.clone();
// let enabled__ = enabled.clone();
let root = rect let root = rect
.on( .on(
CursorSense::HoverStart | CursorSense::unclick(), CursorSense::HoverStart | CursorSense::unclick(),
move |ctx, rsc: &mut Rsc| { move |ctx, rsc: &mut Rsc| {
// if !*enabled_.get() { if !rsc[enabled] {
// return; return;
// } }
rsc.ui[ctx.widget].color = color.brighter(0.1); rsc[ctx.widget].color = color.brighter(0.1);
}, },
) )
.on(CursorSense::HoverEnd, move |ctx, rsc| { .on(CursorSense::HoverEnd, move |ctx, rsc| {
// if !*enabled__.get() { if !rsc[enabled] {
// return; return;
// } }
rsc.ui[ctx.widget].color = color; rsc[ctx.widget].color = color;
}) })
.height(60) .height(60)
.foreground(wtext(text).size(25).text_align(Align::CENTER)) .foreground(wtext(text).size(25).text_align(Align::CENTER))
.add(rsc); .add(rsc);
// let enabled_ = enabled.clone();
rect.on(CursorSense::click(), move |ctx, rsc: &mut Rsc| { rect.on(CursorSense::click(), move |ctx, rsc: &mut Rsc| {
// if !*enabled_.get() { if !rsc[enabled] {
// return; return;
// } }
rsc.ui[ctx.widget].color = color.darker(0.2); rsc[ctx.widget].color = color.darker(0.2);
rsc.run_event::<Submit>(root, (), ctx.state); rsc.run_event::<Submit>(root, (), ctx.state);
}) })
.add(rsc); .add(rsc);
Self { Self {
root, root,
rect, rect,
// enabled, color,
enabled,
} }
} }
@@ -88,21 +81,21 @@ impl Button {
} }
pub fn disable(&self, rsc: &mut Rsc) { pub fn disable(&self, rsc: &mut Rsc) {
*self.enabled.get_mut() = false; rsc[self.enabled] = false;
self.rect.get_mut().color = self.color.darker(0.8); rsc[self.rect].color = self.color.darker(0.8);
} }
} }
widget_trait! { widget_trait! {
pub trait Stuff<Rsc: HasUi + 'static>; pub trait Stuff<Rsc: UiRsc + 'static>;
fn modal(self, width: impl UiNum) -> impl WidgetIdFn<Rsc> { fn modal(self, width: impl UiNum) -> impl WidgetIdFn<Rsc> {
|ui| { |rsc| {
self self
.pad(15) .pad(15)
.background(rect(color::MODAL_BG).radius(15)) .background(rect(color::MODAL_BG).radius(15))
.width(width) .width(width)
.align(Align::CENTER) .align(Align::CENTER)
.add(ui) .add(rsc)
} }
} }
} }