org.terasology.rendering.nui.skin.UISkinBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.terasology.rendering.nui.skin.UISkinBuilder.java

Source

/*
 * Copyright 2014 MovingBlocks
 *
 * 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.
 */
package org.terasology.rendering.nui.skin;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import org.terasology.math.Border;
import org.terasology.rendering.assets.texture.TextureRegion;
import org.terasology.rendering.assets.font.Font;
import org.terasology.rendering.nui.Color;
import org.terasology.rendering.nui.HorizontalAlign;
import org.terasology.rendering.nui.ScaleMode;
import org.terasology.rendering.nui.UIWidget;
import org.terasology.rendering.nui.VerticalAlign;
import org.terasology.utilities.ReflectionUtil;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author Immortius
 */
public class UISkinBuilder {

    private UISkin baseSkin;
    private Set<String> families = Sets.newLinkedHashSet();
    private Set<StyleKey> baseStyleKeys = Sets.newLinkedHashSet();

    private Map<String, UIStyleFragment> baseStyles = Maps.newHashMap();
    private Table<String, StyleKey, UIStyleFragment> elementStyles = HashBasedTable.create();

    private UIStyleFragment currentStyle = new UIStyleFragment();
    private String currentFamily = "";
    private Class<? extends UIWidget> currentElement;
    private String currentPart = "";
    private String currentMode = "";

    private void saveStyle() {
        if (currentFamily.isEmpty() && currentElement != null) {
            baseStyleKeys.add(new StyleKey(currentElement, currentPart, currentMode));
        }
        if (currentElement != null) {
            elementStyles.put(currentFamily, new StyleKey(currentElement, currentPart, currentMode), currentStyle);
        } else {
            baseStyles.put(currentFamily, currentStyle);
        }
        currentStyle = new UIStyleFragment();
    }

    public UISkinBuilder setBaseSkin(UISkin skin) {
        this.baseSkin = skin;
        return this;
    }

    public UISkinBuilder setFamily(String family) {
        saveStyle();
        families.add(family);
        currentFamily = family;
        currentElement = null;
        currentPart = "";
        currentMode = "";
        return this;
    }

    public UISkinBuilder setElementClass(Class<? extends UIWidget> widget) {
        saveStyle();
        currentElement = widget;
        currentMode = "";
        currentPart = "";
        return this;
    }

    public UISkinBuilder setElementPart(String part) {
        if (currentElement == null) {
            throw new IllegalStateException("Element class must be set before element part");
        }
        saveStyle();
        currentPart = part;
        currentMode = "";
        return this;
    }

    public UISkinBuilder setElementMode(String mode) {
        if (currentElement == null) {
            throw new IllegalStateException("Element class must be set before element mode");
        }
        saveStyle();
        currentMode = mode;
        return this;
    }

    public UISkinBuilder setBackground(TextureRegion background) {
        currentStyle.setBackground(background);
        return this;
    }

    public UISkinBuilder setBackgroundBorder(Border border) {
        currentStyle.setBackgroundBorder(border);
        return this;
    }

    public UISkinBuilder setBackgroundMode(ScaleMode mode) {
        currentStyle.setBackgroundScaleMode(mode);
        return this;
    }

    public UISkinBuilder setFixedWidth(int width) {
        currentStyle.setFixedWidth(width);
        return this;
    }

    public UISkinBuilder setFixedHeight(int height) {
        currentStyle.setFixedHeight(height);
        return this;
    }

    public UISkinBuilder setHorizontalAlignment(HorizontalAlign align) {
        currentStyle.setAlignmentH(align);
        return this;
    }

    public UISkinBuilder setVerticalAlignment(VerticalAlign align) {
        currentStyle.setAlignmentV(align);
        return this;
    }

    public UISkinBuilder setMargin(Border margin) {
        currentStyle.setMargin(margin);
        return this;
    }

    public UISkinBuilder setTextureScaleMode(ScaleMode scaleMode) {
        currentStyle.setTextureScaleMode(scaleMode);
        return this;
    }

    public UISkinBuilder setFont(Font font) {
        currentStyle.setFont(font);
        return this;
    }

