Update to allow test menu to enter a campaign screen

This commit is contained in:
Retera 2021-03-22 08:34:44 -04:00
parent 55bdfcb9fc
commit 2890e640e0
18 changed files with 977 additions and 106 deletions

View File

@ -0,0 +1,5 @@
package com.etheller.warsmash;
public interface SingleModelScreen {
void setModel(String path);
}

View File

@ -20,6 +20,8 @@ import com.badlogic.gdx.math.Quaternion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
@ -44,10 +46,11 @@ import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.Sequence;
import com.etheller.warsmash.viewer5.handlers.mdx.SequenceLoopMode;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.MenuUI;
public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Screen {
public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Screen, SingleModelScreen {
private static final boolean ENABLE_AUDIO = true;
private static final boolean ENABLE_MUSIC = true;
private DataSource codebase;
@ -59,7 +62,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
// libGDX stuff
private OrthographicCamera uiCamera;
private SpriteBatch batch;
private ExtendViewport uiViewport;
private Viewport uiViewport;
private GlyphLayout glyphLayout;
private final DataTable warsmashIni;
@ -68,6 +71,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
private MenuUI menuUI;
private final WarsmashGdxMultiScreenGame game;
private Music currentMusic;
private boolean hasPlayedStandHack = false;
public WarsmashGdxMenuScreen(final DataTable warsmashIni, final WarsmashGdxMultiScreenGame game) {
this.warsmashIni = warsmashIni;
@ -94,8 +98,8 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
this.viewer.addHandler(new MdxHandler());
this.viewer.enableAudio();
final Scene scene = this.viewer.addSimpleScene();
scene.enableAudio();
this.scene = this.viewer.addSimpleScene();
this.scene.enableAudio();
this.uiScene = this.viewer.addSimpleScene();
this.uiScene.alpha = true;
@ -121,10 +125,10 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
aspect3By4Width = (height * 4) / 3;
aspect3By4Height = height;
}
this.uiViewport = new ExtendViewport(aspect3By4Width, aspect3By4Height, this.uiCamera);
this.uiViewport = new FitViewport(aspect3By4Width, aspect3By4Height, this.uiCamera);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
this.uiCamera.position.set(getMinWorldWidth() / 2, getMinWorldHeight() / 2, 0);
this.uiCamera.update();
this.batch = new SpriteBatch();
@ -137,7 +141,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
Gdx.input.setInputProcessor(this);
this.cameraManager = new CameraManager();
this.cameraManager.setupCamera(scene);
this.cameraManager.setupCamera(this.scene);
// this.mainModel = (MdxModel) this.viewer.load("Doodads\\Cinematic\\ArthasIllidanFight\\ArthasIllidanFight.mdx",
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\SinglePlayer\\NightElf_Exp\\NightElf_Exp.mdx",
@ -174,7 +178,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
System.out.println("Loaded");
Gdx.gl30.glClearColor(0.0f, 0.0f, 0.0f, 1);
this.menuUI = new MenuUI(this.viewer.dataSource, this.uiViewport, this.uiScene, this.viewer, this.game,
this.menuUI = new MenuUI(this.viewer.dataSource, this.uiViewport, this.uiScene, this.viewer, this.game, this,
this.warsmashIni, new RootFrameListener() {
@Override
public void onCreate(final GameUI rootFrame) {
@ -193,7 +197,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
WarsmashGdxMenuScreen.this.currentMusic = music;
}
singleModelScene(scene,
singleModelScene(WarsmashGdxMenuScreen.this.scene,
War3MapViewer.mdx(rootFrame
.getSkinField("GlueSpriteLayerBackground_V" + WarsmashConstants.GAME_VERSION)),
"Stand");
@ -213,6 +217,20 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
}
private float getMinWorldWidth() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldWidth();
}
return this.uiViewport.getWorldWidth();
}
private float getMinWorldHeight() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldHeight();
}
return this.uiViewport.getWorldHeight();
}
private void updateUIScene() {
this.tempRect.x = this.uiViewport.getScreenX();
this.tempRect.y = this.uiViewport.getScreenY();
@ -221,8 +239,8 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
this.uiScene.camera.viewport(this.tempRect);
final float worldWidth = this.uiViewport.getWorldWidth();
final float worldHeight = this.uiViewport.getWorldHeight();
final float xScale = worldWidth / this.uiViewport.getMinWorldWidth();
final float yScale = worldHeight / this.uiViewport.getMinWorldHeight();
final float xScale = worldWidth / getMinWorldWidth();
final float yScale = worldHeight / getMinWorldHeight();
final float uiSceneWidth = 0.8f * xScale;
final float uiSceneHeight = 0.6f * yScale;
final float uiSceneX = ((0.8f - uiSceneWidth) / 2);
@ -285,11 +303,27 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
}
instance3.setSequence(animIndex);
instance3.setSequenceLoopMode(SequenceLoopMode.ALWAYS_LOOP);
instance3.setSequenceLoopMode(SequenceLoopMode.NEVER_LOOP);
this.mainInstance = instance3;
this.mainModel = model2;
}
@Override
public void setModel(final String path) {
if (this.mainInstance != null) {
this.mainInstance.detach();
}
singleModelScene(this.scene, War3MapViewer.mdx(path), "birth");
WarsmashGdxMenuScreen.this.modelCamera = WarsmashGdxMenuScreen.this.mainModel.cameras.get(0);
// this hack is because we only have the queued animation system in RenderWidget
// which is stupid and back and needs to get moved to the model instance
// itself... our model instance class is a
// hacky replica of a model viewer tool with a bunch of irrelevant loop type
// settings instead of what it should be
this.hasPlayedStandHack = false;
}
private void acolytesHarvestingScene(final Scene scene) {
final MdxModel acolyteModel = (MdxModel) this.viewer.load("units\\undead\\acolyte\\acolyte.mdx",
@ -477,6 +511,7 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
private final float[] cameraPositionTemp = new float[3];
private final float[] cameraTargetTemp = new float[3];
private final boolean firstFrame = true;
private Scene scene;
@Override
public void render(final float delta) {
@ -486,6 +521,12 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
Gdx.gl30.glBindVertexArray(WarsmashGdxGame.VAO);
this.cameraManager.updateCamera();
this.menuUI.update(deltaTime);
if (this.mainInstance.sequenceEnded
&& (((this.mainModel.getSequences().get(this.mainInstance.sequence).getFlags() & 0x1) == 0)
|| !this.hasPlayedStandHack)) {
SequenceUtils.randomStandSequence(this.mainInstance);
this.hasPlayedStandHack = true;
}
this.viewer.updateAndRender();
Gdx.gl30.glDisable(GL30.GL_SCISSOR_TEST);
@ -516,12 +557,26 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
public void resize(final int width, final int height) {
this.tempRect.width = width;
this.tempRect.height = height;
final float fourThirdsHeight = (this.tempRect.height * 4) / 3;
if (fourThirdsHeight < this.tempRect.width) {
final float dx = this.tempRect.width - fourThirdsHeight;
this.tempRect.width = fourThirdsHeight;
this.tempRect.x = dx / 2;
}
else {
final float threeFourthsWidth = (this.tempRect.width * 3) / 4;
if (threeFourthsWidth < this.tempRect.height) {
final float dy = this.tempRect.height - threeFourthsWidth;
this.tempRect.height = threeFourthsWidth;
this.tempRect.y = dy;
}
}
this.cameraManager.camera.viewport(this.tempRect);
// super.resize(width, height);
this.uiViewport.update(width, height);
this.uiCamera.position.set(this.uiViewport.getMinWorldWidth() / 2, this.uiViewport.getMinWorldHeight() / 2, 0);
this.uiCamera.position.set(getMinWorldWidth() / 2, getMinWorldHeight() / 2, 0);
this.menuUI.resize();
updateUIScene();
@ -612,8 +667,8 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
WarsmashGdxMenuScreen.this.cameraPositionTemp[2]);
this.target.add(WarsmashGdxMenuScreen.this.cameraTargetTemp[0],
WarsmashGdxMenuScreen.this.cameraTargetTemp[1], WarsmashGdxMenuScreen.this.cameraTargetTemp[2]);
this.camera.perspective(WarsmashGdxMenuScreen.this.modelCamera.fieldOfView * 0.75f,
Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight(),
this.camera.perspective(WarsmashGdxMenuScreen.this.modelCamera.fieldOfView * 0.6f,
this.camera.rect.width / this.camera.rect.height,
WarsmashGdxMenuScreen.this.modelCamera.nearClippingPlane,
WarsmashGdxMenuScreen.this.modelCamera.farClippingPlane);
}
@ -635,20 +690,17 @@ public class WarsmashGdxMenuScreen implements CanvasProvider, InputProcessor, Sc
@Override
public boolean keyDown(final int keycode) {
// TODO Auto-generated method stub
return false;
return this.menuUI.keyDown(keycode);
}
@Override
public boolean keyUp(final int keycode) {
// TODO Auto-generated method stub
return false;
return this.menuUI.keyUp(keycode);
}
@Override
public boolean keyTyped(final char character) {
// TODO Auto-generated method stub
return false;
return this.menuUI.keyTyped(character);
}
@Override

View File

@ -0,0 +1,22 @@
package com.etheller.warsmash.parsers.fdf;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
public class GameSkin {
private final Element skin;
private final DataTable skinsTable;
public GameSkin(final Element skin, final DataTable skinsTable) {
this.skin = skin;
this.skinsTable = skinsTable;
}
public Element getSkin() {
return this.skin;
}
public DataTable getSkinsTable() {
return this.skinsTable;
}
}

View File

@ -34,9 +34,12 @@ import com.etheller.warsmash.parsers.fdf.datamodel.Vector2Definition;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
import com.etheller.warsmash.parsers.fdf.frames.BackdropFrame;
import com.etheller.warsmash.parsers.fdf.frames.ControlFrame;
import com.etheller.warsmash.parsers.fdf.frames.EditBoxFrame;
import com.etheller.warsmash.parsers.fdf.frames.FilterModeTextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.ListBoxFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.SimpleStatusBarFrame;
@ -52,6 +55,7 @@ import com.etheller.warsmash.util.StringBundle;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.AbstractMdxModelViewer;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.FocusableFrame;
import com.hiveworkshop.rms.parsers.mdlx.MdlxLayer.FilterMode;
public final class GameUI extends AbstractUIFrame implements UIFrame {
@ -77,11 +81,11 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
private final BitmapFont font20;
private final DynamicFontGeneratorHolder dynamicFontGeneratorHolder;
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport, final Scene uiScene,
public GameUI(final DataSource dataSource, final GameSkin skin, final Viewport viewport, final Scene uiScene,
final AbstractMdxModelViewer modelViewer, final int racialCommandIndex, final WTS mapStrings) {
super("GameUI", null);
this.dataSource = dataSource;
this.skin = skin;
this.skin = skin.getSkin();
this.viewport = viewport;
this.uiScene = uiScene;
this.modelViewer = modelViewer;
@ -95,7 +99,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
this.templates = new FrameTemplateEnvironment();
this.dynamicFontGeneratorHolder = new DynamicFontGeneratorHolder(this.modelViewer.dataSource, skin);
this.dynamicFontGeneratorHolder = new DynamicFontGeneratorHolder(this.modelViewer.dataSource, this.skin);
this.fontGenerator = this.dynamicFontGeneratorHolder.getFontGenerator("MasterFont");
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
fontParam.size = 32;
@ -104,32 +108,22 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
this.font20 = this.fontGenerator.generateFont(fontParam);
this.fontParam = new FreeTypeFontParameter();
this.fdfCoordinateResolutionDummyViewport = new FitViewport(0.8f, 0.6f);
this.skinData = new DataTable(modelViewer.getWorldEditStrings());
try {
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\CommandFunc.txt")) {
this.skinData.readTXT(miscDataTxtStream, true);
}
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("Units\\CommandStrings.txt")) {
this.skinData.readTXT(miscDataTxtStream, true);
}
if (this.dataSource.has("war3mapSkin.txt")) {
try (InputStream miscDataTxtStream = this.dataSource.getResourceAsStream("war3mapSkin.txt")) {
this.skinData.readTXT(miscDataTxtStream, true);
}
}
}
catch (final IOException e) {
throw new RuntimeException(e);
}
this.skinData = skin.getSkinsTable();
this.errorStrings = this.skinData.get("Errors");
this.glyphLayout = new GlyphLayout();
this.mapStrings = mapStrings;
}
public static Element loadSkin(final DataSource dataSource, final String skin) {
public static GameSkin loadSkin(final DataSource dataSource, final String skin) {
final DataTable skinsTable = new DataTable(StringBundle.EMPTY);
try (InputStream stream = dataSource.getResourceAsStream("UI\\war3skins.txt")) {
skinsTable.readTXT(stream, true);
try (InputStream miscDataTxtStream = dataSource.getResourceAsStream("Units\\CommandFunc.txt")) {
skinsTable.readTXT(miscDataTxtStream, true);
}
try (InputStream miscDataTxtStream = dataSource.getResourceAsStream("Units\\CommandStrings.txt")) {
skinsTable.readTXT(miscDataTxtStream, true);
}
}
catch (final IOException e) {
throw new RuntimeException(e);
@ -159,10 +153,10 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
userSkin.setField(key, customSkin.getField(key));
}
}
return userSkin;
return new GameSkin(userSkin, skinsTable);
}
public static Element loadSkin(final DataSource dataSource, final int skinIndex) {
public static GameSkin loadSkin(final DataSource dataSource, final int skinIndex) {
final DataTable skinsTable = new DataTable(StringBundle.EMPTY);
try (InputStream stream = dataSource.getResourceAsStream("UI\\war3skins.txt")) {
skinsTable.readTXT(stream, true);
@ -201,7 +195,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
userSkin.setField(key, customSkin.getField(key));
}
}
return userSkin;
return new GameSkin(userSkin, skinsTable);
}
public void loadTOCFile(final String tocFilePath) throws IOException {
@ -246,7 +240,9 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
public UIFrame createFrame(final String name, final UIFrame owner, final int priority, final int createContext) {
final FrameDefinition frameDefinition = this.templates.getFrame(name);
final UIFrame inflatedFrame = inflate(frameDefinition, owner, null, frameDefinition.has("DecorateFileNames"));
add(inflatedFrame);
if (owner == this) {
add(inflatedFrame);
}
return inflatedFrame;
}
@ -344,10 +340,6 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
if (this.skin.hasField(backgroundArt)) {
backgroundArt = this.skin.getField(backgroundArt);
}
else {
throw new IllegalStateException(
"Decorated file name lookup not available: " + backgroundArt);
}
}
}
if (backgroundArt != null) {
@ -373,7 +365,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
final Float textLength = frameDefinition.getFloat("TextLength");
TextJustify justifyH = frameDefinition.getTextJustify("FontJustificationH");
if (justifyH == null) {
justifyH = TextJustify.CENTER;
justifyH = TextJustify.LEFT;
}
TextJustify justifyV = frameDefinition.getTextJustify("FontJustificationV");
if (justifyV == null) {
@ -402,7 +394,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
final FontDefinition font = frameDefinition.getFont("FrameFont");
final Float height = frameDefinition.getFloat("Height");
this.fontParam.size = (int) convertY(viewport2,
font == null ? (height == null ? 0.06f : height) : font.getFontSize());
(font == null ? (height == null ? 0.06f : height) : font.getFontSize()));
if (this.fontParam.size == 0) {
this.fontParam.size = 24;
}
@ -524,6 +516,78 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
inflatedFrame = glueButtonFrame;
}
else if ("EDITBOX".equals(frameDefinition.getFrameType())) {
final float editBorderSize = convertX(viewport2, frameDefinition.getFloat("EditBorderSize"));
final Vector4Definition editCursorColorDefinition = frameDefinition.getVector4("EditCursorColor");
Color editCursorColor;
if (editCursorColorDefinition == null) {
editCursorColor = Color.WHITE;
}
else {
editCursorColor = new Color(editCursorColorDefinition.getX(), editCursorColorDefinition.getY(),
editCursorColorDefinition.getZ(), editCursorColorDefinition.getW());
}
final EditBoxFrame editBoxFrame = new EditBoxFrame(frameDefinition.getName(), parent, editBorderSize,
editCursorColor);
// TODO: we should not need to put ourselves in this map 2x, but we do
// since there are nested inflate calls happening before the general case
// mapping
this.nameToFrame.put(frameDefinition.getName(), editBoxFrame);
final String controlBackdropKey = frameDefinition.getString("ControlBackdrop");
final String editTextFrameKey = frameDefinition.getString("EditTextFrame");
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
if (childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, editBoxFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
editBoxFrame.setControlBackdrop(inflatedChild);
}
else if (childDefinition.getName().equals(editTextFrameKey)) {
final UIFrame inflatedChild = inflate(childDefinition, editBoxFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
final StringFrame editTextFrame = (StringFrame) inflatedChild;
inflatedChild.setSetAllPoints(true, editBorderSize);
editBoxFrame.setEditTextFrame(editTextFrame);
setText(editTextFrame, "");
}
}
inflatedFrame = editBoxFrame;
}
else if ("CONTROL".equals(frameDefinition.getFrameType())) {
final ControlFrame controlFrame = new ControlFrame(frameDefinition.getName(), parent);
// TODO: we should not need to put ourselves in this map 2x, but we do
// since there are nested inflate calls happening before the general case
// mapping
this.nameToFrame.put(frameDefinition.getName(), controlFrame);
final String controlBackdropKey = frameDefinition.getString("ControlBackdrop");
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
if (childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, controlFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
controlFrame.setControlBackdrop(inflatedChild);
}
}
inflatedFrame = controlFrame;
}
else if ("LISTBOX".equals(frameDefinition.getFrameType())) {
// TODO advanced components here
final ListBoxFrame controlFrame = new ListBoxFrame(frameDefinition.getName(), parent, viewport2);
// TODO: we should not need to put ourselves in this map 2x, but we do
// since there are nested inflate calls happening before the general case
// mapping
this.nameToFrame.put(frameDefinition.getName(), controlFrame);
final String controlBackdropKey = frameDefinition.getString("ControlBackdrop");
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
if (childDefinition.getName().equals(controlBackdropKey)) {
final UIFrame inflatedChild = inflate(childDefinition, controlFrame, frameDefinition,
inDecorateFileNames || childDefinition.has("DecorateFileNames"));
inflatedChild.setSetAllPoints(true);
controlFrame.setControlBackdrop(inflatedChild);
}
}
inflatedFrame = controlFrame;
}
else if ("HIGHLIGHT".equals(frameDefinition.getFrameType())) {
final String highlightType = frameDefinition.getString("HighlightType");
if (!"FILETEXTURE".equals(highlightType)) {
@ -542,6 +606,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
}
else if ("BACKDROP".equals(frameDefinition.getFrameType())) {
final boolean tileBackground = frameDefinition.has("BackdropTileBackground");
final boolean mirrored = frameDefinition.has("BackdropMirrored");
String backgroundString = frameDefinition.getString("BackdropBackground");
String cornerFlagsString = frameDefinition.getString("BackdropCornerFlags");
if (cornerFlagsString == null) {
@ -580,7 +645,7 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
final BackdropFrame backdropFrame = new BackdropFrame(frameDefinition.getName(), parent,
decorateFileNames, tileBackground, background, cornerFlags, cornerSize, backgroundSize,
backgroundInsets, edgeFile);
backgroundInsets, edgeFile, mirrored);
this.nameToFrame.put(frameDefinition.getName(), backdropFrame);
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
backdropFrame.add(inflate(childDefinition, backdropFrame, frameDefinition, decorateFileNames));
@ -716,9 +781,15 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
final String inherits, final int createContext) {
// TODO idk what inherits is doing yet, and I didn't implement createContext yet
// even though it looked like just mapping/indexing on int
final FrameDefinition baseTemplateDef = this.templates.getFrame(name);
final FrameDefinition frameDefinition = new FrameDefinition(FrameClass.Frame, typeName, name);
if (baseTemplateDef != null) {
frameDefinition.inheritFrom(baseTemplateDef, "WITHCHILDREN".equals(inherits));
}
final UIFrame inflatedFrame = inflate(frameDefinition, owner, null, frameDefinition.has("DecorateFileNames"));
add(inflatedFrame);
if (this == owner) {
add(inflatedFrame);
}
return inflatedFrame;
}
@ -830,4 +901,9 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
public void dispose() {
this.dynamicFontGeneratorHolder.dispose();
}
public FocusableFrame getNextFocusFrame() {
// TODO to support tabbing thru menus and stuff, we will have to implement this
return null;
}
}

