Initial Commit
This commit is contained in:
commit
1588af501b
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
185
Cargo.lock
generated
Normal file
185
Cargo.lock
generated
Normal 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
12
Cargo.toml
Normal 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
24
src/config.rs
Normal 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
47
src/editor.rs
Normal 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
249
src/main.rs
Normal 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
105
src/menu.rs
Normal 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 }
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue