Python: Initial support for implementing models in Python

This provides a Model base class in Python and sub-classes of that
can be set as data models in slint.

The ListModel is provided as basic sub-class operating on a list() and
allowing mutation and notifying the view on the Slint side.

Similarly, an array declared in Slint is exposed as an object to Python
that looks like a Model.

Both support the sequence protocol.

Fixes #4135
This commit is contained in:
Simon Hausmann 2024-03-04 16:05:20 +01:00 committed by Simon Hausmann
parent 82d784a4d4
commit 2f313f84ec
6 changed files with 393 additions and 1 deletions

View file

@ -14,3 +14,4 @@ def load_file(path):
Image = native.PyImage
Color = native.PyColor
Brush = native.PyBrush
Model = native.PyModelBase

View file

@ -0,0 +1,71 @@
# Copyright © SixtyFPS GmbH <info@slint.dev>
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
from . import slint as native
class Model(native.PyModelBase):
def __new__(cls, *args):
return super().__new__(cls)
def __init__(self, lst=None):
self.init_self(self)
def __len__(self):
return self.row_count()
def __getitem__(self, index):
return self.row_data(index)
def __setitem__(self, index, value):
self.set_row_data(index, value)
def __iter__(self):
return ModelIterator(self)
class ListModel(Model):
def __init__(self, lst=None):
super().__init__()
self.list = lst or []
def row_count(self):
return len(self.list)
def row_data(self, row):
return self.list[row]
def set_row_data(self, row, data):
self.list[row] = data
super().notify_row_changed(row)
def __delitem__(self, key):
if isinstance(key, slice):
start, stop, step = key.indices(len(self.list))
del self.list[key]
count = len(range(start, stop, step))
super().notify_row_removed(start, count)
else:
del self.list[key]
super().notify_row_removed(key, 1)
def append(self, value):
index = len(self.list)
self.list.append(value)
super().notify_row_added(index, 1)
class ModelIterator:
def __init__(self, model):
self.model = model
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= self.model.row_count():
raise StopIteration()
index = self.index
self.index += 1
return self.model.row_data(index)