feat: center cards in FlowLayout with equal margins
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
@@ -5,7 +5,7 @@ from PySide6.QtGui import QFont, QFontMetrics, QPainter
|
|||||||
|
|
||||||
def compute_layout(nat_sizes, rect_width, spacing, max_scale):
|
def compute_layout(nat_sizes, rect_width, spacing, max_scale):
|
||||||
"""
|
"""
|
||||||
Вычисляет расположение элементов с учетом отступов и возможного увеличения карточек.
|
Вычисляет расположение элементов с учетом отступов и максимального масштабирования карточек.
|
||||||
nat_sizes: массив (N, 2) с натуральными размерами элементов (ширина, высота).
|
nat_sizes: массив (N, 2) с натуральными размерами элементов (ширина, высота).
|
||||||
rect_width: доступная ширина контейнера.
|
rect_width: доступная ширина контейнера.
|
||||||
spacing: отступ между элементами.
|
spacing: отступ между элементами.
|
||||||
@@ -19,58 +19,63 @@ def compute_layout(nat_sizes, rect_width, spacing, max_scale):
|
|||||||
result = np.zeros((N, 4), dtype=np.int32)
|
result = np.zeros((N, 4), dtype=np.int32)
|
||||||
y = 0
|
y = 0
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
while i < N:
|
while i < N:
|
||||||
sum_width = 0
|
sum_width = 0
|
||||||
row_max_height = 0
|
row_max_height = 0
|
||||||
count = 0
|
count = 0
|
||||||
j = i
|
j = i
|
||||||
# Подбираем количество элементов для текущего ряда
|
|
||||||
|
# Подбираем количество элементов для текущего ряда с учетом max_scale
|
||||||
|
scaled_sizes = nat_sizes * max_scale
|
||||||
while j < N:
|
while j < N:
|
||||||
w = nat_sizes[j, 0]
|
w = scaled_sizes[j, 0]
|
||||||
# Если уже есть хотя бы один элемент и следующий не помещается с учетом spacing, выходим
|
|
||||||
if count > 0 and (sum_width + spacing + w) > rect_width:
|
if count > 0 and (sum_width + spacing + w) > rect_width:
|
||||||
break
|
break
|
||||||
sum_width += w
|
sum_width += w
|
||||||
count += 1
|
count += 1
|
||||||
h = nat_sizes[j, 1]
|
h = scaled_sizes[j, 1]
|
||||||
if h > row_max_height:
|
if h > row_max_height:
|
||||||
row_max_height = h
|
row_max_height = h
|
||||||
j += 1
|
j += 1
|
||||||
# Доступная ширина ряда с учетом обязательных отступов между элементами
|
|
||||||
available_width = rect_width - spacing * (count - 1)
|
# Вычисляем общую ширину ряда включая отступы
|
||||||
desired_scale = available_width / sum_width if sum_width > 0 else 1.0
|
total_row_width = sum_width + spacing * (count - 1)
|
||||||
# Разрешаем увеличение карточек, но не более max_scale
|
|
||||||
scale = desired_scale if desired_scale < max_scale else max_scale
|
# Вычисляем смещение для центрирования ряда
|
||||||
# Выравниваем по левому краю (offset = 0)
|
x_offset = (rect_width - total_row_width) // 2
|
||||||
x = 0
|
|
||||||
|
# Размещаем элементы в ряду с центрированием
|
||||||
|
x = x_offset
|
||||||
for k in range(i, j):
|
for k in range(i, j):
|
||||||
new_w = int(nat_sizes[k, 0] * scale)
|
new_w = int(nat_sizes[k, 0] * max_scale)
|
||||||
new_h = int(nat_sizes[k, 1] * scale)
|
new_h = int(nat_sizes[k, 1] * max_scale)
|
||||||
result[k, 0] = x
|
result[k, 0] = x
|
||||||
result[k, 1] = y
|
result[k, 1] = y
|
||||||
result[k, 2] = new_w
|
result[k, 2] = new_w
|
||||||
result[k, 3] = new_h
|
result[k, 3] = new_h
|
||||||
x += new_w + spacing
|
x += new_w + spacing
|
||||||
y += int(row_max_height * scale) + spacing
|
|
||||||
|
y += int(row_max_height) + spacing
|
||||||
i = j
|
i = j
|
||||||
|
|
||||||
return result, y
|
return result, y
|
||||||
|
|
||||||
class FlowLayout(QLayout):
|
class FlowLayout(QLayout):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.itemList = []
|
self.itemList = []
|
||||||
# Устанавливаем отступы контейнера в 0 и задаем spacing между карточками
|
|
||||||
self.setContentsMargins(0, 0, 0, 0)
|
self.setContentsMargins(0, 0, 0, 0)
|
||||||
self._spacing = 3 # отступ между карточками
|
self._spacing = 3
|
||||||
self._max_scale = 1.2 # максимальное увеличение карточек (например, на 20%)
|
self._max_scale = 1.2
|
||||||
|
|
||||||
def addItem(self, item: QLayoutItem) -> None:
|
def addItem(self, item: QLayoutItem) -> None:
|
||||||
self.itemList.append(item)
|
self.itemList.append(item)
|
||||||
|
|
||||||
def takeAt(self, index: int) -> QLayoutItem:
|
def takeAt(self, index: int) -> QLayoutItem:
|
||||||
if 0 <= index < len(self.itemList):
|
if 0 <= index < len(self.itemList):
|
||||||
return self.itemList.pop(index)
|
return self.itemList.pop(index)
|
||||||
raise IndexError("Index out of range")
|
raise IndexError("Index out of range")
|
||||||
|
|
||||||
def count(self) -> int:
|
def count(self) -> int:
|
||||||
return len(self.itemList)
|
return len(self.itemList)
|
||||||
@@ -99,10 +104,12 @@ class FlowLayout(QLayout):
|
|||||||
def minimumSize(self):
|
def minimumSize(self):
|
||||||
size = QSize()
|
size = QSize()
|
||||||
for item in self.itemList:
|
for item in self.itemList:
|
||||||
size = size.expandedTo(item.minimumSize())
|
# Учитываем максимальный масштаб при расчете минимального размера
|
||||||
|
item_size = item.sizeHint()
|
||||||
|
scaled_size = QSize(int(item_size.width() * self._max_scale), int(item_size.height() * self._max_scale))
|
||||||
|
size = size.expandedTo(scaled_size)
|
||||||
margins = self.contentsMargins()
|
margins = self.contentsMargins()
|
||||||
size += QSize(margins.left() + margins.right(),
|
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom())
|
||||||
margins.top() + margins.bottom())
|
|
||||||
return size
|
return size
|
||||||
|
|
||||||
def doLayout(self, rect, testOnly):
|
def doLayout(self, rect, testOnly):
|
||||||
@@ -110,14 +117,12 @@ class FlowLayout(QLayout):
|
|||||||
if N == 0:
|
if N == 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Собираем натуральные размеры всех элементов в массив NumPy
|
|
||||||
nat_sizes = np.empty((N, 2), dtype=np.int32)
|
nat_sizes = np.empty((N, 2), dtype=np.int32)
|
||||||
for i, item in enumerate(self.itemList):
|
for i, item in enumerate(self.itemList):
|
||||||
s = item.sizeHint()
|
s = item.sizeHint()
|
||||||
nat_sizes[i, 0] = s.width()
|
nat_sizes[i, 0] = s.width()
|
||||||
nat_sizes[i, 1] = s.height()
|
nat_sizes[i, 1] = s.height()
|
||||||
|
|
||||||
# Вычисляем геометрию с учетом spacing и max_scale через numba-функцию
|
|
||||||
geom_array, total_height = compute_layout(nat_sizes, rect.width(), self._spacing, self._max_scale)
|
geom_array, total_height = compute_layout(nat_sizes, rect.width(), self._spacing, self._max_scale)
|
||||||
|
|
||||||
if not testOnly:
|
if not testOnly:
|
||||||
|
Reference in New Issue
Block a user