Fixed, DECORATE parser: enums were not handled properly.

General interface: selection info is now always displayed.
Visual mode: you can now hold Alt-Shift or Ctrl-Alt while selecting sidedefs to stop selecting connected sidedefs when already (un)selected sidedef is encountered.
Added, Numeric Textbox: you can now use "+++" and "---" prefixes to incrementally increase or decrease result values by given value.
Fixed, Numeric Textbox: fixed a potential divide by zero exception when using "/" prefix in numeric textboxes with decimal input enabled.
Fixed, Thing Info panel: relative z position of things with "+SPAWNCEILING" flag was incorrect.
Changed: Update checker now displays messages using MessageBoxes when called manually.
Map Analysis: changed result descriptions for Unknown Texture and Missing Texture checks.
Doom map format: renamed "Secret" linedef flag to "Shown as 1-sided on automap".
Updated ZDoom_DECORATE.cfg (A_RadiusGive stuff).
This commit is contained in:
MaxED 2015-07-26 23:18:13 +00:00
parent 1118fd6b98
commit c6f9146b8b
23 changed files with 178 additions and 49 deletions

View file

@ -19,7 +19,7 @@ linedefflags
4 = "Double Sided";
8 = "Upper Unpegged";
16 = "Lower Unpegged";
32 = "Secret";
32 = "Shown as 1-sided on automap";
64 = "Block Sound";
128 = "Not shown on automap";
256 = "Initially shown on automap";

View file

@ -190,7 +190,7 @@ polyobj
{
title = "Movement Speed";
type = 11;
enum = "stair_speeds";
enum = "polyobj_speeds";
default = 16;
}

View file

@ -677,6 +677,18 @@ enums
32 = "32: Turbo";
}
polyobj_speeds
{
-32 = "-32: Turbo, CW";
-16 = "-16: Fast, CW";
-4 = "-4: Normal, CW";
-2 = "-2: Slow, CW";
2 = "2: Slow, CCW";
4 = "4: Normal, CCW";
16 = "16: Fast, CCW";
32 = "32: Turbo, CCW";
}
crush_mode
{
0 = "0: Compatibility";
@ -820,6 +832,21 @@ enums
60 = "1 Minute";
}
delay_seconds_0nodelay
{
0 = "No delay";
1 = "1 Second";
2 = "2 Seconds";
3 = "3 Seconds";
5 = "5 Seconds";
10 = "10 Seconds";
15 = "15 Seconds";
20 = "20 Seconds";
25 = "25 Seconds";
30 = "30 Seconds";
60 = "1 Minute";
}
reset_tics
{
0 = "0: Never";

View file

@ -1032,7 +1032,7 @@ zdoom
{
title = "Delay";
type = 11;
enum = "delay_seconds";
enum = "delay_seconds_0nodelay";
}
}

View file

@ -220,7 +220,7 @@ keywords
A_DropInventory = "A_DropInventory(str type)";
A_DropItem = "A_DropItem(str item[, int dropamount = -1[, int chance = 256]])\nThe calling actor drops the specified item.\nThis works in a similar way to the DropItem actor property.";
A_SelectWeapon = "A_SelectWeapon(str type)";
A_RadiusGive = "A_RadiusGive(str item, fixed distance, int flags[, int amount = 0])\nflags: RGF flags.";
A_RadiusGive = "A_RadiusGive(str item, fixed distance, int flags[, int amount = 0[, str filter = \"None\"[, str species = \"None\"]]])\nflags: RGF flags.";
//Weapon functions
A_WeaponReady = "A_WeaponReady[(int flags = 0)]\nflags: WRF flags.";
A_Lower = "A_Lower";
@ -1047,9 +1047,14 @@ constants
RGF_CENTERZ;
RGF_CORPSES;
RGF_CUBE;
RGF_EXFILTER;
RGF_EXPLICITANGLE;
RGF_EXSPECIES;
RGF_FULLBRIGHT;
RGF_GIVESELF;
RGF_INCLUSIVE;
RGF_ITEMS;
RGF_KILLED;
RGF_MISSILES;
RGF_MONSTERS;
RGF_NOMASTER;

View file

