parent
5dd97d182a
commit
33e31a2599
@ -0,0 +1,142 @@
|
|||||||
|
package com.iqball.app.component
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.layout.boundsInParent
|
||||||
|
import androidx.compose.ui.layout.boundsInRoot
|
||||||
|
import androidx.compose.ui.layout.onGloballyPositioned
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.chihsuanwu.freescroll.freeScroll
|
||||||
|
import com.chihsuanwu.freescroll.rememberFreeScrollState
|
||||||
|
import com.iqball.app.model.tactic.StepNodeInfo
|
||||||
|
import com.iqball.app.ui.theme.SelectedStepNode
|
||||||
|
import com.iqball.app.ui.theme.StepNode
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StepsTree(root: StepNodeInfo, selectedNodeId: Int, onNodeSelected: (StepNodeInfo) -> Unit) {
|
||||||
|
|
||||||
|
val scrollState = rememberFreeScrollState()
|
||||||
|
val nodesOffsets = remember { mutableStateMapOf<StepNodeInfo, Rect>() }
|
||||||
|
var globalOffset by remember { mutableStateOf(Offset(0F, 0F)) }
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(Color.LightGray)
|
||||||
|
.freeScroll(scrollState)
|
||||||
|
.onGloballyPositioned { globalOffset = it.boundsInRoot().topLeft }
|
||||||
|
.drawWithContent {
|
||||||
|
|
||||||
|
if (nodesOffsets.isEmpty()) {
|
||||||
|
drawContent()
|
||||||
|
return@drawWithContent
|
||||||
|
}
|
||||||
|
|
||||||
|
val toDraw = mutableListOf(root)
|
||||||
|
while (toDraw.isNotEmpty()) {
|
||||||
|
val parent = toDraw.removeLast()
|
||||||
|
val parentCenter = nodesOffsets[parent]!!.center.minus(globalOffset)
|
||||||
|
for (children in parent.children) {
|
||||||
|
val childrenCenter = nodesOffsets[children]!!.center.minus(globalOffset)
|
||||||
|
Log.d("STATE", "$parentCenter, $childrenCenter")
|
||||||
|
drawLine(Color.Black, start = parentCenter, end = childrenCenter, strokeWidth = 5F)
|
||||||
|
toDraw += children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawContent()
|
||||||
|
|
||||||
|
},
|
||||||
|
contentAlignment = Alignment.TopCenter
|
||||||
|
) {
|
||||||
|
StepsTreeContent(root, selectedNodeId, onNodeSelected, nodesOffsets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun StepsTreeContent(
|
||||||
|
node: StepNodeInfo,
|
||||||
|
selectedNodeId: Int,
|
||||||
|
onNodeSelected: (StepNodeInfo) -> Unit,
|
||||||
|
nodesOffsets: MutableMap<StepNodeInfo, Rect>
|
||||||
|
) {
|
||||||
|
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
StepPiece(
|
||||||
|
node = node,
|
||||||
|
isSelected = selectedNodeId == node.id,
|
||||||
|
onNodeSelected = { onNodeSelected(node) },
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.onGloballyPositioned {
|
||||||
|
nodesOffsets[node] = it.boundsInRoot()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 50.dp)
|
||||||
|
) {
|
||||||
|
for (children in node.children) {
|
||||||
|
StepsTreeContent(
|
||||||
|
node = children,
|
||||||
|
selectedNodeId = selectedNodeId,
|
||||||
|
onNodeSelected = onNodeSelected,
|
||||||
|
nodesOffsets = nodesOffsets
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StepPiece(
|
||||||
|
node: StepNodeInfo,
|
||||||
|
isSelected: Boolean,
|
||||||
|
onNodeSelected: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val color = if (isSelected) SelectedStepNode else StepNode
|
||||||
|
|
||||||
|
return Surface(
|
||||||
|
shape = CircleShape,
|
||||||
|
modifier = modifier.clickable {
|
||||||
|
onNodeSelected()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = node.id.toString(),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = if (isSelected) Color.White else Color.Black,
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color)
|
||||||
|
.size(PlayerPieceDiameterDp.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue