Add word wrapping
This commit is contained in:
parent
f226a83cf6
commit
bb08064b9a
|
@ -9,7 +9,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use cairo::Context;
|
use cairo::{Context, Rectangle};
|
||||||
use cyberpunk::{AsymLine, AsymLineCutout, GlowPen, Pen, Text};
|
use cyberpunk::{AsymLine, AsymLineCutout, GlowPen, Pen, Text};
|
||||||
use glib::{GString, Object};
|
use glib::{GString, Object};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
|
@ -73,13 +73,6 @@ impl Index<usize> for Script {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Region {
|
|
||||||
left: f64,
|
|
||||||
top: f64,
|
|
||||||
width: f64,
|
|
||||||
height: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Fade {
|
struct Fade {
|
||||||
text: String,
|
text: String,
|
||||||
position: Position,
|
position: Position,
|
||||||
|
@ -91,7 +84,7 @@ struct Fade {
|
||||||
trait Animation {
|
trait Animation {
|
||||||
fn position(&self) -> Position;
|
fn position(&self) -> Position;
|
||||||
|
|
||||||
fn tick(&self, now: Instant, context: &Context, region: Region);
|
fn tick(&self, now: Instant, context: &Context, width: f64);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Animation for Fade {
|
impl Animation for Fade {
|
||||||
|
@ -99,15 +92,15 @@ impl Animation for Fade {
|
||||||
self.position.clone()
|
self.position.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&self, now: Instant, context: &Context, region: Region) {
|
fn tick(&self, now: Instant, context: &Context, width: f64) {
|
||||||
let total_frames = self.duration.as_secs() * FPS;
|
let total_frames = self.duration.as_secs() * FPS;
|
||||||
let alpha_rate: f64 = 1. / total_frames as f64;
|
let alpha_rate: f64 = 1. / total_frames as f64;
|
||||||
|
|
||||||
let frames = (now - self.start_time).as_secs_f64() * FPS as f64;
|
let frames = (now - self.start_time).as_secs_f64() * FPS as f64;
|
||||||
let alpha = alpha_rate * frames as f64;
|
let alpha = alpha_rate * frames as f64;
|
||||||
|
|
||||||
let text_display = Text::new(self.text.clone(), context, 32.);
|
let text_display = Text::new(self.text.clone(), context, 32., width);
|
||||||
let _ = context.move_to(region.left, region.top + text_display.extents().height());
|
let _ = context.move_to(0., text_display.extents().height());
|
||||||
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, alpha);
|
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, alpha);
|
||||||
text_display.draw();
|
text_display.draw();
|
||||||
}
|
}
|
||||||
|
@ -127,20 +120,20 @@ impl Animation for CrossFade {
|
||||||
self.position.clone()
|
self.position.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&self, now: Instant, context: &Context, region: Region) {
|
fn tick(&self, now: Instant, context: &Context, width: f64) {
|
||||||
let total_frames = self.duration.as_secs() * FPS;
|
let total_frames = self.duration.as_secs() * FPS;
|
||||||
let alpha_rate: f64 = 1. / total_frames as f64;
|
let alpha_rate: f64 = 1. / total_frames as f64;
|
||||||
|
|
||||||
let frames = (now - self.start_time).as_secs_f64() * FPS as f64;
|
let frames = (now - self.start_time).as_secs_f64() * FPS as f64;
|
||||||
let alpha = alpha_rate * frames as f64;
|
let alpha = alpha_rate * frames as f64;
|
||||||
|
|
||||||
let text_display = Text::new(self.old_text.clone(), context, 32.);
|
let text_display = Text::new(self.old_text.clone(), context, 32., width);
|
||||||
let _ = context.move_to(region.left, region.top + text_display.extents().height());
|
let _ = context.move_to(0., text_display.extents().height());
|
||||||
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, 1. - alpha);
|
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, 1. - alpha);
|
||||||
text_display.draw();
|
text_display.draw();
|
||||||
|
|
||||||
let text_display = Text::new(self.new_text.clone(), context, 32.);
|
let text_display = Text::new(self.new_text.clone(), context, 32., width);
|
||||||
let _ = context.move_to(region.left, region.top + text_display.extents().height());
|
let _ = context.move_to(0., text_display.extents().height());
|
||||||
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, alpha);
|
let _ = context.set_source_rgba(PURPLE.0, PURPLE.1, PURPLE.2, alpha);
|
||||||
text_display.draw();
|
text_display.draw();
|
||||||
}
|
}
|
||||||
|
@ -270,23 +263,17 @@ impl CyberScreen {
|
||||||
let _ = context.paint();
|
let _ = context.paint();
|
||||||
|
|
||||||
let pen = GlowPen::new(width, height, 2., 8., (0.7, 0., 1.));
|
let pen = GlowPen::new(width, height, 2., 8., (0.7, 0., 1.));
|
||||||
/*
|
|
||||||
for i in 0..6 {
|
|
||||||
pen.move_to(0., height as f64 * i as f64 / 5.);
|
|
||||||
pen.line_to(width as f64, height as f64 * i as f64 / 5.);
|
|
||||||
}
|
|
||||||
pen.stroke();
|
|
||||||
*/
|
|
||||||
AsymLineCutout {
|
AsymLineCutout {
|
||||||
orientation: gtk::Orientation::Horizontal,
|
orientation: gtk::Orientation::Horizontal,
|
||||||
start_x: 25.,
|
start_x: 25.,
|
||||||
start_y: height as f64 / 7.,
|
start_y: height as f64 / 7.,
|
||||||
start_length: width as f64 / 3.,
|
start_length: width as f64 / 3.,
|
||||||
cutout_length: width as f64 / 3. - 25.,
|
cutout_length: width as f64 / 3. - 100.,
|
||||||
height: 25.,
|
height: 50.,
|
||||||
end_length: width as f64 / 3. - 50.,
|
end_length: width as f64 / 3. - 50.,
|
||||||
invert: false,
|
invert: false,
|
||||||
}.draw(&pen);
|
}
|
||||||
|
.draw(&pen);
|
||||||
pen.stroke();
|
pen.stroke();
|
||||||
|
|
||||||
AsymLine {
|
AsymLine {
|
||||||
|
@ -297,7 +284,8 @@ impl CyberScreen {
|
||||||
height: 50.,
|
height: 50.,
|
||||||
end_length: 0.,
|
end_length: 0.,
|
||||||
invert: false,
|
invert: false,
|
||||||
}.draw(&pen);
|
}
|
||||||
|
.draw(&pen);
|
||||||
pen.stroke();
|
pen.stroke();
|
||||||
|
|
||||||
let tracery = pen.finish();
|
let tracery = pen.finish();
|
||||||
|
@ -312,33 +300,36 @@ impl CyberScreen {
|
||||||
|
|
||||||
if let Some(animation) = animations.get(&Position::Top) {
|
if let Some(animation) = animations.get(&Position::Top) {
|
||||||
let y = height as f64 * 1. / 5.;
|
let y = height as f64 * 1. / 5.;
|
||||||
let region = Region {
|
let surface = context.target().create_for_rectangle(Rectangle::new(
|
||||||
left: 20.,
|
20.,
|
||||||
top: y,
|
y,
|
||||||
height: region_height,
|
max_width,
|
||||||
width: max_width,
|
region_height,
|
||||||
};
|
)).unwrap();
|
||||||
animation.tick(now, context, region);
|
let ctx = Context::new(&surface).unwrap();
|
||||||
|
animation.tick(now, &ctx, max_width);
|
||||||
}
|
}
|
||||||
if let Some(animation) = animations.get(&Position::Middle) {
|
if let Some(animation) = animations.get(&Position::Middle) {
|
||||||
let y = height as f64 * 2. / 5.;
|
let y = height as f64 * 2. / 5.;
|
||||||
let region = Region {
|
let surface = context.target().create_for_rectangle(Rectangle::new(
|
||||||
left: 20.,
|
20.,
|
||||||
top: y,
|
y,
|
||||||
height: region_height,
|
max_width,
|
||||||
width: max_width,
|
region_height,
|
||||||
};
|
)).unwrap();
|
||||||
animation.tick(now, context, region);
|
let ctx = Context::new(&surface).unwrap();
|
||||||
|
animation.tick(now, &ctx, max_width);
|
||||||
}
|
}
|
||||||
if let Some(animation) = animations.get(&Position::Bottom) {
|
if let Some(animation) = animations.get(&Position::Bottom) {
|
||||||
let y = height as f64 * 3. / 5.;
|
let y = height as f64 * 3. / 5.;
|
||||||
let region = Region {
|
let surface = context.target().create_for_rectangle(Rectangle::new(
|
||||||
left: 20.,
|
20.,
|
||||||
top: y,
|
y,
|
||||||
height: region_height,
|
max_width,
|
||||||
width: max_width,
|
region_height,
|
||||||
};
|
)).unwrap();
|
||||||
animation.tick(now, context, region);
|
let ctx = Context::new(&surface).unwrap();
|
||||||
|
animation.tick(now, &ctx, max_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -251,22 +251,53 @@ impl Pen for GlowPen {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Text<'a> {
|
pub struct Text<'a> {
|
||||||
content: String,
|
content: Vec<String>,
|
||||||
context: &'a Context,
|
context: &'a Context,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Text<'a> {
|
impl<'a> Text<'a> {
|
||||||
pub fn new(content: String, context: &'a Context, size: f64) -> Self {
|
pub fn new(content: String, context: &'a Context, size: f64, width: f64) -> Self {
|
||||||
context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold);
|
context.select_font_face("Alegreya Sans SC", FontSlant::Normal, FontWeight::Bold);
|
||||||
context.set_font_size(size);
|
context.set_font_size(size);
|
||||||
Self { content, context }
|
|
||||||
|
let lines = word_wrap(content, context, width);
|
||||||
|
|
||||||
|
Self { content: lines, context }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extents(&self) -> TextExtents {
|
pub fn extents(&self) -> TextExtents {
|
||||||
self.context.text_extents(&self.content).unwrap()
|
self.context.text_extents(&self.content[0]).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self) {
|
pub fn draw(&self) {
|
||||||
let _ = self.context.show_text(&self.content);
|
let mut baseline = 0.;
|
||||||
|
for line in self.content.iter() {
|
||||||
|
baseline += self.context.text_extents(line).unwrap().height() + 10.;
|
||||||
|
self.context.move_to(0., baseline);
|
||||||
|
let _ = self.context.show_text(&line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn word_wrap(content: String, context: &Context, max_width: f64) -> Vec<String> {
|
||||||
|
let mut lines = vec![];
|
||||||
|
let words: Vec<&str> = content.split_whitespace().collect();
|
||||||
|
let mut start: usize = 0;
|
||||||
|
let mut line = String::new();
|
||||||
|
|
||||||
|
for idx in 0..words.len() + 1 {
|
||||||
|
line = words[start..idx].join(" ");
|
||||||
|
let extents = context.text_extents(&line).unwrap();
|
||||||
|
if extents.width() > max_width {
|
||||||
|
let line = words[start..idx-1].join(" ");
|
||||||
|
println!("line: {}", line);
|
||||||
|
start = idx-1;
|
||||||
|
lines.push(line.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if line.len() > 0 {
|
||||||
|
println!("line: {}", line);
|
||||||
|
lines.push(line);
|
||||||
|
}
|
||||||
|
lines
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue