From 8048b2be2f2e450692f8a820a91af6025995f88f Mon Sep 17 00:00:00 2001 From: "Flora (opencode)" Date: Mon, 17 Aug 2026 18:15:22 +0300 Subject: [PATCH] =?UTF-8?q?Fix:=20=D0=BA=D0=BE=D1=80=D0=B5=D0=BD=D1=8C=20E?= =?UTF-8?q?ditorPanel=20=E2=80=94=20ColumnLayout=20=D0=B2=D0=BC=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=BE=20Item=20(=D0=B8=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20layout=20=D0=B2=20SplitView:?= =?UTF-8?q?=20=D0=B2=D0=BA=D0=BB=D0=B0=D0=B4=D0=BA=D0=B8=20=D1=81=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=85=D1=83,=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=20=D1=81=D0=BD=D0=B8=D0=B7=D1=83);=20=D1=83?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=BD=D0=B0=20=D0=BE=D0=B1=D1=91=D1=80=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20Item;=20color:text=20=D0=BD=D0=B0=20TextArea;=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BE=D1=82=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B2=D0=BE=D0=B3=D0=BE=20.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qml/panels/EditorPanel.qml | 310 ++++++++++++++++++------------------- 1 file changed, 149 insertions(+), 161 deletions(-) diff --git a/qml/panels/EditorPanel.qml b/qml/panels/EditorPanel.qml index 5f0a0cf..db8e5bc 100644 --- a/qml/panels/EditorPanel.qml +++ b/qml/panels/EditorPanel.qml @@ -3,8 +3,9 @@ import QtQuick.Controls import QtQuick.Layouts // Центральная панель: панель вкладок + редактор. -// Поддержка двух панелей рядом («открыть рядом»): правая = вторая вкладка. -Item { +// Корень — ColumnLayout (без обёртки Item), чтобы SplitView корректно +// задавал размеры и вкладки были сверху, а редактор снизу. +ColumnLayout { id: root function baseName(p) { @@ -12,161 +13,17 @@ Item { return idx >= 0 ? p.substring(idx + 1) : p } - ColumnLayout { - anchors.fill: parent - spacing: 0 - - // ----- Панель вкладок ----- - Rectangle { - Layout.fillWidth: true - implicitHeight: 32 - color: "#ececec" - - RowLayout { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - spacing: 2 - - Repeater { - model: documentManager.openTabs - - Rectangle { - id: tab - required property string modelData - required property int index - readonly property bool active: index === documentManager.activeIndex - width: Math.max(96, Math.min(200, tabLabel.implicitWidth + 44)) - height: 26 - radius: 4 - color: active ? "white" : "#e0e0e0" - - RowLayout { - anchors.fill: parent - anchors.leftMargin: 8 - anchors.rightMargin: 2 - spacing: 4 - - MouseArea { - Layout.fillWidth: true - Layout.fillHeight: true - onClicked: documentManager.setActiveIndex(index) - onDoubleClicked: documentManager.closeTab(index) - - Label { - id: tabLabel - anchors.verticalCenter: parent.verticalCenter - text: root.baseName(tab.modelData) - + (documentManager.isDirty(tab.index) ? " •" : "") - font.pixelSize: 12 - color: tab.active ? "#111" : "#555" - } - } - - ToolButton { - text: "\u2715" - implicitWidth: 20 - implicitHeight: 20 - font.pixelSize: 9 - opacity: tab.active || hovered ? 1 : 0 - onClicked: documentManager.closeTab(tab.index) - } - } - } - } - - Item { Layout.fillWidth: true } - - Label { - visible: documentManager.openTabs.length === 0 - text: qsTr("Откройте файл из дерева") - color: "#999" - font.pixelSize: 12 - } - - ToolButton { - id: splitBtn - text: "\u25A1\u25A1" - checkable: true - checked: documentManager.sideBySide - enabled: documentManager.openTabs.length > 0 - ToolTip.visible: hovered - ToolTip.text: qsTr("Открыть рядом (две панели)") - onToggled: { - if (checked) { - documentManager.setSecondaryIndex(documentManager.activeIndex) - documentManager.setSideBySide(true) - } else { - documentManager.setSideBySide(false) - } - } - } - } - } - - // ----- Панель форматирования (Фаза 5) ----- - FormatToolbar { - id: formatToolbar - Layout.fillWidth: true - visible: documentManager.activeIndex >= 0 && toolbarShouldShow() - targetPane: activePane() - onTableRequested: { - tableEditor.resetDialog() - tableEditor.open() - } - } - - // ----- Область редактора (одна или две панели) ----- - RowLayout { - Layout.fillWidth: true - Layout.fillHeight: true - spacing: 0 - - EditorPane { - id: primaryPane - Layout.fillWidth: true - docIndex: documentManager.activeIndex - canOpenBeside: true - onOpenBeside: { - documentManager.setSecondaryIndex(documentManager.activeIndex) - documentManager.setSideBySide(true) - splitBtn.checked = true - } - } - - Rectangle { - visible: documentManager.sideBySide - Layout.fillHeight: true - width: 1 - color: "#ccc" - } - - EditorPane { - id: secondaryPane - visible: documentManager.sideBySide - Layout.preferredWidth: 360 - Layout.maximumWidth: 640 - docIndex: documentManager.secondaryIndex - closable: true - onClosePane: { - documentManager.setSideBySide(false) - splitBtn.checked = false - } - } - } - } - - // ----- Функции активной панели и таблица ----- function activePane() { if (secondaryPane.visible && secondaryPane.hasFocus) return secondaryPane return primaryPane } + function toolbarShouldShow() { const p = primaryPane const s = secondaryPane - return (p.hasFocus && p.editMode) - || (s.visible && s.hasFocus && s.editMode) + return p.editMode + || (s.visible && s.editMode) } Connections { @@ -180,32 +37,163 @@ Item { TableEditor { id: tableEditor - onMarkdownReady: (md) => { - root.activePane().insertText(md) + onMarkdownReady: (md) => root.activePane().insertText(md) + } + + // ---------- Панель вкладок ---------- + Rectangle { + Layout.fillWidth: true + implicitHeight: 32 + color: "#ececec" + + RowLayout { + anchors.fill: parent + anchors.leftMargin: 4 + anchors.rightMargin: 4 + spacing: 2 + + Repeater { + model: documentManager.openTabs + + Rectangle { + id: tab + required property string modelData + required property int index + readonly property bool active: index === documentManager.activeIndex + width: Math.max(96, Math.min(200, tabLabel.implicitWidth + 44)) + height: 26 + radius: 4 + color: active ? "white" : "#e0e0e0" + + RowLayout { + anchors.fill: parent + anchors.leftMargin: 8 + anchors.rightMargin: 2 + spacing: 4 + + MouseArea { + Layout.fillWidth: true + Layout.fillHeight: true + onClicked: documentManager.setActiveIndex(index) + onDoubleClicked: documentManager.closeTab(index) + + Label { + id: tabLabel + anchors.verticalCenter: parent.verticalCenter + text: root.baseName(tab.modelData) + + (documentManager.isDirty(tab.index) ? " •" : "") + font.pixelSize: 12 + color: tab.active ? "#111" : "#555" + } + } + + ToolButton { + text: "\u2715" + implicitWidth: 20 + implicitHeight: 20 + font.pixelSize: 9 + opacity: tab.active || hovered ? 1 : 0 + onClicked: documentManager.closeTab(tab.index) + } + } + } + } + + Item { Layout.fillWidth: true } + + Label { + visible: documentManager.openTabs.length === 0 + text: qsTr("Откройте файл из дерева") + color: "#999" + font.pixelSize: 12 + } + + ToolButton { + id: splitBtn + text: "\u25A1\u25A1" + checkable: true + checked: documentManager.sideBySide + enabled: documentManager.openTabs.length > 0 + ToolTip.visible: hovered + ToolTip.text: qsTr("Открыть рядом (две панели)") + onToggled: { + if (checked) { + documentManager.setSecondaryIndex(documentManager.activeIndex) + documentManager.setSideBySide(true) + } else { + documentManager.setSideBySide(false) + } + } + } } } - // ----- Горячие клавиши ----- + // ---------- Панель форматирования ---------- + FormatToolbar { + id: formatToolbar + Layout.fillWidth: true + visible: documentManager.activeIndex >= 0 && toolbarShouldShow() + targetPane: activePane() + onTableRequested: { + tableEditor.resetDialog() + tableEditor.open() + } + } + + // ---------- Область редактора (одна или две панели) ---------- + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: true + spacing: 0 + + EditorPane { + id: primaryPane + Layout.fillWidth: true + docIndex: documentManager.activeIndex + canOpenBeside: true + onOpenBeside: { + documentManager.setSecondaryIndex(documentManager.activeIndex) + documentManager.setSideBySide(true) + splitBtn.checked = true + } + } + + Rectangle { + visible: documentManager.sideBySide + Layout.fillHeight: true + width: 1 + color: "#ccc" + } + + EditorPane { + id: secondaryPane + visible: documentManager.sideBySide + Layout.preferredWidth: 360 + Layout.maximumWidth: 640 + docIndex: documentManager.secondaryIndex + closable: true + onClosePane: { + documentManager.setSideBySide(false) + splitBtn.checked = false + } + } + } + + // ---------- Горячие клавиши ---------- Shortcut { sequence: "Ctrl+S" context: Qt.WindowShortcut - onActivated: { - documentManager.saveAll() - } + onActivated: documentManager.saveAll() } Shortcut { sequence: "Ctrl+W" context: Qt.WindowShortcut - onActivated: { - documentManager.closeTab(documentManager.activeIndex) - } + onActivated: documentManager.closeTab(documentManager.activeIndex) } Shortcut { sequence: "Ctrl+E" context: Qt.WindowShortcut - onActivated: { - primaryPane.editMode = !primaryPane.editMode - } + onActivated: primaryPane.editMode = !primaryPane.editMode } Shortcut { sequence: "Ctrl+Tab"