diff --git a/qml/panels/EditorPanel.qml b/qml/panels/EditorPanel.qml index 92f98c8..3137d4f 100644 --- a/qml/panels/EditorPanel.qml +++ b/qml/panels/EditorPanel.qml @@ -2,25 +2,21 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -// Центральная панель: вкладки сверху, тулбар, редактор заполняет остаток. -// Используем anchors вместо ColumnLayout — SplitView корректно работает с anchors. +// Центральная панель: вкладки сверху, тулбар, редактор-текст, панель внизу. +// Всё — anchors, без ColumnLayout/RowLayout (SplitView не работает с ними). Item { id: root + property bool sideBySide: false + function baseName(p) { - const idx = p.lastIndexOf("/") - return idx >= 0 ? p.substring(idx + 1) : p + const i = p.lastIndexOf("/") + return i >= 0 ? p.substring(i + 1) : p } - function activePane() { - if (secondaryPane.visible && secondaryPane.hasFocus) - return secondaryPane - return primaryPane - } - - // ---------- Вкладки (сверху) ---------- + // --- Вкладки (верх) --- Rectangle { - id: tabBar + id: tabRow anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right @@ -28,11 +24,7 @@ Item { color: "#ececec" RowLayout { - anchors.fill: parent - anchors.leftMargin: 4 - anchors.rightMargin: 4 - spacing: 2 - + anchors.fill: parent; anchors.leftMargin: 4; spacing: 2 Repeater { model: documentManager.openTabs delegate: Rectangle { @@ -40,127 +32,109 @@ Item { 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 + width: Math.max(90, tabLabel.implicitWidth + 32) + height: 26; radius: 4 color: active ? "white" : "#e0e0e0" - - RowLayout { + MouseArea { 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) - } + onClicked: documentManager.setActiveIndex(index) + onDoubleClicked: documentManager.closeTab(index) + } + Label { + id: tabLabel + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left; anchors.leftMargin: 8 + text: root.baseName(modelData) + (documentManager.isDirty(index) ? " •" : "") + font.pixelSize: 12; color: tab.active ? "#111" : "#555" + } + ToolButton { + text: "\u2715"; anchors.right: parent.right; anchors.verticalCenter: parent.verticalCenter + font.pixelSize: 9; width: 16 + opacity: tab.active || hovered ? 1 : 0 + onClicked: documentManager.closeTab(index) } } } - Item { Layout.fillWidth: true } - - Label { - visible: documentManager.openTabs.length === 0 - text: qsTr("Откройте файл из дерева") - color: "#999" - font.pixelSize: 12 - } - + Label { visible: documentManager.openTabs.length === 0; text: qsTr("Откройте файл"); color: "#999"; font.pixelSize: 12 } ToolButton { - text: "\u25A1\u25A1" - checkable: true - checked: documentManager.sideBySide - enabled: documentManager.openTabs.length > 0 - ToolTip.text: qsTr("Открыть рядом") - onClicked: { - if (checked) { - documentManager.setSecondaryIndex(documentManager.activeIndex) - documentManager.setSideBySide(true) - } else { - documentManager.setSideBySide(false) - } - } + text: "\u25A1\u25A1"; checkable: true; checked: documentManager.sideBySide + enabled: documentManager.activeIndex >= 0 + onClicked: { documentManager.setSecondaryIndex(documentManager.activeIndex); documentManager.setSideBySide(checked) } } } } - // ---------- Формат-тулбар (под вкладками) ---------- + // --- Тулбар (под вкладками) --- FormatToolbar { - id: formatToolbar - anchors.top: tabBar.bottom - anchors.left: parent.left - anchors.right: parent.right + id: fmtBar + anchors.top: tabRow.bottom; anchors.left: parent.left; anchors.right: parent.right height: 34 visible: documentManager.activeIndex >= 0 - targetPane: activePane() onTableRequested: { tableEditor.resetDialog(); tableEditor.open() } } - // ---------- Редактор (заполняет остаток) ---------- - RowLayout { - id: editorArea - anchors.top: formatToolbar.bottom + // --- Текстовый редактор (основная область) --- + TextEdit { + id: textArea + anchors.top: fmtBar.bottom anchors.left: parent.left anchors.right: parent.right - anchors.bottom: parent.bottom - spacing: 0 + anchors.bottom: toolbar.top + clip: true + visible: documentManager.activeIndex >= 0 + text: documentManager.contentAt(documentManager.activeIndex) + color: "black" + font.family: "Menlo, Consolas, 'DejaVu Sans Mono', monospace" + font.pixelSize: 14 + wrapMode: TextEdit.NoWrap + selectByMouse: true + onTextEdited: documentManager.updateContent(documentManager.activeIndex, text) + } - EditorPane { - id: primaryPane - Layout.fillWidth: true - docIndex: documentManager.activeIndex - canOpenBeside: true - onOpenBeside: { - documentManager.setSecondaryIndex(documentManager.activeIndex) - documentManager.setSideBySide(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) + // --- Режим просмотра --- + TextEdit { + id: viewArea + anchors.top: fmtBar.bottom; anchors.left: parent.left; anchors.right: parent.right; anchors.bottom: toolbar.top + visible: false + readOnly: true; clip: true + textFormat: TextEdit.RichText + color: "black" + font.family: "Menlo, Consolas, 'DejaVu Sans Mono', monospace" + font.pixelSize: 14; wrapMode: TextEdit.Wrap + onLinkActivated: (href) => { + if (href.startsWith("flora://open/")) + documentManager.openDocument(decodeURIComponent(href.substring(13))) } } - TableEditor { id: tableEditor; onMarkdownReady: (md) => activePane().insertText(md) } + // --- Серая панель ВНИЗУ (конец) --- + Rectangle { + id: toolbar + anchors.bottom: parent.bottom; anchors.left: parent.left; anchors.right: parent.right + height: 32; color: "#e0e0e0"; border.color: "#ccc" + RowLayout { + anchors.fill: parent; anchors.rightMargin: 4; spacing: 4 + Item { Layout.fillWidth: true } + ToolButton { text: "✎"; checkable: true; checked: documentManager.activeIndex >= 0 && !viewArea.visible; onClicked: { viewArea.visible = false; textArea.visible = true } } + ToolButton { text: "👁"; checkable: true; checked: viewArea.visible; onClicked: { + viewArea.visible = true; textArea.visible = false + viewArea.text = mdParser.render(textArea.text, fileStore.vault, activeFileDir()) + }} + ToolButton { text: "\u2715"; visible: false } + } + } + + function activeFileDir() { + const p = documentManager.pathAt(documentManager.activeIndex) + const i = p.lastIndexOf("/") + return i >= 0 ? p.substring(0, i) : "" + } + + TableEditor { id: tableEditor; onMarkdownReady: (md) => textArea.insert(textArea.cursorPosition, md) } - // ---------- Горячие клавиши ---------- Shortcut { sequence: "Ctrl+S"; onActivated: documentManager.saveAll() } Shortcut { sequence: "Ctrl+W"; onActivated: documentManager.closeTab(documentManager.activeIndex) } - Shortcut { sequence: "Ctrl+E"; onActivated: primaryPane.editMode = !primaryPane.editMode } - Shortcut { sequence: "Ctrl+Tab"; onActivated: { - const n = documentManager.openTabs.length - if (n > 0) documentManager.setActiveIndex((documentManager.activeIndex + 1) % n) - }} + Shortcut { sequence: "Ctrl+E"; onActivated: { viewArea.visible = !viewArea.visible; textArea.visible = !viewArea.visible } } + Shortcut { sequence: "Ctrl+Tab"; onActivated: { const n = documentManager.openTabs.length; if (n > 0) documentManager.setActiveIndex((documentManager.activeIndex + 1) % n) } } } \ No newline at end of file