0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

feat(utils/layout_manager): added GridLayoutManager to extend functionalities of native QGridLayout

This commit is contained in:
2024-05-01 21:05:30 +02:00
parent d8ff8afcd4
commit fcd6ef0975
3 changed files with 141 additions and 2 deletions

View File

@ -5,5 +5,6 @@ from .colors import Colors
from .container_utils import WidgetContainerUtils
from .crosshair import Crosshair
from .entry_validator import EntryValidator
from .layout_manager import GridLayoutManager
from .rpc_decorator import register_rpc_methods, rpc_public
from .validator_delegate import DoubleValidationDelegate

View File

@ -0,0 +1,117 @@
from collections import OrderedDict
from typing import Literal
from qtpy.QtWidgets import QGridLayout, QWidget
class GridLayoutManager:
"""
GridLayoutManager class is used to manage widgets in a QGridLayout and extend its functionality.
The GridLayoutManager class provides methods to add, move, and check the position of widgets in a QGridLayout.
It also provides a method to get the positions of all widgets in the layout.
Args:
layout(QGridLayout): The layout to manage.
"""
def __init__(self, layout: QGridLayout):
self.layout = layout
def is_position_occupied(self, row: int, col: int) -> bool:
"""
Check if the position in the layout is occupied by a widget.
Args:
row(int): The row to check.
col(int): The column to check.
Returns:
bool: True if the position is occupied, False otherwise.
"""
for i in range(self.layout.count()):
widget_row, widget_col, _, _ = self.layout.getItemPosition(i)
if widget_row == row and widget_col == col:
return True
return False
def shift_widgets(
self,
direction: Literal["down", "up", "left", "right"] = "down",
start_row: int = 0,
start_col: int = 0,
):
"""
Shift widgets in the layout in the specified direction starting from the specified position.
Args:
direction(str): The direction to shift the widgets. Can be "down", "up", "left", or "right".
start_row(int): The row to start shifting from. Default is 0.
start_col(int): The column to start shifting from. Default is 0.
"""
for i in reversed(range(self.layout.count())):
widget_item = self.layout.itemAt(i)
widget = widget_item.widget()
row, col, rowspan, colspan = self.layout.getItemPosition(i)
if direction == "down" and row >= start_row:
self.layout.addWidget(widget, row + 1, col, rowspan, colspan)
elif direction == "up" and row > start_row:
self.layout.addWidget(widget, row - 1, col, rowspan, colspan)
elif direction == "right" and col >= start_col:
self.layout.addWidget(widget, row, col + 1, rowspan, colspan)
elif direction == "left" and col > start_col:
self.layout.addWidget(widget, row, col - 1, rowspan, colspan)
def move_widget(self, widget: QWidget, new_row: int, new_col: int):
"""
Move a widget to a new position in the layout.
Args:
widget(QWidget): The widget to move.
new_row(int): The new row to move the widget to.
new_col(int): The new column to move the widget to.
"""
self.layout.removeWidget(widget)
self.layout.addWidget(widget, new_row, new_col)
def add_widget(
self,
widget: QWidget,
row=None,
col=0,
rowspan=1,
colspan=1,
shift: Literal["down", "up", "left", "right"] = "down",
):
"""
Add a widget to the layout at the specified position.
Args:
widget(QWidget): The widget to add.
row(int): The row to add the widget to. If None, the widget will be added to the next available row.
col(int): The column to add the widget to. Default is 0.
rowspan(int): The number of rows the widget will span. Default is 1.
colspan(int): The number of columns the widget will span. Default is 1.
shift(str): The direction to shift the widgets if the position is occupied. Can be "down", "up", "left", or "right".
"""
if row is None:
row = self.layout.rowCount()
if self.is_position_occupied(row, col):
self.shift_widgets(shift, start_row=row)
self.layout.addWidget(widget, row, col, rowspan, colspan)
def get_widgets_positions(self) -> dict:
"""
Get the positions of all widgets in the layout.
Returns:
dict: A dictionary with the positions of the widgets in the layout.
"""
positions = []
for i in range(self.layout.count()):
widget_item = self.layout.itemAt(i)
widget = widget_item.widget()
if widget:
position = self.layout.getItemPosition(i)
positions.append((position, widget))
positions.sort(key=lambda x: (x[0][0], x[0][1], x[0][2], x[0][3]))
ordered_positions = OrderedDict()
for pos, widget in positions:
ordered_positions[pos] = widget
return ordered_positions

View File

@ -6,7 +6,7 @@ from pydantic import Field
from pyqtgraph.dockarea import Dock
from qtpy.QtWidgets import QWidget
from bec_widgets.utils import BECConnector, ConnectionConfig
from bec_widgets.utils import BECConnector, ConnectionConfig, GridLayoutManager
class DockConfig(ConnectionConfig):
@ -47,8 +47,12 @@ class BECDock(BECConnector, Dock):
self.parent_dock_area = parent_dock_area
# Signals
self.sigClosed.connect(self._remove_from_dock_area)
# Layout Manager
self.layout_manager = GridLayoutManager(self.layout)
@property
def widget_list(self) -> list:
return self.widgets
@ -57,7 +61,24 @@ class BECDock(BECConnector, Dock):
def widget_list(self, value: list):
self.widgets = value
def add_widget(self, widget: QWidget, row=None, col=0, rowspan=1, colspan=1):
def get_widgets_positions(self):
return self.layout_manager.get_widgets_positions()
def add_widget(
self,
widget: QWidget,
row=None,
col=0,
rowspan=1,
colspan=1,
shift: Literal["down", "up", "left", "right"] = "down",
):
if row is None:
row = self.layout.rowCount()
if self.layout_manager.is_position_occupied(row, col):
self.layout_manager.shift_widgets(shift, start_row=row)
self.addWidget(widget, row=row, col=col, rowspan=rowspan, colspan=colspan)
def _remove_from_dock_area(self):