mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-30 07:07:25 +00:00
153 lines
4.6 KiB
Rust
153 lines
4.6 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
use slint::Model;
|
|
use slint::VecModel;
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
|
|
slint::slint!(export { MainWindow } from "circledraw.slint";);
|
|
|
|
enum Change {
|
|
CircleAdded { row: usize },
|
|
CircleRemoved { row: usize, circle: Circle },
|
|
CircleResized { row: usize, old_d: f32 },
|
|
}
|
|
|
|
struct UndoStack<F> {
|
|
stack: Vec<Option<Change>>,
|
|
// Everything at and after this is a redo action
|
|
redo_offset: usize,
|
|
undo2redo: F,
|
|
}
|
|
|
|
impl<F> UndoStack<F>
|
|
where
|
|
F: Fn(Change) -> Change,
|
|
{
|
|
fn new(undo2redo: F) -> Self {
|
|
Self { stack: Vec::new(), redo_offset: 0, undo2redo }
|
|
}
|
|
|
|
fn push(&mut self, change: Change) {
|
|
self.stack.truncate(self.redo_offset);
|
|
self.stack.push(Some(change));
|
|
self.redo_offset += 1;
|
|
}
|
|
|
|
fn undoable(&self) -> bool {
|
|
self.redo_offset > 0
|
|
}
|
|
|
|
fn redoable(&self) -> bool {
|
|
self.redo_offset < self.stack.len()
|
|
}
|
|
|
|
fn undo(&mut self) {
|
|
self.redo_offset -= 1;
|
|
|
|
let undo = self.stack.get_mut(self.redo_offset).unwrap().take().unwrap();
|
|
let redo = (self.undo2redo)(undo);
|
|
self.stack[self.redo_offset] = Some(redo);
|
|
}
|
|
|
|
fn redo(&mut self) {
|
|
let redo = self.stack.get_mut(self.redo_offset).unwrap().take().unwrap();
|
|
let undo = (self.undo2redo)(redo);
|
|
self.stack[self.redo_offset] = Some(undo);
|
|
|
|
self.redo_offset += 1;
|
|
}
|
|
}
|
|
|
|
pub fn main() {
|
|
let main_window = MainWindow::new().unwrap();
|
|
|
|
let model = Rc::new(VecModel::default());
|
|
main_window.set_model(model.clone().into());
|
|
|
|
let undo_stack;
|
|
{
|
|
let model = model.clone();
|
|
undo_stack = Rc::new(RefCell::new(UndoStack::new(move |change| match change {
|
|
Change::CircleAdded { row } => {
|
|
let circle = model.row_data(row).unwrap();
|
|
model.remove(row);
|
|
Change::CircleRemoved { row, circle }
|
|
}
|
|
Change::CircleRemoved { row, circle } => {
|
|
model.insert(row, circle);
|
|
Change::CircleAdded { row }
|
|
}
|
|
Change::CircleResized { row, old_d } => {
|
|
let mut circle = model.row_data(row).unwrap();
|
|
let d = circle.d;
|
|
circle.d = old_d;
|
|
model.set_row_data(row, circle);
|
|
Change::CircleResized { row, old_d: d }
|
|
}
|
|
})));
|
|
}
|
|
|
|
{
|
|
let model = model.clone();
|
|
let undo_stack = undo_stack.clone();
|
|
let window_weak = main_window.as_weak();
|
|
main_window.on_background_clicked(move |x, y| {
|
|
let mut undo_stack = undo_stack.borrow_mut();
|
|
let main_window = window_weak.unwrap();
|
|
|
|
model.push(Circle { x: x as f32, y: y as f32, d: 30.0 });
|
|
undo_stack.push(Change::CircleAdded { row: model.row_count() - 1 });
|
|
|
|
main_window.set_undoable(undo_stack.undoable());
|
|
main_window.set_redoable(undo_stack.redoable());
|
|
});
|
|
}
|
|
|
|
{
|
|
let undo_stack = undo_stack.clone();
|
|
let window_weak = main_window.as_weak();
|
|
main_window.on_undo_clicked(move || {
|
|
let mut undo_stack = undo_stack.borrow_mut();
|
|
let main_window = window_weak.unwrap();
|
|
undo_stack.undo();
|
|
main_window.set_undoable(undo_stack.undoable());
|
|
main_window.set_redoable(undo_stack.redoable());
|
|
});
|
|
}
|
|
|
|
{
|
|
let undo_stack = undo_stack.clone();
|
|
let window_weak = main_window.as_weak();
|
|
main_window.on_redo_clicked(move || {
|
|
let mut undo_stack = undo_stack.borrow_mut();
|
|
let main_window = window_weak.unwrap();
|
|
undo_stack.redo();
|
|
main_window.set_undoable(undo_stack.undoable());
|
|
main_window.set_redoable(undo_stack.redoable());
|
|
});
|
|
}
|
|
|
|
{
|
|
let model = model.clone();
|
|
let undo_stack = undo_stack.clone();
|
|
let window_weak = main_window.as_weak();
|
|
main_window.on_circle_resized(move |row, diameter| {
|
|
let row = row as usize;
|
|
let mut undo_stack = undo_stack.borrow_mut();
|
|
let main_window = window_weak.unwrap();
|
|
|
|
let mut circle = model.row_data(row).unwrap();
|
|
let old_d = circle.d;
|
|
circle.d = diameter;
|
|
model.set_row_data(row, circle);
|
|
undo_stack.push(Change::CircleResized { row, old_d });
|
|
|
|
main_window.set_undoable(undo_stack.undoable());
|
|
main_window.set_redoable(undo_stack.redoable());
|
|
});
|
|
}
|
|
|
|
main_window.run().unwrap();
|
|
}
|