2021-05-09 08:53:35 +00:00
|
|
|
//! Source code example about creating a widget which uses `egui::Memory` to store UI state.
|
|
|
|
//!
|
2021-04-18 08:13:08 +00:00
|
|
|
//! This is meant to be read as a tutorial, hence the plethora of comments.
|
|
|
|
|
|
|
|
/// Password entry field with ability to toggle character hiding.
|
|
|
|
///
|
|
|
|
/// ## Example:
|
|
|
|
/// ``` ignore
|
2021-05-09 08:53:35 +00:00
|
|
|
/// password_ui(ui, &mut password);
|
2021-04-18 08:13:08 +00:00
|
|
|
/// ```
|
2021-05-09 08:53:35 +00:00
|
|
|
pub fn password_ui(ui: &mut egui::Ui, text: &mut String) -> egui::Response {
|
|
|
|
// This widget has its own state — show or hide password characters.
|
2021-04-18 08:13:08 +00:00
|
|
|
|
|
|
|
// 1. Declare state struct
|
|
|
|
// This struct represents the state of this widget.
|
2021-05-09 08:53:35 +00:00
|
|
|
// It must implement at least `Clone` and be `'static`.
|
|
|
|
// If you use the `persistence` feature, it also must implement `serde::{Deserialize, Serialize}`.
|
|
|
|
// You should prefer creating custom newtype structs or enums like this, to avoid `TypeId`
|
2021-04-18 08:13:08 +00:00
|
|
|
// intersection errors, especially when you use `Memory::data` without `Id`.
|
|
|
|
#[derive(Clone, Copy, Default)]
|
|
|
|
struct State(bool);
|
|
|
|
|
|
|
|
// 2. Create id
|
2021-05-09 08:53:35 +00:00
|
|
|
let id = ui.id().with("show_password");
|
2021-04-18 08:13:08 +00:00
|
|
|
|
|
|
|
// 3. Get state for this widget
|
|
|
|
// You can read more about available `Memory` functions in the documentation of `egui::Memory`
|
|
|
|
// struct and `egui::any` module.
|
|
|
|
// You should get state by value, not by reference to avoid borrowing of `Memory`.
|
2021-05-09 08:53:35 +00:00
|
|
|
let mut plaintext = *ui.memory().id_data_temp.get_or_default::<State>(id);
|
2021-04-18 08:13:08 +00:00
|
|
|
|
|
|
|
// 4. Process ui, change a local copy of the state
|
|
|
|
// We want TextEdit to fill entire space, and have button after that, so in that case we can
|
|
|
|
// change direction to right_to_left.
|
2021-05-09 08:53:35 +00:00
|
|
|
let result = ui.with_layout(egui::Layout::right_to_left(), |ui| {
|
2021-04-18 08:13:08 +00:00
|
|
|
// Here a local copy of the state can be changed by a user.
|
|
|
|
let response = ui
|
2021-05-09 08:53:35 +00:00
|
|
|
.add(egui::SelectableLabel::new(plaintext.0, "👁"))
|
|
|
|
.on_hover_text("Show/hide password");
|
2021-04-18 08:13:08 +00:00
|
|
|
if response.clicked() {
|
2021-05-09 08:53:35 +00:00
|
|
|
plaintext.0 = !plaintext.0;
|
2021-04-18 08:13:08 +00:00
|
|
|
}
|
|
|
|
|
2021-05-09 08:53:35 +00:00
|
|
|
let text_edit_size = ui.available_size();
|
|
|
|
|
2021-04-18 08:13:08 +00:00
|
|
|
// Here we use this local state.
|
2021-05-09 08:53:35 +00:00
|
|
|
ui.add_sized(
|
|
|
|
text_edit_size,
|
|
|
|
egui::TextEdit::singleline(text).password(!plaintext.0),
|
|
|
|
);
|
2021-04-18 08:13:08 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// 5. Insert changed state back
|
2021-05-09 08:53:35 +00:00
|
|
|
ui.memory().id_data_temp.insert(id, plaintext);
|
2021-04-18 08:13:08 +00:00
|
|
|
|
|
|
|
// All done! Return the interaction response so the user can check what happened
|
|
|
|
// (hovered, clicked, ...) and maybe show a tooltip:
|
|
|
|
result.response
|
|
|
|
}
|
|
|
|
|
|
|
|
// A wrapper that allows the more idiomatic usage pattern: `ui.add(...)`
|
|
|
|
/// Password entry field with ability to toggle character hiding.
|
|
|
|
///
|
|
|
|
/// ## Example:
|
|
|
|
/// ``` ignore
|
2021-05-09 08:53:35 +00:00
|
|
|
/// ui.add(password(&mut password));
|
2021-04-18 08:13:08 +00:00
|
|
|
/// ```
|
2021-05-09 08:53:35 +00:00
|
|
|
pub fn password(text: &mut String) -> impl egui::Widget + '_ {
|
|
|
|
move |ui: &mut egui::Ui| password_ui(ui, text)
|
2021-04-18 08:13:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn url_to_file_source_code() -> String {
|
|
|
|
format!("https://github.com/emilk/egui/blob/master/{}", file!())
|
|
|
|
}
|