diff --git a/maps-basic/src/com/mobidevelop/maps/basic/BasicMap.java b/maps-basic/src/com/mobidevelop/maps/basic/BasicMap.java index 1b62775..76ace4e 100644 --- a/maps-basic/src/com/mobidevelop/maps/basic/BasicMap.java +++ b/maps-basic/src/com/mobidevelop/maps/basic/BasicMap.java @@ -1,6 +1,7 @@ package com.mobidevelop.maps.basic; import com.mobidevelop.maps.Map; +import com.mobidevelop.maps.MapLayer; import com.mobidevelop.maps.MapLayers; import com.mobidevelop.maps.MapProperties; import com.mobidevelop.maps.MapResources; @@ -110,5 +111,12 @@ public BasicMap(float x, float y, float width, float height) { public void dispose() { resources.dispose(); } - + + @Override + public MapLayer createLayer( String name ) { + + BasicMapLayer layer = new BasicMapLayer( this ); + layer.setName( name ); + return layer; + } } diff --git a/maps-basic/src/com/mobidevelop/maps/brush/ImageBrushMapObject.java b/maps-basic/src/com/mobidevelop/maps/brush/ImageBrushMapObject.java new file mode 100644 index 0000000..650b465 --- /dev/null +++ b/maps-basic/src/com/mobidevelop/maps/brush/ImageBrushMapObject.java @@ -0,0 +1,22 @@ +package com.mobidevelop.maps.brush; + +import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.basic.BasicMapObject; + + +public class ImageBrushMapObject extends BasicMapObject { + + private String imageName; + + public ImageBrushMapObject( MapLayer layer, float x, float y, String imageName ) { + + super( layer, x, y ); + + this.imageName = imageName; + } + + public String getImageName() { + + return imageName; + } +} diff --git a/maps-editor-android/assets/data/uiskin.atlas b/maps-editor-android/assets/data/uiskin.atlas index c193581..84d7f47 100644 --- a/maps-editor-android/assets/data/uiskin.atlas +++ b/maps-editor-android/assets/data/uiskin.atlas @@ -3,6 +3,35 @@ uiskin.png format: RGBA8888 filter: Nearest,Nearest repeat: none +check-off + rotate: false + xy: 11, 5 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield + rotate: false + xy: 11, 5 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-on + rotate: false + xy: 125, 35 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +cursor + rotate: false + xy: 23, 1 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 default rotate: false xy: 1, 50 @@ -10,51 +39,44 @@ default orig: 254, 77 offset: 0, 0 index: -1 -default-window - rotate: false - xy: 1, 20 - size: 27, 29 - split: 4, 3, 20, 3 - orig: 27, 29 - offset: 0, 0 - index: -1 -default-select +default-pane rotate: false - xy: 29, 29 - size: 27, 20 - split: 4, 14, 4, 4 - orig: 27, 20 + xy: 11, 1 + size: 5, 3 + split: 1, 1, 1, 1 + orig: 5, 3 offset: 0, 0 index: -1 -default-round-large +default-rect-pad rotate: false - xy: 57, 29 - size: 20, 20 - split: 5, 5, 5, 4 - orig: 20, 20 + xy: 11, 1 + size: 5, 3 + split: 1, 1, 1, 1 + orig: 5, 3 offset: 0, 0 index: -1 -default-scroll +default-pane-noborder rotate: false - xy: 78, 29 - size: 20, 20 - split: 2, 2, 2, 2 - orig: 20, 20 + xy: 129, 33 + size: 1, 1 + split: 0, 0, 0, 0 + orig: 1, 1 offset: 0, 0 index: -1 -default-slider-knob +default-rect rotate: false - xy: 1, 1 - size: 9, 18 - orig: 9, 18 + xy: 38, 25 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 offset: 0, 0 index: -1 -default-round-down +default-rect-down rotate: false - xy: 99, 29 - size: 12, 20 - split: 5, 5, 5, 4 - orig: 12, 20 + xy: 170, 46 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 offset: 0, 0 index: -1 default-round @@ -66,40 +88,44 @@ default-round orig: 12, 20 offset: 0, 0 index: -1 -check-off +default-round-down rotate: false - xy: 11, 5 - size: 14, 14 - orig: 14, 14 + xy: 99, 29 + size: 12, 20 + split: 5, 5, 5, 4 + orig: 12, 20 offset: 0, 0 index: -1 -textfield +default-round-large rotate: false - xy: 11, 5 - size: 14, 14 - split: 3, 3, 3, 3 - orig: 14, 14 + xy: 57, 29 + size: 20, 20 + split: 5, 5, 5, 4 + orig: 20, 20 offset: 0, 0 index: -1 -check-on +default-scroll rotate: false - xy: 125, 35 - size: 14, 14 - orig: 14, 14 + xy: 78, 29 + size: 20, 20 + split: 2, 2, 2, 2 + orig: 20, 20 offset: 0, 0 index: -1 -tree-minus +default-select rotate: false - xy: 140, 35 - size: 14, 14 - orig: 14, 14 + xy: 29, 29 + size: 27, 20 + split: 4, 14, 4, 4 + orig: 27, 20 offset: 0, 0 index: -1 -tree-plus +default-select-selection rotate: false - xy: 155, 35 - size: 14, 14 - orig: 14, 14 + xy: 26, 16 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 offset: 0, 0 index: -1 default-slider @@ -110,20 +136,11 @@ default-slider orig: 8, 8 offset: 0, 0 index: -1 -default-pane - rotate: false - xy: 11, 1 - size: 5, 3 - split: 1, 1, 1, 1 - orig: 5, 3 - offset: 0, 0 - index: -1 -default-rect-pad +default-slider-knob rotate: false - xy: 11, 1 - size: 5, 3 - split: 1, 1, 1, 1 - orig: 5, 3 + xy: 1, 1 + size: 9, 18 + orig: 9, 18 offset: 0, 0 index: -1 default-splitpane @@ -134,14 +151,6 @@ default-splitpane orig: 5, 3 offset: 0, 0 index: -1 -cursor - rotate: false - xy: 23, 1 - size: 3, 3 - split: 1, 1, 1, 1 - orig: 3, 3 - offset: 0, 0 - index: -1 default-splitpane-vertical rotate: false xy: 125, 29 @@ -150,43 +159,33 @@ default-splitpane-vertical orig: 3, 5 offset: 0, 0 index: -1 -default-rect-down - rotate: false - xy: 170, 46 - size: 3, 3 - split: 1, 1, 1, 1 - orig: 3, 3 - offset: 0, 0 - index: -1 -default-rect +default-window rotate: false - xy: 38, 25 - size: 3, 3 - split: 1, 1, 1, 1 - orig: 3, 3 + xy: 1, 20 + size: 27, 29 + split: 4, 3, 20, 3 + orig: 27, 29 offset: 0, 0 index: -1 -default-select-selection +selection rotate: false - xy: 26, 16 - size: 3, 3 - split: 1, 1, 1, 1 - orig: 3, 3 + xy: 170, 44 + size: 1, 1 + orig: 1, 1 offset: 0, 0 index: -1 -default-pane-noborder +tree-minus rotate: false - xy: 129, 33 - size: 1, 1 - split: 0, 0, 0, 0 - orig: 1, 1 + xy: 140, 35 + size: 14, 14 + orig: 14, 14 offset: 0, 0 index: -1 -selection +tree-plus rotate: false - xy: 170, 44 - size: 1, 1 - orig: 1, 1 + xy: 155, 35 + size: 14, 14 + orig: 14, 14 offset: 0, 0 index: -1 white diff --git a/maps-editor-android/assets/data/uiskin.json b/maps-editor-android/assets/data/uiskin.json index 551e3f5..2dd0a5a 100644 --- a/maps-editor-android/assets/data/uiskin.json +++ b/maps-editor-android/assets/data/uiskin.json @@ -39,7 +39,8 @@ com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: { default-horizontal: { background: default-slider, knob: default-slider-knob } }, com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: { - default: { font: default-font, fontColor: white } + default: { font: default-font, fontColor: white }, + selected: { background: selection, font: default-font, fontColor: white } }, com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: { default: { selection: selection, background: textfield, font: default-font, fontColor: white, cursor: cursor } diff --git a/maps-editor-android/assets/data/uiskin.png b/maps-editor-android/assets/data/uiskin.png index f51c5bd..336fff8 100644 Binary files a/maps-editor-android/assets/data/uiskin.png and b/maps-editor-android/assets/data/uiskin.png differ diff --git a/maps-editor/.classpath b/maps-editor/.classpath index 5ded48f..de9306d 100644 --- a/maps-editor/.classpath +++ b/maps-editor/.classpath @@ -1,9 +1,10 @@ - - - - - - - - - + + + + + + + + + + diff --git a/maps-editor/assets-raw/skin/check-off.png b/maps-editor/assets-raw/skin/check-off.png new file mode 100644 index 0000000..14b6512 Binary files /dev/null and b/maps-editor/assets-raw/skin/check-off.png differ diff --git a/maps-editor/assets-raw/skin/check-on.png b/maps-editor/assets-raw/skin/check-on.png new file mode 100644 index 0000000..5d21b76 Binary files /dev/null and b/maps-editor/assets-raw/skin/check-on.png differ diff --git a/maps-editor/assets-raw/skin/cursor.9.png b/maps-editor/assets-raw/skin/cursor.9.png new file mode 100644 index 0000000..aeed93c Binary files /dev/null and b/maps-editor/assets-raw/skin/cursor.9.png differ diff --git a/maps-editor/assets-raw/skin/default-pane-noborder.9.png b/maps-editor/assets-raw/skin/default-pane-noborder.9.png new file mode 100644 index 0000000..d2c3e66 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-pane-noborder.9.png differ diff --git a/maps-editor/assets-raw/skin/default-pane.9.png b/maps-editor/assets-raw/skin/default-pane.9.png new file mode 100644 index 0000000..6b3f904 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-pane.9.png differ diff --git a/maps-editor/assets-raw/skin/default-rect-down.9.png b/maps-editor/assets-raw/skin/default-rect-down.9.png new file mode 100644 index 0000000..81a63e0 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-rect-down.9.png differ diff --git a/maps-editor/assets-raw/skin/default-rect-pad.9.png b/maps-editor/assets-raw/skin/default-rect-pad.9.png new file mode 100644 index 0000000..6b3f904 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-rect-pad.9.png differ diff --git a/maps-editor/assets-raw/skin/default-rect.9.png b/maps-editor/assets-raw/skin/default-rect.9.png new file mode 100644 index 0000000..f1f5363 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-rect.9.png differ diff --git a/maps-editor/assets-raw/skin/default-round-down.9.png b/maps-editor/assets-raw/skin/default-round-down.9.png new file mode 100644 index 0000000..f1616a3 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-round-down.9.png differ diff --git a/maps-editor/assets-raw/skin/default-round-large.9.png b/maps-editor/assets-raw/skin/default-round-large.9.png new file mode 100644 index 0000000..ffc12fd Binary files /dev/null and b/maps-editor/assets-raw/skin/default-round-large.9.png differ diff --git a/maps-editor/assets-raw/skin/default-round.9.png b/maps-editor/assets-raw/skin/default-round.9.png new file mode 100644 index 0000000..adf9568 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-round.9.png differ diff --git a/maps-editor/assets-raw/skin/default-scroll.9.png b/maps-editor/assets-raw/skin/default-scroll.9.png new file mode 100644 index 0000000..832c1a3 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-scroll.9.png differ diff --git a/maps-editor/assets-raw/skin/default-select-selection.9.png b/maps-editor/assets-raw/skin/default-select-selection.9.png new file mode 100644 index 0000000..4649412 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-select-selection.9.png differ diff --git a/maps-editor/assets-raw/skin/default-select.9.png b/maps-editor/assets-raw/skin/default-select.9.png new file mode 100644 index 0000000..38b951a Binary files /dev/null and b/maps-editor/assets-raw/skin/default-select.9.png differ diff --git a/maps-editor/assets-raw/skin/default-slider-knob.png b/maps-editor/assets-raw/skin/default-slider-knob.png new file mode 100644 index 0000000..e03d374 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-slider-knob.png differ diff --git a/maps-editor/assets-raw/skin/default-slider.9.png b/maps-editor/assets-raw/skin/default-slider.9.png new file mode 100644 index 0000000..5d7a781 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-slider.9.png differ diff --git a/maps-editor/assets-raw/skin/default-splitpane-vertical.9.png b/maps-editor/assets-raw/skin/default-splitpane-vertical.9.png new file mode 100644 index 0000000..f6cffa3 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-splitpane-vertical.9.png differ diff --git a/maps-editor/assets-raw/skin/default-splitpane.9.png b/maps-editor/assets-raw/skin/default-splitpane.9.png new file mode 100644 index 0000000..bd72370 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-splitpane.9.png differ diff --git a/maps-editor/assets-raw/skin/default-window.9.png b/maps-editor/assets-raw/skin/default-window.9.png new file mode 100644 index 0000000..0db9e67 Binary files /dev/null and b/maps-editor/assets-raw/skin/default-window.9.png differ diff --git a/maps-editor/assets-raw/skin/default.png b/maps-editor/assets-raw/skin/default.png new file mode 100644 index 0000000..e203acc Binary files /dev/null and b/maps-editor/assets-raw/skin/default.png differ diff --git a/maps-editor/assets-raw/skin/pack.json b/maps-editor/assets-raw/skin/pack.json new file mode 100644 index 0000000..749d207 --- /dev/null +++ b/maps-editor/assets-raw/skin/pack.json @@ -0,0 +1,5 @@ +{ +duplicatePadding: false, +paddingX: 1, +paddingY: 1 +} \ No newline at end of file diff --git a/maps-editor/assets-raw/skin/selection.png b/maps-editor/assets-raw/skin/selection.png new file mode 100644 index 0000000..d2533cb Binary files /dev/null and b/maps-editor/assets-raw/skin/selection.png differ diff --git a/maps-editor/assets-raw/skin/textfield.9.png b/maps-editor/assets-raw/skin/textfield.9.png new file mode 100644 index 0000000..cb8ad31 Binary files /dev/null and b/maps-editor/assets-raw/skin/textfield.9.png differ diff --git a/maps-editor/assets-raw/skin/tree-minus.png b/maps-editor/assets-raw/skin/tree-minus.png new file mode 100644 index 0000000..f8e4079 Binary files /dev/null and b/maps-editor/assets-raw/skin/tree-minus.png differ diff --git a/maps-editor/assets-raw/skin/tree-plus.png b/maps-editor/assets-raw/skin/tree-plus.png new file mode 100644 index 0000000..85d23cc Binary files /dev/null and b/maps-editor/assets-raw/skin/tree-plus.png differ diff --git a/maps-editor/assets-raw/skin/white.png b/maps-editor/assets-raw/skin/white.png new file mode 100644 index 0000000..bbad125 Binary files /dev/null and b/maps-editor/assets-raw/skin/white.png differ diff --git a/maps-editor/src/BuildAssets.java b/maps-editor/src/BuildAssets.java new file mode 100644 index 0000000..4cef110 --- /dev/null +++ b/maps-editor/src/BuildAssets.java @@ -0,0 +1,11 @@ +import com.badlogic.gdx.tools.imagepacker.TexturePacker2; + + +public class BuildAssets { + + public static void main( String[] args ) { + +// Settings settings = new Settings(); + TexturePacker2.process( "assets-raw/skin", "../maps-editor-android/assets/data", "uiskin.atlas" ); + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/LevelStage.java b/maps-editor/src/com/mobidevelop/maps/editor/LevelStage.java new file mode 100644 index 0000000..0c2ce1f --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/LevelStage.java @@ -0,0 +1,227 @@ +package com.mobidevelop.maps.editor; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input.Buttons; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.g2d.PixmapPacker; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.math.Vector3; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.Group; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.utils.SnapshotArray; +import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.MapObject; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerAddedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerHiddenEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerRemovedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerSelectedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerShownEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapObjectsModel.ObjectAddedEvent; +import com.mobidevelop.maps.editor.ui.UIEvents; +import com.mobidevelop.utils.events.Event; +import com.mobidevelop.utils.events.EventDispatcher; +import com.mobidevelop.utils.events.EventListener; + + +public class LevelStage extends Stage implements EventListener { + + + private PixmapPacker imagePacker = null; + private TextureAtlas imageAtlas; + + private Group layers; + + private OrthographicCamera camera; + private Vector2 worldspaceCenter = new Vector2(); + int lastX, lastY; + Vector3 vec3 = new Vector3(); + + public LevelStage( float width, float height, SpriteBatch batch ) { + + super( width, height, true, batch ); + + // imagePacker packs added image resources into an atlas for stage rendering + imagePacker = new PixmapPacker( 1024, 1024, Format.RGBA8888, 2, false ); + imageAtlas = new TextureAtlas(); + + layers = new Group(); + addActor( layers ); + + camera = new OrthographicCamera( width, height ); + setCamera( camera ); + } + + // handles camera controls + @Override + public boolean touchDown( int screenX, int screenY, int pointer, int button ) { + + lastX = screenX; + lastY = screenY; + if ( Gdx.input.isButtonPressed( Buttons.LEFT ) ) { + Actor selected = layers.hit( screenX, screenY, false ); + if ( selected != null ) { + if ( selected instanceof StageObject ) + selected.fire( UIEvents.selectObject( ((StageObject)selected).getMapObject() ) ); + } + } + return super.touchDown( screenX, screenY, pointer, button ); + } + + // handles camera controls + @Override + public boolean touchDragged( int screenX, int screenY, int pointer ) { + + if ( Gdx.input.isButtonPressed( Buttons.RIGHT ) ) { + camera.position.sub( screenX - lastX, lastY - screenY, 0 ); + lastX = screenX; + lastY = screenY; + updateCamera(); + } + + return super.touchDragged( screenX, screenY, pointer ); + } + + // updates the camera and stores the stage center for use with MapObject addition to the stage + private void updateCamera() { + + camera.update(); + camera.unproject( vec3.set( 0.5f*Gdx.graphics.getWidth() + camera.position.x / Gdx.graphics.getWidth(), + 0.5f*Gdx.graphics.getHeight() + ( Gdx.graphics.getHeight() - camera.position.y ) / Gdx.graphics.getHeight(), 0 ) ); + worldspaceCenter.set( vec3.x, vec3.y ); + } + + public Vector2 getCenter() { + return worldspaceCenter; + } + + // adds an image brush to the stage, packing it into the atlas if not already there + public void addImageBrush( MapLayer layer, MapObject object, FileHandle file ) { + + // look for image in atlas, pack if not found + AtlasRegion image = imageAtlas.findRegion( file.name() ); + if ( image == null ) { + imagePacker.pack( file.name(), new Pixmap( file ) ); + imagePacker.updateTextureAtlas( imageAtlas, TextureFilter.Linear, TextureFilter.Linear, true ); + image = imageAtlas.findRegion( file.name() ); + } + + // add image to stage + ImageBrush brush = new ImageBrush( image, object ); + brush.setPosition( object.getX(), object.getY() ); + Group layerGroup = getLayerGroup( layer ); + if ( layerGroup != null ) + layerGroup.addActor( brush ); + } + + private LayerGroup getLayerGroup( MapLayer layer ) { + + SnapshotArray ls = layers.getChildren(); + for ( int i = 0; i < ls.size; i++ ) { + LayerGroup l = (LayerGroup)ls.get( i ); + if ( layer == l.getLayer() ) + return l; + } + return null; + } + + @Override + public void dispose() { + + super.dispose(); + imagePacker.dispose(); + } + + @Override + public void onEvent( EventDispatcher dispatcher, Event event ) { + + // model added a layer + if ( event instanceof LayerAddedEvent ) { + LayerAddedEvent evt = (LayerAddedEvent)event; + LayerGroup layer = new LayerGroup( evt.layer ); + layer.setName( evt.layer.getName() ); + layers.addActor( layer ); + return; + } + + // model removed a layer + if ( event instanceof LayerRemovedEvent ) { + LayerRemovedEvent evt = (LayerRemovedEvent)event; + LayerGroup layer = getLayerGroup( evt.layer ); + if ( layer != null ) + layer.remove(); + return; + } + + // model changed selected layer + if ( event instanceof LayerSelectedEvent ) { + return; + } + + // model hid layer + if ( event instanceof LayerHiddenEvent ) { + LayerHiddenEvent evt = (LayerHiddenEvent)event; + LayerGroup layer = getLayerGroup( evt.layer ); + if ( layer != null ) + layer.setVisible( false ); + return; + } + + // model showed layer + if ( event instanceof LayerShownEvent ) { + LayerShownEvent evt = (LayerShownEvent)event; + LayerGroup layer = getLayerGroup( evt.layer ); + if ( layer != null ) + layer.setVisible( true ); + return; + } + + // model added an image brush + if ( event instanceof ObjectAddedEvent ) { + ObjectAddedEvent evt = (ObjectAddedEvent)event; + addImageBrush( evt.layer, evt.object, evt.file ); + } + } + + public class LayerGroup extends Group { + + private MapLayer layer; + public LayerGroup( MapLayer layer ) { + + this.layer = layer; + } + + public MapLayer getLayer() { + + return layer; + } + } + + public interface StageObject { + public MapObject getMapObject(); + } + + public class ImageBrush extends Image implements StageObject { + + private MapObject object; + + public ImageBrush( AtlasRegion image, MapObject object ) { + + super( image ); + this.object = object; + } + + @Override + public MapObject getMapObject() { + return object; + } + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/MapEditor.java b/maps-editor/src/com/mobidevelop/maps/editor/MapEditor.java index 875c6b4..a4f41ee 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/MapEditor.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/MapEditor.java @@ -17,31 +17,267 @@ package com.mobidevelop.maps.editor; import com.badlogic.gdx.ApplicationListener; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.InputMultiplexer; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.GL10; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.Event; +import com.badlogic.gdx.scenes.scene2d.EventListener; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.SplitPane; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.utils.Align; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Disposable; +import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.MapObject; +import com.mobidevelop.maps.basic.BasicMap; +import com.mobidevelop.maps.brush.ImageBrushMapObject; +import com.mobidevelop.maps.editor.models.MapModels.MapModel; +import com.mobidevelop.maps.editor.ui.FileDialog; +import com.mobidevelop.maps.editor.ui.ImagePicker; +import com.mobidevelop.maps.editor.ui.LayerList; +import com.mobidevelop.maps.editor.ui.SlideWindow; +import com.mobidevelop.maps.editor.ui.UIEvents; +import com.mobidevelop.maps.editor.ui.UIEvents.FileEvent; +import com.mobidevelop.maps.editor.ui.UIEvents.LayerEvent; +import com.mobidevelop.maps.editor.ui.UIEvents.MapObjectEvent; +import com.mobidevelop.maps.editor.ui.UIEvents.UIEvent; -public class MapEditor implements ApplicationListener { +public class MapEditor implements ApplicationListener, EventListener { + + private SpriteBatch batch; + + private Skin skin; + private Stage uiStage; + private LevelStage worldViewport; + + private SlideWindow fileWindow; + private SlideWindow imageWindow; + + private ImagePicker imagePicker; + private LayerList layerList; + private FileDialog fileDialog; + + private MapModel mapModel; + + private Array trash; + + private String projectImagePath; @Override public void create() { + + float w = Gdx.graphics.getWidth(); + float h = Gdx.graphics.getHeight(); + + batch = new SpriteBatch(); + skin = new Skin( Gdx.files.internal( "data/uiskin.json" ) ); + + fileDialog = new FileDialog( "Set Image Path...", Gdx.files.external( "" ), skin ); + + // File Window ******************************************************************************** + + final TextButton openProjectButton = new TextButton( "Set Image Path", skin ); + openProjectButton.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + + fileDialog.editFileName( false ); + uiStage.addActor( fileDialog ); + super.clicked( event, x, y ); + } + } ); + fileWindow = new SlideWindow( skin, Align.top, 10, 200 ); + fileWindow.add( openProjectButton ); + + // Image Window ******************************************************************************* + // holds the image picker and layer list + + imagePicker = new ImagePicker( skin ); + layerList = new LayerList( skin ); + Table pickerTable = new Table(); + pickerTable.add( imagePicker ).pad( 10 ); + Table layerTable = new Table(); + layerTable.add( layerList ).pad( 10 ); + SplitPane splitPane = new SplitPane( pickerTable, layerTable, true, skin ); + imageWindow = new SlideWindow( skin, Align.right, 10, 200 ); + imageWindow.add( splitPane ).expand().fill().pad( 10 ); + + // UI Stage *********************************************************************************** + // holds the menu overlay, with sliding windows for different tool palettes + + uiStage = new Stage( w, h, true, batch ){ + @Override + public boolean touchDown( int screenX, int screenY, int pointer, int button ) { + + if ( screenY < 20 ) + fileWindow.showWindow(); + else if ( screenX > Gdx.graphics.getWidth() - 20 ) + imageWindow.showWindow(); + + return super.touchDown( screenX, screenY, pointer, button ); + } + }; + uiStage.addListener( this ); + uiStage.addActor( fileWindow ); + uiStage.addActor( imageWindow ); + + // World Viewport ***************************************************************************** + // the stage where the map is drawn + + worldViewport = new LevelStage( w, h, batch ); + + createNewMap(); + + Gdx.input.setInputProcessor( new InputMultiplexer( uiStage, worldViewport ) ); + + trash = new Array(); + trash.add( imagePicker ); + trash.add( batch ); + trash.add( skin ); + trash.add( uiStage ); + trash.add( worldViewport ); + + loadSettings(); + } + + private void createNewMap() { + + mapModel = new MapModel( new BasicMap() ); + mapModel.addEventListener( worldViewport ); + mapModel.addEventListener( layerList ); + + // add default layer + mapModel.addLayer(); + mapModel.setCurrentLayer( mapModel.currentLayer() ); } @Override public void pause() { + + saveSettings(); } @Override public void resume() { } - + + private void loadSettings() { + + Settings.load(); + projectImagePath = Settings.getLastImagePath(); + if ( projectImagePath != null ) + imagePicker.loadProjectImages( Gdx.files.external( projectImagePath ) ); + } + + private void saveSettings() { + + Settings.setLastImagePath( projectImagePath ); + Settings.save(); + } + @Override - public void resize(int width, int height) { + public void resize( int width, int height ) { } @Override public void render() { + + Gdx.gl.glClearColor( 0, 0, 0, 1 ); + Gdx.gl.glClear( GL10.GL_COLOR_BUFFER_BIT ); + + worldViewport.act(); + worldViewport.draw(); + + uiStage.act(); + uiStage.draw(); } @Override public void dispose() { + + for ( int i = 0; i < trash.size; i++ ) { + Disposable d = trash.get( i ); + if ( d != null ) + d.dispose(); + } + trash.clear(); } + /** + * handles events sent by ui components to interact with the model + */ + @Override + public boolean handle( Event event ) { + + if ( event instanceof UIEvent ) { + + MapLayer layer; + MapObject mapObject; + switch ( ((UIEvent)event).type ) { + case UIEvents.EV_ADD_LAYER: + mapModel.addLayer(); + break; + + case UIEvents.EV_REMOVE_LAYER: + // can't remove last layer + if ( mapModel.numLayers() > 1 ) + mapModel.removeLayer( mapModel.currentLayer() ); + break; + + case UIEvents.EV_SELECT_LAYER: + layer = ((LayerEvent)event).layer; + mapModel.setCurrentLayer( layer ); + break; + + case UIEvents.EV_HIDE_LAYER: + layer = ((LayerEvent)event).layer; + mapModel.hideLayer( layer ); + break; + + case UIEvents.EV_SHOW_LAYER: + layer = ((LayerEvent)event).layer; + mapModel.showLayer( layer ); + break; + + case UIEvents.EV_ADD_IMAGE: + FileEvent eai = (FileEvent)event; + FileHandle file = eai.file; + layer = mapModel.currentLayer(); + Vector2 v = worldViewport.getCenter(); + mapModel.addImageBrush( layer, new ImageBrushMapObject( layer, v.x, v.y, file.name() ), file ); + break; + + case UIEvents.EV_SELECT_MAP_OBJECT: + MapObjectEvent moe = (MapObjectEvent)event; + mapObject = moe.object; + break; + + case UIEvents.EV_SELECT_IMAGE_PATH: + FileEvent esip = (FileEvent)event; + + // ensure folder + FileHandle folder = esip.file; + if ( !folder.isDirectory() ) + folder = folder.parent(); + + projectImagePath = folder.path(); + imagePicker.loadProjectImages( esip.file ); + break; + + default: + break; + } + return true; + } + + return false; + } } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/Settings.java b/maps-editor/src/com/mobidevelop/maps/editor/Settings.java new file mode 100644 index 0000000..de351f5 --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/Settings.java @@ -0,0 +1,27 @@ +package com.mobidevelop.maps.editor; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Preferences; + + +public class Settings { + + private static Preferences prefs; + + public static void load() { + prefs = Gdx.app.getPreferences( "settings" ); + } + + public static void save() { + if ( prefs != null ) + prefs.flush(); + } + + public static String getLastImagePath() { + return prefs.getString( "lastImagePath" ); + } + + public static void setLastImagePath( String imagePath ) { + prefs.putString( "lastImagePath", imagePath ); + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapCommands.java b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapCommands.java index e3274cb..16fa567 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapCommands.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapCommands.java @@ -18,6 +18,7 @@ import com.mobidevelop.maps.Map; import com.mobidevelop.utils.commands.Command; +import com.mobidevelop.utils.events.Event; public class MapCommands { @@ -50,15 +51,17 @@ public MoveMapCommand(Map map, float newX, float newY) { } @Override - public void execute() { + public Event execute() { map.setX(newX); - map.setY(newY); + map.setY(newY); + return null; } @Override - public void reverse() { + public Event reverse() { map.setX(oldX); map.setY(oldY); + return null; } } @@ -80,15 +83,17 @@ public ResizeMapCommand(Map map, int newWidth, int newHeight) { } @Override - public void execute() { + public Event execute() { map.setWidth(newWidth); - map.setHeight(newHeight); + map.setHeight(newHeight); + return null; } @Override - public void reverse() { + public Event reverse() { map.setWidth(oldWidth); map.setHeight(oldHeight); + return null; } } @@ -106,13 +111,15 @@ public RenameMapCommand(Map map, String newName) { } @Override - public void execute() { + public Event execute() { map.setName(newName); + return null; } @Override - public void reverse() { + public Event reverse() { map.setName(oldName); + return null; } } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayerCommands.java b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayerCommands.java index 9903d2b..6c60b7a 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayerCommands.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayerCommands.java @@ -17,7 +17,10 @@ package com.mobidevelop.maps.editor.commands; import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerHiddenEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerShownEvent; import com.mobidevelop.utils.commands.Command; +import com.mobidevelop.utils.events.Event; public final class MapLayerCommands { @@ -27,6 +30,10 @@ public static HideLayerCommand hide(MapLayer layer) { return new HideLayerCommand(layer); } + public static ShowLayerCommand show(MapLayer layer) { + return new ShowLayerCommand(layer); + } + public static MoveLayerCommand move(MapLayer layer, int newX, int newY) { return new MoveLayerCommand(layer, newX, newY); } @@ -39,10 +46,6 @@ public static RenameLayerCommand rename(MapLayer layer, String newName) { return new RenameLayerCommand(layer, newName); } - public static ShowLayerCommand show(MapLayer layer) { - return new ShowLayerCommand(layer); - } - public static class HideLayerCommand implements Command { private MapLayer layer; @@ -52,17 +55,39 @@ public HideLayerCommand(MapLayer layer) { } @Override - public void execute() { + public Event execute() { layer.setVisible(false); + return new LayerHiddenEvent( layer ); } @Override - public void reverse() { + public Event reverse() { layer.setVisible(true); + return new LayerShownEvent( layer ); + } + } + + public static class ShowLayerCommand implements Command { + + private MapLayer layer; + + public ShowLayerCommand(MapLayer layer) { + this.layer = layer; } + @Override + public Event execute() { + layer.setVisible(true); + return new LayerShownEvent( layer ); + } + + @Override + public Event reverse() { + layer.setVisible(false); + return new LayerHiddenEvent( layer ); + } } - + public static class MoveLayerCommand implements Command { private MapLayer layer; @@ -80,15 +105,17 @@ public MoveLayerCommand(MapLayer layer, int newX, int newY) { } @Override - public void execute() { + public Event execute() { layer.setX(newX); - layer.setY(newY); + layer.setY(newY); + return null; } @Override - public void reverse() { + public Event reverse() { layer.setX(oldX); layer.setY(oldY); + return null; } } @@ -110,15 +137,17 @@ public ResizeLayerCommand(MapLayer layer, int newWidth, int newHeight) { } @Override - public void execute() { + public Event execute() { layer.setWidth(newWidth); - layer.setHeight(newHeight); + layer.setHeight(newHeight); + return null; } @Override - public void reverse() { + public Event reverse() { layer.setWidth(oldWidth); layer.setHeight(oldHeight); + return null; } } @@ -136,35 +165,16 @@ public RenameLayerCommand(MapLayer layer, String newName) { } @Override - public void execute() { + public Event execute() { layer.setName(newName); + return null; } @Override - public void reverse() { + public Event reverse() { layer.setName(oldName); + return null; } } - - public static class ShowLayerCommand implements Command { - - private MapLayer layer; - - public ShowLayerCommand(MapLayer layer) { - this.layer = layer; - } - - @Override - public void execute() { - layer.setVisible(true); - } - - @Override - public void reverse() { - layer.setVisible(false); - } - - } - } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayersCommands.java b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayersCommands.java index 9b7b94b..89cd8f3 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayersCommands.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapLayersCommands.java @@ -19,14 +19,18 @@ import com.mobidevelop.maps.Map; import com.mobidevelop.maps.MapLayer; import com.mobidevelop.maps.MapLayers; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerAddedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerRemovedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerSwappedEvent; import com.mobidevelop.utils.commands.Command; +import com.mobidevelop.utils.events.Event; final public class MapLayersCommands { private MapLayersCommands() { } - public static AddLayerCommand add(Map map, MapLayer layer) { - return new AddLayerCommand(map, layer); + public static AddLayerCommand add(Map map, String layerName) { + return new AddLayerCommand(map, layerName); } public static InsertLayerCommand insert(Map map, int index, MapLayer layer) { @@ -43,23 +47,26 @@ public static SwapLayersCommand swap(Map map, MapLayer layer1, MapLayer layer2) public static class AddLayerCommand implements Command { private Map map; + private String layerName; private MapLayer layer; - public AddLayerCommand(Map map, MapLayer layer) { + public AddLayerCommand(Map map, String name) { this.map = map; - this.layer = layer; + this.layerName = name; } @Override - public void execute() { - map.getLayers().addLayer(layer); + public Event execute() { + layer = map.createLayer( layerName ); + map.getLayers().addLayer( layer ); + return new LayerAddedEvent( layer ); } @Override - public void reverse() { - map.getLayers().removeLayer(layer); + public Event reverse() { + map.getLayers().removeLayer( layer ); + return new LayerRemovedEvent( layer ); } - } public static class InsertLayerCommand implements Command { @@ -76,13 +83,15 @@ public InsertLayerCommand(Map map, int index, MapLayer layer) { } @Override - public void execute() { + public Event execute() { map.getLayers().addLayer(index, layer); + return null; } @Override - public void reverse() { + public Event reverse() { map.getLayers().removeLayer(layer); + return null; } } @@ -98,17 +107,20 @@ public RemoveLayerCommand(Map map, MapLayer layer) { this.map = map; this.layer = layer; } - + @Override - public void execute() { + public Event execute() { MapLayers layers = map.getLayers(); - index = layers.getIndex(layer); - layers.removeLayer(index); + index = layers.getIndex( layer ); + layers.removeLayer( layer ); + return new LayerRemovedEvent( layer ); } + @Override - public void reverse() { + public Event reverse() { MapLayers layers = map.getLayers(); - layers.addLayer(index, layer); + layers.addLayer( index, layer ); + return new LayerAddedEvent( layer ); } } @@ -130,15 +142,17 @@ public SwapLayersCommand(Map map, MapLayer layer1, MapLayer layer2) { this.layer1 = layer1; this.layer2 = layer2; } - + @Override - public void execute() { - map.getLayers().swapLayers(layer1, layer2); + public Event execute() { + map.getLayers().swapLayers( layer1, layer2 ); + return new LayerSwappedEvent( layer1, layer2 ); } @Override - public void reverse() { + public Event reverse() { map.getLayers().swapLayers(layer1, layer2); + return new LayerSwappedEvent( layer1, layer2 ); } } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectCommands.java b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectCommands.java index 0e74cd6..25c25dc 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectCommands.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectCommands.java @@ -18,6 +18,7 @@ import com.mobidevelop.maps.MapObject; import com.mobidevelop.utils.commands.Command; +import com.mobidevelop.utils.events.Event; public final class MapObjectCommands { @@ -27,11 +28,11 @@ public static HideObjectCommand hide(MapObject object) { return new HideObjectCommand(object); } - public static MoveObjectCommand move(MapObject object, int newX, int newY) { + public static MoveObjectCommand move(MapObject object, float newX, float newY) { return new MoveObjectCommand(object, newX, newY); } - public static ResizeObjectCommand resize(MapObject object, int newWidth, int newHeight) { + public static ResizeObjectCommand resize(MapObject object, float newWidth, float newHeight) { return new ResizeObjectCommand(object, newWidth, newHeight); } @@ -52,13 +53,15 @@ public HideObjectCommand(MapObject object) { } @Override - public void execute() { + public Event execute() { object.setVisible(false); + return null; } @Override - public void reverse() { + public Event reverse() { object.setVisible(true); + return null; } } @@ -71,7 +74,7 @@ public static class MoveObjectCommand implements Command { private float newX; private float newY; - public MoveObjectCommand(MapObject object, int newX, int newY) { + public MoveObjectCommand(MapObject object, float newX, float newY) { this.object = object; this.oldX = object.getX(); this.oldY = object.getY(); @@ -80,15 +83,17 @@ public MoveObjectCommand(MapObject object, int newX, int newY) { } @Override - public void execute() { + public Event execute() { object.setX(newX); - object.setY(newY); + object.setY(newY); + return null; } @Override - public void reverse() { + public Event reverse() { object.setX(oldX); object.setY(oldY); + return null; } } @@ -101,7 +106,7 @@ public static class ResizeObjectCommand implements Command { private float newWidth; private float newHeight; - public ResizeObjectCommand(MapObject object, int newWidth, int newHeight) { + public ResizeObjectCommand(MapObject object, float newWidth, float newHeight) { this.object = object; this.oldWidth = object.getWidth(); this.oldHeight = object.getHeight(); @@ -110,15 +115,17 @@ public ResizeObjectCommand(MapObject object, int newWidth, int newHeight) { } @Override - public void execute() { + public Event execute() { object.setWidth(newWidth); object.setHeight(newHeight); + return null; } @Override - public void reverse() { + public Event reverse() { object.setWidth(oldWidth); object.setHeight(oldHeight); + return null; } } @@ -136,13 +143,15 @@ public RenameObjectCommand(MapObject object, String newName) { } @Override - public void execute() { + public Event execute() { object.setName(newName); + return null; } @Override - public void reverse() { + public Event reverse() { object.setName(oldName); + return null; } } @@ -156,13 +165,15 @@ public ShowObjectCommand(MapObject object) { } @Override - public void execute() { + public Event execute() { object.setVisible(true); + return null; } @Override - public void reverse() { + public Event reverse() { object.setVisible(false); + return null; } } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectsCommands.java b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectsCommands.java index bbb70a3..fe1b645 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectsCommands.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/commands/MapObjectsCommands.java @@ -16,25 +16,30 @@ package com.mobidevelop.maps.editor.commands; +import com.badlogic.gdx.files.FileHandle; import com.mobidevelop.maps.MapLayer; import com.mobidevelop.maps.MapObject; import com.mobidevelop.maps.MapObjects; +import com.mobidevelop.maps.editor.models.MapModels.MapObjectsModel.ObjectAddedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapObjectsModel.ObjectRemovedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapObjectsModel.ObjectSwappedEvent; import com.mobidevelop.utils.commands.Command; +import com.mobidevelop.utils.events.Event; public final class MapObjectsCommands { private MapObjectsCommands() { } - public static AddObjectCommand add(MapLayer layer, MapObject object) { - return new AddObjectCommand(layer, object); + public static AddObjectCommand add(MapLayer layer, MapObject object, FileHandle file) { + return new AddObjectCommand(layer, object, file); } public static InsertObjectCommand insert(MapLayer layer, int index, MapObject object) { return new InsertObjectCommand(layer, index, object); } - public static RemoveObjectCommand remove(MapLayer layer, MapObject object) { - return new RemoveObjectCommand(layer, object); + public static RemoveObjectCommand remove(MapLayer layer, MapObject object, FileHandle file) { + return new RemoveObjectCommand(layer, object, file); } public static SwapObjectsCommand swap(MapLayer layer, MapObject object1, MapObject object2) { @@ -45,20 +50,24 @@ public static class AddObjectCommand implements Command { private MapLayer layer; private MapObject object; + private FileHandle file; - public AddObjectCommand(MapLayer layer, MapObject object) { + public AddObjectCommand(MapLayer layer, MapObject object, FileHandle file) { this.layer = layer; this.object = object; + this.file = file; } @Override - public void execute() { + public Event execute() { layer.getObjects().addObject(object); + return new ObjectAddedEvent( layer, object, file ); } @Override - public void reverse() { + public Event reverse() { layer.getObjects().removeObject(object); + return new ObjectRemovedEvent( layer, object ); } } @@ -77,13 +86,15 @@ public InsertObjectCommand(MapLayer layer, int index, MapObject object) { } @Override - public void execute() { + public Event execute() { layer.getObjects().addObject(index, object); + return null; } @Override - public void reverse() { + public Event reverse() { layer.getObjects().removeObject(object); + return null; } } @@ -91,26 +102,29 @@ public void reverse() { public static class RemoveObjectCommand implements Command { private MapLayer layer; - private MapObject object; + private FileHandle file; private int index; - public RemoveObjectCommand(MapLayer layer, MapObject object) { + public RemoveObjectCommand(MapLayer layer, MapObject object, FileHandle file ) { this.layer = layer; this.object = object; + this.file = file; } @Override - public void execute() { + public Event execute() { MapObjects objects = layer.getObjects(); index = objects.getIndex(object); objects.removeObject(index); + return new ObjectRemovedEvent( layer, object ); } @Override - public void reverse() { + public Event reverse() { MapObjects objects = layer.getObjects(); objects.addObject(index, object); + return new ObjectAddedEvent( layer, object, file ); } } @@ -135,14 +149,16 @@ public SwapObjectsCommand(MapLayer layer, MapObject object1, MapObject object2) } @Override - public void execute() { + public Event execute() { layer.getObjects().swapObjects(object1, object2); + return new ObjectSwappedEvent( object1, object2 ); } @Override - public void reverse() { + public Event reverse() { layer.getObjects().swapObjects(object1, object2); + return new ObjectSwappedEvent( object1, object2 ); } - + } } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/models/MapModels.java b/maps-editor/src/com/mobidevelop/maps/editor/models/MapModels.java index ffad80f..44abc12 100644 --- a/maps-editor/src/com/mobidevelop/maps/editor/models/MapModels.java +++ b/maps-editor/src/com/mobidevelop/maps/editor/models/MapModels.java @@ -19,8 +19,13 @@ import java.util.ArrayList; import java.util.List; +import com.badlogic.gdx.files.FileHandle; import com.mobidevelop.maps.Map; import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.MapObject; +import com.mobidevelop.maps.editor.commands.MapLayerCommands; +import com.mobidevelop.maps.editor.commands.MapLayersCommands; +import com.mobidevelop.maps.editor.commands.MapObjectsCommands; import com.mobidevelop.utils.commands.CommandManager; import com.mobidevelop.utils.events.Event; import com.mobidevelop.utils.events.EventDispatcher; @@ -87,8 +92,20 @@ public static class MapModel extends Model { public MapModel(Map map) { this.map = map; + commands = new CommandManager( this ); + layersModel = new MapLayersModel( this ); + objectsModel = new MapObjectsModel( this ); } + + @Override + public void addEventListener( EventListener listener ) { + super.addEventListener( listener ); + + layersModel.addEventListener( listener ); + objectsModel.addEventListener( listener ); + } + public String getFile() { return file; } @@ -103,43 +120,174 @@ public boolean save() { public boolean saveAs(String file) { return false; } - - } + + public void addLayer() { + layersModel.addLayer(); + } + public void removeLayer( MapLayer layer ) { + // deleting current layer, set layer to next nearest + if ( layersModel.getCurrentLayer() == layer ) { + int index = map.getLayers().getIndex( layer ) - 1; + if ( index < 0 ) + index = 1; + MapLayer nextLayer = map.getLayers().getLayer( index ); + layersModel.setCurrentLayer( nextLayer ); + } + layersModel.removeLayer( layer ); + } + + public MapLayer currentLayer() { + return layersModel.getCurrentLayer(); + } + + public int numLayers() { + + return map.getLayers().getCount(); + } + + public void addImageBrush( MapLayer layer, MapObject object, FileHandle file ) { + + objectsModel.add( layer, object, file ); + } + + public void setCurrentLayer( MapLayer layer ) { + + layersModel.setCurrentLayer( layer ); + } + + public void showLayer( MapLayer layer ) { + + layersModel.hideLayer( layer ); + } + + public void hideLayer( MapLayer layer ) { + + layersModel.showLayer( layer ); + } + } + public static class MapLayersModel extends Model { private MapModel model; + private int currentLayer = 0; + private int lastCreatedLayer = 0; - public MapLayersModel() { - + public MapLayersModel(MapModel mapModel) { + + setMapModel( mapModel ); } + public void setCurrentLayer( MapLayer layer ) { + + currentLayer = model.map.getLayers().getIndex( layer ); + dispatchEvent( new LayerSelectedEvent( layer ) ); + } + + public MapLayer getCurrentLayer() { + + return this.model.map.getLayers().getLayer( currentLayer ); + } + public void setMapModel(MapModel model) { this.model = model; } - - public void addLayer(MapLayer layer) { - this.model.map.getLayers().addLayer(layer); - this.dispatchEvent(new LayerAddedEvent()); + + public void addLayer() { + model.commands.execute( MapLayersCommands.add( model.map, "Layer " + ++lastCreatedLayer ) ); } public void removeLayer(MapLayer layer) { - this.model.map.getLayers().removeLayer(layer); - this.dispatchEvent(new LayerRemovedEvent()); + model.commands.execute( MapLayersCommands.remove( model.map, layer ) ); } - - public static class LayerAddedEvent extends Event { - + + public void hideLayer( MapLayer layer ) { + model.commands.execute( MapLayerCommands.hide( layer ) ); } - public static class LayerRemovedEvent extends Event { - + + public void showLayer( MapLayer layer ) { + model.commands.execute( MapLayerCommands.show( layer ) ); + } + + public static class LayerEvent extends Event { + public MapLayer layer; + public LayerEvent( MapLayer layer ) { + this.layer = layer; + } + } + public static class LayerAddedEvent extends LayerEvent { + public LayerAddedEvent( MapLayer layer ) { super( layer ); } + } + public static class LayerRemovedEvent extends LayerEvent { + public LayerRemovedEvent( MapLayer layer ) { super( layer ); } + } + public static class LayerSelectedEvent extends LayerEvent { + public LayerSelectedEvent( MapLayer layer ) { super( layer ); } + } + public static class LayerSwappedEvent extends LayerEvent { + public MapLayer layer2; + public LayerSwappedEvent( MapLayer layer, MapLayer layer2 ) { + super( layer ); + this.layer2 = layer2; + } + } + public static class LayerHiddenEvent extends LayerEvent { + public LayerHiddenEvent( MapLayer layer ) { super( layer ); } + } + public static class LayerShownEvent extends LayerEvent { + public LayerShownEvent( MapLayer layer ) { super( layer ); } } } - + public static class MapObjectsModel extends Model { - private MapLayer model; - + private MapModel model; + + public MapObjectsModel( MapModel mapModel ) { + + setMapModel( mapModel ); + } + + public void setMapModel(MapModel model) { + this.model = model; + } + + public void add( MapLayer layer, MapObject mapObject, FileHandle file ) { + + model.commands.execute( MapObjectsCommands.add( layer, mapObject, file ) ); + } + + public static class ObjectAddedEvent extends Event { + + public MapLayer layer; + public MapObject object; + public FileHandle file; + public ObjectAddedEvent( MapLayer layer, MapObject object, FileHandle file ) { + + this.layer = layer; + this.object = object; + this.file = file; + } + } + public static class ObjectRemovedEvent extends Event { + + public MapLayer layer; + public MapObject object; + public ObjectRemovedEvent( MapLayer layer, MapObject object ) { + + this.layer = layer; + this.object = object; + } + } + public static class ObjectSwappedEvent extends Event { + + public MapObject object1; + public MapObject object2; + public ObjectSwappedEvent( MapObject object1, MapObject object2 ) { + + this.object1 = object1; + this.object2 = object2; + } + } } - } diff --git a/maps-editor/src/com/mobidevelop/maps/editor/ui/FileDialog.java b/maps-editor/src/com/mobidevelop/maps/editor/ui/FileDialog.java new file mode 100644 index 0000000..817efb9 --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/ui/FileDialog.java @@ -0,0 +1,108 @@ +package com.mobidevelop.maps.editor.ui; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.List; +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.TextField; +import com.badlogic.gdx.scenes.scene2d.ui.Window; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; + + +public class FileDialog extends Window { + + List fileList; + TextField fileName; + private String lastFolder; + + public FileDialog( String title, FileHandle initialFolder, Skin skin ) { + + super( title, skin ); + + setModal( true ); + setFillParent( true ); + + lastFolder = initialFolder.path(); + fileList = new List( initialFolder.list(), skin ); + fileList.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + + String path = lastFolder + "/" + Gdx.files.external( fileList.getSelection() ).name(); + FileHandle file = Gdx.files.external( path ); + if ( file.isDirectory() ) { + lastFolder = path; + loadFileList( file.list() ); + } else { + fileName.setText( file.name() ); + } + } + } ); + final ScrollPane listScroll = new ScrollPane( fileList ); + + final TextButton upButton = new TextButton( "Up", skin ); + upButton.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + lastFolder = Gdx.files.external( lastFolder ).parent().name(); + loadFileList( Gdx.files.external( lastFolder ).list() ); + } + }); + + final TextButton okButton = new TextButton( "OK", skin ); + okButton.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + + String path = lastFolder + "/" + fileList.getSelection(); + FileHandle file = Gdx.files.external( path ); +// if ( file.isDirectory() ) { +// loadFileList( file.list() ); +// } else { + fire( UIEvents.selectImagePath( file ) ); + remove(); +// } + } + }); + final TextButton cancelButton = new TextButton( "Cancel", skin ); + cancelButton.addListener( new ClickListener() { + public void clicked( InputEvent event, float x, float y ) { + remove(); + } + } ); + + fileName = new TextField( "", skin ); + + Table table = new Table( skin ); + table.defaults().fill().padTop( 10 ).padBottom( 10 ); + table.row(); + table.add( upButton ).colspan( 2 ); + table.row(); + table.add( listScroll ).expand().colspan( 2 ); + table.row(); + table.add( fileName ); + table.row(); + table.add( okButton ); + table.add( cancelButton ); + + add( table ); + } + + public void editFileName( boolean enable ) { + + fileName.setDisabled( !enable ); + } + + private void loadFileList( FileHandle[] list ) { + + String[] items = new String[list.length]; + for ( int i = 0; i < items.length; i++ ) { + items[i] = list[i].name(); + } + fileList.setItems( items ); + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/ui/ImagePicker.java b/maps-editor/src/com/mobidevelop/maps/editor/ui/ImagePicker.java new file mode 100644 index 0000000..2b8434c --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/ui/ImagePicker.java @@ -0,0 +1,115 @@ +package com.mobidevelop.maps.editor.ui; + +import java.util.HashMap; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; +import com.badlogic.gdx.graphics.Texture.TextureFilter; +import com.badlogic.gdx.graphics.g2d.PixmapPacker; +import com.badlogic.gdx.graphics.g2d.TextureAtlas; +import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion; +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.ui.Image; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Disposable; + + +public class ImagePicker extends Table implements Disposable { + + private PixmapPacker thumbPacker = null; + private TextureAtlas thumbImageAtlas; + private HashMap projectImages; + + private Table thumbTable; + + public ImagePicker( final Skin skin ) { + + thumbImageAtlas = new TextureAtlas(); + projectImages = new HashMap(); + + // thumbnails sit in a table within a scroll pane + thumbTable = new Table(); + thumbTable.row(); + thumbTable.add( new Label( "No images loaded", skin ) ); + final ScrollPane thumbScroll = new ScrollPane( thumbTable ); + + // add click listener to send event for new image to stage + thumbScroll.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + + Actor actor = thumbScroll.hit( x, y, false ); + if ( actor != null ) { + FileHandle file = projectImages.get( actor.getName() ); + if ( file != null ) + fire( UIEvents.addImageEvent( file ) ); + } + super.clicked( event, x, y ); + } + } ); + + add( thumbScroll ); + } + + /** + * creates a 64x64 thumbnail from the given file (should be an image file) + * @param img + */ + private void packImageThumb( FileHandle img ) { + + projectImages.put( img.name(), img ); + Pixmap fullImage = new Pixmap( img ); + Pixmap thumb = new Pixmap( 64, 64, Format.RGB565 ); + thumb.drawPixmap( fullImage, 0, 0, fullImage.getWidth(), fullImage.getHeight(), 0, 0, thumb.getWidth(), thumb.getHeight() ); + thumbPacker.pack( img.name(), thumb ); + } + + /** + * loads images from the project image folder into thumbnails on the image window + * @param file the folder to load images from + */ + public void loadProjectImages( FileHandle folder ) { + + // reset thumbs + if ( thumbPacker != null ) + thumbPacker.dispose(); + thumbPacker = new PixmapPacker( 1024, 1024, Format.RGBA8888, 2, false ); + projectImages.clear(); + + // get image thumbs and pack into atlas + FileHandle[] list = folder.list(); + for ( int i = 0; i < list.length; i++ ) { + FileHandle img = list[i]; + String ext = img.extension().toLowerCase(); + if ( ext.contentEquals( "png" ) || ext.contentEquals( "jpg" ) ) { + packImageThumb( img ); + } + } + thumbPacker.updateTextureAtlas( thumbImageAtlas, TextureFilter.Linear, TextureFilter.Linear, true ); + + // load thumbs into image listbox + Array regions = thumbImageAtlas.getRegions(); + thumbTable.clear(); + for ( int i = 0; i < regions.size; i++ ) { + AtlasRegion region = regions.get( i ); + Image img = new Image( region ); + img.setName( region.name ); + thumbTable.row(); + thumbTable.add( img ); + } + } + + @Override + public void dispose() { + + if ( thumbPacker != null ) + thumbPacker.dispose(); + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/ui/LayerList.java b/maps-editor/src/com/mobidevelop/maps/editor/ui/LayerList.java new file mode 100644 index 0000000..5a028ce --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/ui/LayerList.java @@ -0,0 +1,181 @@ +package com.mobidevelop.maps.editor.ui; + +import com.badlogic.gdx.scenes.scene2d.Actor; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.Touchable; +import com.badlogic.gdx.scenes.scene2d.ui.Button; +import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; +import com.badlogic.gdx.scenes.scene2d.ui.Label; +import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; +import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.Table; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; +import com.badlogic.gdx.utils.SnapshotArray; +import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerAddedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerRemovedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerSelectedEvent; +import com.mobidevelop.maps.editor.models.MapModels.MapLayersModel.LayerSwappedEvent; +import com.mobidevelop.utils.events.Event; +import com.mobidevelop.utils.events.EventDispatcher; +import com.mobidevelop.utils.events.EventListener; + + +public class LayerList extends Table implements EventListener { + + private Skin skin; + private VerticalGroup layers; + private Label lastSelected; + + public LayerList( final Skin skin ) { + + this.skin = skin; + + // rich list box for the layers, just a vertical group of LayerActors in a ScrollPane + layers = new VerticalGroup(); + layers.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + Actor actor = layers.hit( x, y, true ); + if ( actor instanceof Label ) { + // hacky way to get the layer + Label lbl = (Label) actor; + fire( UIEvents.selectLayer( ((LayerListActor)lbl.getParent()).getLayer() ) ); + } + } + } ); + final ScrollPane layerScroll = new ScrollPane( layers ); + layerScroll.setOverscroll( false, true ); + + // controls for add/removing layers + final TextButton addLayerButton = new TextButton( "New Layer", skin ); + addLayerButton.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + fire( UIEvents.addLayerEvent() ); + } + }); + final TextButton removeLayerButton = new TextButton( "Remove Layer", skin ); + removeLayerButton.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + fire( UIEvents.removeLayerEvent() ); + } + }); + + defaults().pad( 10 ); + row(); + add( layerScroll ).colspan( 2 ); + row(); + add( addLayerButton ); + add( removeLayerButton ); + } + + @Override + public void onEvent( EventDispatcher dispatcher, Event event ) { + + // model added layer + if ( event instanceof LayerAddedEvent ) { + MapLayer layer = ((LayerAddedEvent)event).layer; + LayerListActor actor = new LayerListActor( layer, skin ); + layers.addActorAt( layer.getMap().getLayers().getIndex( layer ), actor ); + return; + } + + // model removed layer + if ( event instanceof LayerRemovedEvent ) { + Actor actor = getLayerActor( ((LayerRemovedEvent)event).layer ); + if ( actor != null ) + actor.remove(); + return; + } + + // model changed selected layer + if ( event instanceof LayerSelectedEvent ) { + selectLayer( ((LayerSelectedEvent)event).layer ); + } + + // model swapped layers + if ( event instanceof LayerSwappedEvent ) { + LayerSwappedEvent evt = (LayerSwappedEvent)event; + Actor actor1 = getLayerActor( evt.layer ); + Actor actor2 = getLayerActor( evt.layer2 ); + if ( actor1 != null && actor2 != null ) + layers.swapActor( actor1, actor2 ); + return; + } + } + + public LayerListActor getLayerActor( MapLayer layer ) { + + SnapshotArray ls = layers.getChildren(); + for ( int i = 0; i < ls.size; i++ ) { + LayerListActor l = (LayerListActor)ls.get( i ); + if ( layer == l.getLayer() ) + return l; + } + return null; + } + + public void selectLayer( MapLayer layer ) { + + if ( lastSelected != null ) { + lastSelected.setStyle( skin.get( "default", LabelStyle.class ) ); + } + lastSelected = getLayerActor( layer ).getLabel(); + lastSelected.setStyle( skin.get( "selected", LabelStyle.class ) ); + } + + // LayerListActor will represent a layer in the listbox, with controls to handle locking/visibility, etc. + public class LayerListActor extends Table { + + private MapLayer layer; + private Label label; + + public LayerListActor( MapLayer layer, Skin skin ) { + + this.layer = layer; + + setTouchable( Touchable.childrenOnly ); + setName( layer.getName() ); + label = new Label( getName(), skin ); + label.setTouchable( Touchable.enabled ); + + final CheckBox showHideButton = new CheckBox( "", skin ); + showHideButton.addListener( new ClickShowHideListener( showHideButton, layer ) ); + showHideButton.setChecked( true ); + + row(); + add( showHideButton ); + add( label ); + } + + public Label getLabel() { + return label; + } + + public MapLayer getLayer() { + return layer; + } + } + + public class ClickShowHideListener extends ClickListener { + private Button button; + private MapLayer layer; + public ClickShowHideListener( Button button, MapLayer layer ) { + this.button = button; + this.layer = layer; + } + @Override + public void clicked( InputEvent event, float x, float y ) { + if ( button.isChecked() ) + fire( UIEvents.hideLayer( layer ) ); + else + fire( UIEvents.showLayer( layer ) ); + super.clicked( event, x, y ); + } + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/ui/SlideWindow.java b/maps-editor/src/com/mobidevelop/maps/editor/ui/SlideWindow.java new file mode 100644 index 0000000..3ab1684 --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/ui/SlideWindow.java @@ -0,0 +1,148 @@ +package com.mobidevelop.maps.editor.ui; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.math.Interpolation; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.scenes.scene2d.InputEvent; +import com.badlogic.gdx.scenes.scene2d.Touchable; +import com.badlogic.gdx.scenes.scene2d.actions.Actions; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.scenes.scene2d.ui.TextButton; +import com.badlogic.gdx.scenes.scene2d.ui.Window; +import com.badlogic.gdx.scenes.scene2d.utils.Align; +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; + + +public class SlideWindow extends Window { + + private Vector2 startPos = new Vector2(); + private Vector2 goalPos = new Vector2(); + + /** + * creates a window that slides in from screen edge determined by origin (using {@link com.badlogic.gdx.scenes.scene2d.utils.Align Align}) + * @param skin skin file to use + * @param origin which edge of the screen to slide from (see {@link com.badlogic.gdx.scenes.scene2d.utils.Align Align}) + * @param margin amount of empty space to leave around window + */ + public SlideWindow( Skin skin, int origin, float margin ) { + + this( skin, origin, margin, 0 ); + } + + /** + * creates a window that slides in from screen edge determined by origin (using {@link com.badlogic.gdx.scenes.scene2d.utils.Align Align}) + * @param skin skin file to use + * @param origin which edge of the screen to slide from (see {@link com.badlogic.gdx.scenes.scene2d.utils.Align Align}) + * @param margin amount of empty space to leave around window + * @param lip size of window along sliding axis (0 = fullscreen) + */ + public SlideWindow( Skin skin, int origin, float margin, float lip ) { + + super( "", skin ); + + float w = Gdx.graphics.getWidth(); + float h = Gdx.graphics.getHeight(); + float ww = w - 2*margin; + float wh = h - 2*margin; + + // setup window with desired dimensions to slide in from edge of screen determined by origin + if ( ( origin & Align.left ) != 0 ) { + + ww = lip > 0 ? lip : ww; + setupWindow( skin, ww, wh, -( ww + 2*margin ), margin, margin, margin ); + + } else if ( ( origin & Align.right ) != 0 ) { + + ww = lip > 0 ? lip : ww; + setupWindow( skin, ww, wh, w + 2*margin, margin, w - ( ww + margin ), margin ); + + } else if ( ( origin & Align.top ) != 0 ) { + + wh = lip > 0 ? lip : wh; + setupWindow( skin, ww, wh, margin, h + 2*margin, margin, h - ( wh + margin ) ); + + } else if ( ( origin & Align.bottom ) != 0 ) { + + wh = lip > 0 ? lip : wh; + setupWindow( skin, ww, wh, margin, -( wh + 2*margin ), margin, margin ); + + // default center + } else { + + setupWindow( skin, ww, wh, margin, margin, margin, margin ); + } + } + + /** + * creates a slide window with all properties explicitly defined + * @param skin + * @param windowWidth + * @param windowHeight + * @param startPosX + * @param startPosY + * @param goalPosX + * @param goalPosY + */ + public SlideWindow( Skin skin, float windowWidth, float windowHeight, float startPosX, float startPosY, float goalPosX, float goalPosY ) { + + super( "", skin ); + + setupWindow( skin, windowWidth, windowHeight, startPosX, startPosY, goalPosX, goalPosY ); + } + + private void setupWindow( Skin skin, float width, float height, float startPosX, float startPosY, float goalPosX, float goalPosY ) { + + startPos.set( startPosX, startPosY ); + goalPos.set( goalPosX, goalPosY ); + +// // remove listener which pushes window to front when clicked +// removeCaptureListener( getCaptureListeners().get( 0 ) ); + + // kill click events on the window + addListener( new ClickListener() { + @Override + public boolean touchDown( InputEvent event, float x, float y, int pointer, int button ) { + super.touchDown( event, x, y, pointer, button ); + return true; + } + } ); + setTouchable( Touchable.enabled ); + setBackground( skin.getDrawable( "default-round" ) ); + setKeepWithinStage( false ); + + // add a close button + TextButton dismisser = new TextButton( "X", skin ); + dismisser.addListener( new ClickListener() { + @Override + public void clicked( InputEvent event, float x, float y ) { + hideWindow(); + } + }); + row(); + add( dismisser ).align( Align.right ); + + setSize( width, height ); + setPosition( startPos.x, startPos.y ); + } + + /** + * show the window with a slide and fade-in + */ + public void showWindow() { + + clearActions(); + setPosition( startPos.x, startPos.y ); + setColor( 1, 1, 1, 0 ); + addAction( Actions.parallel( Actions.moveTo( goalPos.x, goalPos.y, 0.3f, Interpolation.swingOut ), Actions.fadeIn( 0.3f ) ) ); + } + + /** + * hide the window with a slide and fade-out + */ + public void hideWindow() { + + clearActions(); + setPosition( goalPos.x, goalPos.y ); + addAction( Actions.parallel( Actions.moveTo( startPos.x, startPos.y, 0.3f ), Actions.fadeOut( 0.3f, Interpolation.exp10Out ) ) ); + } +} diff --git a/maps-editor/src/com/mobidevelop/maps/editor/ui/UIEvents.java b/maps-editor/src/com/mobidevelop/maps/editor/ui/UIEvents.java new file mode 100644 index 0000000..73d94d6 --- /dev/null +++ b/maps-editor/src/com/mobidevelop/maps/editor/ui/UIEvents.java @@ -0,0 +1,66 @@ +package com.mobidevelop.maps.editor.ui; + +import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.scenes.scene2d.Event; +import com.mobidevelop.maps.MapLayer; +import com.mobidevelop.maps.MapObject; + + +public class UIEvents { + + public static final int EV_ADD_LAYER = 1; + public static final int EV_REMOVE_LAYER = 2; + public static final int EV_SELECT_LAYER = 3; + public static final int EV_HIDE_LAYER = 4; + public static final int EV_SHOW_LAYER = 5; + public static final int EV_ADD_IMAGE = 6; + public static final int EV_SELECT_MAP_OBJECT = 7; + public static final int EV_SELECT_IMAGE_PATH = 8; + + /** + * UIEvents are events the scene2d.ui uses to interact with the model. + * They are sent by different ui components and handled by the main uiStage, where the model interaction occurs. + * The model has it's own events which each ui component responds to as needed. + * @author Josh + * + */ + public static class UIEvent extends Event { + public int type; + public UIEvent( int type ) { + this.type = type; + } + } + + public static class LayerEvent extends UIEvent { + public MapLayer layer; + public LayerEvent( int type, MapLayer layer ) { + super( type ); + this.layer = layer; + } + } + + public static class MapObjectEvent extends UIEvent { + public MapObject object; + public MapObjectEvent( int type, MapObject object ) { + super( type ); + this.object = object; + } + } + + public static class FileEvent extends UIEvent { + public FileHandle file; + public FileEvent( int type, FileHandle file ) { + super( type ); + this.file = file; + } + } + + public static UIEvent addLayerEvent() { return new UIEvent( EV_ADD_LAYER ); } + public static UIEvent removeLayerEvent() { return new UIEvent( EV_REMOVE_LAYER ); } + public static UIEvent selectLayer( MapLayer layer ) { return new LayerEvent( EV_SELECT_LAYER, layer ); } + public static UIEvent hideLayer( MapLayer layer ) { return new LayerEvent( EV_HIDE_LAYER, layer ); } + public static UIEvent showLayer( MapLayer layer ) { return new LayerEvent( EV_SHOW_LAYER, layer ); } + public static UIEvent addImageEvent( FileHandle file ) { return new FileEvent( EV_ADD_IMAGE, file ); } + public static UIEvent selectObject( MapObject object ) { return new MapObjectEvent( EV_SELECT_MAP_OBJECT, object ); } + public static UIEvent selectImagePath( FileHandle file ) { return new FileEvent( EV_SELECT_IMAGE_PATH, file ); } +} diff --git a/maps-editor/src/com/mobidevelop/utils/commands/Command.java b/maps-editor/src/com/mobidevelop/utils/commands/Command.java index ccba5eb..12d11f6 100644 --- a/maps-editor/src/com/mobidevelop/utils/commands/Command.java +++ b/maps-editor/src/com/mobidevelop/utils/commands/Command.java @@ -16,6 +16,8 @@ package com.mobidevelop.utils.commands; +import com.mobidevelop.utils.events.Event; + /** * Represents an action that can be executed and reversed. * @@ -23,8 +25,8 @@ */ public interface Command { - public void execute(); + public Event execute(); - public void reverse(); + public Event reverse(); } diff --git a/maps-editor/src/com/mobidevelop/utils/commands/CommandManager.java b/maps-editor/src/com/mobidevelop/utils/commands/CommandManager.java index 5c14482..d8b03d8 100644 --- a/maps-editor/src/com/mobidevelop/utils/commands/CommandManager.java +++ b/maps-editor/src/com/mobidevelop/utils/commands/CommandManager.java @@ -18,6 +18,9 @@ import java.util.*; +import com.mobidevelop.maps.editor.models.MapModels.MapModel; +import com.mobidevelop.utils.events.Event; + /** * The {@code CommandManager} class manages the execution and reversal of {@link Command Commands}. @@ -28,8 +31,11 @@ public class CommandManager { private Deque undoStack; private Deque redoStack; - - public CommandManager() { + + private MapModel model; + + public CommandManager( MapModel model ) { + this.model = model; undoStack = new ArrayDeque(); redoStack = new ArrayDeque(); } @@ -40,7 +46,9 @@ public CommandManager() { * @param command The {@link Command} to execute. */ public void execute(Command command) { - command.execute(); + Event event = command.execute(); + if ( event != null ) + model.dispatchEvent( event ); undoStack.push(command); redoStack.clear(); } @@ -55,7 +63,9 @@ public void undo() { throw new RuntimeException("No commands to undo."); } Command command = undoStack.pop(); - command.reverse(); + Event event = command.reverse(); + if ( event != null ) + model.dispatchEvent( event ); redoStack.push(command); } @@ -70,7 +80,9 @@ public void undo(int count) { } while (!undoStack.isEmpty() && count > 0) { Command command = undoStack.pop(); - command.reverse(); + Event event = command.reverse(); + if ( event != null ) + model.dispatchEvent( event ); redoStack.push(command); count--; } @@ -103,7 +115,9 @@ public void redo() { throw new RuntimeException("No commands to redo."); } Command command = redoStack.pop(); - command.execute(); + Event event = command.execute(); + if ( event != null ) + model.dispatchEvent( event ); undoStack.push(command); } @@ -113,7 +127,9 @@ public void redo(int count) { } while (!undoStack.isEmpty() && count > 0) { Command command = redoStack.pop(); - command.execute(); + Event event = command.execute(); + if ( event != null ) + model.dispatchEvent( event ); undoStack.push(command); count--; } diff --git a/maps/src/com/mobidevelop/maps/Map.java b/maps/src/com/mobidevelop/maps/Map.java index 0e8d1b1..ea4b95d 100644 --- a/maps/src/com/mobidevelop/maps/Map.java +++ b/maps/src/com/mobidevelop/maps/Map.java @@ -46,4 +46,5 @@ public interface Map extends Disposable { public abstract MapResources getResources(); + public abstract MapLayer createLayer( String name ); }