Just use a popup.
Here's a simplified version of what I use:
decorator
from functools import wraps
def loading(message="MESSAGE"):
def _loading(func):
@wraps(func)
def wrapper(*args, **kwargs):
system.perspective.openPopup(
id = 'loader',
view = "components/loader/popup",
position = {'width': "300px", 'height': "300px"},
showCloseIcon = False,
draggable = False,
modal = True,
resizable = False,
overlayDismiss = False,
params = {
'message': message
}
)
popup_open = True
try:
ret = func(*args, **kwargs)
except:
raise
finally:
system.perspective.closePopup('loader')
return ret
return wrapper
return _loading
popup view json
{
"custom": {},
"params": {
"message": "loading..."
},
"propConfig": {
"params.message": {
"paramDirection": "input",
"persistent": true
}
},
"props": {
"defaultSize": {
"height": 300,
"width": 300
}
},
"root": {
"children": [
{
"meta": {
"name": "spinning-circles"
},
"position": {
"basis": "80px"
},
"props": {
"elements": [
{
"elements": [
{
"elements": [
{
"cx": "42.601",
"cy": "11.462",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "1;0;0;0;0;0;0;0"
}
],
"fill": {
"opacity": "1",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "49.063",
"cy": "27.063",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;1;0;0;0;0;0;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "42.601",
"cy": "42.663",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;1;0;0;0;0;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "27",
"cy": "49.125",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;0;1;0;0;0;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "11.399",
"cy": "42.663",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;0;0;1;0;0;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "4.938",
"cy": "27.063",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;0;0;0;1;0;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "11.399",
"cy": "11.462",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;0;0;0;0;1;0"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
},
{
"cx": "27",
"cy": "5",
"elements": [
{
"attributeName": "fill-opacity",
"calcMode": "linear",
"dur": "1.3s",
"name": "animate",
"repeatCount": "indefinite",
"type": "animate",
"values": "0;0;0;0;0;0;0;1"
}
],
"fill": {
"opacity": "0",
"paint": "#fff"
},
"name": "circle",
"r": "5",
"type": "circle"
}
],
"name": "group",
"stroke": {
"paint": "#FFF",
"width": "1.5"
},
"transform": "translate(2 1)",
"type": "group"
}
],
"fill": {
"paint": "transparent",
"rule": "evenodd"
},
"name": "group",
"type": "group"
}
],
"viewBox": "0 0 58 58"
},
"type": "ia.shapes.svg"
},
{
"meta": {
"name": "Label"
},
"propConfig": {
"props.text": {
"binding": {
"config": {
"path": "view.params.message"
},
"type": "property"
}
}
},
"props": {
"textStyle": {
"color": "white"
}
},
"type": "ia.display.label"
}
],
"meta": {
"name": "root"
},
"props": {
"alignItems": "center",
"direction": "column",
"justify": "center",
"style": {
"gap": "20px"
}
},
"type": "ia.container.flex"
}
}
css
#popup-loader {
border: none;
outline: none;
background: transparent;
box-shadow: none;
text-shadow: 2px 2px 3px black;
font-size: 1.3em;
}
Here's how to use it:
When you have a function that may take time to run, put it in your library, and decorate it with the loading decorator.
It should look like this:
@some_module.loading("message")
def slow_function():
sleep(20)
Now call that function in your transforms or whatever. That's it.
You can replace the loading animation by just replacing the svg in the popup. You can find some here: GitHub - SamHerbert/SVG-Loaders: Loading icons and small animations built with pure SVG.
I also have a version of that popup that uses css for the animation if you prefer.