Repository navigation
Add HUD editor onboarding tour - #1204
Conversation
Wyvest
left a comment
There was a problem hiding this comment.
Left a few notes on the tour. The main ones: Escape is swallowed during blocked steps, the replay entry is gated on a merge pair even though the Done step promises it, and the merge-eligibility check is a copy of HudBackgroundMerge's that has already drifted.
| } | ||
| .onKeyEvent { keyEvent -> | ||
| if (keyEvent.type != KeyEventType.KeyDown) return@onKeyEvent false | ||
| if (tourBlocksEditor) { |
There was a problem hiding this comment.
While a non-interactive step is active this returns true for every KeyDown, so Escape never reaches ComposeScreen's super.keyPressed. It can't close the editor or skip the tour, and the only way out is clicking "Skip tour". During the interactive Merging step Escape works normally, so it's inconsistent too. Suggest letting Escape through, or mapping it to endTour(), and only consuming arrows and Enter.
| undoEnabled = canUndo, | ||
| onRedo = { HudDesignSession.handleRedo(true) }, | ||
| redoEnabled = canRedo, | ||
| onTour = if (pasteMenuOffset != null && hasTourMergePair()) ({ startTour() }) else null, |
There was a problem hiding this comment.
The replay entry only shows when hasTourMergePair() is true, but the Done step says "Right-click empty space and pick Editor Tour to see this again". After the user merges their two HUDs, or deletes one, the row disappears and the promised replay isn't available. The Merging step already handles the no-pair case with the task_add text, so this gate doesn't seem necessary.
| hud !is LegacyHud && !hud.locked && !hud.hidden && hud.canMergeBackground() && | ||
| hud.showBackground && hud.mergeBackground && hud.hasBackground() | ||
|
|
||
| private fun tourMergeCompatible(a: Hud, b: Hud): Boolean = |
There was a problem hiding this comment.
canTourMerge/tourMergeCompatible copy the eligibility rules from HudBackgroundMerge.computeGroups and the private Item.sameStyle, and they already differ: this checks LegacyHud where the real code checks LegacyHudMarker, and it skips the renderedW/H > 0 check. If a HUD the real merger rejects counts as a pair here, the tour auto-starts and shows the ghost hint, but no merge ever happens and Next stays disabled on Merging. Could HudBackgroundMerge expose one predicate that both places call?
| tourStep == null && !isDragging && !isResizing && !pointerDown && hasTourMergePair() | ||
| } | ||
| }.first { it } | ||
| if (!OneConfigConfig.hudEditorTourSeen) startTour() |
There was a problem hiding this comment.
Auto-start waits out drag, resize and pointer-down, but not an open panel or a focused text field. A common path: the user clicks a second text HUD in the library, the panel opens, and they start typing its text. The pair now exists, so the tour starts, LaunchedEffect(tourStep) clears the selection and closes the panel, and keyFocusRequester takes focus, swallowing the rest of their typing. Might be worth also waiting until no panel is open or no text input has focus.
| hoveredHud = null | ||
| } | ||
|
|
||
| fun startTour() { |
There was a problem hiding this comment.
HudDesignStudio stays composed across editor closes (RetainedVisibility), and nothing ends the tour on close. If the user closes mid-tour, tourStep and the forced panel/category stay as they are, tourPreviousCategory is never restored, and the next normal open drops them back into the same step. Closing during Anchoring also leaves the preview Popup at full opacity through the fade-out. Probably simplest to call endTour() when the editor closes.
| var lastTourStep by remember { mutableStateOf(HudTourStep.entries.first()) } | ||
| tourStep?.let { lastTourStep = it } | ||
| AnimatedVisibility( | ||
| visible = tourStep != null, |
There was a problem hiding this comment.
After Skip or Done, AnimatedVisibility keeps the overlay composed through fadeOut with lastTourStep, which is non-interactive, so its full-screen pointerInput keeps eating clicks for the length of the fade. CHROME_TOUR_CARD also stays in chromeRects until dispose, so presses where the card was are still treated as chrome.
| if (next != null) tourStep = next else if (delta > 0) endTour() | ||
| } | ||
|
|
||
| LaunchedEffect(tourStep) { |
There was a problem hiding this comment.
Each step clears selectedHuds and closes the panel, and endTour() forces both empty again. Only the category is saved and restored. If you replay from the canvas menu while a HUD is selected with its settings open, the selection and panel are gone when the tour ends. Could snapshot those alongside tourPreviousCategory.
| } | ||
|
|
||
| fun startTour() { | ||
| OneConfigConfig.markHudEditorTourSeen() |
There was a problem hiding this comment.
This marks the tour seen as soon as it starts, before the first step renders. If the game closes or crashes on Welcome, it never auto-shows again, and with the replay row gated on a merge pair the user might not be able to get it back. Marking it seen in endTour() (Skip/Done) seems safer.
| } | ||
| .graphicsLayer { alpha = if (measured) 1f else 0f } | ||
| .then(cardModifier) | ||
| .pointerInput(Unit) { |
There was a problem hiding this comment.
This consume-everything loop appears three times (here, line 180, and in HudSettingsReset.kt for the preview menu), and the copies differ slightly in pass and in hover/scroll handling. Modifier.blockInteraction in Common.kt and chromeBlocker in the studio already cover this. The overlay also blocks twice: it registers CHROME_TOUR for inChrome() and consumes every event.
| undoEnabled = canUndo, | ||
| onRedo = { HudDesignSession.handleRedo(true) }, | ||
| redoEnabled = canRedo, | ||
| onTour = if (pasteMenuOffset != null && hasTourMergePair()) ({ startTour() }) else null, |
There was a problem hiding this comment.
Minor: hasTourMergePair() runs in the composable body on every recomposition while the paste menu is open. That's O(n²) pairs, each calling mergeGroupOf (a linear scan), and canMergeAny already computes the same thing in a derivedStateOf. Could hoist one remembered derived state keyed on instancesRevision and share it with the auto-start condition.
|
Thanks, addressed all of these in 08886cc. Escape now closes the editor (which ends the tour) instead of skipping it. |
Adds a guided tour to the HUD editor that explains its main features.
When it shows
hudEditorTourSeenfield inoneconfig.json.Steps
Non-interactive steps block canvas input and HUD hotkeys. Arrow keys and Enter move between steps. All text is in
en_us.jsonunderoneconfig.hud.tour.*.Changes
HudTour.kt(new): steps, spotlight overlay, card, drag hintHudDesignStudio.kt: tour state, auto-start, input blocking, focus rects, merge detectionHudSettingsReset.kt:previewmode for the HUD context menu, optional tour row in the canvas menuOneConfigConfig.java:hudEditorTourSeenandmarkHudEditorTourSeen()en_us.json: tour stringsTested on 26.3 Fabric.