Newer
Older
use bevy::prelude::*;
use cosmic_text::{Buffer, Edit, Shaping};
input::{input_mouse, kb_input_text, kb_move_cursor},
CosmicBuffer, CosmicEditor, CosmicFontSystem, DefaultAttrs, Render,
pub struct PasswordPlugin;
impl Plugin for PasswordPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
PreUpdate,
(
hide_password_text.before(input_mouse),
restore_password_text.after(input_mouse),
),
)
.add_systems(
Update,
(
hide_password_text.before(kb_move_cursor),
restore_password_text
.before(kb_input_text)
.after(kb_move_cursor),
),
)
PostUpdate,
(
hide_password_text.before(Render),
restore_password_text.after(Render),
),
);
}
}
#[derive(Component)]
pub struct Password {
real_text: String,
glyph: char,
}
impl Default for Password {
fn default() -> Self {
Self {
real_text: Default::default(),
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
}
}
}
fn hide_password_text(
mut q: Query<(
&mut Password,
&mut CosmicBuffer,
&DefaultAttrs,
Option<&mut CosmicEditor>,
)>,
mut font_system: ResMut<CosmicFontSystem>,
) {
for (mut password, mut buffer, attrs, editor_opt) in q.iter_mut() {
if let Some(mut editor) = editor_opt {
editor.with_buffer_mut(|buffer| {
fn get_text(buffer: &mut Buffer) -> String {
let mut text = String::new();
let line_count = buffer.lines.len();
for (i, line) in buffer.lines.iter().enumerate() {
text.push_str(line.text());
if i < line_count - 1 {
text.push('\n');
}
}
text
}
let text = get_text(buffer);
buffer.set_text(
&mut font_system,
password.glyph.to_string().repeat(text.len()).as_str(),
attrs.as_attrs(),
Shaping::Advanced,
);
for (i, c) in text.char_indices() {
if !text.is_char_boundary(i) || c.len_utf8() > 1 {
panic!("Widechars (like {c}) are not yet supported in password fields.")
}
}
let mut cursor = editor.cursor();
cursor.index *= password.glyph.len_utf8(); // HACK: multiply cursor position assuming no widechars are input
// TODO: Count characters until cursor and set new position accordingly,
// noting the previous location for restoring
// TODO: Look into unicode graphemes
editor.set_cursor(cursor);
continue;
}
let text = buffer.get_text();
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
buffer.set_text(
&mut font_system,
password.glyph.to_string().repeat(text.len()).as_str(),
attrs.as_attrs(),
);
password.real_text = text;
}
}
fn restore_password_text(
mut q: Query<(
&Password,
&mut CosmicBuffer,
&DefaultAttrs,
Option<&mut CosmicEditor>,
)>,
mut font_system: ResMut<CosmicFontSystem>,
) {
for (password, mut buffer, attrs, editor_opt) in q.iter_mut() {
if let Some(mut editor) = editor_opt {
editor.with_buffer_mut(|buffer| {
buffer.set_text(
&mut font_system,
password.real_text.as_str(),
attrs.as_attrs(),
Shaping::Advanced,
)
});
let mut cursor = editor.cursor();
cursor.index /= password.glyph.len_utf8(); // HACK: restore cursor position assuming no widechars are input
editor.set_cursor(cursor);