Files
metabuilder/qml/MetaBuilder/CConnectionLayer.qml
johndoe6345789 d9ca84628b feat(a11y): deep keyboard accessibility pass across all QML components
Second-pass a11y work across all 12 component groups. Every interactive
element now has activeFocusOnTab, Keys.onReturnPressed/SpacePressed, and
context-aware Accessible.name/description bindings.

Highlights:
- Dialogs: keyboard handlers with enabled-guard on confirm buttons
- CDropdownMenu: full keyboard nav (Up/Down/Enter/Escape)
- CLoginForm: explicit KeyNavigation.tab chain (username→password→submit)
- CNotificationBell: dynamic "3 notifications"/"No notifications" name
- CJobProgressBar: Accessible.minimumValue/maximumValue/currentValue
- CExecutionStatusDot: "Execution status: Running/Passed/Failed" binding
- CKeyboardShortcuts: invisible Repeater exposes all shortcuts to a11y tree
- CDataTable rows: "Row N of M" descriptions
- Canvas elements: Accessible.Canvas role + keyboard zoom (+/- keys)
- DropdownExpandedList: focus-highlight extended to :activeFocus
- Dynamic names reflect loading state (e.g. "Signing in, please wait")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 20:53:53 +00:00

138 lines
4.7 KiB
QML

import QtQuick
import QmlComponents 1.0
Canvas {
id: root
objectName: "layer_connection"
Accessible.role: Accessible.Canvas
Accessible.name: "Connection Layer"
Accessible.description:
"Renders Bezier curves between " +
"connected workflow node ports"
property var nodes: []
property var connections: ({})
property bool drawingConnection: false
property string connSourceNode: ""
property bool connSourceIsOutput: true
property real connDragX: 0
property real connDragY: 0
property bool isDark: false
function groupColor(nodeType) {
var prefix = nodeType ? nodeType.split(".")[0] : ""
switch (prefix) {
case "metabuilder": return Theme.success
case "logic": return Theme.warning
case "transform":
case "packagerepo": return "#FF9800"
case "sdl":
case "graphics": return "#2196F3"
case "integration": return "#9C27B0"
case "io": return "#00BCD4"
default: return Theme.primary
}
}
function findNodeById(id) {
if (!nodes) return null
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].id === id) return nodes[i]
}
return null
}
onPaint: {
var ctx = getContext("2d")
ctx.reset()
ctx.lineWidth = 2.5
if (!connections || !nodes) return
var nodeW = 180
var headerH = 32
var portSpacing = 24
var portOffset = 8
// Draw established connections
for (var srcId in connections) {
var srcNode = findNodeById(srcId)
if (!srcNode) continue
var srcConns = connections[srcId]
for (var outName in srcConns) {
for (var outIdx in srcConns[outName]) {
var targets = srcConns[outName][outIdx]
var outIndex = parseInt(outIdx)
var srcX = srcNode.position[0] + nodeW
var srcY = srcNode.position[1]
+ headerH + portOffset
+ outIndex * portSpacing + 6
for (var t = 0; t < targets.length; t++) {
var target = targets[t]
var dstNode = findNodeById(target.node)
if (!dstNode) continue
var inIndex = target.index || 0
var dstX = dstNode.position[0]
var dstY = dstNode.position[1]
+ headerH + portOffset
+ inIndex * portSpacing + 6
// Draw Bezier
var cpOffset = Math.max(80, Math.abs(dstX - srcX) * 0.4)
ctx.strokeStyle = groupColor(srcNode.type)
ctx.globalAlpha = 0.8
ctx.beginPath()
ctx.moveTo(srcX, srcY)
ctx.bezierCurveTo(
srcX + cpOffset, srcY,
dstX - cpOffset, dstY,
dstX, dstY)
ctx.stroke()
// Arrow at destination
ctx.globalAlpha = 1.0
ctx.fillStyle = groupColor(srcNode.type)
ctx.beginPath()
ctx.moveTo(dstX, dstY)
ctx.lineTo(dstX - 8, dstY - 4)
ctx.lineTo(dstX - 8, dstY + 4)
ctx.closePath()
ctx.fill()
}
}
}
}
// Draw connection being dragged
if (drawingConnection && connSourceNode) {
var dragSrc = findNodeById(connSourceNode)
if (dragSrc) {
var sx, sy
if (connSourceIsOutput) {
sx = dragSrc.position[0] + nodeW
sy = dragSrc.position[1] + headerH + portOffset + 6
} else {
sx = dragSrc.position[0]
sy = dragSrc.position[1] + headerH + portOffset + 6
}
var dx = connDragX
var dy = connDragY
var cp = Math.max(60, Math.abs(dx - sx) * 0.4)
ctx.strokeStyle = Theme.primary
ctx.globalAlpha = 0.6
ctx.setLineDash([6, 4])
ctx.lineWidth = 2
ctx.beginPath()
ctx.moveTo(sx, sy)
ctx.bezierCurveTo(sx + cp, sy, dx - cp, dy, dx, dy)
ctx.stroke()
ctx.setLineDash([])
}
}
}
}