diff --git a/Assemblies/AIImages.dll b/Assemblies/AIImages.dll
index daa0bbb..569545a 100644
Binary files a/Assemblies/AIImages.dll and b/Assemblies/AIImages.dll differ
diff --git a/Defs/ArtStyleDefs.xml b/Defs/ArtStyleDefs.xml
new file mode 100644
index 0000000..1c3e3e4
--- /dev/null
+++ b/Defs/ArtStyleDefs.xml
@@ -0,0 +1,111 @@
+
+
+
+
+ ArtStyle_None
+
+ No predefined style - use only your custom prompts
+
+
+
+ false
+ false
+ 0
+
+
+
+ ArtStyle_Realistic
+
+ Photorealistic style with high detail
+ photorealistic, hyperrealistic, realistic photo, photography
+ cartoon, anime, painting, drawing, illustration
+ professional photography, 8k uhd, dslr, high quality, sharp focus
+ true
+ true
+ 10
+
+
+
+ ArtStyle_SemiRealistic
+
+ Detailed illustration with realistic elements
+ semi-realistic, detailed illustration, realistic art
+ cartoon, anime, painting, drawing, illustration
+ professional photography, 8k uhd, dslr, high quality, sharp focus
+ true
+ true
+ 20
+
+
+
+ ArtStyle_Anime
+
+ Japanese anime/manga style
+ anime style, manga style, anime character
+ realistic, photo, photography, 3d
+ anime masterpiece, high resolution, vibrant colors
+ true
+ true
+ 30
+
+
+
+ ArtStyle_ConceptArt
+
+ Professional digital concept art
+ concept art, digital art, artstation, professional concept design
+
+ trending on artstation, professional digital art
+ true
+ true
+ 40
+
+
+
+ ArtStyle_DigitalPainting
+
+ Digital painting with brush strokes
+ digital painting, painterly, brush strokes, artistic
+
+
+ true
+ true
+ 50
+
+
+
+ ArtStyle_OilPainting
+
+ Traditional oil painting style
+ oil painting, traditional painting, canvas, fine art
+
+
+ true
+ true
+ 60
+
+
+
+ ArtStyle_Sketch
+
+ Pencil sketch or line art
+ pencil sketch, hand drawn, sketch art, line art
+
+
+ true
+ true
+ 70
+
+
+
+ ArtStyle_CellShaded
+
+ Flat colors with toon shading
+ cell shaded, flat colors, toon shading, stylized
+
+
+ true
+ true
+ 80
+
+
diff --git a/Defs/ImageSizePresetDefs.xml b/Defs/ImageSizePresetDefs.xml
new file mode 100644
index 0000000..1db4801
--- /dev/null
+++ b/Defs/ImageSizePresetDefs.xml
@@ -0,0 +1,78 @@
+
+
+
+
+ Size_512x512
+
+ 512
+ 512
+ Square
+ 10
+
+
+ Size_768x768
+
+ 768
+ 768
+ Square
+ 20
+
+
+ Size_1024x1024
+
+ 1024
+ 1024
+ Square
+ 30
+
+
+
+ Size_512x768
+
+ 512
+ 768
+ Portrait
+ 40
+
+
+ Size_768x1024
+
+ 768
+ 1024
+ Portrait
+ 50
+
+
+ Size_896x1152
+
+ 896
+ 1152
+ Portrait
+ 60
+
+
+
+ Size_768x512
+
+ 768
+ 512
+ Landscape
+ 70
+
+
+ Size_1024x768
+
+ 1024
+ 768
+ Landscape
+ 80
+
+
+ Size_1152x896
+
+ 1152
+ 896
+ Landscape
+ 90
+
+
diff --git a/Defs/README.md b/Defs/README.md
new file mode 100644
index 0000000..8567385
--- /dev/null
+++ b/Defs/README.md
@@ -0,0 +1,124 @@
+# AI Images - Defs Documentation
+
+This folder contains XML definition files that allow you to easily customize art styles and image size presets without recompiling the mod.
+
+## Art Style Definitions (ArtStyleDefs.xml)
+
+Art styles define how images should be generated, including prompts, quality tags, and negative prompts.
+
+### Structure
+
+```xml
+
+ ArtStyle_MyStyle
+
+ Description of the style
+ style keywords here
+ things to avoid
+ additional quality tags
+ true
+ true
+ 100
+
+```
+
+### Fields
+
+- **defName**: Unique identifier (must start with `ArtStyle_`)
+- **label**: Display name shown in the UI
+- **description**: Tooltip text explaining the style
+- **positivePrompt**: Keywords added to the positive prompt (e.g., "photorealistic, 8k uhd")
+- **negativePrompt**: Keywords added to the negative prompt (e.g., "cartoon, anime")
+- **qualityTags**: Style-specific quality tags
+- **addBaseQualityTags**: If true, adds "highly detailed, professional, masterpiece, best quality"
+- **addBaseNegativePrompts**: If true, adds base negative prompts like "ugly, deformed, low quality"
+- **sortOrder**: Determines order in the UI (lower numbers appear first)
+
+### Example: Custom Watercolor Style
+
+```xml
+
+ ArtStyle_Watercolor
+
+ Soft watercolor painting style
+ watercolor painting, soft colors, flowing paint, artistic
+ photograph, digital art, sharp edges
+ traditional art, paper texture
+ true
+ true
+ 65
+
+```
+
+## Image Size Presets (ImageSizePresetDefs.xml)
+
+Image size presets provide quick buttons for common image dimensions.
+
+### Structure
+
+```xml
+
+ Size_1024x1024
+
+ 1024
+ 1024
+ Square
+ 30
+
+```
+
+### Fields
+
+- **defName**: Unique identifier (should start with `Size_`)
+- **label**: Display text on the button
+- **width**: Image width in pixels
+- **height**: Image height in pixels
+- **category**: Grouping category (Square, Portrait, Landscape, or custom)
+- **sortOrder**: Determines button order (lower numbers appear first)
+
+### Example: Ultra-wide Size
+
+```xml
+
+ Size_2048x1024
+
+ 2048
+ 1024
+ Ultrawide
+ 95
+
+```
+
+## Adding Custom Definitions
+
+1. **Create a new XML file** in the `Defs` folder
+2. **Start with the XML header**:
+ ```xml
+
+
+
+
+ ```
+3. **Add your definitions** using the structures above
+4. **Restart RimWorld** to load the new definitions
+
+## Tips
+
+- Keep `defName` unique to avoid conflicts
+- Use descriptive `label` values for the UI
+- Adjust `sortOrder` to organize items logically
+- Test your prompts with different characters to ensure good results
+- For art styles, experiment with different combinations of tags
+- Consider using existing styles as templates
+
+## Compatibility
+
+These definitions are compatible with other mods. If another mod adds art styles or size presets, they will all appear together in the UI.
+
+## Troubleshooting
+
+- **Style doesn't appear**: Check that `defName` is unique and starts with `ArtStyle_`
+- **Size preset missing**: Verify the XML syntax and that `defName` starts with `Size_`
+- **Prompts not working**: Make sure prompts are in English and follow Stable Diffusion prompt syntax
+- **XML errors**: Use an XML validator to check your file for syntax errors
+
diff --git a/Source/AIImages/Defs/ArtStyleDef.cs b/Source/AIImages/Defs/ArtStyleDef.cs
new file mode 100644
index 0000000..5ec1c41
--- /dev/null
+++ b/Source/AIImages/Defs/ArtStyleDef.cs
@@ -0,0 +1,46 @@
+using System.Diagnostics.CodeAnalysis;
+using Verse;
+
+namespace AIImages
+{
+ ///
+ /// Определение художественного стиля для генерации изображений
+ ///
+ [SuppressMessage(
+ "Major Code Smell",
+ "S1104:Fields should not have public accessibility",
+ Justification = "Required for RimWorld's Def system XML serialization"
+ )]
+ public class ArtStyleDef : Def
+ {
+ ///
+ /// Промпт для позитивного описания стиля
+ ///
+ public string positivePrompt = "";
+
+ ///
+ /// Промпт для негативного описания (что исключить)
+ ///
+ public string negativePrompt = "";
+
+ ///
+ /// Теги качества специфичные для этого стиля
+ ///
+ public string qualityTags = "";
+
+ ///
+ /// Добавлять ли базовые теги качества (highly detailed, professional, masterpiece, best quality)
+ ///
+ public bool addBaseQualityTags = true;
+
+ ///
+ /// Добавлять ли базовые негативные промпты (ugly, deformed, low quality, etc.)
+ ///
+ public bool addBaseNegativePrompts = true;
+
+ ///
+ /// Порядок сортировки в UI
+ ///
+ public int sortOrder = 100;
+ }
+}
diff --git a/Source/AIImages/Defs/ImageSizePresetDef.cs b/Source/AIImages/Defs/ImageSizePresetDef.cs
new file mode 100644
index 0000000..c067c33
--- /dev/null
+++ b/Source/AIImages/Defs/ImageSizePresetDef.cs
@@ -0,0 +1,36 @@
+using System.Diagnostics.CodeAnalysis;
+using Verse;
+
+namespace AIImages
+{
+ ///
+ /// Предустановка размера изображения
+ ///
+ [SuppressMessage(
+ "Major Code Smell",
+ "S1104:Fields should not have public accessibility",
+ Justification = "Required for RimWorld's Def system XML serialization"
+ )]
+ public class ImageSizePresetDef : Def
+ {
+ ///
+ /// Ширина изображения в пикселях
+ ///
+ public int width = 512;
+
+ ///
+ /// Высота изображения в пикселях
+ ///
+ public int height = 512;
+
+ ///
+ /// Категория размера (Square, Portrait, Landscape)
+ ///
+ public string category = "Square";
+
+ ///
+ /// Порядок сортировки в UI
+ ///
+ public int sortOrder = 100;
+ }
+}
diff --git a/Source/AIImages/Models/StableDiffusionSettings.cs b/Source/AIImages/Models/StableDiffusionSettings.cs
index 90ffef8..f472b29 100644
--- a/Source/AIImages/Models/StableDiffusionSettings.cs
+++ b/Source/AIImages/Models/StableDiffusionSettings.cs
@@ -15,7 +15,7 @@ namespace AIImages.Models
public string Scheduler { get; set; }
public int Seed { get; set; }
public string Model { get; set; }
- public ArtStyle ArtStyle { get; set; }
+ public string ArtStyleDefName { get; set; }
public StableDiffusionSettings()
{
@@ -25,27 +25,11 @@ namespace AIImages.Models
Width = 512;
Height = 768;
Sampler = "Euler a";
- Scheduler = "Automatic";
+ Scheduler = "Automatic"; // С большой буквы для API
Seed = -1; // Случайный seed
- ArtStyle = ArtStyle.Realistic;
+ ArtStyleDefName = "ArtStyle_Realistic";
PositivePrompt = "";
NegativePrompt = "ugly, deformed, low quality, blurry, bad anatomy, worst quality";
}
}
-
- ///
- /// Художественный стиль изображения
- ///
- public enum ArtStyle
- {
- None, // Без стиля
- Realistic,
- SemiRealistic,
- Anime,
- ConceptArt,
- DigitalPainting,
- OilPainting,
- Sketch,
- CellShaded,
- }
}
diff --git a/Source/AIImages/Services/AdvancedPromptGenerator.cs b/Source/AIImages/Services/AdvancedPromptGenerator.cs
index 8e3d90a..e2a717a 100644
--- a/Source/AIImages/Services/AdvancedPromptGenerator.cs
+++ b/Source/AIImages/Services/AdvancedPromptGenerator.cs
@@ -34,25 +34,6 @@ namespace AIImages.Services
{ "Pretty", "attractive features, pleasant appearance, charming" },
};
- private static readonly Dictionary ArtStylePrompts = new Dictionary<
- ArtStyle,
- string
- >
- {
- { ArtStyle.None, "" },
- { ArtStyle.Realistic, "photorealistic, hyperrealistic, realistic photo, photography" },
- { ArtStyle.SemiRealistic, "semi-realistic, detailed illustration, realistic art" },
- { ArtStyle.Anime, "anime style, manga style, anime character" },
- {
- ArtStyle.ConceptArt,
- "concept art, digital art, artstation, professional concept design"
- },
- { ArtStyle.DigitalPainting, "digital painting, painterly, brush strokes, artistic" },
- { ArtStyle.OilPainting, "oil painting, traditional painting, canvas, fine art" },
- { ArtStyle.Sketch, "pencil sketch, hand drawn, sketch art, line art" },
- { ArtStyle.CellShaded, "cell shaded, flat colors, toon shading, stylized" },
- };
-
public string GeneratePositivePrompt(
PawnAppearanceData appearanceData,
StableDiffusionSettings settings
@@ -66,17 +47,15 @@ namespace AIImages.Services
// 1. Базовый пользовательский промпт (если указан) - идет первым
if (!string.IsNullOrEmpty(settings.PositivePrompt))
{
- prompt.Append(settings.PositivePrompt);
+ prompt.Append(settings.PositivePrompt.TrimEnd(',', ' '));
prompt.Append(", ");
}
// 2. Художественный стиль
- if (
- ArtStylePrompts.TryGetValue(settings.ArtStyle, out string stylePrompt)
- && !string.IsNullOrEmpty(stylePrompt)
- )
+ var styleDef = DefDatabase.GetNamedSilentFail(settings.ArtStyleDefName);
+ if (styleDef != null && !string.IsNullOrEmpty(styleDef.positivePrompt))
{
- prompt.Append(stylePrompt);
+ prompt.Append(styleDef.positivePrompt);
prompt.Append(", ");
}
@@ -127,7 +106,7 @@ namespace AIImages.Services
}
// 10. Качественные теги
- prompt.Append(GetQualityTags(settings.ArtStyle));
+ prompt.Append(GetQualityTags(settings.ArtStyleDefName));
return prompt.ToString().Trim().TrimEnd(',');
}
@@ -139,34 +118,38 @@ namespace AIImages.Services
// 1. Пользовательский негативный промпт (если указан) - идет первым
if (!string.IsNullOrEmpty(settings.NegativePrompt))
{
- negativePrompt.Append(settings.NegativePrompt);
- negativePrompt.Append(", ");
+ negativePrompt.Append(settings.NegativePrompt.TrimEnd(',', ' '));
+ }
+
+ // Получаем стиль из Def
+ var styleDef = DefDatabase.GetNamedSilentFail(settings.ArtStyleDefName);
+ if (styleDef == null || !styleDef.addBaseNegativePrompts)
+ {
+ // Для стилей без базовых негативов - используем только пользовательский промпт
+ return negativePrompt.ToString().Trim();
}
// 2. Базовые негативные промпты
+ if (negativePrompt.Length > 0)
+ {
+ negativePrompt.Append(", ");
+ }
+
negativePrompt.Append(
"ugly, deformed, low quality, blurry, bad anatomy, worst quality, "
);
negativePrompt.Append(
- "mutated, disfigured, bad proportions, extra limbs, missing limbs, "
+ "mutated, disfigured, bad proportions, extra limbs, missing limbs"
);
- // 3. Специфичные для стиля негативы
- switch (settings.ArtStyle)
+ // 3. Специфичные для стиля негативы из Def
+ if (!string.IsNullOrEmpty(styleDef.negativePrompt))
{
- case ArtStyle.Realistic:
- case ArtStyle.SemiRealistic:
- negativePrompt.Append("cartoon, anime, painting, drawing, illustration, ");
- break;
- case ArtStyle.Anime:
- negativePrompt.Append("realistic, photo, photography, 3d, ");
- break;
- case ArtStyle.None:
- // Без дополнительных негативных промптов для стиля None
- break;
+ negativePrompt.Append(", ");
+ negativePrompt.Append(styleDef.negativePrompt);
}
- return negativePrompt.ToString().Trim().TrimEnd(',');
+ return negativePrompt.ToString().Trim();
}
public string GetFullPromptDescription(
@@ -317,24 +300,33 @@ namespace AIImages.Services
return apparelDesc.ToString();
}
- private string GetQualityTags(ArtStyle style)
+ private string GetQualityTags(string styleDefName)
{
- var baseTags = "highly detailed, professional, masterpiece, best quality";
-
- switch (style)
+ var styleDef = DefDatabase.GetNamedSilentFail(styleDefName);
+ if (styleDef == null)
{
- case ArtStyle.None:
- return baseTags;
- case ArtStyle.Realistic:
- case ArtStyle.SemiRealistic:
- return $"{baseTags}, professional photography, 8k uhd, dslr, high quality, sharp focus";
- case ArtStyle.Anime:
- return $"{baseTags}, anime masterpiece, high resolution, vibrant colors";
- case ArtStyle.ConceptArt:
- return $"{baseTags}, trending on artstation, professional digital art";
- default:
- return baseTags;
+ return "";
}
+
+ StringBuilder tags = new StringBuilder();
+
+ // Базовые теги качества
+ if (styleDef.addBaseQualityTags)
+ {
+ tags.Append("highly detailed, professional, masterpiece, best quality");
+ }
+
+ // Специфичные для стиля теги качества
+ if (!string.IsNullOrEmpty(styleDef.qualityTags))
+ {
+ if (tags.Length > 0)
+ {
+ tags.Append(", ");
+ }
+ tags.Append(styleDef.qualityTags);
+ }
+
+ return tags.ToString();
}
///
diff --git a/Source/AIImages/Settings/AIImagesModSettings.cs b/Source/AIImages/Settings/AIImagesModSettings.cs
index b9600e6..6c66461 100644
--- a/Source/AIImages/Settings/AIImagesModSettings.cs
+++ b/Source/AIImages/Settings/AIImagesModSettings.cs
@@ -14,7 +14,7 @@ namespace AIImages.Settings
public string apiEndpoint = "http://127.0.0.1:7860";
public string selectedModel = "";
public string selectedSampler = "Euler a";
- public string selectedScheduler = "Automatic";
+ public string selectedScheduler = "Automatic"; // С большой буквы для API
// Кэшированные списки из API (не сохраняются)
[Unsaved]
@@ -38,8 +38,8 @@ namespace AIImages.Settings
public string baseNegativePrompt =
"ugly, deformed, low quality, blurry, bad anatomy, worst quality";
- // Художественный стиль
- public ArtStyle artStyle = ArtStyle.Realistic;
+ // Художественный стиль (defName)
+ public string artStyleDefName = "ArtStyle_Realistic";
// Путь для сохранения
public string savePath = "AIImages/Generated";
@@ -70,7 +70,7 @@ namespace AIImages.Settings
"ugly, deformed, low quality, blurry, bad anatomy, worst quality"
);
- Scribe_Values.Look(ref artStyle, "artStyle", ArtStyle.Realistic);
+ Scribe_Values.Look(ref artStyleDefName, "artStyleDefName", "ArtStyle_Realistic");
Scribe_Values.Look(ref savePath, "savePath", "AIImages/Generated");
@@ -97,7 +97,7 @@ namespace AIImages.Settings
Scheduler = selectedScheduler,
Seed = seed,
Model = selectedModel,
- ArtStyle = artStyle,
+ ArtStyleDefName = artStyleDefName,
PositivePrompt = basePositivePrompt,
NegativePrompt = baseNegativePrompt,
};
diff --git a/Source/AIImages/UI/AIImagesSettingsUI.cs b/Source/AIImages/UI/AIImagesSettingsUI.cs
index 1d4be27..0bf5e18 100644
--- a/Source/AIImages/UI/AIImagesSettingsUI.cs
+++ b/Source/AIImages/UI/AIImagesSettingsUI.cs
@@ -174,21 +174,37 @@ namespace AIImages
AIImagesModSettings settings
)
{
+ // Получаем текущий стиль
+ var currentStyleDef = DefDatabase.GetNamedSilentFail(
+ settings.artStyleDefName
+ );
+ string currentStyleLabel = currentStyleDef?.label ?? settings.artStyleDefName;
+
if (
listingStandard.ButtonTextLabeled(
"AIImages.Settings.ArtStyle".Translate(),
- settings.artStyle.ToString()
+ currentStyleLabel
)
)
{
List styleOptions = new List();
- foreach (ArtStyle style in Enum.GetValues(typeof(ArtStyle)))
+
+ // Получаем все стили из DefDatabase и сортируем по sortOrder
+ var allStyles = DefDatabase.AllDefs.OrderBy(s => s.sortOrder);
+
+ foreach (var styleDef in allStyles)
{
- ArtStyle localStyle = style;
+ string localDefName = styleDef.defName;
+ string localLabel = styleDef.label;
+
styleOptions.Add(
- new FloatMenuOption(style.ToString(), () => settings.artStyle = localStyle)
+ new FloatMenuOption(
+ localLabel,
+ () => settings.artStyleDefName = localDefName
+ )
);
}
+
Find.WindowStack.Add(new FloatMenu(styleOptions));
}
}
@@ -220,34 +236,47 @@ namespace AIImages
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);
+ // Получаем все предустановки размеров из DefDatabase
+ var allPresets = DefDatabase
+ .AllDefs.OrderBy(p => p.sortOrder)
+ .ToList();
- 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))
+ if (!allPresets.Any())
{
- settings.width = width;
- settings.height = height;
- widthBuffer = width.ToString();
- heightBuffer = height.ToString();
+ return;
+ }
+
+ listingStandard.Gap(4f);
+
+ // Разбиваем на строки по 3 кнопки
+ int buttonsPerRow = 3;
+ float buttonWidth = 80f;
+ float spacing = 5f;
+
+ for (int i = 0; i < allPresets.Count; i += buttonsPerRow)
+ {
+ Rect rowRect = listingStandard.GetRect(30f);
+
+ for (int j = 0; j < buttonsPerRow && (i + j) < allPresets.Count; j++)
+ {
+ var preset = allPresets[i + j];
+ float xOffset = j * (buttonWidth + spacing);
+
+ if (
+ Widgets.ButtonText(
+ new Rect(rowRect.x + xOffset, rowRect.y, buttonWidth, 30f),
+ preset.label
+ )
+ )
+ {
+ settings.width = preset.width;
+ settings.height = preset.height;
+ widthBuffer = preset.width.ToString();
+ heightBuffer = preset.height.ToString();
+ }
+ }
+
+ listingStandard.Gap(4f);
}
}
diff --git a/Source/AIImages/Window_AIImage.cs b/Source/AIImages/Window_AIImage.cs
index 011a3ac..af067fa 100644
--- a/Source/AIImages/Window_AIImage.cs
+++ b/Source/AIImages/Window_AIImage.cs
@@ -70,6 +70,7 @@ namespace AIImages
public override Vector2 InitialSize => new Vector2(900f, 800f);
private Vector2 scrollPosition = Vector2.zero;
+ private Vector2 rightColumnScrollPosition = Vector2.zero;
private Vector2 promptScrollPosition = Vector2.zero;
private Vector2 negativePromptScrollPosition = Vector2.zero;
private float copiedMessageTime = 0f;
@@ -440,17 +441,23 @@ namespace AIImages
private void DrawRightColumn(Rect rect)
{
+ // Рассчитываем высоту контента для скролла
+ float contentHeight = CalculateRightColumnHeight(rect);
+ Rect scrollViewRect = new Rect(0f, 0f, rect.width - 20f, contentHeight);
+
+ Widgets.BeginScrollView(rect, ref rightColumnScrollPosition, scrollViewRect);
+
float curY = 0f;
- curY = DrawImagePreview(rect, curY);
- curY = DrawGenerationStatus(rect, curY);
- curY = DrawProgressBar(rect, curY);
- curY = DrawGenerationButton(rect, curY);
+ curY = DrawImagePreview(scrollViewRect, curY);
+ curY = DrawGenerationStatus(scrollViewRect, curY);
+ curY = DrawProgressBar(scrollViewRect, curY);
+ curY = DrawGenerationButton(scrollViewRect, curY);
// Позитивный промпт секция
Text.Font = GameFont.Medium;
Widgets.Label(
- new Rect(rect.x, rect.y + curY, rect.width, 30f),
+ new Rect(0f, curY, scrollViewRect.width, 30f),
"AIImages.Prompt.PositiveTitle".Translate()
);
curY += 35f;
@@ -464,10 +471,18 @@ namespace AIImages
// Фиксированная высота для области промпта
float promptBoxHeight = 100f;
- float actualPositiveHeight = Text.CalcHeight(positivePrompt, rect.width - 20f);
+ float actualPositiveHeight = Text.CalcHeight(
+ positivePrompt,
+ scrollViewRect.width - 20f
+ );
- Rect positiveOuterRect = new Rect(rect.x, rect.y + curY, rect.width, promptBoxHeight);
- Rect positiveViewRect = new Rect(0f, 0f, rect.width - 20f, actualPositiveHeight);
+ Rect positiveOuterRect = new Rect(0f, curY, scrollViewRect.width, promptBoxHeight);
+ Rect positiveViewRect = new Rect(
+ 0f,
+ 0f,
+ scrollViewRect.width - 20f,
+ actualPositiveHeight
+ );
// Рисуем фон
Widgets.DrawBoxSolid(positiveOuterRect, new Color(0.1f, 0.3f, 0.1f, 0.5f));
@@ -489,7 +504,7 @@ namespace AIImages
// Негативный промпт секция
Text.Font = GameFont.Medium;
Widgets.Label(
- new Rect(rect.x, rect.y + curY, rect.width, 30f),
+ new Rect(0f, curY, scrollViewRect.width, 30f),
"AIImages.Prompt.NegativeTitle".Translate()
);
curY += 35f;
@@ -500,10 +515,18 @@ namespace AIImages
generationSettings
);
- float actualNegativeHeight = Text.CalcHeight(negativePrompt, rect.width - 20f);
+ float actualNegativeHeight = Text.CalcHeight(
+ negativePrompt,
+ scrollViewRect.width - 20f
+ );
- Rect negativeOuterRect = new Rect(rect.x, rect.y + curY, rect.width, promptBoxHeight);
- Rect negativeViewRect = new Rect(0f, 0f, rect.width - 20f, actualNegativeHeight);
+ Rect negativeOuterRect = new Rect(0f, curY, scrollViewRect.width, promptBoxHeight);
+ Rect negativeViewRect = new Rect(
+ 0f,
+ 0f,
+ scrollViewRect.width - 20f,
+ actualNegativeHeight
+ );
// Рисуем фон (красноватый для негативного)
Widgets.DrawBoxSolid(negativeOuterRect, new Color(0.3f, 0.1f, 0.1f, 0.5f));
@@ -525,7 +548,7 @@ namespace AIImages
// Кнопки копирования промптов
if (
Widgets.ButtonText(
- new Rect(rect.x, rect.y + curY, rect.width / 2f - 5f, 30f),
+ new Rect(0f, curY, scrollViewRect.width / 2f - 5f, 30f),
"AIImages.Prompt.CopyPositive".Translate()
)
)
@@ -541,9 +564,9 @@ namespace AIImages
if (
Widgets.ButtonText(
new Rect(
- rect.x + rect.width / 2f + 5f,
- rect.y + curY,
- rect.width / 2f - 5f,
+ scrollViewRect.width / 2f + 5f,
+ curY,
+ scrollViewRect.width / 2f - 5f,
30f
),
"AIImages.Prompt.CopyNegative".Translate()
@@ -561,7 +584,7 @@ namespace AIImages
// Кнопка обновления данных
if (
Widgets.ButtonText(
- new Rect(rect.x, rect.y + curY, rect.width, 30f),
+ new Rect(0f, curY, scrollViewRect.width, 30f),
"AIImages.Window.Refresh".Translate()
)
)
@@ -575,11 +598,13 @@ namespace AIImages
curY += 35f;
GUI.color = new Color(0f, 1f, 0f, copiedMessageTime / 2f);
Widgets.Label(
- new Rect(rect.x, rect.y + curY, rect.width, 25f),
+ new Rect(0f, curY, scrollViewRect.width, 25f),
"AIImages.Prompt.Copied".Translate()
);
GUI.color = Color.white;
}
+
+ Widgets.EndScrollView();
}
private float CalculateContentHeight()
@@ -613,15 +638,46 @@ namespace AIImages
// Дополнительный отступ
height += 50f;
- // Позитивный промпт заголовок
- height += 35f;
- // Позитивный промпт контент
- height += 100f + 10f;
+ return height;
+ }
- // Негативный промпт заголовок
- height += 35f;
- // Негативный промпт контент
- height += 100f + 10f;
+ private float CalculateRightColumnHeight(Rect rect)
+ {
+ float height = 0f;
+ float contentWidth = rect.width - 20f;
+
+ // Превью изображения
+ if (generatedImage != null)
+ {
+ height += 200f + 10f;
+ }
+ else if (!isGenerating)
+ {
+ height += 100f + 10f;
+ }
+
+ // Статус генерации
+ if (!string.IsNullOrEmpty(generationStatus))
+ {
+ height += 30f;
+ }
+
+ // Прогресс бар
+ if (isGenerating && generationProgress > 0.0)
+ {
+ height += 30f;
+ }
+
+ // Кнопка генерации
+ height += 40f;
+
+ // Позитивный промпт
+ height += 35f; // Заголовок
+ height += 100f + 10f; // Бокс
+
+ // Негативный промпт
+ height += 35f; // Заголовок
+ height += 100f + 10f; // Бокс
// Кнопки копирования
height += 35f;
@@ -635,7 +691,7 @@ namespace AIImages
height += 30f;
}
- return height;
+ return height + 50f; // Дополнительный отступ
}
private float DrawImagePreview(Rect rect, float curY)