parent
f632590c2a
commit
5d1147d59e
@ -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