egui_arbor/
default_actions.rs

1//! Default implementation of the OutlinerActions trait.
2//!
3//! This module provides [`DefaultActions`], a ready-to-use implementation of the
4//! [`OutlinerActions`] trait that handles common outliner state management including
5//! selection, visibility, lock states, and optional event logging.
6//!
7//! # Examples
8//!
9//! ```
10//! use egui_arbor::{Outliner, OutlinerNode, default_actions::DefaultActions};
11//!
12//! // Create actions handler with logging
13//! let mut actions = DefaultActions::<u64>::with_logging(10);
14//!
15//! // Use with outliner
16//! // let response = Outliner::new("tree").show(ui, &nodes, &mut actions);
17//!
18//! // Access state
19//! assert_eq!(actions.selected_count(), 0);
20//! assert_eq!(actions.visible_count(), 0);
21//! ```
22
23use crate::event_log::{EventLog, EventType};
24use crate::traits::{DropPosition, OutlinerActions, OutlinerNode};
25use std::collections::HashSet;
26use std::hash::Hash;
27
28/// Default implementation of outliner actions with state tracking.
29///
30/// This struct provides a complete, ready-to-use implementation of the
31/// [`OutlinerActions`] trait. It tracks:
32/// - **Selection state**: Which nodes are currently selected
33/// - **Visibility state**: Which nodes are visible/hidden
34/// - **Lock state**: Which nodes are locked
35/// - **Event log**: Optional logging of all interactions
36///
37/// # Type Parameters
38///
39/// * `Id` - The type used to identify nodes. Must implement `Hash`, `Eq`, and `Clone`.
40///
41/// # Examples
42///
43/// ## Basic Usage
44///
45/// ```
46/// use egui_arbor::default_actions::DefaultActions;
47/// use egui_arbor::OutlinerActions;
48///
49/// # struct TestNode { children: Vec<TestNode> }
50/// # impl egui_arbor::OutlinerNode for TestNode {
51/// #     type Id = u64;
52/// #     fn id(&self) -> Self::Id { 0 }
53/// #     fn name(&self) -> &str { "" }
54/// #     fn is_collection(&self) -> bool { false }
55/// #     fn children(&self) -> &[Self] { &self.children }
56/// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
57/// # }
58/// let mut actions = DefaultActions::<u64>::new();
59///
60/// // All nodes start unselected, visible, and unlocked
61/// assert!(!OutlinerActions::<TestNode>::is_selected(&actions, &1));
62/// assert!(!OutlinerActions::<TestNode>::is_visible(&actions, &1));
63/// assert!(!OutlinerActions::<TestNode>::is_locked(&actions, &1));
64/// ```
65///
66/// ## With Event Logging
67///
68/// ```
69/// use egui_arbor::default_actions::DefaultActions;
70/// use egui_arbor::OutlinerActions;
71///
72/// # struct TestNode { children: Vec<TestNode> }
73/// # impl egui_arbor::OutlinerNode for TestNode {
74/// #     type Id = u64;
75/// #     fn id(&self) -> Self::Id { 0 }
76/// #     fn name(&self) -> &str { "" }
77/// #     fn is_collection(&self) -> bool { false }
78/// #     fn children(&self) -> &[Self] { &self.children }
79/// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
80/// # }
81/// let mut actions = DefaultActions::<u64>::with_logging(50);
82///
83/// // Events are automatically logged
84/// OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
85/// assert_eq!(actions.event_log().unwrap().len(), 1);
86/// ```
87///
88/// ## Pre-populate State
89///
90/// ```
91/// use egui_arbor::default_actions::DefaultActions;
92/// use egui_arbor::OutlinerActions;
93/// use std::collections::HashSet;
94///
95/// # struct TestNode { children: Vec<TestNode> }
96/// # impl egui_arbor::OutlinerNode for TestNode {
97/// #     type Id = u64;
98/// #     fn id(&self) -> Self::Id { 0 }
99/// #     fn name(&self) -> &str { "" }
100/// #     fn is_collection(&self) -> bool { false }
101/// #     fn children(&self) -> &[Self] { &self.children }
102/// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
103/// # }
104/// let mut actions = DefaultActions::<u64>::new();
105///
106/// // Make all nodes visible by default
107/// let visible_ids: HashSet<_> = (0..10).collect();
108/// actions.set_all_visible(visible_ids);
109///
110/// assert!(OutlinerActions::<TestNode>::is_visible(&actions, &5));
111/// ```
112#[derive(Clone, Debug)]
113pub struct DefaultActions<Id>
114where
115    Id: Hash + Eq + Clone + std::fmt::Debug,
116{
117    /// Set of selected node IDs.
118    selected: HashSet<Id>,
119    
120    /// Set of visible node IDs.
121    visible: HashSet<Id>,
122    
123    /// Set of locked node IDs.
124    locked: HashSet<Id>,
125    
126    /// Optional event log for tracking interactions.
127    event_log: Option<EventLog<Id>>,
128}
129
130impl<Id> DefaultActions<Id>
131where
132    Id: Hash + Eq + Clone + std::fmt::Debug,
133{
134    /// Creates a new actions handler with no event logging.
135    ///
136    /// All nodes start unselected, invisible, and unlocked.
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use egui_arbor::default_actions::DefaultActions;
142    ///
143    /// let actions = DefaultActions::<u64>::new();
144    /// ```
145    pub fn new() -> Self {
146        Self {
147            selected: HashSet::new(),
148            visible: HashSet::new(),
149            locked: HashSet::new(),
150            event_log: None,
151        }
152    }
153
154    /// Creates a new actions handler with event logging enabled.
155    ///
156    /// # Arguments
157    ///
158    /// * `max_log_entries` - Maximum number of log entries to keep
159    ///
160    /// # Examples
161    ///
162    /// ```
163    /// use egui_arbor::default_actions::DefaultActions;
164    ///
165    /// let actions = DefaultActions::<u64>::with_logging(100);
166    /// ```
167    pub fn with_logging(max_log_entries: usize) -> Self {
168        Self {
169            selected: HashSet::new(),
170            visible: HashSet::new(),
171            locked: HashSet::new(),
172            event_log: Some(EventLog::new(max_log_entries)),
173        }
174    }
175
176    /// Returns a reference to the event log, if logging is enabled.
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// use egui_arbor::default_actions::DefaultActions;
182    ///
183    /// let actions = DefaultActions::<u64>::with_logging(10);
184    /// assert!(actions.event_log().is_some());
185    ///
186    /// let actions = DefaultActions::<u64>::new();
187    /// assert!(actions.event_log().is_none());
188    /// ```
189    pub fn event_log(&self) -> Option<&EventLog<Id>> {
190        self.event_log.as_ref()
191    }
192
193    /// Returns a mutable reference to the event log, if logging is enabled.
194    ///
195    /// # Examples
196    ///
197    /// ```
198    /// use egui_arbor::default_actions::DefaultActions;
199    ///
200    /// let mut actions = DefaultActions::<u64>::with_logging(10);
201    /// if let Some(log) = actions.event_log_mut() {
202    ///     log.clear();
203    /// }
204    /// ```
205    pub fn event_log_mut(&mut self) -> Option<&mut EventLog<Id>> {
206        self.event_log.as_mut()
207    }
208
209    /// Returns the number of selected nodes.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use egui_arbor::default_actions::DefaultActions;
215    /// use egui_arbor::OutlinerActions;
216    ///
217    /// # struct TestNode { children: Vec<TestNode> }
218    /// # impl egui_arbor::OutlinerNode for TestNode {
219    /// #     type Id = u64;
220    /// #     fn id(&self) -> Self::Id { 0 }
221    /// #     fn name(&self) -> &str { "" }
222    /// #     fn is_collection(&self) -> bool { false }
223    /// #     fn children(&self) -> &[Self] { &self.children }
224    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
225    /// # }
226    /// let mut actions = DefaultActions::<u64>::new();
227    /// OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
228    /// OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
229    /// assert_eq!(actions.selected_count(), 2);
230    /// ```
231    pub fn selected_count(&self) -> usize {
232        self.selected.len()
233    }
234
235    /// Returns the number of visible nodes.
236    ///
237    /// # Examples
238    ///
239    /// ```
240    /// use egui_arbor::default_actions::DefaultActions;
241    /// use egui_arbor::OutlinerActions;
242    ///
243    /// # struct TestNode { children: Vec<TestNode> }
244    /// # impl egui_arbor::OutlinerNode for TestNode {
245    /// #     type Id = u64;
246    /// #     fn id(&self) -> Self::Id { 0 }
247    /// #     fn name(&self) -> &str { "" }
248    /// #     fn is_collection(&self) -> bool { false }
249    /// #     fn children(&self) -> &[Self] { &self.children }
250    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
251    /// # }
252    /// let mut actions = DefaultActions::<u64>::new();
253    /// OutlinerActions::<TestNode>::on_visibility_toggle(&mut actions, &1);
254    /// assert_eq!(actions.visible_count(), 1);
255    /// ```
256    pub fn visible_count(&self) -> usize {
257        self.visible.len()
258    }
259
260    /// Returns the number of locked nodes.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// use egui_arbor::default_actions::DefaultActions;
266    /// use egui_arbor::OutlinerActions;
267    ///
268    /// # struct TestNode { children: Vec<TestNode> }
269    /// # impl egui_arbor::OutlinerNode for TestNode {
270    /// #     type Id = u64;
271    /// #     fn id(&self) -> Self::Id { 0 }
272    /// #     fn name(&self) -> &str { "" }
273    /// #     fn is_collection(&self) -> bool { false }
274    /// #     fn children(&self) -> &[Self] { &self.children }
275    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
276    /// # }
277    /// let mut actions = DefaultActions::<u64>::new();
278    /// OutlinerActions::<TestNode>::on_lock_toggle(&mut actions, &1);
279    /// assert_eq!(actions.locked_count(), 1);
280    /// ```
281    pub fn locked_count(&self) -> usize {
282        self.locked.len()
283    }
284
285    /// Returns a reference to the set of selected node IDs.
286    ///
287    /// # Examples
288    ///
289    /// ```
290    /// use egui_arbor::default_actions::DefaultActions;
291    /// use egui_arbor::OutlinerActions;
292    ///
293    /// # struct TestNode { children: Vec<TestNode> }
294    /// # impl egui_arbor::OutlinerNode for TestNode {
295    /// #     type Id = u64;
296    /// #     fn id(&self) -> Self::Id { 0 }
297    /// #     fn name(&self) -> &str { "" }
298    /// #     fn is_collection(&self) -> bool { false }
299    /// #     fn children(&self) -> &[Self] { &self.children }
300    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
301    /// # }
302    /// let mut actions = DefaultActions::<u64>::new();
303    /// OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
304    /// OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
305    ///
306    /// assert!(actions.selected().contains(&1));
307    /// assert!(actions.selected().contains(&2));
308    /// ```
309    pub fn selected(&self) -> &HashSet<Id> {
310        &self.selected
311    }
312
313    /// Returns a reference to the set of visible node IDs.
314    pub fn visible(&self) -> &HashSet<Id> {
315        &self.visible
316    }
317
318    /// Returns a reference to the set of locked node IDs.
319    pub fn locked(&self) -> &HashSet<Id> {
320        &self.locked
321    }
322
323    /// Sets all nodes as visible.
324    ///
325    /// # Arguments
326    ///
327    /// * `ids` - Set of node IDs to mark as visible
328    ///
329    /// # Examples
330    ///
331    /// ```
332    /// use egui_arbor::default_actions::DefaultActions;
333    /// use egui_arbor::OutlinerActions;
334    /// use std::collections::HashSet;
335    ///
336    /// # struct TestNode { children: Vec<TestNode> }
337    /// # impl egui_arbor::OutlinerNode for TestNode {
338    /// #     type Id = u64;
339    /// #     fn id(&self) -> Self::Id { 0 }
340    /// #     fn name(&self) -> &str { "" }
341    /// #     fn is_collection(&self) -> bool { false }
342    /// #     fn children(&self) -> &[Self] { &self.children }
343    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
344    /// # }
345    /// let mut actions = DefaultActions::<u64>::new();
346    /// let visible: HashSet<_> = (0..10).collect();
347    /// actions.set_all_visible(visible);
348    ///
349    /// assert!(OutlinerActions::<TestNode>::is_visible(&actions, &5));
350    /// ```
351    pub fn set_all_visible(&mut self, ids: HashSet<Id>) {
352        self.visible = ids;
353    }
354
355    /// Clears all selections.
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// use egui_arbor::default_actions::DefaultActions;
361    /// use egui_arbor::OutlinerActions;
362    ///
363    /// # struct TestNode { children: Vec<TestNode> }
364    /// # impl egui_arbor::OutlinerNode for TestNode {
365    /// #     type Id = u64;
366    /// #     fn id(&self) -> Self::Id { 0 }
367    /// #     fn name(&self) -> &str { "" }
368    /// #     fn is_collection(&self) -> bool { false }
369    /// #     fn children(&self) -> &[Self] { &self.children }
370    /// #     fn children_mut(&mut self) -> &mut Vec<Self> { &mut self.children }
371    /// # }
372    /// let mut actions = DefaultActions::<u64>::new();
373    /// OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
374    /// OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
375    /// assert_eq!(actions.selected_count(), 2);
376    ///
377    /// actions.clear_selection();
378    /// assert_eq!(actions.selected_count(), 0);
379    /// ```
380    pub fn clear_selection(&mut self) {
381        self.selected.clear();
382    }
383
384    /// Logs an event if logging is enabled.
385    fn log_event(&mut self, message: String, event_type: EventType, node_id: Option<Id>) {
386        if let Some(log) = &mut self.event_log {
387            log.log(message, event_type, node_id);
388        }
389    }
390}
391
392impl<Id> Default for DefaultActions<Id>
393where
394    Id: Hash + Eq + Clone + std::fmt::Debug,
395{
396    fn default() -> Self {
397        Self::new()
398    }
399}
400
401impl<Id, N> OutlinerActions<N> for DefaultActions<Id>
402where
403    Id: Hash + Eq + Clone + std::fmt::Debug,
404    N: OutlinerNode<Id = Id>,
405{
406    fn on_rename(&mut self, id: &Id, new_name: String) {
407        self.log_event(
408            format!("Renamed node {:?} to '{}'", id, new_name),
409            EventType::Rename,
410            Some(id.clone()),
411        );
412    }
413
414    fn on_move(&mut self, id: &Id, target: &Id, position: DropPosition) {
415        self.log_event(
416            format!("Move: node {:?} → target {:?} ({:?})", id, target, position),
417            EventType::DragDrop,
418            Some(id.clone()),
419        );
420    }
421
422    fn on_select(&mut self, id: &Id, selected: bool) {
423        if selected {
424            self.selected.insert(id.clone());
425            self.log_event(
426                format!("Selected node {:?}", id),
427                EventType::Selection,
428                Some(id.clone()),
429            );
430        } else {
431            self.selected.remove(id);
432            self.log_event(
433                format!("Deselected node {:?}", id),
434                EventType::Selection,
435                Some(id.clone()),
436            );
437        }
438    }
439
440    fn is_selected(&self, id: &Id) -> bool {
441        self.selected.contains(id)
442    }
443
444    fn is_visible(&self, id: &Id) -> bool {
445        self.visible.contains(id)
446    }
447
448    fn is_locked(&self, id: &Id) -> bool {
449        self.locked.contains(id)
450    }
451
452    fn on_visibility_toggle(&mut self, id: &Id) {
453        let was_visible = self.visible.contains(id);
454        if was_visible {
455            self.visible.remove(id);
456            self.log_event(
457                format!("Hidden node {:?}", id),
458                EventType::Visibility,
459                Some(id.clone()),
460            );
461        } else {
462            self.visible.insert(id.clone());
463            self.log_event(
464                format!("Shown node {:?}", id),
465                EventType::Visibility,
466                Some(id.clone()),
467            );
468        }
469    }
470
471    fn on_lock_toggle(&mut self, id: &Id) {
472        let was_locked = self.locked.contains(id);
473        if was_locked {
474            self.locked.remove(id);
475            self.log_event(
476                format!("Unlocked node {:?}", id),
477                EventType::Lock,
478                Some(id.clone()),
479            );
480        } else {
481            self.locked.insert(id.clone());
482            self.log_event(
483                format!("Locked node {:?}", id),
484                EventType::Lock,
485                Some(id.clone()),
486            );
487        }
488    }
489
490    fn on_selection_toggle(&mut self, id: &Id) {
491        let is_selected = OutlinerActions::<N>::is_selected(self, id);
492        OutlinerActions::<N>::on_select(self, id, !is_selected);
493    }
494
495    fn on_custom_action(&mut self, id: &Id, icon: &str) {
496        self.log_event(
497            format!("Custom action '{}' on node {:?}", icon, id),
498            EventType::Custom(icon.to_string()),
499            Some(id.clone()),
500        );
501    }
502}
503
504#[cfg(test)]
505mod tests {
506    use super::*;
507    use crate::traits::{ActionIcon, IconType};
508
509    #[derive(Clone, Debug)]
510    struct TestNode {
511        id: u64,
512        name: String,
513        children: Vec<TestNode>,
514    }
515
516    impl OutlinerNode for TestNode {
517        type Id = u64;
518
519        fn id(&self) -> Self::Id {
520            self.id
521        }
522
523        fn name(&self) -> &str {
524            &self.name
525        }
526
527        fn is_collection(&self) -> bool {
528            !self.children.is_empty()
529        }
530
531        fn children(&self) -> &[Self] {
532            &self.children
533        }
534
535        fn children_mut(&mut self) -> &mut Vec<Self> {
536            &mut self.children
537        }
538
539        fn icon(&self) -> Option<IconType> {
540            None
541        }
542
543        fn action_icons(&self) -> Vec<ActionIcon> {
544            vec![]
545        }
546    }
547
548    #[test]
549    fn test_new() {
550        let actions = DefaultActions::<u64>::new();
551        assert_eq!(actions.selected_count(), 0);
552        assert_eq!(actions.visible_count(), 0);
553        assert_eq!(actions.locked_count(), 0);
554        assert!(actions.event_log().is_none());
555    }
556
557    #[test]
558    fn test_with_logging() {
559        let actions = DefaultActions::<u64>::with_logging(10);
560        assert!(actions.event_log().is_some());
561        assert_eq!(actions.event_log().unwrap().max_entries(), 10);
562    }
563
564    #[test]
565    fn test_selection() {
566        let mut actions = DefaultActions::<u64>::new();
567
568        assert!(!OutlinerActions::<TestNode>::is_selected(&actions, &1));
569        
570        OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
571        assert!(OutlinerActions::<TestNode>::is_selected(&actions, &1));
572        assert_eq!(actions.selected_count(), 1);
573
574        OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
575        assert_eq!(actions.selected_count(), 2);
576
577        OutlinerActions::<TestNode>::on_select(&mut actions, &1, false);
578        assert!(!OutlinerActions::<TestNode>::is_selected(&actions, &1));
579        assert_eq!(actions.selected_count(), 1);
580    }
581
582    #[test]
583    fn test_visibility() {
584        let mut actions = DefaultActions::<u64>::new();
585
586        assert!(!OutlinerActions::<TestNode>::is_visible(&actions, &1));
587        
588        OutlinerActions::<TestNode>::on_visibility_toggle(&mut actions, &1);
589        assert!(OutlinerActions::<TestNode>::is_visible(&actions, &1));
590        assert_eq!(actions.visible_count(), 1);
591
592        OutlinerActions::<TestNode>::on_visibility_toggle(&mut actions, &1);
593        assert!(!OutlinerActions::<TestNode>::is_visible(&actions, &1));
594        assert_eq!(actions.visible_count(), 0);
595    }
596
597    #[test]
598    fn test_lock() {
599        let mut actions = DefaultActions::<u64>::new();
600
601        assert!(!OutlinerActions::<TestNode>::is_locked(&actions, &1));
602        
603        OutlinerActions::<TestNode>::on_lock_toggle(&mut actions, &1);
604        assert!(OutlinerActions::<TestNode>::is_locked(&actions, &1));
605        assert_eq!(actions.locked_count(), 1);
606
607        OutlinerActions::<TestNode>::on_lock_toggle(&mut actions, &1);
608        assert!(!OutlinerActions::<TestNode>::is_locked(&actions, &1));
609        assert_eq!(actions.locked_count(), 0);
610    }
611
612    #[test]
613    fn test_selection_toggle() {
614        let mut actions = DefaultActions::<u64>::new();
615
616        OutlinerActions::<TestNode>::on_selection_toggle(&mut actions, &1);
617        assert!(OutlinerActions::<TestNode>::is_selected(&actions, &1));
618
619        OutlinerActions::<TestNode>::on_selection_toggle(&mut actions, &1);
620        assert!(!OutlinerActions::<TestNode>::is_selected(&actions, &1));
621    }
622
623    #[test]
624    fn test_clear_selection() {
625        let mut actions = DefaultActions::<u64>::new();
626
627        OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
628        OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
629        OutlinerActions::<TestNode>::on_select(&mut actions, &3, true);
630        assert_eq!(actions.selected_count(), 3);
631
632        actions.clear_selection();
633        assert_eq!(actions.selected_count(), 0);
634    }
635
636    #[test]
637    fn test_set_all_visible() {
638        let mut actions = DefaultActions::<u64>::new();
639
640        let visible: HashSet<_> = (0..5).collect();
641        actions.set_all_visible(visible);
642
643        assert_eq!(actions.visible_count(), 5);
644        assert!(OutlinerActions::<TestNode>::is_visible(&actions, &0));
645        assert!(OutlinerActions::<TestNode>::is_visible(&actions, &4));
646        assert!(!OutlinerActions::<TestNode>::is_visible(&actions, &5));
647    }
648
649    #[test]
650    fn test_event_logging() {
651        let mut actions = DefaultActions::<u64>::with_logging(10);
652
653        OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
654        OutlinerActions::<TestNode>::on_visibility_toggle(&mut actions, &2);
655        OutlinerActions::<TestNode>::on_lock_toggle(&mut actions, &3);
656
657        let log = actions.event_log().unwrap();
658        assert_eq!(log.len(), 3);
659
660        let entries: Vec<_> = log.entries().collect();
661        assert_eq!(entries[0].event_type, EventType::Lock);
662        assert_eq!(entries[1].event_type, EventType::Visibility);
663        assert_eq!(entries[2].event_type, EventType::Selection);
664    }
665
666    #[test]
667    fn test_on_rename_logging() {
668        let mut actions = DefaultActions::<u64>::with_logging(10);
669
670        OutlinerActions::<TestNode>::on_rename(&mut actions, &1, "New Name".to_string());
671
672        let log = actions.event_log().unwrap();
673        assert_eq!(log.len(), 1);
674        let entries: Vec<_> = log.entries().collect();
675        assert_eq!(entries[0].event_type, EventType::Rename);
676    }
677
678    #[test]
679    fn test_on_move_logging() {
680        let mut actions = DefaultActions::<u64>::with_logging(10);
681
682        OutlinerActions::<TestNode>::on_move(&mut actions, &1, &2, DropPosition::Inside);
683
684        let log = actions.event_log().unwrap();
685        assert_eq!(log.len(), 1);
686        let entries: Vec<_> = log.entries().collect();
687        assert_eq!(entries[0].event_type, EventType::DragDrop);
688    }
689
690    #[test]
691    fn test_on_custom_action() {
692        let mut actions = DefaultActions::<u64>::with_logging(10);
693
694        OutlinerActions::<TestNode>::on_custom_action(&mut actions, &1, "custom_icon");
695
696        let log = actions.event_log().unwrap();
697        assert_eq!(log.len(), 1);
698        let entries: Vec<_> = log.entries().collect();
699        assert!(matches!(entries[0].event_type, EventType::Custom(_)));
700    }
701
702    #[test]
703    fn test_default() {
704        let actions = DefaultActions::<u64>::default();
705        assert_eq!(actions.selected_count(), 0);
706        assert!(actions.event_log().is_none());
707    }
708
709    #[test]
710    fn test_selected_reference() {
711        let mut actions = DefaultActions::<u64>::new();
712        OutlinerActions::<TestNode>::on_select(&mut actions, &1, true);
713        OutlinerActions::<TestNode>::on_select(&mut actions, &2, true);
714
715        let selected = actions.selected();
716        assert_eq!(selected.len(), 2);
717        assert!(selected.contains(&1));
718        assert!(selected.contains(&2));
719    }
720}