2727# Keep live engine instances to support dynamic interactions (e.g., i18n refresh)
2828_INSTANCES : dict [str , CompilerEngine ] = {}
2929
30+ # Default scroll behavior for engine tabs: wrap in a scroll area so large
31+ # option panels stay usable without bloating the overall UI.
32+ _ENGINE_TAB_SCROLL_MAX_HEIGHT : Optional [int ] = None
33+
3034# Language code aliases for normalization
3135_LANG_ALIASES : dict [str , str ] = {
3236 "en-us" : "en" ,
@@ -215,6 +219,40 @@ def bind_tabs(gui) -> None:
215219 # Track if any engine created a tab
216220 any_engine_tab_created = False
217221
222+ def _wrap_tab_scroll (widget ):
223+ try :
224+ from PySide6 .QtCore import Qt
225+ from PySide6 .QtWidgets import QFrame , QScrollArea , QSizePolicy
226+
227+ if isinstance (widget , QScrollArea ):
228+ scroll = widget
229+ else :
230+ scroll = QScrollArea ()
231+ scroll .setWidget (widget )
232+
233+ scroll .setWidgetResizable (True )
234+ scroll .setFrameShape (QFrame .Shape .NoFrame )
235+ scroll .setHorizontalScrollBarPolicy (Qt .ScrollBarAsNeeded )
236+ scroll .setVerticalScrollBarPolicy (Qt .ScrollBarAsNeeded )
237+ scroll .setSizePolicy (QSizePolicy .Expanding , QSizePolicy .Expanding )
238+
239+ if _ENGINE_TAB_SCROLL_MAX_HEIGHT :
240+ try :
241+ scroll .setMaximumHeight (int (_ENGINE_TAB_SCROLL_MAX_HEIGHT ))
242+ except Exception :
243+ pass
244+
245+ try :
246+ name = widget .objectName ()
247+ if name :
248+ scroll .setObjectName (f"{ name } _scroll" )
249+ except Exception :
250+ pass
251+
252+ return scroll
253+ except Exception :
254+ return widget
255+
218256 for eid in list (_ORDER ):
219257 try :
220258 engine = create (eid )
@@ -228,6 +266,7 @@ def bind_tabs(gui) -> None:
228266 continue
229267 any_engine_tab_created = True
230268 widget , label = pair
269+ widget = _wrap_tab_scroll (widget )
231270 try :
232271 existing = tabs .indexOf (widget )
233272 except Exception :
0 commit comments