Skip to content

Commit 8f236d5

Browse files
committed
implement command dialogs
1 parent 4014135 commit 8f236d5

File tree

17 files changed

+349
-49
lines changed

17 files changed

+349
-49
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package warlockfe.warlock3.compose.icons
2+
3+
import androidx.compose.ui.graphics.Color
4+
import androidx.compose.ui.graphics.PathFillType
5+
import androidx.compose.ui.graphics.SolidColor
6+
import androidx.compose.ui.graphics.StrokeCap
7+
import androidx.compose.ui.graphics.StrokeJoin
8+
import androidx.compose.ui.graphics.vector.ImageVector
9+
import androidx.compose.ui.graphics.vector.path
10+
import androidx.compose.ui.unit.dp
11+
12+
public val Arrow_right: ImageVector
13+
get() {
14+
if (_Arrow_right != null) {
15+
return _Arrow_right!!
16+
}
17+
_Arrow_right = ImageVector.Builder(
18+
name = "Arrow_right",
19+
defaultWidth = 24.dp,
20+
defaultHeight = 24.dp,
21+
viewportWidth = 960f,
22+
viewportHeight = 960f
23+
).apply {
24+
path(
25+
fill = SolidColor(Color.Black),
26+
fillAlpha = 1.0f,
27+
stroke = null,
28+
strokeAlpha = 1.0f,
29+
strokeLineWidth = 1.0f,
30+
strokeLineCap = StrokeCap.Butt,
31+
strokeLineJoin = StrokeJoin.Miter,
32+
strokeLineMiter = 1.0f,
33+
pathFillType = PathFillType.NonZero
34+
) {
35+
moveTo(400f, 680f)
36+
verticalLineToRelative(-400f)
37+
lineToRelative(200f, 200f)
38+
close()
39+
}
40+
}.build()
41+
return _Arrow_right!!
42+
}
43+
44+
private var _Arrow_right: ImageVector? = null

