@datamoc/mw_games 0.20.0 → 0.23.0

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.
Files changed (151) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/dist/audio/Channels.d.ts +19 -0
  3. package/dist/audio/Channels.d.ts.map +1 -1
  4. package/dist/audio/Channels.js +33 -4
  5. package/dist/audio/Channels.js.map +1 -1
  6. package/dist/audio/LoopTags.d.ts +37 -0
  7. package/dist/audio/LoopTags.d.ts.map +1 -0
  8. package/dist/audio/LoopTags.js +116 -0
  9. package/dist/audio/LoopTags.js.map +1 -0
  10. package/dist/audio/Midi.d.ts +29 -0
  11. package/dist/audio/Midi.d.ts.map +1 -1
  12. package/dist/audio/Midi.js +30 -1
  13. package/dist/audio/Midi.js.map +1 -1
  14. package/dist/audio/MidiRender.d.ts +3 -2
  15. package/dist/audio/MidiRender.d.ts.map +1 -1
  16. package/dist/audio/MidiRender.js +2 -2
  17. package/dist/audio/MidiRender.js.map +1 -1
  18. package/dist/audio/humanize/Groove.d.ts +80 -0
  19. package/dist/audio/humanize/Groove.d.ts.map +1 -0
  20. package/dist/audio/humanize/Groove.js +102 -0
  21. package/dist/audio/humanize/Groove.js.map +1 -0
  22. package/dist/audio/humanize/GrooveConverter.d.ts +49 -0
  23. package/dist/audio/humanize/GrooveConverter.d.ts.map +1 -0
  24. package/dist/audio/humanize/GrooveConverter.js +344 -0
  25. package/dist/audio/humanize/GrooveConverter.js.map +1 -0
  26. package/dist/audio/humanize/GrooveExtractor.d.ts +49 -0
  27. package/dist/audio/humanize/GrooveExtractor.d.ts.map +1 -0
  28. package/dist/audio/humanize/GrooveExtractor.js +179 -0
  29. package/dist/audio/humanize/GrooveExtractor.js.map +1 -0
  30. package/dist/audio/humanize/GrooveHumanizer.d.ts +34 -0
  31. package/dist/audio/humanize/GrooveHumanizer.d.ts.map +1 -0
  32. package/dist/audio/humanize/GrooveHumanizer.js +37 -0
  33. package/dist/audio/humanize/GrooveHumanizer.js.map +1 -0
  34. package/dist/audio/humanize/Humanize.d.ts +54 -0
  35. package/dist/audio/humanize/Humanize.d.ts.map +1 -0
  36. package/dist/audio/humanize/Humanize.js +239 -0
  37. package/dist/audio/humanize/Humanize.js.map +1 -0
  38. package/dist/audio/humanize/HumanizerFactory.d.ts +68 -0
  39. package/dist/audio/humanize/HumanizerFactory.d.ts.map +1 -0
  40. package/dist/audio/humanize/HumanizerFactory.js +84 -0
  41. package/dist/audio/humanize/HumanizerFactory.js.map +1 -0
  42. package/dist/audio/humanize/LiteHumanizer.d.ts +30 -0
  43. package/dist/audio/humanize/LiteHumanizer.d.ts.map +1 -0
  44. package/dist/audio/humanize/LiteHumanizer.js +35 -0
  45. package/dist/audio/humanize/LiteHumanizer.js.map +1 -0
  46. package/dist/audio/humanize/Onsets.d.ts +26 -0
  47. package/dist/audio/humanize/Onsets.d.ts.map +1 -0
  48. package/dist/audio/humanize/Onsets.js +164 -0
  49. package/dist/audio/humanize/Onsets.js.map +1 -0
  50. package/dist/audio/index.d.ts +14 -1
  51. package/dist/audio/index.d.ts.map +1 -1
  52. package/dist/audio/index.js +7 -0
  53. package/dist/audio/index.js.map +1 -1
  54. package/dist/board/bitboard.d.ts +132 -0
  55. package/dist/board/bitboard.d.ts.map +1 -0
  56. package/dist/board/bitboard.js +495 -0
  57. package/dist/board/bitboard.js.map +1 -0
  58. package/dist/board/chess.d.ts +16 -0
  59. package/dist/board/chess.d.ts.map +1 -1
  60. package/dist/board/chess.js +43 -0
  61. package/dist/board/chess.js.map +1 -1
  62. package/dist/board/index.d.ts +9 -1
  63. package/dist/board/index.d.ts.map +1 -1
  64. package/dist/board/index.js +5 -1
  65. package/dist/board/index.js.map +1 -1
  66. package/dist/board/openings.d.ts +58 -0
  67. package/dist/board/openings.d.ts.map +1 -0
  68. package/dist/board/openings.js +45 -0
  69. package/dist/board/openings.js.map +1 -0
  70. package/dist/board/tablebase.d.ts +118 -0
  71. package/dist/board/tablebase.d.ts.map +1 -0
  72. package/dist/board/tablebase.js +414 -0
  73. package/dist/board/tablebase.js.map +1 -0
  74. package/dist/board/tourney.d.ts +90 -0
  75. package/dist/board/tourney.d.ts.map +1 -0
  76. package/dist/board/tourney.js +1013 -0
  77. package/dist/board/tourney.js.map +1 -0
  78. package/dist/core/JavaRandom.d.ts +55 -0
  79. package/dist/core/JavaRandom.d.ts.map +1 -0
  80. package/dist/core/JavaRandom.js +81 -0
  81. package/dist/core/JavaRandom.js.map +1 -0
  82. package/dist/core/index.d.ts +2 -0
  83. package/dist/core/index.d.ts.map +1 -1
  84. package/dist/core/index.js +1 -0
  85. package/dist/core/index.js.map +1 -1
  86. package/dist/mw_games.global.js +123 -116
  87. package/dist/rpg/EventRunner.d.ts +7 -0
  88. package/dist/rpg/EventRunner.d.ts.map +1 -1
  89. package/dist/rpg/EventRunner.js +6 -0
  90. package/dist/rpg/EventRunner.js.map +1 -1
  91. package/dist/rpg/MoveRoute.d.ts +35 -4
  92. package/dist/rpg/MoveRoute.d.ts.map +1 -1
  93. package/dist/rpg/MoveRoute.js +40 -11
  94. package/dist/rpg/MoveRoute.js.map +1 -1
  95. package/dist/two-d/render/FogLayer.d.ts +68 -0
  96. package/dist/two-d/render/FogLayer.d.ts.map +1 -0
  97. package/dist/two-d/render/FogLayer.js +83 -0
  98. package/dist/two-d/render/FogLayer.js.map +1 -0
  99. package/dist/two-d/render/LiquidLayer.d.ts +62 -0
  100. package/dist/two-d/render/LiquidLayer.d.ts.map +1 -0
  101. package/dist/two-d/render/LiquidLayer.js +102 -0
  102. package/dist/two-d/render/LiquidLayer.js.map +1 -0
  103. package/dist/two-d/render/RpgmAutotile.d.ts +42 -0
  104. package/dist/two-d/render/RpgmAutotile.d.ts.map +1 -1
  105. package/dist/two-d/render/RpgmAutotile.js +71 -4
  106. package/dist/two-d/render/RpgmAutotile.js.map +1 -1
  107. package/dist/two-d/render/TileMap.d.ts +50 -2
  108. package/dist/two-d/render/TileMap.d.ts.map +1 -1
  109. package/dist/two-d/render/TileMap.js +120 -2
  110. package/dist/two-d/render/TileMap.js.map +1 -1
  111. package/dist/two-d/render/index.d.ts +7 -3
  112. package/dist/two-d/render/index.d.ts.map +1 -1
  113. package/dist/two-d/render/index.js +3 -1
  114. package/dist/two-d/render/index.js.map +1 -1
  115. package/dist/two-d/ui/Label.d.ts.map +1 -1
  116. package/dist/two-d/ui/Label.js +11 -2
  117. package/dist/two-d/ui/Label.js.map +1 -1
  118. package/dist/two-d/ui/ListView.d.ts +24 -0
  119. package/dist/two-d/ui/ListView.d.ts.map +1 -1
  120. package/dist/two-d/ui/ListView.js +97 -4
  121. package/dist/two-d/ui/ListView.js.map +1 -1
  122. package/dist/two-d/ui/MessageLog.d.ts +62 -0
  123. package/dist/two-d/ui/MessageLog.d.ts.map +1 -0
  124. package/dist/two-d/ui/MessageLog.js +114 -0
  125. package/dist/two-d/ui/MessageLog.js.map +1 -0
  126. package/dist/two-d/ui/RadioGroup.d.ts +68 -0
  127. package/dist/two-d/ui/RadioGroup.d.ts.map +1 -0
  128. package/dist/two-d/ui/RadioGroup.js +177 -0
  129. package/dist/two-d/ui/RadioGroup.js.map +1 -0
  130. package/dist/two-d/ui/TextModel.d.ts +26 -1
  131. package/dist/two-d/ui/TextModel.d.ts.map +1 -1
  132. package/dist/two-d/ui/TextModel.js +56 -7
  133. package/dist/two-d/ui/TextModel.js.map +1 -1
  134. package/dist/two-d/ui/TextSharpness.d.ts +33 -0
  135. package/dist/two-d/ui/TextSharpness.d.ts.map +1 -0
  136. package/dist/two-d/ui/TextSharpness.js +56 -0
  137. package/dist/two-d/ui/TextSharpness.js.map +1 -0
  138. package/dist/two-d/ui/index.d.ts +5 -0
  139. package/dist/two-d/ui/index.d.ts.map +1 -1
  140. package/dist/two-d/ui/index.js +3 -0
  141. package/dist/two-d/ui/index.js.map +1 -1
  142. package/dist/version.d.ts +1 -1
  143. package/dist/version.js +1 -1
  144. package/package.json +19 -7
  145. package/sbom.cdx.json +194 -32
  146. package/tools/build-tablebases.d.mts +22 -0
  147. package/tools/build-tablebases.mjs +549 -0
  148. package/tools/compile-openings.d.mts +20 -0
  149. package/tools/compile-openings.mjs +130 -0
  150. package/tools/play-uci.d.mts +26 -0
  151. package/tools/play-uci.mjs +194 -0
@@ -0,0 +1,62 @@
1
+ import { Container } from 'pixi.js';
2
+ /** how a message reads at a glance: routine, good news, bad news, a caution, or an emphasis */
3
+ export type MessageLevel = 'info' | 'positive' | 'negative' | 'warning' | 'highlight';
4
+ /**
5
+ * How many of the oldest entries to drop so the rest fit in `maxLines`. The budget is in
6
+ * wrapped lines, not entries, so one long message costs the room of the several short ones
7
+ * it is worth. The newest entry always stays, even when it alone is over budget.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { linesToDrop } from '@datamoc/mw_games/two-d/ui';
12
+ *
13
+ * console.log(linesToDrop([1, 2, 2], 3)); // 2 - the two oldest go, leaving one 2-line entry
14
+ * ```
15
+ */
16
+ export declare function linesToDrop(lineCounts: readonly number[], maxLines: number): number;
17
+ export interface MessageLogOptions {
18
+ /** wrap width of each message, in pixels */
19
+ wrapWidth: number;
20
+ /** wrapped lines of history to keep; default 3 */
21
+ maxLines?: number;
22
+ /** text size; default the theme's */
23
+ size?: number;
24
+ /** overrides for the per-level colours */
25
+ colors?: Partial<Record<MessageLevel, number>>;
26
+ /** rasterisation resolution of every message, for a log drawn inside a zoomed container */
27
+ resolution?: number;
28
+ }
29
+ /**
30
+ * A player-facing message pane: each message is its own block, coloured by its level, and
31
+ * the oldest blocks fall away once the wrapped lines pass `maxLines`. The classic
32
+ * roguelike "you hit the rat" strip; a `Toast` is transient and a `Logger` is for
33
+ * developers, this is neither.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { MessageLog } from '@datamoc/mw_games/two-d/ui';
38
+ *
39
+ * const log = new MessageLog({ wrapWidth: 200, maxLines: 4 });
40
+ * log.add('You find a dewdrop.', 'positive');
41
+ * log.add('You are starving.', 'negative');
42
+ * console.log(log.entryCount); // 2
43
+ * ```
44
+ */
45
+ export declare class MessageLog extends Container {
46
+ private readonly blocks;
47
+ private readonly options;
48
+ private maxLines;
49
+ constructor(options: MessageLogOptions);
50
+ get entryCount(): number;
51
+ /** the drawn height of every block together, so a caller can sit the log on an edge */
52
+ get contentHeight(): number;
53
+ add(text: string, level?: MessageLevel): void;
54
+ setMaxLines(lines: number): void;
55
+ setWrapWidth(width: number): void;
56
+ clear(): void;
57
+ private colorOf;
58
+ private linesOf;
59
+ private trim;
60
+ private layout;
61
+ }
62
+ //# sourceMappingURL=MessageLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageLog.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/MessageLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAIpC,+FAA+F;AAC/F,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAKtF;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMnF;AAED,MAAM,WAAW,iBAAiB;IACjC,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+C;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAC5C,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,OAAO,EAAE,iBAAiB,EAIrC;IAED,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,uFAAuF;IACvF,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,YAAqB,GAAG,IAAI,CAYpD;IAED,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI/B;IAED,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKhC;IAED,KAAK,IAAI,IAAI,CAEZ;IAED,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,IAAI;IAQZ,OAAO,CAAC,MAAM;CAOd"}
@@ -0,0 +1,114 @@
1
+ import { Container } from 'pixi.js';
2
+ import { Label } from './Label.js';
3
+ import { theme } from './theme.js';
4
+ /** the default per-level text colours; `info` and `highlight` follow the active theme */
5
+ const LEVEL_COLORS = { positive: 0x55dd77, negative: 0xff5555, warning: 0xffb347 };
6
+ /**
7
+ * How many of the oldest entries to drop so the rest fit in `maxLines`. The budget is in
8
+ * wrapped lines, not entries, so one long message costs the room of the several short ones
9
+ * it is worth. The newest entry always stays, even when it alone is over budget.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { linesToDrop } from '@datamoc/mw_games/two-d/ui';
14
+ *
15
+ * console.log(linesToDrop([1, 2, 2], 3)); // 2 - the two oldest go, leaving one 2-line entry
16
+ * ```
17
+ */
18
+ export function linesToDrop(lineCounts, maxLines) {
19
+ let total = 0;
20
+ for (const lines of lineCounts)
21
+ total += lines;
22
+ let dropped = 0;
23
+ while (total > maxLines && dropped < lineCounts.length - 1)
24
+ total -= lineCounts[dropped++];
25
+ return dropped;
26
+ }
27
+ /**
28
+ * A player-facing message pane: each message is its own block, coloured by its level, and
29
+ * the oldest blocks fall away once the wrapped lines pass `maxLines`. The classic
30
+ * roguelike "you hit the rat" strip; a `Toast` is transient and a `Logger` is for
31
+ * developers, this is neither.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { MessageLog } from '@datamoc/mw_games/two-d/ui';
36
+ *
37
+ * const log = new MessageLog({ wrapWidth: 200, maxLines: 4 });
38
+ * log.add('You find a dewdrop.', 'positive');
39
+ * log.add('You are starving.', 'negative');
40
+ * console.log(log.entryCount); // 2
41
+ * ```
42
+ */
43
+ export class MessageLog extends Container {
44
+ constructor(options) {
45
+ super();
46
+ this.blocks = [];
47
+ this.options = options;
48
+ this.maxLines = options.maxLines ?? 3;
49
+ }
50
+ get entryCount() {
51
+ return this.blocks.length;
52
+ }
53
+ /** the drawn height of every block together, so a caller can sit the log on an edge */
54
+ get contentHeight() {
55
+ return this.blocks.reduce((height, block) => height + block.label.height, 0);
56
+ }
57
+ add(text, level = 'info') {
58
+ const label = new Label({
59
+ text,
60
+ size: this.options.size,
61
+ color: this.colorOf(level),
62
+ wrapWidth: this.options.wrapWidth,
63
+ resolution: this.options.resolution,
64
+ });
65
+ this.addChild(label);
66
+ this.blocks.push({ label, level });
67
+ this.trim();
68
+ this.layout();
69
+ }
70
+ setMaxLines(lines) {
71
+ this.maxLines = Math.max(1, Math.floor(lines));
72
+ this.trim();
73
+ this.layout();
74
+ }
75
+ setWrapWidth(width) {
76
+ this.options.wrapWidth = width;
77
+ for (const block of this.blocks)
78
+ block.label.style.wordWrapWidth = width;
79
+ this.trim();
80
+ this.layout();
81
+ }
82
+ clear() {
83
+ for (const block of this.blocks.splice(0))
84
+ block.label.destroy();
85
+ }
86
+ colorOf(level) {
87
+ const own = this.options.colors?.[level];
88
+ if (own !== undefined)
89
+ return own;
90
+ if (level === 'info')
91
+ return theme().color.text;
92
+ if (level === 'highlight')
93
+ return theme().color.textHighlight;
94
+ return LEVEL_COLORS[level];
95
+ }
96
+ linesOf(label) {
97
+ //Pixi measures the wrapped text; its height over the line height is the line count
98
+ const lineHeight = Number(label.style.lineHeight) || Number(label.style.fontSize) || 1;
99
+ return Math.max(1, Math.round(label.height / lineHeight));
100
+ }
101
+ trim() {
102
+ const drop = linesToDrop(this.blocks.map((block) => this.linesOf(block.label)), this.maxLines);
103
+ for (const block of this.blocks.splice(0, drop))
104
+ block.label.destroy();
105
+ }
106
+ layout() {
107
+ let y = 0;
108
+ for (const block of this.blocks) {
109
+ block.label.position.set(0, y);
110
+ y += block.label.height;
111
+ }
112
+ }
113
+ }
114
+ //# sourceMappingURL=MessageLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageLog.js","sourceRoot":"","sources":["../../../src/two-d/ui/MessageLog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { Container } from 'pixi.js';
2
+ import type { Action } from '../../core/Input.ts';
3
+ import { Signal } from '../../core/Signal.ts';
4
+ export interface RadioOption {
5
+ /** what the row reads */
6
+ text: string;
7
+ /** a greyed-out option can be looked at but not chosen */
8
+ disabled?: boolean;
9
+ /** anything the game wants to get back when the option is chosen */
10
+ value?: unknown;
11
+ }
12
+ export interface RadioGroupOptions {
13
+ options?: RadioOption[];
14
+ /** initially selected index; the first enabled option when omitted */
15
+ selected?: number;
16
+ /** the circle's diameter; the dot is drawn inside it */
17
+ size?: number;
18
+ /** vertical space between rows */
19
+ gap?: number;
20
+ }
21
+ /**
22
+ * One choice among several, where a checkbox would allow many: exactly one option
23
+ * is selected, arrows move the selection (which selects at once, the way native
24
+ * radio groups do), and a tap selects directly. Disabled options are skipped by
25
+ * the keyboard and ignore the pointer, the same contract `ListView` rows keep.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { RadioGroup } from '@datamoc/mw_games/two-d/ui';
30
+ *
31
+ * const side = new RadioGroup({ options: [{ text: 'White' }, { text: 'Black' }] });
32
+ * side.onChange.add((index) => console.log('side', index));
33
+ * side.select(1);
34
+ * ```
35
+ */
36
+ export declare class RadioGroup extends Container {
37
+ readonly onChange: Signal<number>;
38
+ private options_;
39
+ private rows;
40
+ private circles;
41
+ private size_;
42
+ private gap_;
43
+ private selected_;
44
+ private readonly themeListener;
45
+ constructor(options?: RadioGroupOptions);
46
+ get selected(): number;
47
+ get selectedOption(): RadioOption | null;
48
+ get length(): number;
49
+ get rowHeight(): number;
50
+ setOptions(options: RadioOption[], selected?: number): void;
51
+ /** picks an option, firing `onChange` only when the choice actually moves */
52
+ select(index: number): void;
53
+ /**
54
+ * Steps the selection by `delta` rows, skipping disabled options and wrapping
55
+ * at both ends, the way a short settings group wants. Returns false when there
56
+ * is nothing selectable to move to, so a caller can beep rather than doing nothing.
57
+ */
58
+ move(delta: number): boolean;
59
+ /** @returns true when the action was used */
60
+ handleAction(action: Action): boolean;
61
+ /** selects row `index` the way a tap does; a disabled row is a no-op */
62
+ tapRow(index: number): void;
63
+ private defaultSelection;
64
+ private buildRows;
65
+ private draw;
66
+ destroy(options?: Parameters<Container['destroy']>[0]): void;
67
+ }
68
+ //# sourceMappingURL=RadioGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/RadioGroup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAI9C,MAAM,WAAW,WAAW;IAC3B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IAEb,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,oEAAoE;IACpE,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IAExB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACxC,QAAQ,CAAC,QAAQ,iBAAwB;IAEzC,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,IAAI,CAAmB;IAC/B,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IAEnD,YAAY,OAAO,GAAE,iBAAsB,EAW1C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,cAAc,IAAI,WAAW,GAAG,IAAI,CAEvC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAI1D;IAED,6EAA6E;IAC7E,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAU1B;IAED;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa3B;IAED,6CAA6C;IAC7C,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAYpC;IAED,wEAAwE;IACxE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE1B;IAED,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,SAAS;IA0BjB,OAAO,CAAC,IAAI;IAuCH,OAAO,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAGpE;CACD"}
@@ -0,0 +1,177 @@
1
+ import { Container, Graphics } from 'pixi.js';
2
+ import { Signal } from '../../core/Signal.js';
3
+ import { Label } from './Label.js';
4
+ import { theme, themeChanged } from './theme.js';
5
+ /**
6
+ * One choice among several, where a checkbox would allow many: exactly one option
7
+ * is selected, arrows move the selection (which selects at once, the way native
8
+ * radio groups do), and a tap selects directly. Disabled options are skipped by
9
+ * the keyboard and ignore the pointer, the same contract `ListView` rows keep.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { RadioGroup } from '@datamoc/mw_games/two-d/ui';
14
+ *
15
+ * const side = new RadioGroup({ options: [{ text: 'White' }, { text: 'Black' }] });
16
+ * side.onChange.add((index) => console.log('side', index));
17
+ * side.select(1);
18
+ * ```
19
+ */
20
+ export class RadioGroup extends Container {
21
+ constructor(options = {}) {
22
+ super();
23
+ this.onChange = new Signal();
24
+ this.options_ = [];
25
+ this.rows = [];
26
+ this.circles = [];
27
+ this.selected_ = -1;
28
+ this.themeListener = () => this.draw();
29
+ this.size_ = options.size ?? 20;
30
+ this.gap_ = options.gap ?? 8;
31
+ this.buildRows(options.options ?? []);
32
+ this.selected_ = this.defaultSelection(options.selected);
33
+ this.draw();
34
+ themeChanged.add(this.themeListener);
35
+ }
36
+ get selected() {
37
+ return this.selected_;
38
+ }
39
+ get selectedOption() {
40
+ return this.options_[this.selected_] ?? null;
41
+ }
42
+ get length() {
43
+ return this.options_.length;
44
+ }
45
+ get rowHeight() {
46
+ return this.size_ + this.gap_;
47
+ }
48
+ setOptions(options, selected) {
49
+ this.buildRows(options);
50
+ this.selected_ = this.defaultSelection(selected);
51
+ this.draw();
52
+ }
53
+ /** picks an option, firing `onChange` only when the choice actually moves */
54
+ select(index) {
55
+ const option = this.options_[index];
56
+ if (!option || option.disabled)
57
+ return;
58
+ if (index === this.selected_) {
59
+ this.draw();
60
+ return;
61
+ }
62
+ this.selected_ = index;
63
+ this.draw();
64
+ this.onChange.dispatch(index);
65
+ }
66
+ /**
67
+ * Steps the selection by `delta` rows, skipping disabled options and wrapping
68
+ * at both ends, the way a short settings group wants. Returns false when there
69
+ * is nothing selectable to move to, so a caller can beep rather than doing nothing.
70
+ */
71
+ move(delta) {
72
+ const count = this.options_.length;
73
+ if (count === 0)
74
+ return false;
75
+ let at = this.selected_;
76
+ for (let tried = 0; tried < count; tried++) {
77
+ at = (at + delta + count) % count;
78
+ const option = this.options_[at];
79
+ if (option && !option.disabled) {
80
+ this.select(at);
81
+ return true;
82
+ }
83
+ }
84
+ return false;
85
+ }
86
+ /** @returns true when the action was used */
87
+ handleAction(action) {
88
+ switch (action) {
89
+ case 'up':
90
+ case 'left':
91
+ return this.move(-1);
92
+ case 'down':
93
+ case 'right':
94
+ return this.move(1);
95
+ default:
96
+ //nothing to confirm: arrows already select, the way native radio groups do
97
+ return false;
98
+ }
99
+ }
100
+ /** selects row `index` the way a tap does; a disabled row is a no-op */
101
+ tapRow(index) {
102
+ this.select(index);
103
+ }
104
+ defaultSelection(wanted) {
105
+ if (wanted !== undefined) {
106
+ const option = this.options_[wanted];
107
+ if (option && !option.disabled)
108
+ return wanted;
109
+ }
110
+ const first = this.options_.findIndex((option) => !option.disabled);
111
+ return first === -1 ? -1 : first;
112
+ }
113
+ buildRows(options) {
114
+ for (const row of this.rows)
115
+ row.destroy({ children: true });
116
+ this.rows = [];
117
+ this.circles = [];
118
+ this.options_ = [...options];
119
+ this.removeChildren();
120
+ options.forEach((option, i) => {
121
+ const row = new Container();
122
+ row.y = i * this.rowHeight;
123
+ row.eventMode = 'static';
124
+ row.cursor = option.disabled ? 'default' : 'pointer';
125
+ row.on('pointertap', () => this.tapRow(i));
126
+ const circle = new Graphics();
127
+ row.addChild(circle);
128
+ this.circles.push(circle);
129
+ const label = new Label({ text: option.text });
130
+ row.addChild(label);
131
+ this.rows.push(row);
132
+ this.addChild(row);
133
+ });
134
+ }
135
+ draw() {
136
+ const t = theme();
137
+ const rtl = t.direction === 'rtl';
138
+ this.rows.forEach((row, i) => {
139
+ const option = this.options_[i];
140
+ const dim = option.disabled;
141
+ const circle = this.circles[i];
142
+ circle
143
+ .clear()
144
+ .circle(this.size_ / 2, this.size_ / 2, this.size_ / 2 - 1)
145
+ .fill({ color: t.color.panelFill })
146
+ .stroke({ color: dim ? t.color.textDim : t.color.panelBorder, width: 2 });
147
+ if (i === this.selected_) {
148
+ circle
149
+ .circle(this.size_ / 2, this.size_ / 2, Math.max(2, this.size_ * 0.28))
150
+ .fill({ color: dim ? t.color.textDim : t.color.textHighlight });
151
+ }
152
+ const textStart = this.size_ + t.spacing;
153
+ const label = row.children.find((child) => child instanceof Label);
154
+ const textWidth = label?.width ?? 0;
155
+ if (label) {
156
+ label.setColor(dim ? t.color.textDim : t.color.text);
157
+ label.y = Math.round((this.size_ - label.height) / 2);
158
+ }
159
+ //mirrored per row, since rows have no shared width to align against
160
+ if (rtl) {
161
+ if (label)
162
+ label.x = 0;
163
+ circle.x = textWidth + t.spacing;
164
+ }
165
+ else {
166
+ circle.x = 0;
167
+ if (label)
168
+ label.x = textStart;
169
+ }
170
+ });
171
+ }
172
+ destroy(options) {
173
+ themeChanged.remove(this.themeListener);
174
+ super.destroy(options);
175
+ }
176
+ }
177
+ //# sourceMappingURL=RadioGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../../src/two-d/ui/RadioGroup.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,12 @@ export interface TextModelOptions {
6
6
  mask?: boolean;
