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
[dependencies]
gtk = "^0.14.0"
relm = "^0.22.0"
relm-derive = "^0.22.0"
druid = { git = "https://github.com/linebender/druid.git" }
uwuify = "0.2.2"

View File

@ -1,127 +1,87 @@
use gtk::{
glib::BoolError,
prelude::{FrameExt, OrientableExt, ScrolledWindowExt, TextBufferExt, TextViewExt, WidgetExt},
Inhibit,
Orientation,
PolicyType,
WrapMode,
use druid::{
widget::{Flex, Label, TextBox},
AppLauncher,
Data,
Lens,
LensExt,
PlatformError,
Widget,
WidgetExt,
WindowDesc,
};
use relm::{connect, Relm, Widget};
use relm_derive::{widget, Msg};
use std::{cell::RefCell, rc::Rc};
use util::{ImmutLens, Key};
use uwuifier::{round_up16, uwuify_sse};
fn main() -> Result<(), BoolError> {
Win::run(())
mod util;
fn main() -> Result<(), PlatformError> {
AppLauncher::with_window(WindowDesc::new(build_ui()).title("guwu")).launch(AppData::default())
}
pub struct Model {
relm: Relm<Win>,
uwubuf1: Vec<u8>,
uwubuf2: Vec<u8>,
#[derive(Default, Data, Lens, Clone)]
struct AppData {
input: String,
output: String,
uwubuf1: Rc<RefCell<Vec<u8>>>,
uwubuf2: Rc<RefCell<Vec<u8>>>,
}
impl Model {
pub fn prep_uwubufs(&mut self, len: usize) {
if len > self.uwubuf1.len() {
self.uwubuf1.resize(len, 0);
impl AppData {
fn alloc_uwubufs(&self, len: usize) {
let mut uwubuf1 = self.uwubuf1.borrow_mut();
let mut uwubuf2 = self.uwubuf2.borrow_mut();
if len > uwubuf1.len() {
uwubuf1.resize(len, 0);
}
if len > self.uwubuf2.len() {
self.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![],
if len > uwubuf2.len() {
uwubuf2.resize(len, 0);
}
}
fn update(&mut self, event: Msg) {
match event {
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],
);
fn uwu(&mut self) {
self.alloc_uwubufs(round_up16(self.input.len()) * 16);
if let Ok(uwu) = std::str::from_utf8(uwu) {
outbuf.set_text(uwu);
}
}
}
},
}
}
let mut uwubuf1 = self.uwubuf1.borrow_mut();
let mut uwubuf2 = self.uwubuf2.borrow_mut();
fn init_view(&mut self) {
self.widgets
.input_scroll
.set_policy(PolicyType::Never, PolicyType::Automatic);
let uwuified = uwuify_sse(self.input.as_bytes(), &mut uwubuf1, &mut uwubuf2);
self.widgets
.output_scroll
.set_policy(PolicyType::Never, PolicyType::Automatic);
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)),
}
// SAFETY: uwuify should always return valid UTF-8 if the input string was valid
// UTF-8, which we can be sure of, as it's a `String`.
self.output = unsafe { String::from_utf8_unchecked(uwuified.to_vec()) };
}
}
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())
}
}