using System;
using System.Collections.Generic;
using BansheeEngine;
namespace BansheeEditor
{
///
/// Manages GUI for the content area of the library window. Content area displays resources as a grid or list of
/// resource icons.
///
internal class LibraryGUIContent
{
private const int MIN_HORZ_SPACING = 8;
private const int GRID_ENTRY_SPACING = 15;
private const int LIST_ENTRY_SPACING = 7;
private GUIPanel mainPanel;
private GUILayout main;
private GUIPanel overlay;
private GUIPanel underlay;
private GUIPanel renameOverlay;
private LibraryWindow window;
private GUIScrollArea parent;
private int tileSize;
private bool gridLayout;
private int elementsPerRow;
private int labelWidth;
private LibraryGUIEntry[] entries = new LibraryGUIEntry[0];
private Dictionary entryLookup = new Dictionary();
///
/// Area of the content area relative to the parent window.
///
public Rect2I Bounds
{
get { return main.Bounds; }
}
///
/// Number of elements per row. Only relvant for grid layouts.
///
public int ElementsPerRow
{
get { return elementsPerRow; }
}
///
/// Determines is the content display in a grid (true) or list (false) layout.
///
public bool GridLayout
{
get { return gridLayout; }
}
///
/// Sizes of a single resource tile in grid layout. Size in list layout is fixed.
///
public int TileSize
{
get { return tileSize; }
}
///
/// Returns objects representing each of the displayed resource icons.
///
public LibraryGUIEntry[] Entries
{
get { return entries; }
}
///
/// Returns parent window the content area is part of.
///
public LibraryWindow Window
{
get { return window; }
}
///
/// Returns a GUI panel that can be used for displaying elements underneath the resource tiles.
///
public GUIPanel Underlay
{
get { return underlay; }
}
///
/// Returns a GUI panel that can be used for displaying elements above the resource tiles.
///
public GUIPanel Overlay
{
get { return overlay; }
}
///
/// Returns a GUI panel that can be used for displaying rename input box. Displayed on top of the resource tiles
/// and the standard overlay.
///
public GUIPanel RenameOverlay
{
get { return renameOverlay; }
}
///
/// Constructs a new GUI library content object.
///
/// Parent window the content area is part of.
/// Scroll area the content area is part of.
public LibraryGUIContent(LibraryWindow window, GUIScrollArea parent)
{
this.window = window;
this.parent = parent;
}
///
/// Refreshes the contents of the content area. Must be called at least once after construction.
///
/// Determines how to display the resource tiles.
/// Project library entries to display.
public void Refresh(ProjectViewType viewType, LibraryEntry[] entriesToDisplay)
{
if (mainPanel != null)
mainPanel.Destroy();
entries = new LibraryGUIEntry[entriesToDisplay.Length];
entryLookup.Clear();
mainPanel = parent.Layout.AddPanel();
GUIPanel contentPanel = mainPanel.AddPanel(1);
overlay = mainPanel.AddPanel(0);
underlay = mainPanel.AddPanel(2);
renameOverlay = mainPanel.AddPanel(-1);
main = contentPanel.AddLayoutY();
if (viewType == ProjectViewType.List16)
{
tileSize = 16;
gridLayout = false;
elementsPerRow = 1;
}
else
{
switch (viewType)
{
case ProjectViewType.Grid64:
tileSize = 64;
break;
case ProjectViewType.Grid48:
tileSize = 48;
break;
case ProjectViewType.Grid32:
tileSize = 32;
break;
}
gridLayout = true;
Rect2I scrollBounds = parent.Bounds;
int availableWidth = scrollBounds.width;
int elemSize = tileSize + GRID_ENTRY_SPACING;
elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
elementsPerRow = Math.Max(elementsPerRow, 1);
int numRows = MathEx.CeilToInt(entriesToDisplay.Length / (float)elementsPerRow);
int neededHeight = numRows * (elemSize);
bool requiresScrollbar = neededHeight > scrollBounds.height;
if (requiresScrollbar)
{
availableWidth -= parent.ScrollBarWidth;
elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
}
if (elementsPerRow > 0)
labelWidth = (availableWidth - (elementsPerRow + 1) * MIN_HORZ_SPACING) / elementsPerRow;
else
labelWidth = 0;
}
if (viewType == ProjectViewType.List16)
{
for (int i = 0; i < entriesToDisplay.Length; i++)
{
LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, main, entriesToDisplay[i], i, labelWidth);
entries[i] = guiEntry;
entryLookup[guiEntry.path] = guiEntry;
if (i != entriesToDisplay.Length - 1)
main.AddSpace(LIST_ENTRY_SPACING);
}
main.AddFlexibleSpace();
}
else
{
main.AddSpace(GRID_ENTRY_SPACING / 2);
GUILayoutX rowLayout = main.AddLayoutX();
main.AddSpace(GRID_ENTRY_SPACING);
rowLayout.AddFlexibleSpace();
int elemsInRow = 0;
for (int i = 0; i < entriesToDisplay.Length; i++)
{
if (elemsInRow == elementsPerRow && elemsInRow > 0)
{
rowLayout = main.AddLayoutX();
main.AddSpace(GRID_ENTRY_SPACING);
rowLayout.AddFlexibleSpace();
elemsInRow = 0;
}
LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, rowLayout, entriesToDisplay[i], i, labelWidth);
entries[i] = guiEntry;
entryLookup[guiEntry.path] = guiEntry;
rowLayout.AddFlexibleSpace();
elemsInRow++;
}
int extraElements = elementsPerRow - elemsInRow;
for (int i = 0; i < extraElements; i++)
{
rowLayout.AddSpace(labelWidth);
rowLayout.AddFlexibleSpace();
}
main.AddFlexibleSpace();
}
for (int i = 0; i < entries.Length; i++)
{
LibraryGUIEntry guiEntry = entries[i];
guiEntry.Initialize();
}
}
///
/// Changes the visual representation of an element at the specified path as being hovered over.
///
/// Project library path to the element to mark.
/// True if mark as hovered, false to reset to normal.
public void MarkAsHovered(string path, bool hovered)
{
if (!string.IsNullOrEmpty(path))
{
LibraryGUIEntry previousUnderCursorElem;
if (entryLookup.TryGetValue(path, out previousUnderCursorElem))
previousUnderCursorElem.MarkAsHovered(hovered);
}
}
///
/// Changes the visual representation of an element at the specified path as being pinged.
///
/// Project library path to the element to mark.
/// True if mark as pinged, false to reset to normal.
public void MarkAsPinged(string path, bool pinged)
{
if (!string.IsNullOrEmpty(path))
{
LibraryGUIEntry previousUnderCursorElem;
if (entryLookup.TryGetValue(path, out previousUnderCursorElem))
previousUnderCursorElem.MarkAsPinged(pinged);
}
}
///
/// Changes the visual representation of an element at the specified path as being cut.
///
/// Project library path to the element to mark.
/// True if mark as cut, false to reset to normal.
public void MarkAsCut(string path, bool cut)
{
if (!string.IsNullOrEmpty(path))
{
LibraryGUIEntry previousUnderCursorElem;
if (entryLookup.TryGetValue(path, out previousUnderCursorElem))
previousUnderCursorElem.MarkAsCut(cut);
}
}
///
/// Changes the visual representation of an element at the specified path as being selected.
///
/// Project library path to the element to mark.
/// True if mark as selected, false to reset to normal.
public void MarkAsSelected(string path, bool selected)
{
if (!string.IsNullOrEmpty(path))
{
LibraryGUIEntry previousUnderCursorElem;
if (entryLookup.TryGetValue(path, out previousUnderCursorElem))
previousUnderCursorElem.MarkAsSelected(selected);
}
}
///
/// Attempts to find a resource tile element at the specified coordinates.
///
/// Coordinates relative to the scroll area the content area is part of.
/// True if found an entry, false otherwise.
public LibraryGUIEntry FindElementAt(Vector2I scrollPos)
{
foreach (var element in entries)
{
if (element.bounds.Contains(scrollPos))
return element;
}
return null;
}
///
/// Attempts to find all resource tile elements overlapping the specified bounds.
///
/// Bounds to check for overlap, specified relative to the scroll area the content area
/// is part of.
/// A list of found entries.
public LibraryGUIEntry[] FindElementsOverlapping(Rect2I scrollBounds)
{
List elements = new List();
foreach (var element in entries)
{
if (element.Bounds.Overlaps(scrollBounds))
elements.Add(element);
}
return elements.ToArray();
}
///
/// Attempts to find a resource tile element with the specified path.
///
/// Project library path to the element.
/// Found element, or null if none found.
/// True if an element was found, false otherwise.
public bool TryGetEntry(string path, out LibraryGUIEntry entry)
{
return entryLookup.TryGetValue(path, out entry);
}
}
}