Initial Commit

pull/1/head
Able 2021-06-03 04:05:08 -05:00
commit 1588af501b
7 changed files with 623 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

185
Cargo.lock generated Normal file
View File

@ -0,0 +1,185 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "able-editor"
version = "0.1.0"
dependencies = [
"fltk",
"home",
"log",
]
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cmake"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855"
dependencies = [
"cc",
]
[[package]]
name = "fltk"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93976066512905df1768cbf8bfe229089f91e992fb826b5ae0aa04db26c374ed"
dependencies = [
"bitflags",
"fltk-derive",
"fltk-sys",
"lazy_static",
"objc",
"raw-window-handle",
]
[[package]]
name = "fltk-derive"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59d32edd6499bef496473f31281a941c8309026a19e4a92839db3bbda591474"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "fltk-sys"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd93e3698638a72c5dd38b9cb34a9eb90417f0ef59028de0f7e3f008304754e3"
dependencies = [
"cmake",
"libc",
]
[[package]]
name = "home"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
dependencies = [
"winapi",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "proc-macro2"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "raw-window-handle"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211"
dependencies = [
"libc",
]
[[package]]
name = "syn"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "able-editor"
version = "0.1.0"
authors = ["Able <abl3theabove@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
fltk = "*"
home = "0.5.3"
log="*"

24
src/config.rs Normal file
View File

@ -0,0 +1,24 @@
use serde::Deserialize;
use std::fs;
#[derive(Debug, Deserialize, Copy, Clone)]
pub struct Configuration {
log: Option<bool>,
}
const DEFAULT_CONFIG: Configuration = Configuration { log: Some(true) };
pub fn load_config() -> Configuration {
let filename = "assets/config.toml";
let contents = fs::read_to_string(filename);
match contents {
Ok(o) => {
println!("{}", o);
let decoded: Configuration = toml::from_str(&o).unwrap_or(DEFAULT_CONFIG);
return decoded;
}
Err(e) => {
println!("{}", e);
return DEFAULT_CONFIG;
}
}
}

47
src/editor.rs Normal file
View File

@ -0,0 +1,47 @@
use fltk::{
enums::{CallbackTrigger, Color, Font},
prelude::{DisplayExt, WidgetBase, WidgetExt},
text,
};
use std::ops::{Deref, DerefMut};
pub struct Editor {
editor: text::TextEditor,
}
impl Editor {
pub fn new(buf: text::TextBuffer) -> Self {
let mut editor = text::TextEditor::new(5, 35, 790, 560, "");
editor.set_buffer(Some(buf));
editor.set_text_color(Color::White);
editor.set_color(Color::Black);
editor.set_cursor_style(fltk::text::Cursor::Simple);
#[cfg(target_os = "macos")]
editor.resize(5, 5, 790, 590);
editor.set_scrollbar_size(15);
editor.set_text_font(Font::Screen);
editor.set_linenumber_width(32);
editor.set_linenumber_fgcolor(Color::White);
editor.set_linenumber_bgcolor(Color::Black);
editor.set_trigger(CallbackTrigger::Changed);
editor.set_cursor_color(Color::White);
Self { editor }
}
}
impl Deref for Editor {
type Target = text::TextEditor;
fn deref(&self) -> &Self::Target {
&self.editor
}
}
impl DerefMut for Editor {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.editor
}
}

249
src/main.rs Normal file
View File

@ -0,0 +1,249 @@
use fltk::{
app, dialog,
enums::Event,
prelude::{GroupExt, WidgetBase, WidgetExt, WindowExt},
text, window,
};
use std::{error, panic, path};
mod editor;
mod menu;
#[derive(Copy, Clone)]
pub enum Message {
Changed,
New,
Open,
Save,
SaveAs,
Quit,
Cut,
Copy,
Paste,
Config,
}
pub fn center() -> (i32, i32) {
(
(app::screen_size().0 / 2.0) as i32,
(app::screen_size().1 / 2.0) as i32,
)
}
pub struct App {
app: app::App,
saved: bool,
filename: String,
r: app::Receiver<Message>,
buf: text::TextBuffer,
editor: editor::Editor,
}
impl App {
pub fn new(args: Vec<String>) -> Self {
let app = app::App::default().with_scheme(app::Scheme::Gtk);
app::background(0, 0, 0);
app::foreground(255, 255, 255);
app::set_frame_type(fltk::enums::FrameType::NoBox);
let (s, r) = app::channel::<Message>();
let mut buf = text::TextBuffer::default();
buf.set_tab_distance(4);
let mut main_win = window::Window::default()
.with_size(800, 600)
.center_screen()
.with_label("AblEditor");
let _menu = menu::Menu::new(&s);
let mut frame = fltk::frame::Frame::default();
frame.set_label_size(30);
frame.set_label(&"hi");
let mut editor = editor::Editor::new(buf.clone());
editor.emit(s, Message::Changed);
main_win.make_resizable(true);
// only resize editor, not the menu bar
main_win.resizable(&*editor);
main_win.end();
main_win.show();
main_win.set_callback(move |_| {
if app::event() == Event::Close {
s.send(Message::Quit);
}
});
let filename = if args.len() > 1 {
let file = path::Path::new(&args[1]);
assert!(
file.exists() && file.is_file(),
"An error occured while opening the file!"
);
buf.load_file(&args[1]).unwrap();
args[1].clone()
} else {
String::new()
};
// Handle drag and drop
let mut dnd = false;
let mut released = false;
editor.handle({
let mut buf = buf.clone();
move |_, ev| match ev {
Event::DndEnter => {
dnd = true;
true
}
Event::DndDrag => true,
Event::DndRelease => {
released = true;
true
}
Event::Paste => {
if dnd && released {
let path = app::event_text();
let path = std::path::Path::new(&path);
assert!(path.exists());
buf.load_file(&path).unwrap();
dnd = false;
released = false;
true
} else {
false
}
}
Event::DndLeave => {
dnd = false;
released = false;
true
}
_ => false,
}
});
Self {
app,
saved: true,
filename,
r,
buf,
editor,
}
}
pub fn save_file(&mut self) -> Result<(), Box<dyn error::Error>> {
let mut filename = self.filename.clone();
if self.saved {
if filename.is_empty() {
let mut dlg = dialog::FileDialog::new(dialog::FileDialogType::BrowseSaveFile);
dlg.set_option(dialog::FileDialogOptions::SaveAsConfirm);
dlg.show();
filename = dlg.filename().to_string_lossy().to_string();
if !filename.is_empty() {
self.buf.save_file(&filename).unwrap_or_else(|_| {
dialog::alert(center().0 - 200, center().1 - 100, "Please specify a file!")
});
self.saved = true;
}
} else if path::Path::new(&filename).exists() {
self.buf.save_file(&filename)?;
self.saved = true;
} else {
dialog::alert(center().0 - 200, center().1 - 100, "Please specify a file!")
}
} else {
let mut dlg = dialog::FileDialog::new(dialog::FileDialogType::BrowseSaveFile);
dlg.set_option(dialog::FileDialogOptions::SaveAsConfirm);
dlg.show();
filename = dlg.filename().to_string_lossy().to_string();
if !filename.is_empty() {
self.buf.save_file(&filename).unwrap_or_else(|_| {
dialog::alert(center().0 - 200, center().1 - 100, "Please specify a file!")
});
self.saved = true;
}
}
Ok(())
}
pub fn launch(&mut self) {
while self.app.wait() {
use Message::*;
if let Some(msg) = self.r.recv() {
match msg {
Changed => self.saved = false,
New => {
if self.buf.text() != "" {
let x = dialog::choice(
center().0 - 200,
center().1 - 100,
"File unsaved, Do you wish to continue?",
"Yes",
"No!",
"",
);
if x == 0 {
self.buf.set_text("");
}
}
}
Open => {
let mut dlg = dialog::FileDialog::new(dialog::FileDialogType::BrowseFile);
dlg.set_option(dialog::FileDialogOptions::NoOptions);
dlg.show();
let filename = dlg.filename().to_string_lossy().to_string();
if !filename.is_empty() {
if path::Path::new(&filename).exists() {
self.buf.load_file(&filename).unwrap();
self.filename = filename;
} else {
dialog::alert(
center().0 - 200,
center().1 - 100,
"File does not exist!",
)
}
}
}
Save | SaveAs => self.save_file().unwrap(),
Quit => {
if self.saved {
self.app.quit();
} else {
let x = dialog::choice(
center().0 - 200,
center().1 - 100,
"Would you like to save your work?",
"Yes",
"No",
"",
);
if x == 0 {
self.save_file().unwrap();
self.app.quit();
} else {
self.app.quit();
}
}
}
Cut => self.editor.cut(),
Copy => self.editor.copy(),
Paste => self.editor.paste(),
_ => {}
}
}
}
}
}
fn main() {
panic::set_hook(Box::new(|info| {
if let Some(s) = info.payload().downcast_ref::<&str>() {
dialog::message(center().0 - 200, center().1 - 100, s);
} else {
dialog::message(center().0 - 200, center().1 - 100, &info.to_string());
}
}));
let args: Vec<_> = std::env::args().collect();
let mut app = App::new(args);
app.launch();
}

105
src/menu.rs Normal file
View File

@ -0,0 +1,105 @@
use fltk::{
app,
enums::{Color, Shortcut},
menu,
prelude::{MenuExt, WidgetExt},
};
use crate::Message;
pub struct Menu {
_menu: menu::SysMenuBar,
}
impl Menu {
pub fn new(s: &app::Sender<Message>) -> Self {
let mut menu = menu::SysMenuBar::default().with_size(800, 35);
menu.set_text_color(Color::White);
menu.set_color(Color::Black);
menu.add_emit(
"&File/New...\t",
Shortcut::Ctrl | 'n',
menu::MenuFlag::Normal,
*s,
Message::New,
);
menu.add_emit(
"&File/Open...\t",
Shortcut::Ctrl | 'o',
menu::MenuFlag::Normal,
*s,
Message::Open,
);
menu.add_emit(
"&File/Save\t",
Shortcut::Ctrl | 's',
menu::MenuFlag::Normal,
*s,
Message::Save,
);
menu.add_emit(
"&File/Save as...\t",
Shortcut::Ctrl | 'w',
menu::MenuFlag::Normal,
*s,
Message::SaveAs,
);
menu.add_emit(
"&File/Quit\t",
Shortcut::Ctrl | 'q',
menu::MenuFlag::Normal,
*s,
Message::Quit,
);
menu.add_emit(
"&Edit/Cut\t",
Shortcut::Ctrl | 'x',
menu::MenuFlag::Normal,
*s,
Message::Cut,
);
menu.add_emit(
"&Edit/Copy\t",
Shortcut::Ctrl | 'c',
menu::MenuFlag::Normal,
*s,
Message::Copy,
);
menu.add_emit(
"&Edit/Paste\t",
Shortcut::Ctrl | 'v',
menu::MenuFlag::Normal,
*s,
Message::Paste,
);
/*
menu.add_emit(
"&Tools/Config\t",
Shortcut::Ctrl | '/',
menu::MenuFlag::Normal,
*s,
Message::Config,
);
menu.add_emit(
"&Tools/Terminal\t",
Shortcut::Ctrl | 't',
menu::MenuFlag::Normal,
*s,
Message::Config,
);
*/
if let Some(mut item) = menu.find_item("&File/Quit\t") {
item.set_label_color(Color::Red);
}
Self { _menu: menu }
}
}