Skip to content

Commit

Permalink
fixed some issues, only render cells on screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Nimaoth committed Nov 1, 2023
1 parent 3e254ab commit 8dc8fb8
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 38 deletions.
8 changes: 4 additions & 4 deletions src/ast/cells.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type
NodeReferenceCell* = ref object of Cell
reference*: Id
property*: Id
child: Cell
targetNodeCell: Cell

AliasCell* = ref object of Cell
discard
Expand All @@ -30,9 +30,9 @@ type

proc buildCell*(self: CellBuilder, map: NodeCellMap, node: AstNode, useDefault: bool = false): Cell

proc child*(cell: NodeReferenceCell): Cell = cell.child
proc child*(cell: NodeReferenceCell): Cell = cell.targetNodeCell
proc `child=`*(cell: NodeReferenceCell, c: Cell) =
cell.child = c
cell.targetNodeCell = c
c.parent = cell

method getText*(cell: Cell): string {.base.} = discard
Expand Down Expand Up @@ -146,7 +146,7 @@ proc nextDirect*(self: Cell): Option[Cell] =
return self.parent.CollectionCell.children[i + 1].some

proc isLeaf*(self: Cell): bool =
if self of CollectionCell and self.CollectionCell.children.len > 0:
if self of CollectionCell:
return false
return true

Expand Down
43 changes: 40 additions & 3 deletions src/model_document.nim
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ type
targetNode*: UINode
targetCell*: Cell
scrolledNode*: UINode
targetCellPosition*: Vec2
selection*: CellSelection
handleClick*: proc(node: UINode, cell: Cell, path: seq[int], cursor: CellCursor, drag: bool)
selectionColor*: Color
Expand Down Expand Up @@ -314,11 +315,11 @@ proc updateScrollOffset(self: ModelDocumentEditor) =
self.scrollOffset = self.scrolledNode.parent.h - buffer * self.app.platform.builder.textHeight

else:
discard
# discard
# todo
# echo fmt"new cell doesn't exist, scroll offset {self.scrollOffset}, {self.targetCellPath}"
# self.targetCellPath = self.selection.last.targetCell.rootPath.path
# self.scrollOffset = self.scrolledNode.parent.h / 2
self.targetCellPath = self.selection.last.targetCell.rootPath.path
self.scrollOffset = self.scrolledNode.parent.h / 2

self.markDirty()

