code cleanup
This commit is contained in:
parent
b0dd7b0004
commit
2abbacf66e
9 changed files with 827 additions and 554 deletions
|
|
@ -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
1012
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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"
|
||||||
|
|
|
||||||
4
build.rs
4
build.rs
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
220
src/main.rs
220
src/main.rs
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
39
src/state.rs
Normal 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
45
src/update.rs
Normal 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
43
src/view.rs
Normal 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()
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue