127 lines
3.6 KiB
Rust
127 lines
3.6 KiB
Rust
use iced::theme::Style;
|
|
use iced::widget::{Column, Container, Id, TextInput, container, operation, text};
|
|
use iced::{Background, Color, Element, Event, Task as Command, window};
|
|
|
|
#[cxx::bridge]
|
|
mod ffi {
|
|
unsafe extern "C++" {
|
|
include!("floating-calculator/src/qalc_bridge.h");
|
|
fn qalc_calculate(expression: &str, timeout_ms: i32) -> String;
|
|
}
|
|
}
|
|
|
|
pub fn main() -> iced::Result {
|
|
let _ = ffi::qalc_calculate("", 2000);
|
|
|
|
iced::application(State::default, State::update, State::view)
|
|
.title("Iced qalc calculator")
|
|
.subscription(State::subscription)
|
|
.style(style)
|
|
.window(window::Settings {
|
|
size: iced::Size::new(400.0, 400.0),
|
|
transparent: true,
|
|
decorations: false,
|
|
level: window::Level::AlwaysOnTop,
|
|
..Default::default()
|
|
})
|
|
.run()
|
|
}
|
|
|
|
struct State {
|
|
initialized: bool,
|
|
current_message: String,
|
|
history: Vec<String>,
|
|
input_id: Id,
|
|
}
|
|
|
|
impl Default for State {
|
|
fn default() -> Self {
|
|
Self {
|
|
initialized: false,
|
|
current_message: String::new(),
|
|
history: Vec::new(),
|
|
input_id: Id::unique(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
enum Message {
|
|
Init,
|
|
TextSubmit,
|
|
TextInput(String),
|
|
IcedEvent(Event),
|
|
}
|
|
|
|
impl State {
|
|
fn subscription(&self) -> iced::Subscription<Message> {
|
|
use iced::event;
|
|
use iced::futures::stream;
|
|
|
|
let init = if !self.initialized {
|
|
iced::Subscription::run_with("init", |_| stream::once(async { Message::Init }))
|
|
} else {
|
|
iced::Subscription::none()
|
|
};
|
|
|
|
iced::Subscription::batch([init, event::listen().map(Message::IcedEvent)])
|
|
}
|
|
|
|
fn update(&mut self, message: Message) -> Command<Message> {
|
|
use iced::keyboard::{Key, key::Named};
|
|
|
|
match message {
|
|
Message::Init => {
|
|
self.initialized = true;
|
|
operation::focus(self.input_id.clone())
|
|
}
|
|
Message::IcedEvent(event) => {
|
|
if let Event::Keyboard(iced::keyboard::Event::KeyReleased {
|
|
key: Key::Named(Named::Escape),
|
|
..
|
|
}) = event
|
|
{
|
|
return iced::exit();
|
|
}
|
|
Command::none()
|
|
}
|
|
Message::TextInput(t) => {
|
|
self.current_message = t;
|
|
Command::none()
|
|
}
|
|
Message::TextSubmit => {
|
|
self.history.push(ffi::qalc_calculate(
|
|
&std::mem::take(&mut self.current_message),
|
|
2000,
|
|
));
|
|
Command::none()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn view(&self) -> Container<'_, Message> {
|
|
let input: TextInput<'_, Message> =
|
|
TextInput::new("Type something here...", &self.current_message)
|
|
.on_input(Message::TextInput)
|
|
.on_submit(Message::TextSubmit)
|
|
.id(self.input_id.clone());
|
|
|
|
let content = Column::with_children(
|
|
std::iter::once(input.into())
|
|
.chain(self.history.iter().rev().map(|msg| text!("{msg}").into()))
|
|
.collect::<Vec<Element<_>>>(),
|
|
);
|
|
|
|
container(content).style(|_theme| container::Style {
|
|
background: Some(Background::Color(Color::TRANSPARENT)),
|
|
..Default::default()
|
|
})
|
|
}
|
|
}
|
|
|
|
fn style(_state: &State, theme: &iced::Theme) -> Style {
|
|
Style {
|
|
background_color: Color::TRANSPARENT,
|
|
text_color: theme.palette().text,
|
|
}
|
|
}
|