Memory usage example in the widget gallery (#307)
* init example * add comments * fix grammar in comments * fix CI * change example from view_edit to password * rename file * fix CI
This commit is contained in:
parent
580d27e0d3
commit
c69ecfe421
3 changed files with 133 additions and 0 deletions
|
@ -14,6 +14,7 @@ pub mod font_contents_emoji;
|
||||||
pub mod font_contents_ubuntu;
|
pub mod font_contents_ubuntu;
|
||||||
pub mod layout_test;
|
pub mod layout_test;
|
||||||
pub mod painting;
|
pub mod painting;
|
||||||
|
pub mod password;
|
||||||
pub mod plot_demo;
|
pub mod plot_demo;
|
||||||
pub mod scrolling;
|
pub mod scrolling;
|
||||||
pub mod sliders;
|
pub mod sliders;
|
||||||
|
|
116
egui_demo_lib/src/apps/demo/password.rs
Normal file
116
egui_demo_lib/src/apps/demo/password.rs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
//! Source code example about creating other type of your widget which uses `egui::Memory` and
|
||||||
|
//! created using a combination of existing widgets.
|
||||||
|
//! This is meant to be read as a tutorial, hence the plethora of comments.
|
||||||
|
|
||||||
|
use egui::Layout;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
/// Password entry field with ability to toggle character hiding.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
/// ``` ignore
|
||||||
|
/// password_ui(ui, &mut password, "password_1");
|
||||||
|
/// ```
|
||||||
|
pub fn password_ui(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
text: &mut String,
|
||||||
|
id_source: impl Hash + Debug,
|
||||||
|
) -> egui::Response {
|
||||||
|
// This widget has its own state — enabled or disabled,
|
||||||
|
// so there is the algorithm for this type of widgets:
|
||||||
|
// 1. Declare state struct
|
||||||
|
// 2. Create id
|
||||||
|
// 3. Get state for this widget
|
||||||
|
// 4. Process ui, change a local copy of the state
|
||||||
|
// 5. Insert changed state back
|
||||||
|
|
||||||
|
// 1. Declare state struct
|
||||||
|
// This struct represents the state of this widget.
|
||||||
|
// 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
|
||||||
|
// intersection errors, especially when you use `Memory::data` without `Id`.
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
struct State(bool);
|
||||||
|
|
||||||
|
// 2. Create id
|
||||||
|
let id = ui.make_persistent_id(id_source);
|
||||||
|
|
||||||
|
// 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`.
|
||||||
|
let mut state = *ui.memory().id_data.get_or_default::<State>(id);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
let result = ui.with_layout(Layout::right_to_left(), |ui| {
|
||||||
|
// Here a local copy of the state can be changed by a user.
|
||||||
|
let response = ui
|
||||||
|
.add(egui::SelectableLabel::new(state.0, "👁"))
|
||||||
|
.on_hover_text("Toggle symbols hiding");
|
||||||
|
if response.clicked() {
|
||||||
|
state.0 = !state.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here we use this local state.
|
||||||
|
ui.add(egui::TextEdit::singleline(text).password(!state.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 5. Insert changed state back
|
||||||
|
ui.memory().id_data.insert(id, state);
|
||||||
|
|
||||||
|
// All done! Return the interaction response so the user can check what happened
|
||||||
|
// (hovered, clicked, ...) and maybe show a tooltip:
|
||||||
|
result.response
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Here is the same code again, but a bit more compact:
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn password_ui_compact(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
text: &mut String,
|
||||||
|
id_source: impl Hash + Debug,
|
||||||
|
) -> egui::Response {
|
||||||
|
#[derive(Clone, Copy, Default)]
|
||||||
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
struct State(bool);
|
||||||
|
|
||||||
|
let id = ui.make_persistent_id(id_source);
|
||||||
|
let mut state = *ui.memory().id_data.get_or_default::<State>(id);
|
||||||
|
|
||||||
|
let result = ui.with_layout(Layout::right_to_left(), |ui| {
|
||||||
|
let response = ui
|
||||||
|
.add(egui::SelectableLabel::new(state.0, "👁"))
|
||||||
|
.on_hover_text("Toggle symbols hiding");
|
||||||
|
if response.clicked() {
|
||||||
|
state.0 = !state.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add(egui::TextEdit::singleline(text).password(!state.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.memory().id_data.insert(id, state);
|
||||||
|
result.response
|
||||||
|
}
|
||||||
|
|
||||||
|
// A wrapper that allows the more idiomatic usage pattern: `ui.add(...)`
|
||||||
|
/// Password entry field with ability to toggle character hiding.
|
||||||
|
///
|
||||||
|
/// ## Example:
|
||||||
|
/// ``` ignore
|
||||||
|
/// ui.add(password(&mut password, "password_1"));
|
||||||
|
/// ```
|
||||||
|
pub fn password<'a>(
|
||||||
|
text: &'a mut String,
|
||||||
|
id_source: impl Hash + Debug + 'a,
|
||||||
|
) -> impl egui::Widget + 'a {
|
||||||
|
move |ui: &mut egui::Ui| password_ui(ui, text, id_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn url_to_file_source_code() -> String {
|
||||||
|
format!("https://github.com/emilk/egui/blob/master/{}", file!())
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ pub struct WidgetGallery {
|
||||||
scalar: f32,
|
scalar: f32,
|
||||||
string: String,
|
string: String,
|
||||||
color: egui::Color32,
|
color: egui::Color32,
|
||||||
|
memory_example: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WidgetGallery {
|
impl Default for WidgetGallery {
|
||||||
|
@ -25,6 +26,7 @@ impl Default for WidgetGallery {
|
||||||
scalar: 42.0,
|
scalar: 42.0,
|
||||||
string: Default::default(),
|
string: Default::default(),
|
||||||
color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5),
|
color: egui::Color32::LIGHT_BLUE.linear_multiply(0.5),
|
||||||
|
memory_example: "qwerty_is_bad_password".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +88,7 @@ impl WidgetGallery {
|
||||||
scalar,
|
scalar,
|
||||||
string,
|
string,
|
||||||
color,
|
color,
|
||||||
|
memory_example,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
ui.set_enabled(*enabled);
|
ui.set_enabled(*enabled);
|
||||||
|
@ -201,6 +204,19 @@ impl WidgetGallery {
|
||||||
This toggle switch is just 15 lines of code.",
|
This toggle switch is just 15 lines of code.",
|
||||||
);
|
);
|
||||||
ui.end_row();
|
ui.end_row();
|
||||||
|
|
||||||
|
ui.hyperlink_to(
|
||||||
|
"egui::Memory usage:",
|
||||||
|
super::password::url_to_file_source_code(),
|
||||||
|
)
|
||||||
|
.on_hover_text(
|
||||||
|
"You can use `egui::Memory` to store your own data.\n\
|
||||||
|
And state of this widget can be saved and loaded \n\
|
||||||
|
between runs automatically under the `persistence`\n\
|
||||||
|
feature.",
|
||||||
|
);
|
||||||
|
ui.add(super::password::password(memory_example, "memory example"));
|
||||||
|
ui.end_row();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue