added undo/redo functionality

This commit is contained in:
2025-07-02 15:28:26 +08:00
parent 60b65e3eec
commit dd0777ff9a
4 changed files with 504 additions and 43 deletions

View File

@@ -4,13 +4,12 @@ use gdk4::cairo::{Context as CairoContext, Matrix, Rectangle};
use glib::ExitCode;
use gtk4::glib::{MainContext, Propagation};
use gtk4::{self as gtk, gdk::ffi::GDK_BUTTON_PRIMARY};
use gtk4::{Application, DrawingArea, prelude::*};
use gtk4::{Application, Button, DrawingArea, HeaderBar, prelude::*};
use rdraught::{
DraughtsBoard, DraughtsGame, Move, Piece, Player, Position, RDraughtApplication,
RectangularBoard,
};
use rsvg::SvgHandle;
use std::thread;
const SQUARE_SIZE: f64 = 1.0;
use super::final_dialog;
@@ -244,14 +243,64 @@ fn create_game_window(
.default_width(800)
.default_height(800)
.build();
let header_bar = HeaderBar::new();
window.set_titlebar(Some(&header_bar));
let undo_button = Button::new();
undo_button.set_icon_name("edit-undo-symbolic");
undo_button.set_sensitive(false);
let redo_button = Button::new();
redo_button.set_icon_name("edit-redo-symbolic");
redo_button.set_sensitive(false);
let selected_piece: SharedMutable<Option<Position>> = new_shared_mut(None);
let available_moves = new_shared_mut_ref(Vec::<Move>::new());
// Create a DrawingArea widget where we will draw the chessboard.
let drawing_area = DrawingArea::new();
// Add the drawing area to the window.
window.set_child(Some(&drawing_area));
let selected_piece: SharedMutable<Option<Position>> = new_shared_mut(None);
let available_moves = new_shared_mut_ref(Vec::<Move>::new());
header_bar.pack_start(&undo_button);
{
let da = drawing_area.clone();
let rd = rd.clone();
let undo_btn_clone = undo_button.clone();
let redo_btn_clone = redo_button.clone();
let selected_piece = selected_piece.clone();
let available_moves = available_moves.clone();
undo_button.connect_clicked(move |_| {
let mut rd = rd.borrow_mut();
if rd.can_undo() {
rd.undo().ok();
redo_btn_clone.set_sensitive(rd.can_redo());
undo_btn_clone.set_sensitive(rd.can_undo());
selected_piece.set(None);
available_moves.borrow_mut().clear();
da.queue_draw();
}
});
}
header_bar.pack_start(&redo_button);
{
let da = drawing_area.clone();
let rd = rd.clone();
let undo_btn_clone = undo_button.clone();
let redo_btn_clone = redo_button.clone();
let selected_piece = selected_piece.clone();
let available_moves = available_moves.clone();
redo_button.connect_clicked(move |_| {
let mut rd = rd.borrow_mut();
if rd.can_redo() {
rd.redo().ok();
redo_btn_clone.set_sensitive(rd.can_redo());
undo_btn_clone.set_sensitive(rd.can_undo());
selected_piece.set(None);
available_moves.borrow_mut().clear();
da.queue_draw();
}
});
}
// Get the allocation information for the widget.
let board_width = SQUARE_SIZE * DraughtsBoard::rows() as f64;
let board_height = SQUARE_SIZE * DraughtsBoard::columns() as f64;
@@ -429,6 +478,8 @@ fn create_game_window(
let drawing_area = drawing_area.clone();
let available_moves = available_moves.clone();
let window = window.clone();
let undo_btn_clone = undo_button.clone();
let redo_btn_clone = redo_button.clone();
gesture.connect_pressed(move |gesture, _, x, y| {
gesture.set_state(gtk::EventSequenceState::Claimed);
if let Some(winner) = rd.borrow().game().winner() {
@@ -455,7 +506,7 @@ fn create_game_window(
(8.0 - p.x() / SQUARE_SIZE) as u8,
),
};
println!("Selected position: {:?}", position);
// println!("Selected position: {:?}", position);
let piece = {
let rd = rd.borrow();
let draughts_game = rd.game();
@@ -471,7 +522,7 @@ fn create_game_window(
for mv in am.into_iter() {
if mv.get_end_position() == pos {
let mut rd_app = rd.borrow_mut();
println!("Applied move: {:?}", mv);
// println!("Applied move: {:?}", mv);
rd_app.apply_move(mv).unwrap();
// let game_copy = rd_app.game().clone();
// thread::spawn(move || {
@@ -491,6 +542,9 @@ fn create_game_window(
}
if move_applied {
selected_piece.set(None);
let rd = rd.borrow();
undo_btn_clone.set_sensitive(rd.can_undo());
redo_btn_clone.set_sensitive(rd.can_redo());
}
}
if !move_applied {