mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
Expose Timer API to rust API
And use it in the puzzle demo to implement the auto play mode
This commit is contained in:
parent
eadfdbe5fb
commit
0672f4b3cd
5 changed files with 66 additions and 4 deletions
|
@ -156,6 +156,7 @@ pub use sixtyfps_corelib::model::{
|
||||||
};
|
};
|
||||||
pub use sixtyfps_corelib::sharedarray::SharedArray;
|
pub use sixtyfps_corelib::sharedarray::SharedArray;
|
||||||
pub use sixtyfps_corelib::string::SharedString;
|
pub use sixtyfps_corelib::string::SharedString;
|
||||||
|
pub use sixtyfps_corelib::timers::{Timer, TimerMode};
|
||||||
pub use sixtyfps_corelib::{ARGBColor, Color};
|
pub use sixtyfps_corelib::{ARGBColor, Color};
|
||||||
|
|
||||||
/// internal re_exports used by the macro generated
|
/// internal re_exports used by the macro generated
|
||||||
|
|
|
@ -13,8 +13,9 @@ Remaining feature to implement to have parity:
|
||||||
Seatle). Note that this feature is kind of broken in the flutter example as it is only applied
|
Seatle). Note that this feature is kind of broken in the flutter example as it is only applied
|
||||||
when changing themes
|
when changing themes
|
||||||
* Expanding cirle animation when pressing a tile.
|
* Expanding cirle animation when pressing a tile.
|
||||||
* Auto-play mode. Including animation of the auto-play checkbox
|
* Animation of the auto-play checkbox.
|
||||||
* When the puzzle is finished, the last tile is added, and the tiles are growing in the Seatle theme,
|
* When the puzzle is finished, the last tile is added, and the tiles are growing in the Seatle theme,
|
||||||
or a hand apears, and the puzzle cannot be moved.
|
or a hand apears, and the puzzle cannot be moved.
|
||||||
* The different styles are well separated in different files.
|
* The different styles are well separated in different files.
|
||||||
|
* Shadow on the tiles
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ struct AppState {
|
||||||
/// An array of 16 values wixh represent a 4x4 matrix containing the piece number in that
|
/// An array of 16 values wixh represent a 4x4 matrix containing the piece number in that
|
||||||
/// position. -1 is no piece.
|
/// position. -1 is no piece.
|
||||||
positions: Vec<i8>,
|
positions: Vec<i8>,
|
||||||
|
auto_play_timer: sixtyfps::Timer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
|
@ -99,6 +100,24 @@ impl AppState {
|
||||||
self.set_pieces_pos(self.positions[swap as usize] as _, swap);
|
self.set_pieces_pos(self.positions[swap as usize] as _, swap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_move(&mut self) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let hole = self.positions.iter().position(|x| *x == -1).unwrap() as i8;
|
||||||
|
let mut p;
|
||||||
|
loop {
|
||||||
|
p = rand::Rng::gen_range(&mut rng, 0, 16);
|
||||||
|
if hole == p {
|
||||||
|
continue;
|
||||||
|
} else if hole % 4 == p % 4 {
|
||||||
|
break;
|
||||||
|
} else if hole / 4 == p / 4 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let p = self.positions[p as usize];
|
||||||
|
self.piece_clicked(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
|
||||||
|
@ -113,12 +132,34 @@ pub fn main() {
|
||||||
pieces: Rc::new(sixtyfps::VecModel::<Piece>::from(vec![Piece::default(); 15])),
|
pieces: Rc::new(sixtyfps::VecModel::<Piece>::from(vec![Piece::default(); 15])),
|
||||||
main_window: main_window.as_weak(),
|
main_window: main_window.as_weak(),
|
||||||
positions: vec![],
|
positions: vec![],
|
||||||
|
auto_play_timer: Default::default(),
|
||||||
}));
|
}));
|
||||||
state.borrow_mut().randomize();
|
state.borrow_mut().randomize();
|
||||||
main_window.as_ref().set_pieces(sixtyfps::ModelHandle::new(state.borrow().pieces.clone()));
|
main_window.as_ref().set_pieces(sixtyfps::ModelHandle::new(state.borrow().pieces.clone()));
|
||||||
let state_copy = state.clone();
|
let state_copy = state.clone();
|
||||||
main_window.as_ref().on_piece_cliked(move |p| state_copy.borrow_mut().piece_clicked(p as i8));
|
main_window.as_ref().on_piece_cliked(move |p| {
|
||||||
|
state_copy.borrow().auto_play_timer.stop();
|
||||||
|
state_copy.borrow().main_window.upgrade().map(|x| x.as_ref().set_auto_play(false));
|
||||||
|
state_copy.borrow_mut().piece_clicked(p as i8);
|
||||||
|
});
|
||||||
let state_copy = state.clone();
|
let state_copy = state.clone();
|
||||||
main_window.as_ref().on_reset(move || state_copy.borrow_mut().randomize());
|
main_window.as_ref().on_reset(move || state_copy.borrow_mut().randomize());
|
||||||
|
let state_copy = state.clone();
|
||||||
|
main_window.as_ref().on_enable_auto_mode(move |enabled| {
|
||||||
|
if enabled {
|
||||||
|
let state_weak = Rc::downgrade(&state_copy);
|
||||||
|
state_copy.borrow().auto_play_timer.start(
|
||||||
|
sixtyfps::TimerMode::Repeated,
|
||||||
|
std::time::Duration::from_millis(200),
|
||||||
|
Box::new(move || {
|
||||||
|
if let Some(state) = state_weak.upgrade() {
|
||||||
|
state.borrow_mut().random_move();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
state_copy.borrow().auto_play_timer.stop();
|
||||||
|
}
|
||||||
|
});
|
||||||
main_window.run();
|
main_window.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ struct Theme := {
|
||||||
export MainWindow := Window {
|
export MainWindow := Window {
|
||||||
signal piece_cliked(int);
|
signal piece_cliked(int);
|
||||||
signal reset();
|
signal reset();
|
||||||
|
signal enable_auto_mode(bool);
|
||||||
|
property <bool> auto_play;
|
||||||
property <int> moves;
|
property <int> moves;
|
||||||
property <int> tiles-left;
|
property <int> tiles-left;
|
||||||
property <[Piece]> pieces: [
|
property <[Piece]> pieces: [
|
||||||
|
@ -206,7 +208,7 @@ export MainWindow := Window {
|
||||||
+ (parent.width - (4*pieces_size + 3*pieces_spacing))/2;
|
+ (parent.width - (4*pieces_size + 3*pieces_spacing))/2;
|
||||||
y: px * (pieces_size + pieces_spacing)
|
y: px * (pieces_size + pieces_spacing)
|
||||||
+ (parent.height - (4*pieces_size + 3*pieces_spacing))/2;
|
+ (parent.height - (4*pieces_size + 3*pieces_spacing))/2;
|
||||||
animate px , py { duration: 200ms; easing: cubic-bezier(0.17,0.76,0.4,1.9); }
|
animate px , py { duration: 170ms; easing: cubic-bezier(0.17,0.76,0.4,1.75); }
|
||||||
animate border-width, border-radius { duration: 500ms; easing: ease-out; }
|
animate border-width, border-radius { duration: 500ms; easing: ease-out; }
|
||||||
|
|
||||||
if (current-theme-index == 1) : Rectangle {
|
if (current-theme-index == 1) : Rectangle {
|
||||||
|
@ -259,6 +261,21 @@ export MainWindow := Window {
|
||||||
clicked => { root.reset(); }
|
clicked => { root.reset(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Text {
|
||||||
|
// FIXME: this should be a rectangle with an animated ✓
|
||||||
|
text: auto_play ? " ☑ " : " ☐ ";
|
||||||
|
color: auto_play ? current-theme.game-highlight-color : current-theme.game-text-color;
|
||||||
|
animate color { duration: 200ms; }
|
||||||
|
vertical-alignment: align-center;
|
||||||
|
TouchArea {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
clicked => {
|
||||||
|
auto_play = !auto_play;
|
||||||
|
root.enable_auto_mode(auto_play);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Rectangle {} // stretch
|
Rectangle {} // stretch
|
||||||
Text {
|
Text {
|
||||||
text: root.moves;
|
text: root.moves;
|
||||||
|
|
|
@ -19,6 +19,8 @@ use std::cell::{Cell, RefCell};
|
||||||
type TimerCallback = Box<dyn Fn()>;
|
type TimerCallback = Box<dyn Fn()>;
|
||||||
|
|
||||||
/// The TimerMode specifies what should happen after the timer fired.
|
/// The TimerMode specifies what should happen after the timer fired.
|
||||||
|
///
|
||||||
|
/// Used by the [`Timer::start`] function.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum TimerMode {
|
pub enum TimerMode {
|
||||||
/// A SingleShot timer is fired only once.
|
/// A SingleShot timer is fired only once.
|
||||||
|
@ -40,7 +42,7 @@ impl Timer {
|
||||||
///
|
///
|
||||||
/// Arguments:
|
/// Arguments:
|
||||||
/// * `mode`: The timer mode to apply, i.e. whether to repeatedly fire the timer or just once.
|
/// * `mode`: The timer mode to apply, i.e. whether to repeatedly fire the timer or just once.
|
||||||
/// * `duration`: The duration from now until when the fire should fire.
|
/// * `duration`: The duration from now until when the timer should fire.
|
||||||
/// * `callback`: The function to call when the time has been reached or exceeded.
|
/// * `callback`: The function to call when the time has been reached or exceeded.
|
||||||
pub fn start(&self, mode: TimerMode, duration: std::time::Duration, callback: TimerCallback) {
|
pub fn start(&self, mode: TimerMode, duration: std::time::Duration, callback: TimerCallback) {
|
||||||
CURRENT_TIMERS.with(|timers| {
|
CURRENT_TIMERS.with(|timers| {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue