diff --git a/.direnv/bin/nix-direnv-reload b/.direnv/bin/nix-direnv-reload index be817d8..f63b15c 100755 --- a/.direnv/bin/nix-direnv-reload +++ b/.direnv/bin/nix-direnv-reload @@ -1,19 +1,19 @@ #!/usr/bin/env bash set -e -if [[ ! -d "/mnt/removable/Projects/Rust/floating-calculator" ]]; then +if [[ ! -d "/home/maxag/Projects/Rust/floating-calculator" ]]; then echo "Cannot find source directory; Did you move it?" - echo "(Looking for "/mnt/removable/Projects/Rust/floating-calculator")" + echo "(Looking for "/home/maxag/Projects/Rust/floating-calculator")" echo 'Cannot force reload with this script - use "direnv reload" manually and then try again' exit 1 fi # rebuild the cache forcefully -_nix_direnv_force_reload=1 direnv exec "/mnt/removable/Projects/Rust/floating-calculator" true +_nix_direnv_force_reload=1 direnv exec "/home/maxag/Projects/Rust/floating-calculator" true # Update the mtime for .envrc. # This will cause direnv to reload again - but without re-building. -touch "/mnt/removable/Projects/Rust/floating-calculator/.envrc" +touch "/home/maxag/Projects/Rust/floating-calculator/.envrc" # Also update the timestamp of whatever profile_rc we have. # This makes sure that we know we are up to date. -touch -r "/mnt/removable/Projects/Rust/floating-calculator/.envrc" "/mnt/removable/Projects/Rust/floating-calculator/.direnv"/*.rc +touch -r "/home/maxag/Projects/Rust/floating-calculator/.envrc" "/home/maxag/Projects/Rust/floating-calculator/.direnv"/*.rc diff --git a/Cargo.lock b/Cargo.lock index 5a3f507..2bea20f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1022,6 +1022,9 @@ dependencies = [ "iced", "iced_layershell", "pkg-config", + "quote", + "serde", + "toml", "winit", ] @@ -2902,6 +2905,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "shlex" version = "1.3.0" @@ -3251,6 +3263,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "toml" +version = "1.0.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime 1.0.0+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow", +] + [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -3260,6 +3287,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -3267,7 +3303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", ] @@ -3281,6 +3317,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_writer" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" + [[package]] name = "tracing" version = "0.1.44" diff --git a/Cargo.toml b/Cargo.toml index 7c0696e..3e82970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,9 @@ winit = { version = "0.30.12", default-features = false, features = ["wayland"] [build-dependencies] cxx-build = "1.0" pkg-config = "0.3" +quote = "1.0.44" +toml = {version = "1.0.3", default-features = false, features = ["parse", "serde", "std"] } +serde = "1.0.228" [profile.release] opt-level = 3 diff --git a/build.rs b/build.rs index 76474d2..b72e3ef 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,21 @@ -fn main() { - let lib = pkg_config::probe_library("libqalculate").expect("libqalculate not found"); +use std::{fs, path::Path}; +use quote::quote; +use serde::Deserialize; + +fn main() { + let lib = probe_libqalculate(); + build_cxx_bridge(&lib); + emit_cargo_metadata(); + load_config(); +} + +fn probe_libqalculate() -> pkg_config::Library { + pkg_config::probe_library("libqalculate") + .expect("libqalculate not found — install it via your package manager") +} + +fn build_cxx_bridge(lib: &pkg_config::Library) { cxx_build::bridge("src/update.rs") .file("src/qalc_bridge.cc") .includes(&lib.include_paths) @@ -8,14 +23,96 @@ fn main() { .flag_if_supported("-std=c++17") .compiler("g++") .compile("qalc-bridge"); +} - println!( - "cargo:rustc-link-search=native={}", - std::env::var("OUT_DIR").unwrap() - ); +fn emit_cargo_metadata() { + let out_dir = std::env::var("OUT_DIR").unwrap(); + println!("cargo:rustc-link-search=native={out_dir}"); println!("cargo:rustc-link-lib=static=qalc-bridge"); - 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.h"); + for file in &["src/update.rs", "src/qalc_bridge.cc", "src/qalc_bridge.h"] { + println!("cargo:rerun-if-changed={file}"); + } +} + +fn load_config() { + println!("cargo:rerun-if-changed=config.toml"); + + let config: Config = + toml::from_str(&fs::read_to_string(Path::new("./config.toml")).unwrap_or_default()) + .unwrap_or_default(); + + let theme = if !config.enable { + quote! { + use iced::Theme; + use crate::state::State; + + pub const BORDER_RADIUS: f32 = 15.; + pub const BORDER_WIDTH: f32 = 2.; + pub const PADDING: f32 = 8.; + pub const WINDOW_SIZE: (u32, u32) = (400, 400); + pub const BG_ALPHA: f32 = 0.75; + + pub fn theme(_state: &State) -> Theme { + match dark_light::detect() { + Ok(dark_light::Mode::Light) => Theme::Light, + _ => Theme::CatppuccinMocha, + } + } + } + } else { + quote! { + use iced::Theme; + use crate::state::State; + + pub const BORDER_RADIUS: f32 = #&config.border.radius; + pub const BORDER_WIDTH: f32 = #&config.border.width; + pub const PADDING: f32 = #&config.border.padding; + pub const WINDOW_SIZE: (u32, u32) = (#(&config.window_size.width), #&config.window_size.height); + pub const BG_ALPHA: f32 = 0.75; + + pub fn theme(_state: &State) -> Theme { + match dark_light::detect() { + Ok(dark_light::Mode::Light) => Theme::Light, + _ => Theme::CatppuccinMocha, + } + } + } + }; + + let out_dir = std::env::var("OUT_DIR").unwrap(); + std::fs::write(format!("{out_dir}/theme.rs"), theme.to_string()).unwrap(); +} + +#[derive(Deserialize, Default)] +struct WindowSize { + width: u32, + height: u32, +} + +#[derive(Deserialize, Default)] +struct Border { + radius: f32, + width: f32, + padding: f32, +} + +#[derive(Deserialize, Default)] +struct Palette { + background: String, + text: String, + primary: String, + success: String, + warning: String, + danger: String, +} + +#[derive(Deserialize, Default)] +struct Config { + enable: bool, + transparency: f32, + + window_size: WindowSize, + border: Border, + palette: Palette, } diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..ca7b0f9 --- /dev/null +++ b/config.toml @@ -0,0 +1,19 @@ +enable = true +transparency = 0.75 + +[window_size] +width = 800 +height = 400 + +[border] +radius = 15.0 +width = 2.0 +padding = 3.0 + +[pallete] +background = "#1a1d23" +text = "#e8e8f4" +primary = "#7c85f0" +success = "#4ecb8f" +warning = "#f0c060" +danger = "#f05a6e" diff --git a/src/main.rs b/src/main.rs index 7b21653..738b04d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,17 @@ mod state; mod update; +mod view; -use crate::state::{Message, State}; +use crate::state::Message; use crate::update::update; -use iced::widget::{Column, TextInput, column, container, text, text_input}; -use iced::{Background, Border, Color, Element, Theme}; +use crate::view::view; +use iced::widget::{container, text_input}; +use iced::{Background, Border, Color}; use iced_layershell::application; use iced_layershell::reexport::Anchor; use iced_layershell::settings::{LayerShellSettings, Settings}; -const BORDER_RADIUS: f32 = 15.; -const BORDER_WIDTH: f32 = 2.; -const PADDING: f32 = 8.; -const WINDOW_SIZE: (u32, u32) = (400, 400); -const BG_ALPHA: f32 = 0.75; +include!(concat!(env!("OUT_DIR"), "/theme.rs")); pub fn main() -> Result<(), iced_layershell::Error> { application( @@ -47,33 +45,6 @@ fn subscription(_state: &State) -> iced::Subscription { ]) } -fn view(state: &State) -> Element<'_, Message> { - let input = TextInput::new("Type something here...", &state.current_message) - .on_input(Message::TextInput) - .on_submit(Message::TextSubmit) - .id(state.input_id.clone()) - .style(input_style); - - let history = state - .history - .iter() - .rev() - .map(|msg| column![text!("{}", msg.promt).size(12), text!(" {}", msg.output),].into()); - - let content = Column::with_children( - std::iter::once(input.into()) - .chain(history) - .collect::>>(), - ); - - container(content) - .width(iced::Length::Fill) - .height(iced::Length::Fill) - .padding(PADDING) - .style(container_style) - .into() -} - fn input_style(theme: &iced::Theme, _status: text_input::Status) -> text_input::Style { let ext = theme.extended_palette(); text_input::Style { @@ -102,13 +73,6 @@ fn container_style(theme: &iced::Theme) -> container::Style { } } -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 { iced::theme::Style { background_color: Color::TRANSPARENT, diff --git a/src/view.rs b/src/view.rs index ac674dc..e7f44b3 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,4 +1,8 @@ -fn view(state: &State) -> Element<'_, Message> { +use crate::state::{Message, State}; +use iced::widget::{Column, TextInput, column, container, text, text_input}; +use iced::{Background, Border, Color, Element, color}; + +pub fn view(state: &State) -> Element<'_, Message> { let input: TextInput<'_, Message> = TextInput::new("Type something here...", &state.current_message) .on_input(Message::TextInput)