Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Selection to Item, MultiSelection to ItemCollection #1104

Merged
merged 1 commit into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/re_viewer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod misc;
mod remote_viewer_app;
mod ui;

pub(crate) use misc::{mesh_loader, time_axis, Selection, TimeControl, TimeView, ViewerContext};
pub(crate) use misc::{mesh_loader, time_axis, Item, TimeControl, TimeView, ViewerContext};
pub(crate) use ui::{event_log_view, memory_panel, selection_panel, time_panel, UiVerbosity};

pub use app::{App, StartupOptions};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,45 @@ use re_log_types::{ComponentPath, MsgId};

use crate::ui::SpaceViewId;

/// One "thing" in the UI.
///
/// This is the granularity of what is selectable and hoverable.
///
/// A set of these is a an [`ItemCollection`].
#[derive(Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
pub enum Selection {
pub enum Item {
MsgId(MsgId),
ComponentPath(ComponentPath),
SpaceView(SpaceViewId),
InstancePath(Option<SpaceViewId>, InstancePath),
DataBlueprintGroup(SpaceViewId, crate::ui::DataBlueprintGroupHandle),
}

impl std::fmt::Debug for Selection {
impl std::fmt::Debug for Item {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Selection::MsgId(s) => s.fmt(f),
Selection::ComponentPath(s) => s.fmt(f),
Selection::SpaceView(s) => write!(f, "{s:?}"),
Selection::InstancePath(sid, path) => write!(f, "({sid:?}, {path})"),
Selection::DataBlueprintGroup(sid, handle) => write!(f, "({sid:?}, {handle:?})"),
Item::MsgId(s) => s.fmt(f),
Item::ComponentPath(s) => s.fmt(f),
Item::SpaceView(s) => write!(f, "{s:?}"),
Item::InstancePath(sid, path) => write!(f, "({sid:?}, {path})"),
Item::DataBlueprintGroup(sid, handle) => write!(f, "({sid:?}, {handle:?})"),
}
}
}