    public UISkinBuilder setTextColor(Color color) {
        currentStyle.setTextColor(color);
        return this;
    }

    public UISkinBuilder setTextShadowColor(Color color) {
        currentStyle.setTextShadowColor(color);
        return this;
    }

    public UISkinBuilder setTextShadowed(boolean shadowed) {
        currentStyle.setTextShadowed(shadowed);
        return this;
    }

    public UISkinBuilder setTextHorizontalAlignment(HorizontalAlign hAlign) {
        currentStyle.setTextAlignmentH(hAlign);
        return this;
    }

    public UISkinBuilder setTextVerticalAlignment(VerticalAlign vAlign) {
        currentStyle.setTextAlignmentV(vAlign);
        return this;
    }

    public UISkinBuilder setStyleFragment(UIStyleFragment fragment) {
        currentStyle = fragment;
        return this;
    }

    public UISkinData build() {
        saveStyle();
        Map<String, UIStyleFamily> skinFamilies = Maps.newHashMap();

        if (baseSkin != null) {
            UIStyle rootStyle = new UIStyle(baseSkin.getDefaultStyle());
            baseStyles.get("").applyTo(rootStyle);
            skinFamilies.put("", buildFamily("", baseSkin));
            for (String family : families) {
                skinFamilies.put(family, buildFamily(family, baseSkin));
            }
            for (String family : baseSkin.getFamilies()) {
                if (!skinFamilies.containsKey(family)) {
                    skinFamilies.put(family, baseSkin.getFamily(family));
                }
            }
            return new UISkinData(skinFamilies);
        } else {
            UIStyle rootStyle = new UIStyle();
            baseStyles.get("").applyTo(rootStyle);
            skinFamilies.put("", buildFamily("", rootStyle));
            for (String family : families) {
                skinFamilies.put(family, buildFamily(family, rootStyle));
            }
            return new UISkinData(skinFamilies);
        }
    }

    private UIStyleFamily buildFamily(String family, UISkin skin) {
        UIStyleFamily baseFamily = skin.getFamily(family);
        UIStyle baseStyle = new UIStyle(skin.getDefaultStyleFor(family));
        if (!family.isEmpty()) {
            UIStyleFragment fragment = baseStyles.get(family);
            fragment.applyTo(baseStyle);
        }

        Set<StyleKey> inheritedStyleKey = Sets.newLinkedHashSet();
        for (Class<? extends UIWidget> widget : baseFamily.getWidgets()) {
            inheritedStyleKey.add(new StyleKey(widget, "", ""));
            for (String part : baseFamily.getPartsFor(widget)) {
                inheritedStyleKey.add(new StyleKey(widget, part, ""));
                for (String mode : baseFamily.getModesFor(widget, part)) {
                    inheritedStyleKey.add(new StyleKey(widget, part, mode));
                }
            }
        }

        Map<Class<? extends UIWidget>, Table<String, String, UIStyle>> familyStyles = Maps.newHashMap();
        Map<StyleKey, UIStyleFragment> styleLookup = elementStyles.row(family);
        Map<StyleKey, UIStyleFragment> baseStyleLookup = (family.isEmpty())
                ? Maps.<StyleKey, UIStyleFragment>newHashMap()
                : elementStyles.row("");
        for (StyleKey styleKey : Sets.union(Sets.union(styleLookup.keySet(), baseStyleKeys), inheritedStyleKey)) {
            UIStyle elementStyle = new UIStyle(
                    baseSkin.getStyleFor(family, styleKey.element, styleKey.part, styleKey.mode));
            baseStyles.get("").applyTo(elementStyle);
            baseStyles.get(family).applyTo(elementStyle);
            List<Class<? extends UIWidget>> inheritanceTree = ReflectionUtil.getInheritanceTree(styleKey.element,
                    UIWidget.class);
            applyStylesForInheritanceTree(inheritanceTree, "", "", elementStyle, styleLookup, baseStyleLookup);

            if (!styleKey.part.isEmpty()) {
                applyStylesForInheritanceTree(inheritanceTree, styleKey.part, "", elementStyle, styleLookup,
                        baseStyleLookup);
            }

            if (!styleKey.mode.isEmpty()) {
                applyStylesForInheritanceTree(inheritanceTree, styleKey.part, styleKey.mode, elementStyle,
                        styleLookup, baseStyleLookup);
            }

            Table<String, String, UIStyle> elementTable = familyStyles.get(styleKey.element);
            if (elementTable == null) {
                elementTable = HashBasedTable.create();
                familyStyles.put(styleKey.element, elementTable);
            }
            elementTable.put(styleKey.part, styleKey.mode, elementStyle);
        }
        return new UIStyleFamily(baseStyle, familyStyles);
    }

