sync commit
This commit is contained in:
parent
8a9f3d82a7
commit
e08b8eb505
|
@ -19,6 +19,8 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"abacus-core",
|
"abacus-core",
|
||||||
"druid",
|
"druid",
|
||||||
|
"ropey",
|
||||||
|
"syntect",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1905,6 +1907,16 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ropey"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd22239fafefc42138ca5da064f3c17726a80d2379d817a3521240e78dd0064"
|
||||||
|
dependencies = [
|
||||||
|
"smallvec",
|
||||||
|
"str_indices",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -2085,6 +2097,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "str_indices"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9d9199fa80c817e074620be84374a520062ebac833f358d74b37060ce4a0f2c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strength_reduce"
|
name = "strength_reduce"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|
|
@ -7,4 +7,6 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
druid = { git = "https://github.com/linebender/druid.git" }
|
druid = { git = "https://github.com/linebender/druid.git" }
|
||||||
abacus-core = { path = "../abacus-core" }
|
abacus-core = { path = "../abacus-core" }
|
||||||
|
syntect = "5.0.0"
|
||||||
|
ropey = "1.5.0"
|
|
@ -1,8 +1,15 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use druid::{
|
use druid::{
|
||||||
piet::{Text, TextLayout, TextLayoutBuilder},
|
piet::{Text, TextAttribute, TextLayout, TextLayoutBuilder},
|
||||||
Color, Data, Event, FontFamily, Lens, LifeCycle, RenderContext, Widget,
|
Color, Data, Event, FontFamily, Lens, LifeCycle, Rect, RenderContext, Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use ropey::Rope;
|
||||||
|
use syntect::easy::HighlightLines;
|
||||||
|
use syntect::highlighting::{Style, ThemeSet};
|
||||||
|
use syntect::parsing::SyntaxSet;
|
||||||
|
|
||||||
#[derive(Clone, Data, PartialEq, Eq)]
|
#[derive(Clone, Data, PartialEq, Eq)]
|
||||||
pub enum EditMode {
|
pub enum EditMode {
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -13,44 +20,150 @@ pub struct AbacusEditor;
|
||||||
|
|
||||||
#[derive(Data, Lens, Clone)]
|
#[derive(Data, Lens, Clone)]
|
||||||
pub struct EditorData {
|
pub struct EditorData {
|
||||||
pub raw_content: String,
|
#[data(same_fn = "PartialEq::eq")]
|
||||||
|
pub content: Rope,
|
||||||
pub cursor_pos: usize,
|
pub cursor_pos: usize,
|
||||||
pub mode: EditMode,
|
pub mode: EditMode,
|
||||||
|
pub cursor_opactiy: f64,
|
||||||
|
pub cursor_fade: f64,
|
||||||
|
pub selection_pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EditorData {
|
impl Default for EditorData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
raw_content: "let x = 1;\nx+1".to_string(),
|
content: Rope::from_str("let x = 1;\nx+1"),
|
||||||
cursor_pos: 5,
|
cursor_pos: 5,
|
||||||
|
selection_pos: 5,
|
||||||
mode: EditMode::Normal,
|
mode: EditMode::Normal,
|
||||||
|
cursor_opactiy: 0.1,
|
||||||
|
cursor_fade: 1.0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditorData {
|
impl EditorData {
|
||||||
|
pub fn move_cursor(&mut self, idx: usize) {
|
||||||
|
self.cursor_pos = idx;
|
||||||
|
self.deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_range(&self) -> Range<usize> {
|
||||||
|
if self.cursor_pos > self.selection_pos {
|
||||||
|
self.selection_pos..self.cursor_pos
|
||||||
|
} else {
|
||||||
|
self.cursor_pos..self.selection_pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push_str(&mut self, s: &str) {
|
pub fn push_str(&mut self, s: &str) {
|
||||||
self.raw_content.push_str(s);
|
if self.selection_pos != self.cursor_pos {
|
||||||
self.cursor_to_end();
|
self.content.remove(self.select_range());
|
||||||
|
self.content.insert(self.select_range().start, s);
|
||||||
|
} else {
|
||||||
|
self.content.insert(self.cursor_pos, s);
|
||||||
|
}
|
||||||
|
self.move_cursor(self.select_range().start + s.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, c: char) {
|
pub fn push(&mut self, c: char) {
|
||||||
self.raw_content.push(c);
|
self.content.insert_char(self.cursor_pos, c);
|
||||||
self.cursor_to_end();
|
self.cursor_right();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_to_end(&mut self) {
|
// pub fn cursor_to_end(&mut self) {
|
||||||
self.cursor_pos = self.raw_content.len();
|
// self.move_cursor(self.content.len_chars());
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub fn deselect(&mut self) {
|
||||||
|
self.selection_pos = self.cursor_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_char_back(&mut self) {
|
pub fn delete_char_back(&mut self) {
|
||||||
self.raw_content.pop();
|
if !self.select_range().is_empty() {
|
||||||
self.cursor_to_end();
|
let range = self.select_range();
|
||||||
|
self.content.remove(self.select_range());
|
||||||
|
self.move_cursor(range.start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.cursor_pos > 0 {
|
||||||
|
if self.cursor_pos == self.content.len_chars() {
|
||||||
|
self.content
|
||||||
|
.remove(self.content.len_chars()..self.content.len_chars());
|
||||||
|
|
||||||
|
// self.raw_content.pop();
|
||||||
|
} else {
|
||||||
|
self.content.remove((self.cursor_pos - 1)..self.cursor_pos);
|
||||||
|
}
|
||||||
|
self.cursor_left();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_left(&mut self) {
|
||||||
|
if self.cursor_pos > 0 {
|
||||||
|
self.move_cursor(self.cursor_pos - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_up(&mut self) {
|
||||||
|
let line_idx = self.content.char_to_line(self.cursor_pos);
|
||||||
|
|
||||||
|
if line_idx > 0 {
|
||||||
|
let start_of_current_line = self.content.line_to_char(line_idx);
|
||||||
|
let line_pos = self.cursor_pos - start_of_current_line;
|
||||||
|
let up_line_start = self.content.line_to_char(line_idx - 1);
|
||||||
|
let up_line = self.content.line(line_idx - 1);
|
||||||
|
dbg!(line_pos.min(up_line.len_chars()));
|
||||||
|
self.move_cursor(up_line_start + line_pos.min(up_line.len_chars() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_down(&mut self) {
|
||||||
|
let line_idx = self.content.char_to_line(self.cursor_pos);
|
||||||
|
if line_idx < self.content.len_lines() - 1 {
|
||||||
|
let start_of_current_line = self.content.line_to_char(line_idx);
|
||||||
|
let line_pos = self.cursor_pos - start_of_current_line;
|
||||||
|
let start_of_next_line = self.content.line_to_char(line_idx + 1);
|
||||||
|
let next_line_len = self.content.line(line_idx + 1).len_chars();
|
||||||
|
|
||||||
|
self.move_cursor(start_of_next_line + line_pos.min(next_line_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_right(&mut self) {
|
||||||
|
if self.cursor_pos < self.content.len_chars() {
|
||||||
|
self.move_cursor(self.cursor_pos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_to_end_of_line(&mut self) {
|
||||||
|
let line_idx = self.content.char_to_line(self.cursor_pos);
|
||||||
|
let start_of_line = self.content.line_to_char(line_idx);
|
||||||
|
let line = self.content.line(line_idx);
|
||||||
|
if line_idx == self.content.len_lines() - 1 {
|
||||||
|
self.move_cursor(start_of_line + line.len_chars());
|
||||||
|
} else {
|
||||||
|
self.move_cursor(start_of_line + line.len_chars() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_to_start_of_line(&mut self) {
|
||||||
|
let start_of_line = self
|
||||||
|
.content
|
||||||
|
.line_to_char(self.content.char_to_line(self.cursor_pos));
|
||||||
|
|
||||||
|
self.move_cursor(start_of_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_all(&mut self) {
|
||||||
|
self.selection_pos = self.content.len_chars();
|
||||||
|
self.cursor_pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget<EditorData> for AbacusEditor {
|
impl Widget<EditorData> for AbacusEditor {
|
||||||
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &EditorData, env: &druid::Env) {
|
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &EditorData, _env: &druid::Env) {
|
||||||
let size = ctx.size();
|
let size = ctx.size();
|
||||||
let rect = size.to_rect();
|
let rect = size.to_rect();
|
||||||
|
|
||||||
|
@ -60,25 +173,94 @@ impl Widget<EditorData> for AbacusEditor {
|
||||||
ctx.fill(rect, &Color::rgb8(20, 20, 20));
|
ctx.fill(rect, &Color::rgb8(20, 20, 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = ctx
|
if data.content.len_chars() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ps = SyntaxSet::load_defaults_newlines();
|
||||||
|
let ts = ThemeSet::load_defaults();
|
||||||
|
let syntax = ps.find_syntax_by_extension("rs").unwrap();
|
||||||
|
let mut h = HighlightLines::new(syntax, &ts.themes["base16-mocha.dark"]);
|
||||||
|
|
||||||
|
let mut layout = ctx
|
||||||
.text()
|
.text()
|
||||||
.new_text_layout(data.raw_content.clone())
|
.new_text_layout(data.content.to_string())
|
||||||
.font(FontFamily::MONOSPACE, 24.0)
|
.font(FontFamily::MONOSPACE, 22.0);
|
||||||
.text_color(Color::rgb8(255, 255, 255))
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
dbg!(layout.rects_for_range((data.cursor_pos - 1)..data.cursor_pos));
|
let mut pos = 0;
|
||||||
ctx.fill(
|
for line in data.content.lines() {
|
||||||
layout
|
let s = line.to_string();
|
||||||
.rects_for_range((data.cursor_pos - 1)..data.cursor_pos)
|
let ranges: Vec<(Style, &str)> = h.highlight_line(&s, &ps).unwrap();
|
||||||
|
|
||||||
|
for (style, txt) in ranges {
|
||||||
|
layout = layout.range_attribute(
|
||||||
|
pos..(pos + txt.len()),
|
||||||
|
TextAttribute::TextColor(Color::rgba8(
|
||||||
|
style.foreground.r,
|
||||||
|
style.foreground.g,
|
||||||
|
style.foreground.b,
|
||||||
|
style.foreground.a,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
pos += txt.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout = layout.build().unwrap();
|
||||||
|
|
||||||
|
// paint cursor
|
||||||
|
if data.mode == EditMode::Insert {
|
||||||
|
if let Some(char_rect) = layout
|
||||||
|
.rects_for_range((data.cursor_pos.max(1) - 1)..data.cursor_pos)
|
||||||
.last()
|
.last()
|
||||||
.unwrap(),
|
{
|
||||||
&Color::rgb8(50, 50, 50),
|
let cursor_rect = Rect::new(
|
||||||
);
|
char_rect.max_x() + 3.0,
|
||||||
ctx.draw_text(&layout, (1.0, 1.0));
|
char_rect.min_y() + 2.0,
|
||||||
|
char_rect.max_x() + 5.0,
|
||||||
|
char_rect.max_y() - 2.0,
|
||||||
|
);
|
||||||
|
|
||||||
dbg!(ctx.is_focused());
|
ctx.fill(
|
||||||
|
cursor_rect,
|
||||||
|
&Color::rgba8(255, 255, 255, data.cursor_opactiy.floor() as u8),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.mode == EditMode::Normal {
|
||||||
|
if let Some(char_rect) = layout
|
||||||
|
.rects_for_range((data.cursor_pos.max(1) - 1)..data.cursor_pos)
|
||||||
|
.last()
|
||||||
|
{
|
||||||
|
if char_rect.width() == 0. {
|
||||||
|
let rect = Rect::new(
|
||||||
|
char_rect.min_x(),
|
||||||
|
char_rect.min_y(),
|
||||||
|
char_rect.min_x() + 10.,
|
||||||
|
char_rect.max_y(),
|
||||||
|
);
|
||||||
|
ctx.fill(
|
||||||
|
rect,
|
||||||
|
&Color::rgba8(255, 255, 255, data.cursor_opactiy.floor() as u8),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
ctx.fill(
|
||||||
|
char_rect,
|
||||||
|
&Color::rgba8(255, 255, 255, data.cursor_opactiy.floor() as u8),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.selection_pos != data.cursor_pos {
|
||||||
|
let rects = layout.rects_for_range(data.select_range());
|
||||||
|
for rect in rects.iter() {
|
||||||
|
ctx.fill(rect, &Color::rgb8(90, 90, 90));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.draw_text(&layout, (1.0, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(
|
fn event(
|
||||||
|
@ -86,33 +268,137 @@ impl Widget<EditorData> for AbacusEditor {
|
||||||
ctx: &mut druid::EventCtx,
|
ctx: &mut druid::EventCtx,
|
||||||
event: &druid::Event,
|
event: &druid::Event,
|
||||||
data: &mut EditorData,
|
data: &mut EditorData,
|
||||||
env: &druid::Env,
|
_env: &druid::Env,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
Event::KeyUp(e) => match &e.key {
|
Event::KeyDown(e) => match &e.key {
|
||||||
druid::keyboard_types::Key::Character(c) => {
|
druid::keyboard_types::Key::Character(ch)
|
||||||
|
if data.mode == EditMode::Insert && e.mods.ctrl() =>
|
||||||
|
{
|
||||||
|
match ch.as_ref() {
|
||||||
|
"a" => {
|
||||||
|
if e.mods.ctrl() {
|
||||||
|
data.select_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"u" => {}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::Character(c) if data.mode == EditMode::Insert => {
|
||||||
data.push_str(c);
|
data.push_str(c);
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
|
druid::keyboard_types::Key::Character(ch) if data.mode == EditMode::Normal => {
|
||||||
|
match ch.as_ref() {
|
||||||
|
"i" => {
|
||||||
|
data.mode = EditMode::Insert;
|
||||||
|
}
|
||||||
|
"A" => {
|
||||||
|
data.mode = EditMode::Insert;
|
||||||
|
data.cursor_to_end_of_line();
|
||||||
|
}
|
||||||
|
"a" => {
|
||||||
|
if e.mods.ctrl() {
|
||||||
|
data.select_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"h" => {
|
||||||
|
data.cursor_left();
|
||||||
|
}
|
||||||
|
"j" => {
|
||||||
|
data.cursor_down();
|
||||||
|
}
|
||||||
|
"k" => {
|
||||||
|
data.cursor_up();
|
||||||
|
}
|
||||||
|
"l" => {
|
||||||
|
data.cursor_right();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
druid::keyboard_types::Key::Enter => {
|
druid::keyboard_types::Key::Enter => {
|
||||||
data.push('\n');
|
data.push('\n');
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
|
ctx.request_layout();
|
||||||
}
|
}
|
||||||
druid::keyboard_types::Key::Backspace => {
|
druid::keyboard_types::Key::Backspace => {
|
||||||
data.delete_char_back();
|
data.delete_char_back();
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
}
|
}
|
||||||
druid::keyboard_types::Key::Escape => {
|
druid::keyboard_types::Key::Escape => {
|
||||||
data.mode == EditMode::Normal;
|
data.mode = EditMode::Normal;
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::ArrowLeft if !e.mods.shift() => {
|
||||||
|
data.cursor_left();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::ArrowRight if !e.mods.shift() => {
|
||||||
|
data.cursor_right();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::ArrowUp if !e.mods.shift() => {
|
||||||
|
data.cursor_up();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::ArrowDown if !e.mods.shift() => {
|
||||||
|
data.cursor_down();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::Tab => {
|
||||||
|
data.push_str(" ");
|
||||||
|
ctx.request_paint();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::End => {
|
||||||
|
data.cursor_to_end_of_line();
|
||||||
|
data.deselect();
|
||||||
|
}
|
||||||
|
druid::keyboard_types::Key::Home => {
|
||||||
|
data.cursor_to_start_of_line();
|
||||||
|
data.deselect();
|
||||||
}
|
}
|
||||||
e => {
|
e => {
|
||||||
dbg!(e);
|
dbg!(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Event::MouseDown(_) => {
|
Event::MouseDown(e) => {
|
||||||
if !ctx.is_focused() {
|
if !ctx.is_focused() {
|
||||||
ctx.request_focus();
|
ctx.request_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let layout = ctx
|
||||||
|
.text()
|
||||||
|
.new_text_layout(data.content.to_string())
|
||||||
|
.font(FontFamily::MONOSPACE, 24.0)
|
||||||
|
.text_color(Color::rgb8(255, 255, 255))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let pos = layout.hit_test_point(e.pos);
|
||||||
|
data.cursor_pos = pos.idx;
|
||||||
|
data.selection_pos = pos.idx;
|
||||||
|
}
|
||||||
|
Event::MouseMove(e) => {
|
||||||
|
let layout = ctx
|
||||||
|
.text()
|
||||||
|
.new_text_layout(data.content.to_string())
|
||||||
|
.font(FontFamily::MONOSPACE, 24.0)
|
||||||
|
.text_color(Color::rgb8(255, 255, 255))
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let pos = layout.hit_test_point(e.pos);
|
||||||
|
if e.buttons.has_left() {
|
||||||
|
data.selection_pos = pos.idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::AnimFrame(e) => {
|
||||||
|
data.cursor_opactiy += ((*e as f64) * 0.00000065) * data.cursor_fade;
|
||||||
|
if data.cursor_opactiy >= 255.0 {
|
||||||
|
data.cursor_opactiy = 255.0;
|
||||||
|
data.cursor_fade *= -1.0;
|
||||||
|
} else if data.cursor_opactiy <= 0.0 {
|
||||||
|
data.cursor_opactiy = 0.1;
|
||||||
|
data.cursor_fade *= -1.0;
|
||||||
|
}
|
||||||
|
ctx.request_paint();
|
||||||
|
ctx.request_anim_frame();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -122,12 +408,13 @@ impl Widget<EditorData> for AbacusEditor {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut druid::LifeCycleCtx,
|
ctx: &mut druid::LifeCycleCtx,
|
||||||
event: &druid::LifeCycle,
|
event: &druid::LifeCycle,
|
||||||
data: &EditorData,
|
_data: &EditorData,
|
||||||
env: &druid::Env,
|
_env: &druid::Env,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
LifeCycle::FocusChanged(_) => {
|
LifeCycle::FocusChanged(_) => {
|
||||||
ctx.request_paint();
|
ctx.request_paint();
|
||||||
|
ctx.request_anim_frame();
|
||||||
}
|
}
|
||||||
LifeCycle::WidgetAdded => {
|
LifeCycle::WidgetAdded => {
|
||||||
// ctx.register_text_input(document)
|
// ctx.register_text_input(document)
|
||||||
|
@ -141,10 +428,10 @@ impl Widget<EditorData> for AbacusEditor {
|
||||||
|
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut druid::UpdateCtx,
|
_ctx: &mut druid::UpdateCtx,
|
||||||
old_data: &EditorData,
|
_old_data: &EditorData,
|
||||||
data: &EditorData,
|
_data: &EditorData,
|
||||||
env: &druid::Env,
|
_env: &druid::Env,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,8 +440,16 @@ impl Widget<EditorData> for AbacusEditor {
|
||||||
ctx: &mut druid::LayoutCtx,
|
ctx: &mut druid::LayoutCtx,
|
||||||
bc: &druid::BoxConstraints,
|
bc: &druid::BoxConstraints,
|
||||||
data: &EditorData,
|
data: &EditorData,
|
||||||
env: &druid::Env,
|
_env: &druid::Env,
|
||||||
) -> druid::Size {
|
) -> druid::Size {
|
||||||
|
let layout = ctx
|
||||||
|
.text()
|
||||||
|
.new_text_layout(data.content.to_string())
|
||||||
|
.font(FontFamily::MONOSPACE, 22.0)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
bc.shrink_max_height_to(layout.size().height);
|
||||||
bc.max()
|
bc.max()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,14 @@
|
||||||
mod editor;
|
mod editor;
|
||||||
|
|
||||||
use druid::widget::{Align, Flex, Label, Padding, RawLabel};
|
use druid::widget::{Flex, Padding};
|
||||||
use druid::{AppLauncher, Color, Data, PlatformError, Widget, WidgetExt, WindowDesc};
|
use druid::{AppLauncher, Data, PlatformError, Widget, WindowDesc};
|
||||||
use editor::EditorData;
|
|
||||||
|
|
||||||
fn build_ui() -> impl Widget<editor::EditorData> {
|
fn build_ui() -> impl Widget<editor::EditorData> {
|
||||||
Padding::new(
|
Padding::new(
|
||||||
10.0,
|
10.0,
|
||||||
Flex::row()
|
Flex::column()
|
||||||
.with_flex_child(
|
.with_flex_child(Padding::new(10.0, editor::AbacusEditor), 2.0)
|
||||||
Flex::column().with_flex_child(editor::AbacusEditor, 1.0),
|
.with_flex_child(editor::AbacusEditor, 1.0),
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
.with_flex_child(
|
|
||||||
Flex::column()
|
|
||||||
.with_flex_child(
|
|
||||||
Label::new("top right").background(Color::rgb8(0, 0, 255)),
|
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
.with_flex_child(Align::centered(Label::new("bottom right")), 1.0),
|
|
||||||
1.0,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue