@scm-js/plugin-api 1.48.0 → 1.50.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 (2) hide show
  1. package/index.d.ts +153 -0
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -980,6 +980,8 @@ export interface UpgradesDat {
980
980
  broodWar: Uint8Array;
981
981
  /** The upgrade's name: a 1-based `stat_txt.tbl` index, 0 for none. */
982
982
  label: Uint16Array;
983
+ /** Its button picture: a frame of `unit\cmdbtns\cmdicons.grp`. */
984
+ icon: Uint16Array;
983
985
  }
984
986
  /** The columns Technology Settings shows as defaults. */
985
987
  export interface TechdataDat {
@@ -992,6 +994,8 @@ export interface TechdataDat {
992
994
  broodWar: Uint8Array;
993
995
  /** The technology's name: a 1-based `stat_txt.tbl` index, 0 for none. */
994
996
  label: Uint16Array;
997
+ /** Its button picture: a frame of `unit\cmdbtns\cmdicons.grp`. */
998
+ icon: Uint16Array;
995
999
  }
996
1000
  /**
997
1001
  * Unit edits as invertible change lists, in the same spirit as terrain's `TileChange`.
@@ -2329,6 +2333,8 @@ export interface StatusBarCells {
2329
2333
  export type PluginUpdateMode = "notify" | "manual" | "auto";
2330
2334
  /** The revisions a new map can start on; the two older ones are for opening old files, not making new ones. */
2331
2335
  export type NewMapVersion = Extract<MapVersion, "broodwar" | "remastered">;
2336
+ export type IconKind = "unit" | "upgrade" | "tech";
2337
+ export type IconLook = "normal" | "disabled" | "selected";
2332
2338
  /**
2333
2339
  * The version a host provides; a manifest that asks for a newer one is refused. It stays
2334
2340
  * at 1 while the API is only used by the plugins in the scm-js organisation and grows
@@ -4138,6 +4144,36 @@ export interface GraphicsApi {
4138
4144
  */
4139
4145
  requestUnit(unitId: number): boolean;
4140
4146
  requestSprite(kind: SpriteKind, id: number): boolean;
4147
+ /**
4148
+ * The game's own button picture for a unit type, an upgrade or a technology — the icon
4149
+ * its command card shows — 36 × 34 at most and transparent round the edges. `look`
4150
+ * colours it as the game does: `"normal"` yellow (the default), `"disabled"` grey,
4151
+ * `"selected"` white. It does not depend on the map or its tileset. Null for an id with
4152
+ * no picture (a unit type past 227, a turret) and until `requestIcons` has the pictures;
4153
+ * null for good from a game data copy made before the editor kept them (installing the
4154
+ * game data again brings them). The canvas is the editor's own cached one: draw from it.
4155
+ *
4156
+ * @example
4157
+ * // A row of what a player researched, as the game's icons, with the names where there are no pictures.
4158
+ * const show = () => list.replaceChildren(...done.map((r) => {
4159
+ * const icon = api.graphics.icon(r.kind, r.id);
4160
+ * if (!icon) return api.ui.el("span", {}, r.kind === "tech" ? api.names.tech(r.id) : api.names.upgrade(r.id));
4161
+ * const canvas = api.ui.el("canvas", { width: icon.width, height: icon.height });
4162
+ * canvas.getContext("2d")?.drawImage(icon.image, 0, 0);
4163
+ * return canvas;
4164
+ * }));
4165
+ * api.graphics.requestIcons();
4166
+ * api.graphics.onImageLoaded(show);
4167
+ * show();
4168
+ */
4169
+ icon(kind: IconKind, id: number, options?: {
4170
+ look?: IconLook;
4171
+ }): PluginImage | null;
4172
+ /**
4173
+ * Start fetching the icon pictures (one sheet holds them all), and say whether they are
4174
+ * in memory. `onImageLoaded` fires when they arrive.
4175
+ */
4176
+ requestIcons(): boolean;
4141
4177
  /** A GRP finished loading: anything drawn from one may look different now. */
4142
4178
  onImageLoaded(listener: () => void): Disposable;
4143
4179
  }
