uuuuuuhhhhhhh
This commit is contained in:
parent
670f7a5c70
commit
89e8300bfb
12 changed files with 33 additions and 310 deletions
|
|
@ -1,19 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
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 "(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'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 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.
|
||||
# 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.
|
||||
# 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
|
||||
|
|
|
|||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1022,7 +1022,6 @@ dependencies = [
|
|||
"iced",
|
||||
"iced_layershell",
|
||||
"pkg-config",
|
||||
"quote",
|
||||
"serde",
|
||||
"toml",
|
||||
"winit",
|
||||
|
|
|
|||
|
|
@ -9,13 +9,12 @@ dark-light = "2.0.0"
|
|||
iced = { version = "0.14.0", default-features = false, features = ["wgpu", "wayland", "tokio"] }
|
||||
iced_layershell = { version = "0.15.0", default-features = false }
|
||||
winit = { version = "0.30.12", default-features = false, features = ["wayland"] }
|
||||
toml = {version = "1.0.3", default-features = false, features = ["parse", "serde", "std"] }
|
||||
serde = "1.0.228"
|
||||
|
||||
[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
|
||||
|
|
|
|||
98
build.rs
98
build.rs
|
|
@ -1,13 +1,7 @@
|
|||
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 {
|
||||
|
|
@ -16,8 +10,8 @@ fn probe_libqalculate() -> pkg_config::Library {
|
|||
}
|
||||
|
||||
fn build_cxx_bridge(lib: &pkg_config::Library) {
|
||||
cxx_build::bridge("src/update.rs")
|
||||
.file("src/qalc_bridge.cc")
|
||||
cxx_build::bridge("src/qalc/mod.rs")
|
||||
.file("src/qalc/qalc_bridge.cc")
|
||||
.includes(&lib.include_paths)
|
||||
.include("src")
|
||||
.flag_if_supported("-std=c++17")
|
||||
|
|
@ -30,89 +24,11 @@ fn emit_cargo_metadata() {
|
|||
println!("cargo:rustc-link-search=native={out_dir}");
|
||||
println!("cargo:rustc-link-lib=static=qalc-bridge");
|
||||
|
||||
for file in &["src/update.rs", "src/qalc_bridge.cc", "src/qalc_bridge.h"] {
|
||||
for file in &[
|
||||
"src/qalc/mod.rs",
|
||||
"src/qalc/qalc_bridge.cc",
|
||||
"src/qalc/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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ radius = 15.0
|
|||
width = 2.0
|
||||
padding = 3.0
|
||||
|
||||
[pallete]
|
||||
[palette]
|
||||
background = "#1a1d23"
|
||||
text = "#e8e8f4"
|
||||
primary = "#7c85f0"
|
||||
|
|
|
|||
85
src/main.rs
85
src/main.rs
|
|
@ -1,81 +1,14 @@
|
|||
mod state;
|
||||
mod update;
|
||||
mod view;
|
||||
mod qalc;
|
||||
use crate::qalc::ffi::qalc_calculate;
|
||||
|
||||
use crate::state::Message;
|
||||
use crate::update::update;
|
||||
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};
|
||||
pub fn main() -> iced::Result {}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/theme.rs"));
|
||||
|
||||
pub fn main() -> Result<(), iced_layershell::Error> {
|
||||
application(
|
||||
State::default,
|
||||
|| "floating-calculator".into(),
|
||||
update,
|
||||
view,
|
||||
)
|
||||
.theme(theme)
|
||||
.style(style)
|
||||
.subscription(subscription)
|
||||
.settings(Settings {
|
||||
layer_settings: LayerShellSettings {
|
||||
size: Some(WINDOW_SIZE),
|
||||
exclusive_zone: -1,
|
||||
anchor: Anchor::empty(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.run()
|
||||
struct Calculator {
|
||||
current_input: String,
|
||||
history: Vec<History>,
|
||||
}
|
||||
|
||||
fn subscription(_state: &State) -> iced::Subscription<Message> {
|
||||
use iced::event;
|
||||
use iced::futures::stream;
|
||||
|
||||
iced::Subscription::batch([
|
||||
iced::Subscription::run_with("init", |_| stream::once(async { Message::Init })),
|
||||
event::listen().map(Message::IcedEvent),
|
||||
])
|
||||
}
|
||||
|
||||
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 style(_state: &State, theme: &iced::Theme) -> iced::theme::Style {
|
||||
iced::theme::Style {
|
||||
background_color: Color::TRANSPARENT,
|
||||
text_color: theme.palette().text,
|
||||
}
|
||||
struct History {
|
||||
prompt: String,
|
||||
result: String,
|
||||
}
|
||||
|
|
|
|||
7
src/qalc/mod.rs
Normal file
7
src/qalc/mod.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#[cxx::bridge]
|
||||
pub mod ffi {
|
||||
unsafe extern "C++" {
|
||||
include!("floating-calculator/src/qalc/qalc_bridge.h");
|
||||
pub fn qalc_calculate(expression: &str, timeout_ms: i32) -> String;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
#include "floating-calculator/src/qalc_bridge.h"
|
||||
#include "floating-calculator/src/update.rs.h"
|
||||
#include "floating-calculator/src/qalc/qalc_bridge.h"
|
||||
#include "floating-calculator/src/qalc/mod.rs.h"
|
||||
#include <libqalculate/qalculate.h>
|
||||
|
||||
Calculator create_calculator() {
|
||||
39
src/state.rs
39
src/state.rs
|
|
@ -1,39 +0,0 @@
|
|||
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),
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
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(),
|
||||
}
|
||||
}
|
||||
47
src/view.rs
47
src/view.rs
|
|
@ -1,47 +0,0 @@
|
|||
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)
|
||||
.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()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue