mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-09-29 02:18:02 +03:00
Refine Hysteria2 editor layout
Signed-off-by: Loren Eteval <loren.eteval@proton.me>
This commit is contained in:
@@ -194,7 +194,10 @@ class GuiHy2InlineBindings(EditorWidgetBinding):
|
||||
|
||||
def __init__(self, *bindings: EditorWidgetBinding, **kwargs):
|
||||
"""Create one persistent row that owns the supplied labeled controls."""
|
||||
expandInputs = kwargs.pop('expandInputs', True)
|
||||
expandInputs, spacing = (
|
||||
kwargs.pop('expandInputs', True),
|
||||
kwargs.pop('spacing', 12),
|
||||
)
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -203,14 +206,11 @@ class GuiHy2InlineBindings(EditorWidgetBinding):
|
||||
|
||||
layout = QHBoxLayout(self._widget)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(12)
|
||||
layout.setSpacing(spacing)
|
||||
|
||||
for index, binding in enumerate(self.bindings):
|
||||
for binding in self.bindings:
|
||||
title, inputWidget = binding.widgets()
|
||||
|
||||
if index:
|
||||
layout.addSpacing(6)
|
||||
|
||||
layout.addWidget(title)
|
||||
layout.addWidget(inputWidget, 1 if expandInputs else 0)
|
||||
|
||||
@@ -978,6 +978,7 @@ class GuiHy2GroupBoxAdvanced(GuiEditorWidgetQGroupBox):
|
||||
self.chromeParrotItem,
|
||||
self.mimicEnabledItem,
|
||||
expandInputs=False,
|
||||
spacing=8,
|
||||
)
|
||||
|
||||
return [
|
||||
@@ -1064,6 +1065,35 @@ class Hysteria2Editor(GuiEditorWidgetQDialog):
|
||||
|
||||
self.setTabText(Protocol.Hysteria2.value)
|
||||
|
||||
def _fitAdvancedOptionsRow(self):
|
||||
"""Honor the styled editor and options row's natural widths."""
|
||||
row = self.advancedGroup.optionsRow._widget
|
||||
trailingSpace = max(0, row.layout().spacing())
|
||||
rowWidthDeficit = max(
|
||||
0,
|
||||
row.sizeHint().width() + trailingSpace - row.contentsRect().width(),
|
||||
)
|
||||
requiredWidth = max(
|
||||
self.minimumSizeHint().width(),
|
||||
self.width() + rowWidthDeficit,
|
||||
)
|
||||
|
||||
if requiredWidth <= self.width():
|
||||
return
|
||||
|
||||
# The shared editor starts from a compact golden-ratio size. Font and
|
||||
# style metrics can require more room for the complete form or this
|
||||
# technical row; grow to that measured requirement instead of clipping
|
||||
# a label or introducing a platform-specific width.
|
||||
self.setFixedWidth(requiredWidth)
|
||||
self.tabCentralWidgetLayout.activate()
|
||||
|
||||
def showEvent(self, event):
|
||||
"""Resolve the styled section geometry before the first frame is drawn."""
|
||||
super().showEvent(event)
|
||||
|
||||
self._fitAdvancedOptionsRow()
|
||||
|
||||
def createGroupBoxSequence(self):
|
||||
"""Create the configuration group boxes in display order."""
|
||||
self.basicGroup, self.advancedGroup = (
|
||||
|
||||
@@ -30,8 +30,12 @@ from Furious.Backends.Hysteria2.Editor import (
|
||||
)
|
||||
from Furious.Backends.Hysteria2.Process import Hysteria2
|
||||
from Furious.Backends.Hysteria2.Protocols import Hysteria2ProtocolHandler
|
||||
from Furious.Backends.Hysteria2.TunSettingsDialog import (
|
||||
GuiHysteria2TUNSettingsGroupBoxInterface,
|
||||
)
|
||||
from Furious.Frozenlib import AppSettings, Mixins
|
||||
from Furious.Models.Profile import ServerProfile
|
||||
from Furious.Qt import AppStyleSheet
|
||||
|
||||
from tests.support import (
|
||||
application,
|
||||
@@ -272,6 +276,120 @@ class Hysteria2CompatibilityTest(unittest.TestCase):
|
||||
|
||||
editor.close()
|
||||
|
||||
def testOriginalSectionInsetsContainNaturalAdvancedOptionsRow(self):
|
||||
"""Restore canonical editor insets while containing compact options."""
|
||||
app = application()
|
||||
previousStyleSheet = app.styleSheet()
|
||||
|
||||
try:
|
||||
for theme in (AppStyleSheet.Light, AppStyleSheet.Dark):
|
||||
with self.subTest(theme=theme):
|
||||
app.setStyleSheet(AppStyleSheet.forTheme(theme))
|
||||
editor = Hysteria2Editor()
|
||||
editor.show()
|
||||
app.processEvents()
|
||||
|
||||
self.assertGreaterEqual(
|
||||
editor.width(), editor.minimumSizeHint().width()
|
||||
)
|
||||
self.assertGreaterEqual(
|
||||
editor.height(), editor.minimumSizeHint().height()
|
||||
)
|
||||
|
||||
basic, proxyBandwidth, advanced, tls = editor.groupBoxSequence()
|
||||
referenceGroup = GuiHysteria2TUNSettingsGroupBoxInterface(
|
||||
parent=editor
|
||||
)
|
||||
referenceSectionMargins = referenceGroup.layout().contentsMargins()
|
||||
referencePageMargins = (
|
||||
referenceGroup._widget.currentWidget()
|
||||
.layout()
|
||||
.contentsMargins()
|
||||
)
|
||||
firstWidgets = (
|
||||
basic._containers[0]._title,
|
||||
proxyBandwidth.proxyFields.bindings[0]._title,
|
||||
advanced.obfsItem.page(advanced.obfsItem.currentIndex())
|
||||
._containers[0]
|
||||
._title,
|
||||
tls._containers[0]._title,
|
||||
)
|
||||
|
||||
for group in editor.groupBoxSequence():
|
||||
sectionMargins = group.layout().contentsMargins()
|
||||
pageMargins = (
|
||||
group._widget.currentWidget().layout().contentsMargins()
|
||||
)
|
||||
|
||||
self.assertEqual(sectionMargins, referenceSectionMargins)
|
||||
self.assertEqual(pageMargins, referencePageMargins)
|
||||
self.assertGreater(pageMargins.left(), 0)
|
||||
self.assertEqual(pageMargins.left(), pageMargins.right())
|
||||
self.assertEqual(pageMargins.top(), pageMargins.bottom())
|
||||
|
||||
firstPositions = tuple(
|
||||
widget.mapTo(group, widget.rect().topLeft()).x()
|
||||
for group, widget in zip(
|
||||
editor.groupBoxSequence(), firstWidgets
|
||||
)
|
||||
)
|
||||
self.assertEqual(len(set(firstPositions)), 1)
|
||||
|
||||
row = advanced.optionsRow._widget
|
||||
rowLayout = row.layout()
|
||||
widgets = tuple(
|
||||
widget
|
||||
for binding in advanced.optionsRow.bindings
|
||||
for widget in binding.widgets()
|
||||
)
|
||||
|
||||
self.assertEqual(rowLayout.contentsMargins().left(), 0)
|
||||
self.assertEqual(rowLayout.contentsMargins().right(), 0)
|
||||
self.assertEqual(rowLayout.spacing(), 8)
|
||||
self.assertIsNotNone(
|
||||
rowLayout.itemAt(rowLayout.count() - 1).spacerItem()
|
||||
)
|
||||
self.assertLessEqual(
|
||||
row.sizeHint().width() + rowLayout.spacing(),
|
||||
row.contentsRect().width(),
|
||||
)
|
||||
|
||||
previousRight = row.contentsRect().left()
|
||||
|
||||
for widget in widgets:
|
||||
topLeft = widget.mapTo(row, widget.rect().topLeft())
|
||||
right = topLeft.x() + widget.width()
|
||||
requiredWidth = min(
|
||||
widget.minimumSizeHint().width(),
|
||||
widget.maximumWidth(),
|
||||
)
|
||||
|
||||
self.assertTrue(widget.isVisible())
|
||||
self.assertGreaterEqual(widget.width(), requiredWidth)
|
||||
self.assertGreaterEqual(topLeft.x(), previousRight)
|
||||
self.assertLessEqual(right, row.contentsRect().right() + 1)
|
||||
|
||||
previousRight = right
|
||||
|
||||
self.assertGreaterEqual(
|
||||
row.contentsRect().right() + 1 - previousRight,
|
||||
rowLayout.spacing(),
|
||||
)
|
||||
|
||||
mimicSwitch = advanced.mimicEnabledItem._input
|
||||
mimicRight = (
|
||||
mimicSwitch.mapTo(advanced, mimicSwitch.rect().topLeft()).x()
|
||||
+ mimicSwitch.width()
|
||||
)
|
||||
|
||||
self.assertLessEqual(
|
||||
mimicRight, advanced.contentsRect().right() + 1
|
||||
)
|
||||
|
||||
editor.close()
|
||||
finally:
|
||||
app.setStyleSheet(previousStyleSheet)
|
||||
|
||||
def testEditorWritesSemanticEnumsAndPositiveChromeToggle(self):
|
||||
"""Persist upstream values rather than translated display labels."""
|
||||
profile = self.profile({'server': 'example.com:443', 'auth': 'secret'})
|
||||
|
||||
Reference in New Issue
Block a user