-
Notifications
You must be signed in to change notification settings - Fork 6
/
text_layout.rs
171 lines (145 loc) · 8.71 KB
/
text_layout.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
use flo_draw::*;
use flo_draw::canvas::*;
use std::sync::*;
///
/// Example that displays various effects that can be achieved via
/// flo_canvas's text layout functions
///
pub fn main() {
with_2d_graphics(|| {
let lato = CanvasFontFace::from_slice(include_bytes!("Lato-Regular.ttf"));
let lato_bold = CanvasFontFace::from_slice(include_bytes!("Lato-Bold.ttf"));
// Create a window
let canvas = create_drawing_window("Text layout example");
// Various text layout demonstrations
canvas.draw(|gc| {
// Set up the canvas
gc.canvas_height(1000.0);
gc.center_region(0.0, 0.0, 1000.0, 1000.0);
// Load the fonts
gc.define_font_data(FontId(1), Arc::clone(&lato));
gc.define_font_data(FontId(2), Arc::clone(&lato_bold));
gc.set_font_size(FontId(1), 18.0);
gc.set_font_size(FontId(2), 18.0);
});
canvas.draw(|gc| {
// Draw some text with layout in these fonts
gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0));
// Start with a simple text layout
gc.begin_line_layout(18.0, 900.0, TextAlignment::Left);
gc.layout_text(FontId(1), "Simple text layout".to_string());
gc.draw_text_layout();
});
canvas.draw(|gc| {
// We can change fonts during a layout
gc.begin_line_layout(18.0, 900.0 - 30.0, TextAlignment::Left);
gc.layout_text(FontId(1), "We can change ".to_string());
gc.layout_text(FontId(2), "fonts".to_string());
gc.layout_text(FontId(1), " during layout ".to_string());
gc.draw_text_layout();
});
canvas.draw(|gc| {
// We can change colours during a layout
gc.begin_line_layout(18.0, 900.0 - 60.0, TextAlignment::Left);
gc.layout_text(FontId(1), "Or we could change ".to_string());
gc.fill_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
gc.layout_text(FontId(1), "colours".to_string());
gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0));
gc.layout_text(FontId(1), " during layout ".to_string());
gc.draw_text_layout();
});
canvas.draw(|gc| {
// We can change font sizes during a layout
gc.begin_line_layout(18.0, 900.0 - 100.0, TextAlignment::Left);
gc.layout_text(FontId(1), "It's also possible to alter ".to_string());
gc.set_font_size(FontId(1), 36.0);
gc.layout_text(FontId(1), "sizes".to_string());
gc.set_font_size(FontId(1), 18.0);
gc.layout_text(FontId(1), " during layout ".to_string());
gc.draw_text_layout();
});
canvas.draw(|gc| {
// Can align text with all the effects
gc.begin_line_layout(500.0, 500.0, TextAlignment::Center);
gc.layout_text(FontId(1), "Text layout demonstration, with changing ".to_string());
gc.set_font_size(FontId(1), 36.0);
gc.layout_text(FontId(1), "sizes,".to_string());
gc.set_font_size(FontId(1), 18.0);
gc.fill_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
gc.layout_text(FontId(1), " colours,".to_string());
gc.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0));
gc.layout_text(FontId(2), " fonts,".to_string());
gc.layout_text(FontId(1), " and center alignment ".to_string());
gc.draw_text_layout();
gc.begin_line_layout(1000.0-18.0, 80.0, TextAlignment::Right);
gc.layout_text(FontId(1), "Right alignment is supported too".to_string());
gc.draw_text_layout();
});
canvas.draw(|gc| {
// Can perform fully manual layout, and annotate with other drawing
let mut text_layout = CanvasFontLineLayout::new(&lato, 18.0);
text_layout.add_text("Performing layout manually is also possible");
// Calling 'align_transform' moves the text to its final position, and 'to_drawing' generates the drawing instructions for the layout (the layout needs to know the FontId to generate drawing instructions)
text_layout.align_transform(500.0, 400.0, TextAlignment::Center);
gc.draw_list(text_layout.to_drawing(FontId(1)));
});
canvas.draw(|gc| {
// We can use the measure() and draw() functions to add annotations to the text as we generate the layout
// font_metrics(em_size) gives some information about a particular font
let lato_metrics = lato.font_metrics(18.0).unwrap();
let mut text_layout = CanvasFontLineLayout::new(&lato, 18.0);
text_layout.add_text("Manual layout allows ");
// 'measure()' interrupts the layout, so measuring half-way between 'f' and 'i' will force the layout to produce no ligature
let start_pos = text_layout.measure();
text_layout.add_text("custom");
let end_pos = text_layout.measure();
// start_pos and end_pos show where the word 'custom' began and ended (as well as giving the overall bounding box)
// CanvasFontLineLayout implements GraphicsContext, so we draw straight to the layout as we're constructing it
// `align_transform` later on will move our drawing with the text
text_layout.new_path();
text_layout.move_to(start_pos.pos.x() as _, start_pos.pos.y() as f32 + lato_metrics.underline_position.unwrap().offset);
text_layout.line_to(end_pos.pos.x() as _, end_pos.pos.y() as f32 + lato_metrics.underline_position.unwrap().offset);
text_layout.stroke_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
text_layout.line_width(lato_metrics.underline_position.unwrap().thickness);
text_layout.stroke();
text_layout.new_path();
text_layout.move_to(start_pos.pos.x() as _, start_pos.pos.y() as f32 + lato_metrics.ascender);
text_layout.line_to(end_pos.pos.x() as _, end_pos.pos.y() as f32 + lato_metrics.ascender);
text_layout.stroke_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
text_layout.line_width(lato_metrics.underline_position.unwrap().thickness);
text_layout.stroke();
let mid_point = (start_pos.pos + end_pos.pos) * 0.5;
text_layout.move_to(mid_point.x() as _, mid_point.y() as f32 + lato_metrics.underline_position.unwrap().offset);
text_layout.line_to(mid_point.x() as _, mid_point.y() as f32 + lato_metrics.underline_position.unwrap().offset - 8.0);
text_layout.stroke_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
text_layout.line_width(2.0);
text_layout.stroke();
// Even possible to lay out text in text ('layout_text' is from the graphics context, so we wind up performing recursive layout here)
text_layout.begin_line_layout(mid_point.x() as _, mid_point.y() as f32-lato_metrics.underline_position.unwrap().offset - 30.0, TextAlignment::Center);
text_layout.layout_text(FontId(1), "here".to_string());
text_layout.draw_text_layout();
// Finish up the text...
text_layout.add_text(" drawing effects, such as this underline");
// ... and align it using align_transform so the underline is moved along with the text
text_layout.align_transform(500.0, 370.0, TextAlignment::Center);
gc.draw_list(text_layout.to_drawing(FontId(1)));
});
canvas.draw(|gc| {
// It's still possible to change fonts and colours while using a manual layout
let mut text_layout = CanvasFontLineLayout::new(&lato, 18.0);
text_layout.add_text("Changing ");
text_layout.fill_color(Color::Rgba(0.8, 0.6, 0.0, 1.0));
text_layout.add_text("colour");
text_layout.fill_color(Color::Rgba(0.0, 0.0, 0.6, 1.0));
text_layout.add_text(" and ");
// FontId 1 = lato, FontId 2 = lato bold (note we supply the old font ID and not the new one here!)
let mut text_layout = text_layout.continue_with_new_font(FontId(1), &lato_bold, 18.0);
text_layout.add_text("font");
let mut text_layout = text_layout.continue_with_new_font(FontId(2), &lato, 18.0);
text_layout.add_text(" is still possible with manual layouts");
// Calling 'align_transform' moves the text to its final position, and 'to_drawing' generates the drawing instructions for the layout (the layout needs to know the FontId to generate drawing instructions)
text_layout.align_transform(500.0, 310.0, TextAlignment::Center);
gc.draw_list(text_layout.to_drawing(FontId(1)));
});
});
}