161 lines
3.9 KiB
Rust
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()
|
|
}
|
|
}
|