impl Selection {
impl Item {
/// If `false`, the selection is referring to data that is no longer present.
pub(crate) fn is_valid(&self, log_db: &LogDb, blueprint: &crate::ui::Blueprint) -> bool {
match self {
Selection::ComponentPath(_) => true,
Selection::InstancePath(space_view_id, _) => space_view_id
Item::ComponentPath(_) => true,
Item::InstancePath(space_view_id, _) => space_view_id
.map(|space_view_id| blueprint.viewport.space_view(&space_view_id).is_some())
.unwrap_or(true),
Selection::MsgId(msg_id) => log_db.get_log_msg(msg_id).is_some(),
Selection::SpaceView(space_view_id) => {
Item::MsgId(msg_id) => log_db.get_log_msg(msg_id).is_some(),
Item::SpaceView(space_view_id) => {
blueprint.viewport.space_view(space_view_id).is_some()
}
Selection::DataBlueprintGroup(space_view_id, data_blueprint_group_handle) => {
Item::DataBlueprintGroup(space_view_id, data_blueprint_group_handle) => {
if let Some(space_view) = blueprint.viewport.space_view(space_view_id) {
space_view
.data_blueprint
Expand All @@ -50,10 +55,10 @@ impl Selection {
}
}

pub fn kind(self: &Selection) -> &'static str {
pub fn kind(self: &Item) -> &'static str {
match self {
Selection::MsgId(_) => "Message",
Selection::InstancePath(space_view_id, instance_path) => {
Item::MsgId(_) => "Message",
Item::InstancePath(space_view_id, instance_path) => {
match (
instance_path.instance_key.is_specific(),
space_view_id.is_some(),
Expand All @@ -64,23 +69,25 @@ impl Selection {
(false, false) => "Entity",
}
}
Selection::ComponentPath(_) => "Entity Component",
Selection::SpaceView(_) => "Space View",
Selection::DataBlueprintGroup(_, _) => "Group",
Item::ComponentPath(_) => "Entity Component",
Item::SpaceView(_) => "Space View",
Item::DataBlueprintGroup(_, _) => "Group",
}
}
}

/// Describing a single selection of things.
/// An ordered collection of [`Item`].
///
/// Used to store what is currently selected and/or hovered.
///
/// Immutable object, may pre-compute additional information about the selection on creation.
#[derive(Default, Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub struct MultiSelection {
selection: Vec<Selection>,
pub struct ItemCollection {
selection: Vec<Item>,
}

impl MultiSelection {
pub fn new(items: impl Iterator<Item = Selection>) -> Self {
impl ItemCollection {
pub fn new(items: impl Iterator<Item = Item>) -> Self {
let selection = items.unique().collect();
Self { selection }
}
Expand All @@ -95,25 +102,25 @@ impl MultiSelection {
}

/// The first selected object if any.
pub fn first(&self) -> Option<&Selection> {
pub fn first(&self) -> Option<&Item> {
self.selection.first()
}

pub fn iter(&self) -> impl Iterator<Item = &Selection> {
pub fn iter(&self) -> impl Iterator<Item = &Item> {
self.selection.iter()
}

pub fn into_iter(self) -> impl Iterator<Item = Selection> {
pub fn into_iter(self) -> impl Iterator<Item = Item> {
self.selection.into_iter()
}

pub fn to_vec(&self) -> Vec<Selection> {
pub fn to_vec(&self) -> Vec<Item> {
self.selection.clone()
}

/// Returns true if the exact selection is part of the current selection.
pub fn contains(&self, selection: &Selection) -> bool {
self.selection.contains(selection)
pub fn contains(&self, item: &Item) -> bool {
self.selection.contains(item)
}

pub fn are_all_same_kind(&self) -> Option<&'static str> {
Expand Down
4 changes: 2 additions & 2 deletions crates/re_viewer/src/misc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
mod app_options;
pub mod caches;
pub(crate) mod color_map;
mod item;
pub(crate) mod mesh_loader;
mod selection;
mod selection_state;
pub(crate) mod space_info;
pub(crate) mod time_axis;
Expand All @@ -28,7 +28,7 @@ pub mod clipboard;
pub use transform_cache::{TransformCache, UnreachableTransform};
pub use {
app_options::*,
selection::{MultiSelection, Selection},
item::{Item, ItemCollection},
selection_state::{
HoverHighlight, HoveredSpace, InteractionHighlight, OptionalSpaceViewEntityHighlight,
SelectionHighlight, SelectionState, SpaceViewHighlights,
Expand Down
59 changes: 28 additions & 31 deletions crates/re_viewer/src/misc/selection_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use re_log_types::{component_types::InstanceKey, EntityPathHash};

use crate::ui::{Blueprint, HistoricalSelection, SelectionHistory, SpaceView, SpaceViewId};

use super::{MultiSelection, Selection};
use super::{Item, ItemCollection};

#[derive(Clone, Default, Debug, PartialEq)]
pub enum HoveredSpace {
Expand Down Expand Up @@ -155,19 +155,19 @@ pub struct SelectionState {
///
/// Do not access this field directly! Use the helper methods instead, which will make sure
/// to properly maintain the undo/redo history.
selection: MultiSelection,
selection: ItemCollection,

/// History of selections (what was selected previously).
#[serde(skip)]
history: SelectionHistory,

/// What objects are hovered? Read from this.
#[serde(skip)]
hovered_previous_frame: MultiSelection,
hovered_previous_frame: ItemCollection,

/// What objects are hovered? Write to this.
#[serde(skip)]
hovered_this_frame: MultiSelection,
hovered_this_frame: ItemCollection,

/// What space is the pointer hovering over? Read from this.
#[serde(skip)]
Expand Down Expand Up @@ -202,51 +202,48 @@ impl SelectionState {

/// Clears the current selection out.
pub fn clear_current(&mut self) {
self.selection = MultiSelection::default();
self.selection = ItemCollection::default();
}

/// Sets a single selection, updating history as needed.
///
/// Returns the previous selection.
pub fn set_single_selection(&mut self, item: Selection) -> MultiSelection {
pub fn set_single_selection(&mut self, item: Item) -> ItemCollection {
self.set_multi_selection(std::iter::once(item))
}

/// Sets several objects to be selected, updating history as needed.
///
/// Returns the previous selection.
pub fn set_multi_selection(
&mut self,
items: impl Iterator<Item = Selection>,
) -> MultiSelection {
let new_selection = MultiSelection::new(items);
pub fn set_multi_selection(&mut self, items: impl Iterator<Item = Item>) -> ItemCollection {
let new_selection = ItemCollection::new(items);
self.history.update_selection(&new_selection);
std::mem::replace(&mut self.selection, new_selection)
}

/// Returns the current selection.
pub fn current(&self) -> &MultiSelection {
pub fn current(&self) -> &ItemCollection {
&self.selection
}

/// Returns the currently hovered objects.
pub fn hovered(&self) -> &MultiSelection {
pub fn hovered(&self) -> &ItemCollection {
&self.hovered_previous_frame
}

/// Set the hovered objects. Will be in [`Self::hovered`] on the next frame.
pub fn set_hovered(&mut self, items: impl Iterator<Item = Selection>) {
self.hovered_this_frame = MultiSelection::new(items);
pub fn set_hovered(&mut self, items: impl Iterator<Item = Item>) {
self.hovered_this_frame = ItemCollection::new(items);
}

/// Select currently hovered objects unless already selected in which case they get unselected.
pub fn toggle_selection(&mut self, toggle_items: Vec<Selection>) {
pub fn toggle_selection(&mut self, toggle_items: Vec<Item>) {
crate::profile_function!();

// Make sure we preserve the order - old items kept in same order, new items added to the end.

// All the items to toggle. If an was already selected, it will be removed from this.
let mut toggle_items_set: HashSet<Selection> = toggle_items.iter().cloned().collect();
let mut toggle_items_set: HashSet<Item> = toggle_items.iter().cloned().collect();

let mut new_selection = self.selection.to_vec();
new_selection.retain(|item| !toggle_items_set.remove(item));
Expand All @@ -273,22 +270,22 @@ impl SelectionState {
&mut self,
ui: &mut egui::Ui,
blueprint: &mut Blueprint,
) -> Option<MultiSelection> {
) -> Option<ItemCollection> {
self.history.selection_ui(ui, blueprint)
}

pub fn highlight_for_ui_element(&self, test: &Selection) -> HoverHighlight {
pub fn highlight_for_ui_element(&self, test: &Item) -> HoverHighlight {
let hovered = self
.hovered_previous_frame
.iter()
.any(|current| match current {
Selection::MsgId(_)
| Selection::ComponentPath(_)
| Selection::SpaceView(_)
| Selection::DataBlueprintGroup(_, _) => current == test,
Item::MsgId(_)
| Item::ComponentPath(_)
| Item::SpaceView(_)
| Item::DataBlueprintGroup(_, _) => current == test,

Selection::InstancePath(current_space_view_id, current_instance_path) => {
if let Selection::InstancePath(test_space_view_id, test_instance_path) = test {
Item::InstancePath(current_space_view_id, current_instance_path) => {
if let Item::InstancePath(test_space_view_id, test_instance_path) = test {
// For both space view id and instance index we want to be inclusive,
// but if both are set to Some, and set to different, then we count that
// as a miss.
Expand Down Expand Up @@ -326,9 +323,9 @@ impl SelectionState {

for current_selection in self.selection.iter() {
match current_selection {
Selection::MsgId(_) | Selection::ComponentPath(_) | Selection::SpaceView(_) => {}
Item::MsgId(_) | Item::ComponentPath(_) | Item::SpaceView(_) => {}

Selection::DataBlueprintGroup(group_space_view_id, group_handle) => {
Item::DataBlueprintGroup(group_space_view_id, group_handle) => {
if *group_space_view_id == space_view_id {
if let Some(space_view) = space_views.get(group_space_view_id) {
space_view.data_blueprint.visit_group_entities_recursively(
Expand All @@ -345,7 +342,7 @@ impl SelectionState {
}
}

Selection::InstancePath(selected_space_view_context, selected_instance) => {
Item::InstancePath(selected_space_view_context, selected_instance) => {
let highlight = if *selected_space_view_context == Some(space_view_id) {
SelectionHighlight::Selection
} else {
Expand Down Expand Up @@ -375,9 +372,9 @@ impl SelectionState {

for current_hover in self.hovered_previous_frame.iter() {
match current_hover {
Selection::MsgId(_) | Selection::ComponentPath(_) | Selection::SpaceView(_) => {}
Item::MsgId(_) | Item::ComponentPath(_) | Item::SpaceView(_) => {}

Selection::DataBlueprintGroup(group_space_view_id, group_handle) => {
Item::DataBlueprintGroup(group_space_view_id, group_handle) => {
// Unlike for selected objects/data we are more picky for data blueprints with our hover highlights
// since they are truly local to a space view.
if *group_space_view_id == space_view_id {
Expand All @@ -396,7 +393,7 @@ impl SelectionState {
}
}

Selection::InstancePath(_, selected_instance) => {
Item::InstancePath(_, selected_instance) => {
let highlighted_entity = highlighted_entity_paths
.entry(selected_instance.entity_path.hash())
.or_default();
Expand Down
Loading