Skip to main content

ak_vis/viewer/session/
state_commands.rs

1use ak_core::Trajectory;
2
3use super::snapshot::clamp_frame;
4use super::{
5    AtomAppearanceRule, BondFrames, CommandOutcome, FaceFrames, ImageSelectionFrames,
6    RenderStyleRule, SelectionFrames, SupercellSettings, ViewerCommand, ViewerState,
7};
8
9impl ViewerState {
10    pub fn apply_command(&mut self, command: ViewerCommand) -> CommandOutcome {
11        match command {
12            ViewerCommand::LoadTrajectory {
13                frames,
14                initial_frame,
15            } => {
16                let frame_count = frames.len();
17                self.traj = Trajectory::new(frames);
18                self.current = clamp_frame(initial_frame, self.traj.len());
19                self.resize_scalar_storage(frame_count);
20                self.bonds = BondFrames::new(frame_count);
21                self.faces = FaceFrames::new(frame_count);
22                self.render_style_rules.clear();
23                self.selection = SelectionFrames::new(&self.traj);
24                self.image_selection = ImageSelectionFrames::new(frame_count);
25                self.supercell = SupercellSettings::default();
26                self.needs_render = true;
27                self.needs_camera_reset = true;
28                CommandOutcome::default()
29            }
30            ViewerCommand::AppendFrame { frame } => {
31                let was_empty = self.traj.is_empty();
32                let previous = if was_empty { None } else { Some(self.current) };
33                self.traj.append(frame);
34                self.bonds.resize(self.traj.len());
35                self.faces.resize(self.traj.len());
36                self.selection.append_empty_for_atom_count(
37                    self.traj.view(self.traj.len() - 1).positions.len(),
38                );
39                self.image_selection.append_empty_frame();
40                if was_empty {
41                    self.current = 0;
42                    self.needs_render = true;
43                    self.needs_camera_reset = true;
44                } else if self.follow_tail {
45                    let next = self.traj.len() - 1;
46                    if let Some(previous) = previous {
47                        self.copy_selection_between_compatible_frames(previous, next);
48                    }
49                    self.current = next;
50                    self.needs_render = true;
51                    self.needs_camera_reset = previous
52                        .map(|old| self.cell_changed(old, self.current))
53                        .unwrap_or(false);
54                }
55                CommandOutcome::default()
56            }
57            ViewerCommand::SetCurrentFrame { index } => {
58                if index < self.traj.len() && index != self.current {
59                    let previous = self.current;
60                    self.copy_selection_between_compatible_frames(previous, index);
61                    self.current = index;
62                    self.needs_render = true;
63                    self.needs_camera_reset = self.cell_changed(previous, self.current);
64                }
65                CommandOutcome::default()
66            }
67            ViewerCommand::SetFollowTail { enabled } => {
68                self.follow_tail = enabled;
69                CommandOutcome::default()
70            }
71            ViewerCommand::SetAtomScalars {
72                name,
73                values,
74                frame_index,
75            } => {
76                let target_frame = frame_index.unwrap_or(self.current);
77                let should_refresh_active_mode = self.current == target_frame
78                    && self
79                        .atom_appearance_rules
80                        .iter()
81                        .any(|rule| rule.name == name);
82                if self.validate_scalar_values(target_frame, &values) {
83                    self.store_scalars(name, target_frame, values);
84                    self.needs_render = should_refresh_active_mode;
85                }
86                CommandOutcome::default()
87            }
88            ViewerCommand::MapAppearanceByScalar {
89                name,
90                channel,
91                palette,
92                min,
93                max,
94                append,
95            } => {
96                let rule = AtomAppearanceRule {
97                    name,
98                    channel,
99                    palette,
100                    min,
101                    max,
102                };
103                if append {
104                    self.atom_appearance_rules.push(rule);
105                } else {
106                    self.atom_appearance_rules
107                        .retain(|existing| existing.channel != channel);
108                    self.atom_appearance_rules.push(rule);
109                }
110                self.needs_render = true;
111                CommandOutcome::default()
112            }
113            ViewerCommand::ResetAtomAppearance { channel } => {
114                match channel {
115                    Some(channel) => {
116                        self.atom_appearance_rules
117                            .retain(|rule| rule.channel != channel);
118                    }
119                    None => self.atom_appearance_rules.clear(),
120                }
121                self.needs_render = true;
122                CommandOutcome::default()
123            }
124            ViewerCommand::SetBonds { bonds, frame_index } => {
125                let target_frame = frame_index.unwrap_or(self.current);
126                if target_frame < self.traj.len() {
127                    self.bonds.set(target_frame, bonds);
128                    self.needs_render = self.current == target_frame;
129                }
130                CommandOutcome::default()
131            }
132            ViewerCommand::AddBonds { bonds, frame_index } => {
133                let target_frame = frame_index.unwrap_or(self.current);
134                if target_frame < self.traj.len() {
135                    self.bonds.add(target_frame, bonds);
136                    self.needs_render = self.current == target_frame;
137                }
138                CommandOutcome::default()
139            }
140            ViewerCommand::RemoveBonds { bonds, frame_index } => {
141                let target_frame = frame_index.unwrap_or(self.current);
142                if target_frame < self.traj.len() {
143                    self.bonds.remove(target_frame, &bonds);
144                    self.needs_render = self.current == target_frame;
145                }
146                CommandOutcome::default()
147            }
148            ViewerCommand::ClearBonds { frame_index } => {
149                let target_frame = frame_index.unwrap_or(self.current);
150                if target_frame < self.traj.len() {
151                    self.bonds.clear(target_frame);
152                    self.needs_render = self.current == target_frame;
153                }
154                CommandOutcome::default()
155            }
156            ViewerCommand::SetFaces { faces, frame_index } => {
157                let target_frame = frame_index.unwrap_or(self.current);
158                if target_frame < self.traj.len() {
159                    let atom_count = self.traj.view(target_frame).positions.len();
160                    self.faces
161                        .set(target_frame, faces.validated_for_atom_count(atom_count));
162                    self.needs_render = self.current == target_frame;
163                }
164                CommandOutcome::default()
165            }
166            ViewerCommand::AddFaces { faces, frame_index } => {
167                let target_frame = frame_index.unwrap_or(self.current);
168                if target_frame < self.traj.len() {
169                    let atom_count = self.traj.view(target_frame).positions.len();
170                    self.faces
171                        .add(target_frame, faces.validated_for_atom_count(atom_count));
172                    self.needs_render = self.current == target_frame;
173                }
174                CommandOutcome::default()
175            }
176            ViewerCommand::RemoveFaces { faces, frame_index } => {
177                let target_frame = frame_index.unwrap_or(self.current);
178                if target_frame < self.traj.len() {
179                    let atom_count = self.traj.view(target_frame).positions.len();
180                    self.faces
181                        .remove(target_frame, &faces.validated_for_atom_count(atom_count));
182                    self.needs_render = self.current == target_frame;
183                }
184                CommandOutcome::default()
185            }
186            ViewerCommand::ClearFaces { frame_index } => {
187                let target_frame = frame_index.unwrap_or(self.current);
188                if target_frame < self.traj.len() {
189                    self.faces.clear(target_frame);
190                    self.needs_render = self.current == target_frame;
191                }
192                CommandOutcome::default()
193            }
194            ViewerCommand::SetRenderStyle {
195                style,
196                selection,
197                frame_index,
198                append,
199            } => {
200                let target_frame = frame_index.unwrap_or(self.current);
201                if self.validate_selection(target_frame, &selection) {
202                    let rule = RenderStyleRule {
203                        frame_index: target_frame,
204                        selection,
205                        style,
206                    };
207                    if append {
208                        self.render_style_rules.push(rule);
209                    } else {
210                        self.render_style_rules.clear();
211                        self.render_style_rules.push(rule);
212                    }
213                    self.needs_render = self.current == target_frame;
214                }
215                CommandOutcome::default()
216            }
217            ViewerCommand::ResetRenderStyle => {
218                self.render_style_rules.clear();
219                self.needs_render = true;
220                CommandOutcome::default()
221            }
222            ViewerCommand::ReplaceSelection {
223                selection,
224                frame_index,
225            } => {
226                let target_frame = frame_index.unwrap_or(self.current);
227                if self.validate_selection(target_frame, &selection) {
228                    self.selection.replace(target_frame, selection);
229                    self.image_selection.replace(
230                        target_frame,
231                        self.selection.selected_main_images(target_frame),
232                    );
233                    self.needs_render = self.current == target_frame;
234                }
235                CommandOutcome::default()
236            }
237            ViewerCommand::AddSelection {
238                selection,
239                frame_index,
240            } => {
241                let target_frame = frame_index.unwrap_or(self.current);
242                if self.validate_selection(target_frame, &selection) {
243                    self.selection.add(target_frame, &selection);
244                    self.image_selection.replace(
245                        target_frame,
246                        self.selection.selected_main_images(target_frame),
247                    );
248                    self.needs_render = self.current == target_frame;
249                }
250                CommandOutcome::default()
251            }
252            ViewerCommand::RemoveSelection {
253                selection,
254                frame_index,
255            } => {
256                let target_frame = frame_index.unwrap_or(self.current);
257                if self.validate_selection(target_frame, &selection) {
258                    self.selection.remove(target_frame, &selection);
259                    self.image_selection.replace(
260                        target_frame,
261                        self.selection.selected_main_images(target_frame),
262                    );
263                    self.needs_render = self.current == target_frame;
264                }
265                CommandOutcome::default()
266            }
267            ViewerCommand::ClearSelection { frame_index } => {
268                let target_frame = frame_index.unwrap_or(self.current);
269                if target_frame < self.traj.len() {
270                    self.selection.clear(target_frame);
271                    self.image_selection.clear(target_frame);
272                    self.needs_render = self.current == target_frame;
273                }
274                CommandOutcome::default()
275            }
276            ViewerCommand::ReplaceImageSelection {
277                selection,
278                frame_index,
279            } => {
280                let target_frame = frame_index.unwrap_or(self.current);
281                if self.validate_image_selection(target_frame, &selection) {
282                    self.image_selection.replace(target_frame, selection);
283                    self.sync_main_selection_from_images(target_frame);
284                    self.needs_render = self.current == target_frame;
285                }
286                CommandOutcome::default()
287            }
288            ViewerCommand::AddImageSelection {
289                selection,
290                frame_index,
291            } => {
292                let target_frame = frame_index.unwrap_or(self.current);
293                if self.validate_image_selection(target_frame, &selection) {
294                    self.image_selection.add(target_frame, &selection);
295                    self.sync_main_selection_from_images(target_frame);
296                    self.needs_render = self.current == target_frame;
297                }
298                CommandOutcome::default()
299            }
300            ViewerCommand::RemoveImageSelection {
301                selection,
302                frame_index,
303            } => {
304                let target_frame = frame_index.unwrap_or(self.current);
305                if self.validate_image_selection(target_frame, &selection) {
306                    self.image_selection.remove(target_frame, &selection);
307                    self.sync_main_selection_from_images(target_frame);
308                    self.needs_render = self.current == target_frame;
309                }
310                CommandOutcome::default()
311            }
312            ViewerCommand::ClearImageSelection { frame_index } => {
313                let target_frame = frame_index.unwrap_or(self.current);
314                if target_frame < self.traj.len() {
315                    self.image_selection.clear(target_frame);
316                    self.sync_main_selection_from_images(target_frame);
317                    self.needs_render = self.current == target_frame;
318                }
319                CommandOutcome::default()
320            }
321            ViewerCommand::SetSupercell { repeats } => {
322                if self.supercell.repeats != repeats {
323                    self.supercell.repeats = repeats;
324                    self.needs_render = true;
325                }
326                CommandOutcome::default()
327            }
328            ViewerCommand::IncrementSupercellAxis { axis } => {
329                if axis < 3 {
330                    self.supercell.repeats[axis] = self.supercell.repeats[axis].saturating_add(1);
331                    self.needs_render = true;
332                }
333                CommandOutcome::default()
334            }
335            ViewerCommand::DecrementSupercellAxis { axis } => {
336                if axis < 3 {
337                    let next = self.supercell.repeats[axis].saturating_sub(1);
338                    if self.supercell.repeats[axis] != next {
339                        self.supercell.repeats[axis] = next;
340                        self.needs_render = true;
341                    }
342                }
343                CommandOutcome::default()
344            }
345            ViewerCommand::ResetSupercell => {
346                if self.supercell.repeats != [0, 0, 0] {
347                    self.supercell.repeats = [0, 0, 0];
348                    self.needs_render = true;
349                }
350                CommandOutcome::default()
351            }
352            ViewerCommand::SetGhostRepeatedImages { enabled } => {
353                if self.supercell.ghost_repeated_images != enabled {
354                    self.supercell.ghost_repeated_images = enabled;
355                    self.needs_render = true;
356                }
357                CommandOutcome::default()
358            }
359            ViewerCommand::ToggleGhostRepeatedImages => {
360                self.supercell.ghost_repeated_images = !self.supercell.ghost_repeated_images;
361                self.needs_render = true;
362                CommandOutcome::default()
363            }
364            ViewerCommand::SetCameraView { .. }
365            | ViewerCommand::PanCamera { .. }
366            | ViewerCommand::ZoomCamera { .. }
367            | ViewerCommand::OrbitCamera { .. }
368            | ViewerCommand::FrameAll
369            | ViewerCommand::StartOrbit { .. }
370            | ViewerCommand::StopCameraMotion => CommandOutcome::default(),
371            ViewerCommand::Close => CommandOutcome { should_close: true },
372        }
373    }
374}