1use crate::fyrox::{
22 core::{
23 err,
24 reflect::{
25 is_path_to_array_element, Reflect, ResolvePath, SetFieldByPathError, SetFieldError,
26 },
27 some_or_return, ComponentProvider,
28 },
29 gui::inspector::{PropertyAction, PropertyChanged},
30};
31use std::{
32 any::{type_name, TypeId},
33 fmt::{Debug, Formatter},
34 ops::{Deref, DerefMut, RangeBounds},
35};
36
37pub mod panel;
38
39pub trait CommandContext: ComponentProvider {}
40
41impl dyn CommandContext + '_ {
42 pub fn component_ref<T>(&self) -> Option<&T>
43 where
44 T: 'static,
45 {
46 self.query_component_ref(TypeId::of::<T>())
47 .and_then(|c| c.downcast_ref())
48 }
49
50 pub fn component_mut<T>(&mut self) -> Option<&mut T>
51 where
52 T: 'static,
53 {
54 self.query_component_mut(TypeId::of::<T>())
55 .and_then(|c| c.downcast_mut())
56 }
57
58 pub fn get<T>(&self) -> &T
59 where
60 T: 'static,
61 {
62 self.component_ref().unwrap_or_else(|| {
63 panic!(
64 "Unable to downcast command context to {} type",
65 type_name::<T>()
66 )
67 })
68 }
69
70 pub fn get_mut<T>(&mut self) -> &mut T
71 where
72 T: 'static,
73 {
74 self.component_mut().unwrap_or_else(|| {
75 panic!(
76 "Unable to downcast command context to {} type",
77 type_name::<T>()
78 )
79 })
80 }
81}
82
83pub trait CommandTrait: Debug + 'static {
86 fn is_significant(&self) -> bool {
91 true
92 }
93 fn name(&mut self, context: &dyn CommandContext) -> String;
95 fn execute(&mut self, context: &mut dyn CommandContext);
99 fn revert(&mut self, context: &mut dyn CommandContext);
101 fn finalize(&mut self, _: &mut dyn CommandContext) {}
104}
105
106#[derive(Debug)]
108pub struct Command(pub Box<dyn CommandTrait>);
109
110impl Command {
111 pub fn new<C: CommandTrait>(cmd: C) -> Self {
113 Self(Box::new(cmd))
114 }
115}
116
117impl Deref for Command {
118 type Target = dyn CommandTrait;
119
120 fn deref(&self) -> &Self::Target {
121 &*self.0
122 }
123}
124
125impl DerefMut for Command {
126 fn deref_mut(&mut self) -> &mut Self::Target {
127 &mut *self.0
128 }
129}
130
131#[derive(Debug, Default)]
137pub struct CommandGroup {
138 commands: Vec<Command>,
139 custom_name: String,
140}
141
142impl From<Vec<Command>> for CommandGroup {
143 fn from(commands: Vec<Command>) -> Self {
144 Self {
145 commands,
146 custom_name: Default::default(),
147 }
148 }
149}
150
151impl CommandGroup {
152 pub fn push<C: CommandTrait>(&mut self, command: C) {
154 self.commands.push(Command::new(command))
155 }
156
157 pub fn push_command(&mut self, command: Command) {
159 self.commands.push(command)
160 }
161
162 pub fn with_custom_name<S: AsRef<str>>(mut self, name: S) -> Self {
164 self.custom_name = name.as_ref().to_string();
165 self
166 }
167
168 pub fn is_empty(&self) -> bool {
170 self.commands.is_empty()
171 }
172
173 pub fn len(&self) -> usize {
175 self.commands.len()
176 }
177}
178
179impl CommandTrait for CommandGroup {
180 fn is_significant(&self) -> bool {
181 self.commands.iter().any(|c| c.is_significant())
182 }
183
184 fn name(&mut self, context: &dyn CommandContext) -> String {
185 if self.custom_name.is_empty() {
186 let mut name = String::from("Command group: ");
187 for cmd in self.commands.iter_mut() {
188 name.push_str(&cmd.name(context));
189 name.push_str(", ");
190 }
191 name
192 } else {
193 self.custom_name.clone()
194 }
195 }
196
197 fn execute(&mut self, context: &mut dyn CommandContext) {
198 for cmd in self.commands.iter_mut() {
199 cmd.execute(context);
200 }
201 }
202
203 fn revert(&mut self, context: &mut dyn CommandContext) {
204 for cmd in self.commands.iter_mut().rev() {
206 cmd.revert(context);
207 }
208 }
209
210 fn finalize(&mut self, context: &mut dyn CommandContext) {
211 for mut cmd in self.commands.drain(..) {
212 cmd.finalize(context);
213 }
214 }
215}
216
217pub struct CommandStack {
218 pub commands: Vec<Command>,
219 pub top: Option<usize>,
220 max_capacity: usize,
221 debug: bool,
222}
223
224impl CommandStack {
225 pub fn new(debug: bool, max_capacity: usize) -> Self {
226 Self {
227 commands: Default::default(),
228 top: None,
229 max_capacity,
230 debug,
231 }
232 }
233
234 pub fn do_command(&mut self, mut command: Command, context: &mut dyn CommandContext) {
235 if self.commands.is_empty() {
236 self.top = Some(0);
237 } else {
238 match self.top.as_mut() {
240 None => self.top = Some(0),
241 Some(top) => *top += 1,
242 }
243
244 fn drain<R: RangeBounds<usize>>(
245 commands: &mut Vec<Command>,
246 range: R,
247 context: &mut dyn CommandContext,
248 debug: bool,
249 ) {
250 for mut dropped_command in commands.drain(range) {
251 if debug {
252 println!("Finalizing command {dropped_command:?}");
253 }
254 dropped_command.finalize(context);
255 }
256 }
257
258 let top = self.top.unwrap_or(0);
260 if top < self.commands.len() {
261 drain(&mut self.commands, top.., context, self.debug);
262 }
263
264 if self.commands.len() >= self.max_capacity {
266 let range = 0..(self.commands.len() - self.max_capacity);
267 drain(&mut self.commands, range, context, self.debug);
268 if let Some(top) = self.top.as_mut() {
269 if *top > self.commands.len() {
270 *top = self.commands.len();
271 }
272 }
273 }
274 }
275
276 if self.debug {
277 println!("Executing command {command:?}");
278 }
279
280 command.execute(context);
281
282 self.commands.push(command);
283 }
284
285 pub fn top_command(&self) -> Option<&dyn CommandTrait> {
286 self.top
287 .and_then(|top| self.commands.get(top))
288 .map(|v| &**v)
289 }
290
291 pub fn undo(&mut self, context: &mut dyn CommandContext) {
292 if !self.commands.is_empty() {
293 if let Some(top) = self.top.as_mut() {
294 if let Some(command) = self.commands.get_mut(*top) {
295 if self.debug {
296 println!("Undo command {command:?}");
297 }
298 command.revert(context)
299 }
300 if *top == 0 {
301 self.top = None;
302 } else {
303 *top -= 1;
304 }
305 }
306 }
307 }
308
309 pub fn redo(&mut self, context: &mut dyn CommandContext) {
310 if !self.commands.is_empty() {
311 let command = match self.top.as_mut() {
312 None => {
313 self.top = Some(0);
314 self.commands.first_mut()
315 }
316 Some(top) => {
317 let last = self.commands.len() - 1;
318 if *top < last {
319 *top += 1;
320 self.commands.get_mut(*top)
321 } else {
322 None
323 }
324 }
325 };
326
327 if let Some(command) = command {
328 if self.debug {
329 println!("Redo command {command:?}");
330 }
331 command.execute(context)
332 }
333 }
334 }
335
336 pub fn clear(&mut self, context: &mut dyn CommandContext) {
337 for mut dropped_command in self.commands.drain(..) {
338 if self.debug {
339 println!("Finalizing command {dropped_command:?}");
340 }
341 dropped_command.finalize(context);
342 }
343 }
344}
345
346pub trait EntityGetter:
347 FnMut(&mut dyn CommandContext) -> Option<&mut dyn Reflect> + 'static
348{
349}
350impl<F> EntityGetter for F where
351 F: 'static + FnMut(&mut dyn CommandContext) -> Option<&mut dyn Reflect>
352{
353}
354
355pub fn make_command(
356 property_changed: &PropertyChanged,
357 entity_getter: impl EntityGetter,
358) -> Option<Command> {
359 match PropertyAction::from_field_action(&property_changed.action) {
360 PropertyAction::Modify { value } => Some(Command::new(SetPropertyCommand::new(
361 property_changed.path(),
362 value,
363 entity_getter,
364 ))),
365 PropertyAction::AddItem { value } => Some(Command::new(AddCollectionItemCommand::new(
366 property_changed.path(),
367 value,
368 entity_getter,
369 ))),
370 PropertyAction::RemoveItem { index } => Some(Command::new(
371 RemoveCollectionItemCommand::new(property_changed.path(), index, entity_getter),
372 )),
373 PropertyAction::Revert => None,
376 }
377}
378
379fn try_modify_property<F>(entity: &mut dyn Reflect, path: &str, func: F)
380where
381 F: FnOnce(&mut dyn Reflect),
382{
383 let mut func = Some(func);
384 entity.resolve_path_mut(path, &mut |result| match result {
385 Ok(field) => func.take().unwrap()(field),
386 Err(e) => {
387 err!("There is no such property {path}! Reason: {e:?}")
388 }
389 })
390}
391
392pub struct SetPropertyCommand<F: EntityGetter> {
393 value: Option<Box<dyn Reflect>>,
394 path: String,
395 entity_getter: F,
396}
397
398impl<F: EntityGetter> Debug for SetPropertyCommand<F> {
399 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
400 write!(f, "SetPropertyCommand")
401 }
402}
403
404impl<F: EntityGetter> SetPropertyCommand<F> {
405 pub fn new(path: String, value: Box<dyn Reflect>, entity_getter: F) -> Self {
406 Self {
407 value: Some(value),
408 path,
409 entity_getter,
410 }
411 }
412
413 fn swap(&mut self, ctx: &mut dyn CommandContext) {
414 if is_path_to_array_element(&self.path) {
415 let entity = some_or_return!((self.entity_getter)(ctx));
416 entity.resolve_path_mut(&self.path, &mut |result| match result {
417 Err(reason) => {
418 err!(
419 "Failed to set property {}! Invalid path {:?}!",
420 self.path,
421 reason
422 );
423 }
424 Ok(property) => match property.set(self.value.take().unwrap()) {
425 Ok(old_value) => {
426 self.value = Some(old_value);
427 }
428 Err(current_value) => {
429 err!(
430 "Failed to set property {}! Incompatible types. \
431 Target property: {}. Value: {}!",
432 self.path,
433 property.type_name(),
434 current_value.type_name()
435 );
436 self.value = Some(current_value);
437 }
438 },
439 });
440 } else {
441 let entity = some_or_return!((self.entity_getter)(ctx));
442 entity.set_field_by_path(&self.path, self.value.take().unwrap(), &mut |result| {
443 match result {
444 Ok(old_value) => {
445 self.value = Some(old_value);
446 }
447 Err(result) => {
448 let value = match result {
449 SetFieldByPathError::InvalidPath { value, reason } => {
450 err!(
451 "Failed to set property {}! Invalid path {:?}!",
452 self.path,
453 reason
454 );
455
456 value
457 }
458 SetFieldByPathError::InvalidValue {
459 field_type_name,
460 value,
461 } => {
462 err!(
463 "Failed to set property {}! Incompatible types. \
464 Target property: {}. Value: {}!",
465 self.path,
466 field_type_name,
467 value.type_name()
468 );
469
470 value
471 }
472 SetFieldByPathError::SetFieldError(err) => match err {
473 SetFieldError::NoSuchField { value, .. } => {
474 err!(
475 "Failed to set property {}, because it does not exist!",
476 self.path,
477 );
478
479 value
480 }
481 SetFieldError::InvalidValue {
482 field_type_name,
483 value,
484 } => {
485 err!(
486 "Failed to set property {}! Incompatible types. \
487 Target property: {}. Value: {}!",
488 self.path,
489 field_type_name,
490 value.type_name()
491 );
492
493 value
494 }
495 },
496 };
497 self.value = Some(value);
498 }
499 }
500 });
501 }
502 }
503}
504
505impl<F: EntityGetter> CommandTrait for SetPropertyCommand<F> {
506 fn name(&mut self, _: &dyn CommandContext) -> String {
507 format!("Set {} property", self.path)
508 }
509
510 fn execute(&mut self, ctx: &mut dyn CommandContext) {
511 self.swap(ctx);
512 }
513
514 fn revert(&mut self, ctx: &mut dyn CommandContext) {
515 self.swap(ctx);
516 }
517}
518
519pub struct AddCollectionItemCommand<F: EntityGetter> {
520 path: String,
521 item: Option<Box<dyn Reflect>>,
522 entity_getter: F,
523}
524
525impl<F: EntityGetter> Debug for AddCollectionItemCommand<F> {
526 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
527 write!(f, "AddCollectionItemCommand")
528 }
529}
530
531impl<F: EntityGetter> AddCollectionItemCommand<F> {
532 pub fn new(path: String, item: Box<dyn Reflect>, entity_getter: F) -> Self {
533 Self {
534 path,
535 item: Some(item),
536 entity_getter,
537 }
538 }
539}
540
541impl<F: EntityGetter> CommandTrait for AddCollectionItemCommand<F> {
542 fn name(&mut self, _: &dyn CommandContext) -> String {
543 format!("Add item to {} collection", self.path)
544 }
545
546 fn execute(&mut self, ctx: &mut dyn CommandContext) {
547 let entity = some_or_return!((self.entity_getter)(ctx));
548 try_modify_property(entity, &self.path, |field| {
549 field.as_list_mut(&mut |result| {
550 if let Some(list) = result {
551 if let Err(item) = list.reflect_push(self.item.take().unwrap()) {
552 err!(
553 "Failed to push item to {} collection. Type mismatch {} and {}!",
554 self.path,
555 item.type_name(),
556 list.type_name()
557 );
558 self.item = Some(item);
559 }
560 } else {
561 err!("Property {} is not a collection!", self.path)
562 }
563 });
564 })
565 }
566
567 fn revert(&mut self, ctx: &mut dyn CommandContext) {
568 let entity = some_or_return!((self.entity_getter)(ctx));
569 try_modify_property(entity, &self.path, |field| {
570 field.as_list_mut(&mut |result| {
571 if let Some(list) = result {
572 if let Some(item) = list.reflect_pop() {
573 self.item = Some(item);
574 } else {
575 err!("Failed to pop item from {} collection!", self.path)
576 }
577 } else {
578 err!("Property {} is not a collection!", self.path)
579 }
580 });
581 })
582 }
583}
584
585pub struct RemoveCollectionItemCommand<F: EntityGetter> {
586 path: String,
587 index: usize,
588 value: Option<Box<dyn Reflect>>,
589 entity_getter: F,
590}
591
592impl<F: EntityGetter> Debug for RemoveCollectionItemCommand<F> {
593 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
594 write!(f, "RemoveCollectionItemCommand")
595 }
596}
597
598impl<F: EntityGetter> RemoveCollectionItemCommand<F> {
599 pub fn new(path: String, index: usize, entity_getter: F) -> Self {
600 Self {
601 path,
602 index,
603 value: None,
604 entity_getter,
605 }
606 }
607}
608
609impl<F: EntityGetter> CommandTrait for RemoveCollectionItemCommand<F> {
610 fn name(&mut self, _: &dyn CommandContext) -> String {
611 format!("Remove collection {} item {}", self.path, self.index)
612 }
613
614 fn execute(&mut self, ctx: &mut dyn CommandContext) {
615 let entity = some_or_return!((self.entity_getter)(ctx));
616 try_modify_property(entity, &self.path, |field| {
617 field.as_list_mut(&mut |result| {
618 if let Some(list) = result {
619 self.value = list.reflect_remove(self.index);
620 } else {
621 err!("Property {} is not a collection!", self.path)
622 }
623 })
624 })
625 }
626
627 fn revert(&mut self, ctx: &mut dyn CommandContext) {
628 let entity = some_or_return!((self.entity_getter)(ctx));
629 try_modify_property(entity, &self.path, |field| {
630 field.as_list_mut(&mut |result| {
631 if let Some(list) = result {
632 if let Err(item) = list.reflect_insert(self.index, self.value.take().unwrap()) {
633 self.value = Some(item);
634 err!(
635 "Failed to insert item to {} collection. Type mismatch!",
636 self.path
637 )
638 }
639 } else {
640 err!("Property {} is not a collection!", self.path)
641 }
642 });
643 })
644 }
645}