MtrlTab UI improvements and code deduplication

This commit is contained in:
Exter-N 2024-08-17 04:34:09 +02:00
parent 1da095be99
commit 5a241e3dbb
9 changed files with 99 additions and 176 deletions

@ -1 +1 @@
Subproject commit b7fdfe9d19f7e3229834480db446478b0bf6acee
Subproject commit 0784569ab59c96b2058730cdb4cefd61c96b5f1a

View file

@ -107,7 +107,9 @@ public class Configuration : IPluginConfiguration, ISavable, IService
public bool AlwaysOpenDefaultImport { get; set; } = false;
public bool KeepDefaultMetaChanges { get; set; } = false;
public string DefaultModAuthor { get; set; } = DefaultTexToolsData.Author;
public bool EditRawTileTransforms { get; set; } = false;
public bool EditRawTileTransforms { get; set; } = false;
public bool WholePairSelectorAlwaysHighlights { get; set; } = false;
public Dictionary<ColorId, uint> Colors { get; set; }
= Enum.GetValues<ColorId>().ToDictionary(c => c, c => c.Data().DefaultColor);

View file

@ -13,15 +13,13 @@ public partial class MtrlTab
{
private const float ColorTableScalarSize = 65.0f;
private int _colorTableSelectedPair;
private bool DrawColorTable(ColorTable table, ColorDyeTable? dyeTable, bool disabled)
private bool DrawColorTable(ColorTable table, ColorDyeTable? dyeTable, bool disabled, MtrlTabUiState uiState)
{
DrawColorTablePairSelector(table, disabled);
return DrawColorTablePairEditor(table, dyeTable, disabled);
DrawColorTablePairSelector(table, disabled, uiState);
return DrawColorTablePairEditor(table, dyeTable, disabled, uiState);
}
private void DrawColorTablePairSelector(ColorTable table, bool disabled)
private void DrawColorTablePairSelector<TRow>(IColorTable<TRow> table, bool disabled, MtrlTabUiState uiState) where TRow : unmanaged, IColorRow
{
var style = ImGui.GetStyle();
var itemSpacing = style.ItemSpacing.X;
@ -38,16 +36,17 @@ public partial class MtrlTab
var spaceWidth = ImUtf8.CalcTextSize(" "u8).X;
var spacePadding = (int)MathF.Ceiling((highlighterSize.X + framePadding.X + itemInnerSpacing) / spaceWidth);
for (var i = 0; i < ColorTable.NumRows >> 1; i += 8)
for (var i = 0; i < table.Height >> 1; i += 8)
{
for (var j = 0; j < 8; ++j)
var numPairsInRow = Math.Min(8, (table.Height >> 1) - i);
for (var j = 0; j < numPairsInRow; ++j)
{
var pairIndex = i + j;
using (ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), pairIndex == _colorTableSelectedPair))
using (ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), pairIndex == uiState.ColorTableSelectedPair))
{
if (ImUtf8.Button($"#{pairIndex + 1}".PadLeft(3 + spacePadding),
new Vector2(buttonWidth, ImGui.GetFrameHeightWithSpacing() + frameHeight)))
_colorTableSelectedPair = pairIndex;
uiState.ColorTableSelectedPair = pairIndex;
}
var rcMin = ImGui.GetItemRectMin() + framePadding;
@ -69,7 +68,7 @@ public partial class MtrlTab
ImGuiUtil.ColorConvertFloat3ToU32(PseudoSqrtRgb((Vector3)table[pairIndex << 1].EmissiveColor)),
ImGuiUtil.ColorConvertFloat3ToU32(PseudoSqrtRgb((Vector3)table[(pairIndex << 1) | 1].EmissiveColor))
);
if (j < 7)
if (j + 1 < numPairsInRow)
ImGui.SameLine();
var cursor = ImGui.GetCursorScreenPos();
@ -82,14 +81,14 @@ public partial class MtrlTab
}
}
private bool DrawColorTablePairEditor(ColorTable table, ColorDyeTable? dyeTable, bool disabled)
private bool DrawColorTablePairEditor(ColorTable table, ColorDyeTable? dyeTable, bool disabled, MtrlTabUiState uiState)
{
var retA = false;
var retB = false;
var rowAIdx = _colorTableSelectedPair << 1;
var rowAIdx = uiState.ColorTableSelectedPair << 1;
var rowBIdx = rowAIdx | 1;
var dyeA = dyeTable?[_colorTableSelectedPair << 1] ?? default;
var dyeB = dyeTable?[(_colorTableSelectedPair << 1) | 1] ?? default;
var dyeA = dyeTable?[uiState.ColorTableSelectedPair << 1] ?? default;
var dyeB = dyeTable?[(uiState.ColorTableSelectedPair << 1) | 1] ?? default;
var previewDyeA = _stainService.GetStainCombo(dyeA.Channel).CurrentSelection.Key;
var previewDyeB = _stainService.GetStainCombo(dyeB.Channel).CurrentSelection.Key;
var dyePackA = _stainService.GudStmFile.GetValueOrNull(dyeA.Template, previewDyeA);
@ -335,7 +334,6 @@ public partial class MtrlTab
var scalarSize = ColorTableScalarSize * UiHelpers.Scale;
var itemSpacing = ImGui.GetStyle().ItemSpacing.X;
var dyeOffset = ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemInnerSpacing.X - ImGui.GetFrameHeight() - scalarSize - 64.0f;
var subColWidth = CalculateSubColumnWidth(2);
var ret = false;
ref var row = ref table[rowIdx];
@ -387,6 +385,20 @@ public partial class MtrlTab
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
ret |= DrawTemplateTile(table, rowIdx);
return ret;
}
private bool DrawTemplateTile<TRow>(IColorTable<TRow> table, int rowIdx) where TRow : unmanaged, IColorRow
{
var scalarSize = ColorTableScalarSize * UiHelpers.Scale;
var itemSpacing = ImGui.GetStyle().ItemSpacing.X;
var subColWidth = CalculateSubColumnWidth(2);
var ret = false;
ref var row = ref table[rowIdx];
var leftLineHeight = 64.0f + ImGui.GetStyle().FramePadding.Y * 2.0f;
var rightLineHeight = 3.0f * ImGui.GetFrameHeight() + 2.0f * ImGui.GetStyle().ItemSpacing.Y;
var lineHeight = Math.Max(leftLineHeight, rightLineHeight);
@ -406,8 +418,13 @@ public partial class MtrlTab
ImGui.Dummy(new Vector2(scalarSize, 0.0f));
ImUtf8.SameLineInner();
ImGui.SetNextItemWidth(scalarSize);
ret |= CtDragScalar("Tile Opacity"u8, default, (float)row.TileAlpha * 100.0f, "%.0f%%"u8, 0.0f, HalfMaxValue * 100.0f, 1.0f,
v => table[rowIdx].TileAlpha = (Half)(v * 0.01f));
if (table is ColorTable rwTable)
{
ret |= CtDragScalar("Tile Opacity"u8, default, (float)row.TileAlpha * 100.0f, "%.0f%%"u8, 0.0f, HalfMaxValue * 100.0f, 1.0f,
v => rwTable[rowIdx].TileAlpha = (Half)(v * 0.01f));
}
else
CtDragScalar<float>("Tile Opacity"u8, default, (float)row.TileAlpha * 100.0f, "%.0f%%"u8);
ret |= CtTileTransformMatrix(row.TileTransform, scalarSize, true,
m => table[rowIdx].TileTransform = m);

View file

@ -20,7 +20,7 @@ public partial class MtrlTab
private static (Vector2 Scale, float Rotation, float Shear)? _pinnedTileTransform;
private bool DrawColorTableSection(bool disabled)
private bool DrawColorTableSection(bool disabled, MtrlTabUiState uiState)
{
if (!_shpkLoading && !SamplerIds.Contains(ShpkFile.TableSamplerId) || Mtrl.Table == null)
return false;
@ -53,7 +53,7 @@ public partial class MtrlTab
LegacyColorTable legacyTable => DrawLegacyColorTable(legacyTable, Mtrl.DyeTable as LegacyColorDyeTable, disabled),
ColorTable table when Mtrl.ShaderPackage.Name is "characterlegacy.shpk" => DrawLegacyColorTable(table,
Mtrl.DyeTable as ColorDyeTable, disabled),
ColorTable table => DrawColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled),
ColorTable table => DrawColorTable(table, Mtrl.DyeTable as ColorDyeTable, disabled, uiState),
_ => false,
};
@ -230,11 +230,13 @@ public partial class MtrlTab
private void ColorTablePairHighlightButton(int pairIdx, bool disabled)
{
var wholePairSelectorHighlight = (_config.WholePairSelectorAlwaysHighlights || ImGui.GetIO().KeyCtrl) && ImGui.IsItemHovered();
ImUtf8.IconButton(FontAwesomeIcon.Crosshairs,
"Highlight this pair of rows on your character, if possible.\n\nHighlight colors can be configured in Penumbra's settings."u8,
ImGui.GetFrameHeight() * Vector2.One, disabled || _colorTablePreviewers.Count == 0);
if (ImGui.IsItemHovered())
if (wholePairSelectorHighlight || ImGui.IsItemHovered())
HighlightColorTablePair(pairIdx);
else if (_highlightedColorTablePair == pairIdx)
CancelColorTableHighlight();
@ -266,14 +268,14 @@ public partial class MtrlTab
else
{
drawList.AddRectFilled(
rcMin, rcMax with { Y = float.Lerp(rcMin.Y, rcMax.Y, 1.0f / 3) },
rcMin, rcMax with { Y = MathF.Floor(float.Lerp(rcMin.Y, rcMax.Y, 1.0f / 3)) },
topColor, frameRounding, ImDrawFlags.RoundCornersTopLeft | ImDrawFlags.RoundCornersTopRight);
drawList.AddRectFilledMultiColor(
rcMin with { Y = float.Lerp(rcMin.Y, rcMax.Y, 1.0f / 3) },
rcMax with { Y = float.Lerp(rcMin.Y, rcMax.Y, 2.0f / 3) },
rcMin with { Y = MathF.Floor(float.Lerp(rcMin.Y, rcMax.Y, 1.0f / 3)) },
rcMax with { Y = MathF.Ceiling(float.Lerp(rcMin.Y, rcMax.Y, 2.0f / 3)) },
topColor, topColor, bottomColor, bottomColor);
drawList.AddRectFilled(
rcMin with { Y = float.Lerp(rcMin.Y, rcMax.Y, 2.0f / 3) }, rcMax,
rcMin with { Y = MathF.Ceiling(float.Lerp(rcMin.Y, rcMax.Y, 2.0f / 3)) }, rcMax,
bottomColor, frameRounding, ImDrawFlags.RoundCornersBottomLeft | ImDrawFlags.RoundCornersBottomRight);
}

View file

@ -16,31 +16,8 @@ public partial class MtrlTab
private const float LegacyColorTableIntegerSize = 40.0f;
private const float LegacyColorTableByteSize = 25.0f;
private bool DrawLegacyColorTable(LegacyColorTable table, LegacyColorDyeTable? dyeTable, bool disabled)
{
using var imTable = ImUtf8.Table("##ColorTable"u8, dyeTable != null ? 10 : 8,
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV);
if (!imTable)
return false;
DrawLegacyColorTableHeader(dyeTable != null);
var ret = false;
for (var i = 0; i < LegacyColorTable.NumRows; ++i)
{
if (DrawLegacyColorTableRow(table, dyeTable, i, disabled))
{
UpdateColorTableRowPreview(i);
ret = true;
}
ImGui.TableNextRow();
}
return ret;
}
private bool DrawLegacyColorTable(ColorTable table, ColorDyeTable? dyeTable, bool disabled)
private bool DrawLegacyColorTable<TRow, TDyeRow>(IColorTable<TRow> table, IColorDyeTable<TDyeRow>? dyeTable, bool disabled)
where TRow : unmanaged, ILegacyColorRow where TDyeRow : unmanaged, ILegacyColorDyeRow
{
using var imTable = ImUtf8.Table("##ColorTable"u8, dyeTable != null ? 10 : 8,
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV);
@ -91,113 +68,8 @@ public partial class MtrlTab
}
}
private bool DrawLegacyColorTableRow(LegacyColorTable table, LegacyColorDyeTable? dyeTable, int rowIdx, bool disabled)
{
using var id = ImRaii.PushId(rowIdx);
ref var row = ref table[rowIdx];
var dye = dyeTable != null ? dyeTable[rowIdx] : default;
var floatSize = LegacyColorTableFloatSize * UiHelpers.Scale;
var pctSize = LegacyColorTablePercentageSize * UiHelpers.Scale;
var intSize = LegacyColorTableIntegerSize * UiHelpers.Scale;
ImGui.TableNextColumn();
ColorTableCopyClipboardButton(rowIdx);
ImUtf8.SameLineInner();
var ret = ColorTablePasteFromClipboardButton(rowIdx, disabled);
ImUtf8.SameLineInner();
ColorTableRowHighlightButton(rowIdx, disabled);
ImGui.TableNextColumn();
using (ImRaii.PushFont(UiBuilder.MonoFont))
{
ImUtf8.Text($"{(rowIdx >> 1) + 1,2:D}{"AB"[rowIdx & 1]}");
}
ImGui.TableNextColumn();
using var dis = ImRaii.Disabled(disabled);
ret |= CtColorPicker("##Diffuse"u8, "Diffuse Color"u8, row.DiffuseColor,
c => table[rowIdx].DiffuseColor = c);
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeDiffuse"u8, "Apply Diffuse Color on Dye"u8, dye.DiffuseColor,
b => dyeTable[rowIdx].DiffuseColor = b);
}
ImGui.TableNextColumn();
ret |= CtColorPicker("##Specular"u8, "Specular Color"u8, row.SpecularColor,
c => table[rowIdx].SpecularColor = c);
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeSpecular"u8, "Apply Specular Color on Dye"u8, dye.SpecularColor,
b => dyeTable[rowIdx].SpecularColor = b);
}
ImGui.SameLine();
ImGui.SetNextItemWidth(pctSize);
ret |= CtDragScalar("##SpecularMask"u8, "Specular Strength"u8, (float)row.SpecularMask * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f,
1.0f,
v => table[rowIdx].SpecularMask = (Half)(v * 0.01f));
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeSpecularMask"u8, "Apply Specular Strength on Dye"u8, dye.SpecularMask,
b => dyeTable[rowIdx].SpecularMask = b);
}
ImGui.TableNextColumn();
ret |= CtColorPicker("##Emissive"u8, "Emissive Color"u8, row.EmissiveColor,
c => table[rowIdx].EmissiveColor = c);
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeEmissive"u8, "Apply Emissive Color on Dye"u8, dye.EmissiveColor,
b => dyeTable[rowIdx].EmissiveColor = b);
}
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(floatSize);
var glossStrengthMin = ImGui.GetIO().KeyCtrl ? 0.0f : HalfEpsilon;
ret |= CtDragHalf("##Shininess"u8, "Gloss Strength"u8, row.Shininess, "%.1f"u8, glossStrengthMin, HalfMaxValue,
Math.Max(0.1f, (float)row.Shininess * 0.025f),
v => table[rowIdx].Shininess = v);
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeShininess"u8, "Apply Gloss Strength on Dye"u8, dye.Shininess,
b => dyeTable[rowIdx].Shininess = b);
}
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(intSize);
ret |= CtTileIndexPicker("##TileIndex"u8, "Tile Index"u8, row.TileIndex, true,
value => table[rowIdx].TileIndex = value);
ImGui.TableNextColumn();
ret |= CtTileTransformMatrix(row.TileTransform, floatSize, false,
m => table[rowIdx].TileTransform = m);
if (dyeTable != null)
{
ImGui.TableNextColumn();
if (_stainService.LegacyTemplateCombo.Draw("##dyeTemplate", dye.Template.ToString(), string.Empty, intSize
+ ImGui.GetStyle().ScrollbarSize / 2, ImGui.GetTextLineHeightWithSpacing(), ImGuiComboFlags.NoArrowButton))
{
dyeTable[rowIdx].Template = _stainService.LegacyTemplateCombo.CurrentSelection;
ret = true;
}
ImGuiUtil.HoverTooltip("Dye Template", ImGuiHoveredFlags.AllowWhenDisabled);
ImGui.TableNextColumn();
ret |= DrawLegacyDyePreview(rowIdx, disabled, dye, floatSize);
}
return ret;
}
private bool DrawLegacyColorTableRow(ColorTable table, ColorDyeTable? dyeTable, int rowIdx, bool disabled)
private bool DrawLegacyColorTableRow<TRow, TDyeRow>(IColorTable<TRow> table, IColorDyeTable<TDyeRow>? dyeTable, int rowIdx, bool disabled)
where TRow : unmanaged, ILegacyColorRow where TDyeRow : unmanaged, ILegacyColorDyeRow
{
using var id = ImRaii.PushId(rowIdx);
ref var row = ref table[rowIdx];
@ -242,13 +114,13 @@ public partial class MtrlTab
ImGui.SameLine();
ImGui.SetNextItemWidth(pctSize);
ret |= CtDragScalar("##SpecularMask"u8, "Specular Strength"u8, (float)row.Scalar7 * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f,
v => table[rowIdx].Scalar7 = (Half)(v * 0.01f));
ret |= CtDragScalar("##SpecularMask"u8, "Specular Strength"u8, (float)row.SpecularMask * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f,
v => table[rowIdx].SpecularMask = (Half)(v * 0.01f));
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeSpecularMask"u8, "Apply Specular Strength on Dye"u8, dye.Metalness,
b => dyeTable[rowIdx].Metalness = b);
ret |= CtApplyStainCheckbox("##dyeSpecularMask"u8, "Apply Specular Strength on Dye"u8, dye.SpecularMask,
b => dyeTable[rowIdx].SpecularMask = b);
}
ImGui.TableNextColumn();
@ -264,15 +136,15 @@ public partial class MtrlTab
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(floatSize);
var glossStrengthMin = ImGui.GetIO().KeyCtrl ? 0.0f : HalfEpsilon;
ret |= CtDragHalf("##Shininess"u8, "Gloss Strength"u8, row.Scalar3, "%.1f"u8, glossStrengthMin, HalfMaxValue,
Math.Max(0.1f, (float)row.Scalar3 * 0.025f),
v => table[rowIdx].Scalar3 = v);
ret |= CtDragHalf("##Shininess"u8, "Gloss Strength"u8, row.Shininess, "%.1f"u8, glossStrengthMin, HalfMaxValue,
Math.Max(0.1f, (float)row.Shininess * 0.025f),
v => table[rowIdx].Shininess = v);
if (dyeTable != null)
{
ImUtf8.SameLineInner();
ret |= CtApplyStainCheckbox("##dyeShininess"u8, "Apply Gloss Strength on Dye"u8, dye.Scalar3,
b => dyeTable[rowIdx].Scalar3 = b);
ret |= CtApplyStainCheckbox("##dyeShininess"u8, "Apply Gloss Strength on Dye"u8, dye.Shininess,
b => dyeTable[rowIdx].Shininess = b);
}
ImGui.TableNextColumn();
@ -281,8 +153,13 @@ public partial class MtrlTab
value => table[rowIdx].TileIndex = value);
ImUtf8.SameLineInner();
ImGui.SetNextItemWidth(pctSize);
ret |= CtDragScalar("##TileAlpha"u8, "Tile Opacity"u8, (float)row.TileAlpha * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f,
v => table[rowIdx].TileAlpha = (Half)(v * 0.01f));
if (table is ColorTable rwTable)
{
ret |= CtDragScalar("##TileAlpha"u8, "Tile Opacity"u8, (float)row.TileAlpha * 100.0f, "%.0f%%"u8, 0f, HalfMaxValue * 100.0f, 1.0f,
v => rwTable[rowIdx].TileAlpha = (Half)(v * 0.01f));
}
else
CtDragScalar<float>("##TileAlpha"u8, "Tile Opacity"u8, (float)row.TileAlpha * 100.0f, "%.0f%%"u8);
ImGui.TableNextColumn();
ret |= CtTileTransformMatrix(row.TileTransform, floatSize, false,
@ -292,8 +169,13 @@ public partial class MtrlTab
{
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(byteSize);
ret |= CtDragScalar("##DyeChannel"u8, "Dye Channel"u8, dye.Channel + 1, "%hhd"u8, 1, StainService.ChannelCount, 0.25f,
value => dyeTable[rowIdx].Channel = (byte)(Math.Clamp(value, 1, StainService.ChannelCount) - 1));
if (dyeTable is ColorDyeTable rwDyeTable)
{
ret |= CtDragScalar("##DyeChannel"u8, "Dye Channel"u8, dye.Channel + 1, "%d"u8, 1, StainService.ChannelCount, 0.25f,
value => rwDyeTable[rowIdx].Channel = (byte)(Math.Clamp(value, 1, StainService.ChannelCount) - 1));
}
else
CtDragScalar<int>("##DyeChannel"u8, "Dye Channel"u8, dye.Channel + 1, "%d"u8);
ImUtf8.SameLineInner();
_stainService.LegacyTemplateCombo.CurrentDyeChannel = dye.Channel;
if (_stainService.LegacyTemplateCombo.Draw("##dyeTemplate", dye.Template.ToString(), string.Empty, intSize
@ -312,7 +194,8 @@ public partial class MtrlTab
return ret;
}
private bool DrawLegacyDyePreview(int rowIdx, bool disabled, LegacyColorDyeTableRow dye, float floatSize)
private bool DrawLegacyDyePreview<TDyeRow>(int rowIdx, bool disabled, TDyeRow dye, float floatSize)
where TDyeRow : unmanaged, ILegacyColorDyeRow
{
var stain = _stainService.StainCombo1.CurrentSelection.Key;
if (stain == 0 || !_stainService.LegacyStmFile.TryGetValue(dye.Template, stain, out var values))

View file

@ -83,7 +83,7 @@ public sealed partial class MtrlTab : IWritable, IDisposable
return true;
}
public bool DrawPanel(bool disabled)
public bool DrawPanel(bool disabled, MtrlTabUiState uiState)
{
if (_updateOnNextFrame)
{
@ -100,7 +100,7 @@ public sealed partial class MtrlTab : IWritable, IDisposable
ret |= DrawShaderSection(disabled);
ret |= DrawTextureSection(disabled);
ret |= DrawColorTableSection(disabled);
ret |= DrawColorTableSection(disabled, uiState);
ret |= DrawConstantsSection(disabled);
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));

View file

@ -0,0 +1,9 @@
namespace Penumbra.UI.AdvancedWindow.Materials;
/// <summary>
/// This class contains UI state that shall be preserved across <see cref="MtrlTab"/> instances.
/// </summary>
public sealed class MtrlTabUiState
{
public int ColorTableSelectedPair = 0;
}

View file

@ -12,12 +12,18 @@ public partial class ModEditWindow
{
private readonly FileEditor<MtrlTab> _materialTab;
private readonly MtrlTabUiState _materialTabRwUiState = new();
private readonly MtrlTabUiState _materialTabRoUiState = new();
private bool DrawMaterialPanel(MtrlTab tab, bool disabled)
{
// This depends on the current inner workings of FileEditor<T>.
var uiState = disabled ? _materialTabRoUiState : _materialTabRwUiState;
if (tab.DrawVersionUpdate(disabled))
_materialTab.SaveFile();
return tab.DrawPanel(disabled);
return tab.DrawPanel(disabled, uiState);
}
private void DrawMaterialReassignmentTab()

View file

@ -733,6 +733,10 @@ public class SettingsTab : ITab, IUiService
Checkbox("Advanced Editing: Edit Raw Tile UV Transforms",
"Edit the raw matrix components of tile UV transforms, instead of having them decomposed into scale, rotation and shear.",
_config.EditRawTileTransforms, v => _config.EditRawTileTransforms = v);
Checkbox("Advanced Editing: Always Highlight Color Row Pair when Hovering Selection Button",
"Make the whole color row pair selection button highlight the pair in game, instead of just the crosshair, even without holding Ctrl.",
_config.WholePairSelectorAlwaysHighlights, v => _config.WholePairSelectorAlwaysHighlights = v);
}
#endregion