Skip to content

Instantly share code, notes, and snippets.

@amPerl
Created July 1, 2023 16:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amPerl/4d4479c3fb893a8d72aae9b6d1199ac5 to your computer and use it in GitHub Desktop.
Save amPerl/4d4479c3fb893a8d72aae9b6d1199ac5 to your computer and use it in GitHub Desktop.
egui todomvc
use eframe::egui::{self, TextBuffer};
#[derive(Clone)]
struct TodoItem {
text: String,
completed: bool,
editing: bool,
}
fn main() {
let mut todos = vec![];
let mut todo_input_text = String::new();
let mut todo_filter: Option<bool> = None;
eframe::run_simple_native(
"TodoMVC",
eframe::NativeOptions::default(),
move |ctx: &egui::Context, _frame: &mut eframe::Frame| {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("todos");
todo_list_header(&mut todos, &mut todo_input_text, ui);
if !todos.is_empty() {
ui.separator();
todo_list_items(&mut todos, &todo_filter, ui);
ui.separator();
todo_list_footer(&mut todos, &mut todo_filter, ui);
}
});
},
)
.unwrap();
}
fn todo_list_header(todos: &mut Vec<TodoItem>, todo_input_text: &mut String, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
let everything_completed = todos.iter().all(|todo| todo.completed);
let complete_button_text = if everything_completed {
"uncomplete all"
} else {
"complete all"
};
if ui.button(complete_button_text).clicked() {
for todo in todos.iter_mut() {
todo.completed = !everything_completed;
}
}
let input_response =
ui.add(egui::TextEdit::singleline(todo_input_text).hint_text("What needs to be done?"));
if input_response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
todos.push(TodoItem {
text: todo_input_text.take(),
completed: false,
editing: false,
});
}
});
}
fn todo_list_items(todos: &mut Vec<TodoItem>, filter: &Option<bool>, ui: &mut egui::Ui) {
let mut todo_to_clear = None;
for (idx, todo) in todos.iter_mut().enumerate() {
if let Some(filter) = filter {
if todo.completed != *filter {
continue;
}
}
ui.horizontal(|ui| {
ui.add(egui::Checkbox::without_text(&mut todo.completed));
if todo.editing {
let input_response = ui.add(egui::TextEdit::singleline(&mut todo.text));
if input_response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
todo.editing = false;
} else {
input_response.request_focus();
}
} else {
let mut label_text = egui::RichText::new(&todo.text);
if todo.completed {
label_text = label_text.strikethrough();
}
let label_response = ui.label(label_text);
if label_response
.interact(egui::Sense::click())
.double_clicked()
{
todo.editing = true;
}
ui.add_space(4.0);
if ui.button("x").clicked() {
todo_to_clear = Some(idx);
}
}
});
}
if let Some(idx) = todo_to_clear.take() {
todos.remove(idx);
}
}
fn todo_list_footer(todos: &mut Vec<TodoItem>, filter: &mut Option<bool>, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
let items_left = todos.iter().filter(|todo| !todo.completed).count();
ui.label(format!("{items_left} items left"));
ui.selectable_value(filter, None, "All");
ui.selectable_value(filter, Some(false), "Active");
ui.selectable_value(filter, Some(true), "Completed");
let completed_todos = todos.iter().filter(|todo| todo.completed).count();
if completed_todos > 0 {
ui.add_space(8.0);
if ui.button("Clear completed").clicked() {
let incomplete_todos = todos
.iter()
.filter(|todo| !todo.completed)
.cloned()
.collect();
*todos = incomplete_todos;
}
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment