hitemlist working

This commit is contained in:
Rowan 2025-06-12 00:32:17 -04:00
parent d1956a95b3
commit 0f49097dd9
11 changed files with 155 additions and 69 deletions

View file

@ -1,17 +1,26 @@
class_name IntRange extends RefCounted class_name IntRange extends RefCounted
static var Zero = IntRange.new(0, 0)
var minmax: PackedInt32Array var minmax: PackedInt32Array
var min: int: var min: int:
get: return minmax[0] get: return minmax[0]
var max: int: 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: 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: func length() -> int:
return absi(max - min) return absi(max - min)
@ -20,16 +29,16 @@ func is_zero() -> bool:
return min == 0 and max == 0 return min == 0 and max == 0
func is_empty() -> bool: func is_empty() -> bool:
return is_zero() return length() == 0
func iter(step: int = 1) -> RangeIterator: func iter(step: int = 1) -> RangeIterator:
return RangeIterator.new(self, min, step) return RangeIterator.new(self, min, step)
func clamp(value: int) -> int: func clamp(value: int) -> int:
return clampi(value, min, max) return clampi(value, minmax[0], minmax[1])
func wrap(value: int) -> int: func wrap(value: int) -> int:
return wrapi(value, min, max) return wrapi(value, minmax[0], minmax[1])
func contains(value: int) -> bool: func contains(value: int) -> bool:
return value >= min and value < max return value >= min and value < max

View file

@ -1,29 +1,35 @@
class_name BoundedRangeIterator extends Iterator class_name BoundedRangeIterator extends Iterator
var range: IntRange var _range: IntRange
var bounds: IntRange var _bounds: IntRange
var step: int var _count: int
var limit: int var _step: int
var index: int var _items_yielded: int = 0
func _init(range: IntRange, bounds: IntRange, step: int = 1, limit: int = 1, start_index: int = range.min) -> void: func _init(range: IntRange, bounds: IntRange, step: int = 1) -> void:
self.range = range self._range = range
self.bounds = bounds self._count = range.length()
self.step = step self._bounds = bounds
self.limit = limit self._step = step
self.index = start_index
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: 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: func next() -> Option:
if bounds.contains(index): if _items_yielded >= _count:
var current_value = Option.some(index) return Option.none
index += step
return current_value var index = _range.min + (_items_yielded * _step)
elif limit > 0: var wrapped_index = _bounds.wrap(index)
limit -= 1 _items_yielded += 1
var current_value = bounds.wrap(index)
index = current_value + 1 return Option.some(wrapped_index)
return Option.some(current_value)
else: return Option.none

View file

@ -1,5 +1,8 @@
class_name Iterator extends RefCounted class_name Iterator extends RefCounted
func _to_string() -> String:
return "Iterator"
func clone() -> Iterator: func clone() -> Iterator:
assert(false, "can't clone a abstract base class") assert(false, "can't clone a abstract base class")
return null return null

View file

@ -4,6 +4,7 @@ var index: int
var range: IntRange var range: IntRange
var step: int var step: int
var descending: bool var descending: bool
var _done: bool = false
func _init(range: IntRange, start_index: int = range.min, step: int = 1) -> void: func _init(range: IntRange, start_index: int = range.min, step: int = 1) -> void:
assert(step != 0, "step cannot be zero") assert(step != 0, "step cannot be zero")
@ -23,8 +24,12 @@ func clone() -> RangeIterator:
return RangeIterator.new(range, index) return RangeIterator.new(range, index)
func next() -> Option: func next() -> Option:
if range.contains(index): if _done: return Option.none
var current_value = Option.some(index) if index == range.max or not range.contains(index):
index += step _done = true
return current_value if range.inclusive: return Option.some(index)
else: return Option.none else: return Option.none
var current_value = Option.some(index)
index += step
return current_value

View file

@ -7,6 +7,11 @@ static func some(value: Variant) -> Option:
static var none: Option.None = None.new() 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: static func collect_some(options: Array[Option], ignore_none: bool = false) -> Option:
var result = [] var result = []
for option in options: for option in options:

View file

@ -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)

View file

@ -17,7 +17,6 @@ script = ExtResource("1_qw0r6")
action = "inventory" action = "inventory"
[node name="ColorRect" type="ColorRect" parent="."] [node name="ColorRect" type="ColorRect" parent="."]
visible = false
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
@ -43,18 +42,6 @@ layout_mode = 2
script = ExtResource("4_yyk2a") script = ExtResource("4_yyk2a")
item_scene = ExtResource("5_uae8j") 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"] [node name="Details" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2 layout_mode = 2

View file

