port to druid

This commit is contained in:
LordMZTE 2021-12-19 14:49:50 +01:00
parent 1e98067548
commit ff0597ac40
3 changed files with 114 additions and 114 deletions

View file

@ -6,7 +6,5 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
gtk = "^0.14.0" druid = { git = "https://github.com/linebender/druid.git" }
relm = "^0.22.0"
relm-derive = "^0.22.0"
uwuify = "0.2.2" uwuify = "0.2.2"

View file

@ -1,127 +1,87 @@
use gtk::{ use druid::{
glib::BoolError, widget::{Flex, Label, TextBox},
prelude::{FrameExt, OrientableExt, ScrolledWindowExt, TextBufferExt, TextViewExt, WidgetExt}, AppLauncher,
Inhibit, Data,
Orientation, Lens,
PolicyType, LensExt,
WrapMode, PlatformError,
Widget,
WidgetExt,
WindowDesc,
}; };
use relm::{connect, Relm, Widget}; use std::{cell::RefCell, rc::Rc};
use relm_derive::{widget, Msg}; use util::{ImmutLens, Key};
use uwuifier::{round_up16, uwuify_sse};
fn main() -> Result<(), BoolError> { mod util;
Win::run(())
fn main() -> Result<(), PlatformError> {
AppLauncher::with_window(WindowDesc::new(build_ui()).title("guwu")).launch(AppData::default())
} }
pub struct Model { #[derive(Default, Data, Lens, Clone)]
relm: Relm<Win>, struct AppData {
uwubuf1: Vec<u8>, input: String,
uwubuf2: Vec<u8>, output: String,
uwubuf1: Rc<RefCell<Vec<u8>>>,
uwubuf2: Rc<RefCell<Vec<u8>>>,
} }
impl Model { impl AppData {
pub fn prep_uwubufs(&mut self, len: usize) { fn alloc_uwubufs(&self, len: usize) {
if len > self.uwubuf1.len() { let mut uwubuf1 = self.uwubuf1.borrow_mut();
self.uwubuf1.resize(len, 0); let mut uwubuf2 = self.uwubuf2.borrow_mut();
if len > uwubuf1.len() {
uwubuf1.resize(len, 0);
} }
if len > self.uwubuf2.len() { if len > uwubuf2.len() {
self.uwubuf2.resize(len, 0); uwubuf2.resize(len, 0);
}
}
}
#[derive(Clone, Msg)]
pub enum Msg {
Quit,
Edited,
}
#[widget]
impl Widget for Win {
fn model(relm: &Relm<Self>, _: ()) -> Model {
Model {
relm: relm.clone(),
uwubuf1: vec![],
uwubuf2: vec![],
} }
} }
fn update(&mut self, event: Msg) { fn uwu(&mut self) {
match event { self.alloc_uwubufs(round_up16(self.input.len()) * 16);
Msg::Quit => gtk::main_quit(),
Msg::Edited => {
if let (Some(inbuf), Some(outbuf)) =
(self.widgets.input.buffer(), self.widgets.output.buffer())
{
if let Some(text) = inbuf.text(&inbuf.start_iter(), &inbuf.end_iter(), true) {
let len = uwuifier::round_up16(text.len()) * 16;
self.model.prep_uwubufs(len);
let uwu = uwuifier::uwuify_sse(
text.as_bytes(),
&mut self.model.uwubuf1[..len],
&mut self.model.uwubuf2[..len],
);
if let Ok(uwu) = std::str::from_utf8(uwu) { let mut uwubuf1 = self.uwubuf1.borrow_mut();
outbuf.set_text(uwu); let mut uwubuf2 = self.uwubuf2.borrow_mut();
}
}
}
},
}
}
fn init_view(&mut self) { let uwuified = uwuify_sse(self.input.as_bytes(), &mut uwubuf1, &mut uwubuf2);
self.widgets
.input_scroll
.set_policy(PolicyType::Never, PolicyType::Automatic);
self.widgets // SAFETY: uwuify should always return valid UTF-8 if the input string was valid
.output_scroll // UTF-8, which we can be sure of, as it's a `String`.
.set_policy(PolicyType::Never, PolicyType::Automatic); self.output = unsafe { String::from_utf8_unchecked(uwuified.to_vec()) };
if let Some(buf) = self.widgets.input.buffer() {
connect!(buf, connect_changed(_), self.model.relm, Msg::Edited);
}
}
view! {
gtk::Window {
gtk::Box {
orientation: Orientation::Horizontal,
gtk::Frame {
label: Some("Input"),
#[name = "input_scroll"]
gtk::ScrolledWindow {
hexpand: true,
vexpand: true,
#[name = "input"]
gtk::TextView {
wrap_mode: WrapMode::WordChar,
},
},
},
gtk::Frame {
label: Some("Output"),
#[name = "output_scroll"]
gtk::ScrolledWindow {
hexpand: true,
vexpand: true,
#[name = "output"]
gtk::TextView {
editable: false,
wrap_mode: WrapMode::WordChar,
},
},
},
},
delete_event(_, _) => (Msg::Quit, Inhibit(false)),
}
} }
} }
fn build_ui() -> impl Widget<AppData> {
Flex::row()
.with_flex_child(
Flex::column()
.with_child(Label::new("Input"))
.with_flex_child(
TextBox::multiline()
.with_placeholder("Type here...")
.expand()
.lens(AppData::input)
.controller(Key::new(|_, data: &mut AppData, _, _| data.uwu())),
1.,
),
1.,
)
.with_spacer(4.)
.with_flex_child(
Flex::column()
.with_child(Label::new("Output"))
.with_flex_child(
TextBox::multiline()
.with_placeholder("UwU")
.lens(AppData::output.then(ImmutLens))
.expand(),
1.,
),
1.,
)
}

42
src/util.rs Normal file
View file

@ -0,0 +1,42 @@
use druid::{widget::Controller, Data, Env, Event, EventCtx, KeyEvent, Widget, Lens};
pub struct Key<T> {
action: Box<dyn Fn(&mut EventCtx, &mut T, &Env, &KeyEvent)>,
}
impl<T: Data> Key<T> {
pub fn new<F: Fn(&mut EventCtx, &mut T, &Env, &KeyEvent) + 'static>(action: F) -> Self {
Self {
action: Box::new(action),
}
}
}
impl<T: Data, W: Widget<T>> Controller<T, W> for Key<T> {
fn event(
&mut self,
child: &mut W,
ctx: &mut EventCtx,
event: &druid::Event,
data: &mut T,
env: &Env,
) {
child.event(ctx, event, data, env);
if let Event::KeyUp(e) = event {
(self.action)(ctx, data, env, e);
}
}
}
pub struct ImmutLens;
impl<T: Clone> Lens<T, T> for ImmutLens {
fn with<V, F: FnOnce(&T) -> V>(&self, data: &T, f: F) -> V {
f(data)
}
fn with_mut<V, F: FnOnce(&mut T) -> V>(&self, data: &mut T, f: F) -> V {
f(&mut data.clone())
}
}