7
7
  /** the character `maskedValue` repeats; a bullet when omitted */
8
8
  maskCharacter?: string;
9
+ /**
10
+ * a multiline field: Enter inserts a real newline and the line helpers below
11
+ * navigate rows. Off by default, in which case newlines never survive an edit -
12
+ * a single-line name entry cannot grow a second row no matter what is pasted.
13
+ */
14
+ multiline?: boolean;
9
15
  }
10
16
  /**
11
17
  * The editing state behind a text field, with no renderer attached - the counterpart to
@@ -33,9 +39,14 @@ export declare class TextModel {
33
39
  private readonly maxLength?;
34
40
  private readonly mask;
35
41
  private readonly maskCharacter;
42
+ private readonly multiline;
43
+ private goalColumn;
36
44
  constructor(options?: TextModelOptions);
37
45
  get value(): string;
38
- /** what to draw for a password field: every character replaced by the mask */
46
+ /**
47
+ * what to draw for a password field: every character replaced by the mask, except
48
+ * newlines, which stay newlines so a masked multiline value keeps its rows
49
+ */
39
50
  get maskedValue(): string;
40
51
  get length(): number;
41
52
  get caret(): number;
@@ -60,6 +71,20 @@ export declare class TextModel {
60
71
  clearSelection(): void;
61
72
  /** replaces the selection (or inserts at the caret) and leaves the caret after the new text */
62
73
  replaceSelection(text: string): void;
74
+ /** newlines as the field keeps them: rows in a multiline field, stripped away otherwise */
75
+ private shape;
76
+ /** rows in a multiline field; always 1 for a single-line one, even when empty */
77
+ get lineCount(): number;
78
+ /** the 0-based row the caret sits on */
79
+ get caretLine(): number;
80
+ /** [start, end) of a row, the end stopping before its newline; out-of-range rows clamp */
81
+ lineRange(line: number): readonly [number, number];
82
+ /**
83
+ * Up/down between rows, holding the column: the caret lands as far along the new
84
+ * row as it goes, the way a `<textarea>` moves. Rows here are newline-delimited,
85
+ * since only the renderer knows where a long row wraps on screen.
86
+ */
87
+ moveCaretLine(delta: number, extend?: boolean): void;
63
88
  private limit;
64
89
  }
65
90
  //# sourceMappingURL=TextModel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextModel.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/TextModel.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,YAAY,OAAO,GAAE,gBAAqB,EAOzC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,8EAA8E;IAC9E,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,uGAAuG;IACvG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAI5B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI,CAG5C;IAED,uFAAuF;IACvF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAGzB;IAED,kFAAkF;IAClF,SAAS,IAAI,IAAI,CAQhB;IAED,8EAA8E;IAC9E,aAAa,IAAI,IAAI,CAQpB;IAED,sFAAsF;IACtF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI,CAE7C;IAED,WAAW,CAAC,MAAM,UAAQ,GAAG,IAAI,CAEhC;IAED,SAAS,CAAC,MAAM,UAAQ,GAAG,IAAI,CAE9B;IAED,SAAS,IAAI,IAAI,CAGhB;IAED,cAAc,IAAI,IAAI,CAErB;IAED,+FAA+F;IAC/F,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAWnC;IAED,OAAO,CAAC,KAAK;CAGb"}
1
+ {"version":3,"file":"TextModel.d.ts","sourceRoot":"","sources":["../../../src/two-d/ui/TextModel.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,SAAS;IACrB,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAU;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,UAAU,CAAuB;IAEzC,YAAY,OAAO,GAAE,gBAAqB,EAQzC;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED;;;OAGG;IACH,IAAI,WAAW,IAAI,MAAM,CAMxB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,uGAAuG;IACvG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK5B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI,CAI5C;IAED,uFAAuF;IACvF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAGzB;IAED,kFAAkF;IAClF,SAAS,IAAI,IAAI,CAQhB;IAED,8EAA8E;IAC9E,aAAa,IAAI,IAAI,CAQpB;IAED,sFAAsF;IACtF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI,CAE7C;IAED,WAAW,CAAC,MAAM,UAAQ,GAAG,IAAI,CAEhC;IAED,SAAS,CAAC,MAAM,UAAQ,GAAG,IAAI,CAE9B;IAED,SAAS,IAAI,IAAI,CAIhB;IAED,cAAc,IAAI,IAAI,CAErB;IAED,+FAA+F;IAC/F,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAYnC;IAED,2FAA2F;IAC3F,OAAO,CAAC,KAAK;IAIb,iFAAiF;IACjF,IAAI,SAAS,IAAI,MAAM,CAGtB;IAED,wCAAwC;IACxC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,0FAA0F;IAC1F,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAMjD;IAED;;;;OAIG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI,CAMjD;IAED,OAAO,CAAC,KAAK;CAGb"}
@@ -19,7 +19,9 @@
19
19
  */
20
20
  export class TextModel {
21
21
  constructor(options = {}) {
22
- this.text = options.value ?? '';
22
+ this.goalColumn = null;
23
+ this.multiline = options.multiline ?? false;
24
+ this.text = this.limit(this.shape(options.value ?? ''));
23
25
  this.maxLength = options.maxLength;
24
26
  this.mask = options.mask ?? false;
25
27
  this.maskCharacter = options.maskCharacter ?? '\u2022';
@@ -29,9 +31,17 @@ export class TextModel {
29
31
  get value() {
30
32
  return this.text;
31
33
  }
32
- /** what to draw for a password field: every character replaced by the mask */
34
+ /**
35
+ * what to draw for a password field: every character replaced by the mask, except
36
+ * newlines, which stay newlines so a masked multiline value keeps its rows
37
+ */
33
38
  get maskedValue() {
34
- return this.mask ? this.maskCharacter.repeat(this.text.length) : this.text;
39
+ if (!this.mask)
40
+ return this.text;
41
+ return this.text
42
+ .split('')
43
+ .map((char) => (char === '\n' ? '\n' : this.maskCharacter))
44
+ .join('');
35
45
  }
36
46
  get length() {
37
47
  return this.text.length;
@@ -53,12 +63,14 @@ export class TextModel {
53
63
  }
54
64
  /** replaces everything; the caret goes to the end and a new string is never longer than `maxLength` */
55
65
  setValue(value) {
56
- this.text = this.limit(value);
66
+ this.text = this.limit(this.shape(value));
57
67
  this.caretIndex = this.text.length;
58
68
  this.anchor = this.caretIndex;
69
+ this.goalColumn = null;
59
70
  }
60
71
  setCaret(index, extend = false) {
61
72
  this.caretIndex = Math.max(0, Math.min(this.text.length, index));
73
+ this.goalColumn = null;
62
74
  if (!extend)
63
75
  this.anchor = this.caretIndex;
64
76
  }
@@ -103,6 +115,7 @@ export class TextModel {
103
115
  selectAll() {
104
116
  this.anchor = 0;
105
117
  this.caretIndex = this.text.length;
118
+ this.goalColumn = null;
106
119
  }
107
120
  clearSelection() {
108
121
  this.anchor = this.caretIndex;
@@ -112,13 +125,49 @@ export class TextModel {
112
125
  const start = this.selectionStart;
113
126
  const end = this.selectionEnd;
114
127
  const base = this.text.slice(0, start) + this.text.slice(end);
128
+ const shaped = this.shape(text);
115
129
  //a paste into a field with little room left stops at the cap rather than being rejected whole
116
- const inserted = this.maxLength !== undefined && base.length + text.length > this.maxLength
117
- ? text.slice(0, Math.max(0, this.maxLength - base.length))
118
- : text;
130
+ const inserted = this.maxLength !== undefined && base.length + shaped.length > this.maxLength
131
+ ? shaped.slice(0, Math.max(0, this.maxLength - base.length))
132
+ : shaped;
119
133
  this.text = this.text.slice(0, start) + inserted + this.text.slice(end);
120
134
  this.setCaret(start + inserted.length);
121
135
  }
136
+ /** newlines as the field keeps them: rows in a multiline field, stripped away otherwise */
137
+ shape(text) {
138
+ return text.replace(/\r\n|\r|\n/g, this.multiline ? '\n' : '');
139
+ }
140
+ /** rows in a multiline field; always 1 for a single-line one, even when empty */
141
+ get lineCount() {
142
+ if (!this.multiline)
143
+ return 1;
144
+ return this.text.split('\n').length;
145
+ }
146
+ /** the 0-based row the caret sits on */
147
+ get caretLine() {
148
+ return this.text.slice(0, this.caretIndex).split('\n').length - 1;
149
+ }
150
+ /** [start, end) of a row, the end stopping before its newline; out-of-range rows clamp */
151
+ lineRange(line) {
152
+ const clamped = Math.max(0, Math.min(this.lineCount - 1, line));
153
+ let start = 0;
154
+ for (let i = 0; i < clamped; i++)
155
+ start = this.text.indexOf('\n', start) + 1;
156
+ const end = this.text.indexOf('\n', start);
157
+ return [start, end === -1 ? this.text.length : end];
158
+ }
159
+ /**
160
+ * Up/down between rows, holding the column: the caret lands as far along the new
161
+ * row as it goes, the way a `<textarea>` moves. Rows here are newline-delimited,
162
+ * since only the renderer knows where a long row wraps on screen.
163
+ */
164
+ moveCaretLine(delta, extend = false) {
165
+ const [start] = this.lineRange(this.caretLine);
166
+ const column = this.goalColumn ?? this.caretIndex - start;
167
+ const [nextStart, nextEnd] = this.lineRange(this.caretLine + delta);
168
+ this.setCaret(nextStart + Math.min(column, nextEnd - nextStart), extend);
169
+ this.goalColumn = column;
170
+ }
122
171
  limit(value) {
123
172
  return this.maxLength !== undefined && value.length > this.maxLength ? value.slice(0, this.maxLength) : value;
124
173
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextModel.js","sourceRoot":"","sources":["../../../src/two-d/ui/TextModel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TextModel.js","sourceRoot":"","sources":["../../../src/two-d/ui/TextModel.ts"],"names":[],"mappings":"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"}