using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace RosettaUI
{
///
/// Find a location where the Window does not overlap with an existing one
///
public static class WindowLayout
{
private static readonly Dictionary> OpenedWindowTable = new();
private static readonly Dictionary ParentWindowRightTopTable = new();
public static Vector2 CalcOpenWindowPosition(Vector2 originalPos,
Rect screenRect,
WindowElement window,
WindowElement parentWindow,
Func getWindowRect,
Func isWindowMoved)
{
List openedWindows = null;
Rect parentRect = default;
if (parentWindow != null)
{
if (!OpenedWindowTable.TryGetValue(parentWindow, out openedWindows))
{
openedWindows = OpenedWindowTable[parentWindow] = new List();
}
// 親Windowが以前の位置から動いていたら子Windowは全部無視
parentRect = getWindowRect(parentWindow);
var newRightTop = new Vector2(parentRect.xMax, parentRect.yMin);
if (ParentWindowRightTopTable.TryGetValue(parentWindow, out var rightTop))
{
if (newRightTop != rightTop)
{
openedWindows.Clear();
}
}
ParentWindowRightTopTable[parentWindow] = newRightTop;
// 閉じているor動いたWindow以降のWindowは無視
var removeStartIndex = openedWindows.FindIndex(w => !w.IsOpen || isWindowMoved(w));
if (removeStartIndex >= 0)
{
openedWindows.RemoveRange(removeStartIndex, openedWindows.Count - removeStartIndex);
}
}
const float delta = 5f;
var pos = originalPos;
var alignX = false;
if (parentWindow != null )
{
var x = parentRect.xMax + delta;
alignX = x < screenRect.xMax;
if ( alignX )
{
pos = new Vector2(x, parentRect.yMin);
}
}
if ((openedWindows?.Any() ?? false) && alignX)
{
var previousRect = getWindowRect(openedWindows.Last());
// 新しいWindowの上部が画面の半分より上なら、previousの下に表示
var newY = previousRect.yMax + delta;
if (newY < screenRect.center.y) // 半分より上
{
pos.x = previousRect.xMin;
pos.y = newY;
}
// previousの下が空いてないときはopenedWindowの一番上にあるものの隣
else
{
var mostTopRect = openedWindows
.Select(getWindowRect)
.Aggregate((l, r) => l.yMin < r.yMin ? l : r); // MinBy
var newX = mostTopRect.xMax + delta;
if (newX < screenRect.xMax)
{
pos.x = newX;
pos.y = mostTopRect.yMin;
}
}
}
if (pos.x < 0f) pos.x = 0f;
if (pos.y < 0f) pos.y = 0f;
openedWindows?.Add(window);
return pos;
}
}
}