@datamoc/mw_games 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +359 -0
- package/README.md +7 -7
- package/dist/actors/Inventory.d.ts +7 -1
- package/dist/actors/Inventory.d.ts.map +1 -1
- package/dist/actors/Inventory.js.map +1 -1
- package/dist/actors/Shop.d.ts.map +1 -1
- package/dist/actors/Shop.js +4 -1
- package/dist/actors/Shop.js.map +1 -1
- package/dist/actors/craft.d.ts +35 -14
- package/dist/actors/craft.d.ts.map +1 -1
- package/dist/actors/craft.js +56 -24
- package/dist/actors/craft.js.map +1 -1
- package/dist/actors/index.d.ts +1 -1
- package/dist/actors/index.d.ts.map +1 -1
- package/dist/ai/Heuristics.d.ts +240 -0
- package/dist/ai/Heuristics.d.ts.map +1 -0
- package/dist/ai/Heuristics.js +298 -0
- package/dist/ai/Heuristics.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +2 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/ai/lua.d.ts +21 -0
- package/dist/ai/lua.d.ts.map +1 -1
- package/dist/ai/lua.js +21 -0
- package/dist/ai/lua.js.map +1 -1
- package/dist/ai/score.d.ts +162 -0
- package/dist/ai/score.d.ts.map +1 -0
- package/dist/ai/score.js +147 -0
- package/dist/ai/score.js.map +1 -0
- package/dist/assets/loader.d.ts +18 -4
- package/dist/assets/loader.d.ts.map +1 -1
- package/dist/assets/loader.js +40 -11
- package/dist/assets/loader.js.map +1 -1
- package/dist/audio/Positional.d.ts +125 -0
- package/dist/audio/Positional.d.ts.map +1 -0
- package/dist/audio/Positional.js +135 -0
- package/dist/audio/Positional.js.map +1 -0
- package/dist/audio/Sound.d.ts +7 -1
- package/dist/audio/Sound.d.ts.map +1 -1
- package/dist/audio/Sound.js +8 -2
- package/dist/audio/Sound.js.map +1 -1
- package/dist/audio/index.d.ts +2 -0
- package/dist/audio/index.d.ts.map +1 -1
- package/dist/audio/index.js +1 -0
- package/dist/audio/index.js.map +1 -1
- package/dist/battle/AttackDialog.d.ts +75 -0
- package/dist/battle/AttackDialog.d.ts.map +1 -0
- package/dist/battle/AttackDialog.js +115 -0
- package/dist/battle/AttackDialog.js.map +1 -0
- package/dist/battle/AttackPreview.d.ts +70 -0
- package/dist/battle/AttackPreview.d.ts.map +1 -0
- package/dist/battle/AttackPreview.js +78 -0
- package/dist/battle/AttackPreview.js.map +1 -0
- package/dist/battle/BattleStats.d.ts +45 -0
- package/dist/battle/BattleStats.d.ts.map +1 -0
- package/dist/battle/BattleStats.js +63 -0
- package/dist/battle/BattleStats.js.map +1 -0
- package/dist/battle/UnitSelector.d.ts +72 -0
- package/dist/battle/UnitSelector.d.ts.map +1 -0
- package/dist/battle/UnitSelector.js +117 -0
- package/dist/battle/UnitSelector.js.map +1 -0
- package/dist/battle/Whiteboard.d.ts +50 -0
- package/dist/battle/Whiteboard.d.ts.map +1 -0
- package/dist/battle/Whiteboard.js +94 -0
- package/dist/battle/Whiteboard.js.map +1 -0
- package/dist/battle/index.d.ts +10 -0
- package/dist/battle/index.d.ts.map +1 -1
- package/dist/battle/index.js +5 -0
- package/dist/battle/index.js.map +1 -1
- package/dist/board/Classics.d.ts.map +1 -1
- package/dist/board/Classics.js +51 -39
- package/dist/board/Classics.js.map +1 -1
- package/dist/board/FogOfWar.d.ts +32 -2
- package/dist/board/FogOfWar.d.ts.map +1 -1
- package/dist/board/FogOfWar.js +70 -6
- package/dist/board/FogOfWar.js.map +1 -1
- package/dist/board/HexSkirmish.d.ts.map +1 -1
- package/dist/board/HexSkirmish.js +69 -20
- package/dist/board/HexSkirmish.js.map +1 -1
- package/dist/board/Tactics.d.ts +7 -0
- package/dist/board/Tactics.d.ts.map +1 -1
- package/dist/board/Tactics.js +2 -2
- package/dist/board/Tactics.js.map +1 -1
- package/dist/core/Achievements.d.ts +40 -7
- package/dist/core/Achievements.d.ts.map +1 -1
- package/dist/core/Achievements.js +53 -7
- package/dist/core/Achievements.js.map +1 -1
- package/dist/core/Hex.d.ts +26 -6
- package/dist/core/Hex.d.ts.map +1 -1
- package/dist/core/Hex.js +40 -13
- package/dist/core/Hex.js.map +1 -1
- package/dist/core/Input.d.ts +36 -0
- package/dist/core/Input.d.ts.map +1 -1
- package/dist/core/Input.js +63 -1
- package/dist/core/Input.js.map +1 -1
- package/dist/core/Random.d.ts +93 -0
- package/dist/core/Random.d.ts.map +1 -1
- package/dist/core/Random.js +177 -0
- package/dist/core/Random.js.map +1 -1
- package/dist/core/SyncGuard.d.ts +57 -0
- package/dist/core/SyncGuard.d.ts.map +1 -0
- package/dist/core/SyncGuard.js +116 -0
- package/dist/core/SyncGuard.js.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/i18n/Po.d.ts +51 -0
- package/dist/i18n/Po.d.ts.map +1 -0
- package/dist/i18n/Po.js +176 -0
- package/dist/i18n/Po.js.map +1 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -1
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/index.js.map +1 -1
- package/dist/mw_games.global.js +104 -98
- package/dist/mwl/MapFile.d.ts +41 -0
- package/dist/mwl/MapFile.d.ts.map +1 -0
- package/dist/mwl/MapFile.js +43 -0
- package/dist/mwl/MapFile.js.map +1 -0
- package/dist/mwl/actors.d.ts +46 -2
- package/dist/mwl/actors.d.ts.map +1 -1
- package/dist/mwl/actors.js +46 -2
- package/dist/mwl/actors.js.map +1 -1
- package/dist/mwl/campaign.d.ts +51 -0
- package/dist/mwl/campaign.d.ts.map +1 -0
- package/dist/mwl/campaign.js +58 -0
- package/dist/mwl/campaign.js.map +1 -0
- package/dist/mwl/carryover.d.ts +86 -0
- package/dist/mwl/carryover.d.ts.map +1 -0
- package/dist/mwl/carryover.js +70 -0
- package/dist/mwl/carryover.js.map +1 -0
- package/dist/mwl/catalog.d.ts +10 -1
- package/dist/mwl/catalog.d.ts.map +1 -1
- package/dist/mwl/catalog.js +10 -1
- package/dist/mwl/catalog.js.map +1 -1
- package/dist/mwl/compiler.d.ts +70 -3
- package/dist/mwl/compiler.d.ts.map +1 -1
- package/dist/mwl/compiler.js +70 -3
- package/dist/mwl/compiler.js.map +1 -1
- package/dist/mwl/conditions.d.ts +10 -1
- package/dist/mwl/conditions.d.ts.map +1 -1
- package/dist/mwl/conditions.js +10 -1
- package/dist/mwl/conditions.js.map +1 -1
- package/dist/mwl/content.d.ts +21 -0
- package/dist/mwl/content.d.ts.map +1 -1
- package/dist/mwl/content.js +19 -0
- package/dist/mwl/content.js.map +1 -1
- package/dist/mwl/expression.d.ts +21 -0
- package/dist/mwl/expression.d.ts.map +1 -1
- package/dist/mwl/expression.js +21 -0
- package/dist/mwl/expression.js.map +1 -1
- package/dist/mwl/fengari.d.ts +12 -1
- package/dist/mwl/fengari.d.ts.map +1 -1
- package/dist/mwl/fengari.js +12 -1
- package/dist/mwl/fengari.js.map +1 -1
- package/dist/mwl/grammar.d.ts +45 -1
- package/dist/mwl/grammar.d.ts.map +1 -1
- package/dist/mwl/grammar.js +45 -1
- package/dist/mwl/grammar.js.map +1 -1
- package/dist/mwl/hooks.d.ts +51 -6
- package/dist/mwl/hooks.d.ts.map +1 -1
- package/dist/mwl/hooks.js +45 -1
- package/dist/mwl/hooks.js.map +1 -1
- package/dist/mwl/index.d.ts +9 -3
- package/dist/mwl/index.d.ts.map +1 -1
- package/dist/mwl/index.js +5 -2
- package/dist/mwl/index.js.map +1 -1
- package/dist/mwl/persistence.d.ts +32 -0
- package/dist/mwl/persistence.d.ts.map +1 -1
- package/dist/mwl/persistence.js +32 -0
- package/dist/mwl/persistence.js.map +1 -1
- package/dist/mwl/readers.d.ts +24 -2
- package/dist/mwl/readers.d.ts.map +1 -1
- package/dist/mwl/readers.js +27 -4
- package/dist/mwl/readers.js.map +1 -1
- package/dist/mwl/report.d.ts +21 -2
- package/dist/mwl/report.d.ts.map +1 -1
- package/dist/mwl/report.js +21 -2
- package/dist/mwl/report.js.map +1 -1
- package/dist/mwl/runtime.d.ts +212 -7
- package/dist/mwl/runtime.d.ts.map +1 -1
- package/dist/mwl/runtime.js +682 -90
- package/dist/mwl/runtime.js.map +1 -1
- package/dist/mwl/schema.d.ts +57 -1
- package/dist/mwl/schema.d.ts.map +1 -1
- package/dist/mwl/schema.js +181 -21
- package/dist/mwl/schema.js.map +1 -1
- package/dist/mwl/scripts.d.ts +12 -1
- package/dist/mwl/scripts.d.ts.map +1 -1
- package/dist/mwl/scripts.js +12 -1
- package/dist/mwl/scripts.js.map +1 -1
- package/dist/mwl/utils.d.ts +2 -0
- package/dist/mwl/utils.d.ts.map +1 -1
- package/dist/mwl/utils.js +4 -1
- package/dist/mwl/utils.js.map +1 -1
- package/dist/roguelike/MultiTurnBeam.d.ts +50 -12
- package/dist/roguelike/MultiTurnBeam.d.ts.map +1 -1
- package/dist/roguelike/MultiTurnBeam.js +100 -53
- package/dist/roguelike/MultiTurnBeam.js.map +1 -1
- package/dist/roguelike/Targeting.d.ts +94 -0
- package/dist/roguelike/Targeting.d.ts.map +1 -1
- package/dist/roguelike/Targeting.js +123 -0
- package/dist/roguelike/Targeting.js.map +1 -1
- package/dist/roguelike/index.d.ts +3 -1
- package/dist/roguelike/index.d.ts.map +1 -1
- package/dist/roguelike/index.js +1 -0
- package/dist/roguelike/index.js.map +1 -1
- package/dist/rpg/GameState.d.ts +2 -2
- package/dist/rpg/GameState.js +2 -2
- package/dist/simulation/CampaignSave.d.ts +68 -0
- package/dist/simulation/CampaignSave.d.ts.map +1 -0
- package/dist/simulation/CampaignSave.js +54 -0
- package/dist/simulation/CampaignSave.js.map +1 -0
- package/dist/simulation/EventPresentation.d.ts +111 -0
- package/dist/simulation/EventPresentation.d.ts.map +1 -0
- package/dist/simulation/EventPresentation.js +120 -0
- package/dist/simulation/EventPresentation.js.map +1 -0
- package/dist/simulation/index.d.ts +4 -0
- package/dist/simulation/index.d.ts.map +1 -1
- package/dist/simulation/index.js +2 -0
- package/dist/simulation/index.js.map +1 -1
- package/dist/two-d/pixi-interop.d.ts +18 -6
- package/dist/two-d/pixi-interop.d.ts.map +1 -1
- package/dist/two-d/pixi-interop.js +18 -6
- package/dist/two-d/pixi-interop.js.map +1 -1
- package/dist/two-d/render/AnimatedSprite.d.ts +74 -7
- package/dist/two-d/render/AnimatedSprite.d.ts.map +1 -1
- package/dist/two-d/render/AnimatedSprite.js +88 -26
- package/dist/two-d/render/AnimatedSprite.js.map +1 -1
- package/dist/two-d/render/Camera.d.ts +64 -4
- package/dist/two-d/render/Camera.d.ts.map +1 -1
- package/dist/two-d/render/Camera.js +132 -11
- package/dist/two-d/render/Camera.js.map +1 -1
- package/dist/two-d/render/ColorTransformBatcher.d.ts +7 -1
- package/dist/two-d/render/ColorTransformBatcher.d.ts.map +1 -1
- package/dist/two-d/render/ColorTransformBatcher.js +10 -1
- package/dist/two-d/render/ColorTransformBatcher.js.map +1 -1
- package/dist/two-d/render/Halo.d.ts +58 -0
- package/dist/two-d/render/Halo.d.ts.map +1 -0
- package/dist/two-d/render/Halo.js +48 -0
- package/dist/two-d/render/Halo.js.map +1 -0
- package/dist/two-d/render/ImageModifiers.d.ts +174 -0
- package/dist/two-d/render/ImageModifiers.d.ts.map +1 -1
- package/dist/two-d/render/ImageModifiers.js +454 -1
- package/dist/two-d/render/ImageModifiers.js.map +1 -1
- package/dist/two-d/render/LightningArc.d.ts +57 -0
- package/dist/two-d/render/LightningArc.d.ts.map +1 -0
- package/dist/two-d/render/LightningArc.js +91 -0
- package/dist/two-d/render/LightningArc.js.map +1 -0
- package/dist/two-d/render/PaletteRemap.d.ts +135 -0
- package/dist/two-d/render/PaletteRemap.d.ts.map +1 -0
- package/dist/two-d/render/PaletteRemap.js +181 -0
- package/dist/two-d/render/PaletteRemap.js.map +1 -0
- package/dist/two-d/render/Particles.d.ts +26 -0
- package/dist/two-d/render/Particles.d.ts.map +1 -1
- package/dist/two-d/render/Particles.js +23 -2
- package/dist/two-d/render/Particles.js.map +1 -1
- package/dist/two-d/render/SpriteAttachment.d.ts +55 -0
- package/dist/two-d/render/SpriteAttachment.d.ts.map +1 -0
- package/dist/two-d/render/SpriteAttachment.js +60 -0
- package/dist/two-d/render/SpriteAttachment.js.map +1 -0
- package/dist/two-d/render/TerrainGraphics.d.ts +142 -0
- package/dist/two-d/render/TerrainGraphics.d.ts.map +1 -0
- package/dist/two-d/render/TerrainGraphics.js +161 -0
- package/dist/two-d/render/TerrainGraphics.js.map +1 -0
- package/dist/two-d/render/TerrainGraphicsLayer.d.ts +55 -0
- package/dist/two-d/render/TerrainGraphicsLayer.d.ts.map +1 -0
- package/dist/two-d/render/TerrainGraphicsLayer.js +54 -0
- package/dist/two-d/render/TerrainGraphicsLayer.js.map +1 -0
- package/dist/two-d/render/TintedSprite.js +2 -2
- package/dist/two-d/render/TintedSprite.js.map +1 -1
- package/dist/two-d/render/index.d.ts +15 -3
- package/dist/two-d/render/index.d.ts.map +1 -1
- package/dist/two-d/render/index.js +7 -1
- package/dist/two-d/render/index.js.map +1 -1
- package/dist/two-d/stage/StoryScreen.d.ts +110 -0
- package/dist/two-d/stage/StoryScreen.d.ts.map +1 -0
- package/dist/two-d/stage/StoryScreen.js +178 -0
- package/dist/two-d/stage/StoryScreen.js.map +1 -0
- package/dist/two-d/stage/index.d.ts +2 -0
- package/dist/two-d/stage/index.d.ts.map +1 -1
- package/dist/two-d/stage/index.js +1 -0
- package/dist/two-d/stage/index.js.map +1 -1
- package/dist/two-d/ui/Checkbox.d.ts +44 -0
- package/dist/two-d/ui/Checkbox.d.ts.map +1 -0
- package/dist/two-d/ui/Checkbox.js +89 -0
- package/dist/two-d/ui/Checkbox.js.map +1 -0
- package/dist/two-d/ui/DataTable.d.ts +79 -0
- package/dist/two-d/ui/DataTable.d.ts.map +1 -0
- package/dist/two-d/ui/DataTable.js +164 -0
- package/dist/two-d/ui/DataTable.js.map +1 -0
- package/dist/two-d/ui/Dropdown.d.ts +72 -0
- package/dist/two-d/ui/Dropdown.d.ts.map +1 -0
- package/dist/two-d/ui/Dropdown.js +126 -0
- package/dist/two-d/ui/Dropdown.js.map +1 -0
- package/dist/two-d/ui/FloatingText.d.ts +43 -4
- package/dist/two-d/ui/FloatingText.d.ts.map +1 -1
- package/dist/two-d/ui/FloatingText.js +52 -5
- package/dist/two-d/ui/FloatingText.js.map +1 -1
- package/dist/two-d/ui/FloatingTextStack.d.ts +86 -13
- package/dist/two-d/ui/FloatingTextStack.d.ts.map +1 -1
- package/dist/two-d/ui/FloatingTextStack.js +89 -18
- package/dist/two-d/ui/FloatingTextStack.js.map +1 -1
- package/dist/two-d/ui/Layout.d.ts +105 -0
- package/dist/two-d/ui/Layout.d.ts.map +1 -0
- package/dist/two-d/ui/Layout.js +174 -0
- package/dist/two-d/ui/Layout.js.map +1 -0
- package/dist/two-d/ui/MarkupText.d.ts +53 -0
- package/dist/two-d/ui/MarkupText.d.ts.map +1 -0
- package/dist/two-d/ui/MarkupText.js +122 -0
- package/dist/two-d/ui/MarkupText.js.map +1 -0
- package/dist/two-d/ui/ScrollBox.d.ts +67 -0
- package/dist/two-d/ui/ScrollBox.d.ts.map +1 -0
- package/dist/two-d/ui/ScrollBox.js +127 -0
- package/dist/two-d/ui/ScrollBox.js.map +1 -0
- package/dist/two-d/ui/Skins.d.ts +59 -0
- package/dist/two-d/ui/Skins.d.ts.map +1 -0
- package/dist/two-d/ui/Skins.js +77 -0
- package/dist/two-d/ui/Skins.js.map +1 -0
- package/dist/two-d/ui/Slider.d.ts +91 -0
- package/dist/two-d/ui/Slider.d.ts.map +1 -0
- package/dist/two-d/ui/Slider.js +170 -0
- package/dist/two-d/ui/Slider.js.map +1 -0
- package/dist/two-d/ui/Spinner.d.ts +67 -0
- package/dist/two-d/ui/Spinner.d.ts.map +1 -0
- package/dist/two-d/ui/Spinner.js +137 -0
- package/dist/two-d/ui/Spinner.js.map +1 -0
- package/dist/two-d/ui/TabbedList.d.ts +118 -0
- package/dist/two-d/ui/TabbedList.d.ts.map +1 -0
- package/dist/two-d/ui/TabbedList.js +221 -0
- package/dist/two-d/ui/TabbedList.js.map +1 -0
- package/dist/two-d/ui/TextModel.d.ts +65 -0
- package/dist/two-d/ui/TextModel.d.ts.map +1 -0
- package/dist/two-d/ui/TextModel.js +126 -0
- package/dist/two-d/ui/TextModel.js.map +1 -0
- package/dist/two-d/ui/TreeView.d.ts +68 -0
- package/dist/two-d/ui/TreeView.d.ts.map +1 -0
- package/dist/two-d/ui/TreeView.js +133 -0
- package/dist/two-d/ui/TreeView.js.map +1 -0
- package/dist/two-d/ui/Window.d.ts +13 -0
- package/dist/two-d/ui/Window.d.ts.map +1 -1
- package/dist/two-d/ui/Window.js +23 -0
- package/dist/two-d/ui/Window.js.map +1 -1
- package/dist/two-d/ui/WindowStack.d.ts.map +1 -1
- package/dist/two-d/ui/WindowStack.js +2 -0
- package/dist/two-d/ui/WindowStack.js.map +1 -1
- package/dist/two-d/ui/index.d.ts +29 -3
- package/dist/two-d/ui/index.d.ts.map +1 -1
- package/dist/two-d/ui/index.js +15 -2
- package/dist/two-d/ui/index.js.map +1 -1
- package/dist/two-d/ui/markup.d.ts +181 -0
- package/dist/two-d/ui/markup.d.ts.map +1 -0
- package/dist/two-d/ui/markup.js +370 -0
- package/dist/two-d/ui/markup.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/world/SideTurns.d.ts +115 -0
- package/dist/world/SideTurns.d.ts.map +1 -0
- package/dist/world/SideTurns.js +138 -0
- package/dist/world/SideTurns.js.map +1 -0
- package/dist/world/index.d.ts +2 -0
- package/dist/world/index.d.ts.map +1 -1
- package/dist/world/index.js +1 -0
- package/dist/world/index.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Container } from 'pixi.js';
|
|
2
|
+
import type { Texture2D } from '../render/Types2D.ts';
|
|
3
|
+
import { type MarkupAlign, type MarkupDirection } from './markup.ts';
|
|
4
|
+
export interface MarkupTextOptions {
|
|
5
|
+
text?: string;
|
|
6
|
+
/** wrap width in pixels; omit for a single unwrapped line */
|
|
7
|
+
maxWidth?: number;
|
|
8
|
+
/** distance between baselines; defaults to the theme's size times line height */
|
|
9
|
+
lineHeight?: number;
|
|
10
|
+
align?: MarkupAlign;
|
|
11
|
+
/** flow direction; defaults to the theme's `direction` */
|
|
12
|
+
direction?: MarkupDirection;
|
|
13
|
+
/** text texture resolution; omit for the renderer default */
|
|
14
|
+
resolution?: number;
|
|
15
|
+
/** how an `<img>` path becomes a texture; defaults to the asset resolver with a `Texture.EMPTY` fallback */
|
|
16
|
+
resolveImage?: (path: string) => Texture2D;
|
|
17
|
+
/** what a `$name` in the text becomes, the same contract `parseMarkup` takes */
|
|
18
|
+
variables?: Readonly<Record<string, string>>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The canvas backend for inline markup, and the counterpart to `RichLabel`'s HTML text: the same
|
|
22
|
+
* `MarkupSpan` stream, laid out once by `layoutMarkupLines` and `positionMarkupLines`, drawn here
|
|
23
|
+
* as one `Text2D` per styled run (colour, size, emphasis) and one `Sprite2D` per `<img>` span,
|
|
24
|
+
* resolved through the asset resolver. That split is the point - Pixi's `HTMLText` (which
|
|
25
|
+
* `RichLabel` builds on) renders emphasis but has no inline-image primitive, so an image would
|
|
26
|
+
* otherwise be dropped or a caller would have to position it itself at a `layoutMarkupLines`
|
|
27
|
+
* offset by hand. This class is the component that does that wiring.
|
|
28
|
+
*
|
|
29
|
+
* Costs more than a `Label` (one drawable per run), so it is for descriptions, dialogue lines
|
|
30
|
+
* and help bodies, not per-frame numbers - the same guidance `RichLabel` already carries.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { MarkupText } from '@datamoc/mw_games/two-d/ui';
|
|
35
|
+
*
|
|
36
|
+
* const description = new MarkupText({ text: 'Pay <b>10</b> gold<img>coin.png</img>', maxWidth: 240 });
|
|
37
|
+
* description.setText('Pay <b>15</b> gold<img>coin.png</img>');
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class MarkupText extends Container {
|
|
41
|
+
private readonly opts;
|
|
42
|
+
private readonly themeListener;
|
|
43
|
+
constructor(options?: MarkupTextOptions);
|
|
44
|
+
/** replaces the markup source and redraws, so a description can be updated in place */
|
|
45
|
+
setText(value: string): void;
|
|
46
|
+
/** re-parses, re-lays-out and re-draws; a theme change must re-measure against the new font */
|
|
47
|
+
private rebuild;
|
|
48
|
+
private measurePiece;
|
|
49
|
+
private textFor;
|
|
50
|
+
private spriteFor;
|
|
51
|
+
destroy(options?: Parameters<Container['destroy']>[0]): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=MarkupText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkupText.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/MarkupText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAW,MAAM,SAAS,CAAC;AAE7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAIN,KAAK,WAAW,EAChB,KAAK,eAAe,EAGpB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,iBAAiB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4GAA4G;IAC5G,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC;IAC3C,gFAAgF;IAChF,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAE/D,YAAY,OAAO,GAAE,iBAAsB,EAK1C;IAED,uFAAuF;IACvF,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG3B;IAED,+FAA+F;IAC/F,OAAO,CAAC,OAAO;IAgCf,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,SAAS;IASR,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAGpE;CACD"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { Container, Texture } from 'pixi.js';
|
|
2
|
+
import { Sprite2D, Text2D } from '../render/Shape2D.js';
|
|
3
|
+
import { texture } from '../../assets/loader.js';
|
|
4
|
+
import { layoutMarkupLines, parseMarkup, positionMarkupLines, } from './markup.js';
|
|
5
|
+
import { theme, themeChanged } from './theme.js';
|
|
6
|
+
/**
|
|
7
|
+
* The canvas backend for inline markup, and the counterpart to `RichLabel`'s HTML text: the same
|
|
8
|
+
* `MarkupSpan` stream, laid out once by `layoutMarkupLines` and `positionMarkupLines`, drawn here
|
|
9
|
+
* as one `Text2D` per styled run (colour, size, emphasis) and one `Sprite2D` per `<img>` span,
|
|
10
|
+
* resolved through the asset resolver. That split is the point - Pixi's `HTMLText` (which
|
|
11
|
+
* `RichLabel` builds on) renders emphasis but has no inline-image primitive, so an image would
|
|
12
|
+
* otherwise be dropped or a caller would have to position it itself at a `layoutMarkupLines`
|
|
13
|
+
* offset by hand. This class is the component that does that wiring.
|
|
14
|
+
*
|
|
15
|
+
* Costs more than a `Label` (one drawable per run), so it is for descriptions, dialogue lines
|
|
16
|
+
* and help bodies, not per-frame numbers - the same guidance `RichLabel` already carries.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* import { MarkupText } from '@datamoc/mw_games/two-d/ui';
|
|
21
|
+
*
|
|
22
|
+
* const description = new MarkupText({ text: 'Pay <b>10</b> gold<img>coin.png</img>', maxWidth: 240 });
|
|
23
|
+
* description.setText('Pay <b>15</b> gold<img>coin.png</img>');
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class MarkupText extends Container {
|
|
27
|
+
constructor(options = {}) {
|
|
28
|
+
super();
|
|
29
|
+
this.themeListener = (t) => this.rebuild(t);
|
|
30
|
+
this.opts = options;
|
|
31
|
+
this.rebuild(theme());
|
|
32
|
+
themeChanged.add(this.themeListener);
|
|
33
|
+
}
|
|
34
|
+
/** replaces the markup source and redraws, so a description can be updated in place */
|
|
35
|
+
setText(value) {
|
|
36
|
+
this.opts.text = value;
|
|
37
|
+
this.rebuild(theme());
|
|
38
|
+
}
|
|
39
|
+
/** re-parses, re-lays-out and re-draws; a theme change must re-measure against the new font */
|
|
40
|
+
rebuild(t) {
|
|
41
|
+
for (const child of this.removeChildren())
|
|
42
|
+
child.destroy();
|
|
43
|
+
const lineHeight = this.opts.lineHeight ?? t.font.size * t.font.lineHeight;
|
|
44
|
+
const wrapWidth = this.opts.maxWidth ?? Number.POSITIVE_INFINITY;
|
|
45
|
+
const alignWidth = this.opts.maxWidth ?? 0;
|
|
46
|
+
const direction = this.opts.direction ?? t.direction;
|
|
47
|
+
const resolveImage = this.opts.resolveImage ?? ((path) => texture(path, Texture.EMPTY));
|
|
48
|
+
const context = canvasContext();
|
|
49
|
+
const measure = (piece) => this.measurePiece(piece, t, lineHeight, resolveImage, context);
|
|
50
|
+
const spans = parseMarkup(this.opts.text ?? '', { variables: this.opts.variables });
|
|
51
|
+
const lines = layoutMarkupLines(spans, measure, wrapWidth);
|
|
52
|
+
const runs = positionMarkupLines(lines, {
|
|
53
|
+
measure,
|
|
54
|
+
maxWidth: alignWidth,
|
|
55
|
+
lineHeight,
|
|
56
|
+
direction,
|
|
57
|
+
align: this.opts.align ?? (this.opts.maxWidth === undefined ? 'left' : undefined),
|
|
58
|
+
});
|
|
59
|
+
for (const run of runs) {
|
|
60
|
+
const child = run.span.image !== undefined
|
|
61
|
+
? this.spriteFor(run.span.image, lineHeight, resolveImage)
|
|
62
|
+
: this.textFor(run.span, t, lineHeight);
|
|
63
|
+
child.x = run.x;
|
|
64
|
+
child.y = run.y;
|
|
65
|
+
this.addChild(child);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
measurePiece(piece, t, lineHeight, resolveImage, context) {
|
|
69
|
+
if (piece.image !== undefined)
|
|
70
|
+
return imageDisplaySize(resolveImage(piece.image), lineHeight).width;
|
|
71
|
+
if (!context)
|
|
72
|
+
return piece.text.length * (piece.size ?? t.font.size);
|
|
73
|
+
context.font = fontString(piece, t.font.family, t.font.size);
|
|
74
|
+
return context.measureText(piece.text).width;
|
|
75
|
+
}
|
|
76
|
+
textFor(span, t, lineHeight) {
|
|
77
|
+
return new Text2D({
|
|
78
|
+
text: span.text,
|
|
79
|
+
resolution: this.opts.resolution,
|
|
80
|
+
style: {
|
|
81
|
+
fontFamily: t.font.family,
|
|
82
|
+
fontSize: span.size ?? t.font.size,
|
|
83
|
+
fontWeight: span.bold ? 'bold' : 'normal',
|
|
84
|
+
fontStyle: span.italic ? 'italic' : 'normal',
|
|
85
|
+
fill: span.color ?? t.color.text,
|
|
86
|
+
lineHeight,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
spriteFor(path, lineHeight, resolveImage) {
|
|
91
|
+
const tex = resolveImage(path);
|
|
92
|
+
const size = imageDisplaySize(tex, lineHeight);
|
|
93
|
+
const sprite = new Sprite2D(tex);
|
|
94
|
+
sprite.width = size.width;
|
|
95
|
+
sprite.height = size.height;
|
|
96
|
+
return sprite;
|
|
97
|
+
}
|
|
98
|
+
destroy(options) {
|
|
99
|
+
themeChanged.remove(this.themeListener);
|
|
100
|
+
super.destroy(options);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** a shared canvas 2D context, the same way Pixi's own `Text` measurement works under the hood */
|
|
104
|
+
let measureContext = null;
|
|
105
|
+
function canvasContext() {
|
|
106
|
+
if (typeof document === 'undefined')
|
|
107
|
+
return null;
|
|
108
|
+
measureContext ??= document.createElement('canvas').getContext('2d');
|
|
109
|
+
return measureContext;
|
|
110
|
+
}
|
|
111
|
+
function fontString(piece, family, fallbackSize) {
|
|
112
|
+
const style = piece.italic ? 'italic ' : '';
|
|
113
|
+
const weight = piece.bold ? 'bold ' : '';
|
|
114
|
+
return `${style}${weight}${piece.size ?? fallbackSize}px ${family}`;
|
|
115
|
+
}
|
|
116
|
+
/** an image run's drawn size: the line's own height, with the texture's aspect ratio kept */
|
|
117
|
+
function imageDisplaySize(tex, lineHeight) {
|
|
118
|
+
const width = tex.width > 0 ? tex.width : lineHeight;
|
|
119
|
+
const height = tex.height > 0 ? tex.height : lineHeight;
|
|
120
|
+
return { width: width * (lineHeight / height), height: lineHeight };
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=MarkupText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkupText.js","sourceRoot":"","sources":["../../../src/two-d/ui/MarkupText.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EACN,iBAAiB,EACjB,WAAW,EACX,mBAAmB,GAKnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAc,MAAM,YAAY,CAAC;AAmB7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,UAAW,SAAQ,SAAS;IAIxC,YAAY,OAAO,GAAsB,EAAE;QAC1C,KAAK,EAAE,CAAC;QAHQ,kBAAa,GAAG,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAI9D,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACpB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QACtB,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC;IAED,uFAAuF;IACvF,OAAO,CAAC,KAAa;QACpB,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,+FAA+F;IACvF,OAAO,CAAC,CAAQ;QACvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc,EAAE;YAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAE3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,iBAAiB,CAAC;QACjE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;QACrD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACxF,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAChC,MAAM,OAAO,GAAkB,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QAEzG,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QACpF,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,mBAAmB,CAAC,KAAK,EAAE;YACvC,OAAO;YACP,QAAQ,EAAE,UAAU;YACpB,UAAU;YACV,SAAS;YACT,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;SACjF,CAAC,CAAC;QAEH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,KAAK,GACV,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS;gBAC3B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,YAAY,CAAC;gBAC1D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,UAAU,CAAC,CAAC;YAC1C,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAChB,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAChB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACF,CAAC;IAEO,YAAY,CACnB,KAAsE,EACtE,CAAQ,EACR,UAAkB,EAClB,YAAyC,EACzC,OAAwC;QAExC,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,gBAAgB,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC;QACpG,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAC9C,CAAC;IAEO,OAAO,CAAC,IAAgB,EAAE,CAAQ,EAAE,UAAkB;QAC7D,OAAO,IAAI,MAAM,CAAC;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU;YAChC,KAAK,EAAE;gBACN,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM;gBACzB,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI;gBAClC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;gBACzC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAC5C,IAAI,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI;gBAChC,UAAU;aACV;SACD,CAAC,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,IAAY,EAAE,UAAkB,EAAE,YAAsC;QACzF,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5B,OAAO,MAAM,CAAC;IACf,CAAC;IAEQ,OAAO,CAAC,OAA6C;QAC7D,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;CACD;AAED,kGAAkG;AAClG,IAAI,cAAc,GAAoC,IAAI,CAAC;AAE3D,SAAS,aAAa;IACrB,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IACjD,cAAc,KAAK,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,cAAc,CAAC;AACvB,CAAC;AAED,SAAS,UAAU,CAAC,KAAmD,EAAE,MAAc,EAAE,YAAoB;IAC5G,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,OAAO,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,IAAI,YAAY,MAAM,MAAM,EAAE,CAAC;AACrE,CAAC;AAED,6FAA6F;AAC7F,SAAS,gBAAgB,CAAC,GAAc,EAAE,UAAkB;IAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IACrD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;IACxD,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Container } from 'pixi.js';
|
|
2
|
+
import { Signal } from '../../core/Signal.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Clamps a scroll offset so the content never pulls away from the top or leaves a gap past the
|
|
5
|
+
* bottom. When the content is shorter than the viewport the only offset is 0.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { scrollOffset } from '@datamoc/mw_games/two-d/ui';
|
|
10
|
+
*
|
|
11
|
+
* console.log(scrollOffset(-5, 500, 200)); // 0
|
|
12
|
+
* console.log(scrollOffset(900, 500, 200)); // 300
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function scrollOffset(offset: number, contentSize: number, viewportSize: number): number;
|
|
16
|
+
export interface ScrollBoxOptions {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
/** how tall the content is; set it again with `setContentHeight` as the content changes */
|
|
20
|
+
contentHeight?: number;
|
|
21
|
+
offset?: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A clipped viewport with a scrollbar: put rows in `content` and they scroll inside the box,
|
|
25
|
+
* everything outside it hidden by a mask. The scrollbar is drawn from the theme; the wheel,
|
|
26
|
+
* `scrollBy` and `scrollIntoView` all run through `scrollOffset`, so they clamp the same way.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { ScrollBox } from '@datamoc/mw_games/two-d/ui';
|
|
31
|
+
*
|
|
32
|
+
* const box = new ScrollBox({ width: 200, height: 120, contentHeight: 400 });
|
|
33
|
+
* box.scrollBy(60);
|
|
34
|
+
* console.log(box.offset); // 60
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare class ScrollBox extends Container {
|
|
38
|
+
readonly onChange: Signal<number>;
|
|
39
|
+
/** add the rows to scroll here */
|
|
40
|
+
readonly content: Container<import("pixi.js").ContainerChild>;
|
|
41
|
+
private maskShape;
|
|
42
|
+
private track;
|
|
43
|
+
private thumb;
|
|
44
|
+
private width_;
|
|
45
|
+
private height_;
|
|
46
|
+
private contentHeight_;
|
|
47
|
+
private offset_;
|
|
48
|
+
private readonly themeListener;
|
|
49
|
+
constructor(options: ScrollBoxOptions);
|
|
50
|
+
get offset(): number;
|
|
51
|
+
get contentHeight(): number;
|
|
52
|
+
get viewportHeight(): number;
|
|
53
|
+
/** how far the content can scroll; 0 when it all fits */
|
|
54
|
+
get maxOffset(): number;
|
|
55
|
+
get scrollable(): boolean;
|
|
56
|
+
setContentHeight(height: number): void;
|
|
57
|
+
resize(width: number, height: number): void;
|
|
58
|
+
scrollBy(delta: number): void;
|
|
59
|
+
scrollTo(offset: number): void;
|
|
60
|
+
/** scrolls just enough to bring a `height`-tall item at `top` fully into view */
|
|
61
|
+
scrollIntoView(top: number, height: number): void;
|
|
62
|
+
private setOffset;
|
|
63
|
+
private readonly handleWheel;
|
|
64
|
+
private draw;
|
|
65
|
+
destroy(options?: Parameters<Container['destroy']>[0]): void;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=ScrollBox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollBox.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/ScrollBox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAE9F;AAED,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAU,SAAQ,SAAS;IACvC,QAAQ,CAAC,QAAQ,iBAAwB;IAEzC,kCAAkC;IAClC,QAAQ,CAAC,OAAO,8CAAmB;IAEnC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,KAAK,CAAkB;IAE/B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IAEnD,YAAY,OAAO,EAAE,gBAAgB,EAoBpC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,yDAAyD;IACzD,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGrC;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI1C;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE5B;IAED,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE7B;IAED,iFAAiF;IACjF,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAGhD;IAED,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAE1B;IAEF,OAAO,CAAC,IAAI;IAmBH,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAGpE;CACD"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { Container, Graphics } from 'pixi.js';
|
|
2
|
+
import { Signal } from '../../core/Signal.js';
|
|
3
|
+
import { theme, themeChanged } from './theme.js';
|
|
4
|
+
/**
|
|
5
|
+
* Clamps a scroll offset so the content never pulls away from the top or leaves a gap past the
|
|
6
|
+
* bottom. When the content is shorter than the viewport the only offset is 0.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { scrollOffset } from '@datamoc/mw_games/two-d/ui';
|
|
11
|
+
*
|
|
12
|
+
* console.log(scrollOffset(-5, 500, 200)); // 0
|
|
13
|
+
* console.log(scrollOffset(900, 500, 200)); // 300
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function scrollOffset(offset, contentSize, viewportSize) {
|
|
17
|
+
return Math.max(0, Math.min(Math.max(0, contentSize - viewportSize), offset));
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A clipped viewport with a scrollbar: put rows in `content` and they scroll inside the box,
|
|
21
|
+
* everything outside it hidden by a mask. The scrollbar is drawn from the theme; the wheel,
|
|
22
|
+
* `scrollBy` and `scrollIntoView` all run through `scrollOffset`, so they clamp the same way.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { ScrollBox } from '@datamoc/mw_games/two-d/ui';
|
|
27
|
+
*
|
|
28
|
+
* const box = new ScrollBox({ width: 200, height: 120, contentHeight: 400 });
|
|
29
|
+
* box.scrollBy(60);
|
|
30
|
+
* console.log(box.offset); // 60
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export class ScrollBox extends Container {
|
|
34
|
+
constructor(options) {
|
|
35
|
+
super();
|
|
36
|
+
this.onChange = new Signal();
|
|
37
|
+
/** add the rows to scroll here */
|
|
38
|
+
this.content = new Container();
|
|
39
|
+
this.maskShape = new Graphics();
|
|
40
|
+
this.track = new Graphics();
|
|
41
|
+
this.thumb = new Graphics();
|
|
42
|
+
this.themeListener = () => this.draw();
|
|
43
|
+
this.handleWheel = (event) => {
|
|
44
|
+
this.scrollBy(event.deltaY);
|
|
45
|
+
};
|
|
46
|
+
this.width_ = options.width;
|
|
47
|
+
this.height_ = options.height;
|
|
48
|
+
this.contentHeight_ = Math.max(0, options.contentHeight ?? 0);
|
|
49
|
+
this.offset_ = scrollOffset(options.offset ?? 0, this.contentHeight_, this.height_);
|
|
50
|
+
this.addChild(this.content);
|
|
51
|
+
this.addChild(this.maskShape);
|
|
52
|
+
this.addChild(this.track);
|
|
53
|
+
this.addChild(this.thumb);
|
|
54
|
+
this.content.mask = this.maskShape;
|
|
55
|
+
this.eventMode = 'static';
|
|
56
|
+
this.on('wheel', this.handleWheel);
|
|
57
|
+
this.draw();
|
|
58
|
+
themeChanged.add(this.themeListener);
|
|
59
|
+
}
|
|
60
|
+
get offset() {
|
|
61
|
+
return this.offset_;
|
|
62
|
+
}
|
|
63
|
+
get contentHeight() {
|
|
64
|
+
return this.contentHeight_;
|
|
65
|
+
}
|
|
66
|
+
get viewportHeight() {
|
|
67
|
+
return this.height_;
|
|
68
|
+
}
|
|
69
|
+
/** how far the content can scroll; 0 when it all fits */
|
|
70
|
+
get maxOffset() {
|
|
71
|
+
return Math.max(0, this.contentHeight_ - this.height_);
|
|
72
|
+
}
|
|
73
|
+
get scrollable() {
|
|
74
|
+
return this.maxOffset > 0;
|
|
75
|
+
}
|
|
76
|
+
setContentHeight(height) {
|
|
77
|
+
this.contentHeight_ = Math.max(0, height);
|
|
78
|
+
this.setOffset(scrollOffset(this.offset_, this.contentHeight_, this.height_));
|
|
79
|
+
}
|
|
80
|
+
resize(width, height) {
|
|
81
|
+
this.width_ = width;
|
|
82
|
+
this.height_ = height;
|
|
83
|
+
this.setOffset(scrollOffset(this.offset_, this.contentHeight_, this.height_));
|
|
84
|
+
}
|
|
85
|
+
scrollBy(delta) {
|
|
86
|
+
this.setOffset(scrollOffset(this.offset_ + delta, this.contentHeight_, this.height_));
|
|
87
|
+
}
|
|
88
|
+
scrollTo(offset) {
|
|
89
|
+
this.setOffset(scrollOffset(offset, this.contentHeight_, this.height_));
|
|
90
|
+
}
|
|
91
|
+
/** scrolls just enough to bring a `height`-tall item at `top` fully into view */
|
|
92
|
+
scrollIntoView(top, height) {
|
|
93
|
+
if (top < this.offset_)
|
|
94
|
+
this.scrollTo(top);
|
|
95
|
+
else if (top + height > this.offset_ + this.height_)
|
|
96
|
+
this.scrollTo(top + height - this.height_);
|
|
97
|
+
}
|
|
98
|
+
setOffset(offset) {
|
|
99
|
+
if (offset === this.offset_) {
|
|
100
|
+
this.draw();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.offset_ = offset;
|
|
104
|
+
this.draw();
|
|
105
|
+
this.onChange.dispatch(offset);
|
|
106
|
+
}
|
|
107
|
+
draw() {
|
|
108
|
+
const t = theme();
|
|
109
|
+
this.content.y = -this.offset_;
|
|
110
|
+
this.maskShape.clear().rect(0, 0, this.width_, this.height_).fill({ color: 0xffffff });
|
|
111
|
+
this.track.clear();
|
|
112
|
+
this.thumb.clear();
|
|
113
|
+
if (!this.scrollable)
|
|
114
|
+
return;
|
|
115
|
+
const barWidth = 6;
|
|
116
|
+
const x = this.width_ - barWidth;
|
|
117
|
+
this.track.roundRect(x, 0, barWidth, this.height_, barWidth / 2).fill({ color: t.color.panelFill });
|
|
118
|
+
const thumbHeight = Math.max(barWidth, (this.height_ / this.contentHeight_) * this.height_);
|
|
119
|
+
const thumbY = (this.offset_ / this.maxOffset) * (this.height_ - thumbHeight);
|
|
120
|
+
this.thumb.roundRect(x, thumbY, barWidth, thumbHeight, barWidth / 2).fill({ color: t.color.textHighlight });
|
|
121
|
+
}
|
|
122
|
+
destroy(options) {
|
|
123
|
+
themeChanged.remove(this.themeListener);
|
|
124
|
+
super.destroy(options);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=ScrollBox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScrollBox.js","sourceRoot":"","sources":["../../../src/two-d/ui/ScrollBox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Texture2D } from '../render/Types2D.ts';
|
|
2
|
+
export type WidgetState = 'idle' | 'hover' | 'pressed' | 'disabled' | 'selected' | 'focused';
|
|
3
|
+
/**
|
|
4
|
+
* The visual a widget draws itself with in one state. Every field is optional and each falls back
|
|
5
|
+
* independently as `Skins.resolve` walks its chain, so a skin can override just one channel of a
|
|
6
|
+
* widget's look - its pressed background, say - and keep the rest.
|
|
7
|
+
*/
|
|
8
|
+
export interface Skin {
|
|
9
|
+
background?: number;
|
|
10
|
+
border?: number;
|
|
11
|
+
borderWidth?: number;
|
|
12
|
+
text?: number;
|
|
13
|
+
padding?: number;
|
|
14
|
+
texture?: Texture2D;
|
|
15
|
+
/** how many pixels of `texture` are its fixed border */
|
|
16
|
+
borderInset?: number;
|
|
17
|
+
}
|
|
18
|
+
export type SkinStates = Partial<Record<WidgetState, Skin>>;
|
|
19
|
+
/** A widget's entry: a bare skin, meaning its idle look, or one look per state. */
|
|
20
|
+
export type SkinData = Skin | SkinStates;
|
|
21
|
+
/**
|
|
22
|
+
* Per-widget and per-state skins, looked up by name - the data-driven half of what GUI2 puts in
|
|
23
|
+
* `data/gui/*.cfg`, and the thing the one global `Theme` has no room for.
|
|
24
|
+
*
|
|
25
|
+
* A lookup walks a fixed chain so a caller never gets `undefined`: the widget's own state, its
|
|
26
|
+
* idle look, the wildcard widget's state, the wildcard's idle look, then an empty skin. That is
|
|
27
|
+
* what lets a game define a shared `*` skin once and override only the two widgets it cares about,
|
|
28
|
+
* and what makes a state a widget never defined fall back rather than disappear.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { Skins } from '@datamoc/mw_games/two-d/ui';
|
|
33
|
+
*
|
|
34
|
+
* const skins = new Skins();
|
|
35
|
+
* skins.define('*', 'idle', { background: 0x101018, text: 0xe8e8f0 });
|
|
36
|
+
* skins.define('button', 'pressed', { background: 0xffe680, text: 0x101018 });
|
|
37
|
+
*
|
|
38
|
+
* console.log(skins.resolve('button', 'pressed').text); // 0x101018, the override
|
|
39
|
+
* console.log(skins.resolve('label', 'idle').background); // 0x101018, the wildcard
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class Skins {
|
|
43
|
+
private readonly map;
|
|
44
|
+
/** the wildcard widget every lookup falls back to */
|
|
45
|
+
static readonly ANY = "*";
|
|
46
|
+
define(widget: string, state: WidgetState, skin: Skin): void;
|
|
47
|
+
has(widget: string): boolean;
|
|
48
|
+
widgets(): string[];
|
|
49
|
+
/** the skin a widget draws in a state, following the fallback chain to an empty skin */
|
|
50
|
+
resolve(widget: string, state?: WidgetState): Skin;
|
|
51
|
+
/** every state a widget has an entry for, not counting the wildcard fallback */
|
|
52
|
+
statesOf(widget: string): WidgetState[];
|
|
53
|
+
/**
|
|
54
|
+
* Builds a registry from plain data - the shape a config file would parse into. An entry with
|
|
55
|
+
* any state key is read as one look per state; anything else is that widget's idle look.
|
|
56
|
+
*/
|
|
57
|
+
static from(data: Readonly<Record<string, SkinData>>): Skins;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=Skins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skins.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/Skins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7F;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5D,mFAAmF;AACnF,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,UAAU,CAAC;AAIzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,KAAK;IACjB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAiC;IAErD,qDAAqD;IACrD,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO;IAE1B,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,CAI3D;IAED,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE3B;IAED,OAAO,IAAI,MAAM,EAAE,CAElB;IAED,wFAAwF;IACxF,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,WAAoB,GAAG,IAAI,CAQzD;IAED,gFAAgF;IAChF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAGtC;IAED;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GAAG,KAAK,CAa3D;CACD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const STATES = ['idle', 'hover', 'pressed', 'disabled', 'selected', 'focused'];
|
|
2
|
+
/**
|
|
3
|
+
* Per-widget and per-state skins, looked up by name - the data-driven half of what GUI2 puts in
|
|
4
|
+
* `data/gui/*.cfg`, and the thing the one global `Theme` has no room for.
|
|
5
|
+
*
|
|
6
|
+
* A lookup walks a fixed chain so a caller never gets `undefined`: the widget's own state, its
|
|
7
|
+
* idle look, the wildcard widget's state, the wildcard's idle look, then an empty skin. That is
|
|
8
|
+
* what lets a game define a shared `*` skin once and override only the two widgets it cares about,
|
|
9
|
+
* and what makes a state a widget never defined fall back rather than disappear.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { Skins } from '@datamoc/mw_games/two-d/ui';
|
|
14
|
+
*
|
|
15
|
+
* const skins = new Skins();
|
|
16
|
+
* skins.define('*', 'idle', { background: 0x101018, text: 0xe8e8f0 });
|
|
17
|
+
* skins.define('button', 'pressed', { background: 0xffe680, text: 0x101018 });
|
|
18
|
+
*
|
|
19
|
+
* console.log(skins.resolve('button', 'pressed').text); // 0x101018, the override
|
|
20
|
+
* console.log(skins.resolve('label', 'idle').background); // 0x101018, the wildcard
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class Skins {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.map = new Map();
|
|
26
|
+
}
|
|
27
|
+
/** the wildcard widget every lookup falls back to */
|
|
28
|
+
static { this.ANY = '*'; }
|
|
29
|
+
define(widget, state, skin) {
|
|
30
|
+
const states = this.map.get(widget) ?? {};
|
|
31
|
+
states[state] = { ...states[state], ...skin };
|
|
32
|
+
this.map.set(widget, states);
|
|
33
|
+
}
|
|
34
|
+
has(widget) {
|
|
35
|
+
return this.map.has(widget);
|
|
36
|
+
}
|
|
37
|
+
widgets() {
|
|
38
|
+
return [...this.map.keys()];
|
|
39
|
+
}
|
|
40
|
+
/** the skin a widget draws in a state, following the fallback chain to an empty skin */
|
|
41
|
+
resolve(widget, state = 'idle') {
|
|
42
|
+
return (this.map.get(widget)?.[state] ??
|
|
43
|
+
this.map.get(widget)?.idle ??
|
|
44
|
+
this.map.get(Skins.ANY)?.[state] ??
|
|
45
|
+
this.map.get(Skins.ANY)?.idle ??
|
|
46
|
+
{});
|
|
47
|
+
}
|
|
48
|
+
/** every state a widget has an entry for, not counting the wildcard fallback */
|
|
49
|
+
statesOf(widget) {
|
|
50
|
+
const states = this.map.get(widget);
|
|
51
|
+
return states ? STATES.filter((state) => states[state] !== undefined) : [];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Builds a registry from plain data - the shape a config file would parse into. An entry with
|
|
55
|
+
* any state key is read as one look per state; anything else is that widget's idle look.
|
|
56
|
+
*/
|
|
57
|
+
static from(data) {
|
|
58
|
+
const skins = new Skins();
|
|
59
|
+
for (const [widget, value] of Object.entries(data)) {
|
|
60
|
+
if (isStateMap(value)) {
|
|
61
|
+
for (const state of STATES) {
|
|
62
|
+
const skin = value[state];
|
|
63
|
+
if (skin)
|
|
64
|
+
skins.define(widget, state, skin);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
skins.define(widget, 'idle', value);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return skins;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function isStateMap(value) {
|
|
75
|
+
return STATES.some((state) => value[state] !== undefined);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=Skins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skins.js","sourceRoot":"","sources":["../../../src/two-d/ui/Skins.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,GAA2B,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAEvG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,KAAK;IAAlB;QACkB,QAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;IAsDtD,CAAC;IApDA,qDAAqD;aACrC,QAAG,GAAG,GAAG,AAAN,CAAO;IAE1B,MAAM,CAAC,MAAc,EAAE,KAAkB,EAAE,IAAU;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;QAC9C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,GAAG,CAAC,MAAc;QACjB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,wFAAwF;IACxF,OAAO,CAAC,MAAc,EAAE,KAAK,GAAgB,MAAM;QAClD,OAAO,CACN,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI;YAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC;YAChC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI;YAC7B,EAAE,CACF,CAAC;IACH,CAAC;IAED,gFAAgF;IAChF,QAAQ,CAAC,MAAc;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,IAAI,CAAC,IAAwC;QACnD,MAAM,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACpD,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;oBAC1B,IAAI,IAAI;wBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;gBAC7C,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YACrC,CAAC;QACF,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;CACD;AAED,SAAS,UAAU,CAAC,KAAe;IAClC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAE,KAAoB,CAAC,KAAK,CAAC,KAAK,SAAS,CAAC,CAAC;AAC3E,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Container } from 'pixi.js';
|
|
2
|
+
import { Signal } from '../../core/Signal.ts';
|
|
3
|
+
export interface SliderOptions {
|
|
4
|
+
width: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
min?: number;
|
|
7
|
+
max?: number;
|
|
8
|
+
/** the value grid; 0 or omitted is continuous */
|
|
9
|
+
step?: number;
|
|
10
|
+
value?: number;
|
|
11
|
+
/** the draggable knob's diameter; defaults to the track height */
|
|
12
|
+
knobSize?: number;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Where `value` sits in `[min, max]`, 0 to 1, clamped. A degenerate range reads 0 rather than
|
|
17
|
+
* dividing by zero.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { sliderFraction } from '@datamoc/mw_games/two-d/ui';
|
|
22
|
+
*
|
|
23
|
+
* console.log(sliderFraction(30, 0, 60)); // 0.5
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function sliderFraction(value: number, min?: number, max?: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* The value at a 0-to-1 position on the track, snapped to `step` and clamped to `[min, max]`.
|
|
29
|
+
* The snap is rounded to the step's own number of decimals, so a 0.1 step reads `0.3` rather
|
|
30
|
+
* than `0.30000000000000004`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { sliderValueAt } from '@datamoc/mw_games/two-d/ui';
|
|
35
|
+
*
|
|
36
|
+
* console.log(sliderValueAt(0.5, 0, 10, 1)); // 5
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function sliderValueAt(fraction: number, min?: number, max?: number, step?: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* A draggable knob on a track, for a volume, difficulty or zoom setting.
|
|
42
|
+
*
|
|
43
|
+
* The track is drawn from the theme and a partial fill shows where the knob is; the value is
|
|
44
|
+
* always a number in `[min, max]`, and `sliderValueAt` is the arithmetic that turns a click or
|
|
45
|
+
* drag into one, exported so a game routing input itself gets the same snapping.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { Slider } from '@datamoc/mw_games/two-d/ui';
|
|
50
|
+
*
|
|
51
|
+
* const volume = new Slider({ width: 200, min: 0, max: 100, step: 5, value: 40 });
|
|
52
|
+
* volume.onChange.add((value) => console.log('volume', value));
|
|
53
|
+
* volume.setValue(75);
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare class Slider extends Container {
|
|
57
|
+
readonly onChange: Signal<number>;
|
|
58
|
+
private track;
|
|
59
|
+
private fill;
|
|
60
|
+
private knob;
|
|
61
|
+
private width_;
|
|
62
|
+
private height_;
|
|
63
|
+
private knobSize;
|
|
64
|
+
private min;
|
|
65
|
+
private max;
|
|
66
|
+
private step;
|
|
67
|
+
private value_;
|
|
68
|
+
private disabled_;
|
|
69
|
+
private dragging;
|
|
70
|
+
private readonly themeListener;
|
|
71
|
+
constructor(options: SliderOptions);
|
|
72
|
+
/** the current value, in `[min, max]` */
|
|
73
|
+
get value(): number;
|
|
74
|
+
/** where the knob sits, 0 to 1 */
|
|
75
|
+
get fraction(): number;
|
|
76
|
+
get disabled(): boolean;
|
|
77
|
+
setDisabled(disabled: boolean): void;
|
|
78
|
+
setValue(value: number): void;
|
|
79
|
+
/** moves the knob to a 0-to-1 position, the arithmetic a track click uses */
|
|
80
|
+
setFraction(fraction: number): void;
|
|
81
|
+
resize(width: number, height: number): void;
|
|
82
|
+
private get trackLength();
|
|
83
|
+
private snap;
|
|
84
|
+
private fractionAt;
|
|
85
|
+
private readonly handleDown;
|
|
86
|
+
private readonly handleMove;
|
|
87
|
+
private readonly handleUp;
|
|
88
|
+
private draw;
|
|
89
|
+
destroy(options?: Parameters<Container['destroy']>[0]): void;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=Slider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/Slider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAI,EAAE,GAAG,SAAI,GAAG,MAAM,CAGtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAI,EAAE,GAAG,SAAI,EAAE,IAAI,SAAI,GAAG,MAAM,CAOlF;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,MAAO,SAAQ,SAAS;IACpC,QAAQ,CAAC,QAAQ,iBAAwB;IAEzC,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,IAAI,CAAkB;IAC9B,OAAO,CAAC,IAAI,CAAkB;IAE9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAU;IAE3B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IAEnD,YAAY,OAAO,EAAE,aAAa,EAyBjC;IAED,yCAAyC;IACzC,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,kCAAkC;IAClC,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAInC;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAS5B;IAED,6EAA6E;IAC7E,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAElC;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAI1C;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAIzB;IAEF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAGzB;IAEF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAEvB;IAEF,OAAO,CAAC,IAAI;IAyBH,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAGpE;CACD"}
|