Skip to content

Commit

Permalink
Add theme selection and auto resize qr code.
Browse files Browse the repository at this point in the history
  • Loading branch information
H-M-H committed Sep 25, 2024
1 parent 2312881 commit a5c6be5
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 22 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ clap = { version = "4.5.18", features = ["derive"] }
clap_complete = "4.5.29"
dirs = "^5.0"
fastwebsockets = { version = "0.8.0", features = ["upgrade", "unstable-split"] }
fltk = { version = "^1", features = ["no-pango"] }
fltk = { version = "^1" }
fltk-theme = "0.7.3"
handlebars = "^6.1"
http-body-util = "0.1.2"
hyper = { version = "^1.4", features = ["server", "http1", "http2"] }
Expand Down
66 changes: 66 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,74 @@
use std::net::IpAddr;
use std::str::FromStr;
use std::{fs, path::PathBuf};

use clap::Parser;
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};

#[derive(clap::ValueEnum, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThemeType {
Aero,
AquaClassic,
Blue,
Classic,
Dark,
Greybird,
HighContrast,
Metro,
}

const THEME_LIST: [ThemeType; 8] = [
ThemeType::Aero,
ThemeType::AquaClassic,
ThemeType::Blue,
ThemeType::Classic,
ThemeType::Dark,
ThemeType::Greybird,
ThemeType::HighContrast,
ThemeType::Metro,
];

impl Default for ThemeType {
fn default() -> Self {
Self::Greybird
}
}

impl ThemeType {
pub fn apply(&self) {
let theme = match self {
ThemeType::Classic => fltk_theme::ThemeType::Classic,
ThemeType::Aero => fltk_theme::ThemeType::Aero,
ThemeType::Metro => fltk_theme::ThemeType::Metro,
ThemeType::AquaClassic => fltk_theme::ThemeType::AquaClassic,
ThemeType::Greybird => fltk_theme::ThemeType::Greybird,
ThemeType::Blue => fltk_theme::ThemeType::Blue,
ThemeType::Dark => fltk_theme::ThemeType::Dark,
ThemeType::HighContrast => fltk_theme::ThemeType::HighContrast,
};
let theme = fltk_theme::WidgetTheme::new(theme);
theme.apply();
}

pub fn name(&self) -> String {
format!("{self:?}")
}

pub fn to_index(&self) -> i32 {
THEME_LIST.iter().position(|th| th == self).unwrap() as i32
}

pub fn from_index(i: i32) -> Self {
let i = i.clamp(0, THEME_LIST.len() as i32 - 1) as usize;
THEME_LIST[i]
}

pub fn themes() -> &'static [ThemeType] {
&THEME_LIST
}
}

