mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-27 12:29:41 +00:00
Add support for mapping image properties
This exposes a slint.Image class, which has a load_from_path class method as well as size/width/height properties. cc #4202
This commit is contained in:
parent
9aa931f1f8
commit
93efd74e24
6 changed files with 97 additions and 3 deletions
|
@ -86,3 +86,17 @@ impl From<slint_interpreter::SetCallbackError> for PySetCallbackError {
|
|||
Self(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PyLoadImageError(pub slint_interpreter::LoadImageError);
|
||||
|
||||
impl From<PyLoadImageError> for PyErr {
|
||||
fn from(err: PyLoadImageError) -> Self {
|
||||
pyo3::exceptions::PyRuntimeError::new_err(err.0.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<slint_interpreter::LoadImageError> for PyLoadImageError {
|
||||
fn from(err: slint_interpreter::LoadImageError) -> Self {
|
||||
Self(err)
|
||||
}
|
||||
}
|
||||
|
|
55
api/python/image.rs
Normal file
55
api/python/image.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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::*;
|
||||
|
||||
#[pyclass(unsendable)]
|
||||
pub struct PyImage {
|
||||
pub image: slint_interpreter::Image,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyImage {
|
||||
#[new]
|
||||
fn py_new() -> PyResult<Self> {
|
||||
Ok(Self { image: Default::default() })
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn size(&self) -> PyResult<(u32, u32)> {
|
||||
Ok(self.image.size().into())
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn width(&self) -> PyResult<u32> {
|
||||
Ok(self.image.size().width)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn height(&self) -> PyResult<u32> {
|
||||
Ok(self.image.size().height)
|
||||
}
|
||||
|
||||
#[getter]
|
||||
fn path(&self) -> PyResult<Option<&std::path::Path>> {
|
||||
Ok(self.image.path())
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn load_from_path(path: std::path::PathBuf) -> Result<Self, crate::errors::PyLoadImageError> {
|
||||
let image = slint_interpreter::Image::load_from_path(&path)?;
|
||||
Ok(Self { image })
|
||||
}
|
||||
|
||||
#[staticmethod]
|
||||
fn load_from_svg_data(data: &[u8]) -> Result<Self, crate::errors::PyLoadImageError> {
|
||||
let image = slint_interpreter::Image::load_from_svg_data(data)?;
|
||||
Ok(Self { image })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&slint_interpreter::Image> for PyImage {
|
||||
fn from(image: &slint_interpreter::Image) -> Self {
|
||||
Self { image: image.clone() }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
|
||||
|
||||
mod image;
|
||||
mod interpreter;
|
||||
use interpreter::{ComponentCompiler, PyDiagnostic, PyDiagnosticLevel, PyValueType};
|
||||
mod errors;
|
||||
|
@ -28,6 +29,7 @@ fn slint(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
|||
.map_err(|e| errors::PyPlatformError(e))?;
|
||||
|
||||
m.add_class::<ComponentCompiler>()?;
|
||||
m.add_class::<image::PyImage>()?;
|
||||
m.add_class::<PyValueType>()?;
|
||||
m.add_class::<PyDiagnosticLevel>()?;
|
||||
m.add_class::<PyDiagnostic>()?;
|
||||
|
|
|
@ -8,3 +8,5 @@ def load_file(path):
|
|||
compdef = compiler.build_from_path(path)
|
||||
instance = compdef.create()
|
||||
return instance
|
||||
|
||||
Image = native.PyImage
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
import pytest
|
||||
from slint import slint as native
|
||||
from slint.slint import ValueType;
|
||||
from slint.slint import ValueType, PyImage;
|
||||
import os
|
||||
|
||||
def test_property_access():
|
||||
compiler = native.ComponentCompiler()
|
||||
|
@ -32,10 +33,11 @@ def test_property_access():
|
|||
title: "builtin",
|
||||
finished: true,
|
||||
};
|
||||
in property <image> imageprop: @image-url("../../../examples/printerdemo/ui/images/cat.jpg");
|
||||
|
||||
callback test-callback();
|
||||
}
|
||||
""", "")
|
||||
""", os.path.join(os.path.dirname(__file__), "main.slint"))
|
||||
assert compdef != None
|
||||
|
||||
instance = compdef.create()
|
||||
|
@ -74,6 +76,19 @@ def test_property_access():
|
|||
instance.set_property("structprop", {'title': 'new', 'finished': False})
|
||||
assert instance.get_property("structprop") == {'title': 'new', 'finished': False}
|
||||
|
||||
imageval = instance.get_property("imageprop")
|
||||
assert imageval.width == 320
|
||||
assert imageval.height == 480
|
||||
assert "cat.jpg" in imageval.path
|
||||
|
||||
with pytest.raises(RuntimeError, match="The image cannot be loaded"):
|
||||
PyImage.load_from_path("non-existent.png")
|
||||
|
||||
instance.set_property("imageprop", PyImage.load_from_path(os.path.join(os.path.dirname(__file__), "../../../examples/iot-dashboard/images/humidity.png")))
|
||||
imageval = instance.get_property("imageprop")
|
||||
assert imageval.size == (36, 36)
|
||||
assert "humidity.png" in imageval.path
|
||||
|
||||
with pytest.raises(TypeError, match="'int' object cannot be converted to 'PyString'"):
|
||||
instance.set_property("structprop", {42: 'wrong'})
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ impl<'a> ToPyObject for PyValueRef<'a> {
|
|||
slint_interpreter::Value::Number(num) => num.into_py(py),
|
||||
slint_interpreter::Value::String(str) => str.into_py(py),
|
||||
slint_interpreter::Value::Bool(b) => b.into_py(py),
|
||||
slint_interpreter::Value::Image(_) => todo!(),
|
||||
slint_interpreter::Value::Image(image) => {
|
||||
crate::image::PyImage::from(image).into_py(py)
|
||||
}
|
||||
slint_interpreter::Value::Model(_) => todo!(),
|
||||
slint_interpreter::Value::Struct(structval) => structval
|
||||
.iter()
|
||||
|
@ -60,6 +62,10 @@ impl FromPyObject<'_> for PyValue {
|
|||
ob.extract::<&'_ str>().map(|s| slint_interpreter::Value::String(s.into()))
|
||||
})
|
||||
.or_else(|_| ob.extract::<f64>().map(|num| slint_interpreter::Value::Number(num)))
|
||||
.or_else(|_| {
|
||||
ob.extract::<PyRef<'_, crate::image::PyImage>>()
|
||||
.map(|pyimg| slint_interpreter::Value::Image(pyimg.image.clone()))
|
||||
})
|
||||
.or_else(|_| {
|
||||
ob.extract::<&PyDict>().and_then(|dict| {
|
||||
let dict_items: Result<Vec<(String, slint_interpreter::Value)>, PyErr> = dict
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue