EmergentOrganization/cell-rpg

View on GitHub
core/src/io/github/emergentorganization/cellrpg/tools/mapeditor/ui/EditorWindow.java

Summary

Maintainability
D
1 day
Test Coverage
package io.github.emergentorganization.cellrpg.tools.mapeditor.ui;

import com.artemis.Entity;
import com.artemis.World;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Cell;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.widget.*;
import io.github.emergentorganization.cellrpg.PixelonTransmission;
import io.github.emergentorganization.cellrpg.core.EntityID;
import io.github.emergentorganization.cellrpg.core.components.Position;
import io.github.emergentorganization.cellrpg.core.components.Rotation;
import io.github.emergentorganization.cellrpg.core.components.Scale;
import io.github.emergentorganization.cellrpg.managers.PhysicsSystem;
import io.github.emergentorganization.cellrpg.scenes.Scene;
import io.github.emergentorganization.cellrpg.tools.FileListNode;
import io.github.emergentorganization.cellrpg.tools.mapeditor.EditorTarget;
import io.github.emergentorganization.cellrpg.tools.mapeditor.MapEditor;
import io.github.emergentorganization.cellrpg.tools.mapeditor.map.MapTools;


public class EditorWindow {
    private static final float LEFT_PANEL_HEIGHT = Gdx.graphics.getHeight();
    private static final float LEFT_PANEL_WIDTH = Gdx.graphics.getWidth() / 8f;
    private static final float MENU_BAR_HEIGHT = Gdx.graphics.getHeight() / 19f;
    private static final float MENU_BAR_WIDTH = Gdx.graphics.getWidth() - LEFT_PANEL_WIDTH;
    private static final float SAVE_WINDOW_WIDTH = Gdx.graphics.getWidth() / 6f;
    private static final float SAVE_WINDOW_HEIGHT = SAVE_WINDOW_WIDTH / 1.5f;
    private final Stage stage;
    private final MapEditor editor;
    private final PixelonTransmission pt;
    private final VisWindow saveWindow = new VisWindow("Save", true);
    private final VisWindow loadWindow = new VisWindow("Load", true);
    private VisTextField xField;
    private VisTextField yField;
    private VisTextField rotField;
    private VisTextField scaleField;
    private PopupMenu contextMenu;
    private VisList<FileListNode> importList;
    private String selectedItem;

    public EditorWindow(PixelonTransmission pt, MapEditor editor, Stage stage, World world) {
        this.pt = pt;
        this.editor = editor;
        this.stage = stage;

        VisUI.setDefaultTitleAlign(Align.center);

        initLeftPane();
        initMenuBar(world);
        initContextMenu();

        initSaveWindow(world);
        initLoadWindow();
    }

