using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Represents GUI for a single resource tile used in .
///
internal class LibraryGUIEntry
{
private const int MAX_LABEL_HEIGHT = 50;
private static readonly Color PING_COLOR = Color.BansheeOrange;
private static readonly Color SELECTION_COLOR = Color.DarkCyan;
private static readonly Color HOVER_COLOR = new Color(Color.DarkCyan.r, Color.DarkCyan.g, Color.DarkCyan.b, 0.5f);
private static readonly Color CUT_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.5f);
private const int SELECTION_EXTRA_WIDTH = 3;
///
/// Possible visual states for the resource tile.
///
enum UnderlayState // Note: Order of these is relevant
{
None, Hovered, Selected, Pinged
}
public int index;
public string path;
public GUITexture icon;
public GUILabel label;
public Rect2I bounds;
private GUITexture underlay;
private LibraryGUIContent owner;
private UnderlayState underlayState;
private GUITextBox renameTextBox;
///
/// Constructs a new resource tile entry.
///
/// Content area this entry is part of.
/// Parent layout to add this entry's GUI elements to.
/// Project library entry this entry displays data for.
/// Sequential index of the entry in the conent area.
/// Width of the GUI labels that display the elements.
public LibraryGUIEntry(LibraryGUIContent owner, GUILayout parent, LibraryEntry entry, int index, int labelWidth)
{
GUILayout entryLayout;
if (owner.GridLayout)
entryLayout = parent.AddLayoutY();
else
entryLayout = parent.AddLayoutX();
SpriteTexture iconTexture = GetIcon(entry);
icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit,
true, GUIOption.FixedHeight(owner.TileSize), GUIOption.FixedWidth(owner.TileSize));
label = null;
if (owner.GridLayout)
{
label = new GUILabel(entry.Name, EditorStyles.MultiLineLabelCentered,
GUIOption.FixedWidth(labelWidth), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
}
else
{
label = new GUILabel(entry.Name);
}
entryLayout.AddElement(icon);
entryLayout.AddElement(label);
this.owner = owner;
this.index = index;
this.path = entry.Path;
this.bounds = new Rect2I();
this.underlay = null;
}
///
/// Positions the GUI elements. Must be called after construction, but only after all content area entries have
/// been constructed so that entry's final bounds are known.
///
public void Initialize()
{
bounds = icon.Bounds;
Rect2I labelBounds = label.Bounds;
bounds.x = MathEx.Min(bounds.x, labelBounds.x - SELECTION_EXTRA_WIDTH);
bounds.y = MathEx.Min(bounds.y, labelBounds.y) - 5; // 5 - Just padding for better look
bounds.width = MathEx.Max(bounds.x + bounds.width,
labelBounds.x + labelBounds.width) - bounds.x + SELECTION_EXTRA_WIDTH;
bounds.height = MathEx.Max(bounds.y + bounds.height,
labelBounds.y + labelBounds.height) - bounds.y;
string hoistedPath = path;
GUIButton overlayBtn = new GUIButton("", EditorStyles.Blank);
overlayBtn.Bounds = bounds;
overlayBtn.OnClick += () => OnEntryClicked(hoistedPath);
overlayBtn.OnDoubleClick += () => OnEntryDoubleClicked(hoistedPath);
overlayBtn.SetContextMenu(owner.Window.ContextMenu);
owner.Overlay.AddElement(overlayBtn);
}
///
/// Bounds of the entry relative to part content area.
///
public Rect2I Bounds
{
get { return bounds; }
}
///
/// Changes the visual representation of the element as being cut.
///
/// True if mark as cut, false to reset to normal.
public void MarkAsCut(bool enable)
{
if (enable)
icon.SetTint(CUT_COLOR);
else
icon.SetTint(Color.White);
}
///
/// Changes the visual representation of the element as being selected.
///
/// True if mark as selected, false to reset to normal.
public void MarkAsSelected(bool enable)
{
if ((int)underlayState > (int)UnderlayState.Selected)
return;
if (enable)
{
CreateUnderlay();
underlay.SetTint(SELECTION_COLOR);
}
else
ClearUnderlay();
underlayState = UnderlayState.Selected;
}
///
/// Changes the visual representation of the element as being pinged.
///
/// True if mark as pinged, false to reset to normal.
public void MarkAsPinged(bool enable)
{
if ((int)underlayState > (int)UnderlayState.Pinged)
return;
if (enable)
{
CreateUnderlay();
underlay.SetTint(PING_COLOR);
}
else
ClearUnderlay();
underlayState = UnderlayState.Pinged;
}
///
/// Changes the visual representation of the element as being hovered over.
///
/// True if mark as hovered, false to reset to normal.
public void MarkAsHovered(bool enable)
{
if ((int)underlayState > (int)UnderlayState.Hovered)
return;
if (enable)
{
CreateUnderlay();
underlay.SetTint(HOVER_COLOR);
}
else
ClearUnderlay();
underlayState = UnderlayState.Hovered;
}
///
/// Starts a rename operation over the entry, displaying the rename input box.
///
public void StartRename()
{
if (renameTextBox != null)
return;
renameTextBox = new GUITextBox(false);
renameTextBox.Bounds = label.Bounds;
owner.RenameOverlay.AddElement(renameTextBox);
string name = Path.GetFileNameWithoutExtension(PathEx.GetTail(path));
renameTextBox.Text = name;
renameTextBox.Focus = true;
label.Active = false;
}
///
/// Stops a rename operation over the entry, hiding the rename input box.
///
public void StopRename()
{
if (renameTextBox != null)
{
renameTextBox.Destroy();
renameTextBox = null;
}
label.Active = true;
}
///
/// Gets the new name of the entry. Only valid while a rename operation is in progress.
///
/// New name of the entry currently entered in the rename input box.
public string GetRenamedName()
{
if (renameTextBox != null)
return renameTextBox.Text;
return "";
}
///
/// Clears the underlay GUI element (e.g. ping, hover, select).
///
private void ClearUnderlay()
{
if (underlay != null)
{
underlay.Destroy();
underlay = null;
}
underlayState = UnderlayState.None;
}
///
/// Creates a GUI elements that may be used for underlay effects (e.g. ping, hover, select).
///
private void CreateUnderlay()
{
if (underlay == null)
{
underlay = new GUITexture(Builtin.WhiteTexture);
underlay.Bounds = Bounds;
owner.Underlay.AddElement(underlay);
}
}
///
/// Triggered when the user clicks on the entry.
///
/// Project library path of the clicked entry.
private void OnEntryClicked(string path)
{
owner.Window.Select(path);
}
///
/// Triggered when the user double-clicked on the entry.
///
/// Project library path of the double-clicked entry.
private void OnEntryDoubleClicked(string path)
{
LibraryEntry entry = ProjectLibrary.GetEntry(path);
if (entry != null)
{
if (entry.Type == LibraryEntryType.Directory)
owner.Window.EnterDirectory(path);
else
{
FileEntry resEntry = (FileEntry)entry;
if (resEntry.ResType == ResourceType.Prefab)
{
EditorApplication.LoadScene(resEntry.Path);
}
}
}
}
///
/// Returns an icon that can be used for displaying a resource of the specified type.
///
/// Project library entry of the resource to retrieve icon for.
/// Icon to display for the specified entry.
private static SpriteTexture GetIcon(LibraryEntry entry)
{
if (entry.Type == LibraryEntryType.Directory)
{
return EditorBuiltin.FolderIcon;
}
else
{
FileEntry fileEntry = (FileEntry)entry;
switch (fileEntry.ResType)
{
case ResourceType.Font:
return EditorBuiltin.FontIcon;
case ResourceType.Mesh:
return EditorBuiltin.MeshIcon;
case ResourceType.Texture:
return EditorBuiltin.TextureIcon;
case ResourceType.PlainText:
return EditorBuiltin.PlainTextIcon;
case ResourceType.ScriptCode:
return EditorBuiltin.ScriptCodeIcon;
case ResourceType.SpriteTexture:
return EditorBuiltin.SpriteTextureIcon;
case ResourceType.Shader:
return EditorBuiltin.ShaderIcon;
case ResourceType.Material:
return EditorBuiltin.MaterialIcon;
case ResourceType.Prefab:
return EditorBuiltin.PrefabIcon;
}
}
return null;
}
}
}