wallet: make a more powerful property system

This commit is contained in:
rsx
2024-05-06 16:48:36 +02:00
parent 7e9fba23fb
commit 2f58097787
12 changed files with 1394 additions and 493 deletions

View File

@@ -28,6 +28,11 @@ class App(EventLoop):
self.cursor_layer = Layer("cursor_layer")
self.cursor_layer.add_obj("cursor")
self.cursor_layer.resize(w, h)
self.rounded_box_layer = Layer("rounded_box_layer")
self.rounded_box_layer.add_obj("box")
self.rounded_box_layer.resize(w, h)
self.user_input = ""
self.last_keypress_time = 0
@@ -35,7 +40,9 @@ class App(EventLoop):
def resize_event(self, w, h):
self.chatbox_layer.resize(w, h)
self.cursor_layer.resize(w, h)
self.rounded_box_layer.resize(w, h)
resize_box()
resize_rounded_box()
draw_txt(self.user_input)
def mouse_click(self, x, y):
@@ -108,8 +115,19 @@ def draw_txt(user_input):
rename_node("/window/chatbox_layer/user_input2/txt2", "txt")
rename_node("/window/chatbox_layer/user_input2", "user_input")
reposition_cursor()
def reposition_cursor():
layer_h = get_property("/window/chatbox_layer", "rect_h")
y = layer_h - 20 - 30
# Move the cursor
text_px_w = get_property("/window/chatbox_layer/user_input/txt", "width")
text_id = api.lookup_node_id("/window/chatbox_layer/user_input/txt")
text_px_w = 0
user_input = ""
if text_id is not None:
text_px_w = get_property(text_id, "width")
user_input = get_property(text_id, "text")
x = text_px_w + 25
if user_input and user_input[-1] == " ":
x += 10
@@ -152,7 +170,7 @@ def resize_box():
box_h = 60
# Inner padding, so box inside will be (box_h - 2*padding) px high
padding = 5
padding = 10
# Lets add a poly - must be counterclockwise
x, y = 0, layer_h - box_h
@@ -177,12 +195,102 @@ def resize_box():
api.set_property_buffer(mesh_id, "verts", vert1 + vert2 + vert3 + vert4)
api.set_property_buffer(mesh_id, "faces", face(0, 2, 1) + face(1, 2, 3))
def draw_rounded_box():
mesh_id = api.add_node("box", SceneNodeType.RENDER_MESH)
api.add_property(mesh_id, "verts", PropertyType.BUFFER)
api.add_property(mesh_id, "faces", PropertyType.BUFFER)
link_node(mesh_id, "/window/rounded_box_layer/box")
mesh_id = api.add_node("inner_box", SceneNodeType.RENDER_MESH)
api.add_property(mesh_id, "verts", PropertyType.BUFFER)
api.add_property(mesh_id, "faces", PropertyType.BUFFER)
link_node(mesh_id, "/window/rounded_box_layer/box")
resize_rounded_box()
def resize_rounded_box():
mesh_id = api.lookup_node_id("/window/rounded_box_layer/box/box")
layer_w = get_property("/window/rounded_box_layer", "rect_w")
layer_h = get_property("/window/rounded_box_layer", "rect_h")
# Inner padding, so box inside will be (box_h - 2*padding) px high
padding = 5
bevel = 20
# Lets add a poly - must be counterclockwise
x, y = layer_w/4, layer_h/4
w, h = layer_w/2, layer_h/2
y0 = y + bevel
h0 = h - 2*bevel
verts = (
vertex(x, y0, 1, 1, 1, 1, 0, 0) +
vertex(x + w, y0, 1, 1, 1, 1, 1, 0) +
vertex(x, y0 + h0, 1, 1, 1, 1, 0, 1) +
vertex(x + w, y0 + h0, 1, 1, 1, 1, 1, 1)
)
faces = face(0, 2, 1) + face(1, 2, 3)
x0 = x + bevel
w0 = w - 2*bevel
h0 = bevel
verts += (
vertex(x0, y, 1, 1, 1, 1, 0, 0) +
vertex(x0 + w0, y, 1, 1, 1, 1, 1, 0) +
vertex(x0, y + h0, 1, 1, 1, 1, 0, 1) +
vertex(x0 + w0, y + h0, 1, 1, 1, 1, 1, 1)
)
o = 4
faces += face(o + 0, o + 2, o + 1) + face(o + 1, o + 2, o + 3)
y0 = y + h - bevel
x0 = x + bevel
w0 = w - 2*bevel
h0 = bevel
verts += (
vertex(x0, y0, 1, 1, 1, 1, 0, 0) +
vertex(x0 + w0, y0, 1, 1, 1, 1, 1, 0) +
vertex(x0, y0 + h0, 1, 1, 1, 1, 0, 1) +
vertex(x0 + w0, y0 + h0, 1, 1, 1, 1, 1, 1)
)
o = 8
faces += face(o + 0, o + 2, o + 1) + face(o + 1, o + 2, o + 3)
api.set_property_buffer(mesh_id, "verts", verts)
api.set_property_buffer(mesh_id, "faces", faces)
# Second mesh
mesh_id = api.lookup_node_id("/window/rounded_box_layer/box/inner_box")
x, y = x + padding, y + padding
w -= 2*padding
h -= 2*padding
vert1 = vertex(x, y, 0, 0, 0, 1, 0, 0)
vert2 = vertex(x + w, y, 0, 0, 0, 1, 1, 0)
vert3 = vertex(x, y + h, 0, 0, 0, 1, 0, 1)
vert4 = vertex(x + w, y + h, 0.3, 0.3, 0.3, 1, 1, 1)
#api.set_property_buffer(mesh_id, "verts", vert1 + vert2 + vert3 + vert4)
#api.set_property_buffer(mesh_id, "faces", face(0, 2, 1) + face(1, 2, 3))
def main():
garbage_collect()
app = App()
draw_box()
draw_cursor()
node_id = api.add_node("foo", SceneNodeType.WINDOW)
prop = Property(
"myprop", PropertyType.FLOAT32, PropertySubType.NULL,
None,
"myprop", "",
False, 2, None, None, []
)
api.add_property(1, prop)
api.link_node(node_id, 0)
api.set_property_f32(1, "myprop", 0, 4.0)
api.set_property_f32(1, "myprop", 1, 110.0)
print(api.get_property_value(1, "myprop"))
print_tree()
app.run()
#garbage_collect()
#app = App()
#draw_box()
#draw_rounded_box()
#draw_cursor()
#reposition_cursor()
##print_tree()
#app.run()

View File

@@ -1,5 +1,5 @@
from collections import namedtuple
from pydrk import Api, HostApi, PropertyType
from pydrk import Api, HostApi, PropertyType, PropertySubType, Property
import zmq
api = Api()
@@ -28,8 +28,8 @@ def register_slot(node_path, sig, tag):
node_id = api.lookup_node_id(node_path)
api.register_slot(node_id, sig, "", tag)
def get_property(node_path, prop):
node_id = api.lookup_node_id(node_path)
def get_property(node_id, prop):
node_id = lookup_node(node_id)
return api.get_property(node_id, prop)
def set_property(node_id, prop, val):

View File

@@ -49,19 +49,19 @@ def print_node_info(parent_id, indent):
print_node_info(child_id, indent+1)
for prop_name, prop_type in api.get_properties(parent_id):
if prop_type == PropertyType.STR:
prop_val = api.get_property(parent_id, prop_name)
prop_val = f" = \"{prop_val}\""
elif prop_type != PropertyType.BUFFER:
prop_val = api.get_property(parent_id, prop_name)
prop_val = f" = {prop_val}"
else:
prop_val = ""
#for prop_name, prop_type in api.get_properties(parent_id):
# if prop_type == PropertyType.STR:
# prop_val = api.get_property(parent_id, prop_name)
# prop_val = f" = \"{prop_val}\""
# elif prop_type != PropertyType.BUFFER:
# prop_val = api.get_property(parent_id, prop_name)
# prop_val = f" = {prop_val}"
# else:
# prop_val = ""
prop_type = PropertyType.to_str(prop_type)
# prop_type = PropertyType.to_str(prop_type)
print(f"{ws}{prop_name}: {prop_type}{prop_val}")
# print(f"{ws}{prop_name}: {prop_type}{prop_val}")
for sig in api.get_signals(parent_id):
print(f"{ws}~{sig}")

View File

@@ -1,4 +1,6 @@
from .api import Api, ErrorCode, SceneNodeType, PropertyType, vertex, face
from .api import (Api, ErrorCode, SceneNodeType,
PropertyType, PropertySubType, Property,
vertex, face)
from .host import HostApi
from . import exc, serial

View File

