/** * Copyright (c) Lambda Innovation, 2013-2016 * This file is part of the AcademyCraft mod. * https://github.com/LambdaInnovation/AcademyCraft * Licensed under GPLv3, see project root for more information. */ package cn.academy.ability.client.ui; import cn.academy.ability.api.Controllable; import cn.academy.ability.api.Skill; import cn.academy.ability.api.data.AbilityData; import cn.academy.ability.api.data.PresetData; import cn.academy.ability.api.data.PresetData.Preset; import cn.academy.core.Resources; import cn.academy.core.client.ACRenderingHelper; import cn.lambdalib.annoreg.core.Registrant; import cn.lambdalib.annoreg.mc.RegInitCallback; import cn.lambdalib.cgui.gui.CGui; import cn.lambdalib.cgui.gui.Widget; import cn.lambdalib.cgui.gui.WidgetContainer; import cn.lambdalib.cgui.gui.component.Component; import cn.lambdalib.cgui.gui.component.DrawTexture; import cn.lambdalib.cgui.gui.component.TextBox; import cn.lambdalib.cgui.gui.component.Tint; import cn.lambdalib.cgui.gui.event.FrameEvent; import cn.lambdalib.cgui.gui.event.IGuiEventHandler; import cn.lambdalib.cgui.gui.event.LeftClickEvent; import cn.lambdalib.cgui.xml.CGUIDocument; import cn.lambdalib.util.client.HudUtils; import cn.lambdalib.util.client.RenderUtils; import cn.lambdalib.util.client.font.IFont; import cn.lambdalib.util.client.font.IFont.FontOption; import cn.lambdalib.util.generic.MathUtils; import cn.lambdalib.util.helper.Color; import cn.lambdalib.util.helper.GameTimer; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.StatCollector; import org.lwjgl.opengl.GL11; import java.util.ArrayList; import java.util.List; /** * @author WeAthFolD */ @Registrant @SideOnly(Side.CLIENT) public class PresetEditUI extends GuiScreen { static final Color CRL_BACK = new Color().setColor4i(49, 49, 49, 200), CRL_WHITE = new Color(1, 1, 1, 0.6), CRL_GLOW = new Color(1, 1, 1, 0.2); static WidgetContainer loaded; static Widget template; static final double STEP = 125; static final long TRANSIT_TIME = 350; static final double MAX_ALPHA = 1, MIN_ALPHA = 0.3; static final double MAX_SCALE = 1, MIN_SCALE = 0.8; static class SelectionProvider { public final int id; public final ResourceLocation texture; public final String hint; public SelectionProvider(int _id, ResourceLocation _texture, String _hint) { id = _id; texture = _texture; hint = _hint; } } /** * Drawer when nothing happened */ CGui foreground = new CGui(); /** * Drawer of transition */ CGui transitor = new CGui(); @RegInitCallback private static void __init() { loaded = CGUIDocument.panicRead(new ResourceLocation("academy:guis/preset_edit.xml")); template = loaded.getWidget("template"); } final EntityPlayer player; final PresetData data; final AbilityData aData; final IFont font = Resources.font(); // lastActive is the preset ID before the transition. int lastActive, active; boolean transiting; long transitStartTime; long deltaTime; //Time that has passed since last transition double transitProgress; Widget selector; public PresetEditUI() { player = Minecraft.getMinecraft().thePlayer; data = PresetData.get(player); aData = AbilityData.get(player); init(); } @Override public void onGuiClosed() { } private String local(String key) { return StatCollector.translateToLocal("ac.gui.preset_edit." + key); } private void init() { foreground.addWidget(loaded.getWidget("background").copy()); transitor.addWidget(loaded.getWidget("background").copy()); // Build the pages for(int i = 0; i < 4; ++i) { Widget normal = createCopy(); TextBox.get(normal.getWidget("title")).setContent(local("tag") + (i + 1)); for(int j = 0; j < 4; ++j) { Widget ww = normal.getWidget(String.valueOf(j)); normal.getWidget(String.valueOf(j)).addComponent(new HintHandler(j)); } normal.addComponent(new ForegroundPage(i)); add(i, foreground, normal); } for(int i = 0; i < 4; ++i) { Widget back = createCopy(); TextBox.get(back.getWidget("title")).setContent(local("tag") + (i + 1)); back.addComponent(new TransitPage(i)); add(i, transitor, back); } resetAll(); } private void resetAll() { updateInfo(foreground); updateInfo(transitor); updatePosForeground(); } private Widget createCopy() { Widget ret = template.copy(); for(Widget w : ret.getDrawList()) { for(Widget w2 : w.getDrawList()) w2.listen(FrameEvent.class, new AlphaAssign(), -1); } return ret; } @Override protected void mouseClicked(int mx, int my, int button) { if(button == 0) { if(!transiting) { foreground.mouseClicked(mx, my, button); } } } @Override public void drawScreen(int mx, int my, float partialTicks) { RenderUtils.drawBlackout(); if(transiting) { updateTransit(); transitor.resize(width, height); transitor.draw(-1, -1); } else { updatePosForeground(); foreground.resize(width, height); foreground.draw(mx, my); } } private double getXFor(int i, int active) { if(i == active) { return 0; } return STEP * (i - active); } private double getXFor(int i) { return getXFor(i, active); } private void add(int i, CGui gui, Widget w) { gui.addWidget("" + i, w); } private Widget get(CGui gui, int i) { return gui.getWidget("" + i); } // Major control private void startTransit(int to) { updateInfo(transitor); lastActive = active; active = to; transiting = true; transitStartTime = GameTimer.getAbsTime(); } private void finishTransit() { updatePosForeground(); } // Foreground page private void onEdit(int keyID, Controllable controllable) { Preset last = data.getPreset(active); Controllable[] arr = last.copyData(); arr[keyID] = controllable; Preset newPreset = new Preset(arr); data.setPresetFromClient(active, newPreset); getPage(get(foreground, active)).updateInfo(newPreset); } // Transition page private void updateTransit() { deltaTime = GameTimer.getAbsTime() - transitStartTime; transitProgress = (double)deltaTime / TRANSIT_TIME; if(transitProgress > 1) { transitProgress = 1; } for(int i = 0; i < PresetData.MAX_PRESETS; ++i) { Widget page = get(transitor, i); getPage(page).updatePosition(); } if(transitProgress == 1) { transiting = false; finishTransit(); } } // Utils private void updateInfo(CGui gui) { for(int i = 0; i < PresetData.MAX_PRESETS; ++i) { Widget page = get(gui, i); getPage(page).updateInfo(data.getPreset(i)); } } private void updatePosForeground() { for(int i = 0; i < 4; ++i) { Widget page = get(foreground, i); getPage(page).updatePosition(); } } private abstract class Page extends Component { /** * Master alpha visited by all sub widgets */ protected double alpha; final int id; public Page(int _id) { super("Page"); id = _id; } public void updateInfo(Preset preset) { for(int i = 0; i < PresetData.MAX_PRESETS; ++i) { Controllable c = preset.getControllable(i); Widget main = widget.getWidget("" + i); DrawTexture.get(main.getWidget("icon")).texture = c == null ? Resources.TEX_EMPTY : c.getHintIcon(); TextBox.get(main.getWidget("text")).content = c == null ? "" : c.getHintText(); } } public void updatePosition() { widget.transform.x = getXFor(id); widget.dirty = true; alpha = id == active ? MAX_ALPHA : MIN_ALPHA; widget.transform.scale = id == active ? MAX_SCALE : MIN_SCALE; DrawTexture.get(widget).color.a = alpha; } } static Page getPage(Widget w) { return w.getComponent("Page"); } private class HintHandler extends Component { final int keyid; public HintHandler(int _keyid) { super("Hint"); keyid = _keyid; listen(FrameEvent.class, (w, event) -> { Page page = getPage(w.getWidgetParent()); DrawTexture dt = DrawTexture.get(w); dt.enabled = page.id == active && event.hovering; dt.color.a = page.alpha; }); listen(LeftClickEvent.class, (w, e) -> { Page page = getPage(w.getWidgetParent()); if(selector != null && !selector.disposed) { selector.dispose(); selector = null; } else if(page.id == active) { // Open the selector selector = new Selector(keyid); selector.transform.setPos(foreground.mouseX, foreground.mouseY); foreground.addWidget(selector); } else { startTransit(page.id); } }); } } private class ForegroundPage extends Page { public ForegroundPage(int _id) { super(_id); } } private class TransitPage extends Page { public TransitPage(int _id) { super(_id); listen(FrameEvent.class, (w, e) -> { DrawTexture.get(w).color.a = alpha; }); } @Override public void updatePosition() { double x0 = getXFor(id, lastActive), x1 = getXFor(id, active); double dx = MathUtils.lerp(x0, x1, transitProgress); double scale; if(isFrom()) { alpha = MathUtils.lerp(MAX_ALPHA, MIN_ALPHA, transitProgress); scale = MathUtils.lerp(MAX_SCALE, MIN_SCALE, transitProgress); } else if(isTo()) { alpha = MathUtils.lerp(MIN_ALPHA, MAX_ALPHA, transitProgress); scale = MathUtils.lerp(MIN_SCALE, MAX_SCALE, transitProgress); } else { alpha = MIN_ALPHA; scale = MIN_SCALE; } widget.transform.x = dx; widget.transform.scale = scale; DrawTexture.get(widget).color.a = alpha; widget.dirty = true; } private boolean isFrom() { return id == lastActive; } private boolean isTo() { return id == active; } } private class AlphaAssign implements IGuiEventHandler<FrameEvent> { @Override public void handleEvent(Widget w, FrameEvent event) { double masterAlpha = getPage(w.getWidgetParent().getWidgetParent()).alpha; DrawTexture dt = DrawTexture.get(w); if(dt != null) { dt.color.a = masterAlpha; } else { TextBox.get(w).option.color.a = masterAlpha; } } } private class Selector extends Widget { final int MAX_PER_ROW = 4; final double MARGIN = 2.5, SIZE = 15, STEP = SIZE + 3; List<Skill> available = new ArrayList(); final int keyid; double width, height; public Selector(int _keyid) { keyid = _keyid; AbilityData aData = AbilityData.get(player); for(Skill s : aData.getControllableSkillList()) { if(!data.getPreset(active).hasControllable(s)) { available.add(s); } } List<SelectionProvider> providers = new ArrayList<>(); providers.add(new SelectionProvider(-1, Resources.getTexture("guis/preset_settings/cancel"), local("skill_remove"))); for(Skill s : available) { providers.add(new SelectionProvider(s.getControlID(), s.getHintIcon(), s.getDisplayName())); } height = MARGIN * 2 + SIZE + STEP * (ldiv(providers.size(), MAX_PER_ROW) - 1); width = available.size() < MAX_PER_ROW ? MARGIN * 2 + SIZE + STEP * (providers.size() - 1) : MARGIN * 2 + SIZE + STEP * (MAX_PER_ROW - 1); transform.setSize(width, height); // Build the window and the widget listen(FrameEvent.class, (w, e) -> { CRL_WHITE.bind(); ACRenderingHelper.drawGlow(0, 0, width, height, 1, CRL_WHITE); CRL_BACK.bind(); HudUtils.colorRect(0, 0, width, height); String str; Widget hovering = foreground.getHoveringWidget(); if(hovering != null && hovering.getName().contains("_sel")) { SelHandler sh = hovering.getComponent("_sel"); str = sh.selection.hint; } else { str = local("skill_select"); } FontOption opt = new FontOption(9, new Color(0xffbbbbbb)); double len = font.getTextWidth(str, opt); CRL_BACK.bind(); HudUtils.colorRect(0, -13.5, len + 6, 11.5); ACRenderingHelper.drawGlow(0, -13.5, len + 6, 11.5, 1, CRL_GLOW); font.draw(str, 3, -12, opt); GL11.glColor4d(1, 1, 1, 1); }); // Build all the skills that can be set for(int i = 0; i < providers.size(); ++i) { int row = i / MAX_PER_ROW, col = i % MAX_PER_ROW; SelectionProvider selection = providers.get(i); Widget single = new Widget(); single.transform.setPos(MARGIN + col * STEP, MARGIN + row * STEP); single.transform.setSize(SIZE, SIZE); DrawTexture tex = new DrawTexture().setTex(selection.texture); single.addComponent(tex); single.addComponent(new Tint(Color.monoBlend(1, 0), Color.monoBlend(1, 0.2), false)); single.addComponent(new SelHandler(selection)); addWidget("_sel" + i, single); } } private class SelHandler extends Component { final SelectionProvider selection; public SelHandler(SelectionProvider _selection) { super("_sel"); selection = _selection; listen(LeftClickEvent.class, (w, e) -> { onEdit(keyid, aData.getCategory().getControllable(selection.id)); Selector.this.dispose(); }); } } } private int ldiv(int a, int b) { return a % b == 0 ? a / b : a / b + 1; } }