134 lines
4.2 KiB
Rust

use relm4::gtk::{glib, prelude::*};
use relm4::{gtk, ComponentParts, ComponentSender, SimpleComponent};
pub struct McduModel {
query: String,
query_changed_by_mcdu_keys: bool,
}
impl McduModel {
fn new() -> Self {
McduModel {
query: String::new(),
query_changed_by_mcdu_keys: false,
}
}
}
#[derive(Debug)]
pub enum McduOutput {
SearchStarted(String),
}
#[derive(Debug)]
pub enum KeyboardEvent {
ButtonPress(char),
ClrButtonPress,
SearchStarted(String),
QueryChanged(String),
}
#[relm4::component(pub)]
impl SimpleComponent for McduModel {
type Init = ();
type Input = KeyboardEvent;
type Output = McduOutput;
view! {
#[root]
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_valign: gtk::Align::Center,
gtk::SearchEntry {
set_margin_bottom: 10,
#[block_signal(change_handler, search_handler)]
#[track = "model.query_changed_by_mcdu_keys"]
set_text: &model.query,
connect_changed[sender] => move |search_entry| sender.input(KeyboardEvent::QueryChanged(search_entry.text().to_string())) @change_handler,
connect_search_changed[sender] => move |search_entry| sender.input(KeyboardEvent::SearchStarted(search_entry.text().to_string())) @search_handler,
},
#[name = "keyboard"]
gtk::Grid {
set_column_homogeneous: true,
set_row_homogeneous: true,
set_column_spacing: 5,
set_row_spacing: 5,
}
}
}
fn init(
_init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let model = McduModel::new();
let widgets = view_output!();
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let mcdu_width = 6;
for (i, c) in alphabet.char_indices() {
let button = gtk::Button::default();
button.set_label(&c.to_string());
button.connect_clicked(glib::clone!(@strong sender => move |_| {
sender.input(KeyboardEvent::ButtonPress(c));
}));
let column = i % mcdu_width;
let row = (i - column) / mcdu_width;
widgets
.keyboard
.attach(&button, column as i32, row as i32, 1, 1);
}
let button = gtk::Button::default();
button.set_label("SPC");
button.connect_clicked(glib::clone!(@strong sender => move |_| {
sender.input(KeyboardEvent::ButtonPress(' '));
}));
let i = alphabet.len();
let column = i % mcdu_width;
let row = (i - column) / mcdu_width;
widgets
.keyboard
.attach(&button, column as i32, row as i32, 1, 1);
let button = gtk::Button::default();
button.set_label("CLR");
button.connect_clicked(glib::clone!(@strong sender => move |_| {
sender.input(KeyboardEvent::ClrButtonPress);
}));
let i = alphabet.len() + 1;
let column = i % mcdu_width;
let row = (i - column) / mcdu_width;
widgets
.keyboard
.attach(&button, column as i32, row as i32, 1, 1);
ComponentParts { model, widgets }
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
self.query_changed_by_mcdu_keys = false;
match message {
KeyboardEvent::ButtonPress(c) => {
self.query_changed_by_mcdu_keys = true;
self.query.push(c);
}
KeyboardEvent::ClrButtonPress => {
self.query_changed_by_mcdu_keys = true;
self.query.clear();
// Run search since gtk::SearchEntry will not run it if text is empty
sender.input(KeyboardEvent::SearchStarted(String::new()));
}
KeyboardEvent::SearchStarted(s) => {
sender.output(McduOutput::SearchStarted(s)).unwrap();
}
KeyboardEvent::QueryChanged(query) => self.query = query,
}
}
}