using System.Collections.Generic;
using System.IO;
using System.Linq;
using AIImages.Helpers;
using RimWorld;
using UnityEngine;
using Verse;
#pragma warning disable IDE1006 // Naming Styles
namespace AIImages
{
///
/// Окно галереи AI-сгенерированных изображений персонажа
///
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Style",
"IDE1006:Naming Styles",
Justification = "RimWorld Window naming convention"
)]
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Minor Code Smell",
"S101:Types should be named in PascalCase",
Justification = "RimWorld Window naming convention"
)]
public class Window_AIGallery : Window
{
private Pawn pawn;
private List portraitPaths = new List();
private List portraitTextures = new List();
private Vector2 mainScrollPosition = Vector2.zero;
private int selectedIndex = 0;
public Window_AIGallery(Pawn pawn)
{
this.pawn = pawn;
this.doCloseX = true;
this.doCloseButton = true;
this.forcePause = false;
this.absorbInputAroundWindow = false;
this.draggable = true;
this.preventCameraMotion = false;
LoadGallery();
}
public override Vector2 InitialSize => new Vector2(900f, 700f);
///
/// Загружает галерею изображений персонажа
///
private void LoadGallery()
{
DebugLogger.Log($"[AI Gallery] Loading gallery for {pawn?.Name}");
// Очищаем старые текстуры
UnloadTextures();
// Загружаем пути к портретам
portraitPaths = PawnPortraitHelper.GetAllPortraits(pawn);
// Загружаем текстуры
foreach (var path in portraitPaths)
{
if (File.Exists(path))
{
try
{
byte[] imageData = File.ReadAllBytes(path);
Texture2D texture = new Texture2D(2, 2);
texture.LoadImage(imageData);
portraitTextures.Add(texture);
DebugLogger.Log($"[AI Gallery] Loaded texture from: {path}");
}
catch (System.Exception ex)
{
DebugLogger.Warning($"[AI Gallery] Failed to load texture: {path}, Error: {ex.Message}");
portraitTextures.Add(null);
}
}
else
{
DebugLogger.Warning($"[AI Gallery] File not found: {path}");
portraitTextures.Add(null);
}
}
DebugLogger.Log($"[AI Gallery] Loaded {portraitTextures.Count} textures for {pawn?.Name}");
}
///
/// Освобождает ресурсы текстур
///
private void UnloadTextures()
{
foreach (var texture in portraitTextures)
{
if (texture != null)
{
Object.Destroy(texture);
}
}
portraitTextures.Clear();
}
///
/// Освобождает ресурсы при закрытии окна
///
public override void PreClose()
{
base.PreClose();
UnloadTextures();
}
///
/// Отрисовка окна
///
public override void DoWindowContents(Rect inRect)
{
// Заголовок
Text.Font = GameFont.Medium;
Widgets.Label(
new Rect(0f, 0f, inRect.width, 40f),
"AIImages.Gallery.Title".Translate()
);
// Имя персонажа
Text.Font = GameFont.Small;
Widgets.Label(
new Rect(0f, 40f, inRect.width, 30f),
"AIImages.Window.PawnLabel".Translate(pawn.NameShortColored.Resolve())
);
// Количество изображений
Widgets.Label(
new Rect(0f, 70f, inRect.width, 25f),
"AIImages.Gallery.Count".Translate(portraitTextures.Count)
);
// Разделитель
Widgets.DrawLineHorizontal(0f, 100f, inRect.width);
// Область для галереи
Rect galleryRect = new Rect(0f, 110f, inRect.width, inRect.height - 180f);
DrawGallery(galleryRect);
// Кнопка обновления
if (
Widgets.ButtonText(
new Rect(0f, inRect.height - 70f, inRect.width * 0.3f, 35f),
"AIImages.Window.Refresh".Translate()
)
)
{
LoadGallery();
}
// Кнопка удаления выбранного изображения
if (
portraitTextures.Count > 0
&& selectedIndex >= 0
&& selectedIndex < portraitTextures.Count
&& Widgets.ButtonText(
new Rect(inRect.width * 0.32f, inRect.height - 70f, inRect.width * 0.3f, 35f),
"AIImages.Gallery.DeleteSelected".Translate()
)
)
{
DeleteSelectedImage();
}
// Кнопка удаления всех изображений
if (
portraitTextures.Count > 0
&& Widgets.ButtonText(
new Rect(inRect.width * 0.64f, inRect.height - 70f, inRect.width * 0.36f, 35f),
"AIImages.Gallery.DeleteAll".Translate(portraitTextures.Count)
)
)
{
DeleteAllImages();
}
}
///
/// Отрисовка галереи изображений
///
private void DrawGallery(Rect rect)
{
if (portraitTextures.Count == 0)
{
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = new Color(1f, 1f, 1f, 0.5f);
Widgets.Label(rect, "AIImages.Gallery.Empty".Translate());
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
return;
}
// Параметры сетки
int columns = 3;
int rows = Mathf.CeilToInt((float)portraitTextures.Count / columns);
float cellWidth = (rect.width - 40f) / columns;
float cellHeight = cellWidth + 40f; // Высота ячейки (изображение + кнопки)
float spacing = 10f;
float viewHeight = rows * cellHeight + spacing;
Rect viewRect = new Rect(0f, 0f, rect.width - 20f, viewHeight);
Widgets.BeginScrollView(rect, ref mainScrollPosition, viewRect);
for (int i = 0; i < portraitTextures.Count; i++)
{
int row = i / columns;
int col = i % columns;
float x = col * (cellWidth + spacing);
float y = row * cellHeight;
Rect cellRect = new Rect(x, y, cellWidth, cellHeight);
DrawGalleryItem(cellRect, i);
}
Widgets.EndScrollView();
}
///
/// Отрисовка одного элемента галереи
///
private void DrawGalleryItem(Rect rect, int index)
{
// Подсветка выбранного элемента
if (index == selectedIndex)
{
Widgets.DrawBoxSolid(rect, new Color(0.3f, 0.5f, 0.8f, 0.2f));
Widgets.DrawBox(rect, 2);
}
else
{
Widgets.DrawBox(rect);
}
// Изображение
Texture2D texture = portraitTextures[index];
if (texture != null)
{
Rect imageRect = new Rect(
rect.x + 5f,
rect.y + 5f,
rect.width - 10f,
rect.width - 10f
);
// Клик по изображению для выбора
if (Widgets.ButtonInvisible(imageRect))
{
selectedIndex = index;
}
GUI.DrawTexture(imageRect, texture);
}
else
{
Rect errorRect = new Rect(rect.x + 5f, rect.y + 5f, rect.width - 10f, rect.width - 10f);
Widgets.DrawBoxSolid(errorRect, new Color(0.5f, 0f, 0f, 0.5f));
Text.Anchor = TextAnchor.MiddleCenter;
GUI.color = Color.white;
Widgets.Label(errorRect, "AIImages.Gallery.LoadError".Translate());
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
}
// Информация под изображением
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.UpperLeft;
float infoY = rect.y + rect.width - 5f;
// Имя файла
string fileName = Path.GetFileName(portraitPaths[index]);
if (fileName.Length > 30)
{
fileName = fileName.Substring(0, 27) + "...";
}
Widgets.Label(
new Rect(rect.x + 5f, infoY, rect.width - 10f, 20f),
fileName
);
// Дата создания
if (File.Exists(portraitPaths[index]))
{
try
{
var fileInfo = new FileInfo(portraitPaths[index]);
string dateStr = fileInfo.CreationTime.ToString("dd.MM.yyyy HH:mm");
Widgets.Label(
new Rect(rect.x + 5f, infoY + 15f, rect.width - 10f, 20f),
dateStr
);
}
catch
{
// Игнорируем ошибки чтения даты
}
}
}
///
/// Удаляет выбранное изображение
///
private void DeleteSelectedImage()
{
if (selectedIndex < 0 || selectedIndex >= portraitPaths.Count)
return;
string path = portraitPaths[selectedIndex];
// Подтверждение
Find.WindowStack.Add(
Dialog_MessageBox.CreateConfirmation(
"AIImages.Gallery.ConfirmDelete".Translate(),
delegate
{
// Удаляем из файловой системы
if (File.Exists(path))
{
try
{
File.Delete(path);
DebugLogger.Log($"[AI Gallery] Deleted file: {path}");
}
catch (System.Exception ex)
{
Messages.Message(
"AIImages.Gallery.DeleteError".Translate(ex.Message),
MessageTypeDefOf.RejectInput
);
return;
}
}
// Удаляем из компонента пешки
PawnPortraitHelper.RemovePortrait(pawn, path);
// Обновляем галерею
LoadGallery();
// Сбрасываем выбор
if (selectedIndex >= portraitTextures.Count)
{
selectedIndex = portraitTextures.Count - 1;
}
Messages.Message(
"AIImages.Gallery.Deleted".Translate(),
MessageTypeDefOf.PositiveEvent
);
},
destructive: true
)
);
}
///
/// Удаляет все изображения
///
private void DeleteAllImages()
{
// Подтверждение
Find.WindowStack.Add(
Dialog_MessageBox.CreateConfirmation(
"AIImages.Gallery.ConfirmDeleteAll".Translate(portraitPaths.Count),
delegate
{
// Удаляем все файлы
int deletedCount = 0;
foreach (var path in portraitPaths)
{
if (File.Exists(path))
{
try
{
File.Delete(path);
deletedCount++;
}
catch (System.Exception ex)
{
DebugLogger.Warning(
$"[AI Gallery] Failed to delete file: {path}, Error: {ex.Message}"
);
}
}
}
// Очищаем компонент пешки
PawnPortraitHelper.ClearPortrait(pawn);
// Обновляем галерею
LoadGallery();
selectedIndex = 0;
Messages.Message(
"AIImages.Gallery.AllDeleted".Translate(deletedCount),
MessageTypeDefOf.PositiveEvent
);
},
destructive: true
)
);
}
}
}