using System; using System.Collections.Generic; using UnityEngine; using FairyGUI.Utils; #if FAIRYGUI_TOLUA using LuaInterface; #endif namespace FairyGUI { /// /// Component /// public class GComponent : GObject { /// /// Root container. /// public Container rootContainer { get; private set; } /// /// Content container. If the component is not clipped, then container==rootContainer. /// public Container container { get; protected set; } /// /// ScrollPane of the component. If the component is not scrollable, the value is null. /// public ScrollPane scrollPane { get; private set; } internal List _children; internal List _controllers; internal List _transitions; internal bool _buildingDisplayList; protected Margin _margin; protected bool _trackBounds; protected bool _boundsChanged; protected ChildrenRenderOrder _childrenRenderOrder; protected int _apexIndex; internal Vector2 _alignOffset; Vector2 _clipSoftness; int _sortingChildCount; Action _buildDelegate; Controller _applyingController; EventListener _onDrop; public GComponent() { _children = new List(); _controllers = new List(); _transitions = new List(); _margin = new Margin(); _buildDelegate = BuildNativeDisplayList; } override protected void CreateDisplayObject() { rootContainer = new Container("GComponent"); rootContainer.gOwner = this; rootContainer.onUpdate += OnUpdate; container = rootContainer; displayObject = rootContainer; } override public void Dispose() { int cnt = _transitions.Count; for (int i = 0; i < cnt; ++i) { Transition trans = _transitions[i]; trans.Dispose(); } cnt = _controllers.Count; for (int i = 0; i < cnt; ++i) { Controller c = _controllers[i]; c.Dispose(); } if (scrollPane != null) scrollPane.Dispose(); base.Dispose(); //Dispose native tree first, avoid DisplayObject.RemoveFromParent call cnt = _children.Count; for (int i = cnt - 1; i >= 0; --i) { GObject obj = _children[i]; obj.InternalSetParent(null); //Avoid GObject.RemoveParent call obj.Dispose(); } #if FAIRYGUI_TOLUA if (_peerTable != null) { _peerTable.Dispose(); _peerTable = null; } #endif #if FAIRYGUI_PUERTS if (__onDispose != null) __onDispose(); __onConstruct = null; __onDispose = null; #endif } /// /// Dispatched when an object was dragged and dropped to this component. /// public EventListener onDrop { get { return _onDrop ?? (_onDrop = new EventListener(this, "onDrop")); } } /// /// Draw call optimization switch. /// public bool fairyBatching { get { return rootContainer.fairyBatching; } set { rootContainer.fairyBatching = value; } } /// /// /// /// public void InvalidateBatchingState(bool childChanged) { if (childChanged) container.InvalidateBatchingState(childChanged); else rootContainer.InvalidateBatchingState(); } /// /// If true, mouse/touch events cannot pass through the empty area of the component. Default is true. /// public bool opaque { get { return rootContainer.opaque; } set { rootContainer.opaque = value; } } /// /// /// /// public Margin margin { get { return _margin; } set { _margin = value; if (rootContainer.clipRect != null && scrollPane == null) //如果scrollPane不为空,则HandleSizeChanged里面的处理会促使ScrollPane处理 container.SetXY(_margin.left + _alignOffset.x, _margin.top + _alignOffset.y); HandleSizeChanged(); } } /// /// /// public ChildrenRenderOrder childrenRenderOrder { get { return _childrenRenderOrder; } set { if (_childrenRenderOrder != value) { _childrenRenderOrder = value; BuildNativeDisplayList(); } } } /// /// /// public int apexIndex { get { return _apexIndex; } set { if (_apexIndex != value) { _apexIndex = value; if (_childrenRenderOrder == ChildrenRenderOrder.Arch) BuildNativeDisplayList(); } } } /// /// If true, children can be navigated by TAB from first to last, and repeat /// public bool tabStopChildren { get { return rootContainer.tabStopChildren; } set { rootContainer.tabStopChildren = value; } } /// /// Add a child to the component. It will be at the frontmost position. /// /// A child object /// GObject public GObject AddChild(GObject child) { AddChildAt(child, _children.Count); return child; } /// /// Adds a child to the component at a certain index. /// /// A child object /// Index /// GObject virtual public GObject AddChildAt(GObject child, int index) { if (index >= 0 && index <= _children.Count) { if (child.parent == this) { SetChildIndex(child, index); } else { child.RemoveFromParent(); child.InternalSetParent(this); int cnt = _children.Count; if (child.sortingOrder != 0) { _sortingChildCount++; index = GetInsertPosForSortingChild(child); } else if (_sortingChildCount > 0) { if (index > (cnt - _sortingChildCount)) index = cnt - _sortingChildCount; } if (index == cnt) _children.Add(child); else _children.Insert(index, child); ChildStateChanged(child); SetBoundsChangedFlag(); } return child; } else { throw new Exception("Invalid child index: " + index + ">" + _children.Count); } } int GetInsertPosForSortingChild(GObject target) { int cnt = _children.Count; int i; for (i = 0; i < cnt; i++) { GObject child = _children[i]; if (child == target) continue; if (target.sortingOrder < child.sortingOrder) break; } return i; } /// /// Removes a child from the component. If the object is not a child, nothing happens. /// /// A child object /// GObject public GObject RemoveChild(GObject child) { return RemoveChild(child, false); } /// /// Removes a child from the component. If the object is not a child, nothing happens. /// /// A child object /// If true, the child will be disposed right away. /// GObject public GObject RemoveChild(GObject child, bool dispose) { int childIndex = _children.IndexOf(child); if (childIndex != -1) { RemoveChildAt(childIndex, dispose); } return child; } /// /// Removes a child at a certain index. Children above the child will move down. /// /// Index /// GObject public GObject RemoveChildAt(int index) { return RemoveChildAt(index, false); } /// /// Removes a child at a certain index. Children above the child will move down. /// /// Index /// If true, the child will be disposed right away. /// GObject virtual public GObject RemoveChildAt(int index, bool dispose) { if (index >= 0 && index < numChildren) { GObject child = _children[index]; child.InternalSetParent(null); if (child.sortingOrder != 0) _sortingChildCount--; _children.RemoveAt(index); child.group = null; if (child.inContainer) { container.RemoveChild(child.displayObject); if (_childrenRenderOrder == ChildrenRenderOrder.Arch) { UpdateContext.OnBegin -= _buildDelegate; UpdateContext.OnBegin += _buildDelegate; } } if (dispose) child.Dispose(); SetBoundsChangedFlag(); return child; } else throw new Exception("Invalid child index: " + index + ">" + numChildren); } /// /// Remove all children. /// public void RemoveChildren() { RemoveChildren(0, -1, false); } /// /// Removes a range of children from the container (endIndex included). /// /// Begin index. /// End index.(Included). /// If true, the child will be disposed right away. public void RemoveChildren(int beginIndex, int endIndex, bool dispose) { if (endIndex < 0 || endIndex >= numChildren) endIndex = numChildren - 1; for (int i = beginIndex; i <= endIndex; ++i) RemoveChildAt(beginIndex, dispose); } /// /// Returns a child object at a certain index. If index out of bounds, exception raised. /// /// Index /// A child object. public GObject GetChildAt(int index) { if (index >= 0 && index < numChildren) return _children[index]; else throw new Exception("Invalid child index: " + index + ">" + numChildren); } /// /// Returns a child object with a certain name. /// /// Name /// A child object. Null if not found. public GObject GetChild(string name) { int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { if (_children[i].name == name) return _children[i]; } return null; } public GObject GetChildByPath(string path) { string[] arr = path.Split('.'); int cnt = arr.Length; GComponent gcom = this; GObject obj = null; for (int i = 0; i < cnt; ++i) { obj = gcom.GetChild(arr[i]); if (obj == null) break; if (i != cnt - 1) { if (!(obj is GComponent)) { obj = null; break; } else gcom = (GComponent)obj; } } return obj; } /// /// Returns a visible child object with a certain name. /// /// Name /// A child object. Null if not found. public GObject GetVisibleChild(string name) { int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; if (child.internalVisible && child.internalVisible2 && child.name == name) return child; } return null; } /// /// Returns a child object belong to a group with a certain name. /// /// A group object /// Name /// A child object. Null if not found. public GObject GetChildInGroup(GGroup group, string name) { int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; if (child.group == group && child.name == name) return child; } return null; } internal GObject GetChildById(string id) { int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { if (_children[i].id == id) return _children[i]; } return null; } /// /// Returns a copy of all children with an array. /// /// An array contains all children public GObject[] GetChildren() { return _children.ToArray(); } /// /// Returns the index of a child within the container, or "-1" if it is not found. /// /// A child object /// Index of the child. -1 If not found. public int GetChildIndex(GObject child) { return _children.IndexOf(child); } /// /// Moves a child to a certain index. Children at and after the replaced position move up. /// /// A Child /// Index public void SetChildIndex(GObject child, int index) { int oldIndex = _children.IndexOf(child); if (oldIndex == -1) throw new ArgumentException("Not a child of this container"); if (child.sortingOrder != 0) //no effect return; if (_sortingChildCount > 0) { int cnt = _children.Count; if (index > (cnt - _sortingChildCount - 1)) index = cnt - _sortingChildCount - 1; } _SetChildIndex(child, oldIndex, index); } /// /// Moves a child to a certain position which is in front of the child previously at given index. /// 与SetChildIndex不同的是,如果child原来在index的前面,那么child插入的位置是index-1,即保证排在原来占据index的对象的前面。 /// /// /// public int SetChildIndexBefore(GObject child, int index) { int oldIndex = _children.IndexOf(child); if (oldIndex == -1) throw new ArgumentException("Not a child of this container"); if (child.sortingOrder != 0) //no effect return oldIndex; int cnt = _children.Count; if (_sortingChildCount > 0) { if (index > (cnt - _sortingChildCount - 1)) index = cnt - _sortingChildCount - 1; } if (oldIndex < index) return _SetChildIndex(child, oldIndex, index - 1); else return _SetChildIndex(child, oldIndex, index); } int _SetChildIndex(GObject child, int oldIndex, int index) { int cnt = _children.Count; if (index > cnt) index = cnt; if (oldIndex == index) return oldIndex; _children.RemoveAt(oldIndex); if (index >= cnt) _children.Add(child); else _children.Insert(index, child); if (child.inContainer) { int displayIndex = 0; if (_childrenRenderOrder == ChildrenRenderOrder.Ascent) { for (int i = 0; i < index; i++) { GObject g = _children[i]; if (g.inContainer) displayIndex++; } container.SetChildIndex(child.displayObject, displayIndex); } else if (_childrenRenderOrder == ChildrenRenderOrder.Descent) { for (int i = cnt - 1; i > index; i--) { GObject g = _children[i]; if (g.inContainer) displayIndex++; } container.SetChildIndex(child.displayObject, displayIndex); } else { UpdateContext.OnBegin -= _buildDelegate; UpdateContext.OnBegin += _buildDelegate; } SetBoundsChangedFlag(); } return index; } /// /// Swaps the indexes of two children. /// /// A child object /// A child object public void SwapChildren(GObject child1, GObject child2) { int index1 = _children.IndexOf(child1); int index2 = _children.IndexOf(child2); if (index1 == -1 || index2 == -1) throw new Exception("Not a child of this container"); SwapChildrenAt(index1, index2); } /// /// Swaps the indexes of two children. /// /// index of first child /// index of second child public void SwapChildrenAt(int index1, int index2) { GObject child1 = _children[index1]; GObject child2 = _children[index2]; SetChildIndex(child1, index2); SetChildIndex(child2, index1); } /// /// The number of children of this component. /// public int numChildren { get { return _children.Count; } } /// /// /// /// /// public bool IsAncestorOf(GObject obj) { if (obj == null) return false; GComponent p = obj.parent; while (p != null) { if (p == this) return true; p = p.parent; } return false; } /// /// /// /// public void ChangeChildrenOrder(IList objs) { int cnt = objs.Count; for (int i = 0; i < cnt; i++) { GObject obj = objs[i]; if (obj.parent != this) throw new Exception("Not a child of this container"); _children[i] = obj; } BuildNativeDisplayList(); SetBoundsChangedFlag(); } /// /// Adds a controller to the container. /// /// Controller object public void AddController(Controller controller) { _controllers.Add(controller); controller.parent = this; ApplyController(controller); } /// /// Returns a controller object at a certain index. /// /// Index /// Controller object. public Controller GetControllerAt(int index) { return _controllers[index]; } /// /// Returns a controller object with a certain name. /// /// Name /// Controller object. Null if not found. public Controller GetController(string name) { int cnt = _controllers.Count; for (int i = 0; i < cnt; ++i) { Controller c = _controllers[i]; if (c.name == name) return c; } return null; } /// /// Removes a controller from the container. /// /// Controller object. public void RemoveController(Controller c) { int index = _controllers.IndexOf(c); if (index == -1) throw new Exception("controller not exists: " + c.name); c.parent = null; _controllers.RemoveAt(index); int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; child.HandleControllerChanged(c); } } /// /// Returns controller list. /// /// Controller list public List Controllers { get { return _controllers; } } /// /// Returns a transition object at a certain index. /// /// Index /// transition object. public Transition GetTransitionAt(int index) { return _transitions[index]; } /// /// Returns a transition object at a certain name. /// /// Name /// Transition Object public Transition GetTransition(string name) { int cnt = _transitions.Count; for (int i = 0; i < cnt; ++i) { Transition trans = _transitions[i]; if (trans.name == name) return trans; } return null; } /// /// Returns transition list. /// /// Transition list public List Transitions { get { return _transitions; } } internal void ChildStateChanged(GObject child) { if (_buildingDisplayList) return; int cnt = _children.Count; if (child is GGroup) { for (int i = 0; i < cnt; ++i) { GObject g = _children[i]; if (g.group == child) ChildStateChanged(g); } return; } if (child.displayObject == null) return; if (child.internalVisible) { if (child.displayObject.parent == null) { if (_childrenRenderOrder == ChildrenRenderOrder.Ascent) { int index = 0; for (int i = 0; i < cnt; i++) { GObject g = _children[i]; if (g == child) break; if (g.displayObject != null && g.displayObject.parent != null) index++; } container.AddChildAt(child.displayObject, index); } else if (_childrenRenderOrder == ChildrenRenderOrder.Descent) { int index = 0; for (int i = cnt - 1; i >= 0; i--) { GObject g = _children[i]; if (g == child) break; if (g.displayObject != null && g.displayObject.parent != null) index++; } container.AddChildAt(child.displayObject, index); } else { container.AddChild(child.displayObject); UpdateContext.OnBegin -= _buildDelegate; UpdateContext.OnBegin += _buildDelegate; } } } else { if (child.displayObject.parent != null) { container.RemoveChild(child.displayObject); if (_childrenRenderOrder == ChildrenRenderOrder.Arch) { UpdateContext.OnBegin -= _buildDelegate; UpdateContext.OnBegin += _buildDelegate; } } } } void BuildNativeDisplayList() { if (displayObject == null || displayObject.isDisposed) return; int cnt = _children.Count; if (cnt == 0) return; switch (_childrenRenderOrder) { case ChildrenRenderOrder.Ascent: { for (int i = 0; i < cnt; i++) { GObject child = _children[i]; if (child.displayObject != null && child.internalVisible) container.AddChild(child.displayObject); } } break; case ChildrenRenderOrder.Descent: { for (int i = cnt - 1; i >= 0; i--) { GObject child = _children[i]; if (child.displayObject != null && child.internalVisible) container.AddChild(child.displayObject); } } break; case ChildrenRenderOrder.Arch: { int apex = Mathf.Clamp(_apexIndex, 0, cnt); for (int i = 0; i < apex; i++) { GObject child = _children[i]; if (child.displayObject != null && child.internalVisible) container.AddChild(child.displayObject); } for (int i = cnt - 1; i >= apex; i--) { GObject child = _children[i]; if (child.displayObject != null && child.internalVisible) container.AddChild(child.displayObject); } } break; } } internal void ApplyController(Controller c) { _applyingController = c; int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; child.HandleControllerChanged(c); } _applyingController = null; c.RunActions(); } void ApplyAllControllers() { int cnt = _controllers.Count; for (int i = 0; i < cnt; ++i) { Controller controller = _controllers[i]; ApplyController(controller); } } internal void AdjustRadioGroupDepth(GObject obj, Controller c) { int cnt = _children.Count; int i; GObject child; int myIndex = -1, maxIndex = -1; for (i = 0; i < cnt; i++) { child = _children[i]; if (child == obj) { myIndex = i; } else if ((child is GButton) && ((GButton)child).relatedController == c) { if (i > maxIndex) maxIndex = i; } } if (myIndex < maxIndex) { if (_applyingController != null) _children[maxIndex].HandleControllerChanged(_applyingController); this.SwapChildrenAt(myIndex, maxIndex); } } /// /// If clipping softness is set, clipped containers will have soft border effect. /// public Vector2 clipSoftness { get { return _clipSoftness; } set { _clipSoftness = value; if (scrollPane != null) scrollPane.UpdateClipSoft(); else if (_clipSoftness.x > 0 || _clipSoftness.y > 0) rootContainer.clipSoftness = new Vector4(value.x, value.y, value.x, value.y); else rootContainer.clipSoftness = null; } } /// /// The mask of the component. /// public DisplayObject mask { get { return container.mask; } set { container.mask = value; if (value != null && value.parent != container) container.AddChild(value); } } /// /// /// public bool reversedMask { get { return container.reversedMask; } set { container.reversedMask = value; } } /// /// /// public string baseUserData { get { ByteBuffer buffer = packageItem.rawData; buffer.Seek(0, 4); return buffer.ReadS(); } } /// /// Test if a child is in view. /// /// A child object /// True if in view public bool IsChildInView(GObject child) { if (scrollPane != null) { return scrollPane.IsChildInView(child); } else if (rootContainer.clipRect != null) { return child.x + child.width >= 0 && child.x <= this.width && child.y + child.height >= 0 && child.y <= this.height; } else return true; } virtual public int GetFirstChildInView() { int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; if (IsChildInView(child)) return i; } return -1; } protected void SetupScroll(ByteBuffer buffer) { if (rootContainer == container) { container = new Container(); rootContainer.AddChild(container); } scrollPane = new ScrollPane(this); scrollPane.Setup(buffer); } protected void SetupOverflow(OverflowType overflow) { if (overflow == OverflowType.Hidden) { if (rootContainer == container) { container = new Container(); rootContainer.AddChild(container); } UpdateClipRect(); container.SetXY(_margin.left, _margin.top); } else if (_margin.left != 0 || _margin.top != 0) { if (rootContainer == container) { container = new Container(); rootContainer.AddChild(container); } container.SetXY(_margin.left, _margin.top); } } void UpdateClipRect() { if (scrollPane == null) { float w = this.width - (_margin.left + _margin.right); float h = this.height - (_margin.top + _margin.bottom); rootContainer.clipRect = new Rect(_margin.left, _margin.top, w, h); } else rootContainer.clipRect = new Rect(0, 0, this.width, this.height); } override protected void HandleSizeChanged() { base.HandleSizeChanged(); if (scrollPane != null) scrollPane.OnOwnerSizeChanged(); if (rootContainer.clipRect != null) UpdateClipRect(); } override protected void HandleGrayedChanged() { Controller cc = GetController("grayed"); if (cc != null) cc.selectedIndex = this.grayed ? 1 : 0; else base.HandleGrayedChanged(); } override public void HandleControllerChanged(Controller c) { base.HandleControllerChanged(c); if (scrollPane != null) scrollPane.HandleControllerChanged(c); } /// /// Notify the component the bounds should recaculate. /// public void SetBoundsChangedFlag() { if (scrollPane == null && !_trackBounds) return; _boundsChanged = true; } /// /// Make sure the bounds of the component is correct. /// Bounds of the component is not updated on every changed. For example, you add a new child to the list, children in the list will be rearranged in next frame. /// If you want to access the correct child position immediatelly, call this function first. /// public void EnsureBoundsCorrect() { if (_boundsChanged) UpdateBounds(); } virtual protected void UpdateBounds() { float ax, ay, aw, ah; if (_children.Count > 0) { ax = int.MaxValue; ay = int.MaxValue; float ar = int.MinValue, ab = int.MinValue; float tmp; int cnt = _children.Count; for (int i = 0; i < cnt; ++i) { GObject child = _children[i]; tmp = child.x; if (tmp < ax) ax = tmp; tmp = child.y; if (tmp < ay) ay = tmp; tmp = child.x + child.actualWidth; if (tmp > ar) ar = tmp; tmp = child.y + child.actualHeight; if (tmp > ab) ab = tmp; } aw = ar - ax; ah = ab - ay; } else { ax = 0; ay = 0; aw = 0; ah = 0; } SetBounds(ax, ay, aw, ah); } protected void SetBounds(float ax, float ay, float aw, float ah) { _boundsChanged = false; if (scrollPane != null) scrollPane.SetContentSize(Mathf.RoundToInt(ax + aw), Mathf.RoundToInt(ay + ah)); } /// /// Viwe port width of the container. /// public float viewWidth { get { if (scrollPane != null) return scrollPane.viewWidth; else return this.width - _margin.left - _margin.right; } set { if (scrollPane != null) scrollPane.viewWidth = value; else this.width = value + _margin.left + _margin.right; } } /// /// View port height of the container. /// public float viewHeight { get { if (scrollPane != null) return scrollPane.viewHeight; else return this.height - _margin.top - _margin.bottom; } set { if (scrollPane != null) scrollPane.viewHeight = value; else this.height = value + _margin.top + _margin.bottom; } } public void GetSnappingPosition(ref float xValue, ref float yValue) { GetSnappingPositionWithDir(ref xValue, ref yValue, 0, 0); } protected bool ShouldSnapToNext(float dir, float delta, float size) { return dir < 0 && delta > UIConfig.defaultScrollSnappingThreshold * size || dir > 0 && delta > (1 - UIConfig.defaultScrollSnappingThreshold) * size || dir == 0 && delta > size / 2; } /** * dir正数表示右移或者下移,负数表示左移或者上移 */ virtual public void GetSnappingPositionWithDir(ref float xValue, ref float yValue, float xDir, float yDir) { int cnt = _children.Count; if (cnt == 0) return; EnsureBoundsCorrect(); GObject obj = null; int i = 0; if (yValue != 0) { for (; i < cnt; i++) { obj = _children[i]; if (yValue < obj.y) { if (i == 0) { yValue = 0; break; } else { GObject prev = _children[i - 1]; if (ShouldSnapToNext(yDir, yValue - prev.y, prev.height)) yValue = obj.y; else yValue = prev.y; break; } } } if (i == cnt) yValue = obj.y; } if (xValue != 0) { if (i > 0) i--; for (; i < cnt; i++) { obj = _children[i]; if (xValue < obj.x) { if (i == 0) { xValue = 0; break; } else { GObject prev = _children[i - 1]; if (ShouldSnapToNext(xDir, xValue - prev.x, prev.width)) xValue = obj.x; else xValue = prev.x; break; } } } if (i == cnt) xValue = obj.x; } } internal void ChildSortingOrderChanged(GObject child, int oldValue, int newValue) { if (newValue == 0) { _sortingChildCount--; SetChildIndex(child, _children.Count); } else { if (oldValue == 0) _sortingChildCount++; int oldIndex = _children.IndexOf(child); int index = GetInsertPosForSortingChild(child); if (oldIndex < index) _SetChildIndex(child, oldIndex, index - 1); else _SetChildIndex(child, oldIndex, index); } } /// /// 每帧调用的一个回调。如果你要override,请记住以下两点: /// 1、记得调用base.onUpdate; /// 2、不要在方法里进行任何会更改显示列表的操作,例如AddChild、RemoveChild、visible等。 /// virtual protected void OnUpdate() { if (_boundsChanged) UpdateBounds(); } override public void ConstructFromResource() { ConstructFromResource(null, 0); } internal void ConstructFromResource(List objectPool, int poolIndex) { this.gameObjectName = packageItem.name; PackageItem contentItem = packageItem.getBranch(); if (!contentItem.translated) { contentItem.translated = true; TranslationHelper.TranslateComponent(contentItem); } ByteBuffer buffer = contentItem.rawData; buffer.Seek(0, 0); underConstruct = true; sourceWidth = buffer.ReadInt(); sourceHeight = buffer.ReadInt(); initWidth = sourceWidth; initHeight = sourceHeight; SetSize(sourceWidth, sourceHeight); if (buffer.ReadBool()) { minWidth = buffer.ReadInt(); maxWidth = buffer.ReadInt(); minHeight = buffer.ReadInt(); maxHeight = buffer.ReadInt(); } if (buffer.ReadBool()) { float f1 = buffer.ReadFloat(); float f2 = buffer.ReadFloat(); SetPivot(f1, f2, buffer.ReadBool()); } if (buffer.ReadBool()) { _margin.top = buffer.ReadInt(); _margin.bottom = buffer.ReadInt(); _margin.left = buffer.ReadInt(); _margin.right = buffer.ReadInt(); } OverflowType overflow = (OverflowType)buffer.ReadByte(); if (overflow == OverflowType.Scroll) { int savedPos = buffer.position; buffer.Seek(0, 7); SetupScroll(buffer); buffer.position = savedPos; } else SetupOverflow(overflow); if (buffer.ReadBool()) { int i1 = buffer.ReadInt(); int i2 = buffer.ReadInt(); this.clipSoftness = new Vector2(i1, i2); } _buildingDisplayList = true; buffer.Seek(0, 1); int controllerCount = buffer.ReadShort(); for (int i = 0; i < controllerCount; i++) { int nextPos = buffer.ReadUshort(); nextPos += buffer.position; Controller controller = new Controller(); _controllers.Add(controller); controller.parent = this; controller.Setup(buffer); buffer.position = nextPos; } buffer.Seek(0, 2); GObject child; int childCount = buffer.ReadShort(); for (int i = 0; i < childCount; i++) { int dataLen = buffer.ReadShort(); int curPos = buffer.position; if (objectPool != null) child = objectPool[poolIndex + i]; else { buffer.Seek(curPos, 0); ObjectType type = (ObjectType)buffer.ReadByte(); string src = buffer.ReadS(); string pkgId = buffer.ReadS(); PackageItem pi = null; if (src != null) { UIPackage pkg; if (pkgId != null) pkg = UIPackage.GetById(pkgId); else pkg = contentItem.owner; pi = pkg != null ? pkg.GetItem(src) : null; } if (pi != null) { child = UIObjectFactory.NewObject(pi); child.ConstructFromResource(); } else child = UIObjectFactory.NewObject(type); } child.underConstruct = true; child.Setup_BeforeAdd(buffer, curPos); child.InternalSetParent(this); _children.Add(child); buffer.position = curPos + dataLen; } buffer.Seek(0, 3); this.relations.Setup(buffer, true); buffer.Seek(0, 2); buffer.Skip(2); for (int i = 0; i < childCount; i++) { int nextPos = buffer.ReadUshort(); nextPos += buffer.position; buffer.Seek(buffer.position, 3); _children[i].relations.Setup(buffer, false); buffer.position = nextPos; } buffer.Seek(0, 2); buffer.Skip(2); for (int i = 0; i < childCount; i++) { int nextPos = buffer.ReadUshort(); nextPos += buffer.position; child = _children[i]; child.Setup_AfterAdd(buffer, buffer.position); child.underConstruct = false; if (child.displayObject != null) child.displayObject.cachedTransform.SetParent(this.displayObject.cachedTransform, false); buffer.position = nextPos; } buffer.Seek(0, 4); buffer.Skip(2); //customData this.opaque = buffer.ReadBool(); int maskId = buffer.ReadShort(); if (maskId != -1) { container.mask = GetChildAt(maskId).displayObject; if (buffer.ReadBool()) container.reversedMask = true; } { string hitTestId = buffer.ReadS(); int i1 = buffer.ReadInt(); int i2 = buffer.ReadInt(); if (hitTestId != null) { PackageItem pi = contentItem.owner.GetItem(hitTestId); if (pi != null && pi.pixelHitTestData != null) rootContainer.hitArea = new PixelHitTest(pi.pixelHitTestData, i1, i2, sourceWidth, sourceHeight); } else if (i1 != 0 && i2 != -1) { rootContainer.hitArea = new ShapeHitTest(this.GetChildAt(i2).displayObject); } } if (buffer.version >= 5) { string str = buffer.ReadS(); if (!string.IsNullOrEmpty(str)) this.onAddedToStage.Add(() => __playSound(str, 1)); string str2 = buffer.ReadS(); if (!string.IsNullOrEmpty(str2)) this.onRemovedFromStage.Add(() => __playSound(str2, 1)); } buffer.Seek(0, 5); int transitionCount = buffer.ReadShort(); for (int i = 0; i < transitionCount; i++) { int nextPos = buffer.ReadUshort(); nextPos += buffer.position; Transition trans = new Transition(this); trans.Setup(buffer); _transitions.Add(trans); buffer.position = nextPos; } if (_transitions.Count > 0) { this.onAddedToStage.Add(__addedToStage); this.onRemovedFromStage.Add(__removedFromStage); } ApplyAllControllers(); _buildingDisplayList = false; underConstruct = false; BuildNativeDisplayList(); SetBoundsChangedFlag(); if (contentItem.objectType != ObjectType.Component) ConstructExtension(buffer); ConstructFromXML(null); #if FAIRYGUI_TOLUA CallLua("ctor"); #endif #if FAIRYGUI_PUERTS if (__onConstruct != null) __onConstruct(); #endif } virtual protected void ConstructExtension(ByteBuffer buffer) { } /// /// Method for extensions to override /// /// virtual public void ConstructFromXML(XML xml) { } public override void Setup_AfterAdd(ByteBuffer buffer, int beginPos) { base.Setup_AfterAdd(buffer, beginPos); buffer.Seek(beginPos, 4); int pageController = buffer.ReadShort(); if (pageController != -1 && scrollPane != null && scrollPane.pageMode) scrollPane.pageController = parent.GetControllerAt(pageController); int cnt = buffer.ReadShort(); for (int i = 0; i < cnt; i++) { Controller cc = GetController(buffer.ReadS()); string pageId = buffer.ReadS(); if (cc != null) cc.selectedPageId = pageId; } if (buffer.version >= 2) { cnt = buffer.ReadShort(); for (int i = 0; i < cnt; i++) { string target = buffer.ReadS(); int propertyId = buffer.ReadShort(); string value = buffer.ReadS(); GObject obj = this.GetChildByPath(target); if (obj != null) { if (propertyId == 0) obj.text = value; else if (propertyId == 1) obj.icon = value; } } } } void __playSound(string soundRes, float volumeScale) { NAudioClip sound = UIPackage.GetItemAssetByURL(soundRes) as NAudioClip; if (sound != null && sound.nativeClip != null) Stage.inst.PlayOneShotSound(sound.nativeClip, volumeScale); } void __addedToStage() { int cnt = _transitions.Count; for (int i = 0; i < cnt; ++i) _transitions[i].OnOwnerAddedToStage(); } void __removedFromStage() { int cnt = _transitions.Count; for (int i = 0; i < cnt; ++i) _transitions[i].OnOwnerRemovedFromStage(); } #if FAIRYGUI_TOLUA internal LuaTable _peerTable; public void SetLuaPeer(LuaTable peerTable) { _peerTable = peerTable; } [NoToLua] public bool CallLua(string funcName) { if (_peerTable != null) { LuaFunction ctor = _peerTable.GetLuaFunction(funcName); if (ctor != null) { try { ctor.Call(this); } catch (Exception err) { Debug.LogError(err); } ctor.Dispose(); return true; } } return false; } #endif #if FAIRYGUI_PUERTS public Action __onConstruct; public Action __onDispose; #endif } }