@@ -1,7 +1,22 @@
import zmq
from collections import namedtuple
from . import serial
from . import exc
Property = namedtuple("Property", [
"name",
"type",
"subtype",
"defaults",
"ui_name",
"desc",
"is_null_allowed",
"array_len",
"min_val",
"max_val",
"enum_items"
])
class Command:
HELLO = 0
ADD_NODE = 1
@@ -16,8 +31,8 @@ class Command:
GET_CHILDREN = 4
GET_PARENTS = 5
GET_PROPERTIES = 3
GET_PROPERTY = 6
SET_PROPERTY = 7
GET_PROPERTY_VALUE = 6
SET_PROPERTY_VALUE = 7
GET_SIGNALS = 14
REGISTER_SLOT = 15
UNREGISTER_SLOT = 16
@@ -45,20 +60,19 @@ class SceneNodeType:
class PropertyType:
NULL = 0
BUFFER = 1
BOOL = 2
UINT32 = 3
FLOAT32 = 4
STR = 5
SCENE_NODE_ID = 6
BOOL = 1
UINT32 = 2
FLOAT32 = 3
STR = 4
ENUM = 5
BUFFER = 6
SCENE_NODE_ID = 7
@staticmethod
def to_str(prop_type):
match prop_type:
case PropertyType.NULL:
return "null"
case PropertyType.BUFFER:
return "buffer"
case PropertyType.BOOL:
return "bool"
case PropertyType.UINT32:
@@ -67,29 +81,55 @@ class PropertyType:
return "float32"
case PropertyType.STR:
return "str"
case PropertyType.ENUM:
return "enum"
case PropertyType.BUFFER:
return "buffer"
case PropertyType.SCENE_NODE_ID:
return "scene_node_id"
class PropertySubType:
NULL = 0
COLOR = 1
PIXEL = 2
@staticmethod
def to_str(prop_type):
match prop_type:
case PropertySubType.NULL:
return "null"
case PropertySubType.Color:
return "color"
case PropertySubType.PIXEL:
return "pixel"
class ErrorCode:
INVALID_SCENE_PATH = 2
NODE_NOT_FOUND = 3
CHILD_NODE_NOT_FOUND = 4
PARENT_NODE_NOT_FOUND = 5
PROPERTY_ALREADY_EXISTS = 6
PROPERTY_NOT_FOUND = 7
PROPERTY_WRONG_TYPE = 8
SIGNAL_ALREADY_EXISTS = 9
SIGNAL_NOT_FOUND = 10
SLOT_NOT_FOUND = 11
METHOD_NOT_FOUND = 12
NODES_ARE_LINKED = 13
NODES_NOT_LINKED = 14
NODE_HAS_PARENTS = 15
NODE_HAS_CHILDREN = 16
NODE_PARENT_NAME_CONFLICT = 17
NODE_CHILD_NAME_CONFLICT = 18
NODE_SIBLING_NAME_CONFLICT = 19
FILE_NOT_FOUND = 20
INVALID_SCENE_PATH = 1
NODE_NOT_FOUND = 2
CHILD_NODE_NOT_FOUND = 3
PARENT_NODE_NOT_FOUND = 4
PROPERTY_ALREADY_EXISTS = 5
PROPERTY_NOT_FOUND = 6
PROPERTY_WRONG_TYPE = 7
PROPERTY_WRONG_LEN = 8
PROPERTY_WRONG_INDEX = 9
PROPERTY_OUT_OF_RANGE = 10
PROPERTY_NULL_NOT_ALLOWED = 11
PROPERTY_IS_BOUNDED = 12
PROPERTY_WRONG_ENUM_ITEM = 13
SIGNAL_ALREADY_EXISTS = 14
SIGNAL_NOT_FOUND = 15
SLOT_NOT_FOUND = 16
METHOD_ALREADY_EXISTS = 17
METHOD_NOT_FOUND = 18
NODES_ARE_LINKED = 19
NODES_NOT_LINKED = 20
NODE_HAS_PARENTS = 21
NODE_HAS_CHILDREN = 22
NODE_PARENT_NAME_CONFLICT = 23
NODE_CHILD_NAME_CONFLICT = 24
NODE_SIBLING_NAME_CONFLICT = 25
FILE_NOT_FOUND = 26
@staticmethod
def to_str(errc):
@@ -108,28 +148,42 @@ class ErrorCode:
return "property_not_found"
case ErrorCode.PROPERTY_WRONG_TYPE:
return "property_wrong_type"
case ErrorCode.PROPERTY_WRONG_LEN:
return "property_wrong_len"
case ErrorCode.PROPERTY_WRONG_INDEX:
return "property_wrong_index"
case ErrorCode.PROPERTY_OUT_OF_RANGE:
return "property_out_of_range"
case ErrorCode.PROPERTY_NULL_NOT_ALLOWED:
return "property_null_not_allowed"
case ErrorCode.PROPERTY_IS_BOUNDED:
return "property_is_bounded"
case ErrorCode.PROPERTY_WRONG_ENUM_ITEM:
return "property_wrong_enum_item"
case ErrorCode.SIGNAL_ALREADY_EXISTS:
return "signal_already_exists"
case ErrorCode.SIGNAL_NOT_FOUND:
return "signal_not_found "
return "signal_not_found"
case ErrorCode.SLOT_NOT_FOUND:
return "slot_not_found "
return "slot_not_found"
case ErrorCode.METHOD_ALREADY_EXISTS:
return "method_already_exists"
case ErrorCode.METHOD_NOT_FOUND:
return "method_not_found "
return "method_not_found"
case ErrorCode.NODES_ARE_LINKED:
return "nodes_are_linked "
return "nodes_are_linked"
case ErrorCode.NODES_NOT_LINKED:
return "nodes_not_linked "
return "nodes_not_linked"
case ErrorCode.NODE_HAS_PARENTS:
return "node_has_parents "
return "node_has_parents"
case ErrorCode.NODE_HAS_CHILDREN:
return "node_has_children "
return "node_has_children"
case ErrorCode.NODE_PARENT_NAME_CONFLICT:
return "node_parent_name_conflict "
return "node_parent_name_conflict"
case ErrorCode.NODE_CHILD_NAME_CONFLICT:
return "node_child_name_conflict "
return "node_child_name_conflict"
case ErrorCode.NODE_SIBLING_NAME_CONFLICT:
return "node_sibling_name_conflict "
return "node_sibling_name_conflict"
case ErrorCode.FILE_NOT_FOUND:
return "file_not_found"
@@ -169,44 +223,58 @@ class Api:
errc = int.from_bytes(errc, "little")
cursor = serial.Cursor(reply)
match errc:
case 1:
raise exc.InvalidScenePath
case 2:
raise exc.RequestInvalidScenePath
raise exc.NodeNotFound
case 3:
raise exc.RequestNodeNotFound
raise exc.ChildNodeNotFound
case 4:
raise exc.RequestChildNodeNotFound
raise exc.ParentNodeNotFound
case 5:
raise exc.RequestParentNodeNotFound
raise exc.PropertyAlreadyExists
case 6:
raise exc.RequestPropertyAlreadyExists
raise exc.PropertyNotFound
case 7:
raise exc.RequestPropertyNotFound
raise exc.PropertyWrongType
case 8:
raise exc.RequestPropertyWrongType
raise exc.PropertyWrongLen
case 9:
raise exc.RequestSignalAlreadyExists
raise exc.PropertyWrongIndex
case 10:
raise exc.RequestSignalNotFound
raise exc.PropertyOutOfRange
case 11:
raise exc.RequestSlotNotFound
raise exc.PropertyNullNotAllowed
case 12:
raise exc.RequestMethodNotFound
raise exc.PropertyIsBounded
case 13:
raise exc.RequestNodesAreLinked
raise exc.PropertyWrongEnumItem
case 14:
raise exc.RequestNodesNotLinked
raise exc.SignalAlreadyExists
case 15:
raise exc.RequestNodeHasParents
raise exc.SignalNotFound
case 16:
raise exc.RequestNodeHasChildren
raise exc.SlotNotFound
case 17:
raise exc.RequestNodeParentNameConflict
raise exc.MethodAlreadyExists
case 18:
raise exc.RequestNodeChildNameConflict
raise exc.MethodNotFound
case 19:
raise exc.RequestNodeSiblingNameConflict
raise exc.NodesAreLinked
case 20:
raise exc.RequestFileNotFound
raise exc.NodesNotLinked
case 21:
raise exc.NodeHasParents
case 22:
raise exc.NodeHasChildren
case 23:
raise exc.NodeParentNameConflict
case 24:
raise exc.NodeChildNameConflict
case 25:
raise exc.NodeSiblingNameConflict
case 26:
raise exc.FileNotFound
return cursor
def hello(self):
@@ -259,27 +327,43 @@ class Api:
props.append((prop_name, prop_type))
return props
def get_property(self, node_id, prop_name):
def get_property_value(self, node_id, prop_name):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
cur = self._make_request(Command.GET_PROPERTY, req)
cur = self._make_request(Command.GET_PROPERTY_VALUE, req)
prop_type = serial.read_u8(cur)
prop_len = serial.decode_varint(cur)
vals = []
def read_array(read_fn):
for _ in range(prop_len):
is_some = serial.read_u8(cur)
if is_some:
val = read_fn()
vals.append(val)
match prop_type:
case 0:
case PropertyType.NULL:
return None
case 1:
return []
case 3:
val = serial.read_u8(cur)
return bool(val)
case 2:
return serial.read_u32(cur)
case 4:
return serial.read_f32(cur)
case 5:
return serial.decode_str(cur)
raise Exception("unknown property type returned")
case PropertyType.BOOL:
read_array(lambda: bool(serial.read_u8(cur)))
case PropertyType.UINT32:
read_array(lambda: serial.read_u32(cur))
case PropertyType.FLOAT32:
read_array(lambda: serial.read_f32(cur))
case PropertyType.STR:
read_array(lambda: serial.decode_str(cur))
case PropertyType.ENUM:
read_array(lambda: serial.decode_str(cur))
case PropertyType.BUFFER:
pass
case PropertyType.SCENE_NODE_ID:
read_array(lambda: serial.read_u32(cur))
case _:
raise Exception("unknown property type returned")
return vals
def add_node(self, node_name, node_type):
req = bytearray()
@@ -318,11 +402,57 @@ class Api:
return None
return serial.read_u32(cur)
def add_property(self, node_id, prop_name, prop_type):
def add_property(self, node_id, prop):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u8(req, int(prop_type))
serial.encode_str(req, prop.name)
serial.write_u8(req, int(prop.type))
serial.write_u8(req, int(prop.subtype))
serial.write_u32(req, int(prop.array_len))
if prop.defaults is None:
serial.write_u8(req, 0)
else:
serial.write_u8(req, 1)
defaults_len = len(prop.defaults)
serial.encode_varint(req, defaults_len)
for default in prop.defaults:
match prop.type:
case PropertyType.UINT32:
serial.write_u32(req, default)
case PropertyType.FLOAT32:
serial.write_f32(req, default)
case _:
raise exc.PropertyWrongType
serial.encode_str(req, prop.ui_name)
serial.encode_str(req, prop.desc)
serial.write_u8(req, int(prop.is_null_allowed))
if prop.min_val is None:
serial.write_u8(req, 0)
else:
serial.write_u8(req, 1)
match prop.type:
case PropertyType.UINT32:
serial.write_u32(req, prop.min_val)
case PropertyType.FLOAT32:
serial.write_f32(req, prop.min_val)
case _:
raise exc.PropertyWrongType
if prop.max_val is None:
serial.write_u8(req, 0)
else:
serial.write_u8(req, 1)
match prop.type:
case PropertyType.UINT32:
serial.write_u32(req, prop.max_val)
case PropertyType.FLOAT32:
serial.write_f32(req, prop.max_val)
case _:
raise exc.PropertyWrongType
serial.encode_varint(req, len(prop.enum_items))
for enum_item in prop.enum_items:
if prop.type != PropertyType.ENUM:
raise exc.PropertyWrongType
serial.encode_str(req, enum_item)
self._make_request(Command.ADD_PROPERTY, req)
def link_node(self, child_id, parent_id):
@@ -342,35 +472,39 @@ class Api:
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u8(req, int(val))
self._make_request(Command.SET_PROPERTY, req)
self._make_request(Command.SET_PROPERTY_VALUE, req)
def set_property_u32(self, node_id, prop_name, val):
def set_property_u32(self, node_id, prop_name, i, val):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u32(req, i)
serial.write_u32(req, val)
self._make_request(Command.SET_PROPERTY, req)
self._make_request(Command.SET_PROPERTY_VALUE, req)
def set_property_f32(self, node_id, prop_name, val):
def set_property_f32(self, node_id, prop_name, i, val):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u32(req, i)
serial.write_f32(req, val)
self._make_request(Command.SET_PROPERTY, req)
self._make_request(Command.SET_PROPERTY_VALUE, req)
def set_property_buffer(self, node_id, prop_name, buf):
def set_property_buffer(self, node_id, prop_name, i, buf):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u32(req, i)
serial.encode_buf(req, buf)
self._make_request(Command.SET_PROPERTY, req)
self._make_request(Command.SET_PROPERTY_VALUE, req)
def set_property_str(self, node_id, prop_name, val):
def set_property_str(self, node_id, prop_name, i, val):
req = bytearray()
serial.write_u32(req, node_id)
serial.encode_str(req, prop_name)
serial.write_u32(req, i)
serial.encode_str(req, val)
self._make_request(Command.SET_PROPERTY, req)
self._make_request(Command.SET_PROPERTY_VALUE, req)
def get_signals(self, node_id):
req = bytearray()

