Add option to select collapsing headers (#623)
* Add collapsing header select as selectable label * Modified Tree demo adding selectable example * Update egui/src/containers/collapsing_header.rs Selected is not linked to selectable Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * Update egui/src/containers/collapsing_header.rs Description example Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * Changing example without name clashing * Fixing merge issue (ah I miss P4 sometimes) * Fixing doctest example * Add possibility to show background to a single one * Fixing clippy test Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
parent
04b3921923
commit
68ed22ab6f
2 changed files with 111 additions and 17 deletions
|
@ -140,6 +140,9 @@ pub struct CollapsingHeader {
|
||||||
default_open: bool,
|
default_open: bool,
|
||||||
id_source: Id,
|
id_source: Id,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
|
selectable: bool,
|
||||||
|
selected: bool,
|
||||||
|
show_background: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CollapsingHeader {
|
impl CollapsingHeader {
|
||||||
|
@ -157,6 +160,9 @@ impl CollapsingHeader {
|
||||||
default_open: false,
|
default_open: false,
|
||||||
id_source,
|
id_source,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
selectable: false,
|
||||||
|
selected: false,
|
||||||
|
show_background: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +194,44 @@ impl CollapsingHeader {
|
||||||
self.enabled = enabled;
|
self.enabled = enabled;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Can the `CollapsingHeader` be selected by clicking it? Default: `false`.
|
||||||
|
///
|
||||||
|
pub fn selectable(mut self, selectable: bool) -> Self {
|
||||||
|
self.selectable = selectable;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If you set this to 'true', the `CollapsingHeader` will be shown as selected.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
/// ```
|
||||||
|
/// # let ui = &mut egui::Ui::__test();
|
||||||
|
/// let mut selected = false;
|
||||||
|
/// let response = egui::CollapsingHeader::new("Select and open me")
|
||||||
|
/// .selectable(true)
|
||||||
|
/// .selected(selected)
|
||||||
|
/// .show(ui, |ui| ui.label("Content"));
|
||||||
|
/// if response.header_response.clicked() {
|
||||||
|
/// selected = true;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn selected(mut self, selected: bool) -> Self {
|
||||||
|
self.selected = selected;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should the `CollapsingHeader` show a background behind it? Default: `false`.
|
||||||
|
///
|
||||||
|
/// To show it behind all `CollapsingHeader` you can just use:
|
||||||
|
/// ```
|
||||||
|
/// # let ui = &mut egui::Ui::__test();
|
||||||
|
/// ui.visuals_mut().collapsing_header_frame = true;
|
||||||
|
/// ```
|
||||||
|
pub fn show_background(mut self, show_background: bool) -> Self {
|
||||||
|
self.show_background = show_background;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Prepared {
|
struct Prepared {
|
||||||
|
@ -207,6 +251,9 @@ impl CollapsingHeader {
|
||||||
default_open,
|
default_open,
|
||||||
id_source,
|
id_source,
|
||||||
enabled: _,
|
enabled: _,
|
||||||
|
selectable: _,
|
||||||
|
selected: _,
|
||||||
|
show_background: _,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
label.text_style = label
|
label.text_style = label
|
||||||
|
@ -247,10 +294,16 @@ impl CollapsingHeader {
|
||||||
header_response
|
header_response
|
||||||
.widget_info(|| WidgetInfo::labeled(WidgetType::CollapsingHeader, &galley.text));
|
.widget_info(|| WidgetInfo::labeled(WidgetType::CollapsingHeader, &galley.text));
|
||||||
|
|
||||||
let visuals = ui.style().interact(&header_response);
|
let visuals = ui
|
||||||
let text_color = visuals.text_color();
|
.style()
|
||||||
|
.interact_selectable(&header_response, self.selected);
|
||||||
|
let text_color = ui
|
||||||
|
.style()
|
||||||
|
.visuals
|
||||||
|
.override_text_color
|
||||||
|
.unwrap_or_else(|| visuals.text_color());
|
||||||
|
|
||||||
if ui.visuals().collapsing_header_frame {
|
if ui.visuals().collapsing_header_frame || self.show_background {
|
||||||
ui.painter().add(Shape::Rect {
|
ui.painter().add(Shape::Rect {
|
||||||
rect: header_response.rect.expand(visuals.expansion),
|
rect: header_response.rect.expand(visuals.expansion),
|
||||||
corner_radius: visuals.corner_radius,
|
corner_radius: visuals.corner_radius,
|
||||||
|
@ -260,6 +313,16 @@ impl CollapsingHeader {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.selected
|
||||||
|
|| self.selectable && (header_response.hovered() || header_response.has_focus())
|
||||||
|
{
|
||||||
|
let rect = rect.expand(visuals.expansion);
|
||||||
|
|
||||||
|
let corner_radius = 2.0;
|
||||||
|
ui.painter()
|
||||||
|
.rect(rect, corner_radius, visuals.bg_fill, visuals.bg_stroke);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let (mut icon_rect, _) = ui.spacing().icon_rectangles(header_response.rect);
|
let (mut icon_rect, _) = ui.spacing().icon_rectangles(header_response.rect);
|
||||||
icon_rect.set_center(pos2(
|
icon_rect.set_center(pos2(
|
||||||
|
|
|
@ -339,28 +339,53 @@ enum Action {
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
struct Tree(Vec<Tree>);
|
struct Tree(String, SubTree);
|
||||||
|
|
||||||
impl Tree {
|
impl Tree {
|
||||||
pub fn demo() -> Self {
|
pub fn demo() -> Self {
|
||||||
Self(vec![
|
Self(
|
||||||
Tree(vec![Tree::default(); 4]),
|
String::from("root"),
|
||||||
Tree(vec![Tree(vec![Tree::default(); 2]); 3]),
|
SubTree(vec![
|
||||||
])
|
SubTree(vec![SubTree::default(); 4]),
|
||||||
|
SubTree(vec![SubTree(vec![SubTree::default(); 2]); 3]),
|
||||||
|
]),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
pub fn ui(&mut self, ui: &mut Ui) -> Action {
|
pub fn ui(&mut self, ui: &mut Ui) -> Action {
|
||||||
self.ui_impl(ui, 0, "root")
|
self.1.ui(ui, 0, "root", &mut self.0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ui_impl(&mut self, ui: &mut Ui, depth: usize, name: &str) -> Action {
|
#[derive(Clone, Default)]
|
||||||
CollapsingHeader::new(name)
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
struct SubTree(Vec<SubTree>);
|
||||||
|
|
||||||
|
impl SubTree {
|
||||||
|
pub fn ui(
|
||||||
|
&mut self,
|
||||||
|
ui: &mut Ui,
|
||||||
|
depth: usize,
|
||||||
|
name: &str,
|
||||||
|
selected_name: &mut String,
|
||||||
|
) -> Action {
|
||||||
|
let response = CollapsingHeader::new(name)
|
||||||
.default_open(depth < 1)
|
.default_open(depth < 1)
|
||||||
.show(ui, |ui| self.children_ui(ui, depth))
|
.selectable(true)
|
||||||
.body_returned
|
.selected(selected_name.as_str() == name)
|
||||||
.unwrap_or(Action::Keep)
|
.show(ui, |ui| self.children_ui(ui, name, depth, selected_name));
|
||||||
|
if response.header_response.clicked() {
|
||||||
|
*selected_name = name.to_string();
|
||||||
|
}
|
||||||
|
response.body_returned.unwrap_or(Action::Keep)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn children_ui(&mut self, ui: &mut Ui, depth: usize) -> Action {
|
fn children_ui(
|
||||||
|
&mut self,
|
||||||
|
ui: &mut Ui,
|
||||||
|
parent_name: &str,
|
||||||
|
depth: usize,
|
||||||
|
selected_name: &mut String,
|
||||||
|
) -> Action {
|
||||||
if depth > 0
|
if depth > 0
|
||||||
&& ui
|
&& ui
|
||||||
.add(Button::new("delete").text_color(Color32::RED))
|
.add(Button::new("delete").text_color(Color32::RED))
|
||||||
|
@ -374,7 +399,13 @@ impl Tree {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, mut tree)| {
|
.filter_map(|(i, mut tree)| {
|
||||||
if tree.ui_impl(ui, depth + 1, &format!("child #{}", i)) == Action::Keep {
|
if tree.ui(
|
||||||
|
ui,
|
||||||
|
depth + 1,
|
||||||
|
&format!("{}/{}", parent_name, i),
|
||||||
|
selected_name,
|
||||||
|
) == Action::Keep
|
||||||
|
{
|
||||||
Some(tree)
|
Some(tree)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -383,7 +414,7 @@ impl Tree {
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if ui.button("+").clicked() {
|
if ui.button("+").clicked() {
|
||||||
self.0.push(Tree::default());
|
self.0.push(SubTree::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::Keep
|
Action::Keep
|
||||||
|
|
Loading…
Reference in a new issue