@@ -5044,6 +5080,70 @@ export interface MapViewSpec {
5044
5080
  * to be called when the view goes (the plugin stops, or `dispose`).
5045
5081
  */
5046
5082
  mount(element: HTMLElement): void | (() => void);
5083
+ /**
5084
+ * The view is shown in the map's place, where the map was looking: `look` is the map's view
5085
+ * at that moment, or the other view's (`setCamera`) when the switch came from one. Turn to
5086
+ * look at the same place, as near the same scale as you can, so the switch keeps the person
5087
+ * where they were. Not called when another map, already showing the view, comes to the front.
5088
+ */
5089
+ onShow?(look: MapViewCamera): void;
5090
+ /**
5091
+ * What the minimap shows while the view is shown. Without it the minimap shows the map, and
5092
+ * its box and presses are the map's own view's (hidden behind this one).
5093
+ */
5094
+ minimap?: MapViewMinimapSpec;
5095
+ }
5096
+ /**
5097
+ * Where a view looks, in map pixels (32 to a tile): the point in the middle of what it shows,
5098
+ * and how much of the map that is.
5099
+ */
5100
+ export interface MapViewCamera {
5101
+ x: number;
5102
+ y: number;
5103
+ width: number;
5104
+ height: number;
5105
+ }
5106
+ /**
5107
+ * A map view's own minimap (`MapViewSpec.minimap`): the minimap draws the map's ground, then
5108
+ * `draw` over it in place of the map's units, start locations and fog, and its box where the
5109
+ * view looks (`MapViewHandle.setCamera`).
5110
+ *
5111
+ * @example
5112
+ * // A replay's units as dots, and the minimap moving the game's camera.
5113
+ * const view = api.ui.mapView({
5114
+ * title: "Replay",
5115
+ * mount: (el) => el.append(frame),
5116
+ * minimap: {
5117
+ * draw(ctx, m) {
5118
+ * for (const u of units) {
5119
+ * ctx.fillStyle = u.colour;
5120
+ * ctx.fillRect(m.x(u.x) - 1, m.y(u.y) - 1, Math.max(2, u.width * m.scale), Math.max(2, u.height * m.scale));
5121
+ * }
5122
+ * },
5123
+ * press: (x, y) => game.lookAt(x, y),
5124
+ * },
5125
+ * });
5126
+ * game.onUnits(() => view.redrawMinimap());
5127
+ * game.onCamera((c) => view.setCamera(c));
5128
+ */
5129
+ export interface MapViewMinimapSpec {
5130
+ /** Draw over the map's ground, each time the minimap's picture is made while the view is shown. */
5131
+ draw?(ctx: CanvasRenderingContext2D, minimap: MinimapView): void;
5132
+ /**
5133
+ * A press on the minimap, and each move of a drag from it, at a map pixel: look there. Without
5134
+ * it the minimap does not move anything while the view is shown.
5135
+ */
5136
+ press?(x: number, y: number): void;
5137
+ }
5138
+ /** Map pixels to minimap canvas pixels, for `MapViewMinimapSpec.draw`. */
5139
+ export interface MinimapView {
5140
+ /** Minimap canvas pixels per map pixel. */
5141
+ scale: number;
5142
+ /** A map pixel's x on the minimap's canvas. */
5143
+ x(px: number): number;
5144
+ y(py: number): number;
5145
+ /** The canvas's size in pixels, each side (the map is centred in it, letterboxed). */
5146
+ size: number;
5047
5147
  }
