mirror of
https://github.com/bec-project/bec_widgets.git
synced 2025-07-14 03:31:50 +02:00
fix(layout_manager): adding relative widget is shifting whole column to not destroy previous layout
This commit is contained in:
@ -53,7 +53,7 @@ class LayoutManagerWidget(QWidget):
|
|||||||
self,
|
self,
|
||||||
widget: QWidget | str,
|
widget: QWidget | str,
|
||||||
row: int | None = None,
|
row: int | None = None,
|
||||||
col: Optional[int] = None,
|
col: int | None = None,
|
||||||
rowspan: int = 1,
|
rowspan: int = 1,
|
||||||
colspan: int = 1,
|
colspan: int = 1,
|
||||||
shift_existing: bool = True,
|
shift_existing: bool = True,
|
||||||
@ -138,6 +138,39 @@ class LayoutManagerWidget(QWidget):
|
|||||||
ref_row, ref_col, ref_rowspan, ref_colspan = self.widget_positions[reference_widget]
|
ref_row, ref_col, ref_rowspan, ref_colspan = self.widget_positions[reference_widget]
|
||||||
|
|
||||||
# Determine new widget position based on the specified relative position
|
# Determine new widget position based on the specified relative position
|
||||||
|
|
||||||
|
# If adding to the left or right with shifting, shift the entire column
|
||||||
|
if (
|
||||||
|
position in ("left", "right")
|
||||||
|
and shift_existing
|
||||||
|
and shift_direction in ("left", "right")
|
||||||
|
):
|
||||||
|
column = ref_col
|
||||||
|
# Collect all rows in this column and sort for safe shifting
|
||||||
|
rows = sorted(
|
||||||
|
{row for (row, col) in self.position_widgets.keys() if col == column},
|
||||||
|
reverse=(shift_direction == "right"),
|
||||||
|
)
|
||||||
|
# Shift each widget in the column
|
||||||
|
for r in rows:
|
||||||
|
self.shift_widgets(direction=shift_direction, start_row=r, start_col=column)
|
||||||
|
# Update reference widget's position after the column shift
|
||||||
|
ref_row, ref_col, ref_rowspan, ref_colspan = self.widget_positions[reference_widget]
|
||||||
|
new_row = ref_row
|
||||||
|
# Compute insertion column based on relative position
|
||||||
|
if position == "left":
|
||||||
|
new_col = ref_col - ref_colspan
|
||||||
|
else:
|
||||||
|
new_col = ref_col + ref_colspan
|
||||||
|
# Add the new widget without triggering another shift
|
||||||
|
return self.add_widget(
|
||||||
|
widget=widget,
|
||||||
|
row=new_row,
|
||||||
|
col=new_col,
|
||||||
|
rowspan=rowspan,
|
||||||
|
colspan=colspan,
|
||||||
|
shift_existing=False,
|
||||||
|
)
|
||||||
if position == "left":
|
if position == "left":
|
||||||
new_row = ref_row
|
new_row = ref_row
|
||||||
new_col = ref_col - 1
|
new_col = ref_col - 1
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from typing import Optional
|
from __future__ import annotations
|
||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -8,7 +9,8 @@ from bec_widgets.widgets.containers.layout_manager.layout_manager import LayoutM
|
|||||||
|
|
||||||
|
|
||||||
class MockWidgetHandler:
|
class MockWidgetHandler:
|
||||||
def create_widget(self, widget_type: str) -> Optional[QWidget]:
|
|
||||||
|
def create_widget(self, widget_type: str) -> QWidget | None:
|
||||||
if widget_type == "ButtonWidget":
|
if widget_type == "ButtonWidget":
|
||||||
return QPushButton()
|
return QPushButton()
|
||||||
elif widget_type == "LabelWidget":
|
elif widget_type == "LabelWidget":
|
||||||
@ -225,13 +227,11 @@ def test_add_widget_overlap_with_span(layout_manager):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"position, btn3_coords",
|
"position, expected_position",
|
||||||
[("left", (1, 0)), ("right", (1, 2)), ("top", (0, 1)), ("bottom", (2, 1))],
|
[("left", "left"), ("right", "right"), ("top", "top"), ("bottom", "bottom")],
|
||||||
)
|
)
|
||||||
def test_add_widget_relative(layout_manager, position, btn3_coords):
|
def test_add_widget_relative(layout_manager, position, expected_position):
|
||||||
"""Test adding a widget relative to an existing widget using parameterized data."""
|
"""Test adding a widget relative to an existing widget using parameterized data."""
|
||||||
expected_row, expected_col = btn3_coords
|
|
||||||
|
|
||||||
btn1 = QPushButton("Button 1")
|
btn1 = QPushButton("Button 1")
|
||||||
btn2 = QPushButton("Button 2")
|
btn2 = QPushButton("Button 2")
|
||||||
btn3 = QPushButton("Button 3")
|
btn3 = QPushButton("Button 3")
|
||||||
@ -241,9 +241,28 @@ def test_add_widget_relative(layout_manager, position, btn3_coords):
|
|||||||
|
|
||||||
layout_manager.add_widget_relative(btn3, reference_widget=btn2, position=position)
|
layout_manager.add_widget_relative(btn3, reference_widget=btn2, position=position)
|
||||||
|
|
||||||
assert layout_manager.get_widget(0, 0) == btn1
|
# Get the actual positions of the widgets
|
||||||
assert layout_manager.get_widget(1, 1) == btn2
|
btn1_pos = layout_manager.widget_positions[btn1]
|
||||||
assert layout_manager.get_widget(expected_row, expected_col) == btn3
|
btn2_pos = layout_manager.widget_positions[btn2]
|
||||||
|
btn3_pos = layout_manager.widget_positions[btn3]
|
||||||
|
|
||||||
|
# Check that btn1 and btn2 are still in the layout
|
||||||
|
assert btn1 in layout_manager.widget_positions
|
||||||
|
assert btn2 in layout_manager.widget_positions
|
||||||
|
|
||||||
|
# Check that btn3 is positioned correctly relative to btn2
|
||||||
|
if expected_position == "left":
|
||||||
|
assert btn3_pos[1] < btn2_pos[1] # btn3's column < btn2's column
|
||||||
|
assert btn3_pos[0] == btn2_pos[0] # same row
|
||||||
|
elif expected_position == "right":
|
||||||
|
assert btn3_pos[1] > btn2_pos[1] # btn3's column > btn2's column
|
||||||
|
assert btn3_pos[0] == btn2_pos[0] # same row
|
||||||
|
elif expected_position == "top":
|
||||||
|
assert btn3_pos[0] < btn2_pos[0] # btn3's row < btn2's row
|
||||||
|
assert btn3_pos[1] == btn2_pos[1] # same column
|
||||||
|
elif expected_position == "bottom":
|
||||||
|
assert btn3_pos[0] > btn2_pos[0] # btn3's row > btn2's row
|
||||||
|
assert btn3_pos[1] == btn2_pos[1] # same column
|
||||||
|
|
||||||
|
|
||||||
def test_add_widget_relative_invalid_position(layout_manager):
|
def test_add_widget_relative_invalid_position(layout_manager):
|
||||||
@ -366,3 +385,74 @@ def test_shift_all_widgets_up_at_top_row(layout_manager):
|
|||||||
layout_manager.shift_all_widgets(direction="up")
|
layout_manager.shift_all_widgets(direction="up")
|
||||||
|
|
||||||
assert "Shifting widgets out of grid boundaries." in str(exc_info.value)
|
assert "Shifting widgets out of grid boundaries." in str(exc_info.value)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"test_id, position, shift_direction, additional_assertions",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"from_left",
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
[
|
||||||
|
# Additional assertions for the left test case
|
||||||
|
lambda btn1_pos, btn1_new_pos, btn2_pos, btn2_new_pos, btn3_pos: btn1_new_pos[1]
|
||||||
|
> btn1_pos[1], # column shifted right
|
||||||
|
lambda btn1_pos, btn1_new_pos, btn2_pos, btn2_new_pos, btn3_pos: btn2_new_pos[1]
|
||||||
|
> btn2_pos[1], # column shifted right
|
||||||
|
lambda btn1_pos, btn1_new_pos, btn2_pos, btn2_new_pos, btn3_pos: btn3_pos[1]
|
||||||
|
< btn2_new_pos[1], # btn3 is to the left of btn2
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"from_right",
|
||||||
|
"right",
|
||||||
|
"right",
|
||||||
|
[
|
||||||
|
# Additional assertions for the right test case
|
||||||
|
lambda btn1_pos, btn1_new_pos, btn2_pos, btn2_new_pos, btn3_pos: btn3_pos[1]
|
||||||
|
> btn2_new_pos[1] # btn3 is to the right of btn2
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_column_shift_when_adding_widget(
|
||||||
|
layout_manager, test_id, position, shift_direction, additional_assertions
|
||||||
|
):
|
||||||
|
"""Test that adding a widget to a column of widgets shifts the entire column appropriately."""
|
||||||
|
# Create a column of widgets
|
||||||
|
btn1 = QPushButton("Button 1")
|
||||||
|
btn2 = QPushButton("Button 2")
|
||||||
|
|
||||||
|
# Add btn1 at position (0, 1)
|
||||||
|
layout_manager.add_widget(btn1, row=0, col=1)
|
||||||
|
|
||||||
|
# Add btn2 below btn1
|
||||||
|
layout_manager.add_widget_relative(btn2, reference_widget=btn1, position="bottom")
|
||||||
|
|
||||||
|
# Get the positions after initial setup
|
||||||
|
btn1_pos = layout_manager.widget_positions[btn1]
|
||||||
|
btn2_pos = layout_manager.widget_positions[btn2]
|
||||||
|
|
||||||
|
# Verify btn2 is below btn1 (same column)
|
||||||
|
assert btn1_pos[0] < btn2_pos[0] # btn2's row > btn1's row
|
||||||
|
assert btn1_pos[1] == btn2_pos[1] # same column
|
||||||
|
|
||||||
|
# Add a new button relative to btn2 with the specified position and shift_direction
|
||||||
|
btn3 = QPushButton("Button 3")
|
||||||
|
layout_manager.add_widget_relative(
|
||||||
|
btn3, reference_widget=btn2, position=position, shift_direction=shift_direction
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get the updated positions
|
||||||
|
btn1_new_pos = layout_manager.widget_positions[btn1]
|
||||||
|
btn2_new_pos = layout_manager.widget_positions[btn2]
|
||||||
|
btn3_pos = layout_manager.widget_positions[btn3]
|
||||||
|
|
||||||
|
# Common assertions for both test cases
|
||||||
|
assert btn1_new_pos[1] == btn2_new_pos[1] # btn1 and btn2 still in same column
|
||||||
|
assert btn3_pos[0] == btn2_new_pos[0] # btn3 is in the same row as btn2
|
||||||
|
|
||||||
|
# Run additional assertions specific to each test case
|
||||||
|
for assertion in additional_assertions:
|
||||||
|
assertion(btn1_pos, btn1_new_pos, btn2_pos, btn2_new_pos, btn3_pos)
|
||||||
|
Reference in New Issue
Block a user