2015-12-31 12:21:44 +00:00
#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 ;
using CodeImp.DoomBuilder.Data ;
using CodeImp.DoomBuilder.Editing ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.GZBuilder.Geometry ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Rendering ;
using CodeImp.DoomBuilder.Types ;
using CodeImp.DoomBuilder.Windows ;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[ EditMode ( DisplayName = "Linedefs Mode" ,
SwitchAction = "linedefsmode" , // Action name used to switch to this mode
ButtonImage = "LinesMode.png" , // Image resource name for the button
ButtonOrder = int . MinValue + 100 , // Position of the button (lower is more to the left)
ButtonGroup = "000_editing" ,
UseByDefault = true ,
SafeStartMode = true ) ]
public class LinedefsMode : BaseClassicMode
{
#region = = = = = = = = = = = = = = = = = = Constants
2016-04-04 22:20:49 +00:00
private const int MAX_LINEDEF_LABELS = 256 ; //mxd
2015-12-31 12:21:44 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Highlighted item
private Linedef highlighted ;
private readonly Association [ ] association = new Association [ Linedef . NUM_ARGS ] ;
private readonly Association highlightasso = new Association ( ) ;
private Vector2D insertpreview = new Vector2D ( float . NaN , float . NaN ) ; //mxd
2016-04-04 22:20:49 +00:00
//mxd. Text labels
2016-04-17 22:52:03 +00:00
private Dictionary < Linedef , SelectionLabel > labels ;
2016-04-04 22:20:49 +00:00
private Dictionary < Sector , TextLabel [ ] > sectorlabels ;
private Dictionary < Sector , string [ ] > sectortexts ;
2015-12-31 12:21:44 +00:00
// Interface
private bool editpressed ;
2016-09-27 19:39:46 +00:00
private bool selectionfromhighlight ; //mxd
2020-10-31 15:09:22 +00:00
2020-10-31 20:06:24 +00:00
// Stores sizes of the text for text labels so that they only have to be computed once
private Dictionary < string , float > textlabelsizecache ;
2015-12-31 12:21:44 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
public override object HighlightedObject { get { return highlighted ; } }
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
public LinedefsMode ( )
{
//mxd. Associations now requre initializing...
for ( int i = 0 ; i < association . Length ; i + + ) association [ i ] = new Association ( ) ;
2020-10-31 20:06:24 +00:00
textlabelsizecache = new Dictionary < string , float > ( ) ;
2015-12-31 12:21:44 +00:00
}
2016-04-04 22:20:49 +00:00
//mxd
public override void Dispose ( )
{
// Not already disposed?
if ( ! isdisposed )
{
// Dispose old labels
2016-04-17 22:52:03 +00:00
if ( labels ! = null ) foreach ( SelectionLabel l in labels . Values ) l . Dispose ( ) ;
2016-04-04 22:20:49 +00:00
if ( sectorlabels ! = null )
{
foreach ( TextLabel [ ] lbl in sectorlabels . Values )
foreach ( TextLabel l in lbl ) l . Dispose ( ) ;
}
// Dispose base
base . Dispose ( ) ;
}
}
2015-12-31 12:21:44 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Methods
2022-12-21 01:21:30 +00:00
public int CreateSelectionCRC ( )
{
CRC crc = new CRC ( ) ;
ICollection < Linedef > orderedselection = General . Map . Map . GetSelectedLinedefs ( true ) ;
crc . Add ( orderedselection . Count ) ;
foreach ( Linedef l in orderedselection )
{
crc . Add ( l . Index ) ;
}
return ( int ) ( crc . Value & 0xFFFFFFFF ) ;
}
//mxd. This makes a CRC for given selection
private static int CreateSelectionCRC ( ICollection < Linedef > selection )
{
CRC crc = new CRC ( ) ;
crc . Add ( selection . Count ) ;
foreach ( Linedef l in selection ) crc . Add ( l . Index ) ;
return ( int ) ( crc . Value & 0xFFFFFFFF ) ;
}
2015-12-31 12:21:44 +00:00
// This highlights a new item
private void Highlight ( Linedef l )
{
bool completeredraw = false ;
// Often we can get away by simply undrawing the previous
// highlight and drawing the new highlight. But if associations
// are or were drawn we need to redraw the entire display.
2016-04-04 22:20:49 +00:00
if ( highlighted ! = null )
{
//mxd. Update label color?
if ( labels . ContainsKey ( highlighted ) )
{
labels [ highlighted ] . Color = General . Colors . Highlight ;
completeredraw = true ;
}
// Previous association highlights something?
if ( highlighted . Tag ! = 0 ) completeredraw = true ;
}
2015-12-31 12:21:44 +00:00
// Set highlight association
2016-04-04 22:20:49 +00:00
if ( l ! = null )
{
//mxd. Update label color?
if ( labels . ContainsKey ( l ) )
{
labels [ l ] . Color = General . Colors . Selection ;
completeredraw = true ;
}
// New association highlights something?
if ( l . Tag ! = 0 )
{
highlightasso . Set ( new Vector2D ( ( l . Start . Position + l . End . Position ) / 2 ) , l . Tags , UniversalType . LinedefTag ) ;
completeredraw = true ;
}
}
2015-12-31 12:21:44 +00:00
else
2016-04-04 22:20:49 +00:00
{
2015-12-31 12:21:44 +00:00
highlightasso . Set ( new Vector2D ( ) , 0 , 0 ) ;
2016-04-04 22:20:49 +00:00
}
2015-12-31 12:21:44 +00:00
// Use the line tag to highlight sectors (Doom style)
if ( General . Map . Config . LineTagIndicatesSectors )
{
if ( l ! = null )
association [ 0 ] . Set ( new Vector2D ( ( l . Start . Position + l . End . Position ) / 2 ) , l . Tags , UniversalType . SectorTag ) ;
else
association [ 0 ] . Set ( new Vector2D ( ) , 0 , 0 ) ;
}
else
{
2016-04-04 22:20:49 +00:00
LinedefActionInfo action = null ;
2015-12-31 12:21:44 +00:00
if ( l ! = null )
{
// Check if we can find the linedefs action
if ( ( l . Action > 0 ) & & General . Map . Config . LinedefActions . ContainsKey ( l . Action ) )
action = General . Map . Config . LinedefActions [ l . Action ] ;
}
// Determine linedef associations
for ( int i = 0 ; i < Linedef . NUM_ARGS ; i + + )
{
// Previous association highlights something?
if ( ( association [ i ] . Type = = UniversalType . SectorTag ) | |
( association [ i ] . Type = = UniversalType . LinedefTag ) | |
( association [ i ] . Type = = UniversalType . ThingTag ) ) completeredraw = true ;
// Make new association
if ( action ! = null )
association [ i ] . Set ( new Vector2D ( ( l . Start . Position + l . End . Position ) / 2 ) , l . Args [ i ] , action . Args [ i ] . Type ) ;
else
association [ i ] . Set ( new Vector2D ( ) , 0 , 0 ) ;
// New association highlights something?
if ( ( association [ i ] . Type = = UniversalType . SectorTag ) | |
( association [ i ] . Type = = UniversalType . LinedefTag ) | |
( association [ i ] . Type = = UniversalType . ThingTag ) ) completeredraw = true ;
}
}
// If we're changing associations, then we
// need to redraw the entire display
if ( completeredraw )
{
// Set new highlight and redraw completely
highlighted = l ;
General . Interface . RedrawDisplay ( ) ;
}
else
{
// Update display
if ( renderer . StartPlotter ( false ) )
{
// Undraw previous highlight
Linedef possiblecommentline = l ? ? highlighted ; //mxd
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
renderer . PlotLinedef ( highlighted , renderer . DetermineLinedefColor ( highlighted ) ) ;
renderer . PlotVertex ( highlighted . Start , renderer . DetermineVertexColor ( highlighted . Start ) ) ;
renderer . PlotVertex ( highlighted . End , renderer . DetermineVertexColor ( highlighted . End ) ) ;
}
// Set new highlight
highlighted = l ;
// Render highlighted item
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
renderer . PlotLinedef ( highlighted , General . Colors . Highlight ) ;
renderer . PlotVertex ( highlighted . Start , renderer . DetermineVertexColor ( highlighted . Start ) ) ;
renderer . PlotVertex ( highlighted . End , renderer . DetermineVertexColor ( highlighted . End ) ) ;
}
// Done with highlight
renderer . Finish ( ) ;
//mxd. Update comment highlight?
if ( General . Map . UDMF & & General . Settings . RenderComments
& & possiblecommentline ! = null & & ! possiblecommentline . IsDisposed
& & renderer . StartOverlay ( false ) )
{
RenderComment ( possiblecommentline ) ;
renderer . Finish ( ) ;
}
renderer . Present ( ) ;
}
}
// Show highlight info
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
General . Interface . ShowLinedefInfo ( highlighted ) ;
}
else
{
General . Interface . Display . HideToolTip ( ) ; //mxd
General . Interface . HideInfo ( ) ;
}
}
//mxd
2021-06-04 23:37:39 +00:00
private void AlignTextureToLine ( bool alignFloors , bool alignToFrontSide )
2015-12-31 12:21:44 +00:00
{
2021-06-04 23:37:39 +00:00
if ( ! General . Map . UDMF & & ! General . Map . SRB2 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action only works in UDMF or SRB2 map format." ) ;
return ;
}
2015-12-31 12:21:44 +00:00
ICollection < Linedef > lines = General . Map . Map . GetSelectedLinedefs ( true ) ;
2021-06-04 23:37:39 +00:00
if ( lines . Count = = 0 & & highlighted ! = null & & ! highlighted . IsDisposed )
2015-12-31 12:21:44 +00:00
lines . Add ( highlighted ) ;
2021-05-06 11:18:50 +00:00
if ( lines . Count = = 0 )
2015-12-31 12:21:44 +00:00
{
2021-05-06 11:18:50 +00:00
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
2021-06-04 23:37:39 +00:00
if ( General . Map . SRB2 & & ! alignToFrontSide )
2021-05-06 11:18:50 +00:00
{
2021-06-04 23:37:39 +00:00
General . Interface . DisplayStatus ( StatusType . Warning , "SRB2 only supports front-side alignment!" ) ;
2015-12-31 12:21:44 +00:00
return ;
}
//Create Undo
2021-05-06 11:18:50 +00:00
string rest = ( alignFloors ? "floors" : "ceilings" ) + " to " + ( alignToFrontSide ? "front" : "back" ) + " side" ;
2015-12-31 12:21:44 +00:00
General . Map . UndoRedo . CreateUndo ( "Align " + rest ) ;
int counter = 0 ;
2021-05-06 11:18:50 +00:00
foreach ( Linedef l in lines )
2015-12-31 12:21:44 +00:00
{
Sector s = null ;
if ( alignToFrontSide )
if ( l . Front ! = null & & l . Front . Sector ! = null ) s = l . Front . Sector ;
else
2021-06-04 23:37:39 +00:00
if ( l . Back ! = null & & l . Back . Sector ! = null ) s = l . Back . Sector ;
2015-12-31 12:21:44 +00:00
if ( s = = null ) continue ;
counter + + ;
s . Fields . BeforeFieldsChange ( ) ;
2021-05-06 11:18:50 +00:00
// hack for SRB2 flat alignment
if ( General . Map . SRB2 )
{
bool existing = true ;
2021-05-10 21:52:54 +00:00
2021-05-06 11:18:50 +00:00
if ( ! l . IsFlatAlignment )
{
2021-05-10 21:52:54 +00:00
if ( l . Action ! = 0 ) // don't overwrite other actions
continue ;
else
{
l . Action = General . Map . FormatInterface . FlatAlignmentType ;
existing = false ;
}
}
if ( l . Tag ! = 0 )
{
l . Tag = 0 ;
2021-05-06 11:18:50 +00:00
existing = false ;
}
if ( alignFloors )
{
if ( l . IsFlagSet ( "2048" ) )
l . SetFlag ( "2048" , false ) ; // enable floor alignment for existing lines
else if ( ! existing )
l . SetFlag ( "4096" , true ) ; // disable ceiling alignment for new lines
2021-06-04 23:37:39 +00:00
else if ( l . IsFlagSet ( "8192" ) )
l . SetFlag ( "8192" , false ) ; // don't use offsets
2021-05-06 11:18:50 +00:00
else
l . SetFlag ( "2048" , true ) ; // toggle floor alignment
s . UpdateFloorSurface ( ) ;
}
else
{
if ( l . IsFlagSet ( "4096" ) )
l . SetFlag ( "4096" , false ) ; // enable ceiling alignment for existing lines
else if ( ! existing )
l . SetFlag ( "2048" , true ) ; // disable floor alignment for new lines
2021-06-04 23:37:39 +00:00
else if ( l . IsFlagSet ( "8192" ) )
l . SetFlag ( "8192" , false ) ; // don't use offsets
2021-05-06 11:18:50 +00:00
else
l . SetFlag ( "4096" , true ) ; // toggle ceiling alignment
s . UpdateCeilingSurface ( ) ;
}
if ( l . IsFlagSet ( "2048" ) & & l . IsFlagSet ( "4096" ) ) // clear action if it does nothing
{
l . SetFlag ( "2048" , false ) ;
l . SetFlag ( "4096" , false ) ;
l . Action = 0 ;
}
s . UpdateNeeded = true ;
s . UpdateCache ( ) ;
2021-06-04 23:37:39 +00:00
l . UpdateCache ( ) ;
2021-05-06 11:18:50 +00:00
continue ;
}
2015-12-31 12:21:44 +00:00
float sourceAngle = ( float ) Math . Round ( General . ClampAngle ( alignToFrontSide ? - Angle2D . RadToDeg ( l . Angle ) + 90 : - Angle2D . RadToDeg ( l . Angle ) - 90 ) , 1 ) ;
if ( ! alignToFrontSide ) sourceAngle = General . ClampAngle ( sourceAngle + 180 ) ;
//update angle
UniFields . SetFloat ( s . Fields , ( alignFloors ? "rotationfloor" : "rotationceiling" ) , sourceAngle , 0f ) ;
//update offset
Vector2D offset = ( alignToFrontSide ? l . Start . Position : l . End . Position ) . GetRotated ( Angle2D . DegToRad ( sourceAngle ) ) ;
ImageData texture = General . Map . Data . GetFlatImage ( s . LongFloorTexture ) ;
if ( ( texture = = null ) | | ( texture = = General . Map . Data . WhiteTexture ) | |
( texture . Width < = 0 ) | | ( texture . Height < = 0 ) | | ! texture . IsImageLoaded )
{
//meh...
}
else
{
2017-01-28 18:11:49 +00:00
offset . x % = texture . Width / s . Fields . GetValue ( ( alignFloors ? "xscalefloor" : "xscaleceiling" ) , 1.0f ) ;
2015-12-31 12:21:44 +00:00
offset . y % = texture . Height / s . Fields . GetValue ( ( alignFloors ? "yscalefloor" : "yscaleceiling" ) , 1.0f ) ;
}
UniFields . SetFloat ( s . Fields , ( alignFloors ? "xpanningfloor" : "xpanningceiling" ) , ( float ) Math . Round ( - offset . x ) , 0f ) ;
UniFields . SetFloat ( s . Fields , ( alignFloors ? "ypanningfloor" : "ypanningceiling" ) , ( float ) Math . Round ( offset . y ) , 0f ) ;
//update
s . UpdateNeeded = true ;
s . UpdateCache ( ) ;
}
2021-05-06 11:18:50 +00:00
General . Interface . DisplayStatus ( StatusType . Info , "Aligned " + counter + " " + rest + "." ) ;
2015-12-31 12:21:44 +00:00
//update
General . Map . Map . Update ( ) ;
General . Interface . RedrawDisplay ( ) ;
General . Interface . RefreshInfo ( ) ;
General . Map . IsChanged = true ;
}
//mxd
private bool IsInSelectionRect ( Linedef l , List < Line2D > selectionOutline )
{
if ( BuilderPlug . Me . MarqueSelectTouching )
{
bool selected = selectionrect . Contains ( l . Start . Position . x , l . Start . Position . y ) | | selectionrect . Contains ( l . End . Position . x , l . End . Position . y ) ;
//check intersections with outline
if ( ! selected )
{
foreach ( Line2D line in selectionOutline )
{
if ( Line2D . GetIntersection ( l . Line , line ) ) return true ;
}
}
return selected ;
}
return selectionrect . Contains ( l . Start . Position . x , l . Start . Position . y ) & & selectionrect . Contains ( l . End . Position . x , l . End . Position . y ) ;
}
2016-04-04 22:20:49 +00:00
2016-04-22 20:17:21 +00:00
//mxd. Gets map elements inside of selectionoutline and sorts them by distance to targetpoint
private List < Linedef > GetOrderedSelection ( Vector2D targetpoint , List < Line2D > selectionoutline )
{
// Gather affected sectors
List < Linedef > result = new List < Linedef > ( ) ;
foreach ( Linedef l in General . Map . Map . Linedefs )
{
if ( IsInSelectionRect ( l , selectionoutline ) ) result . Add ( l ) ;
}
if ( result . Count = = 0 ) return result ;
// Sort by distance to targetpoint
result . Sort ( delegate ( Linedef l1 , Linedef l2 )
{
if ( l1 = = l2 ) return 0 ;
// Get closest distance from l1 to selectstart
float closest1 = float . MaxValue ;
Vector2D pos = l1 . Start . Position ;
float curdistance = Vector2D . DistanceSq ( pos , targetpoint ) ;
if ( curdistance < closest1 ) closest1 = curdistance ;
pos = l1 . End . Position ;
curdistance = Vector2D . DistanceSq ( pos , targetpoint ) ;
if ( curdistance < closest1 ) closest1 = curdistance ;
// Get closest distance from l2 to selectstart
float closest2 = float . MaxValue ;
pos = l2 . Start . Position ;
curdistance = Vector2D . DistanceSq ( pos , targetpoint ) ;
if ( curdistance < closest2 ) closest2 = curdistance ;
pos = l2 . End . Position ;
curdistance = Vector2D . DistanceSq ( pos , targetpoint ) ;
if ( curdistance < closest2 ) closest2 = curdistance ;
// Return closer one
return ( int ) ( closest1 - closest2 ) ;
} ) ;
return result ;
}
2016-04-04 22:20:49 +00:00
//mxd. This sets up new labels
private void SetupSectorLabels ( )
{
// Dispose old labels
if ( sectorlabels ! = null )
{
foreach ( TextLabel [ ] larr in sectorlabels . Values )
foreach ( TextLabel l in larr ) l . Dispose ( ) ;
}
// Make text labels for sectors
sectorlabels = new Dictionary < Sector , TextLabel [ ] > ( ) ;
sectortexts = new Dictionary < Sector , string [ ] > ( ) ;
foreach ( Sector s in General . Map . Map . Sectors )
{
// Setup labels
if ( s . Tag = = 0 ) continue ;
// Make tag text
string [ ] tagdescarr = new string [ 2 ] ;
if ( s . Tags . Count > 1 )
{
string [ ] stags = new string [ s . Tags . Count ] ;
for ( int i = 0 ; i < s . Tags . Count ; i + + ) stags [ i ] = s . Tags [ i ] . ToString ( ) ;
tagdescarr [ 0 ] = "Tags " + string . Join ( ", " , stags ) ;
tagdescarr [ 1 ] = "T" + string . Join ( "," , stags ) ;
}
else
{
tagdescarr [ 0 ] = "Tag " + s . Tag ;
tagdescarr [ 1 ] = "T" + s . Tag ;
}
// Add to collection
sectortexts . Add ( s , tagdescarr ) ;
TextLabel [ ] larr = new TextLabel [ s . Labels . Count ] ;
for ( int i = 0 ; i < s . Labels . Count ; i + + )
{
TextLabel l = new TextLabel ( ) ;
l . TransformCoords = true ;
2016-04-19 20:40:42 +00:00
l . Location = s . Labels [ i ] . position ;
2016-04-04 22:20:49 +00:00
l . AlignX = TextAlignmentX . Center ;
l . AlignY = TextAlignmentY . Middle ;
l . Color = General . Colors . InfoLine ;
2016-04-06 11:44:38 +00:00
l . BackColor = General . Colors . Background . WithAlpha ( 128 ) ;
2016-04-04 22:20:49 +00:00
larr [ i ] = l ;
}
// Add to collection
sectorlabels . Add ( s , larr ) ;
}
}
//mxd. Also update labels for the selected linedefs
public override void UpdateSelectionInfo ( )
{
base . UpdateSelectionInfo ( ) ;
2016-09-27 19:39:46 +00:00
if ( labels ! = null )
{
// Dispose old labels
foreach ( SelectionLabel l in labels . Values ) l . Dispose ( ) ;
// Don't show lables for selected-from-highlight item
if ( selectionfromhighlight )
{
labels . Clear ( ) ;
return ;
}
}
2016-04-04 22:20:49 +00:00
// Make text labels for selected linedefs
ICollection < Linedef > orderedselection = General . Map . Map . GetSelectedLinedefs ( true ) ;
2016-04-17 22:52:03 +00:00
labels = new Dictionary < Linedef , SelectionLabel > ( orderedselection . Count ) ;
2016-04-04 22:20:49 +00:00
// Otherwise significant delays will occure.
// Also we probably won't care about selection ordering when selecting this many anyway
if ( orderedselection . Count > MAX_LINEDEF_LABELS ) return ;
int index = 0 ;
foreach ( Linedef linedef in orderedselection )
{
2016-04-17 22:52:03 +00:00
SelectionLabel l = new SelectionLabel ( ) ;
l . OffsetPosition = true ;
2016-04-04 22:20:49 +00:00
l . Color = ( linedef = = highlighted ? General . Colors . Selection : General . Colors . Highlight ) ;
2016-04-06 11:44:38 +00:00
l . BackColor = General . Colors . Background . WithAlpha ( 192 ) ;
2016-04-17 22:52:03 +00:00
l . TextLabel . Text = ( + + index ) . ToString ( ) ;
2016-04-04 22:20:49 +00:00
labels . Add ( linedef , l ) ;
}
}
2023-04-25 22:36:11 +00:00
2015-12-31 12:21:44 +00:00
#endregion
2023-04-25 22:36:11 +00:00
2015-12-31 12:21:44 +00:00
#region = = = = = = = = = = = = = = = = = = Events
public override void OnHelp ( )
{
General . ShowHelp ( "e_linedefs.html" ) ;
}
// Cancel mode
public override void OnCancel ( )
{
base . OnCancel ( ) ;
// Return to this mode
General . Editing . ChangeMode ( new LinedefsMode ( ) ) ;
}
// Mode engages
public override void OnEngage ( )
{
base . OnEngage ( ) ;
renderer . SetPresentation ( Presentation . Standard ) ;
// Add toolbar buttons
2016-04-04 22:20:49 +00:00
General . Interface . BeginToolbarUpdate ( ) ; //mxd
2015-12-31 12:21:44 +00:00
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 ) ;
2016-04-04 22:20:49 +00:00
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . ViewSelectionNumbers ) ; //mxd
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
2015-12-31 12:21:44 +00:00
if ( General . Map . UDMF ) //mxd
{
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . MakeGradientBrightness ) ;
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . GradientInterpolationMenu ) ;
}
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . CurveLinedefs ) ;
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . MarqueSelectTouching ) ; //mxd
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . SyncronizeThingEditButton ) ; //mxd
if ( General . Map . UDMF ) General . Interface . AddButton ( BuilderPlug . Me . MenusForm . TextureOffsetLock , ToolbarSection . Geometry ) ; //mxd
2020-08-29 14:26:59 +00:00
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . PlaceThings ) ; //JBR
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . PerpendicularVertex ) ; //JBR
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . PerpendicularLinedef ) ; //JBR
General . Interface . AddButton ( BuilderPlug . Me . MenusForm . ParallelLinedef ) ; //JBR
2015-12-31 12:21:44 +00:00
//mxd. Update the tooltip
BuilderPlug . Me . MenusForm . SyncronizeThingEditButton . ToolTipText = "Synchronized Things Editing" + Environment . NewLine + BuilderPlug . Me . MenusForm . SyncronizeThingEditLinedefsItem . ToolTipText ;
2016-04-04 22:20:49 +00:00
General . Interface . EndToolbarUpdate ( ) ; //mxd
2015-12-31 12:21:44 +00:00
// Convert geometry selection to linedefs selection
General . Map . Map . ConvertSelection ( SelectionType . Linedefs ) ;
UpdateSelectionInfo ( ) ; //mxd
2016-04-04 22:20:49 +00:00
SetupSectorLabels ( ) ; //mxd
2015-12-31 12:21:44 +00:00
}
// Mode disengages
public override void OnDisengage ( )
{
base . OnDisengage ( ) ;
// Remove toolbar buttons
2016-04-04 22:20:49 +00:00
General . Interface . BeginToolbarUpdate ( ) ; //mxd
2015-12-31 12:21:44 +00:00
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 ) ;
2016-04-04 22:20:49 +00:00
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . ViewSelectionNumbers ) ; //mxd
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . ViewSelectionEffects ) ; //mxd
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . SeparatorSectors1 ) ; //mxd
2015-12-31 12:21:44 +00:00
if ( General . Map . UDMF ) //mxd
{
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . MakeGradientBrightness ) ;
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . GradientInterpolationMenu ) ;
}
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . CurveLinedefs ) ;
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . MarqueSelectTouching ) ; //mxd
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . SyncronizeThingEditButton ) ; //mxd
if ( General . Map . UDMF ) General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . TextureOffsetLock ) ; //mxd
2016-04-04 22:20:49 +00:00
General . Interface . EndToolbarUpdate ( ) ; //mxd
2015-12-31 12:21:44 +00:00
2020-08-29 14:26:59 +00:00
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . PlaceThings ) ; //JBR
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . PerpendicularVertex ) ; //JBR
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . PerpendicularLinedef ) ; //JBR
General . Interface . RemoveButton ( BuilderPlug . Me . MenusForm . ParallelLinedef ) ; //JBR
2015-12-31 12:21:44 +00:00
// Going to EditSelectionMode?
2016-03-18 12:52:12 +00:00
EditSelectionMode mode = General . Editing . NewMode as EditSelectionMode ;
if ( mode ! = null )
2015-12-31 12:21:44 +00:00
{
// Not pasting anything?
2016-03-18 12:52:12 +00:00
if ( ! mode . Pasting )
2015-12-31 12:21:44 +00:00
{
// No selection made? But we have a highlight!
if ( ( General . Map . Map . GetSelectedLinedefs ( true ) . Count = = 0 ) & & ( highlighted ! = null ) )
{
// Make the highlight the selection
highlighted . Selected = true ;
}
}
}
// Hide highlight info and tooltip
General . Interface . HideInfo ( ) ;
General . Interface . Display . HideToolTip ( ) ; //mxd
}
// This redraws the display
public override void OnRedrawDisplay ( )
{
renderer . RedrawSurface ( ) ;
List < Line3D > eventlines = new List < Line3D > ( ) ; //mxd
// Render lines
if ( renderer . StartPlotter ( true ) )
{
renderer . PlotLinedefSet ( General . Map . Map . Linedefs ) ;
for ( int i = 0 ; i < Linedef . NUM_ARGS ; i + + ) BuilderPlug . PlotAssociations ( renderer , association [ i ] , eventlines ) ;
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
BuilderPlug . PlotReverseAssociations ( renderer , highlightasso , eventlines ) ;
renderer . PlotLinedef ( highlighted , General . Colors . Highlight ) ;
}
renderer . PlotVerticesSet ( General . Map . Map . Vertices ) ;
renderer . Finish ( ) ;
}
// Render things
if ( renderer . StartThings ( true ) )
{
2016-03-30 11:29:39 +00:00
renderer . RenderThingSet ( General . Map . ThingsFilter . HiddenThings , General . Settings . HiddenThingsAlpha ) ;
2016-04-01 10:49:19 +00:00
renderer . RenderThingSet ( General . Map . ThingsFilter . VisibleThings , General . Settings . ActiveThingsAlpha ) ;
renderer . RenderNiGHTSPath ( ) ;
renderer . Finish ( ) ;
2015-12-31 12:21:44 +00:00
}
// Render selection
if ( renderer . StartOverlay ( true ) )
{
if ( ! selecting ) //mxd
{
for ( int i = 0 ; i < Linedef . NUM_ARGS ; i + + ) BuilderPlug . RenderAssociations ( renderer , association [ i ] , eventlines ) ;
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed ) BuilderPlug . RenderReverseAssociations ( renderer , highlightasso , eventlines ) ; //mxd
}
else
{
RenderMultiSelection ( ) ;
}
//mxd. Render vertex insert preview
if ( insertpreview . IsFinite ( ) )
{
float dist = Math . Min ( Vector2D . Distance ( mousemappos , insertpreview ) , BuilderPlug . Me . HighlightRange ) ;
byte alpha = ( byte ) ( 255 - ( dist / BuilderPlug . Me . HighlightRange ) * 128 ) ;
float vsize = ( renderer . VertexSize + 1.0f ) / renderer . Scale ;
renderer . RenderRectangleFilled ( new RectangleF ( insertpreview . x - vsize , insertpreview . y - vsize , vsize * 2.0f , vsize * 2.0f ) , General . Colors . InfoLine . WithAlpha ( alpha ) , true ) ;
}
renderer . RenderArrows ( eventlines ) ; //mxd
2016-04-04 22:20:49 +00:00
//mxd. Render sector tag labels
if ( BuilderPlug . Me . ViewSelectionEffects )
{
2016-04-25 14:48:39 +00:00
List < ITextLabel > torender = new List < ITextLabel > ( sectorlabels . Count ) ;
2016-04-04 22:20:49 +00:00
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
2020-10-31 20:06:24 +00:00
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 )
2016-04-04 22:20:49 +00:00
{
2020-10-31 20:06:24 +00:00
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 : "+" ) ;
Sectors, Linedefs, Things modes: optimized text label rendering.
Fixed, Things mode: in some cases selection labels were not updated after editing a thing.
Fixed, Things mode: selection labels were positioned incorrectly on things with FixedSize setting.
Fixed, Sectors mode: fixed a crash when selecting self-referencing sector when selection labels were enabled.
Fixed, Visual mode: in some cases Auto-align texture actions were not working when "use long texture names" Map Options setting was enabled.
Fixed, MD2/MD3 loader: available animation frames upper bound check was performed incorrectly, which would cause a crash in some very special cases.
Fixed, Game configurations: most Hexen/ZDoom teleport actions use TeleportDests as teleport targets, not MapSpots.
2016-04-05 22:24:36 +00:00
else
2020-10-31 20:06:24 +00:00
newtext = group . Value [ 1 ] ;
if ( l . Text ! = newtext )
l . Text = newtext ;
2016-04-04 22:20:49 +00:00
}
else
{
2020-10-31 20:06:24 +00:00
if ( group . Value [ 0 ] ! = l . Text )
l . Text = group . Value [ 0 ] ;
2016-04-04 22:20:49 +00:00
}
torender . Add ( l ) ;
}
}
// Render labels
renderer . RenderText ( torender ) ;
}
//mxd. Render selection labels
if ( BuilderPlug . Me . ViewSelectionNumbers )
{
2016-04-25 14:48:39 +00:00
List < ITextLabel > torender = new List < ITextLabel > ( labels . Count ) ;
2016-04-17 22:52:03 +00:00
foreach ( KeyValuePair < Linedef , SelectionLabel > group in labels )
2016-04-04 22:20:49 +00:00
{
// Render only when enough space for the label to see
2016-04-17 22:52:03 +00:00
group . Value . Move ( group . Key . Start . Position , group . Key . End . Position ) ;
2016-04-04 22:20:49 +00:00
float requiredsize = ( group . Value . TextSize . Width ) / renderer . Scale ;
2016-04-17 22:52:03 +00:00
if ( group . Key . Length > requiredsize )
{
torender . Add ( group . Value . TextLabel ) ;
}
2016-04-04 22:20:49 +00:00
}
renderer . RenderText ( torender ) ;
}
2015-12-31 12:21:44 +00:00
//mxd. Render comments
if ( General . Map . UDMF & & General . Settings . RenderComments ) foreach ( Linedef l in General . Map . Map . Linedefs ) RenderComment ( l ) ;
renderer . Finish ( ) ;
}
renderer . Present ( ) ;
}
// Selection
protected override void OnSelectBegin ( )
{
// Item highlighted?
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
// Update display
if ( renderer . StartPlotter ( false ) )
{
// Redraw highlight to show selection
renderer . PlotLinedef ( highlighted , renderer . DetermineLinedefColor ( highlighted ) ) ;
renderer . PlotVertex ( highlighted . Start , renderer . DetermineVertexColor ( highlighted . Start ) ) ;
renderer . PlotVertex ( highlighted . End , renderer . DetermineVertexColor ( highlighted . End ) ) ;
renderer . Finish ( ) ;
renderer . Present ( ) ;
}
}
base . OnSelectBegin ( ) ;
}
// End selection
protected override void OnSelectEnd ( )
{
// Not stopping from multiselection?
if ( ! selecting )
{
// Item highlighted?
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
//mxd. Flip selection
highlighted . Selected = ! highlighted . Selected ;
2016-04-04 22:20:49 +00:00
UpdateSelectionInfo ( ) ; //mxd
//mxd. Full redraw when labels were changed
if ( BuilderPlug . Me . ViewSelectionNumbers )
{
General . Interface . RedrawDisplay ( ) ;
}
2015-12-31 12:21:44 +00:00
// Update display
2016-04-04 22:20:49 +00:00
else if ( renderer . StartPlotter ( false ) )
2015-12-31 12:21:44 +00:00
{
// Render highlighted item
renderer . PlotLinedef ( highlighted , General . Colors . Highlight ) ;
renderer . PlotVertex ( highlighted . Start , renderer . DetermineVertexColor ( highlighted . Start ) ) ;
renderer . PlotVertex ( highlighted . End , renderer . DetermineVertexColor ( highlighted . End ) ) ;
renderer . Finish ( ) ;
renderer . Present ( ) ;
}
}
else if ( BuilderPlug . Me . AutoClearSelection & & General . Map . Map . SelectedLinedefsCount > 0 ) //mxd
{
General . Map . Map . ClearSelectedLinedefs ( ) ;
2016-04-04 22:20:49 +00:00
UpdateSelectionInfo ( ) ; //mxd
2015-12-31 12:21:44 +00:00
General . Interface . RedrawDisplay ( ) ;
}
}
base . OnSelectEnd ( ) ;
}
// Start editing
protected override void OnEditBegin ( )
{
// Item highlighted?
if ( ( highlighted ! = null ) & & ! highlighted . IsDisposed )
{
// Edit pressed in this mode
editpressed = true ;
// Highlighted item not selected?
if ( ! highlighted . Selected & & ( BuilderPlug . Me . AutoClearSelection | | ( General . Map . Map . SelectedLinedefsCount = = 0 ) ) )
{
// Make this the only selection
2016-09-27 19:39:46 +00:00
selectionfromhighlight = true ; //mxd
2015-12-31 12:21:44 +00:00
General . Map . Map . ClearSelectedLinedefs ( ) ;
highlighted . Selected = true ;
2016-09-27 19:39:46 +00:00
UpdateSelectionInfo ( ) ; //mxd
2015-12-31 12:21:44 +00:00
General . Interface . RedrawDisplay ( ) ;
}
// Update display
if ( renderer . StartPlotter ( false ) )
{
// Redraw highlight to show selection
renderer . PlotLinedef ( highlighted , renderer . DetermineLinedefColor ( highlighted ) ) ;
renderer . PlotVertex ( highlighted . Start , renderer . DetermineVertexColor ( highlighted . Start ) ) ;
renderer . PlotVertex ( highlighted . End , renderer . DetermineVertexColor ( highlighted . End ) ) ;
renderer . Finish ( ) ;
renderer . Present ( ) ;
}
}
else if ( ! selecting & & BuilderPlug . Me . AutoDrawOnEdit ) //mxd. We don't want to draw while multiselecting
{
// Start drawing mode
DrawGeometryMode drawmode = new DrawGeometryMode ( ) ;
bool snaptogrid = General . Interface . ShiftState ^ General . Interface . SnapToGrid ;
bool snaptonearest = General . Interface . CtrlState ^ General . Interface . AutoMerge ;
2016-04-21 21:00:58 +00:00
DrawnVertex v = DrawGeometryMode . GetCurrentPosition ( mousemappos , snaptonearest , snaptogrid , false , false , renderer , new List < DrawnVertex > ( ) ) ;
2015-12-31 12:21:44 +00:00
if ( drawmode . DrawPointAt ( v ) )
General . Editing . ChangeMode ( drawmode ) ;
else
General . Interface . DisplayStatus ( StatusType . Warning , "Failed to draw point: outside of map boundaries." ) ;
}
base . OnEditBegin ( ) ;
}
// Done editing
protected override void OnEditEnd ( )
{
// Edit pressed in this mode?
if ( editpressed )
{
// Anything selected?
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count > 0 )
{
if ( General . Interface . IsActiveWindow )
{
// Show line edit dialog
DialogResult result = General . Interface . ShowEditLinedefs ( selected ) ;
General . Map . Map . Update ( ) ;
// When a single line was selected, deselect it now
2016-09-27 19:39:46 +00:00
if ( selected . Count = = 1 & & selectionfromhighlight )
2015-12-31 12:21:44 +00:00
{
General . Map . Map . ClearSelectedLinedefs ( ) ;
}
else if ( result = = DialogResult . Cancel ) //mxd. Restore selection...
{
foreach ( Linedef l in selected ) l . Selected = true ;
}
// Update entire display
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
2016-09-27 19:39:46 +00:00
UpdateSelectionInfo ( ) ; //mxd
2015-12-31 12:21:44 +00:00
General . Interface . RedrawDisplay ( ) ;
}
}
}
editpressed = false ;
2016-09-27 19:39:46 +00:00
selectionfromhighlight = false ; //mxd
2015-12-31 12:21:44 +00:00
base . OnEditEnd ( ) ;
}
2016-04-04 22:20:49 +00:00
//mxd
public override void OnUndoEnd ( )
{
base . OnUndoEnd ( ) ;
2021-10-24 17:22:00 +00:00
// Select changed map elements
if ( BuilderPlug . Me . SelectChangedafterUndoRedo )
{
General . Map . Map . SelectMarkedGeometry ( true , true ) ;
General . Map . Map . ConvertSelection ( SelectionType . Linedefs ) ;
}
2016-09-18 23:46:24 +00:00
// Update selection info and labels
UpdateSelectionInfo ( ) ;
SetupSectorLabels ( ) ;
2016-04-04 22:20:49 +00:00
}
//mxd
public override void OnRedoEnd ( )
{
base . OnRedoEnd ( ) ;
2021-10-24 17:22:00 +00:00
// Select changed map elements
if ( BuilderPlug . Me . SelectChangedafterUndoRedo )
{
General . Map . Map . SelectMarkedGeometry ( true , true ) ;
General . Map . Map . ConvertSelection ( SelectionType . Linedefs ) ;
}
2016-09-18 23:46:24 +00:00
// Update selection info and labels
UpdateSelectionInfo ( ) ;
SetupSectorLabels ( ) ;
2016-04-04 22:20:49 +00:00
}
2015-12-31 12:21:44 +00:00
// Mouse moves
public override void OnMouseMove ( MouseEventArgs e )
{
base . OnMouseMove ( e ) ;
if ( panning ) return ; //mxd. Skip all this jazz while panning
//mxd
if ( selectpressed & & ! editpressed & & ! selecting )
{
// Check if moved enough pixels for multiselect
Vector2D delta = mousedownpos - mousepos ;
if ( ( Math . Abs ( delta . x ) > MULTISELECT_START_MOVE_PIXELS ) | |
( Math . Abs ( delta . y ) > MULTISELECT_START_MOVE_PIXELS ) )
{
// Start multiselecting
StartMultiSelection ( ) ;
}
}
else if ( paintselectpressed & & ! editpressed & & ! selecting ) //mxd. Drag-select
{
// Find the nearest thing within highlight range
2023-04-25 22:36:11 +00:00
Linedef l = General . Map . Map . NearestLinedefRange ( mousemappos , BuilderPlug . Me . HighlightRange / renderer . Scale ) ;
2015-12-31 12:21:44 +00:00
if ( l ! = null )
{
if ( l ! = highlighted )
{
//toggle selected state
2019-06-20 13:38:41 +00:00
if ( General . Interface . ShiftState ^ BuilderPlug . Me . AdditivePaintSelect )
2015-12-31 12:21:44 +00:00
l . Selected = true ;
else if ( General . Interface . CtrlState )
l . Selected = false ;
else
l . Selected = ! l . Selected ;
highlighted = l ;
UpdateSelectionInfo ( ) ; //mxd
// Update entire display
General . Interface . RedrawDisplay ( ) ;
}
}
else if ( highlighted ! = null )
{
Highlight ( null ) ;
// Update entire display
General . Interface . RedrawDisplay ( ) ;
}
}
else if ( e . Button = = MouseButtons . None ) // Not holding any buttons?
{
// Find the nearest linedef within highlight range
2023-04-25 22:36:11 +00:00
Linedef l = General . Map . Map . NearestLinedefRange ( mousemappos , BuilderPlug . Me . HighlightRange / renderer . Scale ) ;
2015-12-31 12:21:44 +00:00
//mxd. Render insert vertex preview
2023-04-25 22:36:11 +00:00
Linedef sl = General . Map . Map . NearestLinedefRange ( mousemappos , BuilderPlug . Me . StitchRange / renderer . Scale ) ;
if ( sl ! = null )
2015-12-31 12:21:44 +00:00
{
bool snaptogrid = General . Interface . ShiftState ^ General . Interface . SnapToGrid ;
bool snaptonearest = General . Interface . CtrlState ^ General . Interface . AutoMerge ;
2016-04-21 21:00:58 +00:00
Vector2D v = DrawGeometryMode . GetCurrentPosition ( mousemappos , snaptonearest , snaptogrid , false , false , renderer , new List < DrawnVertex > ( ) ) . pos ;
2015-12-31 12:21:44 +00:00
if ( v ! = insertpreview )
{
insertpreview = v ;
General . Interface . RedrawDisplay ( ) ;
}
}
else if ( insertpreview . IsFinite ( ) )
{
insertpreview . x = float . NaN ;
General . Interface . RedrawDisplay ( ) ;
}
// Highlight if not the same
if ( l ! = highlighted ) Highlight ( l ) ;
//mxd. Show tooltip?
if ( General . Map . UDMF & & General . Settings . RenderComments & & mouselastpos ! = mousepos & & highlighted ! = null & & ! highlighted . IsDisposed & & highlighted . Fields . ContainsKey ( "comment" ) )
{
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 ( ) ) ;
}
General . Interface . Display . ShowToolTip ( "Comment:" , comment , ( int ) ( mousepos . x + 32 * MainForm . DPIScaler . Width ) , ( int ) ( mousepos . y + 8 * MainForm . DPIScaler . Height ) ) ;
}
}
}
// Mouse leaves
public override void OnMouseLeave ( EventArgs e )
{
base . OnMouseLeave ( e ) ;
// Highlight nothing
Highlight ( null ) ;
}
//mxd
protected override void BeginViewPan ( )
{
// We don't want vertex preview while panning
insertpreview . x = float . NaN ;
base . BeginViewPan ( ) ;
}
//mxd
protected override void OnPaintSelectBegin ( )
{
// Highlight nothing
Highlight ( null ) ;
base . OnPaintSelectBegin ( ) ;
}
// 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 )
{
// Highlighted item not selected?
if ( ! highlighted . Selected )
{
// Select only this linedef for dragging
General . Map . Map . ClearSelectedLinedefs ( ) ;
highlighted . Selected = true ;
}
// Start dragging the selection
if ( ! BuilderPlug . Me . DontMoveGeometryOutsideMapBoundary | | CanDrag ( ) ) //mxd
General . Editing . ChangeMode ( new DragLinedefsMode ( mousedownmappos ) ) ;
}
}
}
//mxd. Check if any selected linedef is outside of map boundary
private static bool CanDrag ( )
{
ICollection < Linedef > selectedlines = General . Map . Map . GetSelectedLinedefs ( true ) ;
int unaffectedCount = 0 ;
foreach ( Linedef l in selectedlines )
{
// Make sure the linedef is inside the map boundary
if ( l . Start . Position . x < General . Map . Config . LeftBoundary | | l . Start . Position . x > General . Map . Config . RightBoundary
| | l . Start . Position . y > General . Map . Config . TopBoundary | | l . Start . Position . y < General . Map . Config . BottomBoundary
| | l . End . Position . x < General . Map . Config . LeftBoundary | | l . End . Position . x > General . Map . Config . RightBoundary
| | l . End . Position . y > General . Map . Config . TopBoundary | | l . End . Position . y < General . Map . Config . BottomBoundary )
{
l . Selected = false ;
unaffectedCount + + ;
}
}
if ( unaffectedCount = = selectedlines . Count )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Unable to drag selection: " + ( selectedlines . Count = = 1 ? "selected linedef is" : "all of selected linedefs are" ) + " outside of map boundary!" ) ;
General . Interface . RedrawDisplay ( ) ;
return false ;
}
if ( unaffectedCount > 0 )
General . Interface . DisplayStatus ( StatusType . Warning , unaffectedCount + " of selected linedefs " + ( unaffectedCount = = 1 ? "is" : "are" ) + " outside of map boundary!" ) ;
return true ;
}
// 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 )
{
2016-04-22 20:17:21 +00:00
List < Line2D > selectionoutline = new List < Line2D >
2015-12-31 12:21:44 +00:00
{
new Line2D ( selectionrect . Left , selectionrect . Top , selectionrect . Right , selectionrect . Top ) ,
new Line2D ( selectionrect . Right , selectionrect . Top , selectionrect . Right , selectionrect . Bottom ) ,
new Line2D ( selectionrect . Left , selectionrect . Bottom , selectionrect . Right , selectionrect . Bottom ) ,
new Line2D ( selectionrect . Left , selectionrect . Bottom , selectionrect . Left , selectionrect . Top )
} ;
//mxd
bool selectthings = ( marqueSelectionIncludesThings ^ BuilderPlug . Me . SyncronizeThingEdit ) ;
switch ( marqueSelectionMode )
{
case MarqueSelectionMode . SELECT :
2016-04-22 20:17:21 +00:00
// Get ordered selection
List < Linedef > selectresult = GetOrderedSelection ( base . selectstart , selectionoutline ) ;
// First deselect everything...
foreach ( Linedef l in General . Map . Map . Linedefs ) l . Selected = false ;
// Then select lines in correct order
foreach ( Linedef l in selectresult ) l . Selected = true ;
2015-12-31 12:21:44 +00:00
if ( selectthings )
{
foreach ( Thing t in General . Map . ThingsFilter . VisibleThings )
t . Selected = selectionrect . Contains ( t . Position . x , t . Position . y ) ;
}
break ;
case MarqueSelectionMode . ADD :
2016-04-22 20:17:21 +00:00
// Get ordered selection
List < Linedef > addresult = GetOrderedSelection ( selectstart , selectionoutline ) ;
// First deselect everything inside of selection...
foreach ( Linedef l in addresult ) l . Selected = false ;
// Then reselect in correct order
foreach ( Linedef l in addresult ) l . Selected = true ;
2015-12-31 12:21:44 +00:00
if ( selectthings )
{
foreach ( Thing t in General . Map . ThingsFilter . VisibleThings )
t . Selected | = selectionrect . Contains ( t . Position . x , t . Position . y ) ;
}
break ;
case MarqueSelectionMode . SUBTRACT :
2016-04-22 20:17:21 +00:00
// Selection order doesn't matter here
2015-12-31 12:21:44 +00:00
foreach ( Linedef l in General . Map . Map . Linedefs )
2016-04-22 20:17:21 +00:00
if ( IsInSelectionRect ( l , selectionoutline ) ) l . Selected = false ;
2015-12-31 12:21:44 +00:00
if ( selectthings )
{
foreach ( Thing t in General . Map . ThingsFilter . VisibleThings )
if ( selectionrect . Contains ( t . Position . x , t . Position . y ) ) t . Selected = false ;
}
break ;
2016-04-22 20:17:21 +00:00
// Should be Intersect selection mode
2015-12-31 12:21:44 +00:00
default :
2016-04-22 20:17:21 +00:00
// Selection order doesn't matter here
2015-12-31 12:21:44 +00:00
foreach ( Linedef l in General . Map . Map . Linedefs )
2016-04-22 20:17:21 +00:00
if ( ! IsInSelectionRect ( l , selectionoutline ) ) l . Selected = false ;
2015-12-31 12:21:44 +00:00
if ( selectthings )
{
foreach ( Thing t in General . Map . ThingsFilter . VisibleThings )
if ( ! selectionrect . Contains ( t . Position . x , t . Position . y ) ) t . Selected = false ;
}
break ;
}
//mxd
UpdateSelectionInfo ( ) ;
}
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 . GetSelectedLinedefs ( 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 ( Linedef l )
{
if ( l . Fields . ContainsKey ( "comment" ) )
{
int iconindex = 0 ;
string comment = l . 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 ;
}
Vector2D center = l . GetCenterPoint ( ) ;
RectangleF rect = new RectangleF ( center . x - 8 / renderer . Scale , center . y + 18 / renderer . Scale , 16 / renderer . Scale , - 16 / renderer . Scale ) ;
PixelColor c = ( l = = highlighted ? General . Colors . Highlight : ( l . Selected ? General . Colors . Selection : PixelColor . FromColor ( Color . White ) ) ) ;
renderer . RenderRectangleFilled ( rect , c , true , General . Map . Data . CommentTextures [ iconindex ] ) ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Actions
// This copies the properties
[BeginAction("classiccopyproperties")]
public void CopyProperties ( )
{
// Determine source linedefs
ICollection < Linedef > sel = null ;
if ( General . Map . Map . SelectedLinedefsCount > 0 ) sel = General . Map . Map . GetSelectedLinedefs ( true ) ;
else if ( highlighted ! = null ) sel = new List < Linedef > { highlighted } ;
if ( sel ! = null )
{
// Copy properties from first source linedef
BuilderPlug . Me . CopiedLinedefProps = new LinedefProperties ( General . GetByIndex ( sel , 0 ) ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Copied linedef properties." ) ;
}
else
{
//mxd
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires highlight or selection!" ) ;
}
}
// This pastes the properties
[BeginAction("classicpasteproperties")]
public void PasteProperties ( )
{
if ( BuilderPlug . Me . CopiedLinedefProps ! = null )
{
// Determine target linedefs
ICollection < Linedef > sel = null ;
if ( General . Map . Map . SelectedLinedefsCount > 0 ) sel = General . Map . Map . GetSelectedLinedefs ( true ) ;
else if ( highlighted ! = null ) sel = new List < Linedef > { highlighted } ;
if ( sel ! = null )
{
2021-03-13 16:42:47 +00:00
List < int > linedeftags = new List < int > ( ) ;
2015-12-31 12:21:44 +00:00
// Apply properties to selection
string rest = ( sel . Count = = 1 ? "a single linedef" : sel . Count + " linedefs" ) ; //mxd
General . Map . UndoRedo . CreateUndo ( "Paste properties to " + rest ) ;
foreach ( Linedef l in sel )
{
2021-03-13 16:42:47 +00:00
if ( l . Tag ! = 0 ) linedeftags . Add ( l . Tag ) ;
2015-12-31 12:21:44 +00:00
BuilderPlug . Me . CopiedLinedefProps . Apply ( l , false ) ;
l . UpdateCache ( ) ;
2021-03-13 16:42:47 +00:00
if ( l . IsFlatAlignment & & l . Tag ! = 0 ) linedeftags . Add ( l . Tag ) ;
l . Front . Sector . UpdateFloorSurface ( ) ;
l . Front . Sector . UpdateCeilingSurface ( ) ;
2015-12-31 12:21:44 +00:00
}
2021-03-13 16:42:47 +00:00
foreach ( Sector s in General . Map . Map . Sectors )
if ( linedeftags . Contains ( s . Tag ) )
{
s . UpdateFloorSurface ( ) ;
s . UpdateCeilingSurface ( ) ;
}
2015-12-31 12:21:44 +00:00
General . Interface . DisplayStatus ( StatusType . Action , "Pasted properties to " + rest + "." ) ;
// Update and redraw
General . Map . IsChanged = true ;
General . Interface . RefreshInfo ( ) ;
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
}
else
{
//mxd
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires highlight or selection!" ) ;
}
}
else
{
//mxd
General . Interface . DisplayStatus ( StatusType . Warning , "Copy linedef properties first!" ) ;
}
}
//mxd. This pastes the properties with options
[BeginAction("classicpastepropertieswithoptions")]
public void PastePropertiesWithOptions ( )
{
if ( BuilderPlug . Me . CopiedLinedefProps ! = null )
{
// Determine target linedefs
ICollection < Linedef > sel = null ;
if ( General . Map . Map . SelectedLinedefsCount > 0 ) sel = General . Map . Map . GetSelectedLinedefs ( true ) ;
else if ( highlighted ! = null ) sel = new List < Linedef > { highlighted } ;
if ( sel ! = null )
{
PastePropertiesOptionsForm form = new PastePropertiesOptionsForm ( ) ;
if ( form . Setup ( MapElementType . LINEDEF ) & & form . ShowDialog ( General . Interface ) = = DialogResult . OK )
{
2021-03-13 16:42:47 +00:00
List < int > linedeftags = new List < int > ( ) ;
2015-12-31 12:21:44 +00:00
// Apply properties to selection
string rest = ( sel . Count = = 1 ? "a single linedef" : sel . Count + " linedefs" ) ;
General . Map . UndoRedo . CreateUndo ( "Paste properties with options to " + rest ) ;
foreach ( Linedef l in sel )
{
2021-03-13 16:42:47 +00:00
if ( l . Tag ! = 0 ) linedeftags . Add ( l . Tag ) ;
2015-12-31 12:21:44 +00:00
BuilderPlug . Me . CopiedLinedefProps . Apply ( l , true ) ;
l . UpdateCache ( ) ;
2021-03-13 16:42:47 +00:00
if ( l . IsFlatAlignment & & l . Tag ! = 0 ) linedeftags . Add ( l . Tag ) ;
l . Front . Sector . UpdateFloorSurface ( ) ;
l . Front . Sector . UpdateCeilingSurface ( ) ;
2015-12-31 12:21:44 +00:00
}
2021-03-13 16:42:47 +00:00
foreach ( Sector s in General . Map . Map . Sectors )
if ( linedeftags . Contains ( s . Tag ) )
{
s . UpdateFloorSurface ( ) ;
s . UpdateCeilingSurface ( ) ;
}
2015-12-31 12:21:44 +00:00
General . Interface . DisplayStatus ( StatusType . Action , "Pasted properties with options to " + rest + "." ) ;
// Update and redraw
General . Map . IsChanged = true ;
General . Interface . RefreshInfo ( ) ;
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
}
}
else
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires highlight or selection!" ) ;
}
}
else
{
General . Interface . DisplayStatus ( StatusType . Warning , "Copy linedef properties first!" ) ;
}
}
// This keeps only the single-sided lines selected
[BeginAction("selectsinglesided")]
public void SelectSingleSided ( )
{
int counter = 0 ;
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
foreach ( Linedef ld in selected )
{
if ( ( ld . Front ! = null ) & & ( ld . Back ! = null ) )
ld . Selected = false ;
else
counter + + ;
}
General . Interface . DisplayStatus ( StatusType . Action , "Selected only single-sided linedefs (" + counter + ")" ) ;
General . Interface . RedrawDisplay ( ) ;
}
// This keeps only the double-sided lines selected
[BeginAction("selectdoublesided")]
public void SelectDoubleSided ( )
{
int counter = 0 ;
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
foreach ( Linedef ld in selected )
{
if ( ( ld . Front = = null ) | | ( ld . Back = = null ) )
ld . Selected = false ;
else
counter + + ;
}
General . Interface . DisplayStatus ( StatusType . Action , "Selected only double-sided linedefs (" + counter + ")" ) ;
General . Interface . RedrawDisplay ( ) ;
}
// This clears the selection
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection ( )
{
// Clear selection
General . Map . Map . ClearAllSelected ( ) ;
//mxd. Clear selection info
General . Interface . DisplayStatus ( StatusType . Selection , string . Empty ) ;
2016-04-04 22:20:49 +00:00
//mxd. Clear selection labels
2016-04-17 22:52:03 +00:00
foreach ( SelectionLabel l in labels . Values ) l . Dispose ( ) ;
2016-04-04 22:20:49 +00:00
labels . Clear ( ) ;
2015-12-31 12:21:44 +00:00
// Redraw
General . Interface . RedrawDisplay ( ) ;
}
// This creates a new vertex at the mouse position
[BeginAction("insertitem", BaseAction = true)]
public void InsertVertexAction ( )
{
// Start drawing mode
DrawGeometryMode drawmode = new DrawGeometryMode ( ) ;
if ( mouseinside )
{
bool snaptogrid = General . Interface . ShiftState ^ General . Interface . SnapToGrid ;
bool snaptonearest = General . Interface . CtrlState ^ General . Interface . AutoMerge ;
2016-04-21 21:00:58 +00:00
DrawnVertex v = DrawGeometryMode . GetCurrentPosition ( mousemappos , snaptonearest , snaptogrid , false , false , renderer , new List < DrawnVertex > ( ) ) ;
2015-12-31 12:21:44 +00:00
drawmode . DrawPointAt ( v ) ;
}
General . Editing . ChangeMode ( drawmode ) ;
}
[BeginAction("deleteitem", BaseAction = true)]
public void DeleteItem ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
if ( selected . Count = = 0 ) return ;
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Delete " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Deleted " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Delete linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Deleted a linedef." ) ;
}
// Dispose selected linedefs
foreach ( Linedef ld in selected ) ld . Dispose ( ) ;
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
// Redraw screen
2016-04-22 13:28:23 +00:00
SetupSectorLabels ( ) ; //mxd
2015-12-31 12:21:44 +00:00
UpdateSelectionInfo ( ) ; //mxd
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
2016-04-22 13:28:23 +00:00
// Invoke a new mousemove so that the highlighted item updates
OnMouseMove ( new MouseEventArgs ( MouseButtons . None , 0 , ( int ) mousepos . x , ( int ) mousepos . y , 0 ) ) ;
2015-12-31 12:21:44 +00:00
}
2021-11-10 00:03:40 +00:00
[BeginAction("selectnonessential")]
public void SelectNonEssential ( )
{
int counter = 0 ;
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
foreach ( Linedef ld in selected )
2021-11-15 19:32:58 +00:00
{
2022-03-04 20:13:27 +00:00
if ( ld . Back ! = null & & ld . Front . Sector = = ld . Back . Sector & & ld . Action = = 0 )
2021-11-10 00:03:40 +00:00
counter + + ;
else
ld . Selected = false ;
}
General . Interface . DisplayStatus ( StatusType . Action , "Selected only non-essential lines (" + counter + ")" ) ;
General . Interface . RedrawDisplay ( ) ;
}
2015-12-31 12:21:44 +00:00
[BeginAction("dissolveitem", BaseAction = true)] //mxd
public void DissolveItem ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
// Anything to do?
if ( selected . Count > 0 )
{
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Dissolve " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Dissolved " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Dissolve linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Dissolved a linedef." ) ;
}
//mxd. Find sectors, which will become invalid after linedefs removal.
Dictionary < Sector , Vector2D > toMerge = new Dictionary < Sector , Vector2D > ( ) ;
foreach ( Linedef l in selected )
{
if ( l . Front ! = null & & l . Front . Sector . Sidedefs . Count < 4 & & ! toMerge . ContainsKey ( l . Front . Sector ) )
toMerge . Add ( l . Front . Sector , new Vector2D ( l . Front . Sector . BBox . Location . X + l . Front . Sector . BBox . Width / 2 , l . Front . Sector . BBox . Location . Y + l . Front . Sector . BBox . Height / 2 ) ) ;
if ( l . Back ! = null & & l . Back . Sector . Sidedefs . Count < 4 & & ! toMerge . ContainsKey ( l . Back . Sector ) )
toMerge . Add ( l . Back . Sector , new Vector2D ( l . Back . Sector . BBox . Location . X + l . Back . Sector . BBox . Width / 2 , l . Back . Sector . BBox . Location . Y + l . Back . Sector . BBox . Height / 2 ) ) ;
}
General . Map . Map . BeginAddRemove ( ) ; //mxd
// Dispose selected linedefs
foreach ( Linedef ld in selected )
{
//mxd. If there are different sectors on both sides, join them
if ( ld . Front ! = null & & ld . Front . Sector ! = null & & ld . Back ! = null
& & ld . Back . Sector ! = null & & ld . Front . Sector . Index ! = ld . Back . Sector . Index )
{
if ( ld . Front . Sector . BBox . Width * ld . Front . Sector . BBox . Height > ld . Back . Sector . BBox . Width * ld . Back . Sector . BBox . Height )
ld . Back . Sector . Join ( ld . Front . Sector ) ;
else
ld . Front . Sector . Join ( ld . Back . Sector ) ;
}
ld . Dispose ( ) ;
}
//mxd
General . Map . Map . EndAddRemove ( ) ;
Tools . MergeInvalidSectors ( toMerge ) ;
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
2023-04-25 22:36:11 +00:00
2015-12-31 12:21:44 +00:00
// Redraw screen
2016-04-22 13:28:23 +00:00
SetupSectorLabels ( ) ; //mxd
2015-12-31 12:21:44 +00:00
UpdateSelectionInfo ( ) ; //mxd
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
2016-04-22 13:28:23 +00:00
// Invoke a new mousemove so that the highlighted item updates
OnMouseMove ( new MouseEventArgs ( MouseButtons . None , 0 , ( int ) mousepos . x , ( int ) mousepos . y , 0 ) ) ;
2015-12-31 12:21:44 +00:00
}
}
2021-05-08 21:35:32 +00:00
[BeginAction("resetactionsandtags")]
public void ResetActionsAndTags ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
// Anything to do?
if ( selected . Count > 0 )
{
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Reset actions and tags of " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Reset actions and tags of " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Reset actions and tags of 1 linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Reset actions and tags of 1 linedef." ) ;
}
foreach ( Linedef l in selected )
{
l . Action = 0 ;
l . Tag = 0 ;
2021-05-10 21:52:54 +00:00
// reset hacky flat alignment
2023-02-02 09:54:09 +00:00
if ( l . Front . Sector ! = null )
{
l . Front . Sector . UpdateFloorSurface ( ) ;
l . Front . Sector . UpdateCeilingSurface ( ) ;
}
2021-05-08 21:35:32 +00:00
}
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
// Invoke a new mousemove so that the highlighted item updates
MouseEventArgs e = new MouseEventArgs ( MouseButtons . None , 0 , ( int ) mousepos . x , ( int ) mousepos . y , 0 ) ;
OnMouseMove ( e ) ;
// Redraw screen
UpdateSelectionInfo ( ) ; //mxd
2021-05-10 21:52:54 +00:00
General . Interface . RefreshInfo ( ) ;
2021-05-08 21:35:32 +00:00
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
}
}
2021-05-10 11:45:19 +00:00
[BeginAction("resetflags")]
public void ResetFlags ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
// Anything to do?
if ( selected . Count > 0 )
{
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Reset flags of " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Reset flags of " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Reset flags of 1 linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Reset flags of 1 linedef." ) ;
}
foreach ( Linedef l in selected )
{
l . ClearFlags ( ) ;
if ( l . Back ! = null & & l . Back . Sector ! = null )
l . SetFlag ( General . Map . Config . DoubleSidedFlag , true ) ;
else
l . SetFlag ( General . Map . Config . ImpassableFlag , true ) ;
2021-05-10 21:52:54 +00:00
// reset hacky flat alignment
l . Front . Sector . UpdateFloorSurface ( ) ;
l . Front . Sector . UpdateCeilingSurface ( ) ;
2021-05-10 11:45:19 +00:00
}
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
// Invoke a new mousemove so that the highlighted item updates
MouseEventArgs e = new MouseEventArgs ( MouseButtons . None , 0 , ( int ) mousepos . x , ( int ) mousepos . y , 0 ) ;
OnMouseMove ( e ) ;
// Redraw screen
UpdateSelectionInfo ( ) ; //mxd
2021-05-10 21:52:54 +00:00
General . Interface . RefreshInfo ( ) ;
2021-05-10 11:45:19 +00:00
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
}
}
2023-04-21 00:29:53 +00:00
[BeginAction("clearmidtextures")]
public void ClearMidtextures ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
// Anything to do?
if ( selected . Count > 0 )
{
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Cleared midtextures of " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Cleared midtextures of " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Cleared midtextures of 1 linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Cleared midtextures of 1 linedef." ) ;
}
foreach ( Linedef l in selected )
{
l . SetFlag ( General . Map . Config . PegMidtextureFlag , false ) ;
2023-04-24 23:12:06 +00:00
if ( l . Back ! = null )
{
l . Front . SetTextureMid ( "-" ) ;
l . Back . SetTextureMid ( "-" ) ;
}
2023-04-21 00:29:53 +00:00
}
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
// Invoke a new mousemove so that the highlighted item updates
MouseEventArgs e = new MouseEventArgs ( MouseButtons . None , 0 , ( int ) mousepos . x , ( int ) mousepos . y , 0 ) ;
OnMouseMove ( e ) ;
// Redraw screen
UpdateSelectionInfo ( ) ; //mxd
General . Interface . RefreshInfo ( ) ;
General . Map . Renderer2D . UpdateExtraFloorFlag ( ) ; //mxd
General . Interface . RedrawDisplay ( ) ;
}
}
2015-12-31 12:21:44 +00:00
[BeginAction("splitlinedefs")]
public void SplitLinedefs ( )
{
// Make list of selected linedefs
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( ( selected . Count = = 0 ) & & ( highlighted ! = null ) & & ! highlighted . IsDisposed ) selected . Add ( highlighted ) ;
// Anything to do?
if ( selected . Count > 0 )
{
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Split " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Split " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Split linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Split a linedef." ) ;
}
// Go for all linedefs to split
foreach ( Linedef ld in selected )
{
Vertex splitvertex ;
// Linedef highlighted?
if ( ld = = highlighted )
{
// Split at nearest position on the line
Vector2D nearestpos = ld . NearestOnLine ( mousemappos ) ;
splitvertex = General . Map . Map . CreateVertex ( nearestpos ) ;
}
else
{
// Split in middle of line
splitvertex = General . Map . Map . CreateVertex ( ld . GetCenterPoint ( ) ) ;
}
if ( splitvertex = = null )
{
General . Map . UndoRedo . WithdrawUndo ( ) ;
break ;
}
// Snap to map format accuracy
splitvertex . SnapToAccuracy ( ) ;
// Split the line
Linedef sld = ld . Split ( splitvertex ) ;
if ( sld = = null )
{
General . Map . UndoRedo . WithdrawUndo ( ) ;
break ;
}
//BuilderPlug.Me.AdjustSplitCoordinates(ld, sld);
}
// Update cache values
General . Map . IsChanged = true ;
General . Map . Map . Update ( ) ;
// Redraw screen
General . Interface . RedrawDisplay ( ) ;
}
}
[BeginAction("curvelinesmode")]
public void CurveLinedefs ( )
{
// No selected lines?
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
}
}
// Any selected lines?
if ( selected . Count > 0 )
{
// Go into curve linedefs mode
2016-10-26 22:33:36 +00:00
General . Editing . ChangeMode ( new CurveLinedefsMode ( ) ) ;
2015-12-31 12:21:44 +00:00
}
2016-10-31 18:52:29 +00:00
else
{
//mxd
General . Interface . DisplayStatus ( StatusType . Warning , "This action requres a selection!" ) ;
}
2015-12-31 12:21:44 +00:00
}
[BeginAction("fliplinedefs")]
public void FlipLinedefs ( )
{
2021-05-30 16:27:56 +00:00
bool deselect = false ;
2015-12-31 12:21:44 +00:00
// No selected lines?
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
2021-05-30 16:27:56 +00:00
// If nothing was selected we want to deselect the highlighted line when we're done
deselect = true ;
2015-12-31 12:21:44 +00:00
}
}
// Any selected lines?
2016-03-14 10:25:27 +00:00
if ( selected . Count = = 0 )
2015-12-31 12:21:44 +00:00
{
2016-03-14 10:25:27 +00:00
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
2015-12-31 12:21:44 +00:00
2016-06-26 22:42:24 +00:00
//mxd. Remove single-sided lines with only front side
int selectedcount = selected . Count ; // Store initial selection size...
List < Linedef > filtered = new List < Linedef > ( selectedcount ) ;
foreach ( Linedef l in selected )
{
if ( l . Back ! = null | | l . Front = = null ) filtered . Add ( l ) ;
}
selected = filtered ;
//mxd. Any valid lines?
if ( selected . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , ( selectedcount > 1 ? "Selected linedefs already point in the right direction!"
: "Selected linedef already points in the right direction!" ) ) ;
2021-05-30 16:27:56 +00:00
// There might be linedefs that were filtered out, so deselect all linedefs (if necessary) anyway
if ( deselect )
General . Map . Map . ClearSelectedLinedefs ( ) ;
2016-06-26 22:42:24 +00:00
return ;
}
2016-03-14 10:25:27 +00:00
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Flip " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Flipped " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Flip linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Flipped a linedef." ) ;
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
// Flip all selected linedefs
foreach ( Linedef l in selected )
{
l . FlipVertices ( ) ;
l . FlipSidedefs ( ) ;
}
2021-05-30 16:27:56 +00:00
if ( deselect )
General . Map . Map . ClearSelectedLinedefs ( ) ;
2016-03-14 10:25:27 +00:00
// Redraw
General . Map . Map . Update ( ) ;
General . Map . IsChanged = true ;
General . Interface . RefreshInfo ( ) ;
General . Interface . RedrawDisplay ( ) ;
}
[BeginAction("alignlinedefs")]
public void AlignLinedefs ( ) //mxd
{
// No selected lines?
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
2015-12-31 12:21:44 +00:00
{
2016-03-14 10:25:27 +00:00
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
2015-12-31 12:21:44 +00:00
}
2016-03-14 10:25:27 +00:00
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
// Any selected lines?
if ( selected . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
// Make undo
if ( selected . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Align " + selected . Count + " linedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Aligned " + selected . Count + " linedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Align linedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Aligned a linedef." ) ;
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
//mxd. Do it sector-wise
Dictionary < Sector , int > sectors = new Dictionary < Sector , int > ( ) ;
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
foreach ( Linedef l in selected )
{
if ( l . Front ! = null & & l . Front . Sector ! = null )
2015-12-31 12:21:44 +00:00
{
2016-03-14 10:25:27 +00:00
if ( ! sectors . ContainsKey ( l . Front . Sector ) ) sectors . Add ( l . Front . Sector , 0 ) ;
sectors [ l . Front . Sector ] + + ;
2015-12-31 12:21:44 +00:00
}
2016-03-14 10:25:27 +00:00
if ( l . Back ! = null & & l . Back . Sector ! = null )
{
if ( ! sectors . ContainsKey ( l . Back . Sector ) ) sectors . Add ( l . Back . Sector , 0 ) ;
sectors [ l . Back . Sector ] + + ;
}
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
//mxd. Sort the collection so sectors with the most selected linedefs go first
List < KeyValuePair < Sector , int > > sortedlist = sectors . ToList ( ) ;
sortedlist . Sort ( ( firstPair , nextPair ) = > firstPair . Value . CompareTo ( nextPair . Value ) ) ;
sortedlist . Reverse ( ) ;
//mxd. Gather our ordered sectors
2016-03-18 12:52:12 +00:00
List < Sector > sectorslist = new List < Sector > ( sortedlist . Count ) ;
2016-03-14 10:25:27 +00:00
sectorslist . AddRange ( sortedlist . Select ( pair = > pair . Key ) ) ;
//mxd. Flip the lines
Tools . FlipSectorLinedefs ( sectorslist , true ) ;
// Remove selection if only one linedef was selected
if ( selected . Count = = 1 )
{
foreach ( Linedef ld in selected ) ld . Selected = false ;
selected . Clear ( ) ;
2015-12-31 12:21:44 +00:00
}
2016-03-14 10:25:27 +00:00
// Redraw
General . Map . Map . Update ( ) ;
General . Map . IsChanged = true ;
General . Interface . RefreshInfo ( ) ;
General . Interface . RedrawDisplay ( ) ;
2015-12-31 12:21:44 +00:00
}
[BeginAction("flipsidedefs")]
public void FlipSidedefs ( )
{
// No selected lines?
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
selected . Add ( highlighted ) ;
}
}
2016-03-14 10:25:27 +00:00
//mxd. Any selected lines?
if ( selected . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
2015-12-31 12:21:44 +00:00
//mxd. Do this only with double-sided linedefs
List < Linedef > validlines = new List < Linedef > ( ) ;
foreach ( Linedef l in selected )
{
if ( l . Front ! = null & & l . Back ! = null ) validlines . Add ( l ) ;
}
2016-03-14 10:25:27 +00:00
//mxd. Any double-sided lines selected?
if ( validlines . Count = = 0 )
2015-12-31 12:21:44 +00:00
{
2016-03-14 10:25:27 +00:00
General . Interface . DisplayStatus ( StatusType . Warning , "No sidedefs to flip! Only 2-sided linedefs can be flipped." ) ;
return ;
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
// Make undo
if ( validlines . Count > 1 )
{
General . Map . UndoRedo . CreateUndo ( "Flip " + validlines . Count + " sidedefs" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Flipped " + validlines . Count + " sidedefs." ) ;
}
else
{
General . Map . UndoRedo . CreateUndo ( "Flip sidedef" ) ;
General . Interface . DisplayStatus ( StatusType . Action , "Flipped a sidedef." ) ;
}
2015-12-31 12:21:44 +00:00
2016-03-14 10:25:27 +00:00
// Flip sidedefs in all selected linedefs
foreach ( Linedef l in validlines )
2015-12-31 12:21:44 +00:00
{
2016-03-14 10:25:27 +00:00
l . FlipSidedefs ( ) ;
l . Front . Sector . UpdateNeeded = true ;
l . Back . Sector . UpdateNeeded = true ;
2015-12-31 12:21:44 +00:00
}
2016-03-14 10:25:27 +00:00
// Redraw
General . Map . Map . Update ( ) ;
General . Map . IsChanged = true ;
General . Interface . RefreshInfo ( ) ;
General . Interface . RedrawDisplay ( ) ;
2015-12-31 12:21:44 +00:00
}
//mxd. Make gradient brightness
[BeginAction("gradientbrightness")]
public void MakeGradientBrightness ( )
{
if ( ! General . Map . UDMF ) return ;
// Need at least 3 selected linedefs
// The first and last are not modified
ICollection < Linedef > orderedselection = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( orderedselection . Count > 2 )
{
// Gather values
Linedef start = General . GetByIndex ( orderedselection , 0 ) ;
Linedef end = General . GetByIndex ( orderedselection , orderedselection . Count - 1 ) ;
float startbrightness = GetLinedefBrighness ( start ) ;
float endbrightness = GetLinedefBrighness ( end ) ;
if ( float . IsNaN ( startbrightness ) )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Start linedef doesn't have visible parts!" ) ;
return ;
}
if ( float . IsNaN ( endbrightness ) )
{
General . Interface . DisplayStatus ( StatusType . Warning , "End linedef doesn't have visible parts!" ) ;
return ;
}
//Make undo
General . Interface . DisplayStatus ( StatusType . Action , "Created gradient brightness over selected linedefs." ) ;
General . Map . UndoRedo . CreateUndo ( "Linedefs gradient brightness" ) ;
// Apply changes
InterpolationTools . Mode interpolationmode = ( InterpolationTools . Mode ) BuilderPlug . Me . MenusForm . GradientInterpolationMenu . SelectedIndex ;
int index = 0 ;
// Go for all lines in between first and last
foreach ( Linedef l in orderedselection )
{
float u = index / ( float ) ( orderedselection . Count - 1 ) ;
2016-06-03 20:22:07 +00:00
int b = ( int ) Math . Round ( InterpolationTools . Interpolate ( startbrightness , endbrightness , u , interpolationmode ) ) ;
2015-12-31 12:21:44 +00:00
if ( SidedefHasVisibleParts ( l . Front ) ) ApplySidedefBrighness ( l . Front , b ) ;
if ( SidedefHasVisibleParts ( l . Back ) ) ApplySidedefBrighness ( l . Back , b ) ;
index + + ;
}
// Update
General . Map . Map . Update ( ) ;
General . Interface . RedrawDisplay ( ) ;
General . Interface . RefreshInfo ( ) ;
General . Map . IsChanged = true ;
}
else
{
General . Interface . DisplayStatus ( StatusType . Warning , "Select at least 3 linedefs first!" ) ;
}
}
//mxd. gradientbrightness utility
private static bool SidedefHasVisibleParts ( Sidedef side )
{
if ( side = = null | | side . Sector = = null ) return false ;
return side . HighRequired ( ) | | side . LowRequired ( ) | | ( side . MiddleRequired ( ) | | ( side . Other ! = null & & side . MiddleTexture ! = "-" ) ) ;
}
//mxd. gradientbrightness utility
private static float GetLinedefBrighness ( Linedef line )
{
float frontbrightness = ( SidedefHasVisibleParts ( line . Front ) ? GetSidedefBrighness ( line . Front ) : float . NaN ) ;
float backbrightness = ( SidedefHasVisibleParts ( line . Back ) ? GetSidedefBrighness ( line . Back ) : float . NaN ) ;
if ( float . IsNaN ( frontbrightness ) & & float . IsNaN ( backbrightness ) ) return float . NaN ;
if ( float . IsNaN ( frontbrightness ) ) return backbrightness ;
if ( float . IsNaN ( backbrightness ) ) return frontbrightness ;
return ( frontbrightness + backbrightness ) / 2 ;
}
//mxd. gradientbrightness utility
private static float GetSidedefBrighness ( Sidedef side )
{
if ( side . Fields . GetValue ( "lightabsolute" , false ) ) return side . Fields . GetValue ( "light" , 0 ) ;
return Math . Min ( 255 , Math . Max ( 0 , ( float ) side . Sector . Brightness + side . Fields . GetValue ( "light" , 0 ) ) ) ;
}
//mxd. gradientbrightness utility
private static void ApplySidedefBrighness ( Sidedef side , int brightness )
{
side . Fields . BeforeFieldsChange ( ) ;
//absolute flag set?
if ( side . Fields . GetValue ( "lightabsolute" , false ) )
side . Fields [ "light" ] . Value = brightness ;
else
UniFields . SetInteger ( side . Fields , "light" , brightness - side . Sector . Brightness , 0 ) ;
//apply lightfog flag?
if ( General . Map . UDMF ) Tools . UpdateLightFogFlag ( side ) ;
}
[BeginAction("placethings")] //mxd
public void PlaceThings ( )
{
// Make list of selected linedefs
ICollection < Linedef > lines = General . Map . Map . GetSelectedLinedefs ( true ) ;
List < Vector2D > positions = new List < Vector2D > ( ) ;
if ( lines . Count = = 0 )
{
if ( highlighted ! = null & & ! highlighted . IsDisposed )
{
lines . Add ( highlighted ) ;
}
else
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires selection of some description!" ) ;
return ;
}
}
// Make list of vertex positions
foreach ( Linedef l in lines )
{
if ( ! positions . Contains ( l . Start . Position ) ) positions . Add ( l . Start . Position ) ;
if ( ! positions . Contains ( l . End . Position ) ) positions . Add ( l . End . Position ) ;
}
if ( positions . Count < 1 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "Unable to get vertex positions from selection!" ) ;
return ;
}
PlaceThingsAtPositions ( positions ) ;
}
//mxd
[BeginAction("alignfloortofront")]
public void AlignFloorToFront ( )
{
AlignTextureToLine ( true , true ) ;
}
//mxd
[BeginAction("alignfloortoback")]
public void AlignFloorToBack ( )
{
AlignTextureToLine ( true , false ) ;
}
//mxd
[BeginAction("alignceilingtofront")]
public void AlignCeilingToFront ( )
{
AlignTextureToLine ( false , true ) ;
}
//mxd
[BeginAction("alignceilingtoback")]
public void AlignCeilingToBack ( )
{
AlignTextureToLine ( false , false ) ;
}
//mxd
[BeginAction("selectsimilar")]
public void SelectSimilar ( )
{
ICollection < Linedef > selection = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selection . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
var form = new SelectSimilarElementOptionsPanel ( ) ;
2016-06-20 13:36:10 +00:00
if ( form . Setup ( this ) ) form . ShowDialog ( General . Interface ) ;
2015-12-31 12:21:44 +00:00
}
//mxd
[BeginAction("applylightfogflag")]
private void ApplyLightFogFlag ( )
{
if ( ! General . Map . UDMF ) return ;
// Make list of selected linedefs
ICollection < Linedef > lines = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( lines . Count = = 0 )
{
if ( highlighted ! = null & & ! highlighted . IsDisposed )
{
lines . Add ( highlighted ) ;
}
else
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires selection of some description!" ) ;
return ;
}
}
// Make undo
General . Map . UndoRedo . CreateUndo ( "Apply 'lightfog' flag" ) ;
// Apply the flag
int addedcout = 0 ;
int removedcount = 0 ;
foreach ( Linedef l in lines )
{
if ( l . Front ! = null )
{
int result = Tools . UpdateLightFogFlag ( l . Front ) ;
switch ( result )
{
case 1 : addedcout + + ; break ;
case - 1 : removedcount + + ; break ;
}
}
if ( l . Back ! = null )
{
int result = Tools . UpdateLightFogFlag ( l . Back ) ;
switch ( result )
{
case 1 : addedcout + + ; break ;
case - 1 : removedcount + + ; break ;
}
}
}
// Display info
General . Interface . DisplayStatus ( StatusType . Action , "Added 'lightfog' flag to " + addedcout + " sidedefs, removed it from " + removedcount + " sidedefs." ) ;
}
2020-08-29 14:26:59 +00:00
//JBR Perpendicular Vertex
[BeginAction("perpendicularvertex")]
public void PerpendicularVertex ( )
{
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
// Nothing selected?
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
}
}
// Anything selected?
if ( selected . Count > 0 )
General . Editing . ChangeMode ( new PerpendicularVertexMode ( new LinedefsMode ( ) ) ) ;
else
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
}
//JBR Perpendicular Linedef
[BeginAction("perpendicularlinedef")]
public void PerpendicularLinedef ( )
{
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
// Nothing selected?
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
}
}
// Anything selected?
if ( selected . Count > 0 )
General . Editing . ChangeMode ( new PerpendicularLinedefMode ( new LinedefsMode ( ) ) ) ;
else
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
}
//JBR Parallel Linedef
[BeginAction("parallellinedef")]
public void ParallelLinedef ( )
{
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
// Nothing selected?
if ( selected . Count = = 0 )
{
// Anything highlighted?
if ( highlighted ! = null )
{
// Select the highlighted item
highlighted . Selected = true ;
selected . Add ( highlighted ) ;
}
}
// Anything selected?
if ( selected . Count > 0 )
General . Editing . ChangeMode ( new ParallelLinedefMode ( new LinedefsMode ( ) ) ) ;
else
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
}
2022-12-21 01:21:30 +00:00
[BeginAction("incrementtag")]
public void IncrementTag ( )
{
// Get selection
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 & & highlighted ! = null & & ! highlighted . IsDisposed )
selected . Add ( highlighted ) ;
if ( selected . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
General . Map . UndoRedo . CreateUndo ( "Decrement linedef tags by 1" , this , UndoGroup . LinedefTagChange , CreateSelectionCRC ( selected ) ) ;
2023-04-27 00:23:27 +00:00
2022-12-21 01:21:30 +00:00
foreach ( Linedef l in selected )
{
l . Tag = Math . Min ( l . Tag + 1 , 65535 ) ;
l . UpdateCache ( ) ;
}
2023-04-27 00:23:27 +00:00
if ( selected . Count > 1 )
General . Interface . DisplayStatus ( StatusType . Action , "Incremented tags of " + selected . Count + " linedefs by 1." ) ;
else
General . Interface . DisplayStatus ( StatusType . Action , "Incremented tag of one linedef to " + selected . First ( ) . Tag + "." ) ;
2022-12-21 01:21:30 +00:00
// Update
2023-04-25 21:57:03 +00:00
General . Map . Map . Update ( ) ;
General . Interface . RedrawDisplay ( ) ;
2022-12-21 01:21:30 +00:00
General . Interface . RefreshInfo ( ) ;
General . Map . IsChanged = true ;
}
[BeginAction("decrementtag")]
public void DecrementTag ( )
{
// Get selection
ICollection < Linedef > selected = General . Map . Map . GetSelectedLinedefs ( true ) ;
if ( selected . Count = = 0 & & highlighted ! = null & & ! highlighted . IsDisposed )
selected . Add ( highlighted ) ;
if ( selected . Count = = 0 )
{
General . Interface . DisplayStatus ( StatusType . Warning , "This action requires a selection!" ) ;
return ;
}
General . Map . UndoRedo . CreateUndo ( "Decrement linedef tags by 1" , this , UndoGroup . LinedefTagChange , CreateSelectionCRC ( selected ) ) ;
foreach ( Linedef l in selected )
{
l . Tag = Math . Max ( l . Tag - 1 , 0 ) ;
l . UpdateCache ( ) ;
}
2023-04-27 00:23:27 +00:00
if ( selected . Count > 1 )
General . Interface . DisplayStatus ( StatusType . Action , "Decremented tags of " + selected . Count + " linedefs by 1." ) ;
else
General . Interface . DisplayStatus ( StatusType . Action , "Decremented tag of one linedef to " + selected . First ( ) . Tag + "." ) ;
2022-12-21 01:21:30 +00:00
// Update
2023-04-25 21:57:03 +00:00
General . Map . Map . Update ( ) ;
General . Interface . RedrawDisplay ( ) ;
2022-12-21 01:21:30 +00:00
General . Interface . RefreshInfo ( ) ;
General . Map . IsChanged = true ;
}
2015-12-31 12:21:44 +00:00
#endregion
}
}