/******************************************************************************* * Copyright 2014 Rafael Garcia Moreno. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.bladecoder.engineeditor.ui; import java.awt.Desktop; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle; import com.badlogic.gdx.scenes.scene2d.ui.Dialog; import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; import com.badlogic.gdx.scenes.scene2d.ui.ImageButton.ImageButtonStyle; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.scenes.scene2d.ui.TextTooltip; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Timer; import com.badlogic.gdx.utils.Timer.Task; import com.bladecoder.engine.util.Config; import com.bladecoder.engineeditor.Ctx; import com.bladecoder.engineeditor.common.EditorLogger; import com.bladecoder.engineeditor.common.Message; import com.bladecoder.engineeditor.common.RunProccess; import com.bladecoder.engineeditor.model.Project; import com.kotcrab.vis.ui.widget.file.FileChooser; import com.kotcrab.vis.ui.widget.file.FileChooser.Mode; import com.kotcrab.vis.ui.widget.file.FileChooser.SelectionMode; import com.kotcrab.vis.ui.widget.file.FileChooser.ViewMode; import com.kotcrab.vis.ui.widget.file.FileChooserListener; public class ProjectToolbar extends Table { private ImageButton newBtn; private ImageButton loadBtn; private ImageButton saveBtn; private ImageButton packageBtn; private ImageButton exitBtn; private ImageButton playBtn; private ImageButton assetsBtn; private ImageButton atlasBtn; private Skin skin; private FileChooser fileChooser; public ProjectToolbar(Skin skin) { super(skin); this.skin = skin; left(); newBtn = new ImageButton(skin); saveBtn = new ImageButton(skin); loadBtn = new ImageButton(skin); packageBtn = new ImageButton(skin); exitBtn = new ImageButton(skin); playBtn = new ImageButton(skin); assetsBtn = new ImageButton(skin); atlasBtn = new ImageButton(skin); fileChooser = new FileChooser(Mode.OPEN); fileChooser.setSize(Gdx.graphics.getWidth() * 0.7f, Gdx.graphics.getHeight() * 0.7f); fileChooser.setViewMode(ViewMode.LIST); addToolBarButton(skin, newBtn, "ic_new", "New", "Create a new project"); addToolBarButton(skin, loadBtn, "ic_load", "Load", "Load an existing project"); addToolBarButton(skin, saveBtn, "ic_save", "Save", "Save the current project"); addToolBarButton(skin, exitBtn, "ic_quit", "Exit", "Save changes and exits"); row(); addToolBarButton(skin, playBtn, "ic_play", "Play", "Play Adventure"); addToolBarButton(skin, packageBtn, "ic_package", "Package", "Package the game for distribution"); addToolBarButton(skin, assetsBtn, "ic_assets", "Assets", "Open assets folder"); addToolBarButton(skin, atlasBtn, "ic_atlases", "Atlas", "Create Atlas"); newBtn.setDisabled(false); loadBtn.setDisabled(false); exitBtn.setDisabled(false); newBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { saveProjectAndExecute(new Runnable() { @Override public void run() { newProject(); } }); } }); loadBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { saveProjectAndExecute(new Runnable() { @Override public void run() { loadProject(); } }); } }); exitBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { saveProjectAndExecute(new Runnable() { @Override public void run() { exit(); } }); } }); saveBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { saveProject(); } }); playBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { play(); } }); packageBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { packageProject(); } }); assetsBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { openAssetFolder(); } }); atlasBtn.addListener(new ChangeListener() { @Override public void changed(ChangeEvent event, Actor actor) { createAtlas(); } }); Ctx.project.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { saveBtn.setDisabled(!Ctx.project.isModified()); } }); Ctx.project.addPropertyChangeListener(Project.NOTIFY_PROJECT_LOADED, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent arg0) { packageBtn.setDisabled(Ctx.project.getProjectDir() == null); playBtn.setDisabled(Ctx.project.getProjectDir() == null); assetsBtn.setDisabled(Ctx.project.getProjectDir() == null); atlasBtn.setDisabled(Ctx.project.getProjectDir() == null); } }); } private void addToolBarButton(Skin skin, ImageButton button, String icon, String text, String tooltip) { ImageButtonStyle style = new ImageButtonStyle(skin.get(ButtonStyle.class)); TextureRegion image = Ctx.assetManager.getIcon(icon); style.imageUp = new TextureRegionDrawable(image); try { TextureRegion imageDisabled = Ctx.assetManager.getIcon(icon + "_disabled"); style.imageDisabled = new TextureRegionDrawable(imageDisabled); } catch (Exception e) { } button.setStyle(style); // button.row(); // button.add(new Label(text, skin)); add(button); button.setDisabled(true); TextTooltip t = new TextTooltip(tooltip, skin); button.addListener(t); } private void newProject() { CreateProjectDialog dialog = new CreateProjectDialog(skin); dialog.show(getStage()); } @Override public void act(float delta) { super.act(delta); } private void loadProject() { fileChooser.setSelectionMode(SelectionMode.DIRECTORIES); getStage().addActor(fileChooser); fileChooser.setListener(new FileChooserListener() { @Override public void selected(Array<FileHandle> files) { Message.showMsg(getStage(), "Loading project...", true); final File f = files.get(0).file(); Timer.post(new Task() { @Override public void run() { try { Ctx.project.loadProject(f); playBtn.setDisabled(false); packageBtn.setDisabled(false); Message.showMsg(getStage(), null); if (!Ctx.project.checkVersion()) { new Dialog("Update Engine", skin) { protected void result(Object object) { if (((Boolean) object).booleanValue()) { try { Ctx.project.updateEngineVersion(); Message.showMsg(getStage(), "Project successfully updated.", 3); } catch (IOException e1) { String msg = "Something went wrong while updating the engine.\n\n" + e1.getClass().getSimpleName() + " - " + e1.getMessage(); Message.showMsgDialog(getStage(), "Error", msg); EditorLogger.printStackTrace(e1); } } } }.text("Your game uses an old (" + Ctx.project.getProjectBladeEngineVersion() + ") Engine version. Do you want to update the engine?").button("Yes", true) .button("No", false).key(Keys.ENTER, true).key(Keys.ESCAPE, false) .show(getStage()); } } catch (Exception ex) { if (ex.getCause() != null && ex.getCause().getCause() != null && ex.getCause().getCause() instanceof ClassNotFoundException) { String msg = "The game have custom actions that can not be loaded. Probably the game needs to be compiled. Trying 'gradlew compile'..."; Message.showMsg(getStage(), msg, true); Timer.post(new Task() { @Override public void run() { if (RunProccess.runGradle(Ctx.project.getProjectDir(), "desktop:compileJava")) { try { Ctx.project.loadProject(f); playBtn.setDisabled(false); packageBtn.setDisabled(false); Message.showMsg(getStage(), "Project loaded Successfully", 3); } catch (IOException e) { String msg = e.getClass().getSimpleName() + " - " + e.getMessage(); Message.hideMsg(); Message.showMsgDialog(getStage(), "Error loading project", msg); } } else { Message.hideMsg(); Message.showMsgDialog(getStage(), "Error loading project", "error running 'gradlew desktop:compileJava'"); } } }); } else { String msg = ex.getClass().getSimpleName() + " - " + ex.getMessage(); Message.hideMsg(); Message.showMsgDialog(getStage(), "Error loading project", msg); } EditorLogger.printStackTrace(ex); } } }); } @Override public void canceled() { } }); } public void exit() { Gdx.app.exit(); } private void saveProject() { File file = Ctx.project.getProjectDir(); if (file == null) { String msg = "Please create a new project first."; Message.showMsg(getStage(), msg, 3); return; } try { Ctx.project.saveProject(); } catch (Exception ex) { String msg = "Something went wrong while saving the project.\n\n" + ex.getClass().getSimpleName() + " - " + ex.getMessage(); Message.showMsgDialog(getStage(), "Error saving project", msg); } } private void packageProject() { saveProject(); new PackageDialog(skin).show(getStage()); } private void play() { saveProject(); new Thread(new Runnable() { Stage stage = getStage(); @Override public void run() { if (Ctx.project.getSelectedScene() == null) { String msg = "There are no scenes in this chapter."; Message.showMsg(getStage(), msg, 3); return; } Ctx.project.getProjectConfig().remove(Config.CHAPTER_PROP); Ctx.project.getProjectConfig().remove(Config.TEST_SCENE_PROP); try { Ctx.project.saveProject(); } catch (Exception ex) { String msg = "Something went wrong while saving the project.\n\n" + ex.getClass().getSimpleName() + " - " + ex.getMessage(); Message.showMsgDialog(getStage(), "Error", msg); return; } Message.showMsg(stage, "Running scene...", 3); try { if (!RunProccess.runBladeEngine(Ctx.project.getProjectDir(), null, null)) Message.showMsg(getStage(), "There was a problem running the project", 3); } catch (IOException e) { Message.showMsgDialog(stage, "Error", "There was a problem running the project: " + e.getMessage()); } } }).start(); } private void openAssetFolder() { if (Desktop.isDesktopSupported()) { try { Desktop.getDesktop() .open(new File(Ctx.project.getProjectDir().getAbsoluteFile() + Project.ASSETS_PATH)); } catch (IOException e1) { String msg = "Something went wrong while opening assets folder.\n\n" + e1.getClass().getSimpleName() + " - " + e1.getMessage(); Message.showMsgDialog(getStage(), "Error", msg); } } } private void createAtlas() { new CreateAtlasDialog(skin).show(getStage()); } private void saveProjectAndExecute(final Runnable task) { if (Ctx.project.getProjectDir() != null && Ctx.project.isModified()) { new Dialog("Save Project", skin) { protected void result(Object object) { if (((Boolean) object).booleanValue()) { try { Ctx.project.saveProject(); } catch (IOException e1) { String msg = "Something went wrong while saving the actor.\n\n" + e1.getClass().getSimpleName() + " - " + e1.getMessage(); Message.showMsgDialog(getStage(), "Error", msg); EditorLogger.printStackTrace(e1); } } task.run(); } }.text("Save current project changes?").button("Yes", true).button("No", false).key(Keys.ENTER, true) .key(Keys.ESCAPE, false).show(getStage()); } else { task.run(); } } }