package com.uwsoft.editor.renderer.scene2d; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; import com.badlogic.gdx.scenes.scene2d.ui.Image; import com.badlogic.gdx.scenes.scene2d.ui.Label; import com.badlogic.gdx.utils.Array; import com.uwsoft.editor.renderer.data.*; import com.uwsoft.editor.renderer.resources.IResourceRetriever; import com.uwsoft.editor.renderer.scripts.IActorScript; import com.uwsoft.editor.renderer.utils.CustomVariables; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; /** * Created by azakhary on 7/26/2015. */ public class CompositeActor extends Group { protected IResourceRetriever ir; private float pixelsPerWU; private float resMultiplier; protected CompositeItemVO vo; private ArrayList<IActorScript> scripts = new ArrayList<IActorScript>(3); private HashMap<Integer, Actor> indexes = new HashMap<Integer, Actor>(); private HashMap<String, LayerItemVO> layerMap = new HashMap<String, LayerItemVO>(); public CompositeActor(CompositeItemVO vo, IResourceRetriever ir) { this(vo, ir, BuiltItemHandler.DEFAULT); } public CompositeActor(CompositeItemVO vo, IResourceRetriever ir, BuiltItemHandler itemHandler) { this(vo, ir, itemHandler, true); } private CompositeActor(CompositeItemVO vo, IResourceRetriever ir, BuiltItemHandler itemHandler, boolean isRoot) { this.ir= ir; this.vo = vo; pixelsPerWU = ir.getProjectVO().pixelToWorld; ResolutionEntryVO resolutionEntryVO = ir.getLoadedResolution(); resMultiplier = resolutionEntryVO.getMultiplier(ir.getProjectVO().originalResolution); makeLayerMap(vo); build(vo, itemHandler, isRoot); } private void makeLayerMap(CompositeItemVO vo) { layerMap.clear(); for(int i = 0; i < vo.composite.layers.size(); i++) { layerMap.put(vo.composite.layers.get(i).layerName,vo.composite.layers.get(i)); } } protected void build(CompositeItemVO vo, BuiltItemHandler itemHandler, boolean isRoot) { buildImages(vo.composite.sImages, itemHandler); build9PatchImages(vo.composite.sImage9patchs, itemHandler); buildLabels(vo.composite.sLabels, itemHandler); buildComposites(vo.composite.sComposites, itemHandler); processZIndexes(); recalculateSize(); if(isRoot) { buildCoreData(this, vo); itemHandler.onItemBuild(this); } } protected void buildComposites(ArrayList<CompositeItemVO> composites, BuiltItemHandler itemHandler) { for(int i = 0; i < composites.size(); i++) { String className = getClassName(composites.get(i).customVars); CompositeActor actor; if(className!=null){ try { Class<?> c = Class.forName(className); actor = (CompositeActor) c.getConstructors()[0].newInstance(composites.get(i), ir, itemHandler); }catch (Exception ex){ actor = new CompositeActor(composites.get(i), ir, itemHandler, false); } }else { actor = new CompositeActor(composites.get(i), ir, itemHandler, false); } processMain(actor, composites.get(i)); addActor(actor); itemHandler.onItemBuild(actor); } } private String getClassName(String customVars) { CustomVariables cv = new CustomVariables(); cv.loadFromString(customVars); String className = cv.getStringVariable("className"); if(className!=null && className.equals("")){ className = null; } return className; } public void addScript(IActorScript iScript) { scripts.add(iScript); iScript.init(this); } protected void buildImages(ArrayList<SimpleImageVO> images, BuiltItemHandler itemHandler) { for(int i = 0; i < images.size(); i++) { Image image = new Image(ir.getTextureRegion(images.get(i).imageName)); processMain(image, images.get(i)); addActor(image); itemHandler.onItemBuild(image); } } protected void build9PatchImages(ArrayList<Image9patchVO> patches, BuiltItemHandler itemHandler) { for(int i = 0; i < patches.size(); i++) { TextureAtlas.AtlasRegion region = (TextureAtlas.AtlasRegion) ir.getTextureRegion(patches.get(i).imageName); NinePatch ninePatch = new NinePatch(region, region.splits[0], region.splits[1], region.splits[2], region.splits[3]); Image image = new Image(ninePatch); image.setWidth(patches.get(i).width*pixelsPerWU/resMultiplier); image.setHeight(patches.get(i).height * pixelsPerWU/resMultiplier); processMain(image, patches.get(i)); addActor(image); itemHandler.onItemBuild(image); } } protected void buildLabels(ArrayList<LabelVO> labels, BuiltItemHandler itemHandler) { for(int i = 0; i < labels.size(); i++) { Label.LabelStyle style = new Label.LabelStyle(ir.getBitmapFont(labels.get(i).style, labels.get(i).size), Color.WHITE); Label label = new Label(labels.get(i).text, style); label.setAlignment(labels.get(i).align); label.setWidth(labels.get(i).width * pixelsPerWU / resMultiplier); label.setHeight(labels.get(i).height * pixelsPerWU / resMultiplier); processMain(label, labels.get(i)); addActor(label); itemHandler.onItemBuild(label); } } protected void processMain(Actor actor, MainItemVO vo) { actor.setName(vo.itemIdentifier); buildCoreData(actor, vo); //actor properties actor.setPosition(vo.x * pixelsPerWU/resMultiplier, vo.y * pixelsPerWU/resMultiplier); actor.setOrigin(vo.originX * pixelsPerWU/resMultiplier, vo.originY * pixelsPerWU/resMultiplier); actor.setScale(vo.scaleX, vo.scaleY); actor.setRotation(vo.rotation); actor.setColor(new Color(vo.tint[0], vo.tint[1], vo.tint[2], vo.tint[3])); indexes.put(getLayerIndex(vo.layerName) + vo.zIndex, actor); if(layerMap.get(vo.layerName).isVisible) { actor.setVisible(true); } else { actor.setVisible(false); } } protected void buildCoreData(Actor actor, MainItemVO vo){ //custom variables CustomVariables cv = null; if(vo.customVars != null && !vo.customVars.isEmpty()) { cv = new CustomVariables(); cv.loadFromString(vo.customVars); } //core data CoreActorData data = new CoreActorData(); data.id = vo.itemIdentifier; data.layerIndex = getLayerIndex(vo.layerName); data.tags = vo.tags; data.customVars = cv; actor.setUserObject(data); } protected void processZIndexes() { Object[] indexArray = indexes.keySet().toArray(); Arrays.sort(indexArray); for(int i = 0; i < indexArray.length; i++) { indexes.get(indexArray[i]).setZIndex(i); } } public int getLayerIndex(String name) { return vo.composite.layers.indexOf(layerMap.get(name)); } public Actor getItem(String id) { for(Actor actor: getChildren()) { Object userObject = actor.getUserObject(); if(userObject != null && userObject instanceof CoreActorData && (id.equals(((CoreActorData) userObject).id))) { return actor; } } return null; } public void recalculateSize() { float lowerX = 0, lowerY = 0, upperX = 0, upperY = 0; for (int i = 0; i < getChildren().size; i++) { Actor value = getChildren().get(i); if (i == 0) { if (value.getScaleX() > 0 && value.getWidth() * value.getScaleX() > 0) { lowerX = value.getX(); upperX = value.getX() + value.getWidth() * value.getScaleX(); } else { upperX = value.getX(); lowerX = value.getX() + value.getWidth() * value.getScaleX(); } if (value.getScaleY() > 0 && value.getHeight() * value.getScaleY() > 0) { lowerY = value.getY(); upperY = value.getY() + value.getHeight() * value.getScaleY(); } else { upperY = value.getY(); lowerY = value.getY() + value.getHeight() * value.getScaleY(); } } if (value.getScaleX() > 0 && value.getWidth() > 0) { if (lowerX > value.getX()) lowerX = value.getX(); if (upperX < value.getX() + value.getWidth() * value.getScaleX()) upperX = value.getX() + value.getWidth() * value.getScaleX(); } else { if (upperX < value.getX()) upperX = value.getX(); if (lowerX > value.getX() + value.getWidth() * value.getScaleX()) lowerX = value.getX() + value.getWidth() * value.getScaleX(); } if (value.getScaleY() > 0 && value.getHeight() * value.getScaleY() > 0) { if (lowerY > value.getY()) lowerY = value.getY(); if (upperY < value.getY() + value.getHeight() * value.getScaleY()) upperY = value.getY() + value.getHeight() * value.getScaleY(); } else { if (upperY < value.getY()) upperY = value.getY(); if (lowerY > value.getY() + value.getHeight() * value.getScaleY()) lowerY = value.getY() + value.getHeight() * value.getScaleY(); } } setWidth(upperX); setHeight(upperY); } public void setLayerVisibility(String layerName, boolean isVisible) { final int layerIndex = getLayerIndex(layerName); layerMap.get(layerName).isVisible = isVisible; for(Actor actor: getChildren()) { Object userObject = actor.getUserObject(); if(userObject != null && userObject instanceof CoreActorData && ((CoreActorData)userObject).layerIndex == layerIndex) { actor.setVisible(isVisible); } } } /** * get's list of children that contain a specified tag. * Does not yet go in depth. * * @param tag * @return */ public Array<Actor> getItemsByTag(String tag) { Array<Actor> items = new Array<Actor>(); for(Actor actor: getChildren()) { Object userObject = actor.getUserObject(); if(userObject != null && userObject instanceof CoreActorData) { CoreActorData data = (CoreActorData) userObject; if(data.tags != null && Arrays.asList(data.tags).contains(tag)) items.add(actor); } } return items; } /** * returns children of this actor that are on specified layer * @param layerName * @return */ public Array<Actor> getItemsByLayer(String layerName) { final int layerIndex = getLayerIndex(layerName); Array<Actor> items = new Array<Actor>(); for(Actor actor: getChildren()) { Object userObject = actor.getUserObject(); if(userObject != null && userObject instanceof CoreActorData && ((CoreActorData)userObject).layerIndex == layerIndex) { items.add(actor); } } return items; } public ArrayList<IActorScript> getScripts() { return scripts; } public CompositeItemVO getVo() { return vo; } /** * Enables customization of the CompositeActor during building. * Example use cases: tag handling, custom variables handling */ public interface BuiltItemHandler { BuiltItemHandler DEFAULT = new BuiltItemHandler() { @Override public void onItemBuild(Actor item) { if(item instanceof CompositeActor) { CoreActorData data = (CoreActorData) item.getUserObject(); if(data != null && data.tags != null && Arrays.asList(data.tags).contains("button")) item.addListener(new ButtonClickListener()); } } }; /** * @param item newly built and added to a parent (in case it's not a root actor) */ void onItemBuild(Actor item); } @Override public void act(float delta) { for (int i = 0; i < scripts.size(); i++) { scripts.get(i).act(delta); } super.act(delta); } }