Implement text clicking again
This commit is contained in:
parent
a66b8fdde2
commit
a867d4520a
1 changed files with 99 additions and 25 deletions
|
|
@ -1,6 +1,8 @@
|
|||
use orbclient::{Color, EventOption, Renderer, Window, WindowFlag};
|
||||
use std::{
|
||||
cmp,
|
||||
env,
|
||||
fs,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
|
|
@ -21,7 +23,8 @@ impl<'a> Font<'a> {
|
|||
}
|
||||
|
||||
struct FontLayoutGlyph<'a> {
|
||||
info: rustybuzz::GlyphInfo,
|
||||
start: usize,
|
||||
end: usize,
|
||||
inner: rusttype::PositionedGlyph<'a>,
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +56,8 @@ impl<'a> FontLayoutLine<'a> {
|
|||
}
|
||||
|
||||
struct FontShapeGlyph<'a> {
|
||||
start: usize,
|
||||
end: usize,
|
||||
info: rustybuzz::GlyphInfo,
|
||||
pos: rustybuzz::GlyphPosition,
|
||||
font: &'a Font<'a>
|
||||
|
|
@ -125,7 +130,8 @@ impl<'a> FontShapeLine<'a> {
|
|||
));
|
||||
|
||||
glyphs.push(FontLayoutGlyph {
|
||||
info: glyph.info,
|
||||
start: glyph.start,
|
||||
end: glyph.end,
|
||||
inner,
|
||||
});
|
||||
|
||||
|
|
@ -149,16 +155,18 @@ struct FontMatches<'a> {
|
|||
}
|
||||
|
||||
impl<'a> FontMatches<'a> {
|
||||
pub fn shape_span(&self, string: &str) -> FontShapeSpan {
|
||||
fn shape_span(&self, string: &'a str, start_span: usize, end_span: usize) -> FontShapeSpan {
|
||||
let span = &string[start_span..end_span];
|
||||
|
||||
let mut spans_by_font = Vec::with_capacity(self.fonts.len());
|
||||
for (font_i, font) in self.fonts.iter().enumerate() {
|
||||
let mut buffer = rustybuzz::UnicodeBuffer::new();
|
||||
buffer.push_str(string);
|
||||
buffer.push_str(span);
|
||||
buffer.guess_segment_properties();
|
||||
let script = buffer.script();
|
||||
let direction = buffer.direction();
|
||||
if font_i == 0 {
|
||||
println!(" {:?}, {:?}: '{}'", script, direction, string);
|
||||
println!("{:?}, {:?}: '{}'", script, direction, span);
|
||||
}
|
||||
|
||||
let glyph_buffer = rustybuzz::shape(&font.rustybuzz, &[], buffer);
|
||||
|
|
@ -173,12 +181,21 @@ impl<'a> FontMatches<'a> {
|
|||
misses += 1;
|
||||
}
|
||||
glyphs.push(FontShapeGlyph {
|
||||
start: start_span + info.cluster as usize,
|
||||
end: end_span, // Set later
|
||||
info: *info,
|
||||
pos: *pos,
|
||||
font,
|
||||
});
|
||||
}
|
||||
|
||||
// Adjust end of glyphs
|
||||
for i in (1..glyphs.len()).rev() {
|
||||
if glyphs[i - 1].start == glyphs[i].start {
|
||||
glyphs[i - 1].end = glyphs[i].end;
|
||||
}
|
||||
}
|
||||
|
||||
let span = FontShapeSpan {
|
||||
direction,
|
||||
glyphs
|
||||
|
|
@ -206,26 +223,25 @@ impl<'a> FontMatches<'a> {
|
|||
spans_by_font.remove(least_misses_i).1
|
||||
}
|
||||
|
||||
pub fn shape_line(&self, string: &str) -> FontShapeLine {
|
||||
fn shape_line(&self, string: &'a str, start_line: usize, end_line: usize) -> FontShapeLine {
|
||||
use unicode_script::{Script, UnicodeScript};
|
||||
|
||||
let line = &string[start_line..end_line];
|
||||
|
||||
//TODO: more special handling of characters
|
||||
let mut spans = Vec::new();
|
||||
|
||||
println!("'{}'", string);
|
||||
|
||||
let mut start = 0;
|
||||
let mut prev = Script::Unknown;
|
||||
for (i, c) in string.char_indices() {
|
||||
if ! string.is_char_boundary(i) {
|
||||
for (i, c) in line.char_indices() {
|
||||
if ! line.is_char_boundary(i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cur = c.script();
|
||||
if prev != cur && prev != Script::Unknown {
|
||||
println!("*{:?} != {:?}", prev, cur);
|
||||
// No combination, start new span
|
||||
spans.push(self.shape_span(&string[start..i]));
|
||||
spans.push(self.shape_span(string, start_line + start, start_line + i));
|
||||
start = i;
|
||||
prev = Script::Unknown;
|
||||
} else {
|
||||
|
|
@ -233,9 +249,9 @@ impl<'a> FontMatches<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
spans.push(self.shape_span(&string[start..string.len()]));
|
||||
spans.push(self.shape_span(string, start_line + start, start_line + line.len()));
|
||||
|
||||
let bidi = unicode_bidi::BidiInfo::new(string, None);
|
||||
let bidi = unicode_bidi::BidiInfo::new(line, None);
|
||||
let rtl = if bidi.paragraphs.is_empty() {
|
||||
false
|
||||
} else {
|
||||
|
|
@ -248,6 +264,26 @@ impl<'a> FontMatches<'a> {
|
|||
spans,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shape(&self, string: &'a str) -> Vec<FontShapeLine> {
|
||||
let mut lines = Vec::new();
|
||||
|
||||
let mut start = 0;
|
||||
for (i, c) in string.char_indices() {
|
||||
if ! string.is_char_boundary(i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if c == '\n' {
|
||||
lines.push(self.shape_line(string, start, i));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(self.shape_line(string, start, string.len()));
|
||||
|
||||
lines
|
||||
}
|
||||
}
|
||||
|
||||
struct FontSystem<'a> {
|
||||
|
|
@ -319,9 +355,15 @@ fn main() {
|
|||
).unwrap();
|
||||
|
||||
#[cfg(feature = "mono")]
|
||||
let text = include_str!("../res/mono.txt");
|
||||
let default_text = include_str!("../res/mono.txt");
|
||||
#[cfg(not(feature = "mono"))]
|
||||
let text = include_str!("../res/proportional.txt");
|
||||
let default_text = include_str!("../res/proportional.txt");
|
||||
|
||||
let text = if let Some(arg) = env::args().nth(1) {
|
||||
fs::read_to_string(&arg).expect("failed to open file")
|
||||
} else {
|
||||
default_text.to_string()
|
||||
};
|
||||
|
||||
let bg_color = Color::rgb(0x34, 0x34, 0x34);
|
||||
let font_color = Color::rgb(0xFF, 0xFF, 0xFF);
|
||||
|
|
@ -360,14 +402,12 @@ fn main() {
|
|||
|
||||
let font_matches = font_system.matches(font_pattern).unwrap();
|
||||
|
||||
let mut shape_lines = Vec::new();
|
||||
for line in text.lines() {
|
||||
shape_lines.push(font_matches.shape_line(line));
|
||||
}
|
||||
let shape_lines = font_matches.shape(&text);
|
||||
|
||||
let mut layout_lines = Vec::new();
|
||||
let mut mouse_x = -1;
|
||||
let mut mouse_y = -1;
|
||||
let mut mouse_left = false;
|
||||
let mut redraw = true;
|
||||
let mut relayout = true;
|
||||
let mut scroll = 0;
|
||||
|
|
@ -379,7 +419,8 @@ fn main() {
|
|||
|
||||
layout_lines.clear();
|
||||
for line in shape_lines.iter() {
|
||||
line.layout(font_size, window.width() as i32, &mut layout_lines);
|
||||
let line_width = window.width() as i32 - 16;
|
||||
line.layout(font_size, line_width, &mut layout_lines);
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
|
|
@ -400,17 +441,40 @@ fn main() {
|
|||
scroll
|
||||
));
|
||||
|
||||
let line_x = 8;
|
||||
let mut line_y = line_height;
|
||||
for line in layout_lines.iter().skip(scroll as usize) {
|
||||
if line_y >= window.height() as i32 {
|
||||
break;
|
||||
}
|
||||
|
||||
let mut line_x = 0;
|
||||
let line_width = window.width() as i32;
|
||||
if mouse_y >= line_y - font_size
|
||||
&& mouse_y < line_y - font_size + line_height
|
||||
{
|
||||
let mut i = 0;
|
||||
while i < line.glyphs.len() {
|
||||
let glyph = &line.glyphs[i];
|
||||
i += 1;
|
||||
|
||||
if let Some(bb) = glyph.inner.pixel_bounding_box() {
|
||||
if mouse_x >= line_x + bb.min.x && mouse_x <= line_x + bb.max.x {
|
||||
window.rect(
|
||||
line_x + bb.min.x,
|
||||
line_y - font_size,
|
||||
bb.width() as u32,
|
||||
line_height as u32,
|
||||
Color::rgba(0xFF, 0xFF, 0xFF, 0x20)
|
||||
);
|
||||
|
||||
println!("{}, {}: '{}'", glyph.start, glyph.end, &text[glyph.start..glyph.end]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
line.draw(
|
||||
&mut window,
|
||||
0,
|
||||
line_x,
|
||||
line_y,
|
||||
font_color
|
||||
);
|
||||
|
|
@ -448,8 +512,18 @@ fn main() {
|
|||
EventOption::Mouse(event) => {
|
||||
mouse_x = event.x;
|
||||
mouse_y = event.y;
|
||||
redraw = true;
|
||||
if mouse_left {
|
||||
redraw = true;
|
||||
}
|
||||
},
|
||||
EventOption::Button(event) => {
|
||||
if event.left != mouse_left {
|
||||
mouse_left = event.left;
|
||||
if mouse_left {
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EventOption::Resize(_) => {
|
||||
relayout = true;
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue