diff --git a/tools/check_cowork_screen.py b/tools/check_cowork_screen.py index a7331be..5e54e74 100644 --- a/tools/check_cowork_screen.py +++ b/tools/check_cowork_screen.py @@ -87,6 +87,47 @@ def main() -> int: fails.append(f"thieu nut {name} tren thanh cong cu") print(f"nut tren thanh cong cu: {c.skills_btn.text()!r}, {c._new_btn.text()!r}") + # one heading on the files panel, with the chevron at its right — the + # drawing has "TỆP ĐẦU RA (3) ›" and nothing above it + from PySide6.QtCore import QPoint as _QP + + hdr_w = c.output_section.header + chev = c._io_collapse_btn + same_row = abs(hdr_w.mapTo(c, _QP(0, 0)).y() - chev.mapTo(c, _QP(0, 0)).y()) <= 8 + chev_right = chev.mapTo(c, _QP(0, 0)).x() > hdr_w.mapTo(c, _QP(0, 0)).x() + # Count what the panel actually shows as headings. Asking whether the old + # label is visible proved nothing: unparented, it reports invisible whether + # or not the code hides it. + from PySide6.QtWidgets import QLabel + + heads = [l.text() for l in c._io_widget.findChildren(QLabel) + if l.isVisible() and l.text().strip()] + print(f"tieu de hien trong pane: {heads} | " + f"chevron cung hang={same_row} ben phai={chev_right}") + if heads: + fails.append(f"pane co tieu de thua ngoai '{hdr_w.text()}': {heads}") + if not (same_row and chev_right): + fails.append("chevron thu gon khong nam cuoi hang tieu de pane") + + # the composer spans the screen, under BOTH columns — inside the chat + # column it stopped at the files panel's edge and shrank when files arrived + from PySide6.QtCore import QPoint + + c._set_io_collapsed(False) + app.processEvents() + split = c.center_split + files_pane = split.widget(1) + comp_right = c.composer.mapTo(c, QPoint(c.composer.width(), 0)).x() + files_left = files_pane.mapTo(c, QPoint(0, 0)).x() + below = c.composer.mapTo(c, QPoint(0, 0)).y() > split.mapTo(c, QPoint(0, 0)).y() + spans = comp_right > files_left + print(f"o nhap: rong {c.composer.width()} / man {c.width()} | " + f"duoi splitter={below} | trai qua duoi pane tep={spans}") + if not below: + fails.append("o nhap khong nam duoi hang than") + if not spans: + fails.append("o nhap dung lai o mep pane tep, khong trai het man") + print() for f in fails: print("FAIL " + f) diff --git a/ui/chat_panel.py b/ui/chat_panel.py index f8e8ef7..e19bb86 100644 --- a/ui/chat_panel.py +++ b/ui/chat_panel.py @@ -190,15 +190,20 @@ class ChatPanel(QWidget): cc.addWidget(self.chat_view, 1) self.thinking = ThinkingIndicator() # animated "working…" line while we wait cc.addWidget(self.thinking) + self.center_split = QSplitter(Qt.Horizontal) + self.center_split.addWidget(chat_col) + root.addWidget(self.center_split, 1) + + # The composer spans the whole screen, under BOTH columns — that is how + # the drawing lays it out, and it is the reason the files panel can sit + # beside the transcript without narrowing what you type into. Inside the + # chat column it stopped at the panel's edge and the input shrank + # whenever files appeared. composer_wrap = QWidget() cwl = QVBoxLayout(composer_wrap) cwl.setContentsMargins(8, 4, 8, 8) cwl.addWidget(self.composer) - cc.addWidget(composer_wrap) - - self.center_split = QSplitter(Qt.Horizontal) - self.center_split.addWidget(chat_col) - root.addWidget(self.center_split, 1) + root.addWidget(composer_wrap) # Right sidebar: Output files only (see below — Input is tracked but # not shown). @@ -243,8 +248,15 @@ class ChatPanel(QWidget): self._io_collapse_btn.clicked.connect(lambda: self._set_io_collapsed(True)) self._files_header = QLabel() self._files_header.setStyleSheet("font-weight:600;") + # The drawing gives this panel ONE heading — "TỆP ĐẦU RA (3) ›" — and + # the section already draws exactly that, count included. A separate + # "Files" label above it was the same thing said twice, so the section's + # own header moves onto this row and the collapse chevron sits at its + # right, where the drawing puts it. _files_header stays for the tabs + # that still label their panel, just not in this layout. + self._files_header.setVisible(False) + io_hdr.addWidget(self.output_section.header, 1) io_hdr.addWidget(self._io_collapse_btn) - io_hdr.addWidget(self._files_header, 1) # The plan now shows INLINE in the conversation (an expandable block whose # steps tick off as they complete), not in this right panel — so it's kept # out of the layout here. The object stays (its set_steps/clear calls are