View File

@ -47,6 +47,28 @@ public abstract class AbstractRenderableFrame implements UIFrame {
}
}
@Override
public void setSetAllPoints(final boolean setAllPoints, final float inset) {
this.framePointToAssignment.put(FramePoint.TOPLEFT,
new SetPoint(FramePoint.TOPLEFT, this.parent, FramePoint.TOPLEFT, inset, -inset));
this.framePointToAssignment.put(FramePoint.LEFT,
new SetPoint(FramePoint.LEFT, this.parent, FramePoint.LEFT, inset, 0));
this.framePointToAssignment.put(FramePoint.BOTTOMLEFT,
new SetPoint(FramePoint.BOTTOMLEFT, this.parent, FramePoint.BOTTOMLEFT, inset, inset));
this.framePointToAssignment.put(FramePoint.BOTTOM,
new SetPoint(FramePoint.BOTTOM, this.parent, FramePoint.BOTTOM, 0, inset));
this.framePointToAssignment.put(FramePoint.BOTTOMRIGHT,
new SetPoint(FramePoint.BOTTOMRIGHT, this.parent, FramePoint.BOTTOMRIGHT, -inset, inset));
this.framePointToAssignment.put(FramePoint.RIGHT,
new SetPoint(FramePoint.RIGHT, this.parent, FramePoint.RIGHT, -inset, 0));
this.framePointToAssignment.put(FramePoint.TOPRIGHT,
new SetPoint(FramePoint.TOPRIGHT, this.parent, FramePoint.TOPRIGHT, -inset, -inset));
this.framePointToAssignment.put(FramePoint.TOP,
new SetPoint(FramePoint.TOP, this.parent, FramePoint.TOP, 0, -inset));
this.framePointToAssignment.put(FramePoint.CENTER,
new SetPoint(FramePoint.CENTER, this.parent, FramePoint.CENTER, 0, 0));
}
@Override
public void setWidth(final float width) {
this.assignedWidth = width;
@ -296,6 +318,7 @@ public abstract class AbstractRenderableFrame implements UIFrame {
protected abstract void innerPositionBounds(GameUI gameUI, final Viewport viewport);
@Override
public boolean isVisible() {
return this.visible;
}
@ -320,6 +343,22 @@ public abstract class AbstractRenderableFrame implements UIFrame {
}
}
@Override
public UIFrame getParent() {
return this.parent;
}
@Override
public boolean isVisibleOnScreen() {
boolean visibleOnScreen = this.visible;
UIFrame ancestor = this.parent;
while (visibleOnScreen && (ancestor != null)) {
visibleOnScreen &= ancestor.isVisible();
ancestor = ancestor.getParent();
}
return visibleOnScreen;
}
protected abstract void internalRender(SpriteBatch batch, BitmapFont baseFont, GlyphLayout glyphLayout);
@Override

View File

@ -30,6 +30,11 @@ public abstract class AbstractUIFrame extends AbstractRenderableFrame implements
super(name, parent);
}
@Override
public void setVisible(final boolean visible) {
super.setVisible(visible);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
for (final UIFrame childFrame : this.childFrames) {

View File

@ -22,14 +22,15 @@ public class BackdropFrame extends AbstractUIFrame {
private final float edgeUVWidth;
private final float edgeFileHeight;
private final float edgeUVHeight;
private final boolean mirrored;
public BackdropFrame(final String name, final UIFrame parent, final boolean decorateFileNames,
final boolean tileBackground, final Texture background, final EnumSet<BackdropCornerFlags> cornerFlags,
final float cornerSize, final float backgroundSize, final Vector4Definition backgroundInsets,
final Texture edgeFile) {
final Texture edgeFile, final boolean mirrored) {
super(name, parent);
this.decorateFileNames = decorateFileNames;
this.tileBackground = tileBackground;
this.tileBackground = tileBackground && (backgroundSize > 0);
this.background = background;
this.cornerFlags = cornerFlags;
this.cornerSize = cornerSize;
@ -40,6 +41,7 @@ public class BackdropFrame extends AbstractUIFrame {
this.edgeFileHeight = edgeFile == null ? 0.0f : edgeFile.getHeight();
this.edgeUVWidth = 1f / 8f;
this.edgeUVHeight = 1f;
this.mirrored = mirrored;
}
@Override
@ -83,7 +85,13 @@ public class BackdropFrame extends AbstractUIFrame {
backgroundHeightRemainderRatio);
}
else {
batch.draw(this.background, backgroundX, backgroundY, backgroundWidth, backgroundHeight);
if (this.mirrored) {
batch.draw(this.background, backgroundX, backgroundY, backgroundWidth, backgroundHeight, 0, 0,
this.background.getWidth(), this.background.getHeight(), true, false);
}
else {
batch.draw(this.background, backgroundX, backgroundY, backgroundWidth, backgroundHeight);
}
}
}
if (this.edgeFile != null) {
@ -181,4 +189,7 @@ public class BackdropFrame extends AbstractUIFrame {
super.internalRender(batch, baseFont, glyphLayout);
}
public float getCornerSize() {
return this.cornerSize;
}
}

View File

@ -0,0 +1,35 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
public class ControlFrame extends AbstractRenderableFrame {
private UIFrame controlBackdrop;
public ControlFrame(final String name, final UIFrame parent) {
super(name, parent);
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
public UIFrame getControlBackdrop() {
return this.controlBackdrop;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.controlBackdrop.positionBounds(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.controlBackdrop.render(batch, baseFont, glyphLayout);
}
}

View File

@ -0,0 +1,164 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.TimeUtils;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.FocusableFrame;
public class EditBoxFrame extends AbstractRenderableFrame implements FocusableFrame {
private UIFrame controlBackdrop;
private final float editBorderSize;
private final Color editCursorColor;
private StringFrame editTextFrame;
private boolean focused = false;
private int cursorIndex;
// TODO design in such a way that references to these are not held !! very bad
// code design here
private GameUI gameUI;
private Viewport viewport;
private GlyphLayout glyphLayout;
public EditBoxFrame(final String name, final UIFrame parent, final float editBorderSize,
final Color editCursorColor) {
super(name, parent);
this.editBorderSize = editBorderSize;
this.editCursorColor = editCursorColor;
}
public void setControlBackdrop(final UIFrame controlBackdrop) {
this.controlBackdrop = controlBackdrop;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
this.gameUI = gameUI;
this.viewport = viewport;
this.controlBackdrop.positionBounds(gameUI, viewport);
this.editTextFrame.positionBounds(gameUI, viewport);
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.glyphLayout = glyphLayout;
this.controlBackdrop.render(batch, baseFont, glyphLayout);
this.editTextFrame.render(batch, baseFont, glyphLayout);
if (this.focused) {
final long time = TimeUtils.millis();
if ((time % 500) > 250) {
final BitmapFont frameFont = this.editTextFrame.getFrameFont();
frameFont.setColor(this.editCursorColor);
final int cursorRenderPosition = Math.min(this.cursorIndex, this.editTextFrame.getText().length());
this.cursorIndex = cursorRenderPosition;
glyphLayout.setText(frameFont, this.editTextFrame.getText().substring(0, cursorRenderPosition));
final float cursorXOffset = glyphLayout.width;
glyphLayout.setText(frameFont, "|");
frameFont.draw(batch, "|",
(this.editTextFrame.getFramePointX(FramePoint.LEFT) + cursorXOffset) - (glyphLayout.width / 2),
this.editTextFrame.getFramePointY(FramePoint.LEFT) + ((frameFont.getCapHeight()) / 2));
}
}
}
public void setEditTextFrame(final StringFrame editTextFrame) {
this.editTextFrame = editTextFrame;
}
@Override
public boolean isFocusable() {
return true;
}
@Override
public void onFocusGained() {
this.focused = true;
}
@Override
public void onFocusLost() {
this.focused = false;
}
@Override
public boolean keyDown(final int keycode) {
switch (keycode) {
case Input.Keys.LEFT: {
this.cursorIndex = Math.max(0, this.cursorIndex - 1);
break;
}
case Input.Keys.RIGHT: {
final String text = this.editTextFrame.getText();
this.cursorIndex = Math.min(text.length(), this.cursorIndex + 1);
break;
}
case Input.Keys.BACKSPACE: {
final String prevText = this.editTextFrame.getText();
final int prevTextLength = prevText.length();
final int cursorIndex = Math.min(this.cursorIndex, prevTextLength);
if (cursorIndex >= 1) {
this.cursorIndex = cursorIndex - 1;
final String newText = prevText.substring(0, cursorIndex - 1)
+ prevText.substring(cursorIndex, prevTextLength);
this.editTextFrame.setText(newText, this.gameUI, this.viewport);
}
break;
}
}
return false;
}
@Override
public boolean keyUp(final int keycode) {
return false;
}
@Override
public boolean keyTyped(final char character) {
if (Character.isAlphabetic(character) || Character.isDigit(character)) {
final String prevText = this.editTextFrame.getText();
final int prevTextLength = prevText.length();
final int cursorIndex = Math.min(this.cursorIndex, prevTextLength);
final String newText = prevText.substring(0, cursorIndex) + character
+ prevText.substring(cursorIndex, prevTextLength);
this.editTextFrame.setText(newText, this.gameUI, this.viewport);
this.cursorIndex++;
}
return false;
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
final String text = this.editTextFrame.getText();
int indexFound = -1;
final float fpXOfEditText = this.editTextFrame.getFramePointX(FramePoint.LEFT);
float lastX = 0;
for (int i = 0; i < text.length(); i++) {
final BitmapFont frameFont = this.editTextFrame.getFrameFont();
this.glyphLayout.setText(frameFont, this.editTextFrame.getText().substring(0, i));
final float x = fpXOfEditText + this.glyphLayout.width;
if (((x + lastX) / 2) > screenX) {
indexFound = i - 1;
break;
}
lastX = x;
}
if (indexFound == -1) {
indexFound = text.length();
}
this.cursorIndex = indexFound;
return this;
}
return super.touchDown(screenX, screenY, button);
}
}

View File

@ -0,0 +1,110 @@
package com.etheller.warsmash.parsers.fdf.frames;
import java.util.ArrayList;
import java.util.List;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class ListBoxFrame extends ControlFrame {
private final List<String> listItems = new ArrayList<>();
private final List<SingleStringFrame> stringFrames = new ArrayList<>();
private BitmapFont frameFont;
private float listBoxBorder;
public ListBoxFrame(final String name, final UIFrame parent, final Viewport viewport) {
super(name, parent);
this.listBoxBorder = GameUI.convertX(viewport, 0.01f);
}
public void setListBoxBorder(final float listBoxBorder) {
this.listBoxBorder = listBoxBorder;
}
public float getListBoxBorder() {
return this.listBoxBorder;
}
public void setFrameFont(final BitmapFont frameFont) {
this.frameFont = frameFont;
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
super.innerPositionBounds(gameUI, viewport);
updateUI(gameUI, viewport);
}
private void positionChildren(final GameUI gameUI, final Viewport viewport) {
for (final SingleStringFrame frame : this.stringFrames) {
frame.positionBounds(gameUI, viewport);
}
}
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
super.internalRender(batch, baseFont, glyphLayout);
for (final SingleStringFrame frame : this.stringFrames) {
frame.render(batch, baseFont, glyphLayout);
}
}
public void addItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.add(item);
// updateUI(gameUI, viewport);
}
public void setItems(final List<String> items, final GameUI gameUI, final Viewport viewport) {
this.listItems.clear();
this.listItems.addAll(items);
// updateUI(gameUI, viewport);
}
public void removeItem(final String item, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(item);
// updateUI(gameUI, viewport);
}
public void removeItem(final int index, final GameUI gameUI, final Viewport viewport) {
this.listItems.remove(index);
// updateUI(gameUI, viewport);
}
private void updateUI(final GameUI gameUI, final Viewport viewport) {
this.stringFrames.clear();
SingleStringFrame prev = null;
int i = 0;
for (final String string : this.listItems) {
final SingleStringFrame stringFrame = new SingleStringFrame("LISTY" + i++, this, Color.WHITE,
TextJustify.LEFT, TextJustify.MIDDLE, this.frameFont);
stringFrame.setText(string);
stringFrame.setWidth(this.renderBounds.width);
stringFrame.setHeight(this.frameFont.getLineHeight());
if (prev != null) {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, prev, FramePoint.BOTTOMLEFT, 0, 0));
}
else {
stringFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, this.listBoxBorder,
-this.listBoxBorder));
}
this.stringFrames.add(stringFrame);
prev = stringFrame;
}
positionChildren(gameUI, viewport);
}
@Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
return this;
}
return super.touchDown(screenX, screenY, button);
}
}

