gui: fix tool block rendering — use blockRenderedHtml directly

The Repeater-over-segments approach was failing to display tool output.
When a complete block arrives in one streaming chunk, QML's Repeater
with a var-typed model doesn't reliably re-render delegates on property
changes.

Fix: use a single TextEdit bound to blockRenderedHtml for all non-diagram
blocks. The Repeater path is retained only for blocks containing diagrams
(which need the Loader/component switching). This is simpler, more
reliable, and avoids the Repeater delegate lifecycle issues.
This commit is contained in:
Levi Neely 2026-08-09 12:09:42 +02:00
parent 59e1992f37
commit ed74d421c3
1 changed files with 63 additions and 1 deletions

View File

@ -11,6 +11,7 @@ Column {
required property string blockType
required property string blockName
required property var blockSegments
required property string blockRenderedHtml
// Reference to parent ListView for scroll control
property ListView parentListView: null
@ -119,8 +120,60 @@ Column {
visible: root.blockExpanded
spacing: 4
// Fast path: single TextEdit for the concatenated HTML.
// Diagrams are handled separately via the segments list.
TextEdit {
id: mainTextEdit
width: root.width
visible: !hasDiagrams()
text: root.blockRenderedHtml
textFormat: Text.RichText
readOnly: true
selectByMouse: true
persistentSelection: true
wrapMode: TextEdit.Wrap
font.family: theme.fontFamily || Qt.application.font.family
font.pointSize: theme.fontSize > 0 ? theme.fontSize : 12
selectionColor: theme.highlightColor
selectedTextColor: theme.highlightedTextColor
onActiveFocusChanged: {
if (!activeFocus && root.parentListView)
root.parentListView.interactive = true
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton
propagateComposedEvents: true
cursorShape: Qt.IBeamCursor
onPressed: function(mouse) {
if (root.parentListView) root.parentListView.interactive = false
mouse.accepted = false
}
onReleased: function(mouse) {
if (root.parentListView) root.parentListView.interactive = true
mouse.accepted = false
}
}
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
cursorShape: Qt.IBeamCursor
onClicked: {
if (!mainTextEdit._menu) {
mainTextEdit._menu = contextMenuComponent.createObject(mainTextEdit)
}
mainTextEdit._menu.popup()
}
}
property var _menu: null
}
// Diagram path: use Repeater for blocks that contain diagrams
Repeater {
model: root.blockSegments || []
model: hasDiagrams() ? root.blockSegments : []
delegate: Loader {
width: root.width
@ -131,6 +184,15 @@ Column {
}
}
function hasDiagrams() {
if (!root.blockSegments) return false
for (var i = 0; i < root.blockSegments.length; i++) {
if (root.blockSegments[i] && root.blockSegments[i].type === "diagram")
return true
}
return false
}
// Text segment component
Component {
id: textComponent