Refactor character information display in AIImages mod by modularizing the rendering of basic info, traits, genes, hediffs, and apparel into separate methods. Enhance height calculation logic for improved layout consistency. Update AIImages.dll to reflect these changes.

This commit is contained in:
Leonid Pershin
2025-10-31 10:13:42 +03:00
parent 1ec80a01cb
commit 731428fb44
2 changed files with 244 additions and 162 deletions

View File

@@ -572,12 +572,25 @@ namespace AIImages
{
float contentY = startY;
float lineHeight = 22f;
contentY = DrawBasicInfo(parentRect, contentY, lineHeight);
contentY = DrawTraits(parentRect, contentY, lineHeight);
contentY = DrawGenes(parentRect, contentY, lineHeight);
contentY = DrawHediffs(parentRect, contentY, lineHeight);
DrawApparel(parentRect, contentY, lineHeight);
}
/// <summary>
/// Отрисовывает базовую информацию о персонаже
/// </summary>
private float DrawBasicInfo(Rect parentRect, float startY, float lineHeight)
{
float contentY = startY;
float labelWidth = parentRect.width * 0.45f;
float valueWidth = parentRect.width * 0.50f;
Text.Font = GameFont.Tiny;
// Базовая информация
var info = new[]
{
("AIImages.Info.Gender".Translate(), appearanceData.Gender.ToString()),
@@ -618,123 +631,161 @@ namespace AIImages
contentY += lineHeight;
}
// Черты характера
if (pawn.story?.traits?.allTraits != null && pawn.story.traits.allTraits.Any())
{
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Traits".Translate() + ":"
);
contentY += lineHeight + 2f;
return contentY;
}
Text.Font = GameFont.Tiny;
var traitLabels = pawn.story.traits.allTraits.Select(trait => trait.LabelCap);
foreach (var traitLabel in traitLabels)
{
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight),
"• " + traitLabel
);
contentY += lineHeight;
}
/// <summary>
/// Отрисовывает черты характера персонажа
/// </summary>
private float DrawTraits(Rect parentRect, float startY, float lineHeight)
{
float contentY = startY;
if (pawn.story?.traits?.allTraits == null || !pawn.story.traits.allTraits.Any())
return contentY;
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Traits".Translate() + ":"
);
contentY += lineHeight + 2f;
Text.Font = GameFont.Tiny;
var traitLabels = pawn.story.traits.allTraits.Select(trait => trait.LabelCap);
foreach (var traitLabel in traitLabels)
{
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight),
"• " + traitLabel
);
contentY += lineHeight;
}
// Гены
if (pawn.genes?.GenesListForReading != null && pawn.genes.GenesListForReading.Any())
{
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Genes".Translate() + ":"
);
contentY += lineHeight + 2f;
return contentY;
}
Text.Font = GameFont.Tiny;
var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList();
foreach (var gene in activeGenes)
{
// Получаем лейбл гена (предпочитаем Label, если доступен, иначе LabelCap)
string geneLabel = gene.Label ?? gene.def.LabelCap;
// Собираем дополнительную информацию
string geneInfo = geneLabel;
// Добавляем описание, если оно есть и не слишком длинное
if (!string.IsNullOrEmpty(gene.def.description) && gene.def.description.Length < 100)
{
geneInfo += " - " + gene.def.description;
}
// Рассчитываем высоту текста
float textHeight = Text.CalcHeight(geneInfo, parentRect.width - 25f);
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, textHeight),
"• " + geneInfo
);
contentY += textHeight;
}
/// <summary>
/// Отрисовывает гены персонажа
/// </summary>
private float DrawGenes(Rect parentRect, float startY, float lineHeight)
{
float contentY = startY;
if (pawn.genes?.GenesListForReading == null || !pawn.genes.GenesListForReading.Any())
return contentY;
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Genes".Translate() + ":"
);
contentY += lineHeight + 2f;
Text.Font = GameFont.Tiny;
var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList();
foreach (var gene in activeGenes)
{
string geneInfo = BuildGeneInfo(gene);
float textHeight = Text.CalcHeight(geneInfo, parentRect.width - 25f);
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, textHeight),
"• " + geneInfo
);
contentY += textHeight;
}
// Хедифы (состояния)
if (pawn.health?.hediffSet?.hediffs != null && pawn.health.hediffSet.hediffs.Any())
{
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Hediffs".Translate() + ":"
);
contentY += lineHeight + 2f;
return contentY;
}
Text.Font = GameFont.Tiny;
var hediffLabels = pawn
.health.hediffSet.hediffs.Where(hediff => hediff.Visible)
.Select(hediff => hediff.LabelCap);
foreach (var hediffLabel in hediffLabels)
/// <summary>
/// Строит информационную строку для гена
/// </summary>
private string BuildGeneInfo(Gene gene)
{
string geneLabel = gene.Label ?? gene.def.LabelCap;
string geneInfo = geneLabel;
if (!string.IsNullOrEmpty(gene.def.description))
{
string description = gene.def.description;
if (description.Length > 200)
{
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight),
"• " + hediffLabel
);
contentY += lineHeight;
description = description.Substring(0, 197) + "...";
}
geneInfo += " - " + description;
}
// Одежда
return geneInfo;
}
/// <summary>
/// Отрисовывает хедифы (состояния здоровья) персонажа
/// </summary>
private float DrawHediffs(Rect parentRect, float startY, float lineHeight)
{
float contentY = startY;
if (pawn.health?.hediffSet?.hediffs == null || !pawn.health.hediffSet.hediffs.Any())
return contentY;
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Hediffs".Translate() + ":"
);
contentY += lineHeight + 2f;
Text.Font = GameFont.Tiny;
var hediffLabels = pawn
.health.hediffSet.hediffs.Where(hediff => hediff.Visible)
.Select(hediff => hediff.LabelCap);
foreach (var hediffLabel in hediffLabels)
{
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 20f, lineHeight),
"• " + hediffLabel
);
contentY += lineHeight;
}
return contentY;
}
/// <summary>
/// Отрисовывает одежду персонажа
/// </summary>
private void DrawApparel(Rect parentRect, float startY, float lineHeight)
{
float contentY = startY;
var apparel = pawn.apparel?.WornApparel;
if (apparel != null && apparel.Any())
{
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Apparel".Translate() + ":"
);
contentY += lineHeight + 2f;
Text.Font = GameFont.Tiny;
foreach (var item in apparel)
{
var colorDesc = ColorDescriptionService.GetApparelColorDescription(
item.DrawColor
);
string apparelLabel = $"• {colorDesc} {item.def.label}";
float apparelHeight = Text.CalcHeight(apparelLabel, parentRect.width - 25f);
Widgets.Label(
new Rect(
parentRect.x + 15f,
contentY,
parentRect.width - 25f,
apparelHeight
),
apparelLabel
);
contentY += apparelHeight;
}
if (apparel == null || !apparel.Any())
return;
contentY += 15f;
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(parentRect.x + 5f, contentY, parentRect.width - 10f, lineHeight),
"AIImages.Info.Apparel".Translate() + ":"
);
contentY += lineHeight + 2f;
Text.Font = GameFont.Tiny;
foreach (var item in apparel)
{
var colorDesc = ColorDescriptionService.GetApparelColorDescription(item.DrawColor);
string apparelLabel = $"• {colorDesc} {item.def.label}";
float apparelHeight = Text.CalcHeight(apparelLabel, parentRect.width - 25f);
Widgets.Label(
new Rect(parentRect.x + 15f, contentY, parentRect.width - 25f, apparelHeight),
apparelLabel
);
contentY += apparelHeight;
}
}
@@ -803,79 +854,110 @@ namespace AIImages
private float CalculateContentHeight()
{
float height = 0f;
float height = CalculatePortraitHeight();
height += CalculateBasicInfoHeight();
height += CalculateTraitsHeight();
height += CalculateGenesHeight();
height += CalculateHediffsHeight();
height += CalculateApparelHeight();
height += 50f; // Дополнительный отступ
return height;
}
// Портрет персонажа (если есть)
/// <summary>
/// Рассчитывает высоту портрета персонажа
/// </summary>
private float CalculatePortraitHeight()
{
if (generatedImage != null)
{
float portraitSize = 250f; // Максимальный размер портрета
height += portraitSize + 15f;
return portraitSize + 15f;
}
return 0f;
}
// Заголовок "Информация о персонаже"
height += 35f;
/// <summary>
/// Рассчитывает высоту базовой информации
/// </summary>
private float CalculateBasicInfoHeight()
{
float height = 35f; // Заголовок "Информация о персонаже"
height += 10f; // Разделитель
height += 6 * 22f; // Базовая информация (6 строк по 22px)
return height;
}
// Разделитель
height += 10f;
/// <summary>
/// Рассчитывает высоту секции черт характера
/// </summary>
private float CalculateTraitsHeight()
{
if (pawn.story?.traits?.allTraits == null || !pawn.story.traits.allTraits.Any())
return 0f;
// Базовая информация (6 строк по 22px)
height += 6 * 22f;
float height = 15f; // Отступ
height += 22f; // Заголовок "Черты характера"
height += 2f; // Отступ
height += pawn.story.traits.allTraits.Count * 22f; // Каждая черта
return height;
}
// Черты характера (если есть)
if (pawn.story?.traits?.allTraits != null && pawn.story.traits.allTraits.Any())
/// <summary>
/// Рассчитывает высоту секции генов
/// </summary>
private float CalculateGenesHeight()
{
if (pawn.genes?.GenesListForReading == null || !pawn.genes.GenesListForReading.Any())
return 0f;
float height = 15f; // Отступ
height += 22f; // Заголовок "Гены"
height += 2f; // Отступ
// Рассчитываем высоту для каждого гена с учетом описания
Text.Font = GameFont.Tiny;
var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList();
float approximateColumnWidth = 900f * 0.35f; // Примерная ширина левой колонки
float labelWidth = approximateColumnWidth - 25f;
foreach (var gene in activeGenes)
{
height += 15f; // Отступ
height += 22f; // Заголовок "Черты характера"
height += 2f; // Отступ
height += pawn.story.traits.allTraits.Count * 22f; // Каждая черта
string geneInfo = BuildGeneInfo(gene);
height += Text.CalcHeight("• " + geneInfo, labelWidth);
}
// Гены (если есть)
if (pawn.genes?.GenesListForReading != null && pawn.genes.GenesListForReading.Any())
{
height += 15f; // Отступ
height += 22f; // Заголовок "Гены"
height += 2f; // Отступ
// Рассчитываем высоту для каждого гена с учетом описания
Text.Font = GameFont.Tiny;
var activeGenes = pawn.genes.GenesListForReading.Where(gene => gene.Active).ToList();
float labelWidth = parentRect.width - 25f;
foreach (var gene in activeGenes)
{
string geneLabel = gene.Label ?? gene.def.LabelCap;
string geneInfo = geneLabel;
if (!string.IsNullOrEmpty(gene.def.description) && gene.def.description.Length < 100)
{
geneInfo += " - " + gene.def.description;
}
height += Text.CalcHeight("• " + geneInfo, labelWidth);
}
}
return height;
}
// Хедифы (если есть)
if (pawn.health?.hediffSet?.hediffs != null && pawn.health.hediffSet.hediffs.Any())
{
height += 15f; // Отступ
height += 22f; // Заголовок "Хедифы"
height += 2f; // Отступ
height += pawn.health.hediffSet.hediffs.Count(hediff => hediff.Visible) * 22f; // Каждый видимый хедиф
}
/// <summary>
/// Рассчитывает высоту секции хедифов
/// </summary>
private float CalculateHediffsHeight()
{
if (pawn.health?.hediffSet?.hediffs == null || !pawn.health.hediffSet.hediffs.Any())
return 0f;
// Одежда (если есть)
float height = 15f; // Отступ
height += 22f; // Заголовок "Хедифы"
height += 2f; // Отступ
height += pawn.health.hediffSet.hediffs.Count(hediff => hediff.Visible) * 22f; // Каждый видимый хедиф
return height;
}
/// <summary>
/// Рассчитывает высоту секции одежды
/// </summary>
private float CalculateApparelHeight()
{
var apparel = pawn.apparel?.WornApparel;
if (apparel != null && apparel.Any())
{
height += 15f; // Отступ
height += 22f; // Заголовок "Одежда"
height += 2f; // Отступ
// Примерно по 22-30px на предмет одежды
height += apparel.Count * 26f;
}
// Дополнительный отступ
height += 50f;
if (apparel == null || !apparel.Any())
return 0f;
float height = 15f; // Отступ
height += 22f; // Заголовок "Одежда"
height += 2f; // Отступ
height += apparel.Count * 26f; // Примерно по 22-30px на предмет одежды
return height;
}