Add `ComboBox::icon()` (#1405)
This commit is contained in:
parent
8272b08742
commit
dd9699099f
|
|
@ -1,6 +1,9 @@
|
||||||
use crate::{style::WidgetVisuals, *};
|
use crate::{style::WidgetVisuals, *};
|
||||||
use epaint::Shape;
|
use epaint::Shape;
|
||||||
|
|
||||||
|
/// A function that paints the `ComboBox` icon
|
||||||
|
pub type IconPainter = Box<dyn FnOnce(&Ui, Rect, &WidgetVisuals, bool)>;
|
||||||
|
|
||||||
/// A drop-down selection menu with a descriptive label.
|
/// A drop-down selection menu with a descriptive label.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -24,6 +27,7 @@ pub struct ComboBox {
|
||||||
label: Option<WidgetText>,
|
label: Option<WidgetText>,
|
||||||
selected_text: WidgetText,
|
selected_text: WidgetText,
|
||||||
width: Option<f32>,
|
width: Option<f32>,
|
||||||
|
icon: Option<IconPainter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComboBox {
|
impl ComboBox {
|
||||||
|
|
@ -34,6 +38,7 @@ impl ComboBox {
|
||||||
label: Some(label.into()),
|
label: Some(label.into()),
|
||||||
selected_text: Default::default(),
|
selected_text: Default::default(),
|
||||||
width: None,
|
width: None,
|
||||||
|
icon: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,6 +50,7 @@ impl ComboBox {
|
||||||
label: Some(label),
|
label: Some(label),
|
||||||
selected_text: Default::default(),
|
selected_text: Default::default(),
|
||||||
width: None,
|
width: None,
|
||||||
|
icon: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,6 +61,7 @@ impl ComboBox {
|
||||||
label: Default::default(),
|
label: Default::default(),
|
||||||
selected_text: Default::default(),
|
selected_text: Default::default(),
|
||||||
width: None,
|
width: None,
|
||||||
|
icon: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,6 +77,41 @@ impl ComboBox {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use the provided function to render a different `ComboBox` icon.
|
||||||
|
/// Defaults to a triangle that expands when the cursor is hovering over the `ComboBox`.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
/// ```
|
||||||
|
/// # egui::__run_test_ui(|ui| {
|
||||||
|
/// # let text = "Selected text";
|
||||||
|
/// pub fn filled_triangle(
|
||||||
|
/// ui: &egui::Ui,
|
||||||
|
/// rect: egui::Rect,
|
||||||
|
/// visuals: &egui::style::WidgetVisuals,
|
||||||
|
/// _is_open: bool,
|
||||||
|
/// ) {
|
||||||
|
/// let rect = egui::Rect::from_center_size(
|
||||||
|
/// rect.center(),
|
||||||
|
/// egui::Vec2::new(rect.width() * 0.6, rect.height() * 0.4),
|
||||||
|
/// );
|
||||||
|
/// ui.painter().add(egui::Shape::convex_polygon(
|
||||||
|
/// vec![rect.left_top(), rect.right_top(), rect.center_bottom()],
|
||||||
|
/// visuals.fg_stroke.color,
|
||||||
|
/// visuals.fg_stroke,
|
||||||
|
/// ));
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// egui::ComboBox::from_id_source("my-combobox")
|
||||||
|
/// .selected_text(text)
|
||||||
|
/// .icon(filled_triangle)
|
||||||
|
/// .show_ui(ui, |_ui| {});
|
||||||
|
/// # });
|
||||||
|
/// ```
|
||||||
|
pub fn icon(mut self, icon_fn: impl FnOnce(&Ui, Rect, &WidgetVisuals, bool) + 'static) -> Self {
|
||||||
|
self.icon = Some(Box::new(icon_fn));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Show the combo box, with the given ui code for the menu contents.
|
/// Show the combo box, with the given ui code for the menu contents.
|
||||||
///
|
///
|
||||||
/// Returns `InnerResponse { inner: None }` if the combo box is closed.
|
/// Returns `InnerResponse { inner: None }` if the combo box is closed.
|
||||||
|
|
@ -91,6 +133,7 @@ impl ComboBox {
|
||||||
label,
|
label,
|
||||||
selected_text,
|
selected_text,
|
||||||
width,
|
width,
|
||||||
|
icon,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let button_id = ui.make_persistent_id(id_source);
|
let button_id = ui.make_persistent_id(id_source);
|
||||||
|
|
@ -99,7 +142,7 @@ impl ComboBox {
|
||||||
if let Some(width) = width {
|
if let Some(width) = width {
|
||||||
ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later.
|
ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later.
|
||||||
}
|
}
|
||||||
let mut ir = combo_box_dyn(ui, button_id, selected_text, menu_contents);
|
let mut ir = combo_box_dyn(ui, button_id, selected_text, menu_contents, icon);
|
||||||
if let Some(label) = label {
|
if let Some(label) = label {
|
||||||
ir.response
|
ir.response
|
||||||
.widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text()));
|
.widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text()));
|
||||||
|
|
@ -165,6 +208,7 @@ fn combo_box_dyn<'c, R>(
|
||||||
button_id: Id,
|
button_id: Id,
|
||||||
selected_text: WidgetText,
|
selected_text: WidgetText,
|
||||||
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
|
icon: Option<IconPainter>,
|
||||||
) -> InnerResponse<Option<R>> {
|
) -> InnerResponse<Option<R>> {
|
||||||
let popup_id = button_id.with("popup");
|
let popup_id = button_id.with("popup");
|
||||||
|
|
||||||
|
|
@ -192,7 +236,17 @@ fn combo_box_dyn<'c, R>(
|
||||||
} else {
|
} else {
|
||||||
ui.style().interact(&response)
|
ui.style().interact(&response)
|
||||||
};
|
};
|
||||||
paint_icon(ui.painter(), icon_rect.expand(visuals.expansion), visuals);
|
|
||||||
|
if let Some(icon) = icon {
|
||||||
|
icon(
|
||||||
|
ui,
|
||||||
|
icon_rect.expand(visuals.expansion),
|
||||||
|
visuals,
|
||||||
|
is_popup_open,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
paint_default_icon(ui.painter(), icon_rect.expand(visuals.expansion), visuals);
|
||||||
|
}
|
||||||
|
|
||||||
let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size(), rect);
|
let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size(), rect);
|
||||||
galley.paint_with_visuals(ui.painter(), text_rect.min, visuals);
|
galley.paint_with_visuals(ui.painter(), text_rect.min, visuals);
|
||||||
|
|
@ -262,7 +316,7 @@ fn button_frame(
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_icon(painter: &Painter, rect: Rect, visuals: &WidgetVisuals) {
|
fn paint_default_icon(painter: &Painter, rect: Rect, visuals: &WidgetVisuals) {
|
||||||
let rect = Rect::from_center_size(
|
let rect = Rect::from_center_size(
|
||||||
rect.center(),
|
rect.center(),
|
||||||
vec2(rect.width() * 0.7, rect.height() * 0.45),
|
vec2(rect.width() * 0.7, rect.height() * 0.45),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue