// RhythmBase.View/Assets/AssetManager.ts var Point = class _Point { x = 0; y = 0; constructor(x, y) { if (x !== void 0 && y !== void 0) { this.x = x; this.y = y; return; } } clone() { return new _Point(this.x, this.y); } }; var Rect = class _Rect { left = 0; top = 0; right = 0; bottom = 0; get x() { return this.left; } set x(value) { const diff = value - this.left; this.left += diff; this.right += diff; } get y() { return this.top; } set y(value) { const diff = value - this.top; this.top += diff; this.bottom += diff; } get width() { return this.right - this.left; } set width(value) { this.right = this.left + value; } get height() { return this.bottom - this.top; } set height(value) { this.bottom = this.top + value; } get centerX() { return (this.left + this.right) / 2; } get centerY() { return (this.top + this.bottom) / 2; } get location() { let point = new Point(); point.x = this.centerX; point.y = this.centerY; return point; } set location(point) { let w = this.width; let h = this.height; this.left = point.x; this.right = this.left + w; this.top = point.y; this.bottom = this.top + h; } get isEmpty() { return this.width <= 0 || this.height <= 0; } constructor(arg0, arg1, arg2, arg3) { if (arg0 !== void 0 && arg1 !== void 0) { if (arg2 !== void 0 && arg3 !== void 0) { this.left = arg0; this.top = arg1; this.right = arg0 + arg2; this.bottom = arg1 + arg3; return; } this.right = arg0; this.bottom = arg1; return; } } inflate(dx, dy) { this.left -= dx; this.right += dx; this.top -= dy; this.bottom += dy; } clone() { return new _Rect(this.left, this.top, this.width, this.height); } union(rect) { const left = Math.min(this.left, rect.left); const top = Math.min(this.top, rect.top); const right = Math.max(this.right, rect.right); const bottom = Math.max(this.bottom, rect.bottom); return new _Rect(left, top, right - left, bottom - top); } contains(point) { return point.x >= this.left && point.x <= this.right && point.y >= this.top && point.y <= this.bottom; } }; var Color = class _Color { red; green; blue; alpha; constructor(r, g, b, a) { if (typeof r === "string") { if (r.startsWith("#")) { r = r.substring(1); } r = r.trim(); switch (r.length) { case 3: r = r.split("").map((c) => c + c).join(""); break; case 4: r = "ff" + r.split("").map((c) => c + c).join(""); break; case 6: r = "ff" + r; break; case 8: break; default: r = "ffffffff"; } const u = parseInt(r, 16); this.alpha = u >> 24 & 255; this.red = u >> 16 & 255; this.green = u >> 8 & 255; this.blue = u & 255; return; } if (r !== void 0 && g === void 0 && b === void 0 && a === void 0) { this.alpha = r >> 24 & 255; this.red = r >> 16 & 255; this.green = r >> 8 & 255; this.blue = r & 255; return; } if (r !== void 0 && g !== void 0 && b !== void 0 && a === void 0) { this.red = r; this.green = g; this.blue = b; this.alpha = 255; return; } this.red = r ?? 0; this.green = g ?? 0; this.blue = b ?? 0; this.alpha = a ?? 0; } toUint32() { return ((this.alpha & 255) << 24 | (this.red & 255) << 16 | (this.green & 255) << 8 | this.blue & 255) >>> 0; } clone() { return new _Color(this.red, this.green, this.blue, this.alpha); } }; var Paint = class { color = new Color(255, 255, 255, 255); }; var SliceInfo = class { bounds = new Rect(); center = new Rect(); pivot = new Point(); scale = 1; get isNinePatch() { return !this.center.isEmpty; } }; var AssetManager = class _AssetManager { static AssetFilePath = "assets.png"; static SlicesFilePath = "assets.json"; static DirectoryPath = "."; static assetFile = null; static slices = /* @__PURE__ */ new Map(); static _isLoaded = false; constructor(dirpath) { _AssetManager.DirectoryPath = dirpath; _AssetManager.initialize(); } static get isLoaded() { return this._isLoaded; } static async loadAssetFile() { const pngPath = _AssetManager.DirectoryPath + "/" + this.AssetFilePath; return await new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = (e) => reject(new Error(`Failed to load asset file: ${pngPath}`)); img.src = pngPath; }); } static async loadSlices() { if (this._isLoaded) { return /* @__PURE__ */ new Map(); } const jsonPath = _AssetManager.DirectoryPath + "/" + this.SlicesFilePath; const response = await fetch(jsonPath); const json = await response.json(); const slices = json["meta"]["slices"]; const sliceInfos = /* @__PURE__ */ new Map(); for (const slice of slices) { const name = slice["name"]; const keys = slice["keys"]; const sliceInfo = new SliceInfo(); for (const key of keys) { const bounds = key["bounds"]; sliceInfo.bounds.left = bounds["x"]; sliceInfo.bounds.top = bounds["y"]; sliceInfo.bounds.right = bounds["x"] + bounds["w"]; sliceInfo.bounds.bottom = bounds["y"] + bounds["h"]; const center = key["center"]; if (center) { sliceInfo.center.left = center["x"]; sliceInfo.center.top = center["y"]; sliceInfo.center.right = center["x"] + center["w"]; sliceInfo.center.bottom = center["y"] + center["h"]; } const pivot = key["pivot"]; if (pivot) { sliceInfo.pivot.x = pivot["x"]; sliceInfo.pivot.y = pivot["y"]; } const data = key["data"]; if (data) { } sliceInfos.set(name, sliceInfo); } } return sliceInfos; } static async initialize() { if (this._isLoaded) { return; } this.assetFile = await this.loadAssetFile(); this.slices = await this.loadSlices(); this._isLoaded = true; } }; // RhythmBase.View/Assets/Consts.ts var Tab = /* @__PURE__ */ function(Tab2) { Tab2["Sounds"] = "sounds"; Tab2["Rows"] = "rows"; Tab2["Actions"] = "actions"; Tab2["Decorations"] = "decorations"; Tab2["Rooms"] = "rooms"; Tab2["Windows"] = "windows"; Tab2["Unknown"] = "unknown"; return Tab2; }({}); var EventType = /* @__PURE__ */ function(EventType2) { EventType2["AddClassicBeat"] = "AddClassicBeat"; EventType2["AddFreeTimeBeat"] = "AddFreeTimeBeat"; EventType2["AddOneshotBeat"] = "AddOneshotBeat"; EventType2["AdvanceText"] = "AdvanceText"; EventType2["BassDrop"] = "BassDrop"; EventType2["Blend"] = "Blend"; EventType2["CallCustomMethod"] = "CallCustomMethod"; EventType2["ChangeCharacter"] = "ChangeCharacter"; EventType2["ChangePlayersRows"] = "ChangePlayersRows"; EventType2["Comment"] = "Comment"; EventType2["CustomFlash"] = "CustomFlash"; EventType2["DesktopColor"] = "DesktopColor"; EventType2["FadeRoom"] = "FadeRoom"; EventType2["FinishLevel"] = "FinishLevel"; EventType2["Flash"] = "Flash"; EventType2["FlipScreen"] = "FlipScreen"; EventType2["FloatingText"] = "FloatingText"; EventType2["ForwardDecorationEvent"] = "ForwardDecorationEvent"; EventType2["ForwardEvent"] = "ForwardEvent"; EventType2["ForwardRowEvent"] = "ForwardRowEvent"; EventType2["HideRow"] = "HideRow"; EventType2["HideWindow"] = "HideWindow"; EventType2["InvertColors"] = "InvertColors"; EventType2["MacroEvent"] = "MacroEvent"; EventType2["MaskRoom"] = "MaskRoom"; EventType2["Move"] = "Move"; EventType2["MoveCamera"] = "MoveCamera"; EventType2["MoveRoom"] = "MoveRoom"; EventType2["MoveRow"] = "MoveRow"; EventType2["NarrateRowInfo"] = "NarrateRowInfo"; EventType2["NewWindowDance"] = "NewWindowDance"; EventType2["PaintHands"] = "PaintHands"; EventType2["PlayAnimation"] = "PlayAnimation"; EventType2["PlayExpression"] = "PlayExpression"; EventType2["PlaySong"] = "PlaySong"; EventType2["PlaySound"] = "PlaySound"; EventType2["PulseCamera"] = "PulseCamera"; EventType2["PulseFreeTimeBeat"] = "PulseFreeTimeBeat"; EventType2["ReadNarration"] = "ReadNarration"; EventType2["RenameWindow"] = "RenameWindow"; EventType2["ReorderRooms"] = "ReorderRooms"; EventType2["ReorderRow"] = "ReorderRow"; EventType2["ReorderSprite"] = "ReorderSprite"; EventType2["ReorderWindows"] = "ReorderWindows"; EventType2["SayReadyGetSetGo"] = "SayReadyGetSetGo"; EventType2["SetBackgroundColor"] = "SetBackgroundColor"; EventType2["SetBeatSound"] = "SetBeatSound"; EventType2["SetBeatsPerMinute"] = "SetBeatsPerMinute"; EventType2["SetClapSounds"] = "SetClapSounds"; EventType2["SetCountingSound"] = "SetCountingSound"; EventType2["SetCrotchetsPerBar"] = "SetCrotchetsPerBar"; EventType2["SetForeground"] = "SetForeground"; EventType2["SetGameSound"] = "SetGameSound"; EventType2["SetHandOwner"] = "SetHandOwner"; EventType2["SetHeartExplodeInterval"] = "SetHeartExplodeInterval"; EventType2["SetHeartExplodeVolume"] = "SetHeartExplodeVolume"; EventType2["SetMainWindow"] = "SetMainWindow"; EventType2["SetOneshotWave"] = "SetOneshotWave"; EventType2["SetPlayStyle"] = "SetPlayStyle"; EventType2["SetRoomContentMode"] = "SetRoomContentMode"; EventType2["SetRoomPerspective"] = "SetRoomPerspective"; EventType2["SetRowXs"] = "SetRowXs"; EventType2["SetSpeed"] = "SetSpeed"; EventType2["SetTheme"] = "SetTheme"; EventType2["SetVFXPreset"] = "SetVFXPreset"; EventType2["SetVisible"] = "SetVisible"; EventType2["SetWindowContent"] = "SetWindowContent"; EventType2["ShakeScreen"] = "ShakeScreen"; EventType2["ShakeScreenCustom"] = "ShakeScreenCustom"; EventType2["ShowDialogue"] = "ShowDialogue"; EventType2["ShowHands"] = "ShowHands"; EventType2["ShowRooms"] = "ShowRooms"; EventType2["ShowStatusSign"] = "ShowStatusSign"; EventType2["ShowSubdivisionsRows"] = "ShowSubdivisionsRows"; EventType2["SpinningRows"] = "SpinningRows"; EventType2["Stutter"] = "Stutter"; EventType2["TagAction"] = "TagAction"; EventType2["TextExplosion"] = "TextExplosion"; EventType2["Tile"] = "Tile"; EventType2["Tint"] = "Tint"; EventType2["TintRows"] = "TintRows"; EventType2["WindowResize"] = "WindowResize"; return EventType2; }({}); var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) { EventAttriblte2[EventAttriblte2["None"] = 0] = "None"; EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent"; EventAttriblte2[EventAttriblte2["RoomEvent"] = 2] = "RoomEvent"; return EventAttriblte2; }({}); var EventInfo = class { defaultTab; durationKey = "duration"; attr; get isDurationEvent() { return (this.attr & EventAttriblte.DurationEvent) !== 0; } get isRoomEvent() { return (this.attr & EventAttriblte.RoomEvent) !== 0; } constructor(tab, enumAttriblte, durationKey) { this.defaultTab = tab; this.attr = enumAttriblte ?? EventAttriblte.None; if (durationKey !== void 0) { this.durationKey = durationKey; } } }; var WordInfo = class { phrase; length; constructor(phrase, length) { this.phrase = phrase; this.length = length; } }; var WordInfos = { SayReaDyGetSetGoNew: new WordInfo("Rea, Dy, Get, Set, Go!", 4), SayReaDyGetSetOne: new WordInfo("Rea, Dy, Get, Set, One!", 4), SayGetSetGo: new WordInfo("Get, Set, Go!", 2), SayGetSetOne: new WordInfo("Get, Set, One!", 2), JustSayRea: new WordInfo("Rea", 0), JustSayDy: new WordInfo("Dy", 0), JustSayGet: new WordInfo("Get", 0), JustSaySet: new WordInfo("Set", 0), JustSayAnd: new WordInfo("And", 0), JustSayGo: new WordInfo("Go!", 0), JustSayStop: new WordInfo("Stop", 0), JustSayAndStop: new WordInfo("And Stop!", 0), SaySwitch: new WordInfo("Switch", 0), SayWatch: new WordInfo("Watch", 0), SayListen: new WordInfo("Listen", 0), Count1: new WordInfo("1", 0), Count2: new WordInfo("2", 0), Count3: new WordInfo("3", 0), Count4: new WordInfo("4", 0), Count5: new WordInfo("5", 0), Count6: new WordInfo("6", 0), Count7: new WordInfo("7", 0), Count8: new WordInfo("8", 0), Count9: new WordInfo("9", 0), Count10: new WordInfo("10", 0), SayReadyGetSetGo: new WordInfo("Ready, Get, Set, Go!", 4), JustSayReady: new WordInfo("Ready", 0) }; var EventInfos = { AddClassicBeat: new EventInfo(Tab.Rows), AddFreeTimeBeat: new EventInfo(Tab.Rows), AddOneshotBeat: new EventInfo(Tab.Rows), AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), BassDrop: new EventInfo(Tab.Actions), Blend: new EventInfo(Tab.Decorations), CallCustomMethod: new EventInfo(Tab.Actions), ChangeCharacter: new EventInfo(Tab.Actions), ChangePlayersRows: new EventInfo(Tab.Actions), Comment: new EventInfo(Tab.Unknown), CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent), FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), FinishLevel: new EventInfo(Tab.Actions), Flash: new EventInfo(Tab.Actions), FlipScreen: new EventInfo(Tab.Actions), FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), ForwardDecorationEvent: new EventInfo(Tab.Decorations), ForwardEvent: new EventInfo(Tab.Unknown), ForwardRowEvent: new EventInfo(Tab.Rows), HideRow: new EventInfo(Tab.Actions), HideWindow: new EventInfo(Tab.Windows), InvertColors: new EventInfo(Tab.Actions), MacroEvent: new EventInfo(Tab.Unknown), MaskRoom: new EventInfo(Tab.Rooms), Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), MoveRow: new EventInfo(Tab.Rows, EventAttriblte.DurationEvent), NarrateRowInfo: new EventInfo(Tab.Sounds), NewWindowDance: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), PaintHands: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), PlayAnimation: new EventInfo(Tab.Decorations), PlayExpression: new EventInfo(Tab.Actions), PlaySong: new EventInfo(Tab.Sounds), PlaySound: new EventInfo(Tab.Sounds), PulseCamera: new EventInfo(Tab.Actions), PulseFreeTimeBeat: new EventInfo(Tab.Rows), ReadNarration: new EventInfo(Tab.Sounds), RenameWindow: new EventInfo(Tab.Windows), ReorderRooms: new EventInfo(Tab.Rooms), ReorderRow: new EventInfo(Tab.Rows), ReorderSprite: new EventInfo(Tab.Decorations), ReorderWindows: new EventInfo(Tab.Windows), SayReadyGetSetGo: new EventInfo(Tab.Sounds), SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), SetBeatSound: new EventInfo(Tab.Sounds), SetBeatsPerMinute: new EventInfo(Tab.Sounds), SetClapSounds: new EventInfo(Tab.Sounds), SetCountingSound: new EventInfo(Tab.Sounds), SetCrotchetsPerBar: new EventInfo(Tab.Sounds), SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), SetGameSound: new EventInfo(Tab.Sounds), SetHandOwner: new EventInfo(Tab.Actions), SetHeartExplodeInterval: new EventInfo(Tab.Sounds), SetHeartExplodeVolume: new EventInfo(Tab.Sounds), SetMainWindow: new EventInfo(Tab.Windows), SetOneshotWave: new EventInfo(Tab.Rows), SetPlayStyle: new EventInfo(Tab.Actions), SetRoomContentMode: new EventInfo(Tab.Rooms), SetRoomPerspective: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), SetRowXs: new EventInfo(Tab.Rows), SetSpeed: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), SetTheme: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), SetVFXPreset: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), SetVisible: new EventInfo(Tab.Decorations), SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent), ShakeScreen: new EventInfo(Tab.Actions), ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), ShowDialogue: new EventInfo(Tab.Actions), ShowHands: new EventInfo(Tab.Actions), ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent), ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), ShowSubdivisionsRows: new EventInfo(Tab.Actions), SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), Stutter: new EventInfo(Tab.Actions), TagAction: new EventInfo(Tab.Actions), TextExplosion: new EventInfo(Tab.Actions), Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent), TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent), WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent) }; // RhythmBase.View/Extensions.ts var PatchStyle = /* @__PURE__ */ function(PatchStyle2) { PatchStyle2[PatchStyle2["Repeat"] = 0] = "Repeat"; PatchStyle2[PatchStyle2["Strentch"] = 1] = "Strentch"; return PatchStyle2; }(PatchStyle || {}); var IconStyle = class { Enabled; Active = false; Hover = false; Scale = 2; }; var Extensions = class { static lineHeight = 6; static charHeight = 8; static iconSize = 14; static evtag = "event_tag"; static evbarea = "event_beat_area"; static asm = new AssetManager("./rdviewAssets"); constructor() { AssetManager.initialize(); } static DrawSlice(canvas, src, dest, scale = 1, style = PatchStyle.Strentch, color) { const ctx = canvas; if (!ctx) return; if (!AssetManager.slices.has(src)) { return; } const info = AssetManager.slices.get(src); if (dest instanceof Point) { const destRect = new Rect(dest.x - info.pivot.x * scale, dest.y - info.pivot.y * scale, info.bounds.width * scale, info.bounds.height * scale); if (color) { if (color.alpha === 0) { return destRect; } this.drawSliceWithColor(ctx, info, destRect, color); } else { this.drawSliceNormal(ctx, info, destRect); } return destRect; } else { if (info.isNinePatch) { this.DrawNinePatch(canvas, info, dest, color, scale, style); } else { if (color) { this.drawSliceWithColor(ctx, info, dest, color); } else { this.drawSliceNormal(ctx, info, dest); } } } } static drawSliceNormal(ctx, info, destRect) { const bitmap = AssetManager.assetFile; if (!bitmap) return; ctx.imageSmoothingEnabled = false; ctx.drawImage(bitmap, info.bounds.x, info.bounds.y, info.bounds.width, info.bounds.height, destRect.x, destRect.y, destRect.width, destRect.height); } static drawSliceWithColor(ctx, info, destRect, color) { const bitmap = AssetManager.assetFile; if (!bitmap) return; if (color.alpha === 0) { return; } const tr = color.red / 255; const tg = color.green / 255; const tb = color.blue / 255; const ta = color.alpha / 255; ctx.save(); const tempCanvas = typeof document !== "undefined" ? document.createElement("canvas") : {}; tempCanvas.width = info.bounds.width; tempCanvas.height = info.bounds.height; const tempCtx = tempCanvas.getContext("2d"); tempCtx.imageSmoothingEnabled = false; tempCtx.drawImage(bitmap, info.bounds.x, info.bounds.y, info.bounds.width, info.bounds.height, 0, 0, info.bounds.width, info.bounds.height); const imageData = tempCtx.getImageData(0, 0, info.bounds.width, info.bounds.height); const data = imageData.data; for (let i = 0; i < data.length; i += 4) { const originalAlpha = data[i + 3]; const gray = data[i] * 0.2126 + data[i + 1] * 0.7152 + data[i + 2] * 0.0722; data[i] = gray * tr; data[i + 1] = gray * tg; data[i + 2] = gray * tb; data[i + 3] = originalAlpha * ta; } tempCtx.putImageData(imageData, 0, 0); ctx.imageSmoothingEnabled = false; ctx.globalAlpha = 1; ctx.drawImage(tempCanvas, 0, 0, info.bounds.width, info.bounds.height, destRect.x, destRect.y, destRect.width, destRect.height); ctx.restore(); } static DrawNinePatch(canvas, info, dest, color, scale = 1, style = PatchStyle.Strentch) { const ctx = canvas; if (!ctx) return; const bitmap = AssetManager.assetFile; if (!bitmap) return; const srcBounds = info.bounds; const destRect = dest; const centerBounds = info.center; const sx0 = srcBounds.left; const sx3 = srcBounds.right; const sy0 = srcBounds.top; const sy3 = srcBounds.bottom; const sx1 = sx0 + centerBounds.left; const sx2 = sx0 + centerBounds.right; const sy1 = sy0 + centerBounds.top; const sy2 = sy0 + centerBounds.bottom; const swLeft = sx1 - sx0; const swCenter = sx2 - sx1; const swRight = sx3 - sx2; const shTop = sy1 - sy0; const shCenter = sy2 - sy1; const shBottom = sy3 - sy2; const dwLeft = swLeft * scale; let dwRight = swRight * scale; let dwCenter = destRect.width - dwLeft - dwRight; if (dwCenter < 0) { const scaleX = destRect.width / Math.max(1, swLeft + swRight); dwRight = Math.max(0, destRect.width - Math.round(swLeft * scaleX)); dwCenter = 0; } const dhTop = shTop * scale; let dhBottom = shBottom * scale; let dhCenter = destRect.height - dhTop - dhBottom; if (dhCenter < 0) { const scaleY = destRect.height / Math.max(1, shTop + shBottom); dhBottom = Math.max(0, destRect.height - Math.round(shTop * scaleY)); dhCenter = 0; } const srcXs = [ sx0, sx1, sx2, sx3 ]; const srcYs = [ sy0, sy1, sy2, sy3 ]; const dx0 = destRect.left; const dx1 = dx0 + dwLeft; const dx2 = dx1 + dwCenter; const dx3 = destRect.right; const dy0 = destRect.top; const dy1 = dy0 + dhTop; const dy2 = dy1 + dhCenter; const dy3 = destRect.bottom; const dstXs = [ dx0, dx1, dx2, dx3 ]; const dstYs = [ dy0, dy1, dy2, dy3 ]; for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { const sLeft = srcXs[col]; const sTop = srcYs[row]; const sRight = srcXs[col + 1]; const sBottom = srcYs[row + 1]; const sW = sRight - sLeft; const sH = sBottom - sTop; if (sW <= 0 || sH <= 0) continue; const dLeft = dstXs[col]; const dTop = dstYs[row]; const dRight = dstXs[col + 1]; const dBottom = dstYs[row + 1]; const dW = dRight - dLeft; const dH = dBottom - dTop; if (dW <= 0 || dH <= 0) continue; if (style === PatchStyle.Repeat) { for (let y = dTop; y < dBottom; y += sH * scale) { const th = Math.min(sH, (dBottom - y) / scale); for (let x = dLeft; x < dRight; x += sW * scale) { const tw = Math.min(sW, (dRight - x) / scale); var sRect = new Rect(sLeft, sTop, tw, th); var dRect = new Rect(x, y, tw * scale, th * scale); if (color && color.alpha > 0) { this.drawSliceWithColor(ctx, { bounds: sRect, pivot: new Point(0, 0), isNinePatch: false, center: new Rect(), scale: 1 }, dRect, color); } else { this.drawSliceNormal(ctx, { bounds: sRect, pivot: new Point(0, 0), isNinePatch: false, center: new Rect(), scale: 1 }, dRect); } } } } else { if (color && color.alpha > 0) { this.drawSliceWithColor(ctx, { bounds: new Rect(sLeft, sTop, sW, sH), pivot: new Point(0, 0), isNinePatch: false, center: new Rect(), scale: 1 }, new Rect(dLeft, dTop, dW, dH), color); } else { ctx.imageSmoothingEnabled = false; ctx.drawImage(bitmap, sLeft, sTop, sW, sH, dLeft, dTop, dW, dH); } } } } } static MeasureRDFontText(canvas, text, scale = 1) { let len = 0; for (let i = 0; i < text.length; i++) { const c = text.charAt(i); if (c === "\n") { len = 0; } else { const info = AssetManager.slices.get(`char_${c.charCodeAt(0).toString(16).padStart(4, "0")}`); if (info) { len += info.bounds.width * scale; } } } return len; } static DrawRDFontText(canvas, text, dest, color, scale = 1) { const start = dest.clone(); const result = new Rect(); start.y -= this.lineHeight * scale; for (let i = 0; i < text.length; i++) { const c = text.charAt(i); if (c === "\n") { start.x = dest.x; start.y += this.lineHeight * scale; continue; } else { const charcode = c.charCodeAt(0).toString(16).padStart(4, "0"); const area = this.DrawSlice(canvas, `char_${charcode}`, start, scale, PatchStyle.Strentch, color); result.union(area); start.x += area.width * scale; } } return result; } static DrawEventIcon(canvas, evt, dest, style) { let destRect = new Rect(); const key = `event_${evt.type}`; const evttype = evt.type; const info = AssetManager.slices.get(key) ?? AssetManager.slices.get("event_Unknown") ?? (() => { throw new Error("information not found."); }); if (!(info instanceof SliceInfo)) { return new Rect(); } const pulse = "event_beat_pulse"; const hit = "event_beat_hit"; const hitf = "event_beat_hit_freeze"; const hitb = "event_beat_hit_burn"; const beatcross = "event_beat_cross"; const beatx = "event_beat_x"; const beatsynco = "event_beat_synco"; const beatline = "event_beat_line"; const beatcolor = new Color(4284539717); const evtInfo = EventInfos[evt.type]; evt.tab = evt.tab ?? evtInfo.defaultTab; switch (evt.type) { case EventType.AddClassicBeat: { const tick = evt.tick ?? 1; const swing = evt.swing === 0 ? 1 : evt.swing; const hold = evt.hold ?? 0; const syncoswing = evt.syncoSwing ?? 0; const syncobeat = evt.syncoBeat ?? -1; const classicbeatlength = evt.length ?? 7; destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale * (tick * (classicbeatlength - 1 - (syncoswing ?? 0))), this.iconSize * style.Scale); if (hold > 0) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, this.iconSize * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4291839731 : 4286462352)); } this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); if (style.Hover) { for (let i = 0; i < classicbeatlength - 1; i++) { this.DrawSlice(canvas, pulse, new Point(dest.x + this.iconSize * style.Scale * (tick * (i + i % 2 * (1 - (swing ?? 1)) - (i <= (syncobeat ?? -1) ? 0 : syncoswing ?? 0))), dest.y), style.Scale); } } this.DrawSlice(canvas, hit, new Point(dest.x + style.Scale * (this.iconSize * (tick * (classicbeatlength - 1 - (syncoswing ?? 0))) - 1), dest.y), style.Scale); } break; case EventType.AddFreeTimeBeat: { const hold = (evt.hold ?? 0) - info.bounds.width / this.iconSize; destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(beatcolor.clone(), style.Active, style.Enabled ?? evt.active ?? true), style); this.DrawRDFontText(canvas, ((evt.pulse ?? 0) + 1).toString(), new Point(dest.x + 1.5 * style.Scale, dest.y + 10 * style.Scale), new Color(4294967295), style.Scale); if ((evt.pulse ?? 0) == 6) { this.DrawSlice(canvas, hit, new Point(dest.x, dest.y), style.Scale); } if (hold > 0) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4284539717 : 4281299234)); } } break; case EventType.AddOneshotBeat: { const tick = evt.tick ?? 1; const interval = evt.interval ?? 1; const loop = Math.floor(evt.loops ?? 0); const subdiv = evt.subdivisions ?? 1; const freezeBurnMode = evt.freezeBurnMode ?? "Wave"; const delay = freezeBurnMode === "Freezeshot" ? evt.delay ?? 0 : 0; destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale * (loop * interval + tick + delay), this.iconSize * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); const subdivwidth = this.iconSize * style.Scale * (subdiv - 1) / subdiv * tick; if (subdiv > 1) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, subdivwidth, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(4279480353)); } if (evt.skipshot ?? false) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width + subdivwidth, dest.y, style.Scale * this.iconSize * interval - subdivwidth, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(4291115835)); } if (style.Hover) { for (let l = 0; l <= loop; l++) { for (let i = 0; i < subdiv; i++) { this.DrawSlice(canvas, pulse, new Point(dest.x + this.iconSize * style.Scale * (l * interval + i * tick / subdiv), dest.y), style.Scale); } } } for (let l = 0; l <= loop; l++) { for (let i = 0; i < subdiv; i++) { this.DrawSlice(canvas, hit, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1), dest.y), style.Scale); } } const off = interval - tick; if (freezeBurnMode !== "Wave") { let posx = dest.x - off * style.Scale * this.iconSize; this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale); switch (freezeBurnMode) { case "Freezeshot": posx += delay * style.Scale * this.iconSize; this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale); for (let l = 0; l <= loop; l++) { this.DrawSlice(canvas, hitf, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + tick) - 1), dest.y), style.Scale); } break; case "Burnshot": posx -= tick * style.Scale * this.iconSize; this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale); for (let l = 0; l <= loop; l++) { this.DrawSlice(canvas, hitb, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + tick) - 1), dest.y), style.Scale); } break; default: break; } } if (style.Active && style.Hover) { this.DrawSlice(canvas, "event_beat_loop", new Point(destRect.right, destRect.top), style.Scale); } } break; case EventType.Comment: { const commentColor = new Color(evt.color); console.log(evt.color, commentColor); destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(commentColor, style.Active, style.Enabled ?? evt.active ?? true), style); this.DrawSlice(canvas, key, dest, style.Scale); } break; case EventType.DesktopColor: { destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * 4 * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); const endColor = new Color(evt.endColor); this.DrawSlice(canvas, `${key}_0`, new Point(dest.x, dest.y + info.bounds.height * style.Scale), style.Scale, PatchStyle.Strentch, endColor); this.DrawSlice(canvas, key, new Point(dest.x, dest.y + info.bounds.height * style.Scale), style.Scale); } break; case EventType.PulseFreeTimeBeat: { const hold = (evt.hold ?? 0) - info.bounds.width / this.iconSize; destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(beatcolor.clone(), style.Active, style.Enabled ?? evt.active ?? true), style); let actionText; switch (evt.action) { case "Increment": actionText = ">"; break; case "Decrement": actionText = "<"; break; case "Remove": actionText = "x"; break; case "Custom": default: actionText = ((evt.customPulse ?? 0) + 1).toString(); break; } this.DrawRDFontText(canvas, actionText, new Point(dest.x + 1.5 * style.Scale, dest.y + 8 * style.Scale), new Color(4294967295), style.Scale); if (evt.action === "Custom" && (evt.customPulse ?? 0) === 7) { this.DrawSlice(canvas, hit, new Rect(dest.x - 2 * style.Scale, dest.y, 5 * style.Scale, info.bounds.height * style.Scale), style.Scale, PatchStyle.Strentch); } if (hold > 0) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4291839731 : 4286462352)); } } break; case EventType.ReorderRooms: { destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); let currentDest = dest.clone(); if (evt.order && Array.isArray(evt.order)) { for (const r of evt.order) { this.DrawSlice(canvas, `${key}_${r}`, currentDest.clone(), style.Scale); currentDest.y += this.iconSize * style.Scale; } } } break; case EventType.ReorderWindows: { destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); let currentDest = dest.clone(); if (evt.order && Array.isArray(evt.order)) { for (const r of evt.order) { this.DrawSlice(canvas, `${key}_${r}`, currentDest.clone(), style.Scale); currentDest.y += this.iconSize * style.Scale; } } } break; case EventType.SayReadyGetSetGo: { const wordInfo = WordInfos[evt.phraseToSay]; const len = wordInfo.length * evt.tick + 1; destRect = new Rect(dest.x, dest.y, len * this.iconSize * style.Scale, this.iconSize * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); const stringToJion = wordInfo.phrase.split(" "); let stringToDraw = [ stringToJion[0] ]; let lw = this.MeasureRDFontText(canvas, stringToJion[0]); const sw = this.MeasureRDFontText(canvas, " "); for (let i = 1; i < stringToJion.length; i++) { const part = stringToJion[i]; const w = this.MeasureRDFontText(canvas, part); if (lw + sw + w > (len * this.iconSize - 2) * style.Scale) { lw = w; stringToDraw.push(part); } else { lw += sw + w; stringToDraw[stringToDraw.length - 1] += " " + part; } } stringToDraw.splice(3); const c = stringToDraw.length; const top = dest.y + (this.iconSize - this.charHeight * c / 2) * style.Scale / 2; for (let i = 0; i < c; i++) { const line = stringToDraw[i]; const p = new Point(dest.x + (len * this.iconSize * style.Scale - this.MeasureRDFontText(canvas, line, style.Scale / 2)) / 2, top + (i * this.charHeight + this.lineHeight) * style.Scale / 2); this.DrawRDFontText(canvas, line, p, new Color(4294967295), style.Scale / 2); } } break; case EventType.SetRowXs: { destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); const width = info.bounds.width * style.Scale / 6; const beatxInfo = AssetManager.slices.get(beatx); if (!beatxInfo) break; const iconwidth = beatxInfo.bounds.width; const s = width / iconwidth; let left = 0; const top = this.iconSize * style.Scale / 2 - beatxInfo.bounds.height * s / 2; if (evt.pattern) { const pattern = evt.pattern; for (const p of pattern) { const patternKey = p === "x" ? beatx : beatline; this.DrawSlice(canvas, patternKey, new Rect(dest.x + left, dest.y + top, width, beatxInfo.bounds.height * s), style.Scale, PatchStyle.Strentch); left += width; } } if ((evt.syncoBeat ?? -1) >= 0) { this.DrawSlice(canvas, beatsynco, new Rect(dest.x + width * (evt.syncoBeat ?? 0), dest.y + top, width, beatxInfo.bounds.height * s), style.Scale, PatchStyle.Strentch); } } break; case EventType.ShowRooms: { destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); if (evt.rooms && Array.isArray(evt.rooms)) { for (let i = 0; i < 4; i++) { const roomState = evt.rooms[i] ? "1" : "0"; this.DrawSlice(canvas, `${key}_${roomState}`, new Point(dest.x, dest.y + i * this.iconSize * style.Scale), style.Scale / 2); } } } break; default: destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale); this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style); switch (evt.type) { case EventType.CustomFlash: { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.startColor ?? 0)); this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.endColor ?? 0)); } break; case EventType.FlipScreen: { let suffix = ""; const flipX = evt.flipX ?? false; const flipY = evt.flipY ?? false; if (flipX && flipY) { suffix = "_2"; } else if (flipX && !flipY) { suffix = "_1"; } else if (!flipX && flipY) { suffix = "_0"; } this.DrawSlice(canvas, key + suffix, dest, style.Scale); } break; case EventType.FloatingText: { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.color ?? 0)); this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.outlineColor ?? 0)); } break; case EventType.MoveRoom: { canvas.save(); const degree = evt.angle ?? 0; const scaleWidth = evt.scale?.width ?? 0; const scaleHeight = evt.scale?.height ?? 0; if (scaleWidth === 0 || scaleHeight === 0) { canvas.restore(); break; } const pleft = (evt.pivot?.x ?? 0) / 100; const ptop = 1 - (evt.pivot?.y ?? 0) / 100; const uniform = Math.sqrt(scaleWidth * scaleWidth + scaleHeight * scaleHeight); const w = scaleWidth / uniform; const h = scaleHeight / uniform; canvas.translate(dest.x + destRect.width / 2, dest.y + destRect.height / 2); canvas.rotate(-degree * Math.PI / 180); canvas.scale(w, h); this.DrawSlice(canvas, key, new Point(-destRect.width / 2, -destRect.height / 2), style.Scale); if (!(pleft < 0 || pleft > 1 || ptop < 0 || ptop > 1)) { canvas.fillStyle = "rgb(255, 0, 0)"; canvas.fillRect((pleft - 0.5) * destRect.width - 1, (ptop - 0.5) * destRect.height - 1, 2, 2); } canvas.restore(); } break; case EventType.PaintHands: { this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0)); const border = evt.border ?? "None"; if (border === "Outline") { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } else if (border === "Glow") { this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } } break; case EventType.SetBackgroundColor: { this.DrawSlice(canvas, key, dest, style.Scale); const bgType = evt.backgroundType ?? "Color"; if (bgType === "Color") { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.color ?? 0)); } else if (bgType === "Image") { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(4294967295)); } } break; case EventType.SetCrotchetsPerBar: { const cpb = evt.crotchetsPerBar ?? 4; this.DrawSlice(canvas, key, dest, style.Scale); this.DrawRDFontText(canvas, cpb > 9 ? "-" : cpb.toString(), new Point(dest.x + 2 * style.Scale, dest.y + 7 * style.Scale), new Color(4278190080), style.Scale); this.DrawRDFontText(canvas, "4", new Point(dest.x + 8 * style.Scale, dest.y + 12 * style.Scale), new Color(4278190080), style.Scale); } break; case EventType.SetForeground: { this.DrawSlice(canvas, key, dest, style.Scale); } break; case EventType.Tint: { this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0)); const border = evt.border ?? "None"; if (border === "Outline") { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } else if (border === "Glow") { this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } } break; case EventType.TintRows: { this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0)); const border = evt.border ?? "None"; if (border === "Outline") { this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } else if (border === "Glow") { this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0)); } } break; default: this.drawSliceNormal(canvas, info, destRect); break; } break; } if (evtInfo.isDurationEvent) { evt.duration = 2; } if (evt.duration && evt.duration > 0 && style.Active) { const duration = evt[evtInfo.durationKey]; const durWidth = style.Scale * this.iconSize * duration - destRect.width; const c = this.ColorOf(evt.tab); c.alpha = style.Active ? 192 : 91; if (durWidth > 0) { this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, durWidth, destRect.height), style.Scale, PatchStyle.Repeat, c); } } return destRect; } static ColorOf(tab) { switch (tab) { case "sounds": return new Color(4292355123); case "rows": return new Color(4281094105); case "actions": return new Color(4291118003); case "decorations": return new Color(4278240345); case "rooms": return new Color(4292392978); case "windows": return new Color(4283479511); default: return new Color(4286874756); } } static DrawBack(canvas, destRect, color, style) { const outline = "event_outline"; const back = "event_back"; this.DrawSlice(canvas, outline, destRect, style.Scale, PatchStyle.Strentch, new Color(style.Active ? 4294967295 : 4289243304)); destRect.inflate(-style.Scale, -style.Scale); this.DrawSlice(canvas, back, destRect, style.Scale, PatchStyle.Strentch, color); } static WithState(color, active, enabled) { const c = enabled ? color.clone() : new Color(4286874756); c.alpha = active ? 192 : 91; return c; } }; export { AssetManager, Color, Extensions, IconStyle, Paint, Point, Rect, SliceInfo };