@ -1,7 +1,9 @@
[gd_scene load_steps=3 format=3 uid="uid://gn8k2ir47n1m"] [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="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")] [node name="Item" type="BoxContainer" node_paths=PackedStringArray("name_label", "icon_texture")]
offset_right = 128.0 offset_right = 128.0
@ -18,8 +20,8 @@ layout_mode = 2
[node name="Name" type="Label" parent="VBoxContainer"] [node name="Name" type="Label" parent="VBoxContainer"]
layout_mode = 2 layout_mode = 2
text = "Test Item" text = "Empty"
[node name="Icon" type="TextureRect" parent="VBoxContainer"] [node name="Icon" type="TextureRect" parent="VBoxContainer"]
layout_mode = 2 layout_mode = 2
texture = ExtResource("2_y87vu") texture = SubResource("PlaceholderTexture2D_u4rwp")

View file

@ -11,8 +11,8 @@ var bind_item: Callable = _bind_item
var ring_buffer: RingBuffer var ring_buffer: RingBuffer
func _ready() -> void: func _ready() -> void:
ring_buffer = RingBuffer.new(items.size(), buffer_size, 1, -buffered_items) ring_buffer = RingBuffer.new(items.size(), buffer_size, buffer_size - 1)
ring_buffer.updated.connect(_on_updated) ring_buffer.rotated.connect(_on_rotated)
for _i in range(buffer_size): for _i in range(buffer_size):
add_child(create_item.call()) add_child(create_item.call())
@ -30,21 +30,35 @@ func _hide_buffered_items():
func _create_item() -> Node: func _create_item() -> Node:
return item_scene.instantiate() return item_scene.instantiate()
func _bind_item(node: Node, item: Item): func _bind_item(node: Node, item: Option):
if node.has_method('bind'): if node.has_method('bind'):
node.call('bind', item) node.call('bind', item)
func _on_updated(_current_range: IntRange, _previous_range: IntRange): func _on_rotated(_direction: int):
_update_display() _update_display()
func _update_display(): func _get_item(index: int) -> Option:
var indices: Array = ring_buffer.range().collect() 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 node = get_child(i)
var item = items[indices[i]] var item_index_from_ring_buffer = indices[i]
if item != null: var item_option = _get_item(item_index_from_ring_buffer)
bind_item.call(node, item) 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): func add_item(item: Variant):
items.append(item) items.append(item)
@ -55,3 +69,9 @@ func add_items(new_items: Array):
items.append_array(new_items) items.append_array(new_items)
ring_buffer.source_size = items.size() ring_buffer.source_size = items.size()
_update_display() _update_display()
func move_right():
ring_buffer.move_right()
func move_left():
ring_buffer.move_left()

View file

@ -3,6 +3,21 @@ class_name ItemUI extends Control
@export var name_label: Label @export var name_label: Label
@export var icon_texture: TextureRect @export var icon_texture: TextureRect
func bind(item: Item): var _default_text: String
name_label.text = item.name var _default_icon: Texture2D
icon_texture.texture = item.icon
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

View file

@ -6,6 +6,7 @@ enum Direction {
} }
signal updated(new_range: IntRange, previous_range: IntRange) signal updated(new_range: IntRange, previous_range: IntRange)
signal rotated(direction: int)
var _source_size: int var _source_size: int
var source_size: int: var source_size: int:
@ -39,13 +40,16 @@ var selected_index: int:
set(value): set_selected(value) set(value): set_selected(value)
func set_selected(value: int) -> void: func set_selected(value: int) -> void:
var previous = self.get_range()
_index = self.index(value) _index = self.index(value)
var current = self.get_range()
updated.emit(current, previous)
var start_index: int: var start_index: int:
get: return self.index(_offset + _index) get: return _index
var end_index: int: var end_index: int:
get: return self.index(_offset + _index + _capacity - 1) get: return start_index + capacity
@warning_ignore("shadowed_variable") @warning_ignore("shadowed_variable")
func _init(source_size: int, capacity: int, start_index: int = 0, offset: int = 0) -> void: 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: else:
return value % _source_size return value % _source_size
func range() -> BoundedRangeIterator: func get_range() -> IntRange:
return BoundedRangeIterator.new(IntRange.new(start_index, end_index), IntRange.new(0, capacity)) 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: func move(direction: Direction) -> Result:
if _source_size <= _capacity: if _source_size <= _capacity:
return Result.err("source size is smaller than buffer capacity") push_warning("source size is smaller than buffer capacity")
var previous = range()
_index = self.index(_index + direction) _index = self.index(_index + direction)
updated.emit(range(), previous) rotated.emit(direction)
return Result.Unit return Result.Unit
func move_right() -> Result: func move_right() -> Result: