Newer
Older
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.BuilderModes.Interface;
using CodeImp.DoomBuilder.Config;
MaxED
committed
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.GZBuilder.Data;
MaxED
committed
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Windows;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Things Mode",
SwitchAction = "thingsmode", // Action name used to switch to this mode
ButtonImage = "ThingsMode.png", // Image resource name for the button
ButtonOrder = int.MinValue + 300, // Position of the button (lower is more to the left)
ButtonGroup = "000_editing",
UseByDefault = true,
SafeStartMode = true)]
public class ThingsMode : BaseClassicMode
{
#region ================== Constants
private const int MAX_THING_LABELS = 256; //mxd
#endregion
#region ================== Variables
// Highlighted item
private Thing highlighted;
private bool thinginserted;
private bool awaitingMouseClick; //mxd
//mxd. Helper shapes
private List<Line3D> persistenteventlines;
private List<Line3D> dynamiclightshapes;
private List<Line3D> ambientsoundshapes;
//mxd. Text labels
private Dictionary<Thing, TextLabel> labels;
private Dictionary<Sector, TextLabel[]> sectorlabels;
private Dictionary<Sector, string[]> sectortexts;
// Stores sizes of the text for text labels so that they only have to be computed once
private Dictionary<string, float> textlabelsizecache;
// Things that will be edited
private ICollection<Thing> editthings;
#endregion
#region ================== Properties
public override object HighlightedObject { get { return highlighted; } }
#endregion
#region ================== Constructor / Disposer
public ThingsMode()
{
//mxd. Associations now requre initializing...
textlabelsizecache = new Dictionary<string, float>();
}
//mxd
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Dispose old labels
if(labels != null) foreach(TextLabel l in labels.Values) l.Dispose();
if(sectorlabels != null)
{
foreach(TextLabel[] larr in sectorlabels.Values)
foreach(TextLabel l in larr) l.Dispose();
}
// Dispose base
base.Dispose();
}
}
#endregion
#region ================== Methods
//mxd. This makes a CRC for given selection
MaxED
committed
private static int CreateSelectionCRC(ICollection<Thing> selection)
{
CRC crc = new CRC();
crc.Add(selection.Count);
MaxED
committed
foreach(Thing t in selection) crc.Add(t.Index);
return (int)(crc.Value & 0xFFFFFFFF);
}
public override void OnHelp()
{
General.ShowHelp("e_things.html");
}
// Cancel mode
public override void OnCancel()
{
base.OnCancel();
// Return to this mode
General.Editing.ChangeMode(new ThingsMode());
}
// Mode engages
public override void OnEngage()
{
base.OnEngage();
renderer.SetPresentation(Presentation.Things);
General.Interface.BeginToolbarUpdate(); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.CopyProperties);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.PasteProperties);
General.Interface.AddButton(BuilderPlug.Me.MenusForm.PastePropertiesOptions); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.SeparatorCopyPaste); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.ViewSelectionNumbers); //mxd
if(General.Map.FormatInterface.HasThingAction)
{
BuilderPlug.Me.MenusForm.ViewSelectionEffects.Text = "View Sector Tags"; //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.ViewSelectionEffects); //mxd
}
General.Interface.AddButton(BuilderPlug.Me.MenusForm.SeparatorSectors1); //mxd
General.Interface.AddButton(BuilderPlug.Me.MenusForm.AlignThingsToWall); //mxd
//mxd. Add radii buttons/items...
if (General.Map.Config.DynamicLightSupport) General.Interface.AddButton(BuilderPlug.Me.MenusForm.ButtonLightRadii, ToolbarSection.Helpers);
if (General.Map.Config.SoundSupport) General.Interface.AddButton(BuilderPlug.Me.MenusForm.ButtonSoundRadii, ToolbarSection.Helpers);
if (General.Map.Config.DynamicLightSupport) General.Interface.AddMenu(BuilderPlug.Me.MenusForm.ItemLightRadii, MenuSection.ViewHelpers);
if (General.Map.Config.SoundSupport) General.Interface.AddMenu(BuilderPlug.Me.MenusForm.ItemSoundRadii, MenuSection.ViewHelpers);
General.Interface.EndToolbarUpdate(); //mxd
// Convert geometry selection to linedefs selection
General.Map.Map.ConvertSelection(SelectionType.Linedefs);
General.Map.Map.SelectionType = SelectionType.Things;
UpdateSelectionInfo(); //mxd
UpdateHelperObjects(); //mxd
SetupSectorLabels(); //mxd
// By default we allow autosave
allowautosave = true;
}
// Mode disengages
public override void OnDisengage()
{
base.OnDisengage();
// Remove toolbar buttons
General.Interface.BeginToolbarUpdate(); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.CopyProperties);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.PasteProperties);
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.PastePropertiesOptions); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.SeparatorCopyPaste); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ViewSelectionNumbers); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ViewSelectionEffects); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.SeparatorSectors1); //mxd
General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.AlignThingsToWall); //mxd
//mxd. Remove radii buttons/items...
if (General.Map.Config.DynamicLightSupport) General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ButtonLightRadii);
if (General.Map.Config.SoundSupport) General.Interface.RemoveButton(BuilderPlug.Me.MenusForm.ButtonSoundRadii);
if (General.Map.Config.DynamicLightSupport) General.Interface.RemoveMenu(BuilderPlug.Me.MenusForm.ItemLightRadii);
if (General.Map.Config.SoundSupport) General.Interface.RemoveMenu(BuilderPlug.Me.MenusForm.ItemSoundRadii);
General.Interface.EndToolbarUpdate(); //mxd
//mxd. Do some highlight management...
if(highlighted != null) highlighted.Highlighted = false;
// Going to EditSelectionMode?
EditSelectionMode mode = General.Editing.NewMode as EditSelectionMode;
if(mode != null)
codeimp
committed
// Not pasting anything?
if(!mode.Pasting)
codeimp
committed
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedThings(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
}
MaxED
committed
}
MaxED
committed
// Hide highlight info and tooltip
General.Interface.HideInfo();
MaxED
committed
General.Interface.Display.HideToolTip(); //mxd
}
// This redraws the display
public override void OnRedrawDisplay()
{
renderer.RedrawSurface();
List<Line3D> eventlines = new List<Line3D>(); //mxd
// Render lines and vertices
if(renderer.StartPlotter(true))
MaxED
committed
{
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
if (highlighted != null && !highlighted.IsDisposed) highlightasso.Plot();
renderer.Finish();
}
// Render things
if(renderer.StartThings(true))
{
float alpha = (General.Settings.FixedThingsScale ? Presentation.THINGS_ALPHA : General.Settings.ActiveThingsAlpha); //mxd
renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, General.Settings.HiddenThingsAlpha);
renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha);
renderer.RenderSRB2Extras();
if (highlighted != null && !highlighted.IsDisposed)
renderer.RenderThing(highlighted, General.Colors.Highlight, alpha);
//mxd. Event lines
if(General.Settings.GZShowEventLines) eventlines.AddRange(persistenteventlines);
//mxd. Dynamic light radii
if(BuilderPlug.Me.ShowLightRadii)
eventlines.AddRange(dynamiclightshapes);
if(highlighted != null && !highlighted.IsDisposed)
eventlines.AddRange(LinksCollector.GetDynamicLightShapes(new List<Thing> { highlighted }, true));
//mxd. Ambient sound radii
if(BuilderPlug.Me.ShowSoundRadii)
{
eventlines.AddRange(ambientsoundshapes);
if(highlighted != null && !highlighted.IsDisposed)
eventlines.AddRange(LinksCollector.GetAmbientSoundShapes(new List<Thing> { highlighted }, true));
}
if(eventlines.Count > 0) renderer.RenderArrows(eventlines);
renderer.Finish();
}
// Selecting?
if(renderer.StartOverlay(true))
if(selecting) RenderMultiSelection();
//mxd. Render sector tag labels
if(BuilderPlug.Me.ViewSelectionEffects && General.Map.FormatInterface.HasThingAction)
{
//mxd. sectorlabels will be null after switching map configuration from one
// without ThingAction to one with it while in Things mode
if(sectorlabels == null) SetupSectorLabels();
List<ITextLabel> torender = new List<ITextLabel>(sectorlabels.Count);
foreach(KeyValuePair<Sector, string[]> group in sectortexts)
{
// Pick which text variant to use
TextLabel[] labelarray = sectorlabels[group.Key];
for(int i = 0; i < group.Key.Labels.Count; i++)
{
TextLabel l = labelarray[i];
// Render only when enough space for the label to see
if (!textlabelsizecache.ContainsKey(group.Value[0]))
textlabelsizecache[group.Value[0]] = General.Interface.MeasureString(group.Value[0], l.Font).Width;
float requiredsize = textlabelsizecache[group.Value[0]] / 2 / renderer.Scale;
if (requiredsize > group.Key.Labels[i].radius)
{
if (!textlabelsizecache.ContainsKey(group.Value[1]))
textlabelsizecache[group.Value[1]] = General.Interface.MeasureString(group.Value[1], l.Font).Width;
requiredsize = textlabelsizecache[group.Value[1]] / 2 / renderer.Scale;
string newtext;
if (requiredsize > group.Key.Labels[i].radius)
newtext = (requiredsize > group.Key.Labels[i].radius * 4 ? string.Empty : "+");
newtext = group.Value[1];
if (l.Text != newtext)
l.Text = newtext;
}
else
{
if (group.Value[0] != l.Text)
l.Text = group.Value[0];
}
if (!string.IsNullOrEmpty(l.Text)) torender.Add(l);
}
}
// Render labels
renderer.RenderText(torender);
}
//mxd. Render selection labels
if(BuilderPlug.Me.ViewSelectionNumbers)
{
List<ITextLabel> torender = new List<ITextLabel>(labels.Count);
foreach(KeyValuePair<Thing, TextLabel> group in labels)
{
// Render only when enough space for the label to see
float requiredsize = (group.Value.TextSize.Width) / renderer.Scale;
if(group.Key.Size * 2 > requiredsize) torender.Add(group.Value);
}
renderer.RenderText(torender);
}
//mxd. Render comments
if(General.Map.UDMF && General.Settings.RenderComments) foreach(Thing t in General.Map.Map.Things) RenderComment(t);
renderer.Finish();
}
renderer.Present();
}
// This highlights a new item
MaxED
committed
private void Highlight(Thing t)
{
// Set highlight association
if(t != null)
{
//mxd. Update label color?
if(labels.ContainsKey(t)) labels[t].Color = General.Colors.Selection;
//check if this thing directly links to another type of thing
ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
int linktype = 0;
if (ti != null)
linktype = ti.ThingLink;
// New association highlights something?
}
{
}
if(highlighted != null) //mxd
{
//mxd. Update label color?
if(labels.ContainsKey(highlighted)) labels[highlighted].Color = General.Colors.Highlight;
highlighted.Highlighted = false;
}
MaxED
committed
// Set new highlight and redraw display
highlighted = t;
General.Interface.RedrawDisplay();
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
MaxED
committed
{
General.Interface.ShowThingInfo(highlighted);
MaxED
committed
}
MaxED
committed
{
General.Interface.Display.HideToolTip(); //mxd
General.Interface.HideInfo();
MaxED
committed
}
}
// Selection
protected override void OnSelectBegin()
{
//mxd. Yep, it's kinda hackish...
MaxED
committed
if(awaitingMouseClick)
{
awaitingMouseClick = false;
ThingPointAtCursor();
return;
}
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted), General.Settings.FixedThingsScale ? Presentation.THINGS_ALPHA : General.Settings.ActiveThingsAlpha);
renderer.Finish();
renderer.Present();
}
}
base.OnSelectBegin();
}
// End selection
protected override void OnSelectEnd()
{
// Not ending from a multi-selection?
if(!selecting)
{
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
//mxd. Flip selection
highlighted.Selected = !highlighted.Selected;
UpdateSelectionInfo(); //mxd
//mxd. Full redraw when labels were changed
if(BuilderPlug.Me.ViewSelectionNumbers)
{
General.Interface.RedrawDisplay();
}
else if(renderer.StartThings(false))
{
// Render highlighted item
renderer.RenderThing(highlighted, General.Colors.Highlight, General.Settings.FixedThingsScale ? Presentation.THINGS_ALPHA : General.Settings.ActiveThingsAlpha);
renderer.Finish();
renderer.Present();
}
MaxED
committed
}
MaxED
committed
//mxd
MaxED
committed
else if(BuilderPlug.Me.AutoClearSelection && General.Map.Map.SelectedThingsCount > 0)
{
MaxED
committed
General.Map.Map.ClearSelectedThings();
UpdateSelectionInfo();
MaxED
committed
General.Interface.RedrawDisplay();
}
}
base.OnSelectEnd();
}
// Start editing
protected override void OnEditBegin()
{
thinginserted = false;
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Edit pressed in this mode
editpressed = true;
// Highlighted item not selected?
biwa
committed
if(!highlighted.Selected)
{
// Make this the only selection
General.Map.Map.ClearSelectedThings();
editthings = new List<Thing> { highlighted };
UpdateSelectionInfo(); //mxd
General.Interface.RedrawDisplay();
}
biwa
committed
else
{
editthings = General.Map.Map.GetSelectedThings(true);
biwa
committed
}
// Update display
if(renderer.StartThings(false))
{
// Redraw highlight to show selection
biwa
committed
renderer.RenderThing(highlighted, General.Colors.Highlight, General.Settings.FixedThingsScale ? Presentation.THINGS_ALPHA : General.Settings.ActiveThingsAlpha);
renderer.Finish();
renderer.Present();
}
}
else if(mouseinside && !selecting && BuilderPlug.Me.AutoDrawOnEdit) //mxd. We don't want to insert a thing when multiselecting
// Edit pressed in this mode
editpressed = true;
thinginserted = true;
boris_i
committed
// Insert a new item and select it for dragging
General.Map.UndoRedo.CreateUndo("Insert thing");
Thing t = InsertThing(mousemappos);
MaxED
committed
if(t == null)
{
General.Map.UndoRedo.WithdrawUndo();
MaxED
committed
}
else
{
General.Map.Map.ClearSelectedThings();
biwa
committed
General.Map.Map.ClearMarkedThings(false);
editthings = new List<Thing> { t };
Highlight(t);
General.Interface.RedrawDisplay();
}
}
base.OnEditBegin();
}
// Done editing
protected override void OnEditEnd()
{
// Edit pressed in this mode?
if(editpressed)
{
if(editthings?.Count > 0)
{
if(General.Interface.IsActiveWindow)
{
// Edit only when preferred
if(!thinginserted || BuilderPlug.Me.EditNewThing)
{
// Prevent autosave while the editing dialog is shown
allowautosave = false;
MaxED
committed
//mxd. Show realtime thing edit dialog
General.Interface.OnEditFormValuesChanged += thingEditForm_OnValuesChanged;
biwa
committed
DialogResult result = General.Interface.ShowEditThings(editthings);
MaxED
committed
General.Interface.OnEditFormValuesChanged -= thingEditForm_OnValuesChanged;
//mxd. Update helper lines
UpdateHelperObjects();
//mxd. Update selection info
UpdateSelectionInfo();
// Update display
General.Interface.RedrawDisplay();
}
}
}
}
editpressed = false;
base.OnEditEnd();
}
//mxd
public override void OnUndoEnd()
{
base.OnUndoEnd();
// Select changed map elements
if (BuilderPlug.Me.SelectChangedafterUndoRedo)
{
General.Map.Map.SelectMarkedGeometry(true, true);
}
// If something is highlighted make sure to update the association so that it contains valid data
if (highlighted != null && !highlighted.IsDisposed)
highlightasso.Set(highlighted);
MaxED
committed
UpdateSelectionInfo(); // Update selection info and labels
UpdateHelperObjects(); // Update helper lines
SetupSectorLabels(); // And sector labels
}
//mxd
public override void OnRedoEnd()
{
base.OnRedoEnd();
// Select changed map elements
if (BuilderPlug.Me.SelectChangedafterUndoRedo)
{
General.Map.Map.SelectMarkedGeometry(true, true);
}
// If something is highlighted make sure to update the association so that it contains valid data
if (highlighted != null && !highlighted.IsDisposed)
highlightasso.Set(highlighted);
MaxED
committed
UpdateSelectionInfo(); // Update selection info and labels
UpdateHelperObjects(); // Update helper lines
SetupSectorLabels(); // And sector labels
}
public override void OnScriptRunEnd()
{
base.OnScriptRunEnd();
UpdateSelectionInfo();
General.Interface.RedrawDisplay();
}
//mxd. Otherwise event lines won't be drawn after panning finishes.
protected override void EndViewPan()
{
base.EndViewPan();
if(General.Settings.GZShowEventLines) General.Interface.RedrawDisplay();
}
MaxED
committed
//mxd
MaxED
committed
private void thingEditForm_OnValuesChanged(object sender, EventArgs e)
{
MaxED
committed
// Update things filter
General.Map.ThingsFilter.Update();
// Update entire display
General.Interface.RedrawDisplay();
}
// Mouse moves
public override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if(panning) return; //mxd. Skip all this jazz while panning
MaxED
committed
if(selectpressed && !editpressed && !selecting)
{
// Check if moved enough pixels for multiselect
Vector2D delta = mousedownpos - mousepos;
if((Math.Abs(delta.x) > BuilderPlug.Me.MouseSelectionThreshold) ||
(Math.Abs(delta.y) > BuilderPlug.Me.MouseSelectionThreshold))
MaxED
committed
{
// Start multiselecting
StartMultiSelection();
}
}
MaxED
committed
else if(paintselectpressed && !editpressed && !selecting) //mxd. Drag-select
{
// Find the nearest thing within highlight range
Thing t = MapSet.NearestThingSquareRange(General.Map.ThingsFilter.VisibleThings, mousemappos, BuilderPlug.Me.HighlightThingsRange / renderer.Scale);
MaxED
committed
if(t != null)
{
if(t != highlighted)
{
if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditivePaintSelect)
else if(General.Interface.CtrlState)
t.Selected = false;
else
t.Selected = !t.Selected;
highlighted = t;
UpdateSelectionInfo(); //mxd
// Update entire display
General.Interface.RedrawDisplay();
}
MaxED
committed
}
else if(highlighted != null)
MaxED
committed
{
Highlight(null);
// Update entire display
General.Interface.RedrawDisplay();
}
else if(e.Button == MouseButtons.None) // Not holding any buttons?
{
// Find the nearest thing within highlight range
Thing t = MapSet.NearestThingSquareRange(General.Map.ThingsFilter.VisibleThings, mousemappos, BuilderPlug.Me.HighlightThingsRange / renderer.Scale);
MaxED
committed
//mxd. Show tooltip?
MaxED
committed
if(General.Map.UDMF && General.Settings.RenderComments && mouselastpos != mousepos && highlighted != null && !highlighted.IsDisposed && highlighted.Fields.ContainsKey("comment"))
MaxED
committed
{
string comment = highlighted.Fields.GetValue("comment", string.Empty);
if(comment.Length > 2)
{
string type = comment.Substring(0, 3);
int index = Array.IndexOf(CommentType.Types, type);
if(index > 0) comment = comment.TrimStart(type.ToCharArray());
}
MaxED
committed
General.Interface.Display.ShowToolTip("Comment:", comment, (int)(mousepos.x + 32 * MainForm.DPIScaler.Width), (int)(mousepos.y + 8 * MainForm.DPIScaler.Height));
}
MaxED
committed
if(t != highlighted) Highlight(t);
}
// Mouse leaves
public override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
// Highlight nothing
Highlight(null);
}
MaxED
committed
protected override void OnPaintSelectBegin()
{
// Highlight nothing
Highlight(null);
// Mouse wants to drag
protected override void OnDragStart(MouseEventArgs e)
{
base.OnDragStart(e);
// Edit button used?
if(General.Actions.CheckActionActive(null, "classicedit"))
{
// Anything highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
ICollection<Thing> dragthings;
biwa
committed
// Highlighted item not selected?
if(!highlighted.Selected)
{
// Select only this thing for dragging
General.Map.Map.ClearSelectedThings();
dragthings = new List<Thing> { highlighted };
biwa
committed
}
else
{
// Add all selected things to the things we want to drag
dragthings = General.Map.Map.GetSelectedThings(true);
}
// Start dragging the selection
if(!BuilderPlug.Me.DontMoveGeometryOutsideMapBoundary || CanDrag(dragthings)) //mxd
MaxED
committed
{
// Shift pressed? Clone things!
bool thingscloned = false;
if(General.Interface.ShiftState)
MaxED
committed
{
ICollection<Thing> clonedthings = new List<Thing>(dragthings.Count);
biwa
committed
if(dragthings.Count > 0)
MaxED
committed
{
// Make undo
biwa
committed
General.Map.UndoRedo.CreateUndo((dragthings.Count == 1 ? "Clone-drag thing" : "Clone-drag " + dragthings.Count + " things"));
// Clone things
biwa
committed
foreach(Thing t in dragthings)
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
Thing clone = InsertThing(t.Position);
t.CopyPropertiesTo(clone);
// If the cloned item is an interpolation point or patrol point, then insert the point in the path
ThingTypeInfo info = General.Map.Data.GetThingInfo(t.Type);
int nextpointtagargnum = -1;
// Thing type can be changed in MAPINFO DoomEdNums block...
switch(info.ClassName.ToLowerInvariant())
{
case "interpolationpoint":
nextpointtagargnum = 3;
break;
case "patrolpoint":
nextpointtagargnum = 0;
break;
}
// Apply changes?
if(nextpointtagargnum != -1)
{
if(t.Tag == 0) t.Tag = General.Map.Map.GetNewTag();
t.Args[nextpointtagargnum] = clone.Tag = General.Map.Map.GetNewTag();
}
t.Selected = false;
biwa
committed
clonedthings.Add(clone);
// We'll want to skip creating additional Undo in DragThingsMode
thingscloned = true;
biwa
committed
// All the cloned things are now the things we want to drag
dragthings = clonedthings;
// Update things filter
General.Map.ThingsFilter.Update();
General.Interface.RefreshInfo();
//mxd. Update helper lines
UpdateHelperObjects();
// Redraw
General.Interface.RedrawDisplay();
}
}
biwa
committed
General.Editing.ChangeMode(new DragThingsMode(new ThingsMode(), mousedownmappos, dragthings, !thingscloned));
public override bool OnAutoSaveBegin()
{
return allowautosave;
}
//mxd. Check if any selected thing is outside of map boundary
private static bool CanDrag(ICollection<Thing> dragthings)
foreach(Thing t in dragthings)
MaxED
committed
{
// Make sure the vertex is inside the map boundary
if(t.Position.x < General.Map.Config.LeftBoundary || t.Position.x > General.Map.Config.RightBoundary
MaxED
committed
|| t.Position.y > General.Map.Config.TopBoundary || t.Position.y < General.Map.Config.BottomBoundary)
{
if (unaffectedCount == dragthings.Count)
MaxED
committed
{
General.Interface.DisplayStatus(StatusType.Warning, "Unable to drag selection: " + (dragthings.Count == 1 ? "selected thing is" : "all of selected things are") + " outside of map boundary!");
General.Interface.RedrawDisplay();
return false;
}
if (unaffectedCount > 0)
{
General.Interface.DisplayStatus(StatusType.Warning, unaffectedCount + " of selected vertices " + (unaffectedCount == 1 ? "is" : "are") + " outside of map boundary!");
return false;
}
}
// This is called wheh selection ends
protected override void OnEndMultiSelection()
{
bool selectionvolume = ((Math.Abs(selectionrect.Width) > 0.1f) && (Math.Abs(selectionrect.Height) > 0.1f));
if(selectionvolume)
MaxED
committed
switch(marqueSelectionMode)
{
case MarqueSelectionMode.SELECT:
// Get ordered selection
List<Thing> selectresult = GetOrderedSelection(base.selectstart, selectionrect);
// First deselect everything...
foreach(Thing t in General.Map.Map.Things) t.Selected = false;
// Then select things in correct order
foreach(Thing t in selectresult) t.Selected = true;
break;
case MarqueSelectionMode.ADD:
// Get ordered selection
List<Thing> addresult = GetOrderedSelection(selectstart, selectionrect);
// First deselect everything inside of selection...
foreach(Thing t in addresult) t.Selected = false;
// Then reselect in correct order
foreach(Thing t in addresult) t.Selected = true;
break;
case MarqueSelectionMode.SUBTRACT:
// Selection order doesn't matter here
foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
if(selectionrect.Contains((float)t.Position.x, (float)t.Position.y)) t.Selected = false;
// Should be Intersect selection mode
default:
// Selection order doesn't matter here
foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
if(!selectionrect.Contains((float)t.Position.x, (float)t.Position.y)) t.Selected = false;
UpdateSelectionInfo(); //mxd
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
}
base.OnEndMultiSelection();
// Clear overlay
if(renderer.StartOverlay(true)) renderer.Finish();
// Redraw
General.Interface.RedrawDisplay();
}
// This is called when the selection is updated
protected override void OnUpdateMultiSelection()
{
base.OnUpdateMultiSelection();
// Render selection
if(renderer.StartOverlay(true))
{
RenderMultiSelection();
renderer.Finish();
renderer.Present();
}
}
// When copying
public override bool OnCopyBegin()
{
// No selection made? But we have a highlight!
if((General.Map.Map.GetSelectedThings(true).Count == 0) && (highlighted != null))
{
// Make the highlight the selection
highlighted.Selected = true;
//mxd. Actually, we want it marked, not selected
bool result = base.OnCopyBegin();
highlighted.Selected = false;
return result;
}
return base.OnCopyBegin();
}
//mxd
private void RenderComment(Thing t)
{
if(t.Fields.ContainsKey("comment"))
{
float size = (((t.FixedSize || General.Settings.FixedThingsScale) && renderer.Scale > 1.0f) ? t.Size / renderer.Scale : t.Size);
if(size * renderer.Scale < 1.5f) return; // Thing is too small to render
int iconindex = 0;
string comment = t.Fields.GetValue("comment", string.Empty);
if(comment.Length > 2)
{
string type = comment.Substring(0, 3);
int index = Array.IndexOf(CommentType.Types, type);
if(index != -1) iconindex = index;
}
RectangleF rect = new RectangleF((float)(t.Position.x + size - 10 / renderer.Scale), (float)(t.Position.y + size + 18 / renderer.Scale), 16 / renderer.Scale, -16 / renderer.Scale);
PixelColor c = (t == highlighted ? General.Colors.Highlight : (t.Selected ? General.Colors.Selection : PixelColor.FromColor(Color.White)));
renderer.RenderRectangleFilled(rect, c, true, General.Map.Data.CommentTextures[iconindex]);
}
}
//mxd. Gets map elements inside of selectionoutline and sorts them by distance to targetpoint
private List<Thing> GetOrderedSelection(Vector2D targetpoint, RectangleF selection)
{
// Gather affected sectors
List<Thing> result = new List<Thing>();
foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
{
if(selection.Contains((float)t.Position.x, (float)t.Position.y)) result.Add(t);