Add `ComboBox::icon()` (#1405)

This commit is contained in:
4JX 2022-03-23 21:56:46 +01:00 committed by GitHub
parent 8272b08742
commit dd9699099f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 57 additions and 3 deletions

View File

@ -1,6 +1,9 @@
use crate::{style::WidgetVisuals, *};
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.
///
/// ```
@ -24,6 +27,7 @@ pub struct ComboBox {
label: Option<WidgetText>,
selected_text: WidgetText,
width: Option<f32>,
icon: Option<IconPainter>,
}
impl ComboBox {
@ -34,6 +38,7 @@ impl ComboBox {
label: Some(label.into()),
selected_text: Default::default(),
width: None,
icon: None,
}
}
@ -45,6 +50,7 @@ impl ComboBox {
label: Some(label),
selected_text: Default::default(),
width: None,
icon: None,
}
}
@ -55,6 +61,7 @@ impl ComboBox {
label: Default::default(),
selected_text: Default::default(),
width: None,
icon: None,
}
}
@ -70,6 +77,41 @@ impl ComboBox {
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.
///
/// Returns `InnerResponse { inner: None }` if the combo box is closed.
@ -91,6 +133,7 @@ impl ComboBox {
label,
selected_text,
width,
icon,
} = self;
let button_id = ui.make_persistent_id(id_source);
@ -99,7 +142,7 @@ impl ComboBox {
if let Some(width) = width {
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 {
ir.response
.widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text()));
@ -165,6 +208,7 @@ fn combo_box_dyn<'c, R>(
button_id: Id,
selected_text: WidgetText,
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
icon: Option<IconPainter>,
) -> InnerResponse<Option<R>> {
let popup_id = button_id.with("popup");
@ -192,7 +236,17 @@ fn combo_box_dyn<'c, R>(
} else {
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);
galley.paint_with_visuals(ui.painter(), text_rect.min, visuals);
@ -262,7 +316,7 @@ fn button_frame(
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(
rect.center(),
vec2(rect.width() * 0.7, rect.height() * 0.45),