code cleanup

This commit is contained in:
maxstrb 2026-02-27 00:16:32 +01:00
parent b0dd7b0004
commit 2abbacf66e
9 changed files with 827 additions and 554 deletions

View file

@ -1,19 +1,19 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
if [[ ! -d "/home/maxag/Projects/Rust/floating-calculator" ]]; then if [[ ! -d "/mnt/removable/Projects/Rust/floating-calculator" ]]; then
echo "Cannot find source directory; Did you move it?" echo "Cannot find source directory; Did you move it?"
echo "(Looking for "/home/maxag/Projects/Rust/floating-calculator")" echo "(Looking for "/mnt/removable/Projects/Rust/floating-calculator")"
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again' echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
exit 1 exit 1
fi fi
# rebuild the cache forcefully # rebuild the cache forcefully
_nix_direnv_force_reload=1 direnv exec "/home/maxag/Projects/Rust/floating-calculator" true _nix_direnv_force_reload=1 direnv exec "/mnt/removable/Projects/Rust/floating-calculator" true
# Update the mtime for .envrc. # Update the mtime for .envrc.
# This will cause direnv to reload again - but without re-building. # This will cause direnv to reload again - but without re-building.
touch "/home/maxag/Projects/Rust/floating-calculator/.envrc" touch "/mnt/removable/Projects/Rust/floating-calculator/.envrc"
# Also update the timestamp of whatever profile_rc we have. # Also update the timestamp of whatever profile_rc we have.
# This makes sure that we know we are up to date. # This makes sure that we know we are up to date.
touch -r "/home/maxag/Projects/Rust/floating-calculator/.envrc" "/home/maxag/Projects/Rust/floating-calculator/.direnv"/*.rc touch -r "/mnt/removable/Projects/Rust/floating-calculator/.envrc" "/mnt/removable/Projects/Rust/floating-calculator/.direnv"/*.rc

1012
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,10 +5,10 @@ edition = "2024"
[dependencies] [dependencies]
cxx = "1.0.194" cxx = "1.0.194"
dark-light = "2.0.0"
iced = { version = "0.14.0", default-features = false, features = ["wgpu", "wayland", "tokio"] } iced = { version = "0.14.0", default-features = false, features = ["wgpu", "wayland", "tokio"] }
iced_layershell = "0.15.0" iced_layershell = { version = "0.15.0", default-features = false }
winit = { version = "0.30.12", features = ["wayland"] } winit = { version = "0.30.12", default-features = false, features = ["wayland"] }
[build-dependencies] [build-dependencies]
cxx-build = "1.0" cxx-build = "1.0"

View file

@ -1,7 +1,7 @@
fn main() { fn main() {
let lib = pkg_config::probe_library("libqalculate").expect("libqalculate not found"); let lib = pkg_config::probe_library("libqalculate").expect("libqalculate not found");
cxx_build::bridge("src/main.rs") cxx_build::bridge("src/update.rs")
.file("src/qalc_bridge.cc") .file("src/qalc_bridge.cc")
.includes(&lib.include_paths) .includes(&lib.include_paths)
.include("src") .include("src")
@ -15,7 +15,7 @@ fn main() {
); );
println!("cargo:rustc-link-lib=static=qalc-bridge"); println!("cargo:rustc-link-lib=static=qalc-bridge");
println!("cargo:rerun-if-changed=src/main.rs"); println!("cargo:rerun-if-changed=src/update.rs");
println!("cargo:rerun-if-changed=src/qalc_bridge.cc"); println!("cargo:rerun-if-changed=src/qalc_bridge.cc");
println!("cargo:rerun-if-changed=src/qalc_bridge.h"); println!("cargo:rerun-if-changed=src/qalc_bridge.h");
} }

View file

@ -1,84 +1,40 @@
use iced::widget::{Column, Id, TextInput, column, container, operation, text, text_input}; mod state;
use iced::{Background, Color, Element, Event, Task as Command}; mod update;
use iced::{Border, color};
use crate::state::{Message, State};
use crate::update::update;
use iced::widget::{Column, TextInput, column, container, text, text_input};
use iced::{Background, Border, Color, Element, Theme};
use iced_layershell::application; use iced_layershell::application;
use iced_layershell::reexport::Anchor; use iced_layershell::reexport::Anchor;
use iced_layershell::settings::{LayerShellSettings, Settings, StartMode}; use iced_layershell::settings::{LayerShellSettings, Settings};
use iced_layershell::to_layer_message;
use crate::ffi::qalc_calculate; const BORDER_RADIUS: f32 = 15.;
const BORDER_WIDTH: f32 = 2.;
#[cxx::bridge] const PADDING: f32 = 8.;
mod ffi { const WINDOW_SIZE: (u32, u32) = (400, 400);
unsafe extern "C++" { const BG_ALPHA: f32 = 0.75;
include!("floating-calculator/src/qalc_bridge.h");
fn qalc_calculate(expression: &str, timeout_ms: i32) -> String;
}
}
pub fn main() -> Result<(), iced_layershell::Error> { pub fn main() -> Result<(), iced_layershell::Error> {
let _ = ffi::qalc_calculate("", 2000); application(
State::default,
let binded_output_name = std::env::args().nth(1); || "floating-calculator".into(),
let start_mode = match binded_output_name { update,
Some(output) => StartMode::TargetScreen(output), view,
None => StartMode::Active, )
}; .theme(theme)
.style(style)
application(State::default, namespace, update, view) .subscription(subscription)
.style(style) .settings(Settings {
.subscription(subscription) layer_settings: LayerShellSettings {
.settings(Settings { size: Some(WINDOW_SIZE),
layer_settings: LayerShellSettings { exclusive_zone: -1,
size: Some((400, 400)), anchor: Anchor::empty(),
exclusive_zone: -1,
start_mode,
anchor: Anchor::empty(),
..Default::default()
},
..Default::default() ..Default::default()
}) },
.run() ..Default::default()
} })
.run()
struct State {
current_message: String,
history: Vec<History>,
input_id: Id,
}
struct History {
promt: String,
output: String,
}
impl History {
fn new(promt: String, output: String) -> Self {
Self { promt, output }
}
}
impl Default for State {
fn default() -> Self {
Self {
current_message: String::new(),
history: Vec::new(),
input_id: Id::unique(),
}
}
}
#[to_layer_message]
#[derive(Debug, Clone)]
enum Message {
Init,
TextSubmit,
TextInput(String),
IcedEvent(Event),
}
fn namespace() -> String {
String::from("Iced qalc claculator")
} }
fn subscription(_state: &State) -> iced::Subscription<Message> { fn subscription(_state: &State) -> iced::Subscription<Message> {
@ -91,86 +47,70 @@ fn subscription(_state: &State) -> iced::Subscription<Message> {
]) ])
} }
fn update(state: &mut State, message: Message) -> Command<Message> {
use iced::keyboard::{Event::KeyReleased, Key, key::Named};
match message {
Message::Init => operation::focus(state.input_id.clone()),
Message::IcedEvent(event) => {
if let Event::Keyboard(KeyReleased {
key: Key::Named(Named::Escape),
..
}) = event
{
return iced::exit();
}
Command::none()
}
Message::TextInput(text) => {
state.current_message = text;
Command::none()
}
Message::TextSubmit => {
let result = qalc_calculate(&state.current_message, 2000);
let history = History::new(std::mem::take(&mut state.current_message), result);
state.history.push(history);
Command::none()
}
_ => Command::none(),
}
}
fn view(state: &State) -> Element<'_, Message> { fn view(state: &State) -> Element<'_, Message> {
let input: TextInput<'_, Message> = let input = TextInput::new("Type something here...", &state.current_message)
TextInput::new("Type something here...", &state.current_message) .on_input(Message::TextInput)
.on_input(Message::TextInput) .on_submit(Message::TextSubmit)
.on_submit(Message::TextSubmit) .id(state.input_id.clone())
.id(state.input_id.clone()); .style(input_style);
let input = input.style(|_theme, _status| text_input::Style { let history = state
background: Background::Color(Color::TRANSPARENT), .history
border: Border::default(), .iter()
icon: Color::TRANSPARENT, .rev()
placeholder: color!(0xbbbbbb), .map(|msg| column![text!("{}", msg.promt).size(12), text!(" {}", msg.output),].into());
value: Color::WHITE,
selection: color!(0x0000ff),
});
let content = Column::with_children( let content = Column::with_children(
std::iter::once(input.into()) std::iter::once(input.into())
.chain(state.history.iter().rev().map(|msg| { .chain(history)
column![
text!("{}", msg.promt).size(12).color(color!(0x999999)),
text!(" {}", msg.output)
]
.into()
}))
.collect::<Vec<Element<_>>>(), .collect::<Vec<Element<_>>>(),
); );
container(content) container(content)
.width(iced::Length::Fill) .width(iced::Length::Fill)
.height(iced::Length::Fill) .height(iced::Length::Fill)
.padding(8.) .padding(PADDING)
.style(|_theme| container::Style { .style(container_style)
text_color: Some(Color::WHITE),
background: Some(iced::Background::Color(Color::from_rgba8(30, 30, 46, 0.75))),
border: iced::Border::default()
.rounded(15.)
.color(color!(0xaaaaff))
.width(2.),
..Default::default()
})
.into() .into()
} }
fn input_style(theme: &iced::Theme, _status: text_input::Status) -> text_input::Style {
let ext = theme.extended_palette();
text_input::Style {
background: Background::Color(Color::TRANSPARENT),
border: Border::default(),
icon: Color::TRANSPARENT,
placeholder: ext.background.weak.text,
value: ext.background.base.text,
selection: ext.primary.weak.color,
}
}
fn container_style(theme: &iced::Theme) -> container::Style {
let ext = theme.extended_palette();
let mut bg = ext.background.base.color;
bg.a = BG_ALPHA;
container::Style {
text_color: Some(ext.background.base.text),
background: Some(Background::Color(bg)),
border: Border::default()
.rounded(BORDER_RADIUS)
.color(ext.primary.base.color)
.width(BORDER_WIDTH),
..Default::default()
}
}
fn theme(_state: &State) -> Theme {
match dark_light::detect() {
Ok(dark_light::Mode::Light) => Theme::Light,
_ => Theme::CatppuccinMocha,
}
}
fn style(_state: &State, theme: &iced::Theme) -> iced::theme::Style { fn style(_state: &State, theme: &iced::Theme) -> iced::theme::Style {
use iced::theme::Style; iced::theme::Style {
Style {
background_color: Color::TRANSPARENT, background_color: Color::TRANSPARENT,
text_color: theme.palette().text, text_color: theme.palette().text,
} }

View file

@ -1,5 +1,5 @@
#include "floating-calculator/src/qalc_bridge.h" #include "floating-calculator/src/qalc_bridge.h"
#include "floating-calculator/src/main.rs.h" #include "floating-calculator/src/update.rs.h"
#include <libqalculate/qalculate.h> #include <libqalculate/qalculate.h>
Calculator create_calculator() { Calculator create_calculator() {

39
src/state.rs Normal file
View file

@ -0,0 +1,39 @@
use iced::Event;
use iced::widget::Id;
use iced_layershell::to_layer_message;
pub struct State {
pub current_message: String,
pub history: Vec<History>,
pub input_id: Id,
}
pub struct History {
pub promt: String,
pub output: String,
}
impl History {
pub fn new(promt: String, output: String) -> Self {
Self { promt, output }
}
}
impl Default for State {
fn default() -> Self {
Self {
current_message: String::new(),
history: Vec::new(),
input_id: Id::unique(),
}
}
}
#[to_layer_message]
#[derive(Debug, Clone)]
pub enum Message {
Init,
TextSubmit,
TextInput(String),
IcedEvent(Event),
}

45
src/update.rs Normal file
View file

@ -0,0 +1,45 @@
use crate::state::{History, Message, State};
use iced::keyboard::Event::KeyReleased;
use iced::keyboard::key::{Key, Named};
use iced::widget::operation;
use iced::{Event, Task as Command};
#[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 update(state: &mut State, message: Message) -> Command<Message> {
match message {
Message::Init => operation::focus(state.input_id.clone()),
Message::IcedEvent(event) => {
if let Event::Keyboard(KeyReleased {
key: Key::Named(Named::Escape),
..
}) = event
{
return iced::exit();
}
Command::none()
}
Message::TextInput(text) => {
state.current_message = text;
Command::none()
}
Message::TextSubmit => {
let result = ffi::qalc_calculate(&state.current_message, 2000);
let history = History::new(std::mem::take(&mut state.current_message), result);
state.history.push(history);
Command::none()
}
_ => Command::none(),
}
}

43
src/view.rs Normal file
View file

@ -0,0 +1,43 @@
fn view(state: &State) -> Element<'_, Message> {
let input: TextInput<'_, Message> =
TextInput::new("Type something here...", &state.current_message)
.on_input(Message::TextInput)
.on_submit(Message::TextSubmit)
.id(state.input_id.clone());
let input = input.style(|_theme, _status| text_input::Style {
background: Background::Color(Color::TRANSPARENT),
border: Border::default(),
icon: Color::TRANSPARENT,
placeholder: color!(0xbbbbbb),
value: Color::WHITE,
selection: color!(0x0000ff),
});
let content = Column::with_children(
std::iter::once(input.into())
.chain(state.history.iter().rev().map(|msg| {
column![
text!("{}", msg.promt).size(12).color(color!(0x999999)),
text!(" {}", msg.output)
]
.into()
}))
.collect::<Vec<Element<_>>>(),
);
container(content)
.width(iced::Length::Fill)
.height(iced::Length::Fill)
.padding(8.)
.style(|_theme| container::Style {
text_color: Some(Color::WHITE),
background: Some(iced::Background::Color(Color::from_rgba8(30, 30, 46, 0.75))),
border: iced::Border::default()
.rounded(15.)
.color(color!(0xaaaaff))
.width(2.),
..Default::default()
})
.into()
}