mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 02:39:28 +00:00
Add support for timers and run/quit_event_loop
This commit is contained in:
parent
ebaecbcb7e
commit
33a1d07226
5 changed files with 148 additions and 1 deletions
|
@ -24,8 +24,9 @@ i-slint-backend-testing = { version = "=1.4.0", path="../../internal/backends/te
|
|||
i-slint-renderer-skia = { version = "=1.4.0", path="../../internal/renderers/skia", optional = true, features = ["x11", "wayland"] }
|
||||
i-slint-core = { version = "=1.4.0", path="../../internal/core", features = ["ffi"] }
|
||||
slint-interpreter = { workspace = true, features = ["default", "display-diagnostics", "internal"] }
|
||||
pyo3 = { version = "0.20.0", features = ["extension-module", "indexmap"] }
|
||||
pyo3 = { version = "0.20.0", features = ["extension-module", "indexmap", "chrono"] }
|
||||
indexmap = { version = "2.1.0" }
|
||||
chrono = "0.4"
|
||||
spin_on = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
|
|
|
@ -45,6 +45,20 @@ impl From<slint_interpreter::PlatformError> for PyPlatformError {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PyEventLoopError(pub slint_interpreter::EventLoopError);
|
||||
|
||||
impl From<PyEventLoopError> for PyErr {
|
||||
fn from(err: PyEventLoopError) -> Self {
|
||||
pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<slint_interpreter::EventLoopError> for PyEventLoopError {
|
||||
fn from(err: slint_interpreter::EventLoopError) -> Self {
|
||||
Self(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PyInvokeError(pub slint_interpreter::InvokeError);
|
||||
|
||||
impl From<PyInvokeError> for PyErr {
|
||||
|
|
|
@ -4,16 +4,37 @@
|
|||
mod interpreter;
|
||||
use interpreter::{ComponentCompiler, PyDiagnostic, PyDiagnosticLevel, PyValueType};
|
||||
mod errors;
|
||||
mod timer;
|
||||
mod value;
|
||||
|
||||
#[pyfunction]
|
||||
fn run_event_loop() -> Result<(), errors::PyPlatformError> {
|
||||
slint_interpreter::run_event_loop().map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn quit_event_loop() -> Result<(), errors::PyEventLoopError> {
|
||||
slint_interpreter::quit_event_loop().map_err(|e| e.into())
|
||||
}
|
||||
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[pymodule]
|
||||
fn slint(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||
i_slint_backend_selector::with_platform(|_b| {
|
||||
// Nothing to do, just make sure a backend was created
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|e| errors::PyPlatformError(e))?;
|
||||
|
||||
m.add_class::<ComponentCompiler>()?;
|
||||
m.add_class::<PyValueType>()?;
|
||||
m.add_class::<PyDiagnosticLevel>()?;
|
||||
m.add_class::<PyDiagnostic>()?;
|
||||
m.add_class::<timer::PyTimerMode>()?;
|
||||
m.add_class::<timer::PyTimer>()?;
|
||||
m.add_function(wrap_pyfunction!(run_event_loop, m)?)?;
|
||||
m.add_function(wrap_pyfunction!(quit_event_loop, m)?)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
26
api/python/tests/test_timers.py
Normal file
26
api/python/tests/test_timers.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
import pytest
|
||||
import slint
|
||||
from slint import ValueType
|
||||
from datetime import timedelta
|
||||
|
||||
def test_timer():
|
||||
global counter
|
||||
counter = 0
|
||||
def quit_after_two_invocations():
|
||||
global counter
|
||||
counter = counter + 1
|
||||
if counter >= 2:
|
||||
slint.quit_event_loop()
|
||||
|
||||
test_timer = slint.Timer()
|
||||
test_timer.start(slint.TimerMode.Repeated, timedelta(milliseconds=100), quit_after_two_invocations)
|
||||
slint.run_event_loop()
|
||||
test_timer.stop()
|
||||
assert(counter == 2)
|
||||
|
||||
def test_single_shot():
|
||||
slint.Timer.single_shot(timedelta(milliseconds=100), slint.quit_event_loop)
|
||||
slint.run_event_loop()
|
85
api/python/timer.rs
Normal file
85
api/python/timer.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
use pyo3::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[pyclass(name = "TimerMode")]
|
||||
pub enum PyTimerMode {
|
||||
/// A SingleShot timer is fired only once.
|
||||
SingleShot,
|
||||
/// A Repeated timer is fired repeatedly until it is stopped or dropped.
|
||||
Repeated,
|
||||
}
|
||||
|
||||
impl From<PyTimerMode> for i_slint_core::timers::TimerMode {
|
||||
fn from(value: PyTimerMode) -> Self {
|
||||
match value {
|
||||
PyTimerMode::SingleShot => i_slint_core::timers::TimerMode::SingleShot,
|
||||
PyTimerMode::Repeated => i_slint_core::timers::TimerMode::Repeated,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(name = "Timer")]
|
||||
pub struct PyTimer {
|
||||
timer: i_slint_core::timers::Timer,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyTimer {
|
||||
#[new]
|
||||
fn py_new() -> Self {
|
||||
PyTimer { timer: Default::default() }
|
||||
}
|
||||
|
||||
fn start(
|
||||
&self,
|
||||
mode: PyTimerMode,
|
||||
interval: chrono::Duration,
|
||||
callback: PyObject,
|
||||
) -> PyResult<()> {
|
||||
let interval = interval
|
||||
.to_std()
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
|
||||
self.timer.start(mode.into(), interval, move || {
|
||||
Python::with_gil(|py| {
|
||||
callback.call0(py).expect("unexpected failure running python timer callback");
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn single_shot(duration: chrono::Duration, callback: PyObject) -> PyResult<()> {
|
||||
let duration = duration
|
||||
.to_std()
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
|
||||
i_slint_core::timers::Timer::single_shot(duration, move || {
|
||||
Python::with_gil(|py| {
|
||||
callback.call0(py).expect("unexpected failure running python timer callback");
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
self.timer.stop();
|
||||
}
|
||||
|
||||
fn restart(&self) {
|
||||
self.timer.restart();
|
||||
}
|
||||
|
||||
fn running(&self) -> bool {
|
||||
self.timer.running()
|
||||
}
|
||||
|
||||
fn set_interval(&self, interval: chrono::Duration) -> PyResult<()> {
|
||||
let interval = interval
|
||||
.to_std()
|
||||
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
|
||||
self.timer.set_interval(interval);
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue