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