diff --git a/package/Editor/Images/ImageDataClasses.cs b/package/Editor/Images/ImageDataClasses.cs index 4acb7dc..9297ccd 100644 --- a/package/Editor/Images/ImageDataClasses.cs +++ b/package/Editor/Images/ImageDataClasses.cs @@ -1,27 +1,27 @@ using System; using System.Collections.Generic; -using System.Numerics; using UnityEngine; namespace Scenario.Editor { public static class ImageDataStorage { - [System.Serializable] + [Serializable] public class ImageData { [SerializeField] public string Id; [SerializeField] public string Url; [SerializeField] public string InferenceId; [SerializeField] public string Prompt; - [SerializeField] public float Steps; - [SerializeField] public UnityEngine.Vector2 Size; + [SerializeField] public int Steps; + [SerializeField] public Vector2 Size; [SerializeField] public float Guidance; [SerializeField] public string Scheduler; [SerializeField] public string Seed; [SerializeField] public DateTime CreatedAt; [SerializeField] public Texture2D texture; [SerializeField] public bool isProcessedByPromptImages; + [SerializeField] public string modelId; } } @@ -70,7 +70,7 @@ public class Inference public string status { get; set; } public List images { get; set; } public int imagesNumber { get; set; } - public int progress { get; set; } + public float progress { get; set; } public string displayPrompt { get; set; } } diff --git a/package/Editor/Images/Images.cs b/package/Editor/Images/Images.cs index 53877b4..4c188f9 100644 --- a/package/Editor/Images/Images.cs +++ b/package/Editor/Images/Images.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Newtonsoft.Json; using UnityEditor; using UnityEngine; @@ -8,26 +9,29 @@ namespace Scenario.Editor { public class Images : EditorWindow { - private static readonly string PaginationTokenKey = "paginationToken"; - private static readonly float MinimumWidth = 1000f; - private static readonly float MinimumHeight = 700f; private static readonly ImagesUI ImagesUI = new(); - private static string _paginationToken = ""; - internal static List _imageDataList = new(); + internal static List imageDataList = new(); + + /// + /// Contains a token that is useful to get the next page of inferences + /// + private static string lastPageToken = string.Empty; + + private static bool isVisible = false; [MenuItem("Window/Scenario/Images")] public static void ShowWindow() { - Images window = GetWindow("Images"); - + if (isVisible) + return; + + lastPageToken = string.Empty; + imageDataList.Clear(); GetInferencesData(); - - var images = EditorWindow.GetWindow(typeof(Images)); - ImagesUI.Init((Images)images); - window.minSize = new Vector2(MinimumWidth, window.minSize.y); - window.minSize = new Vector2(window.minSize.x, MinimumHeight); + var images = (Images)GetWindow(typeof(Images)); + ImagesUI.Init(images); } private void OnGUI() @@ -37,42 +41,45 @@ private void OnGUI() private void OnDestroy() { - ImagesUI.ClearSelectedTexture(); + ImagesUI.OnClose(); + ImagesUI.CloseSelectedTextureSection(); + DataCache.instance.ClearAllImageData(); } - - private static void GetInferencesData() + + private void OnBecameVisible() { - string selectedModelId = EditorPrefs.GetString("SelectedModelId"); - if (selectedModelId.Length < 2) - { - Debug.LogError("Please select a model first."); - return; - } + isVisible = true; + } - string paginationTokenString = EditorPrefs.GetString(PaginationTokenKey,""); - if (paginationTokenString != "") - { - paginationTokenString = "&paginationToken=" + paginationTokenString; - } + private void OnBecameInvisible() + { + isVisible = false; + } + + public static void GetInferencesData(Action callback_OnDataGet = null) //why get inferences instead of getting the assets ?? + { + string request = $"inferences"; + if (!string.IsNullOrEmpty(lastPageToken)) + request = $"inferences?paginationToken={lastPageToken}"; - ApiClient.RestGet($"inferences?nextPaginationToken={_paginationToken}", response => + ApiClient.RestGet(request, response => { var inferencesResponse = JsonConvert.DeserializeObject(response.Content); - _paginationToken = inferencesResponse.nextPaginationToken; + + lastPageToken = inferencesResponse.nextPaginationToken; if (inferencesResponse.inferences[0].status == "failed") { Debug.LogError("Api Response: Status == failed, Try Again.."); } - _imageDataList.Clear(); - ImagesUI.textures.Clear(); + List imageDataDownloaded = new List(); foreach (var inference in inferencesResponse.inferences) { foreach (var image in inference.images) { - _imageDataList.Add(new ImageDataStorage.ImageData + imageDataDownloaded.Add(new ImageDataStorage.ImageData { Id = image.id, Url = image.url, @@ -81,69 +88,66 @@ private static void GetInferencesData() Steps = inference.parameters.numInferenceSteps, Size = new Vector2(inference.parameters.width,inference.parameters.height), Guidance = inference.parameters.guidance, - Scheduler = "Default", + Scheduler = "Default", //TODO : change this to reflect the scheduler used for creating this image Seed = image.seed, CreatedAt = inference.createdAt, + modelId = inference.modelId }); } } - ImagesUI.SetFirstPage(); - ImagesUI.UpdatePage(); + imageDataList.AddRange(imageDataDownloaded); + foreach (ImageDataStorage.ImageData imageData in imageDataList) + { + FetchTextureFor(imageData); + } + callback_OnDataGet?.Invoke(); }); } - - public void DeleteImageAtIndex(int selectedTextureIndex) + + /// + /// Fetch a texture for a specific ImageData + /// + private static void FetchTextureFor(ImageDataStorage.ImageData _image, Action callback_OnTextureGet = null) { - ImagesUI.textures.RemoveAt(selectedTextureIndex); + CommonUtils.FetchTextureFromURL(_image.Url, texture => + { + _image.texture = texture; + callback_OnTextureGet?.Invoke(); + }); + } - string imageId = _imageDataList[selectedTextureIndex].Id; - string modelId = EditorPrefs.GetString("SelectedModelId", ""); - string inferenceId = _imageDataList[selectedTextureIndex].InferenceId; + /// + /// + /// + /// The id of the image you want to delete + public void DeleteImage(string _id) + { + var imageData = Images.GetImageDataById(_id); //try to get image from Images + if (imageData == null) + imageData = DataCache.instance.GetImageDataById(_id); //try to get from Datacache (if it has just been prompted) + if (imageData == null) + return; - Debug.Log("Requesting image deletion please wait.."); - - string url = $"models/{modelId}/inferences/{inferenceId}/images/{imageId}"; - + string url = $"models/{imageData.modelId}/inferences/{imageData.InferenceId}/images/{imageData.Id}"; ApiClient.RestDelete(url,null); + imageDataList.Remove(imageData); + + if(DataCache.instance.DoesImageIdExist(_id)) //also delete from Datacache if it's there + DataCache.instance.RemoveImageDataById(_id); Repaint(); } - internal void RemoveBackgroundForImageAtIndex(int selectedTextureIndex) + public static ImageDataStorage.ImageData GetImageDataById(string _id) { - string dataUrl = CommonUtils.Texture2DToDataURL(ImagesUI.textures[selectedTextureIndex]); - string fileName =CommonUtils.GetRandomImageFileName(); - string param = $"{{\"image\":\"{dataUrl}\",\"name\":\"{fileName}\",\"format\":\"png\",\"returnImage\":\"false\"}}"; - - Debug.Log($"Requesting background removal, please wait.."); - - ApiClient.RestPut("images/erase-background",param, response => - { - if (response.ErrorException != null) - { - Debug.LogError($"Error: {response.ErrorException.Message}"); - } - else - { - Debug.Log($"Response: {response.Content}"); - - try - { - dynamic jsonResponse = JsonConvert.DeserializeObject(response.Content); - string imageUrl = jsonResponse.asset.url; + return imageDataList.Find(x => x.Id == _id); + } - CommonUtils.FetchTextureFromURL(imageUrl, texture => - { - CommonUtils.SaveTextureAsPNG(texture); - }); - } - catch (Exception ex) - { - Debug.LogError("An error occurred while processing the response: " + ex.Message); - } - } - }); + public static Texture2D GetTextureByImageId(string _id) + { + return imageDataList.Find(x => x.Id == _id).texture; } + } } diff --git a/package/Editor/Images/ImagesUI.cs b/package/Editor/Images/ImagesUI.cs index 03cfaf7..5edffbe 100644 --- a/package/Editor/Images/ImagesUI.cs +++ b/package/Editor/Images/ImagesUI.cs @@ -1,143 +1,329 @@ using System; using System.Collections.Generic; -using System.Linq; using UnityEditor; using UnityEngine; -using static Scenario.Editor.ImageDataStorage; namespace Scenario.Editor { public class ImagesUI { - public List textures = new(); + public int itemsPerRow = 5; + public float padding = 10f; + public Vector2 scrollPosition = Vector2.zero; + public Vector2 selectedTextureSectionScrollPosition = Vector2.zero; + public Texture2D selectedTexture = null; - private int itemsPerRow = 5; - private float padding = 10f; + internal Images images; - private Vector2 scrollPosition = Vector2.zero; - private Texture2D selectedTexture = null; + /// + /// The id of the image that is currently selected + /// + private string selectedImageId = string.Empty; - private Images images; - private int selectedTextureIndex = 0; + // Dictionary containing button labels and associated actions + private Dictionary buttonActions = new Dictionary(); - private int firstImageIndex = 0; - private int pageImageCount = 15; - private List pageList; + /// + /// Contain the draw function of the current Detail Panel according to the button clicked + /// + private Action buttonDetailPanelDrawFunction = null; - public void Init(Images img) + /// + /// Usefull to show a small message when the images are loading + /// + private bool isLoading = false; + + + #region Initialization + + /// + /// Initializes the PromptImagesUI class with the provided PromptImages instance. + /// + /// The images instance to initialize with. + public void Init(Images _images) { - images = img; + images = _images; + InitializeButtons(); } - public void SetFirstPage() + #endregion + + + #region UI Drawing + + /// + /// Draws the background of the UI element with the specified position. + /// This function fills the background of a UI element with a given color. + /// + /// The position and dimensions of the UI element. + private static void DrawBackground(Rect position) { - firstImageIndex = 0; - pageImageCount = 15; + Color backgroundColor = EditorStyle.GetBackgroundColor(); + EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), backgroundColor); } - public void SetNextPage() + private void InitializeButtons() { - firstImageIndex += pageImageCount; - if (firstImageIndex >= Images._imageDataList.Count - pageImageCount) + // Dictionary containing button labels and associated actions + buttonActions = new Dictionary() { - firstImageIndex -= pageImageCount; - } + { + "Set Image as Reference", () => + { + PromptWindowUI.imageUpload = selectedTexture; + PromptWindow.ShowWindow(); + PromptWindow.SetImageControlTab(1); + buttonDetailPanelDrawFunction = () => + { + GUILayout.Label("Your image has been set in the Image to Image parameter in the Prompt Window.", EditorStyles.wordWrappedLabel); + }; + + } + }, + { + "Download as Texture", () => + { + CommonUtils.SaveTextureAsPNG(selectedTexture, importPreset:PluginSettings.TexturePreset); + buttonDetailPanelDrawFunction = () => + { + GUILayout.Label("Your image has been dowloaded as a Texture in the folder you specified in the Scenario Plugin Settings.", EditorStyles.wordWrappedLabel); + }; + } + }, + { + "Download as Sprite", () => + { + string messageWhileDownloading = "Please wait... The background is currently being removed. The result will be downloaded in the folder you specified in the Scenario Plugin Settings."; + string messageSuccess = "Your image has been downloaded in the folder you specified in the Scenario Plugin Settings."; + + //What to do when file is downloaded + Action successAction = (filePath) => + { + buttonDetailPanelDrawFunction = () => + { + GUILayout.Label(messageSuccess, EditorStyles.wordWrappedLabel); + }; + + if (PluginSettings.UsePixelsUnitsEqualToImage) + { + CommonUtils.ApplyPixelsPerUnit(filePath); + } + }; + + if (PluginSettings.AlwaysRemoveBackgroundForSprites) + { + BackgroundRemoval.RemoveBackground(Images.GetTextureByImageId(selectedImageId), imageBytes => + { + CommonUtils.SaveImageDataAsPNG(imageBytes, null, PluginSettings.SpritePreset, successAction); + }); + + buttonDetailPanelDrawFunction = () => + { + GUILayout.Label(messageWhileDownloading, EditorStyles.wordWrappedLabel); + }; + } + else + { + CommonUtils.SaveTextureAsPNG(selectedTexture, null, PluginSettings.SpritePreset, successAction); + } + } + }, + { + "Download as a Tile", () => + { + /// Contains the side window when the user want to download an image as a tile + TileCreator tileCreator = new(selectedImageId); + buttonDetailPanelDrawFunction = tileCreator.OnGUI; + } + }, + { "Pixelate Image", () => PixelEditor.ShowWindow(selectedTexture, Images.GetImageDataById(selectedImageId))}, + { "Upscale Image", () => UpscaleEditor.ShowWindow(selectedTexture, Images.GetImageDataById(selectedImageId))}, + { + "Delete", () => + { + // Delete the image at the selected index and clear the selected texture + images.DeleteImage(selectedImageId); + buttonDetailPanelDrawFunction = () => + { + GUILayout.Label("Your image has been deleted."); + }; + selectedTexture = null; + } + } + }; } - public void SetPreviousPage() + /// + /// This function is responsible for rendering all the interface + /// + /// The dimensions of the UI element. + public void OnGUI(Rect _dimension) { - firstImageIndex -= pageImageCount; - if (firstImageIndex <= 0) + DrawBackground(_dimension); + float previewWidth = 320f; + float imageListWidth = selectedTexture != null ? _dimension.width - previewWidth : _dimension.width; + float boxWidth = (imageListWidth - padding * (itemsPerRow - 1)) / itemsPerRow; + float boxHeight = boxWidth; + + int numRows = Mathf.CeilToInt((float)Images.imageDataList.Count / itemsPerRow); + + float scrollViewHeight = (boxHeight + padding) * numRows; + var scrollViewRect = new Rect(0, 25, imageListWidth, _dimension.height); + var viewRect = new Rect(0, 0, imageListWidth - 20, scrollViewHeight + 50); + float totalHeight = 0; + + if (Images.imageDataList.Count == 0) { - firstImageIndex = 0; + ShowLoadingPage(); } + else + { + scrollPosition = GUI.BeginScrollView(scrollViewRect, scrollPosition, viewRect); + { + DrawTextureBoxes(boxWidth, boxHeight, out totalHeight); + } + if(!isLoading) + { + if (GUI.Button(new Rect(0, totalHeight + 10, imageListWidth, 20), new GUIContent("Load More", "Load next images from your account."))) + { + isLoading = true; + Images.GetInferencesData( () => + { + isLoading = false; + }); + } + } + GUI.EndScrollView(); + } + + GUILayout.FlexibleSpace(); + + DrawSelectedTextureSection(_dimension, previewWidth, imageListWidth); } - public void UpdatePage() + private void ShowLoadingPage() { - pageList = Images._imageDataList - .GetRange(firstImageIndex, Math.Min(pageImageCount, Images._imageDataList.Count - firstImageIndex)) - .OrderByDescending(x => x.CreatedAt) - .ToList(); - - FetchPageTextures(); + CustomStyle.Label("Loading images..."); } - private void FetchPageTextures() + /// + /// Draws the section displaying the title, the close button, the selected texture along with its details. + /// This function calculates and renders the selected image, its dimensions, and associated UI elements. + /// + /// The position and dimensions of the parent container. + /// The width of the preview section. + /// The position, on X axe, where the selected texture section should begin to draw. + private void DrawSelectedTextureSection(Rect _parentDimension, float _sectionWidth, float _leftPosition) { - var tempTextures = new Texture2D[pageList.Count]; - int loadedCount = 0; + if (selectedTexture == null) + return; - for (int i = 0; i < pageList.Count; i++) + GUILayout.BeginArea(new Rect(_leftPosition, 20, _sectionWidth, _parentDimension.height - 20)); { - int index = i; - CommonUtils.FetchTextureFromURL(pageList[index].Url, texture => + CustomStyle.Space(5); + GUILayout.BeginHorizontal(); { - tempTextures[index] = texture; - loadedCount++; - - if (loadedCount == pageList.Count) + GUILayout.Label("Selected Image", EditorStyles.boldLabel); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Close", EditorStyles.miniButtonRight, GUILayout.Width(50))) { - textures.Clear(); - textures.AddRange(tempTextures); + CloseSelectedTextureSection(); } - }); + } + GUILayout.EndHorizontal(); + + if (selectedTexture != null) //if you click on close, the selected texture can be null + DrawScrollableArea(_sectionWidth, _parentDimension.height - 70); } + GUILayout.EndArea(); } - public void ClearSelectedTexture() + /// + /// Draws the scrollable area containing the selected image, the action buttons, and the image data. + /// + /// The width of the scrollable area. + /// The height of the scrollable area. + private void DrawScrollableArea(float _sectionWidth, float _textureSectionHeight) { - selectedTexture = null; + selectedTextureSectionScrollPosition = GUILayout.BeginScrollView(selectedTextureSectionScrollPosition, GUILayout.Width(_sectionWidth), GUILayout.Height(_textureSectionHeight)); + { + DrawSelectedImage(_sectionWidth); + CustomStyle.Space(10); + GUILayout.BeginVertical(); + { + if (buttonDetailPanelDrawFunction != null) + { + DrawButtonDetailPanel(); + } + else + { + DrawButtons(); + CustomStyle.Space(10); + DrawImageData(); + + } + } + GUILayout.EndVertical(); + CustomStyle.Space(10); + } + GUILayout.EndScrollView(); } - public void OnGUI(Rect position) + /// + /// Draws the selected image in the preview section. + /// This function renders the selected image along with its label and close button. + /// + /// The width of the preview section. + private void DrawSelectedImage(float previewWidth) { - DrawBackground(position); - - float previewWidth = 309f; - float scrollViewWidth = selectedTexture != null ? position.width - previewWidth : position.width; - float boxWidth = (scrollViewWidth - padding * (itemsPerRow - 1)) / itemsPerRow; - float boxHeight = boxWidth; - - int numRows = Mathf.CeilToInt((float)textures.Count / itemsPerRow); - - float scrollViewHeight = (boxHeight + padding) * numRows; - - scrollPosition = GUI.BeginScrollView(new Rect(0, 20, scrollViewWidth, position.height - 70), scrollPosition, - new Rect(0, 0, scrollViewWidth - 20, scrollViewHeight)); + float aspectRatio = (float)selectedTexture.width / selectedTexture.height; + float paddedPreviewWidth = previewWidth - 4 * padding; + float paddedPreviewHeight = paddedPreviewWidth / aspectRatio; - for (int i = 0; i < textures.Count; i++) + GUILayout.BeginHorizontal(); { - DrawTextureButton(boxWidth, boxHeight, i); + CustomStyle.Space(padding); + GUILayout.Label(selectedTexture, GUILayout.Width(paddedPreviewWidth), GUILayout.Height(paddedPreviewHeight)); + CustomStyle.Space(padding); } + GUILayout.EndHorizontal(); + } - GUI.EndScrollView(); + /// + /// Renders the UI in the modal of a selected image with a set of buttons, each associated with specific actions. + /// The buttons are displayed horizontally, and when clicked, they trigger their respective actions. + /// + private void DrawButtons() + { - GUILayout.BeginArea(new Rect(0, position.height - 50, scrollViewWidth, 50)); + // Iterate through the buttons and display them in a horizontal layout + foreach (var button in buttonActions) { GUILayout.BeginHorizontal(); - if (firstImageIndex > 0 && GUILayout.Button("Previous Page")) - { - SetPreviousPage(); - UpdatePage(); - } - if (firstImageIndex < Images._imageDataList.Count - pageImageCount && GUILayout.Button("Next Page")) + // Create a button with the button label + if (GUILayout.Button(button.Key, GUILayout.Height(40))) { - SetNextPage(); - UpdatePage(); + // When the button is clicked, execute the associated action + button.Value(); } GUILayout.EndHorizontal(); + // Add spacing between buttons for visual separation + CustomStyle.Space(5); } - GUILayout.EndArea(); - - GUILayout.FlexibleSpace(); - - DrawSelectedTextureSection(position, previewWidth, scrollViewWidth); } + /// + /// Draws the data associated with the currently selected image, including prompt, steps, size, guidance, and scheduler. + /// This function displays textual information about the selected image's attributes. + /// private void DrawImageData() { - var currentImageData = Images._imageDataList[selectedTextureIndex]; + var currentImageData = Images.GetImageDataById(selectedImageId); //try to get image from Images + if (currentImageData == null) + currentImageData = DataCache.instance.GetImageDataById(selectedImageId); //try to get from Datacache (if it has just been prompted) + if (currentImageData == null) + return; + GUILayout.BeginVertical(); { CustomStyle.Label("Prompt:"); @@ -166,159 +352,141 @@ private void DrawImageData() GUILayout.EndVertical(); } - private static void DrawBackground(Rect position) - { - Color backgroundColor = EditorStyle.GetBackgroundColor(); - EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), backgroundColor); - } - - private void DrawSelectedTextureSection(Rect position, float previewWidth, float scrollViewWidth) + /// + /// When using one of the action button, sometime they opens a panel with some informations and other steps + /// + private void DrawButtonDetailPanel() { - if (selectedTexture == null) - { - return; - } + buttonDetailPanelDrawFunction?.Invoke(); - GUILayout.BeginArea(new Rect(scrollViewWidth, 20, previewWidth, position.height - 20)); + if (GUILayout.Button("< Back", EditorStyles.miniButtonLeft)) { - DrawScrollableArea(previewWidth); + buttonDetailPanelDrawFunction = null; } - GUILayout.EndArea(); + } - private void DrawScrollableArea(float previewWidth) + /// + /// Draws a grid of texture boxes, each containing an image or loading indicator, and handles interactions. + /// This function renders a grid of image boxes and handles interactions . + /// Possible improvement : Provide visual feedback when images are being loaded. For example, display a loading spinner or progress bar within the texture boxes while images are being fetched or loaded asynchronously. + /// + /// The width of each texture box. + /// The height of each texture box. + private void DrawTextureBoxes(float boxWidth, float boxHeight, out float totalHeight) { - DrawSelectedImage(previewWidth); - CustomStyle.Space(10); - GUILayout.BeginVertical(); - { - DrawFirstButtons(); - CustomStyle.Space(10); - DrawSecondButtons(); - CustomStyle.Space(10); - DrawImageData(); - } - GUILayout.EndVertical(); - CustomStyle.Space(10); - } + totalHeight = 0; - private void DrawSecondButtons() - { - string[] buttonNames = { "Remove Background", "Pixelate Image", "Upscale Image" /*, "Generate More Images"*/ }; - System.Action[] buttonCallbacks = - { - () => images.RemoveBackgroundForImageAtIndex(selectedTextureIndex + firstImageIndex), - () => PixelEditor.ShowWindow(selectedTexture, Images._imageDataList[selectedTextureIndex + firstImageIndex]), - () => UpscaleEditor.ShowWindow(selectedTexture, Images._imageDataList[selectedTextureIndex + firstImageIndex]) /*, - () => { - // TODO: Implement generate more images functionality - }*/ - }; + //Create a list of Image Data + List imagesToDisplay = new List(); - for (int i = 0; i < buttonNames.Length; i++) + //Add all the current image that are in the DataCache (the ones that the user generated this session) + imagesToDisplay.AddRange(DataCache.instance.GetImageDataList()); + + //add everything from the cloud that is not already in the DataCache + foreach(ImageDataStorage.ImageData imageData in Images.imageDataList) { - if (GUILayout.Button(buttonNames[i], GUILayout.Height(40))) + if(!imagesToDisplay.Exists(x => x.Id == imageData.Id)) { - buttonCallbacks[i](); + imagesToDisplay.Add(imageData); } - CustomStyle.Space(10); } - } - public void RefineImage() - { - if (PromptWindow.promptWindowUI == null) + for (int i = 0; i < imagesToDisplay.Count; i++) { - Debug.LogError("Prompt Window not found: Open Prompt Window, and try again."); - return; - } - var imageData = Images._imageDataList[selectedTextureIndex + firstImageIndex]; - PromptWindowUI.imageUpload = selectedTexture; - PromptWindow.promptWindowUI.isImageToImage = true; - PromptWindow.promptWindowUI.isTextToImage = false; - PromptWindow.promptWindowUI.promptinputText = imageData.Prompt; - PromptWindow.promptWindowUI.tags = imageData.Prompt.Split(',').ToList(); - PromptWindow.promptWindowUI.samplesliderValue = imageData.Steps; - PromptWindow.promptWindowUI.widthSliderValue = (int)imageData.Size.x; - PromptWindow.promptWindowUI.heightSliderValue = (int)imageData.Size.y; - PromptWindow.promptWindowUI.guidancesliderValue = imageData.Guidance; - PromptWindow.promptWindowUI.seedinputText = imageData.Seed; - PromptWindow.ShowWindow(); - } + int rowIndex = Mathf.FloorToInt((float)i / itemsPerRow); + int colIndex = i % itemsPerRow; - private void DrawFirstButtons() - { - string[] buttonNames = { "Refine Image", "Download", "Delete" }; - System.Action[] buttonCallbacks = - { - () => RefineImage(), - () => CommonUtils.SaveTextureAsPNG(selectedTexture), - () => - { - images.DeleteImageAtIndex(selectedTextureIndex + firstImageIndex); - selectedTexture = null; - } - }; + Rect boxRect = CalculateBoxRect(boxWidth, boxHeight, rowIndex, colIndex); + Texture2D texture = imagesToDisplay[i].texture; - GUILayout.BeginHorizontal(); - for (int i = 0; i < buttonNames.Length; i++) - { - if (GUILayout.Button(buttonNames[i], GUILayout.Height(40))) + totalHeight = boxRect.y + boxRect.height; + + if (texture != null) { - buttonCallbacks[i](); + HandleImageClickEvents(boxRect, texture, imagesToDisplay[i].Id); + RenderTextureBox(boxRect, texture); } - - // Add spacing between buttons but not after the last button - if (i < buttonNames.Length - 1) + else { - CustomStyle.Space(5); + RenderLoadingBox(boxRect); } } - GUILayout.EndHorizontal(); } - private void DrawSelectedImage(float previewWidth) - { - GUILayout.Label("Selected Image", EditorStyles.boldLabel); - CustomStyle.Space(10); + #endregion - float aspectRatio = (float)selectedTexture.width / selectedTexture.height; - float paddedPreviewWidth = previewWidth - 2 * padding; - float paddedPreviewHeight = paddedPreviewWidth / aspectRatio; - GUILayout.BeginHorizontal(); + #region Utility Methods + + + /// + /// Calculates the position and dimensions of each texture box within the grid based on the specified box width, box height, row index, and column index. + /// + /// The width of each texture box. + /// The height of each texture box. + /// The row index of the texture box. + /// The column index of the texture box. + /// A Rect representing the position and dimensions of the texture box. + private Rect CalculateBoxRect(float boxWidth, float boxHeight, int rowIndex, int colIndex) + { + float x = colIndex * (boxWidth + padding); + float y = rowIndex * (boxHeight + padding); + return new Rect(x, y, boxWidth, boxHeight); + } + + /// + /// Manages interactions with texture boxes, including selecting images when clicked. + /// + /// The Rect representing the boundaries of the texture box. + /// The Texture2D associated with the texture box. + /// The id of the ImageData for which the texture is linked. + private void HandleImageClickEvents(Rect boxRect, Texture2D texture, string _id) + { + if (GUI.Button(boxRect, "")) { - CustomStyle.Space(padding); - GUILayout.Label(selectedTexture, GUILayout.Width(paddedPreviewWidth), - GUILayout.Height(paddedPreviewHeight)); - CustomStyle.Space(padding); + selectedTexture = texture; + selectedImageId = _id; + buttonDetailPanelDrawFunction = null; //reset the button detail panel when you select a new image } - GUILayout.EndHorizontal(); } - private void DrawTextureButton(float boxWidth, float boxHeight, int i) + /// + /// Renders a texture box by drawing the associated image within the specified box's boundaries, scaling it to fit. + /// + /// The Rect representing the boundaries of the texture box. + /// The Texture2D to render within the texture box. + private void RenderTextureBox(Rect boxRect, Texture2D texture) { - int rowIndex = Mathf.FloorToInt((float)i / itemsPerRow); - int colIndex = i % itemsPerRow; - - Rect boxRect = new Rect(colIndex * (boxWidth + padding), rowIndex * (boxHeight + padding), boxWidth, boxHeight); - Texture2D texture = textures[i]; + GUI.DrawTexture(boxRect, texture, ScaleMode.ScaleToFit); + } - if (texture != null) + /// + /// Renders a loading indicator within a texture box, providing visual feedback to users while images are being fetched or loaded asynchronously. + /// + /// The Rect representing the boundaries of the texture box. + private void RenderLoadingBox(Rect boxRect) + { + GUIStyle style = new GUIStyle(GUI.skin.label) { - if (GUI.Button(boxRect, "")) - { - selectedTexture = texture; - selectedTextureIndex = i; - } + alignment = TextAnchor.MiddleCenter + }; + GUI.color = Color.white; + GUI.Label(boxRect, $"Loading...", style); + } - GUI.DrawTexture(boxRect, texture, ScaleMode.ScaleToFit); - } - else - { - GUI.Label(new Rect(boxRect.x, boxRect.y + boxHeight, boxWidth, 20), "Loading.."); - } + public void CloseSelectedTextureSection() + { + selectedTexture = null; } + + public void OnClose() + { + isLoading = false; + } + + #endregion + } } \ No newline at end of file diff --git a/package/Editor/PromptImages/PromptImages.cs b/package/Editor/PromptImages/PromptImages.cs deleted file mode 100644 index c5f56b0..0000000 --- a/package/Editor/PromptImages/PromptImages.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Collections; -using System.Threading.Tasks; -using RestSharp; -using Unity.EditorCoroutines.Editor; -using UnityEditor; -using UnityEngine; -using UnityEngine.Networking; - -namespace Scenario.Editor -{ - public class PromptImages : EditorWindow - { - public static PromptImagesUI promptImagesUI = new(); - - public static string downloadPath; - - [MenuItem("Window/Scenario/Prompt Images")] - public static void ShowWindow() - { - UpdateImages(); - - var promptImages = (PromptImages)GetWindow(typeof(PromptImages)); - promptImagesUI.Init(promptImages); - - downloadPath = EditorPrefs.GetString("SaveFolder", "Assets"); - } - - public void DeleteImageAtIndex(int selectedTextureIndex) - { - var imgData = DataCache.instance.GetImageDataAtIndex(selectedTextureIndex); - - string imageId = imgData.Id; - string modelId = DataCache.instance.SelectedModelId; - string inferenceId = imgData.InferenceId; - EditorCoroutineUtility.StartCoroutineOwnerless(DeleteImageRequest(inferenceId, modelId, imageId)); - - Repaint(); - } - - public void CloseSelectedTextureSection() - { - //ClearData(); - promptImagesUI.selectedTexture = null; - promptImagesUI.selectedImageId = null; - } - - private static async void LoadTexture(string url, Action result) - { - using UnityWebRequest www = UnityWebRequestTexture.GetTexture(url); - - www.SendWebRequest(); - - while (!www.isDone) - { - await Task.Delay(10); - } - - if (www.result != UnityWebRequest.Result.Success) - { - Debug.LogError(www.error + $"\n{url}"); - result(null); - } - - result(DownloadHandlerTexture.GetContent(www)); - } - - private void OnGUI() - { - promptImagesUI.OnGUI(this.position); - } - - private static void UpdateImages() - { - for (int i = DataCache.instance.GetImageDataCount() - 1; i >= 0; i--) - { - var imageData = DataCache.instance.GetImageDataAtIndex(i); - - if (imageData.Url != null && imageData.Url.Length > 10 && imageData.texture == null) - { - LoadTexture(imageData.Url, result => - { - imageData.texture = result; - - if (promptImagesUI != null) - { - if (promptImagesUI.promptImages != null) - { - promptImagesUI.promptImages.Repaint(); - } - } - }); - } - } - - if (promptImagesUI != null) - { - if (promptImagesUI.promptImages != null) - { - promptImagesUI.promptImages.Repaint(); - } - } - } - - IEnumerator DeleteImageRequest(string inferenceId, string modelId, string imageId) - { - Debug.Log("Requesting image deletion please wait.."); - - string url = $"{PluginSettings.ApiUrl}/models/{modelId}/inferences/{inferenceId}/images/{imageId}"; - Debug.Log(url); - - RestClient client = new RestClient(url); - RestRequest request = new RestRequest(Method.DELETE); - request.AddHeader("accept", "application/json"); - request.AddHeader("Authorization", $"Basic {PluginSettings.EncodedAuth}"); - - yield return client.ExecuteAsync(request, response => - { - if (response.ErrorException != null) - { - Debug.Log($"Error: {response.ErrorException.Message}"); - } - else - { - Debug.Log($"Response: {response.Content}"); - } - }); - } - - /// - /// When Unity reset the GUI (after compiling for example), the link between this script and the GUI can be broken, so I update it - /// - private void OnValidate() - { - ShowWindow(); - } - - private void OnDestroy() - { - CloseSelectedTextureSection(); - } - - /*private void ClearData() - { - DataCache.instance.ClearAllImageData(); - }*/ - - /// - /// Find the selected texture according to the current user selection and call the API to remove its background - /// - /// - /// Returns a callback with the byte array corresponding of the image (withouth background) data - internal void RemoveBackground(int selectedTextureIndex, Action callback_OnBackgroundRemoved) - { - BackgroundRemoval.RemoveBackground(DataCache.instance.GetImageDataAtIndex(selectedTextureIndex).texture, imageBytes => - { - callback_OnBackgroundRemoved?.Invoke(imageBytes); - }); - } - } -} \ No newline at end of file diff --git a/package/Editor/PromptImages/PromptImages.cs.meta b/package/Editor/PromptImages/PromptImages.cs.meta deleted file mode 100644 index 2165f66..0000000 --- a/package/Editor/PromptImages/PromptImages.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 3e3f6143f79af0344ba84ad3f4e09d37 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/package/Editor/PromptImages/PromptImagesUI.cs b/package/Editor/PromptImages/PromptImagesUI.cs deleted file mode 100644 index 71461ae..0000000 --- a/package/Editor/PromptImages/PromptImagesUI.cs +++ /dev/null @@ -1,524 +0,0 @@ -using Scenario.Editor; -using System; -using System.Collections.Generic; -using UnityEditor; -using UnityEngine; - -namespace Scenario.Editor -{ - public class PromptImagesUI - { - public int itemsPerRow = 5; - public float padding = 10f; - public Vector2 scrollPosition = Vector2.zero; - public Vector2 selectedTextureSectionScrollPosition = Vector2.zero; - public Texture2D selectedTexture = null; - public string selectedImageId = null; - - internal PromptImages promptImages; - - private int selectedTextureIndex = 0; - private bool isModalOpen = false; - - // Dictionary containing button labels and associated actions - private Dictionary buttonActions = new Dictionary(); - - /// - /// Contain the draw function of the current Detail Panel according to the button clicked - /// - private Action buttonDetailPanelDrawFunction = null; - - - #region Initialization - - /// - /// Initializes the PromptImagesUI class with the provided PromptImages instance. - /// - /// The PromptImages instance to initialize with. - public void Init(PromptImages promptImg) - { - promptImages = promptImg; - InitializeButtons(); - } - - #endregion - - - #region UI Drawing - - /// - /// Draws the background of the UI element with the specified position. - /// This function fills the background of a UI element with a given color. - /// - /// The position and dimensions of the UI element. - private static void DrawBackground(Rect position) - { - Color backgroundColor = EditorStyle.GetBackgroundColor(); - EditorGUI.DrawRect(new Rect(0, 0, position.width, position.height), backgroundColor); - } - - private void InitializeButtons() - { - // Dictionary containing button labels and associated actions - buttonActions = new Dictionary() - { - { - "Set Image as Reference", () => - { - PromptWindowUI.imageUpload = selectedTexture; - PromptWindow.ShowWindow(); - PromptWindow.SetImageControlTab(1); - buttonDetailPanelDrawFunction = () => - { - GUILayout.Label("Your image has been set in the Image to Image parameter in the Prompt Window.", EditorStyles.wordWrappedLabel); - }; - - } - }, - { - "Download as Texture", () => - { - CommonUtils.SaveTextureAsPNG(selectedTexture, importPreset:PluginSettings.TexturePreset); - buttonDetailPanelDrawFunction = () => - { - GUILayout.Label("Your image has been dowloaded as a Texture in the folder you specified in the Scenario Plugin Settings.", EditorStyles.wordWrappedLabel); - }; - } - }, - { - "Download as Sprite", () => - { - string messageWhileDownloading = "Please wait... The background is currently being removed. The result will be downloaded in the folder you specified in the Scenario Plugin Settings."; - string messageSuccess = "Your image has been downloaded in the folder you specified in the Scenario Plugin Settings."; - - //What to do when file is downloaded - Action successAction = (filePath) => - { - buttonDetailPanelDrawFunction = () => - { - GUILayout.Label(messageSuccess, EditorStyles.wordWrappedLabel); - }; - - if (PluginSettings.UsePixelsUnitsEqualToImage) - { - CommonUtils.ApplyPixelsPerUnit(filePath); - } - }; - - - if (PluginSettings.AlwaysRemoveBackgroundForSprites) - { - promptImages.RemoveBackground(selectedTextureIndex, (imageBytes) => - { - CommonUtils.SaveImageDataAsPNG(imageBytes, null, PluginSettings.SpritePreset, successAction); - }); - - buttonDetailPanelDrawFunction = () => - { - GUILayout.Label(messageWhileDownloading, EditorStyles.wordWrappedLabel); - }; - } - else - { - CommonUtils.SaveTextureAsPNG(selectedTexture, null, PluginSettings.SpritePreset, successAction); - } - } - }, - { - "Download as a Tile", () => - { - /// Contains the side window when the user want to download an image as a tile - PromptImagesTileCreator tileCreator = new(promptImages, selectedTextureIndex); - buttonDetailPanelDrawFunction = tileCreator.OnGUI; - } - }, - { "Pixelate Image", () => PixelEditor.ShowWindow(selectedTexture, DataCache.instance.GetImageDataAtIndex(selectedTextureIndex))}, - { "Upscale Image", () => UpscaleEditor.ShowWindow(selectedTexture, DataCache.instance.GetImageDataAtIndex(selectedTextureIndex))}, - { - "Delete", () => - { - // Delete the image at the selected index and clear the selected texture - promptImages.DeleteImageAtIndex(selectedTextureIndex); - buttonDetailPanelDrawFunction = () => - { - GUILayout.Label("Your image has been deleted."); - }; - selectedTexture = null; - } - } - }; - } - - /// - /// This function is responsible for rendering all the interface - /// - /// The position and dimensions of the UI element. - public void OnGUI(Rect position) - { - DrawBackground(position); - - if (GUILayout.Button("Clear All Images")) - { - Debug.Log("Clearing Prompt Images"); - DataCache.instance.ClearAllImageData(); - selectedTexture = null; - } - float previewWidth = 309f; - float scrollViewWidth = selectedTexture != null ? position.width - previewWidth : position.width; - float boxWidth = (scrollViewWidth - padding * (itemsPerRow - 1)) / itemsPerRow; - float boxHeight = boxWidth; - - int numRows = Mathf.CeilToInt((float)DataCache.instance.GetImageDataCount() / itemsPerRow); - - float scrollViewHeight = (boxHeight + padding) * numRows; - var scrollViewRect = new Rect(0, 25, scrollViewWidth, position.height - 70); - var viewRect = new Rect(0, 0, scrollViewWidth - 20, scrollViewHeight); - - scrollPosition = GUI.BeginScrollView(scrollViewRect, scrollPosition, viewRect); - { - DrawTextureBoxes(boxWidth, boxHeight); - } - GUI.EndScrollView(); - - GUILayout.FlexibleSpace(); - - if (isModalOpen) - { - DrawZoomedImage(new Rect(0, 0, position.width, position.height)); - } - - DrawSelectedTextureSection(position, previewWidth, scrollViewWidth); - } - - /// - /// Draws the section displaying the title, the close button, the selected texture along with its details. - /// This function calculates and renders the selected image, its dimensions, and associated UI elements. - /// - /// The position and dimensions of the UI element. - /// The width of the preview section. - /// The width of the scrollable area. - private void DrawSelectedTextureSection(Rect position, float previewWidth, float scrollViewWidth) - { - if (selectedTexture == null || DataCache.instance.GetImageDataCount() <= 0) - return; - - GUILayout.BeginArea(new Rect(scrollViewWidth, 20, previewWidth, position.height - 20)); - { - CustomStyle.Space(5); - GUILayout.BeginHorizontal(); - { - GUILayout.Label("Selected Image", EditorStyles.boldLabel); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Close", EditorStyles.miniButtonRight, GUILayout.Width(50))) - { - promptImages.CloseSelectedTextureSection(); - } - } - GUILayout.EndHorizontal(); - - if (selectedTexture != null) //if you click on close, the selected texture can be null - DrawScrollableArea(previewWidth, position.height); - } - GUILayout.EndArea(); - } - - /// - /// Draws the scrollable area containing the selected image, the action buttons, and the image data. - /// - /// The width of the scrollable area. - /// The height of the scrollable area. - private void DrawScrollableArea(float previewWidth, float previewHeight) - { - var scrollViewRect = new Rect(0, 30, previewWidth + 20, previewHeight); - var viewRect = new Rect(0, 0, previewWidth, previewHeight + 150); - - selectedTextureSectionScrollPosition = GUI.BeginScrollView(scrollViewRect, selectedTextureSectionScrollPosition, viewRect); - { - DrawSelectedImage(previewWidth); - CustomStyle.Space(10); - GUILayout.BeginVertical(); - { - if (buttonDetailPanelDrawFunction != null) - { - DrawButtonDetailPanel(); - } - else - { - DrawButtons(); - CustomStyle.Space(10); - DrawImageData(); - } - } - GUILayout.EndVertical(); - CustomStyle.Space(10); - } - GUI.EndScrollView(); - } - - /// - /// Draws the selected image in the preview section. - /// This function renders the selected image along with its label and close button. - /// - /// The width of the preview section. - private void DrawSelectedImage(float previewWidth) - { - float aspectRatio = (float)selectedTexture.width / selectedTexture.height; - float paddedPreviewWidth = previewWidth - 2 * padding; - float paddedPreviewHeight = paddedPreviewWidth / aspectRatio; - - GUILayout.BeginHorizontal(); - { - CustomStyle.Space(padding); - GUILayout.Label(selectedTexture, GUILayout.Width(paddedPreviewWidth), - GUILayout.Height(paddedPreviewHeight)); - CustomStyle.Space(padding); - } - GUILayout.EndHorizontal(); - } - - /// - /// Renders the UI in the modal of a selected image with a set of buttons, each associated with specific actions. - /// The buttons are displayed horizontally, and when clicked, they trigger their respective actions. - /// - private void DrawButtons() - { - - // Iterate through the buttons and display them in a horizontal layout - foreach (var button in buttonActions) - { - GUILayout.BeginHorizontal(); - // Create a button with the button label - if (GUILayout.Button(button.Key, GUILayout.Height(40))) - { - // When the button is clicked, execute the associated action - button.Value(); - } - GUILayout.EndHorizontal(); - // Add spacing between buttons for visual separation - CustomStyle.Space(5); - } - } - - /// - /// Draws the data associated with the currently selected image, including prompt, steps, size, guidance, and scheduler. - /// This function displays textual information about the selected image's attributes. - /// - private void DrawImageData() - { - var currentImageData = DataCache.instance.GetImageDataAtIndex(selectedTextureIndex); - GUILayout.BeginVertical(); - { - CustomStyle.Label("Prompt:"); - CustomStyle.Label($"{currentImageData.Prompt}"); - CustomStyle.Space(padding); - GUILayout.BeginHorizontal(); - { - CustomStyle.Label($"Steps: {currentImageData.Steps}"); - CustomStyle.Label($"Size: {currentImageData.Size}"); - } - GUILayout.EndHorizontal(); - CustomStyle.Space(padding); - GUILayout.BeginHorizontal(); - { - CustomStyle.Label($"Guidance: {currentImageData.Guidance}"); - CustomStyle.Label($"Scheduler: {currentImageData.Scheduler}"); - } - GUILayout.EndHorizontal(); - CustomStyle.Space(padding); - GUILayout.BeginHorizontal(); - { - CustomStyle.Label($"Seed: {currentImageData.Seed}"); - } - GUILayout.EndHorizontal(); - } - GUILayout.EndVertical(); - } - - /// - /// When using one of the action button, sometime they opens a panel with some informations and other steps - /// - private void DrawButtonDetailPanel() - { - buttonDetailPanelDrawFunction?.Invoke(); - - if (GUILayout.Button("< Back", EditorStyles.miniButtonLeft)) - { - buttonDetailPanelDrawFunction = null; - } - } - - - /// - /// Draws a modal displaying the selected image in a bigger size with the option to close it when clicking outside the image. - /// This function renders a modal pop-up for a selected image and allows it to be closed when clicking outside the image boundaries. - /// - /// The position and dimensions of the UI element. - private void DrawZoomedImage(Rect position) - { - // Determine image dimensions at 2x scale - float imageWidth = selectedTexture.width * 2; - float imageHeight = selectedTexture.height * 2; - - // If the scaled image exceeds the window dimensions, adjust it - if (imageWidth > position.width) - { - float ratio = position.width / imageWidth; - imageWidth = position.width; - imageHeight *= ratio; - } - - if (imageHeight > position.height) - { - float ratio = position.height / imageHeight; - imageHeight = position.height; - imageWidth *= ratio; - } - - // Compute the position to center the image in the window - float imageX = (position.width - imageWidth) / 2; - float imageY = (position.height - imageHeight) / 2; - - // Draw the image - GUI.DrawTexture(new Rect(imageX, imageY, imageWidth, imageHeight), selectedTexture, ScaleMode.ScaleToFit); - - // Close the modal if clicked outside the image - if (Event.current.type == EventType.MouseDown && - !new Rect(imageX, imageY, imageWidth, imageHeight).Contains(Event.current.mousePosition)) - { - isModalOpen = false; - Event.current.Use(); - } - } - - /// - /// Draws a grid of texture boxes, each containing an image or loading indicator, and handles interactions like double-clicking. - /// This function renders a grid of image boxes and handles interactions such as double-clicking an image for further details. - /// Possible improvement : Provide visual feedback when images are being loaded. For example, display a loading spinner or progress bar within the texture boxes while images are being fetched or loaded asynchronously. - /// - /// The width of each texture box. - /// The height of each texture box. - private void DrawTextureBoxes(float boxWidth, float boxHeight) - { - for (int i = 0; i < DataCache.instance.GetImageDataCount(); i++) - { - int rowIndex = Mathf.FloorToInt((float)i / itemsPerRow); - int colIndex = i % itemsPerRow; - - Rect boxRect = CalculateBoxRect(boxWidth, boxHeight, rowIndex, colIndex); - Texture2D texture = DataCache.instance.GetImageDataAtIndex(i).texture; - - if (texture != null) - { - HandleImageClickEvents(boxRect, texture, i); - RenderTextureBox(boxRect, texture); - } - else - { - RenderLoadingBox(boxRect); - } - } - } - - - #endregion - - - #region Utility Methods - - /// - /// Calculates the position and dimensions of each texture box within the grid based on the specified box width, box height, row index, and column index. - /// - /// The width of each texture box. - /// The height of each texture box. - /// The row index of the texture box. - /// The column index of the texture box. - /// A Rect representing the position and dimensions of the texture box. - private Rect CalculateBoxRect(float boxWidth, float boxHeight, int rowIndex, int colIndex) - { - float x = colIndex * (boxWidth + padding); - float y = rowIndex * (boxHeight + padding); - return new Rect(x, y, boxWidth, boxHeight); - } - - /// - /// Manages interactions with texture boxes, including detecting double-click events to trigger specific actions or selecting images when clicked. - /// - /// The Rect representing the boundaries of the texture box. - /// The Texture2D associated with the texture box. - /// The index of the texture box in the grid. - private void HandleImageClickEvents(Rect boxRect, Texture2D texture, int index) - { - if (IsDoubleClick(boxRect)) - { - HandleDoubleClickAction(texture, index); - } - else if (GUI.Button(boxRect, "")) - { - HandleImageSelection(texture, index); - } - } - - /// - /// Determines whether a double-click event has occurred within the boundaries of a texture box, helping identify when to activate the enlarged view of an image. - /// - /// The Rect representing the boundaries of the texture box. - /// True if a double-click event occurred within the texture box; otherwise, false. - private bool IsDoubleClick(Rect boxRect) - { - return Event.current.type == EventType.MouseDown && - Event.current.clickCount == 2 && - boxRect.Contains(Event.current.mousePosition); - } - - /// - /// Responds to a double-click event by displaying the selected image in an enlarged modal view and marking the modal as open. - /// - /// The Texture2D to display in the enlarged view. - /// The index of the selected image in the grid. - private void HandleDoubleClickAction(Texture2D texture, int index) - { - selectedTexture = texture; - isModalOpen = true; - Event.current.Use(); - } - - /// - /// Handles the selection of a texture box, setting the selected texture and index when clicked. - /// - /// The Texture2D associated with the selected texture box. - /// The index of the selected texture box in the grid. - private void HandleImageSelection(Texture2D texture, int index) - { - selectedTexture = texture; - selectedTextureIndex = index; - buttonDetailPanelDrawFunction = null; //reset the button detail panel when you select a new image - } - - /// - /// Renders a texture box by drawing the associated image within the specified box's boundaries, scaling it to fit. - /// - /// The Rect representing the boundaries of the texture box. - /// The Texture2D to render within the texture box. - private void RenderTextureBox(Rect boxRect, Texture2D texture) - { - GUI.DrawTexture(boxRect, texture, ScaleMode.ScaleToFit); - } - - /// - /// Renders a loading indicator within a texture box, providing visual feedback to users while images are being fetched or loaded asynchronously. - /// - /// The Rect representing the boundaries of the texture box. - private void RenderLoadingBox(Rect boxRect) - { - GUIStyle style = new GUIStyle(GUI.skin.label) - { - alignment = TextAnchor.MiddleCenter - }; - GUI.color = Color.white; - GUI.Label(boxRect, "Loading...", style); - } - - #endregion - - } -} \ No newline at end of file diff --git a/package/Editor/PromptImages/PromptImagesUI.cs.meta b/package/Editor/PromptImages/PromptImagesUI.cs.meta deleted file mode 100644 index dd86823..0000000 --- a/package/Editor/PromptImages/PromptImagesUI.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5c1783fccf9bd8c4b982a2475a401887 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/package/Editor/PromptImages/PromptImagesTileCreator.cs b/package/Editor/PromptImages/TileCreator.cs similarity index 88% rename from package/Editor/PromptImages/PromptImagesTileCreator.cs rename to package/Editor/PromptImages/TileCreator.cs index 28135a1..ac9271e 100644 --- a/package/Editor/PromptImages/PromptImagesTileCreator.cs +++ b/package/Editor/PromptImages/TileCreator.cs @@ -1,34 +1,27 @@ using System; -using System.Collections; -using System.Collections.Generic; using System.IO; using UnityEditor; -using UnityEditor.Presets; using UnityEngine; using UnityEngine.Tilemaps; -using UnityEngine.UIElements; -using static log4net.Appender.ColoredConsoleAppender; using static UnityEngine.GridLayout; namespace Scenario.Editor { - public class PromptImagesTileCreator + public class TileCreator { private GameObject tilePalette; private Grid grid; private GridPalette gridPalette; private CellLayout layout; - private PromptImages promptImages; - private int selectedTextureIndex; + private string selectedTextureId; private bool isProcessing = false; - public PromptImagesTileCreator(PromptImages _promptImages, int _selectedTextureIndex) + public TileCreator(string _selectedTextureIndex) { - promptImages = _promptImages; - selectedTextureIndex = _selectedTextureIndex; + selectedTextureId = _selectedTextureIndex; } public void OnGUI() @@ -60,7 +53,8 @@ public void OnGUI() if(GUILayout.Button(new GUIContent("Download as Tile", "The image will be processed to remove background then downloaded as a sprite in the Scenario Settings save folder. Then a Tile asset will be created (in the same folder as your Tile Palette) out of this Sprite and added to the Tile Palette your referenced."))) { isProcessing = true; - promptImages.RemoveBackground(selectedTextureIndex, (imageBytes) => + + BackgroundRemoval.RemoveBackground(Images.GetImageDataById(selectedTextureId).texture, imageBytes => { CommonUtils.SaveImageDataAsPNG(imageBytes, null, PluginSettings.TilePreset, (spritePath) => { diff --git a/package/Editor/PromptImages/PromptImagesTileCreator.cs.meta b/package/Editor/PromptImages/TileCreator.cs.meta similarity index 100% rename from package/Editor/PromptImages/PromptImagesTileCreator.cs.meta rename to package/Editor/PromptImages/TileCreator.cs.meta diff --git a/package/Editor/PromptWindow/PromptWindowUI.cs b/package/Editor/PromptWindow/PromptWindowUI.cs index 5810a49..0721965 100644 --- a/package/Editor/PromptWindow/PromptWindowUI.cs +++ b/package/Editor/PromptWindow/PromptWindowUI.cs @@ -53,7 +53,7 @@ public partial class PromptWindowUI internal int heightSliderValue = 512; internal float imagesliderValue = 4; internal int imagesliderIntValue = 4; - internal float samplesliderValue = 30; + internal int samplesliderValue = 30; internal int influenceSliderValue = 25; internal float guidancesliderValue = 7; internal string postedModelName = "Choose Model"; diff --git a/package/Editor/PromptWindow/Views/ImageSettingsView.cs b/package/Editor/PromptWindow/Views/ImageSettingsView.cs index 5fc9f26..38a74b2 100644 --- a/package/Editor/PromptWindow/Views/ImageSettingsView.cs +++ b/package/Editor/PromptWindow/Views/ImageSettingsView.cs @@ -57,11 +57,10 @@ private void RenderImageSettingsSection(bool shouldAutoGenerateSeed) } EditorGUILayout.EndHorizontal(); - int samplesliderIntValue = Mathf.RoundToInt(samplesliderValue); EditorGUILayout.BeginHorizontal(); { - GUILayout.Label("Sampling steps: " + samplesliderIntValue, GUILayout.Width(labelWidth)); - samplesliderValue = GUILayout.HorizontalSlider(samplesliderValue, 10, 150, GUILayout.Width(sliderWidth)); + GUILayout.Label("Sampling steps: " + samplesliderValue.ToString("00"), GUILayout.Width(labelWidth)); + samplesliderValue = (int)GUILayout.HorizontalSlider(samplesliderValue, 10, 150, GUILayout.Width(sliderWidth)); } EditorGUILayout.EndHorizontal(); diff --git a/package/Editor/_CustomStyle/CustomStyle.cs b/package/Editor/_CustomStyle/CustomStyle.cs index 8e27623..a6a8e48 100644 --- a/package/Editor/_CustomStyle/CustomStyle.cs +++ b/package/Editor/_CustomStyle/CustomStyle.cs @@ -69,7 +69,7 @@ public static void Label(string text, int fontSize = 12, bool bold = false, params GUILayoutOption[] layoutOptions) { - var style = new GUIStyle((bold)?EditorStyles.boldLabel:EditorStyles.label) + var style = new GUIStyle((bold) ? EditorStyles.boldLabel : EditorStyles.label) { normal = { @@ -79,6 +79,7 @@ public static void Label(string text, int fontSize = 12, alignment = alignment, fixedWidth = width, fixedHeight = height, + wordWrap = true }; GUILayout.Label(text, style, layoutOptions); diff --git a/package/Editor/_Services/DataCache.cs b/package/Editor/_Services/DataCache.cs index c2742df..767208e 100644 --- a/package/Editor/_Services/DataCache.cs +++ b/package/Editor/_Services/DataCache.cs @@ -7,6 +7,9 @@ namespace Scenario.Editor { + /// + /// Store the cache of images that has been newly generated + /// public class DataCache : ScriptableSingleton { #region ImageDataList @@ -18,6 +21,11 @@ public ImageDataStorage.ImageData GetImageDataAtIndex(int index) return imageDataList[index]; } + public List GetImageDataList() + { + return imageDataList; + } + public void AddImageDataInFront(ImageDataStorage.ImageData imageData) { //Debug.Log($"add image data in front {imageData}"); @@ -55,7 +63,7 @@ public void ClearAllImageData() return imageDataList.GetRange(firstIndex, count); } - public void FillReservedSpaceForImageData(string inferenceId, string id, string url, DateTime createdAt) + public void FillReservedSpaceForImageData(string inferenceId, string id, string url, DateTime createdAt, string _seed) { var itm = imageDataList.FirstOrDefault(x => { @@ -70,11 +78,16 @@ public void FillReservedSpaceForImageData(string inferenceId, string id, string itm.Id = id; itm.Url = url; itm.CreatedAt = createdAt; + itm.Seed = _seed; + CommonUtils.FetchTextureFromURL(itm.Url, texture => + { + itm.texture = texture; + }); } public void ReserveSpaceForImageDatas(int numImages, string inferenceId, string promptinputText, - float samplesliderValue, float widthSliderValue, float heightSliderValue, float guidancesliderValue, - string schedulerText, string seedinputText) + int samplesliderValue, float widthSliderValue, float heightSliderValue, float guidancesliderValue, + string schedulerText, string seedinputText, string modelIdInput) { for (int i = 0; i < numImages; i++) { @@ -88,6 +101,7 @@ public void ReserveSpaceForImageDatas(int numImages, string inferenceId, string Guidance = guidancesliderValue, Scheduler = schedulerText, Seed = seedinputText, + modelId = modelIdInput }); } } @@ -96,10 +110,14 @@ public void ReserveSpaceForImageDatas(int numImages, string inferenceId, string public ImageDataStorage.ImageData GetImageDataByUrl(string url) { - var data = imageDataList.FirstOrDefault(x => x.Url == url); - return data; + return imageDataList.FirstOrDefault(x => x.Url == url); } - + + public ImageDataStorage.ImageData GetImageDataById(string _id) + { + return imageDataList.FirstOrDefault(x => x.Id == _id); + } + public int GetImageDataIndexByUrl(string url) { var data = imageDataList.FirstOrDefault(x => x.Url == url); @@ -107,9 +125,9 @@ public int GetImageDataIndexByUrl(string url) return index; } - public void RemoveImageDataAtIndex(int index) + public void RemoveImageDataById(string _id) { - imageDataList.RemoveAt(index); + imageDataList.RemoveAt(imageDataList.FindIndex(x => x.Id == _id)); } public void RemoveInferenceData(string inferenceId) diff --git a/package/Editor/_Services/PromptFetcher.cs b/package/Editor/_Services/PromptFetcher.cs index 1efc33d..e929ef6 100644 --- a/package/Editor/_Services/PromptFetcher.cs +++ b/package/Editor/_Services/PromptFetcher.cs @@ -13,7 +13,7 @@ public class PromptFetcher public static List cancelledInferences = new(); public static void PostInferenceRequest(string inputData, int imagesliderIntValue, - string promptinputText, float samplesliderValue, float widthSliderValue, float heightSliderValue, + string promptinputText, int samplesliderValue, float widthSliderValue, float heightSliderValue, float guidancesliderValue, string seedinputText) { Debug.Log("Requesting image generation please wait.."); @@ -35,11 +35,11 @@ public static void PostInferenceRequest(string inputData, int imagesliderIntValu heightSliderValue, guidancesliderValue, "Default", - seedinputText); - - PromptImages.ShowWindow(); + seedinputText, + modelId); GetInferenceStatus(inferenceId, modelId); + Images.ShowWindow(); }); } @@ -68,7 +68,7 @@ private static async void GetInferenceStatus(string inferenceId, string modelId) if (inferenceStatusRoot.inference.status != "succeeded" && inferenceStatusRoot.inference.status != "failed" ) { - Debug.Log("Commission in process, please wait.."); + Debug.Log($"Commission in process, please wait..."); GetInferenceStatus(inferenceId, modelId); } else @@ -81,16 +81,15 @@ private static async void GetInferenceStatus(string inferenceId, string modelId) foreach (var item in inferenceStatusRoot.inference.images) { - /*Debug.Log("Image URL: " + item);*/ + //Debug.Log("Image : " + item.ToString()); var img = JsonConvert.DeserializeObject(item.ToString()); DataCache.instance.FillReservedSpaceForImageData( inferenceId, img.Id, img.Url, - inferenceStatusRoot.inference.createdAt); + inferenceStatusRoot.inference.createdAt, + img.Seed); } - - PromptImages.ShowWindow(); } }); } @@ -99,6 +98,7 @@ public class ImageDataAPI { public string Id { get; set; } public string Url { get; set; } + public string Seed { get; set; } } [Serializable]