5048
5148
  export interface MapViewHandle extends Disposable {
5049
5149
  /**
@@ -5061,6 +5161,14 @@ export interface MapViewHandle extends Disposable {
5061
5161
  * `show` was called, or another map came to the front.
5062
5162
  */
5063
5163
  onChange(listener: (shown: boolean) => void): Disposable;
5164
+ /**
5165
+ * Where the view looks now, in map pixels; call it whenever that changes. The minimap draws
5166
+ * its box there while the view is shown, and the map, shown again, opens on the same place at
5167
+ * the same scale.
5168
+ */
5169
+ setCamera(camera: MapViewCamera): void;
5170
+ /** Make the minimap's picture again (`minimap.draw`), at most once a frame. Cheap: call it as the view's contents move. */
5171
+ redrawMinimap(): void;
5064
5172
  }
5065
5173
  export interface PanelHandle {
5066
5174
  close(): void;
@@ -5565,6 +5673,24 @@ export interface UiApi {
5565
5673
  * }
5566
5674
  */
5567
5675
  progress(label: string, options?: ProgressOptions): ProgressHandle;
5676
+ /**
5677
+ * A tooltip in the editor's own style over an element of yours, in place of the
5678
+ * browser's `title`. `content` is a line of text, or a function asked for what to show
5679
+ * at the pointer — rows, bars, pictures, built with `el` and the widgets — which is how
5680
+ * a chart says what is under the pointer: it is asked again as the pointer moves, and
5681
+ * answering null hides the tip there. The editor places it beside the pointer, keeps it
5682
+ * on screen and takes it away when the pointer leaves, the element leaves the page, or
5683
+ * the plugin stops. `refresh()` asks again where the pointer stands (a picture arrived,
5684
+ * the data moved). Remove the element's `title`, or both show.
5685
+ *
5686
+ * @example
5687
+ * // A chart that reads out the value under the pointer.
5688
+ * api.ui.tooltip(canvas, (at) => {
5689
+ * const i = Math.floor((at.offsetX / canvas.clientWidth) * values.length);
5690
+ * return values[i] === undefined ? null : api.ui.el("div", {}, api.ui.el("b", {}, `${values[i]}`), " minerals");
5691
+ * });
5692
+ */
5693
+ tooltip(target: HTMLElement, content: string | ((at: TooltipPointer) => HTMLElement | string | null), options?: TooltipOptions): TooltipHandle;
5568
5694
  /** `el("div", { className: "row" }, …)`: the DOM helper the widgets are built from. */
5569
5695
  el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Record<string, unknown>, ...children: WidgetChild[]): HTMLElementTagNameMap[K];
5570
5696
  /** Buttons, fields, forms and lists in the editor's own styles. */
@@ -5579,6 +5705,33 @@ export interface UiApi {
5579
5705
  /** Ask the viewport to repaint (a transaction does this by itself). Raises no event. */
5580
5706
  repaint(): void;
5581
5707
  }
5708
+ /** Where the pointer is, for a tooltip's `content`. */
5709
+ export interface TooltipPointer {
5710
+ /** In the page, CSS pixels (`clientX` / `clientY`). */
5711
+ x: number;
5712
+ y: number;
5713
+ /** From the target's top-left corner, CSS pixels. */
5714
+ offsetX: number;
5715
+ offsetY: number;
5716
+ /** Whether a button is held — a drag across a chart. */
5717
+ pressed: boolean;
5718
+ }
5719
+ export interface TooltipOptions {
5720
+ /**
5721
+ * Milliseconds the pointer rests before the tip shows. 500 for text, as the editor's own
5722
+ * tooltips; 0 for a function, which reads out what is under the pointer and should keep
5723
+ * up with it.
5724
+ */
5725
+ delay?: number;
5726
+ /** A width the tip does not grow past, CSS pixels; 320 by default. */
5727
+ maxWidth?: number;
5728
+ }
5729
+ export interface TooltipHandle extends Disposable {
5730
+ /** Ask `content` again where the pointer stands; nothing when the tip is not showing. */
5731
+ refresh(): void;
5732
+ /** Take the tip away until the pointer next moves over the target. */
5733
+ hide(): void;
5734
+ }
5582
5735
  export interface ConfirmOptions {
5583
5736
  title?: string;
5584
5737
  /** The primary button; `OK` by default. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.48.0",
3
+ "version": "1.50.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",