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",