alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
root crates client src menu text_field.rs
use winit::keyboard::KeyCode;
pub struct TextField {
pub text: String,
pub focused: bool,
pub cursor: usize,
pub anchor: usize,
max: usize,
/// Only `ChatAllowedCharacters`, as a Beta server would kick for anything else.
pub chat: bool,
}
impl TextField {
/// `GuiTextField.setText` keeps a longer existing text; `max` only limits typing.
pub fn new(text: &str, max: usize) -> Self {
let text = text.to_owned();
let cursor = text.len();
Self {
text,
focused: true,
cursor,
anchor: cursor,
max,
chat: false,
}
}
pub fn chat(max: usize) -> Self {
Self {
chat: true,
..Self::new("", max)
}
}
pub fn selection(&self) -> std::ops::Range<usize> {
self.cursor.min(self.anchor)..self.cursor.max(self.anchor)
}
pub fn insert(&mut self, text: &str) {
let selection = self.selection();
let available = self.max.saturating_sub(
self.text.chars().count() - self.text[selection.clone()].chars().count(),
);
let insert: String = text
.chars()
.filter(|&ch| {
!ch.is_control()
&& ch != '§'
&& (!self.chat || common::text::ALLOWED_CHARACTERS.contains(ch))
})
.take(available)
.collect();
self.text.replace_range(selection.clone(), &insert);
self.cursor = selection.start + insert.len();
self.anchor = self.cursor;
}
pub fn key(&mut self, key: KeyCode, text: Option<&str>, control: bool, shift: bool) {
let previous = |text: &str, cursor| {
text[..cursor]
.char_indices()
.next_back()
.map_or(0, |(index, _)| index)
};
let next = |text: &str, cursor| {
text[cursor..]
.chars()
.next()
.map_or(cursor, |ch| cursor + ch.len_utf8())
};
match key {
KeyCode::KeyA if control => {
self.anchor = 0;
self.cursor = self.text.len();
return;
}
KeyCode::Backspace => {
if self.selection().is_empty() {
self.anchor = previous(&self.text, self.cursor);
}
self.insert("");
return;
}
KeyCode::Delete => {
if self.selection().is_empty() {
self.anchor = next(&self.text, self.cursor);
}
self.insert("");
return;
}
KeyCode::Home => self.cursor = 0,
KeyCode::End => self.cursor = self.text.len(),
KeyCode::ArrowLeft => self.cursor = previous(&self.text, self.cursor),
KeyCode::ArrowRight => self.cursor = next(&self.text, self.cursor),
_ => {
if !control && let Some(text) = text {
self.insert(text);
}
return;
}
}
if !shift {
self.anchor = self.cursor;
}
}
}