diff --git a/gui/ChatBlockDelegate.qml b/gui/ChatBlockDelegate.qml index f7daf84..2af304e 100644 --- a/gui/ChatBlockDelegate.qml +++ b/gui/ChatBlockDelegate.qml @@ -3,7 +3,7 @@ import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 -ColumnLayout { +Column { id: root spacing: 2 @@ -80,7 +80,7 @@ ColumnLayout { // Clickable header Rectangle { - Layout.fillWidth: true + width: root.width height: 22 radius: 3 color: root.headerColor() @@ -115,7 +115,7 @@ ColumnLayout { // Block content rendered as segments Column { - Layout.fillWidth: true + width: root.width visible: root.blockExpanded spacing: 4 @@ -123,7 +123,7 @@ ColumnLayout { model: root.blockSegments || [] delegate: Loader { - width: parent ? parent.width : 0 + width: root.width active: modelData !== null && modelData !== undefined sourceComponent: (modelData && modelData.type === "diagram") ? diagramComponent : textComponent property var segmentData: modelData || {} @@ -137,7 +137,7 @@ ColumnLayout { TextEdit { id: textEdit - width: parent ? parent.width : 100 + width: root.width text: segmentData.html || "" textFormat: Text.RichText readOnly: true @@ -150,23 +150,11 @@ ColumnLayout { selectedTextColor: theme.highlightedTextColor onActiveFocusChanged: { - if (!activeFocus && root.parentListView) - root.parentListView.interactive = true - } - - Menu { - id: contextMenu - MenuItem { - text: "Copy" - enabled: textEdit.selectedText.length > 0 - onTriggered: textEdit.copy() - } - MenuItem { - text: "Select All" - onTriggered: textEdit.selectAll() - } + if (!activeFocus && root.parentListView) + root.parentListView.interactive = true } + // Left-click: disable ListView flick while selecting text MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton @@ -182,11 +170,41 @@ ColumnLayout { } } + // Right-click: lazy context menu MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton cursorShape: Qt.IBeamCursor - onClicked: contextMenu.popup() + onClicked: { + if (!textEdit._menu) { + textEdit._menu = contextMenuComponent.createObject(textEdit) + } + textEdit._menu.popup() + } + } + + property Menu _menu: null + + Component.onDestruction: { + if (_menu) _menu.destroy() + } + } + } + + // Shared context menu component (created on demand) + Component { + id: contextMenuComponent + Menu { + id: ctxMenu + property TextEdit target: parent + MenuItem { + text: "Copy" + enabled: ctxMenu.target ? ctxMenu.target.selectedText.length > 0 : false + onTriggered: if (ctxMenu.target) ctxMenu.target.copy() + } + MenuItem { + text: "Select All" + onTriggered: if (ctxMenu.target) ctxMenu.target.selectAll() } } } @@ -197,7 +215,7 @@ ColumnLayout { Rectangle { id: diagramRect - width: parent ? parent.width : 100 + width: root.width height: diagramContent.height + diagramHeader.height + 8 color: "transparent" border.color: theme.midColor diff --git a/gui/main.qml b/gui/main.qml index 74b457a..b865d7e 100644 --- a/gui/main.qml +++ b/gui/main.qml @@ -883,18 +883,21 @@ ApplicationWindow { visible: ollie.daemonConnected && ollie.activeAgentId !== "" property bool followTail: true - property bool scrollingNow: false - onContentHeightChanged: { - if (followTail && !scrollingNow && contentHeight > 0) { - scrollingNow = true - positionViewAtEnd() - scrollingNow = false - } + reuseItems: true + + onCountChanged: { + if (followTail) + Qt.callLater(chatView.scrollToEnd) } onMovementEnded: followTail = atYEnd + function scrollToEnd() { + if (followTail && contentHeight > height) + positionViewAtEnd() + } + delegate: ChatBlockDelegate { width: chatView.width - 8 parentListView: chatView diff --git a/justfile b/justfile index b34a8d3..30552e7 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,6 @@ # Ollie KDE integration build system home := env_var('HOME') -bin := home / 'bin' +bin := home / '.local/bin' kde: @echo '=== Building ollie-kde (KF6) ==='