Inital Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
4198
Cargo.lock
generated
Normal file
4198
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "gcodium"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
eframe = "0.33.3"
|
||||
rfd = "0.17.1"
|
||||
ropey = "1.6.1"
|
||||
37
src/main.rs
Normal file
37
src/main.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use eframe::egui;
|
||||
use rfd::FileDialog;
|
||||
|
||||
mod ropeintegration;
|
||||
mod rope_editor;
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions::default();
|
||||
eframe::run_native("gcodium", native_options, Box::new(|cc| Ok(Box::new(GCodium::new(cc)))));
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct GCodium {
|
||||
text_buffer: ropeintegration::ERopey,
|
||||
}
|
||||
|
||||
impl GCodium {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for GCodium {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Hello, World!");
|
||||
if ui.button("Open File").clicked() {
|
||||
let filepath = FileDialog::new().add_filter("text", &["txt"]).set_directory("/").pick_file().expect("File not Selected");
|
||||
let file = std::fs::File::open(filepath).expect("unable to open file");
|
||||
self.text_buffer.rope = ropey::Rope::from_reader(file).expect("unable to read file to rope");
|
||||
}
|
||||
ui.text_edit_multiline(&mut self.text_buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
126
src/rope_editor.rs
Normal file
126
src/rope_editor.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use std::{sync::Arc, usize};
|
||||
|
||||
use eframe::egui::{Align2, Color32, Context, EventFilter, FontSelection, Galley, Id, Key, KeyboardShortcut, Margin, Modifiers, NumExt, Shape, TextBuffer, Ui, Vec2, WidgetWithState, text::LayoutJob, text_edit::{TextEditOutput, TextEditState}};
|
||||
|
||||
type LayouterFn<'t> = &'t mut dyn FnMut(&Ui, &dyn TextBuffer, f32) -> Arc<Galley>;
|
||||
|
||||
pub struct RopeEdit<'t> {
|
||||
text: &'t mut dyn TextBuffer,
|
||||
//hint_text: String,
|
||||
//hint_text_font: Option<FontSelection>,
|
||||
id: Option<Id>,
|
||||
id_salt: Option<Id>,
|
||||
font_selection: FontSelection,
|
||||
text_color: Option<Color32>,
|
||||
layouter: Option<LayouterFn<'t>>,
|
||||
frame: bool,
|
||||
margin: Margin,
|
||||
desired_width: Option<f32>,
|
||||
desired_height_rows: usize,
|
||||
event_filter: EventFilter,
|
||||
cursor_at_end: bool,
|
||||
min_size: Vec2,
|
||||
align: Align2,
|
||||
char_limit: usize,
|
||||
return_key: Option<KeyboardShortcut>,
|
||||
background_color: Option<Color32>,
|
||||
}
|
||||
|
||||
impl WidgetWithState for RopeEdit<'_> {
|
||||
type State = TextEditState;
|
||||
}
|
||||
|
||||
impl RopeEdit<'_> {
|
||||
pub fn load_state(ctx: &Context, id: Id) -> Option<TextEditState> {
|
||||
TextEditState::load(ctx, id)
|
||||
}
|
||||
|
||||
pub fn store_state(ctx: &Context, id: Id, state: TextEditState) {
|
||||
state.store(ctx, id);
|
||||
}
|
||||
|
||||
pub fn show(self, ui: &mut Ui) -> TextEditOutput {
|
||||
let frame = self.frame;
|
||||
let where_to_put_background = ui.painter().add(Shape::Noop);
|
||||
let background_color = ui.visuals().text_edit_bg_color();
|
||||
let output = self.show_content(ui);
|
||||
}
|
||||
|
||||
pub fn show_content(self, ui: &mut Ui) -> TextEditOutput {
|
||||
let RopeEdit {
|
||||
text,
|
||||
//hint_text,
|
||||
//hint_text_font,
|
||||
id,
|
||||
id_salt,
|
||||
font_selection,
|
||||
text_color,
|
||||
layouter,
|
||||
frame,
|
||||
margin,
|
||||
desired_width,
|
||||
desired_height_rows,
|
||||
event_filter,
|
||||
cursor_at_end,
|
||||
min_size,
|
||||
align,
|
||||
char_limit,
|
||||
return_key,
|
||||
background_color
|
||||
} = self;
|
||||
|
||||
let text_color = text_color
|
||||
.or(ui.visuals().override_text_color)
|
||||
// .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright
|
||||
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color());
|
||||
|
||||
let font_id = font_selection.resolve(ui.style());
|
||||
let row_height = ui.fonts_mut(|f| f.row_height(&font_id));
|
||||
const MIN_WIDTH: f32 = 24.0;
|
||||
let available_width = (ui.available_width() - margin.sum().x).at_least(MIN_WIDTH);
|
||||
let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width);
|
||||
let wrap_width = if ui.layout().horizontal_justify() {
|
||||
available_width
|
||||
} else {
|
||||
desired_width.min(available_width)
|
||||
};
|
||||
|
||||
let font_id_clone = font_id.clone();
|
||||
let mut default_layouter = move |ui: &Ui, text: &dyn TextBuffer, wrap_width: f32,| {
|
||||
let layout_job = LayoutJob::simple(text, font_id_clone.clone(), text_color, wrap_width)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t> RopeEdit<'t> {
|
||||
pub fn new(text: &'t mut dyn TextBuffer) -> Self {
|
||||
Self {
|
||||
text,
|
||||
//hint_text: Default::default(),
|
||||
//hint_text_font: None,
|
||||
id: None,
|
||||
id_salt: None,
|
||||
font_selection: Default::default(),
|
||||
text_color: None,
|
||||
layouter: None,
|
||||
frame: false,
|
||||
margin: Margin::symmetric(4, 2),
|
||||
desired_width: None,
|
||||
desired_height_rows: 4,
|
||||
event_filter: EventFilter {
|
||||
tab: false,
|
||||
horizontal_arrows: true,
|
||||
vertical_arrows: true,
|
||||
..Default::default()
|
||||
},
|
||||
cursor_at_end: true,
|
||||
min_size: Vec2::ZERO,
|
||||
align: Align2::LEFT_TOP,
|
||||
char_limit: usize::MAX,
|
||||
return_key: Some(KeyboardShortcut::new(Modifiers::NONE, Key::Enter)),
|
||||
background_color: None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
33
src/ropeintegration.rs
Normal file
33
src/ropeintegration.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use eframe::egui::{self, scroll_area::State};
|
||||
use ropey;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ERopey {
|
||||
pub rope: ropey::Rope,
|
||||
viewbuffer: String,
|
||||
}
|
||||
|
||||
impl egui::widgets::TextBuffer for ERopey {
|
||||
fn is_mutable(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn as_str(&self) -> &str {
|
||||
self.rope.slice(..).as_str().unwrap()
|
||||
}
|
||||
|
||||
fn insert_text(&mut self, text: &str, char_index: usize) -> usize {
|
||||
let first = self.rope.len_chars();
|
||||
self.rope.insert(char_index, text);
|
||||
let second = self.rope.len_chars();
|
||||
second-first
|
||||
}
|
||||
|
||||
fn delete_char_range(&mut self, char_range: std::ops::Range<usize>) {
|
||||
self.rope.remove(char_range);
|
||||
}
|
||||
|
||||
fn type_id(&self) -> std::any::TypeId {
|
||||
std::any::TypeId::of::<Self>()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user