Pronoun templating + example usage UI

This commit is contained in:
mars 2022-05-26 21:45:33 -06:00
parent e1e747d107
commit e08573a443
5 changed files with 255 additions and 58 deletions

43
Cargo.lock generated
View File

@ -569,6 +569,12 @@ dependencies = [
"bitflags",
]
[[package]]
name = "ryu"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695"
[[package]]
name = "scopeguard"
version = "1.1.0"
@ -580,6 +586,31 @@ name = "serde"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "signal-hook"
@ -686,6 +717,16 @@ dependencies = [
"num_threads",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "toml"
version = "0.5.9"
@ -705,6 +746,8 @@ dependencies = [
"num_enum",
"protocol",
"protocol-derive",
"serde",
"tinytemplate",
]
[[package]]

View File

@ -16,3 +16,5 @@ cursive = { version = "0.18", default-features = false, features = ["crossterm-b
num_enum = "0.5"
protocol = { path = "./protocol" }
protocol-derive = { path = "./protocol-derive" }
serde = { version = "1", features = ["derive"] }
tinytemplate = "1.2.1"

23
log.txt Normal file
View File

@ -0,0 +1,23 @@
warning: associated function is never used: `format_short`
--> src/pronouns.rs:71:12
|
71 | pub fn format_short(&self) -> String {
| ^^^^^^^^^^^^
|
= note: `#[warn(dead_code)]` on by default
warning: field is never read: `edit_receiver`
--> src/tui.rs:17:5
|
17 | edit_receiver: Receiver<EditEvent>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: field is never read: `identity`
--> src/tui.rs:18:5
|
18 | identity: Identity,
| ^^^^^^^^^^^^^^^^^^
warning: `udp-mud` (bin "udp-mud") generated 3 warnings
Finished release [optimized] target(s) in 0.05s
Running `target/release/udp-mud --username server --bind-addr '0.0.0.0:54321' --connect '98.43.173.90:54321'`

View File

@ -1,4 +1,11 @@
use protocol_derive::{Decode, Encode};
use serde::{Deserialize, Serialize};
pub const EXAMPLE_USAGE: &str = "{S} went to the park.
I went with {o}.
{S} brought {p} frisbee.
At least I think it was {pp}.
{S} threw the frisbee to {r}.";
pub fn make_presets() -> Vec<Pronouns> {
// TODO add more from https://pronoun.is and https://askanonbinary.tumblr.com/pronouns
@ -98,4 +105,78 @@ impl Pronouns {
pronouns
}
}
pub fn make_table(&self) -> PronounTable {
let capitalize = |s: &String| {
if self.case_sensitive {
s.to_string()
} else if s.len() > 0 {
let mut capitalized = s.get(0..1).unwrap().to_uppercase().to_string();
capitalized.push_str(&s[1..]);
capitalized.to_string()
} else {
"".to_string()
}
};
PronounTable {
case_sensitive: self.case_sensitive,
plural: self.plural,
subject: self.subject.clone(),
object: self.object.clone(),
possessive: self.possessive.clone(),
possessive_pronoun: self.possessive_pronoun.clone(),
reflexive: self.reflexive.clone(),
subject_capitalized: capitalize(&self.subject),
object_capitalized: capitalize(&self.object),
possessive_capitalized: capitalize(&self.possessive),
possessive_pronoun_capitalized: capitalize(&self.possessive_pronoun),
reflexive_capitalized: capitalize(&self.reflexive),
}
}
pub fn make_example_usage(&self) -> String {
let table = self.make_table();
let mut tt = tinytemplate::TinyTemplate::new();
tt.set_default_formatter(&tinytemplate::format_unescaped);
tt.add_template("example_usage", EXAMPLE_USAGE).unwrap();
tt.render("example_usage", &table).unwrap()
}
}
/// Baked pronoun lookup table for formatting messages.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct PronounTable {
pub case_sensitive: bool,
pub plural: bool,
#[serde(rename = "s")]
pub subject: String,
#[serde(rename = "o")]
pub object: String,
#[serde(rename = "p")]
pub possessive: String,
#[serde(rename = "pp")]
pub possessive_pronoun: String,
#[serde(rename = "r")]
pub reflexive: String,
#[serde(rename = "S")]
pub subject_capitalized: String,
#[serde(rename = "O")]
pub object_capitalized: String,
#[serde(rename = "P")]
pub possessive_capitalized: String,
#[serde(rename = "PP")]
pub possessive_pronoun_capitalized: String,
#[serde(rename = "R")]
pub reflexive_capitalized: String,
}

View File

@ -103,34 +103,57 @@ impl Tui {
siv.add_layer(dialog);
}
fn make_example_usage_panel() -> impl View {
let text = TextView::new("Highlight a pronoun set to preview its usage!")
.with_name("pronoun_example_text")
.fixed_width(50)
.scrollable();
Panel::new(text).title("Example Usage")
}
fn update_pronouns_edit(siv: &mut Cursive, pronouns: &Pronouns) {
siv.call_on_name("pronoun_example_text", |view: &mut TextView| {
view.set_content(pronouns.make_example_usage());
});
siv.with_user_data(|sender: &mut Sender<EditEvent>| {
sender
.send(EditEvent::Pronouns(Some(pronouns.clone())))
.unwrap();
});
siv.call_on_name("pronouns_text", |view: &mut TextView| {
view.set_content(pronouns.format_full());
})
.unwrap();
}
pub fn select_pronouns(siv: &mut Cursive) {
let example = TextView::new("Highlight a pronoun set to preview its usage!")
.with_name("pronoun_example_text")
.fixed_width(35)
.scrollable();
let presets = SelectView::new()
.with_all(
crate::pronouns::make_presets()
.into_iter()
.map(|pronouns| (pronouns.format_full(), pronouns)),
)
.on_submit(|siv, pronouns| {
siv.with_user_data(|sender: &mut Sender<EditEvent>| {
sender
.send(EditEvent::Pronouns(Some(pronouns.clone())))
.unwrap();
});
siv.call_on_name("pronouns_text", |view: &mut TextView| {
view.set_content(pronouns.format_full());
})
.unwrap();
siv.pop_layer();
})
.on_select(|siv, pronouns| Self::update_pronouns_edit(siv, pronouns))
.scrollable();
let dialog = Dialog::around(presets)
let layout = LinearLayout::horizontal()
.child(Panel::new(presets).title("Presets"))
.child(Panel::new(example).title("Example Usage"));
let dialog = Dialog::around(layout)
.title("Select Pronouns")
.button("Custom...", |siv| {
siv.pop_layer();
Self::edit_pronouns(siv);
})
.dismiss_button("Ok")
.button("None", |siv| {
siv.with_user_data(|sender: &mut Sender<EditEvent>| {
sender.send(EditEvent::Pronouns(None)).unwrap();
@ -140,11 +163,30 @@ impl Tui {
})
.unwrap();
siv.pop_layer();
})
.dismiss_button("Cancel");
});
siv.add_layer(dialog);
}
fn get_edit_pronouns(siv: &mut Cursive) -> Pronouns {
let case_sensitive = get_checkbox_contents(siv, "case_sensitive_edit");
let plural = get_checkbox_contents(siv, "plural_edit");
let subject = get_edit_contents(siv, "subject_edit");
let object = get_edit_contents(siv, "object_edit");
let possessive = get_edit_contents(siv, "possessive_edit");
let possessive_pronoun = get_edit_contents(siv, "possessive_pronoun_edit");
let reflexive = get_edit_contents(siv, "reflexive_edit");
Pronouns {
case_sensitive,
plural,
subject,
object,
possessive,
possessive_pronoun,
reflexive,
}
}
pub fn edit_pronouns(siv: &mut Cursive) {
let labels = make_vertical_labels(&[
"Case-sensitive:",
@ -157,52 +199,58 @@ impl Tui {
])
.fixed_width(20);
let values = LinearLayout::vertical()
.child(Checkbox::new().with_name("case_sensitive_edit"))
.child(Checkbox::new().with_name("plural_edit"))
.child(EditView::new().with_name("subject_edit"))
.child(EditView::new().with_name("object_edit"))
.child(EditView::new().with_name("possessive_edit"))
.child(EditView::new().with_name("possessive_pronoun_edit"))
.child(EditView::new().with_name("reflexive_edit"))
.fixed_width(12);
let mut values = LinearLayout::vertical();
let columns = LinearLayout::horizontal().child(labels).child(values);
let mut dialog = Dialog::around(columns);
dialog.set_title("Edit Pronouns");
dialog.add_button("Ok", |siv| {
let case_sensitive = get_checkbox_contents(siv, "case_sensitive_edit");
let plural = get_checkbox_contents(siv, "plural_edit");
let subject = get_edit_contents(siv, "subject_edit");
let object = get_edit_contents(siv, "object_edit");
let possessive = get_edit_contents(siv, "possessive_edit");
let possessive_pronoun = get_edit_contents(siv, "possessive_pronoun_edit");
let reflexive = get_edit_contents(siv, "reflexive_edit");
let checkboxes = &["case_sensitive_edit", "plural_edit"];
let pronouns = Pronouns {
case_sensitive,
plural,
subject,
object,
possessive,
possessive_pronoun,
reflexive,
};
for name in checkboxes.iter() {
values.add_child(
Checkbox::new()
.on_change(|siv, _value| {
let pronouns = Self::get_edit_pronouns(siv);
Self::update_pronouns_edit(siv, &pronouns);
})
.with_name(*name),
);
}
siv.call_on_name("pronouns_text", |view: &mut TextView| {
view.set_content(pronouns.format_full());
let edit_views = &[
"subject_edit",
"object_edit",
"possessive_edit",
"possessive_pronoun_edit",
"reflexive_edit",
];
for name in edit_views.iter() {
values.add_child(
EditView::new()
.on_edit(|siv, _text, _cursor| {
let pronouns = Self::get_edit_pronouns(siv);
Self::update_pronouns_edit(siv, &pronouns);
})
.with_name(*name),
);
}
let edit_layout = Panel::new(
LinearLayout::horizontal()
.child(labels)
.child(values.fixed_width(12)),
);
let example = Self::make_example_usage_panel();
let layout = LinearLayout::horizontal().child(edit_layout).child(example);
let dialog = Dialog::around(layout)
.title("Edit Pronouns")
.button("Ok", |siv| {
let pronouns = Self::get_edit_pronouns(siv);
Self::update_pronouns_edit(siv, &pronouns);
siv.pop_layer();
})
.unwrap();
siv.with_user_data(|sender: &mut Sender<EditEvent>| {
sender.send(EditEvent::Pronouns(Some(pronouns))).unwrap();
});
siv.pop_layer();
});
dialog.add_button("Cancel", |siv| {
siv.pop_layer().unwrap();
});
.dismiss_button("Cancel");
siv.add_layer(dialog);
}