compose/src/commonMain/kotlin/warlockfe/warlock3/compose/macros/KeyText.kt

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ private val keyMappings = mapOf(
5555
Key.Zero to "0",
5656
Key.Minus to "Minus",
5757
Key.Equals to "Equals",
58+
Key.Backspace to "Backspace",
5859
Key.A to "A",
5960
Key.B to "B",
6061
Key.C to "C",

compose/src/commonMain/kotlin/warlockfe/warlock3/compose/ui/game/GameView.kt

+130-4
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,38 @@ import androidx.compose.foundation.layout.fillMaxSize
99
import androidx.compose.foundation.layout.fillMaxWidth
1010
import androidx.compose.foundation.layout.height
1111
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.material3.DropdownMenu
13+
import androidx.compose.material3.DropdownMenuItem
1214
import androidx.compose.material3.FilledTonalButton
15+
import androidx.compose.material3.Icon
1316
import androidx.compose.material3.MaterialTheme
1417
import androidx.compose.material3.Text
1518
import androidx.compose.material3.contentColorFor
1619
import androidx.compose.runtime.Composable
1720
import androidx.compose.runtime.LaunchedEffect
1821
import androidx.compose.runtime.collectAsState
1922
import androidx.compose.runtime.getValue
23+
import androidx.compose.runtime.mutableStateOf
2024
import androidx.compose.runtime.remember
25+
import androidx.compose.runtime.setValue
2126
import androidx.compose.ui.Alignment
2227
import androidx.compose.ui.Modifier
2328
import androidx.compose.ui.graphics.Color
2429
import androidx.compose.ui.unit.dp
2530
import warlockfe.warlock3.compose.components.CompassView
2631
import warlockfe.warlock3.compose.components.ResizablePanel
2732
import warlockfe.warlock3.compose.components.ResizablePanelState
33+
import warlockfe.warlock3.compose.icons.Arrow_right
2834
import warlockfe.warlock3.compose.ui.components.HandsView
2935
import warlockfe.warlock3.compose.ui.components.IndicatorView
3036
import warlockfe.warlock3.compose.ui.components.VitalBars
3137
import warlockfe.warlock3.compose.ui.window.ScrollEvent
3238
import warlockfe.warlock3.compose.ui.window.WindowUiState
3339
import warlockfe.warlock3.compose.ui.window.WindowView
40+
import warlockfe.warlock3.compose.util.LocalLogger
3441
import warlockfe.warlock3.compose.util.toColor
42+
import warlockfe.warlock3.core.client.WarlockAction
43+
import warlockfe.warlock3.core.client.WarlockMenuData
3544
import warlockfe.warlock3.core.prefs.defaultStyles
3645
import warlockfe.warlock3.core.text.StyleDefinition
3746
import warlockfe.warlock3.core.window.WindowLocation
@@ -62,6 +71,26 @@ fun GameView(
6271

6372
val subWindows = viewModel.windowUiStates.collectAsState()
6473
val mainWindow = viewModel.mainWindowUiState.collectAsState()
74+
75+
var openMenuId: Int? by remember { mutableStateOf(null) }
76+
var openMenu: WarlockMenuData? by remember { mutableStateOf(null) }
77+
78+
LaunchedEffect(openMenuId) {
79+
if (openMenuId != null) {
80+
viewModel.menuData.collect { menuData ->
81+
openMenu = menuData
82+
}
83+
} else {
84+
openMenu = null
85+
}
86+
}
87+
88+
ActionContextMenu(
89+
menuData = openMenu,
90+
expectedMenuId = openMenuId,
91+
onDismiss = { openMenuId = null },
92+
)
93+
6594
GameTextWindows(
6695
modifier = Modifier.fillMaxWidth().weight(1f),
6796
subWindowUiStates = subWindows.value,
@@ -70,8 +99,20 @@ fun GameView(
7099
topHeight = viewModel.topHeight.collectAsState(null).value,
71100
leftWidth = viewModel.leftWidth.collectAsState(null).value,
72101
rightWidth = viewModel.rightWidth.collectAsState(null).value,
73-
onActionClicked = {
74-
viewModel.sendCommand(it)
102+
onActionClicked = { action ->
103+
when (action) {
104+
is WarlockAction.SendCommand -> {
105+
viewModel.sendCommand(action.command)
106+
}
107+
108+
is WarlockAction.OpenMenu -> {
109+
openMenuId = action.onClick()
110+
}
111+
112+
else -> {
113+
// Not our concern
114+
}
115+
}
75116
},
76117
onMoveClicked = { name, location ->
77118
viewModel.moveWindow(name = name, location = location)
@@ -96,6 +137,91 @@ fun GameView(
96137
}
97138
}
98139

140+
@Composable
141+
fun ActionContextMenu(
142+
menuData: WarlockMenuData?,
143+
expectedMenuId: Int?,
144+
onDismiss: () -> Unit,
145+
) {
146+
val logger = LocalLogger.current
147+
if (menuData != null) {
148+
if (expectedMenuId == menuData.id) {
149+
DropdownMenu(
150+
expanded = true,
151+
onDismissRequest = onDismiss,
152+
) {
153+
val groups = menuData.items.groupBy { it.category.split('-').first() }
154+
val categories = groups.keys.sorted()
155+
categories.forEach { category ->
156+
val items = groups[category]!!
157+
if (!category.contains('_')) {
158+
items.forEach { item ->
159+
logger.debug { "Menu item: $item" }
160+
DropdownMenuItem(
161+
text = {
162+
Text(item.label)
163+
},
164+
onClick = item.action
165+
)
166+
}
167+
} else {
168+
var expanded by remember(category) { mutableStateOf(false) }
169+
DropdownMenuItem(
170+
text = {
171+
Text(category.split('_').getOrNull(1) ?: "Unknown")
172+
},
173+
onClick = { expanded = true },
174+
trailingIcon = {
175+
Icon(Arrow_right, contentDescription = "expandable")
176+
}
177+
)
178+
DropdownMenu(
179+
expanded = expanded,
180+
onDismissRequest = { expanded = false },
181+
) {
182+
val subgroups = items.groupBy { it.category.split('-').getOrNull(1) }
183+
subgroups[null]?.forEach { item ->
184+
DropdownMenuItem(
185+
text = {
186+
Text(item.label)
187+
},
188+
onClick = item.action
189+
)
190+
}
191+
val subcatories = subgroups.keys.filterNotNull().sorted()
192+
subcatories.forEach { category ->
193+
var expanded by remember(category) { mutableStateOf(false) }
194+
DropdownMenuItem(
195+
text = {
196+
Text(category)
197+
},
198+
onClick = { expanded = true },
199+
trailingIcon = {
200+
Icon(Arrow_right, contentDescription = "expandable")
201+
}
202+
)
203+
DropdownMenu(
204+
expanded = expanded,
205+
onDismissRequest = { expanded = false },
206+
) {
207+
subgroups[category]?.forEach { item ->
208+
DropdownMenuItem(
209+
text = {
210+
Text(item.label)
211+
},
212+
onClick = item.action
213+
)
214+
}
215+
}
216+
}
217+
}
218+
}
219+
}
220+
}
221+
}
222+
}
223+
}
224+
99225
@Composable
100226
fun GameTextWindows(
101227
modifier: Modifier,
@@ -105,7 +231,7 @@ fun GameTextWindows(
105231
topHeight: Int?,
106232
leftWidth: Int?,
107233
rightWidth: Int?,
108-
onActionClicked: (String) -> Unit,
234+
onActionClicked: (WarlockAction) -> Unit,
109235
onMoveClicked: (name: String, WindowLocation) -> Unit,
110236
onHeightChanged: (String, Int) -> Unit,
111237
onWidthChanged: (String, Int) -> Unit,
@@ -295,7 +421,7 @@ fun WindowViews(
295421
windowStates: List<WindowUiState>,
296422
selectedWindow: String,
297423
isHorizontal: Boolean,
298-
onActionClicked: (String) -> Unit,
424+
onActionClicked: (WarlockAction) -> Unit,
299425
onMoveClicked: (String, WindowLocation) -> Unit,
300426
onWidthChanged: (String, Int) -> Unit,
301427
onHeightChanged: (String, Int) -> Unit,

compose/src/commonMain/kotlin/warlockfe/warlock3/compose/ui/game/GameViewModel.kt

+7-4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import warlockfe.warlock3.core.client.ClientProgressBarEvent
6464
import warlockfe.warlock3.core.client.GameCharacter
6565
import warlockfe.warlock3.core.client.ProgressBarData
6666
import warlockfe.warlock3.core.client.SendCommandType
67+
import warlockfe.warlock3.core.client.WarlockAction
6768
import warlockfe.warlock3.core.client.WarlockClient
6869
import warlockfe.warlock3.core.macro.MacroToken
6970
import warlockfe.warlock3.core.prefs.AliasRepository
@@ -351,6 +352,8 @@ class GameViewModel(
351352

352353
val disconnected = client.disconnected
353354

355+
val menuData = client.menuData
356+
354357
init {
355358
client.eventFlow
356359
.onEach { event ->
@@ -394,19 +397,19 @@ class GameViewModel(
394397
when (info.status) {
395398
ScriptStatus.Running -> text += StyledString(
396399
"pause",
397-
WarlockStyle.Link("action" to "/pause ${it.key}")
400+
WarlockStyle.Link(WarlockAction.SendCommand("/pause ${it.key}"))
398401
)
399402

400403
ScriptStatus.Suspended -> text += StyledString(
401404
"resume",
402-
WarlockStyle.Link("action" to "/resume ${it.key}")
405+
WarlockStyle.Link(WarlockAction.SendCommand("/resume ${it.key}"))
403406
)
404407

405408
else -> {
406409
// do nothing
407410
}
408411
}
409-
text += StyledString(" ") + StyledString("stop", WarlockStyle.Link("action" to "/kill ${it.key}"))
412+
text += StyledString(" ") + StyledString("stop", WarlockStyle.Link(WarlockAction.SendCommand("/kill ${it.key}")))
410413
scriptStream.appendLine(text, false)
411414
}
412415
}
@@ -793,7 +796,7 @@ fun StreamLine.toWindowLine(
793796
highlights: List<ViewHighlight>,
794797
presets: Map<String, StyleDefinition>,
795798
components: Map<String, StyledString>,
796-
actionHandler: (String) -> Unit,
799+
actionHandler: (WarlockAction) -> Unit,
797800
): WindowLine? {
798801
val textWithComponents = text.toAnnotatedString(
799802
variables = components,

compose/src/commonMain/kotlin/warlockfe/warlock3/compose/ui/settings/AppearanceView.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ import kotlinx.coroutines.DelicateCoroutinesApi
3333
import kotlinx.coroutines.GlobalScope
3434
import kotlinx.coroutines.launch
3535
import warlockfe.warlock3.compose.components.ColorPickerDialog
36+
import warlockfe.warlock3.compose.components.FontPickerDialog
37+
import warlockfe.warlock3.compose.components.FontUpdate
3638
import warlockfe.warlock3.compose.components.LocalScrollbarStyle
3739
import warlockfe.warlock3.compose.components.ScrollableColumn
3840
import warlockfe.warlock3.compose.components.ScrollbarStyle
39-
import warlockfe.warlock3.compose.components.FontPickerDialog
40-
import warlockfe.warlock3.compose.components.FontUpdate
4141
import warlockfe.warlock3.compose.util.getEntireLineStyles
4242
import warlockfe.warlock3.compose.util.toAnnotatedString
4343
import warlockfe.warlock3.compose.util.toColor

compose/src/commonMain/kotlin/warlockfe/warlock3/compose/ui/window/WindowView.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import warlockfe.warlock3.compose.ui.settings.WindowSettingsDialog
5353
import warlockfe.warlock3.compose.util.LocalLogger
5454
import warlockfe.warlock3.compose.util.createFontFamily
5555
import warlockfe.warlock3.compose.util.toColor
56+
import warlockfe.warlock3.core.client.WarlockAction
5657
import warlockfe.warlock3.core.text.StyleDefinition
5758
import warlockfe.warlock3.core.text.specifiedOrNull
5859
import warlockfe.warlock3.core.window.Window
@@ -63,7 +64,7 @@ fun WindowView(
6364
modifier: Modifier,
6465
uiState: WindowUiState,
6566
isSelected: Boolean,
66-
onActionClicked: (String) -> Unit,
67+
onActionClicked: (WarlockAction) -> Unit,
6768
onMoveClicked: (WindowLocation) -> Unit,
6869
onMoveTowardsStart: (() -> Unit)?,
6970
onMoveTowardsEnd: (() -> Unit)?,
@@ -280,7 +281,7 @@ private fun WindowViewContent(
280281
highlights: List<ViewHighlight>,
281282
presets: Map<String, StyleDefinition>,
282283
defaultStyle: StyleDefinition,
283-
onActionClicked: (String) -> Unit
284+
onActionClicked: (WarlockAction) -> Unit
284285
) {
285286
val logger = LocalLogger.current
286287

0 commit comments

Comments
 (0)