@ -37,7 +37,7 @@
<li>Open Map Options, Map Options and Game Configurations forms: resources can be added by dragging them on top of resources list.</li>
<li><strong>Game Configurations form</strong>: game configurations can be disabled. This setting is mostly cosmetic. When a game configuration is disabled, it won't be shown in the &quot;game configuration&quot; drop downs in New\Open Map Options and Map Options windows. If a map's .dbs file specifies a disabled configuration, it will be picked as a map configuration anyway.</li>
<li><strong>Game Configurations form</strong>: game configurations can be copied and pasted (a context menu is now available in the game configurations list).</li>
<li>Numeric textboxes: in addition to '++NN' and '--NN' to increment or decrement by given value, you can use '*NN' and '/NN' to multiply or divide by given value.</li>
<li>Numeric textboxes: in addition to '++NN' and '--NN' to increment or decrement by given value, you can use '*NN' and '/NN' to multiply or divide by given value, '+++N' and '---N' to incrementally increase or decrease by given value.</li>
<li>Toolbar button groups can be toggled using context menu. Hold &quot;Shift&quot; to toggle several button groups at once.
<input class="spoilerbutton" type="button" onclick="ToggleSpoiler(this);" href="javascript:void(0);" value="Show image"/>
<div style="display: none; margin: 0px; padding: 6px; border: 1px inset;"><img src="general/toolbarmenu.jpg" alt="" /></div>

View file

@ -203,12 +203,24 @@ namespace CodeImp.DoomBuilder.Controls
return textbox.GetResult(original);
}
//mxd. This determines the result value at given inremental step
public int GetResult(int original, int step)
{
return textbox.GetResult(original, step);
}
// This determines the result value
public float GetResultFloat(float original)
{
return textbox.GetResultFloat(original);
}
//mxd. This determines the result value at given inremental step
public float GetResultFloat(float original, int step)
{
return textbox.GetResultFloat(original, step);
}
//mxd
public void UpdateButtonsTooltip()
{

View file

@ -38,6 +38,7 @@ namespace CodeImp.DoomBuilder.Controls
private bool allowrelative; // Allow ++, --, * and / prefix for relative changes
private bool allowdecimal; // Allow decimal (float) numbers
private bool controlpressed;
private int incrementstep; //mxd. Step for +++ and --- prefixes
private readonly ToolTip tooltip; //mxd
#endregion
@ -58,7 +59,7 @@ namespace CodeImp.DoomBuilder.Controls
this.ImeMode = ImeMode.Off;
//mxd. Setup tooltip
this.tooltip = new ToolTip { AutomaticDelay = 100, AutoPopDelay = 4000, InitialDelay = 100, ReshowDelay = 100 };
this.tooltip = new ToolTip { AutomaticDelay = 100, AutoPopDelay = 8000, InitialDelay = 100, ReshowDelay = 100 };
}
#endregion
@ -82,6 +83,7 @@ namespace CodeImp.DoomBuilder.Controls
// When a key is pressed
protected override void OnKeyPress(KeyPressEventArgs e)
{
incrementstep = 0; //mxd
string allowedchars = "0123456789\b";
// Determine allowed chars
@ -146,17 +148,17 @@ namespace CodeImp.DoomBuilder.Controls
// Limit the number of + and - allowed
int numprefixes = nonselectedtext.Split(e.KeyChar, otherprefix).Length;
if(numprefixes > 2)
if(numprefixes > 3)
{
// Can't have more than 2 prefixes
// Can't have more than 3 prefixes (mxd)
e.Handled = true;
}
else if(numprefixes > 1)
{
// Must have 2 the same prefixes
// Must have 2 or 3 same prefixes
if(this.Text.IndexOf(e.KeyChar) == -1) e.Handled = true;
// Double prefix must be allowed
// Double or triple prefix must be allowed
if(!allowrelative) e.Handled = true;
}
}
@ -204,13 +206,20 @@ namespace CodeImp.DoomBuilder.Controls
// This checks if the number is relative
public bool CheckIsRelative()
{
// Prefixed with ++, --, * or /?
return ( (this.Text.Length > 2 && (this.Text.StartsWith("++") || this.Text.StartsWith("--"))) ||
// Prefixed with +++, ---, ++, --, * or /?
return ( (this.Text.Length > 3 && (this.Text.StartsWith("+++") || this.Text.StartsWith("---"))) || //mxd
(this.Text.Length > 2 && (this.Text.StartsWith("++") || this.Text.StartsWith("--") || this.Text.StartsWith("**") || this.Text.StartsWith("//"))) || //mxd
(this.Text.Length > 1 && (this.Text.StartsWith("*") || this.Text.StartsWith("/"))) ); //mxd
}
// This determines the result value
//mxd. This determines the result value
public int GetResult(int original)
{
return GetResult(original, incrementstep++);
}
//mxd. This determines the result value
public int GetResult(int original, int step)
{
string textpart = this.Text;
@ -222,6 +231,22 @@ namespace CodeImp.DoomBuilder.Controls
{
int result;
//mxd. Prefixed with +++?
if(this.Text.StartsWith("+++"))
{
// Add number to original
int.TryParse(textpart, out result);
return original + result * step;
}
//mxd. Prefixed with ---?
if(this.Text.StartsWith("---"))
{
// Subtract number from original
int.TryParse(textpart, out result);
int newvalue = original - result * step;
if(!allownegative && (newvalue < 0)) newvalue = 0;
return newvalue;
}
// Prefixed with ++?
if(this.Text.StartsWith("++"))
{
@ -270,8 +295,14 @@ namespace CodeImp.DoomBuilder.Controls
return original;
}
// This determines the result value
//mxd. This determines the result value
public float GetResultFloat(float original)
{
return GetResultFloat(original, incrementstep++);
}
// This determines the result value
public float GetResultFloat(float original, int step)
{
// Strip prefixes
string textpart = this.Text.Replace("+", "").Replace("-", "").Replace("*", "").Replace("/", ""); //mxd;
@ -281,6 +312,22 @@ namespace CodeImp.DoomBuilder.Controls
{
float result;
//mxd. Prefixed with +++?
if(this.Text.StartsWith("+++"))
{
// Add number to original
if(!float.TryParse(textpart, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) result = 0;
return original + result * step;
}
//mxd. Prefixed with ---?
if(this.Text.StartsWith("---"))
{
// Subtract number from original
if(!float.TryParse(textpart, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) result = 0;
float newvalue = original - result * step;
if(!allownegative && (newvalue < 0)) newvalue = 0;
return newvalue;
}
// Prefixed with ++?
if(this.Text.StartsWith("++"))
{
@ -310,7 +357,7 @@ namespace CodeImp.DoomBuilder.Controls
if(this.Text.StartsWith("/"))
{
// Divide original by number
if(!float.TryParse(textpart, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) return original;
if(!float.TryParse(textpart, NumberStyles.Float, CultureInfo.CurrentCulture, out result) || result == 0) return original;
float newvalue = (float)Math.Round(original / result, 3);
if(!allownegative && (newvalue < 0)) newvalue = 0;
return newvalue;
@ -338,7 +385,9 @@ namespace CodeImp.DoomBuilder.Controls
this.ForeColor = (allowrelative ? SystemColors.HotTrack : SystemColors.WindowText);
if (allowrelative)
{
tooltip.SetToolTip(this, "Use ++ or -- prefixes to change\r\nexisting values by given value.\r\nUse * or / prefixes to multiply\r\nor divide existing values by given value." + Environment.NewLine + tip);
tooltip.SetToolTip(this, "Use ++ or -- prefixes to change by given value." + Environment.NewLine +
"Use +++ or --- prefixes to incrementally change by given value." + Environment.NewLine +
"Use * or / prefixes to multiply or divide by given value." + Environment.NewLine + tip);
}
else if(!string.IsNullOrEmpty(tip))
{

View file

@ -99,7 +99,7 @@ namespace CodeImp.DoomBuilder.Controls
{
// Hangs from ceiling?
if(ti.Hangs)
zinfo = (t.Position.z - ti.Height) + " (" + ((float)Math.Round(Sector.GetCeilingPlane(t.Sector).GetZ(t.Position) - t.Position.z - ti.Height, General.Map.FormatInterface.VertexDecimals)).ToString(CultureInfo.InvariantCulture) + ")"; //mxd
zinfo = t.Position.z + " (" + ((float)Math.Round(Sector.GetCeilingPlane(t.Sector).GetZ(t.Position) - t.Position.z - ti.Height, General.Map.FormatInterface.VertexDecimals)).ToString(CultureInfo.InvariantCulture) + ")"; //mxd
else
zinfo = t.Position.z + " (" + ((float)Math.Round(Sector.GetFloorPlane(t.Sector).GetZ(t.Position) + t.Position.z, General.Map.FormatInterface.VertexDecimals)).ToString(CultureInfo.InvariantCulture) + ")"; //mxd
}

View file

@ -97,12 +97,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
public void ApplyTo(UniFields fields, int min, int max, float oldValue1, float oldValue2)
{
if(value1.Text != string.Empty)
UDMFTools.SetFloat(fields, field1, General.Clamp(value1.GetResultFloat(defaultValue), min, max), defaultValue);
UDMFTools.SetFloat(fields, field1, General.Clamp(value1.GetResultFloat(oldValue1), min, max), defaultValue);
else
UDMFTools.SetFloat(fields, field1, oldValue1, defaultValue);
if(value2.Text != string.Empty)
UDMFTools.SetFloat(fields, field2, General.Clamp(value2.GetResultFloat(defaultValue), min, max), defaultValue);
UDMFTools.SetFloat(fields, field2, General.Clamp(value2.GetResultFloat(oldValue2), min, max), defaultValue);
else
UDMFTools.SetFloat(fields, field2, oldValue2, defaultValue);
}
@ -110,7 +110,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
private void CheckValues()
{
changed = string.IsNullOrEmpty(value1.Text) || string.IsNullOrEmpty(value2.Text)
|| value1.GetResultFloat(defaultValue) != defaultValue || value2.GetResultFloat(defaultValue) != defaultValue;
|| value1.GetResultFloat(defaultValue, 0) != defaultValue || value2.GetResultFloat(defaultValue, 0) != defaultValue;
bReset.Visible = changed;
if(!blockUpdate && OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);

View file

@ -75,7 +75,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
private void CheckValues()
{
changed = (string.IsNullOrEmpty(value1.Text) || string.IsNullOrEmpty(value2.Text)
|| value1.GetResultFloat(defaultValue) != defaultValue || value2.GetResultFloat(defaultValue) != defaultValue);
|| value1.GetResultFloat(defaultValue, 0) != defaultValue || value2.GetResultFloat(defaultValue, 0) != defaultValue);
bReset.Visible = changed;
if (!blockUpdate && OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);

View file

@ -74,7 +74,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls
private void CheckValues()
{
changed = string.IsNullOrEmpty(value1.Text) || string.IsNullOrEmpty(value2.Text)
|| value1.GetResult(defaultValue) != defaultValue || value2.GetResult(defaultValue) != defaultValue;
|| value1.GetResult(defaultValue, 0) != defaultValue || value2.GetResult(defaultValue, 0) != defaultValue;
bReset.Visible = changed;
if(!blockUpdate && OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);

View file

@ -741,7 +741,7 @@ namespace CodeImp.DoomBuilder
}
else
{
UpdateChecker.PerformCheck();
UpdateChecker.PerformCheck(false);
}
}

View file

@ -3,6 +3,7 @@ using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Forms;
using System.Xml;
namespace CodeImp.DoomBuilder
@ -11,16 +12,25 @@ namespace CodeImp.DoomBuilder
{
private static BackgroundWorker worker;
private static string errordesc;
private static bool verbose;
internal static void PerformCheck()
internal static void PerformCheck(bool verbosemode)
{
if(worker != null && worker.IsBusy)
{
General.ErrorLogger.Add(ErrorType.Warning, "Update check is already running!");
General.MainWindow.ShowErrors();
if(verbosemode)
{
General.ShowWarningMessage("Update check is already running!", MessageBoxButtons.OK);
}
else
{
General.ErrorLogger.Add(ErrorType.Warning, "Update check is already running!");
General.MainWindow.ShowErrors();
}
return;
}
verbose = verbosemode;
worker = new BackgroundWorker();
worker.DoWork += DoWork;
worker.RunWorkerCompleted += RunWorkerCompleted;
@ -81,6 +91,10 @@ namespace CodeImp.DoomBuilder
// Pass data to MainForm
General.MainWindow.UpdateAvailable(remoterev, changelog);
}
else if(verbose)
{
errordesc = "Your version is up to date";
}
}
private static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs)
@ -88,8 +102,15 @@ namespace CodeImp.DoomBuilder
worker = null;
if(!string.IsNullOrEmpty(errordesc))
{
General.ErrorLogger.Add(ErrorType.Warning, errordesc);
General.MainWindow.ShowErrors();
if(verbose)
{
General.ShowWarningMessage(errordesc, MessageBoxButtons.OK);
}
else
{
General.ErrorLogger.Add(ErrorType.Warning, errordesc);
General.MainWindow.ShowErrors();
}
}
}

View file

@ -1007,12 +1007,13 @@ visualselect
{
title = "Select";
category = "visual";
description = "Selects the highlighted item. Hold Shift to select adjacent surfaces with the same texture. Hold Ctrl to select adjacent surfaces with the same height";
description = "Selects the highlighted item. Hold Shift to select adjacent surfaces with the same texture. Hold Ctrl to select adjacent surfaces with the same height. Hold Alt to stop selecting adjacent surfaces when already selected surface is encountered.";
allowkeys = true;
allowmouse = true;
allowscroll = false;
disregardcontrol = true;
disregardshift = true;
disregardalt = true;
}
visualedit

View file

@ -841,6 +841,7 @@ namespace CodeImp.DoomBuilder.Windows
case StatusType.Info:
if(!newstatus.displayed)
{
newstatus.message = selectionInfo + " " + newstatus.message; //mxd
statusresetter.Interval = INFO_RESET_DELAY;
statusresetter.Start();
}
@ -850,6 +851,7 @@ namespace CodeImp.DoomBuilder.Windows
case StatusType.Action:
if(!newstatus.displayed)
{
newstatus.message = selectionInfo + " " + newstatus.message; //mxd
statusflashicon = true;
statusflasher.Interval = ACTION_FLASH_INTERVAL;
statusflashcount = ACTION_FLASH_COUNT;
@ -863,6 +865,7 @@ namespace CodeImp.DoomBuilder.Windows
case StatusType.Warning:
if(!newstatus.displayed)
{
newstatus.message = selectionInfo + " " + newstatus.message; //mxd
MessageBeep(MessageBeepType.Warning);
statusflasher.Interval = WARNING_FLASH_INTERVAL;
statusflashcount = WARNING_FLASH_COUNT;
@ -876,8 +879,7 @@ namespace CodeImp.DoomBuilder.Windows
// Update status description
status = newstatus;
status.displayed = true;
if(statuslabel.Text != status.message)
statuslabel.Text = status.message;
statuslabel.Text = status.message;
// Update icon as well
UpdateStatusIcon();
@ -2770,7 +2772,7 @@ namespace CodeImp.DoomBuilder.Windows
//mxd. Check updates clicked
private void itemhelpcheckupdates_Click(object sender, EventArgs e)
{
UpdateChecker.PerformCheck();
UpdateChecker.PerformCheck(true);
}
// About clicked

View file

@ -111,6 +111,7 @@
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Newsflash (R[rev])!";
this.Shown += new System.EventHandler(this.UpdateForm_Shown);
this.ResumeLayout(false);
this.PerformLayout();

View file

@ -16,6 +16,10 @@ namespace CodeImp.DoomBuilder.Windows
this.Text = this.Text.Replace("[rev]", remoterev.ToString());
this.label.Text = label.Text.Replace("[rev]", remoterev.ToString());
this.changelog.SelectedRtf = changelog;
}
private void UpdateForm_Shown(object sender, EventArgs e)
{
this.changelog.Focus();
}

View file

@ -170,7 +170,7 @@ namespace CodeImp.DoomBuilder.ZDoom
break;
}
}
else if((objdeclaration == "const") || (objdeclaration == "native"))
else if((objdeclaration == "const") || (objdeclaration == "native") || (objdeclaration == "enum"))
{
// We don't need this, ignore up to the first next ;
while(SkipWhitespace(true))

View file

@ -77,13 +77,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
switch (part)
{
case SidedefPart.Upper:
return "Sidedef " + side.Index + " has missing upper texture (" + sidestr + " side)";
return "Linedef " + side.Line.Index + " has missing upper texture (" + sidestr + " side)";
case SidedefPart.Middle:
return "Sidedef " + side.Index + " has missing middle texture (" + sidestr + " side)";
return "Linedef " + side.Line.Index + " has missing middle texture (" + sidestr + " side)";
case SidedefPart.Lower:
return "Sidedef " + side.Index + " has missing lower texture (" + sidestr + " side)";
return "Linedef " + side.Line.Index + " has missing lower texture (" + sidestr + " side)";
default:
return "ERROR";

View file

@ -77,13 +77,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
switch(part)
{
case SidedefPart.Upper:
return "Sidedef " + side.Index + " has unknown upper texture \"" + side.HighTexture + "\"";
return "Linedef " + side.Line.Index + " has unknown upper texture \"" + side.HighTexture + "\" (" + (side.IsFront ? "front" : "back") + " side)";
case SidedefPart.Middle:
return "Sidedef " + side.Index + " has unknown middle texture \"" + side.MiddleTexture + "\"";
return "Linedef " + side.Line.Index + " has unknown middle texture \"" + side.MiddleTexture + "\" (" + (side.IsFront ? "front" : "back") + " side)";
case SidedefPart.Lower:
return "Sidedef " + side.Index + " has unknown lower texture \"" + side.LowTexture + "\"";
return "Linedef " + side.Line.Index + " has unknown lower texture \"" + side.LowTexture + "\" (" + (side.IsFront ? "front" : "back") + " side)";
default:
return "ERROR";

View file

@ -121,7 +121,7 @@ group sidedefs
"Use <k>builder_moveup</k> and <k>builder_movedown</k> to move up and down"
"Press <k>builder_gztogglevisualvertices</k> to toggle vertex handles rendering (UDMF only)"
"Press <k>builder_insertitem</k> to insert a thing at current cursor position"
"Press <k>builder_visualselect</k> to select the highlighted surface. Hold <b>Shift</b> to select adjacent surfaces with the same texture. Hold <b>Ctrl</b> to select adjacent surfaces with the same height"
"Press <k>builder_visualselect</k> to select the highlighted surface. Hold <b>Shift</b> to select adjacent surfaces with the same texture. Hold <b>Ctrl</b> to select adjacent surfaces with the same height. Hold <b>Alt</b> to stop selecting adjacent surfaces when already selected surface is encountered"
"Press <k>builder_deleteitem</k> to remove textures from selected surfaces"
"Use <k>buildermodes_movetextureleft</k>, <k>buildermodes_movetextureright</k>, <k>buildermodes_movetextureup</k> and <k>buildermodes_movetexturedown</k> to change texture offsets by 1 mp."
"Use <k>buildermodes_movetextureleft8</k>, <k>buildermodes_movetextureright8</k>, <k>buildermodes_movetextureup8</k> and <k>buildermodes_movetexturedown8</k> to change texture offsets by current grid size"

View file

@ -668,7 +668,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
string result = string.Join(", ", results.ToArray());
int pos = result.LastIndexOf(",");
if(pos != -1) result = result.Remove(pos, 1).Insert(pos, " and");
General.Interface.DisplayStatus(StatusType.Selection, result + " selected");
General.Interface.DisplayStatus(StatusType.Selection, result + " selected.");
}
}
@ -1937,11 +1937,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd
if((General.Interface.ShiftState || General.Interface.CtrlState) && selectedobjects.Count > 0)
{
IVisualEventReceiver[] selection = new IVisualEventReceiver[selectedobjects.Count];
selectedobjects.CopyTo(selection);
if(General.Interface.AltState)
{
target.SelectNeighbours(target.IsSelected(), General.Interface.ShiftState, General.Interface.CtrlState);
}
else
{
IVisualEventReceiver[] selection = new IVisualEventReceiver[selectedobjects.Count];
selectedobjects.CopyTo(selection);
foreach(IVisualEventReceiver obj in selection)
obj.SelectNeighbours(target.IsSelected(), General.Interface.ShiftState, General.Interface.CtrlState);
foreach(IVisualEventReceiver obj in selection)
obj.SelectNeighbours(target.IsSelected(), General.Interface.ShiftState, General.Interface.CtrlState);
}
}
Renderer.ShowSelection = true;