Files
Flora/qml/dialogs/TableEditor.qml
T

151 lines
5.4 KiB
QML
Raw Normal View History

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Flora
Dialog {
id: root
signal markdownReady(string md)
title: qsTr("Таблица")
modal: true
width: 560
anchors.centerIn: parent
closePolicy: Dialog.NoAutoClose
standardButtons: Dialog.NoButton
background: Rectangle { color: Theme.surface; border.color: Theme.borderStrong; radius: 10 }
property int rows: 1
property int cols: 2
property var cells: []
readonly property int cellW: 120
readonly property int cellH: 34
function cell(r, c) { const i = r * cols + c; return i < cells.length ? cells[i] : "" }
function setCell(r, c, v) { const i = r * cols + c; if (i < cells.length) cells[i] = v }
function addRowAfter(r) {
// Новая строка пустая, а не копия
const ins = r + 1
const flat = []
for (let rr = 0; rr <= rows; ++rr) {
if (rr === ins) for (let c = 0; c < cols; ++c) flat.push("")
for (let c = 0; c < cols; ++c) if (rr < rows) flat.push(cell(rr, c))
}
cells = flat; rows += 1
}
function addColAfter(c) {
const src = []
for (let r = 0; r < rows; ++r) src.push(cell(r, c))
const ins = c + 1
const flat = []
for (let rr = 0; rr < rows; ++rr) {
for (let cc = 0; cc <= cols; ++cc) {
if (cc === ins) flat.push("")
if (cc < cols) flat.push(cell(rr, cc))
}
}
cells = flat; cols += 1
}
function buildMarkdown() {
let out = ""
for (let c = 0; c < cols; ++c) out += (c === 0 ? "| " : " | ") + cell(0, c)
out += " |\n"
for (let c = 0; c < cols; ++c) out += (c === 0 ? "| " : " | ") + "---"
out += " |\n"
for (let r = 1; r < rows; ++r) {
for (let c = 0; c < cols; ++c) out += (c === 0 ? "| " : " | ") + cell(r, c)
out += " |\n"
}
return out
}
function resetDialog() {
rows = 1; cols = 2; cells = []
for (let i = 0; i < rows * cols; ++i) cells.push("")
}
Component.onCompleted: resetDialog()
ColumnLayout {
anchors.fill: parent
spacing: 10
Label { text: qsTr("Заполните ячейки таблицы"); color: Theme.textSecondary; font.pixelSize: 11 }
Flickable {
Layout.fillWidth: true
Layout.fillHeight: true
contentWidth: cellGrid.width + 30
contentHeight: cellGrid.height + 30
clip: true
ScrollBar.horizontal: ScrollBar {}
ScrollBar.vertical: ScrollBar {}
Row {
id: tableRow
spacing: 0
Grid {
id: cellGrid
columns: root.cols
columnSpacing: 3
rowSpacing: 3
Repeater {
model: root.rows * root.cols
delegate: TextField {
width: root.cellW; height: root.cellH
placeholderText: (Math.floor(model / root.cols)===0 ? qsTr("Заголовок") : qsTr("Ячейка"))
placeholderTextColor: Theme.textFaint
text: root.cell(Math.floor(model / root.cols), model % root.cols)
color: Theme.text
background: Rectangle { color: Theme.bgAlt; border.color: parent.activeFocus ? Theme.accent : Theme.border; radius: 6 }
onTextEdited: root.setCell(Math.floor(model / root.cols), model % root.cols, text)
}
}
}
Grid {
columns: 1; columnSpacing: 3; rowSpacing: 3
anchors.leftMargin: 4
Repeater {
model: root.rows
delegate: Button {
width: 24; height: root.cellH
text: "+"
ToolTip.text: qsTr("Добавить строку")
ToolTip.visible: hovered
onClicked: root.addRowAfter(model)
}
}
}
}
Row {
anchors.top: tableRow.bottom; anchors.topMargin: 4
Grid {
columns: root.cols; columnSpacing: 3; rowSpacing: 3
Repeater {
model: root.cols
delegate: Button {
width: root.cellW; height: 24
text: "+"
ToolTip.text: qsTr("Добавить столбец")
ToolTip.visible: hovered
onClicked: root.addColAfter(model)
}
}
}
}
}
RowLayout {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
Label { text: qsTr("Строк: %1 Столбцов: %2").arg(root.rows).arg(root.cols); color: Theme.textMuted; font.pixelSize: 11 }
Button { text: qsTr("Отмена"); onClicked: root.reject() }
Button { text: qsTr("Вставить"); highlighted: true; onClicked: { root.markdownReady(buildMarkdown()); root.accept() } }
}
}
}