platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
61
selective-vpn-gui/main_window/ui_helpers_mixin.py
Normal file
61
selective-vpn-gui/main_window/ui_helpers_mixin.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from PySide6.QtGui import QTextCursor
|
||||
from PySide6.QtWidgets import QMessageBox, QPlainTextEdit
|
||||
|
||||
from main_window.constants import _NEXT_CHECK_RE
|
||||
|
||||
|
||||
class UIHelpersMixin:
|
||||
def _safe(self, fn, *, title: str = "Error"):
|
||||
try:
|
||||
return fn()
|
||||
except Exception as e: # pragma: no cover - GUI
|
||||
try:
|
||||
self.ctrl.log_gui(f"[ui-error] {title}: {e}")
|
||||
except Exception:
|
||||
pass
|
||||
QMessageBox.critical(self, title, str(e))
|
||||
return None
|
||||
|
||||
def _set_text(self, widget: QPlainTextEdit, text: str, *, preserve_scroll: bool = False) -> None:
|
||||
"""Set text, optionally сохраняя положение скролла (для trace)."""
|
||||
if not preserve_scroll:
|
||||
widget.setPlainText(text)
|
||||
return
|
||||
|
||||
sb = widget.verticalScrollBar()
|
||||
old_max = sb.maximum()
|
||||
old_val = sb.value()
|
||||
at_end = old_val >= old_max - 2
|
||||
|
||||
widget.setPlainText(text)
|
||||
|
||||
new_max = sb.maximum()
|
||||
if at_end:
|
||||
sb.setValue(new_max)
|
||||
else:
|
||||
# подвинем на ту же относительную позицию, учитывая прирост размера
|
||||
sb.setValue(max(0, min(new_max, old_val+(new_max-old_max))))
|
||||
|
||||
def _append_text(self, widget: QPlainTextEdit, text: str) -> None:
|
||||
cursor = widget.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
cursor.insertText(text)
|
||||
widget.setTextCursor(cursor)
|
||||
widget.ensureCursorVisible()
|
||||
|
||||
def _clean_ui_lines(self, lines) -> str:
|
||||
buf = "\n".join([str(x) for x in (lines or [])]).replace("\r", "\n")
|
||||
out_lines = []
|
||||
for ln in buf.splitlines():
|
||||
t = ln.strip()
|
||||
if not t:
|
||||
continue
|
||||
t2 = _NEXT_CHECK_RE.sub("", t).strip()
|
||||
if not t2:
|
||||
continue
|
||||
out_lines.append(t2)
|
||||
return "\n".join(out_lines).rstrip()
|
||||
Reference in New Issue
Block a user