Add 'dotscape/' from commit 'f306501a68a51b634e895c5fdac70788ae899d75'

git-subtree-dir: dotscape
git-subtree-mainline: 6b91d64fc3
git-subtree-split: f306501a68
This commit is contained in:
2026-04-24 00:30:08 +01:00
53 changed files with 9187 additions and 0 deletions

View File

@@ -0,0 +1,404 @@
structure NormalMode =
struct
open AppType
open DrawMessage
open FileMessage
open InputMessage
open UpdateMessage
fun getDotVecFromIndices (model: app_type, hIdx, vIdx) =
let
val {windowWidth, windowHeight, xClickPoints, yClickPoints, ...} = model
val xpos = Vector.sub (xClickPoints, hIdx)
val ypos = Vector.sub (yClickPoints, vIdx)
val endXpos =
if hIdx + 1 = Vector.length xClickPoints then xpos
else Vector.sub (xClickPoints, hIdx + 1)
val endYpos =
if vIdx + 1 = Vector.length yClickPoints then ypos
else Vector.sub (yClickPoints, vIdx + 1)
val tl = ClickPoints.getDrawDotRgb
(xpos, ypos, 0.0, 0.0, 1.0, windowWidth, windowHeight)
val tr = ClickPoints.getDrawDotRgb
(endXpos, ypos, 0.0, 0.0, 1.0, windowWidth, windowHeight)
val bl = ClickPoints.getDrawDotRgb
(xpos, endYpos, 0.0, 0.0, 1.0, windowWidth, windowHeight)
val br = ClickPoints.getDrawDotRgb
(endXpos, endYpos, 0.0, 0.0, 1.0, windowWidth, windowHeight)
in
Vector.concat [tl, tr, bl, br]
end
fun mouseMoveOrRelease (model: app_type) =
let
val drawVec =
case ClickPoints.getClickPositionFromMouse model of
SOME (hIdx, vIdx) => getDotVecFromIndices (model, hIdx, vIdx)
| NONE => Vector.fromList []
val drawMsg = DRAW_DOT drawVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
fun getDrawDotMsgWhenArrowIsAtBoundary model =
let
val {arrowX, arrowY, ...} = model
val dotVec = getDotVecFromIndices (model, arrowX, arrowY)
val drawMsg = DRAW_DOT dotVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
fun moveArrowUp (model: app_type) =
let
val {arrowX, arrowY, ...} = model
in
if arrowY > 0 then
let
val newArrowY = arrowY - 1
val model = AppWith.arrowY (model, newArrowY)
val dotVec = getDotVecFromIndices (model, arrowX, newArrowY)
val drawMsg = DRAW_DOT dotVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
else
getDrawDotMsgWhenArrowIsAtBoundary model
end
fun moveArrowLeft (model: app_type) =
let
val {arrowX, arrowY, ...} = model
in
if arrowX > 0 then
let
val newArrowX = arrowX - 1
val model = AppWith.arrowX (model, newArrowX)
val dotVec = getDotVecFromIndices (model, newArrowX, arrowY)
val drawMsg = DRAW_DOT dotVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
else
getDrawDotMsgWhenArrowIsAtBoundary model
end
fun moveArrowRight (model: app_type) =
let
val {arrowX, arrowY, xClickPoints, ...} = model
in
if arrowX < Vector.length xClickPoints - 2 then
let
val newArrowX = arrowX + 1
val model = AppWith.arrowX (model, newArrowX)
val dotVec = getDotVecFromIndices (model, newArrowX, arrowY)
val drawMsg = DRAW_DOT dotVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
else
getDrawDotMsgWhenArrowIsAtBoundary model
end
fun moveArrowDown (model: app_type) =
let
val {arrowX, arrowY, yClickPoints, ...} = model
in
if arrowY < Vector.length yClickPoints - 2 then
let
val newArrowY = arrowY + 1
val model = AppWith.arrowY (model, newArrowY)
val dotVec = getDotVecFromIndices (model, arrowX, newArrowY)
val drawMsg = DRAW_DOT dotVec
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
else
getDrawDotMsgWhenArrowIsAtBoundary model
end
fun realToInt x = Real32.toInt IEEEReal.TO_NEAREST x
fun getDrawMessage (model: app_type, initialMsg) =
let
val
{ canvasWidth
, canvasHeight
, layerTree
, windowWidth
, windowHeight
, xClickPoints
, yClickPoints
, arrowX
, arrowY
, ...
} = model
val maxSide = Int.max (canvasWidth, canvasHeight)
val squares = LayerTree.flatten (maxSide, layerTree)
val dotVec = getDotVecFromIndices (model, arrowX, arrowY)
val squares = CollisionTree.toTriangles
( windowWidth
, windowHeight
, squares
, maxSide
, canvasWidth
, canvasHeight
, xClickPoints
, yClickPoints
)
val drawMsg = DRAW_SQUARES_AND_DOTS {squares = squares, dots = dotVec}
val drawMsg = DRAW (drawMsg) :: initialMsg
in
(model, drawMsg)
end
fun changePixel (model: app_type, hIdx, vIdx, pixel) =
let
val {canvasWidth, canvasHeight, layer, layerTree, ...} = model
val maxSide = Int.max (canvasWidth, canvasHeight)
val layerTree = LayerTree.addPixel
(layer, hIdx, vIdx, maxSide, pixel, layerTree)
val model = AppWith.layerTree (model, layerTree, hIdx, vIdx)
in
getDrawMessage (model, [])
end
fun addPixel (model: app_type, hIdx, vIdx) =
let
val {r, g, b, a, ...} = model
val pixel = {r = r, g = g, b = b, a = a}
in
changePixel (model, hIdx, vIdx, pixel)
end
fun deletePixel (model, hIdx, vIdx) =
changePixel (model, hIdx, vIdx, Grid.emptyPixel)
fun mouseLeftClick model =
case ClickPoints.getClickPositionFromMouse model of
SOME (hIdx, vIdx) => addPixel (model, hIdx, vIdx)
| NONE => (model, [])
fun enterOrSpaceCoordinates model =
let val {arrowX, arrowY, ...} = model
in addPixel (model, arrowX, arrowY)
end
fun backspace model =
let val {arrowX, arrowY, ...} = model
in deletePixel (model, arrowX, arrowY)
end
fun resizeWindow (model, width, height) =
let
val model = AppWith.windowResize (model, width, height)
val {arrowX, arrowY, ...} = model
val dots = getDotVecFromIndices (model, arrowX, arrowY)
in
CommonUpdate.resizeWindow (model, width, height, dots)
end
fun undoAction model = (model, [])
fun redoAction model = (model, [])
fun toggleGraph (model: app_type) =
if #showGraph model then
let
val model = AppWith.graphVisibility (model, false)
val drawMsg = DRAW_GRAPH (Vector.fromList [])
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
else
let
val model = AppWith.graphVisibility (model, true)
val graphLines = GraphLines.generate model
val drawMsg = DRAW_GRAPH graphLines
val drawMsg = [DRAW drawMsg]
in
(model, drawMsg)
end
fun updateNum (model: app_type, newNum) =
(AppWith.modalNum (model, newNum), [])
fun clearNum model = updateNum (model, 0)
fun updateRed model = (AppWith.r model, [])
fun updateGreen model = (AppWith.g model, [])
fun updateBlue model = (AppWith.b model, [])
fun updateAlpha model = (AppWith.a model, [])
fun changeLayer model = (AppWith.layer model, [])
fun selectCursorColour (model: app_type) =
let
val {layer, layerTree, arrowX, arrowY, ...} = model
in
case LayerTree.get (layer, layerTree) of
SOME grid =>
let
val yAxis = Vector.sub (grid, arrowX)
val {r, g, b, a} = Vector.sub (yAxis, arrowY)
val model = AppWith.cursorColour (model, r, g, b, a)
in
(model, [])
end
| NONE => (model, [])
end
fun updateCanvas (model, canvasWidth, canvasHeight) =
let
val
{ arrowX
, arrowY
, windowWidth
, windowHeight
, xClickPoints
, yClickPoints
, showGraph
, layerTree
, ...
} = model
val dotVec = getDotVecFromIndices (model, arrowX, arrowY)
val graphLines =
if showGraph then GraphLines.generate model else Vector.fromList []
val maxSide = Int.max (canvasWidth, canvasHeight)
val squares = LayerTree.flatten (maxSide, layerTree)
val squares = CollisionTree.toTriangles
( windowWidth
, windowHeight
, squares
, maxSide
, canvasWidth
, canvasHeight
, xClickPoints
, yClickPoints
)
val msg =
RESIZE_SQUARES_DOTS_AND_GRAPH
{squares = squares, dots = dotVec, graphLines = graphLines}
in
(model, [DRAW msg])
end
fun updateCanvasWidth model =
let
val {modalNum, layerTree, canvasHeight, ...} = model
val newCanvasWidth = modalNum
val maxSide = Int.max (newCanvasWidth, canvasHeight)
val layerTree = LayerTree.changeGridSize (maxSide, layerTree)
val model = AppWith.canvasWidth (model, newCanvasWidth, layerTree)
val {canvasWidth, canvasHeight, ...} = model
in
updateCanvas (model, canvasWidth, canvasHeight)
end
fun updateCanvasHeight model =
let
val {modalNum, layerTree, canvasWidth, ...} = model
val newCanvasHeight = modalNum
val maxSide = Int.max (newCanvasHeight, canvasWidth)
val layerTree = LayerTree.changeGridSize (maxSide, layerTree)
val model = AppWith.canvasHeight (model, newCanvasHeight, layerTree)
val {canvasWidth, canvasHeight, ...} = model
in
updateCanvas (model, canvasWidth, canvasHeight)
end
fun useLayers (model, layerTree, canvasWidth, canvasHeight) =
let
val model =
AppWith.parsedLayerTree (model, layerTree, canvasWidth, canvasHeight)
val graphLines =
if #showGraph model then GraphLines.generate model
else Vector.fromList []
val initialMsg = DRAW_GRAPH graphLines
val initialMsg = [DRAW initialMsg]
in
getDrawMessage (model, initialMsg)
end
fun enterMoveMode model =
let val model = AppWith.mode (model, AppType.MOVE_MODE)
in (model, [])
end
fun flipHorizontally (model: app_type) =
let
val {layerTree, arrowX, arrowY, ...} = model
val layerTree = LayerTree.flipHorizontally layerTree
val model = AppWith.layerTree (model, layerTree, arrowX, arrowY)
in
getDrawMessage (model, [])
end
fun update (model: app_type, inputMsg) =
case inputMsg of
MOUSE_MOVE {x = mouseX, y = mouseY} =>
let val model = AppWith.mousePosition (model, mouseX, mouseY)
in mouseMoveOrRelease model
end
| MOUSE_LEFT_RELEASE => mouseMoveOrRelease model
| MOUSE_LEFT_CLICK => mouseLeftClick model
| NUM num => updateNum (model, num)
| KEY_ESC => clearNum model
| KEY_R => updateRed model
| KEY_G => updateGreen model
| KEY_B => updateBlue model
| KEY_A => updateAlpha model
| KEY_L => changeLayer model
| KEY_C => selectCursorColour model
| KEY_W => updateCanvasWidth model
| KEY_H => updateCanvasHeight model
| KEY_M => enterMoveMode model
| KEY_F => flipHorizontally model
| RESIZE_WINDOW {width, height} => resizeWindow (model, width, height)
| UNDO_ACTION => undoAction model
| REDO_ACTION => redoAction model
| KEY_T => toggleGraph model
| KEY_CTRL_S => CommonUpdate.getSaveSquaresMsg model
| KEY_CTRL_L => CommonUpdate.getLoadSquaresMsg model
| KEY_CTRL_E => CommonUpdate.getExportSquaresMsg model
| KEY_CTRL_C => CommonUpdate.getCollisionMsg model
| USE_LAYERS {tree, canvasWidth, canvasHeight} =>
useLayers (model, tree, canvasWidth, canvasHeight)
| SQUARES_LOAD_ERROR => CommonUpdate.squaresLoadError model
| ARROW_UP => moveArrowUp model
| ARROW_LEFT => moveArrowLeft model
| ARROW_RIGHT => moveArrowRight model
| ARROW_DOWN => moveArrowDown model
| KEY_BACKSPACE => backspace model
| KEY_ENTER => enterOrSpaceCoordinates model
| KEY_SPACE => enterOrSpaceCoordinates model
end