using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;
using System.IO;
using MapEditorLib;
namespace MapEditor
{
/// <summary>
/// The tiled map control provides an interface for the
/// EditableMap, and makes use of the XnaMapRenderer to
/// render the actual map
/// </summary>
public partial class TiledMap : UserControl
{
#region Variables
//The actual map
private EditableMap m_Map;
//A renderer for the map that uses either XNA or GDI
private IMapRenderer m_renderer;
//Control properties
private Color m_gridColour;
private Color m_overlayColour;
private bool m_showGrid;
private bool m_showSolids;
private bool m_showNumbers;
private Font m_font;
//Nothing special about these
private bool m_ctrlKey;
private bool m_mouseDown;
private int m_x,m_y;
private int x_offset, y_offset;
private bool m_lockEvents;
private string m_tempPath;
#endregion
#region Properties
public event TileSizeChangedEventHandler OnTileSizeChanged;
[Browsable(false)]
public bool CtrlKey
{
get { return m_ctrlKey; }
set { m_ctrlKey = value; }
}
[Browsable(false)]
public bool ShowSolids
{
get { return m_showSolids; }
set
{
m_showSolids = value;
m_renderer.SetSolidsVisible(value);
this.mainGrid_panel.Invalidate();
}
}
public Font MapFont
{
get { return m_font; }
set { m_font = value; this.mainGrid_panel.Invalidate(); }
}
public bool ShowGrid
{
get { return m_showGrid; }
set
{
m_showGrid = value;
m_renderer.SetGridVisible(value);
this.mainGrid_panel.Invalidate();
}
}
public bool ShowNumbers
{
get { return m_showNumbers; }
set { m_showNumbers = value; this.mainGrid_panel.Invalidate(); }
}
public Color GridColour
{
get { return m_gridColour; }
set
{
m_gridColour = value;
m_renderer.SetGridColour(m_gridColour.R, m_gridColour.G, m_gridColour.B);
this.mainGrid_panel.Invalidate();
}
}
public Color OverlayColour
{
get { return m_overlayColour; }
set
{
m_overlayColour = value;
m_renderer.SetOverlayColour(m_overlayColour.R, m_overlayColour.G, m_overlayColour.B);
this.mainGrid_panel.Invalidate();
}
}
public int TileSize
{
get { return m_Map.TileSize; }
set
{
if(value > 0)
m_Map.TileSize = value;
else
m_Map.TileSize = 1;
//Set the new size of the panel
this.mainGrid_panel.Size = new Size(m_Map.RealWidth, m_Map.RealHeight);
}
}
public System.Drawing.Point MapSize
{
get { return new System.Drawing.Point(m_Map.Width, m_Map.Height); }
set
{
this.widthUpDown.Value = value.X;
this.heightUpDown.Value = value.Y;
setSize();
}
}
#endregion
public TiledMap()
{
InitializeComponent();
//Default values
m_gridColour = Color.Gray;
m_overlayColour = Color.Red;
m_showGrid = true;
m_font = this.Font;
m_mouseDown = false;
m_x = 0;
m_y = 0;
m_lockEvents = false;
//Setup the map
m_Map = new EditableMap();
refillLayerList();
m_Map.OnMapChanged += new EditableMap.MapChangedEventHandler(this.redrawMap);
//Set the correct sizes for our panel
this.mainGrid_panel.Size = new Size(m_Map.RealWidth, m_Map.RealHeight);
//Setup the renderer, and trust me, you want the XnaMapRenderer
//m_renderer = new GdiMapRenderer(m_Map);
m_renderer = new XnaMapRenderer(m_Map, this.mainGrid_panel.Handle, this.mainGrid_panel.Width, this.mainGrid_panel.Height);
m_renderer.SetClearColour(this.BackColor.R, this.BackColor.G, this.BackColor.B);
m_renderer.SetGridColour(m_gridColour.R, m_gridColour.G, m_gridColour.B);
m_renderer.SetOverlayColour(m_overlayColour.R, m_overlayColour.G, m_overlayColour.B);
m_renderer.SetGridVisible( m_showGrid);
m_renderer.SetSolidsVisible(m_showSolids);
this.mainGrid_panel.SetRenderMethod(m_renderer.RenderMap);
}
#region Public Functions
public void SetSelectedTiles(Tile[,] tiles)
{
m_Map.SetSelectedTiles(tiles);
}
public void SaveMap(string path)
{
m_Map.Save(path);
//Get the directory the user is saving in to
string parentDir = path.Substring(0, path.LastIndexOf('\\'));
m_Map.SaveTextures(parentDir);
}
public void LoadMap(string path)
{
m_tempPath = path;
m_Map.Load(path, this.textureRequest);
m_tempPath = String.Empty;
//Sort ourselves out
revivification();
}
public void Clear()
{
m_Map.Reset();
revivification();
}
public List<Tileset> GetTilesets()
{
return m_Map.TileSets;
}
#endregion
#region private Functions
private void revivification()
{
refillLayerList();
this.widthUpDown.Value = m_Map.Width;
this.heightUpDown.Value = m_Map.Height;
this.tileSizeUpDown.Value = m_Map.TileSize;
this.zvalueUpDown.Value = (Decimal)m_Map.WorkingLayer.Z_Value;
this.layerVisChkBox.Checked = m_Map.WorkingLayer.Visible;
this.mainGrid_panel.Size = new Size(m_Map.RealWidth, m_Map.RealHeight);
this.mainGrid_panel.Invalidate();
}
private void setTiles(int posX, int posY)
{
m_Map.SetTiles(posX, posY);
}
private void setSize()
{
m_Map.SetSize((int)this.widthUpDown.Value, (int)this.heightUpDown.Value);
this.mainGrid_panel.Size = new Size(m_Map.RealWidth, m_Map.RealHeight);
}
private void refillLayerList()
{
//Clear - refill the combobox with the new list
this.layerSelectBox.SuspendLayout();
this.layerSelectBox.Items.Clear();
foreach (MapLayer layer in m_Map.MapLayers)
this.layerSelectBox.Items.Add(layer);
this.layerSelectBox.Items.Add("Add...");
this.layerSelectBox.SelectedItem = m_Map.WorkingLayer;
this.layerSelectBox.ResumeLayout();
}
private void redrawMap(object sender, EditableMap.MapChangedEventArgs e)
{
//Account for offset
System.Drawing.Rectangle rect = e.Area;
rect.Offset(-x_offset, -y_offset);
this.mainGrid_panel.Invalidate(rect);
}
private void addLayer()
{
bool validName;
bool validZ;
NewLayerDialog diag = new NewLayerDialog();
DialogResult res;
do
{
res = diag.ShowDialog();
//If the user cancels, just break out
if (res == DialogResult.Cancel)
break;
validName = true;
validZ = true;
if (m_Map.LayerNameInUse(diag.LayerName))
{
MessageBox.Show("There is already a layer with the same name", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
validName = false;
}
else if (m_Map.LayerZInUse(diag.Z_Value))
{
DialogResult dr = MessageBox.Show("There is already a layer with the same Z-Value.\nWould you like to change it?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (dr == DialogResult.Yes)
validZ = false;
}
} while (!(validName & validZ));
if (res == DialogResult.OK)
{
m_Map.AddLayer(diag.LayerName, diag.Z_Value, diag.Background);
refillLayerList();
}
//Make sure we're the current layer is still selected
this.layerSelectBox.SelectedItem = m_Map.WorkingLayer;
}
private Image textureRequest(string Name)
{
string parentDir = m_tempPath.Substring(0, m_tempPath.LastIndexOf('\\'));
//Load up the image
Bitmap img = null;
string fullPath = parentDir + "\\MapData\\" + Name;
if (File.Exists(fullPath))
{
img = new Bitmap(fullPath);
}
else
{
MessageBox.Show("Unable to find texture: " + Name, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return img;
}
#endregion
#region Controls Events
void tileClick(object sender, MouseEventArgs e)
{
m_mouseDown = true;
//Find the tile the use clicked
int x = (int)Math.Floor((double) ((e.X+x_offset) / m_Map.TileSize));
int y = (int)Math.Floor((double) ((e.Y+y_offset) / m_Map.TileSize));
if(0 <= x && x < m_Map.Width && 0 <= y && y < m_Map.Height)
{
if (m_ctrlKey)
{
//Set tile to solid
m_Map.ToggleSolid(x, y);
this.mainGrid_panel.Invalidate();
}
else
{
//Get and set a tile, right click will make a new tile
if (e.Button == MouseButtons.Left)
setTiles(x, y);
else if (e.Button == MouseButtons.Right)
{
m_Map.ClearTile(x,y);
}
}
//Store the tile we just clicked
m_x = x;
m_y = y;
}
}
void mainGrid_panelMouseMove(object sender, MouseEventArgs e)
{
//Get the tile we clicked
int x = (int)Math.Floor((double) ((e.X+x_offset) / m_Map.TileSize));
int y = (int)Math.Floor((double) ((e.Y+y_offset) / m_Map.TileSize));
if(0 <= x && x < m_Map.Width && 0 <= y && y < m_Map.Height)
{
if(m_mouseDown && (x != m_x || y != m_y))
{
if (m_ctrlKey)
{
//Set tile to solid
m_Map.ToggleSolid(x, y);
}
else
{
//Set
if(e.Button == MouseButtons.Left)
setTiles(x,y);
else if (e.Button == MouseButtons.Right)
{
m_Map.ClearTile(x,y);
}
}
//Store the tile we just rolled on over
m_x = x;
m_y = y;
}
//Update the status bar
this.tileStatusLabel.Text = x.ToString() + "," + y.ToString();
this.tileInfoStatusLabel.Text = m_Map.GetTilesetName(x, y);
}
}
void mainGrid_panelMouseUp(object sender, MouseEventArgs e)
{
m_mouseDown = false;
}
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (m_lockEvents)
return;
//Lock the events so that setting values here doesn't
// trigger everything to reset itself
m_lockEvents = true;
//If the type is a string, then the user clicked 'Add...'
if (this.layerSelectBox.SelectedItem.GetType() == typeof(string))
{
addLayer();
}
else
{
try
{
m_Map.WorkingLayer = this.layerSelectBox.SelectedItem as MapLayer;
}
catch (System.ArgumentException)
{
//We hope never to get here...
MessageBox.Show("This layer is no longer available.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
refillLayerList();
}
}
this.zvalueUpDown.Value = (Decimal)m_Map.WorkingLayer.Z_Value;
this.layerVisChkBox.Checked = m_Map.WorkingLayer.Visible;
m_lockEvents = false;
}
private void layerVisChkBox_CheckedChanged(object sender, EventArgs e)
{
if (!m_lockEvents)
{
m_Map.SetLayerVisible(this.layerVisChkBox.Checked);
}
}
private void zvalueUpDown_ValueChanged(object sender, EventArgs e)
{
if (!m_lockEvents)
{
m_Map.SetLayerZValue((float)this.zvalueUpDown.Value);
}
}
private void setsize_buttonClick(object sender, EventArgs e)
{
setSize();
}
private void tileSizeUpDown_ValueChanged(object sender, EventArgs e)
{
m_Map.TileSize = (int)this.tileSizeUpDown.Value;
this.mainGrid_panel.Size = new Size(m_Map.RealWidth, m_Map.RealHeight);
if (OnTileSizeChanged != null)
{
TileSizeChangedEventArgs eventArgs = new TileSizeChangedEventArgs(m_Map.TileSize);
OnTileSizeChanged(this, eventArgs);
}
}
private void mainGrid_panel_SizeChanged(object sender, EventArgs e)
{
//Setup the scroll bars
//Horizontal
if (m_Map.RealWidth > this.mainGrid_panel.Width) {
this.hScrollBar1.Maximum = m_Map.RealWidth - this.mainGrid_panel.Width + (this.hScrollBar1.LargeChange - 1);
this.hScrollBar1.Enabled = true;
}
else {
x_offset = 0;
this.hScrollBar1.Enabled = false;
}
//Vertical
if (m_Map.RealHeight > this.mainGrid_panel.Height) {
this.vScrollBar1.Maximum = m_Map.RealHeight - this.mainGrid_panel.Height + (this.vScrollBar1.LargeChange - 1);
this.vScrollBar1.Enabled = true;
}
else {
y_offset = 0;
this.vScrollBar1.Enabled = false;
}
if (m_renderer != null)
{
m_renderer.SetOffset(x_offset, y_offset);
m_renderer.ResetGraphicsDevice(this.mainGrid_panel.Width, this.mainGrid_panel.Height);
}
}
private void hScrollBar1_ValueChanged(object sender, EventArgs e)
{
x_offset = this.hScrollBar1.Value;
m_renderer.SetOffset(x_offset, y_offset);
this.mainGrid_panel.Invalidate();
}
private void vScrollBar1_ValueChanged(object sender, EventArgs e)
{
y_offset = this.vScrollBar1.Value;
m_renderer.SetOffset(x_offset, y_offset);
this.mainGrid_panel.Invalidate();
}
#endregion
}
}