/** * * Copyright 2008 - 2009 * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * @project loon * @author cping * @email:javachenpeng@yahoo.com * @version 0.1 */ package loon.component; import loon.action.ActionBind; import loon.component.layout.LayoutManager; import loon.component.layout.LayoutPort; import loon.event.GameKey; import loon.geom.RectBox; import loon.opengl.GLEx; import loon.utils.CollectionUtils; import loon.utils.IArray; import loon.utils.LayerSorter; import loon.utils.MathUtils; import loon.utils.TArray; public abstract class LContainer extends LComponent implements IArray { protected LComponent[] _childs = new LComponent[0]; private final static LayerSorter<LComponent> compSorter = new LayerSorter<LComponent>(false); private int childCount = 0; private LComponent latestInserted = null; public LContainer(int x, int y, int w, int h) { super(x, y, w, h); this.setFocusable(false); } @Override public boolean isContainer() { return true; } public LComponent add(LComponent... comps) { for (int i = 0; i < comps.length; i++) { add(comps[i]); } return this; } public LComponent add(LComponent comp) { if (this == comp) { return this; } if (this.contains(comp)) { return this; } if (comp.getContainer() != null) { comp.setContainer(null); } comp.setContainer(this); comp.setState(State.ADDED); if (comp instanceof LScrollContainer) { ((LScrollContainer) comp).scrollContainerRealSizeChanged(); } this._childs = CollectionUtils.expand(this._childs, 1, false); this._childs[0] = comp; this.childCount++; if (desktop != null) { this.desktop.setDesktop(comp); if (this.input == null) { this.input = desktop.input; } if (comp.input == null) { comp.input = desktop.input; } } this.sortComponents(); this.latestInserted = comp; return this; } public LComponent add(LComponent comp, int index) { if (comp.getContainer() != null) { throw new IllegalStateException(comp + " already reside in another container!!!"); } comp.setContainer(this); comp.setState(State.ADDED); if (comp instanceof LScrollContainer) { ((LScrollContainer) comp).scrollContainerRealSizeChanged(); } LComponent[] newChilds = new LComponent[this._childs.length + 1]; this.childCount++; int ctr = 0; for (int i = 0; i < this.childCount; i++) { if (i != index) { newChilds[i] = this._childs[ctr]; ctr++; } } this._childs = newChilds; this._childs[index] = comp; this.desktop.setDesktop(comp); this.sortComponents(); this.latestInserted = comp; return this; } /** * 返回一组拥有指定标签的组件 * * @param tags * @return */ public TArray<LComponent> findTags(Object... tags) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (Object tag : tags) { for (int i = size - 1; i > -1; i--) { if (this._childs[i].Tag == tag || tag.equals(this._childs[i].Tag)) { list.add(this._childs[i]); } } } return list; } /** * 返回一组没有指定标签的组件 * * @param tags * @return */ public TArray<LComponent> findNotTags(Object... tags) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (Object tag : tags) { for (int i = size - 1; i > -1; i--) { if (!tag.equals(this._childs[i].Tag)) { list.add(this._childs[i]); } } } return list; } /** * 返回一组拥有指定组件名称的组件 * * @param names * @return */ public TArray<LComponent> findUINames(String... names) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (name.equals(this._childs[i].getUIName())) { list.add(this._childs[i]); } } } return list; } /** * 返回一组没有指定名称的组件 * * @param names * @return */ public TArray<LComponent> findNotUINames(String... names) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (!name.equals(this._childs[i].getUIName())) { list.add(this._childs[i]); } } } return list; } /** * 返回一组指定名的组件 * * @param names * @return */ public TArray<LComponent> findNames(String... names) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (name.equals(this._childs[i].getName())) { list.add(this._childs[i]); } } } return list; } /** * 返回一组没有指定名的组件 * * @param names * @return */ public TArray<LComponent> findNotNames(String... names) { TArray<LComponent> list = new TArray<LComponent>(); final int size = this.childCount; for (String name : names) { for (int i = size - 1; i > -1; i--) { if (!name.equals(this._childs[i].getName())) { list.add(this._childs[i]); } } } return list; } public boolean contains(LComponent comp) { if (comp == null) { return false; } if (_childs == null) { return false; } for (int i = 0; i < this.childCount; i++) { if (_childs[i] != null && comp.equals(_childs[i])) { return true; } } return false; } public int remove(LComponent comp) { final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (this._childs[i] == comp) { this.remove(i); return i; } } return -1; } public boolean removeTag(Object tag) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (this._childs[i].Tag == tag || tag.equals(this._childs[i].Tag)) { this.remove(i); flag = true; } } return flag; } public boolean removeNotTag(Object tag) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (!tag.equals(this._childs[i].Tag)) { this.remove(i); flag = true; } } return flag; } public boolean removeUIName(String name) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (name.equals(this._childs[i].getUIName())) { this.remove(i); flag = true; } } return flag; } public boolean removeNotUIName(String name) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (!name.equals(this._childs[i].getUIName())) { this.remove(i); flag = true; } } return flag; } public boolean removeName(String name) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (name.equals(this._childs[i].getName())) { this.remove(i); flag = true; } } return flag; } public boolean removeNotName(String name) { boolean flag = false; final int size = this.childCount; for (int i = size - 1; i > -1; i--) { if (!name.equals(this._childs[i].getName())) { this.remove(i); flag = true; } } return flag; } public LComponent remove(int index) { LComponent comp = this._childs[index]; if (comp != null) { this.desktop.setComponentStat(comp, false); comp.setContainer(null); comp.setState(State.REMOVED); if (comp instanceof ActionBind) { removeActionEvents((ActionBind) comp); } // comp.dispose(); } this._childs = CollectionUtils.cut(this._childs, index); this.childCount--; return comp; } public void clear() { this.desktop.clearComponentsStat(this._childs); for (int i = 0; i < this.childCount; i++) { LComponent comp = this._childs[i]; if (comp != null) { comp.setContainer(null); comp.setState(State.REMOVED); if (comp instanceof ActionBind) { removeActionEvents((ActionBind) comp); } // comp.dispose(); } } this._childs = new LComponent[0]; this.childCount = 0; } public void replace(LComponent oldComp, LComponent newComp) { int index = this.remove(oldComp); this.add(newComp, index); } @Override public void update(long timer) { if (isClose) { return; } if (!this.isVisible()) { return; } synchronized (_childs) { super.update(timer); LComponent component; for (int i = 0; i < this.childCount; i++) { component = _childs[i]; if (component != null) { component.update(timer); } } } } @Override public void validatePosition() { if (isClose) { return; } super.validatePosition(); for (int i = 0; i < this.childCount; i++) { this._childs[i].validatePosition(); } if (!this.elastic) { for (int i = 0; i < this.childCount; i++) { if (this._childs[i].getX() > this.getWidth() || this._childs[i].getY() > this.getHeight() || this._childs[i].getX() + this._childs[i].getWidth() < 0 || this._childs[i].getY() + this._childs[i].getHeight() < 0) { setElastic(true); break; } } } } @Override protected void validateSize() { super.validateSize(); for (int i = 0; i < this.childCount; i++) { this._childs[i].validateSize(); } } @Override public void createUI(GLEx g) { if (isClose) { return; } if (!this.isVisible()) { return; } synchronized (_childs) { super.createUI(g); if (this.elastic) { g.setClip(this.getScreenX(), this.getScreenY(), this.getWidth(), this.getHeight()); } this.renderComponents(g); if (this.elastic) { g.clearClip(); } } } protected void renderComponents(GLEx g) { for (int i = this.childCount - 1; i >= 0; i--) { this._childs[i].createUI(g); } } public void sendToFront(LComponent comp) { if (this.childCount <= 1 || this._childs[0] == comp) { return; } if (_childs[0] == comp) { return; } for (int i = 0; i < this.childCount; i++) { if (this._childs[i] == comp) { this._childs = CollectionUtils.cut(this._childs, i); this._childs = CollectionUtils.expand(this._childs, 1, false); this._childs[0] = comp; this.sortComponents(); break; } } } public void sendToBack(LComponent comp) { if (this.childCount <= 1 || this._childs[this.childCount - 1] == comp) { return; } if (_childs[this.childCount - 1] == comp) { return; } for (int i = 0; i < this.childCount; i++) { if (this._childs[i] == comp) { this._childs = CollectionUtils.cut(this._childs, i); this._childs = CollectionUtils.expand(this._childs, 1, true); this._childs[this.childCount - 1] = comp; this.sortComponents(); break; } } } public void sortComponents() { compSorter.sort(this._childs); } protected void transferFocus(LComponent component) { for (int i = 0; i < this.childCount; i++) { if (component == this._childs[i]) { int j = i; do { if (--i < 0) { i = this.childCount - 1; } if (i == j) { return; } } while (!this._childs[i].requestFocus()); break; } } } protected void transferFocusBackward(LComponent component) { for (int i = 0; i < this.childCount; i++) { if (component == this._childs[i]) { int j = i; do { if (++i >= this.childCount) { i = 0; } if (i == j) { return; } } while (!this._childs[i].requestFocus()); break; } } } public boolean isSelected() { if (!super.isSelected()) { for (int i = 0; i < this.childCount; i++) { if (this._childs[i].isSelected()) { return true; } } return false; } else { return true; } } public boolean isElastic() { return this.elastic; } public void setElastic(boolean b) { if (getWidth() > 32 || getHeight() > 32) { this.elastic = b; } else { this.elastic = false; } } public LComponent findComponent(int x1, int y1) { if (!this.intersects(x1, y1)) { return null; } for (int i = 0; i < this.childCount; i++) { if (this._childs[i].intersects(x1, y1)) { LComponent comp = (!this._childs[i].isContainer()) ? this._childs[i] : ((LContainer) this._childs[i]).findComponent(x1, y1); LContainer container = comp.getContainer(); if (container != null && container instanceof LScrollContainer) { if (container.contains(comp) && (comp.getWidth() >= container.getWidth() || comp.getHeight() >= container.getHeight())) { return comp.getContainer(); } } return comp; } } return this; } public int getComponentCount() { return this.childCount; } public LComponent[] getComponents() { return CollectionUtils.copyOf(this._childs); } public LComponent get() { return this.latestInserted; } private RectBox getBox() { if (_rect != null) { _rect.setBounds(MathUtils.getBounds(0, 0, getWidth() * _scaleX, getHeight() * _scaleY, _rotation, _rect)); } else { _rect = MathUtils.getBounds(0, 0, getWidth() * _scaleX, getHeight() * _scaleY, _rotation, _rect); } return _rect; } @Override public LayoutPort getLayoutPort() { if (_super == null) { return new LayoutPort(getBox(), getRootConstraints()); } else { return new LayoutPort(this, getRootConstraints()); } } public void layoutElements(final LayoutManager manager, final LComponent... comps) { if (manager != null) { TArray<LComponent> list = new TArray<LComponent>(); for (int i = 0; i < comps.length; i++) { LComponent c = comps[i]; if (c != null && !(c instanceof LToolTip)) { list.add(c); } } LComponent[] tmp = new LComponent[list.size]; for (int i = 0; i < list.size; i++) { tmp[i] = list.get(i); } manager.layoutElements(this, tmp); } } public void packLayout(final LayoutManager manager) { packLayout(manager, 0, 0, 0, 0); } public void packLayout(final LayoutManager manager, final float spacex, final float spacey, final float spaceWidth, final float spaceHeight) { LComponent[] comps = getComponents(); CollectionUtils.reverse(comps); layoutElements(manager, comps); if (spacex != 0 || spacey != 0 || spaceWidth != 0 || spaceHeight != 0) { for (int i = 0; i < comps.length; i++) { LComponent comp = comps[i]; if (comp != null && !(comp instanceof LToolTip)) { comp.setX(comp.getX() + spacex); comp.setY(comp.getY() + spacey); comp.setWidth(comp.getWidth() + spaceWidth); comp.setHeight(comp.getHeight() + spaceHeight); } } } } @Override public LComponent in() { for (int i = 0; i < _childs.length; i++) { LComponent comp = (LComponent) _childs[i]; if (comp != null) { comp.in(); } } super.in(); return this; } @Override public LComponent out() { for (int i = 0; i < _childs.length; i++) { LComponent comp = (LComponent) _childs[i]; if (comp != null) { comp.out(); } } super.out(); return this; } @Override public int size() { return childCount; } @Override public boolean isEmpty() { return childCount == 0 || _childs == null; } @Override public void keyPressed(GameKey key) { super.keyPressed(key); LComponent[] childs = _childs; for (int i = 0; i < childs.length; i++) { LComponent c = childs[i]; if (c != null) { c.keyPressed(key); } } } @Override public void keyReleased(GameKey key) { super.keyReleased(key); LComponent[] childs = _childs; for (int i = 0; i < childs.length; i++) { LComponent c = childs[i]; if (c != null) { c.keyReleased(key); } } } void toString(StringBuilder buffer, int indent) { buffer.append(super.toString()); buffer.append('\n'); LComponent[] comps = _childs; for (int i = 0, size = comps.length; i < size; i++) { for (int ii = 0; ii < indent; ii++) { buffer.append("| "); } LComponent c = comps[i]; if (c instanceof LContainer) { ((LContainer) c).toString(buffer, indent + 1); } else { buffer.append(c); buffer.append('\n'); } } } @Override public String toString() { StringBuilder buffer = new StringBuilder(128); toString(buffer, 1); buffer.setLength(buffer.length() - 1); return buffer.toString(); } @Override public void close() { super.close(); if (autoDestroy) { if (_childs != null) { for (LComponent c : _childs) { if (c != null && !c.isClose) { c.close(); c = null; } } } } } }