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, 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 { 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 { 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::>>(), ); 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, } }