1use crate::{
2 style::TabStyleOverride,
3 tree::{PaneId, PaneRole},
4};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub struct TabDropPolicy {
10 pub locked_to_pane: Option<PaneId>,
12 pub locked_to_role: Option<PaneRole>,
14 pub allowed_panes: Option<Vec<PaneId>>,
16 pub allowed_roles: Option<Vec<PaneRole>>,
18 pub blocked_panes: Vec<PaneId>,
20 pub blocked_roles: Vec<PaneRole>,
22}
23
24impl TabDropPolicy {
25 pub fn allows_target(&self, pane_id: PaneId, role: Option<PaneRole>) -> bool {
31 if let Some(locked_to_pane) = self.locked_to_pane {
32 return locked_to_pane == pane_id;
33 }
34
35 if let Some(locked_to_role) = self.locked_to_role {
36 return role == Some(locked_to_role);
37 }
38
39 if let Some(allowed_panes) = &self.allowed_panes {
40 if !allowed_panes.contains(&pane_id) {
41 return false;
42 }
43 }
44
45 if let Some(allowed_roles) = &self.allowed_roles {
46 if !role.is_some_and(|role| allowed_roles.contains(&role)) {
47 return false;
48 }
49 }
50
51 if self.blocked_panes.contains(&pane_id) {
52 return false;
53 }
54
55 !role.is_some_and(|role| self.blocked_roles.contains(&role))
56 }
57}
58
59impl Default for TabDropPolicy {
60 fn default() -> Self {
61 Self {
62 locked_to_pane: None,
63 locked_to_role: None,
64 allowed_panes: None,
65 allowed_roles: None,
66 blocked_panes: Vec::new(),
67 blocked_roles: Vec::new(),
68 }
69 }
70}
71
72#[derive(Clone, Debug, PartialEq)]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub enum TabIcon {
76 Text(String),
78 Texture {
80 texture_id: egui::TextureId,
81 size: egui::Vec2,
82 },
83}
84
85#[derive(Clone, Debug, PartialEq)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90pub struct Tab<T: Clone + 'static> {
91 pub title: String,
92 pub id: T,
93 pub icon: Option<TabIcon>,
95 pub draggable: bool,
97 pub drop_policy: TabDropPolicy,
99 pub closable: bool,
101 pub style_override: Option<TabStyleOverride>,
103}
104
105impl<T: Clone + 'static> Tab<T> {
106 pub fn new(title: impl Into<String>, id: T) -> Self {
108 Self {
109 title: title.into(),
110 id,
111 icon: None,
112 draggable: true,
113 drop_policy: TabDropPolicy::default(),
114 closable: false,
115 style_override: None,
116 }
117 }
118
119 pub fn with_leading_visual(mut self, leading_visual: impl Into<String>) -> Self {
121 self.icon = Some(TabIcon::Text(leading_visual.into()));
122 self
123 }
124
125 pub fn with_icon(mut self, icon: TabIcon) -> Self {
127 self.icon = Some(icon);
128 self
129 }
130
131 pub fn with_icon_texture(mut self, texture_id: egui::TextureId, size: egui::Vec2) -> Self {
133 self.icon = Some(TabIcon::Texture { texture_id, size });
134 self
135 }
136
137 pub fn with_draggable(mut self, draggable: bool) -> Self {
139 self.draggable = draggable;
140 self
141 }
142
143 pub fn with_drop_policy(mut self, drop_policy: TabDropPolicy) -> Self {
145 self.drop_policy = drop_policy;
146 self
147 }
148
149 pub fn with_locked_pane(mut self, pane_id: PaneId) -> Self {
151 self.drop_policy.locked_to_pane = Some(pane_id);
152 self
153 }
154
155 pub fn with_locked_role(mut self, role: PaneRole) -> Self {
157 self.drop_policy.locked_to_role = Some(role);
158 self
159 }
160
161 pub fn with_allowed_drop_panes(
163 mut self,
164 allowed_panes: impl IntoIterator<Item = PaneId>,
165 ) -> Self {
166 self.drop_policy.allowed_panes = Some(allowed_panes.into_iter().collect());
167 self
168 }
169
170 pub fn with_blocked_drop_panes(
172 mut self,
173 blocked_panes: impl IntoIterator<Item = PaneId>,
174 ) -> Self {
175 self.drop_policy.blocked_panes = blocked_panes.into_iter().collect();
176 self
177 }
178
179 pub fn with_allowed_drop_roles(
181 mut self,
182 allowed_roles: impl IntoIterator<Item = PaneRole>,
183 ) -> Self {
184 self.drop_policy.allowed_roles = Some(allowed_roles.into_iter().collect());
185 self
186 }
187
188 pub fn with_blocked_drop_roles(
190 mut self,
191 blocked_roles: impl IntoIterator<Item = PaneRole>,
192 ) -> Self {
193 self.drop_policy.blocked_roles = blocked_roles.into_iter().collect();
194 self
195 }
196
197 pub fn with_closable(mut self, closable: bool) -> Self {
199 self.closable = closable;
200 self
201 }
202
203 pub fn with_style_override(mut self, style_override: TabStyleOverride) -> Self {
205 self.style_override = Some(style_override);
206 self
207 }
208}