Fix Issue #74: Add missing Grid.grid_y property
Added individual grid_x and grid_y getter properties to the Grid class to complement the existing grid_size property. This allows direct access to grid dimensions and fixes error messages that referenced these properties before they existed. closes #74
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 30 KiB |
|
@ -269,6 +269,14 @@ PyObject* UIGrid::get_grid_size(PyUIGridObject* self, void* closure) {
|
|||
return Py_BuildValue("(ii)", self->data->grid_x, self->data->grid_y);
|
||||
}
|
||||
|
||||
PyObject* UIGrid::get_grid_x(PyUIGridObject* self, void* closure) {
|
||||
return PyLong_FromLong(self->data->grid_x);
|
||||
}
|
||||
|
||||
PyObject* UIGrid::get_grid_y(PyUIGridObject* self, void* closure) {
|
||||
return PyLong_FromLong(self->data->grid_y);
|
||||
}
|
||||
|
||||
PyObject* UIGrid::get_position(PyUIGridObject* self, void* closure) {
|
||||
auto& box = self->data->box;
|
||||
return Py_BuildValue("(ff)", box.getPosition().x, box.getPosition().y);
|
||||
|
@ -431,6 +439,8 @@ PyGetSetDef UIGrid::getsetters[] = {
|
|||
|
||||
// TODO - refactor into get_vector_member with field identifier values `(void*)n`
|
||||
{"grid_size", (getter)UIGrid::get_grid_size, NULL, "Grid dimensions (grid_x, grid_y)", NULL},
|
||||
{"grid_x", (getter)UIGrid::get_grid_x, NULL, "Grid x dimension", NULL},
|
||||
{"grid_y", (getter)UIGrid::get_grid_y, NULL, "Grid y dimension", NULL},
|
||||
{"position", (getter)UIGrid::get_position, (setter)UIGrid::set_position, "Position of the grid (x, y)", NULL},
|
||||
{"size", (getter)UIGrid::get_size, (setter)UIGrid::set_size, "Size of the grid (width, height)", NULL},
|
||||
{"center", (getter)UIGrid::get_center, (setter)UIGrid::set_center, "Grid coordinate at the center of the Grid's view (pan)", NULL},
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
|
||||
static int init(PyUIGridObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* get_grid_size(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_grid_x(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_grid_y(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_position(PyUIGridObject* self, void* closure);
|
||||
static int set_position(PyUIGridObject* self, PyObject* value, void* closure);
|
||||
static PyObject* get_size(PyUIGridObject* self, void* closure);
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
import sys; sys.path.insert(0, '.')
|
||||
#!/usr/bin/env python3
|
||||
"""Test for UICollection - Related to issue #69 (Sequence Protocol)"""
|
||||
import mcrfpy
|
||||
from mcrfpy import automation
|
||||
from datetime import datetime
|
||||
|
||||
def test_UICollection():
|
||||
"""Test UICollection sequence protocol compliance"""
|
||||
# Create test scene
|
||||
mcrfpy.createScene("collection_test")
|
||||
mcrfpy.setScene("collection_test")
|
||||
ui = mcrfpy.sceneUI("collection_test")
|
||||
|
||||
# Add various UI elements
|
||||
frame = mcrfpy.Frame(10, 10, 100, 100)
|
||||
caption = mcrfpy.Caption(mcrfpy.Vector(120, 10), text="Test")
|
||||
sprite = mcrfpy.Sprite(10, 120)
|
||||
|
||||
ui.append(frame)
|
||||
ui.append(caption)
|
||||
ui.append(sprite)
|
||||
|
||||
print("Testing UICollection sequence protocol (Issue #69)...")
|
||||
|
||||
# Test len()
|
||||
try:
|
||||
length = len(ui)
|
||||
print(f"✓ len() works: {length} items")
|
||||
except Exception as e:
|
||||
print(f"✗ len() failed: {e}")
|
||||
|
||||
# Test indexing
|
||||
try:
|
||||
item0 = ui[0]
|
||||
item1 = ui[1]
|
||||
item2 = ui[2]
|
||||
print(f"✓ Indexing works: [{type(item0).__name__}, {type(item1).__name__}, {type(item2).__name__}]")
|
||||
|
||||
# Test negative indexing
|
||||
last_item = ui[-1]
|
||||
print(f"✓ Negative indexing works: ui[-1] = {type(last_item).__name__}")
|
||||
except Exception as e:
|
||||
print(f"✗ Indexing failed: {e}")
|
||||
|
||||
# Test slicing (if implemented)
|
||||
try:
|
||||
slice_items = ui[0:2]
|
||||
print(f"✓ Slicing works: got {len(slice_items)} items")
|
||||
except Exception as e:
|
||||
print(f"✗ Slicing not implemented (Issue #69): {e}")
|
||||
|
||||
# Test iteration
|
||||
try:
|
||||
types = []
|
||||
for item in ui:
|
||||
types.append(type(item).__name__)
|
||||
print(f"✓ Iteration works: {types}")
|
||||
except Exception as e:
|
||||
print(f"✗ Iteration failed: {e}")
|
||||
|
||||
# Test contains
|
||||
try:
|
||||
if frame in ui:
|
||||
print("✓ 'in' operator works")
|
||||
else:
|
||||
print("✗ 'in' operator returned False for existing item")
|
||||
except Exception as e:
|
||||
print(f"✗ 'in' operator not implemented (Issue #69): {e}")
|
||||
|
||||
# Test remove
|
||||
try:
|
||||
ui.remove(1) # Remove caption
|
||||
print(f"✓ remove() works, now {len(ui)} items")
|
||||
except Exception as e:
|
||||
print(f"✗ remove() failed: {e}")
|
||||
|
||||
# Test type preservation (Issue #76)
|
||||
try:
|
||||
# Add a frame with children to test nested collections
|
||||
parent_frame = mcrfpy.Frame(250, 10, 200, 200,
|
||||
fill_color=mcrfpy.Color(200, 200, 200))
|
||||
child_caption = mcrfpy.Caption(mcrfpy.Vector(10, 10), text="Child")
|
||||
parent_frame.children.append(child_caption)
|
||||
ui.append(parent_frame)
|
||||
|
||||
# Check if type is preserved when retrieving
|
||||
retrieved = ui[-1]
|
||||
if type(retrieved).__name__ == "Frame":
|
||||
print("✓ Type preservation works")
|
||||
else:
|
||||
print(f"✗ Type not preserved (Issue #76): got {type(retrieved).__name__}")
|
||||
except Exception as e:
|
||||
print(f"✗ Type preservation test failed: {e}")
|
||||
|
||||
# Test find by name (Issue #41 - not yet implemented)
|
||||
try:
|
||||
found = ui.find("Test")
|
||||
print(f"✓ find() method works: {type(found).__name__}")
|
||||
except AttributeError:
|
||||
print("✗ find() method not implemented (Issue #41)")
|
||||
except Exception as e:
|
||||
print(f"✗ find() method error: {e}")
|
||||
|
||||
# Take screenshot
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"test_UICollection_issue69_{timestamp}.png"
|
||||
automation.screenshot(filename)
|
||||
print(f"Screenshot saved: {filename}")
|
||||
print("PASS")
|
||||
|
||||
# Set up timer to run test
|
||||
mcrfpy.setTimer("test", test_UICollection, 1000)
|
||||
|
||||
# Cancel timer after running once
|
||||
def cleanup():
|
||||
mcrfpy.delTimer("test")
|
||||
mcrfpy.delTimer("cleanup")
|
||||
|
||||
mcrfpy.setTimer("cleanup", cleanup, 1100)
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test for Issue #74: Add missing Grid.grid_y property
|
||||
|
||||
Verifies that Grid objects expose grid_x and grid_y properties correctly.
|
||||
"""
|
||||
|
||||
def test_grid_xy_properties(timer_name):
|
||||
"""Test that Grid has grid_x and grid_y properties"""
|
||||
import mcrfpy
|
||||
|
||||
# Test was run
|
||||
print("Issue #74 test: Grid.grid_x and Grid.grid_y properties")
|
||||
|
||||
# Test with texture
|
||||
texture = mcrfpy.Texture("assets/kenney_ice.png", 16, 16)
|
||||
grid = mcrfpy.Grid(20, 15, texture, (0, 0), (800, 600))
|
||||
|
||||
# Test grid_x property
|
||||
assert hasattr(grid, 'grid_x'), "Grid should have grid_x property"
|
||||
assert grid.grid_x == 20, f"Expected grid_x=20, got {grid.grid_x}"
|
||||
print(f"✓ grid.grid_x = {grid.grid_x}")
|
||||
|
||||
# Test grid_y property
|
||||
assert hasattr(grid, 'grid_y'), "Grid should have grid_y property"
|
||||
assert grid.grid_y == 15, f"Expected grid_y=15, got {grid.grid_y}"
|
||||
print(f"✓ grid.grid_y = {grid.grid_y}")
|
||||
|
||||
# Test grid_size still works
|
||||
assert hasattr(grid, 'grid_size'), "Grid should still have grid_size property"
|
||||
assert grid.grid_size == (20, 15), f"Expected grid_size=(20, 15), got {grid.grid_size}"
|
||||
print(f"✓ grid.grid_size = {grid.grid_size}")
|
||||
|
||||
# Test without texture
|
||||
grid2 = mcrfpy.Grid(30, 25, None, (10, 10), (480, 400))
|
||||
assert grid2.grid_x == 30, f"Expected grid_x=30, got {grid2.grid_x}"
|
||||
assert grid2.grid_y == 25, f"Expected grid_y=25, got {grid2.grid_y}"
|
||||
assert grid2.grid_size == (30, 25), f"Expected grid_size=(30, 25), got {grid2.grid_size}"
|
||||
print("✓ Grid without texture also has correct grid_x and grid_y")
|
||||
|
||||
# Test using in error message context (original issue)
|
||||
try:
|
||||
grid.at((-1, 0)) # Should raise error
|
||||
except ValueError as e:
|
||||
error_msg = str(e)
|
||||
assert "Grid.grid_x" in error_msg, f"Error message should reference Grid.grid_x: {error_msg}"
|
||||
print(f"✓ Error message correctly references Grid.grid_x: {error_msg}")
|
||||
|
||||
try:
|
||||
grid.at((0, -1)) # Should raise error
|
||||
except ValueError as e:
|
||||
error_msg = str(e)
|
||||
assert "Grid.grid_y" in error_msg, f"Error message should reference Grid.grid_y: {error_msg}"
|
||||
print(f"✓ Error message correctly references Grid.grid_y: {error_msg}")
|
||||
|
||||
print("\n✅ Issue #74 test PASSED - Grid.grid_x and Grid.grid_y properties work correctly")
|
||||
|
||||
# Execute the test after a short delay to ensure window is ready
|
||||
import mcrfpy
|
||||
mcrfpy.setTimer("test_timer", test_grid_xy_properties, 100)
|
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 30 KiB |