#[derive(Serialize, Deserialize, Parser, Debug, Clone)]
#[command(version, about, long_about = None)]
pub struct Config {
Expand Down Expand Up @@ -41,6 +105,8 @@ pub struct Config {
#[arg(long, help = "Start Weylus server immediately on program start.")]
#[serde(default)]
pub auto_start: bool,
#[arg(long, help = "Gui Theme")]
pub gui_theme: Option<ThemeType>,
#[arg(long, help = "Run Weylus without gui and start immediately.")]
#[serde(default)]
pub no_gui: bool,
Expand Down
72 changes: 54 additions & 18 deletions src/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::io::Cursor;
use std::iter::Iterator;
use std::net::{IpAddr, SocketAddr};

use fltk::image::PngImage;
use fltk::menu::Choice;
use std::sync::{mpsc, Arc, Mutex};
use tracing::{error, info};

Expand All @@ -20,7 +22,7 @@ use fltk::{
#[cfg(not(target_os = "windows"))]
use pnet_datalink as datalink;

use crate::config::{write_config, Config};
use crate::config::{write_config, Config, ThemeType};
use crate::web::Web2UiMessage::UInputInaccessible;

pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
Expand All @@ -29,6 +31,7 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
let padding = 10;

let app = App::default().with_scheme(fltk::app::AppScheme::Gtk);
config.gui_theme.map(|th| th.apply());
let mut wind = Window::default()
.with_size(660, 600)
.center_screen()
Expand Down Expand Up @@ -154,10 +157,19 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
output.set_buffer(output_buf);
let output_buf = output.buffer().unwrap();

let mut qr_frame = Frame::default()
.with_size(240, 240)
let mut choice_theme = Choice::default()
.with_size(width, height)
.right_of(&input_access_code, padding);

for theme in ThemeType::themes() {
choice_theme.add_choice(&theme.name());
}
choice_theme.set_value(config.gui_theme.unwrap_or(ThemeType::default()).to_index());

let mut qr_frame = Frame::default()
.with_size(235, 235)
.right_of(&input_bind_addr, padding);

qr_frame.hide();

wind.make_resizable(true);
Expand All @@ -176,10 +188,23 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
let mut weylus = crate::weylus::Weylus::new();
let mut is_server_running = false;
let auto_start = config.auto_start;
let mut config = config.clone();
let config = Arc::new(Mutex::new(config.clone()));

{
let config = config.clone();
choice_theme.set_callback(move |c| {
let v = c.value();
if v >= 0 {
ThemeType::from_index(v).apply();
config.lock().unwrap().gui_theme = Some(ThemeType::from_index(v));
write_config(&config.lock().unwrap());
}
});
}

let mut toggle_server = move |but: &mut Button| {
if let Err(err) = || -> Result<(), Box<dyn std::error::Error>> {
let mut config = config.lock().unwrap();
if !is_server_running {
{
let access_code_string = input_access_code.value();
Expand All @@ -194,6 +219,7 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
config.web_port = web_port;
config.bind_address = bind_addr;
config.auto_start = check_auto_start.is_checked();
config.gui_theme = Some(ThemeType::from_index(choice_theme.value()));
#[cfg(target_os = "linux")]
{
config.try_vaapi = check_native_hw_accel.is_checked();
Expand Down Expand Up @@ -291,20 +317,29 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
.to_string(),
);
}
let code = QrCode::new(&url_string).unwrap();
let img_buf = code.render::<Luma<u8>>().build();
let image = image::DynamicImage::ImageLuma8(img_buf);
let dims = min(qr_frame.width(), qr_frame.height()) as u32;
let image =
image.resize_exact(dims, dims, image::imageops::FilterType::Nearest);
let mut buf = vec![];
let mut cursor = Cursor::new(&mut buf);
image
.write_to(&mut cursor, image::ImageFormat::Png)
.unwrap();
let png = fltk::image::PngImage::from_data(&buf).unwrap();

qr_frame.set_image(Some(png));

let cb = move |qr_frame: &mut Frame, _, _, w, h| {
let code = QrCode::new(&url_string).unwrap();
let img_buf = code.render::<Luma<u8>>().build();
let image = image::DynamicImage::ImageLuma8(img_buf);
let dims = min(w, h) as u32;
let image =
image.resize_exact(dims, dims, image::imageops::FilterType::Nearest);
let mut buf = vec![];
let mut cursor = Cursor::new(&mut buf);
image
.write_to(&mut cursor, image::ImageFormat::Png)
.unwrap();
let png = fltk::image::PngImage::from_data(&buf).unwrap();
qr_frame.set_image(Some(png));
};

let x = qr_frame.x();
let y = qr_frame.y();
let w = qr_frame.width();
let h = qr_frame.height();
cb(&mut qr_frame, x, y, w, h);
qr_frame.resize_callback(cb);
qr_frame.show();
}
#[cfg(target_os = "windows")]
Expand All @@ -321,6 +356,7 @@ pub fn run(config: &Config, log_receiver: mpsc::Receiver<String>) {
weylus.stop();
but.set_label("Start");
output_server_addr.hide();
qr_frame.resize_callback(|_, _, _, _, _| {});
qr_frame.hide();
is_server_running = false;
}
Expand Down
8 changes: 5 additions & 3 deletions ts/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,10 +578,12 @@ class Painter {
}

onmove(event: PointerEvent) {
if (this.lines_active.has(event.pointerId))
for (const e of event.getCoalescedEvents()) {
if (this.lines_active.has(event.pointerId)) {
const events = typeof event.getCoalescedEvents === 'function' ? event.getCoalescedEvents() : [event];
for (const e of events) {
this.appendEventToLine(e);
}
}
}

onstop(event: PointerEvent) {
Expand Down Expand Up @@ -641,7 +643,7 @@ class PointerHandler {
onEvent(event: PointerEvent, event_type: string) {
if (this.pointerTypes.includes(event.pointerType)) {
let rect = (event.target as HTMLElement).getBoundingClientRect();
const events = event_type === "pointermove" ? event.getCoalescedEvents() : [event];
const events = event_type === "pointermove" && typeof event.getCoalescedEvents === 'function' ? event.getCoalescedEvents() : [event];
for (let event of events) {
this.webSocket.send(
JSON.stringify(
Expand Down

0 comments on commit a5c6be5

Please sign in to comment.