diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..26f1b69
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,46 @@
+[workspace]
+
+members = [
+ "cairo-demo",
+ "cairo_shadow_button",
+ "calendar",
+ "egui-demo",
+ "ffmpeg",
+ "flcalculator",
+ "flcsv",
+ "fldialect",
+ "flfemtovg",
+ "flglium",
+ "flglow",
+ "flimage",
+ "fllibmpv",
+ "flpixels",
+ "flplotters",
+ "flraqote",
+ "flspeedy2d",
+ "flresters",
+ "fltext",
+ "flwgpu",
+ "framebuffer",
+ "glut",
+ "glyphmap",
+ "gst",
+ "libvlc",
+ "mpv",
+ "musicplayer",
+ "opengl",
+ "rounded-svg",
+ "systray",
+ "terminal",
+ "tinyskia",
+ "web-todo",
+ "web-todo2",
+ "webview",
+ "xterm",
+]
+
+[profile.release]
+strip = true
+opt-level = "z"
+lto = true
+panic = "abort"
diff --git a/README.md b/README.md
index b112b82..e0a8705 100644
--- a/README.md
+++ b/README.md
@@ -64,38 +64,37 @@ This repository is licensed under the MIT license. You can get more information
---
The current demos include:
-- ๐โweb-todo: Creating an async web todo app using fltk, reqwest, serde and tokio.
-- ๐โweb-todo2: Creating an async web todo app using fltk, surf, serde and async-std.
-- ๐บโlibvlc: Creating a media player using fltk and the vlc crate.
-- ๐ถ musicplayer: Creating a music player using custom widgets and the soloud crate.
-- ๐จโopengl: Raw OpenGL drawing in an fltk GlWindow.
-- ๐๏ธโglut: Use the gl crate (An OpenGL function pointer loader) to do OpenGL drawing.
-- ๐๏ธ wgpu: Use wgpu-rs for gpu accelerated drawing.
-- ๐๏ธ pixels: Use the pixels crate to draw a wgpu accelerated framebuffer.
-- โ๏ธ framebuffer: Using fltk for framebuffer drawing.
-- ๐ plotters: Use plotters for live plotting (drawing animations) with fltk.
-- ๐โraqote: Use raqote for custom drawing (paint example).
-- ๐ผ๏ธโtinyskia: Use tiny-skia for custom drawing.
-- ๐ฅ๏ธ systray: Use nwg to create an fltk app with systray functionalities on Windows
-- โจโglow: Use the glow crate to do OpengGL drawing.
-- ๐ glium: Use the glium crate for OpenGL drawing.
-- ๐๏ธโcalendar: Uses the chrono crate to create an fltk calendar dialog.
-- ๐๏ธ image: Uses rust-embed and the image crates to load images into fltk.
-- ๐ speedy2d: Uses speedy2D crate to do 2D drawings of a circle and an RGB image in a GlWindow.
-- ๐ช femtovg: Uses femtovg for 2D drawing in a GlWindow.
-- ๐ฝ๏ธ ffmpeg: Uses ffmpeg for software video rendering.
-- ๐ป webview: Embeds a webview inside an fltk app.
-- ๐๏ธโcsv: Uses serde and csv to perform custom drawing of data.
-- ๐ rounded-svg: Use the svg crate along with fltk to create images with rounded borders.
-- ๐ฆโlibmpv: use libmpv to play a video inside an fltk GlWindow.
-- โ๐งฅโmpv: mpv: Use mpv (the command line app) to play a video inside an fltk window.
-- ๐ฒโxterm: embed an xterm window inside an fltk window.
-- ๐๏ธ egui-demo: Use fltk as a backend for egui
-- ๐๏ธ gst: Use libgstreamer to play a video inside an fltk window
-- ๐๏ธ cairo-demo: Use cairo for custom drawing inside fltk widgets
-- ๐โglyphmap: Maps glyphs (specifically font icons) to their unicode codepoint.
+* [๐โ web-todo:]("#web-todo") Creating an async web todo app using fltk, reqwest, serde and tokio.
+* [๐โ web-todo2:](#web-todo2) Creating an async web todo app using fltk, surf, serde and async-std.
+* [๐บโ libvlc:](#libvlc)" Creating a media player using fltk and the vlc crate.
+* [๐ถ musicplayer:](#musicplayer) Creating a music player using custom widgets and the soloud crate.
+* [๐จโ opengl:](#opengl) Raw OpenGL drawing in an fltk GlWindow.
+* [๐๏ธโ glut:](#glut) Use the gl crate (An OpenGL function pointer loader) to do OpenGL drawing.
+* [๐๏ธ flwgpu:](#flwgpu) Use wgpu-rs for gpu accelerated drawing.
+* [๐๏ธ flpixels:](#flpixels) Use the pixels crate to draw a wgpu accelerated framebuffer.
+* [โ๏ธ framebuffer:](#framebuffer) Using fltk for framebuffer drawing.
+* [๐ flplotters:](#flplotters) Use plotters for live plotting (drawing animations) with fltk.
+* [๐โ flraqote:](#flraqote) Use raqote for custom drawing (paint example).
+* [๐ผ๏ธโ tinyskia:](#tinyskia) Use tiny-skia for custom drawing.
+* [๐ฅ๏ธ systray:](#systray) Use nwg to create an fltk app with systray functionalities on Windows
+* [โจ flโglow:](#flglow) Use the glow crate to do OpengGL drawing.
+* [๐ flglium:](#flglium) Use the glium crate for OpenGL drawing.
+* [๐๏ธโ calendar:](#calendar) Uses the chrono crate to create an fltk calendar dialog.
+* [๐๏ธ flimage:](#flimage) Uses rust-embed and the image crates to load images into fltk.
+* [๐ flspeedy2d:](#flspeedy2d) Uses speedy2D crate to do 2D drawings of a circle and an RGB image in a GlWindow.
+* [๐ช flfemtovg:](#flfemtovg) Uses femtovg for 2D drawing in a GlWindow.
+* [๐ฝ๏ธ ffmpeg:](#ffmpeg) Uses ffmpeg for software video rendering.
+* [๐ป webview:](#webview) Embeds a webview inside an fltk app.
+* [๐๏ธโ flcsv:](#flcsv) Uses serde and csv to perform custom drawing of data.
+* [๐ rounded-svg:](#rounded-svg) Use the svg crate along with fltk to create images with rounded borders.
+* [๐ฆโ fllibmpv:](#libmpv) use libmpv to play a video inside an fltk GlWindow.
+* [โ๐งฅโ mpv:](#mpv) Use mpv (the command line app) to play a video inside an fltk window.
+* [๐ฒโxterm:](#xterm) embed an xterm window inside an fltk window.
+* [๐๏ธ egui-demo:](#egui-demo) Use fltk as a backend for egui
+* [๐๏ธ gst:](#gst) Use libgstreamer to play a video inside an fltk window
+* [๐๏ธ cairo-demo:](#cairo-demo) Use cairo for custom drawing inside fltk widgets
+* [๐โglyphmap:](#glyphmap) Maps glyphs (specifically font icons) to their unicode codepoint.
- ๐ terminal: A minimal terminal emulator.
-
---
@@ -195,4 +194,4 @@ The current demos include:
![cairo](cairo_shadow_button/ex1.jpg)
-
\ No newline at end of file
+
diff --git a/cairo-demo/Cargo.toml b/cairo-demo/Cargo.toml
index 1395397..2aa6e90 100644
--- a/cairo-demo/Cargo.toml
+++ b/cairo-demo/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "1.4.9", features = ["cairoext"] }
+fltk = { version = "^1.4", features = ["cairoext"] }
cairo-rs = "0.18"
diff --git a/cairo_shadow_button/Cargo.toml b/cairo_shadow_button/Cargo.toml
index 3c086b5..86d04ed 100644
--- a/cairo_shadow_button/Cargo.toml
+++ b/cairo_shadow_button/Cargo.toml
@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-fltk = "1.4"
+fltk = "^1.4"
cairo-rs = "0.18"
-cairo-blur = "0.1.0"
\ No newline at end of file
+cairo-blur = "0.1.0"
diff --git a/calendar/Cargo.toml b/calendar/Cargo.toml
index 84c9244..b12f6ea 100644
--- a/calendar/Cargo.toml
+++ b/calendar/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
-chrono = "0.4"
\ No newline at end of file
+fltk = "^1.4"
+chrono = "0.4"
diff --git a/calendar/src/calendar.rs b/calendar/src/calendar.rs
index 6e69183..c6e0ac7 100644
--- a/calendar/src/calendar.rs
+++ b/calendar/src/calendar.rs
@@ -1,7 +1,4 @@
-use chrono::DateTime;
-use chrono::Datelike;
-use chrono::Local;
-use chrono::NaiveDate;
+use chrono::{DateTime, Datelike, Local, NaiveDate};
use fltk::{app, draw, enums::*, menu, prelude::*, table, window};
use std::{cell::RefCell, rc::Rc};
@@ -93,14 +90,14 @@ impl Calendar {
_ => (),
});
- let curr_rc = curr.clone();
+ let curr_rc = curr;
// redraw table when the month changes
month_choice.set_callback(move |c| {
*curr_rc.borrow_mut() = c.value() + 1;
c.parent().unwrap().redraw();
});
- let curr_year_rc = curr_year.clone();
+ let curr_year_rc = curr_year;
// redraw table when the year changes
year_choice.set_callback(move |c| {
*curr_year_rc.borrow_mut() = c.value() + 1900;
diff --git a/egui-demo/src/main.rs b/egui-demo/src/main.rs
index acfa0f7..4ef0d8a 100644
--- a/egui-demo/src/main.rs
+++ b/egui-demo/src/main.rs
@@ -4,8 +4,7 @@ use egui_backend::{
gl, DpiScaling,
};
use fltk_egui as egui_backend;
-use std::rc::Rc;
-use std::{cell::RefCell, time::Instant};
+use std::{cell::RefCell, rc::Rc, time::Instant};
const SCREEN_WIDTH: u32 = 800;
const SCREEN_HEIGHT: u32 = 600;
@@ -31,7 +30,7 @@ fn main() {
slider.set_slider_size(0.20);
slider.set_color(Color::Blue.inactive());
slider.set_selection_color(Color::Red);
- col.set_size(&mut slider, 20);
+ col.fixed(&slider, 20);
col.end();
main_win.end();
main_win.make_resizable(true);
@@ -111,7 +110,7 @@ fn main() {
let paint_jobs = egui_ctx.tessellate(paint_cmds);
//Draw egui texture
- painter.paint_jobs(None, paint_jobs, &egui_ctx.texture());
+ painter.paint_jobs(None, paint_jobs, &egui_ctx.font_image());
glut_win.swap_buffers();
glut_win.flush();
diff --git a/ffmpeg/Cargo.toml b/ffmpeg/Cargo.toml
index 3ac1607..e6d5d50 100644
--- a/ffmpeg/Cargo.toml
+++ b/ffmpeg/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
signal-hook = "0.3"
lazy_static = "1.4"
diff --git a/csv/Cargo.toml b/flcsv/Cargo.toml
similarity index 89%
rename from csv/Cargo.toml
rename to flcsv/Cargo.toml
index 1a1c4e3..0d38aa2 100644
--- a/csv/Cargo.toml
+++ b/flcsv/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "csv"
+name = "flcsv"
version = "0.1.0"
authors = ["MoAlyousef "]
edition = "2021"
@@ -7,8 +7,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
csv = "1.1.6"
serde = { version = "1", features = ["derive"] }
lazy_static = "1.4"
-image = { version = "0.24.5", default-features = false, features = ["jpeg"] }
\ No newline at end of file
+image = { version = "0.24.5", default-features = false, features = ["jpeg"] }
diff --git a/csv/README.md b/flcsv/README.md
similarity index 100%
rename from csv/README.md
rename to flcsv/README.md
diff --git a/csv/csv.gif b/flcsv/csv.gif
similarity index 100%
rename from csv/csv.gif
rename to flcsv/csv.gif
diff --git a/csv/ex.jpg b/flcsv/ex.jpg
similarity index 100%
rename from csv/ex.jpg
rename to flcsv/ex.jpg
diff --git a/csv/historical_data/GME.csv b/flcsv/historical_data/GME.csv
similarity index 100%
rename from csv/historical_data/GME.csv
rename to flcsv/historical_data/GME.csv
diff --git a/csv/historical_data/dlpn.csv b/flcsv/historical_data/dlpn.csv
similarity index 100%
rename from csv/historical_data/dlpn.csv
rename to flcsv/historical_data/dlpn.csv
diff --git a/csv/historical_data/oil.csv b/flcsv/historical_data/oil.csv
similarity index 100%
rename from csv/historical_data/oil.csv
rename to flcsv/historical_data/oil.csv
diff --git a/flcsv/image.jpg b/flcsv/image.jpg
new file mode 100644
index 0000000..7892e61
Binary files /dev/null and b/flcsv/image.jpg differ
diff --git a/csv/src/main.rs b/flcsv/src/main.rs
similarity index 95%
rename from csv/src/main.rs
rename to flcsv/src/main.rs
index fdc5f4b..f9ce504 100644
--- a/csv/src/main.rs
+++ b/flcsv/src/main.rs
@@ -8,8 +8,6 @@ extern crate lazy_static;
#[derive(Debug, Deserialize)]
pub struct Price {
- #[serde(rename = "Date")]
- date: String,
#[serde(rename = "Open")]
open: f64,
#[serde(rename = "High")]
@@ -18,8 +16,6 @@ pub struct Price {
low: f64,
#[serde(rename = "Close")]
close: f64,
- #[serde(rename = "Volume")]
- volume: usize,
}
lazy_static! {
@@ -50,7 +46,7 @@ fn main() {
for file in files {
let entry = file.unwrap().file_name().into_string().unwrap();
if entry.ends_with(".csv") {
- browser.add(&entry.strip_suffix(".csv").unwrap());
+ browser.add(entry.strip_suffix(".csv").unwrap());
}
}
@@ -65,7 +61,7 @@ fn main() {
.collect::>()
.iter()
.cloned()
- .fold(0. / 0., f64::max);
+ .fold(f64::NAN, f64::max);
highest += (highest.to_string().len() * 10) as f64 / 3.;
let factor = f.h() as f64 / highest;
if data.len() != 0 {
diff --git a/femtovg/Cargo.toml b/flfemtovg/Cargo.toml
similarity index 74%
rename from femtovg/Cargo.toml
rename to flfemtovg/Cargo.toml
index 834af3e..7cdc483 100644
--- a/femtovg/Cargo.toml
+++ b/flfemtovg/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "femtovg"
+name = "flfemtovg"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "1", features = ["enable-glwindow"] }
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
femtovg = "0.1.1"
diff --git a/femtovg/README.md b/flfemtovg/README.md
similarity index 100%
rename from femtovg/README.md
rename to flfemtovg/README.md
diff --git a/femtovg/ex.png b/flfemtovg/ex.png
similarity index 100%
rename from femtovg/ex.png
rename to flfemtovg/ex.png
diff --git a/femtovg/femtovg.gif b/flfemtovg/femtovg.gif
similarity index 100%
rename from femtovg/femtovg.gif
rename to flfemtovg/femtovg.gif
diff --git a/femtovg/src/main.rs b/flfemtovg/src/main.rs
similarity index 100%
rename from femtovg/src/main.rs
rename to flfemtovg/src/main.rs
diff --git a/glium/Cargo.toml b/flglium/Cargo.toml
similarity index 79%
rename from glium/Cargo.toml
rename to flglium/Cargo.toml
index a68dde2..0264e49 100644
--- a/glium/Cargo.toml
+++ b/flglium/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "glium"
+name = "flglium"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -8,4 +8,4 @@ edition = "2021"
[dependencies]
glium = { version = "0.29", default-features = false } # no need for glutin
-fltk = { version = "1", features = ["enable-glwindow"] }
\ No newline at end of file
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
diff --git a/glium/README.md b/flglium/README.md
similarity index 100%
rename from glium/README.md
rename to flglium/README.md
diff --git a/glium/ex.jpg b/flglium/ex.jpg
similarity index 100%
rename from glium/ex.jpg
rename to flglium/ex.jpg
diff --git a/glium/glium.gif b/flglium/glium.gif
similarity index 100%
rename from glium/glium.gif
rename to flglium/glium.gif
diff --git a/glium/src/main.rs b/flglium/src/main.rs
similarity index 100%
rename from glium/src/main.rs
rename to flglium/src/main.rs
diff --git a/glow/Cargo.toml b/flglow/Cargo.toml
similarity index 69%
rename from glow/Cargo.toml
rename to flglow/Cargo.toml
index 975092e..959104d 100644
--- a/glow/Cargo.toml
+++ b/flglow/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "glow"
+name = "flglow"
version = "0.1.0"
authors = ["MoAlyousef "]
edition = "2021"
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "1", features = ["enable-glwindow"] }
-glow = "0.7"
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
+glow = "^0.13"
diff --git a/glow/README.md b/flglow/README.md
similarity index 100%
rename from glow/README.md
rename to flglow/README.md
diff --git a/glow/ex.jpg b/flglow/ex.jpg
similarity index 100%
rename from glow/ex.jpg
rename to flglow/ex.jpg
diff --git a/glow/glow.gif b/flglow/glow.gif
similarity index 100%
rename from glow/glow.gif
rename to flglow/glow.gif
diff --git a/glow/src/main.rs b/flglow/src/main.rs
similarity index 100%
rename from glow/src/main.rs
rename to flglow/src/main.rs
diff --git a/image/Cargo.toml b/flimage/Cargo.toml
similarity index 88%
rename from image/Cargo.toml
rename to flimage/Cargo.toml
index 96257d0..d42e66d 100644
--- a/image/Cargo.toml
+++ b/flimage/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "image"
+name = "flimage"
version = "0.1.0"
authors = ["MoAlyousef "]
edition = "2021"
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
image = "0.24"
rust-embed = "6.6.1"
diff --git a/image/README.md b/flimage/README.md
similarity index 100%
rename from image/README.md
rename to flimage/README.md
diff --git a/image/fltk.png b/flimage/fltk.png
similarity index 100%
rename from image/fltk.png
rename to flimage/fltk.png
diff --git a/image/src/main.rs b/flimage/src/main.rs
similarity index 100%
rename from image/src/main.rs
rename to flimage/src/main.rs
diff --git a/libmpv/Cargo.toml b/fllibmpv/Cargo.toml
similarity index 76%
rename from libmpv/Cargo.toml
rename to fllibmpv/Cargo.toml
index ff53c8f..6e23437 100644
--- a/libmpv/Cargo.toml
+++ b/fllibmpv/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "libmpv"
+name = "fllibmpv"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = {version = "1.1", features=["enable-glwindow", "no-pango"]}
+fltk = {version = "^1.4", features=["enable-glwindow", "no-pango"]}
libmpv = { git = "https://github.com/anlumo/libmpv-rs" }
diff --git a/libmpv/README.md b/fllibmpv/README.md
similarity index 100%
rename from libmpv/README.md
rename to fllibmpv/README.md
diff --git a/libmpv/src/main.rs b/fllibmpv/src/main.rs
similarity index 98%
rename from libmpv/src/main.rs
rename to fllibmpv/src/main.rs
index 3a8a5f4..986b592 100644
--- a/libmpv/src/main.rs
+++ b/fllibmpv/src/main.rs
@@ -60,7 +60,7 @@ fn main() {
w.swap_buffers();
});
- app::add_idle(move || {
+ app::add_idle3(move |_| {
mpv_win.redraw();
});
diff --git a/libmpv/src/sys_main.rs b/fllibmpv/src/sys_main.rs
similarity index 100%
rename from libmpv/src/sys_main.rs
rename to fllibmpv/src/sys_main.rs
diff --git a/pixels/Cargo.toml b/flpixels/Cargo.toml
similarity index 70%
rename from pixels/Cargo.toml
rename to flpixels/Cargo.toml
index 93aa68b..3b47564 100644
--- a/pixels/Cargo.toml
+++ b/flpixels/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "pixels"
+name = "flpixels"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -8,5 +8,5 @@ resolver = "2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "^1", features = ["raw-window-handle"] }
-pixels = "0.9.0"
+fltk = { version = "^1.4", features = ["raw-window-handle"] }
+pixels = "^0.13"
diff --git a/pixels/README.md b/flpixels/README.md
similarity index 100%
rename from pixels/README.md
rename to flpixels/README.md
diff --git a/pixels/build.rs b/flpixels/build.rs
similarity index 100%
rename from pixels/build.rs
rename to flpixels/build.rs
diff --git a/pixels/ex.jpg b/flpixels/ex.jpg
similarity index 100%
rename from pixels/ex.jpg
rename to flpixels/ex.jpg
diff --git a/pixels/pixels.gif b/flpixels/pixels.gif
similarity index 100%
rename from pixels/pixels.gif
rename to flpixels/pixels.gif
diff --git a/pixels/src/main.rs b/flpixels/src/main.rs
similarity index 100%
rename from pixels/src/main.rs
rename to flpixels/src/main.rs
diff --git a/plotters/Cargo.toml b/flplotters/Cargo.toml
similarity index 88%
rename from plotters/Cargo.toml
rename to flplotters/Cargo.toml
index be98153..b8934c8 100644
--- a/plotters/Cargo.toml
+++ b/flplotters/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "plotters"
+name = "flplotters"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
plotters = "0.3.0"
plotters-bitmap = "0.3.0"
diff --git a/plotters/README.md b/flplotters/README.md
similarity index 100%
rename from plotters/README.md
rename to flplotters/README.md
diff --git a/plotters/ex.jpg b/flplotters/ex.jpg
similarity index 100%
rename from plotters/ex.jpg
rename to flplotters/ex.jpg
diff --git a/plotters/plotters.gif b/flplotters/plotters.gif
similarity index 100%
rename from plotters/plotters.gif
rename to flplotters/plotters.gif
diff --git a/plotters/src/main.rs b/flplotters/src/main.rs
similarity index 100%
rename from plotters/src/main.rs
rename to flplotters/src/main.rs
diff --git a/raqote/Cargo.toml b/flraqote/Cargo.toml
similarity index 82%
rename from raqote/Cargo.toml
rename to flraqote/Cargo.toml
index 350c83c..2b9981f 100644
--- a/raqote/Cargo.toml
+++ b/flraqote/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "raqote"
+name = "flraqote"
version = "0.1.0"
authors = ["Mohammed Alyousef "]
edition = "2021"
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
-raqote = "0.8"
\ No newline at end of file
+fltk = "^1.4"
+raqote = "0.8"
diff --git a/raqote/README.md b/flraqote/README.md
similarity index 100%
rename from raqote/README.md
rename to flraqote/README.md
diff --git a/raqote/ex.jpg b/flraqote/ex.jpg
similarity index 100%
rename from raqote/ex.jpg
rename to flraqote/ex.jpg
diff --git a/raqote/raqote.gif b/flraqote/raqote.gif
similarity index 100%
rename from raqote/raqote.gif
rename to flraqote/raqote.gif
diff --git a/raqote/src/main.rs b/flraqote/src/main.rs
similarity index 97%
rename from raqote/src/main.rs
rename to flraqote/src/main.rs
index 89d5d95..17e406f 100644
--- a/raqote/src/main.rs
+++ b/flraqote/src/main.rs
@@ -1,4 +1,3 @@
-use fltk::prelude::WindowExt;
use fltk::{
app, draw, enums, frame,
prelude::{GroupExt, WidgetBase, WidgetExt},
@@ -92,6 +91,5 @@ pub fn draw_line(x: i32, y: i32, x2: i32, y2: i32) -> Path {
let mut pb = PathBuilder::new();
pb.move_to(x as f32, y as f32);
pb.line_to(x2 as f32, y2 as f32);
- let path = pb.finish();
- path
+ pb.finish()
}
diff --git a/speedy2d/Cargo.toml b/flspeedy2d/Cargo.toml
similarity index 83%
rename from speedy2d/Cargo.toml
rename to flspeedy2d/Cargo.toml
index d41e6b1..5e288aa 100644
--- a/speedy2d/Cargo.toml
+++ b/flspeedy2d/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "1", features = ["enable-glwindow"] }
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
speedy2d = { version = "1.0.2", default-features = false }
gl = "0.14"
diff --git a/speedy2d/README.md b/flspeedy2d/README.md
similarity index 100%
rename from speedy2d/README.md
rename to flspeedy2d/README.md
diff --git a/speedy2d/ex.jpg b/flspeedy2d/ex.jpg
similarity index 100%
rename from speedy2d/ex.jpg
rename to flspeedy2d/ex.jpg
diff --git a/speedy2d/speedy2d.gif b/flspeedy2d/speedy2d.gif
similarity index 100%
rename from speedy2d/speedy2d.gif
rename to flspeedy2d/speedy2d.gif
diff --git a/speedy2d/src/main.rs b/flspeedy2d/src/main.rs
similarity index 100%
rename from speedy2d/src/main.rs
rename to flspeedy2d/src/main.rs
diff --git a/fltext/Cargo.toml b/fltext/Cargo.toml
new file mode 100644
index 0000000..05a1613
--- /dev/null
+++ b/fltext/Cargo.toml
@@ -0,0 +1,33 @@
+[package]
+name = "fltext"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+fltk = "^1.4"
+fltk-theme = "0.7"
+regex = "1.9.6"
+notify = "5.1"
+# optional deps
+# term
+fltk-term = { version = "0.1", optional = true }
+# highlight
+tree-sitter-highlight = { version = "0.20", optional = true }
+tree-sitter-rust = { version = "0.20", optional = true }
+tree-sitter-toml = { version = "0.20", optional = true }
+tree-sitter-md = { version = "0.1", optional = true }
+
+[features]
+default = ["highlight", "term"]
+highlight = [
+ "tree-sitter-highlight",
+ "tree-sitter-rust",
+ "tree-sitter-toml",
+ "tree-sitter-md",
+ ]
+term = [
+ "fltk-term"
+]
+
+[patch.crates-io]
+fltk = { git = "https://github.com/fltk-rs/fltk-rs" }
diff --git a/fltext/LICENSE b/fltext/LICENSE
new file mode 100644
index 0000000..93a4574
--- /dev/null
+++ b/fltext/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Mohammed Alyousef
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/fltext/README.md b/fltext/README.md
new file mode 100644
index 0000000..1bcf9b9
--- /dev/null
+++ b/fltext/README.md
@@ -0,0 +1,34 @@
+# red
+
+red or the RustyEditor is a lightweight and minimal text editor which supports multiple-tabs (ร la vscode) and which integrates a file browser and a terminal. The editor component supports syntax highlighting via [tree-sitter-highlight](https://github.com/tree-sitter/tree-sitter/tree/master/highlight).
+
+## Building
+```bash
+git clone https://github.com/MoAlyousef/red
+cd red
+cargo build --release
+```
+
+To disable building with tree-sitter and the terminal:
+```bash
+cargo build --no-default-features --release
+```
+
+To build with native wayland support on Linux:
+```bash
+cargo build --features=fltk/use-wayland --release
+```
+
+![image](https://github.com/MoAlyousef/red/assets/37966791/c43a180f-d1db-4528-ace6-d3713dcda202)
+
+## Known issues
+- If you're running KDE and no icons appear in the FileBrowser, you can try setting the KDEDIR to /usr/local.
+- Highlighting via tree-sitter seems to vary between different language modules. tree-sitter-json seems quite limited for example.
+
+## ToDo
+- Add a settings dialog.
+- Save and get user settings using fltk [Preferences](https://docs.rs/fltk/latest/fltk/app/prefs/struct.Preferences.html).
+- Enable using FLTK's FileChooser instead of the system provided one via the settings.
+- Add more options to FileBrowser popup menu and the terminal menu.
+- Support user provided color schemes for the app and the highlighting.
+- Support regex for search & replace.
diff --git a/fltext/src/cbs.rs b/fltext/src/cbs.rs
new file mode 100644
index 0000000..1dec330
--- /dev/null
+++ b/fltext/src/cbs.rs
@@ -0,0 +1,222 @@
+use crate::state::STATE;
+use fltk::{enums::*, prelude::*, *};
+use std::{fs, path::PathBuf};
+
+fn nfc_get_file(mode: dialog::NativeFileChooserType) -> PathBuf {
+ let mut nfc = dialog::NativeFileChooser::new(mode);
+ nfc.show();
+ nfc.filename()
+}
+
+fn find() {
+ let mut dlg: window::Window = app::widget_from_id("find").unwrap();
+ let main_win = app::first_window().unwrap();
+ dlg.resize(main_win.x() + main_win.w() - 300, dlg.y() + 30, 300, 50);
+ dlg.show();
+}
+
+fn replace() {
+ let mut dlg: window::Window = app::widget_from_id("replace").unwrap();
+ let main_win = app::first_window().unwrap();
+ dlg.resize(main_win.x() + main_win.w() - 300, dlg.y() + 30, 300, 80);
+ dlg.show();
+}
+
+pub fn win_cb(_: &mut window::Window) {
+ if app::event() == Event::Close {
+ app::quit();
+ }
+}
+
+pub fn editor_cb(_e: &mut text::TextEditor) {
+ app::add_timeout3(0.01, |_| STATE.with(|s| s.was_modified(true)));
+}
+
+pub fn new_file() {
+ let dlg = dialog::input_default("Enter file name", "");
+ if let Some(f) = dlg {
+ fs::File::create(f).ok();
+ }
+}
+
+pub fn new_dir() {
+ let dlg = dialog::input_default("Enter directory name", "");
+ if let Some(f) = dlg {
+ fs::create_dir(f).ok();
+ }
+}
+
+pub fn menu_cb(m: &mut impl MenuExt) {
+ if let Ok(mpath) = m.item_pathname(None) {
+ match mpath.as_str() {
+ "&File/New File...\t" => {
+ new_file();
+ }
+ "&File/New Dir...\t" => {
+ new_dir();
+ }
+ "&File/Open...\t" => {
+ let c = nfc_get_file(dialog::NativeFileChooserType::BrowseFile);
+ if c.exists() {
+ STATE.with(move |s| {
+ s.append(Some(c.canonicalize().unwrap()));
+ });
+ }
+ }
+ "&File/Save\t" => {
+ STATE.with(|s| {
+ if let Some(id) = s.current_id() {
+ let e = s.map.get(&id).unwrap();
+ let modified = e.modified;
+ if let Some(current_file) = e.current_file.as_ref() {
+ if modified && current_file.exists() {
+ fs::write(current_file, e.buf.text()).ok();
+ s.was_modified(false);
+ }
+ }
+ }
+ });
+ }
+ "&File/Save as...\t" => {
+ let c = nfc_get_file(dialog::NativeFileChooserType::BrowseSaveFile);
+ if c.exists() {
+ STATE.with(move |s| {
+ if let Some(buf) = s.buf().as_ref() {
+ fs::write(&c, buf.text()).expect("Failed to write to file!");
+ s.was_modified(false);
+ }
+ });
+ }
+ }
+ "&File/Save All\t" => {
+ STATE.with(|s| {
+ for v in s.map.values_mut() {
+ if v.modified && v.current_file.as_ref().unwrap().exists() {
+ fs::write(v.current_file.as_ref().unwrap(), v.buf.text()).ok();
+ v.modified = true;
+ }
+ }
+ });
+ }
+ "&File/Quit\t" => app::quit(),
+ "/Undo\t" | "&Edit/Undo\t" => STATE.with(|s| {
+ if let Some(e) = s.current_editor() {
+ e.undo()
+ }
+ }),
+ "/Redo\t" | "&Edit/Redo\t" => STATE.with(|s| {
+ if let Some(e) = s.current_editor() {
+ e.redo()
+ }
+ }),
+ "/Cut\t" | "&Edit/Cut\t" => STATE.with(|s| {
+ if let Some(e) = s.current_editor() {
+ e.cut()
+ }
+ }),
+ "/Copy\t" | "&Edit/Copy\t" => STATE.with(|s| {
+ if let Some(e) = s.current_editor() {
+ e.copy()
+ }
+ }),
+ "/Paste\t" | "&Edit/Paste\t" => STATE.with(|s| {
+ if let Some(e) = s.current_editor() {
+ e.paste()
+ }
+ }),
+ "/Find\t" | "&Edit/Find\t" => find(),
+ "/Replace\t" | "&Edit/Replace\t" => replace(),
+ "&View/File browser\t" => {
+ let mut item = m.at(m.value()).unwrap();
+ let fbr: group::Group = app::widget_from_id("fbr_group").unwrap();
+ let mut parent = group::Flex::from_dyn_widget(&fbr.parent().unwrap()).unwrap();
+ if !item.value() {
+ parent.fixed(&fbr, 1);
+ item.clear();
+ } else {
+ parent.fixed(&fbr, 180);
+ item.set();
+ }
+ app::redraw();
+ }
+ "&View/Terminal\t" => {
+ let mut item = m.at(m.value()).unwrap();
+ let term: group::Group = app::widget_from_id("term_group").unwrap();
+ let mut parent = group::Flex::from_dyn_widget(&term.parent().unwrap()).unwrap();
+ if !item.value() {
+ parent.fixed(&term, 1);
+ item.clear();
+ } else {
+ parent.fixed(&term, 160);
+ item.set();
+ }
+ app::redraw();
+ }
+ "&Help/About\t" => {
+ dialog::message_title("About");
+ dialog::message_default("A minimal text editor written using fltk-rs!")
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+
+pub fn tab_close_cb(g: &mut impl GroupExt) {
+ if app::callback_reason() == CallbackReason::Closed {
+ let ed = text::TextEditor::from_dyn_widget(&g.child(0).unwrap()).unwrap();
+ let edid = ed.as_widget_ptr() as usize;
+ let buf = ed.buffer().unwrap();
+ let mut parent = g.parent().unwrap();
+ parent.remove(g);
+ unsafe {
+ text::TextBuffer::delete(buf);
+ }
+ STATE.with(move |s| s.map.remove(&edid));
+ parent.set_damage(true);
+ }
+}
+
+#[cfg(feature = "term")]
+pub fn tab_splitter_cb(f: &mut frame::Frame, ev: Event) -> bool {
+ let mut parent = group::Flex::from_dyn_widget(&f.parent().unwrap()).unwrap();
+ let term = app::widget_from_id::("term_group").unwrap();
+ match ev {
+ Event::Push => true,
+ Event::Drag => {
+ parent.fixed(&term, parent.h() + parent.y() - app::event_y());
+ app::redraw();
+ true
+ }
+ Event::Enter => {
+ f.window().unwrap().set_cursor(Cursor::NS);
+ true
+ }
+ Event::Leave => {
+ f.window().unwrap().set_cursor(Cursor::Arrow);
+ true
+ }
+ _ => false,
+ }
+}
+
+pub fn fbr_splitter_cb(f: &mut frame::Frame, ev: Event) -> bool {
+ let mut parent = group::Flex::from_dyn_widget(&f.parent().unwrap()).unwrap();
+ let fbr: group::Group = app::widget_from_id("fbr_group").unwrap();
+ match ev {
+ Event::Push => true,
+ Event::Drag => {
+ parent.fixed(&fbr, app::event_x());
+ app::redraw();
+ true
+ }
+ Event::Enter => {
+ f.window().unwrap().set_cursor(Cursor::WE);
+ true
+ }
+ Event::Leave => {
+ f.window().unwrap().set_cursor(Cursor::Arrow);
+ true
+ }
+ _ => false,
+ }
+}
diff --git a/fltext/src/dialogs.rs b/fltext/src/dialogs.rs
new file mode 100644
index 0000000..7608bf1
--- /dev/null
+++ b/fltext/src/dialogs.rs
@@ -0,0 +1,199 @@
+#![allow(dead_code)]
+
+use crate::state::STATE;
+use fltk::{prelude::*, *};
+use std::cell::RefCell;
+use std::rc::Rc;
+
+pub struct FindDialog {
+ win: window::Window,
+}
+
+impl FindDialog {
+ pub fn new() -> Self {
+ let idx = Rc::from(RefCell::from(0));
+ let mut win = window::Window::new(0, 0, 300, 50, "Find").with_id("find");
+ win.set_border(false);
+ let mut row = group::Flex::default_fill();
+ row.set_margin(10);
+ let f = frame::Frame::default().with_label("Find:");
+ row.fixed(&f, 30);
+ let mut i = input::Input::default();
+ i.set_trigger(enums::CallbackTrigger::EnterKeyAlways);
+ let mut reg = button::ToggleButton::default().with_label(".*");
+ reg.set_selection_color(reg.color().lighter());
+ reg.set_tooltip("Use regex");
+ row.fixed(®, 30);
+ let mut b = button::Button::default().with_label("Next");
+ i.set_callback({
+ move |i| {
+ let val = i.value();
+ let reg_val = reg.value();
+ if reg_val && regex::Regex::new(&val).is_err() {
+ i.set_text_color(enums::Color::Red);
+ return;
+ } else {
+ i.set_text_color(enums::Color::Foreground);
+ }
+ if !val.is_empty() {
+ STATE.with({
+ let idx = idx.clone();
+ move |s| {
+ if let Some(buf) = s.buf().as_mut() {
+ let text = buf.text();
+ if reg_val {
+ if let Ok(re) = regex::Regex::new(&val) {
+ let v: Vec<_> =
+ re.find_iter(&text).map(|m| m.range()).collect();
+ if !v.is_empty() {
+ let mut idx = idx.borrow_mut();
+ let curr = &v[*idx];
+ let mut ed: text::TextEditor =
+ s.current_editor().unwrap();
+ buf.select(curr.start as i32, curr.end as i32);
+ ed.scroll(
+ ed.count_lines(0, curr.start as i32, true),
+ 0,
+ );
+ *idx += 1;
+ if *idx == v.len() {
+ *idx = 0;
+ }
+ }
+ }
+ } else {
+ let v: Vec<_> = text.match_indices(&val).collect();
+ if !v.is_empty() {
+ let mut idx = idx.borrow_mut();
+ let curr = v[*idx];
+ let mut ed: text::TextEditor = s.current_editor().unwrap();
+ buf.select(curr.0 as i32, (curr.0 + val.len()) as i32);
+ ed.scroll(ed.count_lines(0, curr.0 as i32, true), 0);
+ *idx += 1;
+ if *idx == v.len() {
+ *idx = 0;
+ }
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+ });
+ b.set_callback(move |_| i.do_callback());
+ row.fixed(&b, 60);
+ row.end();
+ win.end();
+ win.handle(|win, ev| match ev {
+ enums::Event::Hide => {
+ win.hide();
+ true
+ }
+ enums::Event::Close => {
+ win.hide();
+ true
+ }
+ _ => false,
+ });
+ Self { win }
+ }
+}
+
+pub struct ReplaceDialog {
+ win: window::Window,
+}
+
+impl ReplaceDialog {
+ pub fn new() -> Self {
+ let mut win = window::Window::new(0, 0, 300, 80, "Replace").with_id("replace");
+ win.set_border(false);
+ let mut col = group::Flex::default_fill().column();
+ col.set_margin(5);
+ let mut row = group::Flex::default();
+ let f = frame::Frame::default().with_label("Search:");
+ row.fixed(&f, 60);
+ let mut search = input::Input::default();
+ search.set_trigger(enums::CallbackTrigger::Changed);
+ let mut reg = button::ToggleButton::default().with_label(".*");
+ reg.set_selection_color(reg.color().lighter());
+ reg.set_tooltip("Use regex");
+ row.fixed(®, 30);
+ row.end();
+ let mut row = group::Flex::default();
+ let f = frame::Frame::default().with_label("Replace:");
+ row.fixed(&f, 60);
+ let replace = input::Input::default();
+ let mut b = button::Button::default().with_label("@>");
+ b.set_tooltip("Apply");
+ row.fixed(&b, 30);
+ row.end();
+ col.end();
+ win.end();
+ search.set_callback({
+ let reg = reg.clone();
+ move |i| {
+ let val = i.value();
+ let reg_val = reg.value();
+ if reg_val && regex::Regex::new(&val).is_err() {
+ i.set_text_color(enums::Color::Red);
+ } else {
+ i.set_text_color(enums::Color::Foreground);
+ }
+ }
+ });
+ b.set_callback(move |_| {
+ let search = search.value();
+ let replace = replace.value();
+ let reg_val = reg.value();
+ if reg_val && regex::Regex::new(&search).is_err() {
+ return;
+ }
+ STATE.with({
+ move |s| {
+ if let Some(buf) = s.buf().as_mut() {
+ let text = buf.text();
+ if reg_val {
+ if let Ok(re) = regex::Regex::new(&search) {
+ let ntext = re.replace(&text, &replace);
+ buf.set_text(&ntext);
+ }
+ } else {
+ let ntext = text.replace(&search, &replace);
+ buf.set_text(&ntext);
+ }
+ s.was_modified(true);
+ }
+ }
+ });
+ });
+ win.handle(|win, ev| match ev {
+ enums::Event::Hide => {
+ win.hide();
+ true
+ }
+ enums::Event::Close => {
+ win.hide();
+ true
+ }
+ _ => false,
+ });
+ Self { win }
+ }
+}
+
+pub struct ImageDialog {
+ win: window::Window,
+}
+
+impl ImageDialog {
+ pub fn new() -> Self {
+ let mut win = window::Window::default()
+ .with_size(400, 300)
+ .with_id("image_dialog");
+ let mut f = frame::Frame::default_fill();
+ win.end();
+ win.resize_callback(move |_win, _, _, w, h| f.resize(0, 0, w, h));
+ Self { win }
+ }
+}
diff --git a/fltext/src/fbr.rs b/fltext/src/fbr.rs
new file mode 100644
index 0000000..34e49f1
--- /dev/null
+++ b/fltext/src/fbr.rs
@@ -0,0 +1,128 @@
+#![allow(clippy::single_match)]
+
+use crate::{cbs, state::STATE, utils};
+use fltk::{enums::*, prelude::*, *};
+use notify::{event::EventKind, Event, RecursiveMode, Watcher};
+use std::{
+ env,
+ path::{Path, PathBuf},
+};
+
+pub fn menu_cb(m: &mut impl MenuExt) {
+ if let Ok(mpath) = m.item_pathname(None) {
+ match mpath.as_str() {
+ "/New File...\t" => cbs::new_file(),
+ "/New Dir...\t" => cbs::new_dir(),
+ _ => (),
+ }
+ }
+}
+
+pub fn init_menu(m: &mut (impl MenuExt + 'static)) {
+ m.add(
+ "New File...\t",
+ Shortcut::Ctrl | 'n',
+ menu::MenuFlag::Normal,
+ menu_cb,
+ );
+ m.add(
+ "New Dir...\t",
+ Shortcut::Ctrl | Shortcut::Shift | 'n',
+ menu::MenuFlag::Normal,
+ menu_cb,
+ );
+}
+
+pub fn fbr_cb(f: &mut browser::FileBrowser, watcher: &mut dyn Watcher) {
+ if let Some(path) = f.text(f.value()) {
+ let path = PathBuf::from(path);
+ if path.exists() {
+ if path.is_dir() {
+ watcher.watch(&path, RecursiveMode::NonRecursive).unwrap();
+ f.load(&path).expect("Couldn't load directory!");
+ let cwd = env::current_dir().unwrap();
+ env::set_current_dir(cwd.join(path)).unwrap();
+ let mut info: frame::Frame = app::widget_from_id("info").unwrap();
+ info.set_label(&format!(
+ "Directory: {}",
+ utils::strip_unc_path(&env::current_dir().unwrap())
+ ));
+ f.set_damage(true);
+ } else {
+ let mut is_image = false;
+ if let Some(ext) = path.extension() {
+ match ext.to_str().unwrap() {
+ "jpg" | "gif" | "png" | "bmp" => is_image = true,
+ _ => (),
+ }
+ }
+ if is_image {
+ let img = image::SharedImage::load(path).unwrap();
+ let mut win: window::Window = app::widget_from_id("image_dialog").unwrap();
+ win.resize(win.x(), win.y(), img.w(), img.h());
+ win.child(0).unwrap().set_image(Some(img));
+ win.show();
+ } else {
+ STATE.with(move |s| {
+ s.append(Some(path.canonicalize().unwrap()));
+ });
+ }
+ }
+ }
+ }
+}
+
+pub struct Fbr {
+ g: group::Group,
+}
+
+impl Fbr {
+ pub fn new(current_path: &Path) -> Self {
+ let mut g = group::Group::default().with_id("fbr_group");
+ let mut fbr = browser::FileBrowser::default()
+ .with_type(browser::BrowserType::Hold)
+ .with_id("fbr");
+ fbr.load(current_path)
+ .expect("Failed to load working directory");
+ fbr.set_color(Color::Background.darker());
+ let mut m = menu::MenuButton::default()
+ .with_type(menu::MenuButtonType::Popup3)
+ .with_id("pop1");
+ init_menu(&mut m);
+ g.end();
+ let mut watcher = notify::recommended_watcher({
+ let mut fbr = fbr.clone();
+ move |res: Result| match res {
+ Ok(event) => {
+ let mut needs_update = false;
+ match event.kind {
+ EventKind::Create(_) => {
+ needs_update = true;
+ }
+ EventKind::Remove(_) => {
+ needs_update = true;
+ }
+ _ => (),
+ }
+ if needs_update {
+ fbr.load(env::current_dir().unwrap()).unwrap();
+ }
+ }
+ Err(e) => eprintln!("{}", e),
+ }
+ })
+ .unwrap();
+ watcher
+ .watch(current_path, RecursiveMode::NonRecursive)
+ .unwrap();
+ fbr.set_callback(move |f| fbr_cb(f, &mut watcher));
+ g.resize_callback(move |_, x, y, w, h| {
+ m.resize(x, y, w, h);
+ fbr.resize(x, y, w, h);
+ });
+
+ Self { g }
+ }
+}
+
+fltk::widget_extends!(Fbr, group::Group, g);
diff --git a/fltext/src/gui.rs b/fltext/src/gui.rs
new file mode 100644
index 0000000..9c09820
--- /dev/null
+++ b/fltext/src/gui.rs
@@ -0,0 +1,269 @@
+use crate::{cbs, dialogs, fbr, utils};
+use fltk::{enums::*, prelude::*, *};
+use fltk_theme::{color_themes, ColorTheme};
+use std::path::{Path, PathBuf};
+
+#[cfg(feature = "term")]
+use fltk_term as term;
+
+#[cfg(feature = "highlight")]
+use crate::highlight;
+
+const WIDTH: i32 = 800;
+const HEIGHT: i32 = 600;
+const MENU_HEIGHT: i32 = if cfg!(target_os = "macos") { 1 } else { 30 };
+
+pub fn init_gui(current_file: &Option, current_path: &Path) -> app::App {
+ ColorTheme::new(color_themes::DARK_THEME).apply();
+ app::set_scheme(app::Scheme::Plastic);
+ app::set_font(Font::Courier);
+ app::set_menu_linespacing(10);
+ let mut buf = text::TextBuffer::default();
+ buf.set_tab_distance(4);
+
+ let _find_dialog = dialogs::FindDialog::new();
+ let _replace_dialog = dialogs::ReplaceDialog::new();
+ let _image_dialog = dialogs::ImageDialog::new();
+
+ let mut popup = menu::MenuButton::default().with_type(menu::MenuButtonType::Popup3);
+ init_edit_menu(&mut popup, "");
+
+ let mut w = window::Window::default()
+ .with_size(WIDTH, HEIGHT)
+ .with_label("flText");
+ w.set_xclass("red");
+
+ let mut col0 = group::Flex::default_fill().column();
+ col0.set_pad(2);
+ let mut m = menu::SysMenuBar::default().with_id("menu");
+ init_menu(&mut m, current_file.is_none());
+ col0.fixed(&m, MENU_HEIGHT);
+ let mut row = group::Flex::default();
+ row.set_pad(0);
+ let fbr = fbr::Fbr::new(current_path);
+ if current_file.is_none() {
+ row.fixed(&*fbr, 180);
+ } else {
+ row.fixed(&*fbr, 1);
+ }
+ let mut fbr_splitter = frame::Frame::default();
+ fbr_splitter.handle(cbs::fbr_splitter_cb);
+ row.fixed(&fbr_splitter, 4);
+ let mut col = group::Flex::default().column();
+ col.set_pad(0);
+ let mut tabs = group::Tabs::default().with_id("tabs");
+ tabs.handle(move |t, ev| tabs_handle(t, ev, &mut popup));
+ tabs.handle_overflow(group::TabsOverflow::Pulldown);
+ tabs.end();
+ tabs.auto_layout();
+ #[cfg(feature = "term")]
+ {
+ let mut tab_splitter = frame::Frame::default();
+ tab_splitter.handle(cbs::tab_splitter_cb);
+ col.fixed(&tab_splitter, 4);
+ let term = term::PPTerm::default();
+ col.fixed(&*term, 160);
+ }
+ col.end();
+ row.end();
+ let info = frame::Frame::default()
+ .with_label(&format!(
+ "Directory: {}",
+ utils::strip_unc_path(current_path)
+ ))
+ .with_align(enums::Align::Left | enums::Align::Inside)
+ .with_id("info");
+ col0.fixed(&info, 20);
+ col0.end();
+ w.resizable(&row);
+ w.end();
+ w.make_resizable(true);
+ w.show();
+ w.set_callback(cbs::win_cb);
+ app::App::default()
+}
+
+pub fn tabs_handle(t: &mut group::Tabs, ev: Event, popup: &mut menu::MenuButton) -> bool {
+ match ev {
+ Event::Push => {
+ if app::event_mouse_button() == app::MouseButton::Right
+ && app::event_y() > t.y() + 30
+ && t.children() > 0
+ {
+ popup.popup();
+ true
+ } else {
+ false
+ }
+ }
+ _ => false,
+ }
+}
+
+pub fn init_edit_menu(m: &mut (impl MenuExt + 'static), header: &str) {
+ m.add(
+ &format!("{}Undo\t", header),
+ Shortcut::Ctrl | 'z',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Redo\t", header),
+ Shortcut::Ctrl | 'y',
+ menu::MenuFlag::MenuDivider,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Cut\t", header),
+ Shortcut::Ctrl | 'x',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Copy\t", header),
+ Shortcut::Ctrl | 'c',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Paste\t", header),
+ Shortcut::Ctrl | 'v',
+ menu::MenuFlag::MenuDivider,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Find\t", header),
+ Shortcut::Ctrl | 'f',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ &format!("{}Replace\t", header),
+ Shortcut::Ctrl | 'h',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+}
+pub fn init_menu(m: &mut (impl MenuExt + 'static), load_dir: bool) {
+ m.add(
+ "&File/New File...\t",
+ Shortcut::Ctrl | 'n',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ "&File/New Dir...\t",
+ Shortcut::Ctrl | Shortcut::Shift | 'n',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ "&File/Open...\t",
+ Shortcut::Ctrl | 'o',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ "&File/Save\t",
+ Shortcut::Ctrl | 's',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ "&File/Save as...\t",
+ Shortcut::Ctrl | Shortcut::Shift | 'w',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.add(
+ "&File/Save All\t",
+ Shortcut::None,
+ menu::MenuFlag::MenuDivider,
+ cbs::menu_cb,
+ );
+ let idx = m.add(
+ "&File/Quit\t",
+ Shortcut::Ctrl | 'q',
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+ m.at(idx)
+ .unwrap()
+ .set_label_color(Color::from_hex(0xdc322f));
+ init_edit_menu(m, "&Edit/");
+ let idx = m.add(
+ "&View/File browser\t",
+ Shortcut::None,
+ menu::MenuFlag::Toggle,
+ cbs::menu_cb,
+ );
+ if load_dir {
+ m.at(idx).unwrap().set();
+ }
+ #[cfg(feature = "term")]
+ {
+ let idx = m.add(
+ "&View/Terminal\t",
+ Shortcut::None,
+ menu::MenuFlag::Toggle,
+ cbs::menu_cb,
+ );
+ m.at(idx).unwrap().set();
+ }
+ m.add(
+ "&Help/About\t",
+ Shortcut::None,
+ menu::MenuFlag::Normal,
+ cbs::menu_cb,
+ );
+}
+
+pub fn build_editor(id: &str) -> text::TextEditor {
+ let mut texteditor = text::TextEditor::default().with_id(id);
+ texteditor.set_color(Color::from_hex(0x002b36));
+ texteditor.set_linenumber_width(40);
+ texteditor.set_linenumber_size(12);
+ texteditor.set_linenumber_fgcolor(Color::from_hex(0xb58900));
+ texteditor.set_linenumber_bgcolor(Color::Background.darker());
+ texteditor.set_text_font(Font::Courier);
+ texteditor.set_trigger(CallbackTrigger::Changed);
+ texteditor.set_callback(cbs::editor_cb);
+ texteditor
+}
+
+pub fn create_ed(
+ tabs: &mut group::Tabs,
+ id: &str,
+ current_path: &Option,
+) -> text::TextEditor {
+ tabs.begin();
+ let mut edrow = group::Flex::default()
+ .row()
+ .with_label(if let Some(current_path) = current_path.as_ref() {
+ if current_path.is_dir() {
+ "untitled"
+ } else {
+ current_path.file_name().unwrap().to_str().unwrap()
+ }
+ } else {
+ "untitled"
+ })
+ .with_id(id);
+ edrow.set_trigger(CallbackTrigger::Closed);
+ edrow.set_callback(cbs::tab_close_cb);
+ let mut ed = build_editor("ed");
+ edrow.end();
+ tabs.end();
+ tabs.auto_layout();
+ tabs.set_value(&edrow).ok();
+
+ let mut buf = text::TextBuffer::default();
+ buf.set_tab_distance(4);
+ if let Some(p) = current_path.as_ref() {
+ buf.load_file(p).ok();
+ #[cfg(feature = "highlight")]
+ highlight::highlight(p, &mut ed, &mut buf);
+ }
+ ed.set_buffer(buf);
+ ed
+}
diff --git a/fltext/src/highlight/colors.rs b/fltext/src/highlight/colors.rs
new file mode 100644
index 0000000..35026a2
--- /dev/null
+++ b/fltext/src/highlight/colors.rs
@@ -0,0 +1,9 @@
+pub const GREEN: u32 = 0x859900;
+pub const RED: u32 = 0xdc322f;
+pub const YELLOW: u32 = 0xb58900;
+pub const DARKYELLOW: u32 = 0xc69a66;
+pub const WHITE: u32 = 0xabb2bf;
+pub const BLUE: u32 = 0x268bd2;
+pub const PURPLE: u32 = 0xc678dd;
+pub const GREY: u32 = 0x808080;
+pub const LIGHTGREY: u32 = 0xd8d8d8;
diff --git a/fltext/src/highlight/md.rs b/fltext/src/highlight/md.rs
new file mode 100644
index 0000000..85f09e7
--- /dev/null
+++ b/fltext/src/highlight/md.rs
@@ -0,0 +1,23 @@
+use super::colors::*;
+use super::HighlightData;
+use tree_sitter_highlight::HighlightConfiguration;
+
+use tree_sitter_md as ts;
+
+pub const STYLES: &[(&str, u32)] = &[
+ ("DEFAULT", WHITE),
+ ("text.title", RED),
+ ("text.reference", GREY),
+ ("punctuation.special", RED),
+ ("text.literal", GREEN),
+ ("punctuation.delimiter", DARKYELLOW),
+ ("text.uri", DARKYELLOW),
+];
+
+pub fn lang_data() -> HighlightData {
+ let (names, styles) = super::resolve_styles(STYLES);
+ let mut config =
+ HighlightConfiguration::new(ts::language(), ts::HIGHLIGHT_QUERY_BLOCK, "", "").unwrap();
+ config.configure(&names);
+ HighlightData::new(styles, config, None)
+}
diff --git a/fltext/src/highlight/mod.rs b/fltext/src/highlight/mod.rs
new file mode 100644
index 0000000..fca4094
--- /dev/null
+++ b/fltext/src/highlight/mod.rs
@@ -0,0 +1,130 @@
+use fltk::{
+ app,
+ enums::{Color, Font},
+ prelude::DisplayExt,
+ text::{StyleTableEntry, TextBuffer, TextEditor},
+};
+use std::path::Path;
+use tree_sitter_highlight::HighlightConfiguration;
+use tree_sitter_highlight::HighlightEvent;
+use tree_sitter_highlight::Highlighter;
+
+mod colors;
+mod md;
+mod rust;
+mod toml;
+
+fn translate_style(idx: usize) -> char {
+ char::from_u32(65 + idx as u32).unwrap()
+}
+
+fn resolve_styles(v: &[(&'static str, u32)]) -> (Vec<&'static str>, Vec) {
+ let mut names = Vec::new();
+ let mut styles = Vec::new();
+ for elem in v {
+ names.push(elem.0);
+ styles.push(StyleTableEntry {
+ color: Color::from_hex(elem.1),
+ font: Font::Courier,
+ size: app::font_size(),
+ });
+ }
+ (names, styles)
+}
+
+pub struct HighlightData {
+ styles: Vec,
+ config: HighlightConfiguration,
+ exeption_fn: Option char>,
+}
+
+impl HighlightData {
+ pub fn new(
+ styles: Vec,
+ config: HighlightConfiguration,
+ exeption_fn: Option char>,
+ ) -> Self {
+ Self {
+ styles,
+ config,
+ exeption_fn,
+ }
+ }
+}
+
+fn get_highlight(p: &Path) -> Option {
+ if let Some(ext) = p.extension() {
+ match ext.to_str().unwrap() {
+ "rs" => Some(rust::lang_data()),
+ "toml" => Some(toml::lang_data()),
+ "md" => Some(md::lang_data()),
+ _ => None,
+ }
+ } else {
+ None
+ }
+}
+
+pub fn highlight(p: &Path, ed: &mut TextEditor, buf: &mut TextBuffer) {
+ if let Some(HighlightData {
+ styles,
+ config,
+ exeption_fn,
+ }) = get_highlight(p)
+ {
+ let mut highlighter = Highlighter::new();
+ let mut sbuf = TextBuffer::default();
+ ed.set_highlight_data(sbuf.clone(), styles);
+ apply(
+ &mut highlighter,
+ &config,
+ &buf.text(),
+ &mut sbuf,
+ &exeption_fn,
+ );
+ buf.add_modify_callback({
+ let buf = buf.clone();
+ move |_, _, _, _, _| {
+ apply(
+ &mut highlighter,
+ &config,
+ &buf.text(),
+ &mut sbuf,
+ &exeption_fn,
+ );
+ }
+ });
+ }
+}
+
+fn apply(
+ highlighter: &mut Highlighter,
+ config: &HighlightConfiguration,
+ s: &str,
+ sbuf: &mut TextBuffer,
+ exeption_fn: &Option char>,
+) {
+ let highlights = highlighter
+ .highlight(config, s.as_bytes(), None, |_| None)
+ .unwrap();
+
+ let mut local_buf = "A".repeat(s.len());
+ let mut curr = 0;
+ for event in highlights {
+ match event.unwrap() {
+ HighlightEvent::HighlightStart(s) => {
+ curr = s.0;
+ }
+ HighlightEvent::Source { start, end } => {
+ let c = if let Some(f) = exeption_fn {
+ f(curr, &s[start..end])
+ } else {
+ translate_style(curr)
+ };
+ local_buf.replace_range(start..end, &c.to_string().repeat(end - start));
+ }
+ HighlightEvent::HighlightEnd => curr = 0,
+ }
+ }
+ sbuf.set_text(&local_buf);
+}
diff --git a/fltext/src/highlight/rust.rs b/fltext/src/highlight/rust.rs
new file mode 100644
index 0000000..4c6e487
--- /dev/null
+++ b/fltext/src/highlight/rust.rs
@@ -0,0 +1,36 @@
+use super::colors::*;
+use super::HighlightData;
+use tree_sitter_highlight::HighlightConfiguration;
+
+use tree_sitter_rust as ts;
+
+pub const STYLES: &[(&str, u32)] = &[
+ ("DEFAULT", WHITE),
+ ("attribute", RED),
+ ("constructor", DARKYELLOW),
+ ("comment", GREY),
+ ("constant", DARKYELLOW),
+ ("constant.builtin", DARKYELLOW),
+ ("function", BLUE),
+ ("function.method", BLUE),
+ ("keyword", PURPLE),
+ ("operator", WHITE),
+ ("property", RED),
+ ("punctuation.bracket", DARKYELLOW),
+ ("punctuation.delimiter", WHITE),
+ ("string", GREEN),
+ ("type", YELLOW),
+ ("type.builtin", YELLOW),
+ ("variable", RED),
+ ("variable.builtin", RED),
+ ("variable.parameter", WHITE),
+ ("label", WHITE),
+];
+
+pub fn lang_data() -> HighlightData {
+ let (names, styles) = super::resolve_styles(STYLES);
+ let mut config =
+ HighlightConfiguration::new(ts::language(), ts::HIGHLIGHT_QUERY, "", "").unwrap();
+ config.configure(&names);
+ HighlightData::new(styles, config, None)
+}
diff --git a/fltext/src/highlight/toml.rs b/fltext/src/highlight/toml.rs
new file mode 100644
index 0000000..5212d9a
--- /dev/null
+++ b/fltext/src/highlight/toml.rs
@@ -0,0 +1,24 @@
+use super::colors::*;
+use super::HighlightData;
+use tree_sitter_highlight::HighlightConfiguration;
+
+use tree_sitter_toml as ts;
+
+pub const STYLES: &[(&str, u32)] = &[
+ ("DEFAULT", RED),
+ ("property", RED),
+ ("comment", GREY),
+ ("string", GREEN),
+ ("number", GREEN),
+ ("operator", LIGHTGREY),
+ ("punctuation", DARKYELLOW),
+ ("constant.builtin", DARKYELLOW),
+];
+
+pub fn lang_data() -> HighlightData {
+ let (names, styles) = super::resolve_styles(STYLES);
+ let mut config =
+ HighlightConfiguration::new(ts::language(), ts::HIGHLIGHT_QUERY, "", "").unwrap();
+ config.configure(&names);
+ HighlightData::new(styles, config, None)
+}
diff --git a/fltext/src/main.rs b/fltext/src/main.rs
new file mode 100644
index 0000000..7fb654f
--- /dev/null
+++ b/fltext/src/main.rs
@@ -0,0 +1,18 @@
+use std::env;
+
+mod cbs;
+mod dialogs;
+mod fbr;
+mod gui;
+mod state;
+mod utils;
+
+#[cfg(feature = "highlight")]
+mod highlight;
+
+fn main() {
+ let (current_file, current_path) = utils::init_args(env::args());
+ let a = gui::init_gui(¤t_file, ¤t_path);
+ state::init_state(current_file, current_path);
+ a.run().unwrap();
+}
diff --git a/fltext/src/state.rs b/fltext/src/state.rs
new file mode 100644
index 0000000..c9d7646
--- /dev/null
+++ b/fltext/src/state.rs
@@ -0,0 +1,143 @@
+#![allow(dead_code)]
+
+use crate::gui;
+use fltk::{app, group, prelude::*, text, utils::oncelock::Lazy};
+use std::collections::HashMap;
+use std::{
+ path::PathBuf,
+ sync::atomic::{AtomicU32, Ordering},
+};
+
+static COUNT: AtomicU32 = AtomicU32::new(0);
+
+#[derive(Clone, Debug)]
+pub struct MyBuffer {
+ pub modified: bool,
+ pub id: String,
+ pub buf: text::TextBuffer,
+ pub current_file: Option,
+}
+
+pub struct State {
+ pub map: HashMap,
+ pub current_dir: PathBuf,
+}
+
+impl State {
+ pub fn new(current_dir: PathBuf) -> Self {
+ let map = HashMap::default();
+ State { map, current_dir }
+ }
+ pub fn append(&mut self, current_path: Option) {
+ let mut tabs: group::Tabs = app::widget_from_id("tabs").unwrap();
+ let mut open = false;
+ let mut edid = 0;
+ for (k, v) in &self.map {
+ if v.current_file == current_path {
+ open = true;
+ edid = *k;
+ break;
+ }
+ }
+ if !open {
+ let old_count = COUNT.load(Ordering::Relaxed);
+ let id = format!("edrow{}", old_count);
+ COUNT.store(old_count + 1, Ordering::Relaxed);
+ let ed = gui::create_ed(&mut tabs, &id, ¤t_path);
+ let mybuf = MyBuffer {
+ modified: false,
+ id,
+ buf: ed.buffer().unwrap(),
+ current_file: current_path.map(|p| p.canonicalize().unwrap()),
+ };
+ self.map.insert(ed.as_widget_ptr() as usize, mybuf);
+ } else {
+ tabs.set_value(
+ &text::TextEditor::from_dyn_widget_ptr(edid as *mut _)
+ .unwrap()
+ .parent()
+ .unwrap(),
+ )
+ .ok();
+ tabs.set_damage(true);
+ }
+ }
+ pub fn current_id(&self) -> Option {
+ let tabs: group::Tabs = app::widget_from_id("tabs").unwrap();
+ if tabs.children() == 0 {
+ return None;
+ }
+ tabs.value()
+ .unwrap()
+ .child(0)
+ .map(|ed| ed.as_widget_ptr() as usize)
+ }
+ pub fn was_modified(&mut self, flag: bool) {
+ let mut tabs: group::Tabs = app::widget_from_id("tabs").unwrap();
+ if tabs.children() == 0 {
+ return;
+ }
+ let mut edrow = tabs.value().unwrap();
+ if let Some(c) = edrow.child(0) {
+ let id = c.as_widget_ptr() as usize;
+ let mybuf = self.map.get_mut(&id).unwrap();
+ mybuf.modified = flag;
+ if let Some(f) = mybuf.current_file.as_ref() {
+ if flag {
+ edrow.set_label(&format!("\t{} *", f.file_name().unwrap().to_str().unwrap()));
+ } else {
+ edrow.set_label(&format!("\t{}", f.file_name().unwrap().to_str().unwrap()));
+ }
+ tabs.redraw();
+ }
+ }
+ }
+ pub fn modified(&self) -> bool {
+ if let Some(current_id) = self.current_id() {
+ let mybuf = self.map.get(¤t_id).unwrap();
+ mybuf.modified
+ } else {
+ false
+ }
+ }
+ pub fn buf(&self) -> Option {
+ if let Some(current_id) = self.current_id() {
+ let mybuf = self.map.get(¤t_id).unwrap();
+ Some(mybuf.buf.clone())
+ } else {
+ None
+ }
+ }
+ pub fn current_file(&self) -> Option {
+ if let Some(current_id) = self.current_id() {
+ let mybuf = self.map.get(¤t_id).unwrap();
+ mybuf.current_file.clone()
+ } else {
+ None
+ }
+ }
+ pub fn set_current_file(&mut self, path: PathBuf) {
+ if let Some(current_id) = self.current_id() {
+ let mybuf = self.map.get_mut(¤t_id).unwrap();
+ mybuf.current_file = Some(path)
+ }
+ }
+ pub fn current_editor(&self) -> Option {
+ let tabs: group::Tabs = app::widget_from_id("tabs").unwrap();
+ if tabs.children() == 0 {
+ return None;
+ }
+ tabs.value()
+ .unwrap()
+ .child(0)
+ .map(|c| text::TextEditor::from_dyn_widget(&c).unwrap())
+ }
+}
+
+pub static STATE: Lazy> = Lazy::new(app::GlobalState::::get);
+
+pub fn init_state(current_file: Option, current_path: PathBuf) {
+ let mut state = State::new(current_path);
+ state.append(current_file);
+ app::GlobalState::new(state);
+}
diff --git a/fltext/src/utils.rs b/fltext/src/utils.rs
new file mode 100644
index 0000000..2652355
--- /dev/null
+++ b/fltext/src/utils.rs
@@ -0,0 +1,63 @@
+use std::{
+ env,
+ path::{Path, PathBuf},
+ process::Command,
+};
+
+pub fn strip_unc_path(p: &Path) -> String {
+ let p = p.to_str().unwrap();
+ if let Some(end) = p.strip_prefix("\\\\?\\") {
+ end.to_string()
+ } else {
+ p.to_string()
+ }
+}
+
+#[allow(dead_code)]
+pub fn has_program(prog: &str) -> bool {
+ // hacky
+ match Command::new(prog).arg("--version").output() {
+ Ok(out) => !out.stdout.is_empty(),
+ _ => false,
+ }
+}
+
+pub fn init_args(args: env::Args) -> (Option, PathBuf) {
+ let args: Vec<_> = args.collect();
+ let mut current_file: Option = None;
+ // fix our working dir
+ if args.len() > 1 {
+ let path = PathBuf::from(args[1].clone());
+ if path.exists() {
+ if path.is_dir() {
+ env::set_current_dir(path.clone()).unwrap();
+ } else {
+ current_file = Some(PathBuf::from(path.file_name().unwrap()));
+ if let Some(parent) = path.parent() {
+ if parent.exists() {
+ env::set_current_dir(parent).unwrap();
+ }
+ }
+ }
+ }
+ path
+ } else {
+ env::current_dir().unwrap()
+ };
+
+ let current_path = env::current_dir().unwrap().canonicalize().unwrap();
+ (current_file, current_path)
+}
+
+#[allow(dead_code)]
+pub fn can_use_xterm() -> bool {
+ if cfg!(not(any(target_os = "macos", target_os = "windows"))) {
+ if let Ok(var) = env::var("XDG_SESSION_TYPE") {
+ var == "x11" && has_program("xterm")
+ } else {
+ env::var("RED_XTERM").is_ok()
+ }
+ } else {
+ false
+ }
+}
diff --git a/wgpu/Cargo.toml b/flwgpu/Cargo.toml
similarity index 68%
rename from wgpu/Cargo.toml
rename to flwgpu/Cargo.toml
index f3addca..92c9d35 100644
--- a/wgpu/Cargo.toml
+++ b/flwgpu/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "wgpu"
+name = "flwgpu"
version = "0.1.0"
authors = ["Mohammed Alyousef ", "Rongcui Dong "]
edition = "2021"
@@ -8,6 +8,6 @@ resolver = "2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "^1", features = ["fltk-bundled", "raw-window-handle"] }
-wgpu = "^0.13"
-pollster = "^0.2"
+fltk = { version = "^1.4", features = ["fltk-bundled", "raw-window-handle"] }
+wgpu = "^0.19"
+pollster = "^0.3"
diff --git a/wgpu/README.md b/flwgpu/README.md
similarity index 100%
rename from wgpu/README.md
rename to flwgpu/README.md
diff --git a/wgpu/src/main.rs b/flwgpu/src/main.rs
similarity index 100%
rename from wgpu/src/main.rs
rename to flwgpu/src/main.rs
diff --git a/wgpu/src/shader.wgsl b/flwgpu/src/shader.wgsl
similarity index 100%
rename from wgpu/src/shader.wgsl
rename to flwgpu/src/shader.wgsl
diff --git a/wgpu/wgpu.gif b/flwgpu/wgpu.gif
similarity index 100%
rename from wgpu/wgpu.gif
rename to flwgpu/wgpu.gif
diff --git a/framebuffer/Cargo.toml b/framebuffer/Cargo.toml
index 73be3c6..169bf6b 100644
--- a/framebuffer/Cargo.toml
+++ b/framebuffer/Cargo.toml
@@ -7,4 +7,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
diff --git a/framebuffer/src/main.rs b/framebuffer/src/main.rs
index dbffefe..0ad11ce 100644
--- a/framebuffer/src/main.rs
+++ b/framebuffer/src/main.rs
@@ -1,5 +1,4 @@
use fltk::{app, draw, frame, prelude::*, window::Window};
-use std::{thread, time::Duration};
const WIDTH: u32 = 600;
const HEIGHT: u32 = 400;
diff --git a/glut/Cargo.toml b/glut/Cargo.toml
index a77f223..c417813 100644
--- a/glut/Cargo.toml
+++ b/glut/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-gl = "0.14"
-fltk = { version = "1", features = ["enable-glwindow"] }
+gl = "^0.14"
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
diff --git a/glut/src/main.rs b/glut/src/main.rs
index 5dc7173..6b46604 100644
--- a/glut/src/main.rs
+++ b/glut/src/main.rs
@@ -1,23 +1,19 @@
use fltk::{prelude::*, *};
-
use gl::types::*;
-use std::ffi::CString;
-use std::mem;
-use std::ptr;
-use std::str;
+use std::{ffi::CString, mem, ptr, str};
// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];
// Shader sources
-static VS_SRC: &'static str = "
+static VS_SRC: &str = "
#version 150
in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}";
-static FS_SRC: &'static str = "
+static FS_SRC: &str = "
#version 150
out vec4 out_color;
void main() {
@@ -41,8 +37,7 @@ fn compile_shader(src: &str, ty: GLenum) -> GLuint {
if status != (gl::TRUE as GLint) {
let mut len = 0;
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
- let mut buf = Vec::with_capacity(len as usize);
- buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
+ let mut buf: Vec = vec![0; (len as usize) - 1];
gl::GetShaderInfoLog(
shader,
len,
@@ -51,9 +46,7 @@ fn compile_shader(src: &str, ty: GLenum) -> GLuint {
);
panic!(
"{}",
- str::from_utf8(&buf)
- .ok()
- .expect("ShaderInfoLog not valid utf8")
+ str::from_utf8(&buf).expect("ShaderInfoLog not valid utf8")
);
}
}
@@ -74,8 +67,7 @@ fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
if status != (gl::TRUE as GLint) {
let mut len: GLint = 0;
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
- let mut buf = Vec::with_capacity(len as usize);
- buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
+ let mut buf: Vec = vec![0; (len as usize) - 1];
gl::GetProgramInfoLog(
program,
len,
@@ -84,9 +76,7 @@ fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
);
panic!(
"{}",
- str::from_utf8(&buf)
- .ok()
- .expect("ProgramInfoLog not valid utf8")
+ str::from_utf8(&buf).expect("ProgramInfoLog not valid utf8")
);
}
program
@@ -94,7 +84,6 @@ fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
}
fn main() {
- let app = app::App::default();
let mut win = window::GlWindow::new(100, 100, 500, 400, "");
win.make_resizable(true);
win.set_mode(enums::Mode::Opengl3);
@@ -122,7 +111,7 @@ fn main() {
gl::BufferData(
gl::ARRAY_BUFFER,
(VERTEX_DATA.len() * mem::size_of::()) as GLsizeiptr,
- mem::transmute(&VERTEX_DATA[0]),
+ &VERTEX_DATA[0] as *const f32 as *const std::ffi::c_void,
gl::STATIC_DRAW,
);
@@ -154,5 +143,5 @@ fn main() {
g.swap_buffers();
});
- app.run().unwrap();
+ app::App::default().run().unwrap();
}
diff --git a/glyphmap/Cargo.toml b/glyphmap/Cargo.toml
index 28ff21c..7951d47 100644
--- a/glyphmap/Cargo.toml
+++ b/glyphmap/Cargo.toml
@@ -6,5 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1.2"
-ttf-parser = "0.14"
\ No newline at end of file
+fltk = "^1.4"
+ttf-parser = "0.14"
diff --git a/glyphmap/src/main.rs b/glyphmap/src/main.rs
index e2448a4..a2e8aef 100644
--- a/glyphmap/src/main.rs
+++ b/glyphmap/src/main.rs
@@ -2,7 +2,6 @@ extern crate ttf_parser;
use fltk::{enums::*, prelude::*, *};
fn main() {
- let app = app::App::default();
app::set_background_color(170, 189, 206);
dialog::message_title_default("Glyph Map");
let mut wind = window::Window::default()
@@ -56,8 +55,7 @@ fn main() {
let c = char::from_u32(codepoint).unwrap();
let txt = String::from(c);
let (w, h) = draw::measure(&txt, true);
- if w != 0 && h != 0 {
- if face.glyph_index(c).is_some() {
+ if w != 0 && h != 0 && face.glyph_index(c).is_some() {
let hpack = group::Pack::default()
.with_type(group::PackType::Horizontal)
.with_size(0, 50);
@@ -76,7 +74,6 @@ fn main() {
out.set_value(&txt);
hpack.end();
}
- }
});
}
pack.end();
@@ -90,5 +87,5 @@ fn main() {
}
});
- app.run().unwrap();
+ app::App::default().run().unwrap();
}
diff --git a/gst/Cargo.toml b/gst/Cargo.toml
index cc6911d..a4c1663 100644
--- a/gst/Cargo.toml
+++ b/gst/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = " 1"
+fltk = "^1.4"
gstreamer = "0.17"
-gstreamer-video = "0.17"
\ No newline at end of file
+gstreamer-video = "0.17"
diff --git a/gst/src/main.rs b/gst/src/main.rs
index b6ab71a..5378f4a 100644
--- a/gst/src/main.rs
+++ b/gst/src/main.rs
@@ -32,7 +32,7 @@ fn main() {
let mut path = String::from("file:///");
let current_dir = std::env::current_dir().unwrap();
let video_file = current_dir.join(uri);
- path += &video_file.to_str().unwrap();
+ path += video_file.to_str().unwrap();
let playbin = gstreamer::ElementFactory::make("playbin", None).unwrap();
playbin.set_property("uri", &path).unwrap();
diff --git a/libvlc/Cargo.toml b/libvlc/Cargo.toml
index 77eb046..67faade 100644
--- a/libvlc/Cargo.toml
+++ b/libvlc/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
vlc-rs = { git = "https://github.com/garkimasera/vlc-rs.git" }
diff --git a/libvlc/src/main.rs b/libvlc/src/main.rs
index 6fb964e..6d49764 100644
--- a/libvlc/src/main.rs
+++ b/libvlc/src/main.rs
@@ -8,7 +8,7 @@ pub enum Message {
}
fn main() {
- let app = app::App::default().with_scheme(app::AppScheme::Gtk);
+ let (sender, receiver) = app::channel::();
let mut win = window::Window::new(100, 100, 800, 600, "Media Player");
win.make_resizable(true);
@@ -17,21 +17,17 @@ fn main() {
vlc_win.end();
vlc_win.set_color(Color::Black);
- let mut but_play = button::Button::new(320, 545, 80, 40, "Play");
- let mut but_stop = button::Button::new(400, 545, 80, 40, "Stop");
+ button::Button::new(320, 545, 80, 40, "Play").emit(sender, Message::Play);
+ button::Button::new(400, 545, 80, 40, "Stop").emit(sender, Message::Stop);
win.end();
win.show();
win.make_resizable(true);
- // Take in same args as vlc
- let args: Vec = std::env::args().collect();
-
// Instantiate vlc instance and media player
let instance = Instance::new().unwrap();
- let md = Media::new_path(&instance, "video.mp4").unwrap();
let mdp = MediaPlayer::new(&instance).unwrap();
- mdp.set_media(&md);
+ mdp.set_media(&Media::new_path(&instance, "video.mp4").unwrap());
// Get vlc_win handle that we'll pass to libvlc
// Linux u32, windows HWND, Mac NSWindow
@@ -54,13 +50,8 @@ fn main() {
mdp.set_key_input(false);
mdp.set_mouse_input(false);
- let (s, r) = app::channel::();
-
- but_play.emit(s, Message::Play);
- but_stop.emit(s, Message::Stop);
-
- while app.wait() {
- match r.recv() {
+ while app::App::default().with_scheme(app::AppScheme::Gtk).wait() {
+ match receiver.recv() {
Some(val) => match val {
Message::Play => mdp.play().unwrap(),
Message::Stop => mdp.stop(),
diff --git a/mpv/Cargo.toml b/mpv/Cargo.toml
index f791e6c..7c7c134 100644
--- a/mpv/Cargo.toml
+++ b/mpv/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
\ No newline at end of file
+fltk = "^1.4"
diff --git a/musicplayer/Cargo.toml b/musicplayer/Cargo.toml
index 3255478..9447ec9 100644
--- a/musicplayer/Cargo.toml
+++ b/musicplayer/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1.3.33"
-soloud = "1.0.2"
+fltk = "^1.4"
+soloud = "^1.0"
diff --git a/musicplayer/src/main.rs b/musicplayer/src/main.rs
index 5e062c4..6165b0b 100644
--- a/musicplayer/src/main.rs
+++ b/musicplayer/src/main.rs
@@ -1,7 +1,6 @@
use fltk::{app, enums::*, frame::*, prelude::*, window::*};
use soloud::*;
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::{cell::RefCell,rc::Rc};
mod power_button;
use power_button::PowerButton;
diff --git a/musicplayer/src/power_button.rs b/musicplayer/src/power_button.rs
index 762aca8..3f3fa2e 100644
--- a/musicplayer/src/power_button.rs
+++ b/musicplayer/src/power_button.rs
@@ -1,9 +1,9 @@
-use fltk::frame::*;
-use fltk::image::*;
-use fltk::{enums::*, prelude::*};
-use std::cell::RefCell;
-use std::ops::{Deref, DerefMut};
-use std::rc::Rc;
+use fltk::{enums::*, frame::*, image::*, prelude::*};
+use std::{
+ cell::RefCell,
+ ops::{Deref, DerefMut},
+ rc::Rc,
+};
const POWER: &str = r#"
diff --git a/opengl/Cargo.toml b/opengl/Cargo.toml
index 2943956..45ccc8b 100644
--- a/opengl/Cargo.toml
+++ b/opengl/Cargo.toml
@@ -7,6 +7,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = { version = "1", features = ["enable-glwindow"] }
+fltk = { version = "^1.4", features = ["enable-glwindow"] }
glu-sys = "0.1.4"
diff --git a/opengl/src/main.rs b/opengl/src/main.rs
index 0f84779..1ba8a19 100644
--- a/opengl/src/main.rs
+++ b/opengl/src/main.rs
@@ -1,13 +1,11 @@
use fltk::{prelude::*, *};
use glu_sys::*;
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::{cell::RefCell, rc::Rc};
const W: i32 = 600;
const H: i32 = 400;
pub fn main() {
- let app = app::App::default();
let mut wind = window::GlWindow::new(100, 100, W, H, "Rotate me!");
wind.make_resizable(true);
wind.end();
@@ -28,7 +26,7 @@ pub fn main() {
_ => false,
});
- while app.wait() {
+ while app::App::default().wait() {
match r.recv() {
Some(coords) => {
let rand: f32 = ((coords.0 - W / 2) * (coords.1 - H / 2) / 360) as f32;
diff --git a/rounded-svg/Cargo.toml b/rounded-svg/Cargo.toml
index 1b24a82..da67cab 100644
--- a/rounded-svg/Cargo.toml
+++ b/rounded-svg/Cargo.toml
@@ -6,5 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
-svg = "0.10"
\ No newline at end of file
+fltk = "^1.4"
+svg = "0.10"
diff --git a/systray/Cargo.toml b/systray/Cargo.toml
index 731ba8c..506434e 100644
--- a/systray/Cargo.toml
+++ b/systray/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
[target.'cfg(target_os = "windows")'.dependencies]
-native-windows-gui = { version = "1.0.10", default-features=false, features=["tray-notification", "message-window", "menu", "cursor"] }
\ No newline at end of file
+native-windows-gui = { version = "1.0.10", default-features=false, features=["tray-notification", "message-window", "menu", "cursor"] }
diff --git a/systray/src/main.rs b/systray/src/main.rs
index e316589..ef0b5af 100644
--- a/systray/src/main.rs
+++ b/systray/src/main.rs
@@ -3,8 +3,8 @@ use fltk::{app, enums::FrameType, prelude::*, *};
#[cfg(target_os = "windows")]
mod systray;
-type HWND = *mut std::os::raw::c_void;
-pub static mut WINDOW: HWND = std::ptr::null_mut();
+type Hwnd = *mut std::os::raw::c_void;
+pub static mut WINDOW: Hwnd = std::ptr::null_mut();
fn main() {
let app = app::App::default();
diff --git a/systray/src/systray.rs b/systray/src/systray.rs
index 44478ad..4aa8567 100644
--- a/systray/src/systray.rs
+++ b/systray/src/systray.rs
@@ -19,7 +19,7 @@ impl SystemTray {
fn show_main_win(&self) {
extern "C" {
- pub fn ShowWindow(hwnd: crate::HWND, nCmdShow: i32) -> bool;
+ pub fn ShowWindow(hwnd: crate::Hwnd, nCmdShow: i32) -> bool;
}
unsafe {
ShowWindow(crate::WINDOW, 9);
diff --git a/terminal/Cargo.toml b/terminal/Cargo.toml
index 314f654..063c8f4 100644
--- a/terminal/Cargo.toml
+++ b/terminal/Cargo.toml
@@ -6,5 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1.3"
-portable-pty = "0.7"
\ No newline at end of file
+fltk = "^1.4"
+portable-pty = "0.7"
diff --git a/tinyskia/Cargo.toml b/tinyskia/Cargo.toml
index 238fffa..1e1ffe8 100644
--- a/tinyskia/Cargo.toml
+++ b/tinyskia/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
-tiny-skia = "0.5"
\ No newline at end of file
+fltk = "^1.4"
+tiny-skia = "0.5"
diff --git a/tinyskia/src/main.rs b/tinyskia/src/main.rs
index 7eca499..3991385 100644
--- a/tinyskia/src/main.rs
+++ b/tinyskia/src/main.rs
@@ -4,15 +4,17 @@ use tiny_skia::*;
fn main() {
let triangle = create_triangle();
- let mut paint = Paint::default();
- paint.anti_alias = true;
- paint.shader = Pattern::new(
- triangle.as_ref(),
- SpreadMode::Repeat,
- FilterQuality::Bicubic,
- 1.0,
- Transform::from_row(1.5, -0.4, 0.0, -0.8, 5.0, 1.0),
- );
+ let paint = Paint {
+ anti_alias: true,
+ shader: Pattern::new(
+ triangle.as_ref(),
+ SpreadMode::Repeat,
+ FilterQuality::Bicubic,
+ 1.0,
+ Transform::from_row(1.5, -0.4, 0.0, -0.8, 5.0, 1.0),
+ ),
+ .. Paint::default()
+ };
let path = PathBuilder::from_circle(200.0, 200.0, 180.0).unwrap();
diff --git a/web-todo/Cargo.toml b/web-todo/Cargo.toml
index cbfed4f..19c1357 100644
--- a/web-todo/Cargo.toml
+++ b/web-todo/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1.3.33"
+fltk = "^1.4"
serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1.0", features = ["full"] }
diff --git a/web-todo2/Cargo.toml b/web-todo2/Cargo.toml
index 6f5952a..545eeba 100644
--- a/web-todo2/Cargo.toml
+++ b/web-todo2/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
serde = { version = "1.0", features = ["derive"] }
surf = { version = "2.1.0" }
async-std = { version = "1.9", features = ["attributes"] }
diff --git a/webview/Cargo.toml b/webview/Cargo.toml
index d1ad21c..92bfdbc 100644
--- a/webview/Cargo.toml
+++ b/webview/Cargo.toml
@@ -7,5 +7,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
-fltk-webview = "0.2"
+fltk = "^1.4"
+fltk-webview = "^0.3"
diff --git a/webview/src/main.rs b/webview/src/main.rs
index 7f56d0f..1c112f0 100644
--- a/webview/src/main.rs
+++ b/webview/src/main.rs
@@ -1,7 +1,6 @@
-use fltk::{app, enums::Event, prelude::*, window};
+use fltk::{app, prelude::*, window};
fn main() {
- let app = app::App::default();
let mut win = window::Window::default()
.with_size(730, 430)
.with_label("Webview");
@@ -12,9 +11,9 @@ fn main() {
win.end();
win.show();
- let mut wv = fltk_webview::Webview::create(false, &mut wv_win);
+ let wv = fltk_webview::Webview::create(false, &mut wv_win);
wv.navigate("https://google.com");
// the webview handles the main loop
- app.run().unwrap();
+ app::App::default().run().unwrap();
}
diff --git a/xterm/Cargo.toml b/xterm/Cargo.toml
index 0c8fed7..a59d604 100644
--- a/xterm/Cargo.toml
+++ b/xterm/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-fltk = "1"
+fltk = "^1.4"
diff --git a/xterm/src/main.rs b/xterm/src/main.rs
index 73db4fc..972b009 100644
--- a/xterm/src/main.rs
+++ b/xterm/src/main.rs
@@ -14,11 +14,10 @@ fn main() {
win.show();
win.make_resizable(true);
- let mut handle = xterm_win.raw_handle();
std::process::Command::new("xterm")
.args(&[
"-into",
- &format!("{}", handle),
+ &format!("{}", xterm_win.raw_handle()),
"-bg",
"black",
"-fg",