View File

@ -7,6 +7,8 @@ import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
@ -14,6 +16,7 @@ import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.TextJustify;
public class StringFrame extends AbstractRenderableFrame {
private static final boolean DEBUG = false;
private final List<SingleStringFrame> internalFrames = new ArrayList<>();
private Color color;
private String text = "Default string";
@ -27,6 +30,8 @@ public class StringFrame extends AbstractRenderableFrame {
private final SimpleFrame internalFramesContainer;
private float predictedViewportHeight;
static ShapeRenderer shapeRenderer = new ShapeRenderer();
public StringFrame(final String name, final UIFrame parent, final Color color, final TextJustify justifyH,
final TextJustify justifyV, final BitmapFont frameFont, final String text) {
super(name, parent);
@ -38,6 +43,10 @@ public class StringFrame extends AbstractRenderableFrame {
this.internalFramesContainer = new SimpleFrame(null, this);
}
public String getText() {
return this.text;
}
public void setText(final String text, final GameUI gameUI, final Viewport viewport) {
if (text == null) {
throw new IllegalArgumentException();
@ -77,11 +86,32 @@ public class StringFrame extends AbstractRenderableFrame {
@Override
protected void internalRender(final SpriteBatch batch, final BitmapFont baseFont, final GlyphLayout glyphLayout) {
this.internalFramesContainer.render(batch, baseFont, glyphLayout);
if (DEBUG) {
batch.end();
shapeRenderer.setProjectionMatrix(batch.getProjectionMatrix());
shapeRenderer.setColor(1f, 1f, 1f, 1f);
shapeRenderer.begin(ShapeType.Line);
shapeRenderer.rect(this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
this.renderBounds.height);
shapeRenderer.end();
batch.begin();
}
}
@Override
public void positionBounds(final GameUI gameUI, final Viewport viewport) {
createInternalFrames(gameUI.getGlyphLayout());
if (this.renderBounds.height == 0) {
this.renderBounds.height = getPredictedViewportHeight();
}
super.positionBounds(gameUI, viewport);
}
@Override
protected void innerPositionBounds(final GameUI gameUI, final Viewport viewport) {
createInternalFrames(gameUI.getGlyphLayout());
this.internalFramesContainer.positionBounds(gameUI, viewport);
}
@ -436,4 +466,7 @@ public class StringFrame extends AbstractRenderableFrame {
return this.predictedViewportHeight;
}
public BitmapFont getFrameFont() {
return this.frameFont;
}
}

View File

@ -31,8 +31,16 @@ public interface UIFrame {
void setSetAllPoints(boolean setAllPoints);
void setSetAllPoints(boolean setAllPoints, float inset);
void setVisible(boolean visible);
UIFrame getParent();
boolean isVisible();
boolean isVisibleOnScreen();
UIFrame touchDown(float screenX, float screenY, int button);
UIFrame touchUp(float screenX, float screenY, int button);

View File

@ -35,6 +35,7 @@ import com.etheller.interpreter.ast.value.visitor.RealJassValueVisitor;
import com.etheller.interpreter.ast.value.visitor.StringJassValueVisitor;
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameSkin;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
@ -227,11 +228,11 @@ public class Jass2 {
public JassValue call(final List<JassValue> arguments, final GlobalScope globalScope,
final TriggerExecutionScope triggerScope) {
final String skinArg = arguments.get(0).visit(StringJassValueVisitor.getInstance());
final Element skin = GameUI.loadSkin(dataSource, skinArg);
final GameSkin skin = GameUI.loadSkin(dataSource, skinArg);
final GameUI gameUI = new GameUI(dataSource, skin, uiViewport, uiScene, war3MapViewer, 0,
war3MapViewer.getAllObjectData().getWts());
JUIEnvironment.this.gameUI = gameUI;
JUIEnvironment.this.skin = skin;
JUIEnvironment.this.skin = skin.getSkin();
rootFrameListener.onCreate(gameUI);
return new HandleJassValue(frameHandleType, gameUI);
}

View File

@ -6,7 +6,7 @@ public class WarsmashConstants {
* With version, we use 0 for RoC, 1 for TFT emulation, and probably 2+ or
* whatever for custom mods and other stuff
*/
public static int GAME_VERSION = 0;
public static int GAME_VERSION = 1;
public static final int REPLACEABLE_TEXTURE_LIMIT = 64;
public static final float SIMULATION_STEP_TIME = 1 / 20f;
public static final int PORT_NUMBER = 6115;

View File

@ -715,9 +715,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma
this.tooltipUberTipText = (StringFrame) this.rootFrame.getFrameByName("SmashUberTipText", 0);
this.tooltipUberTipText.setWidth(GameUI.convertX(this.uiViewport, 0.274f));
this.uberTipNoResourcesSetPoint = new SetPoint(FramePoint.TOPLEFT, this.tooltipText, FramePoint.BOTTOMLEFT, 0,
GameUI.convertY(this.uiViewport, -0.014f));
GameUI.convertY(this.uiViewport, -0.004f));
this.uberTipWithResourcesSetPoint = new SetPoint(FramePoint.TOPLEFT, this.tooltipText, FramePoint.BOTTOMLEFT, 0,
GameUI.convertY(this.uiViewport, -0.024f));
GameUI.convertY(this.uiViewport, -0.014f));
this.tooltipUberTipText.addSetPoint(this.uberTipNoResourcesSetPoint);
this.tooltipResourceFrames = new UIFrame[ResourceType.VALUES.length];
this.tooltipResourceIconFrames = new TextureFrame[ResourceType.VALUES.length];

View File

@ -10,35 +10,43 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.etheller.warsmash.WarsmashGdxMapScreen;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.etheller.warsmash.SingleModelScreen;
import com.etheller.warsmash.WarsmashGdxMenuScreen;
import com.etheller.warsmash.WarsmashGdxMultiScreenGame;
import com.etheller.warsmash.datasources.DataSource;
import com.etheller.warsmash.parsers.fdf.GameUI;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.frames.EditBoxFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.GlueTextButtonFrame;
import com.etheller.warsmash.parsers.fdf.frames.ListBoxFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
import com.etheller.warsmash.parsers.jass.Jass2.RootFrameListener;
import com.etheller.warsmash.units.DataTable;
import com.etheller.warsmash.units.Element;
import com.etheller.warsmash.units.custom.WTS;
import com.etheller.warsmash.util.StringBundle;
import com.etheller.warsmash.util.WarsmashConstants;
import com.etheller.warsmash.util.WorldEditStrings;
import com.etheller.warsmash.viewer5.Scene;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSound;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.ClickableFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.command.FocusableFrame;
import com.etheller.warsmash.viewer5.handlers.w3x.ui.sound.KeyedSounds;
public class MenuUI {
private static final Vector2 screenCoordsVector = new Vector2();
private static boolean ENABLE_NOT_YET_IMPLEMENTED_BUTTONS = false;
private final DataSource dataSource;
private final Scene uiScene;
private final ExtendViewport uiViewport;
private final Viewport uiViewport;
private final MdxViewer viewer;
private final RootFrameListener rootFrameListener;
private final float widthRatioCorrection;
@ -48,6 +56,7 @@ public class MenuUI {
private ClickableFrame mouseDownUIFrame;
private ClickableFrame mouseOverUIFrame;
private FocusableFrame focusUIFrame;
private UIFrame mainMenuFrame;
@ -74,8 +83,12 @@ public class MenuUI {
private MenuState menuState;
private UIFrame singlePlayerMenu;
private UIFrame singlePlayerMainPanel;
private UIFrame skirmish;
private UIFrame profilePanel;
private EditBoxFrame newProfileEditBox;
private GlueButtonFrame profileButton;
private GlueTextButtonFrame campaignButton;
@ -83,28 +96,61 @@ public class MenuUI {
private GlueTextButtonFrame viewReplayButton;
private GlueTextButtonFrame customCampaignButton;
private GlueTextButtonFrame skirmishButton;
private GlueTextButtonFrame cancelButton;
private GlueTextButtonFrame singlePlayerCancelButton;
private GlueButtonFrame editionButton;
private GlueTextButtonFrame skirmishCancelButton;
private final WarsmashGdxMultiScreenGame screenManager;
private final DataTable warsmashIni;
private UnitSound glueScreenLoop;
public MenuUI(final DataSource dataSource, final ExtendViewport uiViewport, final Scene uiScene,
final MdxViewer viewer, final WarsmashGdxMultiScreenGame screenManager, final DataTable warsmashIni,
final RootFrameListener rootFrameListener) {
private SpriteFrame warcraftIIILogo;
// Campaign
private UIFrame campaignMenu;
private SpriteFrame campaignFade;
private GlueTextButtonFrame campaignBackButton;
private UIFrame missionSelectFrame;
private UIFrame campaignSelectFrame;
private final DataTable campaignStrings;
private SpriteFrame campaignWarcraftIIILogo;
private final SingleModelScreen menuScreen;
private String currentCampaignBackgroundModel;
private String currentCampaignAmbientSound;
private int currentCampaignCursor;
private String[] campaignList;
private Element[] campaignDatas;
private UnitSound mainMenuGlueScreenLoop;
private GlueTextButtonFrame addProfileButton;
private GlueTextButtonFrame deleteProfileButton;
private GlueTextButtonFrame selectProfileButton;
public MenuUI(final DataSource dataSource, final Viewport uiViewport, final Scene uiScene, final MdxViewer viewer,
final WarsmashGdxMultiScreenGame screenManager, final SingleModelScreen menuScreen,
final DataTable warsmashIni, final RootFrameListener rootFrameListener) {
this.dataSource = dataSource;
this.uiViewport = uiViewport;
this.uiScene = uiScene;
this.viewer = viewer;
this.screenManager = screenManager;
this.menuScreen = menuScreen;
this.warsmashIni = warsmashIni;
this.rootFrameListener = rootFrameListener;
this.widthRatioCorrection = this.uiViewport.getMinWorldWidth() / 1600f;
this.heightRatioCorrection = this.uiViewport.getMinWorldHeight() / 1200f;
this.widthRatioCorrection = getMinWorldWidth() / 1600f;
this.heightRatioCorrection = getMinWorldHeight() / 1200f;
this.campaignStrings = new DataTable(StringBundle.EMPTY);
try (InputStream campaignStringStream = dataSource.getResourceAsStream(
"UI\\CampaignStrings" + (WarsmashConstants.GAME_VERSION == 1 ? "_exp" : "") + ".txt")) {
this.campaignStrings.readTXT(campaignStringStream, true);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
public float getHeightRatioCorrection() {
@ -138,13 +184,13 @@ public class MenuUI {
// Create main menu
this.mainMenuFrame = this.rootFrame.createFrame("MainMenuFrame", this.rootFrame, 0, 0);
this.mainMenuFrame.setVisible(false);
final SpriteFrame warcraftIIILogo = (SpriteFrame) this.rootFrame.getFrameByName("WarCraftIIILogo", 0);
this.rootFrame.setSpriteFrameModel(warcraftIIILogo,
this.warcraftIIILogo = (SpriteFrame) this.rootFrame.getFrameByName("WarCraftIIILogo", 0);
this.rootFrame.setSpriteFrameModel(this.warcraftIIILogo,
this.rootFrame.getSkinField("MainMenuLogo_V" + WarsmashConstants.GAME_VERSION));
warcraftIIILogo.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.mainMenuFrame, FramePoint.TOPLEFT,
this.warcraftIIILogo.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.mainMenuFrame, FramePoint.TOPLEFT,
GameUI.convertX(this.uiViewport, 0.13f), GameUI.convertY(this.uiViewport, -0.08f)));
setMainMenuVisible(false);
this.rootFrame.getFrameByName("RealmSelect", 0).setVisible(false);
this.glueSpriteLayerTopRight = (SpriteFrame) this.rootFrame.createFrameByType("SPRITE",
@ -170,17 +216,7 @@ public class MenuUI {
this.cursorFrame.setZDepth(-1.0f);
Gdx.input.setCursorCatched(true);
// Create single player
this.singlePlayerMenu = this.rootFrame.createFrame("SinglePlayerMenu", this.rootFrame, 0, 0);
this.singlePlayerMenu.setVisible(false);
this.profilePanel = this.rootFrame.getFrameByName("ProfilePanel", 0);
this.profilePanel.setVisible(false);
// position all
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
// Main Menu
// Main Menu interactivity
this.singlePlayerButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("SinglePlayerButton", 0);
this.battleNetButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("BattleNetButton", 0);
this.realmButton = (GlueButtonFrame) this.rootFrame.getFrameByName("RealmButton", 0);
@ -197,7 +233,7 @@ public class MenuUI {
WarsmashConstants.GAME_VERSION = (WarsmashConstants.GAME_VERSION == 1 ? 0 : 1);
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
setMainMenuVisible(false);
MenuUI.this.menuState = MenuState.RESTARTING;
}
});
@ -214,7 +250,7 @@ public class MenuUI {
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
setMainMenuVisible(false);
MenuUI.this.menuState = MenuState.QUITTING;
}
});
@ -224,12 +260,37 @@ public class MenuUI {
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("MainMenu Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("MainMenu Death");
MenuUI.this.mainMenuFrame.setVisible(false);
setMainMenuVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_SINGLE_PLAYER;
}
});
// Single Player
// Create single player
this.singlePlayerMenu = this.rootFrame.createFrame("SinglePlayerMenu", this.rootFrame, 0, 0);
this.singlePlayerMenu.setVisible(false);
this.profilePanel = this.rootFrame.getFrameByName("ProfilePanel", 0);
this.profilePanel.setVisible(false);
this.newProfileEditBox = (EditBoxFrame) this.rootFrame.getFrameByName("NewProfileEditBox", 0);
final StringFrame profileListText = (StringFrame) this.rootFrame.getFrameByName("ProfileListText", 0);
final SimpleFrame profileListContainer = (SimpleFrame) this.rootFrame.getFrameByName("ProfileListContainer", 0);
final ListBoxFrame profileListBox = (ListBoxFrame) this.rootFrame.createFrameByType("LISTBOX", "ListBoxWar3",
profileListContainer, "WITHCHILDREN", 0);
profileListBox.setSetAllPoints(true);
profileListBox.setFrameFont(profileListText.getFrameFont());
profileListBox.addItem("Test1", this.rootFrame, this.uiViewport);
profileListBox.addItem("Test2", this.rootFrame, this.uiViewport);
profileListBox.addItem("Test3", this.rootFrame, this.uiViewport);
profileListContainer.add(profileListBox);
this.addProfileButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("AddProfileButton", 0);
this.deleteProfileButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("DeleteProfileButton", 0);
this.selectProfileButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("SelectProfileButton", 0);
this.singlePlayerMainPanel = this.rootFrame.getFrameByName("MainPanel", 0);
// Single Player Interactivity
this.profileButton = (GlueButtonFrame) this.rootFrame.getFrameByName("ProfileButton", 0);
this.campaignButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CampaignButton", 0);
this.loadSavedButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("LoadSavedButton", 0);
@ -237,16 +298,21 @@ public class MenuUI {
this.customCampaignButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CustomCampaignButton", 0);
this.skirmishButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("SkirmishButton", 0);
this.cancelButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CancelButton", 0);
this.singlePlayerCancelButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CancelButton", 0);
final StringFrame profileNameText = (StringFrame) this.rootFrame.getFrameByName("ProfileNameText", 0);
this.rootFrame.setText(profileNameText, "WorldEdit");
this.profileButton.setEnabled(false);
this.loadSavedButton.setEnabled(false);
this.viewReplayButton.setEnabled(false);
this.customCampaignButton.setEnabled(false);
this.skirmishButton.setEnabled(false);
setSinglePlayerButtonsEnabled(true);
this.profileButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("RealmSelection Birth");
setSinglePlayerButtonsEnabled(true);
MenuUI.this.menuState = MenuState.SINGLE_PLAYER_PROFILE;
}
});
this.campaignButton.setOnClick(new Runnable() {
@Override
@ -254,30 +320,125 @@ public class MenuUI {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayer Death");
MenuUI.this.singlePlayerMenu.setVisible(false);
MenuUI.this.profilePanel.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_CAMPAIGN;
}
});
this.cancelButton.setOnClick(new Runnable() {
this.skirmishButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayer Death");
MenuUI.this.singlePlayerMenu.setVisible(false);
MenuUI.this.profilePanel.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_SINGLE_PLAYER_SKIRMISH;
}
});
this.singlePlayerCancelButton.setOnClick(new Runnable() {
@Override
public void run() {
if (MenuUI.this.menuState == MenuState.SINGLE_PLAYER_PROFILE) {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("RealmSelection Death");
MenuUI.this.profilePanel.setVisible(false);
}
else {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Death");
}
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayer Death");
MenuUI.this.singlePlayerMenu.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_MAIN_MENU;
}
});
// Create skirmish UI
this.skirmish = this.rootFrame.createFrame("Skirmish", this.rootFrame, 0, 0);
this.skirmish.setVisible(false);
this.skirmishCancelButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("CancelButton", 0);
this.skirmishCancelButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.glueSpriteLayerTopLeft.setSequence("SinglePlayerSkirmish Death");
MenuUI.this.glueSpriteLayerTopRight.setSequence("SinglePlayerSkirmish Death");
MenuUI.this.skirmish.setVisible(false);
MenuUI.this.menuState = MenuState.GOING_TO_SINGLE_PLAYER;
}
});
this.menuState = MenuState.MAIN_MENU;
// Create Campaign UI
this.campaignMenu = this.rootFrame.createFrame("CampaignMenu", this.rootFrame, 0, 0);
this.campaignMenu.setVisible(false);
this.campaignFade = (SpriteFrame) this.rootFrame.getFrameByName("SlidingDoors", 0);
this.campaignFade.setVisible(false);
this.campaignBackButton = (GlueTextButtonFrame) this.rootFrame.getFrameByName("BackButton", 0);
this.campaignBackButton.setVisible(false);
this.missionSelectFrame = this.rootFrame.getFrameByName("MissionSelectFrame", 0);
this.missionSelectFrame.setVisible(false);
this.campaignSelectFrame = this.rootFrame.getFrameByName("CampaignSelectFrame", 0);
this.campaignSelectFrame.setVisible(false);
this.campaignWarcraftIIILogo = (SpriteFrame) this.rootFrame.getFrameByName("WarCraftIIILogo", 0);
this.rootFrame.setSpriteFrameModel(this.campaignWarcraftIIILogo,
this.rootFrame.getSkinField("MainMenuLogo_V" + WarsmashConstants.GAME_VERSION));
this.campaignWarcraftIIILogo.setVisible(false);
this.campaignBackButton.setOnClick(new Runnable() {
@Override
public void run() {
MenuUI.this.campaignMenu.setVisible(false);
MenuUI.this.campaignBackButton.setVisible(false);
MenuUI.this.missionSelectFrame.setVisible(false);
MenuUI.this.campaignSelectFrame.setVisible(false);
MenuUI.this.campaignFade.setSequence("Birth");
MenuUI.this.menuState = MenuState.LEAVING_CAMPAIGN;
}
});
final Element campaignIndex = this.campaignStrings.get("Index");
this.campaignList = campaignIndex.getField("CampaignList").split(",");
this.campaignDatas = new Element[this.campaignList.length];
for (int i = 0; i < this.campaignList.length; i++) {
final String campaign = this.campaignList[i];
this.campaignDatas[i] = this.campaignStrings.get(campaign);
if ((this.campaignDatas[i] != null) && (this.currentCampaignBackgroundModel == null)) {
this.currentCampaignBackgroundModel = this.rootFrame.getSkinField(
this.campaignDatas[i].getField("Background") + "_V" + WarsmashConstants.GAME_VERSION);
this.currentCampaignAmbientSound = this.rootFrame
.trySkinField(this.campaignDatas[i].getField("AmbientSound"));
this.currentCampaignCursor = this.campaignDatas[i].getFieldValue("Cursor");
}
}
// position all
this.rootFrame.positionBounds(this.rootFrame, this.uiViewport);
this.menuState = MenuState.GOING_TO_MAIN_MENU;
loadSounds();
final String glueLoopField = this.rootFrame.getSkinField("GlueScreenLoop_V" + WarsmashConstants.GAME_VERSION);
this.glueScreenLoop = this.uiSounds.getSound(glueLoopField);
this.mainMenuGlueScreenLoop = this.uiSounds.getSound(glueLoopField);
this.glueScreenLoop = this.mainMenuGlueScreenLoop;
this.glueScreenLoop.play(this.uiScene.audioContext, 0f, 0f, 0f);
}
protected void setSinglePlayerButtonsEnabled(final boolean b) {
this.profileButton.setEnabled(b);
this.campaignButton.setEnabled(b);
this.loadSavedButton.setEnabled(b && ENABLE_NOT_YET_IMPLEMENTED_BUTTONS);
this.viewReplayButton.setEnabled(b && ENABLE_NOT_YET_IMPLEMENTED_BUTTONS);
this.customCampaignButton.setEnabled(b && ENABLE_NOT_YET_IMPLEMENTED_BUTTONS);
this.skirmishButton.setEnabled(b);
}
private void setMainMenuVisible(final boolean visible) {
this.mainMenuFrame.setVisible(visible);
this.warcraftIIILogo.setVisible(visible);
}
public void resize() {
}
@ -288,12 +449,28 @@ public class MenuUI {
font.setColor(Color.YELLOW);
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
glyphLayout.setText(font, fpsString);
font.draw(batch, fpsString, (this.uiViewport.getMinWorldWidth() - glyphLayout.width) / 2,
1100 * this.heightRatioCorrection);
font.draw(batch, fpsString, (getMinWorldWidth() - glyphLayout.width) / 2, 1100 * this.heightRatioCorrection);
this.rootFrame.render(batch, font20, glyphLayout);
}
private float getMinWorldWidth() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldWidth();
}
return this.uiViewport.getWorldWidth();
}
private float getMinWorldHeight() {
if (this.uiViewport instanceof ExtendViewport) {
return ((ExtendViewport) this.uiViewport).getMinWorldHeight();
}
return this.uiViewport.getWorldHeight();
}
public void update(final float deltaTime) {
if ((this.focusUIFrame != null) && !this.focusUIFrame.isVisibleOnScreen()) {
setFocusFrame(getNextFocusFrame());
}
final int baseMouseX = Gdx.input.getX();
int mouseX = baseMouseX;
@ -316,7 +493,8 @@ public class MenuUI {
this.cursorFrame.setFramePointY(FramePoint.BOTTOM, screenCoordsVector.y);
this.cursorFrame.setSequence("Normal");
if (this.glueSpriteLayerTopRight.isSequenceEnded()) {
if (this.glueSpriteLayerTopRight.isSequenceEnded() && this.glueSpriteLayerTopLeft.isSequenceEnded()
&& (!this.campaignFade.isVisible() || this.campaignFade.isSequenceEnded())) {
switch (this.menuState) {
case GOING_TO_MAIN_MENU:
this.glueSpriteLayerTopLeft.setSequence("MainMenu Birth");
@ -324,7 +502,7 @@ public class MenuUI {
this.menuState = MenuState.MAIN_MENU;
break;
case MAIN_MENU:
this.mainMenuFrame.setVisible(true);
setMainMenuVisible(true);
this.glueSpriteLayerTopLeft.setSequence("MainMenu Stand");
this.glueSpriteLayerTopRight.setSequence("MainMenu Stand");
break;
@ -333,14 +511,82 @@ public class MenuUI {
this.glueSpriteLayerTopRight.setSequence("SinglePlayer Birth");
this.menuState = MenuState.SINGLE_PLAYER;
break;
case LEAVING_CAMPAIGN:
this.glueSpriteLayerTopLeft.setSequence("Birth");
this.glueSpriteLayerTopRight.setSequence("Birth");
if (this.campaignFade.isVisible()) {
this.campaignFade.setSequence("Death");
}
this.glueScreenLoop.stop();
this.glueScreenLoop = this.mainMenuGlueScreenLoop;
this.glueScreenLoop.play(this.uiScene.audioContext, 0f, 0f, 0f);
this.menuScreen.setModel(
this.rootFrame.getSkinField("GlueSpriteLayerBackground_V" + WarsmashConstants.GAME_VERSION));
this.rootFrame.setSpriteFrameModel(this.cursorFrame, this.rootFrame.getSkinField("Cursor"));
this.menuState = MenuState.GOING_TO_SINGLE_PLAYER;
break;
case SINGLE_PLAYER:
this.singlePlayerMenu.setVisible(true);
this.campaignFade.setVisible(false);
setSinglePlayerButtonsEnabled(true);
this.glueSpriteLayerTopLeft.setSequence("SinglePlayer Stand");
this.glueSpriteLayerTopRight.setSequence("SinglePlayer Stand");
break;
case GOING_TO_SINGLE_PLAYER_SKIRMISH:
this.glueSpriteLayerTopLeft.setSequence("SinglePlayerSkirmish Birth");
this.glueSpriteLayerTopRight.setSequence("SinglePlayerSkirmish Birth");
this.menuState = MenuState.SINGLE_PLAYER_SKIRMISH;
break;
case SINGLE_PLAYER_SKIRMISH:
this.skirmish.setVisible(true);
this.glueSpriteLayerTopLeft.setSequence("SinglePlayerSkirmish Stand");
this.glueSpriteLayerTopRight.setSequence("SinglePlayerSkirmish Stand");
break;
case GOING_TO_CAMPAIGN:
MenuUI.this.screenManager.setScreen(new WarsmashGdxMapScreen(MenuUI.this.warsmashIni,
this.warsmashIni.get("Map").getField("FilePath")));
this.glueSpriteLayerTopLeft.setSequence("Death");
this.glueSpriteLayerTopRight.setSequence("Death");
this.campaignMenu.setVisible(true);
this.campaignFade.setVisible(true);
this.campaignFade.setSequence("Birth");
this.menuState = MenuState.GOING_TO_CAMPAIGN_PART2;
break;
case GOING_TO_CAMPAIGN_PART2:
this.menuScreen.setModel(this.currentCampaignBackgroundModel);
this.glueScreenLoop.stop();
this.glueScreenLoop = this.uiSounds.getSound(this.currentCampaignAmbientSound);
this.glueScreenLoop.play(this.uiScene.audioContext, 0f, 0f, 0f);
final DataTable skinData = this.rootFrame.getSkinData();
final Element skinDataMain = skinData.get("Main");
int currentCampaignCursor = this.currentCampaignCursor;
if (currentCampaignCursor == 3) {
currentCampaignCursor = 2;
}
else if (currentCampaignCursor == 2) {
currentCampaignCursor = 3;
}
final String cursorSkin = skinDataMain.getField("Skins", currentCampaignCursor);
this.rootFrame.setSpriteFrameModel(this.cursorFrame, skinData.get(cursorSkin).getField("Cursor"));
this.campaignFade.setSequence("Death");
this.menuState = MenuState.CAMPAIGN;
break;
case CAMPAIGN:
this.campaignBackButton.setVisible(true);
this.campaignWarcraftIIILogo.setVisible(true);
this.campaignSelectFrame.setVisible(true);
break;
case GOING_TO_SINGLE_PLAYER_PROFILE:
this.glueSpriteLayerTopLeft.setSequence("RealmSelection Birth");
this.menuState = MenuState.SINGLE_PLAYER_PROFILE;
break;
case SINGLE_PLAYER_PROFILE:
this.profilePanel.setVisible(true);
this.glueSpriteLayerTopLeft.setSequence("RealmSelection Stand");
// TODO the below should probably be some generic focusing thing when we enter a
// new view?
if ((this.newProfileEditBox != null) && this.newProfileEditBox.isFocusable()) {
setFocusFrame(this.newProfileEditBox);
}
break;
case QUITTING:
Gdx.app.exit();
@ -356,6 +602,10 @@ public class MenuUI {
}
private FocusableFrame getNextFocusFrame() {
return this.rootFrame.getNextFocusFrame();
}
public boolean touchDown(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
@ -365,10 +615,26 @@ public class MenuUI {
this.mouseDownUIFrame = (ClickableFrame) clickedUIFrame;
this.mouseDownUIFrame.mouseDown(this.rootFrame, this.uiViewport);
}
if (clickedUIFrame instanceof FocusableFrame) {
final FocusableFrame clickedFocusableFrame = (FocusableFrame) clickedUIFrame;
if (clickedFocusableFrame.isFocusable()) {
setFocusFrame(clickedFocusableFrame);
}
}
}
return false;
}
private void setFocusFrame(final FocusableFrame clickedFocusableFrame) {
if (this.focusUIFrame != null) {
this.focusUIFrame.onFocusLost();
}
this.focusUIFrame = clickedFocusableFrame;
if (this.focusUIFrame != null) {
this.focusUIFrame.onFocusGained();
}
}
public boolean touchUp(final int screenX, final int screenY, final float worldScreenY, final int button) {
screenCoordsVector.set(screenX, screenY);
this.uiViewport.unproject(screenCoordsVector);
@ -437,9 +703,15 @@ public class MenuUI {
GOING_TO_MAIN_MENU,
MAIN_MENU,
GOING_TO_SINGLE_PLAYER,
LEAVING_CAMPAIGN,
SINGLE_PLAYER,
GOING_TO_SINGLE_PLAYER_SKIRMISH,
SINGLE_PLAYER_SKIRMISH,
GOING_TO_CAMPAIGN,
GOING_TO_CAMPAIGN_PART2,
CAMPAIGN,
GOING_TO_SINGLE_PLAYER_PROFILE,
SINGLE_PLAYER_PROFILE,
QUITTING,
RESTARTING;
}
@ -453,4 +725,25 @@ public class MenuUI {
this.rootFrame.dispose();
}
}
public boolean keyDown(final int keycode) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyDown(keycode);
}
return false;
}
public boolean keyUp(final int keycode) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyUp(keycode);
}
return false;
}
public boolean keyTyped(final char character) {
if (this.focusUIFrame != null) {
this.focusUIFrame.keyTyped(character);
}
return false;
}
}

View File

@ -0,0 +1,17 @@
package com.etheller.warsmash.viewer5.handlers.w3x.ui.command;
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
public interface FocusableFrame extends UIFrame {
boolean isFocusable();
void onFocusGained();
void onFocusLost();
boolean keyDown(int keycode);
boolean keyUp(int keycode);
boolean keyTyped(char character);
}

View File

@ -219,7 +219,7 @@ public enum AnimationMap {
/**
* Camera source rotation
*/
KCRL(MdlUtils.TOKEN_ROTATION, MdlxTimelineDescriptor.UINT32_TIMELINE),
KCRL(MdlUtils.TOKEN_ROTATION, MdlxTimelineDescriptor.FLOAT_TIMELINE),
// GenericObject
/**
* Generic object translation