using FairyGUI.Utils;
using UnityEngine;
namespace FairyGUI
{
///
/// GGroup class.
/// 组对象,对应编辑器里的高级组。
///
public class GGroup : GObject
{
GroupLayoutType _layout;
int _lineGap;
int _columnGap;
bool _percentReady;
bool _boundsChanged;
EventCallback0 _refreshDelegate;
internal int _updating;
public GGroup()
{
_refreshDelegate = EnsureBoundsCorrect;
}
///
/// Group layout type.
///
public GroupLayoutType layout
{
get { return _layout; }
set
{
if (_layout != value)
{
_layout = value;
SetBoundsChangedFlag(true);
}
}
}
///
///
///
public int lineGap
{
get { return _lineGap; }
set
{
if (_lineGap != value)
{
_lineGap = value;
SetBoundsChangedFlag();
}
}
}
///
///
///
public int columnGap
{
get { return _columnGap; }
set
{
if (_columnGap != value)
{
_columnGap = value;
SetBoundsChangedFlag();
}
}
}
///
/// Update group bounds.
/// 更新组的包围.
///
public void SetBoundsChangedFlag(bool childSizeChanged = false)
{
if (_updating == 0 && parent != null)
{
if (childSizeChanged)
_percentReady = false;
if (!_boundsChanged)
{
_boundsChanged = true;
if (_layout != GroupLayoutType.None)
{
UpdateContext.OnBegin -= _refreshDelegate;
UpdateContext.OnBegin += _refreshDelegate;
}
}
}
}
public void EnsureBoundsCorrect()
{
if (_boundsChanged)
UpdateBounds();
}
void UpdateBounds()
{
UpdateContext.OnBegin -= _refreshDelegate;
_boundsChanged = false;
if (parent == null)
return;
HandleLayout();
int cnt = parent.numChildren;
int i;
GObject child;
float ax = int.MaxValue, ay = int.MaxValue;
float ar = int.MinValue, ab = int.MinValue;
float tmp;
bool empty = true;
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
tmp = child.x;
if (tmp < ax)
ax = tmp;
tmp = child.y;
if (tmp < ay)
ay = tmp;
tmp = child.x + child.width;
if (tmp > ar)
ar = tmp;
tmp = child.y + child.height;
if (tmp > ab)
ab = tmp;
empty = false;
}
if (!empty)
{
_updating = 1;
SetXY(ax, ay);
_updating = 2;
SetSize(ar - ax, ab - ay);
}
else
{
_updating = 2;
SetSize(0, 0);
}
_updating = 0;
}
void HandleLayout()
{
_updating |= 1;
if (_layout == GroupLayoutType.Horizontal)
{
float curX = float.NaN;
int cnt = parent.numChildren;
for (int i = 0; i < cnt; i++)
{
GObject child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (float.IsNaN(curX))
curX = (int)child.x;
else
child.x = curX;
if (child.width != 0)
curX += (int)(child.width + _columnGap);
}
if (!_percentReady)
UpdatePercent();
}
else if (_layout == GroupLayoutType.Vertical)
{
float curY = float.NaN;
int cnt = parent.numChildren;
for (int i = 0; i < cnt; i++)
{
GObject child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (float.IsNaN(curY))
curY = (int)child.y;
else
child.y = curY;
if (child.height != 0)
curY += (int)(child.height + _lineGap);
}
if (!_percentReady)
UpdatePercent();
}
_updating &= 2;
}
void UpdatePercent()
{
_percentReady = true;
int cnt = parent.numChildren;
int i;
GObject child;
float size = 0;
if (_layout == GroupLayoutType.Horizontal)
{
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
size += child.width;
}
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (size > 0)
child._sizePercentInGroup = child.width / size;
else
child._sizePercentInGroup = 0;
}
}
else
{
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
size += child.height;
}
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (size > 0)
child._sizePercentInGroup = child.height / size;
else
child._sizePercentInGroup = 0;
}
}
}
internal void MoveChildren(float dx, float dy)
{
if ((_updating & 1) != 0 || parent == null)
return;
_updating |= 1;
int cnt = parent.numChildren;
int i;
GObject child;
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group == this)
{
child.SetXY(child.x + dx, child.y + dy);
}
}
_updating &= 2;
}
internal void ResizeChildren(float dw, float dh)
{
if (_layout == GroupLayoutType.None || (_updating & 2) != 0 || parent == null)
return;
_updating |= 2;
if (!_percentReady)
UpdatePercent();
int cnt = parent.numChildren;
int i;
int j;
GObject child;
int last = -1;
int numChildren = 0;
float lineSize = 0;
float remainSize = 0;
bool found = false;
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
last = i;
numChildren++;
}
if (_layout == GroupLayoutType.Horizontal)
{
remainSize = lineSize = this.width - (numChildren - 1) * _columnGap;
float curX = float.NaN;
float nw;
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (float.IsNaN(curX))
curX = (int)child.x;
else
child.x = curX;
if (last == i)
nw = remainSize;
else
nw = Mathf.RoundToInt(child._sizePercentInGroup * lineSize);
child.SetSize(nw, child._rawHeight + dh, true);
remainSize -= child.width;
if (last == i)
{
if (remainSize >= 1) //可能由于有些元件有宽度限制,导致无法铺满
{
for (j = 0; j <= i; j++)
{
child = parent.GetChildAt(j);
if (child.group != this)
continue;
if (!found)
{
nw = child.width + remainSize;
if ((child.maxWidth == 0 || nw < child.maxWidth)
&& (child.minWidth == 0 || nw > child.minWidth))
{
child.SetSize(nw, child.height, true);
found = true;
}
}
else
child.x += remainSize;
}
}
}
else
curX += (child.width + _columnGap);
}
}
else if (_layout == GroupLayoutType.Vertical)
{
remainSize = lineSize = this.height - (numChildren - 1) * _lineGap;
float curY = float.NaN;
float nh;
for (i = 0; i < cnt; i++)
{
child = parent.GetChildAt(i);
if (child.group != this)
continue;
if (float.IsNaN(curY))
curY = (int)child.y;
else
child.y = curY;
if (last == i)
nh = remainSize;
else
nh = Mathf.RoundToInt(child._sizePercentInGroup * lineSize);
child.SetSize(child._rawWidth + dw, nh, true);
remainSize -= child.height;
if (last == i)
{
if (remainSize >= 1) //可能由于有些元件有宽度限制,导致无法铺满
{
for (j = 0; j <= i; j++)
{
child = parent.GetChildAt(j);
if (child.group != this)
continue;
if (!found)
{
nh = child.height + remainSize;
if ((child.maxHeight == 0 || nh < child.maxHeight)
&& (child.minHeight == 0 || nh > child.minHeight))
{
child.SetSize(child.width, nh, true);
found = true;
}
}
else
child.y += remainSize;
}
}
}
else
curY += (child.height + _lineGap);
}
}
_updating &= 1;
}
override protected void HandleAlphaChanged()
{
base.HandleAlphaChanged();
if (this.underConstruct || parent == null)
return;
int cnt = parent.numChildren;
float a = this.alpha;
for (int i = 0; i < cnt; i++)
{
GObject child = parent.GetChildAt(i);
if (child.group == this)
child.alpha = a;
}
}
override internal protected void HandleVisibleChanged()
{
if (parent == null)
return;
int cnt = parent.numChildren;
for (int i = 0; i < cnt; i++)
{
GObject child = parent.GetChildAt(i);
if (child.group == this)
child.HandleVisibleChanged();
}
}
override public void Setup_BeforeAdd(ByteBuffer buffer, int beginPos)
{
base.Setup_BeforeAdd(buffer, beginPos);
buffer.Seek(beginPos, 5);
_layout = (GroupLayoutType)buffer.ReadByte();
_lineGap = buffer.ReadInt();
_columnGap = buffer.ReadInt();
}
override public void Setup_AfterAdd(ByteBuffer buffer, int beginPos)
{
base.Setup_AfterAdd(buffer, beginPos);
if (!this.visible)
HandleVisibleChanged();
}
}
}