View File

@@ -1,38 +1,52 @@
class RequestInvalidScenePath(Exception):
class InvalidScenePath(Exception):
pass
class RequestNodeNotFound(Exception):
class NodeNotFound(Exception):
pass
class RequestChildNodeNotFound(Exception):
class ChildNodeNotFound(Exception):
pass
class RequestParentNodeNotFound(Exception):
class ParentNodeNotFound(Exception):
pass
class RequestPropertyAlreadyExists(Exception):
class PropertyAlreadyExists(Exception):
pass
class RequestPropertyNotFound(Exception):
class PropertyNotFound(Exception):
pass
class RequestPropertyWrongType(Exception):
class PropertyWrongType(Exception):
pass
class RequestSignalAlreadyExists(Exception):
class PropertyWrongLen(Exception):
pass
class RequestSignalNotFound(Exception):
class PropertyWrongIndex(Exception):
pass
class RequestSlotNotFound(Exception):
class PropertyOutOfRange(Exception):
pass
class RequestMethodNotFound(Exception):
class PropertyNullNotAllowed(Exception):
pass
class RequestNodesAreLinked(Exception):
class PropertyIsBounded(Exception):
pass
class RequestNodesNotLinked(Exception):
class PropertyWrongEnumItem(Exception):
pass
class RequestNodeHasParents(Exception):
class SignalAlreadyExists(Exception):
pass
class RequestNodeHasChildren(Exception):
class SignalNotFound(Exception):
pass
class RequestNodeParentNameConflict(Exception):
class SlotNotFound(Exception):
pass
class RequestNodeChildNameConflict(Exception):
class MethodAlreadyExists(Exception):
pass
class RequestNodeSiblingNameConflict(Exception):
class MethodNotFound(Exception):
pass
class RequestFileNotFound(Exception):
class NodesAreLinked(Exception):
pass
class NodesNotLinked(Exception):
pass
class NodeHasParents(Exception):
pass
class NodeHasChildren(Exception):
pass
class NodeParentNameConflict(Exception):
pass
class NodeChildNameConflict(Exception):
pass
class NodeSiblingNameConflict(Exception):
pass
class FileNotFound(Exception):
pass

View File

@@ -4,59 +4,80 @@ pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Copy, Clone, thiserror::Error)]
pub enum Error {
#[error("Invalid scene path")]
InvalidScenePath = 2,
InvalidScenePath = 1,
#[error("Node not found")]
NodeNotFound = 3,
NodeNotFound = 2,
#[error("Child node not found")]
ChildNodeNotFound = 4,
ChildNodeNotFound = 3,
#[error("Parent node not found")]
ParentNodeNotFound = 5,
ParentNodeNotFound = 4,
#[error("Property already exists")]
PropertyAlreadyExists = 6,
PropertyAlreadyExists = 5,
#[error("Property not found")]
PropertyNotFound = 7,
PropertyNotFound = 6,
#[error("Property has wrong type")]
PropertyWrongType = 8,
PropertyWrongType = 7,
#[error("Property value has the wrong length")]
PropertyWrongLen = 8,
#[error("Property index is wrong")]
PropertyWrongIndex = 9,
#[error("Property out of range")]
PropertyOutOfRange = 10,
#[error("Property null not allowed")]
PropertyNullNotAllowed = 11,
#[error("Property array is bounded length")]
PropertyIsBounded = 12,
#[error("Property enum item is invalid")]
PropertyWrongEnumItem = 13,
#[error("Signal already exists")]
SignalAlreadyExists = 9,
SignalAlreadyExists = 14,
#[error("Signal not found")]
SignalNotFound = 10,
SignalNotFound = 15,
#[error("Slot not found")]
SlotNotFound = 11,
SlotNotFound = 16,
#[error("Signal already exists")]
MethodAlreadyExists = 17,
#[error("Method not found")]
MethodNotFound = 12,
MethodNotFound = 18,
#[error("Nodes are not linked")]
NodesAreLinked = 13,
NodesAreLinked = 19,
#[error("Nodes are not linked")]
NodesNotLinked = 14,
NodesNotLinked = 20,
#[error("Node has parents")]
NodeHasParents = 15,
NodeHasParents = 21,
#[error("Node has children")]
NodeHasChildren = 16,
NodeHasChildren = 22,
#[error("Node has a parent with this name")]
NodeParentNameConflict = 17,
NodeParentNameConflict = 23,
#[error("Node has a child with this name")]
NodeChildNameConflict = 18,
NodeChildNameConflict = 24,
#[error("Node has a sibling with this name")]
NodeSiblingNameConflict = 19,
NodeSiblingNameConflict = 25,
#[error("File not found")]
FileNotFound = 20,
FileNotFound = 26,
}

View File

