From 095aa9bb683e9d0e176cb30ed7100be738ecdf0f Mon Sep 17 00:00:00 2001 From: sphere <spherallic@gmail.com> Date: Fri, 25 Nov 2022 17:14:35 +0000 Subject: [PATCH] GZDB merging - part 1 --- Build/Compilers/ZDoom/acc.exe | Bin 66560 -> 67072 bytes Build/Compilers/ZDoom/zspecial.acs | 76 +- .../Includes/ZDoom_linedefs.cfg | 18 +- Build/Configurations/Includes/ZDoom_misc.cfg | 30 + Build/Scripting/ZDoom_ACS.cfg | 5 +- Build/Scripting/ZDoom_DECORATE.cfg | 199 +- Documents/cmdargs.txt | 52 +- Help/commandlineparams.html | 105 +- Help/gc_decoratekeys.html | 5 + Help/gzdb/compilingtheeditor.html | 27 +- Source/Core/Actions/ActionManager.cs | 2 +- Source/Core/Actions/HintsManager.cs | 2 +- Source/Core/Builder.csproj | 1 + Source/Core/Compilers/Compiler.cs | 8 +- Source/Core/Config/ArgumentInfo.cs | 2 +- Source/Core/Config/CompilerInfo.cs | 4 +- Source/Core/Config/GeneralizedOption.cs | 2 +- Source/Core/Config/MapLumpInfo.cs | 2 +- Source/Core/Config/NodebuilderInfo.cs | 4 +- Source/Core/Config/ProgramConfiguration.cs | 14 +- Source/Core/Config/ScriptConfiguration.cs | 105 +- Source/Core/Config/ThingCategory.cs | 2 +- Source/Core/Config/ThingTypeInfo.cs | 5 +- Source/Core/Config/ThingsFlagsCompare.cs | 4 +- Source/Core/Controls/ArgumentBox.cs | 2 +- Source/Core/Controls/ArgumentsControl.cs | 24 + Source/Core/Controls/FieldsEditorControl.cs | 268 +- Source/Core/Controls/FieldsEditorRow.cs | 106 +- Source/Core/Controls/FlatSelectorControl.cs | 2 +- .../Controls/ImageBrowserControl.Designer.cs | 1 + Source/Core/Controls/ImageBrowserControl.cs | 209 +- Source/Core/Controls/ScriptEditorControl.cs | 2836 +++++++++-------- Source/Core/Controls/ScriptFileDocumentTab.cs | 55 +- .../Controls/StatisticsControl.Designer.cs | 22 +- .../Core/Controls/TextureSelectorControl.cs | 8 +- Source/Core/Controls/ThingBrowserControl.cs | 13 +- Source/Core/Data/ColormapImage.cs | 4 +- Source/Core/Data/DataLocation.cs | 4 +- Source/Core/Data/FileImage.cs | 2 +- Source/Core/Data/FlatImage.cs | 4 +- Source/Core/Data/HighResImage.cs | 44 +- Source/Core/Data/ImageData.cs | 8 +- Source/Core/Data/PK3FileImage.cs | 2 +- Source/Core/Data/SimpleTextureImage.cs | 8 +- Source/Core/Data/SpriteImage.cs | 4 +- Source/Core/Data/TextureImage.cs | 8 +- Source/Core/Data/TexturePatch.cs | 3 + Source/Core/Editing/ClassicMode.cs | 4 + Source/Core/Editing/CopyPasteManager.cs | 55 +- Source/Core/Editing/GridSetup.cs | 8 +- Source/Core/Editing/ThingsFilter.cs | 2 +- Source/Core/Editing/UndoManager.cs | 16 +- .../Controls/TagSelector.Designer.cs | 7 +- Source/Core/GZBuilder/Controls/TagSelector.cs | 6 +- .../Core/GZBuilder/Controls/TagsSelector.cs | 12 +- Source/Core/GZBuilder/Data/EngineInfo.cs | 9 +- Source/Core/GZBuilder/Geometry/Line3D.cs | 8 + .../Core/GZBuilder/Windows/ExceptionDialog.cs | 4 +- Source/Core/GZBuilder/md3/ModelReader.cs | 24 +- Source/Core/General/FileLockChecker.cs | 4 +- Source/Core/General/General.cs | 42 +- Source/Core/General/Launcher.cs | 2 +- Source/Core/General/MapManager.cs | 58 +- Source/Core/General/UpdateChecker.cs | 74 +- Source/Core/Geometry/InterpolationTools.cs | 2 +- Source/Core/Geometry/Tools.cs | 8 +- Source/Core/IO/ClipboardStreamReader.cs | 41 +- Source/Core/IO/ClipboardStreamWriter.cs | 17 +- Source/Core/IO/Configuration.cs | 9 +- Source/Core/IO/UniversalEntry.cs | 2 +- Source/Core/IO/UniversalParser.cs | 16 +- Source/Core/IO/UniversalStreamReader.cs | 6 +- Source/Core/Map/MapSet.cs | 2 +- Source/Core/Plugins/Plugin.cs | 6 +- Source/Core/Properties/Resources.Designer.cs | 14 +- Source/Core/Properties/Resources.resx | 3 + Source/Core/Rendering/D3DDevice.cs | 4 +- Source/Core/Rendering/IRenderer2D.cs | 1 + Source/Core/Rendering/Renderer2D.cs | 74 +- Source/Core/Rendering/Renderer3D.cs | 2 - Source/Core/Resources/Actions.cfg | 10 + Source/Core/Resources/FixedThingsScale.png | Bin 0 -> 1595 bytes Source/Core/Types/AngleDegreesFloatHandler.cs | 5 + Source/Core/Types/AngleDegreesHandler.cs | 5 + Source/Core/Types/AngleRadiansHandler.cs | 5 + Source/Core/Types/BoolHandler.cs | 7 +- Source/Core/Types/ColorHandler.cs | 5 + Source/Core/Types/EnumBitsHandler.cs | 13 +- Source/Core/Types/EnumOptionHandler.cs | 7 +- Source/Core/Types/EnumStringsHandler.cs | 13 +- Source/Core/Types/FlatHandler.cs | 5 + Source/Core/Types/FloatHandler.cs | 5 + Source/Core/Types/IntegerHandler.cs | 13 +- Source/Core/Types/LinedefTypeHandler.cs | 5 + Source/Core/Types/NullHandler.cs | 5 + Source/Core/Types/RandomFloatHandler.cs | 15 +- Source/Core/Types/RandomIntegerHandler.cs | 23 +- Source/Core/Types/SectorEffectHandler.cs | 5 + Source/Core/Types/SectorTagHandler.cs | 7 +- Source/Core/Types/StringHandler.cs | 8 +- Source/Core/Types/TextureHandler.cs | 5 + Source/Core/Types/ThingClassHandler.cs | 5 + Source/Core/Types/ThingTypeHandler.cs | 5 + Source/Core/Types/TypeHandler.cs | 9 +- Source/Core/Windows/AboutForm.cs | 3 +- Source/Core/Windows/ActionBrowserForm.cs | 66 +- Source/Core/Windows/ChangeMapForm.cs | 2 +- Source/Core/Windows/ConfigForm.cs | 12 +- Source/Core/Windows/EffectBrowserForm.cs | 76 +- Source/Core/Windows/GridSetupForm.cs | 12 +- Source/Core/Windows/IMainForm.cs | 14 +- .../Core/Windows/LinedefColorPresetsForm.cs | 2 +- .../Core/Windows/LinedefEditForm.Designer.cs | 35 + Source/Core/Windows/LinedefEditForm.cs | 273 +- .../Windows/LinedefEditFormUDMF.Designer.cs | 39 +- Source/Core/Windows/LinedefEditFormUDMF.cs | 289 +- Source/Core/Windows/LinedefEditFormUDMF.resx | 2 +- Source/Core/Windows/MainForm.Designer.cs | 35 +- Source/Core/Windows/MainForm.cs | 91 +- .../Windows/OpenMapOptionsForm.Designer.cs | 2 +- Source/Core/Windows/OpenMapOptionsForm.cs | 87 +- .../Core/Windows/PreferencesForm.Designer.cs | 51 +- Source/Core/Windows/PreferencesForm.cs | 98 +- .../Core/Windows/SectorEditForm.Designer.cs | 6 +- Source/Core/Windows/ThingEditForm.cs | 12 +- Source/Core/Windows/ThingEditFormUDMF.cs | 66 +- Source/Core/ZDoom/ActorStructure.cs | 257 +- Source/Core/ZDoom/AnimdefsParser.cs | 2 +- Source/Core/ZDoom/DecorateParser.cs | 12 +- Source/Core/ZDoom/PatchStructure.cs | 50 +- Source/Core/ZDoom/TextureStructure.cs | 14 +- Source/Core/ZDoom/ZDTextParser.cs | 18 +- .../Interface/JitterSectorsForm.Designer.cs | 2 +- .../Plugins/BuilderModes/BuilderModes.csproj | 12 + .../BuilderModes/ClassicModes/BridgeMode.cs | 2 +- .../ClassicModes/DrawCurveMode.cs | 143 +- .../ClassicModes/DrawEllipseMode.cs | 127 +- .../ClassicModes/DrawGeometryMode.cs | 122 +- .../BuilderModes/ClassicModes/DrawGridMode.cs | 289 +- .../ClassicModes/DrawRectangleMode.cs | 182 +- .../BuilderModes/ClassicModes/SectorsMode.cs | 2 +- .../BuilderModes/ClassicModes/ThingsMode.cs | 4 +- .../ErrorChecks/ResultTexturesMisaligned.cs | 2 +- .../FindReplace/FindLinedefFlags.cs | 2 +- .../FindReplace/FindLinedefTypes.cs | 56 +- .../FindReplace/FindReplaceType.cs | 6 + .../FindReplace/FindSectorEffect.cs | 38 +- .../FindReplace/FindSectorFlags.cs | 2 +- .../FindReplace/FindSidedefFlags.cs | 2 +- .../FindReplace/FindThingAction.cs | 15 +- .../FindReplace/FindThingFlags.cs | 2 +- .../BuilderModes/General/BuilderModesTools.cs | 2 +- .../BuilderModes/IO/WavefrontExporter.cs | 10 +- .../DrawCurveOptionsPanel.Designer.cs | 32 +- .../Interface/DrawCurveOptionsPanel.cs | 17 +- .../DrawEllipseOptionsPanel.Designer.cs | 65 +- .../Interface/DrawEllipseOptionsPanel.cs | 43 +- .../DrawGridOptionsPanel.Designer.cs | 79 +- .../Interface/DrawGridOptionsPanel.cs | 55 +- .../DrawLineOptionsPanel.Designer.cs | 75 + .../Interface/DrawLineOptionsPanel.cs | 32 + .../Interface/DrawLineOptionsPanel.resx | 123 + .../DrawRectangleOptionsPanel.Designer.cs | 28 +- .../Interface/DrawRectangleOptionsPanel.cs | 33 +- .../BuilderModes/Interface/ErrorCheckForm.cs | 10 +- .../BuilderModes/Interface/FindReplaceForm.cs | 6 +- .../Interface/PreferencesForm.Designer.cs | 11 +- .../Properties/Resources.Designer.cs | 132 +- .../BuilderModes/Properties/Resources.resx | 29 +- .../Plugins/BuilderModes/Resources/Repeat.png | Bin 0 -> 587 bytes .../VisualModes/BaseVisualGeometrySector.cs | 4 +- .../VisualModes/BaseVisualGeometrySidedef.cs | 8 +- .../VisualModes/BaseVisualMode.cs | 28 +- .../VisualModes/BaseVisualSector.cs | 25 +- .../BuilderModes/VisualModes/SectorData.cs | 38 +- .../BuilderModes/VisualModes/VisualCeiling.cs | 33 +- .../BuilderModes/VisualModes/VisualFloor.cs | 43 +- .../BuilderModes/VisualModes/VisualLower.cs | 3 +- .../BuilderModes/VisualModes/VisualUpper.cs | 3 +- Source/Plugins/NodesViewer/NodesViewerMode.cs | 2 +- .../TagExplorer/Controls/TagExplorer.cs | 2 +- .../VisplaneExplorer/VisplaneExplorerMode.cs | 9 +- 182 files changed, 5413 insertions(+), 3241 deletions(-) create mode 100644 Source/Core/Resources/FixedThingsScale.png create mode 100644 Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs create mode 100644 Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs create mode 100644 Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx create mode 100644 Source/Plugins/BuilderModes/Resources/Repeat.png diff --git a/Build/Compilers/ZDoom/acc.exe b/Build/Compilers/ZDoom/acc.exe index fbdd29fc88b0c6d242e05354a4264c6a6ec16cdb..a295df1d5995775c500cee526358f6410a266d00 100644 GIT binary patch delta 27304 zcmZqZU}@-Kneal<Z}FZm1}J#Iz|6?a$jQLa!N9;!1rc<f%*m+FG>?6<6{8ws$mB#u zcSeiJD;dqXl-d{=7z7v?7&<1uVw5vm63D>7uz-PqA&7y2p$DQDMmjJsIOwG$mLxJT zFl2B@GB7YOGBBtxFfiPkY{#U|$h0|)sf&rxW%5TBZ6*fg$#Sf+>>SFD3=3J5Cp)p) z*E1+PGVu4VVqjqS@1i2GkVV;%q1#7A;J-=7e-{;r7eCS%7$RSGGcYi8>b_x(V(8R; zz#7HCzmF~8|8?V&%|AT&rylI&{Q?(je&O-`hV+3*hseb*SfdzThji*{uz|FBa6~aQ z*fEqihrM|A@BjbTt3bwgyG&x^um4)Xz>tx!#DO9BwNThT2ev4Nuon+OVi8Lm7{Xo{ zaxgG79}xgKuiHfhM2lFnf}P#->EHkV%{3|#3?;4^Axj(>Uf88EfPCi2@ZaFYZjjR> zEpt>PO64;^rUt+0u3%sYe!<KRv+u=Kb_RyYeQaW84jfSo$5}y+WCZ!u6zphI7mg@~ z7vC}&7+zdWVPJT1F`9wlh4sJx|95mOabU1Cb(nmMO$8i+-7YE;Vd0BGq4(n5pa1_~ zbo~GSAL^Ag*$fQEw}Uf45t9K5`WJVjz&?5r=f=SB;%_7a!wc1P28M-mzD6?aO<L-} zus>m`14H-O<{ykDOx@@Io1S2eVh9Wf%dlDMz!3bRg^ht>AqQI&L-P@d?yt@2U{&9{ zdGD}BF?3&T{t41_JuDz7Fhd5cJ`|*0gl+N?cGUzCur>j=?sM5Ec`RiZORsgy@~}lQ z7$0!x%u$iCzEQ%`S)(G;Z7Ktbv>X)$>knWNg>F$5h=_po1+a)fH!llBM8x_8SVUx@ z1lwdy4qf&utWgXZ9LkepIaKNeR2><*T~s(0^Qby99A3zw>d4S~poBl*zv!I>4h+qz zAOVKRW?K<eM+Sxxjx5Iiq8}DGFdPm8$JjmzRY!)f7j|U~3}G+6uz*61C*#jH2ZpfL z1EuUQ)XEqbUbDV1EMs7ZjO;!ZcetCEfx(f%_`qvEOCJ@M68`Q<oJLF>s*_DPos_^f zl}cm;fYOQ4|Ns93{)@g?;J^?Wxfmq1P(*d|3{JCHkVAsIV>ygZI);T?`tp?4F9i9a z^+1VWw<*XI&8i?iL-&u@{N1)|zD6>1n}Q;))Avuat&F-O14F53cvyzRb_a$|UJ(C< z`Tzg_n~(4`+e)ZU*5*o3n({T0A>#mu5ZLa(aI68uWO%Xd-~ay^Jlh=@{+mvjyq0SY zqr+q`Ze>P?$$8w4j1xC+;J(YqxOs9PuPtNg<TJdcN}#05P-6XG^b05)4=6O(axj&O zHrs*{E<=fOH?PZNWj=StYm>A2Oc~22FXSti2*_h#X#QbSBGPQT<ZC2DatU{qbe7wT z`pE|TO6)%Q3=G|}9g`#Z<?7Y*85pu8vY1}T<ufq+H|_Zv$?)P+Bq;PnS`U<nK}15c zBwxt=27B%0MFs|j7rS#A7$7FA^0!U`iL8W+sFjF>X4SoT_v`=vEVUPtK@K^>^P2TV zJ6wfosdQ*o{fjfd{{L5tjLcGdkq=S?cBpD($$R4it>5^k9%w$m833{VMcrf>0m*vt ze2BBYm2muL1tr?orvF(%Df+c8Tnj5qi+L0%p>#w@w1SmOuthPvX8X?yO2-g~Yx1`o z{`dcXmOz%q3;8&Z;`rF;m*;aB7&2ORI51=}z3~0}|9`WskDVg}V`OA0XML8&i_N(V z43US!!e6Y&VPMEo%VKH%!CuP$;zBM1L$__m*GPu%_g{0rxEKrLMn-0-XQ{u~kP8ju z<sb$()K^C%85pwovJ|^NyyypsYh<y!Xv<|_=&X}i2r{et#KDIG+$WlkXmt9?yfCZJ zfrYtdsd5%baTLf}H<`%DZeEaj)&Kt)7(iMMcDl*DW_>X?mVqIQKTGL_5y;h%FTQ5O z4d8FF{txxLYAo3AaWAidrNQ1UQO#HY2?Osx|Nm#{XEDEcms1Z<AEk-lh<MHVVsSPD z!^?Tu3=A1(AnIlQAcq<Ii>7P_hS!=IJ0P<EenU-Lm;*8lWEV6nq>@2KO1uopW?*>X zo6W%RzeI)QMS(5@LnNqZ{FvpGC7|-6ItJv{mwMR@42`xHlO2Ub6D`af8M=9ObR8KE zK4AIJ3gUKlcz^_bR9HGYd>|~2&W->Oix*U0b#{c9feI*)+SUUlN}zCN>Fxw^t-&VM z@p~)=@eV#<VfC22T}Ve7#52AW)_Sr|b_dAt<_ZqRQm$?TYg3)c|AZv!O-vmb8W<QD zO1ZNbv)o>+|Nj4fWaL7SD9mll|5-uY&JF`Zkb@!aFfnvwIQ&|(o9C#8p(6v-a^?Rf zM|BJx89e@*f>bRAX?vk+5Ar$K#MT3)=MH!Cs%V2szt)p=V%;M3ts2^n49zxEHCRA} z5{HBJ!J1db2M!w_a5&s(Yh#AwIQJLA5XXT;ksJr&c6KPJBOIrq4hkfYc<X@@z1On; zO^$-fIFJ7&DjbVJ!Y?M;F)%Cyv6LbsyLpaEsKfkFe+A8fts0ZfL=x*YbR9w7C;^31 z@(amtpily5z;~Gppd5G63X}?XUarhwV8~$D3C@M;KS3!9S!c?N`(NQYw}5mqzL*Zx znGez_1JU{R2b#{wVxoNYRUi$nFJhq@Ofwi5LizXW9%GGS2<tXo@HLVlyxaB&YZOD{ zb5MSIA(8>hHHsxXVJ~uRK#inN3=9mx#<yR5Plrh=l}Ns51Xb@((is?DxXLgvI77>s zk~h}(`FmC~Ffdr(<?pXw%)r24{MPzwO>`D(y!HKB9_`<uFC=Uj82lqkzk##s%LoRB z7xU5?7>p0>{}0mkoqzrTkLCxRtaXeG3;{0|TY^K$65L2D<+1)=&k^=wp#=lO>)5at z{FV$1uS3D+ECiVomd?PC5zolL@FEASt)3?sqOpYk#S;q#hVS>nUfcocReTW-<#vI% zLf|5G&Vek(<^!eyFVen%LOeP?F7|M<t%0c{g9A9J`@Kj8OLX&s#JXKnSpKtuSe-1r z7N(%&1L8FQV65fKV$AY?q44Fu!2ifd;{%617K3EESz0Y7&lWRdl$d-;%s}b2k^_UN zvIE0=B?pGjN)8O)l^huUDmgGPD?2c7DmyUnD^FGt4`ocATqPdD$T#`CxR}`Yui#p# z`523T>B|g>?cgNyX!37y1)16~P+EgTf+~OORt5%!UN@Oe*FP_0Qzx5C*oc{a0_hca zEgT&1zl<X=qZw3>DNOE^kT(>vWMIe=cyZVaWJK%#I*u&97u!IbX4gL~S-Dwi?k~=U zg5+K_q<~Yv<eL)Gj9Vsul`yKGYysBm0#Y6sA9wO_7%0cQSQx~>(ETB@^;@X`h@Zun zW&R@PBgh3jpymvyyvwM8B;4XJ|Nm$4K}$y7Kn74NUFNuh3AnlHq0!9?ZiIN~bn}AR zB+VW&|C<w37@CiWbb1&Z<_Zn#HU*U*dvzvnkW^xvF!{2iqRN&JAe%&*Z9xrthW}+8 zC0zf@RbEtsqMD0;o4ZQD3+u@eQl^a4C;Lgs+e0i6fLPG!A=1su!Q#l!$+#Fq9fn%) zTK<2T!2dFl7sucJ|KIJ#^1py1i!m$f#lQEH*GNg&fZ835rF>ZoS&UglFW$TdIe_Oy zMG`o?zD6=Am)<u1=Jp~ziGg7uNNw{E#!~()hJdW17yBnkt1#}EtSYTo@085I5NUiH z9Bx@=SxPSqK?0F48yOfF>bzdO1yx1hmV;8MSQcZJ*$cz>|Nm!cy!ZsN=Lk<+^x+qY z!3+%6_evhVH~?3ySt9j9LJTR7-f#U@tNUVpA_K!~=`6;qh}YX+{19beSXd8onRD|G z&63B>Ka@(JLXwkG>7&;y*7r*L!TD@M5Gbn}f3qx65#gVDfb}#3D3_KPLvm@kNr@!1 z6;UD(3@OvYUub}OGe>wVO+oPiiHkEv3=FTKap7gezz`W1{gS^vk%1v&4<uRie*FJG z%OXqtg+USnC{P(*90sR;iI*=E7#K2cKvboJRDl{bTp(2@FWwq~+#&KJ_uK#fFNDk) z7+&rMsr~>_Z3$C-Cy{|6%jCs=sOsAw)lbYA<QZP}CNMCBW$^3*XDu#}dWS5g7i$wi zHF(eDM>0-<EpNd=t_cd>BRp}3U&tmfFm$`|H2>fzv1$InSz_M&gR8`-`3HN6E+ha| zOAY>)fl^D!3-`C+gz=gqOYOz;1W<i%yJT{ytWy1LLk0%^ZEg|)FaCjpQlQy(#n(s% zh7vYVsJ~_bR~&Z&K)EpPWnVl4L$j&^8>qLX3MyI{!i>MUb(*@EIWoLBC(OWLX$lf8 zk;-BS%d&d0^$pn4W>rur#n1_si+h;^t}sAa7=pt%!n;3|a)-SLoh&D(#^^rTRW5_+ z_v_8;<t!N)uT6d_?-3KH<-ky+<-pLY<-jlvimz%pFuc-oU|`mEV35#uV9?ceU~tlQ zU<eM&QZW7&7H)j|#kn|8gz&shX#U4hlJ??u3@k&al?r4rW`LRzFJvb7Do8LgPhO^= z5PZoO<i!`QaCNFB(_hPHF=l1IIQ|k;D!<5zfoCDj64vG)8l`WVZ9)BXh7ySvPklj& zB?C0b@M1bdz13t%MO`6K%5MItSt`=)vinc3N!yFxlOq&01=L@Hf=0mjzzeOP|Np-@ zG<l+;ipb{|V2e2Z{Quw03kqdUUWdsi6?LUHfh9mDWFPp${2{9}OZi2g4+Fys=g9&} z238<DRQOv2K#fhQEX@}lJ|Mrm{0&O|;9RT8-|`OB3NOo2d7%xFeEjeK{}(qWS1C!= z2iQ3>yvTh4auCmA5U0~ths}|p`}n~JOaWO8|4l(+FKS{K7{C@E1@+mxq8LEsTeGTz znIpKw5BOiAqVT`W2BJEP@r5nO_9Hs5Oey)_6r>cC)F4U%UPOQs9FO(k(C#<QZ&Vgu zP;z82KHBN}r`weyEa1gf4_Hy|3@N00UGD_ESQicQ+Y4?`60}`1*-u$qw$+<~;Wcjn zxUBbm4)#X3@1O2t#%JSR9Gu*wtWt0G3M?8N7QP!4@s_fnu6GT07Gsvei)YV3fe!AR z?FRK`jQ>YMth21;C}Dr$<p%B%*SmrpWBt8E1R|Tom?imQ)ibcUuf4KZAfgaG3J^W% zZlE;hW9Jypz!=&6A+nU+_;yE}#B14Zu>Boz5|*_brJP~GFHY-&JoTRy<g6DAk??fJ zU1|;sKam$NKn;!1pa1^{1iuIeX?UIY;z|Ta?c^2}Edfw7pRv34Ph?~XXL#_7s>%CQ zWVJylgS(Wg*Y!rgi|K#=|Br+e44V8c+d=68RDjL$1lj$<cQTu*N<Ao{frBCx)NA5_ zc<M#5D=06?K%LV4qg1fDMumr=l<S3sCj&#LyTWUh=5z&y7q7w@7+!?``2WBALs&)( zq$o>(q^r(yiDp|+l4d9o412+3%fJxuUsPZrXt3ZllktI0cbWLO!_AXdstPeGPTr#` zsk1o(WT(K3(r{20+o&`VTqe(rU|{HWl`#Gm8EJj2R6Hz;G0Wz~iph*>l8kRAORFi= zn`<&KM7|IVXJB~E)10Cr!qA+eBEVq$&G^6dJ^sGKjG!0+1&R`=6v&ErVfzFW`!AP) znr_7&3=G!4`CEKIoO59e48|uNEqzo(N?oC$RwDmG^ZWn*mL)0zC7hiudt_d6f}4uo z8Vn3C|1vNze4D&WO_p)V<Qr;gF{>VfOn%`T28yAtkqpg0H2GUVBaWaN?#0V#pz%S- zKmgCD|Npa?yFa{e)BqRg9v+dACGH*`B^DkfS{@~eS&UiHFQOsF{R;&dH#th(EGAnW z<kdZ)3=GEKUQ2#+QE^}_;Rt&nti{0anlmsf;>GtzAQxP$QE|9fqaxuB^#p&*I?!mL zFSr`N@(5g~ObugTXg<Od9~T?ld_?CZgZtz+>T)U{)fgCFvxU7_0SZ%hkU7@BYtC8! zF5$QSR|m>GW-qEI>uHD!1-pTg5U64<<^EqP^FmgAa=3;~{e3kChRD|2b%OlcT(-yr zym+L_z~E;6IkM(G%%Zs=3=DxUwnNpu{9m#~=7o_ORMp4VH?kOCIDi5NluoyU6Cuyb z%n$~K(C#;3;ot-@5z;;k31MI`{txk?Vkw*Z3+E69HU?1H)iYT_Q=2>WAvmK3zhDcQ z?58PNAFRQ^5D6-a0$zB4n7jY~|6kwwza#<LMp7#A2en3cvKX`YUx+;X|3C7z^^0x6 z3=A*CIY1Erj!&f$ndTpwrMF+q1xfs4hmHeWbpeIOYk?PS!Jx6x7occ*&2IevMOiQd zLvt+$Ly3z+>;F=|@E7OQK?+WQ6hvl$3hvoptuOpQ=B;OkrB%&Ro)^|2p*idf46iw| z7+y@Btftjoe^iBmArjPA$k+kNYjTf4E!r%_7Y9K$9T9ku?**!rntvpgaAk$QIDH@F z57rkf|Nj4v1l8^@Ryu>6dN|_>ME^Z-f_dQ^#K4fn@M6cO|NjGC2t9{3hiaWcX++?q zeh@SOChKUcF@{YJ)>f+b1eqN9;#we73KT3i4!<}S$iVPo5~x=4j(Az{>Hq&1TR<W_ zY%rfGm55|9W?8-XeDDANETtDSf<RXA9DdmgQq}<?LjM2%zr%}>f#LPO|E8efmlqkY zK)$#GEsRQ({+srsf`-%HfjVB`aU`b5Qm*5ypuz^!ln;1)HjCl)$!1${=e9(!xz2zA z+%+zLQF{-RLBd`Xf;zu-I*gH}9H6GHG6O>-xY^_D1PY#)41u7*(r1$+b;{~*-UVrS z&AKm+k%0l60+)lFnG?Xk@Zu~BNL`~6*b|VnsL9_F^#A|=xWi!?Zy;fO=E48}-KL-- zC@b_us1jss>O~UB5Oq*Ufku*292pq8k2N2WX?|fBS0e9GBGLT9poBexk8!e}E|-dw z5@>iVEA=%~R@e((5C`m9$w07c@A!ivVRDUb0Q;T*NbB*kt~JlBJOBSjzC6do!0^Iy zvXq_-xXG<rYVp5}BQ&ezMams;1_8GZSwO8li2GGb-oF;@j<e}L_F~q{|Nk>?fI4qX ziVO^q|I2v7U#xfmN+O>WU`<F-WpDxZ!T>CO3oiZ_93~Pk)0r3;KzaXV*0bRM|Dh53 z2jl~=XqO)-VSp>Ll6TO$hs&ISAz(2$<}ZU3Mq0{(6qKIJcnES!xdH>j>x0H`T|@ty z_Dtr`w`Jn>o9wQyZ1BPtWELo#RZA8BmxDd2bsOQyQ+|*}@YhHN)spuMmrS0euPMJ? zo`E5<+nwjdw`U-aEszI!%v~bj#bHHopgz*qS4ae@`CrcS9~_A<n4W`F`oLA@Pc}3V z<pd4zhGyBmh??wgAgy6{3zTTWUMzd{|NrZ}=6W55Qm)V}yBBI;@$eT?U;qDq9rohj z<VgmqOdoGf-f19fSp#a`%?6DNdcT+;$G{NzTIWRuNbCRu%wtOYEr<X9{}1l^S-x0! z6P$<KCi5FA$btOLUdrb7LdplGnyr-e1rM0#GTGNqS2)lXlw4X5l;{L^%YxLuI5xT0 zP+VHw7My-t50qYuj*mN>#qc8G|NsAyhnrPhChs>?;Rh)NHE0EyOLqTxkvRF2p{79Z z4N$;>TC)>g{Qv(#W3sl9l1}uE|NpyP|3pSI9}9SqAkV<?BJ%(L|HoNWazOPfyDX?C z7vSIKAQA9FeR8Fdf*}75P%wepm|v_J7+$QLyvoQR3}hd2<93}j$lW*^w-X_f;Kr@J z7bvkspF9jUG2NSi;f0PDtkpW%z*qyE1u{#`UVQQd#V)u^w<(co{^3?4+WaHAL?DYX zOZtWOb&#uGq*;TC(icD8gR+qmBLhQlcm~UEaBs~P9F4m{gGk`E(@l^qkgC1V3>ugy z&BhzoK*7bM@mfBM37X7<%|PwT1s-;e4F6d{WMpKAo5YJqu*)X@H&%~U&~{|_&kK^W zK3u9~e87?wRG?)s@J|Jg9vKC^NVxX@|3Z+m<|91Thr50M)UtQ-v>NC-GIU>XSPYT? zwFA3de*|T*cVBz)@)6h-&9+M>H=2mo@A6<^cp?4w|Nqu+CBj*fFHT8;5<jS8_*MoK z;*bJClfUIDtmSyl5+wej(Sv~@K059sq#3Uf92TCT0tuLppcDWe<y#0E@#Eib3L5_d z4aP%8{XnBcm7buvyyhd$0@k1T`=)~Ow4n#2$tMCXUqL|-8F}3G2dFTA&GBNjB?E(E z><{aErJ&I+(-)CfLGjZY$N1vs<S0{(`VW!}43XCNY8l}pgBz{y*GgnDW|_X=y80h9 zYOx+<!4aO9Zj1~J-Jf6cf%>qeKRRP?yqN3`t;8=_fQFZ{G+u1?U|`q@irVHQ0+zmi z$_zo{iQj8^wf|)?yf`Dx02)yIno$c%(q)ni4FBs(|GfAv0jcOCBVV2YjYHnHjQvq+ z-h7NX>_srhb^lBMSjvKjB-me^mH_uJ{3I9{A}wP%_*>R8Ffe2VzR;3nV0Z~?E<#m` z_PTKdybu9dQTpe_RFLw>*AB-2jSpCVt`o5IX}wX-?qGea#_H>9X5;_v-N!+b#;S?` z|Nm!Q0UDEYG58<w;+g~l!~fDhFCL16V$S+^iMa89>(6x>|4a7Xc;Pg8u9-yrW^o1v zck6$VHSaBBIZ6bxf?o82HQji@54Q6~yc;xI1&4-(XShIO`pPv>tp*y;?Y4zPwJbcU zpMeH=zu$im;||IT0>*D!Z`YN-kN|a#ei)VVf+N|%9ps?btS@9|nlmt1zXr#x*$c1B z;JD3ZeDTVaf#HSs<Un)b`i~&TTfeSlgg46%TED9Wb=A#Ya9;*T@CK0KkoN3h<F_y7 zyFz32ju|vo54*v}YZr@yTm>7l3oYS&Atlbh5dK0$oPpsr_lxObAkGmnkn^(4UX+S6 z)H8tR$0JL)GcrN3o(yshxcahmWnc&k&q#m-$=0i&AOV$LS)niN#Gw_vH)w)d05tL# zk)`p%*NlN7V?HR&%YvPuki{1N;*$#l!;4^0ljJ{R9d}klmgWmp@F=H$>;L+P&GnET zeW_dqD0RGe3Ub<u{UALGAUzP-lDFXY-8)mzm|62bN6>)TLhyjuRxxN090IqeMdIUL zHn}h`WHdlr%>c?Fd|8Sw7J~vj17z&UAOHVn90xhFQjCG2x&8=rwo{Y8^$}=*J}mr& zBS_t%AO9f(XO*T53@`LRLj542ge>kCX{Ml17I-1y0;`U=N`<m=vQ+nFfx^(-6%@X& zS@)fUS8l4MK`&l8gXSxuvzX&wxPk_a{xg=aWz|b%X}$)J4!;mI1!;S6#F>G?zw~bN zZ>CZyaBBK#!oUDB{KW&1bw>nVEOKUG@Gjl)TK>hq?@&ixH394GaAsh5@$&os|NBlb zfLd=eL}3opjO1@o`Tzfad|Y(KDUk1LMZu}4Ug^awkollKNh8>Nk(bWSpuxK(kRUt& zN`s&vOa=vk2FQX=kgcGWT>?m_{|jSL28M3%ywi&)Nd|@&%pi|4zR+L=g_1(+0r055 z(+j5ypyUrJc+E@w!m~_X{1mAN&3b~StX?QcGBAWehB{w-6K7y}vDXO{UN0Vjr}YKk z#{4-CGA10V@(d`wM#je-hH2dm7Kl3>2+q)ZAfEVh3EGvI4|0Es69a?sfA{bg?JS`5 ze?+A9Kq*&vmeY$xV57Tb!R}f54LaFbW6Z$t!Vu&b(-&SM3=G}6VEIA`@ZhI~2m`}H zkU*!4io%N+30P2scY;SAU#Nhc54XY|Y(=vwcvLdW<c080VNkEBMwo#i6zZkllk=@b zwb;Q5vrJx`5C+AhH<*;W@&Ese+Ux)S|1VLIfhylKd7ZUb{qKwa|969P3nV5$)zXVe zPM{GCM+Sx$JHGz^56(mVM&La3--mxHXnIHrJW&%O43C9sP{^w|GB9MZyzpd3jlkq{ zppefpd7%P!%yJ<H23R!ItBHYJnRgvj34?OsiEID=2WNbN1b;lpagb0w<-ov@#r)zu z6Ub<u)&r&BkuIkf9Opnfd7vFuA5dS^t3({!7<7K|`YgB{oZtx3BoKW#EF9#$?jJ8U zfw~r;lvmI2qR@eX;l(9TSp-U&D-EFq14xtcfo7P8pEV!w4|tI(1Pb&Qf*?2V1~*?+ zUWi`<=Z=?}4h#&STAybRs5#XA;l(0wx_u$&0PYQ7AD;#{zEn%~U<1_FXTjb9cR+4C zAh*q5b3r;Fg}46yhx%5q#I5;<P>Ey49~MW37s`g9afSo@E$<jWu>vY`Ure)SV0iKU z^Z)<geoFQ=P$PYjAgo1mRG1+Mv;yk2(f=}@fEQLbLDDTyY4FMtQ0>eRP{RJ=y8yU; zt`YzZwm90uONY{;te`BW7pV^5E*7W*$~IZZ&c9yk3^?S^gH(cQpy<Qk&Ka`-sJMxb zi+;J;4%Cp$vVVOgLjxROFSO4i&7hWohI`UpJU$IdIj=b(nV+$Q>qWI4s8ys<`u6aP z0uU3NbTt-&8iA#9%@rDuPHjNqi<Mxl8D~LdRyxSpuXRAu;4&rYMK@UX#T3}EO13@& zL&iCfT5ADNV&Qoy400fBk;;+D2KEZ!DKG#3k3SsN{o%!&H=y3^%hiAX{|^f{{_oys ztD+5^_vQ-E@_3;RHon_Og=Zm1;y){h>^14-VR2;W7Go6E(RF0#<N;5lFI+NtxxGE# zp*#QozYJvpWim_F1(UznD=?kEI9bd=)i>bO|NmL)FTO%LBrm^%YKpd3|Np;y3u1l0 z^#6bBfl{9EEYBBeAe9=gue`W-`~Ux!=Rnfsm%-Ak;aOg<@4xtRdvb?^qtL^P|NmPb zFXaf&@_h+v8oltDeA~g6``qjQ|6i(rbS;^z?C2z>e)<3Zm)AjI@|1yr;UzdEZ(f>Q z?PypJ@{T6h7sdx(&HyR7{^I}t*Q_rTU;qD~W%i<z7n+Nv*?>dyMT9j2!|S9M9v}bz ze;o}Qgy0I#Dt|HM1SpD+vw~Vpj0~&{$5}xwr<?!({||rp9K0w76t@f|V8!VW#j0qk z0~kQflgdy3|3`MS{RgjB&}7w_9N;8gA8{I5g8v5fr4CpzFuYI%P1=F-`VVbzNqm|I zR`$O5B*4J%Vzw0nLl*0c1EAF<M?lpOw5Yjx9Go|^OkT|7ftB5^KVIw;K-51|_#w@B z9!pu!a>i1}(1oDY9IXfVTP`y&fL4vLf>v~dcmL@A{@T2`j)Sq3wL6aIwNzHf3s)Xc zuZ-ozF>Vme^I{)2B<Kv!gGQ2Dzm;Bi*$>LuA702$wstmSd%_KJ#N={k#rlO@plsEB zT>IF;A1nbc%(=lM6D%+Ephl^Ij5;O|8EO5!=y`mW*^3^Kiq_jD{8=V18n{7a8Z$^F z@_*?MXzftP2Qu=7=K25s<DyR<4h+lK1IeblPyYW88hGwB1+5k7G_^2uv|#8o1*d3J zP`|9x6x7Fh(Wl11@PZXS8pT)&>K8{``~N?#`3TF)Hx{72=45{tQ4@A6kWH50VXYFL zuq?*l7h1=_Asw70_2MO@ceTa>RQ0}&vp!nt2pZy;;UcSi?I>6kr0W>^B25ugT%P|Q zsr}<cDrl-%^u>kAH(V6zkDmamdoAC5;(xgI@qo}56|x{J12Q@wURnlLAOJ2^6-!hE zntv$rw?=_70+R)(wDB(G1J{9CmJAFpr+`v>lO_X0mUNcQ3vtlgJ!nN6AIPUi1e$F@ zLBIkoWn^DS9{vA6vK~5-@}eI!P}zC_r4Rh$2*hpbP>r>6@V;;sNO@!zxUUQ840m`) zyeKq>m%aQgRj{G5g`m;f$QL2zpil+(;G^nAOH`YG*p?_v{^lyhxOcLko3IYZZ6(TC zj2WE_3=FS@A$Brm@x_&hXEA1gX1QOu906s=W?PTR0dC5CAPoT-36Nm2pWNt{#I@ou zNP+Qz7i%WJbyKUa0CQh+XYs#g%i?*>l*JMEf)CW)2N%pKrCi3honQPlWng&C(jB8B z04c~*OF5cPGrf3b%D~Wl?uGPm&>$Gds^GBj7h8BhldC^iqrjuD@4th>2h<7zjkG(x z-~?OOYzvZSEaAwqVtjFsoq-`T1Ju9&4^Dai!KpAT{6!!yC<BT7X9cZkjgO6vi#+^- zN1cHIG+h$@;=trH?h-b)kAk`<prJJ5+mVr-B`N})vfy+r3(B{hvfyMb3vyehEI3&& zQ38z*n1aH2vVw<9z5gLlaAbK$ECyA$#wVM9c=Jy^2pRzC^idIcAz%it7@sIGFm(R_ z4NCmxZvoAaHrMm;m8d|HFL)k}`4GsnJjMrJuw4STDVmRPyqsaez+f3~QmU54m=*Qn z!NLFk|Cj6hFE@D6zyJULjQTgAxM2)_apE9IugvSimhl=T(UvhPJf)#oj9KX~)+2Pp zfplDfYM2hypbuaCk)Q~2pz#5R$VlrCr5v5{5}olTulc(n>)8AyI^9h=<5fbtbwLX@ zKn<xE#-{b4jP&9gXbSTOESt!gGBCV60?H<3stgP-ZW@CE3!ErzN>o52O7dAuaiHNP z3-HJi|3Od)9%luGpA9HoD!y0-Hcz#bKTA4G?Zr88A0><VHTw%yRZ!DD4ivmEwwr*) z86X2p{tBR|=0VF`+YW%jgy*$v7$lHi7%709i=L${LAHUDt0sSoA1q5{sxUBgm#D}@ zMq0{(rngJ@vKS!~+wliL4(`m?S-9q_cqBuoyTL+m0&$n=J_cT-uFQI6vcH#@hw+8~ z|6iOoVqk#C$D4GzE4-Wo3Ycw13=CNrS<0Q@;rLEjP;!3p95mt{`C^t4s60OK1vE|h zgR$hx!XJ~@dP&u@sW31EXEA0azSy-N?5(gD)hwVPdZ#Rv7t@s)7+(0mY|?g@LCO!E z@h0J&?g}poxj<ng@}l(I|Not`ph`79E;=$2(%~`wpT%VS);+p2M+H(2f>y;h|8V2) zzsAVGz~A!Ol97SIgTF-()c$^<U83ClLV&;J9%v%*1xE>=2Y>59P<i?L$p8PZ54>pk z@&EtpoiFwnf?|Ghy|-cgM+OE4OYpQriEze+y`bghe-8ft->Lh9!;v8}@<pm41H;RR z|Ns9(6}`(?0akSV;Q#*_HG3TxLSLK#Cs=__TacF5XQ2v@Hrs+aQ5>N5LHvu7eW0kx z$N=k|4YB~d2I+PE+!uOB|Nnpa{onupp)WRqMp$3I{s*_MF~bL}BMYp9fh~$5GSX5P z6zlvgNuZVpB;v*Q{r~?m0JQ4*M*@Efs0?lXkyxVH{3EGEvH3v1_3?7P|2`@LFFt@g z)AR5D|L`oG7mxOW>wwp<!e6&r)~E=S@P=n}fzrS!kVGVSz3Y5XK!FOO$Vls>rD7Qx zVAtF|0E#G(@XNgapcWf{>$QKNq7pQ${$e2~14E~+09zEp%l)854DCn$|9>e0T5a&c zx5V6|#Gv^FcZp*23$7Bu&~T3|lNW`1!O7<3*T0}J(75*h|I42sjorWg|9|=5@BjbZ z-(NEse|rH6gqIiof(oG6=*YvyCyg(4@`8%c<E$cVlM8*->Ou4Kosd=fyr8wtoxGrh z(Ve`YWzsKd^%)pm#Q**O|HX<k|Np<7xa<G_g$co~4BfncSi!3vpRh(TFdxVg4hYo# zxELh!;@_VC{}+Q~nU6Ie;aLn)5O)|hvt<nKBr_kgW(BD&V|}r%{{R2~;AL+AO+iXu z2pKXkFoK!QM|c=Py*dWCZq=~v5)~e3A3x*HO;FeDMe2TVM_A&;Oi)}N5s5ntTEAmy z3JU5HRsL-*DjWfjW>Cf#hz{fZ|Nr;8s7M67Nc;c4{(mz_56pp<{M%hrSi)dBSZ;yr zhzonc0JFto&;S4Y+YfZQsL1rXsK^AoPzGBof$*a#)H|S*oFM`>;KjjxP)F+S`TrlT zH;X0ih0zmGEFVGAuNM~HU8BMi{^GViX#CtQ4BEZUP=T0LHrdTz-Uj47{uTiy(C}P$ zEk`G~618Ln_3=t9|C{V(;B<ub%QNmkG%AA}QOfaR!sLbi>gf@7jtu-Qx{M4A8Cz~S zFoYd<<ya2d)DrvS#f`oH|997NL`J^kV`N}x{0|c6Z}|XfukwPlS)br<`N9Bdu(C!m zXdj%Zedywk<{zwe$=#x$h&TR!jD>4`>w!AyZqYxJ^#h~=L82WlT#OL;jP;;VyIvng zCgzJ7H6Xh?A+?eyI0d+ZleWO?B<sU<iQTp!y<Ha?UIken?hxVc{tYp8R)AC@NT%0^ zkuiYzBE*2+j&%$S41oa|4q!te#y#8v$|)k<wH(c=AjdPj7P4doF-p0>iE%NAjU~Xs zUM!z18W;rLr_#;)XL4Skm<%X%8A^CTiHarQg$HQy$>Eo$L0t>mH<K3xTGWGLg|S4n zm&F{O!f*Wk|9>IKso|i-o1l3kD_v08%>z%?YM^8-0E%>h@UV;zkjR<|n!Yblk$JHk zoW4Zj;|_!RrqF^?4det4u)ct>4368NRQe)qw*@$1%LKeAhG>e52Tx#ti)zLa!?5mB zp78&r9AOy}5FMr<OG-IjESlUOB<TsNw-`XHbRoVl3In;A=Y^LJxb76`{^1T15DClB zfard_3!JD`UVH>6VVU?isBM!!21y9GKoqS8DJtc7Au(ApSULw{vcf`8-ask^Dt`U{ z56Se5s5xE{<V6lxj*oyC>9h+JqXIA1f@h&&IaeO0ssy4+X7YkySp(3F`N0P)ogF!# zQp-n$qq8F;*cG&s3A)a0@eJQkh7#TYNTo1)^4nlpt^$x+Pm#`!lF1?=Dr%srgJJOm zWOX*%Kvh#W?+4Z>&}tkBhJ6{6<3hwZg<;~8YeN*7UT&SdAVe$@<mrw8rtWKA-)~7@ zQWgbyKCRQDGk~WnL`9|}fVo=~)ClVg5HP;f{Ev};$|1+J&J2!Y4lE3vU>iCEL_kX- zLc8BUY&1U5da^ESSJq_yQ2qM6Xjg`AUy<Ix|Bb&u>vhW2Iy!QqT^SBOWD5LWD$(1} z5beqk@ZyptIME$vO$l}d?fqkjiv_L51#Jgw{09;!6#<X4iN5%;1=NZLNi-kf$^6E_ z!oUDZn>=0a8jZ&i92^-s*t*<hI@}n$+!Z?9ChrXuWxO-_a;QeQ4Z0PtS&q3eGyG=- znH6{VKWm3~C<8RuLA$-WLHjINdJ_U&84&F;_bs51Jq(WbgU^_{+Y%-Rg{jp0f*jQc zQVQ}{ctB^{1n*FW7ppWtz7pwnQ4xvnZ0qn0Wr#c6Xd7ea2--%+0A3AO`{MQH|Nmc$ zLM=wvv~M%WriCEI*#|hYI6&ExHNnFbw2CWafdd0rruhiZf7Tc~Pe+Es;V(>hKqI1% z%H&1dZ&2+GN&qiTeE<L77_@uK(iX(8iwN6S6733Fg8Dt+zZw62w=V%1J&;scH`y-S zOcA82W_?`zOKBeP!k@t4@QfW01v=aQ|6h1z^3-r`F;F@&z6~*R@eS4}hPt4zeHoLl zg{v^WnfyCkSpsa#*0}iSlZO|A*r35~<Ny0ICYwcAFn*YvAE7Ds24bqr*8l(c_p=4O zF#7iY|H2!S*F`8WewchdLcShkNhfGeC&&QfZ`OzRim)&+@b^t%U|`r;14>&LEG0`B z-I&jMm437STvwgNlA&|gf#C(;*Z=>!j~#r#9Pnbr*Z=>)4ro5YWBlLxa9!BG>}Xd8 z%Q(SOSN?5m0sqT5`S-j1g$F|97Em4P_BY^#_T=11dBzWudm|+n^CmBglowM0nVtRR z|9{9*%@?d-vnSt<R8io#3ohoiZU*cA74V|{3y8%Q@S^Su$N`h(qa+v$CR;?wi7|jo zx%C-tN(n?kPL!TJ$e)ps?#y4Uf7D#HK3tcu50qO#n@+v6STcT0-Wlc0_+j$jD8(31 zvSr}!1J!<6EEyl}I550m`TYO?LXbGv-?Kme|8IO7>}g9`kZ4`rzC;H{P{cC^Ks?U; zzl=SL@r5X;TN@b=p0VK$*bh#VtD+qk?@ZnuEiD4p7`rdo!4bUm)g_B1W5wiG(Vn&- ziJBEJ-mx(-v>vGA`ELqp%f8S74G)E91b8|Jhrej#VqjPZYQZ%h;jy#@7iFc!->i@C z&6r#eW5&2(^70sy6p(xtQ?&70$TAcD)?W;u^>x-q>q7T~i^cQZ7c4bP7~Pr=3V4-% zwf<UXo5hkb1LR-%kB~@a3V5;e<NyCKtBk){AFY$H)CX;ASqK)NY#%FL56XWfjBbwB zCu%-gf3366V#$~QGUfOOxG9NX)!_Z5JYZ9#EOoYm_3?zgaDhoix><jyc?NNAsjcyU z>!Wqb`#`0#Wgbf@%YU=ijG@6V7PB!hxJNc06R@@g`7pAk{!wU#uWLj=@Qa_I1#KWf zP~3bozHNQ9u6{pQe>_Wxl%>pCP(e~E_}}~mqap)CZwVVK*k_Th&Bq0-U)0>R{#@su z#gfqhay<8k|Np~YtonfB`@?nmaPwp>WwwINs}~7-(fr~6|NrJMcEglMM!JE_{7`ev zQWjMF@wY5s1O>kFN$bP>eV``Q-V#u4bJbD?QV_CQN|iFYIW`{>us%`q%K9^Z3use7 z7E4A0$T9WrAtA{e@In%11=x?)hwF6wdTqcCv6L^7w2Wma6$yLs^*z`*@7_aQ4|2{? z0qYMnSHStSr2G59XH1s!KxJu3QWi@_1;`R<kR@#ilNIA7EI=L$&v1dH+R}BPidVt- zt>rwBc%4KyxD@_xvf@SM`~Ux4t=EBsBWqqPRGC~DFKz}3@n#!vU^A3RG}p5*lnDJd ze~~2*4s%XOm^(uQ{aWj{lH@Fw44cXO;^p{3kymHE7i0p+SCe1I>wtSIHK!o;JyWSz z7E6W+$hqwAK<kBGEPV%Z91pnEZaq*J2U;K7dY~?BH>gPOejWN^vm671d-G9FYjFJ# z*;~TKSo5;=Tb&80L<1SL?=2{%W8Z;>L_zt<6jU|TiFW@Ef6@N#|9@+@=Hr~!V8O_m zxBp921YQ_{)kbEqKzC!XXQ<q9V0g`%Ap<fm|1GG30WG7xGWlYH2&2#BX9>#nOCY7# z>NWrWM;d<vtwr^G`~UwpR!~9A99jASYLvUB=^552hI)HTQ&2fjZ*FM{%HE~=mZqR| zRH|+XE)GiNEx|4-6}L16wNOg=Eloi+d@1{jCeR8jOG{Hw^QDA0ETbLNPZbkb338OB z=?m5<h7$1%i@TE-a*EWy(D)9j%|LGWZwhLxW+Z?X(08u_hbd@gG%QQ(#px9wz0g+P z6yHz=#!}W7GXMYo|6j`SLJBktYs<jIz)-~hzmy}3A&d9LtQBDWVgE}xAO`M~VPNPk z<;fBXd$9y0rwX!>p;=88R4Owp2H6bmF?PEOWE{Bbz_7T-JCvc*6x3Nf&N^jsV3LF) zC{!4lRTub%GB6wl?HlW6Il9C*6vl2{GPx^BSK`8Qu+7E?;tmJ@H_JEz3G{cXCZA8T zssAU<z!2#W@M6RA|NnynI@w-qlm;~;1YR>Yt1)yRk2|~&WICuZ8yJ@H0HU>K6)0I) znu25^BkPpFP1ye?UqM!PvV2|P8_Muv+w1@T-K-%>YVLtms4_D!G{jZ1dNiN-<4_{n zocf0$YjU46m+eB(lF!JKhr=@dKr9ej1&RTX@h`MqgX{t)K@h)A?7s=b0zs$+lP@OQ zGa648Oi7ks;v31(Y{w8@Dw!3W!NS18@WOW4|NoJlY|RP`|5?vWo}8l0cxCeT6jMgo z$!}BK8Lv(@O$}zeGPyHV6I}OeyK?+5<!FAv67XWl8&LE@cb)A6+5AEcw5&D`(i-bE z*$TC+)BtAJ`6d7V!>j@|g&})KA|ny4timNAL;shk@N}EKxDM(u!HuiOG_Qf6c}mFU z?Sq(?p>Ypft6G5~y+(zHAu@7@!aWCuQq~<3_Z%3)vRDFM%y<rJ)q;}Si`#F&1%|fV z3wVetyZ{SHf<#JGWU?5-_AQuvE=`<q$>e8gb_OmG^Cv9(|3Cc2N{~t5ajF;YZ~p)9 zX8UjOVk&rxhDvj-07Hq&!Yh+Q(w!OCOrDXhuli>Z$p2Yf|4URvx<9-y1}#i*2zc>y z5xDOp(Fs}s^=R^&bZIG2H-V9V%E3-Qk#1}2A0@K?%Ry~Ykr&FF6*IIL8MjRK$yDd) zc@Flf<K*g0bs118X$#u@0dDCkytumH|Nqwk9c~i;Syd+Q%M=rYE2upO6@8kiRlmbG zlHq01U$6^U7H;v4WO$JR3dz<3;6=n0FTxjq91UuN^ZYm2x<J7Zw5ggWV+F+S+{KU~ z8<`y-gI>gd=Jh}W7#Qj=K-Am9)q}0lncSBp@9|+iID@_fb>cF9KotH01&S%y&|HwA zsvst45&z)~kr!ZZ-vFxs8{-XDv1RhtEE|6Vh-~ws|Nn!#kG)U>NgWZ0kBdH>;Q^7# zKxo_!mgPCTkb&Qkp&4q2D#%RGp%X4)`#2^yWJe3;Ks4T52o5HJj4hMjWJ}iD34;cm z4@0}g--JLTGz)b;Ml!fXcJoRUMl$q@7+7B{6Uzz?d@*U>|Nn~*_(n2B8Xt&U3{uq1 z3*v&thXi_U7{gyY5dsZ%fn=JG@N^%Kk2}0jq!6^NLZG$|q>AI<1I~RHd?Oi{j|IH& z6=Gnh2g@IPzzGtl1li6D(s1x0C;zq<j`O~e3;{2C7l1+*v{XhMp*o}Dl><Y-3mGAh z^TEQPz3ZIJ=K=#VVqSs6_6|hfe^!u*py4bKEl``%>!QLE@FEDLv$g&}X((7XhU+#8 zGBAK;ppJ_Ln+6)hR|X3stgC@omj_lL0J9EkAlR>AFH*rvGNi!@c;Z?Ql(H@Y1;XL5 z|MjMzeXAJ@AV%mc0A*l}kC6=jMLiaP4#hYFO3OO`{{IIblhSPp;xn>>PDb(T1aq># zsWhvCCMOu0RaHJlGB7kAyO0~n(Cx?4&DO~aGOF8;qmx(RBS?&=llO=(h#}Ak-Z<Os zCnD0xd%`!8q03JpU@^!k9lQdClST6s>tzZ-8w}0E|C@phu?4&5`a+NcB3lpCi3Nx4 zy8^Q4#(%T_*PD;2ct@6gjf-wp1?!7H3|0uP&On>+cwieAnX{B4EWwj0B|=$@pi=b3 zi`k&O`C{G7|NlXo^t(e;Sh|^vQ%}C;fhy#5>}Kg|Jy81LFi0LUN5@d2*=!5;Z>hpU z(9t5@yfeN=GIa8S*o#5T<E$WQ(0bIv!C~Q9w$WMg#{c8~n|yr$%Keau8Li1u`TAZ@ z6dV~K^J51bUcZJ;#=Q9X|9@obfl_AU1BaU{c(_ZyL*{^3L4$@K5}mxDbpYKCGK)bg z13>Nq&Eia+oUdfK0TP%0=l=f>(ZUSU;wA$cJO+)8zZQZBvw(#q7I#d3mTz4TiWh5E zP&5^>WYtF;?qc|N!bZNFX@dg)KG5j}maG%LMlzJ}F9MyLvKZ`3kbtF&3QGz1aj+!V zui(J21s$SP%hS;TQtSX$4GM&Ppka})4A4T^41<r63@_^WK=X|(83G0Jkqj@2_!t;= zFflPP?RO}MWLUkr`G`c?YUA6+2Ra%OChsp0s|V?EX#U|=_dY8zqU%J%%kYj4s90Lv z`z*G|U5t#3jNOO!2Npy!d|sWlI*To``_TSEC@(|5!hs=+!}x$hmR$xY7LKtR6+|*H zFUl{7WayCXFNkC~&I$@4g~CXNPFYa0?34v1^~Io!+bIi9k{z-jKXuB&L*T!t&jJUA ztl)hhKZm{Wo(U=}B;q?wL4{Xbr!1&20vB4*hr30=p)3jxWsYO40)>$b^@p2nK{hd# zO8#dBjaoIUg18J>j2kOnl!3<qS-QBKK-t1LlA#l9Lc>q_a`A?rT%a8+AjP17->3jm z63LLo@WK()#yA|tzt2>la57twB9lPjWX&SYdXRNC^`#HuUYh*>|9>IKE#2UZ`I@&& zz+o|n-|&m8gw6V3(fijz5Z8d6u>oAbv%LKK5451?#kAl5|AXcYGC&zK?8V+0|Nn<| z|9BDp^Z)-aa2|d!=hy%L3qi8YM+A&dI`)cKEI#5}AIV^RAik3qltDYeVE`!vz)62G zD6=dEW$w6_(?Qcvy=zoT{{8>o_=bmxfdRJbv$X@Xrar8D>l8)?hVZbACy=B*aTavA z$i3MXWQ0H|Pgr=C-izqzpt#@x7X{tC^`PP<`+y27sC@d*3R2j~(G4!5Iz3n*A<^l< z(G4!5Iz4z`d;0~t!6j6uhe#JMC<u*jhjn-;bVf+L$eabvqb1-mnU2_w7fmxE0x}Cg z#jDlf65$5hi@uQzR;64Wu6`ZITsy5gV!L`>JHi59FmW?5^tyHgyzrR;cIE3pOIdI_ zi*2d%I_}y4GU0z|16ausF0k6LfEQ;Vtbi9{lVwXJ>p>c7j=pB=K5l)uROdhVNTmPZ zBK^gO$)K_vl%gO4Vc{7qpbm@4G>~;NAagTLK*G;{=Kud7{)@{$pp2^T|Nn!d7g8v{ zI57>h+ZYt1%m*Q5c=*PO#R?K1BN;kvL3Y5h3#caOlvSC0wnV1hf{THn@n{bt1H;L~ z|3PQS{Qvv^KO{0jRCuxvs6-l{bnNUnk{ij;IpG9|<OMa^4!>r7k@M&O{{~x7Xe*R_ zf~4d~hUS0urOeIe{=e`8?R`EL2P#tbgYv5J?e6dV+rZhWt3jY3lEH?tgvDlZMk$}X z;8alIZhgC!V*$vt4mP(J?0^3Me|<ds7#qWju*p+PRlti3nHU%t!2Oe(@4{}r=>7mT zu3-nrIHpq5yQ~ba9T@ocfh}o%VbJON=eFygo2PG_ym$D{$rn?8|NoDwrR4J68#hnh z;r;Q-f#KfA7Z#ih3<sYHXn*JgujE0Lz;P$*4>zlVwk|Qemh1)}9>l-xz`=(s%qKd* zycd=Tv%4BV#huOn(rX9<K!eU8?alv~YFL~9sniLAhn)jo{Fn@iXr3&UIGFijQ1jQH zgByP5*MFn`;GhY6p$)2Xnt%K+y@@a#9LUDEjsNch1@wz`zy5<%PkvdZz+N{Q!WJl( z1(h)R<q~|L*ay`%hl9Ih1qvsJmfO{D?r>lLn{T6CqGDrP!VfW<4YX$NFbe|%gv-Og zzz`Sx^1@G8oh1lb>hKn<F-t$v>R^dHLN5nMZ#!HsA4ut;PF|4ZuXjOGjcq9p#Nc|+ zX@0Mlc7pd|y$ohyU_etK0@B?IQLGIzSf7Of>R`1}sAHu;;&K1~|F^M)31xwVyg^%) zz>Nu65cexH0|UevFJCc3eWuT#1d_T9k`e{E@Z|+&sQJdXoo!<HTi=2*<;@@e|AQ0P z<O3CEnxN<edvZ4e$QTfp9c0QHkkXew{{MeD7a}oPzEYz;Y$7<GU+2BB|MCC-i~I1b zqh7+B#SolT`N9OE;)OhD;eq>cR*-?*Ab(p!*qk7?K7`E+Vk<*Z>1$~lb<jB=ATvHp zfY>6$zwZEeryV57SQs=J7+xIz4$H3U{4I~c+s#0F_CoZ$y!aO!t&`tZ8iO;NI><Bb zOwe$!(JIlh(dTagRa=Ni2D#~_G84%EpkU(%X^DoI^EHw|55)C>bG1O+Z;Vg_tqztb zAq)bC+$~0^K{5;=555$FYZU@%WrlDk@2ygR)RORcmH<hg{PX|6ja{kEi|OBB{)8*Y z11VVX2kgPGkqlBGZV=2i1~CxVnGuodpeafiBwhs91&WN9GGO;d6h<;2l9@P29q8aM z8=F!c@F`8O<O?+@7o<Q7ZV>1k%9mHbi31dBq9EC$5boqH)w=b2`oOXH60|x45`hY! z_^ySpLC06VE(B*fn;KY3mjRiv;5TyO&jtzg{)YKk4rGKC#0X^&TMx~VIUx11zyJRa zhbWQ<DdK{#)xbIbaIYsrREq<HV21<4B`9sx;=oYX;=pjX#erc*ivz>q76%6Q76*oN z%?=FU@+Fet#e*-9GH82^vN|YLzn04W#>KzyKyL}#1xOlxF(0BNl7WBQiH4m51(O+T zwZN$m)c%bIm-*l}D`YYl)C?(=g*4`&9U7!I{Y%jPk6=V2(fBsFssEbwg~%6J%1|iz z1g#19_kk;;<`)blsvafM9wmYvCG0Pj{rvxb@~T=%Hc$jDTr&A&t)e@qEy7S|-0S)$ z;6)o~^I+?N67^>A@)d?|*FTFv)nX}c7DISe&5QOPa1_4KeEa|ZYo_k|t+)BX+lQkU zE}3jtCk)=DY3-uIQu_MkBhVgxF3_QE0xv*oV-_x%oLDDg#?=F=6JK2Dgmieqy1@;G z@NRHL{$d(<;SZ=zFXgZV%apv1k2`#3@}{~Ht_w<z45dt;55Igg*`QuSzS%Z`BZ`5c zL>GKG2S@XhA9rO`KJn|YsGL09Y@0B-zJ7{dz$6ET7spu{7#7xijbu2^qT=!?lHtE; z#n(uN#UN&e$)`w$3=0rp0Fn{S0G+IOL}anUr$~m@1GOAk951eemU11=63DnQIk7>C zF=TR0gRWcvM-+qgu~M!q`4?3n`PbG9K|-wuN_9F-112AD(6;ya6v+S<v_4iUouRVO zfgwX?p##H<1#F;R`*Bu~dQi=88T+J^BRKrOsLlch220r#jwpr_$&8fAhK<6;AkIRN z8@qWc7C10;GX6IO@&22Foc!Mu<mMNVt>8FW?C~j*!BW;{a(Sb=4v1}h+fvr%QzSzv zd%%Cu0<hU2CzZ1O7tLAVz;N944`{{GLXXL(8c*ed6#f^T1L{ot|1UZNaz<tZM-;>2 z7>+20|DsbCI52ecwt#w>9REcpfO!pI-ohRbhheb~=-gCkW(I~ATS1$IY~Lt>j-cbo zI5x$B;lF4H$ix?EV3`+_8JjigBR+$AtRWy$Gyp`(`hZAN4-jeV@;Q<rtw*!~O!20G zDOm?F#cBhlR4u@iuF2;}hB^JL8J{B=x?LF-$AD>;#R;Dy8G2ng7UzKYtq;J3)QV4$ z42%qn3=0!JM_Mo}j`;-Ya|L{gWZ-0BIB=Xb1S}10@OQS}_yd}|RdQtLY`yd6|NsA@ z0t*}%7B86mpjm`h;x))q5}?FlyI?Y7iz?%f$?7dz7!xMnY4Ow$nh25=S>V86eBkhZ z)fCWRhAJp!Wr<`+ym4T7QN#pVdKxp?w^fe^9KP2&U7!3njhNits>=r!D1Gq%TJsT+ z#SxPawc4<qc<sQj@5E%SHkru^Z7ggTK->$Hwc5@}SiEsy$Z(zFz>oskJjW2w{Dvbq zEPUaG$pY<b8C@suYnNfXF!^@74_i#P14G7z$+{gA7%xoT*P+CCW%9$02u@I*`hKm` z^vYzX&V8FFFcmOPp1_n)uk(?CLF^*~1KURihBqG=7;b!EVA%D6fnnYU28ON=3=Cx- z7#JcxFfassU|_KNz`)=HT13dez~JzXfx+t?14GC=28OtI3=A3X7#IrPF)&oTV_;}{ z$H36@j)7s?I|hb%?-&?%yklTE_Ktz!+B*h@2k#gdUc6&q`1X#0f$2R%J%iah1_qh; z3=Br^85rE&Gcbg`XJANs&%jXfo`Iq5Jp;px_Y4f{-ZL;9de6Xc<~;+$t@jKJkKQvd zym`;S@b5hXgTx002CWYa3>xnk7^L1YFbKS3U|@O2!0_uW1H*^63=GfSGBDhE%fN8u zEd#@uw+swN-ZC(3d&|JU_nv`a&D$6ThOCba3?&~K7-~K;FtmJRVCehEz%T>qOVBaQ zPCX7F3XGHb92i(9IxvJxM2LYTU`IiNa=9G?14F}W28M>~o1?lb7?}(WH(%+|k(Tud z4sdlgb&Uve4G#4QVPFVwc8Q0HF>L<1TwH!L&+#X`te|ANV)EB3;R>KAJMh{8G@QW@ z6zme*SeCm$A#$2u>&%@=YvmWJPtLij!{|DB;Z<$c&Ako`$0uLBD$QCj!GWP?^2e+4 zUR;wPjs#_XkRxyW2km}kU;yz~Pj+C~KiPrd#2b(d1h09=z+ka}fnfrYSPUp27EDwW z8|euJv}qPwLfPDUJ(^|H9S#;ooz0vNzO&R{x#_@g<fa3|j++h)D{eY4%(>~nFyW>H zL(5GEhKidG3^_L)7$R;uFu2@wU@*Apz#wzefq~<u0|UcN2Zj$f92g$laA3G{!-3(% z4F`q;Hyjvt+;CvnaKnLN#SI6B1veZRX54UKXu09QP;kS6A?AhygU1aA28$aG3@SGq z7zA!O)H5*LaA5dw-GSlGbq9ts*Bu!4Tz6ntaovGo#&rjVj_VE#CD$DoQm#8Ngj{!E zaJcTkU~t`mLE*Xs1J88_hCkOF7~WiSV7PJ3f#Jk82ZkNj92nMIb6{9-&4FRcH3x={ zYYq$**Blsft~oG7TytRXxaPoMaLs{1<(dP7z%>U3hHLc>3~#PFFx<K7z;NWM1H*=^ z4h%D{IxzHHbzrEu>cEh5)qx@Assn@1RR;!}s}2krR~;B+t~xLXTy<bzxaz?0;fe#p zgDVaU7p^!k?6~5<u;7XV!-Oji3=LNt7z(a9FeF@YU<kP4z+iL5fkEer1B1*J2L_%i z4h#%e92h=ac3`+uf7yZI#AOGDEtee_7F>2<=(+5`P;=RVA>*<GL&#+Z2Aj(c3<{SW z7<eu_F#NdW!0_Ob1H*|+4h&l^IWR1^<iOBz$$_EZk^@7;B?ktFOAZV=mmC-*E;%qT zTykJ|bJ2m}&P4}?6BivAHe7UISa8vSq35ClL&Zf0hLnpA3;`D%80u{<IxuKlbYPIV z=)k~n(ShN|1qX%~7aSPQTyS96alwIM$pr_7DHj|VS}r&+lw5FNh`Hdv;Bmo$!Qg@e zgUkg7296633?I%rFx)xsz;NWe1H*>%4h&PyJ1}&dcVMVE@4%38-hm<HyaR*Fc?SlA z^9~F$=N%YW&O0!CIp@Ie;G9D}!<lmq3_H#_Ff2Lez|eEffuZJ{14G6+2Zoq)4h$aW z92hLlIWVZ4b6^lS=fLpitOLV~vknYb&N?t0IP1W$=Bxw5oU;xLJ!c&lYR)<^<eYV2 zh&k)P;BnT0!Q`w1gTh${2A;DH3_s2|Fg!Wqz;NM=1H+y(4h$>KI512(<G|2yrrv>} z;*0}B#u*2Oh%*ihE@vDVbj~<1$eeLt;5p;K@aMDx!;{kv3};R|Fl;&Pz_8%71H+Wl z4h$`)9T-YZJ20f2c3=oN?Z9Aj+JQmmv;%|8X$J<L(+&)OPB}2VIpx4`=ad7(nNto7 zM@~5~>^SAXu;P>h!;Di73=>W{Fm#-9V5q1+<-m|}%7G!`lmmmuDF+6VQw|I=ryLkK zPB}1qIqAUg;G_e?nUf9-J5D+<EIH}GFyW*FL(NGChLn>I3;`z{7;H{DFld}~U=TU! zz`$_Qf#J;w2ZkFb92kzAa9~(-!hvDR2?vIT6AlbHCma|ePB<{QoN!<;IN`t`al(Ot z=Y#`8{h#9w3?Gg=Fx)xrz;NQY1H*>n4h(aSJ1}${cVH+v?!XXp+=0R4xC4X9aR&yK z;|>fW#~m0LKzfcjFx)uiz;Nc61H+DE4h&0<IWY7bb6_Yr=D-kf%z?q>m;-~!F$V^P zV-5@)#~c{G9Ccv0bJT(1$WaG|HAfv7rW|!(s5$CT&yaG|fx+jf1B1m;2L_d+4h$kk z9T*snIxu`V;=u6Why%l!BMuCEjyN!^IO4!C<%k1A!x0CDf+G$L2}c|le2zFU*c@?S z&^Y42AacZkf#rw;!<WMj3{MU_FkCt8z;NWS1H*>H4h(Y+J23Pdc3`ME?7)z7*nuJD zumgk7VFw0_!}SgfDu*2yL=HPJupD+^_;SdB;mIKfhAW307!DkAU|4g=fnmlW2ZoMA z4h$uS92gP~IWYJfa$vAH<iMbE$bmuRkOKq5AqR#x2OSu09CTnfaL|Ea!9fRxmV*uq zIR_mWA`Ut*I2?3fP&w$pz;n=n;m-jFh8G7M7_J;}U^sBVfnh`a0SAT!2OJnC9B^Q0 zIN-pLbHITi<bVT%%>f4nl>-h890wd2-t2c^xUt`X;lzFihAsOY80PGEVCdQJz)-T^ zfgxeP1B1_g2L_A%4h$;$9T)`mJ23p&=fLn{p98~{eGUu<_Bk-D+2_D8W1j;<%RUE& zf_)AQA^RK{Z1y=YDC~1!5Ea<x!0=};q~>jT?!W+Q4%kjsd?3zQ@!Wv{ByJDp<ve!) zU-%FR;xWcdj(jc88S>nL!GeK-!5l2+GkNA~c}|Dt4h%M+Gl3^Bd@assF!|<dc}|t* z4h&8V3=EEwAHJ2~c<#X9!oa}bJel#0I46h)s?Gx@AN(f4@eE`i14HmcMRCp-P)^ij z$2a1fcc8rJ$&DZ2>SDlBC!kWXlNTbS;=rb_fl9?seu$7tn5_6&VshkLdCnTBbP`B0 zW6tE6Z{-;iChvSJ&lv!fNdw7n+CX{fV4ez;mjUKUKzSV?|8nv`d7WV1pQjN2WP;uK z2Fl9<^KL+S*<juYC@&Yx+X3a}fq6@yy!^=z-$-ykIb~p}4k)jDGUI!B#;VDR@8uaQ zz%mg~nMyFv1Inug^K78Jn#l{_%QMzaPW%QpwhpX70;-^XGUEq%#s;w1k0%hnG=h0g zpu8q9?+TRH0tykvBa?rAkmuY26>Fco@Qnn=69)#+wH;lP9p8#`&UoU$&<nad1kCGz zD(nMAdc_k5h6xM|4E-RJI5VC&Fo4ePpE#NEo5bXsALSWcCja~>&uB1N@{>HL3{<1s zWW`V7oFFSe2}yqP!`I?W3{NIkeUfARGI{1FdB!J`cYc!Ryz$t9VHN`e!_3KyAH_LO zJa%9J?W&p$=Iwdxz_5gYfnhP&MOz*_Ff3zWU|0&~EqM&__?F2F--<KNnOyl<o^itD znV;o3Tc9!rz%GY!4o-gfQJgVj^3TumoFP!L!;=}mh%-7&w)`T`X#y2H0#e7R0p%T? z{P3d$2b6ORB*nz@c=E0<a-2UNL9CaWeDI4n=L;y01<bnx<=vWm@U1xGg~^s*<vGtl z#qNL%;XDE5-39aZKzaATsdEFAcONXb1j>6bx$&z!;}>xFH$cU{g3Ra4f%3kAb;m$? z-@z%s2g>^a=Gj1bKf$KxKzYBwaxzff@5ziGBp4q}{`F0clL0FBcXHzw366&l5B~#O z`UcAT4|e1oD35V6<0o;(6O(6tmuK8DdFOX|&LvP8w#f&-i*rta@;D|h{4UPf0_Aan z0*$d^vgHqX&J3s+H%N>#2Fl|B^E{wDUU0&)f$~HrJN^*o)PeHEz;Y5$o;X+z=5l_p zDL)=S{2>6AdjaK%fOw2ICRhHH=R5)xlLV{Z0p%%yc`KkiH&AkBoHP07PkF|k$&$b1 z8EYn6{*vd+fy#S>RmVViJ|NRMeV{zQ$p=4)bJ{?8{@{?&f${>t`Xr#dz{w9^OK{wW zI5-GoCFc_;FBr_b0Of^De)t8hFccIEoNJ&`VPNy8KzZR{UIUaD0kVy;Wb)77@{B2y zCI85ChCpSaLB=z>Opg3xUvF{WfkEfK1B1+c2L>LH{Cx+8FZUc6p4@X_xN^^d;lw=$ zh8_1D7*^bKV3>2yfnmZu2Zn}w4h#kNAPx_C<-lOTz`)@1%7MX<fq}v0l>>tj0|SG_ zD+dN+1_lO$R}Ks&3=9k!uN)Xm85kH;UO6zBF)%R5ymDYLXJDvjkaz{D&jemMFjz7$ zFz~!`V6b9fU|@OWz+eq3TwX!yHj5n&47Lmm3_o5vfa}XQFC7@{!LtyM8uQLe2L?w5 z28J^)A@$yomktch3=9l=UP7wAEiWAyTp1V`HoSCTaARO#Sn<+<!5!qp1uq>KJQx@l zro41u@C22RFC7@X7#J8@UOF&%GcYjJymVmjVPIe=dFjC5%fP^pGx_9S`}%~J4h*21 zonCBrU<e2K|D^*%1Zd3Tr2|7G0|Uc}?G6l43=9k=FC7@7LH>W~z!1a0z##F`fgu*; zt(OiAaSRL$A6_^x#Dl!?!hs=yfq~({3kL?!MNU^<I4~rEyz|0=AsJ-e3kQZ2kau1< zFr+dtOm6=tX|d&n14AarD=!=v@<I1Qy>MVCU|?XF@xp<j5ag2=4h%&M3=DqH9CmM% X1f97AvY3Hk^M!vJj9WPve=q|8v{#dA delta 26497 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 CT1Yei diff --git a/Build/Compilers/ZDoom/zspecial.acs b/Build/Compilers/ZDoom/zspecial.acs index 63e1b6fd..e85ca558 100644 --- a/Build/Compilers/ZDoom/zspecial.acs +++ b/Build/Compilers/ZDoom/zspecial.acs @@ -24,12 +24,12 @@ special 17:Thing_Raise(1), 18:StartConversation(1,2), 19:Thing_Stop(1), - 20:Floor_LowerByValue(3), - 21:Floor_LowerToLowest(2), - 22:Floor_LowerToNearest(2), - 23:Floor_RaiseByValue(3), - 24:Floor_RaiseToHighest(2), - 25:Floor_RaiseToNearest(2), + 20:Floor_LowerByValue(3,4), + 21:Floor_LowerToLowest(2,3), + 22:Floor_LowerToNearest(2,3), + 23:Floor_RaiseByValue(3,5), + 24:Floor_RaiseToHighest(2,5), + 25:Floor_RaiseToNearest(2,4), 26:Stairs_BuildDown(5), 27:Stairs_BuildUp(5), 28:Floor_RaiseAndCrush(3,4), @@ -39,19 +39,19 @@ special 32:Stairs_BuildUpSync(4), 33:ForceField(0), 34:ClearForceField(1), - 35:Floor_RaiseByValueTimes8(3), - 36:Floor_LowerByValueTimes8(3), - 37:Floor_MoveToValue(3,4), + 35:Floor_RaiseByValueTimes8(3,5), + 36:Floor_LowerByValueTimes8(3,4), + 37:Floor_MoveToValue(3,5), 38:Ceiling_Waggle(5), 39:Teleport_ZombieChanger(2), - 40:Ceiling_LowerByValue(3), - 41:Ceiling_RaiseByValue(3), + 40:Ceiling_LowerByValue(3,4), + 41:Ceiling_RaiseByValue(3,4), 42:Ceiling_CrushAndRaise(3,4), 43:Ceiling_LowerAndCrush(3,4), 44:Ceiling_CrushStop(1), 45:Ceiling_CrushRaiseAndStay(3,4), 46:Floor_CrushStop(1), - 47:Ceiling_MoveToValue(3,4), + 47:Ceiling_MoveToValue(3,5), // 48:Sector_Attach3dMidtex 49:GlassBreak(0,1), // 50:ExtraFloor_LightOnly @@ -70,10 +70,10 @@ special 63:Plat_DownByValue(4), 64:Plat_UpWaitDownStay(3), 65:Plat_UpByValue(4), - 66:Floor_LowerInstant(3), - 67:Floor_RaiseInstant(3), - 68:Floor_MoveToValueTimes8(4), - 69:Ceiling_MoveToValueTimes8(4), + 66:Floor_LowerInstant(3,4), + 67:Floor_RaiseInstant(3,5), + 68:Floor_MoveToValueTimes8(4,5), + 69:Ceiling_MoveToValueTimes8(4,5), 70:Teleport(1,3), 71:Teleport_NoFog(1,4), 72:ThrustThing(2,4), @@ -109,6 +109,9 @@ special // 102:Scroll_Texture_Up // 103:Scroll_Texture_Down 104:Ceiling_CrushAndRaiseSilentDist(4,5), + 105:Door_WaitRaise(4,5), + 106:Door_WaitClose(3,4), + 107:Line_SetPortalTarget(2), 109:Light_ForceLightning(1), 110:Light_RaiseByValue(2), @@ -177,14 +180,14 @@ special 188:Sector_SetCeilingScale(5), 189:Sector_SetFloorScale(5), 191:SetPlayerProperty(3), - 192:Ceiling_LowerToHighestFloor(2), - 193:Ceiling_LowerInstant(3), - 194:Ceiling_RaiseInstant(3), + 192:Ceiling_LowerToHighestFloor(2,4), + 193:Ceiling_LowerInstant(3,5), + 194:Ceiling_RaiseInstant(3,4), 195:Ceiling_CrushRaiseAndStayA(4,5), 196:Ceiling_CrushAndRaiseA(4,5), 197:Ceiling_CrushAndRaiseSilentA(4,5), - 198:Ceiling_RaiseByValueTimes8(3), - 199:Ceiling_LowerByValueTimes8(3), + 198:Ceiling_RaiseByValueTimes8(3,4), + 199:Ceiling_LowerByValueTimes8(3,4), 200:Generic_Floor(5), 201:Generic_Ceiling(5), 202:Generic_Door(5), @@ -223,9 +226,9 @@ special 235:Floor_TransferTrigger(1), 236:Floor_TransferNumeric(1), 237:ChangeCamera(3), - 238:Floor_RaiseToLowestCeiling(2), + 238:Floor_RaiseToLowestCeiling(2,4), 239:Floor_RaiseByValueTxTy(3), - 240:Floor_RaiseByTexture(2), + 240:Floor_RaiseByTexture(2,4), 241:Floor_LowerToLowestTxTy(2), 242:Floor_LowerToHighest(3,4), 243:Exit_Normal(1), @@ -237,10 +240,31 @@ special 249:Door_CloseWaitOpen(3, 4), 250:Floor_Donut(3), 251:FloorAndCeiling_LowerRaise(3,4), - 252:Ceiling_RaiseToNearest(2), - 253:Ceiling_LowerToLowest(2), - 254:Ceiling_LowerToFloor(2), + 252:Ceiling_RaiseToNearest(2,3), + 253:Ceiling_LowerToLowest(2,4), + 254:Ceiling_LowerToFloor(2,4), 255:Ceiling_CrushRaiseAndStaySilA(4,5), + + // These are specialized versions of the Generic_* specials which are defined for EE Extradata. + 256:Floor_LowerToHighestEE(2, 3), + 257:Floor_RaiseToLowest(2, 3), + 258:Floor_LowerToLowestCeiling(2,3), + 259:Floor_RaiseToCeiling(2, 4), + 260:Floor_ToCeilingInstant(1, 3), + 261:Floor_LowerByTexture(2, 3), + 262:Ceiling_RaiseToHighest(2, 3), + 263:Ceiling_ToHighestInstant(1, 3), + 264:Ceiling_LowerToNearest(2, 4), + 265:Ceiling_RaiseToLowest(2, 3), + 266:Ceiling_RaiseToHighestFloor(2, 3), + 267:Ceiling_ToFloorInstant(1, 3), + 268:Ceiling_RaiseByTexture(2, 3), + 269:Ceiling_LowerByTexture(2, 4), + 270:Stairs_BuildDownDoom(5), + 271:Stairs_BuildUpDoomSync(4), + 272:Stairs_BuildDownDoomSync(4), + + // internal functions have negative values -1:GetLineUDMFInt(2), diff --git a/Build/Configurations/Includes/ZDoom_linedefs.cfg b/Build/Configurations/Includes/ZDoom_linedefs.cfg index 40a3d959..d3cae5b2 100644 --- a/Build/Configurations/Includes/ZDoom_linedefs.cfg +++ b/Build/Configurations/Includes/ZDoom_linedefs.cfg @@ -2982,22 +2982,24 @@ zdoom type = 11; enum { - 1 = "Texture only"; - 2 = "Things only"; - 4 = "Both"; + 0 = "Texture only"; + 1 = "Things only"; + 2 = "Both"; } } arg3 { title = "Horizontal Speed"; + default = 128; type = 11; - enum = "scroll_speeds"; + enum = "sector_scroll_speeds_x"; } arg4 { title = "Vertical Speed"; + default = 128; type = 11; - enum = "scroll_speeds"; + enum = "sector_scroll_speeds_y"; } } 224 @@ -3025,14 +3027,16 @@ zdoom arg3 { title = "Horizontal Speed"; + default = 128; type = 11; - enum = "scroll_speeds"; + enum = "sector_scroll_speeds_x"; } arg4 { title = "Vertical Speed"; + default = 128; type = 11; - enum = "scroll_speeds"; + enum = "sector_scroll_speeds_y"; } } 225 diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg index 50f36d72..c1f17c0a 100644 --- a/Build/Configurations/Includes/ZDoom_misc.cfg +++ b/Build/Configurations/Includes/ZDoom_misc.cfg @@ -661,6 +661,36 @@ enums 128 = "128: Very fast"; } + sector_scroll_speeds_x + { + 0 = "0: West very fast"; + 16 = "16: West fast"; + 32 = "32: West normal"; + 64 = "64: West slow"; + 96 = "96: West very slow"; + 128 = "128: Don't scroll"; + 160 = "144: East very slow"; + 192 = "160: East slow"; + 224 = "176: East normal"; + 240 = "192: East fast"; + 256 = "256: East very fast"; + } + + sector_scroll_speeds_y + { + 0 = "0: South very fast"; + 16 = "16: South fast"; + 32 = "32: South normal"; + 64 = "64: South slow"; + 96 = "96: South very slow"; + 128 = "128: Don't scroll"; + 160 = "144: North very slow"; + 192 = "160: North slow"; + 224 = "176: North normal"; + 240 = "192: North fast"; + 256 = "256: North very fast"; + } + stair_speeds { 2 = "2: Slow"; diff --git a/Build/Scripting/ZDoom_ACS.cfg b/Build/Scripting/ZDoom_ACS.cfg index 0c720800..2982cfe8 100644 --- a/Build/Scripting/ZDoom_ACS.cfg +++ b/Build/Scripting/ZDoom_ACS.cfg @@ -72,6 +72,7 @@ keywords Ceiling_CrushAndRaiseA = "Ceiling_CrushAndRaiseA(tag, dspeed, uspeed, crush, crushmode)"; Ceiling_CrushAndRaiseDist = "Ceiling_CrushAndRaiseDist(tag, dist, speed, damage, crushmode)"; Ceiling_CrushAndRaiseSilentA = "Ceiling_CrushAndRaiseSilentA(tag, dspeed, uspeed, crush, crushmode)"; + Ceiling_CrushAndRaiseSilentDist = "Ceiling_CrushAndRaiseSilentDist(tag, dist, speed, damage[, crushmode])"; Ceiling_CrushRaiseAndStay = "Ceiling_CrushRaiseAndStay(tag, speed, crush, crushmode)"; Ceiling_CrushRaiseAndStayA = "Ceiling_CrushRaiseAndStayA(tag, dspeed, uspeed, crush, crushmode)"; Ceiling_CrushRaiseAndStaySilA = "Ceiling_CrushRaiseAndStaySilA(tag, dspeed, uspeed, crush, crushmode)"; @@ -91,8 +92,8 @@ keywords Ceiling_RaiseInstant = "Ceiling_RaiseInstant(tag, unused, height)"; Ceiling_RaiseToNearest = "Ceiling_RaiseToNearest(tag, speed)"; Ceiling_Waggle = "Ceiling_Waggle(tag, amp, freq, offset, time)"; - ChangeActorAngle = "ChangeActorAngle(int tid, fixed angle[, bool interpolate = false])\nSets the angle for the actors with the specified tid.\nIf tid is 0, it sets the angle for the activator of the script.\nangle: a fixed point angle in the range of 0.0 to 1.0 (N = 0.25, W = 0.5, S = 0.75, E = 1.0)."; - ChangeActorPitch = "ChangeActorPitch(int tid, fixed pitch[, bool interpolate = false])\nSets the pitch for the actors with the specified tid. If tid is 0, it sets the pitch for the activator of the script.\npitch: a fixed point angle in the range of 0.0 to 1.0."; + ChangeActorAngle = "void ChangeActorAngle(int tid, fixed angle[, bool interpolate = false])\nSets the angle for the actors with the specified tid.\nIf tid is 0, it sets the angle for the activator of the script.\nangle: a fixed point angle in the range of 0.0 to 1.0 (N = 0.25, W = 0.5, S = 0.75, E = 1.0)."; + ChangeActorPitch = "void ChangeActorPitch(int tid, fixed pitch[, bool interpolate = false])\nSets the pitch for the actors with the specified tid. If tid is 0, it sets the pitch for the activator of the script.\npitch: a fixed point angle in the range of 0.0 to 1.0."; ChangeActorRoll = "void ChangeActorRoll(int tid, fixed angle[, bool interpolate = false])"; ChangeCamera = "ChangeCamera(tid, who, revert)"; ChangeCeiling = "void ChangeCeiling(int tag, str flatname)"; diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg index cb235564..194679dc 100644 --- a/Build/Scripting/ZDoom_DECORATE.cfg +++ b/Build/Scripting/ZDoom_DECORATE.cfg @@ -23,7 +23,50 @@ scripttype = 3; //0 = unknown script, 1 = acc, 2 = modeldef, 3 = decorate keywords { +//Editor special comments +//These are handled in a different fascion: key is replaced with the value and the caret is placed at [EP] position + $Angled = "$Angled"; + $NotAngled = "$NotAngled"; + $Category = "//$Category \"[EP]\""; + $Sprite = "//$Sprite \"[EP]\""; + $IgnoreRenderstyle = "//$IgnoreRenderstyle"; + $Title = "//$Title \"[EP]\""; + $Arg0 = "//$Arg0 \"[EP]\""; + $Arg1 = "//$Arg1 \"[EP]\""; + $Arg2 = "//$Arg2 \"[EP]\""; + $Arg3 = "//$Arg3 \"[EP]\""; + $Arg4 = "//$Arg4 \"[EP]\""; + $Arg0Default = "//$Arg0Default "; + $Arg1Default = "//$Arg1Default "; + $Arg2Default = "//$Arg2Default "; + $Arg3Default = "//$Arg3Default "; + $Arg4Default = "//$Arg4Default "; + $Arg0Tooltip = "//$Arg0Tooltip \"[EP]\""; + $Arg1Tooltip = "//$Arg1Tooltip \"[EP]\""; + $Arg2Tooltip = "//$Arg2Tooltip \"[EP]\""; + $Arg3Tooltip = "//$Arg3Tooltip \"[EP]\""; + $Arg4Tooltip = "//$Arg4Tooltip \"[EP]\""; + $Arg0Type = "//$Arg0Type "; + $Arg1Type = "//$Arg1Type "; + $Arg2Type = "//$Arg2Type "; + $Arg3Type = "//$Arg3Type "; + $Arg4Type = "//$Arg4Type "; + $Arg0Enum = "//$Arg0Enum "; + $Arg1Enum = "//$Arg1Enum "; + $Arg2Enum = "//$Arg2Enum "; + $Arg3Enum = "//$Arg3Enum "; + $Arg4Enum = "//$Arg4Enum "; + $Color = "//$Color "; + $Obsolete = "//$Obsolete \"[EP]\""; + $GZDB_SKIP = "//$GZDB_SKIP"; +//Preprocessor directives #Include = "#Include"; + #region = "#region"; + #endregion = "#endregion"; +//WFDS + A_Bool = "return A_Bool(bool result);"; + A_Int = "return A_Int(int result);"; + A_State = "return A_State(str state);\nreturn A_State(int offset);"; //Monster AI A_AlertMonsters = "A_AlertMonsters[(float maxrange = 0.0[, int flags = 0])]"; A_Burst = "A_Burst(str chunktype)"; @@ -49,7 +92,7 @@ keywords A_KillTracer = "A_KillTracer[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; A_Look = "A_Look"; A_Look2 = "A_Look2"; - A_LookEx = "A_LookEx(int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state seestate)"; + A_LookEx = "A_LookEx(int flags, float minseedist, float maxseedist, float maxheardist, float fov, state seestate)"; A_RaiseChildren = "A_RaiseChildren[(bool copyaffiliation = false)]"; A_RaiseMaster = "A_RaiseMaster[(bool copyaffiliation = false)]"; A_RaiseSiblings = "A_RaiseSiblings[(bool copyaffiliation = false)]"; @@ -64,23 +107,23 @@ keywords A_Srcr2Decide = "A_Srcr2Decide"; A_SwapTeleFog = "A_SwapTeleFog"; A_TurretLook = "A_TurretLook"; - A_Teleport = "A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]"; + A_Teleport = "state A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]\nbool A_Teleport[(str teleportstate = \"Teleport\"[, str targettype = \"BossSpot\"[, str fogtype = \"TeleportFog\"[, int flags = 0[, float mindist = 0.0[, float maxdist = 0.0[, int pointer = AAPTR_DEFAULT]]]]]])]"; A_VileChase = "A_VileChase"; A_Wander = "A_Wander"; //Generic monster attacks A_CustomMissile = "A_CustomMissile(str missiletype[, float spawnheight = 0.0[, int spawnofs_horiz = 0[, int angle = 0[, int aimflags = 0[, int pitch = 0[, int target = AAPTR_TARGET]]]]]])"; A_CustomBulletAttack = "A_CustomBulletAttack(float horz_spread, float vert_spread, int numbullets, int damageperbullet[, str pufftype = \"BulletPuff\"[, float range = 0.0[, int flags = 0[, int target = AAPTR_TARGET]]]])"; - A_CustomRailgun = "A_CustomRailgun(int damage[, int offset[, color ringcolor[, color corecolor[, int flags = 0[, bool aim = false[, float maxdiff = 0.0[, str pufftype = \"\"[, float spread_xy = 0.0[, float spread_z = 0.0[, fixed range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass = \"\"[, float spawnofs_z = 0[, int spiraloffset = 270]]]]]]]]]]]]]]]])"; + A_CustomRailgun = "A_CustomRailgun(int damage[, int offset[, color ringcolor[, color corecolor[, int flags = 0[, bool aim = false[, float maxdiff = 0.0[, str pufftype = \"\"[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass = \"\"[, float spawnofs_z = 0[, int spiraloffset = 270]]]]]]]]]]]]]]]])"; A_CustomMeleeAttack = "A_CustomMeleeAttack[(int damage = 0[, str meleesound = \"\"[, str misssound = \"\"[, str damagetype = \"Melee\"[, bool bleed = true]]]])]"; A_CustomComboAttack = "A_CustomComboAttack(str missiletype, float spawnheight, int damage, str meleesound[, str damagetype = \"Melee\"[, bool bleed = true]])"; - A_MonsterRefire = "A_MonsterRefire(int chancecontinue, str abortstate) "; + A_MonsterRefire = "state A_MonsterRefire(int chancecontinue, str abortstate)"; A_BasicAttack = "A_BasicAttack(int meleedamage, str meleesound, str missiletype, float missileheight)"; A_BulletAttack = "A_BulletAttack"; A_MonsterRail = "A_MonsterRail"; A_Explode = "A_Explode[(int explosiondamage = 128[, int explosionradius = 128[, int flags = XF_HURTSOURCE[, bool alert = false[, int fulldamageradius = 0[, int nails = 0[, int naildamage = 10[, str pufftype = \"BulletPuff\"]]]]]]])]"; A_RadiusThrust = "A_RadiusThrust(int force, int distance[, int flags[, int fullthrustdistance]])"; A_Detonate = "A_Detonate"; - A_ThrowGrenade = "A_ThrowGrenade(str spawntype[, float spawnheight[, float throwspeed_horz[, float throwspeed_vert[, bool useammo]]]])"; + A_ThrowGrenade = "bool A_ThrowGrenade(str spawntype[, float spawnheight[, float throwspeed_horz[, float throwspeed_vert[, bool useammo]]]])"; A_WolfAttack = "A_WolfAttack[(int flags = 0[, str soundname = \"weapons/pistol\"[, float snipe = 1.0[, int damage = 64[, int blocksize = 128[, int pointblank = 0[, int longrange = 0[, float runspeed = 160.0[, str pufftype = \"BulletPuff\"]]]]]]]])]"; //Freeze death functions A_FreezeDeath = "A_FreezeDeath"; @@ -116,45 +159,45 @@ keywords A_CheckTerrain = "A_CheckTerrain"; A_SetBlend = "A_SetBlend(str blendcolor, float alpha, int duration[, str fadecolor])"; A_CheckPlayerDone = "A_CheckPlayerDone"; - A_PlayerSkinCheck = "A_PlayerSkinCheck(str state)"; + A_PlayerSkinCheck = "state A_PlayerSkinCheck(str state)"; A_SkullPop = "A_SkullPop[(str type = \"BloodySkull\")]"; A_Quake = "A_Quake(int intensity, int duration, int damageradius, int tremorradius[, str sound = \"world/quake\"])"; A_QuakeEx = "A_QuakeEx(int intensityX, int intensityY, int intensityZ, int duration, int damrad, int tremrad[, str sound = \"world/quake\"[, int flags = 0[, float mulwavex = 1.0[, float mulwavey = 1.0[, float mulwavez = 1.0]]]]])"; //Spawn functions A_TossGib = "A_TossGib"; A_SpawnDebris = "A_SpawnDebris(str type[, bool translation = false[, float horizontal_vel = 1.0[, float vertical_vel = 1.0]]])"; - A_SpawnItem = "A_SpawnItem(str type, int distance, float zpos, bool useammo, bool translation)"; - A_SpawnItemEx = "A_SpawnItemEx(str type[, float xoffset = 0.0[, float yoffset = 0.0[, float zoffset = 0.0[, float xvelocity = 0.0[, float yvelocity = 0.0[, float zvelocity = 0.0[, float angle = 0.0[, int flags = 0[, int skipchance = 0[, int tid = 0]]]]]]]]]])"; + A_SpawnItem = "bool A_SpawnItem(str type, int distance, float zpos, bool useammo, bool translation)"; + A_SpawnItemEx = "bool A_SpawnItemEx(str type[, float xoffset = 0.0[, float yoffset = 0.0[, float zoffset = 0.0[, float xvelocity = 0.0[, float yvelocity = 0.0[, float zvelocity = 0.0[, float angle = 0.0[, int flags = 0[, int skipchance = 0[, int tid = 0]]]]]]]]]])"; A_SpawnParticle = "A_SpawnParticle(color color[, int flags = 0[, int lifetime = 35[, int size = 1[, float angle = 0.0[, float xoff = 0.0[, float yoff = 0.0[, float zoff = 0.0[, float velx = 0.0[, float vely = 0.0[, float velz = 0.0[, float accelx = 0.0[, float accely = 0.0[, float accelz = 0.0[, float startalpha = 1.0[, float fadestep = -1.0]]]]]]]]]]]]]]])"; //State jumps - A_CheckBlock = "A_CheckBlock(str block[, int flags = 0[, int pointer = AAPTR_TARGET]])"; - A_CheckCeiling = "A_CheckCeiling(int offset OR str state)"; - A_CheckFloor = "A_CheckFloor(int offset OR str state)"; - A_CheckFlag = "A_CheckFlag(str flagname, state label[, int check_pointer = AAPTR_DEFAULT])"; - A_CheckLOF = "A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT]]]]]]]])"; - A_CheckProximity = "A_CheckProximity(str jump, str classname, float distance[, int count = 1[, int flags = 0[, int pointer = AAPTR_DEFAULT]]])"; - A_CheckRange = "A_CheckRange(float distance, int offset OR str state[, bool 2d_check = false])"; - A_CheckSight = "A_CheckSight(int offset OR str state)"; - A_CheckSightOrRange = "A_CheckSightOrRange(float distance, int offset OR str state[, bool 2d_check = false])"; - A_CheckSpecies = "A_CheckSpecies(str jump[, str species=\"None\"[, int pointer = AAPTR_DEFAULT]]) "; - A_Jump = "A_Jump(int chance, int offset OR str state, ...)"; - A_JumpIf = "A_JumpIf(expression, int offset OR str state)"; - A_JumpIfArmorType = "A_JumpIfArmorType(str armortype, str state[, int minimum = 1])"; - A_JumpIfCloser = "A_JumpIfCloser(int distance, int offset OR str state[, bool noz = false])"; - A_JumpIfHealthLower = "A_JumpIfHealthLower(int health, int offset OR str state[, int pointer = AAPTR_DEFAULT])"; - A_JumpIfHigherOrLower = "A_JumpIfHigherOrLower(str high, str low[, float offsethigh = 0.0[, float offsetlow = 0.0[, bool includeHeight = true[, int pointer = AAPTR_TARGET]]]])"; - A_JumpIfInventory = "A_JumpIfInventory(str inventorytype, int amount, int offset OR str state[, int owner = AAPTR_DEFAULT])"; - A_JumpIfInTargetInventory = "A_JumpIfInTargetInventory(str item, int count, int offset OR str state[, int forward = AAPTR_DEFAULT])"; - A_JumpIfInTargetLOS = "A_JumpIfInTargetLOS(int offset OR str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags."; - A_JumpIfMasterCloser = "A_JumpIfMasterCloser(int distance, int offset OR str state[, bool noz = false])"; - A_JumpIfNoAmmo = "A_JumpIfNoAmmo(int offset OR str state)"; - A_JumpIfTargetInLOS = "A_JumpIfTargetInLOS(int offset OR str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags."; - A_JumpIfTargetInsideMeleeRange = "A_JumpIfTargetInsideMeleeRange(int offset OR str state)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is within melee range of the caller."; - A_JumpIfTargetOutsideMeleeRange = "A_JumpIfTargetOutsideMeleeRange(int offset OR str state)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is beyond melee range of the caller."; - A_JumpIfTracerCloser = "A_JumpIfTracerCloser(int distance, int offset OR str state[, bool noz = false])"; + A_CheckBlock = "state A_CheckBlock(str block[, int flags = 0[, int pointer = AAPTR_TARGET]])"; + A_CheckCeiling = "state A_CheckCeiling(str state)\nstate A_CheckCeiling(int offset)"; + A_CheckFloor = "state A_CheckFloor(str state)\nstate A_CheckFloor(int offset)"; + A_CheckFlag = "state A_CheckFlag(str flagname, state label[, int check_pointer = AAPTR_DEFAULT])"; + A_CheckLOF = "state A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT]]]]]]]])"; + A_CheckProximity = "state A_CheckProximity(str jump, str classname, float distance[, int count = 1[, int flags = 0[, int pointer = AAPTR_DEFAULT]]])"; + A_CheckRange = "state A_CheckRange(float distance, str state[, bool 2d_check = false])\nstate A_CheckRange(float distance, int offset[, bool 2d_check = false])"; + A_CheckSight = "state A_CheckSight(str state)\nstate A_CheckSight(int offsete)"; + A_CheckSightOrRange = "state A_CheckSightOrRange(float distance, str state[, bool 2d_check = false])\nstate A_CheckSightOrRange(float distance, int offset[, bool 2d_check = false])"; + A_CheckSpecies = "state A_CheckSpecies(str jump[, str species=\"None\"[, int pointer = AAPTR_DEFAULT]]) "; + A_Jump = "state A_Jump(int chance, str state, ...)\nstate A_Jump(int chance, int offset, ...)"; + A_JumpIf = "state A_JumpIf(expression, str state)\nstate A_JumpIf(expression, int offset)"; + A_JumpIfArmorType = "state A_JumpIfArmorType(str armortype, str state[, int minimum = 1])"; + A_JumpIfCloser = "state A_JumpIfCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfCloser(int distance, int offset[, bool noz = false])"; + A_JumpIfHealthLower = "state A_JumpIfHealthLower(int health, str state[, int pointer = AAPTR_DEFAULT])\nstate A_JumpIfHealthLower(int health, int offset[, int pointer = AAPTR_DEFAULT])"; + A_JumpIfHigherOrLower = "state A_JumpIfHigherOrLower(str high, str low[, float offsethigh = 0.0[, float offsetlow = 0.0[, bool includeheight = true[, int pointer = AAPTR_TARGET]]]])"; + A_JumpIfInventory = "state A_JumpIfInventory(str inventorytype, int amount, str state[, int owner = AAPTR_DEFAULT])\nstate A_JumpIfInventory(str inventorytype, int amount, int offset[, int owner = AAPTR_DEFAULT])"; + A_JumpIfInTargetInventory = "state A_JumpIfInTargetInventory(str item, int count, str state[, int forward = AAPTR_DEFAULT])\nstate A_JumpIfInTargetInventory(str item, int count, int offset[, int forward = AAPTR_DEFAULT])"; + A_JumpIfInTargetLOS = "state A_JumpIfInTargetLOS(str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nstate A_JumpIfInTargetLOS(int offset[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags."; + A_JumpIfMasterCloser = "state A_JumpIfMasterCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfMasterCloser(int distance, int offset[, bool noz = false])"; + A_JumpIfNoAmmo = "state A_JumpIfNoAmmo(str state)\nstate A_JumpIfNoAmmo(int offset)"; + A_JumpIfTargetInLOS = "state A_JumpIfTargetInLOS(str state[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nstate A_JumpIfTargetInLOS(int offset[, float fov = 0.0[, int flags = 0[, float dist_max = 0.0[, float dist_close = 0.0]]]])\nflags: JLOSF flags."; + A_JumpIfTargetInsideMeleeRange = "state A_JumpIfTargetInsideMeleeRange(str state)\nstate A_JumpIfTargetInsideMeleeRange(int offset)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is within melee range of the caller."; + A_JumpIfTargetOutsideMeleeRange = "state A_JumpIfTargetOutsideMeleeRange(str state)\nstate A_JumpIfTargetOutsideMeleeRange(int offset)\nJumps the number of frames (offset) forward, or to the specified state\nwhen the target of the calling actor is beyond melee range of the caller."; + A_JumpIfTracerCloser = "state A_JumpIfTracerCloser(int distance, str state[, bool noz = false])\nstate A_JumpIfTracerCloser(int distance, int offset[, bool noz = false])"; //Status changes A_ActiveAndUnblock = "A_ActiveAndUnblock"; - A_CallSpecial = "A_CallSpecial(int special[, int arg1 = 0[, int arg2 = 0[, int arg3 = 0[, int arg4 = 0[, int arg5 = 0]]]]])"; + A_CallSpecial = "bool A_CallSpecial(int special[, int arg1 = 0[, int arg2 = 0[, int arg3 = 0[, int arg4 = 0[, int arg5 = 0]]]]])"; A_ChangeFlag = "A_ChangeFlag(str flagname, bool value)"; A_ChangeVelocity = "A_ChangeVelocity[(float x = 0.0[, float y = 0.0[, float z = 0.0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]])]\nflags: CVF flags."; A_ClearShadow = "A_ClearShadow"; @@ -163,7 +206,7 @@ keywords A_FadeIn = "A_FadeIn[(float increase_amount = 0.1[, int flags = 0])]\nflags: FTF flags."; A_FadeOut = "A_FadeOut[(float reduce_amount = 0.1[, int flags = FTF_REMOVE])]\nflags: FTF flags."; A_FadeTo = "A_FadeTo(float target[, float amount = 0.1[, int flags = 0]])\nflags: FTF flags."; - A_FaceMovementDirection = "A_FaceMovementDirection([float offset = 0[, float anglelimit = 0[, float pitchlimit = 0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]]])"; + A_FaceMovementDirection = "state A_FaceMovementDirection[(float offset = 0[, float anglelimit = 0[, float pitchlimit = 0[, int flags = 0[, int pointer = AAPTR_DEFAULT]]]])]"; A_Fall = "A_Fall"; A_Gravity = "A_Gravity"; A_HideThing = "A_HideThing"; @@ -178,6 +221,7 @@ keywords A_ScreamAndUnblock = "A_ScreamAndUnblock"; A_SetAngle = "A_SetAngle(float angle[, int flags = 0[, int pointer = AAPTR_DEFAULT]])\nangle: the actor's new angle, in degrees.\nflags: SPF flags."; A_SetArg = "A_SetArg(int position, int value)"; + A_SetChaseThreshold = "A_SetChaseThreshold(int threshold[, bool setdefaultthreshhold = false[, int pointer = AAPTR_DEFAULT]])"; A_SetDamageType = "A_SetDamageType(str damagetype)"; A_SetFloat = "A_SetFloat"; A_SetFloatSpeed = "A_SetFloatSpeed(float speed[, int pointer = AAPTR_DEFAULT])"; @@ -220,23 +264,23 @@ keywords A_FaceTracer = "A_FaceTracer[(float angle = 0.0[, float pitch = 270.0])]\nA_FaceTracer([float max_turn = 0.0[, float max_pitch = 270.0[, float ang_offset = 0.0[, float pitch_offset = 0.0[, int flags = 0[, float z_add = 0.0]]]]]])"; A_Fire = "A_Fire[(float height = 0.0)]"; A_Weave = "A_Weave(int horzspeed, int vertspeed, float horzdist, float vertdist)"; - A_Warp = "A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nflags: WARPF flags."; + A_Warp = "state A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nbool A_Warp(int ptr_destination[, float x-offset = 0[, float y-offset = 0[, float z-offset = 0[, float angle = 0[, int flags = 0[, str success_state = \"\"[, float heightoffset = 0[, float radiusoffset = 0[, float pitch = 0]]]]]]]]])\nflags: WARPF flags."; A_Countdown = "A_Countdown"; A_CountdownArg = "A_CountdownArg(int arg[, str targetstate])"; A_Stop = "A_Stop"; //Inventory functions - A_GiveInventory = "A_GiveInventory(str type[, int count = 0[, int giveto = AAPTR_DEFAULT]])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.\ngiveto: the actor to give the item to"; - A_GiveToChildren = "A_GiveToChildren(str type[, int count])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1."; - A_GiveToSiblings = "A_GiveToSiblings(str type[, int count])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1."; - A_GiveToTarget = "A_GiveToTarget(str type, int count[, int giveto])"; - A_TakeInventory = "A_TakeInventory(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])"; - A_TakeFromChildren = "A_TakeFromChildren(str type[, int count])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0."; - A_TakeFromSiblings = "A_TakeFromSiblings(str type[, int count])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0."; - A_TakeFromTarget = "A_TakeFromTarget(str type, int count[, int flags[, int takefrom]])"; + A_GiveInventory = "bool A_GiveInventory(str type[, int count = 0[, int giveto = AAPTR_DEFAULT]])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1.\ngiveto: the actor to give the item to"; + A_GiveToChildren = "int A_GiveToChildren(str type[, int count = 0])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1."; + A_GiveToSiblings = "int A_GiveToSiblings(str type[, int count = 0])\ntype: the item to give. This should be a valid inventory item.\ncount: the number of samples of this item to give. Default is 0, which is interpreted as 1."; + A_GiveToTarget = "bool A_GiveToTarget(str type, int count[, int giveto = AAPTR_DEFAULT])"; + A_TakeInventory = "bool A_TakeInventory(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])"; + A_TakeFromChildren = "int A_TakeFromChildren(str type[, int count = 0])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0."; + A_TakeFromSiblings = "int A_TakeFromSiblings(str type[, int count = 0])\ntype: the item to take. This should be a valid inventory item.\ncount: the number of samples of this item to take.\nIf this is 0, the item is cleared from the inventory unless it has the\nINVENTORY.KEEPDEPLETED flag set, and in which case, its amount is merely reduced to 0.\nDefault is 0."; + A_TakeFromTarget = "bool A_TakeFromTarget(str type, int count[, int flags[, int takefrom = AAPTR_DEFAULT]])"; 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[, str filter = \"None\"[, str species = \"None\"[, fixed mindist = 0]]]])\nflags: RGF flags."; + A_SelectWeapon = "bool A_SelectWeapon(str type)"; + A_RadiusGive = "int A_RadiusGive(str item, float distance, int flags[, int amount = 0[, str filter = \"None\"[, str species = \"None\"[, float mindist = 0]]]])\nflags: RGF flags."; //Weapon functions A_WeaponReady = "A_WeaponReady[(int flags = 0)]\nflags: WRF flags."; A_Lower = "A_Lower"; @@ -245,7 +289,7 @@ keywords A_ClearReFire = "A_ClearReFire"; A_GunFlash = "A_GunFlash[(str state = \"Flash\"[, int flags = 0])]\nflags: GFF flags."; A_CheckReload = "A_CheckReload"; - A_CheckForReload = "A_CheckForReload(int counter, str state[, bool dontincrement = false])"; + A_CheckForReload = "state A_CheckForReload(int counter, str state[, bool dontincrement = false])"; A_ResetReloadCounter = "A_ResetReloadCounter"; A_Light = "A_Light(int intensity)"; A_Light0 = "A_Light0"; @@ -260,8 +304,8 @@ keywords A_Saw = "A_Saw[(str fullsound = \"weapons/sawfull\"[, str hitsound = \"weapons/sawhit\"[, int damage = 0[, str pufftype = \"BulletPuff\"[, int flags = 0[, float range = 65.0[, float spread_xy = 2.8125[, float spread_z = 0.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"]]]]]]]]]])]"; A_CustomPunch = "A_CustomPunch(int damage[, bool norandom = false[, int flags = 0[, str pufftype = \"BulletPuff\"[, float range = 64.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"[, str meleesound[, str misssound]]]]]]]]])"; A_FireBullets = "A_FireBullets(int spread_horz, int spread_vert, int numbullets, int damage[, str pufftype = \"\"[, int flags = FBF_USEAMMO[, float range = 0.0]]])"; - A_FireCustomMissile = "A_FireCustomMissile(str missiletype[, int angle = 0[, bool useammo = false[, int spawnofs_horz = 0[, int spawnheight = 0[, bool aim = false OR int flags = 0[, angle pitch = 0]]]]]])"; - A_RailAttack = "A_RailAttack(int damage[, int spawnofs_horz[, bool useammo[, str ringcolor[, str corecolor[, int flags[, int maxdiff[, str pufftype[, float spread_xy = 0[, float spread_z = 0.0[, fixed range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass[, float spawnofs_z = 0.0[, int spiraloffset = 270]]]]]]]]]]]]]]]])"; + A_FireCustomMissile = "A_FireCustomMissile(str missiletype[, int angle = 0[, bool useammo = false[, int spawnofs_horz = 0[, int spawnheight = 0[, int flags = 0[, angle pitch = 0]]]]]])"; + A_RailAttack = "A_RailAttack(int damage[, int spawnofs_horz[, bool useammo[, str ringcolor[, str corecolor[, int flags[, int maxdiff[, str pufftype[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192.0[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass[, float spawnofs_z = 0.0[, int spiraloffset = 270]]]]]]]]]]]]]]]])"; A_FireAssaultGun = "A_FireAssaultGun"; A_FireBFG = "A_FireBFG"; A_FireOldBFG = "A_FireOldBFG"; @@ -324,7 +368,7 @@ keywords A_BarrelDestroy = "A_BarrelDestroy"; //Miscellaneous functions not listed in the "Action functions" wiki article A_Bang4Cloud = "A_Bang4Cloud"; - A_Blast = "A_Blast[(int flags = 0[, int strength = 255[, int radius = 255[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, sound blastsound = \"BlastRadius\"]]]]])]"; + A_Blast = "A_Blast[(int flags = 0[, int strength = 255[, int radius = 255[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, str blastsound = \"BlastRadius\"]]]]])]\nA_Blast[(int flags = 0[, int strength = 255[, float radius = 255.0[, float speed = 20.0[, str blasteffect = \"BlastEffect\"[, str blastsound = \"BlastRadius\"]]]]])]"; A_BishopMissileWeave = "A_BishopMissileWeave"; A_DropWeaponPieces = "A_DropWeaponPieces(str actorclass1, str actorclass2, str actorclass3)"; A_Feathers = "A_Feathers"; @@ -341,28 +385,48 @@ keywords abs = "abs(x)\nReturns the absolute value of x."; sin = "sin(x)\nTrigonometry function, x must be in degrees."; cos = "cos(x)\nTrigonometry function, x must be in degrees."; + tan = "tan(x)\nTrigonometry function, x must be in degrees."; + asin = "asin(x)\nTrigonometry function, returns an angle in degrees."; + acos = "acos(x)\nTrigonometry function, returns an angle in degrees."; + atan = "atan(x)\nTrigonometry function, returns an angle in degrees."; + sinh = "sinh(x)\nTrigonometry function, x must be in radians."; + cosh = "cosh(x)\nTrigonometry function, x must be in radians."; + tanh = "tanh(x)\nTrigonometry function, x must be in radians."; + exp = "exp(x)\nReturns the base-e exponential function of x, which is e raised to the power x."; + log = "log(x)\nReturns the natural logarithm of x - the opposite of exp."; + log10 = "log10(x)\nReturns the common (base-10) logarithm of x."; + ceil = "ceil(x)\nRounds the number upward to the next closest integer."; + floor = "floor(x)\nRounds the number downward to the next closest integer."; sqrt = "sqrt(x)\nReturns the square root of x."; - random = "random[identifier](min, max)\nReturns a random integer value between min and max."; - random2 = "random2[identifier](mask)\nReturns a random integer value between -mask and +mask."; - frandom = "frandom[identifier](min, max)\nReturns a random floating point value between min and max."; - randompick = "randompick[identifier](int, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters."; - frandompick = "frandompick[identifier](int, ...)\nSimilar to randompick but for float-point values."; -//State keywords - //Bright = "Bright"; - CanRaise = "CanRaise"; - Fast = "Fast"; + min = "min(x1, ...)\nGets the smallest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats."; + max = "max(x1, ...)\nGets the largest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats."; + clamp = "clamp(src, min, max)\nReturns src within the range of min and max inclusively. All parameters can be ints or floats."; +//Randum number functions + random = "int random[identifier](min, max)\nReturns a random integer value between min and max."; + random2 = "int random2[identifier](mask)\nReturns a random integer value between -mask and +mask."; + frandom = "float frandom[identifier](min, max)\nReturns a random floating point value between min and max."; + randompick = "int randompick[identifier](int, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters."; + frandompick = "float frandompick[identifier](float, ...)\nPicks a number from the numbers placed in it.\nThis can take an unlimited amount of parameters."; +//State functions Light = "Light(str lightname)"; - NoDelay = "NoDelay"; Offset = "Offset(int x, int y)"; - Slow = "Slow"; //Special functions CheckClass = "bool CheckClass(str classname[, int ptr_select = AAPTR_DEFAULT[, bool match_superclass = false]])"; - IsPointerEqual = "bool IsPointerEqual(int ptr_select1, int ptr_select2)"; + IsPointerEqual = "bool IsPointerEqual(int ptr1, int ptr2)"; + CountInv = "int CountInv(str itemclassname[, int ptr_select = AAPTR_DEFAULT])"; + GetDistance = "float GetDistance(bool checkz[, int ptr_select = AAPTR_TARGET])"; + GetSpawnHealth = "int GetSpawnHealth()"; + GetGibHealth = "int GetGibHealth()"; } properties { Actor; + enum; + const; + var; + int; + float; //WFDS if; else; @@ -373,7 +437,13 @@ properties Wait; Fail; goto; -//states: +//State keywords + Bright; + CanRaise; + Fast; + Slow; + NoDelay; +//States States; Spawn:; Idle:; @@ -452,6 +522,8 @@ properties Activation; TeleFogSourceType; TeleFogDestType; + Threshold; + DefThreshold; //Collision and 'Physics' Radius; Height; @@ -1008,6 +1080,7 @@ constants CBF_SETTRACER; CBF_SETONPTR; CBF_DROPOFF; + CBF_NOACTORS; CHF_DONTMOVE; CHF_FASTCHASE; CHF_NIGHTMAREFAST; diff --git a/Documents/cmdargs.txt b/Documents/cmdargs.txt index daf8db53..6e490f72 100644 --- a/Documents/cmdargs.txt +++ b/Documents/cmdargs.txt @@ -1,55 +1,63 @@ -Doom Builder 2 command-line arguments +GZDoom Builder command-line arguments ========================================================================================== Usage: - builder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nopreferences] - [-strictpatches] [-resource wad|dir|pk3 [roottextures] [rootflats] - [strictpatches] [notest] resourcename] + GZBuilder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nopreferences] + [-strictpatches] [-portable] [-resource wad|dir|pk3 [roottextures] + [rootflats] [strictpatches] [notest] resourcename] ========================================================================================== Parameters: -- wadfile +wadfile This is a .WAD file to load immediately after Doom Builder has started up. Unless -map and -cfg are used, this will show the map-options dialog. -- map -Where 'mapname' is the name of the map (map header lump name) such as MAP01 or E1M1. When +-map "mapname" +Where "mapname" is the name of the map (map header lump name) such as MAP01 or E1M1. When specified, this will indicate the map to load from the specified wad file. Use in combination with -cfg to provide the required information to skip the map-options dialog. -- cfg -Where 'configname' is a game configuration filename, for example, "ZDoom_DoomHexen.cfg". +-cfg "configname" +-config "configname" +Where "configname" is a game configuration filename, for example, "ZDoom_DoomHexen.cfg". Do NOT include the path, all game configurations must be in the Configurations subfolder. When used in combination with -map this will provide the required information to load a map directly and skip the map-options dialog. -- delaywindow +-delaywindow This delays showing the main interface window until the automatic map loading from command line parameters is completed, and the program is not terminating yet. This is usefull for plugins that can be used to perform batch processes where the showing of the main interface window is not desired. If a plugin completes it's actions on map load and terminates the application immediately, the main window will not be shown at all. -- nosettings +-nosettings When this parameter is specified, Doom Builder will not load your preferences or game configuration settings and will use the default settings instead. You will not lose your original settings, but when this parameter is specified your settings will not be saved. -- strictpatches +-strictpatches Specify this parameter to enforce strictly loading texture patches from between P_START and P_END marker lumps only. This can solve lump name conflicts, but old WAD files do not always adhere to this rule. -- resource +-portable +The editor will be launched in portable mode. It will use the "GZBuilder.cfg" located in +the program directory instead of the one located in the +"%LocalAppData%\Doom Builder\GZBuilder.cfg" to load and save program settings. Log and +crash report files will be also created in the program directory. + +-resource <resource type> [flags] "path\to\resource" When -wadfile is specified, the -resource option can be used to add additional resources that must be loaded along with the wad file. Note that these are added to the resources which are automatically loaded due to the selection of a game configuration. You can repeat this option for any number of resources you wish to add. As always, the last -specified resource will override any data in earlier specified resource. This parameter -has the following arguments: +specified resource will override any data in earlier specified resource. + +This parameter has the following arguments: wad|dir|pk3 Either 'wad', 'dir' or 'pk3' must be specified to indicate how this resource must be loaded. This is the same as selecting the tabs in @@ -77,16 +85,18 @@ Examples: This loads the file "Ubermegawad.wad" after Doom Builder is initialized and shows the map-options dialog: - builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" + GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" Same as the example above, but now without showing the map-options dialog and instead immediately loads map MAP23 with the game configuration for Doom 2: - builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom2.cfg" + GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom_Doom2Doom.cfg" -Same as the example above, but with added wad file resource and PK3 file resource: +Same as the example above, but using one of GZDoom game configurations with added wad +file resource and PK3 file resources: - builder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom2.cfg" - -resource wad strictpatches "C:\Games\Doom\gothtextures.wad" - -resource pk3 "C:\Games\Doom\hardmonsters.pk3" + GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "GZDoom_DoomUDMF.cfg" + -resource pk3 notest "C:\GZDoom\gzdoom.pk3" + -resource wad strictpatches "C:\Games\Doom\gothtextures.wad" + -resource pk3 "C:\Games\Doom\hardmonsters.pk3" diff --git a/Help/commandlineparams.html b/Help/commandlineparams.html index e42a4073..8e70ff7c 100644 --- a/Help/commandlineparams.html +++ b/Help/commandlineparams.html @@ -7,49 +7,74 @@ </head> <body> <object type="application/x-oleobject" classid="clsid:1e2a7bd0-dab9-11d0-b93a-00c04fc99f9e"> - <param name="keyword" value="command line"> - <param name="keyword" value="arguments"> + <param name="keyword" value="command line"> + <param name="keyword" value="arguments"> </object> <div id="gz_title"> - <h1>Command Line Parameters</h1> + <h1>Command Line Parameters</h1> </div> <div id="contents"> - <p> All command line parameters are case-insensitive.<br /> - <br /> - <b class="fat">-portable</b> - <span class="red">GZDB only.</span><br /> - The editor will be launched in portable mode. It will use the "GZBuilder.cfg" located in the program directory instead of the one located in the "%LocalAppData%\Doom Builder\GZBuilder.cfg" to load and save program settings. Log and crash report files will be also created in the program directory.<br /> - <br /> - <b class="fat">-nosettings</b><br /> - The editor doesn't load or save program settings.<br /> - <br /> - <b class="fat">-delaywindow</b><br /> - Delays showing of the main window.<br /> - <br /> - <b class="fat">-map "path\to\mapfile.wad"</b><br /> - The editor will automatically load the specified map.<br /> - <h2>The following parameters are used only in conjunction with the "-map" parameter</h2> - They replicate the settings, which can be set in the <a href="w_openmapoptions.html">Open Map Window</a>.<br /> - <br /> - <b class="fat">-strictpatches</b><br /> - Enables strict patches rules.<br /> - <br /> - <b class="fat">-cfg "path\to\game configuration.cfg"</b><br /> - <b class="fat">-config "path\to\game configuration.cfg"</b><br /> - The editor will use the specified game configuration file when loading the map.<br /> - <br /> - <b class="fat">-resource <resource type> [flags] "path\to\resource"</b><br /> - Adds a map resource.<br /> - <strong>Resource type</strong> (required): "wad", "dir" or "pk3".<br /> - <strong>Flags</strong> (optional): - <ul> - <li><strong>ROOTTEXTURES</strong> - load images in the root directory of the resource as textures.</li> - <li><strong>ROOTFLATS</strong> - load images in the root directory of the resource as flats.</li> - <li><strong>STRICTPATCHES</strong> - use strict rules for patches.</li> - <li><strong>NOTEST</strong> - exclude this resource from testing parameters.</li> - </ul> - <strong>Examples:</strong> - <pre> - -resource pk3 notest "c:\GZDoom\gzdoom.pk3" - -resource WAD "c:\Doom\DOOM.WAD"</pre> + <h2>Usage:</h2> + All command line parameters are case-insensitive.<br /> + <br /> + <b class="fat">GZBuilder.exe [wadfile] [-map mapname] [-cfg configname] [-delaywindow] [-nosettings] + [-strictpatches] [-portable] [-resource wad|dir|pk3 [roottextures] [rootflats] + [strictpatches] [notest] resourcename]</b> + <h2>Parameters:</h2> + <br /> + <b class="fat">wadfile</b><br /> + This is a .WAD file to load immediately after GZDoom Builder has started up. Unless <strong>-map</strong> and <strong>-cfg</strong> are used, this will show the map-options dialog.<br /> + <p><b class="fat">-map "mapname"</b><br /> + Where "mapname" is the name of the map (map header lump name) such as <strong>MAP01</strong> or <strong>E1M1</strong>.<br /> + When specified, this will indicate the map to load from the specified wad file.<br /> + Use in combination with <strong>-cfg</strong> to provide the required information to skip the map-options dialog. + <p><b class="fat">-delaywindow</b><br /> + This delays showing the main interface window until the automatic map loading from command line parameters is completed, and the program is not terminating yet.<br />This is usefull for plugins that can be used to perform batch processes where the showing of the main interface window is not desired.<br />If a plugin completes it's actions on map load and terminates the application immediately, the main window will not be shown at all. + <p> + <b class="fat">-nosettings</b><br /> + When this parameter is specified, GZDoom Builder will not load your preferences or game configuration settings and will use the default settings instead.<br />You will not lose your original settings, but when this parameter is specified your settings will not be saved.<br /> + <br /> + <b class="fat">-portable</b> - <span class="red">GZDB only.</span><br /> + The editor will be launched in portable mode. It will use the "GZBuilder.cfg" located in the program directory instead of the one located in the "%LocalAppData%\Doom Builder\GZBuilder.cfg" to load and save program settings. Log and crash report files will be also created in the program directory.<br /> + <h2>The following parameters are used only when both "wadfile" and "-map" parameters are present</h2> + They replicate the settings, which can be set in the <a href="w_openmapoptions.html">Open Map Window</a>.<br /> + <br /> + <b class="fat">-strictpatches</b><br /> + Specify this parameter to enforce strictly loading texture patches from between P_START + and P_END marker lumps only. This can solve lump name conflicts, but old WAD files do not + always adhere to this rule.<br /> + <br /> + <b class="fat">-cfg "game_configuration.cfg"</b><br /> + <b class="fat">-config "game_configuration.cfg"</b><br /> + The editor will use the specified game configuration file when loading the map.<br /> + Do not include the path, all game configurations must be in the "Configurations" subfolder.<br /> + <br /> + <b class="fat">-resource <resource type> [flags] "path\to\resource"</b><br /> + Adds a map resource. Note that these are added to the resources, which are automatically loaded according to selected game configuration.<br /> + <strong>Resource type</strong> (required): "wad", "dir" or "pk3".<br /> + <strong>Flags</strong> (optional): + <ul> + <li><strong>ROOTTEXTURES</strong> - load images in the root directory of the resource as textures (directory/pk3 resources only).</li> + <li><strong>ROOTFLATS</strong> - load images in the root directory of the resource as flats (directory/pk3 resources only).</li> + <li><strong>STRICTPATCHES</strong> - use strict rules for patches (wad resources only).</li> + <li><strong>NOTEST</strong> - exclude this resource from testing parameters.</li> + </ul> + <h2>Examples:</h2> + This loads the file "Ubermegawad.wad" after GZDoom Builder is initialized and shows the + map-options dialog: + <pre> +GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" +</pre> + Same as the example above, but now without showing the map-options dialog and instead immediately loading map MAP23 with the Doom 2 game configuration: + <pre> +GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "Doom_Doom2Doom.cfg" +</pre> + Same as the example above, but using one of GZDoom game configurations with added wad file resource and PK3 file resources: + <pre> +GZBuilder.exe "C:\Games\Doom\My Maps\Ubermegawad.wad" -map MAP23 -cfg "GZDoom_DoomUDMF.cfg" + -resource pk3 notest "C:\GZDoom\gzdoom.pk3" + -resource wad strictpatches "C:\Games\Doom\gothtextures.wad" + -resource pk3 "C:\Games\Doom\hardmonsters.pk3" +</pre> </div> </body> diff --git a/Help/gc_decoratekeys.html b/Help/gc_decoratekeys.html index 3cc1d5fe..fdb1dc0d 100644 --- a/Help/gc_decoratekeys.html +++ b/Help/gc_decoratekeys.html @@ -31,6 +31,9 @@ <strong>//$Title <title></strong><br /> Specifies which name to give to the actor. By default, a custom actor not identified in a configuration file will use the Tag property, and if not present, will default to the class name.<br /> <br /> + <strong>//$IgnoreRenderstyle</strong> - <span class="red">GZDB only</span>.<br /> + "RenderStyle" DECORATE property will be ignored by the editor. Helpful when you want to see the sprite of an invisible actor in Visual mode.<br /> + <br /> <strong><a name="argtitle" id="argtitle"></a>//$ArgN <name></strong> - <span class="red">GZDB only</span>.<br /> Allows to override default argument names for this actor.<br /> <br /> @@ -87,6 +90,7 @@ Actor ChexShield : ResistanceRune replaces ResistanceRune 5104 { //$Category "Pickups/Chex Powerups" //$Sprite ARMXA0 + //$IgnoreRenderstyle //$Title "Chex Shield" //$Color 12 //$NotAngled @@ -115,6 +119,7 @@ Actor ChexShield : ResistanceRune replaces ResistanceRune 5104 Height 44 Radius 26 + RenderStyle None Inventory.PickupMessage "Picked up the energized Chex armor!" States diff --git a/Help/gzdb/compilingtheeditor.html b/Help/gzdb/compilingtheeditor.html index 03ef2e33..a515ea54 100644 --- a/Help/gzdb/compilingtheeditor.html +++ b/Help/gzdb/compilingtheeditor.html @@ -28,21 +28,34 @@ <li>7-zip archiver (<a href="www.7-zip.org">www.7-zip.org</a>).</li> <li>Inno Setup 5 or newer (<a href="http://www.jrsoftware.org/isinfo.php">http://www.jrsoftware.org/isinfo.php</a>).</li> <li>Microsoft HTML Help compiler (<a href="http://www.microsoft.com/en-us/download/details.aspx?id=21138">http://www.microsoft.com/en-us/download/details.aspx?id=21138</a>).</li> - <li>SlimDX Developer SDK. You can download it for free from <a href="http://slimdx.org/download.php">http://slimdx.org/download.php</a>.</li> + <li>SlimDX Developer SDK (<a href="http://slimdx.org/download.php">http://slimdx.org/download.php</a>).</li> + <li>DirectX SDK (<a href="https://www.microsoft.com/en-us/download/details.aspx?id=6812">https://www.microsoft.com/en-us/download/details.aspx?id=6812</a>).</li> </ul> <h2>Obtaining the source:</h2> - The Doom Builder 2 source code is hosted on SourceForge and is available through SVN at the following location:<pre>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</pre> - If you don't want to use a SVN client, head to - <a href="https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/">https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/</a> - and press "Download Snapshot" button. + The GZDoom Builder source code is hosted on SourceForge and is available through SVN at the following location: + <pre>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</pre> + If you don't want to use a SVN client, head to <a href="https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/">https://sourceforge.net/p/doombuilder/code/HEAD/tree/branches/GZDoomBuilder/</a> and press "Download Snapshot" button. + <h2>Quick start guide:</h2> + This guide assumes you are using <strong>Visual Studio 2008</strong> / <strong>Visual C# 2008 Express Edition</strong> and <strong>Tortiose SVN</strong>. + <ol> + <li>Create an empty folder, right click on it and choose "<strong>SVN Checkout...</strong>" from the context menu.</li> + <li>Enter "<strong>https://svn.code.sf.net/p/doombuilder/code/branches/GZDoomBuilder</strong>" in the "<strong>URL of repository</strong>" field and click OK.</li> + <li> Open "<strong>Builder.sln</strong>" in the Visual Studio and make sure it compiles and runs (click the green "<strong>Play</strong>" button, or press <strong>F5</strong>). + <ul> + <li>If the Visual Studio complains about missing <strong>SlimDX</strong> reference in the Builder project, you'll need to re-add it manually. To do so, delete SlimDX from the References in the Solution Explorer, right click on the Builder project and choose "<strong>Add reference</strong>". On the .NET tab, choose SlimDX (.net 2.0, x86 version).</li> + <li>You can ignore the warning about missing <strong>JetBrains.Profiler.Core.Api</strong> reference. Everything should build fine, unless you choose a profiler-enabled build target (or you can use dotTrace Performance, if you have access to it).</li> + </ul> + </li> + <li>If you've made some code changes and want to submit them to the main GZDB repository, you can make a diff patch (right-click on the GZDB source folder and choose "<strong>TortioseSVN -> Create patch...</strong>") and post it at the official GZDB thread at ZDoom.org (<a href="http://forum.zdoom.org/viewtopic.php?f=3&t=32392&start=999999">http://forum.zdoom.org/viewtopic.php?f=3&t=32392&start=999999</a>).</li> + </ol> <h2>Batch files:</h2> GZDB source comes with several batch files, which can be used to automatically compile and package the editor. Before launching a batch file for the first time, make sure to open it and check that variables holding software paths point to the right directories. These variables are always located near the top of the file, after the info block. <ul> - <li><strong>Clean Rebuild.bat</strong> - removes project cache files, then compiles it in Release mode.<br />Requires Visual C# Express Edition / Visual Studio.</li><br /> + <li><strong>Clean Rebuild.bat</strong> - removes project cache files, then compiles it in Release mode.<br />Requires Visual C# Express Edition / Visual Studio.</li><br /> <li><strong>CompileHelp.bat</strong> - compiles "Build\Refmanual.chm". Help source files are located in the "Help" directory.<br />Requires Microsoft HTML Help compiler.</li><br /> <li><strong>MakeRelease.bat</strong> - removes project cache files, sets project version number to match the latest SVN revision, compiles the project in Release mode, generates "Build\Changelog.txt", compiles "Build\Refmanual.chm", creates an installer and places it in the "Release" folder.<br />Requires Subversion command-line client, Visual C# Express Edition / Visual Studio, Microsoft HTML Help compiler and Inno Setup 5.</li><br /> - <li><strong>MakeSVNRelease.bat</strong> - removes project cache files, sets project version number to match the latest SVN revision, compiles the project in Release mode, generates "Build\Changelog.txt", compiles "Build\Refmanual.chm", packs the build into 7-zip archive and places it in the "SVN_Build" folder.<br />Requires Subversion command-line client, Visual C# Express Edition / Visual Studio, Microsoft HTML Help compiler and 7-zip archiver.</li> + <li><strong>MakeSVNRelease.bat</strong> - removes project cache files, sets project version number to match the latest SVN revision, compiles the project in Release mode, generates "Build\Changelog.txt", compiles "Build\Refmanual.chm", packs the build into 7-zip archive and places it in the "SVN_Build" folder.<br />Requires Subversion command-line client, Visual C# Express Edition / Visual Studio, Microsoft HTML Help compiler and 7-zip archiver.</li> </ul> </div> </body> diff --git a/Source/Core/Actions/ActionManager.cs b/Source/Core/Actions/ActionManager.cs index dbc4ae91..ee882570 100644 --- a/Source/Core/Actions/ActionManager.cs +++ b/Source/Core/Actions/ActionManager.cs @@ -193,7 +193,7 @@ namespace CodeImp.DoomBuilder.Actions else { // Action already exists! - General.ErrorLogger.Add(ErrorType.Warning, "Action '" + name + "' already exists. Action names must be unique."); + General.ErrorLogger.Add(ErrorType.Warning, "Action \"" + name + "\" already exists. Action names must be unique."); } } diff --git a/Source/Core/Actions/HintsManager.cs b/Source/Core/Actions/HintsManager.cs index 942665f2..5c4a7fc8 100644 --- a/Source/Core/Actions/HintsManager.cs +++ b/Source/Core/Actions/HintsManager.cs @@ -142,7 +142,7 @@ namespace CodeImp.DoomBuilder.Actions { General.Interface.ShowHints(DEFAULT_HINT); #if DEBUG - Console.WriteLine("WARNING: Unable to get hints for class '" + fullname + "', group '" + groupname + "'"); + Console.WriteLine("WARNING: Unable to get hints for class \"" + fullname + "\", group \"" + groupname + "\""); #endif return; } diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 4bd3281c..b09048e9 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -1143,6 +1143,7 @@ <None Include="Resources\GroupRemove.png" /> <None Include="Resources\GridDecrease.png" /> <None Include="Resources\GridIncrease.png" /> + <None Include="Resources\FixedThingsScale.png" /> <Content Include="Resources\Light.png" /> <None Include="Resources\Lightbulb.png" /> <None Include="Resources\LightDisabled.png" /> diff --git a/Source/Core/Compilers/Compiler.cs b/Source/Core/Compilers/Compiler.cs index 7289a4f7..bbc18bfe 100644 --- a/Source/Core/Compilers/Compiler.cs +++ b/Source/Core/Compilers/Compiler.cs @@ -76,9 +76,9 @@ namespace CodeImp.DoomBuilder.Compilers // Initialize this.info = info; this.errors = new List<CompilerError>(); - this.includes = new HashSet<string>(); //mxd - - General.WriteLogLine("Creating compiler '" + info.Name + "' on interface '" + this.GetType().Name + "'..."); + this.includes = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd + + General.WriteLogLine("Creating compiler \"" + info.Name + "\" on interface \"" + this.GetType().Name + "\"..."); // Create temporary directory tempdir = Directory.CreateDirectory(General.MakeTempDirname()); @@ -146,7 +146,7 @@ namespace CodeImp.DoomBuilder.Compilers string srcfile = Path.Combine(info.Path, f); if(!File.Exists(srcfile)) { - General.ErrorLogger.Add(ErrorType.Error, "The file '" + f + "' required by the '" + info.Name + "' compiler is missing. According to the compiler configuration in '" + info.FileName + "', the was expected to be found in the following path: " + info.Path); + General.ErrorLogger.Add(ErrorType.Error, "The file \"" + f + "\" required by the \"" + info.Name + "\" compiler is missing. According to the compiler configuration in \"" + info.FileName + "\", it was expected to be found here: \"" + info.Path + "\""); } else { diff --git a/Source/Core/Config/ArgumentInfo.cs b/Source/Core/Config/ArgumentInfo.cs index e939553f..7187af1c 100644 --- a/Source/Core/Config/ArgumentInfo.cs +++ b/Source/Core/Config/ArgumentInfo.cs @@ -87,7 +87,7 @@ namespace CodeImp.DoomBuilder.Config } else { - General.ErrorLogger.Add(ErrorType.Warning, "'" + argspath + ".arg" + istr + "' references unknown enumeration '" + argdic["enum"] + "'."); + General.ErrorLogger.Add(ErrorType.Warning, "\"" + argspath + ".arg" + istr + "\" references unknown enumeration \"" + argdic["enum"] + "\"."); } } } diff --git a/Source/Core/Config/CompilerInfo.cs b/Source/Core/Config/CompilerInfo.cs index 3cd1c9fb..65b7e9ab 100644 --- a/Source/Core/Config/CompilerInfo.cs +++ b/Source/Core/Config/CompilerInfo.cs @@ -59,7 +59,7 @@ namespace CodeImp.DoomBuilder.Config // Constructor internal CompilerInfo(string filename, string name, string path, Configuration cfg) { - General.WriteLogLine("Registered compiler configuration '" + name + "' from '" + filename + "'"); + General.WriteLogLine("Registered compiler configuration \"" + name + "\" from \"" + filename + "\""); // Initialize this.filename = filename; @@ -80,7 +80,7 @@ namespace CodeImp.DoomBuilder.Config //mxd string include = de.Value.ToString().Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar); if(files.Contains(include)) - General.ErrorLogger.Add(ErrorType.Warning, "Include file '" + de.Value + "' is double-defined in '" + name + "' compiler configuration"); + General.ErrorLogger.Add(ErrorType.Warning, "Include file \"" + de.Value + "\" is double defined in \"" + name + "\" compiler configuration"); else files.Add(include); } diff --git a/Source/Core/Config/GeneralizedOption.cs b/Source/Core/Config/GeneralizedOption.cs index 37973883..794292d9 100644 --- a/Source/Core/Config/GeneralizedOption.cs +++ b/Source/Core/Config/GeneralizedOption.cs @@ -76,7 +76,7 @@ namespace CodeImp.DoomBuilder.Config } else { - General.ErrorLogger.Add(ErrorType.Warning, "Structure '" + fullpath + "." + name + "' contains invalid entries. The keys must be numeric."); + General.ErrorLogger.Add(ErrorType.Warning, "Structure \"" + fullpath + "." + name + "\" contains invalid entries. The keys must be numeric."); } } diff --git a/Source/Core/Config/MapLumpInfo.cs b/Source/Core/Config/MapLumpInfo.cs index efecc10f..802d3695 100644 --- a/Source/Core/Config/MapLumpInfo.cs +++ b/Source/Core/Config/MapLumpInfo.cs @@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Config } else { - General.ErrorLogger.Add(ErrorType.Warning, "Map lump '" + name + "' in the current game configuration specifies an unknown script configuration '" + scriptconfig + "'. Using plain text instead."); + General.ErrorLogger.Add(ErrorType.Warning, "Map lump \"" + name + "\" in the current game configuration specifies an unknown script configuration \"" + scriptconfig + "\". Using plain text instead."); this.Script = new ScriptConfiguration(); } } diff --git a/Source/Core/Config/NodebuilderInfo.cs b/Source/Core/Config/NodebuilderInfo.cs index 8dcb20df..7649c725 100644 --- a/Source/Core/Config/NodebuilderInfo.cs +++ b/Source/Core/Config/NodebuilderInfo.cs @@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Config // Constructor public NodebuilderInfo(string filename, string name, Configuration cfg) { - General.WriteLogLine("Registered nodebuilder configuration '" + name + "' from '" + filename + "'"); + General.WriteLogLine("Registered nodebuilder configuration \"" + name + "\" from \"" + filename + "\""); // Initialize this.name = name; @@ -80,7 +80,7 @@ namespace CodeImp.DoomBuilder.Config } // No compiler found? - if(this.compiler == null) throw new Exception("No such compiler defined: '" + compilername + "'"); + if(this.compiler == null) throw new Exception("Compiler \"" + compilername + "\" is not defined"); } // Constructor for "none" nodebuilder diff --git a/Source/Core/Config/ProgramConfiguration.cs b/Source/Core/Config/ProgramConfiguration.cs index e7d1e32e..7d6947c0 100644 --- a/Source/Core/Config/ProgramConfiguration.cs +++ b/Source/Core/Config/ProgramConfiguration.cs @@ -85,7 +85,8 @@ namespace CodeImp.DoomBuilder.Config private float filteranisotropy; private bool showtexturesizes; private bool locatetexturegroup; //mxd - private SplitLineBehavior splitlinebehavior; //mxd + private bool keeptexturefilterfocused; //mxd + private SplitLineBehavior splitlinebehavior; //mxd //mxd. Script editor settings private string scriptfontname; @@ -131,7 +132,8 @@ namespace CodeImp.DoomBuilder.Config private bool storeSelectedEditTab; private int maxbackups; private bool checkforupdates; - private bool rendercomments; + private bool rendercomments; //mxd + private bool fixedthingsscale; //mxd private bool rendergrid; private bool rendernightspath; private bool dynamicgridsize; @@ -194,6 +196,7 @@ namespace CodeImp.DoomBuilder.Config public float FilterAnisotropy { get { return filteranisotropy; } internal set { filteranisotropy = value; } } public bool ShowTextureSizes { get { return showtexturesizes; } internal set { showtexturesizes = value; } } public bool LocateTextureGroup { get { return locatetexturegroup; } internal set { locatetexturegroup = value; } } //mxd + public bool KeepTextureFilterFocused { get { return keeptexturefilterfocused; } internal set { keeptexturefilterfocused = value; } } //mxd public SplitLineBehavior SplitLineBehavior { get { return splitlinebehavior; } set { splitlinebehavior = value; } } //mxd //mxd. Script editor settings @@ -241,6 +244,7 @@ namespace CodeImp.DoomBuilder.Config internal int MaxBackups { get { return maxbackups; } set { maxbackups = value; } } internal bool CheckForUpdates { get { return checkforupdates; } set { checkforupdates = value; } } //mxd public bool RenderComments { get { return rendercomments; } internal set { rendercomments = value; } } //mxd + public bool FixedThingsScale { get { return fixedthingsscale; } internal set { fixedthingsscale = value; } } //mxd public bool RenderGrid { get { return rendergrid; } internal set { rendergrid = value; } } //mxd public bool RenderNiGHTSPath { get { return rendernightspath; } internal set { rendernightspath = value; } } public bool DynamicGridSize { get { return dynamicgridsize; } internal set { dynamicgridsize = value; } } //mxd @@ -326,6 +330,7 @@ namespace CodeImp.DoomBuilder.Config filteranisotropy = cfg.ReadSetting("filteranisotropy", 8.0f); showtexturesizes = cfg.ReadSetting("showtexturesizes", true); locatetexturegroup = cfg.ReadSetting("locatetexturegroup", true); //mxd + keeptexturefilterfocused = cfg.ReadSetting("keeptexturefilterfocused", true); //mxd splitlinebehavior = (SplitLineBehavior) General.Clamp(cfg.ReadSetting("splitlinebehavior", 0), 0, 3); //mxd //mxd. Script editor @@ -371,6 +376,7 @@ namespace CodeImp.DoomBuilder.Config maxbackups = cfg.ReadSetting("maxbackups", 3); checkforupdates = false; //No update checking for Zone Builder rendercomments = cfg.ReadSetting("rendercomments", true); //mxd + fixedthingsscale = cfg.ReadSetting("fixedthingsscale", false); //mxd rendergrid = cfg.ReadSetting("rendergrid", true); //mxd rendernightspath = cfg.ReadSetting("rendernightspath", true); dynamicgridsize = cfg.ReadSetting("dynamicgridsize", true); //mxd @@ -438,6 +444,7 @@ namespace CodeImp.DoomBuilder.Config cfg.WriteSetting("filteranisotropy", filteranisotropy); cfg.WriteSetting("showtexturesizes", showtexturesizes); cfg.WriteSetting("locatetexturegroup", locatetexturegroup); //mxd + cfg.WriteSetting("keeptexturefilterfocused", keeptexturefilterfocused); //mxd cfg.WriteSetting("splitlinebehavior", (int)splitlinebehavior); //mxd //mxd. Script editor @@ -485,6 +492,7 @@ namespace CodeImp.DoomBuilder.Config cfg.WriteSetting("maxbackups", maxbackups); //cfg.WriteSetting("checkforupdates", checkforupdates); //mxd cfg.WriteSetting("rendercomments", rendercomments); //mxd + cfg.WriteSetting("fixedthingsscale", fixedthingsscale); //mxd cfg.WriteSetting("rendergrid", rendergrid); //mxd cfg.WriteSetting("rendernightspath", rendernightspath); //mxd cfg.WriteSetting("dynamicgridsize", dynamicgridsize); //mxd @@ -498,7 +506,7 @@ namespace CodeImp.DoomBuilder.Config cfg.WriteSetting("defaultbrightness", defaultbrightness); // Save settings configuration - General.WriteLogLine("Saving program configuration to '" + filepathname + "'..."); + General.WriteLogLine("Saving program configuration to \"" + filepathname + "\"..."); cfg.SaveConfiguration(filepathname); } diff --git a/Source/Core/Config/ScriptConfiguration.cs b/Source/Core/Config/ScriptConfiguration.cs index f9c5557f..f389cfcf 100644 --- a/Source/Core/Config/ScriptConfiguration.cs +++ b/Source/Core/Config/ScriptConfiguration.cs @@ -28,12 +28,20 @@ using ScintillaNET; namespace CodeImp.DoomBuilder.Config { //mxd - internal enum ScriptType + public enum ScriptType { UNKNOWN = 0, ACS = 1, MODELDEF = 2, DECORATE = 3, + GLDEFS = 4, + SNDSEQ = 5, + MAPINFO = 6, + VOXELDEF = 7, + TEXTURES = 8, + ANIMDEFS = 9, + REVERBS = 10, + TERRAIN = 11, } internal class ScriptConfiguration : IComparable<ScriptConfiguration> @@ -214,7 +222,7 @@ namespace CodeImp.DoomBuilder.Config string keyword = de.Key.ToString(); if(keywords.ContainsKey(keyword)) //mxd { - General.ErrorLogger.Add(ErrorType.Warning, "Keyword \"" + keyword + "\" is double-defined in \"" + description + "\" script configuration."); + General.ErrorLogger.Add(ErrorType.Warning, "Keyword \"" + keyword + "\" is double defined in \"" + description + "\" script configuration."); continue; } @@ -226,16 +234,16 @@ namespace CodeImp.DoomBuilder.Config //mxd. Sort keywords lookup keywordkeyssorted.Sort(); - //mxd. Load properties - dic = cfg.ReadSetting("properties", new Hashtable()); - foreach (DictionaryEntry de in dic) - { - string property = de.Key.ToString(); - if (lowerproperties.ContainsValue(property)) //mxd - { - General.ErrorLogger.Add(ErrorType.Warning, "Property \"" + property + "\" is double-defined in \"" + description + "\" script configuration."); - continue; - } + //mxd. Load properties + dic = cfg.ReadSetting("properties", new Hashtable()); + foreach(DictionaryEntry de in dic) + { + string property = de.Key.ToString(); + if(lowerproperties.ContainsValue(property)) //mxd + { + General.ErrorLogger.Add(ErrorType.Warning, "Property \"" + property + "\" is double defined in \"" + description + "\" script configuration."); + continue; + } properties.Add(property); lowerproperties[property.ToLowerInvariant()] = property; @@ -248,12 +256,12 @@ namespace CodeImp.DoomBuilder.Config dic = cfg.ReadSetting("constants", new Hashtable()); foreach(DictionaryEntry de in dic) { - string constant = de.Key.ToString(); - if (lowerconstants.ContainsValue(constant)) //mxd - { - General.ErrorLogger.Add(ErrorType.Warning, "Constant \"" + constant + "\" is double-defined in \"" + description + "\" script configuration."); - continue; - } + string constant = de.Key.ToString(); + if(lowerconstants.ContainsValue(constant)) //mxd + { + General.ErrorLogger.Add(ErrorType.Warning, "Constant \"" + constant + "\" is double defined in \"" + description + "\" script configuration."); + continue; + } constants.Add(constant); lowerconstants[constant.ToLowerInvariant()] = constant; @@ -275,10 +283,10 @@ namespace CodeImp.DoomBuilder.Config foreach (string file in files) { string name = Path.GetFileNameWithoutExtension(file); - if (string.IsNullOrEmpty(name)) - { - General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet '" + file + "' for '" + description + "' script configuration."); - } + if(string.IsNullOrEmpty(name)) + { + General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration."); + } else { if (name.Contains(" ")) name = name.Replace(' ', '_'); @@ -290,37 +298,36 @@ namespace CodeImp.DoomBuilder.Config } else { - General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet '" + file + "' for '" + description + "' script configuration: file is empty!"); + General.ErrorLogger.Add(ErrorType.Warning, "Failed to load snippet \"" + file + "\" for \"" + description + "\" script configuration: file is empty!"); } } } - //mxd. Sort snippets lookup - sortedkeys.Sort(); - snippetkeyssorted = new HashSet<string>(sortedkeys, StringComparer.OrdinalIgnoreCase); - - } - } - - // Compiler specified? - if (compilername.Length > 0) - { - // Find compiler - foreach (CompilerInfo c in General.Compilers) - { - // Compiler name matches? - if (c.Name == compilername) - { - // Apply compiler - this.compiler = c; - break; - } - } - - // No compiler found? - if (this.compiler == null) throw new Exception("No such compiler defined: '" + compilername + "'"); - } - } + //mxd. Sort snippets lookup + sortedkeys.Sort(); + snippetkeyssorted = new HashSet<string>(sortedkeys, StringComparer.OrdinalIgnoreCase); + } + } + + // Compiler specified? + if(compilername.Length > 0) + { + // Find compiler + foreach(CompilerInfo c in General.Compilers) + { + // Compiler name matches? + if(c.Name == compilername) + { + // Apply compiler + this.compiler = c; + break; + } + } + + // No compiler found? + if(this.compiler == null) throw new Exception("Compiler \"" + compilername + "\" is not defined"); + } + } #endregion diff --git a/Source/Core/Config/ThingCategory.cs b/Source/Core/Config/ThingCategory.cs index 05cbbabe..06db6ac8 100644 --- a/Source/Core/Config/ThingCategory.cs +++ b/Source/Core/Config/ThingCategory.cs @@ -293,7 +293,7 @@ namespace CodeImp.DoomBuilder.Config if(child.IsValid && child.things.Count > 0) { if(cats.ContainsKey(child.title.ToLowerInvariant())) - General.ErrorLogger.Add(ErrorType.Warning, "Thing Category '" + child.title + "' is double-defined in " + this.title); + General.ErrorLogger.Add(ErrorType.Warning, "Thing Category \"" + child.title + "\" is double defined in " + this.title); cats[child.title.ToLowerInvariant()] = child; } } diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs index a15f4bd1..3bd3ec9a 100644 --- a/Source/Core/Config/ThingTypeInfo.cs +++ b/Source/Core/Config/ThingTypeInfo.cs @@ -559,7 +559,7 @@ namespace CodeImp.DoomBuilder.Config //mxd. Marked as obsolete? if(actor.HasPropertyWithValue("$obsolete")) { - obsoletemessage = ZDTextParser.StripQuotes(actor.GetPropertyValueString("$obsolete", 0)); + obsoletemessage = actor.GetPropertyValueString("$obsolete", 0, true); obsolete = true; color = 4; //red } @@ -591,7 +591,8 @@ namespace CodeImp.DoomBuilder.Config if(actor.HasPropertyWithValue("height")) height = actor.GetPropertyValueInt("height", 0); //mxd. Renderstyle - if(actor.HasPropertyWithValue("renderstyle")) renderstyle = actor.GetPropertyValueString("renderstyle", 0).ToLower(); + if(actor.HasPropertyWithValue("renderstyle") && !actor.HasProperty("$ignorerenderstyle")) + renderstyle = actor.GetPropertyValueString("renderstyle", 0, true).ToLower(); //mxd. Alpha if(actor.HasPropertyWithValue("alpha")) diff --git a/Source/Core/Config/ThingsFlagsCompare.cs b/Source/Core/Config/ThingsFlagsCompare.cs index fcbb4a54..365c0f85 100644 --- a/Source/Core/Config/ThingsFlagsCompare.cs +++ b/Source/Core/Config/ThingsFlagsCompare.cs @@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Config // Duplicate flags check if(Flags.ContainsKey(flag)) - General.ErrorLogger.Add(ErrorType.Warning, "ThingFlagsCompare flag '" + flag + "' is double-defined in '" + name + "' group"); + General.ErrorLogger.Add(ErrorType.Warning, "ThingFlagsCompare flag \"" + flag + "\" is double defined in the \"" + name + "\" group"); Flags[flag] = new ThingFlagsCompare(cfg, name, flag); } @@ -294,7 +294,7 @@ namespace CodeImp.DoomBuilder.Config result.Add("Thing is not used by any class."); break; default: - result.Add("At least one '" + group.Key + "' flag should be set."); + result.Add("At least one \"" + group.Key + "\" flag should be set."); break; } } diff --git a/Source/Core/Controls/ArgumentBox.cs b/Source/Core/Controls/ArgumentBox.cs index 37e5293e..04e9a039 100644 --- a/Source/Core/Controls/ArgumentBox.cs +++ b/Source/Core/Controls/ArgumentBox.cs @@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.Controls //mxd. this sets default value public void SetDefaultValue() { - typehandler.SetDefaultValue(); + typehandler.ApplyDefaultValue(); combobox.SelectedItem = null; combobox.Text = typehandler.GetStringValue(); combobox_Validating(this, new CancelEventArgs()); diff --git a/Source/Core/Controls/ArgumentsControl.cs b/Source/Core/Controls/ArgumentsControl.cs index a511c612..fe9b817a 100644 --- a/Source/Core/Controls/ArgumentsControl.cs +++ b/Source/Core/Controls/ArgumentsControl.cs @@ -204,15 +204,21 @@ namespace CodeImp.DoomBuilder.Controls { // Update arguments int showaction = 0; + ArgumentInfo[] oldarginfo = (arginfo != null ? (ArgumentInfo[])arginfo.Clone() : null); //mxd // Only when action type is known if(General.Map.Config.LinedefActions.ContainsKey(action)) showaction = action; + + // Update argument infos if((showaction == 0) && (info != null)) arginfo = info.Args; else arginfo = General.Map.Config.LinedefActions[showaction].Args; // Don't update action args when thing type is changed if(info != null && showaction != 0 && this.action == showaction) return; + //mxd. Don't update action args when old and new argument infos match + if(arginfo != null && oldarginfo != null && ArgumentInfosMatch(arginfo, oldarginfo)) return; + // Change the argument descriptions this.BeginUpdate(); @@ -387,6 +393,24 @@ namespace CodeImp.DoomBuilder.Controls } } + //mxd + private static bool ArgumentInfosMatch(ArgumentInfo[] info1, ArgumentInfo[] info2) + { + if(info1.Length != info2.Length) return false; + bool haveusedargs = false; // Arguments should still be reset if all arguments are unused + + for(int i = 0; i < info1.Length; i++) + { + if(info1[i].Used != info1[2].Used || info1[i].Type != info1[2].Type + || info1[i].Title.ToUpperInvariant() != info2[i].Title.ToUpperInvariant()) + return false; + + haveusedargs |= (info1[i].Used || info1[2].Used); + } + + return haveusedargs; + } + #endregion #region ================== Redraw control diff --git a/Source/Core/Controls/FieldsEditorControl.cs b/Source/Core/Controls/FieldsEditorControl.cs index 9b4fe135..dc095c27 100644 --- a/Source/Core/Controls/FieldsEditorControl.cs +++ b/Source/Core/Controls/FieldsEditorControl.cs @@ -61,27 +61,27 @@ namespace CodeImp.DoomBuilder.Controls private string lasteditfieldname; private bool autoinsertuserprefix; private Dictionary<string, UniversalType> uifields;//mxd - private bool showfixedfields = true; //mxd - - #endregion + private bool showfixedfields = true; //mxd + + #endregion - #region ================== Properties + #region ================== Properties - public bool AllowInsert { get { return fieldslist.AllowUserToAddRows; } set { fieldslist.AllowUserToAddRows = value; SetupNewRowStyle(); } } + public bool AllowInsert { get { return fieldslist.AllowUserToAddRows; } set { fieldslist.AllowUserToAddRows = value; SetupNewRowStyle(); } } public bool AutoInsertUserPrefix { get { return autoinsertuserprefix; } set { autoinsertuserprefix = value; } } public int PropertyColumnWidth { get { return fieldname.Width; } set { fieldname.Width = value; UpdateValueColumn(); UpdateBrowseButton(); } } public int TypeColumnWidth { get { return fieldtype.Width; } set { fieldtype.Width = value; UpdateValueColumn(); UpdateBrowseButton(); } } public bool PropertyColumnVisible { get { return fieldname.Visible; } set { fieldname.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } } public bool TypeColumnVisible { get { return fieldtype.Visible; } set { fieldtype.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } } public bool ValueColumnVisible { get { return fieldvalue.Visible; } set { fieldvalue.Visible = value; UpdateValueColumn(); UpdateBrowseButton(); } } - public bool ShowFixedFields { get { return showfixedfields; } set { showfixedfields = value; UpdateFixedFieldsVisibility(); } } //mxd + public bool ShowFixedFields {get { return showfixedfields; } set { showfixedfields = value; UpdateFixedFieldsVisibility(); } } //mxd - #endregion + #endregion - #region ================== Constructor + #region ================== Constructor - // Constructor - public FieldsEditorControl() + // Constructor + public FieldsEditorControl() { InitializeComponent(); autoinsertuserprefix = true; @@ -171,6 +171,7 @@ namespace CodeImp.DoomBuilder.Controls // Go for all rows bool foundrow = false; + bool skiprow = false; //mxd foreach(DataGridViewRow row in fieldslist.Rows) { // Row is a field? @@ -181,11 +182,18 @@ namespace CodeImp.DoomBuilder.Controls // Row name matches with field if(frow.Name == f.Key) { + //mxd. User vars are set separately + if(frow.RowType == FieldsEditorRowType.USERVAR) + { + skiprow = true; + break; + } + // First time? if(first) { // Set type when row is not fixed - if(!frow.IsFixed) frow.ChangeType(f.Value.Type); + if(frow.RowType == FieldsEditorRowType.DYNAMIC) frow.ChangeType(f.Value.Type); // Apply value of field to row frow.Define(f.Value.Value); @@ -207,16 +215,18 @@ namespace CodeImp.DoomBuilder.Controls } } } + + //mxd. User vars are set separately + if(skiprow) continue; // Row not found? if(!foundrow) { // Make new row - FieldsEditorRow frow = new FieldsEditorRow(fieldslist, f.Key, f.Value.Type, f.Value.Value); + FieldsEditorRow frow = new FieldsEditorRow(fieldslist, f.Key, f.Value.Type, f.Value.Value, false); fieldslist.Rows.Insert(fieldslist.Rows.Count - 1, frow); - // When not the first, clear the field - // because the others did not define this one + // When not the first, clear the field because the others did not define this one if(!first) frow.Clear(); } } @@ -245,6 +255,82 @@ namespace CodeImp.DoomBuilder.Controls // Sort fields Sort(); } + + //mxd + public void SetUserVars(Dictionary<string, UniversalType> vars, UniFields fromfields, bool first) + { + foreach(KeyValuePair<string, UniversalType> group in vars) + { + // Go for all rows + bool foundrow = false; + TypeHandler vartype = General.Types.GetFieldHandler((int)group.Value, 0); + object value = fromfields.ContainsKey(group.Key) ? fromfields[group.Key].Value : vartype.GetDefaultValue(); + + foreach(DataGridViewRow row in fieldslist.Rows) + { + // Row is a field? + if(row is FieldsEditorRow) + { + FieldsEditorRow frow = row as FieldsEditorRow; + + // Row name matches with user var? + if(frow.RowType == FieldsEditorRowType.USERVAR && frow.Name == group.Key) + { + // First time? + if(first) + { + frow.Define(value); + } + // Check if the value is different + else if(!frow.TypeHandler.GetValue().Equals(value)) + { + // Clear the value in the row + frow.Define(value); + frow.Clear(); + } + + // Done + foundrow = true; + break; + } + } + } + + // Row not found? + if(!foundrow) + { + // Make new row + object defaultvalue = vartype.GetDefaultValue(); + FieldsEditorRow frow = new FieldsEditorRow(fieldslist, group.Key, (int)group.Value, defaultvalue, true); + if(!value.Equals(defaultvalue)) frow.Define(value); + fieldslist.Rows.Insert(fieldslist.Rows.Count - 1, frow); + } + } + + // Now check for rows that the givens fields do NOT have + foreach(DataGridViewRow row in fieldslist.Rows) + { + // Row is a field? + if(row is FieldsEditorRow) + { + FieldsEditorRow frow = row as FieldsEditorRow; + + // Don't undefine user var rows defined by other actor types + if(frow.RowType != FieldsEditorRowType.USERVAR || !vars.ContainsKey(frow.Name)) continue; + + // Is this row defined previously? + if(frow.IsDefined) + { + // Check if this row can not be found in the fields at all + if(!fromfields.ContainsKey(frow.Name)) + { + // It is not defined in these fields, undefine the value + frow.Undefine(); + } + } + } + } + } // This applies the current fields to a UniFields object public void Apply(UniFields tofields) @@ -259,6 +345,7 @@ namespace CodeImp.DoomBuilder.Controls // Go for all rows bool foundrow = false; + bool skiprow = false; //mxd foreach(DataGridViewRow row in fieldslist.Rows) { // Row is a field and matches field name? @@ -266,6 +353,13 @@ namespace CodeImp.DoomBuilder.Controls { FieldsEditorRow frow = row as FieldsEditorRow; + //mxd. User vars are stored separately + if(frow.RowType == FieldsEditorRowType.USERVAR) + { + skiprow = true; + break; + } + // Field is defined? if(frow.IsDefined) { @@ -275,6 +369,9 @@ namespace CodeImp.DoomBuilder.Controls } } + //mxd. User vars are stored separately + if(skiprow) continue; + // No such row? if(!foundrow) { @@ -292,7 +389,7 @@ namespace CodeImp.DoomBuilder.Controls FieldsEditorRow frow = row as FieldsEditorRow; // Field is defined and not empty? - if(frow.IsDefined && !frow.IsEmpty) + if(frow.RowType != FieldsEditorRowType.USERVAR && frow.IsDefined && !frow.IsEmpty) { // Apply field object oldvalue = null; @@ -300,7 +397,7 @@ namespace CodeImp.DoomBuilder.Controls tofields[frow.Name] = new UniValue(frow.TypeHandler.Index, frow.GetResult(oldvalue)); // Custom row? - if(!frow.IsFixed) + if(frow.RowType == FieldsEditorRowType.DYNAMIC) { // Write type to map configuration General.Map.Options.SetUniversalFieldType(elementname, frow.Name, frow.TypeHandler.Index); @@ -310,6 +407,38 @@ namespace CodeImp.DoomBuilder.Controls } } + //mxd + public void ApplyUserVars(Dictionary<string, UniversalType> vars, UniFields tofields) + { + // Apply user variables when target map element contains user var definition and the value is not default + foreach(DataGridViewRow row in fieldslist.Rows) + { + // Row is a field? + if(row is FieldsEditorRow) + { + FieldsEditorRow frow = row as FieldsEditorRow; + if(frow.RowType != FieldsEditorRowType.USERVAR || !vars.ContainsKey(frow.Name)) continue; + + object oldvalue = (tofields.ContainsKey(frow.Name) ? tofields[frow.Name].Value : null); + object newvalue = frow.GetResult(oldvalue); + + // Skip field when mixed values + if(newvalue == null) continue; + + // Remove field + if(newvalue.Equals(frow.TypeHandler.GetDefaultValue())) + { + if(tofields.ContainsKey(frow.Name)) tofields.Remove(frow.Name); + } + // Add field + else if(!newvalue.Equals(oldvalue)) + { + tofields[frow.Name] = new UniValue(frow.TypeHandler.Index, newvalue); + } + } + } + } + #endregion #region ================== Events @@ -377,16 +506,16 @@ namespace CodeImp.DoomBuilder.Controls // First column? if(e.ColumnIndex == 0) { - // Not a fixed field? - if((frow != null) && !frow.IsFixed) + // Dynamic field? + if((frow != null) && frow.RowType == FieldsEditorRowType.DYNAMIC) { lasteditfieldname = frow.Name; fieldslist.CurrentCell = fieldslist.SelectedRows[0].Cells[0]; fieldslist.CurrentCell.ReadOnly = false; - if((e.RowIndex == fieldslist.NewRowIndex) || - frow.Name.StartsWith(FIELD_PREFIX_SUGGESTION, StringComparison.OrdinalIgnoreCase)) - fieldslist.BeginEdit(false); + if((e.RowIndex == fieldslist.NewRowIndex) || + frow.Name.StartsWith(FIELD_PREFIX_SUGGESTION, StringComparison.OrdinalIgnoreCase)) + fieldslist.BeginEdit(false); else fieldslist.BeginEdit(true); } @@ -399,21 +528,20 @@ namespace CodeImp.DoomBuilder.Controls { // Get the row FieldsEditorRow row = e.Row as FieldsEditorRow; + if(row == null) return; - // Fixed field? - if(row.IsFixed) + // Fixed/uservar field? + if(row.RowType == FieldsEditorRowType.FIXED || row.RowType == FieldsEditorRowType.USERVAR) { // Just undefine the field row.Undefine(); e.Cancel = true; - if(OnFieldUndefined != null) - OnFieldUndefined(row.Name); + if(OnFieldUndefined != null) OnFieldUndefined(row.Name); } else { - if(OnFieldDeleted != null) - OnFieldDeleted(row.Name); + if(OnFieldDeleted != null) OnFieldDeleted(row.Name); } } @@ -428,10 +556,7 @@ namespace CodeImp.DoomBuilder.Controls { // Remove all text fieldslist.Rows[e.RowIndex].Cells[0].Style.ForeColor = SystemColors.WindowText; - if(autoinsertuserprefix) - fieldslist.Rows[e.RowIndex].Cells[0].Value = FIELD_PREFIX_SUGGESTION; - else - fieldslist.Rows[e.RowIndex].Cells[0].Value = ""; + fieldslist.Rows[e.RowIndex].Cells[0].Value = (autoinsertuserprefix ? FIELD_PREFIX_SUGGESTION : string.Empty); } } // Value cell? @@ -470,13 +595,13 @@ namespace CodeImp.DoomBuilder.Controls // Select the value of this field (for DropDownList style combo) foreach(EnumItem i in enumscombo.Items) { - // Matches? - if (string.Compare(i.Title, frow.TypeHandler.GetStringValue(), StringComparison.OrdinalIgnoreCase) == 0) - { + // Matches? + if(string.Compare(i.Title, frow.TypeHandler.GetStringValue(), StringComparison.OrdinalIgnoreCase) == 0) + { // Select this item enumscombo.SelectedItem = i; - break; //mxd - } + break; //mxd + } } // Put the display text in the text (for DropDown style combo) @@ -538,12 +663,11 @@ namespace CodeImp.DoomBuilder.Controls int type = General.Map.Options.GetUniversalFieldType(elementname, validname, 0); // Make new row - frow = new FieldsEditorRow(fieldslist, validname, type, null); + frow = new FieldsEditorRow(fieldslist, validname, type, null, false); frow.Visible = false; fieldslist.Rows.Insert(e.RowIndex + 1, frow); - if(OnFieldInserted != null) - OnFieldInserted(validname); + if(OnFieldInserted != null) OnFieldInserted(validname); } } } @@ -587,11 +711,8 @@ namespace CodeImp.DoomBuilder.Controls row.Cells[0].Value = validname; if(type != -1) frow.ChangeType(type); - if(OnFieldNameChanged != null) - OnFieldNameChanged(lasteditfieldname, validname); - - if(OnFieldTypeChanged != null) - OnFieldTypeChanged(validname); + if(OnFieldNameChanged != null) OnFieldNameChanged(lasteditfieldname, validname); + if(OnFieldTypeChanged != null) OnFieldTypeChanged(validname); } else { @@ -615,8 +736,7 @@ namespace CodeImp.DoomBuilder.Controls // Changing field type? if((e.ColumnIndex == 1) && (frow != null)) { - if(OnFieldTypeChanged != null) - OnFieldTypeChanged(frow.Name); + if(OnFieldTypeChanged != null) OnFieldTypeChanged(frow.Name); } // Changing field value? if((e.ColumnIndex == 2) && (frow != null)) @@ -641,18 +761,18 @@ namespace CodeImp.DoomBuilder.Controls // Delete all rows that must be deleted for(int i = fieldslist.Rows.Count - 1; i >= 0; i--) { - if (fieldslist.Rows[i].ReadOnly) - { - try { fieldslist.Rows.RemoveAt(i); } catch { } - } - else - { - //mxd. Preserve fixed fields visibility setting - FieldsEditorRow frow = (fieldslist.Rows[i] as FieldsEditorRow); - if (frow != null && frow.IsFixed) frow.Visible = showfixedfields; - else fieldslist.Rows[i].Visible = true; - } - } + if(fieldslist.Rows[i].ReadOnly) + { + try { fieldslist.Rows.RemoveAt(i); } catch { } + } + else + { + //mxd. Preserve fixed fields visibility setting + FieldsEditorRow frow = (fieldslist.Rows[i] as FieldsEditorRow); + if(frow != null && frow.RowType == FieldsEditorRowType.FIXED) frow.Visible = showfixedfields; + else fieldslist.Rows[i].Visible = true; + } + } // Update new row SetupNewRowStyle(); @@ -730,17 +850,17 @@ namespace CodeImp.DoomBuilder.Controls private void ApplyValue(FieldsEditorRow frow, object value) { // Defined? - if((value != null) && (!frow.IsFixed || !frow.Info.Default.Equals(value))) + if((value != null) && (frow.RowType == FieldsEditorRowType.DYNAMIC || frow.RowType == FieldsEditorRowType.USERVAR + || !frow.Info.Default.Equals(value))) { frow.Define(value); } - else if(frow.IsFixed) + else if(frow.RowType == FieldsEditorRowType.FIXED) { frow.Undefine(); } - if(OnFieldValueChanged != null) - OnFieldValueChanged(frow.Name); + if(OnFieldValueChanged != null) OnFieldValueChanged(frow.Name); } // This applies the contents of the enums combobox and hides (if opened) @@ -841,16 +961,16 @@ namespace CodeImp.DoomBuilder.Controls } } - //mxd - private void UpdateFixedFieldsVisibility() - { - foreach (var row in fieldslist.Rows) - { - FieldsEditorRow frow = (row as FieldsEditorRow); - if (frow != null && frow.IsFixed) frow.Visible = showfixedfields; - } - } - - #endregion - } + //mxd + private void UpdateFixedFieldsVisibility() + { + foreach(var row in fieldslist.Rows) + { + FieldsEditorRow frow = (row as FieldsEditorRow); + if(frow != null && frow.RowType == FieldsEditorRowType.FIXED) frow.Visible = showfixedfields; + } + } + + #endregion + } } diff --git a/Source/Core/Controls/FieldsEditorRow.cs b/Source/Core/Controls/FieldsEditorRow.cs index 6a276301..99f647b2 100644 --- a/Source/Core/Controls/FieldsEditorRow.cs +++ b/Source/Core/Controls/FieldsEditorRow.cs @@ -26,6 +26,23 @@ using CodeImp.DoomBuilder.Types; namespace CodeImp.DoomBuilder.Controls { + internal enum FieldsEditorRowType //mxd + { + // This is a fixed field defined in the game configuration + // The field cannot be deleted (delete will result in a reset) + // and cannot change type. + FIXED, + + // This is an abstartct variable field enetered by user + // The field can be deleted and can change type. + DYNAMIC, + + // This is a user variable field defined in actor's DECORATE + // The field cannot be deleted (delete will result in a reset) + // but can change type. + USERVAR, + } + internal class FieldsEditorRow : DataGridViewRow { #region ================== Constants @@ -34,13 +51,11 @@ namespace CodeImp.DoomBuilder.Controls #region ================== Variables - // This is true when for a fixed field as defined in the game configuration - // This means that the field cannot be deleted (delete will result in a reset) - // and cannot change type. - private bool isfixed; + //mxd. Row type + private readonly FieldsEditorRowType rowtype; // Field information (only for fixed fields) - private UniversalFieldInfo fieldinfo; + private readonly UniversalFieldInfo fieldinfo; // This is true when the field is defined. Cannot be false when this field // is not fixed, because non-fixed fields are deleted from the list when undefined. @@ -53,7 +68,7 @@ namespace CodeImp.DoomBuilder.Controls #region ================== Properties - public bool IsFixed { get { return isfixed; } } + public FieldsEditorRowType RowType { get { return rowtype; } } //mxd public bool IsDefined { get { return isdefined; } } public bool IsEmpty { get { return (this.Cells[2].Value == null) || (this.Cells[2].Value.ToString().Length == 0); } } public string Name { get { return this.Cells[0].Value.ToString(); } } @@ -73,7 +88,7 @@ namespace CodeImp.DoomBuilder.Controls // Fixed this.fieldinfo = fixedfield; - isfixed = true; + this.rowtype = FieldsEditorRowType.FIXED; //mxd // Type this.fieldtype = General.Types.GetFieldHandler(fixedfield); @@ -97,31 +112,54 @@ namespace CodeImp.DoomBuilder.Controls } // Constructor for a non-fixed, defined field - public FieldsEditorRow(DataGridView view, string name, int type, object value) + //mxd. Also for a user variable field. + public FieldsEditorRow(DataGridView view, string name, int type, object value, bool isuservar) { - // Defined - this.DefaultCellStyle.ForeColor = SystemColors.WindowText; - isdefined = true; - - // Non-fixed - isfixed = false; + //mxd. Row type + this.rowtype = (isuservar ? FieldsEditorRowType.USERVAR : FieldsEditorRowType.DYNAMIC); // Type this.fieldtype = General.Types.GetFieldHandler(type, value); // Make all cells base.CreateCells(view); - - // Setup property cell - this.Cells[0].Value = name; - this.Cells[0].ReadOnly = true; - // Setup type cell - this.Cells[1].Value = fieldtype.GetDisplayType(); - this.Cells[1].ReadOnly = false; + //mxd. Our path splits here... + if(isuservar) + { + // Not defined + this.DefaultCellStyle.ForeColor = SystemColors.GrayText; + isdefined = false; + fieldtype.ApplyDefaultValue(); - // Setup value cell - this.Cells[2].Value = fieldtype.GetStringValue(); + // Setup property cell + this.Cells[0].Value = name; + this.Cells[0].ReadOnly = true; + + // Setup type cell + this.Cells[1].Value = fieldtype.GetDisplayType(); + this.Cells[1].ReadOnly = true; + + // Setup value cell + this.Cells[2].Value = fieldtype.GetStringValue(); + } + else + { + // Defined + this.DefaultCellStyle.ForeColor = SystemColors.WindowText; + isdefined = true; + + // Setup property cell + this.Cells[0].Value = name; + this.Cells[0].ReadOnly = true; + + // Setup type cell + this.Cells[1].Value = fieldtype.GetDisplayType(); + this.Cells[1].ReadOnly = false; + + // Setup value cell + this.Cells[2].Value = fieldtype.GetStringValue(); + } // We have no destructor GC.SuppressFinalize(this); @@ -140,7 +178,7 @@ namespace CodeImp.DoomBuilder.Controls fieldtype.Browse(parent); // This is a fixed field? - if(isfixed) + if(rowtype == FieldsEditorRowType.FIXED) { // Does this match the default setting? if(fieldtype.GetValue().Equals(fieldinfo.Default)) @@ -188,7 +226,7 @@ namespace CodeImp.DoomBuilder.Controls this.Cells[2].Value = fieldtype.GetStringValue(); // This is a fixed field? - if(isfixed) + if(rowtype == FieldsEditorRowType.FIXED) { // Does this match the default setting? if(fieldtype.GetValue().Equals(fieldinfo.Default)) @@ -201,15 +239,19 @@ namespace CodeImp.DoomBuilder.Controls } // This undefines the field - // ONLY VALID FOR FIXED FIELDS + // ONLY VALID FOR FIXED AND USERVAR FIELDS // You should just delete non-fixed fields public void Undefine() { // Must be fixed! - if(!isfixed) throw new InvalidOperationException(); + if(rowtype != FieldsEditorRowType.FIXED && rowtype != FieldsEditorRowType.USERVAR) throw new InvalidOperationException(); // Now undefined - fieldtype.SetValue(fieldinfo.Default); + if(rowtype == FieldsEditorRowType.USERVAR) + fieldtype.ApplyDefaultValue(); + else + fieldtype.SetValue(fieldinfo.Default); + this.Cells[2].Value = fieldtype.GetStringValue(); this.DefaultCellStyle.ForeColor = SystemColors.GrayText; isdefined = false; @@ -218,10 +260,13 @@ namespace CodeImp.DoomBuilder.Controls // This defines the field public void Define(object value) { + //mxd. Don't count as defined when default value is passed + if(value.ToString() == fieldtype.GetDefaultValue().ToString()) return; + // Now defined fieldtype.SetValue(value); this.Cells[2].Value = fieldtype.GetStringValue(); - this.DefaultCellStyle.ForeColor = SystemColors.WindowText; + this.DefaultCellStyle.ForeColor = (rowtype == FieldsEditorRowType.USERVAR ? SystemColors.HotTrack : SystemColors.WindowText); isdefined = true; } @@ -229,13 +274,12 @@ namespace CodeImp.DoomBuilder.Controls public void ChangeType(int typeindex) { // Can't do this for a fixed field! - if(isfixed) throw new InvalidOperationException(); + if(rowtype == FieldsEditorRowType.FIXED) throw new InvalidOperationException(); // Different? if(typeindex != fieldtype.Index) { // Change field type! - //TypeHandlerAttribute attrib = General.Types.GetAttribute(typeindex); //mxd fieldtype = General.Types.GetFieldHandler(typeindex, this.Cells[2].Value); this.Cells[1].Value = fieldtype.GetDisplayType(); } diff --git a/Source/Core/Controls/FlatSelectorControl.cs b/Source/Core/Controls/FlatSelectorControl.cs index c466a9a6..3c76acbc 100644 --- a/Source/Core/Controls/FlatSelectorControl.cs +++ b/Source/Core/Controls/FlatSelectorControl.cs @@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.Controls if(usepreviews ? !texture.IsPreviewLoaded : !texture.IsImageLoaded) timer.Start(); //mxd // Set the image - return (usepreviews ? texture.GetPreview() : texture.GetBitmap()); + return new Bitmap(usepreviews ? texture.GetPreview() : texture.GetBitmap()); } } diff --git a/Source/Core/Controls/ImageBrowserControl.Designer.cs b/Source/Core/Controls/ImageBrowserControl.Designer.cs index 567270c5..2549132a 100644 --- a/Source/Core/Controls/ImageBrowserControl.Designer.cs +++ b/Source/Core/Controls/ImageBrowserControl.Designer.cs @@ -116,6 +116,7 @@ namespace CodeImp.DoomBuilder.Controls this.list.DoubleClick += new System.EventHandler(this.list_DoubleClick); this.list.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.list_ItemSelectionChanged); this.list.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.list_KeyPress); + this.list.KeyDown += new System.Windows.Forms.KeyEventHandler(this.list_KeyDown); // // showsubdirtextures // diff --git a/Source/Core/Controls/ImageBrowserControl.cs b/Source/Core/Controls/ImageBrowserControl.cs index ede2166f..b7b8c2a0 100644 --- a/Source/Core/Controls/ImageBrowserControl.cs +++ b/Source/Core/Controls/ImageBrowserControl.cs @@ -237,6 +237,20 @@ namespace CodeImp.DoomBuilder.Controls } } + //mxd. Handle keyboard navigation the same way regardless of list being focused... + private void list_KeyDown(object sender, KeyEventArgs e) + { + // Check what key is pressed + switch(e.KeyData) + { + // Cursor keys + case Keys.Left: SelectNextItem(SearchDirectionHint.Left); e.SuppressKeyPress = true; break; + case Keys.Right: SelectNextItem(SearchDirectionHint.Right); e.SuppressKeyPress = true; break; + case Keys.Up: SelectNextItem(SearchDirectionHint.Up); e.SuppressKeyPress = true; break; + case Keys.Down: SelectNextItem(SearchDirectionHint.Down); e.SuppressKeyPress = true; break; + } + } + //mxd private void filterSize_WhenTextChanged(object sender, EventArgs e) { @@ -277,6 +291,8 @@ namespace CodeImp.DoomBuilder.Controls //mxd. Transfer focus to Filter textbox private void list_KeyPress(object sender, KeyPressEventArgs e) { + if(!General.Settings.KeepTextureFilterFocused) return; + objectname.Focus(); if(e.KeyChar == '\b') // Any better way to check for Backspace?.. { @@ -388,36 +404,115 @@ namespace CodeImp.DoomBuilder.Controls } else { - // Get selected item - ListViewItem lvi = list.SelectedItems[0]; - Rectangle lvirect = list.GetItemRect(lvi.Index, ItemBoundsPortion.Entire); - Point spos = new Point(lvirect.Location.X + lvirect.Width / 2, lvirect.Y + lvirect.Height / 2); + //mxd + int index = list.SelectedItems[0].Index; + int targetindex = -1; + ListViewGroup startgroup = list.SelectedItems[0].Group; + Rectangle startrect = list.SelectedItems[0].GetBounds(ItemBoundsPortion.Entire); - // Try finding 5 times in the given direction - for(int i = 0; i < 5; i++) + switch(dir) { - // Move point in given direction - switch(dir) - { - case SearchDirectionHint.Left: spos.X -= list.TileSize.Width / 2; break; - case SearchDirectionHint.Right: spos.X += list.TileSize.Width / 2; break; - case SearchDirectionHint.Up: spos.Y -= list.TileSize.Height / 2; break; - case SearchDirectionHint.Down: spos.Y += list.TileSize.Height / 2; break; - } - - // Test position - lvi = list.GetItemAt(spos.X, spos.Y); - if(lvi != null) - { - // Select item - list.SelectedItems.Clear(); - lvi.Selected = true; + // Check previous items untill groups match... + case SearchDirectionHint.Left: + if(list.SelectedIndices[0] > 0) + { + while(--index > -1) + { + if(list.Items[index].Group == startgroup) + { + targetindex = index; + break; + } + } + } + break; + + // Same thing, other direction... + case SearchDirectionHint.Right: + if(list.SelectedIndices[0] < list.Items.Count - 1) + { + while(++index < list.Items.Count) + { + if(list.Items[index].Group == startgroup) + { + targetindex = index; + break; + } + } + } + break; + + // Check previous items untill X coordinate match and Y coordinate is less than the start ones... + case SearchDirectionHint.Up: + while(--index > -1) + { + ListViewItem item = list.Items[index]; + if(item != null && item.Group == startgroup) + { + Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire); + if(rect.X == startrect.X && rect.Y < startrect.Y) + { + targetindex = index; + break; + } + } + } break; + + // Same thing, other direction... + case SearchDirectionHint.Down: + if(list.SelectedIndices[0] < list.Items.Count - 1) + { + while(++index < list.Items.Count) + { + ListViewItem item = list.Items[index]; + if(item != null && item.Group == startgroup) + { + Rectangle rect = item.GetBounds(ItemBoundsPortion.Entire); + if(rect.X == startrect.X && rect.Y > startrect.Y) + { + targetindex = index; + break; + } + } + } + } + break; + } + + //mxd. Use the old method for Up/Down keys, becaue it can jump between Groups... + if(targetindex == -1 && (dir == SearchDirectionHint.Up || dir == SearchDirectionHint.Down)) + { + Point spos = new Point(startrect.Location.X + startrect.Width / 2, startrect.Y + startrect.Height / 2); + + // Try finding 5 times in the given direction + for(int i = 0; i < 5; i++) + { + // Move point in given direction + switch(dir) + { + case SearchDirectionHint.Up: spos.Y -= list.TileSize.Height / 2; break; + case SearchDirectionHint.Down: spos.Y += list.TileSize.Height / 2; break; + } + + // Test position + ListViewItem lvi = list.GetItemAt(spos.X, spos.Y); + if(lvi != null) + { + targetindex = lvi.Index; + break; + } } } - - // Make selection visible - if(list.SelectedItems.Count > 0) list.SelectedItems[0].EnsureVisible(); + + //mxd. Found something?.. + if(targetindex != -1) + { + // Select item + list.SelectedItems.Clear(); + list.Items[targetindex].Selected = true; + list.SelectedItems[0].EnsureVisible(); + } } } @@ -514,6 +609,15 @@ namespace CodeImp.DoomBuilder.Controls private void RefillList(bool selectfirst) { visibleitems = new List<ImageBrowserItem>(); + + //mxd. Store info about currently selected item + string selectedname = string.Empty; + ListViewGroup selecteditemgroup = null; + if(!selectfirst && keepselected == -1 && list.SelectedIndices.Count > 0) + { + selectedname = list.Items[list.SelectedIndices[0]].Text; + selecteditemgroup = list.Items[list.SelectedIndices[0]].Group; + } // Begin updating list updating = true; @@ -569,6 +673,56 @@ namespace CodeImp.DoomBuilder.Controls { SelectFirstItem(); } + //mxd. Try reselecting the same/next closest item + else if(selecteditemgroup != null && !string.IsNullOrEmpty(selectedname)) + { + ListViewItem bestmatch = null; + int charsmatched = 1; + foreach(ListViewItem item in list.Items) + { + if(item.Group == selecteditemgroup && item.Text[0] == selectedname[0]) + { + if(item.Text == selectedname) + { + bestmatch = item; + break; + } + + for(int i = 1; i < Math.Min(item.Text.Length, selectedname.Length); i++) + { + if(item.Text[i] != selectedname[i]) + { + if(i > charsmatched) + { + bestmatch = item; + charsmatched = i; + } + break; + } + } + } + } + + // Select the first item from the same group... + if(bestmatch == null) + { + foreach(ListViewItem item in list.Items) + { + if(item.Group == selecteditemgroup) + { + bestmatch = item; + break; + } + } + } + + // Select found item + if(bestmatch != null) + { + bestmatch.Selected = true; + bestmatch.EnsureVisible(); + } + } } // Raise event @@ -605,7 +759,10 @@ namespace CodeImp.DoomBuilder.Controls // This sends the focus to the textbox public void FocusTextbox() { - objectname.Focus(); + if(General.Settings.KeepTextureFilterFocused) //mxd + objectname.Focus(); + else + list.Focus(); } #endregion diff --git a/Source/Core/Controls/ScriptEditorControl.cs b/Source/Core/Controls/ScriptEditorControl.cs index c001cc54..14bcc86b 100644 --- a/Source/Core/Controls/ScriptEditorControl.cs +++ b/Source/Core/Controls/ScriptEditorControl.cs @@ -35,1417 +35,1425 @@ using ScintillaNET; namespace CodeImp.DoomBuilder.Controls { - internal enum ScriptStyleType - { - PlainText = 0, - Keyword = 1, - Constant = 2, - Comment = 3, - Literal = 4, - LineNumber = 5, - String = 6, //mxd - Include = 7, //mxd - Property = 8, //mxd - } - - internal partial class ScriptEditorControl : UserControl - { - #region ================== Enums - - // Index for registered images - private enum ImageIndex - { - ScriptConstant = 0, - ScriptKeyword = 1, - ScriptError = 2, - ScriptSnippet = 3, //mxd - ScriptProperty = 4, //mxd - } - - #endregion - - #region ================== Constants - - private const string LEXERS_RESOURCE = "Lexers.cfg"; - private const int MAX_BACKTRACK_LENGTH = 200; - private const int HIGHLIGHT_INDICATOR = 8; //mxd. Indicators 0-7 could be in use by a lexer so we'll use indicator 8 to highlight words. - - #endregion - - #region ================== Delegates / Events - - public delegate void ExplicitSaveTabDelegate(); - public delegate void OpenScriptBrowserDelegate(); - public delegate void OpenFindReplaceDelegate(); - public delegate void FindNextDelegate(); - public delegate void FindPreviousDelegate(); //mxd - - public event ExplicitSaveTabDelegate OnExplicitSaveTab; - public event OpenScriptBrowserDelegate OnOpenScriptBrowser; - public event OpenFindReplaceDelegate OnOpenFindAndReplace; - public event FindNextDelegate OnFindNext; - public event FindPreviousDelegate OnFindPrevious; //mxd - public new event EventHandler OnTextChanged; //mxd - - #endregion - - #region ================== Variables - - // Script configuration - private ScriptConfiguration scriptconfig; - - // List of keywords and constants - private List<string> autocompletelist; - - // Style translation from Scintilla style to ScriptStyleType - private Dictionary<int, ScriptStyleType> stylelookup; - - // Current position information - private string curfunctionname = ""; - private int curargumentindex; - private int curfunctionstartpos; - private int linenumbercharlength; //mxd. Current max number of chars in the line number - private int lastcaretpos; //mxd. Used in brace matching - private int caretoffset; //mxd. Used to modify caret position after autogenerating stuff - private bool skiptextinsert; //mxd. Gross hacks - private bool expandcodeblock; //mxd. More gross hacks - private string highlightedword; //mxd - private Encoding encoding; //mxd - - #endregion - - #region ================== Properties - - public bool IsChanged { get { return scriptedit.Modified; } } - public int SelectionStart { get { return scriptedit.SelectionStart; } set { scriptedit.SelectionStart = value; } } - public int SelectionEnd { get { return scriptedit.SelectionEnd; } set { scriptedit.SelectionEnd = value; } } - public new string Text { get { return scriptedit.Text; } set { scriptedit.Text = value; } } //mxd - public string SelectedText { get { return scriptedit.SelectedText; } } //mxd - public bool ShowWhitespace { get { return scriptedit.ViewWhitespace != WhitespaceMode.Invisible; } set { scriptedit.ViewWhitespace = value ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; } } - public bool WrapLongLines { get { return scriptedit.WrapMode != WrapMode.None; } set { scriptedit.WrapMode = (value ? WrapMode.Char : WrapMode.None); } } - public ComboBox FunctionBar { get { return functionbar; } } //mxd - public Scintilla Scintilla { get { return scriptedit; } } //mxd - - #endregion - - #region ================== Contructor / Disposer - - // Constructor - public ScriptEditorControl() - { - // Initialize - InitializeComponent(); - - //mxd. ASCII with cyrillic support... - encoding = Encoding.GetEncoding(1251); - - // Script editor properties - //TODO: use ScintillaNET properties instead when they become available - scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1)); - scriptedit.DirectMessage(NativeMethods.SCI_SETMOUSEDOWNCAPTURES, new IntPtr(1)); - scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1)); - - // Symbol margin - scriptedit.Margins[0].Type = MarginType.Symbol; - scriptedit.Margins[0].Width = 20; - scriptedit.Margins[0].Mask = 1 << (int)ImageIndex.ScriptError; // Error marker only - scriptedit.Margins[0].Cursor = MarginCursor.Arrow; - scriptedit.Margins[0].Sensitive = true; - - // Line numbers margin - if (General.Settings.ScriptShowLineNumbers) - { - scriptedit.Margins[1].Type = MarginType.Number; - scriptedit.Margins[1].Width = 16; - } - scriptedit.Margins[1].Mask = 0; // No markers here - - // Spacing margin - scriptedit.Margins[2].Type = MarginType.Symbol; - scriptedit.Margins[2].Width = 5; - scriptedit.Margins[2].Cursor = MarginCursor.Arrow; - scriptedit.Margins[2].Mask = 0; // No markers here - - // Images - RegisterAutoCompleteImage(ImageIndex.ScriptConstant, Resources.ScriptConstant); - RegisterAutoCompleteImage(ImageIndex.ScriptKeyword, Resources.ScriptKeyword); - RegisterAutoCompleteImage(ImageIndex.ScriptSnippet, Resources.ScriptSnippet); //mxd - RegisterAutoCompleteImage(ImageIndex.ScriptProperty, Resources.ScriptProperty); //mxd - RegisterMarkerImage(ImageIndex.ScriptError, Resources.ScriptError); - - //mxd. These key combinations put odd characters in the script. Let's disable them - scriptedit.AssignCmdKey(Keys.Control | Keys.Q, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.W, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.E, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.R, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Y, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.U, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.I, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.P, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.A, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.D, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.G, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.H, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.J, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.K, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.L, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.Z, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.X, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.C, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.V, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.B, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.N, Command.Null); - scriptedit.AssignCmdKey(Keys.Control | Keys.M, Command.Null); - - //mxd. These key combinations are used to perform special actions. Let's disable them - scriptedit.AssignCmdKey(Keys.F3, Command.Null); // F3 for Find Next - scriptedit.AssignCmdKey(Keys.F2, Command.Null); // F2 for Find Previous - scriptedit.AssignCmdKey(Keys.Control | Keys.F, Command.Null); // CTRL+F for find & replace - scriptedit.AssignCmdKey(Keys.Control | Keys.S, Command.Null); // CTRL+S for save - scriptedit.AssignCmdKey(Keys.Control | Keys.O, Command.Null); // CTRL+O for open - scriptedit.AssignCmdKey(Keys.Control | Keys.Space, Command.Null); // CTRL+Space to autocomplete <- TODO: this doesn't seem to work... - } - - #endregion - - #region ================== Public methods - - // This launches keyword help website - public bool LaunchKeywordHelp() - { - string helpsite = scriptconfig.KeywordHelp; - string currentword = GetCurrentWord(); - if (!string.IsNullOrEmpty(currentword) && (currentword.Length > 1) && !string.IsNullOrEmpty(helpsite)) - { - currentword = scriptconfig.GetKeywordCase(currentword); - helpsite = helpsite.Replace("%K", currentword); - General.OpenWebsite(helpsite); - return true; - } - - return !string.IsNullOrEmpty(helpsite); //mxd - } - - // This replaces the selection with the given text - public void ReplaceSelection(string replacement) - { - scriptedit.ReplaceSelection(replacement); //mxd TODO: encoding check/conversion? - } - - // This moves the caret to a given line and ensures the line is visible - public void MoveToLine(int linenumber) - { - scriptedit.Lines[linenumber].Goto(); - EnsureLineVisible(linenumber); - } - - // This makes sure a line is visible - public void EnsureLineVisible(int linenumber) - { - // Determine target lines range - int startline = Math.Max(0, linenumber - 4); - int endline = Math.Min(scriptedit.Lines.Count, Math.Max(linenumber, linenumber + scriptedit.LinesOnScreen - 6)); - - // Go to target line - scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed - scriptedit.ShowLines(startline, endline); - - // We may want to do some scrolling... - if (scriptedit.FirstVisibleLine >= startline) - scriptedit.Lines[startline].Goto(); - else if (scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline) - scriptedit.Lines[endline].Goto(); - } - - //mxd - private void SelectAndShow(int startpos, int endpos) - { - // Select the result - int startline = scriptedit.LineFromPosition(startpos); - int endline = scriptedit.LineFromPosition(endpos); - - // Go to target line - scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed - scriptedit.ShowLines(startline, endline); - scriptedit.GotoPosition(startpos); - - // We may want to do some extra scrolling... - if (startline > 1 && scriptedit.FirstVisibleLine >= startline - 1) - scriptedit.Lines[startline - 1].Goto(); - else if (endline < scriptedit.Lines.Count - 1 && scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline + 1) - scriptedit.Lines[endline + 1].Goto(); - - // Update selection - scriptedit.SelectionStart = startpos; - scriptedit.SelectionEnd = endpos; - } - - // This returns the line for a position - public int LineFromPosition(int position) - { - return scriptedit.LineFromPosition(position); - } - - // This clears all marks - public void ClearMarks() - { - scriptedit.MarkerDeleteAll((int)ImageIndex.ScriptError); - } - - // This adds a mark on the given line - public void AddMark(int linenumber) - { - scriptedit.Lines[linenumber].MarkerAdd((int)ImageIndex.ScriptError); - } - - // This refreshes the style setup - public void RefreshStyle() - { - // Re-setup with the same config - SetupStyles(scriptconfig); - } - - // This sets up the script editor with a script configuration - public void SetupStyles(ScriptConfiguration config) - { - Configuration lexercfg = new Configuration(); - - // Make collections - stylelookup = new Dictionary<int, ScriptStyleType>(); - Dictionary<string, string> autocompletedict = new Dictionary<string, string>(StringComparer.Ordinal); - - // Keep script configuration - scriptconfig = config; - - // Find a resource named Lexers.cfg - string[] resnames = General.ThisAssembly.GetManifestResourceNames(); - foreach (string rn in resnames) - { - // Found one? - if (rn.EndsWith(LEXERS_RESOURCE, StringComparison.OrdinalIgnoreCase)) - { - // Get a stream from the resource - Stream lexersdata = General.ThisAssembly.GetManifestResourceStream(rn); - if (lexersdata != null) - { - StreamReader lexersreader = new StreamReader(lexersdata, Encoding.ASCII); - - // Load configuration from stream - lexercfg.InputConfiguration(lexersreader.ReadToEnd()); - - // Done with the resource - lexersreader.Dispose(); - lexersdata.Dispose(); - } - - //mxd. We are done here - break; - } - } - - //mxd. Reset document slyle - scriptedit.ClearDocumentStyle(); - scriptedit.StyleResetDefault(); - - // Check if specified lexer exists and set the lexer to use - string lexername = "lexer" + (int)scriptconfig.Lexer; - if (!lexercfg.SettingExists(lexername)) throw new InvalidOperationException("Unknown lexer " + scriptconfig.Lexer + " specified in script configuration!"); - scriptedit.Lexer = scriptconfig.Lexer; - - //mxd. Set word chars - scriptedit.SetWordChars(scriptconfig.WordCharacters); - - // Set the default style and settings - scriptedit.Styles[Style.Default].Font = General.Settings.ScriptFontName; - scriptedit.Styles[Style.Default].Size = General.Settings.ScriptFontSize; - scriptedit.Styles[Style.Default].Bold = General.Settings.ScriptFontBold; - scriptedit.Styles[Style.Default].Italic = false; - scriptedit.Styles[Style.Default].Underline = false; - scriptedit.Styles[Style.Default].Case = StyleCase.Mixed; - scriptedit.Styles[Style.Default].ForeColor = General.Colors.PlainText.ToColor(); - scriptedit.Styles[Style.Default].BackColor = General.Colors.ScriptBackground.ToColor(); - scriptedit.CaretPeriod = SystemInformation.CaretBlinkTime; - scriptedit.CaretForeColor = General.Colors.ScriptBackground.Inverse().ToColor(); - - // Set tabulation settings - scriptedit.UseTabs = General.Settings.ScriptUseTabs; - scriptedit.TabWidth = General.Settings.ScriptTabWidth; - //scriptedit.IndentWidth = General.Settings.ScriptTabWidth; // Equals to TabWidth by default - //TODO: use ScintillaNET properties instead when they become available - scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1)); - scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1)); - - // This applies the default style to all styles - scriptedit.StyleClearAll(); - - // Set the code page to use. [mxd] No longer needed? - //scriptedit.CodePage = scriptconfig.CodePage; - - //mxd. We can't change Font or Size here because this will screw displayed tab width (because it's based on character width)... - // Set the default to something normal (this is used by the autocomplete list) - //scriptedit.Styles[Style.Default].Font = this.Font.Name; - scriptedit.Styles[Style.Default].Bold = this.Font.Bold; - scriptedit.Styles[Style.Default].Italic = this.Font.Italic; - scriptedit.Styles[Style.Default].Underline = this.Font.Underline; - //scriptedit.Styles[Style.Default].Size = (int)Math.Round(this.Font.SizeInPoints); - - // Set style for linenumbers and margins - scriptedit.Styles[Style.LineNumber].BackColor = General.Colors.ScriptBackground.ToColor(); - scriptedit.SetFoldMarginColor(true, General.Colors.ScriptFoldBackColor.ToColor()); - scriptedit.SetFoldMarginHighlightColor(true, General.Colors.ScriptFoldBackColor.ToColor()); - for (int i = 25; i < 32; i++) - { - scriptedit.Markers[i].SetForeColor(General.Colors.ScriptFoldBackColor.ToColor()); - scriptedit.Markers[i].SetBackColor(General.Colors.ScriptFoldForeColor.ToColor()); - } - - //mxd. Set style for (mis)matching braces - scriptedit.Styles[Style.BraceLight].BackColor = General.Colors.ScriptBraceHighlight.ToColor(); - scriptedit.Styles[Style.BraceBad].BackColor = General.Colors.ScriptBadBraceHighlight.ToColor(); - - //mxd. Set whitespace color - scriptedit.SetWhitespaceForeColor(true, General.Colors.ScriptWhitespace.ToColor()); - - //mxd. Set selection colors - scriptedit.SetSelectionForeColor(true, General.Colors.ScriptSelectionForeColor.ToColor()); - scriptedit.SetSelectionBackColor(true, General.Colors.ScriptSelectionBackColor.ToColor()); - - // Clear all keywords - for (int i = 0; i < 9; i++) scriptedit.SetKeywords(i, null); - - // Now go for all elements in the lexer configuration - // We are looking for the numeric keys, because these are the - // style index to set and the value is our ScriptStyleType - IDictionary dic = lexercfg.ReadSetting(lexername, new Hashtable()); - foreach (DictionaryEntry de in dic) - { - // Check if this is a numeric key - int stylenum; - if (int.TryParse(de.Key.ToString(), out stylenum)) - { - // Add style to lookup table - stylelookup.Add(stylenum, (ScriptStyleType)(int)de.Value); - - // Apply color to style - int colorindex; - ScriptStyleType type = (ScriptStyleType)(int)de.Value; - switch (type) - { - case ScriptStyleType.PlainText: colorindex = ColorCollection.PLAINTEXT; break; - case ScriptStyleType.Comment: colorindex = ColorCollection.COMMENTS; break; - case ScriptStyleType.Constant: colorindex = ColorCollection.CONSTANTS; break; - case ScriptStyleType.Keyword: colorindex = ColorCollection.KEYWORDS; break; - case ScriptStyleType.LineNumber: colorindex = ColorCollection.LINENUMBERS; break; - case ScriptStyleType.Literal: colorindex = ColorCollection.LITERALS; break; - case ScriptStyleType.String: colorindex = ColorCollection.STRINGS; break; - case ScriptStyleType.Include: colorindex = ColorCollection.INCLUDES; break; - case ScriptStyleType.Property: colorindex = ColorCollection.PROPERTIES; break; - default: colorindex = ColorCollection.PLAINTEXT; break; - } - - scriptedit.Styles[stylenum].ForeColor = General.Colors.Colors[colorindex].ToColor(); - } - } - - // Create the keywords list and apply it - string imageindex = ((int)ImageIndex.ScriptKeyword).ToString(CultureInfo.InvariantCulture); - int keywordsindex = lexercfg.ReadSetting(lexername + ".keywordsindex", -1); - if (keywordsindex > -1) - { - StringBuilder keywordslist = new StringBuilder(""); - foreach (string k in scriptconfig.Keywords) - { - if (keywordslist.Length > 0) keywordslist.Append(" "); - keywordslist.Append(k); - - //mxd. Skip adding the keyword if we have a snippet with the same name - if (!scriptconfig.Snippets.Contains(k)) - autocompletedict.Add(k.ToUpperInvariant(), k + "?" + imageindex); - } - string words = keywordslist.ToString(); - scriptedit.SetKeywords(keywordsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); - } - - //mxd. Create the properties list and apply it - imageindex = ((int)ImageIndex.ScriptProperty).ToString(CultureInfo.InvariantCulture); - int propertiesindex = lexercfg.ReadSetting(lexername + ".propertiesindex", -1); - if (propertiesindex > -1) - { - StringBuilder propertieslist = new StringBuilder(""); - HashSet<string> addedprops = new HashSet<string>(); - char[] dot = new[] { '.' }; - foreach (string p in scriptconfig.Properties) - { - if (propertieslist.Length > 0) propertieslist.Append(" "); - - // Scintilla doesn't highlight keywords with '.' or ':', so get rid of those - if (scriptconfig.ScriptType == ScriptType.DECORATE) - { - string prop = p; - if (prop.Contains(":")) prop = prop.Replace(":", string.Empty); - if (prop.Contains(".")) - { - // Split dotted properties into separate entries - string[] parts = prop.Split(dot, StringSplitOptions.RemoveEmptyEntries); - List<string> result = new List<string>(); - foreach (string part in parts) - { - if (!addedprops.Contains(part)) - { - result.Add(part); - addedprops.Add(part); - } - } - - if (result.Count > 0) propertieslist.Append(string.Join(" ", result.ToArray())); - } - else - { - addedprops.Add(prop); - propertieslist.Append(prop); - } - } - else - { - propertieslist.Append(p); - } - - // Autocomplete doesn't mind '.' or ':' - autocompletedict[p.ToUpperInvariant()] = p + "?" + imageindex; - } - string words = propertieslist.ToString(); - scriptedit.SetKeywords(propertiesindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); - } - - // Create the constants list and apply it - imageindex = ((int)ImageIndex.ScriptConstant).ToString(CultureInfo.InvariantCulture); - int constantsindex = lexercfg.ReadSetting(lexername + ".constantsindex", -1); - if (constantsindex > -1) - { - StringBuilder constantslist = new StringBuilder(""); - foreach (string c in scriptconfig.Constants) - { - if (autocompletedict.ContainsKey(c.ToUpperInvariant())) //mxd. This happens when there's a keyword and a constant with the same name... - { - General.ErrorLogger.Add(ErrorType.Error, "Constant '" + c + "' is double-defined in '" + scriptconfig.Description + "' script configuration!"); - continue; - } - - if (constantslist.Length > 0) constantslist.Append(" "); - constantslist.Append(c); - - //mxd. Skip adding the constant if we have a snippet with the same name - if (!scriptconfig.Snippets.Contains(c)) - autocompletedict.Add(c.ToUpperInvariant(), c + "?" + imageindex); - } - string words = constantslist.ToString(); - scriptedit.SetKeywords(constantsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); - } - - //mxd. Create the snippets list and apply it - imageindex = ((int)ImageIndex.ScriptSnippet).ToString(CultureInfo.InvariantCulture); - int snippetindex = lexercfg.ReadSetting(lexername + ".snippetindex", -1); - if (snippetindex > -1 && scriptconfig.Snippets.Count > 0) - { - StringBuilder snippetslist = new StringBuilder(""); - foreach (string c in scriptconfig.Snippets) - { - if (autocompletedict.ContainsKey(c.ToUpperInvariant())) continue; - if (snippetslist.Length > 0) snippetslist.Append(" "); - snippetslist.Append(c); - autocompletedict.Add(c.ToUpperInvariant(), c + "?" + imageindex); - } - string words = snippetslist.ToString(); - scriptedit.SetKeywords(snippetindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); - } - - // Make autocomplete list - autocompletelist = new List<string>(autocompletedict.Values); - - // Setup folding (https://github.com/jacobslusser/ScintillaNET/wiki/Automatic-Code-Folding) - if (General.Settings.ScriptShowFolding && (scriptconfig.Lexer == Lexer.Cpp || scriptconfig.Lexer == Lexer.CppNoCase)) - { - // Instruct the lexer to calculate folding - scriptedit.SetProperty("fold", "1"); - scriptedit.SetProperty("fold.compact", "0"); // 1 = folds blank lines - scriptedit.SetProperty("fold.comment", "1"); // Enable block comment folding - scriptedit.SetProperty("fold.preprocessor", "1"); // Enable #region folding - scriptedit.SetFoldFlags(FoldFlags.LineAfterContracted); // Draw line below if not expanded - - // Configure a margin to display folding symbols - scriptedit.Margins[2].Type = MarginType.Symbol; - scriptedit.Margins[2].Mask = Marker.MaskFolders; - scriptedit.Margins[2].Sensitive = true; - scriptedit.Margins[2].Width = 12; - - // Configure folding markers with respective symbols - scriptedit.Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus; - scriptedit.Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus; - scriptedit.Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected; - scriptedit.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner; - scriptedit.Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected; - scriptedit.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine; - scriptedit.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner; - - // Enable automatic folding - scriptedit.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change); - } - else - { - // Disable folding - scriptedit.SetProperty("fold", "0"); - scriptedit.SetProperty("fold.compact", "0"); - - scriptedit.Margins[2].Type = MarginType.Symbol; - scriptedit.Margins[2].Mask = 0; // No markers here - scriptedit.Margins[2].Sensitive = false; - scriptedit.Margins[2].Width = 5; - - scriptedit.AutomaticFold = AutomaticFold.None; - } - - // Rearrange the layout - this.PerformLayout(); - } - - // This returns the current word (where the caret is at) - public string GetCurrentWord() - { - return GetWordAt(scriptedit.CurrentPosition); - } - - // This returns the word at the given position - public string GetWordAt(int position) - { - return scriptedit.GetWordFromPosition(position); - } - - // Perform undo - public void Undo() - { - scriptedit.Undo(); - } - - // Perform redo - public void Redo() - { - scriptedit.Redo(); - } - - // This clears all undo levels - public void ClearUndoRedo() - { - scriptedit.EmptyUndoBuffer(); - } - - //mxd. This marks the current document as unmodified - public void SetSavePoint() - { - scriptedit.SetSavePoint(); - } - - // Perform cut - public void Cut() - { - scriptedit.Cut(); - } - - // Perform copy - public void Copy() - { - scriptedit.Copy(); - } - - // Perform paste - public void Paste() - { - scriptedit.Paste(); - } - - // This steals the focus (use with care!) - public void GrabFocus() - { - scriptedit.Focus(); - } - - public byte[] GetText() - { - return encoding.GetBytes(scriptedit.Text); //mxd TODO: other encodings?.. - } - - public void SetText(byte[] text) - { - scriptedit.Text = encoding.GetString(text); //mxd TODO: other encodings?.. - } - - //mxd - public void InsertSnippet(string[] lines) - { - // Insert the snippet - int curline = scriptedit.LineFromPosition(scriptedit.SelectionStart); - int indent = scriptedit.Lines[scriptedit.CurrentLine].Indentation; - string tabs = Environment.NewLine + GetIndentationString(indent); - string spaces = new String(' ', General.Settings.ScriptTabWidth); - int entrypos = -1; - int entryline = -1; - string[] processedlines = ProcessLineBreaks(lines); - - // Process special chars, try to find entry position marker - for (int i = 0; i < lines.Length; i++) - { - if (!scriptedit.UseTabs) processedlines[i] = processedlines[i].Replace("\t", spaces); - - // Check if we have the [EP] marker - if (entrypos == -1) - { - int pos = processedlines[i].IndexOf("[EP]", StringComparison.Ordinal); - if (pos != -1) - { - processedlines[i] = processedlines[i].Remove(pos, 4); - entryline = curline + i; - entrypos = processedlines[i].Length - pos; - } - } - } - - // Replace the text - string text = string.Join(tabs, processedlines); - scriptedit.SelectionStart = scriptedit.WordStartPosition(scriptedit.CurrentPosition, true); - scriptedit.SelectionEnd = scriptedit.WordEndPosition(scriptedit.CurrentPosition, true); - scriptedit.ReplaceSelection(text); - - // Move the cursor if we had the [EP] marker - if (entrypos != -1) - { - scriptedit.SetEmptySelection(scriptedit.Lines[entryline].EndPosition - entrypos - 2); - } - } - - //mxd. Find next result - public bool FindNext(FindReplaceOptions options, bool useselectionstart) - { - int startpos = (useselectionstart ? Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) : Math.Max(scriptedit.SelectionStart, scriptedit.SelectionEnd)); - - // Search the document - scriptedit.TargetStart = startpos; - scriptedit.TargetEnd = scriptedit.TextLength; - scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None; - if (options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord; - - int result = scriptedit.SearchInTarget(options.FindText); - - // Wrap around? - if (result == -1) - { - scriptedit.TargetStart = 0; - scriptedit.TargetEnd = startpos; - result = scriptedit.SearchInTarget(options.FindText); - } - - // Found something - if (result != -1) - { - // Select the result - SelectAndShow(result, result + options.FindText.Length); - - // Update extra highlights - HighlightWord(options.FindText); - - // All done - return true; - } - - // Nothing found... - return false; - } - - //mxd. Find previous result - public bool FindPrevious(FindReplaceOptions options) - { - int endpos = Math.Max(0, Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) - 1); - - // Search the document - scriptedit.TargetStart = endpos; - scriptedit.TargetEnd = 0; - scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None; - if (options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord; - - int result = scriptedit.SearchInTarget(options.FindText); - - // Wrap around? - if (result == -1) - { - scriptedit.TargetStart = scriptedit.TextLength; - scriptedit.TargetEnd = endpos; - result = scriptedit.SearchInTarget(options.FindText); - } - - // Found something - if (result != -1) - { - // Select the result - SelectAndShow(result, result + options.FindText.Length); - - // Update extra highlights - HighlightWord(options.FindText); - - // All done - return true; - } - - // Nothing found... - return false; - } - - //mxd. (Un)indents selection - public void IndentSelection(bool indent) - { - // Get selected range of lines - int startline = scriptedit.LineFromPosition(scriptedit.SelectionStart); - int endline = scriptedit.LineFromPosition(scriptedit.SelectionEnd); - - for (int i = startline; i < endline + 1; i++) - { - scriptedit.Lines[i].Indentation += (indent ? General.Settings.ScriptTabWidth : -General.Settings.ScriptTabWidth); - } - } - - #endregion - - #region ================== Utility methods - - // This returns the ScriptStyleType for a given Scintilla style - private ScriptStyleType GetScriptStyle(int scintillastyle) - { - return (stylelookup.ContainsKey(scintillastyle) ? stylelookup[scintillastyle] : ScriptStyleType.PlainText); - } - - // This gathers information about the current caret position - private void UpdatePositionInfo() - { - int bracketlevel = 0; // bracket level counting - int argindex = 0; // function argument counting - int pos = scriptedit.CurrentPosition; - - // Get the text - string scripttext = scriptedit.Text; - - // Reset position info - curfunctionname = ""; - curargumentindex = 0; - curfunctionstartpos = 0; - - // Determine lowest backtrack position - int limitpos = scriptedit.CurrentPosition - MAX_BACKTRACK_LENGTH; - if (limitpos < 0) limitpos = 0; - - // We can only do this when we have function syntax information - if ((scriptconfig.ArgumentDelimiter.Length == 0) || (scriptconfig.FunctionClose.Length == 0) || - (scriptconfig.FunctionOpen.Length == 0) || (scriptconfig.Terminator.Length == 0)) return; - - // Get int versions of the function syntax informantion - int argumentdelimiter = scriptconfig.ArgumentDelimiter[0]; - int functionclose = scriptconfig.FunctionClose[0]; - int functionopen = scriptconfig.FunctionOpen[0]; - int terminator = scriptconfig.Terminator[0]; - - // Continue backtracking until we reached the limitpos - while (pos >= limitpos) - { - // Backtrack 1 character - pos--; - - // Get the style and character at this position - ScriptStyleType curstyle = GetScriptStyle(scriptedit.GetStyleAt(pos)); - int curchar = scriptedit.GetCharAt(pos); - - // Then meeting ) then increase bracket level - // When meeting ( then decrease bracket level - // When bracket level goes -1, then the next word should be the function name - // Only when at bracket level 0, count the comma's for argument index - - // TODO: - // Original code checked for scope character here and breaks if found - - // Check if in plain text or keyword - if ((curstyle == ScriptStyleType.PlainText) || (curstyle == ScriptStyleType.Keyword)) - { - // Closing bracket - if (curchar == functionclose) - { - bracketlevel++; - } - // Opening bracket - else if (curchar == functionopen) - { - bracketlevel--; - - // Out of the brackets? - if (bracketlevel < 0) - { - // Skip any whitespace before this bracket - do - { - // Backtrack 1 character - curchar = scriptedit.GetCharAt(--pos); - } - while ((pos >= limitpos) && ((curchar == ' ') || (curchar == '\t') || - (curchar == '\r') || (curchar == '\n'))); - - // NOTE: We may need to set onlyWordCharacters argument in the - // following calls to false to get any argument delimiter included, - // but this may also cause a valid keyword to be combined with other - // surrounding characters that do not belong to the keyword. - - // Find the word before this bracket - int wordstart = scriptedit.WordStartPosition(pos, true); - int wordend = scriptedit.WordEndPosition(pos, true); - string word = scripttext.Substring(wordstart, wordend - wordstart); - if (word.Length > 0) - { - // Check if this is an argument delimiter - // I can't remember why I did this, but I'll probably stumble - // upon the problem if this doesn't work right (see note above) - if (word[0] == argumentdelimiter) - { - // We are now in the parent function - bracketlevel++; - argindex = 0; - } - // Now check if this is a keyword - else if (scriptconfig.IsKeyword(word)) - { - // Found it! - curfunctionname = scriptconfig.GetKeywordCase(word); - curargumentindex = argindex; - curfunctionstartpos = wordstart; - break; - } - else - { - // Don't know this word - break; - } - } - } - } - // Argument delimiter - else if (curchar == argumentdelimiter) - { - // Only count these at brackt level 0 - if (bracketlevel == 0) argindex++; - } - // Terminator - else if (curchar == terminator) - { - // Can't find anything, break now - break; - } - } - } - } - - // This registers an image for the autocomplete list - private void RegisterAutoCompleteImage(ImageIndex index, Bitmap image) - { - // Register image - scriptedit.RegisterRgbaImage((int)index, image); - } - - // This registers an image for the markes list - private void RegisterMarkerImage(ImageIndex index, Bitmap image) - { - // Register image - scriptedit.Markers[(int)index].DefineRgbaImage(image); - scriptedit.Markers[(int)index].Symbol = MarkerSymbol.RgbaImage; - } - - //mxd. This converts [LB] markers to line breaks if necessary - private static string[] ProcessLineBreaks(string[] lines) - { - List<string> result = new List<string>(lines.Length); - string[] separator = new[] { "[LB]" }; - - foreach (string line in lines) - { - if (line.IndexOf(separator[0], StringComparison.Ordinal) != -1) - { - if (General.Settings.ScriptAllmanStyle) - result.AddRange(line.Split(separator, StringSplitOptions.RemoveEmptyEntries)); - else - result.Add(line.Replace(separator[0], " ")); - } - else - { - result.Add(line); - } - } - - return result.ToArray(); - } - - //mxd. Autocompletion handling (https://github.com/jacobslusser/ScintillaNET/wiki/Basic-Autocompletion) - private bool ShowAutoCompletionList() - { - int currentpos = scriptedit.CurrentPosition; - int wordstartpos = scriptedit.WordStartPosition(currentpos, true); - - if (wordstartpos >= currentpos) - { - // Hide the list - scriptedit.AutoCCancel(); - return false; - } - - // Get entered text - string start = scriptedit.GetTextRange(wordstartpos, currentpos - wordstartpos); - if (string.IsNullOrEmpty(start)) - { - // Hide the list - scriptedit.AutoCCancel(); - return false; - } - - // Filter the list - List<string> filtered = new List<string>(); - foreach (string s in autocompletelist) - if (s.IndexOf(start, StringComparison.OrdinalIgnoreCase) != -1) filtered.Add(s); - - // Any matches? - if (filtered.Count > 0) - { - // Show the list - scriptedit.AutoCShow(currentpos - wordstartpos, string.Join(" ", filtered.ToArray())); - return true; - } - - // Hide the list - scriptedit.AutoCCancel(); - return false; - } - - //mxd - private string GetIndentationString(int indent) - { - if (scriptedit.UseTabs) - { - string indentstr = string.Empty; - int numtabs = indent / scriptedit.TabWidth; - if (numtabs > 0) indentstr = new string('\t', numtabs); - - // Mixed padding? Add spaces - if (numtabs * scriptedit.TabWidth < indent) - { - int numspaces = indent - numtabs * scriptedit.TabWidth; - indentstr += new string(' ', numspaces); - } - - return indentstr; - } - else - { - return new string(' ', indent); - } - } - - //mxd. https://github.com/jacobslusser/ScintillaNET/wiki/Find-and-Highlight-Words - private void HighlightWord(string text) - { - // Remove all uses of our indicator - scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR; - scriptedit.IndicatorClearRange(0, scriptedit.TextLength); - - // Update indicator appearance - scriptedit.Indicators[HIGHLIGHT_INDICATOR].Style = IndicatorStyle.RoundBox; - scriptedit.Indicators[HIGHLIGHT_INDICATOR].Under = true; - scriptedit.Indicators[HIGHLIGHT_INDICATOR].ForeColor = General.Colors.ScriptIndicator.ToColor(); - scriptedit.Indicators[HIGHLIGHT_INDICATOR].OutlineAlpha = 50; - scriptedit.Indicators[HIGHLIGHT_INDICATOR].Alpha = 30; - - // Search the document - scriptedit.TargetStart = 0; - scriptedit.TargetEnd = scriptedit.TextLength; - scriptedit.SearchFlags = SearchFlags.WholeWord; - - while (scriptedit.SearchInTarget(text) != -1) - { - //mxd. Don't mark currently selected word - if (scriptedit.SelectionStart != scriptedit.TargetStart && scriptedit.SelectionEnd != scriptedit.TargetEnd) - { - // Mark the search results with the current indicator - scriptedit.IndicatorFillRange(scriptedit.TargetStart, scriptedit.TargetEnd - scriptedit.TargetStart); - } - - // Search the remainder of the document - scriptedit.TargetStart = scriptedit.TargetEnd; - scriptedit.TargetEnd = scriptedit.TextLength; - } - } - - #endregion - - #region ================== Events - - // Layout needs to be re-organized - protected override void OnLayout(LayoutEventArgs e) - { - base.OnLayout(e); - - // With or without functions bar? - if (functionbar.Visible) - { - scriptpanel.Top = functionbar.Bottom + 6; - scriptpanel.Height = this.ClientSize.Height - scriptpanel.Top; - } - else - { - scriptpanel.Top = 0; - scriptpanel.Height = this.ClientSize.Height; - } - } - - //mxd. Script text changed - private void scriptedit_TextChanged(object sender, EventArgs e) - { - // Line number margin width needs changing? - int curlinenumbercharlength = scriptedit.Lines.Count.ToString().Length; - - // Calculate the width required to display the last line number - // and include some padding for good measure. - if (curlinenumbercharlength != linenumbercharlength) - { - const int padding = 2; - scriptedit.Margins[1].Width = scriptedit.TextWidth(Style.LineNumber, new string('9', curlinenumbercharlength + 1)) + padding; - linenumbercharlength = curlinenumbercharlength; - } - - if (OnTextChanged != null) OnTextChanged(this, EventArgs.Empty); - } - - //mxd - private void scriptedit_CharAdded(object sender, CharAddedEventArgs e) - { - // Hide call tip if any - scriptedit.CallTipCancel(); - - // Offset caret if needed - if (caretoffset != 0) - { - scriptedit.SetEmptySelection(scriptedit.SelectionStart + caretoffset); - caretoffset = 0; - if (!expandcodeblock) return; - } - - // Move CodeBlockOpen to the new line? - if (expandcodeblock) - { - if (scriptedit.CurrentLine > 0) - { - string linetext = scriptedit.Lines[scriptedit.CurrentLine - 1].Text; - int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, StringComparison.Ordinal)); - if (blockopenpos != -1) - { - // Do it only if initial line doesn't start with CodeBlockOpen - string linestart = linetext.Substring(0, blockopenpos).Trim(); - if (linestart.Length > 0) - { - scriptedit.InsertText(scriptedit.Lines[scriptedit.CurrentLine - 1].Position + blockopenpos, - Environment.NewLine + GetIndentationString(scriptedit.Lines[scriptedit.CurrentLine - 1].Indentation)); - } - } - } - - expandcodeblock = false; - return; - } - - // Auto-match braces - if (General.Settings.ScriptAutoCloseBrackets) - { - //TODO: Auto-match quotes - bool endpos = (scriptedit.CurrentPosition == scriptedit.TextLength); - if (!string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) && e.Char == scriptconfig.CodeBlockOpen[0] && !string.IsNullOrEmpty(scriptconfig.CodeBlockClose) && - (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.CodeBlockClose[0])) - { - scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.CodeBlockClose); - return; - } - - if (!string.IsNullOrEmpty(scriptconfig.FunctionOpen) && e.Char == scriptconfig.FunctionOpen[0] && !string.IsNullOrEmpty(scriptconfig.FunctionClose) && - (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.FunctionClose[0])) - { - scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.FunctionClose); - return; - } - - if (!string.IsNullOrEmpty(scriptconfig.ArrayOpen) && e.Char == scriptconfig.ArrayOpen[0] && !string.IsNullOrEmpty(scriptconfig.ArrayClose) && - (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.ArrayClose[0])) - { - scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.ArrayClose); - return; - } - } - - if (General.Settings.ScriptAutoShowAutocompletion) - { - // Display the autocompletion list - ShowAutoCompletionList(); - } - } - - //mxd - private void scriptedit_UpdateUI(object sender, UpdateUIEventArgs e) - { - // If a word is selected, highlight the same words - if (scriptedit.SelectedText != highlightedword) - { - // Highlight only when whole word is selected - if (!string.IsNullOrEmpty(scriptedit.SelectedText) && scriptedit.GetWordFromPosition(scriptedit.SelectionStart) == scriptedit.SelectedText) - { - HighlightWord(scriptedit.SelectedText); - } - else - { - // Clear highlight - scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR; - scriptedit.IndicatorClearRange(0, scriptedit.TextLength); - } - - highlightedword = scriptedit.SelectedText; - } - - // Has the caret changed position? - int caretpos = scriptedit.CurrentPosition; - if (lastcaretpos != caretpos && scriptconfig.BraceChars.Count > 0) - { - // Perform brace matching (https://github.com/jacobslusser/ScintillaNET/wiki/Brace-Matching) - lastcaretpos = caretpos; - int bracepos1 = -1; - - // Is there a brace to the left or right? - if (caretpos > 0 && scriptconfig.BraceChars.Contains((char)scriptedit.GetCharAt(caretpos - 1))) - bracepos1 = (caretpos - 1); - else if (scriptconfig.BraceChars.Contains((char)(scriptedit.GetCharAt(caretpos)))) - bracepos1 = caretpos; - - if (bracepos1 > -1) - { - // Find the matching brace - int bracepos2 = scriptedit.BraceMatch(bracepos1); - if (bracepos2 == Scintilla.InvalidPosition) - scriptedit.BraceBadLight(bracepos1); - else - scriptedit.BraceHighlight(bracepos1, bracepos2); - } - else - { - // Turn off brace matching - scriptedit.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition); - } - } - } - - //mxd - private void scriptedit_InsertCheck(object sender, InsertCheckEventArgs e) - { - // Gross hacks... - if (skiptextinsert) - { - e.Text = string.Empty; - skiptextinsert = false; - } - // Do we want auto-indentation? - else if (!expandcodeblock && General.Settings.ScriptAutoIndent && e.Text == "\r\n") - { - // Get current line indentation up to the cursor position - string linetext = scriptedit.Lines[scriptedit.CurrentLine].Text; - int selectionpos = scriptedit.SelectionStart - scriptedit.Lines[scriptedit.CurrentLine].Position; - int indent = 0; - for (int i = 0; i < selectionpos; i++) - { - switch (linetext[i]) - { - case ' ': indent++; break; - case '\t': indent += scriptedit.TabWidth; break; - default: i = selectionpos; break; // break the loop - } - } - - // Store initial indentation - int initialindent = indent; - - // Need to increase indentation? We do this when: - // 1. Line contains '{' and '}' and the cursor is between them - // 2. Line either doesn't contain '}', or it's before '{', or the line contains '{' and the cursor is after it - int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, selectionpos, StringComparison.Ordinal)); - int blockclosepos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.IndexOf(scriptconfig.CodeBlockClose, selectionpos, StringComparison.Ordinal)); - - // Add indentation when the cursor is between { and } - bool addindent = (blockopenpos != -1 && blockopenpos < selectionpos) && (blockclosepos == -1 || (blockopenpos < blockclosepos && blockclosepos >= selectionpos)); - if (addindent) indent += scriptedit.TabWidth; - - // Calculate indentation - string indentstr = GetIndentationString(indent); - - // Move CodeBlockOpen to the new line? (will be applied in scriptedit_CharAdded) - expandcodeblock = General.Settings.ScriptAllmanStyle; - - // Offset closing block char? - if (addindent && blockclosepos != -1) - { - string initialindentstr = GetIndentationString(initialindent); - indentstr += Environment.NewLine + initialindentstr; - - // Offset cursor position (will be performed in scriptedit_CharAdded) - caretoffset = -(initialindentstr.Length + Environment.NewLine.Length); - } - - // Apply new indentation - e.Text += indentstr; - } - } - - //mxd - private void scriptedit_AutoCCompleted(object sender, AutoCSelectionEventArgs e) - { - // Expand snippet? - string[] lines = scriptconfig.GetSnippet(e.Text); - if (lines != null) InsertSnippet(lines); - } - - // Key pressed down - private void scriptedit_KeyDown(object sender, KeyEventArgs e) - { - // F3 for Find Next - if ((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None)) - { - if (OnFindNext != null) OnFindNext(); - } - // F2 for Find Previous (mxd) - else if ((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None)) - { - if (OnFindPrevious != null) OnFindPrevious(); - } - // CTRL+F for find & replace - else if ((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control)) - { - if (OnOpenFindAndReplace != null) OnOpenFindAndReplace(); - } - // CTRL+S for save - else if ((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control)) - { - if (OnExplicitSaveTab != null) OnExplicitSaveTab(); - } - // CTRL+O for open - else if ((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control)) - { - if (OnOpenScriptBrowser != null) OnOpenScriptBrowser(); - } - // CTRL+Space to autocomplete - else if ((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control)) - { - // Hide call tip if any - scriptedit.CallTipCancel(); - - // Show autocomplete - if (ShowAutoCompletionList()) skiptextinsert = true; - } - //mxd. Tab to expand code snippet. Do it only when the text cursor is at the end of a keyword. - else if (e.KeyCode == Keys.Tab) - { - if (!scriptedit.AutoCActive) - { - string curword = GetCurrentWord().ToLowerInvariant(); - if (scriptconfig.Snippets.Contains(curword) && scriptedit.CurrentPosition == scriptedit.WordEndPosition(scriptedit.CurrentPosition, true)) - { - InsertSnippet(scriptconfig.GetSnippet(curword)); - skiptextinsert = true; - } - } - } - else - { - //mxd. Skip text insert when "save screenshot" action's keys are pressed - Actions.Action[] actions = General.Actions.GetActionsByKey((int)e.KeyData); - foreach (Actions.Action action in actions) - { - if (action.ShortName == "savescreenshot" || action.ShortName == "saveeditareascreenshot") - { - skiptextinsert = true; - return; - } - } - } - } - - // Key released - private void scriptedit_KeyUp(object sender, KeyEventArgs e) - { - bool showcalltip = false; - int highlightstart = 0; - int highlightend = 0; - - UpdatePositionInfo(); - - // Call tip shown - if (scriptedit.CallTipActive) - { - // Should we hide the call tip? - if (curfunctionname.Length == 0) - { - // Hide the call tip - scriptedit.CallTipCancel(); - } - else - { - // Update the call tip - showcalltip = true; - } - } - // No call tip - else - { - // Should we show a call tip? - showcalltip = (curfunctionname.Length > 0) && !scriptedit.AutoCActive; - } - - // Show or update call tip - if (showcalltip) - { - string functiondef = scriptconfig.GetFunctionDefinition(curfunctionname); - if (functiondef != null) - { - // Determine the range to highlight - int argsopenpos = functiondef.IndexOf(scriptconfig.FunctionOpen, StringComparison.Ordinal); - int argsclosepos = functiondef.LastIndexOf(scriptconfig.FunctionClose, StringComparison.Ordinal); - if ((argsopenpos > -1) && (argsclosepos > -1)) - { - string argsstr = functiondef.Substring(argsopenpos + 1, argsclosepos - argsopenpos - 1); - string[] args = argsstr.Split(scriptconfig.ArgumentDelimiter[0]); - if ((curargumentindex >= 0) && (curargumentindex < args.Length)) - { - int argoffset = 0; - for (int i = 0; i < curargumentindex; i++) argoffset += args[i].Length + 1; - highlightstart = argsopenpos + argoffset + 1; - highlightend = highlightstart + args[curargumentindex].Length; - } - } - - //mxd. If the tip obscures the view, move it down - int tippos; - int funcline = scriptedit.LineFromPosition(curfunctionstartpos); - if (scriptedit.CurrentLine > funcline) - tippos = scriptedit.Lines[scriptedit.CurrentLine].Position + scriptedit.Lines[scriptedit.CurrentLine].Indentation; //scriptedit.PositionFromLine(curline) /*+ (curfunctionstartpos - scriptedit.PositionFromLine(funcline))*/; - else - tippos = curfunctionstartpos; - - // Show tip - scriptedit.CallTipShow(tippos, functiondef); - scriptedit.CallTipSetHlt(highlightstart, highlightend); - } - } - } - - #endregion - } -} \ No newline at end of file + internal enum ScriptStyleType + { + PlainText = 0, + Keyword = 1, + Constant = 2, + Comment = 3, + Literal = 4, + LineNumber = 5, + String = 6, //mxd + Include = 7, //mxd + Property = 8, //mxd + } + + internal partial class ScriptEditorControl : UserControl + { + #region ================== Enums + + // Index for registered images + private enum ImageIndex + { + ScriptConstant = 0, + ScriptKeyword = 1, + ScriptError = 2, + ScriptSnippet = 3, //mxd + ScriptProperty = 4, //mxd + } + + #endregion + + #region ================== Constants + + private const string LEXERS_RESOURCE = "Lexers.cfg"; + private const int MAX_BACKTRACK_LENGTH = 200; + private const int HIGHLIGHT_INDICATOR = 8; //mxd. Indicators 0-7 could be in use by a lexer so we'll use indicator 8 to highlight words. + + #endregion + + #region ================== Delegates / Events + + public delegate void ExplicitSaveTabDelegate(); + public delegate void OpenScriptBrowserDelegate(); + public delegate void OpenFindReplaceDelegate(); + public delegate void FindNextDelegate(); + public delegate void FindPreviousDelegate(); //mxd + + public event ExplicitSaveTabDelegate OnExplicitSaveTab; + public event OpenScriptBrowserDelegate OnOpenScriptBrowser; + public event OpenFindReplaceDelegate OnOpenFindAndReplace; + public event FindNextDelegate OnFindNext; + public event FindPreviousDelegate OnFindPrevious; //mxd + public new event EventHandler OnTextChanged; //mxd + + #endregion + + #region ================== Variables + + // Script configuration + private ScriptConfiguration scriptconfig; + + // List of keywords and constants + private List<string> autocompletelist; + + // Style translation from Scintilla style to ScriptStyleType + private Dictionary<int, ScriptStyleType> stylelookup; + + // Current position information + private string curfunctionname = ""; + private int curargumentindex; + private int curfunctionstartpos; + private int linenumbercharlength; //mxd. Current max number of chars in the line number + private int lastcaretpos; //mxd. Used in brace matching + private int caretoffset; //mxd. Used to modify caret position after autogenerating stuff + private bool skiptextinsert; //mxd. Gross hacks + private bool expandcodeblock; //mxd. More gross hacks + private string highlightedword; //mxd + private Encoding encoding; //mxd + + #endregion + + #region ================== Properties + + public bool IsChanged { get { return scriptedit.Modified; } } + public int SelectionStart { get { return scriptedit.SelectionStart; } set { scriptedit.SelectionStart = value; } } + public int SelectionEnd { get { return scriptedit.SelectionEnd; } set { scriptedit.SelectionEnd = value; } } + public new string Text { get { return scriptedit.Text; } set { scriptedit.Text = value; } } //mxd + public string SelectedText { get { return scriptedit.SelectedText; } } //mxd + public bool ShowWhitespace { get { return scriptedit.ViewWhitespace != WhitespaceMode.Invisible; } set { scriptedit.ViewWhitespace = value ? WhitespaceMode.VisibleAlways : WhitespaceMode.Invisible; } } + public bool WrapLongLines { get { return scriptedit.WrapMode != WrapMode.None; } set { scriptedit.WrapMode = (value ? WrapMode.Char : WrapMode.None); } } + public ComboBox FunctionBar { get { return functionbar; } } //mxd + public Scintilla Scintilla { get { return scriptedit; } } //mxd + + #endregion + + #region ================== Contructor / Disposer + + // Constructor + public ScriptEditorControl() + { + // Initialize + InitializeComponent(); + + //mxd. ASCII with cyrillic support... + encoding = Encoding.GetEncoding(1251); + + // Script editor properties + //TODO: use ScintillaNET properties instead when they become available + scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1)); + scriptedit.DirectMessage(NativeMethods.SCI_SETMOUSEDOWNCAPTURES, new IntPtr(1)); + scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1)); + + // Symbol margin + scriptedit.Margins[0].Type = MarginType.Symbol; + scriptedit.Margins[0].Width = 20; + scriptedit.Margins[0].Mask = 1 << (int)ImageIndex.ScriptError; // Error marker only + scriptedit.Margins[0].Cursor = MarginCursor.Arrow; + scriptedit.Margins[0].Sensitive = true; + + // Line numbers margin + if(General.Settings.ScriptShowLineNumbers) + { + scriptedit.Margins[1].Type = MarginType.Number; + scriptedit.Margins[1].Width = 16; + } + scriptedit.Margins[1].Mask = 0; // No markers here + + // Spacing margin + scriptedit.Margins[2].Type = MarginType.Symbol; + scriptedit.Margins[2].Width = 5; + scriptedit.Margins[2].Cursor = MarginCursor.Arrow; + scriptedit.Margins[2].Mask = 0; // No markers here + + // Images + RegisterAutoCompleteImage(ImageIndex.ScriptConstant, Resources.ScriptConstant); + RegisterAutoCompleteImage(ImageIndex.ScriptKeyword, Resources.ScriptKeyword); + RegisterAutoCompleteImage(ImageIndex.ScriptSnippet, Resources.ScriptSnippet); //mxd + RegisterAutoCompleteImage(ImageIndex.ScriptProperty, Resources.ScriptProperty); //mxd + RegisterMarkerImage(ImageIndex.ScriptError, Resources.ScriptError); + + //mxd. These key combinations put odd characters in the script. Let's disable them + scriptedit.AssignCmdKey(Keys.Control | Keys.Q, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.W, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.E, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.R, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Y, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.U, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.I, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.P, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.A, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.D, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.G, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.H, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.J, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.K, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.L, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.Z, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.X, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.C, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.Shift | Keys.V, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.B, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.N, Command.Null); + scriptedit.AssignCmdKey(Keys.Control | Keys.M, Command.Null); + + //mxd. These key combinations are used to perform special actions. Let's disable them + scriptedit.AssignCmdKey(Keys.F3, Command.Null); // F3 for Find Next + scriptedit.AssignCmdKey(Keys.F2, Command.Null); // F2 for Find Previous + scriptedit.AssignCmdKey(Keys.Control | Keys.F, Command.Null); // CTRL+F for find & replace + scriptedit.AssignCmdKey(Keys.Control | Keys.S, Command.Null); // CTRL+S for save + scriptedit.AssignCmdKey(Keys.Control | Keys.O, Command.Null); // CTRL+O for open + scriptedit.AssignCmdKey(Keys.Control | Keys.Space, Command.Null); // CTRL+Space to autocomplete <- TODO: this doesn't seem to work... + } + + #endregion + + #region ================== Public methods + + // This launches keyword help website + public bool LaunchKeywordHelp() + { + string helpsite = scriptconfig.KeywordHelp; + string currentword = GetCurrentWord(); + if(!string.IsNullOrEmpty(currentword) && (currentword.Length > 1) && !string.IsNullOrEmpty(helpsite)) + { + currentword = scriptconfig.GetKeywordCase(currentword); + helpsite = helpsite.Replace("%K", currentword); + General.OpenWebsite(helpsite); + return true; + } + + return !string.IsNullOrEmpty(helpsite); //mxd + } + + // This replaces the selection with the given text + public void ReplaceSelection(string replacement) + { + scriptedit.ReplaceSelection(replacement); //mxd TODO: encoding check/conversion? + } + + // This moves the caret to a given line and ensures the line is visible + public void MoveToLine(int linenumber) + { + scriptedit.Lines[linenumber].Goto(); + EnsureLineVisible(linenumber); + } + + // This makes sure a line is visible + public void EnsureLineVisible(int linenumber) + { + // Determine target lines range + int startline = Math.Max(0, linenumber - 4); + int endline = Math.Min(scriptedit.Lines.Count, Math.Max(linenumber, linenumber + scriptedit.LinesOnScreen - 6)); + + // Go to target line + scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed + scriptedit.ShowLines(startline, endline); + + // We may want to do some scrolling... + if(scriptedit.FirstVisibleLine >= startline) + scriptedit.Lines[startline].Goto(); + else if(scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline) + scriptedit.Lines[endline].Goto(); + } + + //mxd + private void SelectAndShow(int startpos, int endpos) + { + // Select the result + int startline = scriptedit.LineFromPosition(startpos); + int endline = scriptedit.LineFromPosition(endpos); + + // Go to target line + scriptedit.DirectMessage(NativeMethods.SCI_ENSUREVISIBLEENFORCEPOLICY, (IntPtr)startline); // Unfold the whole text block if needed + scriptedit.ShowLines(startline, endline); + scriptedit.GotoPosition(startpos); + + // We may want to do some extra scrolling... + if(startline > 1 && scriptedit.FirstVisibleLine >= startline - 1) + scriptedit.Lines[startline - 1].Goto(); + else if(endline < scriptedit.Lines.Count - 1 && scriptedit.FirstVisibleLine + scriptedit.LinesOnScreen <= endline + 1) + scriptedit.Lines[endline + 1].Goto(); + + // Update selection + scriptedit.SelectionStart = startpos; + scriptedit.SelectionEnd = endpos; + } + + // This returns the line for a position + public int LineFromPosition(int position) + { + return scriptedit.LineFromPosition(position); + } + + // This clears all marks + public void ClearMarks() + { + scriptedit.MarkerDeleteAll((int)ImageIndex.ScriptError); + } + + // This adds a mark on the given line + public void AddMark(int linenumber) + { + scriptedit.Lines[linenumber].MarkerAdd((int)ImageIndex.ScriptError); + } + + // This refreshes the style setup + public void RefreshStyle() + { + // Re-setup with the same config + SetupStyles(scriptconfig); + } + + // This sets up the script editor with a script configuration + public void SetupStyles(ScriptConfiguration config) + { + Configuration lexercfg = new Configuration(); + + // Make collections + stylelookup = new Dictionary<int, ScriptStyleType>(); + Dictionary<string, string> autocompletedict = new Dictionary<string, string>(StringComparer.Ordinal); + + // Keep script configuration + scriptconfig = config; + + // Find a resource named Lexers.cfg + string[] resnames = General.ThisAssembly.GetManifestResourceNames(); + foreach(string rn in resnames) + { + // Found one? + if(rn.EndsWith(LEXERS_RESOURCE, StringComparison.OrdinalIgnoreCase)) + { + // Get a stream from the resource + Stream lexersdata = General.ThisAssembly.GetManifestResourceStream(rn); + if(lexersdata != null) + { + StreamReader lexersreader = new StreamReader(lexersdata, Encoding.ASCII); + + // Load configuration from stream + lexercfg.InputConfiguration(lexersreader.ReadToEnd()); + + // Done with the resource + lexersreader.Dispose(); + lexersdata.Dispose(); + } + + //mxd. We are done here + break; + } + } + + //mxd. Reset document slyle + scriptedit.ClearDocumentStyle(); + scriptedit.StyleResetDefault(); + + // Check if specified lexer exists and set the lexer to use + string lexername = "lexer" + (int)scriptconfig.Lexer; + if(!lexercfg.SettingExists(lexername)) throw new InvalidOperationException("Unknown lexer " + scriptconfig.Lexer + " specified in script configuration!"); + scriptedit.Lexer = scriptconfig.Lexer; + + //mxd. Set word chars + scriptedit.SetWordChars(scriptconfig.WordCharacters); + + // Set the default style and settings + scriptedit.Styles[Style.Default].Font = General.Settings.ScriptFontName; + scriptedit.Styles[Style.Default].Size = General.Settings.ScriptFontSize; + scriptedit.Styles[Style.Default].Bold = General.Settings.ScriptFontBold; + scriptedit.Styles[Style.Default].Italic = false; + scriptedit.Styles[Style.Default].Underline = false; + scriptedit.Styles[Style.Default].Case = StyleCase.Mixed; + scriptedit.Styles[Style.Default].ForeColor = General.Colors.PlainText.ToColor(); + scriptedit.Styles[Style.Default].BackColor = General.Colors.ScriptBackground.ToColor(); + scriptedit.CaretPeriod = SystemInformation.CaretBlinkTime; + scriptedit.CaretForeColor = General.Colors.ScriptBackground.Inverse().ToColor(); + + // Set tabulation settings + scriptedit.UseTabs = General.Settings.ScriptUseTabs; + scriptedit.TabWidth = General.Settings.ScriptTabWidth; + //scriptedit.IndentWidth = General.Settings.ScriptTabWidth; // Equals to TabWidth by default + //TODO: use ScintillaNET properties instead when they become available + scriptedit.DirectMessage(NativeMethods.SCI_SETTABINDENTS, new IntPtr(1)); + scriptedit.DirectMessage(NativeMethods.SCI_SETBACKSPACEUNINDENTS, new IntPtr(1)); + + // This applies the default style to all styles + scriptedit.StyleClearAll(); + + // Set the code page to use. [mxd] No longer needed? + //scriptedit.CodePage = scriptconfig.CodePage; + + //mxd. We can't change Font or Size here because this will screw displayed tab width (because it's based on character width)... + // Set the default to something normal (this is used by the autocomplete list) + //scriptedit.Styles[Style.Default].Font = this.Font.Name; + scriptedit.Styles[Style.Default].Bold = this.Font.Bold; + scriptedit.Styles[Style.Default].Italic = this.Font.Italic; + scriptedit.Styles[Style.Default].Underline = this.Font.Underline; + //scriptedit.Styles[Style.Default].Size = (int)Math.Round(this.Font.SizeInPoints); + + // Set style for linenumbers and margins + scriptedit.Styles[Style.LineNumber].BackColor = General.Colors.ScriptBackground.ToColor(); + scriptedit.SetFoldMarginColor(true, General.Colors.ScriptFoldBackColor.ToColor()); + scriptedit.SetFoldMarginHighlightColor(true, General.Colors.ScriptFoldBackColor.ToColor()); + for(int i = 25; i < 32; i++) + { + scriptedit.Markers[i].SetForeColor(General.Colors.ScriptFoldBackColor.ToColor()); + scriptedit.Markers[i].SetBackColor(General.Colors.ScriptFoldForeColor.ToColor()); + } + + //mxd. Set style for (mis)matching braces + scriptedit.Styles[Style.BraceLight].BackColor = General.Colors.ScriptBraceHighlight.ToColor(); + scriptedit.Styles[Style.BraceBad].BackColor = General.Colors.ScriptBadBraceHighlight.ToColor(); + + //mxd. Set whitespace color + scriptedit.SetWhitespaceForeColor(true, General.Colors.ScriptWhitespace.ToColor()); + + //mxd. Set selection colors + scriptedit.SetSelectionForeColor(true, General.Colors.ScriptSelectionForeColor.ToColor()); + scriptedit.SetSelectionBackColor(true, General.Colors.ScriptSelectionBackColor.ToColor()); + + // Clear all keywords + for(int i = 0; i < 9; i++) scriptedit.SetKeywords(i, null); + + // Now go for all elements in the lexer configuration + // We are looking for the numeric keys, because these are the + // style index to set and the value is our ScriptStyleType + IDictionary dic = lexercfg.ReadSetting(lexername, new Hashtable()); + foreach(DictionaryEntry de in dic) + { + // Check if this is a numeric key + int stylenum; + if(int.TryParse(de.Key.ToString(), out stylenum)) + { + // Add style to lookup table + stylelookup.Add(stylenum, (ScriptStyleType)(int)de.Value); + + // Apply color to style + int colorindex; + ScriptStyleType type = (ScriptStyleType)(int)de.Value; + switch(type) + { + case ScriptStyleType.PlainText: colorindex = ColorCollection.PLAINTEXT; break; + case ScriptStyleType.Comment: colorindex = ColorCollection.COMMENTS; break; + case ScriptStyleType.Constant: colorindex = ColorCollection.CONSTANTS; break; + case ScriptStyleType.Keyword: colorindex = ColorCollection.KEYWORDS; break; + case ScriptStyleType.LineNumber: colorindex = ColorCollection.LINENUMBERS; break; + case ScriptStyleType.Literal: colorindex = ColorCollection.LITERALS; break; + case ScriptStyleType.String: colorindex = ColorCollection.STRINGS; break; + case ScriptStyleType.Include: colorindex = ColorCollection.INCLUDES; break; + case ScriptStyleType.Property: colorindex = ColorCollection.PROPERTIES; break; + default: colorindex = ColorCollection.PLAINTEXT; break; + } + + scriptedit.Styles[stylenum].ForeColor = General.Colors.Colors[colorindex].ToColor(); + } + } + + // Create the keywords list and apply it + string imageindex = ((int)ImageIndex.ScriptKeyword).ToString(CultureInfo.InvariantCulture); + int keywordsindex = lexercfg.ReadSetting(lexername + ".keywordsindex", -1); + if(keywordsindex > -1) + { + StringBuilder keywordslist = new StringBuilder(); + foreach(string k in scriptconfig.Keywords) + { + if(keywordslist.Length > 0) keywordslist.Append(" "); + keywordslist.Append(k); + + //mxd. Skip adding the keyword if we have a snippet with the same name + if(!scriptconfig.Snippets.Contains(k)) + autocompletedict.Add(k, k + "?" + imageindex); + } + string words = keywordslist.ToString(); + scriptedit.SetKeywords(keywordsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); + } + + //mxd. Create the properties list and apply it + imageindex = ((int)ImageIndex.ScriptProperty).ToString(CultureInfo.InvariantCulture); + int propertiesindex = lexercfg.ReadSetting(lexername + ".propertiesindex", -1); + if(propertiesindex > -1) + { + StringBuilder propertieslist = new StringBuilder(); + HashSet<string> addedprops = new HashSet<string>(); + char[] dot = {'.'}; + foreach(string p in scriptconfig.Properties) + { + if(propertieslist.Length > 0) propertieslist.Append(" "); + + // Scintilla doesn't highlight keywords with '.' or ':', so get rid of those + if(scriptconfig.ScriptType == ScriptType.DECORATE) + { + string prop = p; + if(prop.Contains(":")) prop = prop.Replace(":", string.Empty); + if(prop.Contains(".")) + { + // Split dotted properties into separate entries + string[] parts = prop.Split(dot, StringSplitOptions.RemoveEmptyEntries); + List<string> result = new List<string>(); + foreach(string part in parts) + { + if(!addedprops.Contains(part)) + { + result.Add(part); + addedprops.Add(part); + } + } + + if(result.Count > 0) propertieslist.Append(string.Join(" ", result.ToArray())); + } + else + { + addedprops.Add(prop); + propertieslist.Append(prop); + } + } + else + { + propertieslist.Append(p); + } + + // Autocomplete doesn't mind '.' or ':' + // Skip adding the keyword if we have a snippet with the same name + if(!scriptconfig.Snippets.Contains(p)) + autocompletedict.Add(p, p + "?" + imageindex); + } + string words = propertieslist.ToString(); + scriptedit.SetKeywords(propertiesindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); + } + + // Create the constants list and apply it + imageindex = ((int)ImageIndex.ScriptConstant).ToString(CultureInfo.InvariantCulture); + int constantsindex = lexercfg.ReadSetting(lexername + ".constantsindex", -1); + if(constantsindex > -1) + { + StringBuilder constantslist = new StringBuilder(); + foreach(string c in scriptconfig.Constants) + { + if(autocompletedict.ContainsKey(c)) continue; //mxd. This happens when there's a keyword and a constant with the same name... + + if(constantslist.Length > 0) constantslist.Append(" "); + constantslist.Append(c); + + //mxd. Skip adding the constant if we have a snippet with the same name + if(!scriptconfig.Snippets.Contains(c)) + autocompletedict.Add(c, c + "?" + imageindex); + } + string words = constantslist.ToString(); + scriptedit.SetKeywords(constantsindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); + } + + //mxd. Create the snippets list and apply it + imageindex = ((int)ImageIndex.ScriptSnippet).ToString(CultureInfo.InvariantCulture); + int snippetindex = lexercfg.ReadSetting(lexername + ".snippetindex", -1); + if(snippetindex > -1 && scriptconfig.Snippets.Count > 0) + { + StringBuilder snippetslist = new StringBuilder(); + foreach(string s in scriptconfig.Snippets) + { + if(snippetslist.Length > 0) snippetslist.Append(" "); + snippetslist.Append(s); + autocompletedict.Add(s, s + "?" + imageindex); + } + string words = snippetslist.ToString(); + scriptedit.SetKeywords(snippetindex, (scriptconfig.CaseSensitive ? words : words.ToLowerInvariant())); + } + + // Make autocomplete list + autocompletelist = new List<string>(autocompletedict.Values); + + // Setup folding (https://github.com/jacobslusser/ScintillaNET/wiki/Automatic-Code-Folding) + if(General.Settings.ScriptShowFolding && (scriptconfig.Lexer == Lexer.Cpp || scriptconfig.Lexer == Lexer.CppNoCase)) + { + // Instruct the lexer to calculate folding + scriptedit.SetProperty("fold", "1"); + scriptedit.SetProperty("fold.compact", "0"); // 1 = folds blank lines + scriptedit.SetProperty("fold.comment", "1"); // Enable block comment folding + scriptedit.SetProperty("fold.preprocessor", "1"); // Enable #region folding + scriptedit.SetFoldFlags(FoldFlags.LineAfterContracted); // Draw line below if not expanded + + // Configure a margin to display folding symbols + scriptedit.Margins[2].Type = MarginType.Symbol; + scriptedit.Margins[2].Mask = Marker.MaskFolders; + scriptedit.Margins[2].Sensitive = true; + scriptedit.Margins[2].Width = 12; + + // Configure folding markers with respective symbols + scriptedit.Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus; + scriptedit.Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus; + scriptedit.Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected; + scriptedit.Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner; + scriptedit.Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected; + scriptedit.Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine; + scriptedit.Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner; + + // Enable automatic folding + scriptedit.AutomaticFold = (AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change); + } + else + { + // Disable folding + scriptedit.SetProperty("fold", "0"); + scriptedit.SetProperty("fold.compact", "0"); + + scriptedit.Margins[2].Type = MarginType.Symbol; + scriptedit.Margins[2].Mask = 0; // No markers here + scriptedit.Margins[2].Sensitive = false; + scriptedit.Margins[2].Width = 5; + + scriptedit.AutomaticFold = AutomaticFold.None; + } + + // Rearrange the layout + this.PerformLayout(); + } + + // This returns the current word (where the caret is at) + public string GetCurrentWord() + { + return GetWordAt(scriptedit.CurrentPosition); + } + + // This returns the word at the given position + public string GetWordAt(int position) + { + return scriptedit.GetWordFromPosition(position); + } + + // Perform undo + public void Undo() + { + scriptedit.Undo(); + } + + // Perform redo + public void Redo() + { + scriptedit.Redo(); + } + + // This clears all undo levels + public void ClearUndoRedo() + { + scriptedit.EmptyUndoBuffer(); + } + + //mxd. This marks the current document as unmodified + public void SetSavePoint() + { + scriptedit.SetSavePoint(); + } + + // Perform cut + public void Cut() + { + scriptedit.Cut(); + } + + // Perform copy + public void Copy() + { + scriptedit.Copy(); + } + + // Perform paste + public void Paste() + { + scriptedit.Paste(); + } + + // This steals the focus (use with care!) + public void GrabFocus() + { + scriptedit.Focus(); + } + + public byte[] GetText() + { + return encoding.GetBytes(scriptedit.Text); //mxd TODO: other encodings?.. + } + + public void SetText(byte[] text) + { + scriptedit.Text = encoding.GetString(text); //mxd TODO: other encodings?.. + } + + //mxd + public void InsertSnippet(string[] lines) + { + // Insert the snippet + int curline = scriptedit.LineFromPosition(scriptedit.SelectionStart); + int indent = scriptedit.Lines[scriptedit.CurrentLine].Indentation; + string tabs = Environment.NewLine + GetIndentationString(indent); + string spaces = new String(' ', General.Settings.ScriptTabWidth); + int entrypos = -1; + int entryline = -1; + string[] processedlines = ProcessLineBreaks(lines); + + // Process special chars, try to find entry position marker + for(int i = 0; i < lines.Length; i++) + { + if(!scriptedit.UseTabs) processedlines[i] = processedlines[i].Replace("\t", spaces); + + // Check if we have the [EP] marker + if(entrypos == -1) + { + int pos = processedlines[i].IndexOf("[EP]", StringComparison.Ordinal); + if(pos != -1) + { + processedlines[i] = processedlines[i].Remove(pos, 4); + entryline = curline + i; + entrypos = processedlines[i].Length - pos; + } + } + } + + // Replace the text + string text = string.Join(tabs, processedlines); + scriptedit.SelectionStart = scriptedit.WordStartPosition(scriptedit.CurrentPosition, true); + scriptedit.SelectionEnd = scriptedit.WordEndPosition(scriptedit.CurrentPosition, true); + scriptedit.ReplaceSelection(text); + + // Move the cursor if we had the [EP] marker + if(entrypos != -1) + { + scriptedit.SetEmptySelection(scriptedit.Lines[entryline].EndPosition - entrypos - 2); + } + } + + //mxd. Find next result + public bool FindNext(FindReplaceOptions options, bool useselectionstart) + { + int startpos = (useselectionstart ? Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) : Math.Max(scriptedit.SelectionStart, scriptedit.SelectionEnd)); + + // Search the document + scriptedit.TargetStart = startpos; + scriptedit.TargetEnd = scriptedit.TextLength; + scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None; + if(options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord; + + int result = scriptedit.SearchInTarget(options.FindText); + + // Wrap around? + if(result == -1) + { + scriptedit.TargetStart = 0; + scriptedit.TargetEnd = startpos; + result = scriptedit.SearchInTarget(options.FindText); + } + + // Found something + if(result != -1) + { + // Select the result + SelectAndShow(result, result + options.FindText.Length); + + // Update extra highlights + HighlightWord(options.FindText); + + // All done + return true; + } + + // Nothing found... + return false; + } + + //mxd. Find previous result + public bool FindPrevious(FindReplaceOptions options) + { + int endpos = Math.Max(0, Math.Min(scriptedit.SelectionStart, scriptedit.SelectionEnd) - 1); + + // Search the document + scriptedit.TargetStart = endpos; + scriptedit.TargetEnd = 0; + scriptedit.SearchFlags = options.CaseSensitive ? SearchFlags.MatchCase : SearchFlags.None; + if(options.WholeWord) scriptedit.SearchFlags |= SearchFlags.WholeWord; + + int result = scriptedit.SearchInTarget(options.FindText); + + // Wrap around? + if(result == -1) + { + scriptedit.TargetStart = scriptedit.TextLength; + scriptedit.TargetEnd = endpos; + result = scriptedit.SearchInTarget(options.FindText); + } + + // Found something + if(result != -1) + { + // Select the result + SelectAndShow(result, result + options.FindText.Length); + + // Update extra highlights + HighlightWord(options.FindText); + + // All done + return true; + } + + // Nothing found... + return false; + } + + //mxd. (Un)indents selection + public void IndentSelection(bool indent) + { + // Get selected range of lines + int startline = scriptedit.LineFromPosition(scriptedit.SelectionStart); + int endline = scriptedit.LineFromPosition(scriptedit.SelectionEnd); + + for(int i = startline; i < endline + 1; i++) + { + scriptedit.Lines[i].Indentation += (indent ? General.Settings.ScriptTabWidth : -General.Settings.ScriptTabWidth); + } + } + + #endregion + + #region ================== Utility methods + + // This returns the ScriptStyleType for a given Scintilla style + private ScriptStyleType GetScriptStyle(int scintillastyle) + { + return (stylelookup.ContainsKey(scintillastyle) ? stylelookup[scintillastyle] : ScriptStyleType.PlainText); + } + + // This gathers information about the current caret position + private void UpdatePositionInfo() + { + int bracketlevel = 0; // bracket level counting + int argindex = 0; // function argument counting + int pos = scriptedit.CurrentPosition; + + // Get the text + string scripttext = scriptedit.Text; + + // Reset position info + curfunctionname = ""; + curargumentindex = 0; + curfunctionstartpos = 0; + + // Determine lowest backtrack position + int limitpos = scriptedit.CurrentPosition - MAX_BACKTRACK_LENGTH; + if(limitpos < 0) limitpos = 0; + + // We can only do this when we have function syntax information + if((scriptconfig.ArgumentDelimiter.Length == 0) || (scriptconfig.FunctionClose.Length == 0) || + (scriptconfig.FunctionOpen.Length == 0) || (scriptconfig.Terminator.Length == 0)) return; + + // Get int versions of the function syntax informantion + int argumentdelimiter = scriptconfig.ArgumentDelimiter[0]; + int functionclose = scriptconfig.FunctionClose[0]; + int functionopen = scriptconfig.FunctionOpen[0]; + int terminator = scriptconfig.Terminator[0]; + + // Continue backtracking until we reached the limitpos + while(pos >= limitpos) + { + // Backtrack 1 character + pos--; + + // Get the style and character at this position + ScriptStyleType curstyle = GetScriptStyle(scriptedit.GetStyleAt(pos)); + int curchar = scriptedit.GetCharAt(pos); + + // Then meeting ) then increase bracket level + // When meeting ( then decrease bracket level + // When bracket level goes -1, then the next word should be the function name + // Only when at bracket level 0, count the comma's for argument index + + // TODO: + // Original code checked for scope character here and breaks if found + + // Check if in plain text or keyword + if((curstyle == ScriptStyleType.PlainText) || (curstyle == ScriptStyleType.Keyword)) + { + // Closing bracket + if(curchar == functionclose) + { + bracketlevel++; + } + // Opening bracket + else if(curchar == functionopen) + { + bracketlevel--; + + // Out of the brackets? + if(bracketlevel < 0) + { + // Skip any whitespace before this bracket + do + { + // Backtrack 1 character + curchar = scriptedit.GetCharAt(--pos); + } + while((pos >= limitpos) && ((curchar == ' ') || (curchar == '\t') || + (curchar == '\r') || (curchar == '\n'))); + + // NOTE: We may need to set onlyWordCharacters argument in the + // following calls to false to get any argument delimiter included, + // but this may also cause a valid keyword to be combined with other + // surrounding characters that do not belong to the keyword. + + // Find the word before this bracket + int wordstart = scriptedit.WordStartPosition(pos, true); + int wordend = scriptedit.WordEndPosition(pos, true); + string word = scripttext.Substring(wordstart, wordend - wordstart); + if(word.Length > 0) + { + // Check if this is an argument delimiter + // I can't remember why I did this, but I'll probably stumble + // upon the problem if this doesn't work right (see note above) + if(word[0] == argumentdelimiter) + { + // We are now in the parent function + bracketlevel++; + argindex = 0; + } + // Now check if this is a keyword + else if(scriptconfig.IsKeyword(word)) + { + // Found it! + curfunctionname = scriptconfig.GetKeywordCase(word); + curargumentindex = argindex; + curfunctionstartpos = wordstart; + break; + } + else + { + // Don't know this word + break; + } + } + } + } + // Argument delimiter + else if(curchar == argumentdelimiter) + { + // Only count these at brackt level 0 + if(bracketlevel == 0) argindex++; + } + // Terminator + else if(curchar == terminator) + { + // Can't find anything, break now + break; + } + } + } + } + + // This registers an image for the autocomplete list + private void RegisterAutoCompleteImage(ImageIndex index, Bitmap image) + { + // Register image + scriptedit.RegisterRgbaImage((int)index, image); + } + + // This registers an image for the markes list + private void RegisterMarkerImage(ImageIndex index, Bitmap image) + { + // Register image + scriptedit.Markers[(int)index].DefineRgbaImage(image); + scriptedit.Markers[(int)index].Symbol = MarkerSymbol.RgbaImage; + } + + //mxd. This converts [LB] markers to line breaks if necessary + private static string[] ProcessLineBreaks(string[] lines) + { + List<string> result = new List<string>(lines.Length); + string[] separator = new[] { "[LB]" }; + + foreach(string line in lines) + { + if(line.IndexOf(separator[0], StringComparison.Ordinal) != -1) + { + if(General.Settings.ScriptAllmanStyle) + result.AddRange(line.Split(separator, StringSplitOptions.RemoveEmptyEntries)); + else + result.Add(line.Replace(separator[0], " ")); + } + else + { + result.Add(line); + } + } + + return result.ToArray(); + } + + //mxd. Autocompletion handling (https://github.com/jacobslusser/ScintillaNET/wiki/Basic-Autocompletion) + private bool ShowAutoCompletionList() + { + int currentpos = scriptedit.CurrentPosition; + int wordstartpos = scriptedit.WordStartPosition(currentpos, true); + + if(wordstartpos >= currentpos) + { + // Hide the list + scriptedit.AutoCCancel(); + return false; + } + + // Get entered text + string start = scriptedit.GetTextRange(wordstartpos, currentpos - wordstartpos); + if(string.IsNullOrEmpty(start)) + { + // Hide the list + scriptedit.AutoCCancel(); + return false; + } + + // Don't show Auto-completion list when editing comment, include or string + switch(GetScriptStyle(scriptedit.GetStyleAt(currentpos))) + { + case ScriptStyleType.Comment: + case ScriptStyleType.String: + case ScriptStyleType.Include: + // Hide the list + scriptedit.AutoCCancel(); + return false; + } + + // Filter the list + List<string> filtered = new List<string>(); + foreach(string s in autocompletelist) + if(s.IndexOf(start, StringComparison.OrdinalIgnoreCase) != -1) filtered.Add(s); + + // Any matches? + if(filtered.Count > 0) + { + // Show the list + scriptedit.AutoCShow(currentpos - wordstartpos, string.Join(" ", filtered.ToArray())); + return true; + } + + // Hide the list + scriptedit.AutoCCancel(); + return false; + } + + //mxd + private string GetIndentationString(int indent) + { + if(scriptedit.UseTabs) + { + string indentstr = string.Empty; + int numtabs = indent / scriptedit.TabWidth; + if(numtabs > 0) indentstr = new string('\t', numtabs); + + // Mixed padding? Add spaces + if(numtabs * scriptedit.TabWidth < indent) + { + int numspaces = indent - numtabs * scriptedit.TabWidth; + indentstr += new string(' ', numspaces); + } + + return indentstr; + } + else + { + return new string(' ', indent); + } + } + + //mxd. https://github.com/jacobslusser/ScintillaNET/wiki/Find-and-Highlight-Words + private void HighlightWord(string text) + { + // Remove all uses of our indicator + scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR; + scriptedit.IndicatorClearRange(0, scriptedit.TextLength); + + // Update indicator appearance + scriptedit.Indicators[HIGHLIGHT_INDICATOR].Style = IndicatorStyle.RoundBox; + scriptedit.Indicators[HIGHLIGHT_INDICATOR].Under = true; + scriptedit.Indicators[HIGHLIGHT_INDICATOR].ForeColor = General.Colors.ScriptIndicator.ToColor(); + scriptedit.Indicators[HIGHLIGHT_INDICATOR].OutlineAlpha = 50; + scriptedit.Indicators[HIGHLIGHT_INDICATOR].Alpha = 30; + + // Search the document + scriptedit.TargetStart = 0; + scriptedit.TargetEnd = scriptedit.TextLength; + scriptedit.SearchFlags = SearchFlags.WholeWord; + + while(scriptedit.SearchInTarget(text) != -1) + { + //mxd. Don't mark currently selected word + if(scriptedit.SelectionStart != scriptedit.TargetStart && scriptedit.SelectionEnd != scriptedit.TargetEnd) + { + // Mark the search results with the current indicator + scriptedit.IndicatorFillRange(scriptedit.TargetStart, scriptedit.TargetEnd - scriptedit.TargetStart); + } + + // Search the remainder of the document + scriptedit.TargetStart = scriptedit.TargetEnd; + scriptedit.TargetEnd = scriptedit.TextLength; + } + } + + #endregion + + #region ================== Events + + // Layout needs to be re-organized + protected override void OnLayout(LayoutEventArgs e) + { + base.OnLayout(e); + + // With or without functions bar? + if(functionbar.Visible) + { + scriptpanel.Top = functionbar.Bottom + 6; + scriptpanel.Height = this.ClientSize.Height - scriptpanel.Top; + } + else + { + scriptpanel.Top = 0; + scriptpanel.Height = this.ClientSize.Height; + } + } + + //mxd. Script text changed + private void scriptedit_TextChanged(object sender, EventArgs e) + { + // Line number margin width needs changing? + int curlinenumbercharlength = scriptedit.Lines.Count.ToString().Length; + + // Calculate the width required to display the last line number + // and include some padding for good measure. + if(curlinenumbercharlength != linenumbercharlength) + { + const int padding = 2; + scriptedit.Margins[1].Width = scriptedit.TextWidth(Style.LineNumber, new string('9', curlinenumbercharlength + 1)) + padding; + linenumbercharlength = curlinenumbercharlength; + } + + if(OnTextChanged != null) OnTextChanged(this, EventArgs.Empty); + } + + //mxd + private void scriptedit_CharAdded(object sender, CharAddedEventArgs e) + { + // Hide call tip if any + scriptedit.CallTipCancel(); + + // Offset caret if needed + if(caretoffset != 0) + { + scriptedit.SetEmptySelection(scriptedit.SelectionStart + caretoffset); + caretoffset = 0; + if(!expandcodeblock) return; + } + + // Move CodeBlockOpen to the new line? + if(expandcodeblock) + { + if(scriptedit.CurrentLine > 0) + { + string linetext = scriptedit.Lines[scriptedit.CurrentLine - 1].Text; + int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, StringComparison.Ordinal)); + if(blockopenpos != -1) + { + // Do it only if initial line doesn't start with CodeBlockOpen + string linestart = linetext.Substring(0, blockopenpos).Trim(); + if(linestart.Length > 0) + { + scriptedit.InsertText(scriptedit.Lines[scriptedit.CurrentLine - 1].Position + blockopenpos, + Environment.NewLine + GetIndentationString(scriptedit.Lines[scriptedit.CurrentLine - 1].Indentation)); + } + } + } + + expandcodeblock = false; + return; + } + + // Auto-match braces + if(General.Settings.ScriptAutoCloseBrackets) + { + //TODO: Auto-match quotes + bool endpos = (scriptedit.CurrentPosition == scriptedit.TextLength); + if(!string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) && e.Char == scriptconfig.CodeBlockOpen[0] && !string.IsNullOrEmpty(scriptconfig.CodeBlockClose) && + (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.CodeBlockClose[0])) + { + scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.CodeBlockClose); + return; + } + + if(!string.IsNullOrEmpty(scriptconfig.FunctionOpen) && e.Char == scriptconfig.FunctionOpen[0] && !string.IsNullOrEmpty(scriptconfig.FunctionClose) && + (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.FunctionClose[0])) + { + scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.FunctionClose); + return; + } + + if(!string.IsNullOrEmpty(scriptconfig.ArrayOpen) && e.Char == scriptconfig.ArrayOpen[0] && !string.IsNullOrEmpty(scriptconfig.ArrayClose) && + (endpos || (char)scriptedit.GetCharAt(scriptedit.CurrentPosition + 1) != scriptconfig.ArrayClose[0])) + { + scriptedit.InsertText(scriptedit.CurrentPosition, scriptconfig.ArrayClose); + return; + } + } + + if(General.Settings.ScriptAutoShowAutocompletion) + { + // Display the autocompletion list + ShowAutoCompletionList(); + } + } + + //mxd + private void scriptedit_UpdateUI(object sender, UpdateUIEventArgs e) + { + // If a word is selected, highlight the same words + if(scriptedit.SelectedText != highlightedword) + { + // Highlight only when whole word is selected + if(!string.IsNullOrEmpty(scriptedit.SelectedText) && scriptedit.GetWordFromPosition(scriptedit.SelectionStart) == scriptedit.SelectedText) + { + HighlightWord(scriptedit.SelectedText); + } + else + { + // Clear highlight + scriptedit.IndicatorCurrent = HIGHLIGHT_INDICATOR; + scriptedit.IndicatorClearRange(0, scriptedit.TextLength); + } + + highlightedword = scriptedit.SelectedText; + } + + // Has the caret changed position? + int caretpos = scriptedit.CurrentPosition; + if(lastcaretpos != caretpos && scriptconfig.BraceChars.Count > 0) + { + // Perform brace matching (https://github.com/jacobslusser/ScintillaNET/wiki/Brace-Matching) + lastcaretpos = caretpos; + int bracepos1 = -1; + + // Is there a brace to the left or right? + if(caretpos > 0 && scriptconfig.BraceChars.Contains((char)scriptedit.GetCharAt(caretpos - 1))) + bracepos1 = (caretpos - 1); + else if(scriptconfig.BraceChars.Contains((char)(scriptedit.GetCharAt(caretpos)))) + bracepos1 = caretpos; + + if(bracepos1 > -1) + { + // Find the matching brace + int bracepos2 = scriptedit.BraceMatch(bracepos1); + if(bracepos2 == Scintilla.InvalidPosition) + scriptedit.BraceBadLight(bracepos1); + else + scriptedit.BraceHighlight(bracepos1, bracepos2); + } + else + { + // Turn off brace matching + scriptedit.BraceHighlight(Scintilla.InvalidPosition, Scintilla.InvalidPosition); + } + } + } + + //mxd + private void scriptedit_InsertCheck(object sender, InsertCheckEventArgs e) + { + // Gross hacks... + if(skiptextinsert) + { + e.Text = string.Empty; + skiptextinsert = false; + } + // Do we want auto-indentation? + else if(!expandcodeblock && General.Settings.ScriptAutoIndent && e.Text == "\r\n") + { + // Get current line indentation up to the cursor position + string linetext = scriptedit.Lines[scriptedit.CurrentLine].Text; + int selectionpos = scriptedit.SelectionStart - scriptedit.Lines[scriptedit.CurrentLine].Position; + int indent = 0; + for(int i = 0; i < selectionpos; i++) + { + switch(linetext[i]) + { + case ' ': indent++; break; + case '\t': indent += scriptedit.TabWidth; break; + default: i = selectionpos; break; // break the loop + } + } + + // Store initial indentation + int initialindent = indent; + + // Need to increase indentation? We do this when: + // 1. Line contains '{' and '}' and the cursor is between them + // 2. Line either doesn't contain '}', or it's before '{', or the line contains '{' and the cursor is after it + int blockopenpos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.LastIndexOf(scriptconfig.CodeBlockOpen, selectionpos, StringComparison.Ordinal)); + int blockclosepos = (string.IsNullOrEmpty(scriptconfig.CodeBlockOpen) ? -1 : linetext.IndexOf(scriptconfig.CodeBlockClose, selectionpos, StringComparison.Ordinal)); + + // Add indentation when the cursor is between { and } + bool addindent = (blockopenpos != -1 && blockopenpos < selectionpos) && (blockclosepos == -1 || (blockopenpos < blockclosepos && blockclosepos >= selectionpos)); + if(addindent) indent += scriptedit.TabWidth; + + // Calculate indentation + string indentstr = GetIndentationString(indent); + + // Move CodeBlockOpen to the new line? (will be applied in scriptedit_CharAdded) + expandcodeblock = General.Settings.ScriptAllmanStyle; + + // Offset closing block char? + if(addindent && blockclosepos != -1) + { + string initialindentstr = GetIndentationString(initialindent); + indentstr += Environment.NewLine + initialindentstr; + + // Offset cursor position (will be performed in scriptedit_CharAdded) + caretoffset = -(initialindentstr.Length + Environment.NewLine.Length); + } + + // Apply new indentation + e.Text += indentstr; + } + } + + //mxd + private void scriptedit_AutoCCompleted(object sender, AutoCSelectionEventArgs e) + { + // Expand snippet? + string[] lines = scriptconfig.GetSnippet(e.Text); + if(lines != null) InsertSnippet(lines); + } + + // Key pressed down + private void scriptedit_KeyDown(object sender, KeyEventArgs e) + { + // F3 for Find Next + if((e.KeyCode == Keys.F3) && (e.Modifiers == Keys.None)) + { + if(OnFindNext != null) OnFindNext(); + } + // F2 for Find Previous (mxd) + else if((e.KeyCode == Keys.F2) && (e.Modifiers == Keys.None)) + { + if(OnFindPrevious != null) OnFindPrevious(); + } + // CTRL+F for find & replace + else if((e.KeyCode == Keys.F) && ((e.Modifiers & Keys.Control) == Keys.Control)) + { + if(OnOpenFindAndReplace != null) OnOpenFindAndReplace(); + } + // CTRL+S for save + else if((e.KeyCode == Keys.S) && ((e.Modifiers & Keys.Control) == Keys.Control)) + { + if(OnExplicitSaveTab != null) OnExplicitSaveTab(); + } + // CTRL+O for open + else if((e.KeyCode == Keys.O) && ((e.Modifiers & Keys.Control) == Keys.Control)) + { + if(OnOpenScriptBrowser != null) OnOpenScriptBrowser(); + } + // CTRL+Space to autocomplete + else if((e.KeyCode == Keys.Space) && (e.Modifiers == Keys.Control)) + { + // Hide call tip if any + scriptedit.CallTipCancel(); + + // Show autocomplete + if(ShowAutoCompletionList()) skiptextinsert = true; + } + //mxd. Tab to expand code snippet. Do it only when the text cursor is at the end of a keyword. + else if(e.KeyCode == Keys.Tab) + { + if(!scriptedit.AutoCActive) + { + string curword = GetCurrentWord().ToLowerInvariant(); + if(scriptconfig.Snippets.Contains(curword) && scriptedit.CurrentPosition == scriptedit.WordEndPosition(scriptedit.CurrentPosition, true)) + { + InsertSnippet(scriptconfig.GetSnippet(curword)); + skiptextinsert = true; + } + } + } + else + { + //mxd. Skip text insert when "save screenshot" action's keys are pressed + Actions.Action[] actions = General.Actions.GetActionsByKey((int)e.KeyData); + foreach(Actions.Action action in actions) + { + if(action.ShortName == "savescreenshot" || action.ShortName == "saveeditareascreenshot") + { + skiptextinsert = true; + return; + } + } + } + } + + // Key released + private void scriptedit_KeyUp(object sender, KeyEventArgs e) + { + bool showcalltip = false; + int highlightstart = 0; + int highlightend = 0; + + UpdatePositionInfo(); + + // Call tip shown + if(scriptedit.CallTipActive) + { + // Should we hide the call tip? + if(curfunctionname.Length == 0) + { + // Hide the call tip + scriptedit.CallTipCancel(); + } + else + { + // Update the call tip + showcalltip = true; + } + } + // No call tip + else + { + // Should we show a call tip? + showcalltip = (curfunctionname.Length > 0) && !scriptedit.AutoCActive; + } + + // Show or update call tip + if(showcalltip) + { + string functiondef = scriptconfig.GetFunctionDefinition(curfunctionname); + if(functiondef != null) + { + // Determine the range to highlight + int argsopenpos = functiondef.IndexOf(scriptconfig.FunctionOpen, StringComparison.Ordinal); + int argsclosepos = functiondef.LastIndexOf(scriptconfig.FunctionClose, StringComparison.Ordinal); + if((argsopenpos > -1) && (argsclosepos > -1)) + { + string argsstr = functiondef.Substring(argsopenpos + 1, argsclosepos - argsopenpos - 1); + string[] args = argsstr.Split(scriptconfig.ArgumentDelimiter[0]); + if((curargumentindex >= 0) && (curargumentindex < args.Length)) + { + int argoffset = 0; + for(int i = 0; i < curargumentindex; i++) argoffset += args[i].Length + 1; + highlightstart = argsopenpos + argoffset + 1; + highlightend = highlightstart + args[curargumentindex].Length; + } + } + + //mxd. If the tip obscures the view, move it down + int tippos; + int funcline = scriptedit.LineFromPosition(curfunctionstartpos); + if(scriptedit.CurrentLine > funcline) + tippos = scriptedit.Lines[scriptedit.CurrentLine].Position + scriptedit.Lines[scriptedit.CurrentLine].Indentation; //scriptedit.PositionFromLine(curline) /*+ (curfunctionstartpos - scriptedit.PositionFromLine(funcline))*/; + else + tippos = curfunctionstartpos; + + // Show tip + scriptedit.CallTipShow(tippos, functiondef); + scriptedit.CallTipSetHlt(highlightstart, highlightend); + } + } + } + + #endregion + } +} diff --git a/Source/Core/Controls/ScriptFileDocumentTab.cs b/Source/Core/Controls/ScriptFileDocumentTab.cs index 98b2cc1d..8978b07f 100644 --- a/Source/Core/Controls/ScriptFileDocumentTab.cs +++ b/Source/Core/Controls/ScriptFileDocumentTab.cs @@ -61,15 +61,15 @@ namespace CodeImp.DoomBuilder.Controls if(config.Extensions.Length > 0) ext = "." + config.Extensions[0]; SetTitle("Untitled" + ext); editor.ClearUndoRedo(); - editor.FunctionBar.Enabled = (config.ScriptType != ScriptType.UNKNOWN); //mxd - } - - #endregion - - #region ================== Methods - - // This compiles the script file - public override void Compile() + editor.FunctionBar.Enabled = (config.ScriptType != ScriptType.UNKNOWN); //mxd + } + + #endregion + + #region ================== Methods + + // This compiles the script file + public override void Compile() { //mxd. ACS requires special handling... if(config.ScriptType == ScriptType.ACS) @@ -126,8 +126,8 @@ namespace CodeImp.DoomBuilder.Controls // Dispose compiler compiler.Dispose(); - //mxd. Update script navigator - UpdateNavigator(); + //mxd. Update script navigator + UpdateNavigator(); // Feed errors to panel panel.ShowErrors(errors); @@ -147,7 +147,7 @@ namespace CodeImp.DoomBuilder.Controls // Boilderplate if(!General.CompiledScriptConfigs.ContainsKey(General.Map.Options.ScriptCompiler)) { - General.ShowErrorMessage("Unable to compile '" + inputfile + "'. Unable to find required script compiler configuration ('" + General.Map.Options.ScriptCompiler + "').", MessageBoxButtons.OK); + General.ShowErrorMessage("Unable to compile \"" + inputfile + "\". Unable to find required script compiler configuration (\"" + General.Map.Options.ScriptCompiler + "\").", MessageBoxButtons.OK); return; } @@ -232,7 +232,7 @@ namespace CodeImp.DoomBuilder.Controls { // Fail compiler.Dispose(); - errors.Add(new CompilerError("Output file '" + outputfile + "' doesn't exist.")); + errors.Add(new CompilerError("Output file \"" + outputfile + "\" doesn't exist.")); panel.ShowErrors(errors); return; } @@ -247,7 +247,7 @@ namespace CodeImp.DoomBuilder.Controls { // Fail compiler.Dispose(); - errors.Add(new CompilerError("Unable to create library file '" + targetfilename + "'. " + e.GetType().Name + ": " + e.Message)); + errors.Add(new CompilerError("Unable to create library file \"" + targetfilename + "\". " + e.GetType().Name + ": " + e.Message)); panel.ShowErrors(errors); return; } @@ -257,8 +257,8 @@ namespace CodeImp.DoomBuilder.Controls // Dispose compiler compiler.Dispose(); - // Update script navigator - UpdateNavigator(); + // Update script navigator + UpdateNavigator(); // Feed errors to panel panel.ShowErrors(errors); @@ -282,16 +282,16 @@ namespace CodeImp.DoomBuilder.Controls catch(Exception e) { // Failed - General.ErrorLogger.Add(ErrorType.Error, "Cannot open file '" + filepathname + "' for writing. Make sure the path exists and that the file is not in use by another application."); + General.ErrorLogger.Add(ErrorType.Error, "Cannot open file \"" + filepathname + "\" for writing. Make sure the path exists and that the file is not in use by another application."); General.WriteLogLine(e.GetType().Name + ": " + e.Message); General.ShowErrorMessage("Unable to open file \"" + filepathname + "\" for writing. Make sure the path exists and that the file is not in use by another application.", MessageBoxButtons.OK); return false; } - - // Done - editor.SetSavePoint(); //mxd - UpdateTitle(); //mxd - return true; + + // Done + editor.SetSavePoint(); //mxd + UpdateTitle(); //mxd + return true; } // This saves the document to a new file @@ -317,14 +317,13 @@ namespace CodeImp.DoomBuilder.Controls { try { - // Read the file - editor.Text = File.ReadAllText(filepathname); //mxd - } - - catch (Exception e) + // Read the file + editor.Text = File.ReadAllText(filepathname); //mxd + } + catch(Exception e) { // Failed - General.ErrorLogger.Add(ErrorType.Error, "Cannot open file '" + filepathname + "' for reading. Make sure the path exists and that the file is not in use by another application."); + General.ErrorLogger.Add(ErrorType.Error, "Cannot open file \"" + filepathname + "\" for reading. Make sure the path exists and that the file is not in use by another application."); General.WriteLogLine(e.GetType().Name + ": " + e.Message); General.ShowErrorMessage("Unable to open file \"" + filepathname + "\" for reading. Make sure the path exists and that the file is not in use by another application.", MessageBoxButtons.OK); return false; diff --git a/Source/Core/Controls/StatisticsControl.Designer.cs b/Source/Core/Controls/StatisticsControl.Designer.cs index 9ade8ee1..387d1746 100644 --- a/Source/Core/Controls/StatisticsControl.Designer.cs +++ b/Source/Core/Controls/StatisticsControl.Designer.cs @@ -45,7 +45,7 @@ this.thingscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.thingscount.Location = new System.Drawing.Point(10, 81); this.thingscount.Name = "thingscount"; - this.thingscount.Size = new System.Drawing.Size(43, 14); + this.thingscount.Size = new System.Drawing.Size(63, 14); this.thingscount.TabIndex = 19; this.thingscount.Text = "0"; this.thingscount.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -55,7 +55,7 @@ this.sectorscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.sectorscount.Location = new System.Drawing.Point(10, 62); this.sectorscount.Name = "sectorscount"; - this.sectorscount.Size = new System.Drawing.Size(43, 14); + this.sectorscount.Size = new System.Drawing.Size(63, 14); this.sectorscount.TabIndex = 18; this.sectorscount.Text = "0"; this.sectorscount.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -65,7 +65,7 @@ this.sidedefscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.sidedefscount.Location = new System.Drawing.Point(10, 44); this.sidedefscount.Name = "sidedefscount"; - this.sidedefscount.Size = new System.Drawing.Size(43, 14); + this.sidedefscount.Size = new System.Drawing.Size(63, 14); this.sidedefscount.TabIndex = 17; this.sidedefscount.Text = "0"; this.sidedefscount.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -75,7 +75,7 @@ this.linedefscount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.linedefscount.Location = new System.Drawing.Point(10, 26); this.linedefscount.Name = "linedefscount"; - this.linedefscount.Size = new System.Drawing.Size(43, 14); + this.linedefscount.Size = new System.Drawing.Size(63, 14); this.linedefscount.TabIndex = 16; this.linedefscount.Text = "0"; this.linedefscount.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -85,7 +85,7 @@ this.verticescount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); this.verticescount.Location = new System.Drawing.Point(10, 8); this.verticescount.Name = "verticescount"; - this.verticescount.Size = new System.Drawing.Size(43, 14); + this.verticescount.Size = new System.Drawing.Size(63, 14); this.verticescount.TabIndex = 15; this.verticescount.Text = "0"; this.verticescount.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -93,7 +93,7 @@ // thingslabel // this.thingslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.thingslabel.Location = new System.Drawing.Point(55, 81); + this.thingslabel.Location = new System.Drawing.Point(75, 81); this.thingslabel.Name = "thingslabel"; this.thingslabel.Size = new System.Drawing.Size(60, 15); this.thingslabel.TabIndex = 14; @@ -102,7 +102,7 @@ // sectorslabel // this.sectorslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.sectorslabel.Location = new System.Drawing.Point(55, 62); + this.sectorslabel.Location = new System.Drawing.Point(75, 62); this.sectorslabel.Name = "sectorslabel"; this.sectorslabel.Size = new System.Drawing.Size(60, 15); this.sectorslabel.TabIndex = 13; @@ -111,7 +111,7 @@ // sidedefslabel // this.sidedefslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.sidedefslabel.Location = new System.Drawing.Point(55, 44); + this.sidedefslabel.Location = new System.Drawing.Point(75, 44); this.sidedefslabel.Name = "sidedefslabel"; this.sidedefslabel.Size = new System.Drawing.Size(60, 15); this.sidedefslabel.TabIndex = 12; @@ -120,7 +120,7 @@ // linedefslabel // this.linedefslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.linedefslabel.Location = new System.Drawing.Point(55, 26); + this.linedefslabel.Location = new System.Drawing.Point(75, 26); this.linedefslabel.Name = "linedefslabel"; this.linedefslabel.Size = new System.Drawing.Size(60, 15); this.linedefslabel.TabIndex = 11; @@ -129,7 +129,7 @@ // verticeslabel // this.verticeslabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); - this.verticeslabel.Location = new System.Drawing.Point(55, 8); + this.verticeslabel.Location = new System.Drawing.Point(75, 8); this.verticeslabel.Name = "verticeslabel"; this.verticeslabel.Size = new System.Drawing.Size(60, 15); this.verticeslabel.TabIndex = 10; @@ -151,7 +151,7 @@ this.Controls.Add(this.verticeslabel); this.ForeColor = System.Drawing.SystemColors.GrayText; this.Name = "StatisticsControl"; - this.Size = new System.Drawing.Size(118, 104); + this.Size = new System.Drawing.Size(138, 104); this.ResumeLayout(false); } diff --git a/Source/Core/Controls/TextureSelectorControl.cs b/Source/Core/Controls/TextureSelectorControl.cs index 0410e3f7..4df91dd0 100644 --- a/Source/Core/Controls/TextureSelectorControl.cs +++ b/Source/Core/Controls/TextureSelectorControl.cs @@ -74,10 +74,12 @@ namespace CodeImp.DoomBuilder.Controls if(string.IsNullOrEmpty(texture.FilePathName) || texture is UnknownImage) DisplayImageSize(0, 0); //mxd else DisplayImageSize(texture.ScaledWidth, texture.ScaledHeight); //mxd - if(usepreviews ? !texture.IsPreviewLoaded : !texture.IsImageLoaded) timer.Start(); //mxd - + + if(usepreviews && !texture.IsPreviewLoaded) timer.Start(); //mxd + else if(!texture.IsImageLoaded) texture.LoadImage(); //mxd. In some cases the image may never me loaded by the DataManager + // Set the image - return (usepreviews ? texture.GetPreview() : texture.GetBitmap()); + return new Bitmap((usepreviews ? texture.GetPreview() : texture.GetBitmap())); } } diff --git a/Source/Core/Controls/ThingBrowserControl.cs b/Source/Core/Controls/ThingBrowserControl.cs index d010904d..be0ffae7 100644 --- a/Source/Core/Controls/ThingBrowserControl.cs +++ b/Source/Core/Controls/ThingBrowserControl.cs @@ -495,14 +495,25 @@ namespace CodeImp.DoomBuilder.Controls validnodes.Clear(); string match = tbFilter.Text.ToUpperInvariant(); + HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + + // First add nodes, which titles start with given text foreach(TreeNode node in nodes) { - if(node.Text.ToUpperInvariant().Contains(match)) + if(node.Text.ToUpperInvariant().StartsWith(match)) { typelist.Nodes.Add(node); + added.Add(node.Text); } } + // Then add nodes, which titles contain given text + foreach(TreeNode node in nodes) + { + if(!added.Contains(node.Text) && node.Text.ToUpperInvariant().Contains(match)) + typelist.Nodes.Add(node); + } + doupdatenode = true; doupdatetextbox = true; } diff --git a/Source/Core/Data/ColormapImage.cs b/Source/Core/Data/ColormapImage.cs index 487c483a..6f056381 100644 --- a/Source/Core/Data/ColormapImage.cs +++ b/Source/Core/Data/ColormapImage.cs @@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Colormap lump '" + Name + "' data format could not be read. Does this lump contain valid colormap data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Colormap lump \"" + Name + "\" data format could not be read. Does this lump contain valid colormap data at all?"); bitmap = null; } else @@ -97,7 +97,7 @@ namespace CodeImp.DoomBuilder.Data else { // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing colormap lump '" + Name + "'. Did you forget to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Missing colormap lump \"" + Name + "\". Did you forget to include required resources?"); loadfailed = true; } diff --git a/Source/Core/Data/DataLocation.cs b/Source/Core/Data/DataLocation.cs index c12df73c..1bc1c4cb 100644 --- a/Source/Core/Data/DataLocation.cs +++ b/Source/Core/Data/DataLocation.cs @@ -79,8 +79,8 @@ namespace CodeImp.DoomBuilder.Data } } - return name; - } + return (name ?? string.Empty); + } // This compares two locations public int CompareTo(DataLocation other) diff --git a/Source/Core/Data/FileImage.cs b/Source/Core/Data/FileImage.cs index adfefe4c..2d99cfa6 100644 --- a/Source/Core/Data/FileImage.cs +++ b/Source/Core/Data/FileImage.cs @@ -172,7 +172,7 @@ namespace CodeImp.DoomBuilder.Data // Not loaded? if(bitmap == null) { - General.ErrorLogger.Add(ErrorType.Error, "Image file '" + filepathname + "' data format could not be read, while loading image '" + this.Name + "'. Is this a valid picture file at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Image file \"" + filepathname + "\" data format could not be read, while loading image \"" + this.Name + "\". Is this a valid picture file at all?"); loadfailed = true; } else diff --git a/Source/Core/Data/FlatImage.cs b/Source/Core/Data/FlatImage.cs index 578a6c87..b098a67c 100644 --- a/Source/Core/Data/FlatImage.cs +++ b/Source/Core/Data/FlatImage.cs @@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Flat lump '" + Name + "' data format could not be read. Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Flat lump \"" + Name + "\" data format could not be read. Does this lump contain valid picture data at all?"); bitmap = null; } else @@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.Data else { // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing flat lump '" + Name + "'. Did you forget to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Missing flat lump \"" + Name + "\". Did you forget to include required resources?"); loadfailed = true; } diff --git a/Source/Core/Data/HighResImage.cs b/Source/Core/Data/HighResImage.cs index fb058813..9cb1a82b 100644 --- a/Source/Core/Data/HighResImage.cs +++ b/Source/Core/Data/HighResImage.cs @@ -125,17 +125,26 @@ namespace CodeImp.DoomBuilder.Data catch(Exception e) { // Unable to make bitmap - General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message); loadfailed = true; } int missingpatches = 0; //mxd - if(!loadfailed) + if(patches.Count == 0) //mxd + { + // No patches! + General.ErrorLogger.Add(ErrorType.Warning, "No patches are defined for texture \"" + this.Name + "\""); + loadfailed = true; + } + else if(!loadfailed) { // Go for all patches foreach(TexturePatch p in patches) { + //mxd. Some patches (like "TNT1A0") should be skipped + if(p.skip) continue; + // Get the patch data stream Stream patchdata = General.Map.Data.GetPatchData(p.lumpname, p.haslongname); @@ -161,7 +170,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } } @@ -175,7 +184,7 @@ namespace CodeImp.DoomBuilder.Data catch(InvalidDataException) { // Data cannot be read! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } @@ -217,7 +226,7 @@ namespace CodeImp.DoomBuilder.Data } // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\""); missingpatches++; //mxd } } @@ -243,12 +252,9 @@ namespace CodeImp.DoomBuilder.Data if(p.flipx || p.flipy) { RotateFlipType flip; - if(p.flipx && !p.flipy) - flip = RotateFlipType.RotateNoneFlipX; - else if(!p.flipx && p.flipy) - flip = RotateFlipType.RotateNoneFlipY; - else - flip = RotateFlipType.RotateNoneFlipXY; + if(p.flipx && !p.flipy) flip = RotateFlipType.RotateNoneFlipX; + else if(!p.flipx && p.flipy) flip = RotateFlipType.RotateNoneFlipY; + else flip = RotateFlipType.RotateNoneFlipXY; patchbmp.RotateFlip(flip); } @@ -258,15 +264,9 @@ namespace CodeImp.DoomBuilder.Data RotateFlipType rotate; switch(p.rotate) { - case 90: - rotate = RotateFlipType.Rotate90FlipNone; - break; - case 180: - rotate = RotateFlipType.Rotate180FlipNone; - break; - default: - rotate = RotateFlipType.Rotate270FlipNone; - break; + case 90: rotate = RotateFlipType.Rotate90FlipNone; break; + case 180: rotate = RotateFlipType.Rotate180FlipNone; break; + default: rotate = RotateFlipType.Rotate270FlipNone; break; } patchbmp.RotateFlip(rotate); } @@ -282,7 +282,7 @@ namespace CodeImp.DoomBuilder.Data } catch(Exception e) { - General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + p.lumpname + "' for alpha adjustment. " + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + p.lumpname + "\" for alpha adjustment. " + e.GetType().Name + ": " + e.Message); } if(bmpdata != null) @@ -347,7 +347,7 @@ namespace CodeImp.DoomBuilder.Data } catch(Exception e) { - General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture '" + this.Name + "' to apply render style. " + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Error, "Cannot lock texture \"" + this.Name + "\" to apply render style. " + e.GetType().Name + ": " + e.Message); } if(texturebmpdata != null) diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs index 8fc96103..fc89ce4c 100644 --- a/Source/Core/Data/ImageData.cs +++ b/Source/Core/Data/ImageData.cs @@ -277,7 +277,7 @@ namespace CodeImp.DoomBuilder.Data catch(Exception e) { bitmap = oldbitmap; - General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for pixel format conversion. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } } @@ -293,7 +293,7 @@ namespace CodeImp.DoomBuilder.Data } catch(Exception e) { - General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image '" + name + "' for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Warning, "Cannot lock image \"" + name + "\" for color correction. The image may not be displayed correctly.\n" + e.GetType().Name + ": " + e.Message); } // Bitmap locked? @@ -348,7 +348,7 @@ namespace CodeImp.DoomBuilder.Data { BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } - catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + this.filepathname + "' for glow color calculation. " + e.GetType().Name + ": " + e.Message); } + catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for glow color calculation. " + e.GetType().Name + ": " + e.Message); } if(bmpdata != null) { @@ -403,7 +403,7 @@ namespace CodeImp.DoomBuilder.Data { BitmapData bmpdata = null; try { bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); } - catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image '" + this.filepathname + "' for translucency check. " + e.GetType().Name + ": " + e.Message); } + catch(Exception e) { General.ErrorLogger.Add(ErrorType.Error, "Cannot lock image \"" + this.filepathname + "\" for translucency check. " + e.GetType().Name + ": " + e.Message); } if(bmpdata != null) { diff --git a/Source/Core/Data/PK3FileImage.cs b/Source/Core/Data/PK3FileImage.cs index 33da887d..4546fd21 100644 --- a/Source/Core/Data/PK3FileImage.cs +++ b/Source/Core/Data/PK3FileImage.cs @@ -140,7 +140,7 @@ namespace CodeImp.DoomBuilder.Data // Not loaded? if(bitmap == null) { - General.ErrorLogger.Add(ErrorType.Error, "Image file '" + filepathname + "' data format could not be read, while loading texture '" + this.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Image file \"" + filepathname + "\" data format could not be read, while loading texture \"" + this.Name + "\""); loadfailed = true; } else diff --git a/Source/Core/Data/SimpleTextureImage.cs b/Source/Core/Data/SimpleTextureImage.cs index eb79db49..7f740737 100644 --- a/Source/Core/Data/SimpleTextureImage.cs +++ b/Source/Core/Data/SimpleTextureImage.cs @@ -17,8 +17,8 @@ #region ================== Namespaces using System; -using CodeImp.DoomBuilder.IO; using System.IO; +using CodeImp.DoomBuilder.IO; #endregion @@ -32,7 +32,7 @@ namespace CodeImp.DoomBuilder.Data #region ================== Variables - private string lumpname; + private readonly string lumpname; #endregion @@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Data // Not loaded? if(bitmap == null) { - General.ErrorLogger.Add(ErrorType.Error, "Image lump '" + lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; } else @@ -108,7 +108,7 @@ namespace CodeImp.DoomBuilder.Data } else { - General.ErrorLogger.Add(ErrorType.Error, "Image lump '" + lumpname + "' could not be found, while loading texture '" + this.Name + "'. Did you forget to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + lumpname + "\" could not be found, while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); loadfailed = true; } diff --git a/Source/Core/Data/SpriteImage.cs b/Source/Core/Data/SpriteImage.cs index 4c31db5f..9e1e870f 100644 --- a/Source/Core/Data/SpriteImage.cs +++ b/Source/Core/Data/SpriteImage.cs @@ -95,7 +95,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Sprite lump '" + Name + "' data format could not be read. Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Sprite lump \"" + Name + "\" data format could not be read. Does this lump contain valid picture data at all?"); bitmap = null; } else @@ -133,7 +133,7 @@ namespace CodeImp.DoomBuilder.Data else { // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing sprite lump '" + Name + "'. Forgot to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Missing sprite lump \"" + Name + "\". Forgot to include required resources?"); } // Pass on to base diff --git a/Source/Core/Data/TextureImage.cs b/Source/Core/Data/TextureImage.cs index 9ca200b8..768bf7f2 100644 --- a/Source/Core/Data/TextureImage.cs +++ b/Source/Core/Data/TextureImage.cs @@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.Data catch(Exception e) { // Unable to make bitmap - General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image '" + this.Name + "'. " + e.GetType().Name + ": " + e.Message); + General.ErrorLogger.Add(ErrorType.Error, "Unable to load texture image \"" + this.Name + "\". " + e.GetType().Name + ": " + e.Message); loadfailed = true; } @@ -124,7 +124,7 @@ namespace CodeImp.DoomBuilder.Data if(reader is UnknownImageReader) { // Data is in an unknown format! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } @@ -138,7 +138,7 @@ namespace CodeImp.DoomBuilder.Data catch(InvalidDataException) { // Data cannot be read! - General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?"); + General.ErrorLogger.Add(ErrorType.Error, "Patch lump \"" + p.lumpname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); loadfailed = true; missingpatches++; //mxd } @@ -150,7 +150,7 @@ namespace CodeImp.DoomBuilder.Data else { // Missing a patch lump! - General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'. Did you forget to include required resources?"); + General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump \"" + p.lumpname + "\" while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); loadfailed = true; missingpatches++; //mxd } diff --git a/Source/Core/Data/TexturePatch.cs b/Source/Core/Data/TexturePatch.cs index 7b7c9101..efec5da6 100644 --- a/Source/Core/Data/TexturePatch.cs +++ b/Source/Core/Data/TexturePatch.cs @@ -59,6 +59,7 @@ namespace CodeImp.DoomBuilder.Data public readonly TexturePathRenderStyle style; public readonly TexturePathBlendStyle blendstyle; //mxd public readonly float tintammount;//mxd + public readonly bool skip; //mxd // Constructor for simple patches public TexturePatch(string lumpname, int x, int y) @@ -76,6 +77,7 @@ namespace CodeImp.DoomBuilder.Data this.blendstyle = TexturePathBlendStyle.None;//mxd this.tintammount = 0; //mxd this.haslongname = false; //mxd + this.skip = false; //mxd } //mxd. Constructor for hires patches @@ -94,6 +96,7 @@ namespace CodeImp.DoomBuilder.Data this.blendstyle = patch.BlendStyle; this.tintammount = patch.TintAmmount; this.haslongname = (Path.GetFileNameWithoutExtension(this.lumpname) != this.lumpname); + this.skip = patch.Skip; //mxd. Check data so we don't perform unneeded operations later on if(this.alpha == 1.0f) diff --git a/Source/Core/Editing/ClassicMode.cs b/Source/Core/Editing/ClassicMode.cs index 3dcedeff..2b38cc96 100644 --- a/Source/Core/Editing/ClassicMode.cs +++ b/Source/Core/Editing/ClassicMode.cs @@ -565,6 +565,10 @@ namespace CodeImp.DoomBuilder.Editing // Save mouse down position mousedownpos = mousepos; mousedownmappos = mousemappos; + + //mxd. Looks like in some cases (very detailed maps / slow CPUs) OnMouseUp is not fired + // This is my attempt at fixing this... + if(e.Button == mousedragging) mousedragging = MouseButtons.None; // Let the base class know base.OnMouseDown(e); diff --git a/Source/Core/Editing/CopyPasteManager.cs b/Source/Core/Editing/CopyPasteManager.cs index 8e72b861..618f0cc0 100644 --- a/Source/Core/Editing/CopyPasteManager.cs +++ b/Source/Core/Editing/CopyPasteManager.cs @@ -246,7 +246,7 @@ namespace CodeImp.DoomBuilder.Editing // Write data to stream MemoryStream memstream = new MemoryStream(); ClipboardStreamWriter writer = new ClipboardStreamWriter(); //mxd - writer.Write(copyset, memstream, General.Map.Config.UseLongTextureNames); + writer.Write(copyset, memstream); // Set on clipboard Clipboard.SetData(CLIPBOARD_DATA_FORMAT, memstream); @@ -290,37 +290,31 @@ namespace CodeImp.DoomBuilder.Editing // Create undo General.MainWindow.DisplayStatus(StatusType.Action, "Pasted selected elements."); General.Map.UndoRedo.CreateUndo("Paste"); - - // Read from clipboard - Stream memstream = (Stream)Clipboard.GetData(CLIPBOARD_DATA_FORMAT); - memstream.Seek(0, SeekOrigin.Begin); // Mark all current geometry General.Map.Map.ClearAllMarks(true); - // Read data stream - ClipboardStreamReader reader = new ClipboardStreamReader(); //mxd - General.Map.Map.BeginAddRemove(); - reader.Read(General.Map.Map, memstream); - General.Map.Map.EndAddRemove(); + // Read from clipboard + using(Stream memstream = (Stream)Clipboard.GetData(CLIPBOARD_DATA_FORMAT)) + { + // Rewind before use + memstream.Seek(0, SeekOrigin.Begin); + + // Read data stream + ClipboardStreamReader reader = new ClipboardStreamReader(); //mxd + General.Map.Map.BeginAddRemove(); + bool success = reader.Read(General.Map.Map, memstream); + General.Map.Map.EndAddRemove(); + if(!success) //mxd + { + General.Map.UndoRedo.WithdrawUndo(); // This will also mess with the marks... + General.Map.Map.ClearAllMarks(true); // So re-mark all current geometry... + } + } // The new geometry is not marked, so invert the marks to get it marked General.Map.Map.InvertAllMarks(); - // Convert UDMF fields back to flags and activations, if needed - if(!(General.Map.FormatInterface is UniversalMapSetIO || General.Map.FormatInterface is SRB2MapSetIO)) General.Map.Map.TranslateFromUDMF(); - - //mxd. Translate texture names - General.Map.Map.TranslateTextureNames(General.Map.Config.UseLongTextureNames, true); - - // Modify tags and actions if preferred - if(options.ChangeTags == PasteOptions.TAGS_REMOVE) Tools.RemoveMarkedTags(); - if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags(); - if(options.RemoveActions) Tools.RemoveMarkedActions(); - - // Clean up - memstream.Dispose(); - // Check if anything was pasted List<Thing> things = General.Map.Map.GetMarkedThings(true); //mxd int totalpasted = things.Count; @@ -328,14 +322,25 @@ namespace CodeImp.DoomBuilder.Editing totalpasted += General.Map.Map.GetMarkedLinedefs(true).Count; totalpasted += General.Map.Map.GetMarkedSidedefs(true).Count; totalpasted += General.Map.Map.GetMarkedSectors(true).Count; + if(totalpasted > 0) { + // Convert UDMF fields back to flags and activations, if needed + if(!(General.Map.FormatInterface is UniversalMapSetIO || General.Map.FormatInterface is SRB2MapSetIO)) General.Map.Map.TranslateFromUDMF(); + + //mxd. Translate texture names + General.Map.Map.TranslateTextureNames(General.Map.Config.UseLongTextureNames, true); + + // Modify tags and actions if preferred + if(options.ChangeTags == PasteOptions.TAGS_REMOVE) Tools.RemoveMarkedTags(); + if(options.ChangeTags == PasteOptions.TAGS_RENUMBER) Tools.RenumberMarkedTags(); + if(options.RemoveActions) Tools.RemoveMarkedActions(); + foreach(Thing t in things) t.UpdateConfiguration(); //mxd General.Map.ThingsFilter.Update(); General.Editing.Mode.OnPasteEnd(options.Copy()); General.Plugins.OnPasteEnd(options); } - return; } } } diff --git a/Source/Core/Editing/GridSetup.cs b/Source/Core/Editing/GridSetup.cs index a053d69b..fd0eb749 100644 --- a/Source/Core/Editing/GridSetup.cs +++ b/Source/Core/Editing/GridSetup.cs @@ -246,7 +246,7 @@ namespace CodeImp.DoomBuilder.Editing // This snaps to the nearest grid coordinate public Vector2D SnappedToGrid(Vector2D v) { - return GridSetup.SnappedToGrid(v, gridsizef, gridsizefinv); + return SnappedToGrid(v, gridsizef, gridsizefinv); } // This snaps to the nearest grid coordinate @@ -291,6 +291,9 @@ namespace CodeImp.DoomBuilder.Editing // Not lower than 1 if(gridsize >= 2) { + //mxd. Disable automatic grid resizing + General.MainWindow.DisableDynamicGridResize(); + // Change grid SetGridSize(gridsize >> 1); @@ -307,6 +310,9 @@ namespace CodeImp.DoomBuilder.Editing // Not higher than 1024 if(gridsize <= 512) { + //mxd. Disable automatic grid resizing + General.MainWindow.DisableDynamicGridResize(); + // Change grid SetGridSize(gridsize << 1); diff --git a/Source/Core/Editing/ThingsFilter.cs b/Source/Core/Editing/ThingsFilter.cs index 9d58a380..d93d6450 100644 --- a/Source/Core/Editing/ThingsFilter.cs +++ b/Source/Core/Editing/ThingsFilter.cs @@ -272,7 +272,7 @@ namespace CodeImp.DoomBuilder.Editing //Integrity check if(!IsValid()) - General.ErrorLogger.Add(ErrorType.Warning, "Things filter '" + name + "' has invalid properties. Configure the things filter to fix this!"); + General.ErrorLogger.Add(ErrorType.Warning, "Things filter \"" + name + "\" has invalid properties. Configure the things filter to fix this!"); } //mxd diff --git a/Source/Core/Editing/UndoManager.cs b/Source/Core/Editing/UndoManager.cs index 66f8fea9..aab46cc0 100644 --- a/Source/Core/Editing/UndoManager.cs +++ b/Source/Core/Editing/UndoManager.cs @@ -1116,8 +1116,12 @@ namespace CodeImp.DoomBuilder.Editing Sidedef sd = (sindex >= 0) ? General.Map.Map.GetSidedefByIndex(sindex) : null; l.AttachFront(sd); l.Marked = true; - if (l.Tag != 0) linedeftags.Add(l.Tag); - if (sd != null) sd.Marked = true; + if (l.Tag != 0) linedeftags.Add(l.Tag); + if (sd != null) + { + sd.Marked = true; + if(sd.Sector != null) sd.Sector.UpdateNeeded = true; //mxd. Sector needs to be updated as well... + } geometrychanged = true; } @@ -1141,8 +1145,12 @@ namespace CodeImp.DoomBuilder.Editing Sidedef sd = (sindex >= 0) ? General.Map.Map.GetSidedefByIndex(sindex) : null; l.AttachBack(sd); l.Marked = true; - if (l.Tag != 0) linedeftags.Add(l.Tag); - if (sd != null) sd.Marked = true; + if (l.Tag != 0) linedeftags.Add(l.Tag); + if (sd != null) + { + sd.Marked = true; + if(sd.Sector != null) sd.Sector.UpdateNeeded = true; //mxd. Sector needs to be updated as well... + } geometrychanged = true; } diff --git a/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs b/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs index be89edfe..2e5ea4b7 100644 --- a/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs +++ b/Source/Core/GZBuilder/Controls/TagSelector.Designer.cs @@ -68,8 +68,7 @@ this.newTag.Size = new System.Drawing.Size(54, 24); this.newTag.TabIndex = 2; this.newTag.Text = "New"; - this.tooltip.SetToolTip(this.newTag, "Finds a tag, which is not used as a tag or tag action argument \r\nby any map eleme" + - "nt"); + this.tooltip.SetToolTip(this.newTag, "Find a tag, which is not used as a tag or tag action argument\r\nby any map element"); this.newTag.UseVisualStyleBackColor = true; this.newTag.Click += new System.EventHandler(this.newTag_Click); // @@ -80,7 +79,7 @@ this.unusedTag.Size = new System.Drawing.Size(54, 24); this.unusedTag.TabIndex = 3; this.unusedTag.Text = "Unused"; - this.tooltip.SetToolTip(this.unusedTag, "Finds a tag, which is not used as a tag \r\nby any map element of this type"); + this.tooltip.SetToolTip(this.unusedTag, "Find a tag, which is not used as a tag\r\nby any map element of this type"); this.unusedTag.UseVisualStyleBackColor = true; this.unusedTag.Click += new System.EventHandler(this.unusedTag_Click); // @@ -98,7 +97,7 @@ this.clear.Name = "clear"; this.clear.Size = new System.Drawing.Size(26, 24); this.clear.TabIndex = 4; - this.tooltip.SetToolTip(this.clear, "Sets tag to 0"); + this.tooltip.SetToolTip(this.clear, "Set tag to 0"); this.clear.UseVisualStyleBackColor = true; this.clear.Click += new System.EventHandler(this.clear_Click); // diff --git a/Source/Core/GZBuilder/Controls/TagSelector.cs b/Source/Core/GZBuilder/Controls/TagSelector.cs index b8744433..937e0f65 100644 --- a/Source/Core/GZBuilder/Controls/TagSelector.cs +++ b/Source/Core/GZBuilder/Controls/TagSelector.cs @@ -255,9 +255,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls private void TagSelector_Resize(object sender, EventArgs e) { clear.Left = this.Width - clear.Width - clear.Margin.Right; - unusedTag.Left = clear.Left - clear.Margin.Left - unusedTag.Margin.Right - unusedTag.Width; - newTag.Left = unusedTag.Left - unusedTag.Margin.Left - newTag.Margin.Right - newTag.Width; - cbTagPicker.Width = newTag.Left - newTag.Margin.Left - cbTagPicker.Margin.Right - cbTagPicker.Left; + unusedTag.Left = clear.Left - unusedTag.Margin.Right - unusedTag.Width; + newTag.Left = unusedTag.Left - newTag.Margin.Right - newTag.Width; + cbTagPicker.Width = newTag.Left - cbTagPicker.Margin.Right - cbTagPicker.Left; } #endregion diff --git a/Source/Core/GZBuilder/Controls/TagsSelector.cs b/Source/Core/GZBuilder/Controls/TagsSelector.cs index 7168b9b1..427fb979 100644 --- a/Source/Core/GZBuilder/Controls/TagsSelector.cs +++ b/Source/Core/GZBuilder/Controls/TagsSelector.cs @@ -257,6 +257,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls if(tagpicker.SelectedIndex == -1) tagpicker.Text = tag.ToString(); } + clear.Enabled = (tagpicker.Text.Trim() != "0"); + blockupdate = false; } @@ -278,6 +280,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls private void clear_Click(object sender, EventArgs e) { + tagpicker.Focus(); tagpicker.SelectedIndex = -1; tagpicker.Text = "0"; } @@ -356,6 +359,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls { if(blockupdate) return; + clear.Enabled = (tagpicker.Text.Trim() != "0"); if(tagpicker.SelectedItem != null) { TagInfo info = (TagInfo)tagpicker.SelectedItem; @@ -420,11 +424,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.Controls private void TagsSelector_Resize(object sender, EventArgs e) { clear.Left = this.Width - clear.Width - clear.Margin.Right; - unusedtag.Left = clear.Left - clear.Margin.Left - unusedtag.Margin.Right - unusedtag.Width; - newtag.Left = unusedtag.Left - unusedtag.Margin.Left - newtag.Margin.Right - newtag.Width; - tagpicker.Width = newtag.Left - newtag.Margin.Left - tagpicker.Margin.Right - tagpicker.Left; + unusedtag.Left = clear.Left - unusedtag.Margin.Right - unusedtag.Width; + newtag.Left = unusedtag.Left - newtag.Margin.Right - newtag.Width; + tagpicker.Width = newtag.Left - tagpicker.Margin.Right - tagpicker.Left; removetag.Left = clear.Left; - addtag.Left = removetag.Left - removetag.Margin.Left - addtag.Margin.Right - addtag.Width; + addtag.Left = removetag.Left - addtag.Margin.Right - addtag.Width; } #endregion diff --git a/Source/Core/GZBuilder/Data/EngineInfo.cs b/Source/Core/GZBuilder/Data/EngineInfo.cs index 55d73a86..de217051 100644 --- a/Source/Core/GZBuilder/Data/EngineInfo.cs +++ b/Source/Core/GZBuilder/Data/EngineInfo.cs @@ -45,7 +45,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data { if(testprogramname == DEFAULT_ENGINE_NAME && !String.IsNullOrEmpty(TestProgram)) { - //get engine name from path + // Get engine name from path testprogramname = Path.GetFileNameWithoutExtension(TestProgram); } @@ -59,12 +59,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data if(File.Exists(TestProgram)) { Icon i = Icon.ExtractAssociatedIcon(TestProgram); - if(i != null) icon = i.ToBitmap(); + icon = (i != null ? i.ToBitmap() : new Bitmap(Properties.Resources.Question)); } - - if(icon == null) + else { - icon = new Bitmap(16, 16); + icon = new Bitmap(Properties.Resources.Warning); } } diff --git a/Source/Core/GZBuilder/Geometry/Line3D.cs b/Source/Core/GZBuilder/Geometry/Line3D.cs index 9cd37036..f7ed0d9a 100644 --- a/Source/Core/GZBuilder/Geometry/Line3D.cs +++ b/Source/Core/GZBuilder/Geometry/Line3D.cs @@ -22,6 +22,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry { this.Start = start; this.End = end; + this.Start2D = start; + this.End2D = end; this.Color = General.Colors.InfoLine; this.RenderArrowhead = true; } @@ -30,6 +32,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry { this.Start = start; this.End = end; + this.Start2D = start; + this.End2D = end; this.Color = General.Colors.InfoLine; this.RenderArrowhead = renderArrowhead; } @@ -38,6 +42,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry { this.Start = start; this.End = end; + this.Start2D = start; + this.End2D = end; this.Color = color; this.RenderArrowhead = true; } @@ -46,6 +52,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Geometry { this.Start = start; this.End = end; + this.Start2D = start; + this.End2D = end; this.Color = color; this.RenderArrowhead = renderArrowhead; } diff --git a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs index 55d10566..7773d22f 100644 --- a/Source/Core/GZBuilder/Windows/ExceptionDialog.cs +++ b/Source/Core/GZBuilder/Windows/ExceptionDialog.cs @@ -130,7 +130,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows // Get OS name ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem"); - foreach(ManagementObject mo in searcher.Get()) + foreach(ManagementBaseObject mo in searcher.Get()) { result += "OS: " + mo["Caption"] + Environment.NewLine; break; @@ -138,7 +138,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Windows // Get GPU name searcher = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController"); - foreach(ManagementObject mo in searcher.Get()) + foreach(ManagementBaseObject mo in searcher.Get()) { PropertyData bpp = mo.Properties["CurrentBitsPerPixel"]; PropertyData description = mo.Properties["Description"]; diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index 7c5e9f78..bc831fef 100644 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -102,7 +102,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 MemoryStream ms = LoadFile(containers, mde.ModelNames[i], true); if(ms == null) { - General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': unable to find file."); + General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": unable to find file."); continue; } @@ -112,7 +112,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 case ".md3": if(!string.IsNullOrEmpty(mde.FrameNames[i])) { - General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': frame names are not supported for MD3 models!"); + General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": frame names are not supported for MD3 models!"); continue; } result = ReadMD3Model(ref bbs, useSkins, ms, device, mde.FrameIndices[i]); @@ -131,7 +131,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //got errors? if(!String.IsNullOrEmpty(result.Errors)) { - General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': " + result.Errors); + General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + result.Errors); } else { @@ -164,7 +164,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); - errors.Add("image format '" + ext + "' is not supported!"); + errors.Add("image format \"" + ext + "\" is not supported!"); continue; } @@ -177,7 +177,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(t == null) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); - errors.Add("unable to load skin '" + result.Skins[m] + "'"); + errors.Add("unable to load skin \"" + result.Skins[m] + "\""); continue; } @@ -191,7 +191,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(t == null) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); - errors.Add("unable to load texture '" + mde.TextureNames[i] + "'"); + errors.Add("unable to load texture \"" + mde.TextureNames[i] + "\""); } else { @@ -203,7 +203,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(errors.Count > 0) { foreach(string e in errors) - General.ErrorLogger.Add(ErrorType.Error, "Error while loading '" + mde.ModelNames[i] + "': " + e); + General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + e); } } } @@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 string magic = ReadString(br, 4); if(magic != "IDP3") { - result.Errors = "unknown header: expected 'IDP3', but got '" + magic + "'"; + result.Errors = "unknown header: expected \"IDP3\", but got \"" + magic + "\""; return result; } @@ -341,7 +341,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 long start = br.BaseStream.Position; string magic = ReadString(br, 4); - if(magic != "IDP3") return "error while reading surface. Unknown header: expected 'IDP3', but got '" + magic + "'"; + if(magic != "IDP3") return "error while reading surface. Unknown header: expected \"IDP3\", but got \"" + magic + "\""; string name = ReadString(br, 64); int flags = br.ReadInt32(); @@ -432,8 +432,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 { string magic = ReadString(br, 4); if(magic != "IDP2") //magic number: "IDP2" - { - result.Errors = "unknown header: expected 'IDP2', but got '" + magic + "'"; + { + result.Errors = "unknown header: expected \"IDP2\", but got \"" + magic + "\""; return result; } @@ -521,7 +521,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 // No dice? Bail out! if(!framefound) { - result.Errors = "unable to find frame '" + framename + "'!"; + result.Errors = "unable to find frame \"" + framename + "\"!"; return result; } } diff --git a/Source/Core/General/FileLockChecker.cs b/Source/Core/General/FileLockChecker.cs index 79aa82c0..64d0226d 100644 --- a/Source/Core/General/FileLockChecker.cs +++ b/Source/Core/General/FileLockChecker.cs @@ -176,8 +176,8 @@ namespace CodeImp.DoomBuilder foreach(Process process in result.Processes) { result.Error += Path.GetFileName(process.MainModule.FileName) - + " ('" + process.MainModule.FileName - + "', started at " + process.StartTime + ")" + + " (\"" + process.MainModule.FileName + + "\", started at " + process.StartTime + ")" + Environment.NewLine + Environment.NewLine; } } diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs index a31a12ea..8307d02d 100644 --- a/Source/Core/General/General.cs +++ b/Source/Core/General/General.cs @@ -318,7 +318,7 @@ namespace CodeImp.DoomBuilder ConfigurationInfo cfginfo = new ConfigurationInfo(cfg, fullfilename); // Add to lists - General.WriteLogLine("Registered game configuration '" + cfginfo.Name + "' from '" + fullfilename + "'"); + General.WriteLogLine("Registered game configuration \"" + cfginfo.Name + "\" from \"" + fullfilename + "\""); configs.Add(cfginfo); } } @@ -369,7 +369,7 @@ namespace CodeImp.DoomBuilder catch(Exception e) { // Unable to load configuration - errorlogger.Add(ErrorType.Error, "Unable to load the nodebuilder configuration '" + de.Key + "' from \"" + Path.GetFileName(filepath) + "\". Error: " + e.Message); + errorlogger.Add(ErrorType.Error, "Unable to load the nodebuilder configuration \"" + de.Key + "\" from \"" + Path.GetFileName(filepath) + "\". Error: " + e.Message); } } } @@ -677,7 +677,7 @@ namespace CodeImp.DoomBuilder // Show any errors if preferred if(errorlogger.IsErrorAdded) { - mainwindow.DisplayStatus(StatusType.Warning, "There were errors during program statup!"); + mainwindow.DisplayStatus(StatusType.Warning, "There were errors during program startup!"); if(!delaymainwindow && General.Settings.ShowErrorsWindow) mainwindow.ShowErrors(); } @@ -707,7 +707,7 @@ namespace CodeImp.DoomBuilder if((DateTime.Now - File.GetLastWriteTime(backup)).TotalDays > 30) { File.Delete(backup); - WriteLogLine("Removed '" + backup + "' map backup."); + WriteLogLine("Removed \"" + backup + "\" map backup."); } } } @@ -749,7 +749,7 @@ namespace CodeImp.DoomBuilder MessageBoxIcon.Exclamation) == DialogResult.Yes) { // Go to DirectX End-User Runtime Web Installer page (mxd) - OpenWebsite("http://www.microsoft.com/en-us/download/details.aspx?id=35"); + OpenWebsite("https://www.microsoft.com/en-us/download/details.aspx?id=35&44F86079-8679-400C-BFF2-9CA5F2BCBDFC=1"); } // End program here @@ -859,7 +859,7 @@ namespace CodeImp.DoomBuilder catch(Exception) { } // Warn the user? - if(!portablemode) ShowWarningMessage("Failed to enable portable mode.\nMake sure you have write premission for '" + apppath + "' directory.", MessageBoxButtons.OK); + if(!portablemode) ShowWarningMessage("Failed to enable portable mode.\nMake sure you have write premission for \"" + apppath + "\" directory.", MessageBoxButtons.OK); } // Resource? else if(string.Compare(curarg, "-RESOURCE", true) == 0) @@ -1219,8 +1219,8 @@ namespace CodeImp.DoomBuilder if(changemapwindow.ShowDialog(mainwindow) != DialogResult.OK) return; // Display status - mainwindow.DisplayStatus(StatusType.Busy, "Switching to map '" + changemapwindow.Options.CurrentName + "'..."); - WriteLogLine("Switching to map '" + changemapwindow.Options.CurrentName + "'..."); + mainwindow.DisplayStatus(StatusType.Busy, "Switching to map \"" + changemapwindow.Options.CurrentName + "\"..."); + WriteLogLine("Switching to map \"" + changemapwindow.Options.CurrentName + "\"..."); Cursor.Current = Cursors.WaitCursor; @@ -1431,8 +1431,14 @@ namespace CodeImp.DoomBuilder mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!"); if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors(); } - else + else if(result) + { mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + "."); + } + else + { + mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd + } Cursor.Current = Cursors.Default; } @@ -1499,10 +1505,16 @@ namespace CodeImp.DoomBuilder { // Show any errors if preferred mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!"); - if(!delaymainwindow && General.Settings.ShowErrorsWindow) mainwindow.ShowErrors(); + if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors(); } - else + else if(result) + { mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + "."); + } + else + { + mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd + } Cursor.Current = Cursors.Default; } @@ -1561,8 +1573,14 @@ namespace CodeImp.DoomBuilder mainwindow.DisplayStatus(StatusType.Warning, "There were errors during saving!"); if(!delaymainwindow && settings.ShowErrorsWindow) mainwindow.ShowErrors(); } + else if(result) + { + mainwindow.DisplayStatus(StatusType.Info, "Map saved in " + map.FileTitle + "."); + } else - mainwindow.DisplayStatus(StatusType.Info, "Map saved into " + map.FileTitle + "."); + { + mainwindow.DisplayStatus(StatusType.Info, "Map saving cancelled."); //mxd + } Cursor.Current = Cursors.Default; } diff --git a/Source/Core/General/Launcher.cs b/Source/Core/General/Launcher.cs index 3f659eb9..762ff71c 100644 --- a/Source/Core/General/Launcher.cs +++ b/Source/Core/General/Launcher.cs @@ -245,7 +245,7 @@ namespace CodeImp.DoomBuilder { if(process != null) { - General.ShowWarningMessage("Game engine is already running." + Environment.NewLine + "Please close '" + process.MainModule.FileName + "' first.", MessageBoxButtons.OK); + General.ShowWarningMessage("Game engine is already running." + Environment.NewLine + "Please close \"" + process.MainModule.FileName + "\" first.", MessageBoxButtons.OK); return true; } diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs index 1ca70b56..6fafb93f 100644 --- a/Source/Core/General/MapManager.cs +++ b/Source/Core/General/MapManager.cs @@ -724,7 +724,7 @@ namespace CodeImp.DoomBuilder internal bool SaveMap(string newfilepathname, SavePurpose purpose) { string settingsfile; - WAD targetwad; + WAD targetwad = null; bool includenodes; General.WriteLogLine("Saving map to file: " + newfilepathname); @@ -773,6 +773,31 @@ namespace CodeImp.DoomBuilder includenodes = VerifyNodebuilderLumps(tempwad, TEMP_MAP_HEADER); } + //mxd. Target file is read-only? + FileInfo info = new FileInfo(newfilepathname); + if(info.Exists && info.IsReadOnly) + { + if(General.ShowWarningMessage("Unable to save the map: target file is read-only.\nRemove read-only flag and save the map anyway?", MessageBoxButtons.YesNo) == DialogResult.Yes) + { + General.WriteLogLine("Removing read-only flag from the map file..."); + try + { + info.IsReadOnly = false; + } + catch(Exception e) + { + General.ShowErrorMessage("Failed to remove read-only flag from \"" + filepathname + "\":" + Environment.NewLine + Environment.NewLine + e.Message, MessageBoxButtons.OK); + General.WriteLogLine("Failed to remove read-only flag from \"" + filepathname + "\":" + e.Message); + return false; + } + } + else + { + General.WriteLogLine("Map saving cancelled..."); + return false; + } + } + // Suspend data resources data.Suspend(); @@ -916,22 +941,29 @@ namespace CodeImp.DoomBuilder targetwad = new WAD(newfilepathname); } } - catch (IOException) + catch(Exception e) { - General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); - if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up + General.ShowErrorMessage("Unable to write the map to target file \"" + newfilepathname + "\":\n" + e.Message, MessageBoxButtons.OK); + if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) + { + //mxd. Clean-up + if(File.Exists(newfilepathname)) + { + //mxd. We MAY've just deleted the map from the target file. Let's pretend this never happened + if(targetwad != null) targetwad.Dispose(); + File.Delete(newfilepathname); + File.Move(origwadfile, newfilepathname); + } + else + { + File.Delete(origwadfile); + } + } + data.Resume(); - General.WriteLogLine("Map saving failed"); + General.WriteLogLine("Map saving failed: " + e.Message); return false; } - catch (UnauthorizedAccessException) - { - General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK); - if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up - data.Resume(); - General.WriteLogLine("Map saving failed"); - return false; - } // Copy map lumps to target file CopyLumpsByType(tempwad, TEMP_MAP_HEADER, targetwad, origmapname, true, true, includenodes, true); diff --git a/Source/Core/General/UpdateChecker.cs b/Source/Core/General/UpdateChecker.cs index 26c34fcf..1bd87f68 100644 --- a/Source/Core/General/UpdateChecker.cs +++ b/Source/Core/General/UpdateChecker.cs @@ -10,8 +10,9 @@ namespace CodeImp.DoomBuilder { internal static class UpdateChecker { + private const string NO_UPDATE_REQUIRED = "Your version is up to date."; + private static BackgroundWorker worker; - private static string errordesc; private static bool verbose; internal static void PerformCheck(bool verbosemode) @@ -19,15 +20,7 @@ namespace CodeImp.DoomBuilder // Update check already runing? if(worker != null && worker.IsBusy) { - 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(); - } + if(verbosemode) General.ShowWarningMessage("Update check is already running!", MessageBoxButtons.OK); return; } @@ -45,7 +38,7 @@ namespace CodeImp.DoomBuilder string updaterpath = Path.Combine(General.AppPath, "Updater.exe"); if(!File.Exists(updaterpath)) { - errordesc = "Update check failed: '" + updaterpath + "' does not exist!"; + e.Result = "Update check failed: \"" + updaterpath + "\" does not exist!"; e.Cancel = true; return; } @@ -53,7 +46,7 @@ namespace CodeImp.DoomBuilder string inipath = Path.Combine(General.AppPath, "Updater.ini"); if(!File.Exists(inipath)) { - errordesc = "Update check failed: '" + inipath + "' does not exist!"; + e.Result = "Update check failed: \"" + inipath + "\" does not exist!"; e.Cancel = true; return; } @@ -61,7 +54,7 @@ namespace CodeImp.DoomBuilder string url = GetDownloadUrl(inipath); if(string.IsNullOrEmpty(url)) { - errordesc = "Update check failed: failed to get update url from Updater.ini!"; + e.Result = "Update check failed: failed to get update url from Updater.ini!"; e.Cancel = true; return; } @@ -77,7 +70,7 @@ namespace CodeImp.DoomBuilder { if(stream == null) { - errordesc = "Update check failed: failed to retrieve remote revision info."; + e.Result = "Update check failed: failed to retrieve remote revision info."; e.Cancel = true; return; } @@ -90,7 +83,7 @@ namespace CodeImp.DoomBuilder if(!int.TryParse(s, out remoterev)) { - errordesc = "Update check failed: failed to retrieve remote revision number."; + e.Result = "Update check failed: failed to retrieve remote revision number."; e.Cancel = true; return; } @@ -103,7 +96,7 @@ namespace CodeImp.DoomBuilder if(string.IsNullOrEmpty(changelog)) { - errordesc = "Update check failed: failed to retrieve changelog."; + e.Result = "Update check failed: failed to retrieve changelog."; e.Cancel = true; return; } @@ -113,24 +106,20 @@ namespace CodeImp.DoomBuilder } else if(verbose) { - errordesc = "Your version is up to date"; + e.Result = NO_UPDATE_REQUIRED; } } - private static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs runWorkerCompletedEventArgs) + private static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { worker = null; + string errordesc = (e.Result != null ? e.Result.ToString() : string.Empty); if(!string.IsNullOrEmpty(errordesc)) { if(verbose) - { General.ShowWarningMessage(errordesc, MessageBoxButtons.OK); - } - else - { - General.ErrorLogger.Add(ErrorType.Warning, errordesc); - General.MainWindow.ShowErrors(); - } + else if(errordesc != NO_UPDATE_REQUIRED) + General.ErrorLogger.Add(ErrorType.Error, errordesc); } } @@ -178,47 +167,42 @@ namespace CodeImp.DoomBuilder private static MemoryStream DownloadWebFile(string url) { // Open a data stream from the supplied URL - WebRequest webReq = WebRequest.Create(url); - WebResponse webResponse; + WebRequest request = WebRequest.Create(url); + WebResponse response; try { - webResponse = webReq.GetResponse(); + response = request.GetResponse(); } catch(WebException) { return null; } - Stream dataStream = webResponse.GetResponseStream(); + Stream source = response.GetResponseStream(); + if(source == null) return null; // Download the data in chuncks - byte[] dataBuffer = new byte[1024]; + byte[] buffer = new byte[1024]; // Download the data - MemoryStream memoryStream = new MemoryStream(); + MemoryStream result = new MemoryStream(); while(!General.MainWindow.IsDisposed) { // Let's try and read the data - int bytesFromStream = dataStream.Read(dataBuffer, 0, dataBuffer.Length); - if(bytesFromStream == 0) - { - // Download complete - break; - } - else - { - // Write the downloaded data - memoryStream.Write(dataBuffer, 0, bytesFromStream); - } + int numbytes = source.Read(buffer, 0, buffer.Length); + if(numbytes == 0) break; // Download complete + + // Write the downloaded data + result.Write(buffer, 0, numbytes); } // Release resources - dataStream.Close(); + source.Close(); // Rewind and return the stream - memoryStream.Position = 0; - return memoryStream; + result.Position = 0; + return result; } private static string GetDownloadUrl(string filename) diff --git a/Source/Core/Geometry/InterpolationTools.cs b/Source/Core/Geometry/InterpolationTools.cs index 7ca42aa1..7d8f2fb9 100644 --- a/Source/Core/Geometry/InterpolationTools.cs +++ b/Source/Core/Geometry/InterpolationTools.cs @@ -21,7 +21,7 @@ namespace CodeImp.DoomBuilder.Geometry case Mode.EASE_IN_SINE: return EaseInSine(val1, val2, delta); case Mode.EASE_OUT_SINE: return EaseOutSine(val1, val2, delta); case Mode.EASE_IN_OUT_SINE: return EaseInOutSine(val1, val2, delta); - default: throw new NotImplementedException("InterpolationTools.Interpolate: '" + mode + "' mode is not supported!"); + default: throw new NotImplementedException("InterpolationTools.Interpolate: \"" + mode + "\" mode is not supported!"); } } diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs index 5d076db3..fa631218 100644 --- a/Source/Core/Geometry/Tools.cs +++ b/Source/Core/Geometry/Tools.cs @@ -1845,7 +1845,7 @@ namespace CodeImp.DoomBuilder.Geometry return GetSidedefBottomOffsetY(side, offset, scaleY, fromNormalized); default: - throw new NotSupportedException("Tools.GetSidedefOffsetY: '" + part + "' geometry type is not supported!"); + throw new NotSupportedException("Tools.GetSidedefOffsetY: \"" + part + "\" geometry type is not supported!"); } } @@ -2236,7 +2236,7 @@ namespace CodeImp.DoomBuilder.Geometry /// <summary>Flips sector linedefs so they all face either inward or outward.</summary> public static void FlipSectorLinedefs(ICollection<Sector> sectors, bool selectedlinesonly) { - Dictionary<Linedef, bool> processed = new Dictionary<Linedef, bool>(); + HashSet<Linedef> processed = new HashSet<Linedef>(); foreach(Sector s in sectors) { @@ -2248,7 +2248,7 @@ namespace CodeImp.DoomBuilder.Geometry //sort lines foreach(Sidedef side in s.Sidedefs) { - if(processed.ContainsKey(side.Line)) continue; + if(processed.Contains(side.Line)) continue; if(selectedlinesonly && !side.Line.Selected) { if(side == side.Line.Front) unselectedfrontlines++; @@ -2261,7 +2261,7 @@ namespace CodeImp.DoomBuilder.Geometry else backlines.Add(side.Line); - processed.Add(side.Line, false); + processed.Add(side.Line); } //flip lines diff --git a/Source/Core/IO/ClipboardStreamReader.cs b/Source/Core/IO/ClipboardStreamReader.cs index 22fc2652..4580b849 100644 --- a/Source/Core/IO/ClipboardStreamReader.cs +++ b/Source/Core/IO/ClipboardStreamReader.cs @@ -7,6 +7,7 @@ using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Windows; #endregion @@ -29,32 +30,56 @@ namespace CodeImp.DoomBuilder.IO public Dictionary<string, bool> Flags; } - private bool uselongtexturenames; //mxd - #endregion #region ================== Properties - public bool UseLongTextureNames { get { return uselongtexturenames; } } //mxd - #endregion #region ================== Reading // This reads from a stream - public MapSet Read(MapSet map, Stream stream) + public bool Read(MapSet map, Stream stream) { BinaryReader reader = new BinaryReader(stream); + //mxd. Sanity checks + int numverts = reader.ReadInt32(); + if(map.Vertices.Count + numverts >= General.Map.FormatInterface.MaxVertices) + { + General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of vertices (" + (map.Vertices.Count + numverts) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxVertices + ")."); + return false; + } + + int numsectors = reader.ReadInt32(); + if(map.Sectors.Count + numsectors >= General.Map.FormatInterface.MaxSectors) + { + General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of sectors (" + (map.Sectors.Count + numsectors) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxSectors + ")."); + return false; + } + + int numlinedefs = reader.ReadInt32(); + if(map.Linedefs.Count + numlinedefs >= General.Map.FormatInterface.MaxLinedefs) + { + General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of linedefs (" + (map.Linedefs.Count + numlinedefs) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxLinedefs + ")."); + return false; + } + + int numthings = reader.ReadInt32(); + if(map.Things.Count + numthings >= General.Map.FormatInterface.MaxThings) + { + General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste: resulting number of things (" + (map.Things.Count + numthings) + ") will exceed map format's maximum (" + General.Map.FormatInterface.MaxThings + ")."); + return false; + } + // Read the map - uselongtexturenames = reader.ReadBoolean(); //mxd Dictionary<int, Vertex> vertexlink = ReadVertices(map, reader); Dictionary<int, Sector> sectorlink = ReadSectors(map, reader); Dictionary<int, SidedefData> sidedeflink = ReadSidedefs(reader); ReadLinedefs(map, reader, vertexlink, sectorlink, sidedeflink); ReadThings(map, reader); - return map; + return true; } private static Dictionary<int, Vertex> ReadVertices(MapSet map, BinaryReader reader) @@ -388,7 +413,7 @@ namespace CodeImp.DoomBuilder.IO break; default: //WOLOLO! ERRORS! - throw new Exception("Got unknown value type while reading custom fields from clipboard data! Field '" + name + "', type '" + type + "', primitive type '" + valueType + "'"); + throw new Exception("Got unknown value type while reading custom fields from clipboard data! Field \"" + name + "\", type \"" + type + "\", primitive type \"" + valueType + "\""); } } diff --git a/Source/Core/IO/ClipboardStreamWriter.cs b/Source/Core/IO/ClipboardStreamWriter.cs index 28ee6f1b..7c7bce25 100644 --- a/Source/Core/IO/ClipboardStreamWriter.cs +++ b/Source/Core/IO/ClipboardStreamWriter.cs @@ -22,7 +22,7 @@ namespace CodeImp.DoomBuilder.IO #region ================== Variables - private Configuration config; + private readonly Configuration config; #endregion @@ -83,13 +83,13 @@ namespace CodeImp.DoomBuilder.IO #region ================== Writing - public void Write(MapSet map, Stream stream, bool longtexturenames) + public void Write(MapSet map, Stream stream) { - Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream, longtexturenames); + Write(map.Vertices, map.Linedefs, map.Sidedefs, map.Sectors, map.Things, stream); } public void Write(ICollection<Vertex> vertices, ICollection<Linedef> linedefs, ICollection<Sidedef> sidedefs, - ICollection<Sector> sectors, ICollection<Thing> things, Stream stream, bool longtexturenames) + ICollection<Sector> sectors, ICollection<Thing> things, Stream stream) { // Create collections Dictionary<Vertex, int> vertexids = new Dictionary<Vertex, int>(); @@ -104,7 +104,10 @@ namespace CodeImp.DoomBuilder.IO BinaryWriter writer = new BinaryWriter(stream); // Write the data structures to stream - writer.Write(longtexturenames); //mxd + writer.Write(vertices.Count); //mxd + writer.Write(sectors.Count); //mxd + writer.Write(linedefs.Count); //mxd + writer.Write(things.Count); //mxd WriteVertices(vertices, writer); WriteSectors(sectors, writer); WriteSidedefs(sidedefs, writer, sectorids); @@ -292,8 +295,8 @@ namespace CodeImp.DoomBuilder.IO writer.Write(s.ToCharArray()); } else //WOLOLO! ERRORS! - { - General.ErrorLogger.Add(ErrorType.Error, "Unable to copy Universal Field '" + f.Key + "' to clipboard: unknown value type '" + f.Value.Type + "'!"); + { + General.ErrorLogger.Add(ErrorType.Error, "Unable to copy Universal Field \"" + f.Key + "\" to clipboard: unknown value type \"" + f.Value.Type + "\"!"); } } } diff --git a/Source/Core/IO/Configuration.cs b/Source/Core/IO/Configuration.cs index d5008d22..9eb36e99 100644 --- a/Source/Core/IO/Configuration.cs +++ b/Source/Core/IO/Configuration.cs @@ -804,7 +804,8 @@ namespace CodeImp.DoomBuilder.IO case "true": return true; case "false": return false; case "null": return null; - default: RaiseError(file, line, ERROR_KEYWORDUNKNOWN + "\nUnrecognized token: '" + val.Trim().ToLowerInvariant() + "'"); return null; + default: RaiseError(file, line, ERROR_KEYWORDUNKNOWN + "\nUnrecognized token: \"" + val.Trim().ToLowerInvariant() + "\""); + return null; } } } @@ -860,7 +861,7 @@ namespace CodeImp.DoomBuilder.IO } else { - RaiseError(file, line, "Include missing structure '" + args[1] + "' in file '" + includefile + "'"); + RaiseError(file, line, "Include missing structure \"" + args[1] + "\" in file \"" + includefile + "\""); return; } } @@ -885,7 +886,7 @@ namespace CodeImp.DoomBuilder.IO } catch(Exception e) { - RaiseError(file, line, "Unable to include file '" + includefile + "'. " + e.GetType().Name + ": " + e.Message); + RaiseError(file, line, "Unable to include file \"" + includefile + "\". " + e.GetType().Name + ": " + e.Message); return; } @@ -915,7 +916,7 @@ namespace CodeImp.DoomBuilder.IO } else { - RaiseError(file, line, "Include missing structure '" + args[1] + "' in file '" + includefile + "'"); + RaiseError(file, line, "Include missing structure \"" + args[1] + "\" in file \"" + includefile + "\""); return; } } diff --git a/Source/Core/IO/UniversalEntry.cs b/Source/Core/IO/UniversalEntry.cs index a69b9482..d08d1b4d 100644 --- a/Source/Core/IO/UniversalEntry.cs +++ b/Source/Core/IO/UniversalEntry.cs @@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.IO // Will throw and exception when it is not public void ValidateType(Type t) { - if(value.GetType() != t) throw new Exception("The value of entry '" + key + "' is of incompatible type (expected " + t.Name + ")"); + if(value.GetType() != t) throw new Exception("The value of entry \"" + key + "\" is of incompatible type (expected " + t.Name + ")"); } //mxd diff --git a/Source/Core/IO/UniversalParser.cs b/Source/Core/IO/UniversalParser.cs index 6a881526..cd4fa478 100644 --- a/Source/Core/IO/UniversalParser.cs +++ b/Source/Core/IO/UniversalParser.cs @@ -414,13 +414,13 @@ namespace CodeImp.DoomBuilder.IO catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } // Floating point? @@ -434,7 +434,7 @@ namespace CodeImp.DoomBuilder.IO catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } // Add it to struct @@ -476,13 +476,13 @@ namespace CodeImp.DoomBuilder.IO catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + s.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + s.Trim() + "\""); } } @@ -533,7 +533,7 @@ namespace CodeImp.DoomBuilder.IO catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + v.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\""); } // Convert the number to a char @@ -541,7 +541,7 @@ namespace CodeImp.DoomBuilder.IO catch(FormatException) { // ERROR: Invalid value in assignment - RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: '" + v.Trim() + "'"); + RaiseError(line, ERROR_VALUEINVALID + "\n\nUnrecognized token: \"" + v.Trim() + "\""); } // Add the char @@ -623,7 +623,7 @@ namespace CodeImp.DoomBuilder.IO default: // Unknown keyword - RaiseError(line, ERROR_KEYWORDUNKNOWN + "\n\nUnrecognized token: '" + val.ToString().Trim() + "'"); + RaiseError(line, ERROR_KEYWORDUNKNOWN + "\n\nUnrecognized token: \"" + val.ToString().Trim() + "\""); break; } diff --git a/Source/Core/IO/UniversalStreamReader.cs b/Source/Core/IO/UniversalStreamReader.cs index b5062469..c52666a5 100644 --- a/Source/Core/IO/UniversalStreamReader.cs +++ b/Source/Core/IO/UniversalStreamReader.cs @@ -494,7 +494,7 @@ namespace CodeImp.DoomBuilder.IO } else if(!e.IsValidType(e.Value.GetType())) { - General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry '" + e.Key + "' is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); + General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); continue; } @@ -522,7 +522,7 @@ namespace CodeImp.DoomBuilder.IO } else if(!e.IsValidType(e.Value.GetType())) { - General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry '" + e.Key + "' is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); + General.ErrorLogger.Add(ErrorType.Warning, element + ": the value of entry \"" + e.Key + "\" is of incompatible type (expected " + e.GetType().Name + ", but got " + e.Value.GetType().Name + "). If you save the map, this value will be ignored."); continue; } @@ -582,7 +582,7 @@ namespace CodeImp.DoomBuilder.IO { // Report error when entry is required! if(required) - General.ErrorLogger.Add(ErrorType.Error, "Error while reading UDMF map data: Missing required field '" + entryname + "' at " + where + "."); + General.ErrorLogger.Add(ErrorType.Error, "Error while reading UDMF map data: Missing required field \"" + entryname + "\" at " + where + "."); // Make default entry result = defaultvalue; diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs index ef6300a8..07a8f3f0 100644 --- a/Source/Core/Map/MapSet.cs +++ b/Source/Core/Map/MapSet.cs @@ -2721,7 +2721,7 @@ namespace CodeImp.DoomBuilder.Map { float px = t.Position.x; float py = t.Position.y; - float ts = ((t.FixedSize && General.Map.Renderer2D.Scale > 1.0f) ? t.Size / General.Map.Renderer2D.Scale : t.Size); + float ts = (((t.FixedSize || General.Settings.FixedThingsScale) && General.Map.Renderer2D.Scale > 1.0f) ? t.Size / General.Map.Renderer2D.Scale : t.Size); //mxd. Within range? if(px < range.Left - ts || px > range.Right + ts || py < range.Top - ts || py > range.Bottom + ts) continue; diff --git a/Source/Core/Plugins/Plugin.cs b/Source/Core/Plugins/Plugin.cs index 3c548015..536f6e01 100644 --- a/Source/Core/Plugins/Plugin.cs +++ b/Source/Core/Plugins/Plugin.cs @@ -66,7 +66,7 @@ namespace CodeImp.DoomBuilder.Plugins // Initialize string shortfilename = Path.GetFileName(filename); name = Path.GetFileNameWithoutExtension(filename); - General.WriteLogLine("Loading plugin '" + name + "' from '" + shortfilename + "'..."); + General.WriteLogLine("Loading plugin \"" + name + "\" from \"" + shortfilename + "\"..."); try { @@ -218,7 +218,7 @@ namespace CodeImp.DoomBuilder.Plugins catch(TargetInvocationException e) { // Error! - string error = "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'."; + string error = "Failed to create class instance \"" + t.Name + "\" from plugin \"" + name + "\"."; General.ShowErrorMessage(error + Environment.NewLine + Environment.NewLine + "See the error log for more details", MessageBoxButtons.OK, false); General.WriteLogLine(error + " " + e.InnerException.GetType().Name + " at target: " + e.InnerException.Message + Environment.NewLine + "Stacktrace: " + e.InnerException.StackTrace.Trim()); @@ -227,7 +227,7 @@ namespace CodeImp.DoomBuilder.Plugins catch(Exception e) { // Error! - string error = "Failed to create class instance '" + t.Name + "' from plugin '" + name + "'."; + string error = "Failed to create class instance \"" + t.Name + "\" from plugin \"" + name + "\"."; General.ShowErrorMessage(error + Environment.NewLine + Environment.NewLine + "See the error log for more details", MessageBoxButtons.OK, false); General.WriteLogLine(error + " " + e.GetType().Name + ": " + e.Message + Environment.NewLine + "Stacktrace: " + e.StackTrace.Trim()); diff --git a/Source/Core/Properties/Resources.Designer.cs b/Source/Core/Properties/Resources.Designer.cs index 57be92f7..a6f6670d 100644 --- a/Source/Core/Properties/Resources.Designer.cs +++ b/Source/Core/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // <auto-generated> -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:2.0.50727.5466 // // Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn // der Code erneut generiert wird. @@ -370,9 +370,13 @@ namespace CodeImp.DoomBuilder.Properties { } } - /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. - /// </summary> + internal static System.Drawing.Bitmap FixedThingsScale { + get { + object obj = ResourceManager.GetObject("FixedThingsScale", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + internal static System.Drawing.Bitmap fog { get { object obj = ResourceManager.GetObject("fog", resourceCulture); diff --git a/Source/Core/Properties/Resources.resx b/Source/Core/Properties/Resources.resx index 7ac990d1..46ad6a9e 100644 --- a/Source/Core/Properties/Resources.resx +++ b/Source/Core/Properties/Resources.resx @@ -574,4 +574,7 @@ <data name="ScriptProperty" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\ScriptProperty.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> + <data name="FixedThingsScale" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\FixedThingsScale.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> </root> \ No newline at end of file diff --git a/Source/Core/Rendering/D3DDevice.cs b/Source/Core/Rendering/D3DDevice.cs index a4fa7c83..888dfb1e 100644 --- a/Source/Core/Rendering/D3DDevice.cs +++ b/Source/Core/Rendering/D3DDevice.cs @@ -168,8 +168,8 @@ namespace CodeImp.DoomBuilder.Rendering device.SetRenderState(RenderState.NormalizeNormals, false); device.SetRenderState(RenderState.PointSpriteEnable, false); device.SetRenderState(RenderState.RangeFogEnable, false); - device.SetRenderState(RenderState.ShadeMode, ShadeMode.Flat); //mxd - device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha); + device.SetRenderState(RenderState.ShadeMode, ShadeMode.Gouraud); + device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha); device.SetRenderState(RenderState.SpecularEnable, false); device.SetRenderState(RenderState.StencilEnable, false); device.SetRenderState(RenderState.TextureFactor, -1); diff --git a/Source/Core/Rendering/IRenderer2D.cs b/Source/Core/Rendering/IRenderer2D.cs index deae50f1..6ae68637 100644 --- a/Source/Core/Rendering/IRenderer2D.cs +++ b/Source/Core/Rendering/IRenderer2D.cs @@ -74,6 +74,7 @@ namespace CodeImp.DoomBuilder.Rendering void RenderRectangleFilled(RectangleF rect, PixelColor c, bool transformrect, ImageData texture); void RenderLine(Vector2D start, Vector2D end, float thickness, PixelColor c, bool transformcoords); void RenderArrows(ICollection<Line3D> line); //mxd + void RenderArrows(ICollection<Line3D> line, bool transformcoords); //mxd void RenderText(TextLabel text); void RenderGeometry(FlatVertex[] vertices, ImageData texture, bool transformcoords); void RenderHighlight(FlatVertex[] vertices, int color); //mxd diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs index e92ce23c..e5e5ad81 100644 --- a/Source/Core/Rendering/Renderer2D.cs +++ b/Source/Core/Rendering/Renderer2D.cs @@ -250,7 +250,6 @@ namespace CodeImp.DoomBuilder.Rendering // BACKGROUND case RendererLayer.Background: if((backimageverts == null) || (General.Map.Grid.Background.Texture == null)) break; - graphics.Device.SetTexture(0, General.Map.Grid.Background.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Grid.Background.Texture; graphics.Shaders.Display2D.SetSettings(1f / windowsize.Width, 1f / windowsize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -261,7 +260,6 @@ namespace CodeImp.DoomBuilder.Rendering // GRID case RendererLayer.Grid: - graphics.Device.SetTexture(0, backtex); graphics.Shaders.Display2D.Texture1 = backtex; graphics.Shaders.Display2D.SetSettings(1f / backsize.Width, 1f / backsize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -271,7 +269,6 @@ namespace CodeImp.DoomBuilder.Rendering // GEOMETRY case RendererLayer.Geometry: - graphics.Device.SetTexture(0, plottertex); graphics.Shaders.Display2D.Texture1 = plottertex; graphics.Shaders.Display2D.SetSettings(1f / structsize.Width, 1f / structsize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -281,7 +278,6 @@ namespace CodeImp.DoomBuilder.Rendering // THINGS case RendererLayer.Things: - graphics.Device.SetTexture(0, thingstex); graphics.Shaders.Display2D.Texture1 = thingstex; graphics.Shaders.Display2D.SetSettings(1f / thingssize.Width, 1f / thingssize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -291,7 +287,6 @@ namespace CodeImp.DoomBuilder.Rendering // OVERLAY case RendererLayer.Overlay: - graphics.Device.SetTexture(0, overlaytex); graphics.Shaders.Display2D.Texture1 = overlaytex; graphics.Shaders.Display2D.SetSettings(1f / overlaysize.Width, 1f / overlaysize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -301,7 +296,6 @@ namespace CodeImp.DoomBuilder.Rendering // SURFACE case RendererLayer.Surface: - graphics.Device.SetTexture(0, surfacetex); graphics.Shaders.Display2D.Texture1 = surfacetex; graphics.Shaders.Display2D.SetSettings(1f / overlaysize.Width, 1f / overlaysize.Height, FSAA_FACTOR, layer.alpha, false); graphics.Shaders.Display2D.BeginPass(aapass); @@ -317,7 +311,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Present(); // Release binds - graphics.Device.SetTexture(0, null); graphics.Shaders.Display2D.Texture1 = null; graphics.Device.SetStreamSource(0, null, 0, 0); } @@ -985,20 +978,22 @@ namespace CodeImp.DoomBuilder.Rendering // This makes vertices for a thing // Returns false when not on the screen - private bool CreateThingBoxVerts(Thing t, ref FlatVertex[] verts, Dictionary<Thing, Vector2D> thingsByPosition, int offset, PixelColor c) + private bool CreateThingBoxVerts(Thing t, ref FlatVertex[] verts, ref List<Line3D> bboxes, Dictionary<Thing, Vector2D> thingsByPosition, int offset, PixelColor c, byte bboxalpha) { float thingsize = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : t.Size; if(thingsize * scale < MINIMUM_THING_RADIUS) return false; //mxd. Don't render tiny little things - // Determine size - float circlesize = (t.FixedSize && (scale > 1.0f) ? thingsize /* * THING_CIRCLE_SIZE*/ : thingsize * scale /* * THING_CIRCLE_SIZE*/); + // Determine sizes + float circlesize = ((t.FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size : t.Size * scale); + float bboxsize = ((!t.FixedSize && General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size * scale : -1); //mxd + float screensize = Math.Max(circlesize, bboxsize); //mxd // Transform to screen coordinates Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale); // Check if the thing is actually on screen - if(((screenpos.x + circlesize) <= 0.0f) || ((screenpos.x - circlesize) >= windowsize.Width) || - ((screenpos.y + circlesize) <= 0.0f) || ((screenpos.y - circlesize) >= windowsize.Height)) + if(((screenpos.x + screensize) <= 0.0f) || ((screenpos.x - screensize) >= windowsize.Width) || + ((screenpos.y + screensize) <= 0.0f) || ((screenpos.y - screensize) >= windowsize.Height)) return false; // Get integral color @@ -1036,6 +1031,22 @@ namespace CodeImp.DoomBuilder.Rendering //mxd. Add to list thingsByPosition.Add(t, screenpos); + //mxd. Add bounding box? + if(bboxsize > 0) + { + PixelColor boxcolor = c.WithAlpha(bboxalpha); + + Vector2D tl = new Vector2D(screenpos.x - bboxsize, screenpos.y - bboxsize); + Vector2D tr = new Vector2D(screenpos.x + bboxsize, screenpos.y - bboxsize); + Vector2D bl = new Vector2D(screenpos.x - bboxsize, screenpos.y + bboxsize); + Vector2D br = new Vector2D(screenpos.x + bboxsize, screenpos.y + bboxsize); + + bboxes.Add(new Line3D(tl, tr, boxcolor, false)); + bboxes.Add(new Line3D(tr, br, boxcolor, false)); + bboxes.Add(new Line3D(bl, br, boxcolor, false)); + bboxes.Add(new Line3D(tl, bl, boxcolor, false)); + } + // Done return true; } @@ -1045,10 +1056,10 @@ namespace CodeImp.DoomBuilder.Rendering { // Determine size float thingsize = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : t.Size; - float arrowsize = (t.FixedSize && (scale > 1.0f) ? thingsize : thingsize * scale) * THING_ARROW_SIZE; //mxd + float arrowsize = ((t.FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f) ? t.Size : t.Size * scale) * THING_ARROW_SIZE; //mxd - // Setup rotated rect for arrow - float sinarrowsize = (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * arrowsize; + // Setup rotated rect for arrow + float sinarrowsize = (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * arrowsize; float cosarrowsize = (float)Math.Cos(t.Angle + Angle2D.PI * 0.25f) * arrowsize; verts[offset].x = screenpos.x + sinarrowsize; @@ -1123,6 +1134,7 @@ namespace CodeImp.DoomBuilder.Rendering // Make alpha color Color4 alphacolor = new Color4(alpha, 1.0f, 1.0f, 1.0f); + bool isthingsmode = (General.Editing.Mode.GetType().Name == "ThingsMode"); // Set renderstates for things rendering graphics.Device.SetRenderState(RenderState.CullMode, Cull.None); @@ -1136,7 +1148,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride); // Set things texture - graphics.Device.SetTexture(0, thingtexture.Texture); graphics.Shaders.Things2D.Texture1 = thingtexture.Texture; SetWorldTransformation(false); graphics.Shaders.Things2D.SetSettings(alpha); @@ -1148,6 +1159,7 @@ namespace CodeImp.DoomBuilder.Rendering // Determine next lock size int locksize = (things.Count > THING_BUFFER_SIZE) ? THING_BUFFER_SIZE : things.Count; FlatVertex[] verts = new FlatVertex[THING_BUFFER_SIZE * 6]; + List<Line3D> bboxes = new List<Line3D>(locksize); //mxd //mxd Dictionary<int, List<Thing>> thingsByType = new Dictionary<int, List<Thing>>(); @@ -1171,7 +1183,8 @@ namespace CodeImp.DoomBuilder.Rendering // Create vertices PixelColor tc = fixedcolor ? c : DetermineThingColor(t); - if(CreateThingBoxVerts(t, ref verts, thingsByPosition, buffercount * 6, tc)) + byte bboxalpha = (byte)(alpha * ((!fixedcolor && !t.Selected && isthingsmode) ? 128 : 255)); + if(CreateThingBoxVerts(t, ref verts, ref bboxes, thingsByPosition, buffercount * 6, tc, bboxalpha)) { buffercount++; @@ -1234,8 +1247,8 @@ namespace CodeImp.DoomBuilder.Rendering } if(sprite.Texture == null) sprite.CreateTexture(); - graphics.Device.SetTexture(0, sprite.Texture); graphics.Shaders.Things2D.Texture1 = sprite.Texture; + graphics.Shaders.Things2D.ApplySettings(); // Determine next lock size locksize = (group.Value.Count > THING_BUFFER_SIZE) ? THING_BUFFER_SIZE : group.Value.Count; @@ -1246,7 +1259,7 @@ namespace CodeImp.DoomBuilder.Rendering totalcount = 0; float spriteWidth, spriteHeight; - float spriteScale = (group.Value[0].FixedSize && (scale > 1.0f)) ? 1.0f : scale; + float spriteScale = ((group.Value[0].FixedSize || General.Settings.FixedThingsScale) && (scale > 1.0f)) ? 1.0f : scale; float radius = General.Settings.DrawThingsFixedSize ? General.Settings.DefaultThingSize : info.Radius; if(sprite.Width > sprite.Height) @@ -1310,7 +1323,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Shaders.Things2D.EndPass(); //mxd. Render thing arrows - graphics.Device.SetTexture(0, thingtexture.Texture); graphics.Shaders.Things2D.Texture1 = thingtexture.Texture; graphics.Shaders.Things2D.BeginPass(0); @@ -1418,6 +1430,9 @@ namespace CodeImp.DoomBuilder.Rendering } graphics.Shaders.Things2D.End(); + + //mxd. Render thing boxes + RenderArrows(bboxes, false); } } @@ -1625,7 +1640,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); graphics.Shaders.Display2D.Texture1 = t; - graphics.Device.SetTexture(0, t); SetWorldTransformation(transformcoords); graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); @@ -1682,7 +1696,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Shaders.Display2D.Texture1 = graphics.FontTexture; SetWorldTransformation(false); graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, true); - graphics.Device.SetTexture(0, graphics.FontTexture); graphics.Device.SetStreamSource(0, text.VertexBuffer, 0, FlatVertex.Stride); // Draw @@ -1745,7 +1758,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); SetWorldTransformation(false); - graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture; graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); @@ -1784,7 +1796,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); SetWorldTransformation(false); - graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture; graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); @@ -1820,7 +1831,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); SetWorldTransformation(false); - graphics.Device.SetTexture(0, texture.Texture); graphics.Shaders.Display2D.Texture1 = texture.Texture; graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); @@ -1833,7 +1843,8 @@ namespace CodeImp.DoomBuilder.Rendering } //mxd - public void RenderArrows(ICollection<Line3D> lines) + public void RenderArrows(ICollection<Line3D> lines) { RenderArrows(lines, true); } + public void RenderArrows(ICollection<Line3D> lines, bool transformcoords) { if(lines.Count == 0) return; int pointscount = 0; @@ -1841,9 +1852,12 @@ namespace CodeImp.DoomBuilder.Rendering // Translate to screen coords, determine renderability foreach(Line3D line in lines) { - // Calculate screen positions - line.Start2D = ((Vector2D)line.Start).GetTransformed(translatex, translatey, scale, -scale); //start - line.End2D = ((Vector2D)line.End).GetTransformed(translatex, translatey, scale, -scale); //end + // Calculate screen positions? + if(transformcoords) + { + line.Start2D = ((Vector2D)line.Start).GetTransformed(translatex, translatey, scale, -scale); //start + line.End2D = ((Vector2D)line.End).GetTransformed(translatex, translatey, scale, -scale); //end + } float maxx = Math.Max(line.Start2D.x, line.End2D.x); float minx = Math.Min(line.Start2D.x, line.End2D.x); @@ -1922,7 +1936,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); SetWorldTransformation(false); - graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture; graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); @@ -1999,7 +2012,6 @@ namespace CodeImp.DoomBuilder.Rendering graphics.Device.SetRenderState(RenderState.TextureFactor, -1); graphics.Device.SetRenderState(RenderState.FogEnable, false); SetWorldTransformation(false); - graphics.Device.SetTexture(0, General.Map.Data.WhiteTexture.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.WhiteTexture.Texture; graphics.Shaders.Display2D.SetSettings(1f, 1f, 0f, 1f, General.Settings.ClassicBilinear); diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 1cb9e59a..2c723f9e 100644 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -1874,13 +1874,11 @@ namespace CodeImp.DoomBuilder.Rendering if(crosshairbusy) { if(General.Map.Data.CrosshairBusy3D.Texture == null) General.Map.Data.CrosshairBusy3D.CreateTexture(); - graphics.Device.SetTexture(0, General.Map.Data.CrosshairBusy3D.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.CrosshairBusy3D.Texture; } else { if(General.Map.Data.Crosshair3D.Texture == null) General.Map.Data.Crosshair3D.CreateTexture(); - graphics.Device.SetTexture(0, General.Map.Data.Crosshair3D.Texture); graphics.Shaders.Display2D.Texture1 = General.Map.Data.Crosshair3D.Texture; } diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg index 5c4bb6df..61a629ed 100644 --- a/Source/Core/Resources/Actions.cfg +++ b/Source/Core/Resources/Actions.cfg @@ -1037,6 +1037,16 @@ togglecomments //mxd allowscroll = false; } +togglefixedthingsscale //mxd +{ + title = "Toggle Fixed Things Scale"; + category = "view"; + description = "When enabled, Things will no longer be scaled based on current zoom level in Classic modes."; + allowkeys = true; + allowmouse = false; + allowscroll = false; +} + togglebrightness //mxd { title = "Toggle Full Brightness"; diff --git a/Source/Core/Resources/FixedThingsScale.png b/Source/Core/Resources/FixedThingsScale.png new file mode 100644 index 0000000000000000000000000000000000000000..b94d1acfa5e05dfa73f72709313f50e6ec602796 GIT binary patch literal 1595 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7BuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFso&TM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtB zi9%9pdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tSWK~ za#KqZ6)JLb@`|l0Y?Z*~TICg6frRyy6u?SKvTc<hj*9RNP;kyKN>wn`Gt*5rFf&&$ zx70H<H8(dg*HJJsFf`RSFxEFV&^0o)GBL0+F;aj6B|8P1qLehNAQv~NT}3Hrwn`Z# zB?VUc`sL;2dgaD?`9<mahL)C=`UXb&Mn<|tDQUXJm3bwJ6}oxF$}kgLQj3#|G7CyF z^YauyCMG83mzLNnDM5{`$Sr^yn^z1CrsVuw{ffi_eM3D1ke48S%`Nct#ji9s7p}Uv zBq$Z(UaSTehg24%>IbD3=a&{Grv{~_DTCZpVC7ttnpl!w6q28x0}I7~jQo=P;*9(P z1!re)s3~ZKXXd5kmltb-_4xW)dFB<DB<3Zjdb-#uRpb`vWoD*Wxwsj+xtN)|xLBH* z8ydQrIvN_8Ihz_dIT|^+8ap|g!t}c2Czs}?=9R$orXcjX;?xUD4xk{ha!D=9EK5ys zE6UGR0DIdi6SrHOaGD3zn}XXd&N%hz+bP)SgCZ9xvSC6&E^Z(uI9-C$sGR~L@u%jc z*eVq%+1ojn^xkG*U|Q|z;uunKt0p+sBREl_?p)cn#d+r}mkXIOU-shJqxoNB;)yzy zBMKZ`i}H@FQ_<Kx@xrT3zgKiOHFZgqC<h5mNz9t`wAIqoG{bjpcJbTqInURBUsIei z?d!qQhridp|NNou{dc=F&#R_4tqJ{nFWN~UP(-y=_nMFM&t)}k;tG#An>1V-4!JW; zT+1TSwo!13V7}Yk%~mt{*f^v^CMy4ZcV~6-3eJx!I=UM)G`$-i?0Wt+(tXCeV6Dir zsxs-O4_DL`Y<_%g<z4o^^4VuCG7K5B16j2*Id!I+*L(?l!1i>{q8RbQPsXBwBEc4+ z6R+({@6|2cTJHNTsQOBVvw@=GvF-pLnVR@zic-ak&a8TV=)=};np=fJ4=gbAsVxp( zAH5<sZ}*deX}4-K`7Ymgo>61nVql@uxBtMAuVqL6-mAIx@YP9OovB;mSR>ZnUTLf! zn0wNB@qDw_MjLE?^UY)5+rb{b@xu=Ob;;t1_k;UyTv~3`w)u_nyy*1~@lz!uwXDxD z|LbIQ5wlNvRwjOmZ?5yvm#1f{+&tkJCbHb`mVm%Z<HMOw&4Mep=KuJZ_`%%KL)pf* z=c>8C;_}G>DvSXsZqHxtXRw<a_u({~L{Y>VA3nurvzxDm@*ck@W|75zIBcu@Bn`!_ zM*JK$|ED)d@SbrMNeeNEoRzR`!Lr|WT^%!C-<h{E*hfupmaOxq*H30BeON5r?0WV_ zhSTl6JFmIu{EIoGy{X_QpH_IA&QgU>g(@|lJA8Qmed*s(opkW2`mZHvZZp{yJIprN zw|VD(mBW$ik5n$~^grV1&>+O^#8c_MVk5u0)=lf1KQHVFSgUxodv562w@+PfmzB)m z_OkNb_DFB@)(<s(TNA|ZuC&|ma;H|>?3Iqvt9lmxd+KH+yxdR!<DS`fW~8QH|IhMo d%V&K?HU|EwVSW<4>I*={xu>h2%Q~loCICdTVY&bS literal 0 HcmV?d00001 diff --git a/Source/Core/Types/AngleDegreesFloatHandler.cs b/Source/Core/Types/AngleDegreesFloatHandler.cs index 82b074a7..47f35888 100644 --- a/Source/Core/Types/AngleDegreesFloatHandler.cs +++ b/Source/Core/Types/AngleDegreesFloatHandler.cs @@ -102,6 +102,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0f; + } + #endregion } } diff --git a/Source/Core/Types/AngleDegreesHandler.cs b/Source/Core/Types/AngleDegreesHandler.cs index ec4e7c9c..0120c0ce 100644 --- a/Source/Core/Types/AngleDegreesHandler.cs +++ b/Source/Core/Types/AngleDegreesHandler.cs @@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0; + } + #endregion } } diff --git a/Source/Core/Types/AngleRadiansHandler.cs b/Source/Core/Types/AngleRadiansHandler.cs index 57a9315d..dee4904c 100644 --- a/Source/Core/Types/AngleRadiansHandler.cs +++ b/Source/Core/Types/AngleRadiansHandler.cs @@ -102,6 +102,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0f; + } + #endregion } } diff --git a/Source/Core/Types/BoolHandler.cs b/Source/Core/Types/BoolHandler.cs index 0b3f369c..d70d48e7 100644 --- a/Source/Core/Types/BoolHandler.cs +++ b/Source/Core/Types/BoolHandler.cs @@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Types public override int GetIntValue() { - if(this.value) return 1; else return 0; + return (this.value ? 1 : 0); } public override string GetStringValue() @@ -106,6 +106,11 @@ namespace CodeImp.DoomBuilder.Types { return list; } + + public override object GetDefaultValue() + { + return false; + } #endregion } diff --git a/Source/Core/Types/ColorHandler.cs b/Source/Core/Types/ColorHandler.cs index 37f7ac9c..b48c6e71 100644 --- a/Source/Core/Types/ColorHandler.cs +++ b/Source/Core/Types/ColorHandler.cs @@ -113,6 +113,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString("X6"); } + public override object GetDefaultValue() + { + return 0; + } + #endregion } } diff --git a/Source/Core/Types/EnumBitsHandler.cs b/Source/Core/Types/EnumBitsHandler.cs index c392bf53..267e7ab8 100644 --- a/Source/Core/Types/EnumBitsHandler.cs +++ b/Source/Core/Types/EnumBitsHandler.cs @@ -38,7 +38,7 @@ namespace CodeImp.DoomBuilder.Types private EnumList list; private int value; - private int defaultValue; //mxd + private int defaultvalue; //mxd #endregion @@ -55,7 +55,7 @@ namespace CodeImp.DoomBuilder.Types // When set up for an argument public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) { - defaultValue = (int)arginfo.DefaultValue;//mxd + defaultvalue = (int)arginfo.DefaultValue;//mxd base.SetupArgument(attr, arginfo); // Keep enum list reference @@ -100,9 +100,9 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { - value = defaultValue; + value = defaultvalue; } public override object GetValue() @@ -120,6 +120,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return defaultvalue; + } + #endregion } } diff --git a/Source/Core/Types/EnumOptionHandler.cs b/Source/Core/Types/EnumOptionHandler.cs index 30184b14..1ce9ce3e 100644 --- a/Source/Core/Types/EnumOptionHandler.cs +++ b/Source/Core/Types/EnumOptionHandler.cs @@ -140,7 +140,7 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { value = defaultvalue; } @@ -189,6 +189,11 @@ namespace CodeImp.DoomBuilder.Types { return General.Types.GetAttribute((int)UniversalType.Integer); } + + public override object GetDefaultValue() + { + return defaultvalue; + } #endregion } diff --git a/Source/Core/Types/EnumStringsHandler.cs b/Source/Core/Types/EnumStringsHandler.cs index 0ad1d6d4..75031662 100644 --- a/Source/Core/Types/EnumStringsHandler.cs +++ b/Source/Core/Types/EnumStringsHandler.cs @@ -34,7 +34,7 @@ namespace CodeImp.DoomBuilder.Types private EnumList list; private EnumItem value; - private EnumItem defaultValue; //mxd + private EnumItem defaultvalue; //mxd #endregion @@ -50,7 +50,7 @@ namespace CodeImp.DoomBuilder.Types // When set up for an argument public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) { - defaultValue = new EnumItem(arginfo.DefaultValue.ToString(), arginfo.DefaultValue.ToString()); //mxd + defaultvalue = new EnumItem(arginfo.DefaultValue.ToString(), arginfo.DefaultValue.ToString()); //mxd base.SetupArgument(attr, arginfo); // Keep enum list reference @@ -121,9 +121,9 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { - value = defaultValue; + value = defaultvalue; } public override object GetValue() @@ -171,6 +171,11 @@ namespace CodeImp.DoomBuilder.Types return General.Types.GetAttribute((int)UniversalType.String); } + public override object GetDefaultValue() + { + return defaultvalue; + } + #endregion } } diff --git a/Source/Core/Types/FlatHandler.cs b/Source/Core/Types/FlatHandler.cs index 339ac1f1..4aa40363 100644 --- a/Source/Core/Types/FlatHandler.cs +++ b/Source/Core/Types/FlatHandler.cs @@ -70,6 +70,11 @@ namespace CodeImp.DoomBuilder.Types return this.value; } + public override object GetDefaultValue() + { + return string.Empty; + } + #endregion } } diff --git a/Source/Core/Types/FloatHandler.cs b/Source/Core/Types/FloatHandler.cs index 4cb05edd..67ab905c 100644 --- a/Source/Core/Types/FloatHandler.cs +++ b/Source/Core/Types/FloatHandler.cs @@ -85,6 +85,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0f; + } + #endregion } } diff --git a/Source/Core/Types/IntegerHandler.cs b/Source/Core/Types/IntegerHandler.cs index c6fab35c..0760e92d 100644 --- a/Source/Core/Types/IntegerHandler.cs +++ b/Source/Core/Types/IntegerHandler.cs @@ -34,7 +34,7 @@ namespace CodeImp.DoomBuilder.Types #region ================== Variables private int value; - private int defaultValue; //mxd + private int defaultvalue; //mxd #endregion @@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Types //mxd public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) { - defaultValue = (int)arginfo.DefaultValue; + defaultvalue = (int)arginfo.DefaultValue; base.SetupArgument(attr, arginfo); } @@ -85,9 +85,9 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { - value = defaultValue; + value = defaultvalue; } public override object GetValue() @@ -104,6 +104,11 @@ namespace CodeImp.DoomBuilder.Types { return this.value.ToString(); } + + public override object GetDefaultValue() + { + return defaultvalue; + } #endregion } diff --git a/Source/Core/Types/LinedefTypeHandler.cs b/Source/Core/Types/LinedefTypeHandler.cs index db7c5b97..ee1cd522 100644 --- a/Source/Core/Types/LinedefTypeHandler.cs +++ b/Source/Core/Types/LinedefTypeHandler.cs @@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0; + } + #endregion } } diff --git a/Source/Core/Types/NullHandler.cs b/Source/Core/Types/NullHandler.cs index 2de10e85..3e5b87ac 100644 --- a/Source/Core/Types/NullHandler.cs +++ b/Source/Core/Types/NullHandler.cs @@ -62,6 +62,11 @@ namespace CodeImp.DoomBuilder.Types { return this.value.ToString(); } + + public override object GetDefaultValue() + { + return 0; + } #endregion } diff --git a/Source/Core/Types/RandomFloatHandler.cs b/Source/Core/Types/RandomFloatHandler.cs index 0d26774c..b3b38326 100644 --- a/Source/Core/Types/RandomFloatHandler.cs +++ b/Source/Core/Types/RandomFloatHandler.cs @@ -18,7 +18,7 @@ namespace CodeImp.DoomBuilder.Types #region ================== Variables private float value; - private bool randomValue; + private bool randomvalue; private float min; private float max; @@ -77,7 +77,7 @@ namespace CodeImp.DoomBuilder.Types if(float.TryParse(parts[0], NumberStyles.Float, CultureInfo.CurrentCulture, out min) && float.TryParse(parts[1], NumberStyles.Float, CultureInfo.CurrentCulture, out max)) { - randomValue = (min != max); + randomvalue = (min != max); if(min == max) this.value = min; else if(min > max) General.Swap(ref min, ref max); @@ -91,22 +91,27 @@ namespace CodeImp.DoomBuilder.Types public override object GetValue() { - if(randomValue) return General.Random(min, max); //mxd + if(randomvalue) return General.Random(min, max); //mxd return this.value; } public override int GetIntValue() { - if(randomValue) return (int)General.Random(min, max); //mxd + if(randomvalue) return (int)General.Random(min, max); //mxd return (int)this.value; } public override string GetStringValue() { - if(randomValue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd + if(randomvalue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd return this.value.ToString(CultureInfo.InvariantCulture); } + public override object GetDefaultValue() + { + return 0f; + } + #endregion } } diff --git a/Source/Core/Types/RandomIntegerHandler.cs b/Source/Core/Types/RandomIntegerHandler.cs index 208168d1..3b63513d 100644 --- a/Source/Core/Types/RandomIntegerHandler.cs +++ b/Source/Core/Types/RandomIntegerHandler.cs @@ -14,8 +14,8 @@ namespace CodeImp.DoomBuilder.Types #region ================== Variables private int value; - private int defaultValue; - private bool randomValue; + private int defaultvalue; + private bool randomvalue; private int min; private int max; @@ -29,7 +29,7 @@ namespace CodeImp.DoomBuilder.Types public override void SetupArgument(TypeHandlerAttribute attr, ArgumentInfo arginfo) { - defaultValue = (int)arginfo.DefaultValue; + defaultvalue = (int)arginfo.DefaultValue; base.SetupArgument(attr, arginfo); //mxd. We don't want to store this type @@ -74,7 +74,7 @@ namespace CodeImp.DoomBuilder.Types if(int.TryParse(parts[0], NumberStyles.Integer, CultureInfo.CurrentCulture, out min) && int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.CurrentCulture, out max)) { - randomValue = (min != max); + randomvalue = (min != max); if(min == max) this.value = min; else if(min > max) General.Swap(ref min, ref max); } @@ -89,29 +89,34 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { - value = defaultValue; + value = defaultvalue; } public override object GetValue() { - if(randomValue) return General.Random(min, max); //mxd + if(randomvalue) return General.Random(min, max); //mxd return this.value; } public override int GetIntValue() { - if(randomValue) return General.Random(min, max); //mxd + if(randomvalue) return General.Random(min, max); //mxd return this.value; } public override string GetStringValue() { - if(randomValue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd + if(randomvalue) return General.Random(min, max).ToString(CultureInfo.InvariantCulture); //mxd return this.value.ToString(CultureInfo.InvariantCulture); } + public override object GetDefaultValue() + { + return defaultvalue; + } + #endregion } } diff --git a/Source/Core/Types/SectorEffectHandler.cs b/Source/Core/Types/SectorEffectHandler.cs index af18f9bd..dd342eba 100644 --- a/Source/Core/Types/SectorEffectHandler.cs +++ b/Source/Core/Types/SectorEffectHandler.cs @@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0; + } + #endregion } } diff --git a/Source/Core/Types/SectorTagHandler.cs b/Source/Core/Types/SectorTagHandler.cs index 3f680fab..79eed319 100644 --- a/Source/Core/Types/SectorTagHandler.cs +++ b/Source/Core/Types/SectorTagHandler.cs @@ -170,7 +170,7 @@ namespace CodeImp.DoomBuilder.Types } //mxd - public override void SetDefaultValue() + public override void ApplyDefaultValue() { value = defaultvalue; } @@ -197,6 +197,11 @@ namespace CodeImp.DoomBuilder.Types return (this.value != null ? this.value.Title : "0: No Tag"); } + public override object GetDefaultValue() + { + return defaultvalue; + } + // This returns an enum list public override EnumList GetEnumList() { diff --git a/Source/Core/Types/StringHandler.cs b/Source/Core/Types/StringHandler.cs index 9f08dd34..e4cee5bc 100644 --- a/Source/Core/Types/StringHandler.cs +++ b/Source/Core/Types/StringHandler.cs @@ -68,8 +68,7 @@ namespace CodeImp.DoomBuilder.Types public override int GetIntValue() { int result; - if(int.TryParse(this.value, out result)) return result; - else return 0; + return (int.TryParse(this.value, out result) ? result : 0); } public override string GetStringValue() @@ -77,6 +76,11 @@ namespace CodeImp.DoomBuilder.Types return this.value; } + public override object GetDefaultValue() + { + return string.Empty; + } + #endregion } } diff --git a/Source/Core/Types/TextureHandler.cs b/Source/Core/Types/TextureHandler.cs index 5f338fe4..9d89c6a1 100644 --- a/Source/Core/Types/TextureHandler.cs +++ b/Source/Core/Types/TextureHandler.cs @@ -70,6 +70,11 @@ namespace CodeImp.DoomBuilder.Types return this.value; } + public override object GetDefaultValue() + { + return string.Empty; + } + #endregion } } diff --git a/Source/Core/Types/ThingClassHandler.cs b/Source/Core/Types/ThingClassHandler.cs index 34663f23..6eb96602 100644 --- a/Source/Core/Types/ThingClassHandler.cs +++ b/Source/Core/Types/ThingClassHandler.cs @@ -91,6 +91,11 @@ namespace CodeImp.DoomBuilder.Types return this.value; } + public override object GetDefaultValue() + { + return string.Empty; + } + #endregion } } diff --git a/Source/Core/Types/ThingTypeHandler.cs b/Source/Core/Types/ThingTypeHandler.cs index 9751c5c0..41f5a446 100644 --- a/Source/Core/Types/ThingTypeHandler.cs +++ b/Source/Core/Types/ThingTypeHandler.cs @@ -101,6 +101,11 @@ namespace CodeImp.DoomBuilder.Types return this.value.ToString(); } + public override object GetDefaultValue() + { + return 0; + } + #endregion } } diff --git a/Source/Core/Types/TypeHandler.cs b/Source/Core/Types/TypeHandler.cs index db6ad473..d8f9d504 100644 --- a/Source/Core/Types/TypeHandler.cs +++ b/Source/Core/Types/TypeHandler.cs @@ -120,11 +120,14 @@ namespace CodeImp.DoomBuilder.Types public abstract void SetValue(object value); //mxd. This should replace current value with the default one - public virtual void SetDefaultValue() { } + public virtual void ApplyDefaultValue() { } // This must return the value as one of the primitive data types // supported by UDMF: int, string, float or bool public abstract object GetValue(); + + //mxd. This should return the default value + public abstract object GetDefaultValue(); // This must return the value as integer (for arguments) public virtual int GetIntValue() @@ -136,9 +139,7 @@ namespace CodeImp.DoomBuilder.Types public abstract string GetStringValue(); // This is called when the user presses the browse button - public virtual void Browse(IWin32Window parent) - { - } + public virtual void Browse(IWin32Window parent) { } // This must returns an enum list when IsEnumerable is true public virtual EnumList GetEnumList() diff --git a/Source/Core/Windows/AboutForm.cs b/Source/Core/Windows/AboutForm.cs index d18f72a3..cb631152 100644 --- a/Source/Core/Windows/AboutForm.cs +++ b/Source/Core/Windows/AboutForm.cs @@ -67,8 +67,7 @@ namespace CodeImp.DoomBuilder.Windows // This copies the version number to clipboard private void copyversion_Click(object sender, EventArgs e) { - Clipboard.Clear(); - Clipboard.SetText(Application.ProductVersion); + Clipboard.SetDataObject(Application.ProductVersion, true, 5, 200); //mxd } } } \ No newline at end of file diff --git a/Source/Core/Windows/ActionBrowserForm.cs b/Source/Core/Windows/ActionBrowserForm.cs index 8ec64585..71a890e2 100644 --- a/Source/Core/Windows/ActionBrowserForm.cs +++ b/Source/Core/Windows/ActionBrowserForm.cs @@ -36,16 +36,20 @@ namespace CodeImp.DoomBuilder.Windows private readonly ComboBox[] options; private readonly Label[] optionlbls; private readonly TreeNode[] allNodes; //mxd + private readonly bool addanyaction; //mxd // Properties public int SelectedAction { get { return selectedaction; } } // Constructor - public ActionBrowserForm(int action) + public ActionBrowserForm(int action, bool addanyaction) { // Initialize InitializeComponent(); + //mxd. Show "Any action" item? + this.addanyaction = addanyaction; + // Make array references for controls options = new[] { option0, option1, option2, option3, option4, option5, option6, option7 }; optionlbls = new[] { option0label, option1label, option2label, option3label, option4label, @@ -94,12 +98,24 @@ namespace CodeImp.DoomBuilder.Windows foreach(GeneralizedBit ab in sc.Options[i].Bits) { // Select this setting if matches - if((actionbits & ab.Index) == ab.Index) options[i].SelectedItem = ab; + if((actionbits & ab.Index) == ab.Index) + { + options[i].SelectedItem = ab; + if(ab.Index > 0) break; //mxd + } } } + else + { + break; //mxd + } } } } + + //mxd. Make sure something is selected + if(category.SelectedIndex == -1 && category.Items.Count > 0) + category.SelectedIndex = 0; } else { @@ -110,9 +126,10 @@ namespace CodeImp.DoomBuilder.Windows // This browses for an action // Returns the new action or the same action when cancelled - public static int BrowseAction(IWin32Window owner, int action) + public static int BrowseAction(IWin32Window owner, int action) { return BrowseAction(owner, action, false); } //mxd + public static int BrowseAction(IWin32Window owner, int action, bool addanyaction) { - ActionBrowserForm f = new ActionBrowserForm(action); + ActionBrowserForm f = new ActionBrowserForm(action, addanyaction); if(f.ShowDialog(owner) == DialogResult.OK) action = f.SelectedAction; f.Dispose(); return action; @@ -123,6 +140,19 @@ namespace CodeImp.DoomBuilder.Windows { actions.BeginUpdate(); actions.ShowLines = true; + + // Add "Any action" item? + if(addanyaction) + { + TreeNode aan = actions.Nodes.Add("Any action"); + aan.Tag = new LinedefActionInfo(-1, "Any action", false, false); + if(action == -1) + { + actions.SelectedNode = aan; + aan.EnsureVisible(); + } + } + foreach(LinedefActionCategory ac in General.Map.Config.ActionCategories) { // Empty category names will not be created @@ -162,24 +192,40 @@ namespace CodeImp.DoomBuilder.Windows } //mxd - private void FilterActions(string p) + private void FilterActions(string text) { - List<TreeNode> filteredNodes = new List<TreeNode>(); + List<TreeNode> filterednodes = new List<TreeNode>(); + HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase); + // First add nodes, which titles start with given text foreach(TreeNode n in allNodes) { foreach(TreeNode cn in n.Nodes) { LinedefActionInfo ai = cn.Tag as LinedefActionInfo; - if(ai.Title.ToLowerInvariant().IndexOf(p) != -1) - filteredNodes.Add(cn); + if(ai != null && ai.Title.ToUpperInvariant().StartsWith(text)) + { + filterednodes.Add(cn); + added.Add(ai.Title); + } + } + } + + // Then add nodes, which titles contain given text + foreach(TreeNode n in allNodes) + { + foreach(TreeNode cn in n.Nodes) + { + LinedefActionInfo ai = cn.Tag as LinedefActionInfo; + if(ai != null && !added.Contains(ai.Title) && ai.Title.ToUpperInvariant().Contains(text)) + filterednodes.Add(cn); } } actions.BeginUpdate(); actions.Nodes.Clear(); actions.ShowLines = false; - actions.Nodes.AddRange(filteredNodes.ToArray()); + actions.Nodes.AddRange(filterednodes.ToArray()); actions.EndUpdate(); } @@ -292,7 +338,7 @@ namespace CodeImp.DoomBuilder.Windows { if(!string.IsNullOrEmpty(tbFilter.Text.Trim())) { - FilterActions(tbFilter.Text); + FilterActions(tbFilter.Text.ToUpperInvariant()); } else { diff --git a/Source/Core/Windows/ChangeMapForm.cs b/Source/Core/Windows/ChangeMapForm.cs index 522c4b69..bd3a62c7 100644 --- a/Source/Core/Windows/ChangeMapForm.cs +++ b/Source/Core/Windows/ChangeMapForm.cs @@ -180,7 +180,7 @@ namespace CodeImp.DoomBuilder.Windows // Current map is already loaded if(mapslist.SelectedItems[0].Text == options.LevelName) { - MessageBox.Show(this, "Map '" + options.LevelName + "' is already loaded.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show(this, "Map \"" + options.LevelName + "\" is already loaded.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); mapslist.Focus(); return; } diff --git a/Source/Core/Windows/ConfigForm.cs b/Source/Core/Windows/ConfigForm.cs index bc76e833..f1e806cd 100644 --- a/Source/Core/Windows/ConfigForm.cs +++ b/Source/Core/Windows/ConfigForm.cs @@ -402,7 +402,7 @@ namespace CodeImp.DoomBuilder.Windows ci = listconfigs.Items[i].Tag as ConfigurationInfo; if(!ci.Resources.IsValid()) { - MessageBox.Show(this, "At least one resource doesn't exist in '" + ci.Name + "' game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); + MessageBox.Show(this, "At least one resource doesn't exist in \"" + ci.Name + "\" game configuration!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning); tabs.SelectedTab = tabresources; listconfigs.Focus(); listconfigs.Items[i].Selected = true; @@ -871,7 +871,7 @@ namespace CodeImp.DoomBuilder.Windows configinfocopy = current.Clone(); //display info - General.Interface.DisplayStatus(StatusType.Info, "Copied '" + configinfocopy.Name + "' game configuration"); + General.Interface.DisplayStatus(StatusType.Info, "Copied \"" + configinfocopy.Name + "\" game configuration"); } private void pasteall_Click(object sender, EventArgs e) @@ -885,7 +885,7 @@ namespace CodeImp.DoomBuilder.Windows //update display cbEngineSelector.Text = string.Empty; // Otherwise current text from cbEngineSelector will override the pasted one listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty); - General.Interface.DisplayStatus(StatusType.Info, "Pasted game configuration from '" + configinfocopy.Name + "'"); + General.Interface.DisplayStatus(StatusType.Info, "Pasted game configuration from \"" + configinfocopy.Name + "\""); } private void pasteresources_Click(object sender, EventArgs e) @@ -898,7 +898,7 @@ namespace CodeImp.DoomBuilder.Windows //update display listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty); - General.Interface.DisplayStatus(StatusType.Info, "Pasted resources from '" + configinfocopy.Name + "'"); + General.Interface.DisplayStatus(StatusType.Info, "Pasted resources from \"" + configinfocopy.Name + "\""); } private void pasteengines_Click(object sender, EventArgs e) @@ -912,7 +912,7 @@ namespace CodeImp.DoomBuilder.Windows //update display cbEngineSelector.Text = string.Empty; // Otherwise current text from cbEngineSelector will override the pasted one listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty); - General.Interface.DisplayStatus(StatusType.Info, "Pasted engines list from '" + configinfocopy.Name + "'"); + General.Interface.DisplayStatus(StatusType.Info, "Pasted engines list from \"" + configinfocopy.Name + "\""); } private void pastecolorpresets_Click(object sender, EventArgs e) @@ -925,7 +925,7 @@ namespace CodeImp.DoomBuilder.Windows //update display listconfigs_SelectedIndexChanged(listconfigs, EventArgs.Empty); - General.Interface.DisplayStatus(StatusType.Info, "Pasted color presets from '" + configinfocopy.Name + "'"); + General.Interface.DisplayStatus(StatusType.Info, "Pasted color presets from \"" + configinfocopy.Name + "\""); } #endregion diff --git a/Source/Core/Windows/EffectBrowserForm.cs b/Source/Core/Windows/EffectBrowserForm.cs index 0c8d1661..e29d2a53 100644 --- a/Source/Core/Windows/EffectBrowserForm.cs +++ b/Source/Core/Windows/EffectBrowserForm.cs @@ -33,28 +33,31 @@ namespace CodeImp.DoomBuilder.Windows // Variables private int selectedeffect; - private ComboBox[] options; - private Label[] optionlbls; - private ListViewItem[] allItems; //mxd + private readonly ComboBox[] options; + private readonly ListViewItem[] allitems; //mxd + private readonly bool addanyeffect; // Properties public int SelectedEffect { get { return selectedeffect; } } // Constructor - public EffectBrowserForm(int effect) + public EffectBrowserForm(int effect, bool addanyeffect) { // Initialize InitializeComponent(); + //mxd. Show "Any action" item? + this.addanyeffect = addanyeffect; + // Make array references for controls options = new[] { option0, option1, option2, option3, option4, option5, option6, option7 }; - optionlbls = new[] { option0label, option1label, option2label, option3label, option4label, - option5label, option6label, option7label }; + Label[] optionlbls = { option0label, option1label, option2label, option3label, + option4label, option5label, option6label, option7label }; // Go for all predefined effects bool selected = CreateEffects(effect); //mxd - allItems = new ListViewItem[effects.Items.Count]; //mxd - effects.Items.CopyTo(allItems, 0); //mxd + allitems = new ListViewItem[effects.Items.Count]; //mxd + effects.Items.CopyTo(allitems, 0); //mxd // Using generalized effects? if(General.Map.Config.GeneralizedEffects) @@ -82,7 +85,11 @@ namespace CodeImp.DoomBuilder.Windows foreach(GeneralizedBit ab in o.Bits) { // Select this setting if matches - if((effect & ab.Index) == ab.Index) options[i].SelectedItem = ab; + if((effect & ab.Index) == ab.Index) + { + options[i].SelectedItem = ab; + if(ab.Index > 0) break; //mxd + } } } } @@ -106,9 +113,10 @@ namespace CodeImp.DoomBuilder.Windows // This browses for an effect // Returns the new effect or the same effect when cancelled - public static int BrowseEffect(IWin32Window owner, int effect) + public static int BrowseEffect(IWin32Window owner, int effect) { return BrowseEffect(owner, effect, false); } //mxd + public static int BrowseEffect(IWin32Window owner, int effect, bool addanyeffect) { - EffectBrowserForm f = new EffectBrowserForm(effect); + EffectBrowserForm f = new EffectBrowserForm(effect, addanyeffect); if(f.ShowDialog(owner) == DialogResult.OK) effect = f.SelectedEffect; f.Dispose(); return effect; @@ -119,6 +127,18 @@ namespace CodeImp.DoomBuilder.Windows { bool selected = false; + if(addanyeffect) + { + ListViewItem n = effects.Items.Add("-1"); + n.SubItems.Add("Any effect"); + n.Tag = new SectorEffectInfo(-1, "Any effect", false, false); + if(effect == -1) + { + selected = true; + n.Selected = true; + } + } + foreach(SectorEffectInfo si in General.Map.Config.SortedSectorEffects) { // Create effect @@ -135,20 +155,36 @@ namespace CodeImp.DoomBuilder.Windows } //mxd - private void FilterEffects(string p) + private void FilterEffects(string text) { - List<ListViewItem> filteredItems = new List<ListViewItem>(); + List<ListViewItem> filtereditems = new List<ListViewItem>(); + HashSet<string> added = new HashSet<string>(StringComparer.OrdinalIgnoreCase); - foreach(ListViewItem i in allItems) + // First add nodes, which titles start with given text + foreach(ListViewItem i in allitems) { SectorEffectInfo si = i.Tag as SectorEffectInfo; - if(si.Title.ToLowerInvariant().IndexOf(p) != -1) - filteredItems.Add(i); + if(si != null && si.Title.ToUpperInvariant().StartsWith(text)) + { + filtereditems.Add(i); + added.Add(si.Title); + } + } + + // Then add nodes, which titles contain given text + foreach(ListViewItem i in allitems) + { + SectorEffectInfo si = i.Tag as SectorEffectInfo; + if(si != null && !added.Contains(si.Title) && si.Title.ToUpperInvariant().Contains(text)) + { + filtereditems.Add(i); + added.Add(si.Title); + } } effects.BeginUpdate(); effects.Items.Clear(); - effects.Items.AddRange(filteredItems.ToArray()); + effects.Items.AddRange(filtereditems.ToArray()); effects.EndUpdate(); } @@ -181,6 +217,10 @@ namespace CodeImp.DoomBuilder.Windows if(options[i].SelectedIndex > -1) selectedeffect += (options[i].SelectedItem as GeneralizedBit).Index; } + else + { + break; //mxd + } } } @@ -212,7 +252,7 @@ namespace CodeImp.DoomBuilder.Windows { if(!string.IsNullOrEmpty(tbFilter.Text.Trim())) { - FilterEffects(tbFilter.Text); + FilterEffects(tbFilter.Text.ToUpperInvariant()); } else { diff --git a/Source/Core/Windows/GridSetupForm.cs b/Source/Core/Windows/GridSetupForm.cs index a86778c0..5eecedc0 100644 --- a/Source/Core/Windows/GridSetupForm.cs +++ b/Source/Core/Windows/GridSetupForm.cs @@ -140,8 +140,18 @@ namespace CodeImp.DoomBuilder.Windows // Apply private void apply_Click(object sender, EventArgs e) { + //mxd. Apply + int newgridsize = gridsize.GetResult(General.Map.Grid.GridSize); + if(newgridsize != General.Map.Grid.GridSize) + { + //Disable automatic grid resizing + General.MainWindow.DisableDynamicGridResize(); + + //Apply grid size + General.Map.Grid.SetGridSize(newgridsize); + } + // Apply - General.Map.Grid.SetGridSize(gridsize.GetResult(General.Map.Grid.GridSize)); General.Map.Grid.SetBackgroundView(backoffsetx.GetResult(General.Map.Grid.BackgroundX), backoffsety.GetResult(General.Map.Grid.BackgroundY), backscalex.GetResult((int)(General.Map.Grid.BackgroundScaleX * 100.0f)) / 100.0f, diff --git a/Source/Core/Windows/IMainForm.cs b/Source/Core/Windows/IMainForm.cs index 2b6c7a07..0754b00b 100644 --- a/Source/Core/Windows/IMainForm.cs +++ b/Source/Core/Windows/IMainForm.cs @@ -87,12 +87,24 @@ namespace CodeImp.DoomBuilder.Windows /// </summary> /// <returns>Returns the new action or the same action when cancelled</returns> int BrowseLinedefActions(IWin32Window owner, int initialvalue); - + + /// <summary> + /// This browses the lindef types + /// </summary> + /// <returns>Returns the new action or the same action when cancelled</returns> + int BrowseLinedefActions(IWin32Window owner, int initialvalue, bool addanyaction); + /// <summary> /// This browses sector effects /// </summary> /// <returns>Returns the new effect or the same effect when cancelled</returns> int BrowseSectorEffect(IWin32Window owner, int initialvalue); + + /// <summary> + /// This browses sector effects + /// </summary> + /// <returns>Returns the new effect or the same effect when cancelled</returns> + int BrowseSectorEffect(IWin32Window owner, int initialvalue, bool addanyeffect); /// <summary> /// This browses for a texture diff --git a/Source/Core/Windows/LinedefColorPresetsForm.cs b/Source/Core/Windows/LinedefColorPresetsForm.cs index dd746db4..0eb00147 100644 --- a/Source/Core/Windows/LinedefColorPresetsForm.cs +++ b/Source/Core/Windows/LinedefColorPresetsForm.cs @@ -180,7 +180,7 @@ namespace CodeImp.DoomBuilder.Windows if(gotmismatch) continue; //we have a match - warning = "Preset matches '" + other.Preset.Name + "'!"; + warning = "Preset matches \"" + other.Preset.Name + "\"!"; item.ShowWarning = true; break; } diff --git a/Source/Core/Windows/LinedefEditForm.Designer.cs b/Source/Core/Windows/LinedefEditForm.Designer.cs index 37f9414b..c25230ba 100644 --- a/Source/Core/Windows/LinedefEditForm.Designer.cs +++ b/Source/Core/Windows/LinedefEditForm.Designer.cs @@ -47,6 +47,8 @@ namespace CodeImp.DoomBuilder.Windows this.backside = new System.Windows.Forms.CheckBox(); this.frontside = new System.Windows.Forms.CheckBox(); this.frontgroup = new System.Windows.Forms.GroupBox(); + this.replaceunusedfronttextures = new System.Windows.Forms.CheckBox(); + this.replaceunusedbacktextures = new System.Windows.Forms.CheckBox(); this.labelFrontTextureOffset = new System.Windows.Forms.Label(); this.frontsector = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); this.frontlow = new CodeImp.DoomBuilder.Controls.TextureSelectorControl(); @@ -100,6 +102,7 @@ namespace CodeImp.DoomBuilder.Windows // // label5 // + label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); label5.Location = new System.Drawing.Point(437, 13); label5.Name = "label5"; label5.Size = new System.Drawing.Size(83, 16); @@ -109,6 +112,7 @@ namespace CodeImp.DoomBuilder.Windows // // label4 // + label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); label4.Location = new System.Drawing.Point(346, 13); label4.Name = "label4"; label4.Size = new System.Drawing.Size(83, 16); @@ -118,6 +122,7 @@ namespace CodeImp.DoomBuilder.Windows // // label3 // + label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); label3.Location = new System.Drawing.Point(255, 13); label3.Name = "label3"; label3.Size = new System.Drawing.Size(83, 16); @@ -136,6 +141,7 @@ namespace CodeImp.DoomBuilder.Windows // // label8 // + label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); label8.Location = new System.Drawing.Point(437, 13); label8.Name = "label8"; label8.Size = new System.Drawing.Size(83, 16); @@ -154,6 +160,7 @@ namespace CodeImp.DoomBuilder.Windows // // label10 // + label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); label10.Location = new System.Drawing.Point(255, 13); label10.Name = "label10"; label10.Size = new System.Drawing.Size(83, 16); @@ -257,6 +264,7 @@ namespace CodeImp.DoomBuilder.Windows // this.frontgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.frontgroup.Controls.Add(this.replaceunusedfronttextures); this.frontgroup.Controls.Add(this.labelFrontTextureOffset); this.frontgroup.Controls.Add(this.frontsector); this.frontgroup.Controls.Add(label11); @@ -275,6 +283,18 @@ namespace CodeImp.DoomBuilder.Windows this.frontgroup.TabStop = false; this.frontgroup.Text = " "; // + // replaceunusedfronttextures + // + this.replaceunusedfronttextures.AutoSize = true; + this.replaceunusedfronttextures.Location = new System.Drawing.Point(90, 121); + this.replaceunusedfronttextures.Name = "replaceunusedfronttextures"; + this.replaceunusedfronttextures.Size = new System.Drawing.Size(144, 17); + this.replaceunusedfronttextures.TabIndex = 43; + this.replaceunusedfronttextures.Text = "Replace unused textures"; + this.replaceunusedfronttextures.UseVisualStyleBackColor = true; + this.replaceunusedfronttextures.CheckedChanged += new System.EventHandler(this.replaceunusedfronttextures_CheckedChanged); + // + // // labelFrontTextureOffset // this.labelFrontTextureOffset.Location = new System.Drawing.Point(6, 70); @@ -354,6 +374,7 @@ namespace CodeImp.DoomBuilder.Windows // this.backgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.backgroup.Controls.Add(this.replaceunusedbacktextures); this.backgroup.Controls.Add(this.labelBackTextureOffset); this.backgroup.Controls.Add(this.backsector); this.backgroup.Controls.Add(label12); @@ -372,6 +393,18 @@ namespace CodeImp.DoomBuilder.Windows this.backgroup.TabStop = false; this.backgroup.Text = " "; // + // replaceunusedbacktextures + // + this.replaceunusedbacktextures.AutoSize = true; + this.replaceunusedbacktextures.Location = new System.Drawing.Point(90, 121); + this.replaceunusedbacktextures.Name = "replaceunusedbacktextures"; + this.replaceunusedbacktextures.Size = new System.Drawing.Size(144, 17); + this.replaceunusedbacktextures.TabIndex = 44; + this.replaceunusedbacktextures.Text = "Replace unused textures"; + this.replaceunusedbacktextures.UseVisualStyleBackColor = true; + this.replaceunusedbacktextures.CheckedChanged += new System.EventHandler(this.replaceunusedbacktextures_CheckedChanged); + // + // // labelBackTextureOffset // this.labelBackTextureOffset.Location = new System.Drawing.Point(6, 70); @@ -625,5 +658,7 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.Label labelFrontTextureOffset; private System.Windows.Forms.Label labelBackTextureOffset; private CodeImp.DoomBuilder.Controls.ArgumentsControl argscontrol; + private System.Windows.Forms.CheckBox replaceunusedfronttextures; + private System.Windows.Forms.CheckBox replaceunusedbacktextures; } } \ No newline at end of file diff --git a/Source/Core/Windows/LinedefEditForm.cs b/Source/Core/Windows/LinedefEditForm.cs index dcf617ab..2a09b16f 100644 --- a/Source/Core/Windows/LinedefEditForm.cs +++ b/Source/Core/Windows/LinedefEditForm.cs @@ -65,20 +65,20 @@ namespace CodeImp.DoomBuilder.Windows public readonly int OffsetX; public readonly int OffsetY; - public readonly string TextureTop; - public readonly string TextureMid; - public readonly string TextureLow; + public readonly string HighTexture; + public readonly string MiddleTexture; + public readonly string LowTexture; public SidedefProperties(Sidedef side) { - //offset + // Offset OffsetX = side.OffsetX; OffsetY = side.OffsetY; - //textures - TextureTop = side.HighTexture; - TextureMid = side.MiddleTexture; - TextureLow = side.LowTexture; + // Textures + HighTexture = side.HighTexture; + MiddleTexture = side.MiddleTexture; + LowTexture = side.LowTexture; } } @@ -149,6 +149,12 @@ namespace CodeImp.DoomBuilder.Windows apply.Top = panel.Bottom + panel.Margin.Bottom + apply.Margin.Top; cancel.Top = apply.Top; + //mxd. Apply texture replacement settings + preventchanges = true; + replaceunusedfronttextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedfronttextures", true); + replaceunusedbacktextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedbacktextures", true); + preventchanges = false; + // Update window height this.Height = apply.Bottom + apply.Margin.Bottom * 2 + (this.Height - this.ClientRectangle.Height) + 1; } @@ -285,22 +291,22 @@ namespace CodeImp.DoomBuilder.Windows if(l.Front != null) { //mxd - if(fronthigh.TextureName != l.Front.HighTexture) + if(!string.IsNullOrEmpty(fronthigh.TextureName) && fronthigh.TextureName != l.Front.HighTexture) { if(!fronthigh.Required && l.Front.HighRequired()) fronthigh.Required = true; - fronthigh.MultipleTextures = true; //mxd + fronthigh.MultipleTextures = true; fronthigh.TextureName = string.Empty; } - if(frontmid.TextureName != l.Front.MiddleTexture) + if(!string.IsNullOrEmpty(frontmid.TextureName) && frontmid.TextureName != l.Front.MiddleTexture) { if(!frontmid.Required && l.Front.MiddleRequired()) frontmid.Required = true; - frontmid.MultipleTextures = true; //mxd + frontmid.MultipleTextures = true; frontmid.TextureName = string.Empty; } - if(frontlow.TextureName != l.Front.LowTexture) + if(!string.IsNullOrEmpty(frontlow.TextureName) && frontlow.TextureName != l.Front.LowTexture) { if(!frontlow.Required && l.Front.LowRequired()) frontlow.Required = true; - frontlow.MultipleTextures = true; //mxd + frontlow.MultipleTextures = true; frontlow.TextureName = string.Empty; } if(frontsector.Text != l.Front.Sector.Index.ToString()) frontsector.Text = string.Empty; @@ -312,22 +318,22 @@ namespace CodeImp.DoomBuilder.Windows if(l.Back != null) { //mxd - if(backhigh.TextureName != l.Back.HighTexture) + if(!string.IsNullOrEmpty(backhigh.TextureName) && backhigh.TextureName != l.Back.HighTexture) { if(!backhigh.Required && l.Back.HighRequired()) backhigh.Required = true; - backhigh.MultipleTextures = true; //mxd + backhigh.MultipleTextures = true; backhigh.TextureName = string.Empty; } - if(backmid.TextureName != l.Back.MiddleTexture) + if(!string.IsNullOrEmpty(backmid.TextureName) && backmid.TextureName != l.Back.MiddleTexture) { if(!backmid.Required && l.Back.MiddleRequired()) backmid.Required = true; - backmid.MultipleTextures = true; //mxd + backmid.MultipleTextures = true; backmid.TextureName = string.Empty; } - if(backlow.TextureName != l.Back.LowTexture) + if(!string.IsNullOrEmpty(backlow.TextureName) && backlow.TextureName != l.Back.LowTexture) { if(!backlow.Required && l.Back.LowRequired()) backlow.Required = true; - backlow.MultipleTextures = true; //mxd + backlow.MultipleTextures = true; backlow.TextureName = string.Empty; } if(backsector.Text != l.Back.Sector.Index.ToString()) backsector.Text = string.Empty; @@ -593,7 +599,12 @@ namespace CodeImp.DoomBuilder.Windows //mxd. Store window location private void LinedefEditForm_FormClosing(object sender, FormClosingEventArgs e) { + // Save location location = this.Location; + + // Save persistent settings + General.Settings.WriteSetting("editlinedefswindow.replaceunusedfronttextures", replaceunusedfronttextures.Checked); + General.Settings.WriteSetting("editlinedefswindow.replaceunusedbacktextures", replaceunusedbacktextures.Checked); } // Help! @@ -659,24 +670,31 @@ namespace CodeImp.DoomBuilder.Windows private void fronthigh_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(fronthigh.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.TextureTop : "-"); + if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { - foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.HighRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.HighTexture != "-")))) + l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + i++; + } } // Update the used textures @@ -689,24 +707,31 @@ namespace CodeImp.DoomBuilder.Windows private void frontmid_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(frontmid.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.TextureMid : "-"); + if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { - foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.MiddleRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.MiddleTexture != "-")))) + l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + i++; + } } // Update the used textures @@ -719,24 +744,31 @@ namespace CodeImp.DoomBuilder.Windows private void frontlow_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(frontlow.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.TextureLow : "-"); + if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.LowRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.LowTexture != "-")))) + l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + i++; + } } // Update the used textures @@ -749,24 +781,31 @@ namespace CodeImp.DoomBuilder.Windows private void backhigh_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backhigh.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.TextureTop : "-"); + if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.HighRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.HighTexture != "-")))) + l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + i++; + } } // Update the used textures @@ -779,24 +818,31 @@ namespace CodeImp.DoomBuilder.Windows private void backmid_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backmid.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.TextureMid : "-"); + if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.MiddleRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.MiddleTexture != "-")))) + l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + i++; + } } // Update the used textures @@ -809,24 +855,111 @@ namespace CodeImp.DoomBuilder.Windows private void backlow_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backlow.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.TextureLow : "-"); + if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-"); i++; } - - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.LowRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.LowTexture != "-")))) + l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + i++; + } + } + + // Update the used textures + General.Map.Data.UpdateUsedTextures(); + + General.Map.IsChanged = true; + if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty); + } + + private void replaceunusedfronttextures_CheckedChanged(object sender, EventArgs e) + { + //Re-apply front textures + if(preventchanges) return; + MakeUndo(); + + // Set values + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front == null) continue; + + // Update top texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(fronthigh.TextureName)) + l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-"); + else + l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + + // Update middle texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontmid.TextureName)) + l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-"); + else + l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + + // Update bottom texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontlow.TextureName)) + l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-"); + else + l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + + i++; + } + + // Update the used textures + General.Map.Data.UpdateUsedTextures(); + + General.Map.IsChanged = true; + if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty); + } + + private void replaceunusedbacktextures_CheckedChanged(object sender, EventArgs e) + { + //Re-apply back textures + if(preventchanges) return; + MakeUndo(); + + // Set values + int i = 0; + foreach(Linedef l in lines) + { + if(l.Back == null) continue; + + // Update top texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backhigh.TextureName)) + l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-"); + else + l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + + // Update middle texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backmid.TextureName)) + l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-"); + else + l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + + // Update bottom texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backlow.TextureName)) + l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-"); + else + l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + + i++; } // Update the used textures diff --git a/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs b/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs index ee764311..902e5c6e 100644 --- a/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs +++ b/Source/Core/Windows/LinedefEditFormUDMF.Designer.cs @@ -60,6 +60,7 @@ namespace CodeImp.DoomBuilder.Windows this.tabfront = new System.Windows.Forms.TabPage(); this.frontside = new System.Windows.Forms.CheckBox(); this.frontgroup = new System.Windows.Forms.GroupBox(); + this.replaceunusedfronttextures = new System.Windows.Forms.CheckBox(); this.frontflagsgroup = new System.Windows.Forms.GroupBox(); this.flagsFront = new CodeImp.DoomBuilder.Controls.CheckboxArrayControl(); this.frontscalegroup = new System.Windows.Forms.GroupBox(); @@ -90,6 +91,7 @@ namespace CodeImp.DoomBuilder.Windows this.tabback = new System.Windows.Forms.TabPage(); this.backside = new System.Windows.Forms.CheckBox(); this.backgroup = new System.Windows.Forms.GroupBox(); + this.replaceunusedbacktextures = new System.Windows.Forms.CheckBox(); this.groupBox4 = new System.Windows.Forms.GroupBox(); this.resetbacklight = new System.Windows.Forms.Button(); this.backsector = new CodeImp.DoomBuilder.Controls.ButtonsNumericTextbox(); @@ -496,6 +498,7 @@ namespace CodeImp.DoomBuilder.Windows this.frontgroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.frontgroup.Controls.Add(this.replaceunusedfronttextures); this.frontgroup.Controls.Add(this.frontflagsgroup); this.frontgroup.Controls.Add(this.frontscalegroup); this.frontgroup.Controls.Add(this.groupBox6); @@ -511,6 +514,17 @@ namespace CodeImp.DoomBuilder.Windows this.frontgroup.TabStop = false; this.frontgroup.Text = " "; // + // replaceunusedfronttextures + // + this.replaceunusedfronttextures.AutoSize = true; + this.replaceunusedfronttextures.Location = new System.Drawing.Point(312, 15); + this.replaceunusedfronttextures.Name = "replaceunusedfronttextures"; + this.replaceunusedfronttextures.Size = new System.Drawing.Size(144, 17); + this.replaceunusedfronttextures.TabIndex = 46; + this.replaceunusedfronttextures.Text = "Replace unused textures"; + this.replaceunusedfronttextures.UseVisualStyleBackColor = true; + this.replaceunusedfronttextures.CheckedChanged += new System.EventHandler(this.replaceunusedfronttextures_CheckedChanged); + // // frontflagsgroup // this.frontflagsgroup.Controls.Add(this.flagsFront); @@ -862,7 +876,7 @@ namespace CodeImp.DoomBuilder.Windows // // frontmid // - this.frontmid.Location = new System.Drawing.Point(309, 217); + this.frontmid.Location = new System.Drawing.Point(309, 225); this.frontmid.MultipleTextures = false; this.frontmid.Name = "frontmid"; this.frontmid.Required = false; @@ -874,7 +888,7 @@ namespace CodeImp.DoomBuilder.Windows // // fronthigh // - this.fronthigh.Location = new System.Drawing.Point(309, 19); + this.fronthigh.Location = new System.Drawing.Point(309, 35); this.fronthigh.MultipleTextures = false; this.fronthigh.Name = "fronthigh"; this.fronthigh.Required = false; @@ -914,6 +928,7 @@ namespace CodeImp.DoomBuilder.Windows this.backgroup.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.backgroup.Controls.Add(this.replaceunusedbacktextures); this.backgroup.Controls.Add(this.groupBox4); this.backgroup.Controls.Add(this.backflagsgroup); this.backgroup.Controls.Add(this.backscalegroup); @@ -929,6 +944,17 @@ namespace CodeImp.DoomBuilder.Windows this.backgroup.TabStop = false; this.backgroup.Text = " "; // + // replaceunusedbacktextures + // + this.replaceunusedbacktextures.AutoSize = true; + this.replaceunusedbacktextures.Location = new System.Drawing.Point(312, 15); + this.replaceunusedbacktextures.Name = "replaceunusedbacktextures"; + this.replaceunusedbacktextures.Size = new System.Drawing.Size(144, 17); + this.replaceunusedbacktextures.TabIndex = 47; + this.replaceunusedbacktextures.Text = "Replace unused textures"; + this.replaceunusedbacktextures.UseVisualStyleBackColor = true; + this.replaceunusedbacktextures.CheckedChanged += new System.EventHandler(this.replaceunusedbacktextures_CheckedChanged); + // // groupBox4 // this.groupBox4.Controls.Add(this.resetbacklight); @@ -1290,7 +1316,7 @@ namespace CodeImp.DoomBuilder.Windows // // backmid // - this.backmid.Location = new System.Drawing.Point(309, 217); + this.backmid.Location = new System.Drawing.Point(309, 225); this.backmid.MultipleTextures = false; this.backmid.Name = "backmid"; this.backmid.Required = false; @@ -1302,7 +1328,7 @@ namespace CodeImp.DoomBuilder.Windows // // backhigh // - this.backhigh.Location = new System.Drawing.Point(309, 19); + this.backhigh.Location = new System.Drawing.Point(309, 35); this.backhigh.MultipleTextures = false; this.backhigh.Name = "backhigh"; this.backhigh.Required = false; @@ -1359,6 +1385,7 @@ namespace CodeImp.DoomBuilder.Windows this.fieldslist.Name = "fieldslist"; this.fieldslist.PropertyColumnVisible = true; this.fieldslist.PropertyColumnWidth = 150; + this.fieldslist.ShowFixedFields = true; this.fieldslist.Size = new System.Drawing.Size(527, 602); this.fieldslist.TabIndex = 0; this.fieldslist.TypeColumnVisible = true; @@ -1406,6 +1433,7 @@ namespace CodeImp.DoomBuilder.Windows this.tabfront.ResumeLayout(false); this.tabfront.PerformLayout(); this.frontgroup.ResumeLayout(false); + this.frontgroup.PerformLayout(); this.frontflagsgroup.ResumeLayout(false); this.frontscalegroup.ResumeLayout(false); this.groupBox6.ResumeLayout(false); @@ -1414,6 +1442,7 @@ namespace CodeImp.DoomBuilder.Windows this.tabback.ResumeLayout(false); this.tabback.PerformLayout(); this.backgroup.ResumeLayout(false); + this.backgroup.PerformLayout(); this.groupBox4.ResumeLayout(false); this.groupBox4.PerformLayout(); this.backflagsgroup.ResumeLayout(false); @@ -1517,5 +1546,7 @@ namespace CodeImp.DoomBuilder.Windows private CodeImp.DoomBuilder.GZBuilder.Controls.TagsSelector tagsselector; private System.Windows.Forms.Button resetfrontlight; private System.Windows.Forms.Button resetbacklight; + private System.Windows.Forms.CheckBox replaceunusedfronttextures; + private System.Windows.Forms.CheckBox replaceunusedbacktextures; } } \ No newline at end of file diff --git a/Source/Core/Windows/LinedefEditFormUDMF.cs b/Source/Core/Windows/LinedefEditFormUDMF.cs index 8098c5da..35069bfb 100644 --- a/Source/Core/Windows/LinedefEditFormUDMF.cs +++ b/Source/Core/Windows/LinedefEditFormUDMF.cs @@ -102,22 +102,22 @@ namespace CodeImp.DoomBuilder.Windows public readonly int Brightness; public readonly bool AbsoluteBrightness; - public readonly string TextureTop; - public readonly string TextureMid; - public readonly string TextureLow; + public readonly string HighTexture; + public readonly string MiddleTexture; + public readonly string LowTexture; public SidedefProperties(Sidedef side) { Flags = side.GetFlags(); - //offset + // Offset OffsetX = side.OffsetX; OffsetY = side.OffsetY; Brightness = UniFields.GetInteger(side.Fields, "light", 0); AbsoluteBrightness = side.Fields.GetValue("lightabsolute", false); - //scales + // Scale ScaleTopX = UniFields.GetFloat(side.Fields, "scalex_top", 1.0f); ScaleTopY = UniFields.GetFloat(side.Fields, "scaley_top", 1.0f); ScaleMidX = UniFields.GetFloat(side.Fields, "scalex_mid", 1.0f); @@ -125,7 +125,7 @@ namespace CodeImp.DoomBuilder.Windows ScaleBottomX = UniFields.GetFloat(side.Fields, "scalex_bottom", 1.0f); ScaleBottomY = UniFields.GetFloat(side.Fields, "scaley_bottom", 1.0f); - //offsets + // Local offsets OffsetTopX = UniFields.GetFloat(side.Fields, "offsetx_top", 0f); OffsetTopY = UniFields.GetFloat(side.Fields, "offsety_top", 0f); OffsetMidX = UniFields.GetFloat(side.Fields, "offsetx_mid", 0f); @@ -133,10 +133,10 @@ namespace CodeImp.DoomBuilder.Windows OffsetBottomX = UniFields.GetFloat(side.Fields, "offsetx_bottom", 0f); OffsetBottomY = UniFields.GetFloat(side.Fields, "offsety_bottom", 0f); - //textures - TextureTop = side.HighTexture; - TextureMid = side.MiddleTexture; - TextureLow = side.LowTexture; + // Textures + HighTexture = side.HighTexture; + MiddleTexture = side.MiddleTexture; + LowTexture = side.LowTexture; } } @@ -149,7 +149,7 @@ namespace CodeImp.DoomBuilder.Windows // Initialize InitializeComponent(); - //mxd. Widow setup + // Widow setup if(location != Point.Empty) { this.StartPosition = FormStartPosition.Manual; @@ -169,7 +169,7 @@ namespace CodeImp.DoomBuilder.Windows flags.Add(lf.Value, lf.Key); flags.Enabled = General.Map.Config.LinedefFlags.Count > 0; - //mxd + // Fill sidedef flags lists foreach(KeyValuePair<string, string> lf in General.Map.Config.SidedefFlags) { flagsFront.Add(lf.Value, lf.Key); @@ -184,7 +184,7 @@ namespace CodeImp.DoomBuilder.Windows // Fill activations list foreach(LinedefActivateInfo ai in General.Map.Config.LinedefActivates) udmfactivates.Add(ai.Title, ai); - //mxd. Fill keys list + // Fill keys list keynumbers = new List<int>(); if(General.Map.Config.Enums.ContainsKey("keys")) { @@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.Windows // Fill universal fields list fieldslist.ListFixedFields(General.Map.Config.LinedefFields); - //initialize controls + // Initialize controls frontUdmfControls = new List<PairedFieldsControl> { pfcFrontOffsetTop, pfcFrontOffsetMid, pfcFrontOffsetBottom, pfcFrontScaleTop, pfcFrontScaleMid, pfcFrontScaleBottom }; backUdmfControls = new List<PairedFieldsControl> { pfcBackOffsetTop, pfcBackOffsetMid, pfcBackOffsetBottom, pfcBackScaleTop, pfcBackScaleMid, pfcBackScaleBottom }; @@ -225,13 +225,19 @@ namespace CodeImp.DoomBuilder.Windows foreach(KeyValuePair<string, string> lf in General.Map.Config.LinedefRenderStyles) renderStyle.Items.Add(lf.Value); - //Restore value linking + // Restore value linking pfcFrontScaleTop.LinkValues = linkFrontTopScale; pfcFrontScaleMid.LinkValues = linkFrontMidScale; pfcFrontScaleBottom.LinkValues = linkFrontBottomScale; pfcBackScaleTop.LinkValues = linkBackTopScale; pfcBackScaleMid.LinkValues = linkBackMidScale; pfcBackScaleBottom.LinkValues = linkBackBottomScale; + + // Apply texture replacement settings + preventchanges = true; + replaceunusedfronttextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedfronttextures", true); + replaceunusedbacktextures.Checked = General.Settings.ReadSetting("editlinedefswindow.replaceunusedbacktextures", true); + preventchanges = false; } #endregion @@ -301,11 +307,11 @@ namespace CodeImp.DoomBuilder.Windows frontlow.Required = fl.Front.LowRequired(); frontsector.Text = fl.Front.Sector.Index.ToString(); - //flags + // Flags foreach(CheckBox c in flagsFront.Checkboxes) if(fl.Front.Flags.ContainsKey(c.Tag.ToString())) c.Checked = fl.Front.Flags[c.Tag.ToString()]; - //front settings + // Front settings foreach(PairedFieldsControl pfc in frontUdmfControls) pfc.SetValuesFrom(fl.Front.Fields, true); @@ -326,11 +332,11 @@ namespace CodeImp.DoomBuilder.Windows backlow.Required = fl.Back.LowRequired(); backsector.Text = fl.Back.Sector.Index.ToString(); - //flags + // Flags foreach(CheckBox c in flagsBack.Checkboxes) if(fl.Back.Flags.ContainsKey(c.Tag.ToString())) c.Checked = fl.Back.Flags[c.Tag.ToString()]; - //back settings + // Back settings foreach(PairedFieldsControl pfc in backUdmfControls) pfc.SetValuesFrom(fl.Back.Fields, true); @@ -432,19 +438,19 @@ namespace CodeImp.DoomBuilder.Windows if(l.Front != null) { //mxd - if(fronthigh.TextureName != l.Front.HighTexture) + if(!string.IsNullOrEmpty(fronthigh.TextureName) && fronthigh.TextureName != l.Front.HighTexture) { if(!fronthigh.Required && l.Front.HighRequired()) fronthigh.Required = true; - fronthigh.MultipleTextures = true; //mxd + fronthigh.MultipleTextures = true; fronthigh.TextureName = string.Empty; } - if(frontmid.TextureName != l.Front.MiddleTexture) + if(!string.IsNullOrEmpty(frontmid.TextureName) && frontmid.TextureName != l.Front.MiddleTexture) { if(!frontmid.Required && l.Front.MiddleRequired()) frontmid.Required = true; - frontmid.MultipleTextures = true; //mxd + frontmid.MultipleTextures = true; frontmid.TextureName = string.Empty; } - if(frontlow.TextureName != l.Front.LowTexture) + if(!string.IsNullOrEmpty(frontlow.TextureName) && frontlow.TextureName != l.Front.LowTexture) { if(!frontlow.Required && l.Front.LowRequired()) frontlow.Required = true; frontlow.MultipleTextures = true; //mxd @@ -486,22 +492,22 @@ namespace CodeImp.DoomBuilder.Windows if(l.Back != null) { //mxd - if(backhigh.TextureName != l.Back.HighTexture) + if(!string.IsNullOrEmpty(backhigh.TextureName) && backhigh.TextureName != l.Back.HighTexture) { if(!backhigh.Required && l.Back.HighRequired()) backhigh.Required = true; - backhigh.MultipleTextures = true; //mxd + backhigh.MultipleTextures = true; backhigh.TextureName = string.Empty; } - if(backmid.TextureName != l.Back.MiddleTexture) + if(!string.IsNullOrEmpty(backmid.TextureName) && backmid.TextureName != l.Back.MiddleTexture) { if(!backmid.Required && l.Back.MiddleRequired()) backmid.Required = true; - backmid.MultipleTextures = true; //mxd + backmid.MultipleTextures = true; backmid.TextureName = string.Empty; } - if(backlow.TextureName != l.Back.LowTexture) + if(!string.IsNullOrEmpty(backlow.TextureName) && backlow.TextureName != l.Back.LowTexture) { if(!backlow.Required && l.Back.LowRequired()) backlow.Required = true; - backlow.MultipleTextures = true; //mxd + backlow.MultipleTextures = true; backlow.TextureName = string.Empty; } if(backsector.Text != l.Back.Sector.Index.ToString()) backsector.Text = string.Empty; @@ -829,11 +835,16 @@ namespace CodeImp.DoomBuilder.Windows fieldslist.Focus(); } - //mxd. Store window location + //mxd. Store window settings private void LinedefEditForm_FormClosing(object sender, FormClosingEventArgs e) { + // Save location and active tab location = this.Location; activetab = tabs.SelectedIndex; + + // Save persistent settings + General.Settings.WriteSetting("editlinedefswindow.replaceunusedfronttextures", replaceunusedfronttextures.Checked); + General.Settings.WriteSetting("editlinedefswindow.replaceunusedbacktextures", replaceunusedbacktextures.Checked); } // Help! @@ -1055,23 +1066,31 @@ namespace CodeImp.DoomBuilder.Windows private void fronthigh_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(fronthigh.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.TextureTop : "-"); + if(l.Front != null) l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-"); i++; } - } - else //update values + } + // Update values + else { - foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.HighRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.HighTexture != "-")))) + l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + i++; + } } // Update the used textures @@ -1084,23 +1103,31 @@ namespace CodeImp.DoomBuilder.Windows private void frontmid_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(frontmid.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.TextureMid : "-"); + if(l.Front != null) l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-"); i++; } - } - else //update values + } + // Update values + else { - foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.MiddleRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.MiddleTexture != "-")))) + l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + i++; + } } // Update the used textures @@ -1113,23 +1140,31 @@ namespace CodeImp.DoomBuilder.Windows private void frontlow_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(frontlow.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.TextureLow : "-"); + if(l.Front != null) l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-"); i++; } - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Front != null) l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + { + if(l.Front != null + && (replaceunusedfronttextures.Checked + || (l.Front.LowRequired() + || (linedefprops[i].Front != null && linedefprops[i].Front.LowTexture != "-")))) + l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + i++; + } } // Update the used textures @@ -1142,23 +1177,31 @@ namespace CodeImp.DoomBuilder.Windows private void backhigh_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backhigh.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.TextureTop : "-"); + if(l.Back != null) l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-"); i++; } - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.HighRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.HighTexture != "-")))) + l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + i++; + } } // Update the used textures @@ -1171,23 +1214,31 @@ namespace CodeImp.DoomBuilder.Windows private void backmid_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backmid.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.TextureMid : "-"); + if(l.Back != null) l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-"); i++; } - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.MiddleRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.MiddleTexture != "-")))) + l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + i++; + } } // Update the used textures @@ -1200,23 +1251,111 @@ namespace CodeImp.DoomBuilder.Windows private void backlow_OnValueChanged(object sender, EventArgs e) { if(preventchanges) return; - MakeUndo(); //mxd + MakeUndo(); - //restore values + // Restore values if(string.IsNullOrEmpty(backlow.TextureName)) { int i = 0; - foreach(Linedef l in lines) { - if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.TextureLow : "-"); + if(l.Back != null) l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-"); i++; } - } - else //update values + } + // Update values + else { + int i = 0; foreach(Linedef l in lines) - if(l.Back != null) l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + { + if(l.Back != null + && (replaceunusedbacktextures.Checked + || (l.Back.LowRequired() + || (linedefprops[i].Back != null && linedefprops[i].Back.LowTexture != "-")))) + l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + i++; + } + } + + // Update the used textures + General.Map.Data.UpdateUsedTextures(); + + General.Map.IsChanged = true; + if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty); + } + + private void replaceunusedfronttextures_CheckedChanged(object sender, EventArgs e) + { + //Re-apply front textures + if(preventchanges) return; + MakeUndo(); + + // Set values + int i = 0; + foreach(Linedef l in lines) + { + if(l.Front == null) continue; + + // Update top texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(fronthigh.TextureName)) + l.Front.SetTextureHigh(linedefprops[i].Front != null ? linedefprops[i].Front.HighTexture : "-"); + else + l.Front.SetTextureHigh(fronthigh.GetResult(l.Front.HighTexture)); + + // Update middle texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontmid.TextureName)) + l.Front.SetTextureMid(linedefprops[i].Front != null ? linedefprops[i].Front.MiddleTexture : "-"); + else + l.Front.SetTextureMid(frontmid.GetResult(l.Front.MiddleTexture)); + + // Update bottom texture + if(!replaceunusedfronttextures.Checked || string.IsNullOrEmpty(frontlow.TextureName)) + l.Front.SetTextureLow(linedefprops[i].Front != null ? linedefprops[i].Front.LowTexture : "-"); + else + l.Front.SetTextureLow(frontlow.GetResult(l.Front.LowTexture)); + + i++; + } + + // Update the used textures + General.Map.Data.UpdateUsedTextures(); + + General.Map.IsChanged = true; + if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty); + } + + private void replaceunusedbacktextures_CheckedChanged(object sender, EventArgs e) + { + //Re-apply back textures + if(preventchanges) return; + MakeUndo(); + + // Set values + int i = 0; + foreach(Linedef l in lines) + { + if(l.Back == null) continue; + + // Update top texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backhigh.TextureName)) + l.Back.SetTextureHigh(linedefprops[i].Back != null ? linedefprops[i].Back.HighTexture : "-"); + else + l.Back.SetTextureHigh(backhigh.GetResult(l.Back.HighTexture)); + + // Update middle texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backmid.TextureName)) + l.Back.SetTextureMid(linedefprops[i].Back != null ? linedefprops[i].Back.MiddleTexture : "-"); + else + l.Back.SetTextureMid(backmid.GetResult(l.Back.MiddleTexture)); + + // Update bottom texture + if(!replaceunusedbacktextures.Checked || string.IsNullOrEmpty(backlow.TextureName)) + l.Back.SetTextureLow(linedefprops[i].Back != null ? linedefprops[i].Back.LowTexture : "-"); + else + l.Back.SetTextureLow(backlow.GetResult(l.Back.LowTexture)); + + i++; } // Update the used textures diff --git a/Source/Core/Windows/LinedefEditFormUDMF.resx b/Source/Core/Windows/LinedefEditFormUDMF.resx index d572a5b7..e3a990b4 100644 --- a/Source/Core/Windows/LinedefEditFormUDMF.resx +++ b/Source/Core/Windows/LinedefEditFormUDMF.resx @@ -146,7 +146,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADM - CAAAAk1TRnQBSQFMAgEBAgEAAcABAAHAAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + CAAAAk1TRnQBSQFMAgEBAgEAAcgBAAHIAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs index ef555c39..ed083009 100644 --- a/Source/Core/Windows/MainForm.Designer.cs +++ b/Source/Core/Windows/MainForm.Designer.cs @@ -182,6 +182,7 @@ namespace CodeImp.DoomBuilder.Windows this.buttonviewceilings = new System.Windows.Forms.ToolStripButton(); this.seperatorviews = new System.Windows.Forms.ToolStripSeparator(); this.buttontogglecomments = new System.Windows.Forms.ToolStripButton(); + this.buttontogglefixedthingsscale = new System.Windows.Forms.ToolStripButton(); this.buttonsnaptogrid = new System.Windows.Forms.ToolStripButton(); this.buttonautomerge = new System.Windows.Forms.ToolStripButton(); this.buttonautoclearsidetextures = new System.Windows.Forms.ToolStripButton(); @@ -256,6 +257,7 @@ namespace CodeImp.DoomBuilder.Windows this.flowLayoutPanel = new System.Windows.Forms.FlowLayoutPanel(); this.modecontrolsloolbar = new System.Windows.Forms.ToolStrip(); this.itemtogglecomments = new System.Windows.Forms.ToolStripMenuItem(); + this.itemtogglefixedthingsscale = new System.Windows.Forms.ToolStripMenuItem(); this.itemdynamicgridsize = new System.Windows.Forms.ToolStripMenuItem(); this.itemrendernightspath = new System.Windows.Forms.ToolStripMenuItem(); toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); @@ -741,6 +743,7 @@ namespace CodeImp.DoomBuilder.Windows this.itemtogglegrid, this.itemrendernightspath, this.itemtogglecomments, + this.itemtogglefixedthingsscale, this.toolStripSeparator4, this.menuzoom, this.itemgotocoords, @@ -1247,6 +1250,7 @@ namespace CodeImp.DoomBuilder.Windows this.buttonfullbrightness, this.buttontogglegrid, this.buttontogglecomments, + this.buttontogglefixedthingsscale, this.separatorfullbrightness, this.buttonviewnormal, this.buttonviewbrightness, @@ -1677,6 +1681,19 @@ namespace CodeImp.DoomBuilder.Windows this.buttontogglecomments.Text = "Show Comments"; this.buttontogglecomments.Click += new System.EventHandler(this.InvokeTaggedAction); // + // buttontogglefixedthingsscale + // + this.buttontogglefixedthingsscale.Checked = true; + this.buttontogglefixedthingsscale.CheckState = System.Windows.Forms.CheckState.Checked; + this.buttontogglefixedthingsscale.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttontogglefixedthingsscale.Image = global::CodeImp.DoomBuilder.Properties.Resources.FixedThingsScale; + this.buttontogglefixedthingsscale.ImageTransparentColor = System.Drawing.Color.Magenta; + this.buttontogglefixedthingsscale.Name = "buttontogglefixedthingsscale"; + this.buttontogglefixedthingsscale.Size = new System.Drawing.Size(23, 22); + this.buttontogglefixedthingsscale.Tag = "builder_togglefixedthingsscale"; + this.buttontogglefixedthingsscale.Text = "Fixed Things Scale"; + this.buttontogglefixedthingsscale.Click += new System.EventHandler(this.InvokeTaggedAction); + // // buttonsnaptogrid // this.buttonsnaptogrid.Checked = true; @@ -2234,9 +2251,9 @@ namespace CodeImp.DoomBuilder.Windows // this.statistics.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.statistics.ForeColor = System.Drawing.SystemColors.GrayText; - this.statistics.Location = new System.Drawing.Point(869, 2); + this.statistics.Location = new System.Drawing.Point(849, 2); this.statistics.Name = "statistics"; - this.statistics.Size = new System.Drawing.Size(118, 102); + this.statistics.Size = new System.Drawing.Size(138, 102); this.statistics.TabIndex = 9; this.statistics.Visible = false; // @@ -2448,6 +2465,18 @@ namespace CodeImp.DoomBuilder.Windows this.itemtogglecomments.Text = "Show Comments"; this.itemtogglecomments.Click += new System.EventHandler(this.InvokeTaggedAction); // + // itemtogglefixedthingsscale + // + this.itemtogglefixedthingsscale.Checked = true; + this.itemtogglefixedthingsscale.CheckOnClick = true; + this.itemtogglefixedthingsscale.CheckState = System.Windows.Forms.CheckState.Checked; + this.itemtogglefixedthingsscale.Image = global::CodeImp.DoomBuilder.Properties.Resources.FixedThingsScale; + this.itemtogglefixedthingsscale.Name = "itemtogglefixedthingsscale"; + this.itemtogglefixedthingsscale.Size = new System.Drawing.Size(215, 22); + this.itemtogglefixedthingsscale.Tag = "builder_togglefixedthingsscale"; + this.itemtogglefixedthingsscale.Text = "Fixed Things Scale"; + this.itemtogglefixedthingsscale.Click += new System.EventHandler(this.InvokeTaggedAction); + // // itemdynamicgridsize // this.itemdynamicgridsize.Checked = true; @@ -2725,6 +2754,7 @@ namespace CodeImp.DoomBuilder.Windows private ToolStripMenuItem item2zoom800; private ToolStripMenuItem itemzoom800; private ToolStripButton buttontogglecomments; + private ToolStripButton buttontogglefixedthingsscale; private ToolStripMenuItem itemlinedefcolors; private ToolStripSeparator separatorlinecolors; private ToolStripButton buttonlinededfcolors; @@ -2737,5 +2767,6 @@ namespace CodeImp.DoomBuilder.Windows private ToolStripMenuItem itemdynamicgridsize; private ToolStripMenuItem itemrendernightspath; private ToolStripMenuItem itemtogglecomments; + private ToolStripMenuItem itemtogglefixedthingsscale; } } \ No newline at end of file diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs index cdde40ad..64fd4c7b 100644 --- a/Source/Core/Windows/MainForm.cs +++ b/Source/Core/Windows/MainForm.cs @@ -734,14 +734,14 @@ namespace CodeImp.DoomBuilder.Windows if(!File.Exists(filePaths[0])) { - General.Interface.DisplayStatus(StatusType.Warning, "Cannot open '" + filePaths[0] + "': file does not exist!"); + General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filePaths[0] + "\": file does not exist!"); return; } string ext = Path.GetExtension(filePaths[0]); if(string.IsNullOrEmpty(ext) || ext.ToLower() != ".wad") { - General.Interface.DisplayStatus(StatusType.Warning, "Cannot open '" + filePaths[0] + "': only WAD files can be loaded this way!"); + General.Interface.DisplayStatus(StatusType.Warning, "Cannot open \"" + filePaths[0] + "\": only WAD files can be loaded this way!"); return; } @@ -970,6 +970,9 @@ namespace CodeImp.DoomBuilder.Windows // Get integral zoom level int size = int.Parse((sender as ToolStripMenuItem).Tag.ToString(), CultureInfo.InvariantCulture); + //mxd. Disable automatic grid resizing + DisableDynamicGridResize(); + // Change grid size General.Map.Grid.SetGridSize(size); @@ -1493,8 +1496,7 @@ namespace CodeImp.DoomBuilder.Windows if(General.Map != null) { // Make the new items list - ToolStripItem[] items = new ToolStripItem[(General.Map.Config.Skills.Count * 2) + General.Map.ConfigSettings.TestEngines.Count + 2]; //mxd - int addindex = 0; + List<ToolStripItem> items = new List<ToolStripItem>(General.Map.Config.Skills.Count * 2 + General.Map.ConfigSettings.TestEngines.Count + 2); // Positive skills are with monsters foreach(SkillInfo si in General.Map.Config.Skills) @@ -1504,12 +1506,11 @@ namespace CodeImp.DoomBuilder.Windows menuitem.Click += TestSkill_Click; menuitem.Tag = si.Index; menuitem.Checked = (General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index)); - items[addindex++] = menuitem; + items.Add(menuitem); } // Add seperator - items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) }; - addindex++; + items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) }); // Negative skills are without monsters foreach(SkillInfo si in General.Map.Config.Skills) @@ -1519,26 +1520,37 @@ namespace CodeImp.DoomBuilder.Windows menuitem.Click += TestSkill_Click; menuitem.Tag = -si.Index; menuitem.Checked = (!General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index)); - items[addindex++] = menuitem; + items.Add(menuitem); } //mxd. Add seperator - items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) }; - addindex++; + items.Add(new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) }); //mxd. Add test engines for(int i = 0; i < General.Map.ConfigSettings.TestEngines.Count; i++) { + if(General.Map.ConfigSettings.TestEngines[i].TestProgramName == EngineInfo.DEFAULT_ENGINE_NAME) continue; ToolStripMenuItem menuitem = new ToolStripMenuItem(General.Map.ConfigSettings.TestEngines[i].TestProgramName); menuitem.Image = General.Map.ConfigSettings.TestEngines[i].TestProgramIcon; menuitem.Click += TestEngine_Click; menuitem.Tag = i; menuitem.Checked = (i == General.Map.ConfigSettings.CurrentEngineIndex); - items[addindex++] = menuitem; + items.Add(menuitem); } // Add to list - buttontest.DropDownItems.AddRange(items); + buttontest.DropDownItems.AddRange(items.ToArray()); + } + } + + //mxd + internal void DisableDynamicGridResize() + { + if(General.Settings.DynamicGridSize) + { + General.Settings.DynamicGridSize = false; + itemdynamicgridsize.Checked = false; + buttontoggledynamicgrid.Checked = false; } } @@ -2027,6 +2039,8 @@ namespace CodeImp.DoomBuilder.Windows itemrendernightspath.Checked = General.Settings.RenderNiGHTSPath; buttontogglecomments.Visible = General.Settings.ToolbarViewModes && maploaded && General.Map.UDMF; //mxd buttontogglecomments.Checked = General.Settings.RenderComments; //mxd + buttontogglefixedthingsscale.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd + buttontogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd separatorfullbrightness.Visible = General.Settings.ToolbarViewModes && maploaded; //mxd buttonviewbrightness.Visible = General.Settings.ToolbarViewModes && maploaded; buttonviewceilings.Visible = General.Settings.ToolbarViewModes && maploaded; @@ -2048,7 +2062,7 @@ namespace CodeImp.DoomBuilder.Windows buttontogglefog.Visible = General.Settings.GZToolbarGZDoom && maploaded; buttontogglesky.Visible = maploaded && (General.Settings.GZToolbarGZDoom || General.Map.SRB2); buttontoggleeventlines.Visible = General.Settings.GZToolbarGZDoom && maploaded; - buttontogglevisualvertices.Visible = General.Settings.GZToolbarGZDoom && maploaded; + buttontogglevisualvertices.Visible = General.Settings.GZToolbarGZDoom && maploaded && General.Map.UDMF; separatorgzmodes.Visible = General.Settings.GZToolbarGZDoom && maploaded; //mxd. Show/hide additional panels @@ -2776,6 +2790,19 @@ namespace CodeImp.DoomBuilder.Windows RedrawDisplay(); } + //mxd. Action to toggle fixed things scale + [BeginAction("togglefixedthingsscale")] + internal void ToggleFixedThingsScale() + { + buttontogglefixedthingsscale.Checked = !buttontogglefixedthingsscale.Checked; + itemtogglefixedthingsscale.Checked = buttontogglefixedthingsscale.Checked; + General.Settings.FixedThingsScale = buttontogglefixedthingsscale.Checked; + DisplayStatus(StatusType.Action, "Fixed things scale is " + (buttontogglefixedthingsscale.Checked ? "ENABLED" : "DISABLED")); + + // Redraw display to show changes + RedrawDisplay(); + } + // Action to toggle snap to grid [BeginAction("togglesnap")] internal void ToggleSnapToGrid() @@ -2888,6 +2915,8 @@ namespace CodeImp.DoomBuilder.Windows itemtoggleinfo.Checked = IsInfoPanelExpanded; itemtogglecomments.Visible = (General.Map != null && General.Map.UDMF); //mxd itemtogglecomments.Checked = General.Settings.RenderComments; //mxd + itemtogglefixedthingsscale.Visible = (General.Map != null); //mxd + itemtogglefixedthingsscale.Checked = General.Settings.FixedThingsScale; //mxd // View mode items if(General.Map != null) @@ -3059,7 +3088,7 @@ namespace CodeImp.DoomBuilder.Windows } //open file - DisplayStatus(StatusType.Info, "Shortcut reference saved to '" + path + "'"); + DisplayStatus(StatusType.Info, "Shortcut reference saved to \"" + path + "\""); Process.Start(path); } @@ -3067,8 +3096,8 @@ namespace CodeImp.DoomBuilder.Windows private void itemopenconfigfolder_Click(object sender, EventArgs e) { if(Directory.Exists(General.SettingsPath)) Process.Start(General.SettingsPath); - else General.ShowErrorMessage("Huh? Where did Settings folder go?.." + Environment.NewLine - + "I swear it was here: '" + General.SettingsPath + "'!", MessageBoxButtons.OK); // I don't think this will ever happen + else General.ShowErrorMessage("Huh? Where did Settings folder go?.." + Environment.NewLine + + "I swear it was here: \"" + General.SettingsPath + "\"!", MessageBoxButtons.OK); // I don't think this will ever happen } #endregion @@ -3195,11 +3224,11 @@ namespace CodeImp.DoomBuilder.Windows string folder = General.Settings.ScreenshotsPath; if(!Directory.Exists(folder)) { - if(folder != General.DefaultScreenshotsPath - && General.ShowErrorMessage("Screenshots save path '" + folder - + "' does not exist!\nPress OK to save to the default folder ('" - + General.DefaultScreenshotsPath - + "').\nPress Cancel to abort.", MessageBoxButtons.OKCancel) == DialogResult.Cancel) return; + if(folder != General.DefaultScreenshotsPath + && General.ShowErrorMessage("Screenshots save path \"" + folder + + "\" does not exist!\nPress OK to save to the default folder (\"" + + General.DefaultScreenshotsPath + + "\").\nPress Cancel to abort.", MessageBoxButtons.OKCancel) == DialogResult.Cancel) return; folder = General.DefaultScreenshotsPath; @@ -3332,7 +3361,7 @@ namespace CodeImp.DoomBuilder.Windows { bitmap.Save(path, ImageFormat.Png); } - DisplayStatus(StatusType.Info, "Screenshot saved to '" + path + "'"); + DisplayStatus(StatusType.Info, "Screenshot saved to \"" + path + "\""); } catch(ExternalException e) { @@ -3690,14 +3719,28 @@ namespace CodeImp.DoomBuilder.Windows // Returns the new action or the same action when cancelled public int BrowseLinedefActions(IWin32Window owner, int initialvalue) { - return ActionBrowserForm.BrowseAction(owner, initialvalue); + return ActionBrowserForm.BrowseAction(owner, initialvalue, false); + } + + //mxd. This browses the lindef types + // Returns the new action or the same action when cancelled + public int BrowseLinedefActions(IWin32Window owner, int initialvalue, bool addanyaction) + { + return ActionBrowserForm.BrowseAction(owner, initialvalue, addanyaction); } // This browses sector effects // Returns the new effect or the same effect when cancelled public int BrowseSectorEffect(IWin32Window owner, int initialvalue) { - return EffectBrowserForm.BrowseEffect(owner, initialvalue); + return EffectBrowserForm.BrowseEffect(owner, initialvalue, false); + } + + //mxd. This browses sector effects + // Returns the new effect or the same effect when cancelled + public int BrowseSectorEffect(IWin32Window owner, int initialvalue, bool addanyeffect) + { + return EffectBrowserForm.BrowseEffect(owner, initialvalue, addanyeffect); } // This browses thing types diff --git a/Source/Core/Windows/OpenMapOptionsForm.Designer.cs b/Source/Core/Windows/OpenMapOptionsForm.Designer.cs index e6db6557..93442de0 100644 --- a/Source/Core/Windows/OpenMapOptionsForm.Designer.cs +++ b/Source/Core/Windows/OpenMapOptionsForm.Designer.cs @@ -225,7 +225,7 @@ namespace CodeImp.DoomBuilder.Windows this.MaximizeBox = false; this.MinimizeBox = false; this.Name = "OpenMapOptionsForm"; - this.Opacity = 1; + this.Opacity = 0; this.ShowIcon = false; this.ShowInTaskbar = false; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; diff --git a/Source/Core/Windows/OpenMapOptionsForm.cs b/Source/Core/Windows/OpenMapOptionsForm.cs index cfcfe6ff..d6dfd94d 100644 --- a/Source/Core/Windows/OpenMapOptionsForm.cs +++ b/Source/Core/Windows/OpenMapOptionsForm.cs @@ -30,7 +30,7 @@ using CodeImp.DoomBuilder.Config; namespace CodeImp.DoomBuilder.Windows { - internal partial class OpenMapOptionsForm : DelayedForm + internal partial class OpenMapOptionsForm : Form { // Variables private Configuration mapsettings; @@ -126,72 +126,103 @@ namespace CodeImp.DoomBuilder.Windows scriptcompiler.Items.Add(group.Value); } - //mxd. Go for all enabled configurations - for(int i = 0; i < General.Configs.Count; i++) + // Go for all configurations + foreach(ConfigurationInfo info in General.Configs) { - if(!General.Configs[i].Enabled) continue; - // Add config name to list - index = config.Items.Add(General.Configs[i]); + index = config.Items.Add(info); // Select this item - if(General.Configs[i].Filename == gameconfig) config.SelectedIndex = index; + if(info.Filename == gameconfig) config.SelectedIndex = index; } - //mxd. No dice? Try disabled ones + // Still no configuration selected? if(config.SelectedIndex == -1) { - for(int i = 0; i < General.Configs.Count; i++) + //mxd. Then go for all ENABLED configurations with resources to find a suitable one + foreach(ConfigurationInfo info in General.Configs) { - if(General.Configs[i].Enabled) continue; - if(General.Configs[i].Filename == gameconfig) + // Check if a resource location is set for this configuration, if so, match the wad against this configuration + if(info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile)) { - //add and Select this item - config.SelectedIndex = config.Items.Add(General.Configs[i]); + //mxd. Already added? + index = config.Items.IndexOf(info); + + // Select or add and select this item + config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } - // Still no configuration selected? - if(config.SelectedIndex == -1) + //mxd. Still no configuration selected? + if(config.SelectedIndex == -1) { - // Then go for all configurations with resources to find a suitable one - for(int i = 0; i < General.Configs.Count; i++) + // Then go for all DISABLED configurations with resources to find a suitable one + foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is set for this configuration, if so, match the wad against this configuration - if(General.Configs[i].Resources.Count > 0 && MatchConfiguration(General.Configs[i].Configuration, wadfile)) + if(!info.Enabled && info.Resources.Count > 0 && MatchConfiguration(info.Configuration, wadfile)) { - index = config.Items.IndexOf(General.Configs[i]); //mxd. Already added? - config.SelectedIndex = (index != -1 ? index : config.Items.Add(General.Configs[i])); // Select or add and select this item + //mxd. Already added? + index = config.Items.IndexOf(info); + + // Select or add and select this item + config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Still no configuration selected? - if(config.SelectedIndex == -1) + if(config.SelectedIndex == -1) + { + //mxd. Then go for all ENABLED configurations without resources to find a suitable one + foreach(ConfigurationInfo info in General.Configs) + { + // Check if a resource location is not set for this configuration, if so, match the wad against this configuration + if(info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile)) + { + //mxd. Already added? + index = config.Items.IndexOf(info); + + // Select or add and select this item + config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); + break; + } + } + } + + //mxd. Still no configuration selected? + if(config.SelectedIndex == -1) { - // Then go for all configurations without resources to find a suitable one - for(int i = 0; i < General.Configs.Count; i++) + // Then go for all DISABLED configurations without resources to find a suitable one + foreach(ConfigurationInfo info in General.Configs) { // Check if a resource location is not set for this configuration, if so, match the wad against this configuration - if(General.Configs[i].Resources.Count == 0 && MatchConfiguration(General.Configs[i].Configuration, wadfile)) + if(!info.Enabled && info.Resources.Count == 0 && MatchConfiguration(info.Configuration, wadfile)) { - index = config.Items.IndexOf(General.Configs[i]); //mxd. Already added? - config.SelectedIndex = (index != -1 ? index : config.Items.Add(General.Configs[i])); // Select or add and select this item + //mxd. Already added? + index = config.Items.IndexOf(info); + + // Select or add and select this item + config.SelectedIndex = (index != -1 ? index : config.Items.Add(info)); break; } } } //mxd. Bail out if still no dice... - if(config.SelectedIndex == -1) + if(config.SelectedIndex == -1 || mapslist.Items.Count == 0) { - this.Visible = false; General.ShowWarningMessage("Unable to find maps using any game configuration.\nDoes this wad contain any maps at all?..", MessageBoxButtons.OK); cancel_Click(this, EventArgs.Empty); } + else + { + // Show the window + this.Opacity = 1; + } // Done Cursor.Current = Cursors.Default; diff --git a/Source/Core/Windows/PreferencesForm.Designer.cs b/Source/Core/Windows/PreferencesForm.Designer.cs index b9fafc31..4871b4d3 100644 --- a/Source/Core/Windows/PreferencesForm.Designer.cs +++ b/Source/Core/Windows/PreferencesForm.Designer.cs @@ -40,10 +40,10 @@ namespace CodeImp.DoomBuilder.Windows System.Windows.Forms.Label label21; System.Windows.Forms.Label label29; System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PreferencesForm)); + this.keepfilterfocused = new System.Windows.Forms.CheckBox(); this.maxBackups = new System.Windows.Forms.TrackBar(); this.labelBackups = new System.Windows.Forms.Label(); this.label27 = new System.Windows.Forms.Label(); - this.checkforupdates = new System.Windows.Forms.CheckBox(); this.cbStoreEditTab = new System.Windows.Forms.CheckBox(); this.locatetexturegroup = new System.Windows.Forms.CheckBox(); this.recentFiles = new System.Windows.Forms.TrackBar(); @@ -215,7 +215,6 @@ namespace CodeImp.DoomBuilder.Windows this.colorliterals = new CodeImp.DoomBuilder.Controls.ColorControl(); this.colorconstants = new CodeImp.DoomBuilder.Controls.ColorControl(); this.previewgroup = new System.Windows.Forms.GroupBox(); - this.scriptedit = new CodeImp.DoomBuilder.Controls.ScriptEditorPreviewControl(); this.tabpasting = new System.Windows.Forms.TabPage(); this.label16 = new System.Windows.Forms.Label(); this.pasteoptions = new CodeImp.DoomBuilder.Controls.PasteOptionsControl(); @@ -266,7 +265,6 @@ namespace CodeImp.DoomBuilder.Windows this.groupBox8.SuspendLayout(); this.groupBox7.SuspendLayout(); this.groupBox6.SuspendLayout(); - this.previewgroup.SuspendLayout(); this.tabpasting.SuspendLayout(); this.SuspendLayout(); // @@ -299,10 +297,10 @@ namespace CodeImp.DoomBuilder.Windows // // groupBox1 // + groupBox1.Controls.Add(this.keepfilterfocused); groupBox1.Controls.Add(this.maxBackups); groupBox1.Controls.Add(this.labelBackups); groupBox1.Controls.Add(this.label27); - groupBox1.Controls.Add(this.checkforupdates); groupBox1.Controls.Add(this.cbStoreEditTab); groupBox1.Controls.Add(this.locatetexturegroup); groupBox1.Controls.Add(this.recentFiles); @@ -332,6 +330,18 @@ namespace CodeImp.DoomBuilder.Windows groupBox1.TabStop = false; groupBox1.Text = " Options "; // + // keepfilterfocused + // + this.keepfilterfocused.AutoSize = true; + this.keepfilterfocused.Location = new System.Drawing.Point(32, 356); + this.keepfilterfocused.Name = "keepfilterfocused"; + this.keepfilterfocused.Size = new System.Drawing.Size(280, 17); + this.keepfilterfocused.TabIndex = 52; + this.keepfilterfocused.Text = "Keep Filter input focused when image browser is open"; + this.toolTip1.SetToolTip(this.keepfilterfocused, "When enabled, all key presses in \r\nimage browsers will be redirected \r\nto the Fil" + + "ter textbox."); + this.keepfilterfocused.UseVisualStyleBackColor = true; + // // maxBackups // this.maxBackups.BackColor = System.Drawing.SystemColors.Window; @@ -364,21 +374,10 @@ namespace CodeImp.DoomBuilder.Windows this.label27.Text = "Max. backups:"; this.toolTip1.SetToolTip(this.label27, "Controls how many backups \r\nare made when a map is saved."); // - // checkforupdates - // - this.checkforupdates.AutoSize = true; - this.checkforupdates.Location = new System.Drawing.Point(32, 440); - this.checkforupdates.Name = "checkforupdates"; - this.checkforupdates.Size = new System.Drawing.Size(160, 17); - this.checkforupdates.TabIndex = 51; - this.checkforupdates.Text = "Check for updates at startup"; - this.checkforupdates.UseVisualStyleBackColor = true; - this.checkforupdates.Visible = false; - // // cbStoreEditTab // this.cbStoreEditTab.AutoSize = true; - this.cbStoreEditTab.Location = new System.Drawing.Point(32, 419); + this.cbStoreEditTab.Location = new System.Drawing.Point(32, 440); this.cbStoreEditTab.Name = "cbStoreEditTab"; this.cbStoreEditTab.Size = new System.Drawing.Size(203, 17); this.cbStoreEditTab.TabIndex = 50; @@ -388,7 +387,7 @@ namespace CodeImp.DoomBuilder.Windows // locatetexturegroup // this.locatetexturegroup.AutoSize = true; - this.locatetexturegroup.Location = new System.Drawing.Point(32, 377); + this.locatetexturegroup.Location = new System.Drawing.Point(32, 398); this.locatetexturegroup.Name = "locatetexturegroup"; this.locatetexturegroup.Size = new System.Drawing.Size(267, 17); this.locatetexturegroup.TabIndex = 49; @@ -465,7 +464,7 @@ namespace CodeImp.DoomBuilder.Windows // cbSynchCameras // this.cbSynchCameras.AutoSize = true; - this.cbSynchCameras.Location = new System.Drawing.Point(32, 398); + this.cbSynchCameras.Location = new System.Drawing.Point(32, 419); this.cbSynchCameras.Name = "cbSynchCameras"; this.cbSynchCameras.Size = new System.Drawing.Size(260, 17); this.cbSynchCameras.TabIndex = 42; @@ -475,7 +474,7 @@ namespace CodeImp.DoomBuilder.Windows // showtexturesizes // this.showtexturesizes.AutoSize = true; - this.showtexturesizes.Location = new System.Drawing.Point(32, 356); + this.showtexturesizes.Location = new System.Drawing.Point(32, 377); this.showtexturesizes.Name = "showtexturesizes"; this.showtexturesizes.Size = new System.Drawing.Size(208, 17); this.showtexturesizes.TabIndex = 41; @@ -612,7 +611,7 @@ namespace CodeImp.DoomBuilder.Windows label1.AutoSize = true; label1.Location = new System.Drawing.Point(28, 29); label1.Name = "label1"; - label1.Size = new System.Drawing.Size(143, 13); + label1.Size = new System.Drawing.Size(135, 13); label1.TabIndex = 20; label1.Text = "Texture and flat brightness:"; label1.TextAlign = System.Drawing.ContentAlignment.TopRight; @@ -2100,6 +2099,7 @@ namespace CodeImp.DoomBuilder.Windows this.scripttabwidth.ButtonStepsUseModifierKeys = false; this.scripttabwidth.ButtonStepsWrapAround = false; this.scripttabwidth.Location = new System.Drawing.Point(181, 22); + this.scripttabwidth.MaximumValue = 2147483647; this.scripttabwidth.Name = "scripttabwidth"; this.scripttabwidth.Size = new System.Drawing.Size(71, 24); this.scripttabwidth.StepValues = null; @@ -2464,7 +2464,6 @@ namespace CodeImp.DoomBuilder.Windows // this.previewgroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.previewgroup.Controls.Add(this.scriptedit); this.previewgroup.Location = new System.Drawing.Point(217, 344); this.previewgroup.Name = "previewgroup"; this.previewgroup.Size = new System.Drawing.Size(457, 157); @@ -2472,13 +2471,6 @@ namespace CodeImp.DoomBuilder.Windows this.previewgroup.TabStop = false; this.previewgroup.Text = " Preview "; // - // scriptedit - // - this.scriptedit.Location = new System.Drawing.Point(6, 19); - this.scriptedit.Name = "scriptedit"; - this.scriptedit.Size = new System.Drawing.Size(445, 132); - this.scriptedit.TabIndex = 0; - // // tabpasting // this.tabpasting.Controls.Add(this.label16); @@ -2589,7 +2581,6 @@ namespace CodeImp.DoomBuilder.Windows this.groupBox7.PerformLayout(); this.groupBox6.ResumeLayout(false); this.groupBox6.PerformLayout(); - this.previewgroup.ResumeLayout(false); this.tabpasting.ResumeLayout(false); this.ResumeLayout(false); @@ -2715,7 +2706,6 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.Label label26; private System.Windows.Forms.CheckBox locatetexturegroup; private System.Windows.Forms.CheckBox cbStoreEditTab; - private System.Windows.Forms.CheckBox checkforupdates; private System.Windows.Forms.TrackBar maxBackups; private System.Windows.Forms.Label labelBackups; private System.Windows.Forms.Label label27; @@ -2778,5 +2768,6 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.CheckBox cbDrawThingsFixedSize; private System.Windows.Forms.Label labelDefaultThingSize; private System.Windows.Forms.TrackBar tbDefaultThingSize; + private System.Windows.Forms.CheckBox keepfilterfocused; } } \ No newline at end of file diff --git a/Source/Core/Windows/PreferencesForm.cs b/Source/Core/Windows/PreferencesForm.cs index 6e0aab3e..7c8b7421 100644 --- a/Source/Core/Windows/PreferencesForm.cs +++ b/Source/Core/Windows/PreferencesForm.cs @@ -39,8 +39,8 @@ namespace CodeImp.DoomBuilder.Windows private bool allowapplycontrol; private bool disregardshift; private bool disregardcontrol; - private readonly List<ListViewItem> actionListItems; //mxd - private readonly List<int> actionListItemsGroupIndices; //mxd + private readonly List<ListViewItem> allactionitems; //mxd + private readonly List<int> allactionitemsgroups; //mxd private bool reloadresources; @@ -90,8 +90,8 @@ namespace CodeImp.DoomBuilder.Windows //mxd locatetexturegroup.Checked = General.Settings.LocateTextureGroup; + keepfilterfocused.Checked = General.Settings.KeepTextureFilterFocused; cbStoreEditTab.Checked = General.Settings.StoreSelectedEditTab; - checkforupdates.Checked = General.Settings.CheckForUpdates; toolbar_gzdoom.Checked = General.Settings.GZToolbarGZDoom; cbSynchCameras.Checked = General.Settings.GZSynchCameras; tbDynLightCount.Value = General.Clamp(General.Settings.GZMaxDynamicLights, tbDynLightCount.Minimum, tbDynLightCount.Maximum); @@ -154,8 +154,10 @@ namespace CodeImp.DoomBuilder.Windows // Fill list of actions Action[] actions = General.Actions.GetAllActions(); - actionListItems = new List<ListViewItem>(); //mxd - actionListItemsGroupIndices = new List<int>(); //mxd + allactionitems = new List<ListViewItem>(); //mxd + allactionitemsgroups = new List<int>(); //mxd + + listactions.BeginUpdate(); //mxd foreach(Action a in actions) { // Create item @@ -167,15 +169,16 @@ namespace CodeImp.DoomBuilder.Windows if(General.Actions.Categories.ContainsKey(a.Category)) { item.Group = listactions.Groups[a.Category]; - actionListItemsGroupIndices.Add(listactions.Groups.IndexOf(item.Group)); + allactionitemsgroups.Add(listactions.Groups.IndexOf(item.Group)); //mxd } else //mxd { - actionListItemsGroupIndices.Add(-1); + allactionitemsgroups.Add(-1); } - actionListItems.Add(item); //mxd + allactionitems.Add(item); //mxd } + listactions.EndUpdate(); //mxd // Set the colors // TODO: Make this automated by using the collection @@ -298,8 +301,8 @@ namespace CodeImp.DoomBuilder.Windows General.Settings.GZToolbarGZDoom = toolbar_gzdoom.Checked; //mxd General.Settings.ShowTextureSizes = showtexturesizes.Checked; General.Settings.StoreSelectedEditTab = cbStoreEditTab.Checked; //mxd - General.Settings.CheckForUpdates = checkforupdates.Checked; //mxd General.Settings.LocateTextureGroup = locatetexturegroup.Checked; //mxd + General.Settings.KeepTextureFilterFocused = keepfilterfocused.Checked; //mxd General.Settings.MaxRecentFiles = recentFiles.Value; //mxd General.Settings.MaxBackups = maxBackups.Value; General.Settings.ScreenshotsPath = screenshotsfolderpath.Text.Trim(); //mxd @@ -323,7 +326,7 @@ namespace CodeImp.DoomBuilder.Windows General.Settings.ScriptFontSize = fontsize; // Apply control keys to actions - foreach(ListViewItem item in actionListItems) //mxd + foreach(ListViewItem item in allactionitems) //mxd General.Actions[item.Name].SetShortcutKey((int)item.SubItems[1].Tag); // Apply the colors @@ -540,7 +543,7 @@ namespace CodeImp.DoomBuilder.Windows if(thiskey != 0) { // Find actions with same key - foreach(ListViewItem item in actionListItems) + foreach(ListViewItem item in allactionitems) { // Don't count the selected action if(item != listactions.SelectedItems[0]) @@ -702,6 +705,9 @@ namespace CodeImp.DoomBuilder.Windows // Item selected private void listactions_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { + //mxd. Leave when not allowed to update + if(!allowapplycontrol) return; + string disregardkeys = ""; // Anything selected? @@ -886,51 +892,61 @@ namespace CodeImp.DoomBuilder.Windows } //mxd - private void tbFilterActions_TextChanged(object sender, EventArgs e) + private void tbFilterActions_TextChanged(object sender, EventArgs e) { + ListViewItem curselection = (listactions.SelectedItems.Count > 0 ? listactions.SelectedItems[0] : null); + ListViewItem toselect = null; + + allowapplycontrol = false; listactions.BeginUpdate(); + listactions.Items.Clear(); - //restore everything - if(string.IsNullOrEmpty(tbFilterActions.Text)) + // Restore everything + if(string.IsNullOrEmpty(tbFilterActions.Text)) { - //restore items - listactions.Items.Clear(); - listactions.Items.AddRange(actionListItems.ToArray()); - - //restore groups - for(int i = 0; i < actionListItems.Count; i++) + // Restore items and groups + for(int i = 0; i < allactionitems.Count; i++) { - if(actionListItemsGroupIndices[i] != -1) - actionListItems[i].Group = listactions.Groups[actionListItemsGroupIndices[i]]; + if(allactionitemsgroups[i] != -1) + allactionitems[i].Group = listactions.Groups[allactionitemsgroups[i]]; + + // Item sould be added AFTER restoring it's group, otherwise item sorting will be screwed! + listactions.Items.Add(allactionitems[i]); + + // Restore selection? + if(allactionitems[i] == curselection) toselect = curselection; } - } - else //apply filtering - { + } + // Apply filtering + else + { string match = tbFilterActions.Text.ToUpperInvariant(); - for(int i = 0; i < actionListItems.Count; i++) + for(int i = 0; i < allactionitems.Count; i++) { - if(actionListItems[i].Text.ToUpperInvariant().Contains(match)) + if(allactionitems[i].Text.ToUpperInvariant().Contains(match)) { - //ensure visible - if(!listactions.Items.Contains(actionListItems[i])) - { - listactions.Items.Add(actionListItems[i]); + // Restore group + if(allactionitemsgroups[i] != -1) + allactionitems[i].Group = listactions.Groups[allactionitemsgroups[i]]; - //restore group - if(actionListItemsGroupIndices[i] != -1) - actionListItems[i].Group = listactions.Groups[actionListItemsGroupIndices[i]]; - } + // Add item + listactions.Items.Add(allactionitems[i]); + + // Restore selection? + if(allactionitems[i] == curselection) toselect = curselection; } - else if(listactions.Items.Contains(actionListItems[i])) - { - //ensure invisible - listactions.Items.Remove(actionListItems[i]); - } } } - listactions.Sort(); + // Restore selection? + if(toselect != null) + { + toselect.Selected = true; + listactions.EnsureVisible(toselect.Index); + } + listactions.EndUpdate(); + allowapplycontrol = true; } #endregion diff --git a/Source/Core/Windows/SectorEditForm.Designer.cs b/Source/Core/Windows/SectorEditForm.Designer.cs index dc8df19c..0717ce2d 100644 --- a/Source/Core/Windows/SectorEditForm.Designer.cs +++ b/Source/Core/Windows/SectorEditForm.Designer.cs @@ -265,7 +265,8 @@ namespace CodeImp.DoomBuilder.Windows // // label2 // - label2.Location = new System.Drawing.Point(193, 16); + label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + label2.Location = new System.Drawing.Point(196, 16); label2.Name = "label2"; label2.Size = new System.Drawing.Size(114, 16); label2.TabIndex = 15; @@ -283,7 +284,8 @@ namespace CodeImp.DoomBuilder.Windows // // label4 // - label4.Location = new System.Drawing.Point(313, 16); + label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + label4.Location = new System.Drawing.Point(316, 16); label4.Name = "label4"; label4.Size = new System.Drawing.Size(114, 16); label4.TabIndex = 14; diff --git a/Source/Core/Windows/ThingEditForm.cs b/Source/Core/Windows/ThingEditForm.cs index 80a4dfd3..0b8c1193 100644 --- a/Source/Core/Windows/ThingEditForm.cs +++ b/Source/Core/Windows/ThingEditForm.cs @@ -391,7 +391,7 @@ namespace CodeImp.DoomBuilder.Windows } // Verify the type - if(((thingtype.GetFullType(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetFullType(0) > General.Map.FormatInterface.MaxThingType))) + if(!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetFullType(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetFullType(0) > General.Map.FormatInterface.MaxThingType))) { General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK); return; @@ -621,12 +621,14 @@ namespace CodeImp.DoomBuilder.Windows action_ValueChanges(this, EventArgs.Empty); //mxd. Update things - if(preventchanges) return; - MakeUndo(); //mxd - - if(((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) + if(preventchanges || + (!string.IsNullOrEmpty(thingtype.TypeStringValue) && + thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType + || thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)) return; + MakeUndo(); //mxd + foreach(Thing t in things) { //Set type diff --git a/Source/Core/Windows/ThingEditFormUDMF.cs b/Source/Core/Windows/ThingEditFormUDMF.cs index dfc1ca43..73f89f9d 100644 --- a/Source/Core/Windows/ThingEditFormUDMF.cs +++ b/Source/Core/Windows/ThingEditFormUDMF.cs @@ -131,11 +131,11 @@ namespace CodeImp.DoomBuilder.Windows // Fill universal fields list fieldslist.ListFixedFields(General.Map.Config.ThingFields); - //mxd. Show fixed fields? - hidefixedfields.Checked = !General.Settings.ReadSetting("customfieldsshowfixed", true); + //mxd. Show fixed fields? + hidefixedfields.Checked = !General.Settings.ReadSetting("customfieldsshowfixed", true); - // Thing height? - posZ.Visible = General.Map.FormatInterface.HasThingHeight; + // Thing height? + posZ.Visible = General.Map.FormatInterface.HasThingHeight; zlabel.Visible = General.Map.FormatInterface.HasThingHeight; cbAbsoluteHeight.Visible = General.Map.FormatInterface.HasThingHeight; //mxd @@ -177,7 +177,7 @@ namespace CodeImp.DoomBuilder.Windows Thing ft = General.GetByIndex(things, 0); // Set type - thingtype.SelectType(ft.FullType); + thingtype.SelectType(ft.SRB2Type); // Flags foreach(CheckBox c in flags.Checkboxes) @@ -199,6 +199,11 @@ namespace CodeImp.DoomBuilder.Windows posY.ButtonStep = General.Map.Grid.GridSize; posZ.ButtonStep = General.Map.Grid.GridSize; + //mxd. User vars. Should be done before adding regular fields + ThingTypeInfo fti = General.Map.Data.GetThingInfoEx(ft.SRB2Type); + if(fti != null && fti.Actor != null && fti.Actor.UserVars.Count > 0) + fieldslist.SetUserVars(fti.Actor.UserVars, ft.Fields, true); + // Custom fields fieldslist.SetValues(ft.Fields, true); commenteditor.SetValues(ft.Fields, true); @@ -236,7 +241,7 @@ namespace CodeImp.DoomBuilder.Windows // Type does not match? ThingTypeInfo info = thingtype.GetSelectedInfo(); //mxd - if(info != null && info.Index != t.FullType) thingtype.ClearSelectedType(); + if(info != null && info.Index != t.SRB2Type) thingtype.ClearSelectedType(); // Flags foreach(CheckBox c in flags.Checkboxes) @@ -272,6 +277,11 @@ namespace CodeImp.DoomBuilder.Windows //mxd. Arguments argscontrol.SetValue(t, false); + //mxd. User vars. Should be done before adding regular fields + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.SRB2Type); + if(ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0) + fieldslist.SetUserVars(ti.Actor.UserVars, t.Fields, false); + //mxd. Custom fields fieldslist.SetValues(t.Fields, false); commenteditor.SetValues(t.Fields, false); //mxd. Comments @@ -294,16 +304,6 @@ namespace CodeImp.DoomBuilder.Windows //mxd. Store initial properties thingprops.Add(new ThingProperties(t)); - - //mxd. add user vars - /*if(info != null && info.Actor != null && info.Actor.UserVars.Count > 0) - { - foreach(string s in info.Actor.UserVars) - { - if(!t.Fields.ContainsKey(s)) - fieldslist.SetValue(s, 0, CodeImp.DoomBuilder.Types.UniversalType.Integer); - } - }*/ } preventchanges = false; @@ -442,7 +442,7 @@ namespace CodeImp.DoomBuilder.Windows } // Verify the type - if(((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) + if(!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType))) { General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK); return; @@ -490,6 +490,11 @@ namespace CodeImp.DoomBuilder.Windows if(!string.IsNullOrEmpty(score.Text)) UniFields.SetInteger(t.Fields, "score", score.GetResult(t.Fields.GetValue("score", 0)), 0); + //mxd. User vars. Should be called after fieldslist.Apply() + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.SRB2Type); + if(ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0) + fieldslist.ApplyUserVars(ti.Actor.UserVars, t.Fields); + color.ApplyTo(t.Fields, t.Fields.GetValue("fillcolor", 0)); //mxd. Comments @@ -505,7 +510,7 @@ namespace CodeImp.DoomBuilder.Windows if(c.CheckState == CheckState.Checked) defaultflags.Add(c.Tag.ToString()); } General.Settings.DefaultThingType = thingtype.GetResult(General.Settings.DefaultThingType); - General.Settings.DefaultThingAngle = angle.GetResult(General.Settings.DefaultThingAngle); + General.Settings.DefaultThingAngle = (int)Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90); General.Settings.SetDefaultThingFlags(defaultflags); // Store value linking @@ -581,8 +586,8 @@ namespace CodeImp.DoomBuilder.Windows { location = this.Location; activetab = tabs.SelectedIndex; - General.Settings.WriteSetting("customfieldsshowfixed", !hidefixedfields.Checked); - } + General.Settings.WriteSetting("customfieldsshowfixed", !hidefixedfields.Checked); + } // Help private void ThingEditForm_HelpRequested(object sender, HelpEventArgs hlpevent) @@ -679,9 +684,10 @@ namespace CodeImp.DoomBuilder.Windows action_ValueChanges(this, EventArgs.Empty); //mxd. Update things - if(preventchanges - || (thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) - || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)) + if(preventchanges || + (!string.IsNullOrEmpty(thingtype.TypeStringValue) && + thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType + || thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)) return; MakeUndo(); //mxd @@ -689,7 +695,7 @@ namespace CodeImp.DoomBuilder.Windows foreach(Thing t in things) { //Set type - t.FullType = thingtype.GetResult(t.FullType); + t.SRB2Type = thingtype.GetResult(t.SRB2Type); // Update settings t.UpdateConfiguration(); @@ -871,12 +877,12 @@ namespace CodeImp.DoomBuilder.Windows if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty); } - private void hidefixedfields_CheckedChanged(object sender, EventArgs e) - { - fieldslist.ShowFixedFields = !hidefixedfields.Checked; - } + private void hidefixedfields_CheckedChanged(object sender, EventArgs e) + { + fieldslist.ShowFixedFields = !hidefixedfields.Checked; + } - #endregion + #endregion - } + } } \ No newline at end of file diff --git a/Source/Core/ZDoom/ActorStructure.cs b/Source/Core/ZDoom/ActorStructure.cs index fc99f25b..544f814c 100644 --- a/Source/Core/ZDoom/ActorStructure.cs +++ b/Source/Core/ZDoom/ActorStructure.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Globalization; using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Types; #endregion @@ -52,7 +53,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Properties private Dictionary<string, List<string>> props; - private readonly List<string> userVars; //mxd + private readonly Dictionary<string, UniversalType> uservars; //mxd // States private Dictionary<string, StateStructure> states; @@ -68,7 +69,7 @@ namespace CodeImp.DoomBuilder.ZDoom public string ReplacesClass { get { return replaceclass; } } public ActorStructure BaseClass { get { return baseclass; } } internal int DoomEdNum { get { return doomednum; } set { doomednum = value; } } - public List<string> UserVars { get { return userVars; } } //mxd + public Dictionary<string, UniversalType> UserVars { get { return uservars; } } //mxd #endregion @@ -78,10 +79,10 @@ namespace CodeImp.DoomBuilder.ZDoom internal ActorStructure(DecorateParser parser) { // Initialize - flags = new Dictionary<string, bool>(StringComparer.Ordinal); - props = new Dictionary<string, List<string>>(StringComparer.Ordinal); - states = new Dictionary<string, StateStructure>(StringComparer.Ordinal); - userVars = new List<string>();//mxd + flags = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); + props = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); + states = new Dictionary<string, StateStructure>(StringComparer.OrdinalIgnoreCase); + uservars = new Dictionary<string, UniversalType>(StringComparer.OrdinalIgnoreCase);//mxd bool done = false; //mxd // Always define a game property, but default to 0 values @@ -163,7 +164,7 @@ namespace CodeImp.DoomBuilder.ZDoom else if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out doomednum)) // Check if numeric { // Not numeric! - parser.ReportError("Expected editor thing number or start of actor scope while parsing '" + classname + "'"); + parser.ReportError("Expected editor thing number or start of actor scope while parsing \"" + classname + "\""); return; } break; @@ -271,18 +272,87 @@ namespace CodeImp.DoomBuilder.ZDoom break; case "var": //mxd - while(parser.SkipWhitespace(true)) + // Type + parser.SkipWhitespace(true); + string typestr = parser.ReadToken().ToUpperInvariant(); + UniversalType type = UniversalType.EnumOption; // There is no Unknown type, so let's use something impossiburu... + switch(typestr) { - string t = parser.ReadToken(); - if(string.IsNullOrEmpty(t) || t == ";") break; - if(t.StartsWith("user_") && !userVars.Contains(t)) - userVars.Add(t); + case "INT": + type = UniversalType.Integer; + break; + + default: + parser.LogWarning("Unknown user variable type"); + break; + } + + // Name + parser.SkipWhitespace(true); + string name = parser.ReadToken(); + if(string.IsNullOrEmpty(name)) + { + parser.ReportError("Expected User Variable name"); + return; + } + if(!name.StartsWith("user_", StringComparison.OrdinalIgnoreCase)) + { + parser.ReportError("User Variable name must start with \"user_\" prefix"); + return; + } + if(uservars.ContainsKey(name)) + { + parser.ReportError("User Variable \"" + name + "\" is double-defined"); + return; + } + if(!skipsuper && baseclass != null && baseclass.uservars.ContainsKey(name)) + { + parser.ReportError("User variable \"" + name + "\" is already defined in one of the parent classes"); + return; + } + + // Rest + parser.SkipWhitespace(true); + string next = parser.ReadToken(); + if(next == "[") // that's User Array. Let's skip it... + { + int arrlen = -1; + if(!parser.ReadSignedInt(ref arrlen)) + { + parser.ReportError("Expected User Array length, but got \"" + next + "\""); + return; + } + if(arrlen < 1) + { + parser.ReportError("User Array length must be a positive value"); + return; + } + if(!parser.NextTokenIs("]") || !parser.NextTokenIs(";")) + { + return; + } + } + else if(next != ";") + { + parser.ReportError("Expected \";\", but got \"" + next + "\""); + return; + } + else + { + // Add to collection + uservars.Add(name, type); } break; case "}": - // Actor scope ends here, - // break out of this parse loop + //mxd. Get user vars from the BaseClass, if we have one + if(!skipsuper && baseclass != null && baseclass.uservars.Count > 0) + { + foreach(var group in baseclass.uservars) + uservars.Add(group.Key, group.Value); + } + + // Actor scope ends here, break out of this parse loop done = true; break; @@ -414,7 +484,7 @@ namespace CodeImp.DoomBuilder.ZDoom } } - parser.LogWarning("Unable to find '" + inheritclass + "' class to inherit from, while parsing '" + classname + ":" + doomednum + "'"); + parser.LogWarning("Unable to find \"" + inheritclass + "\" class to inherit from, while parsing \"" + classname + ":" + doomednum + "\""); } } @@ -466,12 +536,13 @@ namespace CodeImp.DoomBuilder.ZDoom /// <summary> /// This returns a specific value of a specific property as a string. Returns an empty string when the propery does not have the specified value. /// </summary> - public string GetPropertyValueString(string propname, int valueindex) + public string GetPropertyValueString(string propname, int valueindex) { return GetPropertyValueString(propname, valueindex, true); } //mxd. Added "stripquotes" parameter + public string GetPropertyValueString(string propname, int valueindex, bool stripquotes) { if(props.ContainsKey(propname) && (props[propname].Count > valueindex)) - return props[propname][valueindex]; + return (stripquotes ? ZDTextParser.StripQuotes(props[propname][valueindex]) : props[propname][valueindex]); if(!skipsuper && (baseclass != null)) - return baseclass.GetPropertyValueString(propname, valueindex); + return baseclass.GetPropertyValueString(propname, valueindex, stripquotes); return ""; } @@ -480,11 +551,11 @@ namespace CodeImp.DoomBuilder.ZDoom /// </summary> public int GetPropertyValueInt(string propname, int valueindex) { - string str = GetPropertyValueString(propname, valueindex); + string str = GetPropertyValueString(propname, valueindex, false); //mxd. It can be negative... - if(str == "-" && props.Count > valueindex + 1) - str += GetPropertyValueString(propname, valueindex + 1); + if(str == "-" && props.Count > valueindex + 1) + str += GetPropertyValueString(propname, valueindex + 1, false); int intvalue; if(int.TryParse(str, NumberStyles.Integer, CultureInfo.InvariantCulture, out intvalue)) @@ -497,11 +568,11 @@ namespace CodeImp.DoomBuilder.ZDoom /// </summary> public float GetPropertyValueFloat(string propname, int valueindex) { - string str = GetPropertyValueString(propname, valueindex); + string str = GetPropertyValueString(propname, valueindex, false); //mxd. It can be negative... if(str == "-" && props.Count > valueindex + 1) - str += GetPropertyValueString(propname, valueindex + 1); + str += GetPropertyValueString(propname, valueindex + 1, false); float fvalue; if(float.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out fvalue)) @@ -554,7 +625,7 @@ namespace CodeImp.DoomBuilder.ZDoom /// </summary> public Dictionary<string, StateStructure> GetAllStates() { - Dictionary<string, StateStructure> list = new Dictionary<string, StateStructure>(states); + Dictionary<string, StateStructure> list = new Dictionary<string, StateStructure>(states, StringComparer.OrdinalIgnoreCase); if(!skipsuper && (baseclass != null)) { @@ -590,75 +661,75 @@ namespace CodeImp.DoomBuilder.ZDoom // Sprite forced? if(HasPropertyWithValue("$sprite")) { - string sprite = GetPropertyValueString("$sprite", 0); //mxd - if ((sprite.Length > DataManager.INTERNAL_PREFIX.Length) && - sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX)) return sprite; //mxd - if (General.Map.Data.GetSpriteExists(sprite)) return sprite; //mxd. Added availability check - - //mxd. Bitch and moan - General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in " + classname + ":" + doomednum + ". The sprite \"" + sprite + "\" assigned by the \"$sprite\" property does not exist."); - } - - // Try the idle state - if (HasState("idle")) - { - StateStructure s = GetState("idle"); - string spritename = s.GetSprite(0); - if (!string.IsNullOrEmpty(spritename)) - result = spritename; - } - - // Try the see state - if (string.IsNullOrEmpty(result) && HasState("see")) - { - StateStructure s = GetState("see"); - string spritename = s.GetSprite(0); - if (!string.IsNullOrEmpty(spritename)) - result = spritename; - } - - // Try the inactive state - if (string.IsNullOrEmpty(result) && HasState("inactive")) - { - StateStructure s = GetState("inactive"); - string spritename = s.GetSprite(0); - if (!string.IsNullOrEmpty(spritename)) - result = spritename; - } - - // Try the spawn state - if (string.IsNullOrEmpty(result) && HasState("spawn")) - { - StateStructure s = GetState("spawn"); - string spritename = s.GetSprite(0); - if (!string.IsNullOrEmpty(spritename)) - result = spritename; - } - - // Still no sprite found? then just pick the first we can find - if (string.IsNullOrEmpty(result)) - { - Dictionary<string, StateStructure> list = GetAllStates(); - foreach (StateStructure s in list.Values) - { - string spritename = s.GetSprite(0); - if (!string.IsNullOrEmpty(spritename)) - { - result = spritename; - break; - } - } - } - - if (!string.IsNullOrEmpty(result)) - { - // The sprite name is not actually complete, we still have to append - // the direction characters to it. Find an existing sprite with direction. - foreach (string postfix in SPRITE_POSTFIXES) - { - if (General.Map.Data.GetSpriteExists(result + postfix)) - return result + postfix; - } + string sprite = GetPropertyValueString("$sprite", 0, true); //mxd + if((sprite.Length > DataManager.INTERNAL_PREFIX.Length) && + sprite.ToLowerInvariant().StartsWith(DataManager.INTERNAL_PREFIX)) return sprite; //mxd + if(General.Map.Data.GetSpriteExists(sprite)) return sprite; //mxd. Added availability check + + //mxd. Bitch and moan + General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in " + classname + ":" + doomednum + ". The sprite \"" + sprite + "\" assigned by the \"$sprite\" property does not exist."); + } + + // Try the idle state + if(HasState("idle")) + { + StateStructure s = GetState("idle"); + string spritename = s.GetSprite(0); + if(!string.IsNullOrEmpty(spritename)) + result = spritename; + } + + // Try the see state + if(string.IsNullOrEmpty(result) && HasState("see")) + { + StateStructure s = GetState("see"); + string spritename = s.GetSprite(0); + if(!string.IsNullOrEmpty(spritename)) + result = spritename; + } + + // Try the inactive state + if(string.IsNullOrEmpty(result) && HasState("inactive")) + { + StateStructure s = GetState("inactive"); + string spritename = s.GetSprite(0); + if(!string.IsNullOrEmpty(spritename)) + result = spritename; + } + + // Try the spawn state + if(string.IsNullOrEmpty(result) && HasState("spawn")) + { + StateStructure s = GetState("spawn"); + string spritename = s.GetSprite(0); + if(!string.IsNullOrEmpty(spritename)) + result = spritename; + } + + // Still no sprite found? then just pick the first we can find + if(string.IsNullOrEmpty(result)) + { + Dictionary<string, StateStructure> list = GetAllStates(); + foreach(StateStructure s in list.Values) + { + string spritename = s.GetSprite(0); + if(!string.IsNullOrEmpty(spritename)) + { + result = spritename; + break; + } + } + } + + if(!string.IsNullOrEmpty(result)) + { + // The sprite name is not actually complete, we still have to append + // the direction characters to it. Find an existing sprite with direction. + foreach(string postfix in SPRITE_POSTFIXES) + { + if(General.Map.Data.GetSpriteExists(result + postfix)) + return result + postfix; + } } // No sprite found diff --git a/Source/Core/ZDoom/AnimdefsParser.cs b/Source/Core/ZDoom/AnimdefsParser.cs index d48cc9bd..65d02085 100644 --- a/Source/Core/ZDoom/AnimdefsParser.cs +++ b/Source/Core/ZDoom/AnimdefsParser.cs @@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Check results if(cameratextures.ContainsKey(texturename.ToUpperInvariant())) { - ReportError("Camera texture '" + texturename + "' is defined more than once"); + ReportError("Camera texture \"" + texturename + "\" is defined more than once"); return false; } diff --git a/Source/Core/ZDoom/DecorateParser.cs b/Source/Core/ZDoom/DecorateParser.cs index 1475b359..2529e955 100644 --- a/Source/Core/ZDoom/DecorateParser.cs +++ b/Source/Core/ZDoom/DecorateParser.cs @@ -86,12 +86,12 @@ namespace CodeImp.DoomBuilder.ZDoom { // Syntax whitespace = "\n \t\r\u00A0"; //mxd. non-breaking space is also space :) - specialtokens = ":{}+-\n;,"; - - // Initialize - actors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase); - archivedactors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase); - parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd + specialtokens = ":{}[]+-\n;,"; + + // Initialize + actors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase); + archivedactors = new Dictionary<string, ActorStructure>(StringComparer.OrdinalIgnoreCase); + parsedlumps = new HashSet<string>(StringComparer.OrdinalIgnoreCase); //mxd } // Disposer diff --git a/Source/Core/ZDoom/PatchStructure.cs b/Source/Core/ZDoom/PatchStructure.cs index 17fb6093..1eea528e 100644 --- a/Source/Core/ZDoom/PatchStructure.cs +++ b/Source/Core/ZDoom/PatchStructure.cs @@ -30,23 +30,27 @@ namespace CodeImp.DoomBuilder.ZDoom { #region ================== Constants + // Some odd things in ZDoom + private const string IGNORE_SPRITE = "TNT1A0"; + #endregion #region ================== Variables // Declaration - private string name; - private int offsetx; - private int offsety; - private bool flipx; - private bool flipy; - private float alpha; - private int rotation; //mxd - private TexturePathRenderStyle renderStyle; //mxd - private PixelColor blendColor; //mxd - private TexturePathBlendStyle blendStyle; //mxd - private float tintAmmount; //mxd - private static string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd + private readonly string name; + private readonly int offsetx; + private readonly int offsety; + private readonly bool flipx; + private readonly bool flipy; + private readonly float alpha; + private readonly int rotation; //mxd + private readonly TexturePathRenderStyle renderStyle; //mxd + private readonly PixelColor blendColor; //mxd + private readonly TexturePathBlendStyle blendStyle; //mxd + private readonly float tintAmmount; //mxd + private static readonly string[] renderStyles = { "copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay" }; //mxd + private readonly bool skip; //mxd #endregion @@ -63,6 +67,7 @@ namespace CodeImp.DoomBuilder.ZDoom public TexturePathBlendStyle BlendStyle { get { return blendStyle; } } public float TintAmmount { get { return tintAmmount; } } public PixelColor BlendColor { get { return blendColor; } }//mxd + public bool Skip { get { return skip; } } //mxd #endregion @@ -88,6 +93,9 @@ namespace CodeImp.DoomBuilder.ZDoom return; } + //mxd. Skip what must be skipped + skip = (name.ToUpperInvariant() == IGNORE_SPRITE); + //mxd name = name.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); @@ -147,7 +155,7 @@ namespace CodeImp.DoomBuilder.ZDoom if(rotation != 0 && rotation != 90 && rotation != 180 && rotation != 270) { - parser.LogWarning("Unsupported rotation (" + rotation + ") in patch '" + name + "'"); + parser.LogWarning("Unsupported rotation (" + rotation + ") in patch \"" + name + "\""); rotation = 0; } break; @@ -206,7 +214,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Try parsing as value if(!float.TryParse(strvalue, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { - parser.ReportError("Expected numeric value for property '" + propertyname + "'"); + parser.ReportError("Expected numeric value for property \"" + propertyname + "\""); return false; } // Success @@ -214,7 +222,7 @@ namespace CodeImp.DoomBuilder.ZDoom } // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); value = 0.0f; return false; } @@ -230,7 +238,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Try parsing as value if(!int.TryParse(strvalue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) { - parser.ReportError("Expected integral value for property '" + propertyname + "'"); + parser.ReportError("Expected integral value for property \"" + propertyname + "\""); return false; } @@ -239,7 +247,7 @@ namespace CodeImp.DoomBuilder.ZDoom } // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); value = 0; return false; } @@ -253,7 +261,7 @@ namespace CodeImp.DoomBuilder.ZDoom if(string.IsNullOrEmpty(value)) { // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); return false; } @@ -270,20 +278,20 @@ namespace CodeImp.DoomBuilder.ZDoom if(string.IsNullOrEmpty(strvalue)) { // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); return false; } if(strvalue[0] != '#') { - parser.ReportError("Expected color value for property '" + propertyname + "'"); + parser.ReportError("Expected color value for property \"" + propertyname + "\""); return false; } // Try parsing as value if(!int.TryParse(strvalue.Remove(0, 1), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out value)) { - parser.ReportError("Expected color value for property '" + propertyname + "'"); + parser.ReportError("Expected color value for property \"" + propertyname + "\""); return false; } diff --git a/Source/Core/ZDoom/TextureStructure.cs b/Source/Core/ZDoom/TextureStructure.cs index 0650c93d..47eda03b 100644 --- a/Source/Core/ZDoom/TextureStructure.cs +++ b/Source/Core/ZDoom/TextureStructure.cs @@ -28,9 +28,6 @@ namespace CodeImp.DoomBuilder.ZDoom { #region ================== Constants - // Some odd thing in ZDoom - private const string IGNORE_SPRITE = "TNT1A0"; - #endregion #region ================== Variables @@ -169,9 +166,6 @@ namespace CodeImp.DoomBuilder.ZDoom PatchStructure pt = new PatchStructure(parser); if(parser.HasError) break; - //mxd. Let's ignore TNT1A0 - if(pt.Name == IGNORE_SPRITE) break; - // Add the patch patches.Add(pt); break; @@ -200,7 +194,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Try parsing as value if(!float.TryParse(strvalue, NumberStyles.Float, CultureInfo.InvariantCulture, out value)) { - parser.ReportError("Expected numeric value for property '" + propertyname + "'"); + parser.ReportError("Expected numeric value for property \"" + propertyname + "\""); return false; } @@ -209,7 +203,7 @@ namespace CodeImp.DoomBuilder.ZDoom } // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); value = 0.0f; return false; } @@ -225,7 +219,7 @@ namespace CodeImp.DoomBuilder.ZDoom // Try parsing as value if(!int.TryParse(strvalue, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) { - parser.ReportError("Expected integral value for property '" + propertyname + "'"); + parser.ReportError("Expected integral value for property \"" + propertyname + "\""); return false; } @@ -234,7 +228,7 @@ namespace CodeImp.DoomBuilder.ZDoom } // Can't find the property value! - parser.ReportError("Expected a value for property '" + propertyname + "'"); + parser.ReportError("Expected a value for property \"" + propertyname + "\""); value = 0; return false; } diff --git a/Source/Core/ZDoom/ZDTextParser.cs b/Source/Core/ZDoom/ZDTextParser.cs index d9df88fa..e76247d3 100644 --- a/Source/Core/ZDoom/ZDTextParser.cs +++ b/Source/Core/ZDoom/ZDTextParser.cs @@ -201,7 +201,7 @@ namespace CodeImp.DoomBuilder.ZDoom if(datastream.Position == datastream.Length) //mxd { // ZDoom doesn't give even a warning message about this, so we shouldn't report error or fail parsing. - General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in '" + sourcename + "', line " + GetCurrentLineNumber() + ". Block comment is not closed."); + General.ErrorLogger.Add(ErrorType.Warning, "DECORATE warning in \"" + sourcename + "\", line " + GetCurrentLineNumber() + ". Block comment is not closed."); return false; } @@ -441,7 +441,7 @@ namespace CodeImp.DoomBuilder.ZDoom if(string.Compare(token, expectedtoken, true) != 0) { - if(reporterror) ReportError("Expected '" + expectedtoken + "', but got '" + token + "'"); + if(reporterror) ReportError("Expected \"" + expectedtoken + "\", but got \"" + token + "\""); // Rewind so this structure can be read again DataStream.Seek(-token.Length - 1, SeekOrigin.Current); @@ -529,18 +529,18 @@ namespace CodeImp.DoomBuilder.ZDoom //mxd. This adds a warning to the ErrorLogger protected internal void LogWarning(string message) { - // Add a warning - int errline = (datastream != null ? GetCurrentLineNumber() : CompilerError.NO_LINE_NUMBER); - General.ErrorLogger.Add(ErrorType.Warning, GetLanguageType() + " warning in '" + sourcename - + (errline != CompilerError.NO_LINE_NUMBER ? "', line " + (errline + 1) : "'") + ". " + // Add a warning + int errline = (datastream != null ? GetCurrentLineNumber() : CompilerError.NO_LINE_NUMBER); + General.ErrorLogger.Add(ErrorType.Warning, GetLanguageType() + " warning in \"" + sourcename + + (errline != CompilerError.NO_LINE_NUMBER ? "\", line " + (errline + 1) : "\"") + ". " + message + "."); } //mxd. This adds an error to the ErrorLogger public void LogError() { - General.ErrorLogger.Add(ErrorType.Error, GetLanguageType() + " error in '" + errorsource - + (errorline != CompilerError.NO_LINE_NUMBER ? "', line " + (errorline + 1) : "'") + ". " + General.ErrorLogger.Add(ErrorType.Error, GetLanguageType() + " error in \"" + errorsource + + (errorline != CompilerError.NO_LINE_NUMBER ? "\", line " + (errorline + 1) : "\"") + ". " + errordesc + "."); } @@ -611,7 +611,7 @@ namespace CodeImp.DoomBuilder.ZDoom // includefilename references something above the root? if(index-- < 0) { - ReportError("Unable to construct rooted path from '" + includefilename + "'"); + ReportError("Unable to construct rooted path from \"" + includefilename + "\""); return string.Empty; } diff --git a/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs b/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs index 9abf7d60..902a0953 100644 --- a/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs +++ b/Source/Plugins/BuilderEffects/Interface/JitterSectorsForm.Designer.cs @@ -238,7 +238,7 @@ // this.floorHeightAmmount.AllowNegative = false; this.floorHeightAmmount.ExtendedLimits = false; - this.floorHeightAmmount.Label = "Floor height:"; + this.floorHeightAmmount.Label = "Height:"; this.floorHeightAmmount.Location = new System.Drawing.Point(6, 19); this.floorHeightAmmount.Maximum = 100; this.floorHeightAmmount.Minimum = 0; diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index ac6d2a70..accc5ae3 100644 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -361,6 +361,12 @@ <Compile Include="Interface\DrawGridOptionsPanel.Designer.cs"> <DependentUpon>DrawGridOptionsPanel.cs</DependentUpon> </Compile> + <Compile Include="Interface\DrawLineOptionsPanel.cs"> + <SubType>UserControl</SubType> + </Compile> + <Compile Include="Interface\DrawLineOptionsPanel.Designer.cs"> + <DependentUpon>DrawLineOptionsPanel.cs</DependentUpon> + </Compile> <Compile Include="Interface\DrawRectangleOptionsPanel.cs"> <SubType>UserControl</SubType> </Compile> @@ -563,6 +569,9 @@ <EmbeddedResource Include="Resources\DrawGeometryMode.png" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="Interface\DrawLineOptionsPanel.resx"> + <DependentUpon>DrawLineOptionsPanel.cs</DependentUpon> + </EmbeddedResource> <EmbeddedResource Include="Interface\FilterSelectedThingsForm.resx"> <DependentUpon>FilterSelectedThingsForm.cs</DependentUpon> </EmbeddedResource> @@ -635,6 +644,9 @@ <ItemGroup> <EmbeddedResource Include="Resources\InsertThingsRadiallyMode.png" /> </ItemGroup> + <ItemGroup> + <None Include="Resources\Repeat.png" /> + </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs index e367f659..2808e59a 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs @@ -737,7 +737,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes return InterpolationTools.EaseInOutSine(val1, val2, delta); default: - throw new Exception("DrawBezierPathMode.IntepolateValue: '" + mode + "' mode is not supported!"); + throw new Exception("DrawBezierPathMode.IntepolateValue: \"" + mode + "\" mode is not supported!"); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs index 06872fea..3dfd7e81 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawCurveMode.cs @@ -31,12 +31,12 @@ namespace CodeImp.DoomBuilder.BuilderModes private readonly HintLabel hintlabel; private Curve curve; - private static int segmentLength = 32; - private const int MIN_SEGMENT_LENGTH = 1; + private int segmentlength; + private const int MIN_SEGMENT_LENGTH = 16; private const int MAX_SEGMENT_LENGTH = 4096; //just some arbitrary number - //interface - private readonly DrawCurveOptionsPanel panel; + // Interface + private DrawCurveOptionsPanel panel; #endregion @@ -46,10 +46,6 @@ namespace CodeImp.DoomBuilder.BuilderModes { hintlabel = new HintLabel(General.Colors.InfoLine); labeluseoffset = false; - - //Options docker - panel = new DrawCurveOptionsPanel(MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH); - panel.OnValueChanged += OptionsPanelOnValueChanged; } public override void Dispose() @@ -102,7 +98,7 @@ namespace CodeImp.DoomBuilder.BuilderModes List<Vector2D> verts = new List<Vector2D>(); for(int i = 0; i < points.Count; i++) verts.Add(points[i].pos); if(curp.pos != verts[verts.Count-1]) verts.Add(curp.pos); - curve = CurveTools.CurveThroughPoints(verts, 0.5f, 0.75f, segmentLength); + curve = CurveTools.CurveThroughPoints(verts, 0.5f, 0.75f, segmentlength); // Render lines for(int i = 1; i < curve.Shape.Count; i++) @@ -151,7 +147,7 @@ namespace CodeImp.DoomBuilder.BuilderModes Vector2D start = new Vector2D(mousemappos.x + (32 / renderer.Scale), mousemappos.y - (16 / renderer.Scale)); Vector2D end = new Vector2D(mousemappos.x + (96 / renderer.Scale), mousemappos.y); hintlabel.Move(start, end); - hintlabel.Text = "SEG LEN: " + segmentLength; + hintlabel.Text = "SEG LEN: " + segmentlength; renderer.RenderText(hintlabel.TextLabel); // Done @@ -171,7 +167,7 @@ namespace CodeImp.DoomBuilder.BuilderModes base.OnEngage(); //setup settings panel - panel.SegmentLength = segmentLength; + panel.SegmentLength = segmentlength; panel.Register(); } @@ -245,55 +241,62 @@ namespace CodeImp.DoomBuilder.BuilderModes } // Make the drawing - if(!Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd + if(Tools.DrawLines(verts, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd { - // Drawing failed - // NOTE: I have to call this twice, because the first time only cancels this volatile mode - General.Map.UndoRedo.WithdrawUndo(); - General.Map.UndoRedo.WithdrawUndo(); - return; - } - - // Snap to map format accuracy - General.Map.Map.SnapAllToAccuracy(); + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); - // Clear selection - General.Map.Map.ClearAllSelected(); + // Clear selection + General.Map.Map.ClearAllSelected(); - // Update cached values - General.Map.Map.Update(); + // Update cached values + General.Map.Map.Update(); - // Edit new sectors? - List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); - if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) - General.Interface.ShowEditSectors(newsectors); + // Edit new sectors? + List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); + if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) + General.Interface.ShowEditSectors(newsectors); - // Update the used textures - General.Map.Data.UpdateUsedTextures(); + // Update the used textures + General.Map.Data.UpdateUsedTextures(); - //mxd - General.Map.Renderer2D.UpdateExtraFloorFlag(); + //mxd + General.Map.Renderer2D.UpdateExtraFloorFlag(); - // Map is changed - General.Map.IsChanged = true; + // Map is changed + General.Map.IsChanged = true; + } + else + { + // Drawing failed + // NOTE: I have to call this twice, because the first time only cancels this volatile mode + General.Map.UndoRedo.WithdrawUndo(); + General.Map.UndoRedo.WithdrawUndo(); + } } // Done Cursor.Current = Cursors.Default; - // Return to original mode - General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); - } + if(continuousdrawing) + { + // Reset settings + points.Clear(); + labels.Clear(); - public override void OnDisengage() - { - base.OnDisengage(); - panel.Unregister(); + // Redraw display + General.Interface.RedrawDisplay(); + } + else + { + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } } private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) { - segmentLength = panel.SegmentLength; + segmentlength = panel.SegmentLength; Update(); } @@ -304,18 +307,52 @@ namespace CodeImp.DoomBuilder.BuilderModes #endregion + #region ================== mxd. Settings panel + + protected override void SetupInterface() + { + // Load stored settings + segmentlength = General.Clamp(General.Settings.ReadPluginSetting("drawcurvemode.segmentlength", 32), MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH); + + // Add options docker + panel = new DrawCurveOptionsPanel(MIN_SEGMENT_LENGTH, MAX_SEGMENT_LENGTH); + panel.SegmentLength = segmentlength; + panel.OnValueChanged += OptionsPanelOnValueChanged; + panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; + + // Needs to be set after adding the OnContinuousDrawingChanged event... + panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawcurvemode.continuousdrawing", false); + } + + protected override void AddInterface() + { + panel.Register(); + } + + protected override void RemoveInterface() + { + // Store settings + General.Settings.WritePluginSetting("drawcurvemode.segmentlength", segmentlength); + General.Settings.WritePluginSetting("drawcurvemode.continuousdrawing", panel.ContinuousDrawing); + + // Remove the buttons + panel.Unregister(); + } + + #endregion + #region ================== Actions [BeginAction("increasesubdivlevel")] protected virtual void IncreaseSubdivLevel() { - if(segmentLength < MAX_SEGMENT_LENGTH) + if(segmentlength < MAX_SEGMENT_LENGTH) { - int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentLength / 32 * 16); - segmentLength += increment; + int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16); + segmentlength += increment; - if(segmentLength > MAX_SEGMENT_LENGTH) segmentLength = MAX_SEGMENT_LENGTH; - panel.SegmentLength = segmentLength; + if(segmentlength > MAX_SEGMENT_LENGTH) segmentlength = MAX_SEGMENT_LENGTH; + panel.SegmentLength = segmentlength; Update(); } } @@ -323,13 +360,13 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("decreasesubdivlevel")] protected virtual void DecreaseSubdivLevel() { - if(segmentLength > MIN_SEGMENT_LENGTH) + if(segmentlength > MIN_SEGMENT_LENGTH) { - int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentLength / 32 * 16); - segmentLength -= increment; + int increment = Math.Max(MIN_SEGMENT_LENGTH, segmentlength / 32 * 16); + segmentlength -= increment; - if(segmentLength < MIN_SEGMENT_LENGTH) segmentLength = MIN_SEGMENT_LENGTH; - panel.SegmentLength = segmentLength; + if(segmentlength < MIN_SEGMENT_LENGTH) segmentlength = MIN_SEGMENT_LENGTH; + panel.SegmentLength = segmentlength; Update(); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs index acbba493..c14e5f1a 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawEllipseMode.cs @@ -21,47 +21,64 @@ namespace CodeImp.DoomBuilder.BuilderModes { #region ================== Variables - //interface + // Drawing + private float angle; // in radians + + // Interface private DrawEllipseOptionsPanel panel; #endregion #region ================== Constructor - public DrawEllipseMode() - { - undoName = "Ellipse draw"; - shapeName = "ellipse"; - usefourcardinaldirections = true; - } - #endregion #region ================== Settings panel override protected void SetupInterface() { - maxSubdivisions = 512; - minSubdivisions = 6; + maxsubdivisions = 512; + minsubdivisions = 3; + minpointscount = 3; + alwaysrendershapehints = true; + + // Load stored settings + subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawellipsemode.subdivisions", 8), minsubdivisions, maxsubdivisions); + bevelwidth = General.Settings.ReadPluginSetting("drawellipsemode.bevelwidth", 0); + int angledeg = General.Settings.ReadPluginSetting("drawellipsemode.angle", 0); + angle = Angle2D.DegToRad(angledeg); + currentbevelwidth = bevelwidth; //Add options docker panel = new DrawEllipseOptionsPanel(); - panel.MaxSubdivisions = maxSubdivisions; - panel.MinSubdivisions = minSubdivisions; + panel.MaxSubdivisions = maxsubdivisions; + panel.MinSubdivisions = minsubdivisions; panel.MinSpikiness = (int)General.Map.FormatInterface.MinCoordinate; panel.MaxSpikiness = (int)General.Map.FormatInterface.MaxCoordinate; + panel.Spikiness = bevelwidth; + panel.Angle = angledeg; + panel.Subdivisions = subdivisions; panel.OnValueChanged += OptionsPanelOnValueChanged; + panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; + + // Needs to be set after adding the OnContinuousDrawingChanged event... + panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawellipsemode.continuousdrawing", false); } override protected void AddInterface() { panel.Register(); - bevelWidth = panel.Spikiness; - subdivisions = panel.Subdivisions; } override protected void RemoveInterface() { + // Store settings + General.Settings.WritePluginSetting("drawellipsemode.subdivisions", subdivisions); + General.Settings.WritePluginSetting("drawellipsemode.bevelwidth", bevelwidth); + General.Settings.WritePluginSetting("drawellipsemode.angle", panel.Angle); + General.Settings.WritePluginSetting("drawellipsemode.continuousdrawing", panel.ContinuousDrawing); + + // Remove the buttons panel.Unregister(); } @@ -71,21 +88,19 @@ namespace CodeImp.DoomBuilder.BuilderModes override protected Vector2D[] GetShape(Vector2D pStart, Vector2D pEnd) { - //no shape + // No shape if(pEnd.x == pStart.x && pEnd.y == pStart.y) return new Vector2D[0]; - //line + // Line if(pEnd.x == pStart.x || pEnd.y == pStart.y) return new[] { pStart, pEnd }; - //got shape - if(bevelWidth < 0) - { - currentBevelWidth = -Math.Min(Math.Abs(bevelWidth), Math.Min(width, height) / 2) + 1; - } + // Got shape + if(subdivisions < 6) + currentbevelwidth = 0; // Works strange otherwise + else if(bevelwidth < 0) + currentbevelwidth = -Math.Min(Math.Abs(bevelwidth), Math.Min(width, height) / 2) + 1; else - { - currentBevelWidth = bevelWidth; - } + currentbevelwidth = bevelwidth; Vector2D[] shape = new Vector2D[subdivisions + 1]; @@ -94,7 +109,7 @@ namespace CodeImp.DoomBuilder.BuilderModes int hh = height / 2; Vector2D center = new Vector2D(pStart.x + hw, pStart.y + hh); - float curAngle = 0; + float curAngle = angle; float angleStep = -Angle2D.PI / subdivisions * 2; for(int i = 0; i < subdivisions; i++) @@ -102,8 +117,8 @@ namespace CodeImp.DoomBuilder.BuilderModes int px, py; if(doBevel) { - px = (int)(center.x - (float)Math.Sin(curAngle) * (hw + currentBevelWidth)); - py = (int)(center.y - (float)Math.Cos(curAngle) * (hh + currentBevelWidth)); + px = (int)(center.x - (float)Math.Sin(curAngle) * (hw + currentbevelwidth)); + py = (int)(center.y - (float)Math.Cos(curAngle) * (hh + currentbevelwidth)); } else { @@ -114,24 +129,54 @@ namespace CodeImp.DoomBuilder.BuilderModes shape[i] = new Vector2D(px, py); curAngle += angleStep; } - //add final point + + // Add final point shape[subdivisions] = shape[0]; return shape; } protected override string GetHintText() { - return "BVL: " + bevelWidth + "; VERTS: " + subdivisions; + return "BVL: " + bevelwidth + "; VERTS: " + subdivisions; } #endregion #region ================== Events + public override void OnAccept() + { + switch(points.Count - 1) // Last point matches the first one + { + case 3: undoname = "Triangle draw"; shapename = "triangle"; break; + case 4: undoname = "Rhombus draw"; shapename = "rhombus"; break; + case 5: undoname = "Pentagon draw"; shapename = "pentagon"; break; + case 6: undoname = "Hexagon draw"; shapename = "hexagon"; break; + case 7: undoname = "Heptagon draw"; shapename = "heptagon"; break; + case 8: undoname = "Octagon draw"; shapename = "octagon"; break; + case 9: undoname = "Enneagon draw"; shapename = "enneagon"; break; + case 10: undoname = "Decagon draw"; shapename = "decagon"; break; + case 11: undoname = "Hendecagon draw"; shapename = "hendecagon"; break; + case 12: undoname = "Dodecagon draw"; shapename = "dodecagon"; break; + case 13: undoname = "Tridecagon draw"; shapename = "tridecagon"; break; + case 14: undoname = "Tetradecagon draw"; shapename = "tetradecagon"; break; + case 15: undoname = "Pentadecagon draw"; shapename = "pentadecagon"; break; + case 16: undoname = "Hexadecagon draw"; shapename = "hexadecagon"; break; + case 17: undoname = "Heptadecagon draw"; shapename = "heptadecagon"; break; + case 18: undoname = "Octadecagon draw"; shapename = "octadecagon"; break; + case 19: undoname = "Enneadecagon draw"; shapename = "enneadecagon"; break; + case 20: undoname = "Icosagon draw"; shapename = "icosagon"; break; + default: undoname = "Ellipse draw"; shapename = "ellipse"; break; + } + + base.OnAccept(); + } + private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) { - bevelWidth = panel.Spikiness; - subdivisions = Math.Min(maxSubdivisions, panel.Subdivisions); + bevelwidth = panel.Spikiness; + subdivisions = Math.Min(maxsubdivisions, panel.Subdivisions); + angle = Angle2D.DegToRad(panel.Angle); Update(); } @@ -146,9 +191,9 @@ namespace CodeImp.DoomBuilder.BuilderModes override protected void IncreaseSubdivLevel() { - if(maxSubdivisions - subdivisions > 1) + if(maxsubdivisions - subdivisions > 1) { - subdivisions += 2; + subdivisions += (subdivisions % 2 != 0 ? 1 : 2); panel.Subdivisions = subdivisions; Update(); } @@ -156,9 +201,9 @@ namespace CodeImp.DoomBuilder.BuilderModes override protected void DecreaseSubdivLevel() { - if(subdivisions - minSubdivisions > 1) + if(subdivisions - minsubdivisions > 1) { - subdivisions -= 2; + subdivisions -= (subdivisions % 2 != 0 ? 1 : 2); panel.Subdivisions = subdivisions; Update(); } @@ -166,20 +211,20 @@ namespace CodeImp.DoomBuilder.BuilderModes protected override void IncreaseBevel() { - if(points.Count < 2 || currentBevelWidth == bevelWidth || bevelWidth < 0) + if(points.Count < 2 || currentbevelwidth == bevelwidth || bevelwidth < 0) { - bevelWidth = Math.Min(bevelWidth + General.Map.Grid.GridSize, panel.MaxSpikiness); - panel.Spikiness = bevelWidth; + bevelwidth = Math.Min(bevelwidth + General.Map.Grid.GridSize, panel.MaxSpikiness); + panel.Spikiness = bevelwidth; Update(); } } protected override void DecreaseBevel() { - if(bevelWidth > 0 || currentBevelWidth <= bevelWidth + 1) + if(bevelwidth > 0 || currentbevelwidth <= bevelwidth + 1) { - bevelWidth = Math.Max(bevelWidth - General.Map.Grid.GridSize, panel.MinSpikiness); - panel.Spikiness = bevelWidth; + bevelwidth = Math.Max(bevelwidth - General.Map.Grid.GridSize, panel.MinSpikiness); + panel.Spikiness = bevelwidth; Update(); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs index ca2c2baa..31fce87d 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs @@ -18,14 +18,14 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Windows.Forms; -using CodeImp.DoomBuilder.Windows; +using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Editing; +using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Rendering; -using CodeImp.DoomBuilder.Geometry; -using System.Drawing; -using CodeImp.DoomBuilder.Editing; -using CodeImp.DoomBuilder.Actions; +using CodeImp.DoomBuilder.Windows; #endregion @@ -65,10 +65,14 @@ namespace CodeImp.DoomBuilder.BuilderModes protected bool snaptonearest; // CTRL to enable protected bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable protected static bool usefourcardinaldirections; + protected bool continuousdrawing; //mxd. Restart after finishing drawing? //mxd. Labels display style protected bool labelshowangle = true; protected bool labeluseoffset = true; + + //mxd. Interface + private DrawLineOptionsPanel panel; #endregion @@ -88,6 +92,9 @@ namespace CodeImp.DoomBuilder.BuilderModes // No selection in this mode General.Map.Map.ClearAllSelected(); General.Map.Map.ClearAllMarks(false); + + //mxd + SetupInterface(); // We have no destructor GC.SuppressFinalize(this); @@ -446,6 +453,31 @@ namespace CodeImp.DoomBuilder.BuilderModes #endregion + #region ================== mxd. Settings panel + + protected virtual void SetupInterface() + { + //Add options docker + panel = new DrawLineOptionsPanel(); + panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; + + // Needs to be set after adding the OnContinuousDrawingChanged event... + panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawlinesmode.continuousdrawing", false); + } + + protected virtual void AddInterface() + { + panel.Register(); + } + + protected virtual void RemoveInterface() + { + General.Settings.WritePluginSetting("drawlinesmode.continuousdrawing", panel.ContinuousDrawing); + panel.Unregister(); + } + + #endregion + #region ================== Events public override void OnHelp() @@ -458,6 +490,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { base.OnEngage(); EnableAutoPanning(); + AddInterface(); //mxd renderer.SetPresentation(Presentation.Standard); // Set cursor @@ -467,6 +500,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Disengaging public override void OnDisengage() { + RemoveInterface(); //mxd base.OnDisengage(); DisableAutoPanning(); } @@ -474,6 +508,9 @@ namespace CodeImp.DoomBuilder.BuilderModes // Cancelled public override void OnCancel() { + //mxd. Cannot leave this way when continuous drawing is enabled + if(continuousdrawing) return; + // Cancel base class base.OnCancel(); @@ -505,44 +542,57 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " drawing."); // Make the drawing - if(!Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd + if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) //mxd + { + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); + + // Clear selection + General.Map.Map.ClearAllSelected(); + + // Update cached values + General.Map.Map.Update(); + + // Edit new sectors? + List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); + if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) + General.Interface.ShowEditSectors(newsectors); + + // Update the used textures + General.Map.Data.UpdateUsedTextures(); + + //mxd + General.Map.Renderer2D.UpdateExtraFloorFlag(); + + // Map is changed + General.Map.IsChanged = true; + } + else { // Drawing failed // NOTE: I have to call this twice, because the first time only cancels this volatile mode General.Map.UndoRedo.WithdrawUndo(); General.Map.UndoRedo.WithdrawUndo(); - return; } - - // Snap to map format accuracy - General.Map.Map.SnapAllToAccuracy(); - - // Clear selection - General.Map.Map.ClearAllSelected(); - - // Update cached values - General.Map.Map.Update(); - - // Edit new sectors? - List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); - if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) - General.Interface.ShowEditSectors(newsectors); - - // Update the used textures - General.Map.Data.UpdateUsedTextures(); - - //mxd - General.Map.Renderer2D.UpdateExtraFloorFlag(); - - // Map is changed - General.Map.IsChanged = true; } // Done Cursor.Current = Cursors.Default; - - // Return to original mode - General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + + if(continuousdrawing) + { + //mxd. Reset settings + points.Clear(); + labels.Clear(); + + //mxd. Redraw display + General.Interface.RedrawDisplay(); + } + else + { + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } } // This redraws the display @@ -595,6 +645,12 @@ namespace CodeImp.DoomBuilder.BuilderModes (snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) || (snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update(); } + + //mxd + protected void OnContinuousDrawingChanged(object value, EventArgs e) + { + continuousdrawing = (bool)value; + } #endregion diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs index 1261e048..3ce24993 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs @@ -27,15 +27,29 @@ namespace CodeImp.DoomBuilder.BuilderModes public class DrawGridMode : DrawGeometryMode { + #region ================== Enums + + public enum GridLockMode + { + NONE, + HORIZONTAL, + VERTICAL, + BOTH, + } + + #endregion + #region ================== Variables - private static int horizontalSlices = 3; - private static int verticalSlices = 3; - private static bool triangulate; - private static bool gridlock; - private static InterpolationTools.Mode horizontalinterpolation = InterpolationTools.Mode.LINEAR; - private static InterpolationTools.Mode verticalinterpolation = InterpolationTools.Mode.LINEAR; + // Settings + private int horizontalslices; + private int verticalslices; + private bool triangulate; + private GridLockMode gridlockmode; + private InterpolationTools.Mode horizontalinterpolation; + private InterpolationTools.Mode verticalinterpolation; + // Drawing private readonly List<DrawnVertex[]> gridpoints; private HintLabel hintlabel; @@ -46,7 +60,7 @@ namespace CodeImp.DoomBuilder.BuilderModes private Vector2D start; private Vector2D end; - //interface + // Interface private DrawGridOptionsPanel panel; private Docker docker; @@ -65,40 +79,6 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Events - public override void OnEngage() - { - base.OnEngage(); - - // Create and setup settings panel - panel = new DrawGridOptionsPanel(); - panel.MaxHorizontalSlices = (int)General.Map.FormatInterface.MaxCoordinate; - panel.MaxVerticalSlices = (int) General.Map.FormatInterface.MaxCoordinate; - panel.Triangulate = triangulate; - panel.LockToGrid = gridlock; - panel.HorizontalSlices = horizontalSlices - 1; - panel.VerticalSlices = verticalSlices - 1; - panel.HorizontalInterpolationMode = horizontalinterpolation; - panel.VerticalInterpolationMode = verticalinterpolation; - - panel.OnValueChanged += OptionsPanelOnValueChanged; - panel.OnGridLockChanged += OptionsPanelOnOnGridLockChanged; - - // Add docker - docker = new Docker("drawgrid", "Draw Grid", panel); - General.Interface.AddDocker(docker); - General.Interface.SelectDocker(docker); - } - - public override void OnDisengage() - { - base.OnDisengage(); - - // Remove docker - General.Interface.RemoveDocker(docker); - panel.Dispose(); - panel = null; - } - override public void OnAccept() { Cursor.Current = Cursors.AppStarting; @@ -120,62 +100,75 @@ namespace CodeImp.DoomBuilder.BuilderModes List<Sector> newsectors = new List<Sector>(); foreach(DrawnVertex[] shape in gridpoints) { - if(!Tools.DrawLines(shape, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) + if(Tools.DrawLines(shape, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) { - // Drawing failed - // NOTE: I have to call this twice, because the first time only cancels this volatile mode - General.Map.UndoRedo.WithdrawUndo(); - General.Map.UndoRedo.WithdrawUndo(); - return; - } + // Update cached values after each step... + General.Map.Map.Update(); - // Update cached values after each step... - General.Map.Map.Update(); - - newsectors.AddRange(General.Map.Map.GetMarkedSectors(true)); - } + newsectors.AddRange(General.Map.Map.GetMarkedSectors(true)); - // Snap to map format accuracy - General.Map.Map.SnapAllToAccuracy(); + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); - // Clear selection - General.Map.Map.ClearAllSelected(); + // Clear selection + General.Map.Map.ClearAllSelected(); - // Edit new sectors? - if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) - General.Interface.ShowEditSectors(newsectors); + // Edit new sectors? + if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) + General.Interface.ShowEditSectors(newsectors); - // Update the used textures - General.Map.Data.UpdateUsedTextures(); + // Update the used textures + General.Map.Data.UpdateUsedTextures(); - //mxd - General.Map.Renderer2D.UpdateExtraFloorFlag(); + //mxd + General.Map.Renderer2D.UpdateExtraFloorFlag(); - // Map is changed - General.Map.IsChanged = true; + // Map is changed + General.Map.IsChanged = true; + } + else + { + // Drawing failed + // NOTE: I have to call this twice, because the first time only cancels this volatile mode + General.Map.UndoRedo.WithdrawUndo(); + General.Map.UndoRedo.WithdrawUndo(); + } + } } // Done Cursor.Current = Cursors.Default; - // Return to original mode - General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + if(continuousdrawing) + { + // Reset settings + points.Clear(); + labels.Clear(); + + // Redraw display + General.Interface.RedrawDisplay(); + } + else + { + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } } private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) { triangulate = panel.Triangulate; - horizontalSlices = panel.HorizontalSlices + 1; - verticalSlices = panel.VerticalSlices + 1; + horizontalslices = panel.HorizontalSlices + 1; + verticalslices = panel.VerticalSlices + 1; horizontalinterpolation = panel.HorizontalInterpolationMode; verticalinterpolation = panel.VerticalInterpolationMode; Update(); } - private void OptionsPanelOnOnGridLockChanged(object sender, EventArgs eventArgs) + private void OptionsPanelOnGridLockChanged(object sender, EventArgs eventArgs) { - gridlock = panel.LockToGrid; - General.Hints.ShowHints(this.GetType(), (gridlock ? "gridlockhelp" : "general")); + gridlockmode = panel.GridLockMode; + General.Hints.ShowHints(this.GetType(), ((gridlockmode != GridLockMode.NONE) ? "gridlockhelp" : "general")); Update(); } @@ -195,8 +188,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // We WANT snaptogrid and DON'T WANT snaptonearest when lock to grid is enabled snaptocardinaldirection = General.Interface.ShiftState && General.Interface.AltState; //mxd - snaptogrid = (snaptocardinaldirection || gridlock || (General.Interface.ShiftState ^ General.Interface.SnapToGrid)); - snaptonearest = (!gridlock && (General.Interface.CtrlState ^ General.Interface.AutoMerge)); + snaptogrid = (snaptocardinaldirection || gridlockmode != GridLockMode.NONE || (General.Interface.ShiftState ^ General.Interface.SnapToGrid)); + snaptonearest = (gridlockmode == GridLockMode.NONE && (General.Interface.CtrlState ^ General.Interface.AutoMerge)); DrawnVertex curp; if(points.Count == 1) @@ -246,7 +239,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //render hint - if(horizontalSlices > 1 || verticalSlices > 1) + if(horizontalslices > 1 || verticalslices > 1) { hintlabel.Text = "H: " + (slicesH - 1) + "; V: " + (slicesV - 1); if(width > hintlabel.Text.Length * vsize && height > 16 * vsize) @@ -277,10 +270,7 @@ namespace CodeImp.DoomBuilder.BuilderModes pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary) return false; - DrawnVertex newpoint = new DrawnVertex(); - newpoint.pos = pos; - newpoint.stitch = true; - newpoint.stitchline = stitchline; + DrawnVertex newpoint = new DrawnVertex { pos = pos, stitch = true, stitchline = stitchline }; points.Add(newpoint); if(points.Count == 1) @@ -311,10 +301,7 @@ namespace CodeImp.DoomBuilder.BuilderModes DrawnVertex[] verts = new DrawnVertex[shape.Length]; for(int i = 0; i < shape.Length; i++) { - newpoint = new DrawnVertex(); - newpoint.pos = shape[i]; - newpoint.stitch = true; - newpoint.stitchline = stitchline; + newpoint = new DrawnVertex { pos = shape[i], stitch = true, stitchline = stitchline }; verts[i] = newpoint; } @@ -328,22 +315,34 @@ namespace CodeImp.DoomBuilder.BuilderModes private List<Vector2D[]> GetShapes(Vector2D s, Vector2D e) { - //no shape + // No shape if(s == e) return new List<Vector2D[]>(); - //setup slices - if(gridlock) - { - slicesH = width / General.Map.Grid.GridSize; - slicesV = height / General.Map.Grid.GridSize; - } - else + // Setup slices + switch(gridlockmode) { - slicesH = horizontalSlices; - slicesV = verticalSlices; + case GridLockMode.NONE: + slicesH = horizontalslices; + slicesV = verticalslices; + break; + + case GridLockMode.HORIZONTAL: + slicesH = width / General.Map.Grid.GridSize; + slicesV = verticalslices; + break; + + case GridLockMode.VERTICAL: + slicesH = horizontalslices; + slicesV = height / General.Map.Grid.GridSize; + break; + + case GridLockMode.BOTH: + slicesH = width / General.Map.Grid.GridSize; + slicesV = height / General.Map.Grid.GridSize; + break; } - //create a segmented line + // Create a segmented line List<Vector2D[]> shapes; if(width == 0 || height == 0) { @@ -369,19 +368,19 @@ namespace CodeImp.DoomBuilder.BuilderModes return shapes; } - //create a line + // Create a line return new List<Vector2D[]> {new[] {s, e}}; } - //create shape + // Create shape List<Vector2D> rect = new List<Vector2D> { s, new Vector2D((int)s.x, (int)e.y), e, new Vector2D((int)e.x, (int)s.y), s }; - if(!gridlock && slicesH == 1 && slicesV == 1) + if(slicesH == 1 && slicesV == 1) { if(triangulate) rect.AddRange(new[] { s, e }); return new List<Vector2D[]> { rect.ToArray() }; } - //create blocks + // Create blocks shapes = new List<Vector2D[]> { rect.ToArray() }; RectangleF[,] blocks = new RectangleF[slicesH, slicesV]; for(int w = 0; w < slicesH; w++) @@ -396,7 +395,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //add subdivisions + // Add subdivisions if(slicesH > 1) { for(int w = 1; w < slicesH; w++) @@ -414,7 +413,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //triangulate? + // Triangulate? if(triangulate) { bool startflip = ((int)Math.Round(((s.x + e.y) / General.Map.Grid.GridSize) % 2) == 0); @@ -440,7 +439,7 @@ namespace CodeImp.DoomBuilder.BuilderModes return shapes; } - //update bottom-left and top-right points, which define drawing shape + // Update bottom-left and top-right points, which define drawing shape private void UpdateReferencePoints(DrawnVertex p1, DrawnVertex p2) { if(!p1.pos.IsFinite() || !p2.pos.IsFinite()) return; @@ -473,15 +472,75 @@ namespace CodeImp.DoomBuilder.BuilderModes #endregion + #region ================== Settings panel + + protected override void SetupInterface() + { + // Load stored settings + triangulate = General.Settings.ReadPluginSetting("drawgridmode.triangulate", false); + gridlockmode = (GridLockMode)General.Settings.ReadPluginSetting("drawgridmode.gridlockmode", 0); + horizontalslices = Math.Max(General.Settings.ReadPluginSetting("drawgridmode.horizontalslices", 3), 3); + verticalslices = Math.Max(General.Settings.ReadPluginSetting("drawgridmode.verticalslices", 3), 3); + horizontalinterpolation = (InterpolationTools.Mode)General.Settings.ReadPluginSetting("drawgridmode.horizontalinterpolation", 0); + verticalinterpolation = (InterpolationTools.Mode)General.Settings.ReadPluginSetting("drawgridmode.verticalinterpolation", 0); + + // Create and setup settings panel + panel = new DrawGridOptionsPanel(); + panel.MaxHorizontalSlices = (int)General.Map.FormatInterface.MaxCoordinate; + panel.MaxVerticalSlices = (int)General.Map.FormatInterface.MaxCoordinate; + panel.Triangulate = triangulate; + panel.GridLockMode = gridlockmode; + panel.HorizontalSlices = horizontalslices - 1; + panel.VerticalSlices = verticalslices - 1; + panel.HorizontalInterpolationMode = horizontalinterpolation; + panel.VerticalInterpolationMode = verticalinterpolation; + + panel.OnValueChanged += OptionsPanelOnValueChanged; + panel.OnGridLockModeChanged += OptionsPanelOnGridLockChanged; + panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; + + // Needs to be set after adding the OnContinuousDrawingChanged event... + panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawgridmode.continuousdrawing", false); + } + + protected override void AddInterface() + { + // Add docker + docker = new Docker("drawgrid", "Draw Grid", panel); + General.Interface.AddDocker(docker); + General.Interface.SelectDocker(docker); + } + + protected override void RemoveInterface() + { + // Store settings + General.Settings.WritePluginSetting("drawgridmode.triangulate", triangulate); + General.Settings.WritePluginSetting("drawgridmode.gridlockmode", (int)gridlockmode); + General.Settings.WritePluginSetting("drawgridmode.horizontalslices", horizontalslices); + General.Settings.WritePluginSetting("drawgridmode.verticalslices", verticalslices); + General.Settings.WritePluginSetting("drawgridmode.horizontalinterpolation", (int)horizontalinterpolation); + General.Settings.WritePluginSetting("drawgridmode.verticalinterpolation", (int)verticalinterpolation); + General.Settings.WritePluginSetting("drawgridmode.continuousdrawing", panel.ContinuousDrawing); + + // Remove docker + General.Interface.RemoveDocker(docker); + panel.Dispose(); + panel = null; + } + + #endregion + #region ================== Actions [BeginAction("increasebevel")] protected void IncreaseBevel() { - if(!gridlock && (points.Count < 2 || horizontalSlices < width - 2) && horizontalSlices - 1 < panel.MaxHorizontalSlices) + if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.VERTICAL) + && (points.Count < 2 || horizontalslices < width - 2) + && horizontalslices - 1 < panel.MaxHorizontalSlices) { - horizontalSlices++; - panel.HorizontalSlices = horizontalSlices - 1; + horizontalslices++; + panel.HorizontalSlices = horizontalslices - 1; Update(); } } @@ -489,10 +548,10 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("decreasebevel")] protected void DecreaseBevel() { - if(!gridlock && horizontalSlices > 1) + if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.VERTICAL) && horizontalslices > 1) { - horizontalSlices--; - panel.HorizontalSlices = horizontalSlices - 1; + horizontalslices--; + panel.HorizontalSlices = horizontalslices - 1; Update(); } } @@ -500,10 +559,12 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("increasesubdivlevel")] protected void IncreaseSubdivLevel() { - if(!gridlock && (points.Count < 2 || verticalSlices < height - 2) && verticalSlices - 1 < panel.MaxVerticalSlices) + if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.HORIZONTAL) + && (points.Count < 2 || verticalslices < height - 2) + && verticalslices - 1 < panel.MaxVerticalSlices) { - verticalSlices++; - panel.VerticalSlices = verticalSlices - 1; + verticalslices++; + panel.VerticalSlices = verticalslices - 1; Update(); } } @@ -511,10 +572,10 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("decreasesubdivlevel")] protected void DecreaseSubdivLevel() { - if(!gridlock && verticalSlices > 1) + if((gridlockmode == GridLockMode.NONE || gridlockmode == GridLockMode.HORIZONTAL) && verticalslices > 1) { - verticalSlices--; - panel.VerticalSlices = verticalSlices - 1; + verticalslices--; + panel.VerticalSlices = verticalslices - 1; Update(); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs index 5269ad90..688508f5 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawRectangleMode.cs @@ -30,22 +30,24 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables protected HintLabel hintlabel; - protected int bevelWidth; - protected int currentBevelWidth; + protected int bevelwidth; + protected int currentbevelwidth; protected int subdivisions; - protected int maxSubdivisions; - protected int minSubdivisions; + protected int maxsubdivisions; + protected int minsubdivisions; - protected string undoName = "Rectangle draw"; - protected string shapeName = "rectangle"; + protected string undoname = "Rectangle draw"; + protected string shapename = "rectangle"; protected Vector2D start; protected Vector2D end; protected int width; protected int height; + protected int minpointscount; + protected bool alwaysrendershapehints; - //interface + // Interface private DrawRectangleOptionsPanel panel; #endregion @@ -56,7 +58,6 @@ namespace CodeImp.DoomBuilder.BuilderModes { snaptogrid = true; usefourcardinaldirections = true; - SetupInterface(); } public override void Dispose() @@ -76,28 +77,44 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Settings panel - protected virtual void SetupInterface() + protected override void SetupInterface() { - maxSubdivisions = 16; + maxsubdivisions = 16; + minpointscount = 4; + + // Load stored settings + subdivisions = General.Clamp(General.Settings.ReadPluginSetting("drawrectanglemode.subdivisions", 0), minsubdivisions, maxsubdivisions); + bevelwidth = General.Settings.ReadPluginSetting("drawrectanglemode.bevelwidth", 0); + currentbevelwidth = bevelwidth; //Add options docker panel = new DrawRectangleOptionsPanel(); - panel.MaxSubdivisions = maxSubdivisions; - panel.MinSubdivisions = minSubdivisions; + panel.MaxSubdivisions = maxsubdivisions; + panel.MinSubdivisions = minsubdivisions; panel.MaxBevelWidth = (int)General.Map.FormatInterface.MaxCoordinate; panel.MinBevelWidth = (int)General.Map.FormatInterface.MinCoordinate; + panel.BevelWidth = bevelwidth; + panel.Subdivisions = subdivisions; panel.OnValueChanged += OptionsPanelOnValueChanged; + panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged; + + // Needs to be set after adding the OnContinuousDrawingChanged event... + panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawrectanglemode.continuousdrawing", false); } - protected virtual void AddInterface() + protected override void AddInterface() { panel.Register(); - bevelWidth = panel.BevelWidth; - subdivisions = panel.Subdivisions; } - protected virtual void RemoveInterface() + protected override void RemoveInterface() { + // Store settings + General.Settings.WritePluginSetting("drawrectanglemode.subdivisions", subdivisions); + General.Settings.WritePluginSetting("drawrectanglemode.bevelwidth", bevelwidth); + General.Settings.WritePluginSetting("drawrectanglemode.continuousdrawing", panel.ContinuousDrawing); + + // Remove the buttons panel.Unregister(); } @@ -144,7 +161,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //got beveled corners? - if(shape.Length > 5) + if(alwaysrendershapehints || shape.Length > minpointscount + 1) { //render hint if(width > 64 * vsize && height > 16 * vsize) @@ -178,47 +195,47 @@ namespace CodeImp.DoomBuilder.BuilderModes //no shape if(pStart == pEnd) { - currentBevelWidth = 0; + currentbevelwidth = 0; return new Vector2D[0]; } //line if(pEnd.x == pStart.x || pEnd.y == pStart.y) { - currentBevelWidth = 0; + currentbevelwidth = 0; return new[] { pStart, pEnd }; } //no corners - if(bevelWidth == 0) + if(bevelwidth == 0) { - currentBevelWidth = 0; + currentbevelwidth = 0; return new[] { pStart, new Vector2D((int)pStart.x, (int)pEnd.y), pEnd, new Vector2D((int)pEnd.x, (int)pStart.y), pStart }; } //got corners. TODO: check point order bool reverse = false; - currentBevelWidth = Math.Min(Math.Abs(bevelWidth), Math.Min(width, height) / 2); + currentbevelwidth = Math.Min(Math.Abs(bevelwidth), Math.Min(width, height) / 2); - if(bevelWidth < 0) + if(bevelwidth < 0) { - currentBevelWidth *= -1; + currentbevelwidth *= -1; reverse = true; } List<Vector2D> shape = new List<Vector2D>(); //top-left corner - shape.AddRange(GetCornerPoints(pStart, currentBevelWidth, currentBevelWidth, !reverse)); + shape.AddRange(GetCornerPoints(pStart, currentbevelwidth, currentbevelwidth, !reverse)); //top-right corner - shape.AddRange(GetCornerPoints(new Vector2D(pEnd.x, pStart.y), -currentBevelWidth, currentBevelWidth, reverse)); + shape.AddRange(GetCornerPoints(new Vector2D(pEnd.x, pStart.y), -currentbevelwidth, currentbevelwidth, reverse)); //bottom-right corner - shape.AddRange(GetCornerPoints(pEnd, -currentBevelWidth, -currentBevelWidth, !reverse)); + shape.AddRange(GetCornerPoints(pEnd, -currentbevelwidth, -currentbevelwidth, !reverse)); //bottom-left corner - shape.AddRange(GetCornerPoints(new Vector2D(pStart.x, pEnd.y), currentBevelWidth, -currentBevelWidth, reverse)); + shape.AddRange(GetCornerPoints(new Vector2D(pStart.x, pEnd.y), currentbevelwidth, -currentbevelwidth, reverse)); //closing point shape.Add(shape[0]); @@ -229,7 +246,7 @@ namespace CodeImp.DoomBuilder.BuilderModes private Vector2D[] GetCornerPoints(Vector2D startPoint, int bevel_width, int bevel_height, bool reverse) { Vector2D[] points; - Vector2D center = (bevelWidth > 0 ? new Vector2D(startPoint.x + bevel_width, startPoint.y + bevel_height) : startPoint); + Vector2D center = (bevelwidth > 0 ? new Vector2D(startPoint.x + bevel_width, startPoint.y + bevel_height) : startPoint); float curAngle = Angle2D.PI; int steps = subdivisions + 2; @@ -248,14 +265,15 @@ namespace CodeImp.DoomBuilder.BuilderModes protected virtual string GetHintText() { - return "BVL: " + bevelWidth + "; SUB: " + subdivisions; + return "BVL: " + bevelwidth + "; SUB: " + subdivisions; } - //update top-left and bottom-right points, which define drawing shape + // Update top-left and bottom-right points, which define drawing shape private void UpdateReferencePoints(DrawnVertex p1, DrawnVertex p2) { if(!p1.pos.IsFinite() || !p2.pos.IsFinite()) return; + // Make sure start always stays at left and up from the end if(p1.pos.x < p2.pos.x) { start.x = p1.pos.x; @@ -278,6 +296,7 @@ namespace CodeImp.DoomBuilder.BuilderModes end.y = p1.pos.y; } + // Update size width = (int)(end.x - start.x); height = (int)(end.y - start.y); } @@ -330,18 +349,6 @@ namespace CodeImp.DoomBuilder.BuilderModes #endregion #region ================== Events - - public override void OnEngage() - { - base.OnEngage(); - AddInterface(); - } - - public override void OnDisengage() - { - RemoveInterface(); - base.OnDisengage(); - } override public void OnAccept() { @@ -349,57 +356,70 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Settings.FindDefaultDrawSettings(); // When we have a rectangle or a line - if(points.Count > 4 || points.Count == 2) + if(points.Count > minpointscount || points.Count == 2) { // Make undo for the draw - General.Map.UndoRedo.CreateUndo(undoName); + General.Map.UndoRedo.CreateUndo(undoname); // Make an analysis and show info string[] adjectives = new[] { "gloomy", "sad", "unhappy", "lonely", "troubled", "depressed", "heartsick", "glum", "pessimistic", "bitter", "downcast" }; // aaand my english vocabulary ends here :) string word = adjectives[new Random().Next(adjectives.Length - 1)]; string a = (word[0] == 'u' ? "an " : "a "); - General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " " + shapeName + "."); + General.Interface.DisplayStatus(StatusType.Action, "Created " + a + word + " " + shapename + "."); // Make the drawing - if(!Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) + if(Tools.DrawLines(points, true, BuilderPlug.Me.AutoAlignTextureOffsetsOnCreate)) { - // Drawing failed - // NOTE: I have to call this twice, because the first time only cancels this volatile mode - General.Map.UndoRedo.WithdrawUndo(); - General.Map.UndoRedo.WithdrawUndo(); - return; - } - - // Snap to map format accuracy - General.Map.Map.SnapAllToAccuracy(); + // Snap to map format accuracy + General.Map.Map.SnapAllToAccuracy(); - // Clear selection - General.Map.Map.ClearAllSelected(); + // Clear selection + General.Map.Map.ClearAllSelected(); - // Update cached values - General.Map.Map.Update(); + // Update cached values + General.Map.Map.Update(); - // Edit new sectors? - List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); - if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) - General.Interface.ShowEditSectors(newsectors); + // Edit new sectors? + List<Sector> newsectors = General.Map.Map.GetMarkedSectors(true); + if(BuilderPlug.Me.EditNewSector && (newsectors.Count > 0)) + General.Interface.ShowEditSectors(newsectors); - // Update the used textures - General.Map.Data.UpdateUsedTextures(); + // Update the used textures + General.Map.Data.UpdateUsedTextures(); - //mxd - General.Map.Renderer2D.UpdateExtraFloorFlag(); + //mxd + General.Map.Renderer2D.UpdateExtraFloorFlag(); - // Map is changed - General.Map.IsChanged = true; + // Map is changed + General.Map.IsChanged = true; + } + else + { + // Drawing failed + // NOTE: I have to call this twice, because the first time only cancels this volatile mode + General.Map.UndoRedo.WithdrawUndo(); + General.Map.UndoRedo.WithdrawUndo(); + } } // Done Cursor.Current = Cursors.Default; - // Return to original mode - General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + if(continuousdrawing) + { + // Reset settings + points.Clear(); + labels.Clear(); + + // Redraw display + General.Interface.RedrawDisplay(); + } + else + { + // Return to original mode + General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name); + } } public override void OnHelp() @@ -409,7 +429,7 @@ namespace CodeImp.DoomBuilder.BuilderModes private void OptionsPanelOnValueChanged(object sender, EventArgs eventArgs) { - bevelWidth = panel.BevelWidth; + bevelwidth = panel.BevelWidth; subdivisions = panel.Subdivisions; Update(); } @@ -421,7 +441,7 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("increasesubdivlevel")] protected virtual void IncreaseSubdivLevel() { - if(subdivisions < maxSubdivisions) + if(subdivisions < maxsubdivisions) { subdivisions++; panel.Subdivisions = subdivisions; @@ -432,7 +452,7 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("decreasesubdivlevel")] protected virtual void DecreaseSubdivLevel() { - if(subdivisions > minSubdivisions) + if(subdivisions > minsubdivisions) { subdivisions--; panel.Subdivisions = subdivisions; @@ -443,10 +463,10 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("increasebevel")] protected virtual void IncreaseBevel() { - if(points.Count < 2 || currentBevelWidth == bevelWidth || bevelWidth < 0) + if(points.Count < 2 || currentbevelwidth == bevelwidth || bevelwidth < 0) { - bevelWidth = Math.Min(bevelWidth + General.Map.Grid.GridSize, panel.MaxBevelWidth); - panel.BevelWidth = bevelWidth; + bevelwidth = Math.Min(bevelwidth + General.Map.Grid.GridSize, panel.MaxBevelWidth); + panel.BevelWidth = bevelwidth; Update(); } } @@ -454,10 +474,10 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("decreasebevel")] protected virtual void DecreaseBevel() { - if(currentBevelWidth == bevelWidth || bevelWidth > 0) + if(currentbevelwidth == bevelwidth || bevelwidth > 0) { - bevelWidth = Math.Max(bevelWidth - General.Map.Grid.GridSize, panel.MinBevelWidth); - panel.BevelWidth = bevelWidth; + bevelwidth = Math.Max(bevelwidth - General.Map.Grid.GridSize, panel.MinBevelWidth); + panel.BevelWidth = bevelwidth; Update(); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs index 9f564195..baa53867 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs @@ -2004,7 +2004,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(!start.Fields.ContainsKey(key) && !end.Fields.ContainsKey(key)) { - General.Interface.DisplayStatus(StatusType.Warning, "First or last selected sector must have the '" + key + "' property!"); + General.Interface.DisplayStatus(StatusType.Warning, "First or last selected sector must have the \"" + key + "\" property!"); } else { diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs index b8e20965..64fecd3c 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs @@ -761,7 +761,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(t.Fields.ContainsKey("comment")) { - float size = ((t.FixedSize && renderer.Scale > 1.0f) ? t.Size / renderer.Scale : t.Size); + float size = (((t.FixedSize || General.Settings.FixedThingsScale) && renderer.Scale > 1.0f) ? t.Size / renderer.Scale : t.Size); if(size * renderer.Scale < 1.5f) return; // Thing is too small to render int iconindex = 0; @@ -1141,7 +1141,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if(excludedLines.Count == thingsCount) { ThingTypeInfo tti = General.Map.Data.GetThingInfo(t.SRB2Type); - General.ErrorLogger.Add(ErrorType.Warning, "Unable to align Thing �" + t.Index + " (" + tti.Title + ") to any linedef in a map!"); + General.ErrorLogger.Add(ErrorType.Warning, "Unable to align " + tti.Title + " (index " + t.Index + ") to any linedef!"); aligned = true; } } diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs index 1a8e2801..1f424aef 100644 --- a/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs +++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultTexturesMisaligned.cs @@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // This must return the string that is displayed in the listbox public override string ToString() { - return "Texture '" + texturename + "' is not aligned on linedefs " + side1.Line.Index + " (" + (side1.IsFront ? "front" : "back") + return "Texture \"" + texturename + "\" is not aligned on linedefs " + side1.Line.Index + " (" + (side1.IsFront ? "front" : "back") + ") and " + side2.Line.Index + " (" + (side2.IsFront ? "front" : "back") + ")"; } diff --git a/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs index ecaad6e4..224ee01a 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindLinedefFlags.cs @@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string f = flag.Trim(); if(!General.Map.Config.LinedefFlags.ContainsKey(f)) { - MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); return objs.ToArray(); } replaceflagslist.Add(f); diff --git a/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs b/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs index 52fcca57..27ebc387 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindLinedefTypes.cs @@ -38,8 +38,6 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables - private List<int> generalizedbits; - #endregion #region ================== Properties @@ -50,31 +48,20 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Constructor / Destructor - //mxd - public FindLinedefTypes() - { - if(!General.Map.Config.GeneralizedActions) return; - - // Get all them generalized bits - generalizedbits = new List<int>(); - foreach(GeneralizedCategory cat in General.Map.Config.GenActionCategories) - { - foreach(GeneralizedOption option in cat.Options) - { - foreach(GeneralizedBit bit in option.Bits) - { - if(bit.Index > 0) generalizedbits.Add(bit.Index); - } - } - } - } - #endregion #region ================== Methods // This is called when the browse button is pressed public override string Browse(string initialvalue) + { + int num; + int.TryParse(initialvalue, out num); + return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, num, true).ToString(); + } + + //mxd. This is called when the browse replace button is pressed + public override string BrowseReplace(string initialvalue) { int num; int.TryParse(initialvalue, out num); @@ -178,7 +165,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - List<int> expectedbits = GetGeneralizedBits(action); + HashSet<int> expectedbits = GetGeneralizedBits(action); // Where to search? ICollection<Linedef> list = withinselection ? General.Map.Map.GetSelectedLinedefs(true) : General.Map.Map.Linedefs; @@ -186,8 +173,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Go for all linedefs foreach(Linedef l in list) { - // Action matches? - if(l.Action != action && !BitsMatch(l.Action, expectedbits)) continue; + // Action matches? -1 means any action (mxd) + if((action == -1 && l.Action == 0) || (action > -1 && (l.Action != action && !BitsMatch(l.Action, expectedbits)))) continue; bool match = true; string argtext = ""; @@ -260,18 +247,20 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - private static List<int> GetGeneralizedBits(int effect) + private static HashSet<int> GetGeneralizedBits(int action) { - if(!General.Map.Config.GeneralizedActions) return new List<int>(); - List<int> bits = new List<int>(); + if(!General.Map.Config.GeneralizedActions) return new HashSet<int>(); + HashSet<int> bits = new HashSet<int>(); foreach(GeneralizedCategory cat in General.Map.Config.GenActionCategories) { + if((action < cat.Offset) || (action >= (cat.Offset + cat.Length))) continue; + int actionbits = action - cat.Offset; foreach(GeneralizedOption option in cat.Options) { foreach(GeneralizedBit bit in option.Bits) { - if(bit.Index > 0 && (effect & bit.Index) == bit.Index) + if(bit.Index > 0 && (actionbits & bit.Index) == bit.Index) bits.Add(bit.Index); } } @@ -281,16 +270,19 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - private static bool BitsMatch(int action, List<int> expectedbits) + private static bool BitsMatch(int action, HashSet<int> expectedbits) { - if(!General.Map.Config.GeneralizedActions) return false; + if(!General.Map.Config.GeneralizedActions || expectedbits.Count == 0) return false; + + HashSet<int> bits = GetGeneralizedBits(action); + if(bits.Count == 0) return false; foreach(int bit in expectedbits) { - if((action & bit) != bit) return false; + if(bits.Contains(bit)) return true; } - return true; + return false; } #endregion diff --git a/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs b/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs index 26885b2d..ebad8552 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindReplaceType.cs @@ -80,6 +80,12 @@ namespace CodeImp.DoomBuilder.BuilderModes { return string.Empty; } + + //mxd. This is called when the replace browse button is pressed + public virtual string BrowseReplace(string initialvalue) + { + return Browse(initialvalue); + } // This is called to perform a search (and replace) // Must return a list of items to show in the results list diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs b/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs index cd937069..e21791c7 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindSectorEffect.cs @@ -18,10 +18,10 @@ using System; using System.Collections.Generic; -using System.Windows.Forms; -using CodeImp.DoomBuilder.Map; using System.Drawing; +using System.Windows.Forms; using CodeImp.DoomBuilder.Config; +using CodeImp.DoomBuilder.Map; #endregion @@ -36,8 +36,6 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables - private List<int> generalizedbits; - #endregion #region ================== Properties @@ -48,22 +46,6 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Constructor / Destructor - //mxd - public FindSectorEffect() - { - if(!General.Map.Config.GeneralizedEffects) return; - - // Get all them generalized bits - generalizedbits = new List<int>(); - foreach(GeneralizedOption option in General.Map.Config.GenEffectOptions) - { - foreach(GeneralizedBit bit in option.Bits) - { - if(bit.Index > 0) generalizedbits.Add(bit.Index); - } - } - } - #endregion #region ================== Methods @@ -73,10 +55,16 @@ namespace CodeImp.DoomBuilder.BuilderModes { int effect; int.TryParse(initialvalue, out effect); - effect = General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect); - return effect.ToString(); + return General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect, true).ToString(); } + //mxd. This is called when the browse replace button is pressed + public override string BrowseReplace(string initialvalue) + { + int effect; + int.TryParse(initialvalue, out effect); + return General.Interface.BrowseSectorEffect(BuilderPlug.Me.FindReplaceForm, effect).ToString(); + } // This is called to perform a search (and replace) // Returns a list of items to show in the results list @@ -113,8 +101,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Go for all sectors foreach(Sector s in list) { - // Effect matches? - if(s.Effect == effect || BitsMatch(s.Effect, expectedbits)) + // Effect matches? -1 means any effect (mxd) + if((effect == -1 && s.Effect > 0) || (effect > -1 && (s.Effect == effect || BitsMatch(s.Effect, expectedbits)))) { // Replace if(replace) s.Effect = replaceeffect; @@ -150,7 +138,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - private static bool BitsMatch(int effect, List<int> expectedbits) + private static bool BitsMatch(int effect, IEnumerable<int> expectedbits) { if(!General.Map.Config.GeneralizedEffects) return false; diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs index eef28388..560ac22d 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindSectorFlags.cs @@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string f = flag.Trim(); if(!General.Map.Config.SectorFlags.ContainsKey(f)) { - MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); return objs.ToArray(); } replaceflagslist.Add(f); diff --git a/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs index 4409719b..39caa40b 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindSidedefFlags.cs @@ -67,7 +67,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string f = flag.Trim(); if(!General.Map.Config.SidedefFlags.ContainsKey(f)) { - MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); return objs.ToArray(); } replaceflagslist.Add(f); diff --git a/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs b/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs index 5ae4c805..e1bc042a 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindThingAction.cs @@ -60,16 +60,21 @@ namespace CodeImp.DoomBuilder.BuilderModes return General.Map.FormatInterface.HasThingAction; } - // This is called when the browse button is pressed public override string Browse(string initialvalue) { int action; int.TryParse(initialvalue, out action); - action = General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action); - return action.ToString(); + return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action, true).ToString(); } + // This is called when the browse replace button is pressed + public override string BrowseReplace(string initialvalue) + { + int action; + int.TryParse(initialvalue, out action); + return General.Interface.BrowseLinedefActions(BuilderPlug.Me.FindReplaceForm, action).ToString(); + } // This is called to perform a search (and replace) // Returns a list of items to show in the results list @@ -172,8 +177,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Go for all things foreach(Thing t in list) { - // Action matches? - if(t.Action != action) continue; + // Action matches? -1 means any action (mxd) + if((action == -1 && t.Action == 0) || (action > -1 && t.Action != action)) continue; bool match = true; string argtext = ""; diff --git a/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs b/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs index cfe3efe4..cb70f0ee 100644 --- a/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs +++ b/Source/Plugins/BuilderModes/FindReplace/FindThingFlags.cs @@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string f = flag.Trim(); if(!General.Map.Config.ThingFlags.ContainsKey(f)) { - MessageBox.Show("Invalid replace value '" + f + "' for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("Invalid replace value \"" + f + "\" for this search type!", "Find and Replace", MessageBoxButtons.OK, MessageBoxIcon.Error); return objs.ToArray(); } replaceflagslist.Add(f); diff --git a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs index 1b0038ee..0cf67208 100644 --- a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs +++ b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs @@ -164,7 +164,7 @@ namespace CodeImp.DoomBuilder.BuilderModes break; default: - throw new NotImplementedException("GetSidedefPartSize: got unsupported geometry type: '" + type + "'"); + throw new NotImplementedException("GetSidedefPartSize: got unsupported geometry type: \"" + type + "\""); } return rect; diff --git a/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs b/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs index d67b2227..f9b7dc47 100644 --- a/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs +++ b/Source/Plugins/BuilderModes/IO/WavefrontExporter.cs @@ -90,7 +90,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO ImageData id = General.Map.Data.GetTextureImage(s); if(id.Width == 0 || id.Height == 0) { - General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture '" + s + "' has invalid size (" + id.Width + "x" + id.Height + ")!"); + General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!"); continue; } @@ -100,7 +100,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO } else { - General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture '" + s + "' does not exist!"); + General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: texture \"" + s + "\" does not exist!"); } } } @@ -115,7 +115,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO ImageData id = General.Map.Data.GetFlatImage(s); if(id.Width == 0 || id.Height == 0) { - General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' has invalid size (" + id.Width + "x" + id.Height + ")!"); + General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" has invalid size (" + id.Width + "x" + id.Height + ")!"); continue; } @@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO } else { - General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat '" + s + "' does not exist!"); + General.ErrorLogger.Add(ErrorType.Warning, "OBJ Exporter: flat \"" + s + "\" does not exist!"); } } } @@ -185,7 +185,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO sw.Write(mtl.ToString()); //done - General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to '" + savePath + ".obj'"); + General.Interface.DisplayStatus(StatusType.Warning, "Geometry exported to \"" + savePath + ".obj\""); } #endregion diff --git a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs index f590468c..2f0810b3 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.Designer.cs @@ -32,26 +32,29 @@ this.seglabel = new System.Windows.Forms.ToolStripLabel(); this.seglen = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); this.reset = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.continuousdrawing = new System.Windows.Forms.ToolStripButton(); this.toolstrip.SuspendLayout(); this.SuspendLayout(); // // toolstrip // this.toolstrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.continuousdrawing, + this.toolStripSeparator1, this.seglabel, this.seglen, this.reset}); this.toolstrip.Location = new System.Drawing.Point(0, 0); this.toolstrip.Name = "toolstrip"; - this.toolstrip.Size = new System.Drawing.Size(249, 25); + this.toolstrip.Size = new System.Drawing.Size(320, 25); this.toolstrip.TabIndex = 7; this.toolstrip.Text = "toolStrip1"; // // seglabel // - this.seglabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear; this.seglabel.Name = "seglabel"; - this.seglabel.Size = new System.Drawing.Size(113, 22); + this.seglabel.Size = new System.Drawing.Size(97, 22); this.seglabel.Text = "Segment Length:"; // // seglen @@ -69,7 +72,7 @@ 0, 0}); this.seglen.Name = "seglen"; - this.seglen.Size = new System.Drawing.Size(56, 20); + this.seglen.Size = new System.Drawing.Size(56, 23); this.seglen.Text = "0"; this.seglen.Value = new decimal(new int[] { 0, @@ -84,17 +87,32 @@ this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset; this.reset.ImageTransparentColor = System.Drawing.Color.Magenta; this.reset.Name = "reset"; - this.reset.Size = new System.Drawing.Size(23, 22); + this.reset.Size = new System.Drawing.Size(23, 20); this.reset.Text = "Reset"; this.reset.Click += new System.EventHandler(this.reset_Click); // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // continuousdrawing + // + this.continuousdrawing.CheckOnClick = true; + this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat; + this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta; + this.continuousdrawing.Name = "continuousdrawing"; + this.continuousdrawing.Size = new System.Drawing.Size(135, 22); + this.continuousdrawing.Text = "Continuous drawing"; + this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged); + // // DrawCurveOptionsPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.Controls.Add(this.toolstrip); this.Name = "DrawCurveOptionsPanel"; - this.Size = new System.Drawing.Size(249, 60); + this.Size = new System.Drawing.Size(320, 60); this.toolstrip.ResumeLayout(false); this.toolstrip.PerformLayout(); this.ResumeLayout(false); @@ -108,6 +126,8 @@ internal CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown seglen; private System.Windows.Forms.ToolStrip toolstrip; private System.Windows.Forms.ToolStripButton reset; + private System.Windows.Forms.ToolStripButton continuousdrawing; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs index d97ba896..f3cd0538 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawCurveOptionsPanel.cs @@ -6,9 +6,11 @@ namespace CodeImp.DoomBuilder.BuilderModes internal partial class DrawCurveOptionsPanel : UserControl { public event EventHandler OnValueChanged; - private bool blockEvents; + public event EventHandler OnContinuousDrawingChanged; + private bool blockevents; - public int SegmentLength { get { return (int)seglen.Value; } set { blockEvents = true; seglen.Value = value; blockEvents = false; } } + public int SegmentLength { get { return (int)seglen.Value; } set { blockevents = true; seglen.Value = value; blockevents = false; } } + public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } } public DrawCurveOptionsPanel(int minLength, int maxLength) { @@ -22,6 +24,8 @@ namespace CodeImp.DoomBuilder.BuilderModes public void Register() { + General.Interface.AddButton(continuousdrawing); + General.Interface.AddButton(toolStripSeparator1); General.Interface.AddButton(seglabel); General.Interface.AddButton(seglen); General.Interface.AddButton(reset); @@ -32,16 +36,23 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Interface.RemoveButton(reset); General.Interface.RemoveButton(seglen); General.Interface.RemoveButton(seglabel); + General.Interface.RemoveButton(toolStripSeparator1); + General.Interface.RemoveButton(continuousdrawing); } private void seglen_ValueChanged(object sender, EventArgs e) { - if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); + if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); } private void reset_Click(object sender, EventArgs e) { seglen.Value = seglen.Minimum; } + + private void continuousdrawing_CheckedChanged(object sender, EventArgs e) + { + if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty); + } } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs index bb88abb8..b95825fe 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.Designer.cs @@ -29,10 +29,14 @@ private void InitializeComponent() { this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.continuousdrawing = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.subdivslabel = new System.Windows.Forms.ToolStripLabel(); this.subdivs = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); this.spikinesslabel = new System.Windows.Forms.ToolStripLabel(); this.spikiness = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); + this.anglelabel = new System.Windows.Forms.ToolStripLabel(); + this.angle = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); this.reset = new System.Windows.Forms.ToolStripButton(); this.toolStrip1.SuspendLayout(); this.SuspendLayout(); @@ -40,22 +44,40 @@ // toolStrip1 // this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.continuousdrawing, + this.toolStripSeparator1, this.subdivslabel, this.subdivs, this.spikinesslabel, this.spikiness, + this.anglelabel, + this.angle, this.reset}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Name = "toolStrip1"; - this.toolStrip1.Size = new System.Drawing.Size(348, 25); + this.toolStrip1.Size = new System.Drawing.Size(582, 25); this.toolStrip1.TabIndex = 6; this.toolStrip1.Text = "toolStrip1"; // + // continuousdrawing + // + this.continuousdrawing.CheckOnClick = true; + this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat; + this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta; + this.continuousdrawing.Name = "continuousdrawing"; + this.continuousdrawing.Size = new System.Drawing.Size(135, 22); + this.continuousdrawing.Text = "Continuous drawing"; + this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // // subdivslabel // - this.subdivslabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear; this.subdivslabel.Name = "subdivslabel"; - this.subdivslabel.Size = new System.Drawing.Size(53, 22); + this.subdivslabel.Size = new System.Drawing.Size(37, 22); this.subdivslabel.Text = "Sides:"; // // subdivs @@ -102,12 +124,41 @@ 0, 0}); this.spikiness.Name = "spikiness"; - this.spikiness.Size = new System.Drawing.Size(56, 20); + this.spikiness.Size = new System.Drawing.Size(56, 23); this.spikiness.Text = "0"; this.spikiness.Value = new decimal(new int[] { 0, 0, 0, + 0}); + // + // anglelabel + // + this.anglelabel.Name = "anglelabel"; + this.anglelabel.Size = new System.Drawing.Size(41, 22); + this.anglelabel.Text = "Angle:"; + // + // angle + // + this.angle.AutoSize = false; + this.angle.Margin = new System.Windows.Forms.Padding(3, 0, 3, 0); + this.angle.Maximum = new decimal(new int[] { + 360, + 0, + 0, + 0}); + this.angle.Minimum = new decimal(new int[] { + 360, + 0, + 0, + -2147483648}); + this.angle.Name = "angle"; + this.angle.Size = new System.Drawing.Size(56, 23); + this.angle.Text = "0"; + this.angle.Value = new decimal(new int[] { + 0, + 0, + 0, 0}); // // reset @@ -126,7 +177,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.Controls.Add(this.toolStrip1); this.Name = "DrawEllipseOptionsPanel"; - this.Size = new System.Drawing.Size(348, 60); + this.Size = new System.Drawing.Size(582, 60); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); this.ResumeLayout(false); @@ -142,5 +193,9 @@ private System.Windows.Forms.ToolStripLabel spikinesslabel; private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown spikiness; private System.Windows.Forms.ToolStripButton reset; + private System.Windows.Forms.ToolStripButton continuousdrawing; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripLabel anglelabel; + private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown angle; } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs index d2fcb945..eee4b7e6 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawEllipseOptionsPanel.cs @@ -6,17 +6,17 @@ namespace CodeImp.DoomBuilder.BuilderModes internal partial class DrawEllipseOptionsPanel : UserControl { public event EventHandler OnValueChanged; - private bool blockEvents; + public event EventHandler OnContinuousDrawingChanged; + private bool blockevents; - private static int aquityValue; - private static int subdivsValue = 8; - - public int Spikiness { get { return (int)spikiness.Value; } set { blockEvents = true; spikiness.Value = value; blockEvents = false; } } - public int Subdivisions { get { return (int)subdivs.Value; } set { blockEvents = true; subdivs.Value = value; blockEvents = false; } } + public int Spikiness { get { return (int)spikiness.Value; } set { blockevents = true; spikiness.Value = value; blockevents = false; } } + public int Subdivisions { get { return (int)subdivs.Value; } set { blockevents = true; subdivs.Value = value; blockevents = false; } } + public int Angle { get { return (int)angle.Value; } set { blockevents = true; angle.Value = value; blockevents = false; } } public int MaxSubdivisions { get { return (int)subdivs.Maximum; } set { subdivs.Maximum = value; } } public int MinSubdivisions { get { return (int)subdivs.Minimum; } set { subdivs.Minimum = value; } } public int MaxSpikiness { get { return (int)spikiness.Maximum; } set { spikiness.Maximum = value; } } public int MinSpikiness { get { return (int)spikiness.Minimum; } set { spikiness.Minimum = value; } } + public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } } public DrawEllipseOptionsPanel() { @@ -25,40 +25,55 @@ namespace CodeImp.DoomBuilder.BuilderModes public void Register() { - spikiness.Value = aquityValue; - subdivs.Value = subdivsValue; spikiness.ValueChanged += ValueChanged; subdivs.ValueChanged += ValueChanged; + angle.ValueChanged += ValueChanged; + General.Interface.AddButton(continuousdrawing); + General.Interface.AddButton(toolStripSeparator1); General.Interface.AddButton(subdivslabel); General.Interface.AddButton(subdivs); General.Interface.AddButton(spikinesslabel); General.Interface.AddButton(spikiness); + General.Interface.AddButton(anglelabel); + General.Interface.AddButton(angle); General.Interface.AddButton(reset); } public void Unregister() { General.Interface.RemoveButton(reset); + General.Interface.RemoveButton(angle); + General.Interface.RemoveButton(anglelabel); General.Interface.RemoveButton(spikiness); General.Interface.RemoveButton(spikinesslabel); General.Interface.RemoveButton(subdivs); General.Interface.RemoveButton(subdivslabel); + General.Interface.RemoveButton(toolStripSeparator1); + General.Interface.RemoveButton(continuousdrawing); } private void ValueChanged(object sender, EventArgs e) { - aquityValue = (int)spikiness.Value; - subdivsValue = (int)subdivs.Value; - if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); + if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); } private void reset_Click(object sender, EventArgs e) { - blockEvents = true; + // Reset values + blockevents = true; spikiness.Value = 0; - blockEvents = false; - subdivs.Value = subdivs.Minimum; + angle.Value = 0; + subdivs.Value = 6; + blockevents = false; + + // Dispatch event + OnValueChanged(this, EventArgs.Empty); + } + + private void continuousdrawing_CheckedChanged(object sender, EventArgs e) + { + if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty); } } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs index 368897f6..ad2e5fd5 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.Designer.cs @@ -29,8 +29,9 @@ private void InitializeComponent() { this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.gridlockmode = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); this.triangulate = new System.Windows.Forms.CheckBox(); - this.gridlock = new System.Windows.Forms.CheckBox(); this.reset = new System.Windows.Forms.Button(); this.slicesV = new System.Windows.Forms.NumericUpDown(); this.slicesH = new System.Windows.Forms.NumericUpDown(); @@ -41,18 +42,22 @@ this.interphmode = new System.Windows.Forms.ComboBox(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.continuousdrawing = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.slicesV)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.slicesH)).BeginInit(); this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); this.SuspendLayout(); // // groupBox1 // this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.gridlockmode); + this.groupBox1.Controls.Add(this.label5); this.groupBox1.Controls.Add(this.triangulate); - this.groupBox1.Controls.Add(this.gridlock); this.groupBox1.Controls.Add(this.reset); this.groupBox1.Controls.Add(this.slicesV); this.groupBox1.Controls.Add(this.slicesH); @@ -65,6 +70,32 @@ this.groupBox1.TabStop = false; this.groupBox1.Text = " Number of slices: "; // + // gridlockmode + // + this.gridlockmode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gridlockmode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.gridlockmode.FormattingEnabled = true; + this.gridlockmode.Items.AddRange(new object[] { + "None", + "Horizontal", + "Vertical", + "Both"}); + this.gridlockmode.Location = new System.Drawing.Point(118, 77); + this.gridlockmode.Name = "gridlockmode"; + this.gridlockmode.Size = new System.Drawing.Size(76, 21); + this.gridlockmode.TabIndex = 16; + this.gridlockmode.SelectedIndexChanged += new System.EventHandler(this.gridlockmode_SelectedIndexChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(17, 80); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(95, 13); + this.label5.TabIndex = 15; + this.label5.Text = "Lock slices to grid:"; + // // triangulate // this.triangulate.AutoSize = true; @@ -76,17 +107,6 @@ this.triangulate.UseVisualStyleBackColor = true; this.triangulate.CheckedChanged += new System.EventHandler(this.ValueChanged); // - // gridlock - // - this.gridlock.AutoSize = true; - this.gridlock.Location = new System.Drawing.Point(20, 80); - this.gridlock.Name = "gridlock"; - this.gridlock.Size = new System.Drawing.Size(111, 17); - this.gridlock.TabIndex = 13; - this.gridlock.Text = "Lock slices to grid"; - this.gridlock.UseVisualStyleBackColor = true; - this.gridlock.CheckedChanged += new System.EventHandler(this.gridlock_CheckedChanged); - // // reset // this.reset.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Reset; @@ -190,20 +210,46 @@ this.label4.TabIndex = 15; this.label4.Text = "Horizontal"; // + // groupBox3 + // + this.groupBox3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox3.Controls.Add(this.continuousdrawing); + this.groupBox3.Location = new System.Drawing.Point(3, 225); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(200, 55); + this.groupBox3.TabIndex = 11; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Additional options"; + // + // continuousdrawing + // + this.continuousdrawing.AutoSize = true; + this.continuousdrawing.Location = new System.Drawing.Point(20, 24); + this.continuousdrawing.Name = "continuousdrawing"; + this.continuousdrawing.Size = new System.Drawing.Size(119, 17); + this.continuousdrawing.TabIndex = 15; + this.continuousdrawing.Text = "Continuous drawing"; + this.continuousdrawing.UseVisualStyleBackColor = true; + this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged); + // // DrawGridOptionsPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.Controls.Add(this.groupBox3); this.Controls.Add(this.groupBox2); this.Controls.Add(this.groupBox1); this.Name = "DrawGridOptionsPanel"; - this.Size = new System.Drawing.Size(206, 299); + this.Size = new System.Drawing.Size(206, 426); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.slicesV)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.slicesH)).EndInit(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); this.ResumeLayout(false); } @@ -212,7 +258,6 @@ private System.Windows.Forms.GroupBox groupBox1; private System.Windows.Forms.CheckBox triangulate; - private System.Windows.Forms.CheckBox gridlock; private System.Windows.Forms.Button reset; private System.Windows.Forms.NumericUpDown slicesV; private System.Windows.Forms.NumericUpDown slicesH; @@ -223,5 +268,9 @@ private System.Windows.Forms.ComboBox interphmode; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label4; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.CheckBox continuousdrawing; + private System.Windows.Forms.ComboBox gridlockmode; + private System.Windows.Forms.Label label5; } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs index a9d2f72e..f9476fc7 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawGridOptionsPanel.cs @@ -1,29 +1,42 @@ using System; using System.Windows.Forms; -using CodeImp.DoomBuilder.Geometry; +using InterpolationMode = CodeImp.DoomBuilder.Geometry.InterpolationTools.Mode; +using GridLockMode = CodeImp.DoomBuilder.BuilderModes.DrawGridMode.GridLockMode; namespace CodeImp.DoomBuilder.BuilderModes { internal partial class DrawGridOptionsPanel : UserControl { public event EventHandler OnValueChanged; - public event EventHandler OnGridLockChanged; + public event EventHandler OnGridLockModeChanged; + public event EventHandler OnContinuousDrawingChanged; private bool blockevents; public bool Triangulate { get { return triangulate.Checked; } set { blockevents = true; triangulate.Checked = value; blockevents = false; } } - public bool LockToGrid { get { return gridlock.Checked; } set { blockevents = true; gridlock.Checked = value; blockevents = false; } } + public GridLockMode GridLockMode { get { return (GridLockMode)gridlockmode.SelectedIndex; } set { blockevents = true; gridlockmode.SelectedIndex = (int)value; blockevents = false; } } public int HorizontalSlices { get { return (int)slicesH.Value; } set { blockevents = true; slicesH.Value = value; blockevents = false; } } public int MaxHorizontalSlices { get { return (int)slicesH.Maximum; } set { slicesH.Maximum = value; } } public int VerticalSlices { get { return (int)slicesV.Value; } set { blockevents = true; slicesV.Value = value; blockevents = false; } } public int MaxVerticalSlices { get { return (int)slicesV.Maximum; } set { slicesV.Maximum = value; } } - public InterpolationTools.Mode HorizontalInterpolationMode + public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } } + public InterpolationMode HorizontalInterpolationMode { - get { return gridlock.Checked ? InterpolationTools.Mode.LINEAR : (InterpolationTools.Mode)interphmode.SelectedIndex; } + get + { + GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex; + return (mode == GridLockMode.BOTH || mode == GridLockMode.HORIZONTAL) + ? InterpolationMode.LINEAR : (InterpolationMode)interphmode.SelectedIndex; + } set { interphmode.SelectedIndex = (int)value; } } - public InterpolationTools.Mode VerticalInterpolationMode + public InterpolationMode VerticalInterpolationMode { - get { return gridlock.Checked ? InterpolationTools.Mode.LINEAR : (InterpolationTools.Mode)interpvmode.SelectedIndex; } + get + { + GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex; + return (mode == GridLockMode.BOTH || mode == GridLockMode.VERTICAL) + ? InterpolationMode.LINEAR : (InterpolationMode)interpvmode.SelectedIndex; + } set { interpvmode.SelectedIndex = (int)value; } } @@ -43,15 +56,16 @@ namespace CodeImp.DoomBuilder.BuilderModes if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); } - private void gridlock_CheckedChanged(object sender, EventArgs e) + private void gridlockmode_SelectedIndexChanged(object sender, EventArgs e) { - slicesH.Enabled = !gridlock.Checked; - slicesV.Enabled = !gridlock.Checked; - interpvmode.Enabled = !gridlock.Checked; - interphmode.Enabled = !gridlock.Checked; - reset.Enabled = !gridlock.Checked; - - if(!blockevents && OnGridLockChanged != null) OnGridLockChanged(this, EventArgs.Empty); + GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex; + slicesH.Enabled = (mode == GridLockMode.NONE || mode == GridLockMode.VERTICAL); + slicesV.Enabled = (mode == GridLockMode.NONE || mode == GridLockMode.HORIZONTAL); + interphmode.Enabled = slicesH.Enabled; + interpvmode.Enabled = slicesV.Enabled; + reset.Enabled = (mode != GridLockMode.BOTH); + + if(!blockevents && OnGridLockModeChanged != null) OnGridLockModeChanged(this, EventArgs.Empty); } private void interpmode_DropDownClosed(object sender, EventArgs e) @@ -61,12 +75,19 @@ namespace CodeImp.DoomBuilder.BuilderModes private void reset_Click(object sender, EventArgs e) { + GridLockMode mode = (GridLockMode)gridlockmode.SelectedIndex; + blockevents = true; - slicesH.Value = 3; - slicesV.Value = 3; + if((mode == GridLockMode.NONE || mode == GridLockMode.VERTICAL)) slicesH.Value = 3; + if(mode == GridLockMode.NONE || mode == GridLockMode.HORIZONTAL) slicesV.Value = 3; blockevents = false; if(OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); } + + private void continuousdrawing_CheckedChanged(object sender, EventArgs e) + { + if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty); + } } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs new file mode 100644 index 00000000..af61aca3 --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs @@ -0,0 +1,75 @@ +namespace CodeImp.DoomBuilder.BuilderModes +{ + partial class DrawLineOptionsPanel + { + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.continuousdrawing = new System.Windows.Forms.ToolStripButton(); + this.toolStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.continuousdrawing}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(200, 25); + this.toolStrip1.TabIndex = 8; + this.toolStrip1.Text = "toolStrip1"; + // + // continuousdrawing + // + this.continuousdrawing.CheckOnClick = true; + this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat; + this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta; + this.continuousdrawing.Name = "continuousdrawing"; + this.continuousdrawing.Size = new System.Drawing.Size(135, 22); + this.continuousdrawing.Text = "Continuous drawing"; + this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged); + // + // DrawLineOptionsPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.toolStrip1); + this.Name = "DrawLineOptionsPanel"; + this.Size = new System.Drawing.Size(200, 60); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ToolStrip toolStrip1; + private System.Windows.Forms.ToolStripButton continuousdrawing; + } +} diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs new file mode 100644 index 00000000..fbc34259 --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs @@ -0,0 +1,32 @@ +using System; +using System.Windows.Forms; + +namespace CodeImp.DoomBuilder.BuilderModes +{ + internal partial class DrawLineOptionsPanel : UserControl + { + public event EventHandler OnContinuousDrawingChanged; + + public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } } + + public DrawLineOptionsPanel() + { + InitializeComponent(); + } + + public void Register() + { + General.Interface.AddButton(continuousdrawing); + } + + public void Unregister() + { + General.Interface.RemoveButton(continuousdrawing); + } + + private void continuousdrawing_CheckedChanged(object sender, EventArgs e) + { + if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty); + } + } +} diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx new file mode 100644 index 00000000..36f2967b --- /dev/null +++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.resx @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> + <value>17, 17</value> + </metadata> +</root> \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs index a86a0f01..edfc1649 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.Designer.cs @@ -29,10 +29,12 @@ private void InitializeComponent() { this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); this.radiuslabel = new System.Windows.Forms.ToolStripLabel(); this.radius = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); this.subdivslabel = new System.Windows.Forms.ToolStripLabel(); this.subdivs = new CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown(); + this.continuousdrawing = new System.Windows.Forms.ToolStripButton(); this.reset = new System.Windows.Forms.ToolStripButton(); this.toolStrip1.SuspendLayout(); this.SuspendLayout(); @@ -40,6 +42,8 @@ // toolStrip1 // this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.continuousdrawing, + this.toolStripSeparator1, this.radiuslabel, this.radius, this.subdivslabel, @@ -47,15 +51,19 @@ this.reset}); this.toolStrip1.Location = new System.Drawing.Point(0, 0); this.toolStrip1.Name = "toolStrip1"; - this.toolStrip1.Size = new System.Drawing.Size(380, 25); + this.toolStrip1.Size = new System.Drawing.Size(488, 25); this.toolStrip1.TabIndex = 7; this.toolStrip1.Text = "toolStrip1"; // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // // radiuslabel // - this.radiuslabel.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Gear; this.radiuslabel.Name = "radiuslabel"; - this.radiuslabel.Size = new System.Drawing.Size(92, 22); + this.radiuslabel.Size = new System.Drawing.Size(76, 22); this.radiuslabel.Text = "Bevel Radius:"; // // radius @@ -112,6 +120,16 @@ 0}); this.subdivs.ValueChanged += new System.EventHandler(this.ValueChanged); // + // continuousdrawing + // + this.continuousdrawing.CheckOnClick = true; + this.continuousdrawing.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Repeat; + this.continuousdrawing.ImageTransparentColor = System.Drawing.Color.Magenta; + this.continuousdrawing.Name = "continuousdrawing"; + this.continuousdrawing.Size = new System.Drawing.Size(135, 22); + this.continuousdrawing.Text = "Continuous drawing"; + this.continuousdrawing.CheckedChanged += new System.EventHandler(this.continuousdrawing_CheckedChanged); + // // reset // this.reset.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; @@ -128,7 +146,7 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; this.Controls.Add(this.toolStrip1); this.Name = "DrawRectangleOptionsPanel"; - this.Size = new System.Drawing.Size(380, 60); + this.Size = new System.Drawing.Size(488, 60); this.toolStrip1.ResumeLayout(false); this.toolStrip1.PerformLayout(); this.ResumeLayout(false); @@ -144,5 +162,7 @@ private System.Windows.Forms.ToolStripLabel subdivslabel; private CodeImp.DoomBuilder.Controls.ToolStripNumericUpDown subdivs; private System.Windows.Forms.ToolStripButton reset; + private System.Windows.Forms.ToolStripButton continuousdrawing; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; } } diff --git a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs index c885ea33..bb4f6387 100644 --- a/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs +++ b/Source/Plugins/BuilderModes/Interface/DrawRectangleOptionsPanel.cs @@ -6,17 +6,16 @@ namespace CodeImp.DoomBuilder.BuilderModes internal partial class DrawRectangleOptionsPanel : UserControl { public event EventHandler OnValueChanged; - private bool blockEvents; + public event EventHandler OnContinuousDrawingChanged; + private bool blockevents; - private static int radiusValue; - private static int subdivsValue; - - public int BevelWidth { get { return (int)radius.Value; } set { blockEvents = true; radius.Value = value; blockEvents = false; } } + public int BevelWidth { get { return (int)radius.Value; } set { blockevents = true; radius.Value = value; blockevents = false; } } public int MaxBevelWidth { get { return (int)radius.Maximum; } set { radius.Maximum = value; } } public int MinBevelWidth { get { return (int)radius.Minimum; } set { radius.Minimum = value; } } - public int Subdivisions { get { return (int)subdivs.Value; } set { blockEvents = true; subdivs.Value = value; blockEvents = false; } } + public int Subdivisions { get { return (int)subdivs.Value; } set { blockevents = true; subdivs.Value = value; blockevents = false; } } public int MaxSubdivisions { get { return (int)subdivs.Maximum; } set { subdivs.Maximum = value; } } public int MinSubdivisions { get { return (int)subdivs.Minimum; } set { subdivs.Minimum = value; } } + public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } } public DrawRectangleOptionsPanel() { @@ -25,11 +24,11 @@ namespace CodeImp.DoomBuilder.BuilderModes public void Register() { - radius.Value = radiusValue; - subdivs.Value = subdivsValue; radius.ValueChanged += ValueChanged; subdivs.ValueChanged += ValueChanged; + General.Interface.AddButton(continuousdrawing); + General.Interface.AddButton(toolStripSeparator1); General.Interface.AddButton(radiuslabel); General.Interface.AddButton(radius); General.Interface.AddButton(subdivslabel); @@ -44,22 +43,30 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Interface.RemoveButton(subdivslabel); General.Interface.RemoveButton(radius); General.Interface.RemoveButton(radiuslabel); + General.Interface.RemoveButton(toolStripSeparator1); + General.Interface.RemoveButton(continuousdrawing); } private void ValueChanged(object sender, EventArgs e) { - radiusValue = (int)radius.Value; - subdivsValue = (int)subdivs.Value; - if(!blockEvents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); + if(!blockevents && OnValueChanged != null) OnValueChanged(this, EventArgs.Empty); } private void reset_Click(object sender, EventArgs e) { - blockEvents = true; + // Reset values + blockevents = true; radius.Value = 0; - blockEvents = false; subdivs.Value = 0; + blockevents = false; + + // Dispatch event + OnValueChanged(this, EventArgs.Empty); } + private void continuousdrawing_CheckedChanged(object sender, EventArgs e) + { + if(OnContinuousDrawingChanged != null) OnContinuousDrawingChanged(continuousdrawing.Checked, EventArgs.Empty); + } } } diff --git a/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs b/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs index a782ef92..f0dabd2a 100644 --- a/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs +++ b/Source/Plugins/BuilderModes/Interface/ErrorCheckForm.cs @@ -330,16 +330,16 @@ namespace CodeImp.DoomBuilder.BuilderModes catch(TargetInvocationException ex) { // Error! - General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\""); General.WriteLogLine(ex.InnerException.GetType().Name + ": " + ex.InnerException.Message); - throw ex; + throw; } catch(Exception ex) { // Error! - General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\""); General.WriteLogLine(ex.GetType().Name + ": " + ex.Message); - throw ex; + throw; } // Add to list @@ -749,7 +749,7 @@ namespace CodeImp.DoomBuilder.BuilderModes foreach(ErrorResult result in results.SelectedItems) sb.AppendLine(result.ToString()); // Set on clipboard - Clipboard.SetText(sb.ToString()); + Clipboard.SetDataObject(sb.ToString(), true, 5, 200); //mxd // Inform the user General.Interface.DisplayStatus(StatusType.Info, "Analysis results copied to clipboard."); diff --git a/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs b/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs index 83c7d841..789112fa 100644 --- a/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs +++ b/Source/Plugins/BuilderModes/Interface/FindReplaceForm.cs @@ -80,14 +80,14 @@ namespace CodeImp.DoomBuilder.BuilderModes catch(TargetInvocationException ex) { // Error! - General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\""); General.WriteLogLine(ex.InnerException.GetType().Name + ": " + ex.InnerException.Message); throw; } catch(Exception ex) { // Error! - General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance '" + t.Name + "'"); + General.ErrorLogger.Add(ErrorType.Error, "Failed to create class instance \"" + t.Name + "\""); General.WriteLogLine(ex.GetType().Name + ": " + ex.Message); throw; } @@ -151,7 +151,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Browse replacement clicked private void browsereplace_Click(object sender, EventArgs e) { - replaceinput.Text = newfinder.Browse(replaceinput.Text); + replaceinput.Text = newfinder.BrowseReplace(replaceinput.Text); } //mxd diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs index c61aee09..2b1741aa 100644 --- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs +++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs @@ -263,9 +263,10 @@ namespace CodeImp.DoomBuilder.BuilderModes this.autodrawonedit.AutoSize = true; this.autodrawonedit.Location = new System.Drawing.Point(13, 24); this.autodrawonedit.Name = "autodrawonedit"; - this.autodrawonedit.Size = new System.Drawing.Size(346, 17); + this.autodrawonedit.Size = new System.Drawing.Size(353, 30); this.autodrawonedit.TabIndex = 11; - this.autodrawonedit.Text = "Start drawing when Edit pressed over empty space in Classic modes"; + this.autodrawonedit.Text = "Start drawing when Edit pressed over empty space in Classic modes\r\nInsert new thi" + + "ng when Edit pressed over empty space in Things mode"; this.autodrawonedit.UseVisualStyleBackColor = true; // // syncSelection @@ -331,7 +332,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // editnewthing // this.editnewthing.AutoSize = true; - this.editnewthing.Location = new System.Drawing.Point(13, 49); + this.editnewthing.Location = new System.Drawing.Point(13, 62); this.editnewthing.Name = "editnewthing"; this.editnewthing.Size = new System.Drawing.Size(248, 17); this.editnewthing.TabIndex = 1; @@ -341,7 +342,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // editnewsector // this.editnewsector.AutoSize = true; - this.editnewsector.Location = new System.Drawing.Point(13, 74); + this.editnewsector.Location = new System.Drawing.Point(13, 87); this.editnewsector.Name = "editnewsector"; this.editnewsector.Size = new System.Drawing.Size(258, 17); this.editnewsector.TabIndex = 2; @@ -351,7 +352,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // additiveselect // this.additiveselect.AutoSize = true; - this.additiveselect.Location = new System.Drawing.Point(13, 99); + this.additiveselect.Location = new System.Drawing.Point(13, 112); this.additiveselect.Name = "additiveselect"; this.additiveselect.Size = new System.Drawing.Size(205, 17); this.additiveselect.TabIndex = 3; diff --git a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs index aa41c515..b86a9646 100644 --- a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs +++ b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ // <auto-generated> -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ @@ -13,13 +13,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { /// <summary> - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// A strongly-typed resource class, for looking up localized strings, etc. /// </summary> - // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -33,7 +33,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// Returns the cached ResourceManager instance used by this class. /// </summary> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { @@ -47,8 +47,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. /// </summary> [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { @@ -61,7 +61,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap AlignThings { get { @@ -71,7 +71,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Angle { get { @@ -81,7 +81,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap BrightnessGradient { get { @@ -91,7 +91,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap CeilingAlign { get { @@ -101,7 +101,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap CeilsGradient { get { @@ -111,7 +111,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap ColorPick { get { @@ -121,7 +121,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Copy { get { @@ -131,7 +131,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap CopyProperties { get { @@ -141,7 +141,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap CurveLines { get { @@ -151,7 +151,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Door { get { @@ -161,7 +161,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap DrawCurveMode { get { @@ -171,7 +171,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap DrawEllipseMode { get { @@ -181,7 +181,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap DrawGeometryMode { get { @@ -191,7 +191,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap DrawGridMode { get { @@ -201,7 +201,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap DrawRectangleMode { get { @@ -211,7 +211,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap FilterThings { get { @@ -221,7 +221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Flip { get { @@ -231,7 +231,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap FlipSelectionH { get { @@ -241,7 +241,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap FlipSelectionV { get { @@ -251,7 +251,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap FloorAlign { get { @@ -261,7 +261,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap FloorsGradient { get { @@ -271,7 +271,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Folder { get { @@ -281,7 +281,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Gear { get { @@ -291,7 +291,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Hide { get { @@ -301,7 +301,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap HideAll { get { @@ -311,7 +311,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap InsertThingsRadiallyMode { get { @@ -321,7 +321,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Join { get { @@ -331,7 +331,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap List { get { @@ -341,7 +341,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap List_Images { get { @@ -351,7 +351,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Merge { get { @@ -361,7 +361,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap PasteProperties { get { @@ -371,7 +371,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap PastePropertiesOptions { get { @@ -381,7 +381,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap PlaceThings { get { @@ -391,7 +391,17 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// </summary> + internal static System.Drawing.Bitmap Repeat { + get { + object obj = ResourceManager.GetObject("Repeat", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// <summary> + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Reset { get { @@ -401,7 +411,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Save { get { @@ -411,7 +421,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap SelectThingsInSectors { get { @@ -421,7 +431,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap SelectTouching { get { @@ -431,7 +441,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Show { get { @@ -441,7 +451,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Show2 { get { @@ -451,7 +461,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Show3 { get { @@ -461,7 +471,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Similar { get { @@ -471,7 +481,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap Text { get { @@ -481,7 +491,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap TextureLock { get { @@ -491,7 +501,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap ThingPointAtCursor { get { @@ -501,7 +511,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap treeview { get { @@ -511,7 +521,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap ViewSelectionEffects { get { @@ -521,7 +531,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap ViewSelectionIndex { get { @@ -531,7 +541,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties { } /// <summary> - /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// Looks up a localized resource of type System.Drawing.Bitmap. /// </summary> internal static System.Drawing.Bitmap VisualModeGZ { get { diff --git a/Source/Plugins/BuilderModes/Properties/Resources.resx b/Source/Plugins/BuilderModes/Properties/Resources.resx index 5ee3b44d..5d591af1 100644 --- a/Source/Plugins/BuilderModes/Properties/Resources.resx +++ b/Source/Plugins/BuilderModes/Properties/Resources.resx @@ -118,9 +118,6 @@ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> </resheader> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> - <data name="Join" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\Join.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> - </data> <data name="FloorAlign" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\FloorAlign.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> @@ -139,9 +136,6 @@ <data name="ViewSelectionEffects" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\ViewSelectionEffects.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> - <data name="Gear" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\Gear.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> - </data> <data name="HideAll" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\HideAll.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> @@ -196,12 +190,12 @@ <data name="ThingPointAtCursor" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\ThingPointAtCursor.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> - <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> - </data> <data name="Text" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\Text.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> + <data name="Show" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\Show.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> <data name="BrightnessGradient" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\BrightnessGradient.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> @@ -217,8 +211,8 @@ <data name="Reset" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\Reset.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> - <data name="Show" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\Show.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + <data name="Join" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\Join.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> <data name="ViewSelectionIndex" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\ViewSelectionIndex.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> @@ -229,6 +223,9 @@ <data name="Show2" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\Show2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> + <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> <data name="ColorPick" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\ColorPick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> @@ -238,8 +235,8 @@ <data name="FlipSelectionH" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\FlipSelectionH.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> - <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms"> - <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> <data name="Angle" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\Angle.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> @@ -262,4 +259,10 @@ <data name="InsertThingsRadiallyMode" type="System.Resources.ResXFileRef, System.Windows.Forms"> <value>..\Resources\InsertThingsRadiallyMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> </data> + <data name="Gear" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\Gear.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> + <data name="Repeat" type="System.Resources.ResXFileRef, System.Windows.Forms"> + <value>..\Resources\Repeat.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> + </data> </root> \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/Resources/Repeat.png b/Source/Plugins/BuilderModes/Resources/Repeat.png new file mode 100644 index 0000000000000000000000000000000000000000..48350331c3025d345424a05147edaa22ea0ad025 GIT binary patch literal 587 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7BuiW)N`mv#O3D+9QW+dm z@{>{(JaZG%Q-e|yQz{EjrrIztFuwJ4aSW-rwItZkTgFkO&UkZQdyLK+C7mvrXF5EZ z*Frd3LfCYg=CTDXwGj9tem!dGu0yBXJSLY23OOAxV&AFJq|w=^5Vq*vy|?eqyy<y= zws19Dk><ODx9{HkzVH3n-}iWm&mA;4mgvF#;$zO|HD@f>KYXtA>qx!9^B30FZXLUB z{yo{hq5IaCl+4_^XK@<tEix_VO4fa=-=?j;JT@w?f@$&BM|VOjZGM$5w5z#!TiWHr zr=N$jOlA1{>*FuwneSn<I;}Q?`RBjl*8+1^FVz2YID5+DHIrL3U5>D(%w$a0y<wAo zD1Nf!QyG?IJ2y+uB%5Ul0hwHx=8V&y-z#3*c<l6)rocbbJPg!a1m7Q%?ceD<p=4Lc zL2KnE3%8?Hp%dP)RylLMdpx%+Mxa74bdtlGiFYM9B)VIQedq98D(1hI8TH*oLOoym zvElaef^|CsCi5>_&5;+dwJ!C|)_+-F3tdD7|MV7ZN^lW;mc|~r?Q+)KkTm(TZEtt3 zeDQm?f9>B_tFyf?zKi6Vx>Q{-(>iUd)sMnI?FLg0c&zz&{dQ`$Poa=xvTs7qG0(l% z=dWAuvO9nK?Ct(a{7uKMUh}%6&d}T?F3wV&e#QP(L;IP@KmI%EC{+5}XfkqE>GBw{ t)Sn5o*pgaxI_Ra}9Ny}=>scijx;>mKyDDp5FfcGMc)I$ztaD0e0s!D-2)O_N literal 0 HcmV?d00001 diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs index bdd27278..3d33932b 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs @@ -801,7 +801,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Apply Texture public virtual void ApplyTexture(string texture) { - mode.CreateUndo("Change flat '" + texture + "'"); + mode.CreateUndo("Change flat \"" + texture + "\""); SetTexture(texture); OnTextureChanged(); //mxd } @@ -813,7 +813,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string texturename = ((General.Map.Options.UseLongTextureNames && Texture != null && Texture.UsedInMap) ? Texture.Name : GetTextureName()); BuilderPlug.Me.CopiedFlat = texturename; if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedTexture = texturename; - mode.SetActionResult("Copied flat '" + texturename + "'."); + mode.SetActionResult("Copied flat \"" + texturename + "\"."); } public virtual void OnPasteTexture() { } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs index 6ae07697..2b724500 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs @@ -1186,10 +1186,10 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(BuilderPlug.Me.CopiedTexture != null) { - mode.CreateUndo("Paste texture '" + BuilderPlug.Me.CopiedTexture + "'"); - mode.SetActionResult("Pasted texture '" + BuilderPlug.Me.CopiedTexture + "'."); + mode.CreateUndo("Paste texture \"" + BuilderPlug.Me.CopiedTexture + "\""); + mode.SetActionResult("Pasted texture \"" + BuilderPlug.Me.CopiedTexture + "\"."); SetTexture(BuilderPlug.Me.CopiedTexture); - OnTextureChanged();//mxd + OnTextureChanged(); //mxd } } @@ -1221,7 +1221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes string texturename = ((General.Map.Options.UseLongTextureNames && Texture != null && Texture.UsedInMap) ? Texture.Name : GetTextureName()); BuilderPlug.Me.CopiedTexture = texturename; if(General.Map.Config.MixTexturesFlats) BuilderPlug.Me.CopiedFlat = texturename; - mode.SetActionResult("Copied texture '" + texturename + "'."); + mode.SetActionResult("Copied texture \"" + texturename + "\"."); } // Copy texture offsets diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index a1ebc442..b9db85e1 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -517,6 +517,11 @@ namespace CodeImp.DoomBuilder.BuilderModes // This updates the VisualSectors and VisualThings that have their Changed property set private void UpdateChangedObjects() { + //mxd + SectorData[] toupdate = new SectorData[sectordata.Values.Count]; + sectordata.Values.CopyTo(toupdate, 0); + foreach(SectorData data in toupdate) data.Update(); + foreach(KeyValuePair<Sector, VisualSector> vs in allsectors) { if(vs.Value != null) @@ -1538,8 +1543,6 @@ namespace CodeImp.DoomBuilder.BuilderModes // and uses the marks to check what needs to be reloaded. protected override void ResourcesReloadedPartial() { - bool sectorsmarked = false; - if(General.Map.UndoRedo.GeometryChanged) { // Let the core do this (it will just dispose the sectors that were changed) @@ -1547,6 +1550,8 @@ namespace CodeImp.DoomBuilder.BuilderModes } else { + bool sectorsmarked = false; + // Neighbour sectors must be updated as well foreach(Sector s in General.Map.Map.Sectors) { @@ -1578,7 +1583,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if(s.Marked) { SectorData sd = GetSectorData(s); - sd.Reset(); + sd.Reset(false); //mxd (changed Reset implementation) // UpdateSectorGeometry for associated sectors (sd.UpdateAlso) as well! foreach(KeyValuePair<Sector, bool> us in sd.UpdateAlso) @@ -1603,8 +1608,22 @@ namespace CodeImp.DoomBuilder.BuilderModes { // No sectors or geometry changed. So we only have // to update things when they have changed. + HashSet<Thing> toremove = new HashSet<Thing>(); //mxd foreach(KeyValuePair<Thing, VisualThing> vt in allthings) - if((vt.Value != null) && vt.Key.Marked) (vt.Value as BaseVisualThing).Rebuild(); + { + if((vt.Value != null) && vt.Key.Marked) + { + if(vt.Key.IsDisposed) toremove.Add(vt.Key); //mxd. Disposed things will cause problems + else (vt.Value as BaseVisualThing).Rebuild(); + } + } + + //mxd. Remove disposed things + foreach(Thing t in toremove) + { + if(allthings[t] != null) allthings[t].Dispose(); + allthings.Remove(t); + } } else { @@ -3011,7 +3030,6 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.SetCrosshairBusy(true); General.Interface.RedrawDisplay(); GetTargetEventReceiver(false).OnSelectTexture(); - UpdateChangedObjects(); RebuildElementData(); //mxd. Extrafloors or Glow effects may've been changed renderer.SetCrosshairBusy(false); PostAction(); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs index d28640a6..cc06ba67 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs @@ -35,14 +35,14 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Variables - private BaseVisualMode mode; + private readonly BaseVisualMode mode; private VisualFloor floor; private VisualCeiling ceiling; private List<VisualFloor> extrafloors; private List<VisualCeiling> extraceilings; - private List<VisualFloor> extrabackfloors; //mxd - private List<VisualCeiling> extrabackceilings; //mxd + private readonly List<VisualFloor> extrabackfloors; //mxd + private readonly List<VisualCeiling> extrabackceilings; //mxd private Dictionary<Sidedef, VisualSidedefParts> sides; // If this is set to true, the sector will be rebuilt after the action is performed. @@ -121,16 +121,19 @@ namespace CodeImp.DoomBuilder.BuilderModes changed = true; // Not sure what from this part we need, so commented out for now - SectorData data = GetSectorData(); - data.Reset(); - - // Update sectors that rely on this sector - foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso) + SectorData data = mode.GetSectorDataEx(this.Sector); //mxd + if(data != null) //mxd { - if(mode.VisualSectorExists(s.Key)) + data.Reset(includeneighbours); + + // Update sectors that rely on this sector + foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso) { - BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key); - vs.UpdateSectorGeometry(s.Value); + if(mode.VisualSectorExists(s.Key)) + { + BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key); + vs.Changed = true; + } } } diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs index 22349e7f..03ea37e6 100644 --- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs +++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs @@ -113,6 +113,13 @@ namespace CodeImp.DoomBuilder.BuilderModes Effect3DFloor e = new Effect3DFloor(this, sourcelinedef); extrafloors.Add(e); alleffects.Add(e); + + //mxd. Extrafloor neighbours should be updated when extrafloor is changed + foreach(Sidedef sd in this.Sector.Sidedefs) + { + if(sd.Other != null && sd.Other.Sector != null) + AddUpdateSector(sd.Other.Sector, false); + } } // Brightness level effect @@ -214,7 +221,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } // This resets this sector data and all sectors that require updating after me - public void Reset() + /*public void Reset() { if(isupdating) return; isupdating = true; @@ -236,6 +243,35 @@ namespace CodeImp.DoomBuilder.BuilderModes sd.Reset(); } + isupdating = false; + }*/ + + //mxd. This marks this sector data and all sector datas that require updating as not updated + public void Reset(bool resetneighbours) + { + if(isupdating) return; + isupdating = true; + + // This is set to false so that this sector is rebuilt the next time it is needed! + updated = false; + + // The visual sector associated is now outdated + if(mode.VisualSectorExists(sector)) + { + BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector); + vs.Changed = true; + } + + // Reset the sectors that depend on this sector + if(resetneighbours) + { + foreach(KeyValuePair<Sector, bool> s in updatesectors) + { + SectorData sd = mode.GetSectorDataEx(s.Key); + if(sd != null) sd.Reset(s.Value); + } + } + isupdating = false; } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs index f8e206c3..efb5a88e 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs @@ -369,27 +369,11 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(BuilderPlug.Me.CopiedFlat != null) { - mode.CreateUndo("Paste ceiling '" + BuilderPlug.Me.CopiedFlat + "'"); - mode.SetActionResult("Pasted flat '" + BuilderPlug.Me.CopiedFlat + "' on ceiling."); - - //mxd. Glow effect may require SectorData and geometry update - bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture); + mode.CreateUndo("Paste ceiling \"" + BuilderPlug.Me.CopiedFlat + "\""); + mode.SetActionResult("Pasted flat \"" + BuilderPlug.Me.CopiedFlat + "\" on ceiling."); SetTexture(BuilderPlug.Me.CopiedFlat); - //mxd. Glow effect may require SectorData and geometry update - if(prevtextureglows && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture)) - { - SectorData sd = mode.GetSectorData(level.sector); - sd.UpdateForced(); - - if(mode.VisualSectorExists(level.sector)) - { - BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector); - vs.UpdateSectorGeometry(false); - } - } - //mxd. 3D floors may need updating... OnTextureChanged(); } @@ -591,7 +575,20 @@ namespace CodeImp.DoomBuilder.BuilderModes // This changes the texture protected override void SetTexture(string texturename) { + //mxd. Glow effect may require SectorData and geometry update + bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture); + + // Set new texture level.sector.SetCeilTexture(texturename); + + //mxd. Glow effect may require SectorData and geometry update + if(prevtextureglows + && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture) + && mode.VisualSectorExists(level.sector)) + { + ((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true; + } + General.Map.Data.UpdateUsedTextures(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs index cd098635..c0125c0d 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs @@ -368,27 +368,11 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(BuilderPlug.Me.CopiedFlat != null) { - mode.CreateUndo("Paste floor '" + BuilderPlug.Me.CopiedFlat + "'"); - mode.SetActionResult("Pasted flat '" + BuilderPlug.Me.CopiedFlat + "' on floor."); - - //mxd. Glow effect may require SectorData and geometry update - bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture); + mode.CreateUndo("Paste floor \"" + BuilderPlug.Me.CopiedFlat + "\""); + mode.SetActionResult("Pasted flat \"" + BuilderPlug.Me.CopiedFlat + "\" on floor."); SetTexture(BuilderPlug.Me.CopiedFlat); - //mxd. Glow effect may require SectorData and geometry update - if(prevtextureglows && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture)) - { - SectorData sd = mode.GetSectorData(level.sector); - sd.UpdateForced(); - - if(mode.VisualSectorExists(level.sector)) - { - BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector); - vs.UpdateSectorGeometry(false); - } - } - //mxd. 3D floors may need updating... OnTextureChanged(); } @@ -464,12 +448,20 @@ namespace CodeImp.DoomBuilder.BuilderModes { // This floor is part of 3D-floor if(level.sector != Sector.Sector) - ((BaseVisualSector)mode.GetVisualSector(level.sector)).Floor.OnChangeTargetBrightness(up); + { + BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector); + vs.Floor.OnChangeTargetBrightness(up); + vs.UpdateSectorGeometry(true); + } // This is actual floor of a sector with extrafloors else if(Sector.ExtraFloors.Count > 0 && !Sector.ExtraFloors[0].ExtraFloor.Floor.restrictlighting && !Sector.ExtraFloors[0].ExtraFloor.Floor.disablelighting) + { Sector.ExtraFloors[0].OnChangeTargetBrightness(up); + } else + { base.OnChangeTargetBrightness(up); + } } else { @@ -554,7 +546,20 @@ namespace CodeImp.DoomBuilder.BuilderModes // This changes the texture protected override void SetTexture(string texturename) { + //mxd. Glow effect may require SectorData and geometry update + bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture); + + // Set new texture level.sector.SetFloorTexture(texturename); + + //mxd. Glow effect may require SectorData and geometry update + if(prevtextureglows + && !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture) + && mode.VisualSectorExists(level.sector)) + { + ((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true; + } + General.Map.Data.UpdateUsedTextures(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs index d2a27931..63f84177 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualLower.cs @@ -240,7 +240,8 @@ namespace CodeImp.DoomBuilder.BuilderModes if(polygons.Count > 0) { // Keep top and bottom planes for intersection testing - top = osd.Floor.plane; + Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's ceiling can be lower than the other sector's floor! + top = (osd.Floor.plane.GetZ(linecenter) < sd.Ceiling.plane.GetZ(linecenter) ? osd.Floor.plane : sd.Ceiling.plane); bottom = sd.Floor.plane; // Process the polygon and create vertices diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs index 5bb64635..a281d5f4 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualUpper.cs @@ -235,8 +235,9 @@ namespace CodeImp.DoomBuilder.BuilderModes if(polygons.Count > 0) { // Keep top and bottom planes for intersection testing + Vector2D linecenter = Sidedef.Line.GetCenterPoint(); //mxd. Our sector's floor can be higher than the other sector's ceiling! top = sd.Ceiling.plane; - bottom = osd.Ceiling.plane; + bottom = (osd.Ceiling.plane.GetZ(linecenter) > sd.Floor.plane.GetZ(linecenter) ? osd.Ceiling.plane : sd.Floor.plane); // Process the polygon and create vertices List<WorldVertex> verts = CreatePolygonVertices(polygons, tp, sd, lightvalue, lightabsolute); diff --git a/Source/Plugins/NodesViewer/NodesViewerMode.cs b/Source/Plugins/NodesViewer/NodesViewerMode.cs index 1552d97a..45f89e50 100644 --- a/Source/Plugins/NodesViewer/NodesViewerMode.cs +++ b/Source/Plugins/NodesViewer/NodesViewerMode.cs @@ -244,7 +244,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer nodesformat = new string(reader.ReadChars(4)); if(!supportedFormats.Contains(nodesformat)) { - MessageBox.Show("'" + nodesformat + "' node format is not supported.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error); + MessageBox.Show("\"" + nodesformat + "\" node format is not supported.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } diff --git a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs index 8ccaab4d..db2b9e84 100644 --- a/Source/Plugins/TagExplorer/Controls/TagExplorer.cs +++ b/Source/Plugins/TagExplorer/Controls/TagExplorer.cs @@ -655,7 +655,7 @@ namespace CodeImp.DoomBuilder.TagExplorer break; default: - throw new NotImplementedException("Tag Explorer: Sort mode '" + sortMode + "' is not implemented!"); + throw new NotImplementedException("Tag Explorer: Sort mode \"" + sortMode + "\" is not implemented!"); } } diff --git a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs index 783d25a3..b379f2d5 100644 --- a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs +++ b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs @@ -260,7 +260,14 @@ namespace CodeImp.DoomBuilder.Plugins.VisplaneExplorer // Export the current map to a temporary WAD file tempfile = BuilderPlug.MakeTempFilename(".wad"); - General.Map.ExportToFile(tempfile); + if(!General.Map.ExportToFile(tempfile)) + { + //mxd. Abort on export fail + Cursor.Current = Cursors.Default; + General.Interface.DisplayStatus(StatusType.Warning, "Unable to set test environment..."); + OnCancel(); + return; + } // Load the map in VPO_DLL BuilderPlug.VPO.Start(tempfile, General.Map.Options.LevelName); -- GitLab