    private void initSaveWindow(final World world) {
        final float PADDING = 2f;

        saveWindow.setWidth(SAVE_WINDOW_WIDTH);
        saveWindow.setHeight(SAVE_WINDOW_HEIGHT);
        saveWindow.setPosition(Gdx.graphics.getWidth() / 2f, Gdx.graphics.getHeight() / 2f, Align.center);

        VisTable table = new VisTable();

        VisLabel fileNameLabel = new VisLabel("Map Name", Align.center);
        table.add(fileNameLabel).pad(PADDING).fill(true, false).colspan(2).row();

        final VisTextField fileField = new VisTextField();
        table.add(fileField).pad(PADDING).fill(true, false).colspan(2).row();

        VisTextButton save = new VisTextButton("Save");
        table.add(save).pad(PADDING).fill(true, false);

        VisTextButton cancel = new VisTextButton("Cancel");
        table.add(cancel).pad(PADDING).fill(true, false);

        saveWindow.add(table).expand().fill();
        saveWindow.getTitleLabel().setColor(Color.GRAY);

        save.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                super.clicked(event, x, y);

                if (!fileField.getText().isEmpty()) {
                    MapTools.exportMap(world, fileField.getText());
                    setSaveWindowVisible(false);
                }
            }
        });

        cancel.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                super.clicked(event, x, y);

                setSaveWindowVisible(false);
            }
        });
    }

    private void initLoadWindow() {
        final float PADDING = 2f;

        loadWindow.setWidth(SAVE_WINDOW_WIDTH);
        loadWindow.setHeight(SAVE_WINDOW_HEIGHT);
        loadWindow.setPosition(Gdx.graphics.getWidth() / 2f, Gdx.graphics.getHeight() / 2f, Align.center);

        importList = new VisList<FileListNode>();

        FileListNode[] maps = editor.getMaps();
        if (maps != null) {
            importList.setItems(maps);
        }

        final VisScrollPane scrollPane = new VisScrollPane(importList);
        scrollPane.setScrollingDisabled(true, false);
        scrollPane.setupFadeScrollBars(1f, 0.3f);
        scrollPane.setupOverscroll(20f, 30f, 200f);

        VisTable table = new VisTable();

        VisTextButton load = new VisTextButton("Load");
        table.add(load).pad(PADDING).expand().fill().align(Align.left);

        VisTextButton cancel = new VisTextButton("Cancel");
        table.add(cancel).pad(PADDING).fill();

        loadWindow.add(scrollPane).pad(PADDING).expand().fill(true, false).row();
        loadWindow.add(table).expand().fill(true, false);

        load.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                super.clicked(event, x, y);
                FileListNode selected = importList.getSelected();
                if (selected != null) {
                    String fileName = selected.file.getName();
                    String mapName = fileName.substring(0, fileName.length() - MapTools.EXTENSION.length());

                    editor.load(mapName);
                    setLoadWindowVisible(false);
                }
            }
        });

        cancel.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                super.clicked(event, x, y);
                setLoadWindowVisible(false);
            }
        });
    }

    private void initContextMenu() {
        contextMenu = new PopupMenu();

        contextMenu.addItem(new MenuItem("Add Entity from List", new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                editor.createNewEntity(EntityID.fromString(selectedItem), editor.getLastLMBClick());
                closeContextMenu();
            }
        }));
    }

    private void initMenuBar(final World world) {
        MenuBar menuBar = new MenuBar();
        final VisTable table = (VisTable) menuBar.getTable();
        table.setWidth(MENU_BAR_WIDTH);
        table.setHeight(MENU_BAR_HEIGHT);
        table.setPosition(LEFT_PANEL_WIDTH, Gdx.graphics.getHeight() - MENU_BAR_HEIGHT);

        Menu menu = new Menu("File");

        MenuItem clear = new MenuItem("Clear Map");
        menu.addItem(clear);

        MenuItem imp = new MenuItem("Import");
        menu.addItem(imp);

        MenuItem exp = new MenuItem("Export");
        menu.addItem(exp);

        MenuItem exit = new MenuItem("Exit to Main Menu");
        menu.addItem(exit);

        menuBar.addMenu(menu);
        table.addSeparator(true);

        table.add(new VisLabel("X: "));
        xField = new VisTextField("0.0");
        table.add(xField).width(MENU_BAR_WIDTH / 8f);
        table.addSeparator(true);

        table.add(new VisLabel("Y: "));
        yField = new VisTextField("0.0");
        table.add(yField).width(MENU_BAR_WIDTH / 8f);
        table.addSeparator(true);

        table.add(new VisLabel("Rotation: "));
        rotField = new VisTextField("0.0");
        table.add(rotField).width(MENU_BAR_WIDTH / 8f);
        table.addSeparator(true);

        table.add(new VisLabel("Scale: "));
        scaleField = new VisTextField("0.0");
        table.add(scaleField).width(MENU_BAR_WIDTH / 8f);
        table.addSeparator(true);

        clear.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                editor.clearMap();
            }
        });

        imp.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                setLoadWindowVisible(true);
            }
        });

        exp.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                setSaveWindowVisible(true);
            }
        });

        exit.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                // TODO: Throw warning window saying that changes won't be saved if they continue
                pt.setScene(Scene.MAIN_MENU);
            }
        });
        final PhysicsSystem physicsSystem = world.getSystem(PhysicsSystem.class);
        xField.setTextFieldFilter(new TransformTextFilter());
        xField.setTextFieldListener(new VisTextField.TextFieldListener() {
            @Override
            public void keyTyped(VisTextField textField, char c) {
                try {
                    float v = Float.parseFloat(textField.getText());
                    EditorTarget target = editor.getTarget();
                    if (target != null) {
                        Body body = physicsSystem.getBody(target.getEntity().getId());
                        if (body != null)
                            body.setTransform(v, body.getPosition().y, body.getAngle());
                        else
                            target.getEntity().getComponent(Position.class).position.x = v;
                    }
                } catch (NumberFormatException e) {
                    // meh
                }
            }
        });
        yField.setTextFieldFilter(new TransformTextFilter());
        yField.setTextFieldListener(new VisTextField.TextFieldListener() {
            @Override
            public void keyTyped(VisTextField textField, char c) {
                try {
                    float v = Float.parseFloat(textField.getText());
                    EditorTarget target = editor.getTarget();
                    if (target != null) {
                        Body body = physicsSystem.getBody(target.getEntity().getId());
                        if (body != null)
                            body.setTransform(body.getPosition().x, v, body.getAngle());
                        else
                            target.getEntity().getComponent(Position.class).position.y = v;
                    }
                } catch (NumberFormatException e) {
                    // meh
                }
            }
        });
        rotField.setTextFieldFilter(new TransformTextFilter());
        rotField.setTextFieldListener(new VisTextField.TextFieldListener() {
            @Override
            public void keyTyped(VisTextField textField, char c) {
                try {
                    float v = Float.parseFloat(textField.getText());
                    EditorTarget target = editor.getTarget();
                    if (target != null) {
                        Body body = physicsSystem.getBody(target.getEntity().getId());
                        if (body != null)
                            body.setTransform(body.getPosition().x, body.getPosition().y, MathUtils.degreesToRadians * v);
                        else
                            target.getEntity().getComponent(Rotation.class).angle = v;
                    }
                } catch (NumberFormatException e) {
                    // meh
                }
            }
        });
        scaleField.setTextFieldFilter(new TransformTextFilter());
        scaleField.setTextFieldListener(new VisTextField.TextFieldListener() {
            @Override
            public void keyTyped(VisTextField textField, char c) {
                try {
                    float v = Float.parseFloat(textField.getText());
                    EditorTarget target = editor.getTarget();
                    if (target != null)
                        target.getEntity().getComponent(Scale.class).scale = v; // TODO: rebuild colliders on resize
                } catch (NumberFormatException e) {
                    // meh
                }
            }
        });

        stage.addActor(menuBar.getTable());
    }

    private void initLeftPane() {
        VisList<String> entityList = new VisList<String>();
        entityList.setVisible(true);

        entityList.setItems(EntityID.getIDs());
        selectedItem = entityList.getItems().get(entityList.getSelectedIndex());
        final VisList<String> listRef = entityList;
        entityList.addListener(new ChangeListener() {
            @Override
            public void changed(ChangeEvent event, Actor actor) {
                selectedItem = listRef.getItems().get(listRef.getSelectedIndex());
            }
        });

        VisScrollPane scrollPane = new VisScrollPane(entityList);
        scrollPane.setVisible(true);
        scrollPane.setScrollingDisabled(true, false);
        scrollPane.setupFadeScrollBars(1f, 0.3f);
        scrollPane.setupOverscroll(20f, 30f, 200f);

        VisWindow leftPane = new VisWindow("Assets");
        leftPane.setWidth(LEFT_PANEL_WIDTH);
        leftPane.setHeight(LEFT_PANEL_HEIGHT);
        leftPane.clearListeners(); // disable interaction on window

        Cell<VisScrollPane> scrollCell = leftPane.add(scrollPane);
        scrollCell.align(Align.topLeft);
        stage.addActor(leftPane);
    }

    public void openContextMenu(Vector2 pos) {
        contextMenu.showMenu(stage, pos.x, pos.y);
    }

    private void closeContextMenu() {
        contextMenu.remove();
    }

    private void setSaveWindowVisible(boolean show) {
        if (show) {
            stage.addActor(saveWindow);
            saveWindow.fadeIn();
        } else
            saveWindow.fadeOut();

        editor.setMapInput(!show);
    }

    private void setLoadWindowVisible(boolean show) {
        if (show) {
            stage.addActor(loadWindow);
            importList.setItems(editor.getMaps());
            loadWindow.fadeIn();
        } else
            loadWindow.fadeOut();

        editor.setMapInput(!show);
    }

    public void updateTransform(Entity entity) {
        Vector2 pos = entity.getComponent(Position.class).position;
        float rot = entity.getComponent(Rotation.class).angle;
        float scale = entity.getComponent(Scale.class).scale;
        xField.setText(String.valueOf(pos.x));
        yField.setText(String.valueOf(pos.y));
        rotField.setText(String.valueOf(rot));
        scaleField.setText(String.valueOf(scale));
    }

    public void zeroizeTransform() {
        xField.setText("0.0");
        yField.setText("0.0");
        rotField.setText("0.0");
        scaleField.setText("0.0");
    }
}