@@ -8,7 +8,8 @@ use std::{fmt, io::Cursor};
use crate::{
error::{Error, Result},
scene::{PropertyType, SceneGraph, SceneGraphPtr, SceneNode, SceneNodeId, SceneNodeType},
prop::{Property, PropertySubType, PropertyType},
scene::{SceneGraph, SceneGraphPtr, SceneNode, SceneNodeId, SceneNodeType},
shader,
};
@@ -157,15 +158,15 @@ impl Stage {
let font = include_bytes!("../Inter-Regular.ttf") as &[u8];
let font = Font::from_bytes(font, FontSettings::default()).unwrap();
let line_metrics = font.horizontal_line_metrics(1.).unwrap();
inter_regular.add_property_f32("ascent", line_metrics.ascent).unwrap();
inter_regular.add_property_f32("descent", line_metrics.descent).unwrap();
inter_regular.add_property_f32("line_gap", line_metrics.line_gap).unwrap();
inter_regular.add_property_f32("new_line_size", line_metrics.new_line_size).unwrap();
//inter_regular.add_property_f32("ascent", line_metrics.ascent).unwrap();
//inter_regular.add_property_f32("descent", line_metrics.descent).unwrap();
//inter_regular.add_property_f32("line_gap", line_metrics.line_gap).unwrap();
//inter_regular.add_property_f32("new_line_size", line_metrics.new_line_size).unwrap();
inter_regular.add_method(
"create_text",
vec![("text", PropertyType::Str), ("font_size", PropertyType::Float32)],
vec![("node_id", PropertyType::SceneNodeId)],
vec![("text", "", PropertyType::Str), ("font_size", "", PropertyType::Float32)],
vec![("node_id", "", PropertyType::SceneNodeId)],
);
let inter_regular_id = inter_regular.id;
@@ -183,14 +184,29 @@ impl Stage {
let window = scene_graph.add_node("window", SceneNodeType::Window);
let (screen_width, screen_height) = window::screen_size();
window.add_property_f32("width", screen_width).unwrap();
window.add_property_f32("height", screen_height).unwrap();
window.add_signal("resize").unwrap();
window.add_method(
"load_texture",
vec![("node_name", PropertyType::Str), ("path", PropertyType::Str)],
vec![("node_id", PropertyType::SceneNodeId)],
);
let mut prop = Property::new("screen_size", PropertyType::Float32, PropertySubType::Pixel);
prop.set_array_len(2);
prop.set_f32(0, screen_width);
prop.set_f32(1, screen_height);
window.add_property(prop).unwrap();
window
.add_signal(
"resize",
vec![
("screen_width", "", PropertyType::Float32),
("screen_height", "", PropertyType::Float32),
],
)
.unwrap();
window
.add_method(
"load_texture",
vec![("node_name", "", PropertyType::Str), ("path", "", PropertyType::Str)],
vec![("node_id", "", PropertyType::SceneNodeId)],
)
.unwrap();
let window_id = window.id;
scene_graph.link(window_id, SceneGraph::ROOT_ID).unwrap();
@@ -199,27 +215,54 @@ impl Stage {
scene_graph.link(input_id, window_id).unwrap();
let keyb = scene_graph.add_node("keyboard", SceneNodeType::Keyboard);
keyb.add_property("shift", PropertyType::Bool).unwrap();
keyb.add_property("ctrl", PropertyType::Bool).unwrap();
keyb.add_property("alt", PropertyType::Bool).unwrap();
keyb.add_property("logo", PropertyType::Bool).unwrap();
keyb.add_property("repeat", PropertyType::Bool).unwrap();
keyb.add_property("keycode", PropertyType::Str).unwrap();
keyb.add_signal("key_down").unwrap();
keyb.add_signal(
"key_down",
vec![
("shift", "", PropertyType::Bool),
("ctrl", "", PropertyType::Bool),
("alt", "", PropertyType::Bool),
("logo", "", PropertyType::Bool),
("repeat", "", PropertyType::Bool),
("keycode", "", PropertyType::Enum),
],
)
.unwrap();
let keyb_id = keyb.id;
scene_graph.link(keyb_id, input_id).unwrap();
let mouse = scene_graph.add_node("mouse", SceneNodeType::Mouse);
mouse.add_property("button", PropertyType::Uint32).unwrap();
mouse.add_property("motion_x", PropertyType::Float32).unwrap();
mouse.add_property("motion_y", PropertyType::Float32).unwrap();
mouse.add_property("wheel_y", PropertyType::Float32).unwrap();
mouse.add_property("click_x", PropertyType::Float32).unwrap();
mouse.add_property("click_y", PropertyType::Float32).unwrap();
mouse.add_signal("button_up").unwrap();
mouse.add_signal("button_down").unwrap();
mouse.add_signal("wheel").unwrap();
mouse.add_signal("move").unwrap();
mouse
.add_signal(
"button_up",
vec![
("button", "", PropertyType::Enum),
("x", "", PropertyType::Float32),
("y", "", PropertyType::Float32),
],
)
.unwrap();
mouse
.add_signal(
"button_down",
vec![
("button", "", PropertyType::Enum),
("x", "", PropertyType::Float32),
("y", "", PropertyType::Float32),
],
)
.unwrap();
mouse
.add_signal(
"wheel",
vec![("x", "", PropertyType::Float32), ("y", "", PropertyType::Float32)],
)
.unwrap();
mouse
.add_signal(
"move",
vec![("x", "", PropertyType::Float32), ("y", "", PropertyType::Float32)],
)
.unwrap();
let mouse_id = mouse.id;
scene_graph.link(mouse_id, input_id).unwrap();
}
@@ -312,12 +355,16 @@ impl Stage {
) -> Result<SceneNodeId> {
let mut scene_graph = self.scene_graph.lock().unwrap();
let text_node = scene_graph.add_node(node_name, SceneNodeType::RenderText);
text_node.add_property_str("text", text.clone()).unwrap();
text_node.add_property_f32("font_size", font_size).unwrap();
text_node.add_property_f32("r", 0.).unwrap();
text_node.add_property_f32("g", 0.).unwrap();
text_node.add_property_f32("b", 0.).unwrap();
text_node.add_property_f32("a", 0.).unwrap();
let mut prop = Property::new("text", PropertyType::Str, PropertySubType::Null);
text_node.add_property(prop)?;
let mut prop = Property::new("font_size", PropertyType::Float32, PropertySubType::Pixel);
text_node.add_property(prop)?;
let mut prop = Property::new("color", PropertyType::Float32, PropertySubType::Color);
prop.set_array_len(4);
text_node.add_property(prop)?;
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
layout.reset(&LayoutSettings { ..LayoutSettings::default() });
@@ -328,8 +375,6 @@ impl Stage {
let fonts = [font];
layout.append(&fonts, &TextStyle::new(&text, font_size, 0));
text_node.add_property_f32("height", layout.height()).unwrap();
// Calculate the text width
// std::cmp::max() not impl for f32
let max_f32 = |x: f32, y: f32| {
@@ -347,28 +392,33 @@ impl Stage {
total_width = max_f32(total_width, right);
}
text_node.add_property_f32("width", total_width).unwrap();
let mut prop = Property::new("size", PropertyType::Float32, PropertySubType::Pixel);
prop.set_array_len(2);
prop.set_f32(0, total_width).unwrap();
prop.set_f32(1, layout.height()).unwrap();
let text_node_id = text_node.id;
/*
let lines = layout.lines();
if lines.is_some() {
for (idx, line) in lines.unwrap().into_iter().enumerate() {
let line_node_name = format!("line.{}", idx);
let line_node = scene_graph.add_node(line_node_name, SceneNodeType::LinePosition);
line_node.add_property_u32("idx", idx as u32).unwrap();
line_node.add_property_f32("baseline_y", line.baseline_y).unwrap();
line_node.add_property_f32("padding", line.padding).unwrap();
line_node.add_property_f32("max_ascent", line.max_ascent).unwrap();
line_node.add_property_f32("min_descent", line.min_descent).unwrap();
line_node.add_property_f32("max_line_gap", line.max_line_gap).unwrap();
line_node.add_property_u32("glyph_start", line.glyph_start as u32).unwrap();
line_node.add_property_u32("glyph_end", line.glyph_end as u32).unwrap();
//line_node.add_property_u32("idx", idx as u32).unwrap();
//line_node.add_property_f32("baseline_y", line.baseline_y).unwrap();
//line_node.add_property_f32("padding", line.padding).unwrap();
//line_node.add_property_f32("max_ascent", line.max_ascent).unwrap();
//line_node.add_property_f32("min_descent", line.min_descent).unwrap();
//line_node.add_property_f32("max_line_gap", line.max_line_gap).unwrap();
//line_node.add_property_u32("glyph_start", line.glyph_start as u32).unwrap();
//line_node.add_property_u32("glyph_end", line.glyph_end as u32).unwrap();
let line_node_id = line_node.id;
scene_graph.link(line_node_id, text_node_id)?;
}
}
*/
scene_graph.link(font_node_id, text_node_id)?;
Ok(text_node_id)
@@ -387,13 +437,25 @@ impl Stage {
let mut scene_graph = self.scene_graph.lock().unwrap();
let img_node = scene_graph.add_node(node_name, SceneNodeType::RenderTexture);
img_node.add_property_u32("width", width).unwrap();
img_node.add_property_u32("height", height).unwrap();
img_node.add_property_u32("texture_id", id).unwrap();
//img_node.add_property_u32("width", width).unwrap();
//img_node.add_property_u32("height", height).unwrap();
//img_node.add_property_u32("texture_id", id).unwrap();
let mut prop = Property::new("size", PropertyType::Uint32, PropertySubType::Pixel);
prop.set_array_len(2);
prop.set_u32(0, width).unwrap();
prop.set_u32(1, height).unwrap();
img_node.add_property(prop)?;
let mut prop = Property::new("texture_id", PropertyType::Uint32, PropertySubType::Null);
prop.set_u32(0, id).unwrap();
img_node.add_property(prop)?;
Ok(img_node.id)
}
}
/*
fn get_obj_props(obj: &SceneNode) -> Result<(f32, f32, f32, f32, bool)> {
let x = obj.get_property_f32("x")?;
let y = obj.get_property_f32("y")?;
@@ -413,6 +475,7 @@ fn get_text_props(render_text: &SceneNode) -> Result<(String, f32, [f32; 4])> {
let color = [r, g, b, a];
Ok((text, font_size, color))
}
*/
impl EventHandler for Stage {
fn update(&mut self) {
@@ -501,10 +564,10 @@ impl EventHandler for Stage {
// This will make the top left (0, 0) and the bottom right (1, 1)
// Default is (-1, 1) -> (1, -1)
let proj = glam::Mat4::from_translation(glam::Vec3::new(-1., 1., 0.)) *
glam::Mat4::from_scale(glam::Vec3::new(2./screen_width, -2./screen_height, 1.));
glam::Mat4::from_scale(glam::Vec3::new(2. / screen_width, -2. / screen_height, 1.));
// Reusable text layout
let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
//let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
let scene_graph = self.scene_graph.lock().unwrap();
@@ -522,6 +585,7 @@ impl EventHandler for Stage {
self.ctx.begin_default_pass(PassAction::Nothing);
self.ctx.apply_pipeline(&self.pipeline);
/*
let rect_x = layer.get_property_u32("rect_x").unwrap();
let rect_y = layer.get_property_u32("rect_y").unwrap();
let rect_w = layer.get_property_u32("rect_w").unwrap();
@@ -666,6 +730,7 @@ impl EventHandler for Stage {
}
self.ctx.end_render_pass();
*/
}
self.ctx.commit_frame();
}
@@ -674,14 +739,14 @@ impl EventHandler for Stage {
let mut scene_graph = self.scene_graph.lock().unwrap();
let win = scene_graph.lookup_node_mut("/window/input/keyboard").unwrap();
win.set_property_bool("shift", modifiers.shift).unwrap();
win.set_property_bool("ctrl", modifiers.ctrl).unwrap();
win.set_property_bool("alt", modifiers.alt).unwrap();
win.set_property_bool("logo", modifiers.logo).unwrap();
win.set_property_bool("repeat", repeat).unwrap();
//win.set_property_bool("shift", modifiers.shift).unwrap();
//win.set_property_bool("ctrl", modifiers.ctrl).unwrap();
//win.set_property_bool("alt", modifiers.alt).unwrap();
//win.set_property_bool("logo", modifiers.logo).unwrap();
//win.set_property_bool("repeat", repeat).unwrap();
let send_key_down = |key: &str| {
win.set_property_str("keycode", key).unwrap();
//win.set_property_str("keycode", key).unwrap();
win.trigger("key_down").unwrap();
};
@@ -812,39 +877,39 @@ impl EventHandler for Stage {
fn mouse_motion_event(&mut self, x: f32, y: f32) {
let mut scene_graph = self.scene_graph.lock().unwrap();
let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
mouse.set_property_f32("motion_x", x).unwrap();
mouse.set_property_f32("motion_y", y).unwrap();
//mouse.set_property_f32("motion_x", x).unwrap();
//mouse.set_property_f32("motion_y", y).unwrap();
mouse.trigger("move").unwrap();
}
fn mouse_wheel_event(&mut self, x: f32, y: f32) {
let mut scene_graph = self.scene_graph.lock().unwrap();
let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
//mouse.set_property_f32("x", x).unwrap();
mouse.set_property_f32("wheel_y", y).unwrap();
//mouse.set_property_f32("wheel_y", y).unwrap();
mouse.trigger("wheel").unwrap();
}
fn mouse_button_down_event(&mut self, button: MouseButton, x: f32, y: f32) {
let mut scene_graph = self.scene_graph.lock().unwrap();
let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
mouse.set_property_u32("button", button.to_u8() as u32).unwrap();
mouse.set_property_f32("click_x", x).unwrap();
mouse.set_property_f32("click_y", y).unwrap();
//mouse.set_property_u32("button", button.to_u8() as u32).unwrap();
//mouse.set_property_f32("click_x", x).unwrap();
//mouse.set_property_f32("click_y", y).unwrap();
mouse.trigger("button_down").unwrap();
}
fn mouse_button_up_event(&mut self, button: MouseButton, x: f32, y: f32) {
let mut scene_graph = self.scene_graph.lock().unwrap();
let mouse = scene_graph.lookup_node_mut("/window/input/mouse").unwrap();
mouse.set_property_u32("button", button.to_u8() as u32).unwrap();
mouse.set_property_f32("click_x", x).unwrap();
mouse.set_property_f32("click_y", y).unwrap();
//mouse.set_property_u32("button", button.to_u8() as u32).unwrap();
//mouse.set_property_f32("click_x", x).unwrap();
//mouse.set_property_f32("click_y", y).unwrap();
mouse.trigger("button_up").unwrap();
}
fn resize_event(&mut self, width: f32, height: f32) {
let mut scene_graph = self.scene_graph.lock().unwrap();
let win = scene_graph.lookup_node_mut("/window").unwrap();
win.set_property_f32("width", width).unwrap();
win.set_property_f32("height", height).unwrap();
//win.set_property_f32("width", width).unwrap();
//win.set_property_f32("height", height).unwrap();
win.trigger("resize").unwrap();
}
}

View File

@@ -14,6 +14,8 @@ use net::ZeroMQAdapter;
mod scene;
use scene::{SceneGraph, SceneGraphPtr};
mod prop;
mod shader;
#[macro_use]
@@ -31,6 +33,8 @@ fn init_zmq(scene_graph: SceneGraphPtr) {
fn main() {
let scene_graph = Arc::new(Mutex::new(SceneGraph::new()));
init_zmq(scene_graph.clone());
init_gui(scene_graph);
//init_zmq(scene_graph.clone());
//init_gui(scene_graph);
let mut zmq_rpc = ZeroMQAdapter::new(scene_graph);
zmq_rpc.poll();
}

View File

@@ -1,4 +1,4 @@
use darkfi_serial::{deserialize, Decodable, Encodable, SerialDecodable};
use darkfi_serial::{deserialize, Decodable, Encodable, SerialDecodable, VarInt};
use std::{
io::Cursor,
sync::{atomic::Ordering, mpsc},
@@ -7,7 +7,8 @@ use std::{
use crate::{
error::{Error, Result},
scene::{PropertyType, PropertyValue, SceneGraphPtr, SceneNodeId, SceneNodeType, Slot, SlotId},
prop::{Property, PropertySubType, PropertyType, PropertyValue},
scene::{SceneGraphPtr, SceneNodeId, SceneNodeType, Slot, SlotId},
};
#[derive(Debug, SerialDecodable)]
@@ -26,8 +27,8 @@ enum Command {
GetChildren = 4,
GetParents = 5,
GetProperties = 3,
GetProperty = 6,
SetProperty = 7,
GetPropertyValue = 6,
SetPropertyValue = 7,
GetSignals = 14,
RegisterSlot = 15,
UnregisterSlot = 16,
@@ -38,6 +39,14 @@ enum Command {
CallMethod = 22,
}
// Missing calls todo:
// GetPropLen
// UnsetProperty
// SetPropertyNull
// PropertyPushNull
// PropertyPush
// PropertyIsUnset
pub struct ZeroMQAdapter {
// req-reply commands
req_socket: zmq::Socket,
@@ -156,52 +165,103 @@ impl ZeroMQAdapter {
debug!(target: "req", "{:?}({})", cmd, node_id);
let node = scene_graph.get_node(node_id).ok_or(Error::NodeNotFound)?;
let mut props = vec![];
//let mut props = vec![];
for prop in &node.props {
props.push((prop.name.clone(), prop.get_type() as u8));
//props.push((prop.name.clone(), prop.get_type() as u8));
}
props.encode(&mut reply).unwrap();
//props.encode(&mut reply).unwrap();
}
Command::GetProperty => {
Command::GetPropertyValue => {
let node_id = SceneNodeId::decode(&mut cur).unwrap();
let prop_name = String::decode(&mut cur).unwrap();
debug!(target: "req", "{:?}({}, {})", cmd, node_id, prop_name);
let node = scene_graph.get_node(node_id).ok_or(Error::NodeNotFound)?;
let prop = node.get_property(&prop_name).ok_or(Error::PropertyNotFound)?;
match &prop.val {
PropertyValue::Null => {
0u8.encode(&mut reply).unwrap();
prop.typ.encode(&mut reply).unwrap();
VarInt(prop.get_len() as u64).encode(&mut reply).unwrap();
match prop.typ {
PropertyType::Null => {}
PropertyType::Bool => {
for i in 0..prop.get_len() {
match prop.get_bool_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::Buffer(_) => {
1u8.encode(&mut reply).unwrap();
PropertyType::Uint32 => {
for i in 0..prop.get_len() {
match prop.get_u32_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::Bool(val) => {
3u8.encode(&mut reply).unwrap();
let val = val.load(Ordering::SeqCst);
val.encode(&mut reply).unwrap();
PropertyType::Float32 => {
for i in 0..prop.get_len() {
match prop.get_f32_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::Uint32(val) => {
2u8.encode(&mut reply).unwrap();
let val = val.load(Ordering::SeqCst);
val.encode(&mut reply).unwrap();
PropertyType::Str => {
for i in 0..prop.get_len() {
match prop.get_str_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::Float32(val) => {
4u8.encode(&mut reply).unwrap();
let val = val.load(Ordering::SeqCst);
val.encode(&mut reply).unwrap();
PropertyType::Enum => {
for i in 0..prop.get_len() {
match prop.get_enum_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::Str(val) => {
5u8.encode(&mut reply).unwrap();
let val = val.lock().unwrap();
val.encode(&mut reply).unwrap();
PropertyType::Buffer => {}
PropertyType::SceneNodeId => {
for i in 0..prop.get_len() {
match prop.get_node_id_opt(i).unwrap() {
Some(v) => {
true.encode(&mut reply).unwrap();
v.encode(&mut reply).unwrap();
}
None => {
false.encode(&mut reply).unwrap();
}
}
}
}
PropertyValue::SceneNodeId(val) => {
6u8.encode(&mut reply).unwrap();
let val = val.load(Ordering::SeqCst);
val.encode(&mut reply).unwrap();
}
};
}
}
Command::AddNode => {
let node_name = String::decode(&mut cur).unwrap();
@@ -236,10 +296,90 @@ impl ZeroMQAdapter {
let node_id = SceneNodeId::decode(&mut cur).unwrap();
let prop_name = String::decode(&mut cur).unwrap();
let prop_type = PropertyType::decode(&mut cur).unwrap();
debug!(target: "req", "{:?}({}, {}, {:?})", cmd, node_id, prop_name, prop_type);
let prop_subtype = PropertySubType::decode(&mut cur).unwrap();
debug!(target: "req", "{:?}({}, {}, {:?}, {:?}, ...)", cmd, node_id, prop_name, prop_type, prop_subtype);
let mut prop = Property::new(prop_name, prop_type, prop_subtype);
let prop_array_len = u32::decode(&mut cur).unwrap();
prop.set_array_len(prop_array_len as usize);
let prop_defaults_is_some = bool::decode(&mut cur).unwrap();
if prop_defaults_is_some {
let prop_defaults_len = VarInt::decode(&mut cur).unwrap();
match prop_type {
PropertyType::Uint32 => {
let mut prop_defaults = vec![];
for _ in 0..prop_defaults_len.0 {
prop_defaults.push(u32::decode(&mut cur).unwrap());
}
prop.set_defaults_u32(prop_defaults)?;
}
PropertyType::Float32 => {
let mut prop_defaults = vec![];
for _ in 0..prop_defaults_len.0 {
prop_defaults.push(f32::decode(&mut cur).unwrap());
}
prop.set_defaults_f32(prop_defaults)?;
}
_ => return Err(Error::PropertyWrongType),
}
}
let prop_ui_name = String::decode(&mut cur).unwrap();
let prop_desc = String::decode(&mut cur).unwrap();
let prop_is_null_allowed = bool::decode(&mut cur).unwrap();
match prop_type {
PropertyType::Uint32 => {
let min_is_some = bool::decode(&mut cur).unwrap();
let min = if min_is_some {
let min = u32::decode(&mut cur).unwrap();
Some(PropertyValue::Uint32(min))
} else {
None
};
let max_is_some = bool::decode(&mut cur).unwrap();
let max = if max_is_some {
let max = u32::decode(&mut cur).unwrap();
Some(PropertyValue::Uint32(max))
} else {
None
};
prop.min_val = min;
prop.max_val = max;
}
PropertyType::Float32 => {
let min_is_some = bool::decode(&mut cur).unwrap();
let min = if min_is_some {
let min = f32::decode(&mut cur).unwrap();
Some(PropertyValue::Float32(min))
} else {
None
};
let max_is_some = bool::decode(&mut cur).unwrap();
let max = if max_is_some {
let max = f32::decode(&mut cur).unwrap();
Some(PropertyValue::Float32(max))
} else {
None
};
prop.min_val = min;
prop.max_val = max;
}
_ => return Err(Error::PropertyWrongType),
}
let prop_enum_items = Vec::<String>::decode(&mut cur).unwrap();
let node = scene_graph.get_node_mut(node_id).ok_or(Error::NodeNotFound)?;
node.add_property(prop_name, prop_type)?;
prop.set_ui_text(prop_ui_name, prop_desc);
prop.is_null_allowed = prop_is_null_allowed;
if !prop_enum_items.is_empty() {
prop.set_enum_items(prop_enum_items)?;
}
node.add_property(prop)?;
}
Command::LinkNode => {
let child_id = SceneNodeId::decode(&mut cur).unwrap();
@@ -253,39 +393,40 @@ impl ZeroMQAdapter {
debug!(target: "req", "{:?}({}, {})", cmd, child_id, parent_id);
scene_graph.unlink(child_id, parent_id)?;
}
Command::SetProperty => {
Command::SetPropertyValue => {
let node_id = SceneNodeId::decode(&mut cur).unwrap();
let prop_name = String::decode(&mut cur).unwrap();
let prop_i = u32::decode(&mut cur).unwrap() as usize;
debug!(target: "req", "{:?}({}, {})", cmd, node_id, prop_name);
let node = scene_graph.get_node_mut(node_id).ok_or(Error::NodeNotFound)?;
let prop = node.get_property(&prop_name).ok_or(Error::PropertyNotFound)?;
match prop.get_type() {
match prop.typ {
PropertyType::Null => {}
PropertyType::Buffer => {
let val = Vec::<u8>::decode(&mut cur).unwrap();
prop.set_buf(val)?;
}
PropertyType::Bool => {
let val = bool::decode(&mut cur).unwrap();
prop.set_bool(val)?;
prop.set_bool(prop_i, val)?;
}
PropertyType::Uint32 => {
let val = u32::decode(&mut cur).unwrap();
prop.set_u32(val)?;
prop.set_u32(prop_i, val)?;
}
PropertyType::Float32 => {
let val = f32::decode(&mut cur).unwrap();
prop.set_f32(val)?;
prop.set_f32(prop_i, val)?;
}
PropertyType::Str => {
PropertyType::Str | PropertyType::Enum => {
let val = String::decode(&mut cur).unwrap();
prop.set_str(val)?;
prop.set_str(prop_i, val)?;
}
PropertyType::Buffer => {
let val = Vec::<u8>::decode(&mut cur).unwrap();
prop.set_buf(prop_i, val)?;
}
PropertyType::SceneNodeId => {
let val = SceneNodeId::decode(&mut cur).unwrap();
prop.set_node_id(val)?;
prop.set_node_id(prop_i, val)?;
}
}
}

574
bin/darkwallet/src/prop.rs Normal file
View File

@@ -0,0 +1,574 @@
use crate::error::{Error, Result};
use atomic_float::AtomicF32;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use std::{
fmt,
str::FromStr,
sync::{
atomic::{AtomicBool, AtomicU32, Ordering},
Arc, Mutex, MutexGuard,
},
};
use crate::scene::SceneNodeId;
type BufferGuard<'a> = MutexGuard<'a, Vec<u8>>;
type Buffer = Arc<Vec<u8>>;
#[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
#[repr(u8)]
pub enum PropertyType {
Null = 0,
Bool = 1,
Uint32 = 2,
Float32 = 3,
Str = 4,
Enum = 5,
Buffer = 6,
SceneNodeId = 7,
}
impl PropertyType {
fn default_value(&self) -> PropertyValue {
match self {
Self::Null => PropertyValue::Null,
Self::Bool => PropertyValue::Bool(false),
Self::Uint32 => PropertyValue::Uint32(0),
Self::Float32 => PropertyValue::Float32(0.),
Self::Str => PropertyValue::Str(String::new()),
Self::Enum => PropertyValue::Enum(String::new()),
Self::Buffer => PropertyValue::Buffer(Arc::new(vec![])),
Self::SceneNodeId => PropertyValue::SceneNodeId(0),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
#[repr(u8)]
pub enum PropertySubType {
Null = 0,
Color = 1,
// Size of something in pixels
Pixel = 2,
}
#[derive(Debug, Clone)]
pub enum PropertyValue {
Unset,
Null,
Bool(bool),
Uint32(u32),
Float32(f32),
Str(String),
Enum(String),
Buffer(Arc<Vec<u8>>),
SceneNodeId(SceneNodeId),
}
impl PropertyValue {
fn as_type(&self) -> PropertyType {
match self {
Self::Unset => todo!("not sure"),
Self::Null => PropertyType::Null,
Self::Bool(_) => PropertyType::Bool,
Self::Uint32(_) => PropertyType::Uint32,
Self::Float32(_) => PropertyType::Float32,
Self::Str(_) => PropertyType::Str,
Self::Enum(_) => PropertyType::Enum,
Self::Buffer(_) => PropertyType::Buffer,
Self::SceneNodeId(_) => PropertyType::SceneNodeId,
}
}
fn is_unset(&self) -> bool {
match self {
Self::Unset => true,
_ => false,
}
}
fn is_null(&self) -> bool {
match self {
Self::Null => true,
_ => false,
}
}
fn as_bool(&self) -> Result<bool> {
match self {
Self::Bool(v) => Ok(*v),
_ => Err(Error::PropertyWrongType),
}
}
fn as_u32(&self) -> Result<u32> {
match self {
Self::Uint32(v) => Ok(*v),
_ => Err(Error::PropertyWrongType),
}
}
fn as_f32(&self) -> Result<f32> {
match self {
Self::Float32(v) => Ok(*v),
_ => Err(Error::PropertyWrongType),
}
}
fn as_str(&self) -> Result<String> {
match self {
Self::Str(v) => Ok(v.clone()),
_ => Err(Error::PropertyWrongType),
}
}
fn as_enum(&self) -> Result<String> {
match self {
Self::Enum(v) => Ok(v.clone()),
_ => Err(Error::PropertyWrongType),
}
}
fn as_buf(&self) -> Result<Buffer> {
match self {
Self::Buffer(v) => Ok(v.clone()),
_ => Err(Error::PropertyWrongType),
}
}
fn as_node_id(&self) -> Result<SceneNodeId> {
match self {
Self::SceneNodeId(v) => Ok(*v),
_ => Err(Error::PropertyWrongType),
}
}
}
pub struct Property {
pub name: String,
pub typ: PropertyType,
pub subtype: PropertySubType,
pub defaults: Vec<PropertyValue>,
pub vals: Mutex<Vec<PropertyValue>>,
pub ui_name: String,
pub desc: String,
pub is_null_allowed: bool,
// Use 0 for unbounded length
pub array_len: usize,
pub min_val: Option<PropertyValue>,
pub max_val: Option<PropertyValue>,
// PropertyType must be Enum
pub enum_items: Option<Vec<String>>,
}
impl Property {
pub fn new<S: Into<String>>(name: S, typ: PropertyType, subtype: PropertySubType) -> Self {
Self {
name: name.into(),
typ,
subtype,
defaults: vec![typ.default_value()],
vals: Mutex::new(vec![PropertyValue::Unset]),
ui_name: String::new(),
desc: String::new(),
is_null_allowed: false,
array_len: 1,
min_val: None,
max_val: None,
enum_items: None,
}
}
pub fn set_ui_text<S: Into<String>>(&mut self, ui_name: S, desc: S) {
self.ui_name = ui_name.into();
self.desc = desc.into();
}
pub fn set_array_len(&mut self, len: usize) {
self.array_len = len;
self.defaults.resize(len, self.typ.default_value());
self.vals.lock().unwrap().resize(len, PropertyValue::Unset);
}
pub fn set_unbounded(&mut self) {
self.set_array_len(0);
}
pub fn set_range_u32(&mut self, min: u32, max: u32) {
self.min_val = Some(PropertyValue::Uint32(min));
self.max_val = Some(PropertyValue::Uint32(max));
}
pub fn set_range_f32(&mut self, min: f32, max: f32) {
self.min_val = Some(PropertyValue::Float32(min));
self.max_val = Some(PropertyValue::Float32(max));
}
pub fn set_enum_items<S: Into<String>>(&mut self, enum_items: Vec<S>) -> Result<()> {
if self.typ != PropertyType::Enum {
return Err(Error::PropertyWrongType)
}
self.enum_items = Some(enum_items.into_iter().map(|item| item.into()).collect());
Ok(())
}
pub fn allow_null_values(&mut self) {
self.is_null_allowed = true;
}
fn check_defaults_len(&self, defaults_len: usize) -> Result<()> {
if !self.is_bounded() || defaults_len != self.array_len {
return Err(Error::PropertyWrongLen)
}
Ok(())
}
pub fn set_defaults_u32(&mut self, defaults: Vec<u32>) -> Result<()> {
self.check_defaults_len(defaults.len())?;
self.defaults = defaults.into_iter().map(|v| PropertyValue::Uint32(v)).collect();
Ok(())
}
pub fn set_defaults_f32(&mut self, defaults: Vec<f32>) -> Result<()> {
self.check_defaults_len(defaults.len())?;
self.defaults = defaults.into_iter().map(|v| PropertyValue::Float32(v)).collect();
Ok(())
}
pub fn get_len(&self) -> usize {
// Avoid locking unless we need to
// If array len is nonzero, then vals len should be the same.
if !self.is_bounded() {
return self.vals.lock().unwrap().len()
}
self.array_len
}
fn is_bounded(&self) -> bool {
self.array_len != 0
}
/// This will clear all values, resetting them to the default
pub fn clear_values(&self) {
let vals = &mut self.vals.lock().unwrap();
vals.clear();
vals.resize(self.array_len, PropertyValue::Unset);
}
// Set
fn set_raw_value(&self, i: usize, val: PropertyValue) -> Result<()> {
if self.typ != val.as_type() {
return Err(Error::PropertyWrongType)
}
let vals = &mut self.vals.lock().unwrap();
if i >= vals.len() {
return Err(Error::PropertyWrongIndex)
}
vals[i] = val;
Ok(())
}
pub fn unset(&self, i: usize) -> Result<()> {
let vals = &mut self.vals.lock().unwrap();
if i >= vals.len() {
return Err(Error::PropertyWrongIndex)
}
vals[i] = PropertyValue::Unset;
Ok(())
}
pub fn set_null(&self, i: usize) -> Result<()> {
if !self.is_null_allowed {
return Err(Error::PropertyNullNotAllowed)
}
let vals = &mut self.vals.lock().unwrap();
if i >= vals.len() {
return Err(Error::PropertyWrongIndex)
}
vals[i] = PropertyValue::Null;
Ok(())
}
pub fn set_bool(&self, i: usize, val: bool) -> Result<()> {
self.set_raw_value(i, PropertyValue::Bool(val))
}
pub fn set_u32(&self, i: usize, val: u32) -> Result<()> {
if self.min_val.is_some() {
let min = self.min_val.as_ref().unwrap().as_u32()?;
if val < min {
return Err(Error::PropertyOutOfRange);
}
}
if self.max_val.is_some() {
let max = self.max_val.as_ref().unwrap().as_u32()?;
if val > max {
return Err(Error::PropertyOutOfRange);
}
}
self.set_raw_value(i, PropertyValue::Uint32(val))
}
pub fn set_f32(&self, i: usize, val: f32) -> Result<()> {
if self.min_val.is_some() {
let min = self.min_val.as_ref().unwrap().as_f32()?;
if val < min {
return Err(Error::PropertyOutOfRange);
}
}
if self.max_val.is_some() {
let max = self.max_val.as_ref().unwrap().as_f32()?;
if val > max {
return Err(Error::PropertyOutOfRange);
}
}
self.set_raw_value(i, PropertyValue::Float32(val))
}
pub fn set_str<S: Into<String>>(&self, i: usize, val: S) -> Result<()> {
self.set_raw_value(i, PropertyValue::Str(val.into()))
}
pub fn set_enum<S: Into<String>>(&self, i: usize, val: S) -> Result<()> {
if self.typ != PropertyType::Enum {
return Err(Error::PropertyWrongType)
}
let val = val.into();
if !self.enum_items.as_ref().unwrap().contains(&val) {
return Err(Error::PropertyWrongEnumItem)
}
self.set_raw_value(i, PropertyValue::Enum(val.into()))
}
pub fn set_buf(&self, i: usize, val: Vec<u8>) -> Result<()> {
self.set_raw_value(i, PropertyValue::Buffer(Arc::new(val)))
}
pub fn set_node_id(&self, i: usize, val: SceneNodeId) -> Result<()> {
self.set_raw_value(i, PropertyValue::SceneNodeId(val))
}
// Push
pub fn push_null(&self) -> Result<usize> {
if self.is_bounded() {
return Err(Error::PropertyIsBounded)
}
let vals = &mut self.vals.lock().unwrap();
let i = vals.len();
vals.push(PropertyValue::Null);
Ok(i)
}
pub fn push_bool(&self, val: bool) -> Result<usize> {
let i = self.push_null()?;
self.set_bool(i, val)?;
Ok(i)
}
pub fn push_u32(&self, val: u32) -> Result<usize> {
let i = self.push_null()?;
self.set_u32(i, val)?;
Ok(i)
}
pub fn push_f32(&self, val: f32) -> Result<usize> {
let i = self.push_null()?;
self.set_f32(i, val)?;
Ok(i)
}
pub fn push_str<S: Into<String>>(&self, val: S) -> Result<usize> {
let i = self.push_null()?;
self.set_str(i, val)?;
Ok(i)
}
pub fn push_enum<S: Into<String>>(&self, val: S) -> Result<usize> {
let i = self.push_null()?;
self.set_enum(i, val)?;
Ok(i)
}
pub fn push_buf(&self, val: Vec<u8>) -> Result<usize> {
let i = self.push_null()?;
self.set_buf(i, val)?;
Ok(i)
}
pub fn push_node_id(&self, val: SceneNodeId) -> Result<usize> {
let i = self.push_null()?;
self.set_node_id(i, val)?;
Ok(i)
}
// Get
pub fn is_unset(&self, i: usize) -> Result<bool> {
let val = self.get_raw_value(i)?;
Ok(val.is_unset())
}
pub fn get_raw_value(&self, i: usize) -> Result<PropertyValue> {
let vals = &self.vals.lock().unwrap();
if self.is_bounded() {
assert_eq!(vals.len(), self.array_len);
}
if i >= vals.len() {
return Err(Error::PropertyWrongIndex)
}
Ok(vals[i].clone())
}
pub fn get_value(&self, i: usize) -> Result<PropertyValue> {
let val = self.get_raw_value(i)?;
if val.is_unset() {
return Ok(self.defaults[i].clone())
}
Ok(val)
}
pub fn get_bool(&self, i: usize) -> Result<bool> {
self.get_value(i)?.as_bool()
}
pub fn get_bool_opt(&self, i: usize) -> Result<Option<bool>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_bool()?))
}
pub fn get_u32(&self, i: usize) -> Result<u32> {
self.get_value(i)?.as_u32()
}
pub fn get_u32_opt(&self, i: usize) -> Result<Option<u32>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_u32()?))
}
pub fn get_f32(&self, i: usize) -> Result<f32> {
self.get_value(i)?.as_f32()
}
pub fn get_f32_opt(&self, i: usize) -> Result<Option<f32>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_f32()?))
}
pub fn get_str(&self, i: usize) -> Result<String> {
self.get_value(i)?.as_str()
}
pub fn get_str_opt(&self, i: usize) -> Result<Option<String>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_str()?))
}
pub fn get_enum(&self, i: usize) -> Result<String> {
self.get_value(i)?.as_enum()
}
pub fn get_enum_opt(&self, i: usize) -> Result<Option<String>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_enum()?))
}
pub fn get_buf(&self, i: usize) -> Result<Buffer> {
self.get_value(i)?.as_buf()
}
pub fn get_buf_opt(&self, i: usize) -> Result<Option<Buffer>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_buf()?))
}
pub fn get_node_id(&self, i: usize) -> Result<SceneNodeId> {
self.get_value(i)?.as_node_id()
}
pub fn get_node_id_opt(&self, i: usize) -> Result<Option<SceneNodeId>> {
let val = self.get_value(i)?;
if val.is_null() {
return Ok(None)
}
Ok(Some(val.as_node_id()?))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_getset() {
let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
assert!(prop.set_f32(1, 4.).is_err());
assert!(prop.is_unset(0).unwrap());
assert!(prop.set_f32(0, 4.).is_ok());
assert_eq!(prop.get_f32(0).unwrap(), 4.);
assert!(!prop.is_unset(0).unwrap());
prop.unset(0).unwrap();
assert!(prop.is_unset(0).unwrap());
assert_eq!(prop.get_f32(0).unwrap(), 0.);
}
#[test]
fn test_nullable() {
// default len is 1
let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
assert!(prop.set_defaults_f32(vec![1.0, 0.0]).is_err());
assert!(prop.set_defaults_f32(vec![2.0]).is_ok());
prop.allow_null_values();
prop.set_null(0).unwrap();
assert!(prop.get_f32_opt(1).is_err());
assert!(prop.get_f32_opt(0).is_ok());
assert!(prop.get_f32_opt(0).unwrap().is_none());
prop.clear_values();
assert!(prop.get_f32(0).is_ok());
assert!(prop.get_f32_opt(0).unwrap().is_some());
assert_eq!(prop.get_f32(0).unwrap(), 2.0);
}
#[test]
fn test_nonnullable() {
let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
assert!(prop.set_null(0).is_err());
assert!(prop.is_unset(0).unwrap());
}
#[test]
fn test_unbounded() {
let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
prop.set_unbounded();
assert_eq!(prop.get_len(), 0);
prop.push_f32(2.0).unwrap();
prop.push_f32(3.0).unwrap();
assert_eq!(prop.get_len(), 2);
prop.clear_values();
assert_eq!(prop.get_len(), 0);
prop.allow_null_values();
prop.push_null().unwrap();
prop.push_f32(4.0).unwrap();
prop.push_f32(5.0).unwrap();
assert_eq!(prop.get_len(), 3);
assert!(prop.get_f32_opt(0).unwrap().is_none());
assert!(prop.get_f32_opt(1).unwrap().is_some());
assert!(prop.get_f32_opt(2).unwrap().is_some());
assert!(prop.get_f32_opt(3).is_err());
let mut prop2 = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
assert!(prop2.push_f32(4.0).is_err());
}
#[test]
fn test_range() {
let mut prop = Property::new("foo", PropertyType::Float32, PropertySubType::Null);
let half_pi = 3.1415926535 / 2.;
prop.set_range_f32(-half_pi, half_pi);
assert!(prop.set_f32(0, 6.).is_err());
assert!(prop.set_f32(0, 1.).is_ok());
}
#[test]
fn test_enum() {
let mut prop = Property::new("foo", PropertyType::Enum, PropertySubType::Null);
prop.set_enum_items(vec!["ABC", "XYZ", "FOO"]).unwrap();
assert!(prop.set_enum(0, "ABC").is_ok());
assert!(prop.set_enum(0, "BAR").is_err());
}
}

View File

@@ -1,4 +1,3 @@
use crate::error::{Error, Result};
use atomic_float::AtomicF32;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use std::{
@@ -10,6 +9,11 @@ use std::{
},
};
use crate::{
error::{Error, Result},
prop::{Property, PropertyType},
};
pub struct ScenePath(Vec<String>);
impl<S: Into<String>> From<S> for ScenePath {
@@ -397,43 +401,11 @@ impl SceneNode {
.map(|child_inf| scene_graph.get_node(child_inf.id).unwrap())
}
pub fn add_property<S: Into<String>>(
&mut self,
name: S,
typ: PropertyType,
) -> Result<Arc<Property>> {
let name = name.into();
if self.has_property(&name) {
pub fn add_property(&mut self, prop: Property) -> Result<()> {
if self.has_property(&prop.name) {
return Err(Error::PropertyAlreadyExists);
}
let prop = Property::new(name, typ);
self.props.push(prop.clone());
Ok(prop)
}
// Convenience methods
pub fn add_property_buf(&mut self, name: &str, val: Vec<u8>) -> Result<()> {
self.add_property(name, PropertyType::Buffer)?.set_buf(val)?;
Ok(())
}
pub fn add_property_bool(&mut self, name: &str, val: bool) -> Result<()> {
self.add_property(name, PropertyType::Bool)?.set_bool(val)?;
Ok(())
}
pub fn add_property_u32(&mut self, name: &str, val: u32) -> Result<()> {
self.add_property(name, PropertyType::Uint32)?.set_u32(val)?;
Ok(())
}
pub fn add_property_f32(&mut self, name: &str, val: f32) -> Result<()> {
self.add_property(name, PropertyType::Float32)?.set_f32(val)?;
Ok(())
}
pub fn add_property_str<S: Into<String>>(&mut self, name: &str, val: S) -> Result<()> {
self.add_property(name, PropertyType::Str)?.set_str(val)?;
Ok(())
}
pub fn add_property_node_id(&mut self, name: &str, val: SceneNodeId) -> Result<()> {
self.add_property(name, PropertyType::SceneNodeId)?.set_node_id(val)?;
self.props.push(Arc::new(prop));
Ok(())
}
@@ -447,43 +419,51 @@ impl SceneNode {
// Convenience methods
pub fn get_property_bool(&self, name: &str) -> Result<bool> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_bool()
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_bool(0)
}
pub fn get_property_u32(&self, name: &str) -> Result<u32> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_u32()
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_u32(0)
}
pub fn get_property_f32(&self, name: &str) -> Result<f32> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_f32()
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_f32(0)
}
pub fn get_property_str(&self, name: &str) -> Result<String> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_str()
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_str(0)
}
pub fn get_property_node_id(&self, name: &str) -> Result<SceneNodeId> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_node_id()
}
// Setters
pub fn set_property_bool(&self, name: &str, val: bool) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_bool(val)
}
pub fn set_property_u32(&self, name: &str, val: u32) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_u32(val)
}
pub fn set_property_f32(&self, name: &str, val: f32) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_f32(val)
}
pub fn set_property_str<S: Into<String>>(&self, name: &str, val: S) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_str(val)
}
pub fn set_property_node_id(&self, name: &str, val: SceneNodeId) -> Result<()> {
self.get_property(name).ok_or(Error::PropertyNotFound)?.set_node_id(val)
self.get_property(name).ok_or(Error::PropertyNotFound)?.get_node_id(0)
}
//// Setters
//pub fn set_property_bool(&self, name: &str, val: bool) -> Result<()> {
// self.get_property(name).ok_or(Error::PropertyNotFound)?.set_bool(val)
//}
//pub fn set_property_u32(&self, name: &str, val: u32) -> Result<()> {
// self.get_property(name).ok_or(Error::PropertyNotFound)?.set_u32(val)
//}
//pub fn set_property_f32(&self, name: &str, val: f32) -> Result<()> {
// self.get_property(name).ok_or(Error::PropertyNotFound)?.set_f32(val)
//}
//pub fn set_property_str<S: Into<String>>(&self, name: &str, val: S) -> Result<()> {
// self.get_property(name).ok_or(Error::PropertyNotFound)?.set_str(val)
//}
//pub fn set_property_node_id(&self, name: &str, val: SceneNodeId) -> Result<()> {
// self.get_property(name).ok_or(Error::PropertyNotFound)?.set_node_id(val)
//}
pub fn add_signal<S: Into<String>>(&mut self, name: S) -> Result<()> {
pub fn add_signal<S: Into<String>>(
&mut self,
name: S,
fmt: Vec<(S, S, PropertyType)>,
) -> Result<()> {
let name = name.into();
if self.has_signal(&name) {
return Err(Error::SignalAlreadyExists);
}
self.sigs.push(Signal { name: name.into(), slots: vec![], freed: vec![] });
let fmt = fmt
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
self.sigs.push(Signal { name: name.into(), fmt, slots: vec![], freed: vec![] });
Ok(())
}
@@ -530,12 +510,23 @@ impl SceneNode {
pub fn add_method<S: Into<String>>(
&mut self,
name: S,
args: Vec<(S, PropertyType)>,
result: Vec<(S, PropertyType)>,
) {
let args = args.into_iter().map(|(s, p)| (s.into(), p)).collect();
let result = result.into_iter().map(|(s, p)| (s.into(), p)).collect();
self.methods.push(Method { name: name.into(), args, result, queue: vec![] })
args: Vec<(S, S, PropertyType)>,
result: Vec<(S, S, PropertyType)>,
) -> Result<()> {
let name = name.into();
if self.has_signal(&name) {
return Err(Error::MethodAlreadyExists);
}
let args = args
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
let result = result
.into_iter()
.map(|(n, d, t)| CallArg { name: n.into(), desc: d.into(), typ: t })
.collect();
self.methods.push(Method { name: name.into(), args, result, queue: vec![] });
Ok(())
}
pub fn get_method(&self, name: &str) -> Option<&Method> {
@@ -557,165 +548,11 @@ impl SceneNode {
}
}
type BufferGuard<'a> = MutexGuard<'a, Vec<u8>>;
#[derive(Debug, Copy, Clone, PartialEq, SerialEncodable, SerialDecodable)]
#[repr(u8)]
pub enum PropertyType {
Null = 0,
Buffer = 1,
Bool = 2,
Uint32 = 3,
Float32 = 4,
Str = 5,
SceneNodeId = 6,
}
pub enum PropertyValue {
Null,
Buffer(Mutex<Vec<u8>>),
Bool(AtomicBool),
Uint32(AtomicU32),
Float32(AtomicF32),
Str(Mutex<String>),
SceneNodeId(AtomicU32),
}
pub struct Property {
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
pub struct CallArg {
pub name: String,
//typ: PropertyType,
pub val: PropertyValue,
}
impl Property {
fn new(name: String, typ: PropertyType) -> Arc<Self> {
let val = match typ {
PropertyType::Null => PropertyValue::Null,
PropertyType::Buffer => PropertyValue::Buffer(Mutex::new(Vec::new())),
PropertyType::Bool => PropertyValue::Bool(AtomicBool::new(false)),
PropertyType::Uint32 => PropertyValue::Uint32(AtomicU32::new(0)),
PropertyType::Float32 => PropertyValue::Float32(AtomicF32::new(0.)),
PropertyType::Str => PropertyValue::Str(Mutex::new(String::new())),
PropertyType::SceneNodeId => PropertyValue::SceneNodeId(AtomicU32::new(0)),
};
Arc::new(Self { name, val })
}
pub fn get_type(&self) -> PropertyType {
match self.val {
PropertyValue::Null => PropertyType::Null,
PropertyValue::Buffer(_) => PropertyType::Buffer,
PropertyValue::Bool(_) => PropertyType::Bool,
PropertyValue::Uint32(_) => PropertyType::Uint32,
PropertyValue::Float32(_) => PropertyType::Float32,
PropertyValue::Str(_) => PropertyType::Str,
PropertyValue::SceneNodeId(_) => PropertyType::SceneNodeId,
}
}
pub fn get_buf<'a>(&'a self) -> Result<BufferGuard<'a>> {
match &self.val {
PropertyValue::Buffer(propval) => Ok(propval.lock().unwrap()),
_ => Err(Error::PropertyWrongType),
}
}
pub fn get_bool(&self) -> Result<bool> {
match &self.val {
PropertyValue::Bool(propval) => Ok(propval.load(Ordering::SeqCst)),
_ => Err(Error::PropertyWrongType),
}
}
pub fn get_u32(&self) -> Result<u32> {
match &self.val {
PropertyValue::Uint32(propval) => Ok(propval.load(Ordering::SeqCst)),
_ => Err(Error::PropertyWrongType),
}
}
pub fn get_f32(&self) -> Result<f32> {
match &self.val {
PropertyValue::Float32(propval) => Ok(propval.load(Ordering::SeqCst)),
_ => Err(Error::PropertyWrongType),
}
}
pub fn get_str(&self) -> Result<String> {
match &self.val {
PropertyValue::Str(propval) => Ok(propval.lock().unwrap().clone()),
_ => Err(Error::PropertyWrongType),
}
}
pub fn get_node_id(&self) -> Result<SceneNodeId> {
match &self.val {
PropertyValue::SceneNodeId(propval) => Ok(propval.load(Ordering::SeqCst)),
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_buf(&self, val: Vec<u8>) -> Result<()> {
match &self.val {
PropertyValue::Buffer(propval) => {
let mut buf = propval.lock().unwrap();
let _ = std::mem::replace(&mut *buf, val);
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_bool(&self, val: bool) -> Result<()> {
match &self.val {
PropertyValue::Bool(propval) => {
propval.store(val, Ordering::SeqCst);
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_u32(&self, val: u32) -> Result<()> {
match &self.val {
PropertyValue::Uint32(propval) => {
propval.store(val, Ordering::SeqCst);
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_f32(&self, val: f32) -> Result<()> {
match &self.val {
PropertyValue::Float32(propval) => {
propval.store(val, Ordering::SeqCst);
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_str<S: Into<String>>(&self, val: S) -> Result<()> {
match &self.val {
PropertyValue::Str(propval) => {
let mut pv = propval.lock().unwrap();
*pv = val.into();
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub fn set_node_id(&self, val: SceneNodeId) -> Result<()> {
match &self.val {
PropertyValue::SceneNodeId(propval) => {
propval.store(val, Ordering::SeqCst);
Ok(())
}
_ => Err(Error::PropertyWrongType),
}
}
pub desc: String,
pub typ: PropertyType,
}
type SlotFn = Box<dyn Fn() + Send>;
@@ -734,6 +571,7 @@ impl Slot {
pub struct Signal {
pub name: String,
pub fmt: Vec<CallArg>,
slots: Vec<Slot>,
freed: Vec<SlotId>,
}
@@ -768,7 +606,7 @@ type MethodResponseFn = Box<dyn Fn(Result<Vec<u8>>) + Send>;
pub struct Method {
pub name: String,
pub args: Vec<(String, PropertyType)>,
pub result: Vec<(String, PropertyType)>,
pub args: Vec<CallArg>,
pub result: Vec<CallArg>,
pub queue: Vec<(Vec<u8>, MethodResponseFn)>,
}