mirror of
https://gitgud.io/BondageProjects/Bondage-College.git
synced 2025-04-25 17:59:34 +00:00
ENH: Convert the SavedExpressions
panel to DOM
This commit is contained in:
parent
109e72eea2
commit
2f7c1717bf
2 changed files with 282 additions and 109 deletions
BondageClub
|
@ -352,22 +352,40 @@
|
|||
}
|
||||
|
||||
#dialog-expression {
|
||||
width: fit-content;
|
||||
grid-template:
|
||||
"dialog-menubar dialog-menubar" var(--menu-button-size)
|
||||
"dialog-status dialog-status" min-content
|
||||
"dialog-left-menu dialog-grid" auto / var(--menu-button-size) min-content;
|
||||
}
|
||||
|
||||
#dialog-expression,
|
||||
#dialog-pose,
|
||||
#dialog-expression-preset {
|
||||
gap: 0 var(--gap);
|
||||
}
|
||||
|
||||
#dialog-pose > .dialog-grid,
|
||||
#dialog-expression-preset > .dialog-grid {
|
||||
width: min-content;
|
||||
padding-right: var(--scrollbar-gutter);
|
||||
}
|
||||
|
||||
#dialog-expression > .dialog-status,
|
||||
#dialog-pose > .dialog-status,
|
||||
#dialog-expression-preset > .dialog-status {
|
||||
padding-bottom: var(--gap);
|
||||
}
|
||||
|
||||
#dialog-expression-menubar,
|
||||
#dialog-pose-menubar {
|
||||
#dialog-pose-menubar,
|
||||
#dialog-expression-preset-menubar {
|
||||
min-width: calc(5 * var(--menu-button-size) + 2 * var(--gap));
|
||||
grid-area: dialog-menubar;
|
||||
display: grid;
|
||||
gap: calc(0.5 * var(--gap));
|
||||
direction: rtl;
|
||||
grid-auto-flow: column;
|
||||
grid-template-columns: repeat(3, var(--menu-button-size)) calc(var(--menu-button-size) + 0.5 * var(--gap)) repeat(auto-fill, var(--menu-button-size));
|
||||
grid-template-columns: repeat(3, var(--menu-button-size)) calc(3px + var(--menu-button-size) + 0.5 * var(--gap)) repeat(auto-fill, var(--menu-button-size));
|
||||
}
|
||||
|
||||
#dialog-expression-menu-left {
|
||||
|
@ -416,6 +434,64 @@
|
|||
gap: calc(0.5 * var(--gap));
|
||||
}
|
||||
|
||||
#dialog-expression-preset {
|
||||
width: fit-content;
|
||||
grid-template:
|
||||
"dialog-menubar dialog-menubar" var(--menu-button-size)
|
||||
"dialog-status dialog-status" min-content
|
||||
"dialog-grid dialog-grid" auto / var(--menu-button-size) min-content;
|
||||
}
|
||||
|
||||
#dialog-expression-preset-button-grid {
|
||||
display: block;
|
||||
padding: 3px;
|
||||
margin: unset;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot {
|
||||
--bob: min(8dvh, 4dvw);
|
||||
display: grid;
|
||||
gap: calc(var(--gap) / 2);
|
||||
grid-template:
|
||||
"canvas save-button" 50%
|
||||
"canvas load-button" 50% / calc(2 * var(--menu-button-size) + var(--gap)) min-content;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot button {
|
||||
height: var(--bob);
|
||||
width: calc(2 * var(--menu-button-size) + 0.5 * var(--gap));
|
||||
justify-self: start;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot button[name="save"] {
|
||||
grid-area: save-button;
|
||||
margin-top: calc(var(--gap) / 4);
|
||||
align-self: self-end;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot button[name="load"] {
|
||||
grid-area: load-button;
|
||||
margin-bottom: calc(var(--gap) / 4);
|
||||
align-self: self-start;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot:first-child button {
|
||||
margin-top: unset;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot:last-child button {
|
||||
margin-bottom: unset;
|
||||
}
|
||||
|
||||
.dialog-expression-preset-slot canvas {
|
||||
grid-area: canvas;
|
||||
max-height: calc(2 * var(--bob) + var(--gap) / 2);
|
||||
max-width: calc(2 * var(--bob) + var(--gap) / 2);
|
||||
min-height: min(20dvh, 10dvw, 200px) !important;
|
||||
min-width: min(20dvh, 10dvw, 200px) !important;
|
||||
position: static;
|
||||
}
|
||||
|
||||
@supports(height: 100dvh) {
|
||||
.dialog-root {
|
||||
--menu-button-size: min(9dvh, 4.5dvw);
|
||||
|
|
|
@ -93,11 +93,7 @@ var DialogCraftingMenu = /** @type {never} */(false);
|
|||
*/
|
||||
var DialogExpressionPreviousMode = null;
|
||||
|
||||
/** @type {ExpressionItem[]} */
|
||||
var DialogFacialExpressions = [];
|
||||
var DialogFacialExpressionsSelectedBlindnessLevel = 2;
|
||||
/** @type {Character[]} */
|
||||
var DialogSavedExpressionPreviews = [];
|
||||
var DialogExtendedMessage = "";
|
||||
/**
|
||||
* The list of available activities for the selected group.
|
||||
|
@ -182,12 +178,6 @@ var DialogFavoriteStateDetails = [
|
|||
* @type {readonly DialogSelfMenuOptionType[]}
|
||||
*/
|
||||
var DialogSelfMenuOptions = [
|
||||
{
|
||||
Name: "SavedExpressions",
|
||||
IsAvailable: () => true,
|
||||
Draw: () => DialogDrawSavedExpressionsMenu(),
|
||||
Click: () => DialogClickSavedExpressionsMenu(),
|
||||
},
|
||||
{
|
||||
Name: "OwnerRules",
|
||||
IsAvailable: () => false,
|
||||
|
@ -788,6 +778,7 @@ function DialogLeave() {
|
|||
// Reset the mode, selected group & character, exiting the dialog
|
||||
DialogMenuMode = null;
|
||||
DialogSidePanelMapping.expression.Exit();
|
||||
DialogSidePanelMapping.expressionPreset.Exit();
|
||||
DialogSidePanelMapping.pose.Exit();
|
||||
Object.values(DialogMenuMapping).forEach(obj => obj.Exit());
|
||||
|
||||
|
@ -809,10 +800,6 @@ function DialogLeave() {
|
|||
|
||||
// Reset the state of the self menu
|
||||
DialogSelfMenuSelected = null;
|
||||
for (const preview of DialogSavedExpressionPreviews) {
|
||||
CharacterDelete(preview, false);
|
||||
}
|
||||
DialogSavedExpressionPreviews = [];
|
||||
|
||||
// Go controller, go!
|
||||
ControllerClearAreas();
|
||||
|
@ -1701,50 +1688,6 @@ function DialogInventoryStringified(C) {
|
|||
return (C.FocusGroup ? C.FocusGroup.Name : "") + (DialogInventory ? JSON.stringify(DialogInventory.map(I => I.Asset.Name).sort()) : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the initial state of the selection available in the facial expressions menu
|
||||
* @returns {void} - Nothing
|
||||
*/
|
||||
function DialogFacialExpressionsBuild() {
|
||||
DialogFacialExpressions = [];
|
||||
for (let I = 0; I < Player.Appearance.length; I++) {
|
||||
const PA = Player.Appearance[I];
|
||||
const ExpressionList = [...(PA.Asset.Group.AllowExpression || [])];
|
||||
if (!ExpressionList.length || PA.Asset.Group.Name == "Eyes2") continue;
|
||||
// Make sure the default expression always appear
|
||||
if (!ExpressionList.includes(null)) ExpressionList.unshift(null);
|
||||
// If there are no allowed expression, skip the group entirely
|
||||
if (!ExpressionList.some(expr => CharacterIsExpressionAllowed(Player, PA, expr))) continue;
|
||||
/** @type {ExpressionItem} */
|
||||
const Item = {
|
||||
Appearance: PA,
|
||||
Group: /** @type {ExpressionGroupName} */(PA.Asset.Group.Name),
|
||||
CurrentExpression: (PA.Property == null) ? null : PA.Property.Expression,
|
||||
ExpressionList: ExpressionList,
|
||||
};
|
||||
DialogFacialExpressions.push(Item);
|
||||
}
|
||||
// Temporary (?) solution to make the facial elements appear in a more logical order, as their alphabetical order currently happens to match up
|
||||
DialogFacialExpressions = DialogFacialExpressions.sort(function (a, b) {
|
||||
return a.Appearance.Asset.Group.Name < b.Appearance.Asset.Group.Name ? -1 : a.Appearance.Asset.Group.Name > b.Appearance.Asset.Group.Name ? 1 : 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the expressions to a slot
|
||||
* @param {number} Slot - Index of saved expression (0 to 4)
|
||||
*/
|
||||
function DialogFacialExpressionsSave(Slot) {
|
||||
Player.SavedExpressions[Slot] = [];
|
||||
for (let x = 0; x < DialogFacialExpressions.length; x++) {
|
||||
Player.SavedExpressions[Slot].push({ Group: DialogFacialExpressions[x].Group, CurrentExpression: DialogFacialExpressions[x].CurrentExpression });
|
||||
}
|
||||
if (Player.SavedExpressions[Slot].every(expression => !expression.CurrentExpression))
|
||||
Player.SavedExpressions[Slot] = null;
|
||||
ServerAccountUpdate.QueueData({ SavedExpressions: Player.SavedExpressions });
|
||||
DialogBuildSavedExpressionsMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads expressions from a slot
|
||||
* @param {number} Slot - Index of saved expression (0 to 4)
|
||||
|
@ -1753,20 +1696,19 @@ function DialogFacialExpressionsLoad(Slot) {
|
|||
const expressions = Player.SavedExpressions && Player.SavedExpressions[Slot];
|
||||
if (expressions != null) {
|
||||
expressions.forEach(e => CharacterSetFacialExpression(Player, e.Group, e.CurrentExpression));
|
||||
DialogFacialExpressionsBuild();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the savedexpressions menu previews.
|
||||
* @returns {void} - Nothing
|
||||
* @returns {(null | Character)[]} - Nothing
|
||||
*/
|
||||
function DialogBuildSavedExpressionsMenu() {
|
||||
const ExcludedGroups = ["Mask"];
|
||||
const AppearanceItems = Player.Appearance.filter(A => A.Asset.Group.Category === "Appearance" && !ExcludedGroups.includes(A.Asset.Group.Name));
|
||||
const BaseAppearance = AppearanceItems.filter(A => !A.Asset.Group.AllowExpression);
|
||||
const ExpressionGroups = AppearanceItems.filter(A => A.Asset.Group.AllowExpression);
|
||||
Player.SavedExpressions.forEach((expression, i) => {
|
||||
return Player.SavedExpressions.map((expression, i) => {
|
||||
if (expression) {
|
||||
const PreviewCharacter = CharacterLoadSimple("SavedExpressionPreview-" + i);
|
||||
PreviewCharacter.Appearance = BaseAppearance.slice();
|
||||
|
@ -1783,54 +1725,13 @@ function DialogBuildSavedExpressionsMenu() {
|
|||
}
|
||||
CharacterRefresh(PreviewCharacter);
|
||||
|
||||
DialogSavedExpressionPreviews[i] = PreviewCharacter;
|
||||
return PreviewCharacter;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the savedexpressions menu
|
||||
* @returns {void} - Nothing
|
||||
*/
|
||||
function DialogDrawSavedExpressionsMenu() {
|
||||
DrawText(InterfaceTextGet("SavedExpressions"), 210, 90, "White", "Black");
|
||||
|
||||
if ((!DialogSavedExpressionPreviews || !DialogSavedExpressionPreviews.length) && Player.SavedExpressions.some(expression => expression != null))
|
||||
DialogBuildSavedExpressionsMenu();
|
||||
|
||||
for (let x = 0; x < 5; x++) {
|
||||
if (Player.SavedExpressions[x] == null) {
|
||||
DrawText(InterfaceTextGet("SavedExpressionsEmpty"), 160, 216 + (x * 170), "White", "Black");
|
||||
} else {
|
||||
const PreviewCanvas = DrawCharacterSegment(DialogSavedExpressionPreviews[x], 100, 30, 300, 220);
|
||||
MainCanvas.drawImage(PreviewCanvas, 20, 92 + (x * 175), 260, 190);
|
||||
}
|
||||
|
||||
DrawButton(290, 160 + (x * 170), 120, 50, InterfaceTextGet("SavedExpressionsSave"), "White");
|
||||
DrawButton(290, 220 + (x * 170), 120, 50, InterfaceTextGet("SavedExpressionsLoad"), "White");
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles clicks in the savedexpressions menu
|
||||
* @returns {void} - Nothing
|
||||
*/
|
||||
function DialogClickSavedExpressionsMenu() {
|
||||
if (MouseXIn(290, 120)) {
|
||||
for (let x = 0; x < 5; x++) {
|
||||
if (MouseYIn(160 + (x * 170), 50)) {
|
||||
DialogFacialExpressionsSave(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MouseXIn(290, 120)) {
|
||||
for (let x = 0; x < 5; x++) {
|
||||
if (MouseYIn(220 + (x * 170), 50)) {
|
||||
DialogFacialExpressionsLoad(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the Click events in the Dialog Screen
|
||||
* @returns {boolean} - Whether a button was clicked
|
||||
|
@ -2392,6 +2293,7 @@ function DialogResize(load) {
|
|||
|
||||
DialogSidePanelMapping.expression.Resize(load);
|
||||
DialogSidePanelMapping.pose.Resize(load);
|
||||
DialogSidePanelMapping.expressionPreset.Resize(load);
|
||||
DialogMenuMapping[DialogMenuMode]?.Resize(load);
|
||||
}
|
||||
|
||||
|
@ -4784,7 +4686,7 @@ class _DialogPoseMenu extends DialogMenu {
|
|||
/** @type {(this: HTMLButtonElement, ev: MouseEvent) => void} */
|
||||
nextPageClick: function(ev) {
|
||||
const prev = document.getElementById(dialogMenu.ids.root);
|
||||
const next = document.getElementById(DialogSidePanelMapping.expression.ids.root);
|
||||
const next = document.getElementById(DialogSidePanelMapping.expressionPreset.ids.root);
|
||||
prev?.toggleAttribute("data-unload", true);
|
||||
next?.toggleAttribute("data-unload", false);
|
||||
},
|
||||
|
@ -4975,6 +4877,198 @@ class _DialogPoseMenu extends DialogMenu {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template {string} ModeType
|
||||
* @extends {DialogMenu<ModeType, number, { C: Character }>}
|
||||
*/
|
||||
class _DialogExpressionSaveMenu extends DialogMenu {
|
||||
ids = Object.freeze({
|
||||
root: "dialog-expression-preset",
|
||||
status: "dialog-expression-preset-status",
|
||||
menubar: "dialog-expression-preset-menubar",
|
||||
grid: "dialog-expression-preset-button-grid",
|
||||
});
|
||||
|
||||
defaultShape = Object.freeze(/** @type {const} */([15, 15, 500, 940]));
|
||||
|
||||
_initPropertyNames = /** @type {const} */(["C"]);
|
||||
|
||||
/** @type {DialogMenu<ModeType, number>["clickStatusCallbacks"]} */
|
||||
clickStatusCallbacks = {
|
||||
};
|
||||
|
||||
/**
|
||||
* See {@link expressionPreviews}
|
||||
* @private
|
||||
* @type {null | (null | Character)[]}
|
||||
*/
|
||||
_expressionPreviews = null;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @type {readonly (null | Character)[]}
|
||||
*/
|
||||
get expressionPreviews() {
|
||||
if (this._expressionPreviews == null) {
|
||||
return this._expressionPreviews = DialogBuildSavedExpressionsMenu();
|
||||
} else {
|
||||
return this._expressionPreviews;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ModeType} mode The name of the mode associated with this instance
|
||||
*/
|
||||
constructor(mode) {
|
||||
super(mode);
|
||||
const dialogMenu = this;
|
||||
this.eventListeners = {
|
||||
...this.eventListeners,
|
||||
|
||||
/** @type {(this: HTMLButtonElement, ev: MouseEvent) => void} */
|
||||
nextPageClick: function(ev) {
|
||||
const prev = document.getElementById(dialogMenu.ids.root);
|
||||
const next = document.getElementById(DialogSidePanelMapping.expression.ids.root);
|
||||
prev?.toggleAttribute("data-unload", true);
|
||||
next?.toggleAttribute("data-unload", false);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Draw() {
|
||||
const root = document.getElementById(this.ids.root);
|
||||
if (!root || root.hasAttribute("data-unload")) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [i, preview] of this.expressionPreviews.entries()) {
|
||||
const canvas = /** @type {null | HTMLCanvasElement} */(root.querySelector(`li[data-index="${i}"] > canvas`))?.getContext("2d");
|
||||
if (!canvas) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preview != null) {
|
||||
const canvasSegment = DrawCharacterSegment(preview, 150, 30, 200, 200);
|
||||
canvas.drawImage(canvasSegment, 0, 0, 200, 200);
|
||||
} else {
|
||||
canvas.clearRect(0, 0, 200, 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Exit() {
|
||||
super.Exit();
|
||||
for (const C of this.expressionPreviews) {
|
||||
CharacterDelete(C, false);
|
||||
}
|
||||
}
|
||||
|
||||
_Load() {
|
||||
const ids = this.ids;
|
||||
return document.getElementById(ids.root) ?? ElementCreate({
|
||||
tag: "div",
|
||||
attributes: { id: ids.root, "aria-labelledby": ids.status },
|
||||
parent: document.body,
|
||||
classList: ["dialog-root"],
|
||||
children: [
|
||||
{
|
||||
tag: "span",
|
||||
attributes: { id: ids.status },
|
||||
classList: ["dialog-status", "scroll-box"],
|
||||
},
|
||||
ElementMenu.Create(
|
||||
ids.menubar,
|
||||
[
|
||||
ElementButton.Create(
|
||||
`${ids.menubar}-next`,
|
||||
this.eventListeners.nextPageClick,
|
||||
{ tooltip: InterfaceTextGet("NextPage"), tooltipPosition: "right", image: "Icons/Next.png" },
|
||||
{ button: { attributes: { name: "next" }, classList: ["dialog-menubar-button"] } },
|
||||
),
|
||||
],
|
||||
{ direction: "rtl" },
|
||||
),
|
||||
{
|
||||
tag: "menu",
|
||||
attributes: { id: ids.grid },
|
||||
classList: ["dialog-grid", "scroll-box"],
|
||||
children: [0, 1, 2, 3, 4].map(i => {
|
||||
return {
|
||||
tag: "li",
|
||||
dataAttributes: { index: i },
|
||||
classList: ["dialog-expression-preset-slot"],
|
||||
children: [
|
||||
{ tag: "canvas", attributes: { width: 200, height: 200 } },
|
||||
ElementButton.Create(
|
||||
`${ids.grid}-${i}-save`,
|
||||
this.eventListeners._ClickButton,
|
||||
{ clickDisabled: this.eventListeners._ClickDisabledButton, label: "Save", labelPosition: "center" },
|
||||
{ button: {
|
||||
attributes: { name: "save" },
|
||||
}},
|
||||
),
|
||||
ElementButton.Create(
|
||||
`${ids.grid}-${i}-load`,
|
||||
this.eventListeners._ClickButton,
|
||||
{ clickDisabled: this.eventListeners._ClickDisabledButton, label: "Load", labelPosition: "center" },
|
||||
{ button: {
|
||||
attributes: { name: "load" },
|
||||
}}
|
||||
),
|
||||
],
|
||||
};
|
||||
}),
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/** @type {DialogMenu["_ReloadStatus"]} */
|
||||
_ReloadStatus(root, span, parameters, options) {
|
||||
const textContent = options.status ?? InterfaceTextGet("SavedExpressions");
|
||||
DialogSetStatus(textContent, options.statusTimer ?? 0, null, this.ids.status);
|
||||
}
|
||||
|
||||
/** @type {DialogMenu["_ReloadButtonGrid"]} */
|
||||
_ReloadButtonGrid(root, buttonGrid, parameters, options) {
|
||||
this._expressionPreviews = DialogBuildSavedExpressionsMenu();
|
||||
}
|
||||
|
||||
/** @type {DialogMenu["_ReloadIcon"]} */
|
||||
_ReloadIcon(root, icon, parameters, options) { /** noop */ }
|
||||
|
||||
/** @type {DialogMenu["_ReloadMenubar"]} */
|
||||
_ReloadMenubar(root, menubar, parameters, options) { /** noop */ }
|
||||
|
||||
/** @type {DialogMenu<string, number>["_GetClickedObject"]} */
|
||||
_GetClickedObject(button) {
|
||||
const slot = Number.parseInt(button.closest("li")?.getAttribute("data-index"), 10);
|
||||
console.log(slot);
|
||||
return Number.isNaN(slot) ? null : slot;
|
||||
}
|
||||
|
||||
/** @type {DialogMenu<string, number>["_ClickButton"]} */
|
||||
_ClickButton(button, C, expressionSlot) {
|
||||
switch (button.name) {
|
||||
case "save": {
|
||||
const expressions = C.Appearance.filter(item => item.Asset.Group.AllowExpression).map(item => {
|
||||
return {
|
||||
Group: item.Asset.Group.Name,
|
||||
CurrentExpression: item.Property?.Expression,
|
||||
};
|
||||
});
|
||||
Player.SavedExpressions[expressionSlot] = expressions.every(i => i.CurrentExpression == null) ? null : expressions;
|
||||
ServerAccountUpdate.QueueData({ SavedExpressions: Player.SavedExpressions });
|
||||
this._expressionPreviews = DialogBuildSavedExpressionsMenu();
|
||||
break;
|
||||
}
|
||||
case "load":
|
||||
DialogFacialExpressionsLoad(expressionSlot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @satisfies {Partial<Record<DialogMenuMode, DialogMenu<DialogMenuMode>>>} */
|
||||
var DialogMenuMapping = /** @type {const} */({
|
||||
activities: new _DialogActivitiesMenu("activities"),
|
||||
|
@ -4990,6 +5084,7 @@ var DialogMenuMapping = /** @type {const} */({
|
|||
var DialogSidePanelMapping = /** @type {const} */({
|
||||
expression: new _DialogExpressionMenu("expression"),
|
||||
pose: new _DialogPoseMenu("pose"),
|
||||
expressionPreset: new _DialogExpressionSaveMenu("expressionPreset"),
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -5188,6 +5283,7 @@ function DialogLoad() {
|
|||
|
||||
DialogSidePanelMapping.expression.Init({ C });
|
||||
DialogSidePanelMapping.pose.Init({ C })?.toggleAttribute("data-unload", true);
|
||||
DialogSidePanelMapping.expressionPreset.Init({ C })?.toggleAttribute("data-unload", true);
|
||||
DialogChangeMode(DialogMenuMode ?? "dialog", true);
|
||||
}
|
||||
|
||||
|
@ -5306,6 +5402,7 @@ function DialogDraw() {
|
|||
DialogDrawRepositionButton();
|
||||
|
||||
DialogMenuMapping[DialogMenuMode]?.Draw();
|
||||
DialogSidePanelMapping.expressionPreset.Draw();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue