From 2f580977871f1dc1110e2414ce8fb50b74e240cb Mon Sep 17 00:00:00 2001 From: rsx Date: Mon, 6 May 2024 16:48:36 +0200 Subject: [PATCH] wallet: make a more powerful property system --- bin/darkwallet/gui/__init__.py | 124 ++++++- bin/darkwallet/gui/api.py | 6 +- bin/darkwallet/gui/print_tree.py | 22 +- bin/darkwallet/pydrk/__init__.py | 4 +- bin/darkwallet/pydrk/api.py | 304 +++++++++++----- bin/darkwallet/pydrk/exc.py | 52 ++- bin/darkwallet/src/error.rs | 59 +++- bin/darkwallet/src/gfx.rs | 207 +++++++---- bin/darkwallet/src/main.rs | 8 +- bin/darkwallet/src/net.rs | 239 ++++++++++--- bin/darkwallet/src/prop.rs | 574 +++++++++++++++++++++++++++++++ bin/darkwallet/src/scene.rs | 288 ++++------------ 12 files changed, 1394 insertions(+), 493 deletions(-) create mode 100644 bin/darkwallet/src/prop.rs diff --git a/bin/darkwallet/gui/__init__.py b/bin/darkwallet/gui/__init__.py index d63b672ba..a16691be8 100644 --- a/bin/darkwallet/gui/__init__.py +++ b/bin/darkwallet/gui/__init__.py @@ -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() diff --git a/bin/darkwallet/gui/api.py b/bin/darkwallet/gui/api.py index bfe44d316..ff17a0b22 100644 --- a/bin/darkwallet/gui/api.py +++ b/bin/darkwallet/gui/api.py @@ -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): diff --git a/bin/darkwallet/gui/print_tree.py b/bin/darkwallet/gui/print_tree.py index c03e91de4..f00a9d68c 100644 --- a/bin/darkwallet/gui/print_tree.py +++ b/bin/darkwallet/gui/print_tree.py @@ -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}") diff --git a/bin/darkwallet/pydrk/__init__.py b/bin/darkwallet/pydrk/__init__.py index 42e669804..5bdd4e4a3 100644 --- a/bin/darkwallet/pydrk/__init__.py +++ b/bin/darkwallet/pydrk/__init__.py @@ -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 diff --git a/bin/darkwallet/pydrk/api.py b/bin/darkwallet/pydrk/api.py index 7bb349dc6..a8e5e291b 100644 --- a/bin/darkwallet/pydrk/api.py +++ b/bin/darkwallet/pydrk/api.py @@ -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() diff --git a/bin/darkwallet/pydrk/exc.py b/bin/darkwallet/pydrk/exc.py index acd212168..351e2a7e8 100644 --- a/bin/darkwallet/pydrk/exc.py +++ b/bin/darkwallet/pydrk/exc.py @@ -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 diff --git a/bin/darkwallet/src/error.rs b/bin/darkwallet/src/error.rs index a3ac08ac3..de54ad68d 100644 --- a/bin/darkwallet/src/error.rs +++ b/bin/darkwallet/src/error.rs @@ -4,59 +4,80 @@ pub type Result = std::result::Result; #[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, } diff --git a/bin/darkwallet/src/gfx.rs b/bin/darkwallet/src/gfx.rs index 43faf162f..040b45efe 100644 --- a/bin/darkwallet/src/gfx.rs +++ b/bin/darkwallet/src/gfx.rs @@ -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 { 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(); } } diff --git a/bin/darkwallet/src/main.rs b/bin/darkwallet/src/main.rs index fe5222c68..8c2037674 100644 --- a/bin/darkwallet/src/main.rs +++ b/bin/darkwallet/src/main.rs @@ -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(); } diff --git a/bin/darkwallet/src/net.rs b/bin/darkwallet/src/net.rs index d1c06bf46..439eb13e5 100644 --- a/bin/darkwallet/src/net.rs +++ b/bin/darkwallet/src/net.rs @@ -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::::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::::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::::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)?; } } } diff --git a/bin/darkwallet/src/prop.rs b/bin/darkwallet/src/prop.rs new file mode 100644 index 000000000..89856a403 --- /dev/null +++ b/bin/darkwallet/src/prop.rs @@ -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>; + +type Buffer = Arc>; + +#[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>), + 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 { + match self { + Self::Bool(v) => Ok(*v), + _ => Err(Error::PropertyWrongType), + } + } + fn as_u32(&self) -> Result { + match self { + Self::Uint32(v) => Ok(*v), + _ => Err(Error::PropertyWrongType), + } + } + fn as_f32(&self) -> Result { + match self { + Self::Float32(v) => Ok(*v), + _ => Err(Error::PropertyWrongType), + } + } + fn as_str(&self) -> Result { + match self { + Self::Str(v) => Ok(v.clone()), + _ => Err(Error::PropertyWrongType), + } + } + fn as_enum(&self) -> Result { + match self { + Self::Enum(v) => Ok(v.clone()), + _ => Err(Error::PropertyWrongType), + } + } + fn as_buf(&self) -> Result { + match self { + Self::Buffer(v) => Ok(v.clone()), + _ => Err(Error::PropertyWrongType), + } + } + fn as_node_id(&self) -> Result { + 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, + pub vals: Mutex>, + + 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, + pub max_val: Option, + + // PropertyType must be Enum + pub enum_items: Option>, +} + +impl Property { + pub fn new>(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>(&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>(&mut self, enum_items: Vec) -> 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) -> 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) -> 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>(&self, i: usize, val: S) -> Result<()> { + self.set_raw_value(i, PropertyValue::Str(val.into())) + } + pub fn set_enum>(&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) -> 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 { + 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 { + let i = self.push_null()?; + self.set_bool(i, val)?; + Ok(i) + } + pub fn push_u32(&self, val: u32) -> Result { + let i = self.push_null()?; + self.set_u32(i, val)?; + Ok(i) + } + pub fn push_f32(&self, val: f32) -> Result { + let i = self.push_null()?; + self.set_f32(i, val)?; + Ok(i) + } + pub fn push_str>(&self, val: S) -> Result { + let i = self.push_null()?; + self.set_str(i, val)?; + Ok(i) + } + pub fn push_enum>(&self, val: S) -> Result { + let i = self.push_null()?; + self.set_enum(i, val)?; + Ok(i) + } + pub fn push_buf(&self, val: Vec) -> Result { + let i = self.push_null()?; + self.set_buf(i, val)?; + Ok(i) + } + pub fn push_node_id(&self, val: SceneNodeId) -> Result { + let i = self.push_null()?; + self.set_node_id(i, val)?; + Ok(i) + } + + // Get + + pub fn is_unset(&self, i: usize) -> Result { + let val = self.get_raw_value(i)?; + Ok(val.is_unset()) + } + + pub fn get_raw_value(&self, i: usize) -> Result { + 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 { + 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 { + self.get_value(i)?.as_bool() + } + pub fn get_bool_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_u32() + } + pub fn get_u32_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_f32() + } + pub fn get_f32_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_str() + } + pub fn get_str_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_enum() + } + pub fn get_enum_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_buf() + } + pub fn get_buf_opt(&self, i: usize) -> Result> { + 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 { + self.get_value(i)?.as_node_id() + } + pub fn get_node_id_opt(&self, i: usize) -> Result> { + 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()); + } +} diff --git a/bin/darkwallet/src/scene.rs b/bin/darkwallet/src/scene.rs index f42f70656..57173bbff 100644 --- a/bin/darkwallet/src/scene.rs +++ b/bin/darkwallet/src/scene.rs @@ -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); impl> From for ScenePath { @@ -397,43 +401,11 @@ impl SceneNode { .map(|child_inf| scene_graph.get_node(child_inf.id).unwrap()) } - pub fn add_property>( - &mut self, - name: S, - typ: PropertyType, - ) -> Result> { - 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) -> 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>(&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 { - 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 { - 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 { - 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 { - 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 { - 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>(&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>(&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>(&mut self, name: S) -> Result<()> { + pub fn add_signal>( + &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>( &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>; - -#[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>), - Bool(AtomicBool), - Uint32(AtomicU32), - Float32(AtomicF32), - Str(Mutex), - 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 { - 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> { - match &self.val { - PropertyValue::Buffer(propval) => Ok(propval.lock().unwrap()), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn get_bool(&self) -> Result { - match &self.val { - PropertyValue::Bool(propval) => Ok(propval.load(Ordering::SeqCst)), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn get_u32(&self) -> Result { - match &self.val { - PropertyValue::Uint32(propval) => Ok(propval.load(Ordering::SeqCst)), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn get_f32(&self) -> Result { - match &self.val { - PropertyValue::Float32(propval) => Ok(propval.load(Ordering::SeqCst)), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn get_str(&self) -> Result { - match &self.val { - PropertyValue::Str(propval) => Ok(propval.lock().unwrap().clone()), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn get_node_id(&self) -> Result { - match &self.val { - PropertyValue::SceneNodeId(propval) => Ok(propval.load(Ordering::SeqCst)), - _ => Err(Error::PropertyWrongType), - } - } - - pub fn set_buf(&self, val: Vec) -> 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>(&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; @@ -734,6 +571,7 @@ impl Slot { pub struct Signal { pub name: String, + pub fmt: Vec, slots: Vec, freed: Vec, } @@ -768,7 +606,7 @@ type MethodResponseFn = Box>) + Send>; pub struct Method { pub name: String, - pub args: Vec<(String, PropertyType)>, - pub result: Vec<(String, PropertyType)>, + pub args: Vec, + pub result: Vec, pub queue: Vec<(Vec, MethodResponseFn)>, }