using System; using System.Collections.Generic; using System.Linq; using AIImages.Models; using AIImages.Settings; using RimWorld; using UnityEngine; using Verse; namespace AIImages { /// /// UI для настроек мода в меню настроек RimWorld /// 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) { InitializeBuffers(settings); 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); DrawApiSettings(listingStandard, settings); DrawGenerationSettings(listingStandard, settings); DrawSamplerSchedulerSettings(listingStandard, settings); DrawPromptsSettings(listingStandard, settings); DrawOptionsSettings(listingStandard, settings); listingStandard.End(); Widgets.EndScrollView(); } private static void InitializeBuffers(AIImagesModSettings settings) { if (string.IsNullOrEmpty(stepsBuffer)) { stepsBuffer = settings.steps.ToString(); widthBuffer = settings.width.ToString(); heightBuffer = settings.height.ToString(); } } private static void DrawApiSettings( Listing_Standard listingStandard, AIImagesModSettings 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); } DrawModelDropdown(listingStandard, settings); if (listingStandard.ButtonText("AIImages.Settings.LoadSamplersSchedulers".Translate())) { _ = LoadSamplersAndSchedulers(settings); } listingStandard.Gap(12f); } private static void DrawModelDropdown( Listing_Standard listingStandard, AIImagesModSettings settings ) { if ( listingStandard.ButtonTextLabeled( "AIImages.Settings.Model".Translate(), string.IsNullOrEmpty(settings.selectedModel) ? "AIImages.Settings.NoModelSelected".Translate() : settings.selectedModel ) ) { List modelOptions = new List(); if (!settings.availableModels.Any()) { modelOptions.Add( new FloatMenuOption("AIImages.Settings.LoadModelsFirst".Translate(), null) ); } else { foreach (string model in settings.availableModels) { string localModel = model; modelOptions.Add( new FloatMenuOption(model, () => settings.selectedModel = localModel) ); } } Find.WindowStack.Add(new FloatMenu(modelOptions)); } } private static void DrawGenerationSettings( Listing_Standard listingStandard, AIImagesModSettings settings ) { listingStandard.Label( "AIImages.Settings.GenerationSection".Translate(), -1f, "AIImages.Settings.GenerationSectionTooltip".Translate() ); listingStandard.GapLine(); DrawArtStyleDropdown(listingStandard, settings); listingStandard.Gap(8f); listingStandard.Label("AIImages.Settings.Steps".Translate() + $": {settings.steps}"); settings.steps = (int)listingStandard.Slider(settings.steps, 1, 150); listingStandard.Gap(8f); listingStandard.Label( "AIImages.Settings.CfgScale".Translate() + $": {settings.cfgScale:F1}" ); settings.cfgScale = listingStandard.Slider(settings.cfgScale, 1f, 30f); listingStandard.Gap(8f); DrawSizeSettings(listingStandard, settings); listingStandard.Gap(12f); } private static void DrawArtStyleDropdown( Listing_Standard listingStandard, AIImagesModSettings settings ) { if ( listingStandard.ButtonTextLabeled( "AIImages.Settings.ArtStyle".Translate(), settings.artStyle.ToString() ) ) { List styleOptions = new List(); 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)); } } private static void DrawSizeSettings( Listing_Standard listingStandard, AIImagesModSettings settings ) { listingStandard.Label("AIImages.Settings.Width".Translate() + ":"); widthBuffer = listingStandard.TextEntry(widthBuffer); if (int.TryParse(widthBuffer, out int width)) { settings.width = Mathf.Clamp(width, 64, 2048); } listingStandard.Label("AIImages.Settings.Height".Translate() + ":"); heightBuffer = listingStandard.TextEntry(heightBuffer); if (int.TryParse(heightBuffer, out int height)) { settings.height = Mathf.Clamp(height, 64, 2048); } DrawSizePresets(listingStandard, settings); } private static void DrawSizePresets( Listing_Standard listingStandard, AIImagesModSettings settings ) { listingStandard.Gap(4f); Rect presetRect1 = listingStandard.GetRect(30f); DrawPresetButton(presetRect1, 0f, "512x512", 512, 512, settings); DrawPresetButton(presetRect1, 85f, "512x768", 512, 768, settings); DrawPresetButton(presetRect1, 170f, "768x768", 768, 768, settings); listingStandard.Gap(4f); Rect presetRect2 = listingStandard.GetRect(30f); DrawPresetButton(presetRect2, 0f, "896x1152", 896, 1152, settings, 90f); DrawPresetButton(presetRect2, 95f, "1024x1024", 1024, 1024, settings, 90f); } private static void DrawPresetButton( Rect rect, float xOffset, string label, int width, int height, AIImagesModSettings settings, float buttonWidth = 80f ) { if (Widgets.ButtonText(new Rect(rect.x + xOffset, rect.y, buttonWidth, 30f), label)) { settings.width = width; settings.height = height; widthBuffer = width.ToString(); heightBuffer = height.ToString(); } } private static void DrawSamplerSchedulerSettings( Listing_Standard listingStandard, AIImagesModSettings settings ) { DrawSamplerDropdown(listingStandard, settings); DrawSchedulerDropdown(listingStandard, settings); listingStandard.Gap(12f); } private static void DrawSamplerDropdown( Listing_Standard listingStandard, AIImagesModSettings settings ) { if ( listingStandard.ButtonTextLabeled( "AIImages.Settings.Sampler".Translate(), settings.selectedSampler ) ) { List samplerOptions = new List(); var availableSamplers = settings.availableSamplers.Any() ? settings.availableSamplers : new List { settings.selectedSampler }; foreach (string sampler in availableSamplers) { string localSampler = sampler; samplerOptions.Add( new FloatMenuOption(sampler, () => settings.selectedSampler = localSampler) ); } Find.WindowStack.Add(new FloatMenu(samplerOptions)); } } private static void DrawSchedulerDropdown( Listing_Standard listingStandard, AIImagesModSettings settings ) { if ( listingStandard.ButtonTextLabeled( "AIImages.Settings.Scheduler".Translate(), settings.selectedScheduler ) ) { List schedulerOptions = new List(); var availableSchedulers = settings.availableSchedulers.Any() ? settings.availableSchedulers : new List { settings.selectedScheduler }; foreach (string scheduler in availableSchedulers) { string localScheduler = scheduler; schedulerOptions.Add( new FloatMenuOption( scheduler, () => settings.selectedScheduler = localScheduler ) ); } Find.WindowStack.Add(new FloatMenu(schedulerOptions)); } } private static void DrawPromptsSettings( Listing_Standard listingStandard, AIImagesModSettings settings ) { 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); } private static void DrawOptionsSettings( Listing_Standard listingStandard, AIImagesModSettings settings ) { 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); listingStandard.Label("AIImages.Settings.SavePath".Translate() + ":"); settings.savePath = listingStandard.TextEntry(settings.savePath); } 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); settings.availableModels = models; if (models.Count > 0) { Messages.Message( "AIImages.Settings.ModelsLoaded".Translate(models.Count), MessageTypeDefOf.PositiveEvent ); if ( ( string.IsNullOrEmpty(settings.selectedModel) || !models.Contains(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 ); } } private static async System.Threading.Tasks.Task LoadSamplersAndSchedulers( AIImagesModSettings settings ) { try { Log.Message("[AI Images] Loading samplers and schedulers from API..."); var samplers = await AIImagesMod.ApiService.GetAvailableSamplers( settings.apiEndpoint ); settings.availableSamplers = samplers; var schedulers = await AIImagesMod.ApiService.GetAvailableSchedulers( settings.apiEndpoint ); settings.availableSchedulers = schedulers; int totalCount = samplers.Count + schedulers.Count; if (totalCount > 0) { Messages.Message( "AIImages.Settings.SamplersSchedulersLoaded".Translate( samplers.Count, schedulers.Count ), MessageTypeDefOf.PositiveEvent ); if ( ( string.IsNullOrEmpty(settings.selectedSampler) || !samplers.Contains(settings.selectedSampler) ) && samplers.Count > 0 ) { settings.selectedSampler = samplers[0]; } if ( ( string.IsNullOrEmpty(settings.selectedScheduler) || !schedulers.Contains(settings.selectedScheduler) ) && schedulers.Count > 0 ) { settings.selectedScheduler = schedulers[0]; } } else { Messages.Message( "AIImages.Settings.NoSamplersSchedulersFound".Translate(), MessageTypeDefOf.RejectInput ); } } catch (Exception ex) { Messages.Message( $"Error loading samplers/schedulers: {ex.Message}", MessageTypeDefOf.RejectInput ); } } } }