mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-10 03:10:41 +00:00
Better UTF-8 support in views
EditView, TextView, Dialog and Button should now properly display and layout non-ascii text. The lorem example now includes greek text to show this.
This commit is contained in:
parent
ae93b68c05
commit
6c6f929430
@ -17,3 +17,23 @@ Praesent dui lectus, commodo eget nulla ut, maximus facilisis ligula. Aliquam ul
|
|||||||
Etiam diam neque, dictum in eros ac, lacinia gravida orci. Cras in nisi augue. Fusce condimentum vestibulum nisl convallis lacinia. Mauris ligula diam, facilisis quis nulla ut, luctus feugiat eros. Duis ac consequat nisl. Nulla facilisi. Integer euismod mauris a feugiat gravida. Nulla consectetur est vitae lectus semper porttitor. Cras pellentesque tincidunt lacus, id sagittis lectus tincidunt eu. Mauris pellentesque lobortis aliquet. Mauris nec est bibendum, cursus metus eget, maximus nunc. Donec fermentum eros quis dolor imperdiet accumsan.
|
Etiam diam neque, dictum in eros ac, lacinia gravida orci. Cras in nisi augue. Fusce condimentum vestibulum nisl convallis lacinia. Mauris ligula diam, facilisis quis nulla ut, luctus feugiat eros. Duis ac consequat nisl. Nulla facilisi. Integer euismod mauris a feugiat gravida. Nulla consectetur est vitae lectus semper porttitor. Cras pellentesque tincidunt lacus, id sagittis lectus tincidunt eu. Mauris pellentesque lobortis aliquet. Mauris nec est bibendum, cursus metus eget, maximus nunc. Donec fermentum eros quis dolor imperdiet accumsan.
|
||||||
|
|
||||||
Sed vitae rhoncus velit. Proin eu luctus libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean imperdiet diam vitae eros vehicula mattis. Sed auctor erat et sapien mattis, sit amet faucibus risus tempus. Praesent ut commodo dui. Pellentesque et sodales purus. Nullam mollis sed urna eget aliquet.
|
Sed vitae rhoncus velit. Proin eu luctus libero. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean imperdiet diam vitae eros vehicula mattis. Sed auctor erat et sapien mattis, sit amet faucibus risus tempus. Praesent ut commodo dui. Pellentesque et sodales purus. Nullam mollis sed urna eget aliquet.
|
||||||
|
|
||||||
|
Μελιορε ιμπερδιετ αδ φιξ, δωλορε θριθανι ασυσαμυς ευ πρι. Ευ ναμ αδχυς σριπτορεμ. Δισερετ ωπωρθεαθ δεφινιτιωνες υθ σεα, φιδιτ φιθαε κυαλισκυε ετ εσθ, ιυς δισπυθανδο ινστρυσθιορ εα. Νε σεδ ρεγιονε οσυρρερεθ.
|
||||||
|
|
||||||
|
Ατ συμο υλλυμ ηομερω φελ, αεκυε πραεσενθ ρεπυδιαρε ιυς αν. Εσθ δισπυθανδο μεδιοσριθαθεμ ιν, φις ευ δισιθ αυδιαμ μενθιτυμ. Νο περ δισαμ τρασθατος, ιδ ιγνωθα ποπυλω ειρμωδ ιυς, ιδ δισαντ δεσερυισε μεα. Αδ παρτεμ φεριθυς πρω.
|
||||||
|
|
||||||
|
Φιδιτ δοσθυς ρεπρεχενδυντ νες νο, ιλλυδ αθκυι εξπλισαρι υθ εως, πρω ερος φαλλι ινιμισυς νο. Νο φιμ νυλλα σεντεντιαε συσιπιαντυρ, αδ νοσθρω ιμπεδιτ φασιλις σεδ, αδ ευμ δισο προμπτα ιμπερδιετ. Ιδ ηις μαγνα ωμιτθαμ θχεωπηραστυς, οδιο παθριοκυε ηας ιν, εξ ιυς ινθεγρε αλθερυμ περσεσυτι. Ιδ ανιμαλ τεμποριβυς δεφινιτιωνες φιξ. Σεδ ευ πλασεραθ σωνσεπθαμ, αδ κυωδ ειυς σομπλεσθιθυρ ιυς, εσεντ δολορες ετ κυι.
|
||||||
|
|
||||||
|
Νο σεδ σολετ σωνσεθεθυρ αδιπισινγ. Νο σιθ φαστιδιι περφεσθο σαπιενθεμ, εα ινερμις ινδοστυμ δισεντιας φελ, υσυ ει υθροκυε μαλυισετ. Μει κυαεστιο μνεσαρσχυμ νο. Εα δομινγ αεθερνο αλθερυμ δυο, ευ σεα σασε μολλις, λωρεμ ωμνιυμ ιισκυε σεδ νε.
|
||||||
|
|
||||||
|
Μεα θε δισαθ φαλλι οφφισιις. Ναμ δυις ιριυρε αδ. Φασιλις σεθερος αλβυσιυς ατ μει, μελ υθ ρεπυδιαρε ασεντιορ ινσιδεριντ. Σαεπε πρωβατυς ηις αν, φευγιαθ υλλαμσορπερ ατ μει, ει κυο ριδενς αππαρεατ διγνισιμ. Αλιενυμ ελαβοραρετ σονσλυσιονεμκυε κυι αν, παυλω μεδιοσρεμ υσυ συ, συ γραεσι λυπταθυμ σωνσεκυαθ σιθ. Σιθ θε ηαβεο φοσιβυς σονστιθυαμ, περ ετ φιθαε εξερσι μολλις.
|
||||||
|
|
||||||
|
Ναμ αθκυι αυδιαμ αδ. Ευ κυαεστιο φυλπυτατε εσθ. Υθ σολυτα σομμοδο δετρασθο δυο, εα σιθ δελισατα σωνσεπθαμ. Ευμ υτιναμ ασομμοδαρε ει, σολεατ ιριυρε ιν συμ. Φιδερερ σεθερος δεφινιεβας ιυς θε.
|
||||||
|
|
||||||
|
Δεσωρε πωσιθ φιφενδυμ εα φιμ, κυωδ σονσυλατυ σοτιδιεκυε φελ αδ. Ιδ ναμ δισαθ ταντας, δισαντ φασιλις ηις υθ. Κυεμ εραντ δισερε σεδ ει, εα φιρθυθε ωπωρθεαθ σενσεριτ ευμ. Μελ θαλε αππελλανθυρ ιδ. Ιδ κυι σαλε περσιπιθ. Ιδ σεδ λαβιθυρ σωνσεκυαθ φορενσιβυς, εξ στετ δελενιτι σιθ. Αδ μοδυς νοφυμ σωνσλυδαθυρκυε συμ, φιμ ευ χινς δεβετ, φιξ ιν αλια ριδενς παθριοκυε.
|
||||||
|
|
||||||
|
Δυο απεριαμ σομπλεσθιθυρ ιδ, νο μανδαμυς παρτιενδω συμ, φιδιτ λιβρις φαβυλας μεα νε. Θαλε μυτατ πωνδερυμ ευ περ, ριδενς οπωρθερε περ αδ, εα φασερ ερρωρ πρω. Υσυ ατ φελιτ λαορεεθ. Μεα πορρω επισυρι εξπλισαρι ιδ, βωνορυμ δολωρυμ νυσκυαμ εαμ αν, παυλω λυσιλιυς ερροριβυς μεα υθ. Ει φελ αμετ νιηιλ σριπτορεμ, σοπιωσαε ινφενιρε σεα νο. Νε σολεατ περπετυα υσυ. Εα πρω δελεσθυς θχεωπηραστυς, θαθιων σεθερος φις θε, ιυς ετ σαεπε φολυτπατ μαιεσθατις.
|
||||||
|
|
||||||
|
Ιυς ιν διαμ μαλυισετ σορρυμπιθ. Οδιο σπλενδιδε σιθ ατ, νες εραθ λατινε ατ. Νες εξ ποσιμ δεσερυισε. Ευμ εξ τιβικυε νωμιναφι αππαρεατ, ωφφενδιθ ευριπιδις ιδ ιυς, σιθ σαεπε μολεστιε εα. Φις χαρυμ κυοδσι ευ. Περτινασια λιβεραφισε σεα ιδ. Φιξ ηαβεο εραντ φιθαε υθ, δολορ δοσθυς ιν κυι, φιξ ατ σινθ σεμπερ δεφινιθιονεμ.
|
||||||
|
|
||||||
|
Ταντας νομινατι σωνσεθεθυρ ει ναμ. Ιδ φιξ πωσε λαβιθυρ νομινατι, πρινσιπες ιρασυνδια υσυ υθ, ποπυλω σονσλυσιονεμκυε φελ ιν. Αλικυανδο νεσεσιταθιβυς μελ θε, συμ ετ πριμα ρεφορμιδανς, κυοδσι περσεκυερις ετ νες. Εκυιδεμ φιφενδω πρωβατυς ηας ετ. Νε σεδ ταντας σολυτα ανιμαλ.
|
||||||
|
@ -41,7 +41,7 @@ impl View for Button {
|
|||||||
|
|
||||||
fn get_min_size(&self, _: SizeRequest) -> Vec2 {
|
fn get_min_size(&self, _: SizeRequest) -> Vec2 {
|
||||||
// Meh. Fixed size we are.
|
// Meh. Fixed size we are.
|
||||||
Vec2::new(2 + self.label.len(), 1)
|
Vec2::new(2 + self.label.chars().count(), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(&mut self, event: Event) -> EventResult {
|
fn on_event(&mut self, event: Event) -> EventResult {
|
||||||
|
@ -108,9 +108,10 @@ impl View for Dialog {
|
|||||||
printer.print_box(Vec2::new(0,0), printer.size);
|
printer.print_box(Vec2::new(0,0), printer.size);
|
||||||
|
|
||||||
if self.title.len() > 0 {
|
if self.title.len() > 0 {
|
||||||
let x = (printer.size.x - self.title.len()) / 2;
|
let len = self.title.chars().count();
|
||||||
|
let x = (printer.size.x - len) / 2;
|
||||||
printer.print((x-2,0), "┤ ");
|
printer.print((x-2,0), "┤ ");
|
||||||
printer.print((x+self.title.len(),0), " ├");
|
printer.print((x+len,0), " ├");
|
||||||
|
|
||||||
printer.with_color(color::TITLE_PRIMARY, |p| p.print((x,0), &self.title));
|
printer.with_color(color::TITLE_PRIMARY, |p| p.print((x,0), &self.title));
|
||||||
}
|
}
|
||||||
@ -137,7 +138,7 @@ impl View for Dialog {
|
|||||||
|
|
||||||
if self.title.len() > 0 {
|
if self.title.len() > 0 {
|
||||||
// If we have a title, we have to fit it too!
|
// If we have a title, we have to fit it too!
|
||||||
inner_size.x = max(inner_size.x, self.title.len() + 6);
|
inner_size.x = max(inner_size.x, self.title.chars().count() + 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_size
|
inner_size
|
||||||
|
@ -48,22 +48,31 @@ impl EditView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_char(s: &mut String, cursor: usize) {
|
||||||
|
let i = match s.char_indices().nth(cursor) {
|
||||||
|
Some((i,_)) => i,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
s.remove(i);
|
||||||
|
}
|
||||||
|
|
||||||
impl View for EditView {
|
impl View for EditView {
|
||||||
fn draw(&mut self, printer: &Printer, focused: bool) {
|
fn draw(&mut self, printer: &Printer, focused: bool) {
|
||||||
// let style = if focused { color::HIGHLIGHT } else { color::HIGHLIGHT_INACTIVE };
|
// let style = if focused { color::HIGHLIGHT } else { color::HIGHLIGHT_INACTIVE };
|
||||||
|
let len = self.content.chars().count();
|
||||||
printer.with_color(color::SECONDARY, |printer| {
|
printer.with_color(color::SECONDARY, |printer| {
|
||||||
printer.with_style(ncurses::A_REVERSE(), |printer| {
|
printer.with_style(ncurses::A_REVERSE(), |printer| {
|
||||||
printer.print((0,0), &self.content);
|
printer.print((0,0), &self.content);
|
||||||
printer.print_hline((self.content.len(),0), printer.size.x-self.content.len(), '_' as u64);
|
printer.print_hline((len,0), printer.size.x-len, '_' as u64);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Now print cursor
|
// Now print cursor
|
||||||
if focused {
|
if focused {
|
||||||
let c = if self.cursor == self.content.len() {
|
let c = if self.cursor == len {
|
||||||
'_'
|
'_'
|
||||||
} else {
|
} else {
|
||||||
// Get the char from the string... Is it so hard?
|
// Get the char from the string... Is it so hard?
|
||||||
self.content.chars().nth(self.cursor).unwrap()
|
self.content.chars().nth(self.cursor).expect(&format!("Found no char at cursor {} in {}", self.cursor, self.content))
|
||||||
};
|
};
|
||||||
printer.print_hline((self.cursor, 0), 1, c as u64);
|
printer.print_hline((self.cursor, 0), 1, c as u64);
|
||||||
}
|
}
|
||||||
@ -82,17 +91,22 @@ impl View for EditView {
|
|||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::CharEvent(ch) => {
|
Event::CharEvent(ch) => {
|
||||||
self.content.insert(self.cursor, ch);
|
// Find the byte index of the char at self.cursor
|
||||||
|
|
||||||
|
match self.content.char_indices().nth(self.cursor) {
|
||||||
|
None => self.content.push(ch),
|
||||||
|
Some((i,_)) => self.content.insert(i, ch),
|
||||||
|
}
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
return EventResult::Consumed(None);
|
return EventResult::Consumed(None);
|
||||||
},
|
},
|
||||||
Event::KeyEvent(key) => match key {
|
Event::KeyEvent(key) => match key {
|
||||||
Key::Home => self.cursor = 0,
|
Key::Home => self.cursor = 0,
|
||||||
Key::End => self.cursor = self.content.len(),
|
Key::End => self.cursor = self.content.chars().count(),
|
||||||
Key::Left if self.cursor > 0 => self.cursor -= 1,
|
Key::Left if self.cursor > 0 => self.cursor -= 1,
|
||||||
Key::Right if self.cursor < self.content.len() => self.cursor += 1,
|
Key::Right if self.cursor < self.content.chars().count() => self.cursor += 1,
|
||||||
Key::Backspace if self.cursor > 0 => { self.cursor -= 1; self.content.remove(self.cursor); },
|
Key::Backspace if self.cursor > 0 => { self.cursor -= 1; remove_char(&mut self.content, self.cursor); },
|
||||||
Key::Del if self.cursor < self.content.len() => { self.content.remove(self.cursor); },
|
Key::Del if self.cursor < self.content.chars().count() => { remove_char(&mut self.content, self.cursor); },
|
||||||
_ => return EventResult::Ignored,
|
_ => return EventResult::Ignored,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
@ -37,7 +37,7 @@ fn get_line_span(line: &str, max_width: usize) -> usize {
|
|||||||
// (Or use a common function? Better!)
|
// (Or use a common function? Better!)
|
||||||
let mut lines = 1;
|
let mut lines = 1;
|
||||||
let mut length = 0;
|
let mut length = 0;
|
||||||
for l in line.split(" ").map(|word| word.len()) {
|
for l in line.split(" ").map(|word| word.chars().count()) {
|
||||||
length += l;
|
length += l;
|
||||||
if length > max_width {
|
if length > max_width {
|
||||||
length = l;
|
length = l;
|
||||||
@ -81,7 +81,8 @@ impl TextView {
|
|||||||
|
|
||||||
// Given the specified height, how many columns do we need to properly display?
|
// Given the specified height, how many columns do we need to properly display?
|
||||||
fn get_num_cols(&self, max_height: usize) -> usize {
|
fn get_num_cols(&self, max_height: usize) -> usize {
|
||||||
(div_up_usize(self.content.len(), max_height)..self.content.len())
|
let len = self.content.chars().count();
|
||||||
|
(div_up_usize(len, max_height)..len)
|
||||||
.find(|w| self.get_num_lines(*w) <= max_height)
|
.find(|w| self.get_num_lines(*w) <= max_height)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
@ -93,7 +94,7 @@ impl TextView {
|
|||||||
|
|
||||||
for line in self.content.split("\n") {
|
for line in self.content.split("\n") {
|
||||||
height += 1;
|
height += 1;
|
||||||
max_width = max(max_width, line.len());
|
max_width = max(max_width, line.chars().count());
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2::new(max_width, height)
|
Vec2::new(max_width, height)
|
||||||
@ -133,7 +134,7 @@ impl <'a> Iterator for LinesIterator<'a> {
|
|||||||
let content = &self.content[self.start..];
|
let content = &self.content[self.start..];
|
||||||
|
|
||||||
if let Some(next) = content.find("\n") {
|
if let Some(next) = content.find("\n") {
|
||||||
if next <= self.width {
|
if content[..next].chars().count() <= self.width {
|
||||||
// We found a newline before the allowed limit.
|
// We found a newline before the allowed limit.
|
||||||
// Break early.
|
// Break early.
|
||||||
self.start += next+1;
|
self.start += next+1;
|
||||||
@ -144,7 +145,8 @@ impl <'a> Iterator for LinesIterator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if content.len() <= self.width {
|
let content_len = content.chars().count();
|
||||||
|
if content_len <= self.width {
|
||||||
// I thought it would be longer! -- that's what she said :(
|
// I thought it would be longer! -- that's what she said :(
|
||||||
self.start += content.len();
|
self.start += content.len();
|
||||||
return Some(Row{
|
return Some(Row{
|
||||||
@ -153,7 +155,14 @@ impl <'a> Iterator for LinesIterator<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(i) = content[..self.width+1].rfind(" ") {
|
let i = if content_len == self.width+1 {
|
||||||
|
// We can't look at the index if we're looking at the end of the string
|
||||||
|
content.len()
|
||||||
|
} else {
|
||||||
|
content.char_indices().nth(self.width+1).unwrap().0
|
||||||
|
};
|
||||||
|
let substr = &content[..i];
|
||||||
|
if let Some(i) = substr.rfind(" ") {
|
||||||
// If we have to break, try to find a whitespace for that.
|
// If we have to break, try to find a whitespace for that.
|
||||||
self.start += i+1;
|
self.start += i+1;
|
||||||
return Some(Row {
|
return Some(Row {
|
||||||
@ -200,8 +209,8 @@ impl View for TextView {
|
|||||||
match event {
|
match event {
|
||||||
Event::KeyEvent(Key::Up) if self.start_line > 0 => self.start_line -= 1,
|
Event::KeyEvent(Key::Up) if self.start_line > 0 => self.start_line -= 1,
|
||||||
Event::KeyEvent(Key::Down) if self.start_line+self.view_height < self.rows.len() => self.start_line += 1,
|
Event::KeyEvent(Key::Down) if self.start_line+self.view_height < self.rows.len() => self.start_line += 1,
|
||||||
Event::KeyEvent(Key::PageUp) => self.start_line = min(self.start_line+10, self.rows.len()-self.view_height),
|
Event::KeyEvent(Key::PageDown) => self.start_line = min(self.start_line+10, self.rows.len()-self.view_height),
|
||||||
Event::KeyEvent(Key::PageDown) => self.start_line -= min(self.start_line, 10),
|
Event::KeyEvent(Key::PageUp) => self.start_line -= min(self.start_line, 10),
|
||||||
_ => return EventResult::Ignored,
|
_ => return EventResult::Ignored,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user