    private UIStyleFamily buildFamily(String family, UIStyle defaultStyle) {
        UIStyle baseStyle = new UIStyle(defaultStyle);
        if (!family.isEmpty()) {
            UIStyleFragment fragment = baseStyles.get(family);
            fragment.applyTo(baseStyle);
        }

        Map<Class<? extends UIWidget>, Table<String, String, UIStyle>> familyStyles = Maps.newHashMap();
        Map<StyleKey, UIStyleFragment> styleLookup = elementStyles.row(family);
        Map<StyleKey, UIStyleFragment> baseStyleLookup = (family.isEmpty())
                ? Maps.<StyleKey, UIStyleFragment>newHashMap()
                : elementStyles.row("");
        for (StyleKey styleKey : Sets.union(styleLookup.keySet(), baseStyleKeys)) {
            UIStyle elementStyle = new UIStyle(baseStyle);
            List<Class<? extends UIWidget>> inheritanceTree = ReflectionUtil.getInheritanceTree(styleKey.element,
                    UIWidget.class);
            applyStylesForInheritanceTree(inheritanceTree, "", "", elementStyle, styleLookup, baseStyleLookup);

            if (!styleKey.part.isEmpty()) {
                applyStylesForInheritanceTree(inheritanceTree, styleKey.part, "", elementStyle, styleLookup,
                        baseStyleLookup);
            }

            if (!styleKey.mode.isEmpty()) {
                applyStylesForInheritanceTree(inheritanceTree, styleKey.part, styleKey.mode, elementStyle,
                        styleLookup, baseStyleLookup);
            }

            Table<String, String, UIStyle> elementTable = familyStyles.get(styleKey.element);
            if (elementTable == null) {
                elementTable = HashBasedTable.create();
                familyStyles.put(styleKey.element, elementTable);
            }
            elementTable.put(styleKey.part, styleKey.mode, elementStyle);
        }
        return new UIStyleFamily(baseStyle, familyStyles);
    }

    private void applyStylesForInheritanceTree(List<Class<? extends UIWidget>> inheritanceTree, String part,
            String mode, UIStyle elementStyle, Map<StyleKey, UIStyleFragment> styleLookup,
            Map<StyleKey, UIStyleFragment> baseStyleLookup) {
        for (Class<? extends UIWidget> element : inheritanceTree) {
            StyleKey key = new StyleKey(element, part, mode);
            UIStyleFragment baseElementStyle = baseStyleLookup.get(key);
            if (baseElementStyle != null) {
                baseElementStyle.applyTo(elementStyle);
            }

            UIStyleFragment elemStyle = styleLookup.get(key);
            if (elemStyle != null) {
                elemStyle.applyTo(elementStyle);
            }
        }
    }

    private static final class StyleKey {
        private Class<? extends UIWidget> element;
        private String part;
        private String mode;

        private StyleKey(Class<? extends UIWidget> element, String part, String mode) {
            this.element = element;
            this.part = part;
            this.mode = mode;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == this) {
                return true;
            }
            if (obj instanceof StyleKey) {
                StyleKey other = (StyleKey) obj;
                return Objects.equals(other.element, element) && Objects.equals(other.part, part)
                        && Objects.equals(other.mode, mode);
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(element, part, mode);
        }

        @Override
        public String toString() {
            return element.getSimpleName() + ":" + part + ":" + mode;
        }
    }
}