summaryrefslogtreecommitdiff
path: root/rust/crates/commands/src/history.rs
blob: f8792373f727fa153885ad8eb6cb417e325e664f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use scene::Project;

use crate::command::{Command, CommandError, CommandResult};

#[derive(Default)]
pub struct CommandHistory {
    history: Vec<Box<dyn Command>>,
    redo_stack: Vec<Box<dyn Command>>,
}

impl CommandHistory {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn execute(
        &mut self,
        mut command: Box<dyn Command>,
        project: &mut Project,
    ) -> Result<Option<CommandResult>, CommandError> {
        let result = command.execute(project)?;
        self.history.push(command);
        self.redo_stack.clear();
        Ok(result)
    }

    pub fn push(&mut self, command: Box<dyn Command>) {
        self.history.push(command);
        self.redo_stack.clear();
    }

    pub fn undo(&mut self, project: &mut Project) {
        let Some(mut command) = self.history.pop() else {
            return;
        };
        command.undo(project);
        self.redo_stack.push(command);
    }

    pub fn redo(
        &mut self,
        project: &mut Project,
    ) -> Result<Option<CommandResult>, CommandError> {
        let Some(mut command) = self.redo_stack.pop() else {
            return Ok(None);
        };
        let result = command.redo(project)?;
        self.history.push(command);
        Ok(result)
    }

    pub fn can_undo(&self) -> bool {
        !self.history.is_empty()
    }

    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }

    pub fn len(&self) -> usize {
        self.history.len()
    }

    pub fn clear(&mut self) {
        self.history.clear();
        self.redo_stack.clear();
    }
}