abacus/abacus-ui/src/editor.rs

161 lines
3.9 KiB
Rust

use druid::{
piet::{Text, TextLayout, TextLayoutBuilder},
Color, Data, Event, FontFamily, Lens, LifeCycle, RenderContext, Widget,
};
#[derive(Clone, Data, PartialEq, Eq)]
pub enum EditMode {
Normal,
Insert,
}
pub struct AbacusEditor;
#[derive(Data, Lens, Clone)]
pub struct EditorData {
pub raw_content: String,
pub cursor_pos: usize,
pub mode: EditMode,
}
impl Default for EditorData {
fn default() -> Self {
Self {
raw_content: "let x = 1;\nx+1".to_string(),
cursor_pos: 5,
mode: EditMode::Normal,
}
}
}
impl EditorData {
pub fn push_str(&mut self, s: &str) {
self.raw_content.push_str(s);
self.cursor_to_end();
}
pub fn push(&mut self, c: char) {
self.raw_content.push(c);
self.cursor_to_end();
}
pub fn cursor_to_end(&mut self) {
self.cursor_pos = self.raw_content.len();
}
pub fn delete_char_back(&mut self) {
self.raw_content.pop();
self.cursor_to_end();
}
}
impl Widget<EditorData> for AbacusEditor {
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &EditorData, env: &druid::Env) {
let size = ctx.size();
let rect = size.to_rect();
if ctx.is_focused() {
ctx.fill(rect, &Color::rgb8(10, 10, 10));
} else {
ctx.fill(rect, &Color::rgb8(20, 20, 20));
}
let layout = ctx
.text()
.new_text_layout(data.raw_content.clone())
.font(FontFamily::MONOSPACE, 24.0)
.text_color(Color::rgb8(255, 255, 255))
.build()
.unwrap();
dbg!(layout.rects_for_range((data.cursor_pos - 1)..data.cursor_pos));
ctx.fill(
layout
.rects_for_range((data.cursor_pos - 1)..data.cursor_pos)
.last()
.unwrap(),
&Color::rgb8(50, 50, 50),
);
ctx.draw_text(&layout, (1.0, 1.0));
dbg!(ctx.is_focused());
}
fn event(
&mut self,
ctx: &mut druid::EventCtx,
event: &druid::Event,
data: &mut EditorData,
env: &druid::Env,
) {
match event {
Event::KeyUp(e) => match &e.key {
druid::keyboard_types::Key::Character(c) => {
data.push_str(c);
ctx.request_paint();
}
druid::keyboard_types::Key::Enter => {
data.push('\n');
ctx.request_paint();
}
druid::keyboard_types::Key::Backspace => {
data.delete_char_back();
ctx.request_paint();
}
druid::keyboard_types::Key::Escape => {
data.mode == EditMode::Normal;
}
e => {
dbg!(e);
}
},
Event::MouseDown(_) => {
if !ctx.is_focused() {
ctx.request_focus();
}
}
_ => {}
}
}
fn lifecycle(
&mut self,
ctx: &mut druid::LifeCycleCtx,
event: &druid::LifeCycle,
data: &EditorData,
env: &druid::Env,
) {
match event {
LifeCycle::FocusChanged(_) => {
ctx.request_paint();
}
LifeCycle::WidgetAdded => {
// ctx.register_text_input(document)
}
LifeCycle::BuildFocusChain => {
ctx.register_for_focus();
}
_ => {}
}
}
fn update(
&mut self,
ctx: &mut druid::UpdateCtx,
old_data: &EditorData,
data: &EditorData,
env: &druid::Env,
) {
}
fn layout(
&mut self,
ctx: &mut druid::LayoutCtx,
bc: &druid::BoxConstraints,
data: &EditorData,
env: &druid::Env,
) -> druid::Size {
bc.max()
}
}