1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Widgets are pieces of GUI such as [`Label`], [`Button`], [`Slider`] etc.
//!
//! Example widget uses:
//! * `ui.add(Label::new("Text").text_color(color::red));`
//! * `if ui.add(Button::new("Click me")).clicked() { … }`

use crate::{epaint, Response, Ui};

mod button;
mod checkbox;
pub mod color_picker;
pub(crate) mod drag_value;
mod hyperlink;
mod image;
mod image_button;
mod label;
mod progress_bar;
mod radio_button;
mod selected_label;
mod separator;
mod slider;
mod spinner;
pub mod text_edit;

pub use self::{
    button::Button,
    checkbox::Checkbox,
    drag_value::DragValue,
    hyperlink::{Hyperlink, Link},
    image::{
        decode_gif_uri, has_gif_magic_header, paint_texture_at, GifFrameDurations, Image, ImageFit,
        ImageOptions, ImageSize, ImageSource,
    },
    image_button::ImageButton,
    label::Label,
    progress_bar::ProgressBar,
    radio_button::RadioButton,
    selected_label::SelectableLabel,
    separator::Separator,
    slider::{Slider, SliderClamping, SliderOrientation},
    spinner::Spinner,
    text_edit::{TextBuffer, TextEdit},
};

// ----------------------------------------------------------------------------

/// Anything implementing Widget can be added to a [`Ui`] with [`Ui::add`].
///
/// [`Button`], [`Label`], [`Slider`], etc all implement the [`Widget`] trait.
///
/// You only need to implement `Widget` if you care about being able to do `ui.add(your_widget);`.
///
/// Note that the widgets ([`Button`], [`TextEdit`] etc) are
/// [builders](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html),
/// and not objects that hold state.
///
/// Tip: you can `impl Widget for &mut YourThing { }`.
///
/// `|ui: &mut Ui| -> Response { … }` also implements [`Widget`].
#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
pub trait Widget {
    /// Allocate space, interact, paint, and return a [`Response`].
    ///
    /// Note that this consumes `self`.
    /// This is because most widgets ([`Button`], [`TextEdit`] etc) are
    /// [builders](https://doc.rust-lang.org/1.0.0/style/ownership/builders.html)
    ///
    /// Tip: you can `impl Widget for &mut YourObject { }`.
    fn ui(self, ui: &mut Ui) -> Response;
}

/// This enables functions that return `impl Widget`, so that you can
/// create a widget by just returning a lambda from a function.
///
/// For instance: `ui.add(slider_vec2(&mut vec2));` with:
///
/// ```
/// pub fn slider_vec2(value: &mut egui::Vec2) -> impl egui::Widget + '_ {
///    move |ui: &mut egui::Ui| {
///        ui.horizontal(|ui| {
///            ui.add(egui::Slider::new(&mut value.x, 0.0..=1.0).text("x"));
///            ui.add(egui::Slider::new(&mut value.y, 0.0..=1.0).text("y"));
///        })
///        .response
///    }
/// }
/// ```
impl<F> Widget for F
where
    F: FnOnce(&mut Ui) -> Response,
{
    fn ui(self, ui: &mut Ui) -> Response {
        self(ui)
    }
}

/// Helper so that you can do e.g. `TextEdit::State::load`.
pub trait WidgetWithState {
    type State;
}

// ----------------------------------------------------------------------------

/// Show a button to reset a value to its default.
/// The button is only enabled if the value does not already have its original value.
///
/// The `text` could be something like "Reset foo".
pub fn reset_button<T: Default + PartialEq>(ui: &mut Ui, value: &mut T, text: &str) {
    reset_button_with(ui, value, text, T::default());
}

/// Show a button to reset a value to its default.
/// The button is only enabled if the value does not already have its original value.
///
/// The `text` could be something like "Reset foo".
pub fn reset_button_with<T: PartialEq>(ui: &mut Ui, value: &mut T, text: &str, reset_value: T) {
    if ui
        .add_enabled(*value != reset_value, Button::new(text))
        .clicked()
    {
        *value = reset_value;
    }
}

// ----------------------------------------------------------------------------

#[deprecated = "Use `ui.add(&mut stroke)` instead"]
pub fn stroke_ui(ui: &mut crate::Ui, stroke: &mut epaint::Stroke, text: &str) {
    ui.horizontal(|ui| {
        ui.label(text);
        ui.add(stroke);
    });
}

/// Show a small button to switch to/from dark/light mode (globally).
pub fn global_theme_preference_switch(ui: &mut Ui) {
    if let Some(new_theme) = ui.ctx().theme().small_toggle_button(ui) {
        ui.ctx().set_theme(new_theme);
    }
}

/// Show larger buttons for switching between light and dark mode (globally).
pub fn global_theme_preference_buttons(ui: &mut Ui) {
    let mut theme_preference = ui.ctx().options(|opt| opt.theme_preference);
    theme_preference.radio_buttons(ui);
    ui.ctx().set_theme(theme_preference);
}

/// Show a small button to switch to/from dark/light mode (globally).
#[deprecated = "Use global_theme_preference_switch instead"]
pub fn global_dark_light_mode_switch(ui: &mut Ui) {
    global_theme_preference_switch(ui);
}

/// Show larger buttons for switching between light and dark mode (globally).
#[deprecated = "Use global_theme_preference_buttons instead"]
pub fn global_dark_light_mode_buttons(ui: &mut Ui) {
    global_theme_preference_buttons(ui);
}