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}