egui Custom Widgets: impl Widget for Reusable Components | Rust GUI Ep 25
Video: egui Custom Widgets: impl Widget for Reusable Components | Rust GUI Ep 25 by Taught by Celeste AI - AI Coding Coach
Watch full page →egui Custom Widgets: impl Widget for Reusable Components
In this tutorial, you will learn how to create a reusable toggle switch widget by implementing the egui::Widget trait in Rust. The example covers reserving widget space, handling click interactions, and custom painting using egui's Painter API to build a polished toggle component that can be easily reused in your GUI applications.
Code
use egui::{Response, Sense, Ui, Widget, Vec2, Painter, Pos2, Color32, Stroke, Rounding, Rect};
/// A reusable toggle switch widget borrowing a boolean state.
pub struct Toggle<'a> {
/// Mutable reference to the toggle state.
pub state: &'a mut bool,
}
impl<'a> Toggle<'a> {
/// Create a new Toggle widget from a mutable boolean reference.
pub fn new(state: &'a mut bool) -> Self {
Self { state }
}
}
impl<'a> Widget for Toggle<'a> {
fn ui(self, ui: &mut Ui) -> Response {
// Define desired size for the toggle switch
let desired_size = Vec2::new(40.0, 20.0);
// Reserve exact space in the UI
let (rect, response) = ui.allocate_exact_size(desired_size, Sense::click());
// Toggle state on click
if response.clicked() {
*self.state = !*self.state;
}
// Painter for custom drawing
let painter: &Painter = ui.painter();
// Background color depends on toggle state
let bg_color = if *self.state {
Color32::from_rgb(0, 150, 136) // teal when ON
} else {
Color32::from_gray(180) // gray when OFF
};
// Draw rounded rectangle background
painter.rect_filled(
rect,
Rounding::same(10.0),
bg_color,
);
// Calculate position for the sliding circle knob
let circle_radius = 8.0;
let circle_x = if *self.state {
rect.right() - circle_radius - 4.0
} else {
rect.left() + circle_radius + 4.0
};
let circle_center = Pos2::new(circle_x, rect.center().y);
// Draw the circle knob with white fill and subtle stroke
painter.circle_filled(circle_center, circle_radius, Color32::WHITE);
painter.circle_stroke(circle_center, circle_radius, Stroke::new(1.0, Color32::BLACK));
response
}
}
// Usage example inside an egui app's ui code:
// let mut toggle_state = false;
// ui.add(Toggle::new(&mut toggle_state));
Key Points
- Implement the
egui::Widgettrait by defining theui(self, &mut Ui) -> Responsemethod for custom widgets. - Use
ui.allocate_exact_size()withSense::click()to reserve widget space and handle click interactions. - Toggle boolean state by checking
response.clicked()inside the widget'suimethod. - Use
ui.painter()to draw custom shapes like rounded rectangles and circles for the widget's visual appearance. - Pass mutable references to widget state with lifetimes to enable reusable, stateful components used via
ui.add().