diff --git a/godot/addons/collections/int_range.gd b/godot/addons/collections/int_range.gd index 2cd3166..021d90e 100644 --- a/godot/addons/collections/int_range.gd +++ b/godot/addons/collections/int_range.gd @@ -1,17 +1,26 @@ class_name IntRange extends RefCounted +static var Zero = IntRange.new(0, 0) + var minmax: PackedInt32Array var min: int: get: return minmax[0] var max: int: - get: return minmax[1] + get: + if inclusive: return minmax[1] + 1 + else: return minmax[1] -static var Zero = IntRange.new(0, 0) +var inclusive: bool func _init(start: int, end: int, inclusive: bool = false) -> void: - minmax = PackedInt32Array([start, end if not inclusive else end + 1]) + minmax = PackedInt32Array([start, end]) + self.inclusive = inclusive + +func _to_string() -> String: + var ch = "]" if inclusive else ")" + return "IntRange [%s, %s%s" % [min, max, ch] func length() -> int: return absi(max - min) @@ -20,16 +29,16 @@ func is_zero() -> bool: return min == 0 and max == 0 func is_empty() -> bool: - return is_zero() + return length() == 0 func iter(step: int = 1) -> RangeIterator: return RangeIterator.new(self, min, step) func clamp(value: int) -> int: - return clampi(value, min, max) + return clampi(value, minmax[0], minmax[1]) func wrap(value: int) -> int: - return wrapi(value, min, max) + return wrapi(value, minmax[0], minmax[1]) func contains(value: int) -> bool: return value >= min and value < max diff --git a/godot/addons/iterator/bounded_range.gd b/godot/addons/iterator/bounded_range.gd index 8895385..540d8a8 100644 --- a/godot/addons/iterator/bounded_range.gd +++ b/godot/addons/iterator/bounded_range.gd @@ -1,29 +1,35 @@ class_name BoundedRangeIterator extends Iterator -var range: IntRange -var bounds: IntRange -var step: int -var limit: int -var index: int +var _range: IntRange +var _bounds: IntRange +var _count: int +var _step: int +var _items_yielded: int = 0 -func _init(range: IntRange, bounds: IntRange, step: int = 1, limit: int = 1, start_index: int = range.min) -> void: - self.range = range - self.bounds = bounds - self.step = step - self.limit = limit - self.index = start_index +func _init(range: IntRange, bounds: IntRange, step: int = 1) -> void: + self._range = range + self._count = range.length() + self._bounds = bounds + self._step = step + +static func from_array(xs: Array, iteration_range: IntRange, step: int = 1) -> BoundedRangeIterator: + return BoundedRangeIterator.new(iteration_range, IntRange.new(0, len(xs)), step) + +func _to_string() -> String: + return "BoundedRangeIterator { range: %s, count: %s, bounds: %s, step: %s, items_yielded: %s }" % \ + [_range, _count, _bounds, _step, _items_yielded] func clone() -> BoundedRangeIterator: - return BoundedRangeIterator.new(range, bounds, step, limit, index) + var iter = BoundedRangeIterator.new(_range, _bounds, _step) + iter._items_yielded = _items_yielded + return iter func next() -> Option: - if bounds.contains(index): - var current_value = Option.some(index) - index += step - return current_value - elif limit > 0: - limit -= 1 - var current_value = bounds.wrap(index) - index = current_value + 1 - return Option.some(current_value) - else: return Option.none + if _items_yielded >= _count: + return Option.none + + var index = _range.min + (_items_yielded * _step) + var wrapped_index = _bounds.wrap(index) + _items_yielded += 1 + + return Option.some(wrapped_index) diff --git a/godot/addons/iterator/iterator.gd b/godot/addons/iterator/iterator.gd index cbe0947..bcdf8e2 100644 --- a/godot/addons/iterator/iterator.gd +++ b/godot/addons/iterator/iterator.gd @@ -1,5 +1,8 @@ class_name Iterator extends RefCounted +func _to_string() -> String: + return "Iterator" + func clone() -> Iterator: assert(false, "can't clone a abstract base class") return null diff --git a/godot/addons/iterator/range.gd b/godot/addons/iterator/range.gd index 424cbc5..5effb90 100644 --- a/godot/addons/iterator/range.gd +++ b/godot/addons/iterator/range.gd @@ -4,6 +4,7 @@ var index: int var range: IntRange var step: int var descending: bool +var _done: bool = false func _init(range: IntRange, start_index: int = range.min, step: int = 1) -> void: assert(step != 0, "step cannot be zero") @@ -23,8 +24,12 @@ func clone() -> RangeIterator: return RangeIterator.new(range, index) func next() -> Option: - if range.contains(index): - var current_value = Option.some(index) - index += step - return current_value - else: return Option.none + if _done: return Option.none + if index == range.max or not range.contains(index): + _done = true + if range.inclusive: return Option.some(index) + else: return Option.none + + var current_value = Option.some(index) + index += step + return current_value diff --git a/godot/addons/monads/option.gd b/godot/addons/monads/option.gd index eb43dcb..6b5815a 100644 --- a/godot/addons/monads/option.gd +++ b/godot/addons/monads/option.gd @@ -7,6 +7,11 @@ static func some(value: Variant) -> Option: static var none: Option.None = None.new() +static func from(value: Variant) -> Option: + if typeof(value) == TYPE_NIL: + return Option.none + else: return Option.some(value) + static func collect_some(options: Array[Option], ignore_none: bool = false) -> Option: var result = [] for option in options: diff --git a/godot/addons/utils/utils.gd b/godot/addons/utils/utils.gd new file mode 100644 index 0000000..2a846bc --- /dev/null +++ b/godot/addons/utils/utils.gd @@ -0,0 +1,28 @@ +class_name Utils + +static func get_class_name(value: Object) -> String: + match value.get_script(): + var script: + match script.get_global_name(): + var name: return name + _: return script.get_instance_base_type() + _: return value.get_class() + +static func is_string_like(value: Variant) -> bool: + match typeof(value): + TYPE_STRING: return true + TYPE_STRING_NAME: return true + TYPE_NODE_PATH: return true + _: return false + +static func to_str(value: Variant) -> String: + match typeof(value): + TYPE_OBJECT: + if value.has_method('_to_string'): + return value.to_string() + else: + var name = get_class_name(value) + value = value as Object + var props: Dictionary = inst_to_dict(value) + return "%s %s" % [name, to_str(props)] + _: return str(value) diff --git a/godot/scenes/inventory.tscn b/godot/scenes/inventory.tscn index 90fe8cf..e7c480e 100644 --- a/godot/scenes/inventory.tscn +++ b/godot/scenes/inventory.tscn @@ -17,7 +17,6 @@ script = ExtResource("1_qw0r6") action = "inventory" [node name="ColorRect" type="ColorRect" parent="."] -visible = false layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -43,18 +42,6 @@ layout_mode = 2 script = ExtResource("4_yyk2a") item_scene = ExtResource("5_uae8j") -[node name="Item" parent="VBoxContainer/HItemList" instance=ExtResource("5_uae8j")] -layout_mode = 2 - -[node name="Item2" parent="VBoxContainer/HItemList" instance=ExtResource("5_uae8j")] -layout_mode = 2 - -[node name="Item3" parent="VBoxContainer/HItemList" instance=ExtResource("5_uae8j")] -layout_mode = 2 - -[node name="Item4" parent="VBoxContainer/HItemList" instance=ExtResource("5_uae8j")] -layout_mode = 2 - [node name="Details" type="HBoxContainer" parent="VBoxContainer"] layout_mode = 2 diff --git a/godot/scenes/inventory_item.tscn b/godot/scenes/inventory_item.tscn index 2d7ddfd..22a88cc 100644 --- a/godot/scenes/inventory_item.tscn +++ b/godot/scenes/inventory_item.tscn @@ -1,7 +1,9 @@ [gd_scene load_steps=3 format=3 uid="uid://gn8k2ir47n1m"] [ext_resource type="Script" uid="uid://dt67n4jti376d" path="res://src/item_ui.gd" id="1_letey"] -[ext_resource type="Texture2D" uid="uid://djmxd4580q6xs" path="res://icon.svg" id="2_y87vu"] + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_u4rwp"] +size = Vector2(128, 128) [node name="Item" type="BoxContainer" node_paths=PackedStringArray("name_label", "icon_texture")] offset_right = 128.0 @@ -18,8 +20,8 @@ layout_mode = 2 [node name="Name" type="Label" parent="VBoxContainer"] layout_mode = 2 -text = "Test Item" +text = "Empty" [node name="Icon" type="TextureRect" parent="VBoxContainer"] layout_mode = 2 -texture = ExtResource("2_y87vu") +texture = SubResource("PlaceholderTexture2D_u4rwp") diff --git a/godot/src/h_item_list.gd b/godot/src/h_item_list.gd index 1aee577..3455369 100644 --- a/godot/src/h_item_list.gd +++ b/godot/src/h_item_list.gd @@ -11,8 +11,8 @@ var bind_item: Callable = _bind_item var ring_buffer: RingBuffer func _ready() -> void: - ring_buffer = RingBuffer.new(items.size(), buffer_size, 1, -buffered_items) - ring_buffer.updated.connect(_on_updated) + ring_buffer = RingBuffer.new(items.size(), buffer_size, buffer_size - 1) + ring_buffer.rotated.connect(_on_rotated) for _i in range(buffer_size): add_child(create_item.call()) @@ -30,21 +30,35 @@ func _hide_buffered_items(): func _create_item() -> Node: return item_scene.instantiate() -func _bind_item(node: Node, item: Item): +func _bind_item(node: Node, item: Option): if node.has_method('bind'): node.call('bind', item) -func _on_updated(_current_range: IntRange, _previous_range: IntRange): +func _on_rotated(_direction: int): _update_display() -func _update_display(): - var indices: Array = ring_buffer.range().collect() +func _get_item(index: int) -> Option: + if index < 0 or index >= len(items): + return Option.none + return Option.from(items[index]) - for i in range(min(indices.size(), max_items)): +func _update_display(): + var iter = ring_buffer.iter() + var indices = iter.collect() + + for i in range(buffer_size): var node = get_child(i) - var item = items[indices[i]] - if item != null: - bind_item.call(node, item) + var item_index_from_ring_buffer = indices[i] + var item_option = _get_item(item_index_from_ring_buffer) + bind_item.call(node, item_option) + + #if item_option.is_none(): + # node.hide() # Hide if no item available + #else: + # if i >= buffered_items and i < (buffer_size - buffered_items): + # node.show() + # else: + # node.hide() func add_item(item: Variant): items.append(item) @@ -55,3 +69,9 @@ func add_items(new_items: Array): items.append_array(new_items) ring_buffer.source_size = items.size() _update_display() + +func move_right(): + ring_buffer.move_right() + +func move_left(): + ring_buffer.move_left() diff --git a/godot/src/item_ui.gd b/godot/src/item_ui.gd index df671a3..6a2f68a 100644 --- a/godot/src/item_ui.gd +++ b/godot/src/item_ui.gd @@ -3,6 +3,21 @@ class_name ItemUI extends Control @export var name_label: Label @export var icon_texture: TextureRect -func bind(item: Item): - name_label.text = item.name - icon_texture.texture = item.icon +var _default_text: String +var _default_icon: Texture2D + +func _ready() -> void: + _default_text = name_label.text + _default_icon = icon_texture.texture + +func bind(_item: Option): + if _item.is_none(): + unbind() + else: + var item = _item.unwrap() + name_label.text = item.name + icon_texture.texture = item.icon + +func unbind(): + name_label.text = _default_text + icon_texture.texture = _default_icon diff --git a/godot/src/ring_buffer.gd b/godot/src/ring_buffer.gd index b129fd6..315cf07 100644 --- a/godot/src/ring_buffer.gd +++ b/godot/src/ring_buffer.gd @@ -6,6 +6,7 @@ enum Direction { } signal updated(new_range: IntRange, previous_range: IntRange) +signal rotated(direction: int) var _source_size: int var source_size: int: @@ -39,13 +40,16 @@ var selected_index: int: set(value): set_selected(value) func set_selected(value: int) -> void: + var previous = self.get_range() _index = self.index(value) + var current = self.get_range() + updated.emit(current, previous) var start_index: int: - get: return self.index(_offset + _index) + get: return _index var end_index: int: - get: return self.index(_offset + _index + _capacity - 1) + get: return start_index + capacity @warning_ignore("shadowed_variable") func _init(source_size: int, capacity: int, start_index: int = 0, offset: int = 0) -> void: @@ -62,15 +66,17 @@ func index(value: int) -> int: else: return value % _source_size -func range() -> BoundedRangeIterator: - return BoundedRangeIterator.new(IntRange.new(start_index, end_index), IntRange.new(0, capacity)) +func get_range() -> IntRange: + return IntRange.new(start_index, end_index) + +func iter() -> BoundedRangeIterator: + return BoundedRangeIterator.new(get_range(), IntRange.new(0, _source_size)) func move(direction: Direction) -> Result: if _source_size <= _capacity: - return Result.err("source size is smaller than buffer capacity") - var previous = range() + push_warning("source size is smaller than buffer capacity") _index = self.index(_index + direction) - updated.emit(range(), previous) + rotated.emit(direction) return Result.Unit func move_right() -> Result: