text_input_example/
text_input_example.rs1use spottedcat::{Context, Key, Spot, Text, DrawOption};
2
3struct TextInputExample {
4 committed: String,
5 preedit: String,
6 font_data: Vec<u8>,
7 capture_enabled: bool,
8}
9
10impl Spot for TextInputExample {
11 fn initialize(_: &mut Context) -> Self {
12 const FALLBACK_FONT: &[u8] = include_bytes!("../assets/DejaVuSans.ttf");
15
16 let font_candidates = [
17 "/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
18 "/System/Library/Fonts/PingFang.ttc",
19 "/System/Library/Fonts/Supplemental/Songti.ttc",
20 "/System/Library/Fonts/Supplemental/Heiti TC.ttc",
21 "/System/Library/Fonts/Supplemental/STHeiti Medium.ttc",
22 ];
23
24 let mut font_data = None;
25 for path in font_candidates {
26 if let Ok(data) = spottedcat::load_font_from_file(path) {
27 font_data = Some(data);
28 break;
29 }
30 }
31
32 let font_data = font_data.unwrap_or_else(|| spottedcat::load_font_from_bytes(FALLBACK_FONT));
33 Self {
34 committed: String::new(),
35 preedit: String::new(),
36 font_data,
37 capture_enabled: false,
38 }
39 }
40
41 fn update(&mut self, ctx: &mut Context, _dt: std::time::Duration) {
42 if spottedcat::key_pressed(ctx, Key::F1) {
43 self.capture_enabled = !self.capture_enabled;
44 spottedcat::set_text_input_enabled(ctx, self.capture_enabled);
45 }
46
47 self.committed.push_str(spottedcat::text_input(ctx));
49
50 self.preedit = spottedcat::ime_preedit(ctx).unwrap_or("").to_string();
52
53 if spottedcat::key_pressed(ctx, Key::Backspace) {
55 self.committed.pop();
56 }
57
58 if spottedcat::key_pressed(ctx, Key::Escape) {
60 self.committed.clear();
61 self.preedit.clear();
62 }
63 }
64
65 fn draw(&mut self, ctx: &mut Context) {
66 let mut title_opts = DrawOption::new();
67 title_opts.position = [spottedcat::Pt::from(20.0), spottedcat::Pt::from(40.0)];
68 let status = if self.capture_enabled { "ON" } else { "OFF" };
69 Text::new(
70 format!(
71 "Text Input Example (capture: {}, F1 toggle, Backspace delete, Esc clear)",
72 status
73 ),
74 self.font_data.clone(),
75 )
76 .with_font_size(spottedcat::Pt::from(22.0))
77 .with_color([1.0, 1.0, 1.0, 1.0])
78 .draw(ctx, title_opts);
79
80 let mut input_opts = DrawOption::new();
81 input_opts.position = [spottedcat::Pt::from(20.0), spottedcat::Pt::from(90.0)];
82
83 let mut composed = self.committed.clone();
84 if !self.preedit.is_empty() {
85 composed.push_str(&self.preedit);
86 }
87 Text::new(composed, self.font_data.clone())
88 .with_font_size(spottedcat::Pt::from(28.0))
89 .with_color([0.9, 0.9, 0.9, 1.0])
90 .draw(ctx, input_opts);
91
92 if !self.preedit.is_empty() {
93 let mut ime_opts = DrawOption::new();
94 ime_opts.position = [spottedcat::Pt::from(20.0), spottedcat::Pt::from(130.0)];
95 Text::new(
96 format!("IME preedit: {}", self.preedit),
97 self.font_data.clone(),
98 )
99 .with_font_size(spottedcat::Pt::from(16.0))
100 .with_color([0.6, 0.8, 1.0, 1.0])
101 .draw(ctx, ime_opts);
102 }
103 }
104
105 fn remove(&self) {}
106}
107
108fn main() {
109 spottedcat::run::<TextInputExample>(spottedcat::WindowConfig::default());
110}