/** * Copyright (c) Lambda Innovation, 2013-2015 * 本作品版权由Lambda Innovation所有。 * http://www.li-dev.cn/ * * This project is open-source, and it is distributed under * the terms of GNU General Public License. You can modify * and distribute freely as long as you follow the license. * 本项目是一个开源项目,且遵循GNU通用公共授权协议。 * 在遵照该协议的情况下,您可以自由传播和修改。 * http://www.gnu.org/licenses/gpl.html */ package cn.liutils.cgui.gui; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import com.google.common.collect.ImmutableList; import cn.liutils.cgui.gui.component.Component; import cn.liutils.cgui.gui.component.Transform; import cn.liutils.cgui.gui.event.GuiEvent; import cn.liutils.cgui.gui.event.GuiEventBus; import cn.liutils.cgui.gui.event.GuiEventHandler; import cn.liutils.cgui.gui.event.IGuiEventHandler; /** * @author WeathFolD */ public class Widget extends WidgetContainer { private GuiEventBus eventBus = new GuiEventBus(); private List<Component> components = new ArrayList(); public boolean disposed = false; public boolean dirty = true; //Indicate that this widget's pos data is dirty and requires update. LIGui gui; Widget parent; //*INTERNAL* Real-time calculated data not directly relevant to widget properties public double x, y; public double scale; /** * *INTERNAL*Used ONLY in editing gui. */ public boolean visible = true; /** * *INTERNAL*Whether this widget can be copied when going down copy recursion process. */ public boolean needCopy = true; public Transform transform; //Defaults { addComponent(transform = new Transform()); } public Widget() {} public boolean isVisible() { return visible && transform.doesDraw; } /** * Return a reasonable copy of this widget. Retains all the properties and functions, * along with its all sub widgets recursively. */ public Widget copy() { Widget n = null; try { n = getClass().newInstance(); } catch (Exception e) { e.printStackTrace(); } copyInfoTo(n); return n; } protected void copyInfoTo(Widget n) { n.components.clear(); for(Component c : components) { n.addComponent(c.copy()); } n.transform = n.getComponent("Transform"); n.eventBus = eventBus.copy(); //Also copy the widget's sub widgets recursively. for(Widget asub : getDrawList()) { if(asub.needCopy) n.addWidget(asub.getName(), asub.copy()); } } /** * Called when added into a GUI. */ protected void onAdded() {} public boolean initialized() { return gui != null; } public boolean isWidgetParent() { return parent != null; } public Widget getWidgetParent() { return parent; } public LIGui getGui() { return gui; } /** * Dispose this gui. Will get removed next frame. */ public void dispose() { disposed = true; } //Component handling /** * Java generic type is shit, so use it at your own risk. * @return the first component with the name specified, or null if no such component. */ public <T extends Component> T getComponent(String name) { for(Component c : components) { if(c.name.equals(name)) return (T) c; } return null; } public Widget addComponent(Component c) { if(c.widget != null) throw new RuntimeException("Can't add one component into multiple widgets!"); for(Component cc : components) { if(cc.name.equals(c.name)) { throw new RuntimeException("Duplicate component!"); } } c.widget = this; components.add(c); c.onAdded(); return this; } public void removeComponent(Component c) { removeComponent(c.name); } public void removeComponent(String name) { Iterator<Component> iter = components.iterator(); while(iter.hasNext()) { Component c = iter.next(); if(c.name.equals(name)) { c.onRemoved(); c.widget = null; iter.remove(); return; } } } /** * Return the raw component list. */ public List<Component> getComponentList() { return (components); } //Event dispatch public final Widget regEventHandler(GuiEventHandler h) { eventBus.regEventHandler(h); return this; } public final Widget regEventHandlerAtBegin(GuiEventHandler h) { eventBus.regAtBeginning(h); return this; } public final <T extends GuiEvent> Widget regEventHandler(Class<? extends T> clazz, IGuiEventHandler<T> handler) { eventBus.reg(clazz, handler); return this; } public final <T extends GuiEvent> Widget regEventHandlerAtBegin(Class<? extends GuiEvent> clazz, IGuiEventHandler<T> handler) { eventBus.regAtBeginning(clazz, handler); return this; } public final void postEvent(GuiEvent event) { eventBus.postEvent(this, event); for(Component c : components) { if(c.enabled) c.postEvent(this, event); } } //Utils public String getName() { WidgetContainer parent = getAbstractParent(); return parent == null ? "null" : parent.getWidgetName(this); } public boolean isPointWithin(double tx, double ty) { double w = transform.width, h = transform.height; double x1 = x + w * scale, y1 = y + h * scale; return (x <= tx && tx <x1) && (y <= ty && ty < y1); } public boolean isFocused() { return gui != null && this == gui.getFocus(); } @Override protected void onWidgetAdded(String name, Widget w) { this.dirty = true; w.parent = this; w.gui = gui; } public int getHierarchyLevel() { int ret = 0; Widget cur = this; while(cur.isWidgetParent()) { cur = cur.getWidgetParent(); ++ret; } return ret; } public WidgetContainer getAbstractParent() { return isWidgetParent() ? parent : gui; } public void moveDown() { WidgetContainer parent = getAbstractParent(); int i = parent.locate(this); if(i == -1 || i == parent.widgetList.size() - 1) return; Widget next = parent.getWidget(i + 1); parent.widgetList.set(i, next); parent.widgetList.set(i + 1, this); } public void moveUp() { WidgetContainer parent = getAbstractParent(); int i = parent.locate(this); if(i == -1 || i == 0) return; Widget last = parent.getWidget(i - 1); parent.widgetList.set(i, last); parent.widgetList.set(i - 1, this); } public void moveLeft() { if(!this.isWidgetParent()) return; WidgetContainer pp = parent.getAbstractParent(); String name = this.getName(); parent.forceRemoveWidget(this); this.disposed = false; if(!pp.addWidget(name, this)) { pp.addWidget(this); } } public void moveRight() { WidgetContainer parent = getAbstractParent(); int i = parent.locate(this) - 1; if(i >= 0) { Widget newParent = parent.getWidget(i); String name = this.getName(); parent.forceRemoveWidget(this); this.disposed = false; newParent.addWidget(name, this); } } public boolean rename(String newName) { WidgetContainer parent = getAbstractParent(); if(parent.hasWidget(newName)) return false; getAbstractParent().renameWidget(getName(), newName); return true; } public void gainFocus() { getGui().gainFocus(this); } }