Expand Down Expand Up @@ -905,6 +906,13 @@ proc getCursorOffset(self: ModelDocumentEditor, builder: UINodeBuilder, cell: Ce
return byteIndex

proc getCellInLine*(self: ModelDocumentEditor, cell: Cell, direction: int, targetX: float): Option[tuple[cell: Cell, offset: int]] =
## Searches for the next cell in a line base way.
## direction:
## If direction is 0 then only the same line as the input cell is searched.
## If direction is -1 then the previous lines will be searched.
## If direction is +1 then the next lines will be searched.
## targetX: return the cell closest to this X location

let builder = self.app.platform.builder
let uiRoot = self.scrolledNode
let maxYDiff = builder.lineHeight / 2
Expand Down Expand Up @@ -1365,6 +1373,31 @@ proc getFirstEditableCellOfNode*(self: ModelDocumentEditor, node: AstNode): Opti
echo fmt"a: visible descendant {targetCell}"
return self.nodeCellMap.toCursor(targetCell, true).some

proc getFirstSelectableCellOfNode*(self: ModelDocumentEditor, node: AstNode): Option[CellCursor] =
result = CellCursor.none

debugf"getFirstSelectableCellOfNode {node}"
var nodeCell = self.nodeCellMap.cell(node)
if nodeCell.isNil:
return

nodeCell = nodeCell.getFirstLeaf()
echo fmt"first leaf {nodeCell}"

proc selectableDescendant(n: Cell): (bool, Option[Cell]) =
if n.node == nodeCell.node or n.node.isDescendant(nodeCell.node):
return (isVisible(n) and n.canSelect, n.some)
else:
return (true, Cell.none)

if nodeCell.getSelfOrNeighborLeafWhere(Right, selectableDescendant).getSome(targetCell):
echo fmt"a: selectable descendant {targetCell}"
return self.nodeCellMap.toCursor(targetCell, true).some

if nodeCell.getSelfOrNextLeafWhere((n) => isVisible(n) and not n.disableSelection).getSome(targetCell):
echo fmt"a: visible descendant {targetCell}"
return self.nodeCellMap.toCursor(targetCell, true).some

proc getFirstPropertyCellOfNode*(self: ModelDocumentEditor, node: AstNode, role: Id): Option[CellCursor] =
result = CellCursor.none

Expand Down Expand Up @@ -2233,6 +2266,10 @@ proc redo*(self: ModelDocumentEditor) {.expose("editor.model").} =
proc toggleUseDefaultCellBuilder*(self: ModelDocumentEditor) {.expose("editor.model").} =
self.nodeCellMap.builder.forceDefault = not self.nodeCellMap.builder.forceDefault
self.rebuildCells()
if self.getFirstSelectableCellOfNode(self.selection.first.node).getSome(first) and self.getFirstSelectableCellOfNode(self.selection.last.node).getSome(last):
self.selection = (first, last)
else:
self.cursor = self.nodeCellMap.toCursor(self.nodeCellMap.cell(self.cursor.node).getFirstLeaf(), true)
self.markDirty()

proc showCompletions*(self: ModelDocumentEditor) {.expose("editor.model").} =
Expand Down
116 changes: 87 additions & 29 deletions src/platform/widget_builder_model_document.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type
pivot: Vec2
lastCell: Cell
lines: seq[seq[UINode]]
currentPos: Vec2

CellLayoutContext = ref object
parent: CellLayoutContext
Expand All @@ -45,6 +46,8 @@ type
tempNode: UINode
joinLines: bool = false
containsCenter: bool = false
childContainsCenter: bool = false
centerChildTargetPos: Vec2 # target position of the child node that contains the center, in content space (i.e. same space as scroll offset)

var stackSize = 0
var cellPath = newSeq[int]()
Expand Down Expand Up @@ -87,6 +90,8 @@ proc newCellLayoutContext(parent: CellLayoutContext, cell: Cell, remainingHeight
result.parent = parent
result.remainingHeightDown = remainingHeightDown
result.remainingHeightUp = remainingHeightUp
result.forwardData.currentPos = parent.forwardData.currentPos
result.backwardData.currentPos = parent.backwardData.currentPos
result.cell = cell

when defined(uiNodeDebugData):
Expand Down Expand Up @@ -156,14 +161,20 @@ proc decreaseIndent(self: CellLayoutContext) =
proc notifyCellCreated(self: CellLayoutContext, cell: Cell) =
self.currentDirectionData.lastCell = cell

proc handleSpaceClickOrDrag(builder: UINodeBuilder, updateContext: UpdateContext, node: UINode, lastCell: Cell, cell: Cell, cellPath: seq[int], drag: bool, pos: Vec2, btn: MouseButton, modifiers: Modifiers) =
proc handleSpaceClickOrDrag(builder: UINodeBuilder, node: UINode, drag: bool, pos: Vec2, btn: MouseButton, modifiers: Modifiers) =
let posAbs = rect(pos, vec2()).transformRect(node, builder.root).xy

let targetNode = if pos.x <= builder.charWidth * 0.5:
let targetNode = if node.prev.isNil:
node.next
elif node.next.isNil:
node.prev
elif pos.x <= builder.charWidth * 0.5:
node.prev
else:
node.next

# debugf"handleSpaceClickOrDrag {targetNode.dump}, {pos}"

if targetNode.isNotNil:
if drag and targetNode.handleDrag.isNotNil:
discard targetNode.handleDrag()(targetNode, btn, modifiers, posAbs - targetNode.boundsAbsolute.xy, vec2())
Expand All @@ -176,17 +187,15 @@ proc addSpace(self: CellLayoutContext, cell: Cell, updateContext: UpdateContext)

# # echo "add space, current indent ", self.currentIndent, ", ", cell

let cellPath = cellPath
let builder = self.builder
let lastCell = self.currentDirectionData.lastCell

self.builder.panel(&{FillY}, w = self.builder.charWidth):
onClickAny btn:
if btn == MouseButton.Left:
handleSpaceClickOrDrag(builder, updateContext, currentNode, lastCell, cell, cellPath, false, pos, btn, modifiers)
handleSpaceClickOrDrag(builder, currentNode, false, pos, btn, modifiers)

onDrag MouseButton.Left:
handleSpaceClickOrDrag(builder, updateContext, currentNode, lastCell, cell, cellPath, true, pos, btn, modifiers)
handleSpaceClickOrDrag(builder, currentNode, true, pos, btn, modifiers)

when defined(uiNodeDebugData):
currentNode.aDebugData.metaData["isForward"] = newJBool self.currentDirection == Forwards
Expand All @@ -197,17 +206,15 @@ proc addSpace(self: CellLayoutContext, cell: Cell, updateContext: UpdateContext,
return

# # echo "add space, current indent ", self.currentIndent, ", ", cell
let cellPath = cellPath
let builder = self.builder
let lastCell = self.currentDirectionData.lastCell

self.builder.panel(&{FillY, FillBackground}, w = self.builder.charWidth, backgroundColor = color):
onClickAny btn:
if btn == MouseButton.Left:
handleSpaceClickOrDrag(builder, updateContext, currentNode, lastCell, cell, cellPath, false, pos, btn, modifiers)
handleSpaceClickOrDrag(builder, currentNode, false, pos, btn, modifiers)

onDrag MouseButton.Left:
handleSpaceClickOrDrag(builder, updateContext, currentNode, lastCell, cell, cellPath, true, pos, btn, modifiers)
handleSpaceClickOrDrag(builder, currentNode, true, pos, btn, modifiers)

when defined(uiNodeDebugData):
currentNode.aDebugData.metaData["isSpace"] = newJBool true
Expand All @@ -226,11 +233,25 @@ proc saveLine(self: CellLayoutContext) =
c.removeFromParent()
self.backwardData.lines.last.add c

when defined(uiNodeDebugData):
for node in self.currentDirectionData.lines.last:
node.aDebugData.metaData["pos"] = newJString $self.currentDirectionData.currentPos

self.builder.continueFrom(self.tempNode, nil)

proc newLine(self: CellLayoutContext) =
self.saveLine()

var maxHeight = 0.0
for node in self.currentDirectionData.lines.last:
self.builder.updateSizeToContent(node)
maxHeight = max(maxHeight, node.h)

if self.currentDirection == Forwards:
self.currentDirectionData.currentPos.y += maxHeight
else:
self.currentDirectionData.currentPos.y -= maxHeight

if self.currentDirectionData.lines.last.len > 0:
self.currentDirectionData.lines.add @[]

Expand Down Expand Up @@ -524,23 +545,24 @@ proc finish(self: CellLayoutContext) =
# debugf"finish {self.joinLines}"
# echo self.tempNode.dump

self.builder.continueFrom(self.parentNode, nil)
var builder = self.builder
builder.continueFrom(self.parentNode, nil)

var noneId = noneUserId

var lineNode: UINode
for line in countdown(self.backwardData.lines.high, 0):
lineNode = self.builder.prepareNode(&{SizeToContentX, FillX, SizeToContentY, LayoutHorizontal}, string.none, float32.none, float32.none, float32.none, float32.none, vec2(0, 0).some, noneId, UINodeFlags.none)
self.builder.clearUnusedChildren(lineNode, nil)
lineNode = builder.prepareNode(&{SizeToContentX, FillX, SizeToContentY, LayoutHorizontal}, string.none, float32.none, float32.none, float32.none, float32.none, vec2(0, 0).some, noneId, UINodeFlags.none)
builder.clearUnusedChildren(lineNode, nil)

if self.currentIndent > 0:
self.builder.panel(&{FillY}, w = self.indentText.len.float * self.currentIndent.float * self.builder.charWidth, textColor = color(0, 1, 0)):
builder.panel(&{FillY}, w = self.indentText.len.float * self.currentIndent.float * builder.charWidth, textColor = color(0, 1, 0)):
onClickAny btn:
if btn == MouseButton.Left:
handleIndentClickOrDrag(self.builder, btn, modifiers, currentNode, false, pos)
handleIndentClickOrDrag(builder, btn, modifiers, currentNode, false, pos)

onDrag MouseButton.Left:
handleIndentClickOrDrag(self.builder, btn, modifiers, currentNode, true, pos)
handleIndentClickOrDrag(builder, btn, modifiers, currentNode, true, pos)

when defined(uiNodeDebugData):
currentNode.aDebugData.metaData["isBackwards"] = newJBool true
Expand All @@ -549,25 +571,25 @@ proc finish(self: CellLayoutContext) =
for i in countdown(self.backwardData.lines[line].high, 0):
# self.backwardData.lines[line][i].removeFromParent()
lineNode.insert(self.backwardData.lines[line][i], lineNode.last)
self.builder.continueFrom(lineNode, lineNode.last)
builder.continueFrom(lineNode, lineNode.last)

if line != 0 or not self.joinLines:
self.builder.finishNode(lineNode)
builder.finishNode(lineNode)

for line in 0..self.forwardData.lines.high:

if lineNode.isNil or line > 0 or not self.joinLines:
lineNode = self.builder.prepareNode(&{SizeToContentX, FillX, SizeToContentY, LayoutHorizontal}, string.none, float32.none, float32.none, float32.none, float32.none, vec2(0, 0).some, noneId, UINodeFlags.none)
self.builder.clearUnusedChildren(lineNode, nil)
lineNode = builder.prepareNode(&{SizeToContentX, FillX, SizeToContentY, LayoutHorizontal}, string.none, float32.none, float32.none, float32.none, float32.none, vec2(0, 0).some, noneId, UINodeFlags.none)
builder.clearUnusedChildren(lineNode, nil)

if self.currentIndent > 0:
self.builder.panel(&{FillY}, w = self.indentText.len.float * self.currentIndent.float * self.builder.charWidth, textColor = color(0, 1, 0)):
builder.panel(&{FillY}, w = self.indentText.len.float * self.currentIndent.float * builder.charWidth, textColor = color(0, 1, 0)):
onClickAny btn:
if btn == MouseButton.Left:
handleIndentClickOrDrag(self.builder, btn, modifiers, currentNode, false, pos)
handleIndentClickOrDrag(builder, btn, modifiers, currentNode, false, pos)

onDrag MouseButton.Left:
handleIndentClickOrDrag(self.builder, btn, modifiers, currentNode, true, pos)
handleIndentClickOrDrag(builder, btn, modifiers, currentNode, true, pos)

when defined(uiNodeDebugData):
currentNode.aDebugData.metaData["isForwards"] = newJBool true
Expand All @@ -578,14 +600,27 @@ proc finish(self: CellLayoutContext) =

for i in 0..self.forwardData.lines[line].high:
lineNode.insert(self.forwardData.lines[line][i], lineNode.last)
self.builder.continueFrom(lineNode, lineNode.last)
builder.continueFrom(lineNode, lineNode.last)

self.builder.finishNode(lineNode)
# todo: add space after last cell in line for mouse handling
# builder.panel(&{FillX, FillY}):
# onClickAny btn:
# if btn == MouseButton.Left:
# handleSpaceClickOrDrag(builder, currentNode, false, pos, btn, modifiers)

self.builder.finishNode(self.parentNode)
# onDrag MouseButton.Left:
# handleSpaceClickOrDrag(builder, currentNode, true, pos, btn, modifiers)

# when defined(uiNodeDebugData):
# currentNode.aDebugData.metaData["isPostSpace"] = newJBool true
# currentNode.aDebugData.metaData["isForward"] = newJBool true

builder.finishNode(lineNode)

builder.finishNode(self.parentNode)

assert self.tempNode.first.isNil
self.builder.returnNode(self.tempNode)
builder.returnNode(self.tempNode)

proc shouldBeOnNewLine(cell: Cell): bool =
if cell.style.isNotNil and cell.style.onNewLine:
Expand Down Expand Up @@ -616,10 +651,11 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
if vertical and spaceLeft:
ctx.addSpace(cell, updateContext)

let parentCtx = ctx
var ctx = ctx
var hasContext = false
if cell.inline or vertical:
ctx = newCellLayoutContext(ctx, cell, ctx.remainingHeightDown, ctx.remainingHeightUp, not cell.inline)
ctx = newCellLayoutContext(parentCtx, cell, ctx.remainingHeightDown, ctx.remainingHeightUp, not cell.inline)
hasContext = true

if cell.style.isNotNil and cell.style.indentChildren:
Expand All @@ -633,6 +669,17 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
if hasContext:
ctx.finish()

if ctx.containsCenter or ctx.childContainsCenter:
parentCtx.childContainsCenter = true

let targetCellPosInSelf = updateContext.targetNode.transformBounds(ctx.parentNode)
# let targetPosSelf = updateContext.targetCellPos.transformPos(updateContext.targetNode, updateContext.scrolledNode.parent)
let newTargetCellPos = updateContext.targetCellPosition - targetCellPosInSelf.xy
# debugf"targetCellPos: {updateContext.targetCellPosition}, self: {targetCellPosInSelf}, new: {newTargetCellPos}"
parentCtx.centerChildTargetPos = newTargetCellPos
parentCtx.forwardData.currentPos = newTargetCellPos
parentCtx.backwardData.currentPos = newTargetCellPos

updateContext.nodeCellMap.fill(cell)
if cell.children.len == 0:
return
Expand All @@ -647,6 +694,10 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
# forwards
if adjustedCenterIndex <= cell.children.high:
for i in adjustedCenterIndex..cell.children.high:
if ctx.forwardData.currentPos.y - updateContext.targetCellPosition.y > ctx.remainingHeightDown:
# debugf"reached bottom {cell}"
break

ctx.goForward()

let c = cell.children[i]
Expand Down Expand Up @@ -685,7 +736,6 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
else:
@[int.high],
cursorFirst.getChildPath(i), cursorLast.getChildPath(i))

discard cellPath.pop

if i == centerIndex:
Expand All @@ -699,6 +749,9 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
centerNewLine = onNewLine
ctx.containsCenter = true

ctx.forwardData.currentPos = updateContext.targetCellPosition
ctx.backwardData.currentPos = updateContext.targetCellPosition

# echo "set target ", cellPath, ", ", path
updateContext.targetCell = c
updateContext.targetNode = ctx.tempNode.last
Expand Down Expand Up @@ -727,6 +780,10 @@ method createCellUI*(cell: CollectionCell, builder: UINodeBuilder, app: App, ctx
ctx.newLine()

for i in countdown(adjustedCenterIndex - 1, 0):
if updateContext.targetCellPosition.y - ctx.backwardData.currentPos.y > ctx.remainingHeightUp:
# debugf"reached top {cell}"
break

ctx.goBackward()

let c = cell.children[i]
Expand Down Expand Up @@ -874,6 +931,7 @@ method createUI*(self: ModelDocumentEditor, builder: UINodeBuilder, app: App): s
self.cellWidgetContext.targetNode = nil
self.cellWidgetContext.selection = self.selection
self.cellWidgetContext.scrolledNode = scrolledNode
self.cellWidgetContext.targetCellPosition = vec2(0, self.scrollOffset)
self.cellWidgetContext.handleClick = proc(node: UINode, cell: Cell, cellPath: seq[int], cursor: CellCursor, drag: bool) =
if node.isNotNil:
let bounds = node.bounds.transformRect(node.parent, scrolledNode.parent)
Expand Down
Loading

0 comments on commit 8dc8fb8

Please sign in to comment.