extends RefCounted class_name GDB_Entity var _title := "" var _title_property : Object = null var _properties := [].duplicate() var _property_ids := [].duplicate() class _CommonWrapperProperty extends GDB_Property: func _init(val, sig : Signal = Signal(), flags := 0): super.set_type(typeof(val)) super.set_value(val) super.set_flags(flags) if !sig.is_null(): sig.connect(self._on_object_value_changed) func _on_object_value_changed(p0 = null, p1 = null, p2 = null, p3 = null) -> void: _value = self.get_value() value_changed.emit() class _WrapperProperty extends _CommonWrapperProperty: var object : WeakRef var member : String func _init(object_ : Object, member_ : String, sig : Signal, flags : int): super(object_.get(member), sig, flags) self.object = object_ self.member = member_ super.set_name(member_.capitalize()) func get_value(): var obj : Object = self.object.get_ref() if obj: return obj.get(self.member) return super.get_value() func set_value(value) -> void: var obj : Object = self.object.get_ref() if obj: obj.set(self.member, value) super.set_value(obj.get(self.member)) else: super.set_value(value) class _ArrayWrapperProperty extends _WrapperProperty: func _init(object_ : Object, member_ : String, sig_added : Signal = Signal(), sig_removed : Signal = Signal(), flags := 0): super(object_, member_, Signal(), flags) if !sig_added.is_null(): sig_added.connect(self._on_object_value_added) if !sig_removed.is_null(): sig_removed.connect(self._on_object_value_removed) func _on_object_value_added(value, p0 = null, p1 = null, p2 = null, p3 = null) -> void: var obj : Object = self.object.get_ref() if obj: _value = obj.get(self.member) value_changed.emit() value_added.emit(value) func _on_object_value_removed(value, p0 = null, p1 = null, p2 = null, p3 = null) -> void: var obj : Object = self.object.get_ref() if obj: _value = obj.get(self.member) value_changed.emit() value_removed.emit(value) class _GetSetWrapperProperty extends _CommonWrapperProperty: var getter := Callable() var setter := Callable() func _init(getter_ : Callable, setter_ := Callable(), sig : Signal = Signal(), flags := 0): super(getter_.call(), sig, flags) self.getter = getter_ self.setter = setter_ func get_value(): var obj : Object = self.object.get_ref() if obj: return self.getter.call() return super.get_value() func set_value(value) -> void: if self.setter.is_null(): return var obj : Object = self.object.get_ref() if obj: self.setter.call(value) super.set_value(self.getter.call()) else: super.set_value(value) ################ # public stuff # ################ func get_title() -> String: return _title func set_title(title : String) -> void: if _title_property: # title and title_property are mutually exclusive GDBUtility.disconnect_all(_title_property, self) _title_property = null __set_title(title) func set_title_property(property : Object) -> void: if property.get_type() != TYPE_STRING: printerr("Title property must be string.") return if _title_property == property: return if _title_property: GDBUtility.disconnect_all(_title_property, self) _title_property = property var new_title := "" if _title_property: new_title = _title_property.get_value() GDBUtility.try_connect(_title_property, "value_changed", self, "_on_title_property_value_changed") __set_title(new_title) func get_properties() -> Array: return _properties func get_property_ids() -> Array: return _property_ids func get_property(index : int) -> Object: if index < 0 || index >= _properties.size(): return null return _properties[index] func get_property_id(index : int) -> String: if index < 0 || index >= _property_ids.size(): return "" return _property_ids[index] func get_property_by_id(id : String) -> Object: return get_property(find_property_by_id(id)) func add_property(id : String, property : Object, index := -1) -> void: if !GDB_Property.is_valid_property(property): printerr("GDB_Entity: attempted to add invalid property.") return if find_property(property) >= 0: return if find_property_by_id(id) >= 0: printerr("GDB_Entity: duplicate property id") return if index < 0: index = _properties.size() index = min(index, _properties.size()) _properties.insert(index, property) _property_ids.insert(index, id) property_added.emit(index) func remove_property(property : Object) -> bool: var index := find_property(property) if index < 0: return false _properties.remove(index) _property_ids.remove(index) property_removed.emit(index, property) return true func remove_property_at(index : int) -> bool: if index < 0 || index >= _properties.size(): return false return remove_property(_properties[index]) func find_property(property : Object) -> int: return _properties.find(property) func find_property_by_id(id : String) -> int: return _property_ids.find(id) ################# # private stuff # ################# func __set_title(title : String) -> void: if title != _title: _title = title entity_title_changed.emit() ################ # static stuff # ################ static func is_valid_entity(object : Object) -> bool: return object != null \ && object.has_method("get_properties") static func make_property(object : Object, member : String, sig := Signal(), flags := 0) -> GDB_Property: return _WrapperProperty.new(object, member, sig, flags) static func make_getset_property(getter : Callable, setter := Callable(), sig := Signal(), flags := 0) -> GDB_Property: return _GetSetWrapperProperty.new(getter, setter, sig, flags) static func make_array_property(object : Object, member : String, sig_added := Signal(), sig_removed := Signal(), array_type := TYPE_NIL, flags := 0) -> GDB_Property: var prop := _ArrayWrapperProperty.new(object, member, sig_added, sig_removed, flags) prop.set_content_type(array_type) return prop static func make_entity_title_property(entity : Object) -> Object: var property : Object if entity.has_method("get_title_property"): property = entity.get_title_property() if property: return property if entity.get("title") is String: var sig := Signal() if entity.has_signal("title_changed"): sig = entity.title_changed return make_property(entity, "title", sig) if entity.has_method("get_title"): var setter := Callable() var sig := Signal() var flags := 0 if entity.has_method("set_title"): setter = entity.set_title else: flags |= GDB_Property.FLAG_READONLY if entity.has_signal("title_changed"): sig = entity.title_changed return make_getset_property(entity.get_title, setter, sig, flags) return null static func get_entity_property_ids(entity : Object) -> Array: return __get_entity_optional(entity, "property_ids", []) ################# # private stuff # ################# static func __get_entity_optional(entity : Object, name : String, default = null): return GDB_Property.__get_prop_optional(entity, name, default) # why write this twice? ############ # handlers # ############ func _on_title_property_value_changed() -> void: if !_title_property: # should exist return __set_title(_title_property.get_value()) ########### # signals # ########### signal entity_title_changed() signal property_added(index) signal property_removed(index, property)