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); } } }