fix(ui): tách hàng Cài đặt khỏi nhóm menu ngay trên nó
CI / test (pull_request) Canceled after 0s

Thanh rail đặt setSpacing(0) nên nút Cài đặt dán sát Dashboard/Giám sát, ba
dòng đọc thành một khối. Thêm hằng _NAV_SETTINGS_GAP trong rail_metrics và
xin khe bằng nvl.addSpacing() — margin trong QSS vẽ BÊN TRONG hộp widget, mà
nút này bị _rebuild_nav ghim đúng chiều cao một dòng menu nên margin không
mua được pixel nào.

Rút gọn lại comment ở _rebuild_nav cho khớp.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 21:27:28 +09:00
co-authored by Claude Opus 5
parent 0efc4bbf0e
commit c05de8054a
3 changed files with 18 additions and 14 deletions
+6 -13
View File
@@ -251,24 +251,17 @@ class NavRailMixin:
blocked = tree.blockSignals(True) blocked = tree.blockSignals(True)
tree.addTopLevelItem(it) tree.addTopLevelItem(it)
tree.blockSignals(blocked) tree.blockSignals(blocked)
# Both destination lists are exactly as tall as their rows; the # Rows plus frame, nothing else: the flat ``+ 8`` this replaces
# stretch in between belongs to RECENTS. # left 6px of dead space under the last row, and since Settings
# # sits directly under nav_bottom it fell between Giám sát and
# The frame, and nothing else. A flat ``+ 8`` here used to leave 6px # Settings alone — 18/26px for rows that read as one list.
# of dead space under the last row of each list, and because the
# Settings button sits DIRECTLY under nav_bottom (nvl has no
# spacing), that space landed between Giám sát and Settings only —
# so three rows that read as one list were spaced 18/26px. Padding
# a row is the item delegate's job; this is the frame's.
row_h = 0 row_h = 0
for tree in (self.nav, self.nav_bottom): for tree in (self.nav, self.nav_bottom):
n = tree.topLevelItemCount() n = tree.topLevelItemCount()
row_h = tree.sizeHintForRow(0) if n else row_h row_h = tree.sizeHintForRow(0) if n else row_h
tree.setFixedHeight(n * row_h + 2 * tree.frameWidth()) tree.setFixedHeight(n * row_h + 2 * tree.frameWidth())
# Settings is one more row of the same list, so it gets the rows' # Settings is one more row of the list, so it takes the rows' own
# own height rather than a second set of paddings guessed to match # height instead of paddings guessed to match it.
# it — the only way the three stay evenly spaced when the font (and
# with it ``sizeHintForRow``) is not the one this was tuned on.
if row_h and hasattr(self, "_nav_settings_btn"): if row_h and hasattr(self, "_nav_settings_btn"):
self._nav_settings_btn.setFixedHeight(row_h) self._nav_settings_btn.setFixedHeight(row_h)
if keep: if keep:
+5
View File
@@ -15,6 +15,11 @@ _NAV_EXPANDED_WIDTH = 232
_NAV_COLLAPSED_WIDTH = 54 _NAV_COLLAPSED_WIDTH = 54
_NAV_ROW_INSET = 4 _NAV_ROW_INSET = 4
_NAV_ROW_GAP = 6 _NAV_ROW_GAP = 6
# Khe TRÊN nút Cài đặt, tính bằng khoảng trống thật trong layout của rail.
# Không đặt bằng ``margin`` trong QSS: margin của stylesheet được vẽ BÊN TRONG
# hộp của widget, mà nút này lại bị ``_rebuild_nav`` ghim đúng chiều cao một
# dòng menu — nên margin không mua được một pixel khoảng cách nào.
_NAV_SETTINGS_GAP = 10
# 132 -> 232: o 132px nhan "Cuoc tro chuyen moi" bi cat mat chu. San phai du # 132 -> 232: o 132px nhan "Cuoc tro chuyen moi" bi cat mat chu. San phai du
# rong cho nhan DAI NHAT tren thanh, khong phai cho nhan trung binh. # rong cho nhan DAI NHAT tren thanh, khong phai cho nhan trung binh.
_NAV_MIN_WIDTH = 232 _NAV_MIN_WIDTH = 232
+7 -1
View File
@@ -35,7 +35,7 @@ class TopBarMixin:
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton
from ...i18n import tr from ...i18n import tr
from ...ui.icons import icon as _icon from ...ui.icons import icon as _icon
from .rail_metrics import _NAV_ROW_GAP, _NAV_ROW_INSET from .rail_metrics import _NAV_ROW_GAP, _NAV_ROW_INSET, _NAV_SETTINGS_GAP
# Bottom-pinned group: the places you visit occasionally, kept out of the # Bottom-pinned group: the places you visit occasionally, kept out of the
# way of the ones you live in. A hairline (styled via #navrailBottom in # way of the ones you live in. A hairline (styled via #navrailBottom in
@@ -71,6 +71,12 @@ class TopBarMixin:
# The first _rebuild_nav() ran before this button existed (it is what # The first _rebuild_nav() ran before this button existed (it is what
# fills the list this row belongs under), so take the height here too. # fills the list this row belongs under), so take the height here too.
self._nav_settings_btn.setFixedHeight(self.nav_bottom.sizeHintForRow(0)) self._nav_settings_btn.setFixedHeight(self.nav_bottom.sizeHintForRow(0))
# Khe TRÊN hàng Cài đặt, xin thẳng từ layout — thanh rail đặt
# ``setSpacing(0)`` nên không có khoảng nào sẵn, và margin trong QSS thì
# không mua được pixel nào (xem ``_NAV_SETTINGS_GAP``). Cài đặt là việc
# khác với nhóm Dashboard/Giám sát ngay trên nó; dán sát vào thì hai thứ
# đọc thành một khối.
nvl.addSpacing(_NAV_SETTINGS_GAP)
nvl.addWidget(self._nav_settings_btn) nvl.addWidget(self._nav_settings_btn)
self._account_row = self._build_account_row() self._account_row = self._build_account_row()