mirror of
https://github.com/enso-org/enso.git
synced 2024-12-24 15:22:01 +03:00
Show section name in breadcrumbs (#3778)
This PR implements displaying a currently active section name as a first crumb in the breadcrumbs panel. Sections are called `Popular`, `Modules` and `Local`. https://user-images.githubusercontent.com/6566674/194551276-90bd7d6b-8509-43ec-b3c0-11c35fda9063.mp4 # Important Notes This PR also contains a fix for [this bug](https://www.pivotaltracker.com/story/show/183499312). It was caused by mistake in the FRP implementation of the breadcrumbs. You could only trigger this bug after code changes in the `animation/loop.rs` module. It is not possible to see it otherwise. Still, the code was not correct, and now it is fixed.
This commit is contained in:
parent
701c644d0e
commit
78b8f43b96
@ -21,6 +21,7 @@ use enso_frp as frp;
|
|||||||
use ide_view as view;
|
use ide_view as view;
|
||||||
use ide_view::component_browser::component_list_panel::grid as component_grid;
|
use ide_view::component_browser::component_list_panel::grid as component_grid;
|
||||||
use ide_view::component_browser::component_list_panel::BreadcrumbId;
|
use ide_view::component_browser::component_list_panel::BreadcrumbId;
|
||||||
|
use ide_view::component_browser::component_list_panel::SECTION_NAME_CRUMB_INDEX;
|
||||||
use ide_view::graph_editor::component::node as node_view;
|
use ide_view::graph_editor::component::node as node_view;
|
||||||
use ide_view::graph_editor::GraphEditor;
|
use ide_view::graph_editor::GraphEditor;
|
||||||
use ide_view::project::SearcherParams;
|
use ide_view::project::SearcherParams;
|
||||||
@ -221,6 +222,17 @@ impl Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_section_name_crumb(&self, text: &str) {
|
||||||
|
if let SearcherVariant::ComponentBrowser(browser) = self.view.searcher() {
|
||||||
|
let breadcrumbs = &browser.model().list.model().breadcrumbs;
|
||||||
|
breadcrumbs.set_entry((SECTION_NAME_CRUMB_INDEX, ImString::new(text).into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_active_section_change(&self, section_id: component_grid::SectionId) {
|
||||||
|
self.set_section_name_crumb(section_id.as_str());
|
||||||
|
}
|
||||||
|
|
||||||
fn module_entered(&self, module: component_grid::ElementId) {
|
fn module_entered(&self, module: component_grid::ElementId) {
|
||||||
self.enter_module(module);
|
self.enter_module(module);
|
||||||
}
|
}
|
||||||
@ -380,6 +392,8 @@ impl Searcher {
|
|||||||
eval entry_selected((entry) model.suggestion_selected(*entry));
|
eval entry_selected((entry) model.suggestion_selected(*entry));
|
||||||
eval grid.module_entered((id) model.module_entered(*id));
|
eval grid.module_entered((id) model.module_entered(*id));
|
||||||
eval breadcrumbs.selected((id) model.breadcrumb_selected(*id));
|
eval breadcrumbs.selected((id) model.breadcrumb_selected(*id));
|
||||||
|
active_section <- grid.active_section.filter_map(|s| *s);
|
||||||
|
eval active_section((section) model.on_active_section_change(*section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SearcherVariant::OldNodeSearcher(searcher) => {
|
SearcherVariant::OldNodeSearcher(searcher) => {
|
||||||
|
@ -178,9 +178,9 @@ impl EntryData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_layout(&self, contour: Contour, text_size: text::Size, text_offset: f32) {
|
fn update_layout(&self, contour: Contour, text_size: text::Size, text_padding: f32) {
|
||||||
let size = contour.size;
|
let size = contour.size;
|
||||||
self.text.set_position_xy(Vector2(text_offset - size.x / 2.0, text_size.value / 2.0));
|
self.text.set_position_xy(Vector2(text_padding - size.x / 2.0, text_size.value / 2.0));
|
||||||
self.separator.size.set(size);
|
self.separator.size.set(size);
|
||||||
self.ellipsis.size.set(size);
|
self.ellipsis.size.set(size);
|
||||||
}
|
}
|
||||||
@ -216,15 +216,19 @@ impl EntryData {
|
|||||||
self.state.get() == State::Text
|
self.state.get() == State::Text
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the width of the entry if it is known. If the entry displays text, the width needs to
|
fn width(&self, text_padding: f32) -> f32 {
|
||||||
/// be calculated separately.
|
|
||||||
fn fixed_width(&self) -> Option<f32> {
|
|
||||||
match self.state.get() {
|
match self.state.get() {
|
||||||
State::Text => None,
|
State::Text => self.text_width(self.text.width.value(), text_padding),
|
||||||
State::Separator => Some(separator::ICON_WIDTH),
|
State::Separator => separator::ICON_WIDTH,
|
||||||
State::Ellipsis => Some(ellipsis::ICON_WIDTH),
|
State::Ellipsis => ellipsis::ICON_WIDTH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Width of the breadcrumb column filled with text of width [`text_width`] and with margin
|
||||||
|
/// [`text_padding`].
|
||||||
|
fn text_width(&self, text_width: f32, text_padding: f32) -> f32 {
|
||||||
|
text_width + text_padding * 2.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === Params ===
|
// === Params ===
|
||||||
@ -238,7 +242,7 @@ pub struct Params {
|
|||||||
pub margin: f32,
|
pub margin: f32,
|
||||||
pub hover_color: color::Lcha,
|
pub hover_color: color::Lcha,
|
||||||
pub font_name: ImString,
|
pub font_name: ImString,
|
||||||
pub text_padding_left: f32,
|
pub text_padding: f32,
|
||||||
pub text_size: text::Size,
|
pub text_size: text::Size,
|
||||||
pub selected_color: color::Lcha,
|
pub selected_color: color::Lcha,
|
||||||
pub highlight_corners_radius: f32,
|
pub highlight_corners_radius: f32,
|
||||||
@ -278,7 +282,7 @@ impl ensogl_grid_view::Entry for Entry {
|
|||||||
margin <- input.set_params.map(|p| p.margin).on_change();
|
margin <- input.set_params.map(|p| p.margin).on_change();
|
||||||
hover_color <- input.set_params.map(|p| p.hover_color).on_change();
|
hover_color <- input.set_params.map(|p| p.hover_color).on_change();
|
||||||
font <- input.set_params.map(|p| p.font_name.clone_ref()).on_change();
|
font <- input.set_params.map(|p| p.font_name.clone_ref()).on_change();
|
||||||
text_offset <- input.set_params.map(|p| p.text_padding_left).on_change();
|
text_padding <- input.set_params.map(|p| p.text_padding).on_change();
|
||||||
text_color <- input.set_params.map(|p| p.selected_color).on_change();
|
text_color <- input.set_params.map(|p| p.selected_color).on_change();
|
||||||
text_size <- input.set_params.map(|p| p.text_size).on_change();
|
text_size <- input.set_params.map(|p| p.text_size).on_change();
|
||||||
greyed_out_color <- input.set_params.map(|p| p.greyed_out_color).on_change();
|
greyed_out_color <- input.set_params.map(|p| p.greyed_out_color).on_change();
|
||||||
@ -306,7 +310,7 @@ impl ensogl_grid_view::Entry for Entry {
|
|||||||
size: *size - Vector2(*margin, *margin) * 2.0,
|
size: *size - Vector2(*margin, *margin) * 2.0,
|
||||||
corners_radius: 0.0,
|
corners_radius: 0.0,
|
||||||
});
|
});
|
||||||
layout <- all(contour, text_size, text_offset);
|
layout <- all(contour, text_size, text_padding);
|
||||||
eval layout ((&(c, ts, to)) data.update_layout(c, ts, to));
|
eval layout ((&(c, ts, to)) data.update_layout(c, ts, to));
|
||||||
eval color((c) data.set_default_color(*c));
|
eval color((c) data.set_default_color(*c));
|
||||||
eval font((f) data.set_font(f.to_string()));
|
eval font((f) data.set_font(f.to_string()));
|
||||||
@ -324,16 +328,16 @@ impl ensogl_grid_view::Entry for Entry {
|
|||||||
// === Override column width ===
|
// === Override column width ===
|
||||||
|
|
||||||
// We need to adjust the width of the grid view column depending on the width of
|
// We need to adjust the width of the grid view column depending on the width of
|
||||||
// the entry. For entries displaying icons we use [`EntryData::fixed_width`] method.
|
// the entry.
|
||||||
// For text entries, we listen for [`Text::width`] changes.
|
out.override_column_width <+ input.set_model.map2(&text_padding,
|
||||||
out.override_column_width <+ input.set_model.map(
|
f!([data](model, text_padding) {
|
||||||
f!((model) {
|
|
||||||
data.set_model(model);
|
data.set_model(model);
|
||||||
data.fixed_width()
|
data.width(*text_padding)
|
||||||
})
|
})
|
||||||
).filter_map(|w| *w);
|
);
|
||||||
text_width <- data.text.width.filter(f_!(data.is_text_displayed()));
|
text_width <- data.text.width.filter(f_!(data.is_text_displayed()));
|
||||||
entry_width <- text_width.map2(&text_offset, |w, text_offset| w + text_offset * 2.0);
|
// For text entries, we also listen for [`Text::width`] changes.
|
||||||
|
entry_width <- text_width.map2(&text_padding, f!((w, o) data.text_width(*w, *o)));
|
||||||
out.override_column_width <+ entry_width;
|
out.override_column_width <+ entry_width;
|
||||||
}
|
}
|
||||||
init.emit(());
|
init.emit(());
|
||||||
|
@ -75,6 +75,8 @@ mod entry;
|
|||||||
/// the last one or if it is placed in the right region of the viewport. This way, we avoid
|
/// the last one or if it is placed in the right region of the viewport. This way, we avoid
|
||||||
/// unnecessary scrolling when the user selects some breadcrumb close to the end of the list.
|
/// unnecessary scrolling when the user selects some breadcrumb close to the end of the list.
|
||||||
const SCROLLING_THRESHOLD_FRACTION: f32 = 0.5;
|
const SCROLLING_THRESHOLD_FRACTION: f32 = 0.5;
|
||||||
|
/// An index of the breadcrumb that displays the name of the active section.
|
||||||
|
pub const SECTION_NAME_CRUMB_INDEX: BreadcrumbId = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -210,7 +212,7 @@ impl Model {
|
|||||||
let (_, hover_color,selected_color,greyed_out_color) = colors;
|
let (_, hover_color,selected_color,greyed_out_color) = colors;
|
||||||
entry::Params {
|
entry::Params {
|
||||||
margin,
|
margin,
|
||||||
text_padding_left: *text_padding,
|
text_padding: *text_padding,
|
||||||
text_size: text::Size::from(*text_size),
|
text_size: text::Size::from(*text_size),
|
||||||
hover_color: hover_color.into(),
|
hover_color: hover_color.into(),
|
||||||
font_name: font.clone(),
|
font_name: font.clone(),
|
||||||
@ -347,12 +349,20 @@ impl Model {
|
|||||||
self.grid.set_entries_params(params);
|
self.grid.set_entries_params(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the breadcrumb at a specified index. Does nothing if index is out of bounds.
|
||||||
|
pub fn set_entry(&self, entry: &Breadcrumb, index: BreadcrumbId) {
|
||||||
|
if let Some(e) = self.entries.borrow_mut().get_mut(index) {
|
||||||
|
*e = entry.clone_ref();
|
||||||
|
}
|
||||||
|
self.grid.request_model_for_visible_entries();
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the breadcrumbs starting from the [`starting_from`] index. Existing entries after
|
/// Set the breadcrumbs starting from the [`starting_from`] index. Existing entries after
|
||||||
/// [`starting_from`] will be overwritten. [`self.entries`] will be extended if needed to fit
|
/// [`starting_from`] will be overwritten. [`self.entries`] will be extended if needed to fit
|
||||||
/// all added entries.
|
/// all added entries.
|
||||||
/// Immediately selects the last breadcrumb. All inactive (greyed out) breadcrumbs will be
|
/// Immediately selects the last breadcrumb. All inactive (greyed out) breadcrumbs will be
|
||||||
/// removed.
|
/// removed.
|
||||||
pub fn set_entries(&self, starting_from: usize, new_entries: &[Breadcrumb]) {
|
pub fn set_entries(&self, new_entries: &[Breadcrumb], starting_from: BreadcrumbId) {
|
||||||
{
|
{
|
||||||
let mut borrowed = self.entries.borrow_mut();
|
let mut borrowed = self.entries.borrow_mut();
|
||||||
let end_of_overwritten_entries = starting_from + new_entries.len();
|
let end_of_overwritten_entries = starting_from + new_entries.len();
|
||||||
@ -375,7 +385,7 @@ impl Model {
|
|||||||
/// A newly added breadcrumb will be placed after the currently selected one. All inactive
|
/// A newly added breadcrumb will be placed after the currently selected one. All inactive
|
||||||
/// (greyed out) breadcrumbs will be removed.
|
/// (greyed out) breadcrumbs will be removed.
|
||||||
pub fn push(&self, breadcrumb: &Breadcrumb) {
|
pub fn push(&self, breadcrumb: &Breadcrumb) {
|
||||||
self.set_entries(self.entries.borrow().len(), &[breadcrumb.clone_ref()]);
|
self.set_entries(&[breadcrumb.clone_ref()], self.entries.borrow().len());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move the selection to the previous breadcrumb. Stops at the first one. There is always at
|
/// Move the selection to the previous breadcrumb. Stops at the first one. There is always at
|
||||||
@ -431,7 +441,9 @@ ensogl_core::define_endpoints_2! {
|
|||||||
/// Add a new breadcrumb after the currently selected one.
|
/// Add a new breadcrumb after the currently selected one.
|
||||||
push(Breadcrumb),
|
push(Breadcrumb),
|
||||||
/// Set the displayed breadcrumbs starting from the specific index.
|
/// Set the displayed breadcrumbs starting from the specific index.
|
||||||
set_entries_from((Vec<Breadcrumb>, usize)),
|
set_entries_from((Vec<Breadcrumb>, BreadcrumbId)),
|
||||||
|
/// Set the breadcrumb at a specified index.
|
||||||
|
set_entry((BreadcrumbId, Breadcrumb)),
|
||||||
/// Enable or disable displaying of the ellipsis icon at the end of the list.
|
/// Enable or disable displaying of the ellipsis icon at the end of the list.
|
||||||
show_ellipsis(bool),
|
show_ellipsis(bool),
|
||||||
/// Remove all breadcrumbs.
|
/// Remove all breadcrumbs.
|
||||||
@ -484,7 +496,8 @@ impl Breadcrumbs {
|
|||||||
eval_ input.clear(model.clear());
|
eval_ input.clear(model.clear());
|
||||||
selected <- selected_grid_col.map(|(_, col)| col / 2);
|
selected <- selected_grid_col.map(|(_, col)| col / 2);
|
||||||
eval input.push((b) model.push(b));
|
eval input.push((b) model.push(b));
|
||||||
eval input.set_entries_from(((entries, from)) model.set_entries(*from, entries));
|
eval input.set_entries_from(((entries, from)) model.set_entries(entries, *from));
|
||||||
|
eval input.set_entry(((index, entry)) model.set_entry(entry, *index));
|
||||||
out.selected <+ selected;
|
out.selected <+ selected;
|
||||||
|
|
||||||
scroll_anim.target <+ all_with3(&model.grid.content_size, &input.set_size, &model.grid
|
scroll_anim.target <+ all_with3(&model.grid.content_size, &input.set_size, &model.grid
|
||||||
|
@ -26,6 +26,17 @@ pub enum SectionId {
|
|||||||
SubModules,
|
SubModules,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SectionId {
|
||||||
|
/// Return a displayed name of the section.
|
||||||
|
pub const fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Popular => "Popular",
|
||||||
|
Self::LocalScope => "Local",
|
||||||
|
Self::SubModules => "Modules",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// === GroupId ===
|
// === GroupId ===
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ use ensogl_shadow as shadow;
|
|||||||
mod navigator;
|
mod navigator;
|
||||||
|
|
||||||
pub use breadcrumbs::BreadcrumbId;
|
pub use breadcrumbs::BreadcrumbId;
|
||||||
|
pub use breadcrumbs::SECTION_NAME_CRUMB_INDEX;
|
||||||
pub use ensogl_core::prelude;
|
pub use ensogl_core::prelude;
|
||||||
pub use ide_view_component_list_panel_breadcrumbs as breadcrumbs;
|
pub use ide_view_component_list_panel_breadcrumbs as breadcrumbs;
|
||||||
pub use ide_view_component_list_panel_grid as grid;
|
pub use ide_view_component_list_panel_grid as grid;
|
||||||
@ -87,6 +88,7 @@ pub use ide_view_component_list_panel_grid::entry::icon;
|
|||||||
|
|
||||||
/// The selection animation is faster than the default one because of the increased spring force.
|
/// The selection animation is faster than the default one because of the increased spring force.
|
||||||
const SELECTION_ANIMATION_SPRING_FORCE_MULTIPLIER: f32 = 1.5;
|
const SELECTION_ANIMATION_SPRING_FORCE_MULTIPLIER: f32 = 1.5;
|
||||||
|
const INITIAL_SECTION_NAME: &str = grid::SectionId::Popular.as_str();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -269,7 +271,8 @@ impl Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_initial_breadcrumbs(&self) {
|
fn set_initial_breadcrumbs(&self) {
|
||||||
self.breadcrumbs.set_entries_from((vec![breadcrumbs::Breadcrumb::new("All")], 0));
|
let breadcrumb = breadcrumbs::Breadcrumb::new(INITIAL_SECTION_NAME);
|
||||||
|
self.breadcrumbs.set_entries_from((vec![breadcrumb], 0));
|
||||||
self.breadcrumbs.show_ellipsis(true);
|
self.breadcrumbs.show_ellipsis(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user