Files
ai-images/Source/AIImages/UI/AIImagesSettingsUI.cs

285 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using AIImages.Models;
using AIImages.Settings;
using RimWorld;
using UnityEngine;
using Verse;
namespace AIImages
{
/// <summary>
/// UI для настроек мода в меню настроек RimWorld
/// </summary>
public static class AIImagesSettingsUI
{
private static Vector2 scrollPosition = Vector2.zero;
private static string stepsBuffer;
private static string widthBuffer;
private static string heightBuffer;
public static void DoSettingsWindowContents(Rect inRect, AIImagesModSettings settings)
{
// Инициализируем буферы при первом вызове
if (string.IsNullOrEmpty(stepsBuffer))
{
stepsBuffer = settings.steps.ToString();
widthBuffer = settings.width.ToString();
heightBuffer = settings.height.ToString();
}
Listing_Standard listingStandard = new Listing_Standard();
Rect viewRect = new Rect(0f, 0f, inRect.width - 20f, 1200f);
Widgets.BeginScrollView(inRect, ref scrollPosition, viewRect);
listingStandard.Begin(viewRect);
// === API Settings ===
listingStandard.Label(
"AIImages.Settings.ApiSection".Translate(),
-1f,
"AIImages.Settings.ApiSectionTooltip".Translate()
);
listingStandard.GapLine();
listingStandard.Label("AIImages.Settings.ApiEndpoint".Translate() + ":");
settings.apiEndpoint = listingStandard.TextEntry(settings.apiEndpoint);
listingStandard.Gap(8f);
// Кнопка проверки подключения
if (listingStandard.ButtonText("AIImages.Settings.TestConnection".Translate()))
{
_ = TestApiConnection(settings.apiEndpoint);
}
// Кнопка загрузки моделей
if (listingStandard.ButtonText("AIImages.Settings.LoadModels".Translate()))
{
_ = LoadModelsFromApi(settings);
}
listingStandard.Gap(12f);
// === Generation Settings ===
listingStandard.Label(
"AIImages.Settings.GenerationSection".Translate(),
-1f,
"AIImages.Settings.GenerationSectionTooltip".Translate()
);
listingStandard.GapLine();
// Art Style
if (
listingStandard.ButtonTextLabeled(
"AIImages.Settings.ArtStyle".Translate(),
settings.artStyle.ToString()
)
)
{
List<FloatMenuOption> styleOptions = new List<FloatMenuOption>();
foreach (ArtStyle style in Enum.GetValues(typeof(ArtStyle)))
{
ArtStyle localStyle = style;
styleOptions.Add(
new FloatMenuOption(style.ToString(), () => settings.artStyle = localStyle)
);
}
Find.WindowStack.Add(new FloatMenu(styleOptions));
}
// Shot Type
if (
listingStandard.ButtonTextLabeled(
"AIImages.Settings.ShotType".Translate(),
settings.shotType.ToString()
)
)
{
List<FloatMenuOption> shotOptions = new List<FloatMenuOption>();
foreach (ShotType shot in Enum.GetValues(typeof(ShotType)))
{
ShotType localShot = shot;
shotOptions.Add(
new FloatMenuOption(shot.ToString(), () => settings.shotType = localShot)
);
}
Find.WindowStack.Add(new FloatMenu(shotOptions));
}
listingStandard.Gap(8f);
// Steps
listingStandard.Label("AIImages.Settings.Steps".Translate() + $": {settings.steps}");
settings.steps = (int)listingStandard.Slider(settings.steps, 1, 150);
listingStandard.Gap(8f);
// CFG Scale
listingStandard.Label(
"AIImages.Settings.CfgScale".Translate() + $": {settings.cfgScale:F1}"
);
settings.cfgScale = listingStandard.Slider(settings.cfgScale, 1f, 30f);
listingStandard.Gap(8f);
// Width
listingStandard.Label("AIImages.Settings.Width".Translate() + ":");
widthBuffer = listingStandard.TextEntry(widthBuffer);
if (int.TryParse(widthBuffer, out int width))
{
settings.width = Mathf.Clamp(width, 64, 2048);
}
// Height
listingStandard.Label("AIImages.Settings.Height".Translate() + ":");
heightBuffer = listingStandard.TextEntry(heightBuffer);
if (int.TryParse(heightBuffer, out int height))
{
settings.height = Mathf.Clamp(height, 64, 2048);
}
// Common size presets
listingStandard.Gap(4f);
Rect presetRect = listingStandard.GetRect(30f);
if (Widgets.ButtonText(new Rect(presetRect.x, presetRect.y, 80f, 30f), "512x512"))
{
settings.width = 512;
settings.height = 512;
widthBuffer = "512";
heightBuffer = "512";
}
if (Widgets.ButtonText(new Rect(presetRect.x + 85f, presetRect.y, 80f, 30f), "512x768"))
{
settings.width = 512;
settings.height = 768;
widthBuffer = "512";
heightBuffer = "768";
}
if (
Widgets.ButtonText(new Rect(presetRect.x + 170f, presetRect.y, 80f, 30f), "768x768")
)
{
settings.width = 768;
settings.height = 768;
widthBuffer = "768";
heightBuffer = "768";
}
listingStandard.Gap(12f);
// Sampler
listingStandard.Label("AIImages.Settings.Sampler".Translate() + ":");
settings.selectedSampler = listingStandard.TextEntry(settings.selectedSampler);
listingStandard.Gap(12f);
// === Prompts ===
listingStandard.Label(
"AIImages.Settings.PromptsSection".Translate(),
-1f,
"AIImages.Settings.PromptsSectionTooltip".Translate()
);
listingStandard.GapLine();
listingStandard.Label("AIImages.Settings.BasePositivePrompt".Translate() + ":");
settings.basePositivePrompt = listingStandard.TextEntry(settings.basePositivePrompt, 3);
listingStandard.Gap(8f);
listingStandard.Label("AIImages.Settings.BaseNegativePrompt".Translate() + ":");
settings.baseNegativePrompt = listingStandard.TextEntry(settings.baseNegativePrompt, 3);
listingStandard.Gap(12f);
// === Options ===
listingStandard.Label("AIImages.Settings.OptionsSection".Translate());
listingStandard.GapLine();
listingStandard.CheckboxLabeled(
"AIImages.Settings.AutoLoadModels".Translate(),
ref settings.autoLoadModels
);
listingStandard.CheckboxLabeled(
"AIImages.Settings.ShowTechnicalInfo".Translate(),
ref settings.showTechnicalInfo
);
listingStandard.CheckboxLabeled(
"AIImages.Settings.SaveHistory".Translate(),
ref settings.saveGenerationHistory
);
listingStandard.Gap(12f);
// Save path
listingStandard.Label("AIImages.Settings.SavePath".Translate() + ":");
settings.savePath = listingStandard.TextEntry(settings.savePath);
listingStandard.End();
Widgets.EndScrollView();
}
private static async System.Threading.Tasks.Task TestApiConnection(string endpoint)
{
try
{
Log.Message($"[AI Images] Testing connection to {endpoint}...");
bool available = await AIImagesMod.ApiService.CheckApiAvailability(endpoint);
if (available)
{
Messages.Message(
"AIImages.Settings.ConnectionSuccess".Translate(),
MessageTypeDefOf.PositiveEvent
);
}
else
{
Messages.Message(
"AIImages.Settings.ConnectionFailed".Translate(),
MessageTypeDefOf.RejectInput
);
}
}
catch (Exception ex)
{
Messages.Message($"Error: {ex.Message}", MessageTypeDefOf.RejectInput);
}
}
private static async System.Threading.Tasks.Task LoadModelsFromApi(
AIImagesModSettings settings
)
{
try
{
Log.Message("[AI Images] Loading models from API...");
var models = await AIImagesMod.ApiService.GetAvailableModels(settings.apiEndpoint);
if (models.Count > 0)
{
Messages.Message(
"AIImages.Settings.ModelsLoaded".Translate(models.Count),
MessageTypeDefOf.PositiveEvent
);
// Если модель не выбрана, выбираем первую
if (string.IsNullOrEmpty(settings.selectedModel) && models.Count > 0)
{
settings.selectedModel = models[0];
}
}
else
{
Messages.Message(
"AIImages.Settings.NoModelsFound".Translate(),
MessageTypeDefOf.RejectInput
);
}
}
catch (Exception ex)
{
Messages.Message(
$"Error loading models: {ex.Message}",
MessageTypeDefOf.RejectInput
);
}
}
}
}