This commit is contained in:
Nolan Kovacs 2026-04-04 14:20:37 -04:00
parent 0de9beec8e
commit 6bc851b03c
2 changed files with 44 additions and 38 deletions

80
dist/screener_gui.py vendored
View File

@ -1494,30 +1494,29 @@ class _MetricRow(QWidget):
self.val_lbl.setStyleSheet(f"color:{c}; font-size:12px; font-family:'Consolas';")
def _make_scroll_tab(fields):
"""Return (QWidget tab, dict of key->_MetricRow)."""
def _make_grid_tab(fields, cols=2):
"""Return (QWidget tab, dict of key->MetricCell) using 2-col metric card grid."""
tab = QWidget()
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.NoFrame)
inner = QWidget()
lay = QVBoxLayout(inner)
lay.setContentsMargins(0, 4, 0, 4)
lay.setSpacing(0)
rows = {}
for label, key in fields:
row_w = _MetricRow(label, key)
rows[key] = row_w
lay.addWidget(row_w)
sep = QFrame(); sep.setFixedHeight(1)
sep.setStyleSheet(f"background:{_C['border']};")
lay.addWidget(sep)
lay.addStretch()
lay = QGridLayout(inner)
lay.setContentsMargins(10, 10, 10, 10)
lay.setSpacing(6)
cells = {}
for i, (label, key) in enumerate(fields):
tip = _METRIC_TOOLTIPS.get(label, "")
cell = MetricCell(label, key, tip)
cells[key] = cell
lay.addWidget(cell, i // cols, i % cols)
# stretch the last row so cards stay top-aligned
lay.setRowStretch((len(fields) - 1) // cols + 1, 1)
scroll.setWidget(inner)
outer = QVBoxLayout(tab)
outer.setContentsMargins(0, 0, 0, 0)
outer.addWidget(scroll)
return tab, rows
return tab, cells
class DetailPanel(QWidget):
@ -1560,43 +1559,41 @@ class DetailPanel(QWidget):
self._tabs.addTab(self._score_tab, "Scores")
# Valuation
t, rows = _make_scroll_tab(_VAL_FIELDS)
self._all_rows.update(rows)
t, cells = _make_grid_tab(_VAL_FIELDS)
self._all_rows.update(cells)
self._tabs.addTab(t, "Valuation")
# Growth
t, rows = _make_scroll_tab(_GROWTH_FIELDS)
self._all_rows.update(rows)
t, cells = _make_grid_tab(_GROWTH_FIELDS)
self._all_rows.update(cells)
self._tabs.addTab(t, "Growth")
# Momentum
t, rows = _make_scroll_tab(_MOM_FIELDS)
self._all_rows.update(rows)
t, cells = _make_grid_tab(_MOM_FIELDS)
self._all_rows.update(cells)
self._tabs.addTab(t, "Momentum")
# Quality & Profit
t, rows = _make_scroll_tab(_QUAL_FIELDS)
self._all_rows.update(rows)
t, cells = _make_grid_tab(_QUAL_FIELDS)
self._all_rows.update(cells)
self._tabs.addTab(t, "Quality & Profit")
# Analyst tab (metrics + commentary)
# Analyst tab (metric grid + commentary)
analyst_tab = QWidget()
al = QVBoxLayout(analyst_tab)
al.setContentsMargins(0, 0, 0, 0)
al.setSpacing(0)
# Metrics in a small scrollable area
anlst_inner = QWidget()
anlst_lay = QVBoxLayout(anlst_inner)
anlst_lay.setContentsMargins(0, 4, 0, 4)
anlst_lay.setSpacing(0)
for label, key in _ANLST_FIELDS:
row_w = _MetricRow(label, key)
self._all_rows[key] = row_w
anlst_lay.addWidget(row_w)
sep2 = QFrame(); sep2.setFixedHeight(1)
sep2.setStyleSheet(f"background:{_C['border']};")
anlst_lay.addWidget(sep2)
al.addWidget(anlst_inner)
# Metrics as a 2-col grid
anlst_grid_w = QWidget()
anlst_grid_lay = QGridLayout(anlst_grid_w)
anlst_grid_lay.setContentsMargins(10, 10, 10, 6)
anlst_grid_lay.setSpacing(6)
for i, (label, key) in enumerate(_ANLST_FIELDS):
tip = _METRIC_TOOLTIPS.get(label, "")
cell = MetricCell(label, key, tip)
self._all_rows[key] = cell
anlst_grid_lay.addWidget(cell, i // 2, i % 2)
al.addWidget(anlst_grid_w)
hdiv = QFrame(); hdiv.setFixedHeight(1)
hdiv.setStyleSheet(f"background:{_C['border']};")
@ -2044,6 +2041,7 @@ class ScreenerPage(QWidget):
self._run_btn.setEnabled(True)
self._stop_btn.setEnabled(False)
self._progress.hide()
QMessageBox.critical(self, "Screen Error", f"The screening run failed:\n\n{text}")
@Slot()
def _on_stopped(self):
@ -2054,6 +2052,14 @@ class ScreenerPage(QWidget):
def _apply_filters(self):
if self._df is None: return
try:
self._apply_filters_inner()
except Exception as exc:
import traceback
QMessageBox.critical(self, "Display Error",
f"Failed to display results:\n\n{traceback.format_exc()}")
def _apply_filters_inner(self):
df = self._df
rule = _SECTOR_FILTER_MAP.get(self._sector_cb.currentText())
if rule:

View File

@ -19,7 +19,7 @@ import requests
# ---------------------------------------------------------------------------
# Current app version — kept in sync by push_update.py before each build.
# ---------------------------------------------------------------------------
APP_VERSION = "1.4.3"
APP_VERSION = "1.4.4"
def _exe_dir() -> str: