editors.pas 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754
  1. unit Editors;
  2. {$i platform.inc}
  3. {$ifdef PPC_FPC}
  4. {$H-}
  5. {$else}
  6. {$F+,O+,E+,N+}
  7. {$endif}
  8. {$X+,R-,I-,Q-,V-}
  9. {$ifndef OS_UNIX}
  10. {$S-}
  11. {$endif}
  12. {$define UNIXLF}
  13. interface
  14. uses
  15. Objects, Drivers,Views,Dialogs,FVCommon,FVConsts;
  16. const
  17. { Length constants. }
  18. Tab_Stop_Length = 74;
  19. {$ifdef PPC_BP}
  20. MaxLineLength = 1024;
  21. MinBufLength = $1000;
  22. MaxBufLength = $ff00;
  23. NotFoundValue = $ffff;
  24. LineInfoGrow = 256;
  25. MaxLines = 16000;
  26. {$else}
  27. MaxLineLength = 4096;
  28. MinBufLength = $1000;
  29. MaxBufLength = $7fffff00;
  30. NotFoundValue = $ffffffff;
  31. LineInfoGrow = 1024;
  32. MaxLines = $7ffffff;
  33. {$endif}
  34. { Editor constants for dialog boxes. }
  35. edOutOfMemory = 0;
  36. edReadError = 1;
  37. edWriteError = 2;
  38. edCreateError = 3;
  39. edSaveModify = 4;
  40. edSaveUntitled = 5;
  41. edSaveAs = 6;
  42. edFind = 7;
  43. edSearchFailed = 8;
  44. edReplace = 9;
  45. edReplacePrompt = 10;
  46. edJumpToLine = 11;
  47. edPasteNotPossible = 12;
  48. edReformatDocument = 13;
  49. edReformatNotAllowed = 14;
  50. edReformNotPossible = 15;
  51. edReplaceNotPossible = 16;
  52. edRightMargin = 17;
  53. edSetTabStops = 18;
  54. edWrapNotPossible = 19;
  55. { Editor flag constants for dialog options. }
  56. efCaseSensitive = $0001;
  57. efWholeWordsOnly = $0002;
  58. efPromptOnReplace = $0004;
  59. efReplaceAll = $0008;
  60. efDoReplace = $0010;
  61. efBackupFiles = $0100;
  62. { Constants for object palettes. }
  63. CIndicator = #2#3;
  64. CEditor = #6#7;
  65. CMemo = #26#27;
  66. type
  67. TEditorDialog = function (Dialog : Integer; Info : Pointer) : Word;
  68. PIndicator = ^TIndicator;
  69. TIndicator = object (TView)
  70. Location : Objects.TPoint;
  71. Modified : Boolean;
  72. AutoIndent : Boolean; { Added boolean for AutoIndent mode. }
  73. WordWrap : Boolean; { Added boolean for WordWrap mode. }
  74. constructor Init (var Bounds : TRect);
  75. procedure Draw; virtual;
  76. function GetPalette : PPalette; virtual;
  77. procedure SetState (AState : Word; Enable : Boolean); virtual;
  78. procedure SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
  79. IsModified : Boolean;
  80. IsWordWrap : Boolean);
  81. end;
  82. TLineInfoRec = record
  83. Len,Attr : Sw_word;
  84. end;
  85. TLineInfoArr = array[0..MaxLines] of TLineInfoRec;
  86. PLineInfoArr = ^TLineInfoArr;
  87. PLineInfo = ^TLineInfo;
  88. TLineInfo = object
  89. Info : PLineInfoArr;
  90. MaxPos : Sw_Word;
  91. constructor Init;
  92. destructor Done;
  93. procedure Grow(pos:Sw_word);
  94. procedure SetLen(pos,val:Sw_Word);
  95. procedure SetAttr(pos,val:Sw_Word);
  96. function GetLen(pos:Sw_Word):Sw_Word;
  97. function GetAttr(pos:Sw_Word):Sw_Word;
  98. end;
  99. PEditBuffer = ^TEditBuffer;
  100. TEditBuffer = array[0..MaxBufLength] of Char;
  101. PEditor = ^TEditor;
  102. TEditor = object (TView)
  103. HScrollBar : PScrollBar;
  104. VScrollBar : PScrollBar;
  105. Indicator : PIndicator;
  106. Buffer : PEditBuffer;
  107. BufSize : Sw_Word;
  108. BufLen : Sw_Word;
  109. GapLen : Sw_Word;
  110. SelStart : Sw_Word;
  111. SelEnd : Sw_Word;
  112. CurPtr : Sw_Word;
  113. CurPos : Objects.TPoint;
  114. Delta : Objects.TPoint;
  115. Limit : Objects.TPoint;
  116. DrawLine : Sw_Integer;
  117. DrawPtr : Sw_Word;
  118. DelCount : Sw_Word;
  119. InsCount : Sw_Word;
  120. Flags : Longint;
  121. IsReadOnly : Boolean;
  122. IsValid : Boolean;
  123. CanUndo : Boolean;
  124. Modified : Boolean;
  125. Selecting : Boolean;
  126. Overwrite : Boolean;
  127. AutoIndent : Boolean;
  128. NoSelect : Boolean;
  129. TabSize : Sw_Word; { tabsize for displaying }
  130. BlankLine : Sw_Word; { First blank line after a paragraph. }
  131. Word_Wrap : Boolean; { Added boolean to toggle wordwrap on/off. }
  132. Line_Number : string[8]; { Holds line number to jump to. }
  133. Right_Margin : Sw_Integer; { Added integer to set right margin. }
  134. Tab_Settings : String[Tab_Stop_Length]; { Added string to hold tab stops. }
  135. constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
  136. AIndicator : PIndicator; ABufSize : Sw_Word);
  137. constructor Load (var S : Objects.TStream);
  138. destructor Done; virtual;
  139. function BufChar (P : Sw_Word) : Char;
  140. function BufPtr (P : Sw_Word) : Sw_Word;
  141. procedure ChangeBounds (var Bounds : TRect); virtual;
  142. procedure ConvertEvent (var Event : Drivers.TEvent); virtual;
  143. function CursorVisible : Boolean;
  144. procedure DeleteSelect;
  145. procedure DoneBuffer; virtual;
  146. procedure Draw; virtual;
  147. procedure FormatLine (var DrawBuf; LinePtr : Sw_Word; Width : Sw_Integer; Colors : Word);virtual;
  148. function GetPalette : PPalette; virtual;
  149. procedure HandleEvent (var Event : Drivers.TEvent); virtual;
  150. procedure InitBuffer; virtual;
  151. function InsertBuffer (var P : PEditBuffer; Offset, Length : Sw_Word;AllowUndo, SelectText : Boolean) : Boolean;
  152. function InsertFrom (Editor : PEditor) : Boolean; virtual;
  153. function InsertText (Text : Pointer; Length : Sw_Word; SelectText : Boolean) : Boolean;
  154. procedure ScrollTo (X, Y : Sw_Integer);
  155. function Search (const FindStr : String; Opts : Word) : Boolean;
  156. function SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
  157. procedure SetCmdState (Command : Word; Enable : Boolean);
  158. procedure SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
  159. procedure SetCurPtr (P : Sw_Word; SelectMode : Byte);
  160. procedure SetState (AState : Word; Enable : Boolean); virtual;
  161. procedure Store (var S : Objects.TStream);
  162. procedure TrackCursor (Center : Boolean);
  163. procedure Undo;
  164. procedure UpdateCommands; virtual;
  165. function Valid (Command : Word) : Boolean; virtual;
  166. private
  167. KeyState : Integer;
  168. LockCount : Byte;
  169. UpdateFlags : Byte;
  170. Place_Marker : Array [1..10] of Sw_Word; { Inserted array to hold place markers. }
  171. Search_Replace : Boolean; { Added boolean to test for Search and Replace insertions. }
  172. procedure Center_Text (Select_Mode : Byte);
  173. function CharPos (P, Target : Sw_Word) : Sw_Integer;
  174. function CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
  175. procedure Check_For_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean);
  176. function ClipCopy : Boolean;
  177. procedure ClipCut;
  178. procedure ClipPaste;
  179. procedure DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
  180. procedure DoSearchReplace;
  181. procedure DoUpdate;
  182. function Do_Word_Wrap (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
  183. procedure DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
  184. procedure Find;
  185. function GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
  186. function HasSelection : Boolean;
  187. procedure HideSelect;
  188. procedure Insert_Line (Select_Mode : Byte);
  189. function IsClipboard : Boolean;
  190. procedure Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
  191. procedure Jump_To_Line (Select_Mode : Byte);
  192. function LineEnd (P : Sw_Word) : Sw_Word;
  193. function LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
  194. function LineStart (P : Sw_Word) : Sw_Word;
  195. function LineNr (P : Sw_Word) : Sw_Word;
  196. procedure Lock;
  197. function NewLine (Select_Mode : Byte) : Boolean;
  198. function NextChar (P : Sw_Word) : Sw_Word;
  199. function NextLine (P : Sw_Word) : Sw_Word;
  200. function NextWord (P : Sw_Word) : Sw_Word;
  201. function PrevChar (P : Sw_Word) : Sw_Word;
  202. function PrevLine (P : Sw_Word) : Sw_Word;
  203. function PrevWord (P : Sw_Word) : Sw_Word;
  204. procedure Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
  205. function Reformat_Paragraph (Select_Mode : Byte; Center_Cursor : Boolean) : Boolean;
  206. procedure Remove_EOL_Spaces (Select_Mode : Byte);
  207. procedure Replace;
  208. procedure Scroll_Down;
  209. procedure Scroll_Up;
  210. procedure Select_Word;
  211. procedure SetBufLen (Length : Sw_Word);
  212. procedure Set_Place_Marker (Element : Byte);
  213. procedure Set_Right_Margin;
  214. procedure Set_Tabs;
  215. procedure StartSelect;
  216. procedure Tab_Key (Select_Mode : Byte);
  217. procedure ToggleInsMode;
  218. procedure Unlock;
  219. procedure Update (AFlags : Byte);
  220. procedure Update_Place_Markers (AddCount : Word; KillCount : Word; StartPtr,EndPtr : Sw_Word);
  221. end;
  222. TMemoData = record
  223. Length : Sw_Word;
  224. Buffer : TEditBuffer;
  225. end;
  226. PMemo = ^TMemo;
  227. TMemo = object (TEditor)
  228. constructor Load (var S : Objects.TStream);
  229. function DataSize : Sw_Word; virtual;
  230. procedure GetData (var Rec); virtual;
  231. function GetPalette : PPalette; virtual;
  232. procedure HandleEvent (var Event : Drivers.TEvent); virtual;
  233. procedure SetData (var Rec); virtual;
  234. procedure Store (var S : Objects.TStream);
  235. end;
  236. PFileEditor = ^TFileEditor;
  237. TFileEditor = object (TEditor)
  238. FileName : FNameStr;
  239. constructor Init (var Bounds : TRect; AHScrollBar, AVScrollBar : PScrollBar;
  240. AIndicator : PIndicator; AFileName : FNameStr);
  241. constructor Load (var S : Objects.TStream);
  242. procedure DoneBuffer; virtual;
  243. procedure HandleEvent (var Event : Drivers.TEvent); virtual;
  244. procedure InitBuffer; virtual;
  245. function LoadFile : Boolean;
  246. function Save : Boolean;
  247. function SaveAs : Boolean;
  248. function SaveFile : Boolean;
  249. function SetBufSize (NewSize : Sw_Word) : Boolean; virtual;
  250. procedure Store (var S : Objects.TStream);
  251. procedure UpdateCommands; virtual;
  252. function Valid (Command : Word) : Boolean; virtual;
  253. end;
  254. PEditWindow = ^TEditWindow;
  255. TEditWindow = object (TWindow)
  256. Editor : PFileEditor;
  257. constructor Init (var Bounds : TRect; FileName : FNameStr; ANumber : Integer);
  258. constructor Load (var S : Objects.TStream);
  259. procedure Close; virtual;
  260. function GetTitle (MaxSize : Sw_Integer) : TTitleStr; virtual;
  261. procedure HandleEvent (var Event : Drivers.TEvent); virtual;
  262. procedure SizeLimits(var Min, Max: TPoint); virtual;
  263. procedure Store (var S : Objects.TStream);
  264. end;
  265. function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
  266. function CreateFindDialog: PDialog;
  267. function CreateReplaceDialog: PDialog;
  268. function JumpLineDialog : PDialog;
  269. function ReformDocDialog : PDialog;
  270. function RightMarginDialog : PDialog;
  271. function TabStopDialog : Dialogs.PDialog;
  272. function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
  273. const
  274. WordChars : set of Char = ['!'..#255];
  275. LineBreak : string[2]=
  276. {$ifdef UNIXLF}
  277. #10;
  278. {$else}
  279. #13#10;
  280. {$endif}
  281. { The Allow_Reformat boolean is a programmer hook. }
  282. { I've placed this here to allow programmers to }
  283. { determine whether or not paragraph and document }
  284. { reformatting are allowed if Word_Wrap is not }
  285. { active. Some people say don't allow, and others }
  286. { say allow it. I've left it up to the programmer. }
  287. { Set to FALSE if not allowed, or TRUE if allowed. }
  288. Allow_Reformat : Boolean = True;
  289. EditorDialog : TEditorDialog = {$ifdef fpc}@{$endif}DefEditorDialog;
  290. EditorFlags : Word = efBackupFiles + efPromptOnReplace;
  291. FindStr : String[80] = '';
  292. ReplaceStr : String[80] = '';
  293. Clipboard : PEditor = nil;
  294. ToClipCmds : TCommandSet = ([cmCut,cmCopy,cmClear]);
  295. FromClipCmds : TCommandSet = ([cmPaste]);
  296. UndoCmds : TCommandSet = ([cmUndo,cmRedo]);
  297. TYPE
  298. TFindDialogRec =
  299. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  300. packed
  301. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  302. record
  303. Find : String[80];
  304. Options : Word;
  305. end;
  306. TReplaceDialogRec =
  307. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  308. packed
  309. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  310. record
  311. Find : String[80];
  312. Replace : String[80];
  313. Options : Word;
  314. end;
  315. TRightMarginRec =
  316. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  317. packed
  318. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  319. record
  320. Margin_Position : String[3];
  321. end;
  322. TTabStopRec =
  323. {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}
  324. packed
  325. {$endif FPC_REQUIRES_PROPER_ALIGNMENT}
  326. record
  327. Tab_String : String [Tab_Stop_Length];
  328. end;
  329. CONST
  330. { VMT constants. }
  331. REditor : TStreamRec = (ObjType : 70;
  332. VmtLink : Ofs (TypeOf (TEditor)^);
  333. Load : @TEditor.Load;
  334. Store : @TEditor.Store);
  335. RMemo : TStreamRec = (ObjType : 71;
  336. VmtLink : Ofs (TypeOf (TMemo)^);
  337. Load : @TMemo.Load;
  338. Store : @TMemo.Store);
  339. RFileEditor : TStreamRec = (ObjType : 72;
  340. VmtLink : Ofs (TypeOf (TFileEditor)^);
  341. Load : @TFileEditor.Load;
  342. Store : @TFileEditor.Store);
  343. RIndicator : TStreamRec = (ObjType : 73;
  344. VmtLink : Ofs (TypeOf (TIndicator)^);
  345. Load : @TIndicator.Load;
  346. Store : @TIndicator.Store);
  347. REditWindow : TStreamRec = (ObjType : 74;
  348. VmtLink : Ofs (TypeOf (TEditWindow)^);
  349. Load : @TEditWindow.Load;
  350. Store : @TEditWindow.Store);
  351. procedure RegisterEditors;
  352. {****************************************************************************
  353. Implementation
  354. ****************************************************************************}
  355. implementation
  356. uses
  357. Dos, App, StdDlg, MsgBox, Resource;
  358. type
  359. pword = ^word;
  360. CONST
  361. { Update flag constants. }
  362. ufUpdate = $01;
  363. ufLine = $02;
  364. ufView = $04;
  365. ufStats = $05;
  366. { SelectMode constants. }
  367. smExtend = $01;
  368. smDouble = $02;
  369. sfSearchFailed = NotFoundValue;
  370. { Arrays that hold all the command keys and options. }
  371. FirstKeys : array[0..46 * 2] of Word = (46, Ord (^A), cmWordLeft,
  372. Ord (^B), cmReformPara,
  373. Ord (^C), cmPageDown,
  374. Ord (^D), cmCharRight,
  375. Ord (^E), cmLineUp,
  376. Ord (^F), cmWordRight,
  377. Ord (^G), cmDelChar,
  378. Ord (^H), cmBackSpace,
  379. Ord (^I), cmTabKey,
  380. Ord (^J), $FF04,
  381. Ord (^K), $FF02,
  382. Ord (^L), cmSearchAgain,
  383. Ord (^M), cmNewLine,
  384. Ord (^N), cmInsertLine,
  385. Ord (^O), $FF03,
  386. Ord (^Q), $FF01,
  387. Ord (^R), cmPageUp,
  388. Ord (^S), cmCharLeft,
  389. Ord (^T), cmDelWord,
  390. Ord (^U), cmUndo,
  391. Ord (^V), cmInsMode,
  392. Ord (^W), cmScrollUp,
  393. Ord (^X), cmLineDown,
  394. Ord (^Y), cmDelLine,
  395. Ord (^Z), cmScrollDown,
  396. kbLeft, cmCharLeft,
  397. kbRight, cmCharRight,
  398. kbCtrlLeft, cmWordLeft,
  399. kbCtrlRight, cmWordRight,
  400. kbHome, cmLineStart,
  401. kbEnd, cmLineEnd,
  402. kbCtrlHome, cmHomePage,
  403. kbCtrlEnd, cmEndPage,
  404. kbUp, cmLineUp,
  405. kbDown, cmLineDown,
  406. kbPgUp, cmPageUp,
  407. kbPgDn, cmPageDown,
  408. kbCtrlPgUp, cmTextStart,
  409. kbCtrlPgDn, cmTextEnd,
  410. kbIns, cmInsMode,
  411. kbDel, cmDelChar,
  412. kbCtrlBack, cmDelStart,
  413. kbShiftIns, cmPaste,
  414. kbShiftDel, cmCut,
  415. kbCtrlIns, cmCopy,
  416. kbCtrlDel, cmClear);
  417. { SCRLUP - Stop. } { Added ^W to scroll screen up. }
  418. { SCRLDN - Stop. } { Added ^Z to scroll screen down. }
  419. { REFORM - Stop. } { Added ^B for paragraph reformatting. }
  420. { PRETAB - Stop. } { Added ^I for preset tabbing. }
  421. { JLINE - Stop. } { Added ^J to jump to a line number. }
  422. { INSLIN - Stop. } { Added ^N to insert line at cursor. }
  423. { INDENT - Stop. } { Removed ^O and put it into ^QI. }
  424. { HOMEND - Stop. } { Added kbCtrlHome and kbCtrlEnd pages. }
  425. { CTRLBK - Stop. } { Added kbCtrlBack same as ^QH. }
  426. QuickKeys : array[0..21 * 2] of Word = (21, Ord ('0'), cmJumpMark0,
  427. Ord ('1'), cmJumpMark1,
  428. Ord ('2'), cmJumpMark2,
  429. Ord ('3'), cmJumpMark3,
  430. Ord ('4'), cmJumpMark4,
  431. Ord ('5'), cmJumpMark5,
  432. Ord ('6'), cmJumpMark6,
  433. Ord ('7'), cmJumpMark7,
  434. Ord ('8'), cmJumpMark8,
  435. Ord ('9'), cmJumpMark9,
  436. Ord ('A'), cmReplace,
  437. Ord ('C'), cmTextEnd,
  438. Ord ('D'), cmLineEnd,
  439. Ord ('F'), cmFind,
  440. Ord ('H'), cmDelStart,
  441. Ord ('I'), cmIndentMode,
  442. Ord ('L'), cmUndo,
  443. Ord ('R'), cmTextStart,
  444. Ord ('S'), cmLineStart,
  445. Ord ('U'), cmReformDoc,
  446. Ord ('Y'), cmDelEnd);
  447. { UNDO - Stop. } { Added IDE undo feature of ^QL. }
  448. { REFDOC - Stop. } { Added document reformat feature if ^QU pressed. }
  449. { MARK - Stop. } { Added cmJumpMark# to allow place marking. }
  450. { INDENT - Stop. } { Moved IndentMode here from Firstkeys. }
  451. BlockKeys : array[0..20 * 2] of Word = (20, Ord ('0'), cmSetMark0,
  452. Ord ('1'), cmSetMark1,
  453. Ord ('2'), cmSetMark2,
  454. Ord ('3'), cmSetMark3,
  455. Ord ('4'), cmSetMark4,
  456. Ord ('5'), cmSetMark5,
  457. Ord ('6'), cmSetMark6,
  458. Ord ('7'), cmSetMark7,
  459. Ord ('8'), cmSetMark8,
  460. Ord ('9'), cmSetMark9,
  461. Ord ('B'), cmStartSelect,
  462. Ord ('C'), cmPaste,
  463. Ord ('D'), cmSave,
  464. Ord ('F'), cmSaveAs,
  465. Ord ('H'), cmHideSelect,
  466. Ord ('K'), cmCopy,
  467. Ord ('S'), cmSave,
  468. Ord ('T'), cmSelectWord,
  469. Ord ('Y'), cmCut,
  470. Ord ('X'), cmSaveDone);
  471. { SELWRD - Stop. } { Added ^KT to select word only. }
  472. { SAVE - Stop. } { Added ^KD, ^KF, ^KS, ^KX key commands. }
  473. { MARK - Stop. } { Added cmSetMark# to allow place marking. }
  474. FormatKeys : array[0..5 * 2] of Word = (5, Ord ('C'), cmCenterText,
  475. Ord ('T'), cmCenterText,
  476. Ord ('I'), cmSetTabs,
  477. Ord ('R'), cmRightMargin,
  478. Ord ('W'), cmWordWrap);
  479. { WRAP - Stop. } { Added Wordwrap feature if ^OW pressed. }
  480. { RMSET - Stop. } { Added set right margin feature if ^OR pressed. }
  481. { PRETAB - Stop. } { Added preset tab feature if ^OI pressed. }
  482. { CENTER - Stop. } { Added center text option ^OC for a line. }
  483. JumpKeys : array[0..1 * 2] of Word = (1, Ord ('L'), cmJumpLine);
  484. { JLINE - Stop. } { Added jump to line number feature if ^JL pressed. }
  485. KeyMap : array[0..4] of Pointer = (@FirstKeys,
  486. @QuickKeys,
  487. @BlockKeys,
  488. @FormatKeys,
  489. @JumpKeys);
  490. { WRAP - Stop. } { Added @FormatKeys for new ^O? keys. }
  491. { PRETAB - Stop. } { Added @FormatKeys for new ^O? keys. }
  492. { JLINE - Stop. } { Added @JumpKeys for new ^J? keys. }
  493. { CENTER - Stop. } { Added @FormatKeys for new ^O? keys. }
  494. {****************************************************************************
  495. Dialogs
  496. ****************************************************************************}
  497. function DefEditorDialog (Dialog : Integer; Info : Pointer) : Word;
  498. begin
  499. DefEditorDialog := cmCancel;
  500. end; { DefEditorDialog }
  501. function CreateFindDialog: PDialog;
  502. var
  503. D: PDialog;
  504. Control: PView;
  505. R: TRect;
  506. begin
  507. R.Assign(0, 0, 38, 12);
  508. D := New(PDialog, Init(R, strings^.get(sFind)));
  509. with D^ do
  510. begin
  511. Options := Options or ofCentered;
  512. R.Assign(3, 3, 32, 4);
  513. Control := New(PInputLine, Init(R, 80));
  514. Control^.HelpCtx := hcDFindText;
  515. Insert(Control);
  516. R.Assign(2, 2, 15, 3);
  517. Insert(New(PLabel, Init(R, labels^.get(slTextToFind), Control)));
  518. R.Assign(32, 3, 35, 4);
  519. Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  520. R.Assign(3, 5, 35, 7);
  521. Control := New(PCheckBoxes, Init(R,
  522. NewSItem (labels^.get(slCaseSensitive),
  523. NewSItem (labels^.get(slWholeWordsOnly),nil))));
  524. Control^.HelpCtx := hcCCaseSensitive;
  525. Insert(Control);
  526. R.Assign(14, 9, 24, 11);
  527. Control := New (PButton, Init(R,labels^.get(slOK),cmOk,bfDefault));
  528. Control^.HelpCtx := hcDOk;
  529. Insert (Control);
  530. Inc(R.A.X, 12); Inc(R.B.X, 12);
  531. Control := New (PButton, Init(R,labels^.get(slCancel),cmCancel, bfNormal));
  532. Control^.HelpCtx := hcDCancel;
  533. Insert (Control);
  534. SelectNext(False);
  535. end;
  536. CreateFindDialog := D;
  537. end;
  538. function CreateReplaceDialog: PDialog;
  539. var
  540. D: PDialog;
  541. Control: PView;
  542. R: TRect;
  543. begin
  544. R.Assign(0, 0, 40, 16);
  545. D := New(PDialog, Init(R,labels^.get(slReplace)));
  546. with D^ do
  547. begin
  548. Options := Options or ofCentered;
  549. R.Assign(3, 3, 34, 4);
  550. Control := New(PInputLine, Init(R, 80));
  551. Control^.HelpCtx := hcDFindText;
  552. Insert(Control);
  553. R.Assign(2, 2, 15, 3);
  554. Insert(New(PLabel, Init(R,labels^.get(slTextToFind), Control)));
  555. R.Assign(34, 3, 37, 4);
  556. Insert(New(PHistory, Init(R, PInputLine(Control), 10)));
  557. R.Assign(3, 6, 34, 7);
  558. Control := New(PInputLine, Init(R, 80));
  559. Control^.HelpCtx := hcDReplaceText;
  560. Insert(Control);
  561. R.Assign(2, 5, 12, 6);
  562. Insert(New(PLabel, Init(R,labels^.get(slNewText), Control)));
  563. R.Assign(34, 6, 37, 7);
  564. Insert(New(PHistory, Init(R, PInputLine(Control), 11)));
  565. R.Assign(3, 8, 37, 12);
  566. Control := New (Dialogs.PCheckBoxes, Init (R,
  567. NewSItem (labels^.get(slCasesensitive),
  568. NewSItem (labels^.get(slWholewordsonly),
  569. NewSItem (labels^.get(slPromptonreplace),
  570. NewSItem (labels^.get(slReplaceall), nil))))));
  571. Control^.HelpCtx := hcCCaseSensitive;
  572. Insert (Control);
  573. R.Assign (8, 13, 18, 15);
  574. Control := New (PButton, Init (R,labels^.get(slOK), cmOk, bfDefault));
  575. Control^.HelpCtx := hcDOk;
  576. Insert (Control);
  577. R.Assign (22, 13, 32, 15);
  578. Control := New (PButton, Init (R,labels^.get(slCancel), cmCancel, bfNormal));
  579. Control^.HelpCtx := hcDCancel;
  580. Insert (Control);
  581. SelectNext(False);
  582. end;
  583. CreateReplaceDialog := D;
  584. end;
  585. function JumpLineDialog : PDialog;
  586. VAR
  587. D : PDialog;
  588. R : TRect;
  589. Control: PView;
  590. Begin
  591. R.Assign (0, 0, 26, 8);
  592. D := New(PDialog, Init(R,strings^.get(sJumpTo)));
  593. with D^ do
  594. begin
  595. Options := Options or ofCentered;
  596. R.Assign (3, 2, 15, 3);
  597. Control := New (Dialogs.PStaticText, Init (R,labels^.get(slLineNumber)));
  598. Insert (Control);
  599. R.Assign (15, 2, 21, 3);
  600. Control := New (Dialogs.PInputLine, Init (R, 4));
  601. Control^.HelpCtx := hcDLineNumber;
  602. Insert (Control);
  603. R.Assign (21, 2, 24, 3);
  604. Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 12)));
  605. R.Assign (2, 5, 12, 7);
  606. Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
  607. Control^.HelpCtx := hcDOk;
  608. Insert (Control);
  609. R.Assign (14, 5, 24, 7);
  610. Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
  611. Control^.HelpCtx := hcDCancel;
  612. Insert (Control);
  613. SelectNext (False);
  614. end;
  615. JumpLineDialog := D;
  616. end; { JumpLineDialog }
  617. function ReformDocDialog : Dialogs.PDialog;
  618. { This is a local function that brings up a dialog box }
  619. { that asks where to start reformatting the document. }
  620. VAR
  621. R : TRect;
  622. D : Dialogs.PDialog;
  623. Control : PView;
  624. Begin
  625. R.Assign (0, 0, 32, 11);
  626. D := New (Dialogs.PDialog, Init (R, strings^.get(sReformatDocument)));
  627. with D^ do
  628. begin
  629. Options := Options or ofCentered;
  630. R.Assign (2, 2, 30, 3);
  631. Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSelectWhereToBegin)));
  632. Insert (Control);
  633. R.Assign (3, 3, 29, 4);
  634. Control := New (Dialogs.PStaticText, Init (R, strings^.get(sReformattingTheDocument)));
  635. Insert (Control);
  636. R.Assign (50, 5, 68, 6);
  637. Control := New (Dialogs.PLabel, Init (R, strings^.get(sReformatDocument), Control));
  638. Insert (Control);
  639. R.Assign (5, 5, 26, 7);
  640. Control := New (Dialogs.PRadioButtons, Init (R,
  641. NewSItem (labels^.get(slCurrentLine),
  642. NewSItem (labels^.get(slEntireDocument), Nil))));
  643. Control^.HelpCtx := hcDReformDoc;
  644. Insert (Control);
  645. R.Assign (4, 8, 14, 10);
  646. Control := New (Dialogs.PButton, Init (R,labels^.get(slOK), cmOK, Dialogs.bfDefault));
  647. Control^.HelpCtx := hcDOk;
  648. Insert (Control);
  649. R.Assign (17, 8, 27, 10);
  650. Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
  651. Control^.HelpCtx := hcDCancel;
  652. Insert (Control);
  653. SelectNext (False);
  654. end;
  655. ReformDocDialog := D;
  656. end; { ReformDocDialog }
  657. function RightMarginDialog : Dialogs.PDialog;
  658. { This is a local function that brings up a dialog box }
  659. { that allows the user to change the Right_Margin. }
  660. VAR
  661. R : TRect;
  662. D : PDialog;
  663. Control : PView;
  664. Begin
  665. R.Assign (0, 0, 26, 8);
  666. D := New (Dialogs.PDialog, Init (R, strings^.get(sRightMargin)));
  667. with D^ do
  668. begin
  669. Options := Options or ofCentered;
  670. R.Assign (5, 2, 13, 3);
  671. Control := New (Dialogs.PStaticText, Init (R, strings^.get(sSetting)));
  672. Insert (Control);
  673. R.Assign (13, 2, 18, 3);
  674. Control := New (Dialogs.PInputLine, Init (R, 3));
  675. Control^.HelpCtx := hcDRightMargin;
  676. Insert (Control);
  677. R.Assign (18, 2, 21, 3);
  678. Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 13)));
  679. R.Assign (2, 5, 12, 7);
  680. Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
  681. Control^.HelpCtx := hcDOk;
  682. Insert (Control);
  683. R.Assign (14, 5, 24, 7);
  684. Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
  685. Control^.HelpCtx := hcDCancel;
  686. Insert (Control);
  687. SelectNext (False);
  688. end;
  689. RightMarginDialog := D;
  690. end; { RightMarginDialog; }
  691. function TabStopDialog : Dialogs.PDialog;
  692. { This is a local function that brings up a dialog box }
  693. { that allows the user to set their own tab stops. }
  694. VAR
  695. Index : Sw_Integer; { Local Indexing variable. }
  696. R : TRect;
  697. D : PDialog;
  698. Control : PView;
  699. Tab_Stop : String[2]; { Local string to print tab column number. }
  700. Begin
  701. R.Assign (0, 0, 80, 8);
  702. D := New (Dialogs.PDialog, Init (R, strings^.get(sTabSettings)));
  703. with D^ do
  704. begin
  705. Options := Options or ofCentered;
  706. R.Assign (2, 2, 77, 3);
  707. Control := New (Dialogs.PStaticText, Init (R,
  708. ' ....|....|....|....|....|....|....|....|....|....|....|....|....|....|....'));
  709. Insert (Control);
  710. for Index := 1 to 7 do
  711. begin
  712. R.Assign (Index * 10 + 1, 1, Index * 10 + 3, 2);
  713. Str (Index * 10, Tab_Stop);
  714. Control := New (Dialogs.PStaticText, Init (R, Tab_Stop));
  715. Insert (Control);
  716. end;
  717. R.Assign (2, 3, 78, 4);
  718. Control := New (Dialogs.PInputLine, Init (R, 74));
  719. Control^.HelpCtx := hcDTabStops;
  720. Insert (Control);
  721. R.Assign (38, 5, 41, 6);
  722. Insert (New (Dialogs.PHistory, Init (R, Dialogs.PInputLine (Control), 14)));
  723. R.Assign (27, 5, 37, 7);
  724. Control := New (Dialogs.PButton, Init (R, labels^.get(slOK), cmOK, Dialogs.bfDefault));
  725. Control^.HelpCtx := hcDOk;
  726. Insert (Control);
  727. R.Assign (42, 5, 52, 7);
  728. Control := New (Dialogs.PButton, Init (R, labels^.get(slCancel), cmCancel, Dialogs.bfNormal));
  729. Control^.HelpCtx := hcDCancel;
  730. Insert (Control);
  731. SelectNext (False);
  732. end;
  733. TabStopDialog := D;
  734. end { TabStopDialog };
  735. function StdEditorDialog(Dialog: Integer; Info: Pointer): Word;
  736. var
  737. R: TRect;
  738. T: TPoint;
  739. begin
  740. case Dialog of
  741. edOutOfMemory:
  742. StdEditorDialog := MessageBox(strings^.get(sOutOfMemory), nil, mfError + mfOkButton);
  743. edReadError:
  744. StdEditorDialog := MessageBox(strings^.get(sFileReadError), @Info, mfError + mfOkButton);
  745. edWriteError:
  746. StdEditorDialog := MessageBox(strings^.get(sFileWriteError), @Info, mfError + mfOkButton);
  747. edCreateError:
  748. StdEditorDialog := MessageBox(strings^.get(sFileCreateError), @Info, mfError + mfOkButton);
  749. edSaveModify:
  750. StdEditorDialog := MessageBox(strings^.get(sModified), @Info, mfInformation + mfYesNoCancel);
  751. edSaveUntitled:
  752. StdEditorDialog := MessageBox(strings^.get(sFileUntitled), nil, mfInformation + mfYesNoCancel);
  753. edSaveAs:
  754. StdEditorDialog := Application^.ExecuteDialog(New(PFileDialog, Init('*.*',
  755. labels^.get(slSaveFileAs), labels^.get(slName), fdOkButton, 101)), Info);
  756. edFind:
  757. StdEditorDialog := Application^.ExecuteDialog(CreateFindDialog, Info);
  758. edSearchFailed:
  759. StdEditorDialog := MessageBox(strings^.get(sSearchStringNotFound), nil, mfError + mfOkButton);
  760. edReplace:
  761. StdEditorDialog := Application^.ExecuteDialog(CreateReplaceDialog, Info);
  762. edReplacePrompt:
  763. begin
  764. { Avoid placing the dialog on the same line as the cursor }
  765. R.Assign(0, 1, 40, 8);
  766. R.Move((Desktop^.Size.X - R.B.X) div 2, 0);
  767. Desktop^.MakeGlobal(R.B, T);
  768. Inc(T.Y);
  769. if PPoint(Info)^.Y <= T.Y then
  770. R.Move(0, Desktop^.Size.Y - R.B.Y - 2);
  771. StdEditorDialog := MessageBoxRect(R, strings^.get(sReplaceThisOccurence),
  772. nil, mfYesNoCancel + mfInformation);
  773. end;
  774. edJumpToLine:
  775. StdEditorDialog := Application^.ExecuteDialog(JumpLineDialog, Info);
  776. edSetTabStops:
  777. StdEditorDialog := Application^.ExecuteDialog(TabStopDialog, Info);
  778. edPasteNotPossible:
  779. StdEditorDialog := MessageBox (strings^.get(sPasteNotPossible), nil, mfError + mfOkButton);
  780. edReformatDocument:
  781. StdEditorDialog := Application^.ExecuteDialog(ReformDocDialog, Info);
  782. edReformatNotAllowed:
  783. StdEditorDialog := MessageBox (strings^.get(sWordWrapOff), nil, mfError + mfOkButton);
  784. edReformNotPossible:
  785. StdEditorDialog := MessageBox (strings^.get(sReformatNotPossible), nil, mfError + mfOkButton);
  786. edReplaceNotPossible:
  787. StdEditorDialog := MessageBox (strings^.get(sReplaceNotPossible), nil, mfError + mfOkButton);
  788. edRightMargin:
  789. StdEditorDialog := Application^.ExecuteDialog(RightMarginDialog, Info);
  790. edWrapNotPossible:
  791. StdEditorDialog := MessageBox (strings^.get(sWordWrapNotPossible), nil, mfError + mfOKButton);
  792. else
  793. StdEditorDialog := MessageBox (strings^.get(sUnknownDialog), nil, mfError + mfOkButton);
  794. end;
  795. end;
  796. {****************************************************************************
  797. Helpers
  798. ****************************************************************************}
  799. function CountLines(var Buf; Count: sw_Word): sw_Integer;
  800. var
  801. p : pchar;
  802. lines : sw_word;
  803. begin
  804. p:=pchar(@buf);
  805. lines:=0;
  806. while (count>0) do
  807. begin
  808. if p^ in [#10,#13] then
  809. begin
  810. inc(lines);
  811. if ord((p+1)^)+ord(p^)=23 then
  812. begin
  813. inc(p);
  814. dec(count);
  815. if count=0 then
  816. break;
  817. end;
  818. end;
  819. inc(p);
  820. dec(count);
  821. end;
  822. CountLines:=Lines;
  823. end;
  824. procedure GetLimits(var Buf; Count: sw_Word;var lim:objects.TPoint);
  825. { Get the limits needed for Buf, its an extended version of countlines (lim.y),
  826. which also gets the maximum line length in lim.x }
  827. var
  828. p : pchar;
  829. len : sw_word;
  830. begin
  831. lim.x:=0;
  832. lim.y:=0;
  833. len:=0;
  834. p:=pchar(@buf);
  835. while (count>0) do
  836. begin
  837. if p^ in [#10,#13] then
  838. begin
  839. if len>lim.x then
  840. lim.x:=len;
  841. inc(lim.y);
  842. if ord((p+1)^)+ord(p^)=23 then
  843. begin
  844. inc(p);
  845. dec(count);
  846. end;
  847. len:=0;
  848. end
  849. else
  850. inc(len);
  851. inc(p);
  852. dec(count);
  853. end;
  854. end;
  855. function ScanKeyMap(KeyMap: Pointer; KeyCode: Word): Word;
  856. var
  857. p : pword;
  858. count : sw_word;
  859. begin
  860. p:=keymap;
  861. count:=p^;
  862. inc(p);
  863. while (count>0) do
  864. begin
  865. if (lo(p^)=lo(keycode)) and
  866. ((hi(p^)=0) or (hi(p^)=hi(keycode))) then
  867. begin
  868. inc(p);
  869. scankeymap:=p^;
  870. exit;
  871. end;
  872. inc(p,2);
  873. dec(count);
  874. end;
  875. scankeymap:=0;
  876. end;
  877. Type
  878. Btable = Array[0..255] of Byte;
  879. Procedure BMMakeTable(const s:string; Var t : Btable);
  880. { Makes a Boyer-Moore search table. s = the search String t = the table }
  881. Var
  882. x : sw_integer;
  883. begin
  884. FillChar(t,sizeof(t),length(s));
  885. For x := length(s) downto 1 do
  886. if (t[ord(s[x])] = length(s)) then
  887. t[ord(s[x])] := length(s) - x;
  888. end;
  889. function Scan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
  890. Var
  891. buffer : Array[0..MaxBufLength-1] of Byte Absolute block;
  892. s2 : String;
  893. len,
  894. numb : Sw_Word;
  895. found : Boolean;
  896. bt : Btable;
  897. begin
  898. BMMakeTable(str,bt);
  899. len:=length(str);
  900. s2[0]:=chr(len); { sets the length to that of the search String }
  901. found:=False;
  902. numb:=pred(len);
  903. While (not found) and (numb<(size-len)) do
  904. begin
  905. { partial match }
  906. if buffer[numb] = ord(str[len]) then
  907. begin
  908. { less partial! }
  909. if buffer[numb-pred(len)] = ord(str[1]) then
  910. begin
  911. move(buffer[numb-pred(len)],s2[1],len);
  912. if (str=s2) then
  913. begin
  914. found:=true;
  915. break;
  916. end;
  917. end;
  918. inc(numb);
  919. end
  920. else
  921. inc(numb,Bt[buffer[numb]]);
  922. end;
  923. if not found then
  924. Scan := NotFoundValue
  925. else
  926. Scan := numb - pred(len);
  927. end;
  928. function IScan(var Block; Size: Sw_Word;const Str: String): Sw_Word;
  929. Var
  930. buffer : Array[0..MaxBufLength-1] of Char Absolute block;
  931. s : String;
  932. len,
  933. numb,
  934. x : Sw_Word;
  935. found : Boolean;
  936. bt : Btable;
  937. p : pchar;
  938. c : char;
  939. begin
  940. len:=length(str);
  941. if (len=0) or (len>size) then
  942. begin
  943. IScan := NotFoundValue;
  944. exit;
  945. end;
  946. { create uppercased string }
  947. s[0]:=chr(len);
  948. for x:=1 to len do
  949. begin
  950. if str[x] in ['a'..'z'] then
  951. s[x]:=chr(ord(str[x])-32)
  952. else
  953. s[x]:=str[x];
  954. end;
  955. BMMakeTable(s,bt);
  956. found:=False;
  957. numb:=pred(len);
  958. While (not found) and (numb<(size-len)) do
  959. begin
  960. { partial match }
  961. c:=buffer[numb];
  962. if c in ['a'..'z'] then
  963. c:=chr(ord(c)-32);
  964. if (c=s[len]) then
  965. begin
  966. { less partial! }
  967. p:=@buffer[numb-pred(len)];
  968. x:=1;
  969. while (x<=len) do
  970. begin
  971. if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or
  972. (p^=s[x])) then
  973. break;
  974. inc(p);
  975. inc(x);
  976. end;
  977. if (x>len) then
  978. begin
  979. found:=true;
  980. break;
  981. end;
  982. inc(numb);
  983. end
  984. else
  985. inc(numb,Bt[ord(c)]);
  986. end;
  987. if not found then
  988. IScan := NotFoundValue
  989. else
  990. IScan := numb - pred(len);
  991. end;
  992. {****************************************************************************
  993. TIndicator
  994. ****************************************************************************}
  995. constructor TIndicator.Init (var Bounds : TRect);
  996. begin
  997. Inherited Init (Bounds);
  998. GrowMode := gfGrowLoY + gfGrowHiY;
  999. end; { TIndicator.Init }
  1000. procedure TIndicator.Draw;
  1001. VAR
  1002. Color : Byte;
  1003. Frame : Char;
  1004. L : array[0..1] of Longint;
  1005. S : String[15];
  1006. B : TDrawBuffer;
  1007. begin
  1008. if State and sfDragging = 0 then
  1009. begin
  1010. Color := GetColor (1);
  1011. Frame := #205;
  1012. end
  1013. else
  1014. begin
  1015. Color := GetColor (2);
  1016. Frame := #196;
  1017. end;
  1018. MoveChar (B, Frame, Color, Size.X);
  1019. { If the text has been modified, put an 'M' in the TIndicator display. }
  1020. if Modified then
  1021. WordRec (B[1]).Lo := 77;
  1022. { If WordWrap is active put a 'W' in the TIndicator display. }
  1023. if WordWrap then
  1024. WordRec (B[2]).Lo := 87
  1025. else
  1026. WordRec (B[2]).Lo := Byte (Frame);
  1027. { If AutoIndent is active put an 'I' in TIndicator display. }
  1028. if AutoIndent then
  1029. WordRec (B[0]).Lo := 73
  1030. else
  1031. WordRec (B[0]).Lo := Byte (Frame);
  1032. L[0] := Location.Y + 1;
  1033. L[1] := Location.X + 1;
  1034. FormatStr (S, ' %d:%d ', L);
  1035. MoveStr (B[9 - Pos (':', S)], S, Color); { Changed original 8 to 9. }
  1036. WriteBuf (0, 0, Size.X, 1, B);
  1037. end; { TIndicator.Draw }
  1038. function TIndicator.GetPalette : PPalette;
  1039. const
  1040. P : string[Length (CIndicator)] = CIndicator;
  1041. begin
  1042. GetPalette := @P;
  1043. end; { TIndicator.GetPalette }
  1044. procedure TIndicator.SetState (AState : Word; Enable : Boolean);
  1045. begin
  1046. Inherited SetState (AState, Enable);
  1047. if AState = sfDragging then
  1048. DrawView;
  1049. end; { TIndicator.SetState }
  1050. procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
  1051. IsModified : Boolean;
  1052. IsWordWrap : Boolean);
  1053. begin
  1054. if (Location.X<>ALocation.X) or
  1055. (Location.Y<>ALocation.Y) or
  1056. (AutoIndent <> IsAutoIndent) or
  1057. (Modified <> IsModified) or
  1058. (WordWrap <> IsWordWrap) then
  1059. begin
  1060. Location := ALocation;
  1061. AutoIndent := IsAutoIndent; { Added provisions to show AutoIndent. }
  1062. Modified := IsModified;
  1063. WordWrap := IsWordWrap; { Added provisions to show WordWrap. }
  1064. DrawView;
  1065. end;
  1066. end; { TIndicator.SetValue }
  1067. {****************************************************************************
  1068. TLineInfo
  1069. ****************************************************************************}
  1070. constructor TLineInfo.Init;
  1071. begin
  1072. MaxPos:=0;
  1073. Grow(1);
  1074. end;
  1075. destructor TLineInfo.Done;
  1076. begin
  1077. FreeMem(Info,MaxPos*sizeof(TLineInfoRec));
  1078. Info := nil;
  1079. end;
  1080. procedure TLineInfo.Grow(pos:Sw_word);
  1081. var
  1082. NewSize : Sw_word;
  1083. P : pointer;
  1084. begin
  1085. NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow));
  1086. GetMem(P,NewSize*sizeof(TLineInfoRec));
  1087. FillChar(P^,NewSize*sizeof(TLineInfoRec),0);
  1088. Move(Info^,P^,MaxPos*sizeof(TLineInfoRec));
  1089. Freemem(Info,MaxPos*sizeof(TLineInfoRec));
  1090. Info:=P;
  1091. end;
  1092. procedure TLineInfo.SetLen(pos,val:Sw_Word);
  1093. begin
  1094. if pos>=MaxPos then
  1095. Grow(Pos);
  1096. Info^[Pos].Len:=val
  1097. end;
  1098. procedure TLineInfo.SetAttr(pos,val:Sw_Word);
  1099. begin
  1100. if pos>=MaxPos then
  1101. Grow(Pos);
  1102. Info^[Pos].Attr:=val
  1103. end;
  1104. function TLineInfo.GetLen(pos:Sw_Word):Sw_Word;
  1105. begin
  1106. GetLen:=Info^[Pos].Len;
  1107. end;
  1108. function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word;
  1109. begin
  1110. GetAttr:=Info^[Pos].Attr;
  1111. end;
  1112. {****************************************************************************
  1113. TEditor
  1114. ****************************************************************************}
  1115. constructor TEditor.Init (var Bounds : TRect;
  1116. AHScrollBar, AVScrollBar : PScrollBar;
  1117. AIndicator : PIndicator; ABufSize : Sw_Word);
  1118. var
  1119. Element : Byte; { Place_Marker array element to initialize array with. }
  1120. begin
  1121. Inherited Init (Bounds);
  1122. GrowMode := gfGrowHiX + gfGrowHiY;
  1123. Options := Options or ofSelectable;
  1124. Flags := EditorFlags;
  1125. EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
  1126. ShowCursor;
  1127. HScrollBar := AHScrollBar;
  1128. VScrollBar := AVScrollBar;
  1129. Indicator := AIndicator;
  1130. BufSize := ABufSize;
  1131. CanUndo := True;
  1132. InitBuffer;
  1133. if assigned(Buffer) then
  1134. IsValid := True
  1135. else
  1136. begin
  1137. EditorDialog (edOutOfMemory, nil);
  1138. BufSize := 0;
  1139. end;
  1140. SetBufLen (0);
  1141. for Element := 1 to 10 do
  1142. Place_Marker[Element] := 0;
  1143. Element := 1;
  1144. while Element <= 70 do
  1145. begin
  1146. if Element mod 5 = 0 then
  1147. Insert ('x', Tab_Settings, Element)
  1148. else
  1149. Insert (#32, Tab_Settings, Element);
  1150. Inc (Element);
  1151. end;
  1152. { Default Right_Margin value. Change it if you want another. }
  1153. Right_Margin := 76;
  1154. TabSize:=8;
  1155. end; { TEditor.Init }
  1156. constructor TEditor.Load (var S : Objects.TStream);
  1157. begin
  1158. Inherited Load (S);
  1159. GetPeerViewPtr (S, HScrollBar);
  1160. GetPeerViewPtr (S, VScrollBar);
  1161. GetPeerViewPtr (S, Indicator);
  1162. S.Read (BufSize, SizeOf (BufSize));
  1163. S.Read (CanUndo, SizeOf (CanUndo));
  1164. S.Read (AutoIndent, SizeOf (AutoIndent));
  1165. S.Read (Line_Number, SizeOf (Line_Number));
  1166. S.Read (Place_Marker, SizeOf (Place_Marker));
  1167. S.Read (Right_Margin, SizeOf (Right_Margin));
  1168. S.Read (Tab_Settings, SizeOf (Tab_Settings));
  1169. S.Read (Word_Wrap, SizeOf (Word_Wrap));
  1170. InitBuffer;
  1171. if Assigned(Buffer) then
  1172. IsValid := True
  1173. else
  1174. begin
  1175. EditorDialog (edOutOfMemory, nil);
  1176. BufSize := 0;
  1177. end;
  1178. Lock;
  1179. SetBufLen (0);
  1180. end; { TEditor.Load }
  1181. destructor TEditor.Done;
  1182. begin
  1183. DoneBuffer;
  1184. Inherited Done;
  1185. end; { TEditor.Done }
  1186. function TEditor.BufChar(P: Sw_Word): Char;
  1187. begin
  1188. if P>=CurPtr then
  1189. inc(P,Gaplen);
  1190. BufChar:=Buffer^[P];
  1191. end;
  1192. function TEditor.BufPtr(P: Sw_Word): Sw_Word;
  1193. begin
  1194. if P>=CurPtr then
  1195. BufPtr:=P+GapLen
  1196. else
  1197. BufPtr:=P;
  1198. end;
  1199. procedure TEditor.Center_Text (Select_Mode : Byte);
  1200. { This procedure will center the current line of text. }
  1201. { Centering is based on the current Right_Margin. }
  1202. { If the Line_Length exceeds the Right_Margin, or the }
  1203. { line is just a blank line, we exit and do nothing. }
  1204. VAR
  1205. Spaces : array [1..80] of Char; { Array to hold spaces we'll insert. }
  1206. Index : Byte; { Index into Spaces array. }
  1207. Line_Length : Sw_Integer; { Holds the length of the line. }
  1208. E,S : Sw_Word; { End of the current line. }
  1209. begin
  1210. E := LineEnd (CurPtr);
  1211. S := LineStart (CurPtr);
  1212. { If the line is blank (only a CR/LF on it) then do noting. }
  1213. if E = S then
  1214. Exit;
  1215. { Set CurPtr to start of line. Check if line begins with a space. }
  1216. { We must strip out any spaces from the beginning, or end of lines. }
  1217. { If line does not start with space, make sure line length does not }
  1218. { exceed the Right_Margin. If it does, then do nothing. }
  1219. SetCurPtr (S, Select_Mode);
  1220. Remove_EOL_Spaces (Select_Mode);
  1221. if Buffer^[CurPtr] = #32 then
  1222. begin
  1223. { If the next word is greater than the end of line then do nothing. }
  1224. { If the line length is greater than Right_Margin then do nothing. }
  1225. { Otherwise, delete all spaces at the start of line. }
  1226. { Then reset end of line and put CurPtr at start of modified line. }
  1227. E := LineEnd (CurPtr);
  1228. if NextWord (CurPtr) > E then
  1229. Exit;
  1230. if E - NextWord (CurPtr) > Right_Margin then
  1231. Exit;
  1232. DeleteRange (CurPtr, NextWord (CurPtr), True);
  1233. E := LineEnd (CurPtr);
  1234. SetCurPtr (LineStart (CurPtr), Select_Mode);
  1235. end
  1236. else
  1237. if E - CurPtr > Right_Margin then
  1238. Exit;
  1239. { Now we determine the real length of the line. }
  1240. { Then we subtract the Line_Length from Right_Margin. }
  1241. { Dividing the result by two tells us how many spaces }
  1242. { must be inserted at start of line to center it. }
  1243. { When we're all done, set the CurPtr to end of line. }
  1244. Line_Length := E - CurPtr;
  1245. for Index := 1 to ((Right_Margin - Line_Length) shr 1) do
  1246. Spaces[Index] := #32;
  1247. InsertText (@Spaces, Index, False);
  1248. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  1249. end; { TEditor.Center_Text }
  1250. procedure TEditor.ChangeBounds (var Bounds : TRect);
  1251. begin
  1252. SetBounds (Bounds);
  1253. Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X));
  1254. Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
  1255. Update (ufView);
  1256. end; { TEditor.ChangeBounds }
  1257. function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer;
  1258. VAR
  1259. Pos : Sw_Integer;
  1260. begin
  1261. Pos := 0;
  1262. while P < Target do
  1263. begin
  1264. if BufChar (P) = #9 then
  1265. Pos := Pos or 7;
  1266. Inc (Pos);
  1267. Inc (P);
  1268. end;
  1269. CharPos := Pos;
  1270. end; { TEditor.CharPos }
  1271. function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
  1272. VAR
  1273. Pos : Sw_Integer;
  1274. begin
  1275. Pos := 0;
  1276. while (Pos < Target) and (P < BufLen) and not(BufChar (P) in [#10,#13]) do
  1277. begin
  1278. if BufChar (P) = #9 then
  1279. Pos := Pos or 7;
  1280. Inc (Pos);
  1281. Inc (P);
  1282. end;
  1283. if Pos > Target then
  1284. Dec (P);
  1285. CharPtr := P;
  1286. end; { TEditor.CharPtr }
  1287. procedure TEditor.Check_For_Word_Wrap (Select_Mode : Byte;
  1288. Center_Cursor : Boolean);
  1289. { This procedure checks if CurPos.X > Right_Margin. }
  1290. { If it is, then we Do_Word_Wrap. Simple, eh? }
  1291. begin
  1292. if CurPos.X > Right_Margin then
  1293. Do_Word_Wrap (Select_Mode, Center_Cursor);
  1294. end; {Check_For_Word_Wrap}
  1295. function TEditor.ClipCopy : Boolean;
  1296. begin
  1297. ClipCopy := False;
  1298. if Assigned(Clipboard) and (Clipboard <> @Self) then
  1299. begin
  1300. ClipCopy := Clipboard^.InsertFrom (@Self);
  1301. Selecting := False;
  1302. Update (ufUpdate);
  1303. end;
  1304. end; { TEditor.ClipCopy }
  1305. procedure TEditor.ClipCut;
  1306. begin
  1307. if ClipCopy then
  1308. begin
  1309. Update_Place_Markers (0,
  1310. Self.SelEnd - Self.SelStart,
  1311. Self.SelStart,
  1312. Self.SelEnd);
  1313. DeleteSelect;
  1314. end;
  1315. end; { TEditor.ClipCut }
  1316. procedure TEditor.ClipPaste;
  1317. begin
  1318. if Assigned(Clipboard) and (Clipboard <> @Self) then
  1319. begin
  1320. { Do not allow paste operations that will exceed }
  1321. { the Right_Margin when Word_Wrap is active and }
  1322. { cursor is at EOL. }
  1323. if Word_Wrap and (CurPos.X > Right_Margin) then
  1324. begin
  1325. EditorDialog (edPasteNotPossible, nil);
  1326. Exit;
  1327. end;
  1328. { The editor will not copy selected text if the CurPtr }
  1329. { is not the same value as the SelStart. However, it }
  1330. { does return an InsCount. This may, or may not, be a }
  1331. { bug. We don't want to update the Place_Marker if }
  1332. { there's no text copied. }
  1333. if CurPtr = SelStart then
  1334. Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart,
  1335. 0,
  1336. Clipboard^.SelStart,
  1337. Clipboard^.SelEnd);
  1338. InsertFrom (Clipboard);
  1339. end;
  1340. end; { TEditor.ClipPaste }
  1341. procedure TEditor.ConvertEvent (var Event : Drivers.TEvent);
  1342. VAR
  1343. ShiftState : Byte;
  1344. Key : Word;
  1345. begin
  1346. ShiftState:=GetShiftState;
  1347. if Event.What = evKeyDown then
  1348. begin
  1349. if (ShiftState and $03 <> 0)
  1350. and (Event.ScanCode >= $47)
  1351. and (Event.ScanCode <= $51) then
  1352. Event.CharCode := #0;
  1353. Key := Event.KeyCode;
  1354. if KeyState <> 0 then
  1355. begin
  1356. if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then
  1357. Inc (Key, $40);
  1358. if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then
  1359. Dec (Key, $20);
  1360. end;
  1361. Key := ScanKeyMap (KeyMap[KeyState], Key);
  1362. KeyState := 0;
  1363. if Key <> 0 then
  1364. if Hi (Key) = $FF then
  1365. begin
  1366. KeyState := Lo (Key);
  1367. ClearEvent (Event);
  1368. end
  1369. else
  1370. begin
  1371. Event.What := evCommand;
  1372. Event.Command := Key;
  1373. end;
  1374. end;
  1375. end; { TEditor.ConvertEvent }
  1376. function TEditor.CursorVisible : Boolean;
  1377. begin
  1378. CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
  1379. end; { TEditor.CursorVisible }
  1380. procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
  1381. begin
  1382. { This will update Place_Marker for all deletions. }
  1383. { EXCEPT the Remove_EOL_Spaces deletion. }
  1384. Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr);
  1385. if HasSelection and DelSelect then
  1386. DeleteSelect
  1387. else
  1388. begin
  1389. SetSelect (CurPtr, EndPtr, True);
  1390. DeleteSelect;
  1391. SetSelect (StartPtr, CurPtr, False);
  1392. DeleteSelect;
  1393. end;
  1394. end; { TEditor.DeleteRange }
  1395. procedure TEditor.DeleteSelect;
  1396. begin
  1397. InsertText (nil, 0, False);
  1398. end; { TEditor.DeleteSelect }
  1399. procedure TEditor.DoneBuffer;
  1400. begin
  1401. ReAllocMem(Buffer, 0);
  1402. end; { TEditor.DoneBuffer }
  1403. procedure TEditor.DoSearchReplace;
  1404. VAR
  1405. I : Sw_Word;
  1406. C : Objects.TPoint;
  1407. begin
  1408. repeat
  1409. I := cmCancel;
  1410. if not Search (FindStr, Flags) then
  1411. begin
  1412. if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then
  1413. EditorDialog (edSearchFailed, nil)
  1414. end
  1415. else
  1416. if Flags and efDoReplace <> 0 then
  1417. begin
  1418. I := cmYes;
  1419. if Flags and efPromptOnReplace <> 0 then
  1420. begin
  1421. MakeGlobal (Cursor, C);
  1422. I := EditorDialog (edReplacePrompt, Pointer(@C));
  1423. end;
  1424. if I = cmYes then
  1425. begin
  1426. { If Word_Wrap is active and we are at EOL }
  1427. { disallow replace by bringing up a dialog }
  1428. { stating that replace is not possible. }
  1429. if Word_Wrap and
  1430. ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then
  1431. EditorDialog (edReplaceNotPossible, nil)
  1432. else
  1433. begin
  1434. Lock;
  1435. Search_Replace := True;
  1436. if length (ReplaceStr) < length (FindStr) then
  1437. Update_Place_Markers (0,
  1438. Length (FindStr) - Length (ReplaceStr),
  1439. CurPtr - Length (FindStr) + Length (ReplaceStr),
  1440. CurPtr)
  1441. else
  1442. if length (ReplaceStr) > length (FindStr) then
  1443. Update_Place_Markers (Length (ReplaceStr) - Length (FindStr),
  1444. 0,
  1445. CurPtr,
  1446. CurPtr + (Length (ReplaceStr) - Length (FindStr)));
  1447. InsertText (@ReplaceStr[1], Length (ReplaceStr), False);
  1448. Search_Replace := False;
  1449. TrackCursor (False);
  1450. Unlock;
  1451. end;
  1452. end;
  1453. end;
  1454. until (I = cmCancel) or (Flags and efReplaceAll = 0);
  1455. end; { TEditor.DoSearchReplace }
  1456. procedure TEditor.DoUpdate;
  1457. begin
  1458. if UpdateFlags <> 0 then
  1459. begin
  1460. SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y);
  1461. if UpdateFlags and ufView <> 0 then
  1462. DrawView
  1463. else
  1464. if UpdateFlags and ufLine <> 0 then
  1465. DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr));
  1466. if assigned(HScrollBar) then
  1467. HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
  1468. if assigned(VScrollBar) then
  1469. VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
  1470. if assigned(Indicator) then
  1471. Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap);
  1472. if State and sfActive <> 0 then
  1473. UpdateCommands;
  1474. UpdateFlags := 0;
  1475. end;
  1476. end; { TEditor.DoUpdate }
  1477. function TEditor.Do_Word_Wrap (Select_Mode : Byte;
  1478. Center_Cursor : Boolean) : Boolean;
  1479. { This procedure does the actual wordwrap. It always assumes the CurPtr }
  1480. { is at Right_Margin + 1. It makes several tests for special conditions }
  1481. { and processes those first. If they all fail, it does a normal wrap. }
  1482. VAR
  1483. A : Sw_Word; { Distance between line start and first word on line. }
  1484. C : Sw_Word; { Current pointer when we come into procedure. }
  1485. L : Sw_Word; { BufLen when we come into procedure. }
  1486. P : Sw_Word; { Position of pointer at any given moment. }
  1487. S : Sw_Word; { Start of a line. }
  1488. begin
  1489. Do_Word_Wrap := False;
  1490. Select_Mode := 0;
  1491. if BufLen >= (BufSize - 1) then
  1492. exit;
  1493. C := CurPtr;
  1494. L := BufLen;
  1495. S := LineStart (CurPtr);
  1496. { If first character in the line is a space and autoindent mode is on }
  1497. { then we check to see if NextWord(S) exceeds the CurPtr. If it does, }
  1498. { we set CurPtr as the AutoIndent marker. If it doesn't, we will set }
  1499. { NextWord(S) as the AutoIndent marker. If neither, we set it to S. }
  1500. if AutoIndent and (Buffer^[S] = ' ') then
  1501. begin
  1502. if NextWord (S) > CurPtr then
  1503. A := CurPtr
  1504. else
  1505. A := NextWord (S);
  1506. end
  1507. else
  1508. A := NextWord (S);
  1509. { Though NewLine will remove EOL spaces, we do it here too. }
  1510. { This catches the instance where a user may try to space }
  1511. { completely across the line, in which case CurPtr.X = 0. }
  1512. Remove_EOL_Spaces (Select_Mode);
  1513. if CurPos.X = 0 then
  1514. begin
  1515. NewLine (Select_Mode);
  1516. Do_Word_Wrap := True;
  1517. Exit;
  1518. end;
  1519. { At this point we have one of five situations: }
  1520. { }
  1521. { 1) AutoIndent is on and this line is all spaces before CurPtr. }
  1522. { 2) AutoIndent is off and this line is all spaces before CurPtr. }
  1523. { 3) AutoIndent is on and this line is continuous characters before CurPtr. }
  1524. { 4) AutoIndent is off and this line is continuous characters before CurPtr. }
  1525. { 5) This is just a normal line of text. }
  1526. { }
  1527. { Conditions 1 through 4 have to be taken into account before condition 5. }
  1528. { First, we see if there are all spaces and/or all characters. }
  1529. { Then we determine which one it really is. Finally, we take }
  1530. { a course of action based on the state of AutoIndent. }
  1531. if PrevWord (CurPtr) <= S then
  1532. begin
  1533. P := CurPtr - 1;
  1534. while ((Buffer^[P] <> ' ') and (P > S)) do
  1535. Dec (P);
  1536. { We found NO SPACES. Conditions 4 and 5 are treated the same. }
  1537. { We can NOT do word wrap and put up a dialog box stating such. }
  1538. { Delete character just entered so we don't exceed Right_Margin. }
  1539. if P = S then
  1540. begin
  1541. EditorDialog (edWrapNotPossible, nil);
  1542. DeleteRange (PrevChar (CurPtr), CurPtr, True);
  1543. Exit;
  1544. end
  1545. else
  1546. begin
  1547. { There are spaces. Now find out if they are all spaces. }
  1548. { If so, see if AutoIndent is on. If it is, turn it off, }
  1549. { do a NewLine, and turn it back on. Otherwise, just do }
  1550. { the NewLine. We go through all of these gyrations for }
  1551. { AutoIndent. Being way out here with a preceding line }
  1552. { of spaces and wrapping with AutoIndent on is real dumb! }
  1553. { However, the user expects something. The wrap will NOT }
  1554. { autoindent, but they had no business being here anyway! }
  1555. P := CurPtr - 1;
  1556. while ((Buffer^[P] = ' ') and (P > S)) do
  1557. Dec (P);
  1558. if P = S then
  1559. begin
  1560. if Autoindent then
  1561. begin
  1562. AutoIndent := False;
  1563. NewLine (Select_Mode);
  1564. AutoIndent := True;
  1565. end
  1566. else
  1567. NewLine (Select_Mode);
  1568. end; { AutoIndent }
  1569. end; { P = S for spaces }
  1570. end { P = S for no spaces }
  1571. else { PrevWord (CurPtr) <= S }
  1572. begin
  1573. { Hooray! We actually had a plain old line of text to wrap! }
  1574. { Regardless if we are pushing out a line beyond the Right_Margin, }
  1575. { or at the end of a line itself, the following will determine }
  1576. { exactly where to do the wrap and re-set the cursor accordingly. }
  1577. { However, if P = A then we can't wrap. Show dialog and exit. }
  1578. P := CurPtr;
  1579. while P - S > Right_Margin do
  1580. P := PrevWord (P);
  1581. if (P = A) then
  1582. begin
  1583. EditorDialog (edReformNotPossible, nil);
  1584. SetCurPtr (P, Select_Mode);
  1585. Exit;
  1586. end;
  1587. SetCurPtr (P, Select_Mode);
  1588. NewLine (Select_Mode);
  1589. end; { PrevWord (CurPtr <= S }
  1590. { Track the cursor here (it is at CurPos.X = 0) so the view }
  1591. { will redraw itself at column 0. This eliminates having it }
  1592. { redraw starting at the current cursor and not being able }
  1593. { to see text before the cursor. Of course, we also end up }
  1594. { redrawing the view twice, here and back in HandleEvent. }
  1595. { }
  1596. { Reposition cursor so user can pick up where they left off. }
  1597. TrackCursor (Center_Cursor);
  1598. SetCurPtr (C - (L - BufLen), Select_Mode);
  1599. Do_Word_Wrap := True;
  1600. end; { TEditor.Do_Word_Wrap }
  1601. procedure TEditor.Draw;
  1602. begin
  1603. if DrawLine <> Delta.Y then
  1604. begin
  1605. DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine);
  1606. DrawLine := Delta.Y;
  1607. end;
  1608. DrawLines (0, Size.Y, DrawPtr);
  1609. end; { TEditor.Draw }
  1610. procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
  1611. VAR
  1612. Color : Word;
  1613. B : array[0..MaxLineLength - 1] of Sw_Word;
  1614. begin
  1615. Color := GetColor ($0201);
  1616. while Count > 0 do
  1617. begin
  1618. FormatLine (B, LinePtr, Delta.X + Size.X, Color);
  1619. WriteBuf (0, Y, Size.X, 1, B[Delta.X]);
  1620. LinePtr := NextLine (LinePtr);
  1621. Inc (Y);
  1622. Dec (Count);
  1623. end;
  1624. end; { TEditor.DrawLines }
  1625. procedure TEditor.Find;
  1626. VAR
  1627. FindRec : TFindDialogRec;
  1628. begin
  1629. with FindRec do
  1630. begin
  1631. Find := FindStr;
  1632. Options := Flags;
  1633. if EditorDialog (edFind, @FindRec) <> cmCancel then
  1634. begin
  1635. FindStr := Find;
  1636. Flags := Options and not efDoReplace;
  1637. DoSearchReplace;
  1638. end;
  1639. end;
  1640. end; { TEditor.Find }
  1641. procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word;
  1642. Width : Sw_Integer;
  1643. Colors : Word);
  1644. var
  1645. outptr : pword;
  1646. outcnt,
  1647. idxpos : Sw_Word;
  1648. attr : Word;
  1649. procedure FillSpace(i:Sw_Word);
  1650. var
  1651. w : word;
  1652. begin
  1653. inc(OutCnt,i);
  1654. w:=32 or attr;
  1655. while (i>0) do
  1656. begin
  1657. OutPtr^:=w;
  1658. inc(OutPtr);
  1659. dec(i);
  1660. end;
  1661. end;
  1662. function FormatUntil(endpos:Sw_word):boolean;
  1663. var
  1664. p : pchar;
  1665. begin
  1666. FormatUntil:=false;
  1667. p:=pchar(Buffer)+idxpos;
  1668. while endpos>idxpos do
  1669. begin
  1670. if OutCnt>=Width then
  1671. exit;
  1672. case p^ of
  1673. #9 :
  1674. FillSpace(Tabsize-(outcnt mod Tabsize));
  1675. #10,#13 :
  1676. begin
  1677. FillSpace(Width-OutCnt);
  1678. FormatUntil:=true;
  1679. exit;
  1680. end;
  1681. else
  1682. begin
  1683. inc(OutCnt);
  1684. OutPtr^:=ord(p^) or attr;
  1685. inc(OutPtr);
  1686. end;
  1687. end; { case }
  1688. inc(p);
  1689. inc(idxpos);
  1690. end;
  1691. end;
  1692. begin
  1693. OutCnt:=0;
  1694. OutPtr:=@DrawBuf;
  1695. idxPos:=LinePtr;
  1696. attr:=lo(Colors) shl 8;
  1697. if FormatUntil(SelStart) then
  1698. exit;
  1699. attr:=hi(Colors) shl 8;
  1700. if FormatUntil(CurPtr) then
  1701. exit;
  1702. inc(idxPos,GapLen);
  1703. if FormatUntil(SelEnd+GapLen) then
  1704. exit;
  1705. attr:=lo(Colors) shl 8;
  1706. if FormatUntil(BufSize) then
  1707. exit;
  1708. { fill up until width }
  1709. FillSpace(Width-OutCnt);
  1710. end; {TEditor.FormatLine}
  1711. function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
  1712. begin
  1713. MakeLocal (Mouse, Mouse);
  1714. Mouse.X := Max (0, Min (Mouse.X, Size.X - 1));
  1715. Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1));
  1716. GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine),
  1717. Mouse.X + Delta.X);
  1718. end; { TEditor.GetMousePtr }
  1719. function TEditor.GetPalette : PPalette;
  1720. CONST
  1721. P : String[Length (CEditor)] = CEditor;
  1722. begin
  1723. GetPalette := @P;
  1724. end; { TEditor.GetPalette }
  1725. procedure TEditor.HandleEvent (var Event : Drivers.TEvent);
  1726. VAR
  1727. ShiftState : Byte;
  1728. CenterCursor : Boolean;
  1729. SelectMode : Byte;
  1730. D : Objects.TPoint;
  1731. Mouse : Objects.TPoint;
  1732. function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean;
  1733. begin
  1734. CheckScrollBar := FALSE;
  1735. if (Event.InfoPtr = P) and (P^.Value <> D) then
  1736. begin
  1737. D := P^.Value;
  1738. Update (ufView);
  1739. CheckScrollBar := TRUE;
  1740. end;
  1741. end; {CheckScrollBar}
  1742. begin
  1743. Inherited HandleEvent (Event);
  1744. ConvertEvent (Event);
  1745. CenterCursor := not CursorVisible;
  1746. SelectMode := 0;
  1747. ShiftState:=GetShiftState;
  1748. if Selecting or (ShiftState and $03 <> 0) then
  1749. SelectMode := smExtend;
  1750. case Event.What of
  1751. Drivers.evMouseDown:
  1752. begin
  1753. if Event.Double then
  1754. SelectMode := SelectMode or smDouble;
  1755. repeat
  1756. Lock;
  1757. if Event.What = evMouseAuto then
  1758. begin
  1759. MakeLocal (Event.Where, Mouse);
  1760. D := Delta;
  1761. if Mouse.X < 0 then
  1762. Dec (D.X);
  1763. if Mouse.X >= Size.X then
  1764. Inc (D.X);
  1765. if Mouse.Y < 0 then
  1766. Dec (D.Y);
  1767. if Mouse.Y >= Size.Y then
  1768. Inc (D.Y);
  1769. ScrollTo (D.X, D.Y);
  1770. end;
  1771. SetCurPtr (GetMousePtr (Event.Where), SelectMode);
  1772. SelectMode := SelectMode or smExtend;
  1773. Unlock;
  1774. until not MouseEvent (Event, evMouseMove + evMouseAuto);
  1775. end; { Drivers.evMouseDown }
  1776. Drivers.evKeyDown:
  1777. case Event.CharCode of
  1778. #32..#255:
  1779. begin
  1780. Lock;
  1781. if Overwrite and not HasSelection then
  1782. if CurPtr <> LineEnd (CurPtr) then
  1783. SelEnd := NextChar (CurPtr);
  1784. InsertText (@Event.CharCode, 1, False);
  1785. if Word_Wrap then
  1786. Check_For_Word_Wrap (SelectMode, CenterCursor);
  1787. TrackCursor (CenterCursor);
  1788. Unlock;
  1789. end;
  1790. else
  1791. Exit;
  1792. end; { Drivers.evKeyDown }
  1793. Drivers.evCommand:
  1794. case Event.Command of
  1795. cmFind : Find;
  1796. cmReplace : Replace;
  1797. cmSearchAgain : DoSearchReplace;
  1798. else
  1799. begin
  1800. Lock;
  1801. case Event.Command of
  1802. cmCut : ClipCut;
  1803. cmCopy : ClipCopy;
  1804. cmPaste : ClipPaste;
  1805. cmUndo : Undo;
  1806. cmClear : DeleteSelect;
  1807. cmCharLeft : SetCurPtr (PrevChar (CurPtr), SelectMode);
  1808. cmCharRight : SetCurPtr (NextChar (CurPtr), SelectMode);
  1809. cmWordLeft : SetCurPtr (PrevWord (CurPtr), SelectMode);
  1810. cmWordRight : SetCurPtr (NextWord (CurPtr), SelectMode);
  1811. cmLineStart : SetCurPtr (LineStart (CurPtr), SelectMode);
  1812. cmLineEnd : SetCurPtr (LineEnd (CurPtr), SelectMode);
  1813. cmLineUp : SetCurPtr (LineMove (CurPtr, -1), SelectMode);
  1814. cmLineDown : SetCurPtr (LineMove (CurPtr, 1), SelectMode);
  1815. cmPageUp : SetCurPtr (LineMove (CurPtr, - (Size.Y - 1)), SelectMode);
  1816. cmPageDown : SetCurPtr (LineMove (CurPtr, Size.Y - 1), SelectMode);
  1817. cmTextStart : SetCurPtr (0, SelectMode);
  1818. cmTextEnd : SetCurPtr (BufLen, SelectMode);
  1819. cmNewLine : NewLine (SelectMode);
  1820. cmBackSpace : DeleteRange (PrevChar (CurPtr), CurPtr, True);
  1821. cmDelChar : DeleteRange (CurPtr, NextChar (CurPtr), True);
  1822. cmDelWord : DeleteRange (CurPtr, NextWord (CurPtr), False);
  1823. cmDelStart : DeleteRange (LineStart (CurPtr), CurPtr, False);
  1824. cmDelEnd : DeleteRange (CurPtr, LineEnd (CurPtr), False);
  1825. cmDelLine : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False);
  1826. cmInsMode : ToggleInsMode;
  1827. cmStartSelect : StartSelect;
  1828. cmHideSelect : HideSelect;
  1829. cmIndentMode : begin
  1830. AutoIndent := not AutoIndent;
  1831. Update (ufStats);
  1832. end; { Added provision to update TIndicator if ^QI pressed. }
  1833. cmCenterText : Center_Text (SelectMode);
  1834. cmEndPage : SetCurPtr (LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode);
  1835. cmHomePage : SetCurPtr (LineMove (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode);
  1836. cmInsertLine : Insert_Line (SelectMode);
  1837. cmJumpLine : Jump_To_Line (SelectMode);
  1838. cmReformDoc : Reformat_Document (SelectMode, CenterCursor);
  1839. cmReformPara : Reformat_Paragraph (SelectMode, CenterCursor);
  1840. cmRightMargin : Set_Right_Margin;
  1841. cmScrollDown : Scroll_Down;
  1842. cmScrollUp : Scroll_Up;
  1843. cmSelectWord : Select_Word;
  1844. cmSetTabs : Set_Tabs;
  1845. cmTabKey : Tab_Key (SelectMode);
  1846. cmWordWrap : begin
  1847. Word_Wrap := not Word_Wrap;
  1848. Update (ufStats);
  1849. end; { Added provision to update TIndicator if ^OW pressed. }
  1850. cmSetMark0 : Set_Place_Marker (10);
  1851. cmSetMark1 : Set_Place_Marker (1);
  1852. cmSetMark2 : Set_Place_Marker (2);
  1853. cmSetMark3 : Set_Place_Marker (3);
  1854. cmSetMark4 : Set_Place_Marker (4);
  1855. cmSetMark5 : Set_Place_Marker (5);
  1856. cmSetMark6 : Set_Place_Marker (6);
  1857. cmSetMark7 : Set_Place_Marker (7);
  1858. cmSetMark8 : Set_Place_Marker (8);
  1859. cmSetMark9 : Set_Place_Marker (9);
  1860. cmJumpMark0 : Jump_Place_Marker (10, SelectMode);
  1861. cmJumpMark1 : Jump_Place_Marker (1, SelectMode);
  1862. cmJumpMark2 : Jump_Place_Marker (2, SelectMode);
  1863. cmJumpMark3 : Jump_Place_Marker (3, SelectMode);
  1864. cmJumpMark4 : Jump_Place_Marker (4, SelectMode);
  1865. cmJumpMark5 : Jump_Place_Marker (5, SelectMode);
  1866. cmJumpMark6 : Jump_Place_Marker (6, SelectMode);
  1867. cmJumpMark7 : Jump_Place_Marker (7, SelectMode);
  1868. cmJumpMark8 : Jump_Place_Marker (8, SelectMode);
  1869. cmJumpMark9 : Jump_Place_Marker (9, SelectMode);
  1870. else
  1871. Unlock;
  1872. Exit;
  1873. end; { Event.Command (Inner) }
  1874. TrackCursor (CenterCursor);
  1875. { If the user presses any key except cmNewline or cmBackspace }
  1876. { we need to check if the file has been modified yet. There }
  1877. { can be no spaces at the end of a line, or wordwrap doesn't }
  1878. { work properly. We don't want to do this if the file hasn't }
  1879. { been modified because the user could be bringing in an ASCII }
  1880. { file from an editor that allows spaces at the EOL. If we }
  1881. { took them out in that scenario the "M" would appear on the }
  1882. { TIndicator line and the user would get upset or confused. }
  1883. if (Event.Command <> cmNewLine) and
  1884. (Event.Command <> cmBackSpace) and
  1885. (Event.Command <> cmTabKey) and
  1886. Modified then
  1887. Remove_EOL_Spaces (SelectMode);
  1888. Unlock;
  1889. end; { Event.Command (Outer) }
  1890. end; { Drivers.evCommand }
  1891. Drivers.evBroadcast:
  1892. case Event.Command of
  1893. cmScrollBarChanged:
  1894. if (Event.InfoPtr = HScrollBar) or
  1895. (Event.InfoPtr = VScrollBar) then
  1896. begin
  1897. CheckScrollBar (HScrollBar, Delta.X);
  1898. CheckScrollBar (VScrollBar, Delta.Y);
  1899. end
  1900. else
  1901. exit;
  1902. else
  1903. Exit;
  1904. end; { Drivers.evBroadcast }
  1905. end;
  1906. ClearEvent (Event);
  1907. end; { TEditor.HandleEvent }
  1908. function TEditor.HasSelection : Boolean;
  1909. begin
  1910. HasSelection := SelStart <> SelEnd;
  1911. end; { TEditor.HasSelection }
  1912. procedure TEditor.HideSelect;
  1913. begin
  1914. Selecting := False;
  1915. SetSelect (CurPtr, CurPtr, False);
  1916. end; { TEditor.HideSelect }
  1917. procedure TEditor.InitBuffer;
  1918. begin
  1919. Assert(Buffer = nil, 'TEditor.InitBuffer: Buffer is not nil');
  1920. ReAllocMem(Buffer, BufSize);
  1921. end; { TEditor.InitBuffer }
  1922. function TEditor.InsertBuffer (var P : PEditBuffer;
  1923. Offset, Length : Sw_Word;
  1924. AllowUndo, SelectText : Boolean) : Boolean;
  1925. VAR
  1926. SelLen : Sw_Word;
  1927. DelLen : Sw_Word;
  1928. SelLines : Sw_Word;
  1929. Lines : Sw_Word;
  1930. NewSize : Longint;
  1931. begin
  1932. InsertBuffer := True;
  1933. Selecting := False;
  1934. SelLen := SelEnd - SelStart;
  1935. if (SelLen = 0) and (Length = 0) then
  1936. Exit;
  1937. DelLen := 0;
  1938. if AllowUndo then
  1939. if CurPtr = SelStart then
  1940. DelLen := SelLen
  1941. else
  1942. if SelLen > InsCount then
  1943. DelLen := SelLen - InsCount;
  1944. NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length;
  1945. if NewSize > BufLen + DelCount then
  1946. if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then
  1947. begin
  1948. EditorDialog (edOutOfMemory, nil);
  1949. InsertBuffer := False;
  1950. SelEnd := SelStart;
  1951. Exit;
  1952. end;
  1953. SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen);
  1954. if CurPtr = SelEnd then
  1955. begin
  1956. if AllowUndo then
  1957. begin
  1958. if DelLen > 0 then
  1959. Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
  1960. Dec (InsCount, SelLen - DelLen);
  1961. end;
  1962. CurPtr := SelStart;
  1963. Dec (CurPos.Y, SelLines);
  1964. end;
  1965. if Delta.Y > CurPos.Y then
  1966. begin
  1967. Dec (Delta.Y, SelLines);
  1968. if Delta.Y < CurPos.Y then
  1969. Delta.Y := CurPos.Y;
  1970. end;
  1971. if Length > 0 then
  1972. Move (P^[Offset], Buffer^[CurPtr], Length);
  1973. Lines := CountLines (Buffer^[CurPtr], Length);
  1974. Inc (CurPtr, Length);
  1975. Inc (CurPos.Y, Lines);
  1976. DrawLine := CurPos.Y;
  1977. DrawPtr := LineStart (CurPtr);
  1978. CurPos.X := CharPos (DrawPtr, CurPtr);
  1979. if not SelectText then
  1980. SelStart := CurPtr;
  1981. SelEnd := CurPtr;
  1982. if Length>Sellen then
  1983. begin
  1984. Inc (BufLen, Length - SelLen);
  1985. Dec (GapLen, Length - SelLen);
  1986. end
  1987. else
  1988. begin
  1989. Dec (BufLen, Sellen - Length);
  1990. Inc (GapLen, Sellen - Length);
  1991. end;
  1992. if AllowUndo then
  1993. begin
  1994. Inc (DelCount, DelLen);
  1995. Inc (InsCount, Length);
  1996. end;
  1997. Inc (Limit.Y, Lines - SelLines);
  1998. Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
  1999. if not IsClipboard then
  2000. Modified := True;
  2001. SetBufSize (BufLen + DelCount);
  2002. if (SelLines = 0) and (Lines = 0) then
  2003. Update (ufLine)
  2004. else
  2005. Update (ufView);
  2006. end; { TEditor.InsertBuffer }
  2007. function TEditor.InsertFrom (Editor : PEditor) : Boolean;
  2008. begin
  2009. InsertFrom := InsertBuffer (Editor^.Buffer,
  2010. Editor^.BufPtr (Editor^.SelStart),
  2011. Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
  2012. end; { TEditor.InsertFrom }
  2013. procedure TEditor.Insert_Line (Select_Mode : Byte);
  2014. { This procedure inserts a newline at the current cursor position }
  2015. { if a ^N is pressed. Unlike cmNewLine, the cursor will return }
  2016. { to its original position. If the cursor was at the end of a }
  2017. { line, and its spaces were removed, the cursor returns to the }
  2018. { end of the line instead. }
  2019. begin
  2020. NewLine (Select_Mode);
  2021. SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode);
  2022. end; { TEditor.Insert_Line }
  2023. function TEditor.InsertText (Text : Pointer;
  2024. Length : Sw_Word;
  2025. SelectText : Boolean) : Boolean;
  2026. begin
  2027. if assigned(Text) and not Search_Replace then
  2028. Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd);
  2029. InsertText := InsertBuffer (PEditBuffer (Text),
  2030. 0, Length, CanUndo, SelectText);
  2031. end; { TEditor.InsertText }
  2032. function TEditor.IsClipboard : Boolean;
  2033. begin
  2034. IsClipboard := Clipboard = @Self;
  2035. end; { TEditor.IsClipboard }
  2036. procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
  2037. { This procedure jumps to a place marker if ^Q# is pressed. }
  2038. { We don't go anywhere if Place_Marker[Element] is not zero. }
  2039. begin
  2040. if (not IsClipboard) and (Place_Marker[Element] <> 0) then
  2041. SetCurPtr (Place_Marker[Element], Select_Mode);
  2042. end; { TEditor.Jump_Place_Marker }
  2043. procedure TEditor.Jump_To_Line (Select_Mode : Byte);
  2044. { This function brings up a dialog box that allows }
  2045. { the user to select a line number to jump to. }
  2046. VAR
  2047. Code : Integer; { Used for Val conversion. }
  2048. Temp_Value : Longint; { Holds converted dialog value. }
  2049. begin
  2050. if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then
  2051. begin
  2052. { Convert the Line_Number string to an interger. }
  2053. { Put it into Temp_Value. If the number is not }
  2054. { in the range 1..9999 abort. If the number is }
  2055. { our current Y position, abort. Otherwise, }
  2056. { go to top of document, and jump to the line. }
  2057. { There are faster methods. This one's easy. }
  2058. { Note that CurPos.Y is always 1 less than what }
  2059. { the TIndicator line says. }
  2060. val (Line_Number, Temp_Value, Code);
  2061. if (Temp_Value < 1) or (Temp_Value > 9999999) then
  2062. Exit;
  2063. if Temp_Value = CurPos.Y + 1 then
  2064. Exit;
  2065. SetCurPtr (0, Select_Mode);
  2066. SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode);
  2067. end;
  2068. end; {TEditor.Jump_To_Line}
  2069. function TEditor.LineEnd (P : Sw_Word) : Sw_Word;
  2070. var
  2071. start,
  2072. i : Sw_word;
  2073. pc : pchar;
  2074. begin
  2075. if P<CurPtr then
  2076. begin
  2077. i:=CurPtr-P;
  2078. pc:=pchar(Buffer)+P;
  2079. while (i>0) do
  2080. begin
  2081. if pc^ in [#10,#13] then
  2082. begin
  2083. LineEnd:=pc-pchar(Buffer);
  2084. exit;
  2085. end;
  2086. inc(pc);
  2087. dec(i);
  2088. end;
  2089. start:=CurPtr;
  2090. end
  2091. else
  2092. start:=P;
  2093. i:=BufLen-Start;
  2094. pc:=pchar(Buffer)+GapLen+start;
  2095. while (i>0) do
  2096. begin
  2097. if pc^ in [#10,#13] then
  2098. begin
  2099. LineEnd:=pc-(pchar(Buffer)+Gaplen);
  2100. exit;
  2101. end;
  2102. inc(pc);
  2103. dec(i);
  2104. end;
  2105. LineEnd:=pc-(pchar(Buffer)+Gaplen);
  2106. end; { TEditor.LineEnd }
  2107. function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
  2108. VAR
  2109. Pos : Sw_Integer;
  2110. I : Sw_Word;
  2111. begin
  2112. I := P;
  2113. P := LineStart (P);
  2114. Pos := CharPos (P, I);
  2115. while Count <> 0 do
  2116. begin
  2117. I := P;
  2118. if Count < 0 then
  2119. begin
  2120. P := PrevLine (P);
  2121. Inc (Count);
  2122. end
  2123. else
  2124. begin
  2125. P := NextLine (P);
  2126. Dec (Count);
  2127. end;
  2128. end;
  2129. if P <> I then
  2130. P := CharPtr (P, Pos);
  2131. LineMove := P;
  2132. end; { TEditor.LineMove }
  2133. function TEditor.LineStart (P : Sw_Word) : Sw_Word;
  2134. var
  2135. i : Sw_word;
  2136. start,pc : pchar;
  2137. oc : char;
  2138. begin
  2139. if P>CurPtr then
  2140. begin
  2141. start:=pchar(Buffer)+GapLen;
  2142. pc:=start;
  2143. i:=P-CurPtr;
  2144. dec(pc);
  2145. while (i>0) do
  2146. begin
  2147. if pc^ in [#10,#13] then
  2148. break;
  2149. dec(pc);
  2150. dec(i);
  2151. end;
  2152. end
  2153. else
  2154. i:=0;
  2155. if i=0 then
  2156. begin
  2157. start:=pchar(Buffer);
  2158. i:=P;
  2159. pc:=start+p;
  2160. dec(pc);
  2161. while (i>0) do
  2162. begin
  2163. if pc^ in [#10,#13] then
  2164. break;
  2165. dec(pc);
  2166. dec(i);
  2167. end;
  2168. if i=0 then
  2169. begin
  2170. LineStart:=0;
  2171. exit;
  2172. end;
  2173. end;
  2174. oc:=pc^;
  2175. LineStart:=pc-start+1;
  2176. end; { TEditor.LineStart }
  2177. function TEditor.LineNr (P : Sw_Word) : Sw_Word;
  2178. var
  2179. pc,endp : pchar;
  2180. lines : sw_word;
  2181. begin
  2182. endp:=pchar(Buffer)+BufPtr(P);
  2183. pc:=pchar(Buffer);
  2184. lines:=0;
  2185. while (pc<endp) do
  2186. begin
  2187. if pc^ in [#10,#13] then
  2188. begin
  2189. inc(lines);
  2190. if ord((pc+1)^)+ord(pc^)=23 then
  2191. begin
  2192. inc(pc);
  2193. if (pc>=endp) then
  2194. break;
  2195. end;
  2196. end;
  2197. inc(pc);
  2198. end;
  2199. LineNr:=Lines;
  2200. end;
  2201. procedure TEditor.Lock;
  2202. begin
  2203. Inc (LockCount);
  2204. end; { TEditor.Lock }
  2205. function TEditor.NewLine (Select_Mode : Byte) : Boolean;
  2206. VAR
  2207. I : Sw_Word; { Used to track spaces for AutoIndent. }
  2208. P : Sw_Word; { Position of Cursor when we arrive and after Newline. }
  2209. begin
  2210. P := LineStart (CurPtr);
  2211. I := P;
  2212. { The first thing we do is remove any End Of Line spaces. }
  2213. { Then we check to see how many spaces are on beginning }
  2214. { of a line. We need this check to add them after CR/LF }
  2215. { if AutoIndenting. Last of all we insert spaces required }
  2216. { for the AutoIndenting, if it was on. }
  2217. Remove_EOL_Spaces (Select_Mode);
  2218. while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do
  2219. Inc (I);
  2220. if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then
  2221. exit;
  2222. if AutoIndent then
  2223. InsertText (@Buffer^[P], I - P, False);
  2224. { Remember where the CurPtr is at this moment. }
  2225. { Remember the length of the buffer at the moment. }
  2226. { Go to the previous line and remove EOL spaces. }
  2227. { Once removed, re-set the cursor to where we were }
  2228. { minus any spaces that might have been removed. }
  2229. I := BufLen;
  2230. P := CurPtr;
  2231. SetCurPtr (LineMove (CurPtr, - 1), Select_Mode);
  2232. Remove_EOL_Spaces (Select_Mode);
  2233. if I - BufLen <> 0 then
  2234. SetCurPtr (P - (I - BufLen), Select_Mode)
  2235. else
  2236. SetCurPtr (P, Select_Mode);
  2237. NewLine:=true;
  2238. end; { TEditor.NewLine }
  2239. function TEditor.NextChar (P : Sw_Word) : Sw_Word;
  2240. var
  2241. pc : pchar;
  2242. begin
  2243. if P<>BufLen then
  2244. begin
  2245. inc(P);
  2246. if P<>BufLen then
  2247. begin
  2248. pc:=pchar(Buffer);
  2249. if P>=CurPtr then
  2250. inc(pc,GapLen);
  2251. inc(pc,P-1);
  2252. if ord(pc^)+ord((pc+1)^)=23 then
  2253. inc(p);
  2254. end;
  2255. end;
  2256. NextChar:=P;
  2257. end; { TEditor.NextChar }
  2258. function TEditor.NextLine (P : Sw_Word) : Sw_Word;
  2259. begin
  2260. NextLine := NextChar (LineEnd (P));
  2261. end; { TEditor.NextLine }
  2262. function TEditor.NextWord (P : Sw_Word) : Sw_Word;
  2263. begin
  2264. { skip word }
  2265. while (P < BufLen) and (BufChar (P) in WordChars) do
  2266. P := NextChar (P);
  2267. { skip spaces }
  2268. while (P < BufLen) and not (BufChar (P) in WordChars) do
  2269. P := NextChar (P);
  2270. NextWord := P;
  2271. end; { TEditor.NextWord }
  2272. function TEditor.PrevChar (P : Sw_Word) : Sw_Word;
  2273. var
  2274. pc : pchar;
  2275. begin
  2276. if p<>0 then
  2277. begin
  2278. dec(p);
  2279. if p<>0 then
  2280. begin
  2281. pc:=pchar(Buffer);
  2282. if P>=CurPtr then
  2283. inc(pc,GapLen);
  2284. inc(pc,P-1);
  2285. if ord(pc^)+ord((pc+1)^)=23 then
  2286. dec(p);
  2287. end;
  2288. end;
  2289. PrevChar:=P;
  2290. end; { TEditor.PrevChar }
  2291. function TEditor.PrevLine (P : Sw_Word) : Sw_Word;
  2292. begin
  2293. PrevLine := LineStart (PrevChar (P));
  2294. end; { TEditor.PrevLine }
  2295. function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
  2296. begin
  2297. { skip spaces }
  2298. while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do
  2299. P := PrevChar (P);
  2300. { skip word }
  2301. while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do
  2302. P := PrevChar (P);
  2303. PrevWord := P;
  2304. end; { TEditor.PrevWord }
  2305. procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
  2306. { This procedure will do a reformat of the entire document, or just }
  2307. { from the current line to the end of the document, if ^QU is pressed. }
  2308. { It simply brings up the correct dialog box, and then calls the }
  2309. { TEditor.Reformat_Paragraph procedure to do the actual reformatting. }
  2310. CONST
  2311. efCurrentLine = $0000; { Radio button #1 selection for dialog box. }
  2312. efWholeDocument = $0001; { Radio button #2 selection for dialog box. }
  2313. VAR
  2314. Reformat_Options : Word; { Holds the dialog options for reformatting. }
  2315. begin
  2316. { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
  2317. { allows reformatting of document and if not show user dialog that }
  2318. { says reformatting is not permissable. }
  2319. if not Word_Wrap then
  2320. begin
  2321. if not Allow_Reformat then
  2322. begin
  2323. EditorDialog (edReformatNotAllowed, nil);
  2324. Exit;
  2325. end;
  2326. Word_Wrap := True;
  2327. Update (ufStats);
  2328. end;
  2329. { Default radio button option to 1st one. Bring up dialog box. }
  2330. Reformat_Options := efCurrentLine;
  2331. if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then
  2332. begin
  2333. { If the option to reformat the whole document was selected }
  2334. { we need to go back to start of document. Otherwise we stay }
  2335. { on the current line. Call Reformat_Paragraph until we get }
  2336. { to the end of the document to do the reformatting. }
  2337. if Reformat_Options and efWholeDocument <> 0 then
  2338. SetCurPtr (0, Select_Mode);
  2339. Unlock;
  2340. repeat
  2341. Lock;
  2342. if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then
  2343. Exit;
  2344. TrackCursor (False);
  2345. Unlock;
  2346. until CurPtr = BufLen;
  2347. end;
  2348. end; { TEditor.Reformat_Document }
  2349. function TEditor.Reformat_Paragraph (Select_Mode : Byte;
  2350. Center_Cursor : Boolean) : Boolean;
  2351. { This procedure will do a reformat of the current paragraph if ^B pressed. }
  2352. { The feature works regardless if wordrap is on or off. It also supports }
  2353. { the AutoIndent feature. Reformat is not possible if the CurPos exceeds }
  2354. { the Right_Margin. Right_Margin is where the EOL is considered to be. }
  2355. CONST
  2356. Space : array [1..2] of Char = #32#32;
  2357. VAR
  2358. C : Sw_Word; { Position of CurPtr when we come into procedure. }
  2359. E : Sw_Word; { End of a line. }
  2360. S : Sw_Word; { Start of a line. }
  2361. begin
  2362. Reformat_Paragraph := False;
  2363. { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
  2364. { allows reformatting of paragraph and if not show user dialog that }
  2365. { says reformatting is not permissable. }
  2366. if not Word_Wrap then
  2367. begin
  2368. if not Allow_Reformat then
  2369. begin
  2370. EditorDialog (edReformatNotAllowed, nil);
  2371. Exit;
  2372. end;
  2373. Word_Wrap := True;
  2374. Update (ufStats);
  2375. end;
  2376. C := CurPtr;
  2377. E := LineEnd (CurPtr);
  2378. S := LineStart (CurPtr);
  2379. { Reformat possible only if current line is NOT blank! }
  2380. if E <> S then
  2381. begin
  2382. { Reformat is NOT possible if the first word }
  2383. { on the line is beyond the Right_Margin. }
  2384. S := LineStart (CurPtr);
  2385. if NextWord (S) - S >= Right_Margin - 1 then
  2386. begin
  2387. EditorDialog (edReformNotPossible, nil);
  2388. Exit;
  2389. end;
  2390. { First objective is to find the first blank line }
  2391. { after this paragraph so we know when to stop. }
  2392. { That could be the end of the document. }
  2393. Repeat
  2394. SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
  2395. E := LineEnd (CurPtr);
  2396. S := LineStart (CurPtr);
  2397. BlankLine := E;
  2398. until ((CurPtr = BufLen) or (E = S));
  2399. SetCurPtr (C, Select_Mode);
  2400. repeat
  2401. { Set CurPtr to LineEnd and remove the EOL spaces. }
  2402. { Pull up the next line and remove its EOL space. }
  2403. { First make sure the next line is not BlankLine! }
  2404. { Insert spaces as required between the two lines. }
  2405. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2406. Remove_EOL_Spaces (Select_Mode);
  2407. if CurPtr <> Blankline - 2 then
  2408. DeleteRange (CurPtr, Nextword (CurPtr), True);
  2409. Remove_EOL_Spaces (Select_Mode);
  2410. case Buffer^[CurPtr-1] of
  2411. '!' : InsertText (@Space, 2, False);
  2412. '.' : InsertText (@Space, 2, False);
  2413. ':' : InsertText (@Space, 2, False);
  2414. '?' : InsertText (@Space, 2, False);
  2415. else
  2416. InsertText (@Space, 1, False);
  2417. end;
  2418. { Reset CurPtr to EOL. While line length is > Right_Margin }
  2419. { go Do_Word_Wrap. If wordrap failed, exit routine. }
  2420. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2421. while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do
  2422. if not Do_Word_Wrap (Select_Mode, Center_Cursor) then
  2423. Exit;
  2424. { If LineEnd - LineStart > Right_Margin then set CurPtr }
  2425. { to Right_Margin on current line. Otherwise we set the }
  2426. { CurPtr to LineEnd. This gyration sets up the conditions }
  2427. { to test for time of loop exit. }
  2428. if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then
  2429. SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode)
  2430. else
  2431. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2432. until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2));
  2433. end;
  2434. { If not at the end of the document reset CurPtr to start of next line. }
  2435. { This should be a blank line between paragraphs. }
  2436. if CurPtr < BufLen then
  2437. SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
  2438. Reformat_Paragraph := True;
  2439. end; { TEditor.Reformat_Paragraph }
  2440. procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte);
  2441. { This procedure tests to see if there are consecutive spaces }
  2442. { at the end of a line (EOL). If so, we delete all spaces }
  2443. { after the last non-space character to the end of line. }
  2444. { We then reset the CurPtr to where we ended up at. }
  2445. VAR
  2446. C : Sw_Word; { Current pointer when we come into procedure. }
  2447. E : Sw_Word; { End of line. }
  2448. P : Sw_Word; { Position of pointer at any given moment. }
  2449. S : Sw_Word; { Start of a line. }
  2450. begin
  2451. C := CurPtr;
  2452. E := LineEnd (CurPtr);
  2453. P := E;
  2454. S := LineStart (CurPtr);
  2455. { Start at the end of a line and move towards the start. }
  2456. { Find first non-space character in that direction. }
  2457. while (P > S) and (BufChar (PrevChar (P)) = #32) do
  2458. P := PrevChar (P);
  2459. { If we found any spaces then delete them. }
  2460. if P < E then
  2461. begin
  2462. SetSelect (P, E, True);
  2463. DeleteSelect;
  2464. Update_Place_Markers (0, E - P, P, E);
  2465. end;
  2466. { If C, our pointer when we came into this procedure, }
  2467. { is less than the CurPtr then reset CurPtr to C so }
  2468. { cursor is where we started. Otherwise, set it to }
  2469. { the new CurPtr, for we have deleted characters. }
  2470. if C < CurPtr then
  2471. SetCurPtr (C, Select_Mode)
  2472. else
  2473. SetCurPtr (CurPtr, Select_Mode);
  2474. end; { TEditor.Remove_EOL_Spaces }
  2475. procedure TEditor.Replace;
  2476. VAR
  2477. ReplaceRec : TReplaceDialogRec;
  2478. begin
  2479. with ReplaceRec do
  2480. begin
  2481. Find := FindStr;
  2482. Replace := ReplaceStr;
  2483. Options := Flags;
  2484. if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then
  2485. begin
  2486. FindStr := Find;
  2487. ReplaceStr := Replace;
  2488. Flags := Options or efDoReplace;
  2489. DoSearchReplace;
  2490. end;
  2491. end;
  2492. end; { TEditor.Replace }
  2493. procedure TEditor.Scroll_Down;
  2494. { This procedure will scroll the screen up, and always keep }
  2495. { the cursor on the CurPos.Y position, but not necessarily on }
  2496. { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
  2497. { will stay in the upper left corner of the screen. This will }
  2498. { simulate the same process in the IDE. The CurPos.X coordinate }
  2499. { only messes up if we are on long lines and we then encounter }
  2500. { a shorter or blank line beneath the current one as we scroll. }
  2501. { In that case, it goes to the end of the new line. }
  2502. VAR
  2503. C : Sw_Word; { Position of CurPtr when we enter procedure. }
  2504. P : Sw_Word; { Position of CurPtr at any given time. }
  2505. W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
  2506. begin
  2507. { Remember current cursor position. Remember current CurPos.Y position. }
  2508. { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will }
  2509. { go to the bottom of the current screen. Reset the cursor to this new }
  2510. { position and then send FALSE to TrackCursor so we fool it into }
  2511. { incrementing Delta.Y by only +1. If we didn't do this it would try }
  2512. { to center the cursor on the screen by fiddling with Delta.Y. }
  2513. C := CurPtr;
  2514. W.X := CurPos.Y;
  2515. P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y);
  2516. SetCurPtr (P, 0);
  2517. TrackCursor (False);
  2518. { Now remember where the new CurPos.Y is. See if distance between new }
  2519. { CurPos.Y and old CurPos.Y are greater than the current screen size. }
  2520. { If they are, we need to move cursor position itself down by one. }
  2521. { Otherwise, send the cursor back to our original CurPtr. }
  2522. W.Y := CurPos.Y;
  2523. if W.Y - W.X > Size.Y - 1 then
  2524. SetCurPtr (LineMove (C, 1), 0)
  2525. else
  2526. SetCurPtr (C, 0);
  2527. end; { TEditor.Scroll_Down }
  2528. procedure TEditor.Scroll_Up;
  2529. { This procedure will scroll the screen down, and always keep }
  2530. { the cursor on the CurPos.Y position, but not necessarily on }
  2531. { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
  2532. { will stay in the bottom left corner of the screen. This will }
  2533. { simulate the same process in the IDE. The CurPos.X coordinate }
  2534. { only messes up if we are on long lines and we then encounter }
  2535. { a shorter or blank line beneath the current one as we scroll. }
  2536. { In that case, it goes to the end of the new line. }
  2537. VAR
  2538. C : Sw_Word; { Position of CurPtr when we enter procedure. }
  2539. P : Sw_Word; { Position of CurPtr at any given time. }
  2540. W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
  2541. begin
  2542. { Remember current cursor position. Remember current CurPos.Y position. }
  2543. { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will }
  2544. { go to the top of the current screen. Reset the cursor to this new }
  2545. { position and then send FALSE to TrackCursor so we fool it into }
  2546. { decrementing Delta.Y by only -1. If we didn't do this it would try }
  2547. { to center the cursor on the screen by fiddling with Delta.Y. }
  2548. C := CurPtr;
  2549. W.Y := CurPos.Y;
  2550. P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1));
  2551. SetCurPtr (P, 0);
  2552. TrackCursor (False);
  2553. { Now remember where the new CurPos.Y is. See if distance between new }
  2554. { CurPos.Y and old CurPos.Y are greater than the current screen size. }
  2555. { If they are, we need to move the cursor position itself up by one. }
  2556. { Otherwise, send the cursor back to our original CurPtr. }
  2557. W.X := CurPos.Y;
  2558. if W.Y - W.X > Size.Y - 1 then
  2559. SetCurPtr (LineMove (C, -1), 0)
  2560. else
  2561. SetCurPtr (C, 0);
  2562. end; { TEditor.Scroll_Up }
  2563. procedure TEditor.ScrollTo (X, Y : Sw_Integer);
  2564. begin
  2565. X := Max (0, Min (X, Limit.X - Size.X));
  2566. Y := Max (0, Min (Y, Limit.Y - Size.Y));
  2567. if (X <> Delta.X) or (Y <> Delta.Y) then
  2568. begin
  2569. Delta.X := X;
  2570. Delta.Y := Y;
  2571. Update (ufView);
  2572. end;
  2573. end; { TEditor.ScrollTo }
  2574. function TEditor.Search (const FindStr : String; Opts : Word) : Boolean;
  2575. VAR
  2576. I,Pos : Sw_Word;
  2577. begin
  2578. Search := False;
  2579. Pos := CurPtr;
  2580. repeat
  2581. if Opts and efCaseSensitive <> 0 then
  2582. I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr)
  2583. else
  2584. I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr);
  2585. if (I <> sfSearchFailed) then
  2586. begin
  2587. Inc (I, Pos);
  2588. if (Opts and efWholeWordsOnly = 0) or
  2589. not (((I <> 0) and (BufChar (I - 1) in WordChars)) or
  2590. ((I + Length (FindStr) <> BufLen) and
  2591. (BufChar (I + Length (FindStr)) in WordChars))) then
  2592. begin
  2593. Lock;
  2594. SetSelect (I, I + Length (FindStr), False);
  2595. TrackCursor (not CursorVisible);
  2596. Unlock;
  2597. Search := True;
  2598. Exit;
  2599. end
  2600. else
  2601. Pos := I + 1;
  2602. end;
  2603. until I = sfSearchFailed;
  2604. end; { TEditor.Search }
  2605. procedure TEditor.Select_Word;
  2606. { This procedure will select the a word to put into the clipboard. }
  2607. { I've added it just to maintain compatibility with the IDE editor. }
  2608. { Note that selection starts at the current cursor position and ends }
  2609. { when a space or the end of line is encountered. }
  2610. VAR
  2611. E : Sw_Word; { End of the current line. }
  2612. Select_Mode : Byte; { Allows us to turn select mode on inside procedure. }
  2613. begin
  2614. E := LineEnd (CurPtr);
  2615. { If the cursor is on a space or at the end of a line, abort. }
  2616. { Stupid action on users part for you can't select blanks! }
  2617. if (BufChar (CurPtr) = #32) or (CurPtr = E) then
  2618. Exit;
  2619. { Turn on select mode and tell editor to start selecting text. }
  2620. { As long as we have a character > a space (this is done to }
  2621. { exclude CR/LF pairs at end of a line) and we are NOT at the }
  2622. { end of a line, set the CurPtr to the next character. }
  2623. { Once we find a space or CR/LF, selection is done and we }
  2624. { automatically put the selected word into the Clipboard. }
  2625. Select_Mode := smExtend;
  2626. StartSelect;
  2627. while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do
  2628. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2629. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2630. ClipCopy;
  2631. end; {TEditor.Select_Word }
  2632. procedure TEditor.SetBufLen (Length : Sw_Word);
  2633. begin
  2634. BufLen := Length;
  2635. GapLen := BufSize - Length;
  2636. SelStart := 0;
  2637. SelEnd := 0;
  2638. CurPtr := 0;
  2639. CurPos.X:=0;
  2640. CurPos.Y:=0;
  2641. Delta.X:=0;
  2642. Delta.Y:=0;
  2643. GetLimits(Buffer^[GapLen], BufLen,Limit);
  2644. inc(Limit.X);
  2645. inc(Limit.Y);
  2646. DrawLine := 0;
  2647. DrawPtr := 0;
  2648. DelCount := 0;
  2649. InsCount := 0;
  2650. Modified := False;
  2651. Update (ufView);
  2652. end; { TEditor.SetBufLen }
  2653. function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
  2654. begin
  2655. ReAllocMem(Buffer, NewSize);
  2656. BufSize := NewSize;
  2657. SetBufSize := True;
  2658. end; { TEditor.SetBufSize }
  2659. procedure TEditor.SetCmdState (Command : Word; Enable : Boolean);
  2660. VAR
  2661. S : TCommandSet;
  2662. begin
  2663. S := [Command];
  2664. if Enable and (State and sfActive <> 0) then
  2665. EnableCommands (S)
  2666. else
  2667. DisableCommands (S);
  2668. end; { TEditor.SetCmdState }
  2669. procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte);
  2670. VAR
  2671. Anchor : Sw_Word;
  2672. begin
  2673. if SelectMode and smExtend = 0 then
  2674. Anchor := P
  2675. else
  2676. if CurPtr = SelStart then
  2677. Anchor := SelEnd
  2678. else
  2679. Anchor := SelStart;
  2680. if P < Anchor then
  2681. begin
  2682. if SelectMode and smDouble <> 0 then
  2683. begin
  2684. P := PrevLine (NextLine (P));
  2685. Anchor := NextLine (PrevLine (Anchor));
  2686. end;
  2687. SetSelect (P, Anchor, True);
  2688. end
  2689. else
  2690. begin
  2691. if SelectMode and smDouble <> 0 then
  2692. begin
  2693. P := NextLine (P);
  2694. Anchor := PrevLine (NextLine (Anchor));
  2695. end;
  2696. SetSelect (Anchor, P, False);
  2697. end;
  2698. end; { TEditor.SetCurPtr }
  2699. procedure TEditor.Set_Place_Marker (Element : Byte);
  2700. { This procedure sets a place marker for the CurPtr if ^K# is pressed. }
  2701. begin
  2702. if not IsClipboard then
  2703. Place_Marker[Element] := CurPtr;
  2704. end; { TEditor.Set_Place_Marker }
  2705. procedure TEditor.Set_Right_Margin;
  2706. { This procedure will bring up a dialog box }
  2707. { that allows the user to set Right_Margin. }
  2708. { Values must be < MaxLineLength and > 9. }
  2709. VAR
  2710. Code : Integer; { Used for Val conversion. }
  2711. Margin_Data : TRightMarginRec; { Holds dialog results. }
  2712. Temp_Value : Sw_Integer; { Holds converted dialog value. }
  2713. begin
  2714. with Margin_Data do
  2715. begin
  2716. Str (Right_Margin, Margin_Position);
  2717. if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then
  2718. begin
  2719. val (Margin_Position, Temp_Value, Code);
  2720. if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then
  2721. Right_Margin := Temp_Value;
  2722. end;
  2723. end;
  2724. end; { TEditor.Set_Right_Margin }
  2725. procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
  2726. VAR
  2727. UFlags : Byte;
  2728. P : Sw_Word;
  2729. L : Sw_Word;
  2730. begin
  2731. if CurStart then
  2732. P := NewStart
  2733. else
  2734. P := NewEnd;
  2735. UFlags := ufUpdate;
  2736. if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
  2737. if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
  2738. UFlags := ufView;
  2739. if P <> CurPtr then
  2740. begin
  2741. if P > CurPtr then
  2742. begin
  2743. L := P - CurPtr;
  2744. Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
  2745. Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L));
  2746. CurPtr := P;
  2747. end
  2748. else
  2749. begin
  2750. L := CurPtr - P;
  2751. CurPtr := P;
  2752. Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L));
  2753. Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
  2754. end;
  2755. DrawLine := CurPos.Y;
  2756. DrawPtr := LineStart (P);
  2757. CurPos.X := CharPos (DrawPtr, P);
  2758. DelCount := 0;
  2759. InsCount := 0;
  2760. SetBufSize (BufLen);
  2761. end;
  2762. SelStart := NewStart;
  2763. SelEnd := NewEnd;
  2764. Update (UFlags);
  2765. end; { TEditor.Select }
  2766. procedure TEditor.SetState (AState : Word; Enable : Boolean);
  2767. begin
  2768. Inherited SetState (AState, Enable);
  2769. case AState of
  2770. sfActive: begin
  2771. if assigned(HScrollBar) then
  2772. HScrollBar^.SetState (sfVisible, Enable);
  2773. if assigned(VScrollBar) then
  2774. VScrollBar^.SetState (sfVisible, Enable);
  2775. if assigned(Indicator) then
  2776. Indicator^.SetState (sfVisible, Enable);
  2777. UpdateCommands;
  2778. end;
  2779. sfExposed: if Enable then Unlock;
  2780. end;
  2781. end; { TEditor.SetState }
  2782. procedure TEditor.Set_Tabs;
  2783. { This procedure will bring up a dialog box }
  2784. { that allows the user to set tab stops. }
  2785. VAR
  2786. Index : Sw_Integer; { Index into string array. }
  2787. Tab_Data : TTabStopRec; { Holds dialog results. }
  2788. begin
  2789. with Tab_Data do
  2790. begin
  2791. { Assign current Tab_Settings to Tab_String. }
  2792. { Bring up the tab dialog so user can set tabs. }
  2793. Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length);
  2794. if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then
  2795. begin
  2796. { If Tab_String comes back as empty then set Tab_Settings to nil. }
  2797. { Otherwise, find the last character in Tab_String that is not }
  2798. { a space and copy Tab_String into Tab_Settings up to that spot. }
  2799. if Length (Tab_String) = 0 then
  2800. begin
  2801. FillChar (Tab_Settings, SizeOf (Tab_Settings), #0);
  2802. Tab_Settings[0] := #0;
  2803. Exit;
  2804. end
  2805. else
  2806. begin
  2807. Index := Length (Tab_String);
  2808. while Tab_String[Index] <= #32 do
  2809. Dec (Index);
  2810. Tab_Settings := Copy (Tab_String, 1, Index);
  2811. end;
  2812. end;
  2813. end;
  2814. end; { TEditor.Set_Tabs }
  2815. procedure TEditor.StartSelect;
  2816. begin
  2817. HideSelect;
  2818. Selecting := True;
  2819. end; { TEditor.StartSelect }
  2820. procedure TEditor.Store (var S : Objects.TStream);
  2821. begin
  2822. Inherited Store (S);
  2823. PutPeerViewPtr (S, HScrollBar);
  2824. PutPeerViewPtr (S, VScrollBar);
  2825. PutPeerViewPtr (S, Indicator);
  2826. S.Write (BufSize, SizeOf (BufSize));
  2827. S.Write (Canundo, SizeOf (Canundo));
  2828. S.Write (AutoIndent, SizeOf (AutoIndent));
  2829. S.Write (Line_Number, SizeOf (Line_Number));
  2830. S.Write (Place_Marker, SizeOf (Place_Marker));
  2831. S.Write (Right_Margin, SizeOf (Right_Margin));
  2832. S.Write (Tab_Settings, SizeOf (Tab_Settings));
  2833. S.Write (Word_Wrap, SizeOf (Word_Wrap));
  2834. end; { Editor.Store }
  2835. procedure TEditor.Tab_Key (Select_Mode : Byte);
  2836. { This function determines if we are in overstrike or insert mode, }
  2837. { and then moves the cursor if overstrike, or adds spaces if insert. }
  2838. VAR
  2839. E : Sw_Word; { End of current line. }
  2840. Index : Sw_Integer; { Loop counter. }
  2841. Position : Sw_Integer; { CurPos.X position. }
  2842. S : Sw_Word; { Start of current line. }
  2843. Spaces : array [1..80] of Char; { Array to hold spaces for insertion. }
  2844. begin
  2845. E := LineEnd (CurPtr);
  2846. S := LineStart (CurPtr);
  2847. { Find the current horizontal cursor position. }
  2848. { Now loop through the Tab_Settings string and }
  2849. { find the next available tab stop. }
  2850. Position := CurPos.X + 1;
  2851. repeat
  2852. Inc (Position);
  2853. until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0]));
  2854. E := CurPos.X;
  2855. Index := 1;
  2856. { Now we enter a loop to go to the next tab position. }
  2857. { If we are in overwrite mode, we just move the cursor }
  2858. { through the text to the next tab stop. If we are in }
  2859. { insert mode, we add spaces to the Spaces array for }
  2860. { the number of times we loop. }
  2861. while Index < Position - E do
  2862. begin
  2863. if Overwrite then
  2864. begin
  2865. if (Position > LineEnd (CurPtr) - LineStart (CurPtr))
  2866. or (Position > Ord (Tab_Settings[0])) then
  2867. begin
  2868. SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
  2869. Exit;
  2870. end
  2871. else
  2872. if CurPtr < BufLen then
  2873. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2874. end
  2875. else
  2876. begin
  2877. if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then
  2878. begin
  2879. SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
  2880. Exit;
  2881. end
  2882. else
  2883. Spaces[Index] := #32;
  2884. end;
  2885. Inc (Index);
  2886. end;
  2887. { If we are insert mode, we insert spaces to the next tab stop. }
  2888. { When we're all done, the cursor will be sitting on the new tab stop. }
  2889. if not OverWrite then
  2890. InsertText (@Spaces, Index - 1, False);
  2891. end; { TEditor.Tab_Key }
  2892. procedure TEditor.ToggleInsMode;
  2893. begin
  2894. Overwrite := not Overwrite;
  2895. SetState (sfCursorIns, not GetState (sfCursorIns));
  2896. end; { TEditor.ToggleInsMode }
  2897. procedure TEditor.TrackCursor (Center : Boolean);
  2898. begin
  2899. if Center then
  2900. ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2)
  2901. else
  2902. ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)),
  2903. Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y)));
  2904. end; { TEditor.TrackCursor }
  2905. procedure TEditor.Undo;
  2906. VAR
  2907. Length : Sw_Word;
  2908. begin
  2909. if (DelCount <> 0) or (InsCount <> 0) then
  2910. begin
  2911. Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount);
  2912. SelStart := CurPtr - InsCount;
  2913. SelEnd := CurPtr;
  2914. Length := DelCount;
  2915. DelCount := 0;
  2916. InsCount := 0;
  2917. InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True);
  2918. end;
  2919. end; { TEditor.Undo }
  2920. procedure TEditor.Unlock;
  2921. begin
  2922. if LockCount > 0 then
  2923. begin
  2924. Dec (LockCount);
  2925. if LockCount = 0 then
  2926. DoUpdate;
  2927. end;
  2928. end; { TEditor.Unlock }
  2929. procedure TEditor.Update (AFlags : Byte);
  2930. begin
  2931. UpdateFlags := UpdateFlags or AFlags;
  2932. if LockCount = 0 then
  2933. DoUpdate;
  2934. end; { TEditor.Update }
  2935. procedure TEditor.UpdateCommands;
  2936. begin
  2937. SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0));
  2938. if not IsClipboard then
  2939. begin
  2940. SetCmdState (cmCut, HasSelection);
  2941. SetCmdState (cmCopy, HasSelection);
  2942. SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
  2943. end;
  2944. SetCmdState (cmClear, HasSelection);
  2945. SetCmdState (cmFind, True);
  2946. SetCmdState (cmReplace, True);
  2947. SetCmdState (cmSearchAgain, True);
  2948. end; { TEditor.UpdateCommands }
  2949. procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word;
  2950. StartPtr,EndPtr : Sw_Word);
  2951. { This procedure updates the position of the place markers }
  2952. { as the user inserts and deletes text in the document. }
  2953. VAR
  2954. Element : Byte; { Place_Marker array element to traverse array with. }
  2955. begin
  2956. for Element := 1 to 10 do
  2957. begin
  2958. if AddCount > 0 then
  2959. begin
  2960. if (Place_Marker[Element] >= Curptr)
  2961. and (Place_Marker[Element] <> 0) then
  2962. Place_Marker[Element] := Place_Marker[Element] + AddCount;
  2963. end
  2964. else
  2965. begin
  2966. if Place_Marker[Element] >= StartPtr then
  2967. begin
  2968. if (Place_Marker[Element] >= StartPtr) and
  2969. (Place_Marker[Element] < EndPtr) then
  2970. Place_marker[Element] := 0
  2971. else
  2972. begin
  2973. if integer (Place_Marker[Element]) - integer (KillCount) > 0 then
  2974. Place_Marker[Element] := Place_Marker[Element] - KillCount
  2975. else
  2976. Place_Marker[Element] := 0;
  2977. end;
  2978. end;
  2979. end;
  2980. end;
  2981. if AddCount > 0 then
  2982. BlankLine := BlankLine + AddCount
  2983. else
  2984. begin
  2985. if integer (BlankLine) - Integer (KillCount) > 0 then
  2986. BlankLine := BlankLine - KillCount
  2987. else
  2988. BlankLine := 0;
  2989. end;
  2990. end; { TEditor.Update_Place_Markers }
  2991. function TEditor.Valid (Command : Word) : Boolean;
  2992. begin
  2993. Valid := IsValid;
  2994. end; { TEditor.Valid }
  2995. {****************************************************************************
  2996. TMEMO
  2997. ****************************************************************************}
  2998. constructor TMemo.Load (var S : Objects.TStream);
  2999. VAR
  3000. Length : Sw_Word;
  3001. begin
  3002. Inherited Load (S);
  3003. S.Read (Length, SizeOf (Length));
  3004. if IsValid then
  3005. begin
  3006. S.Read (Buffer^[BufSize - Length], Length);
  3007. SetBufLen (Length);
  3008. end
  3009. else
  3010. S.Seek (S.GetPos + Length);
  3011. end; { TMemo.Load }
  3012. function TMemo.DataSize : Sw_Word;
  3013. begin
  3014. DataSize := BufSize + SizeOf (Sw_Word);
  3015. end; { TMemo.DataSize }
  3016. procedure TMemo.GetData (var Rec);
  3017. VAR
  3018. Data : TMemoData absolute Rec;
  3019. begin
  3020. Data.Length := BufLen;
  3021. Move (Buffer^, Data.Buffer, CurPtr);
  3022. Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
  3023. FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0);
  3024. end; { TMemo.GetData }
  3025. function TMemo.GetPalette : PPalette;
  3026. CONST
  3027. P : String[Length (CMemo)] = CMemo;
  3028. begin
  3029. GetPalette := @P;
  3030. end; { TMemo.GetPalette }
  3031. procedure TMemo.HandleEvent (var Event : Drivers.TEvent);
  3032. begin
  3033. if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then
  3034. Inherited HandleEvent (Event);
  3035. end; { TMemo.HandleEvent }
  3036. procedure TMemo.SetData (var Rec);
  3037. VAR
  3038. Data : TMemoData absolute Rec;
  3039. begin
  3040. Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
  3041. SetBufLen (Data.Length);
  3042. end; { TMemo.SetData }
  3043. procedure TMemo.Store (var S : Objects.TStream);
  3044. begin
  3045. Inherited Store (S);
  3046. S.Write (BufLen, SizeOf (BufLen));
  3047. S.Write (Buffer^, CurPtr);
  3048. S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  3049. end; { TMemo.Store }
  3050. {****************************************************************************
  3051. TFILEEDITOR
  3052. ****************************************************************************}
  3053. constructor TFileEditor.Init (var Bounds : TRect;
  3054. AHScrollBar, AVScrollBar : PScrollBar;
  3055. AIndicator : PIndicator;
  3056. AFileName : FNameStr);
  3057. begin
  3058. Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
  3059. if AFileName <> '' then
  3060. begin
  3061. FileName := FExpand (AFileName);
  3062. if IsValid then
  3063. IsValid := LoadFile;
  3064. end;
  3065. end; { TFileEditor.Init }
  3066. constructor TFileEditor.Load (var S : Objects.TStream);
  3067. VAR
  3068. SStart,SEnd,Curs : Sw_Word;
  3069. begin
  3070. Inherited Load (S);
  3071. BufSize := 0;
  3072. S.Read (FileName[0], SizeOf (Byte));
  3073. S.Read (Filename[1], Length (FileName));
  3074. if IsValid then
  3075. IsValid := LoadFile;
  3076. S.Read (SStart, SizeOf (SStart));
  3077. S.Read (SEnd, SizeOf (SEnd));
  3078. S.Read (Curs, SizeOf (Curs));
  3079. if IsValid and (SEnd <= BufLen) then
  3080. begin
  3081. SetSelect (SStart, SEnd, Curs = SStart);
  3082. TrackCursor (True);
  3083. end;
  3084. end; { TFileEditor.Load }
  3085. procedure TFileEditor.DoneBuffer;
  3086. begin
  3087. ReAllocMem(Buffer, 0);
  3088. end; { TFileEditor.DoneBuffer }
  3089. procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent);
  3090. begin
  3091. Inherited HandleEvent (Event);
  3092. case Event.What of
  3093. Drivers.evCommand:
  3094. case Event.Command of
  3095. cmSave : Save;
  3096. cmSaveAs : SaveAs;
  3097. cmSaveDone : if Save then
  3098. Message (Owner, Drivers.evCommand, cmClose, nil);
  3099. else
  3100. Exit;
  3101. end;
  3102. else
  3103. Exit;
  3104. end;
  3105. ClearEvent (Event);
  3106. end; { TFileEditor.HandleEvent }
  3107. procedure TFileEditor.InitBuffer;
  3108. begin
  3109. Assert(Buffer = nil, 'TFileEditor.InitBuffer: Buffer is not nil');
  3110. ReAllocMem(Buffer, MinBufLength);
  3111. BufSize := MinBufLength;
  3112. end; { TFileEditor.InitBuffer }
  3113. function TFileEditor.LoadFile: Boolean;
  3114. VAR
  3115. Length : Sw_Word;
  3116. FSize : Longint;
  3117. FRead : Sw_Integer;
  3118. F : File;
  3119. begin
  3120. LoadFile := False;
  3121. Length := 0;
  3122. Assign(F, FileName);
  3123. Reset(F, 1);
  3124. if IOResult <> 0 then
  3125. EditorDialog(edReadError, @FileName)
  3126. else
  3127. begin
  3128. FSize := FileSize(F);
  3129. if (FSize > MaxBufLength) or not SetBufSize(FSize) then
  3130. EditorDialog(edOutOfMemory, nil)
  3131. else
  3132. begin
  3133. BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead);
  3134. if (IOResult <> 0) or (FRead<>FSize) then
  3135. EditorDialog(edReadError, @FileName)
  3136. else
  3137. begin
  3138. LoadFile := True;
  3139. Length := FRead;
  3140. end;
  3141. end;
  3142. Close(F);
  3143. end;
  3144. SetBufLen(Length);
  3145. end; { TFileEditor.LoadFile }
  3146. function TFileEditor.Save : Boolean;
  3147. begin
  3148. if FileName = '' then
  3149. Save := SaveAs
  3150. else
  3151. Save := SaveFile;
  3152. end; { TFileEditor.Save }
  3153. function TFileEditor.SaveAs : Boolean;
  3154. begin
  3155. SaveAs := False;
  3156. if EditorDialog (edSaveAs, @FileName) <> cmCancel then
  3157. begin
  3158. FileName := FExpand (FileName);
  3159. Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil);
  3160. SaveAs := SaveFile;
  3161. if IsClipboard then
  3162. FileName := '';
  3163. end;
  3164. end; { TFileEditor.SaveAs }
  3165. function TFileEditor.SaveFile : Boolean;
  3166. VAR
  3167. F : File;
  3168. BackupName : Objects.FNameStr;
  3169. D : DOS.DirStr;
  3170. N : DOS.NameStr;
  3171. E : DOS.ExtStr;
  3172. begin
  3173. SaveFile := False;
  3174. if Flags and efBackupFiles <> 0 then
  3175. begin
  3176. FSplit (FileName, D, N, E);
  3177. BackupName := D + N + '.bak';
  3178. Assign (F, BackupName);
  3179. Erase (F);
  3180. Assign (F, FileName);
  3181. Rename (F, BackupName);
  3182. InOutRes := 0;
  3183. end;
  3184. Assign (F, FileName);
  3185. Rewrite (F, 1);
  3186. if IOResult <> 0 then
  3187. EditorDialog (edCreateError, @FileName)
  3188. else
  3189. begin
  3190. BlockWrite (F, Buffer^, CurPtr);
  3191. BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  3192. if IOResult <> 0 then
  3193. EditorDialog (edWriteError, @FileName)
  3194. else
  3195. begin
  3196. Modified := False;
  3197. Update (ufUpdate);
  3198. SaveFile := True;
  3199. end;
  3200. Close (F);
  3201. end;
  3202. end; { TFileEditor.SaveFile }
  3203. function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
  3204. VAR
  3205. N : Sw_Word;
  3206. begin
  3207. SetBufSize := False;
  3208. if NewSize = 0 then
  3209. NewSize := MinBufLength
  3210. else
  3211. if NewSize > (MaxBufLength-MinBufLength) then
  3212. NewSize := MaxBufLength
  3213. else
  3214. NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1)));
  3215. if NewSize <> BufSize then
  3216. begin
  3217. if NewSize > BufSize then ReAllocMem(Buffer, NewSize);
  3218. N := BufLen - CurPtr + DelCount;
  3219. Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
  3220. if NewSize < BufSize then ReAllocMem(Buffer, NewSize);
  3221. BufSize := NewSize;
  3222. GapLen := BufSize - BufLen;
  3223. end;
  3224. SetBufSize := True;
  3225. end; { TFileEditor.SetBufSize }
  3226. procedure TFileEditor.Store (var S : Objects.TStream);
  3227. begin
  3228. Inherited Store (S);
  3229. S.Write (FileName, Length (FileName) + 1);
  3230. S.Write (SelStart, SizeOf (SelStart));
  3231. S.Write (SelEnd, SizeOf (SelEnd));
  3232. S.Write (CurPtr, SizeOf (CurPtr));
  3233. end; { TFileEditor.Store }
  3234. procedure TFileEditor.UpdateCommands;
  3235. begin
  3236. Inherited UpdateCommands;
  3237. SetCmdState (cmSave, True);
  3238. SetCmdState (cmSaveAs, True);
  3239. SetCmdState (cmSaveDone, True);
  3240. end; { TFileEditor.UpdateCommands }
  3241. function TFileEditor.Valid (Command : Word) : Boolean;
  3242. VAR
  3243. D : Integer;
  3244. begin
  3245. if Command = cmValid then
  3246. Valid := IsValid
  3247. else
  3248. begin
  3249. Valid := True;
  3250. if Modified then
  3251. begin
  3252. if FileName = '' then
  3253. D := edSaveUntitled
  3254. else
  3255. D := edSaveModify;
  3256. case EditorDialog (D, @FileName) of
  3257. cmYes : Valid := Save;
  3258. cmNo : Modified := False;
  3259. cmCancel : Valid := False;
  3260. end;
  3261. end;
  3262. end;
  3263. end; { TFileEditor.Valid }
  3264. {****************************************************************************
  3265. TEDITWINDOW
  3266. ****************************************************************************}
  3267. constructor TEditWindow.Init (var Bounds : TRect;
  3268. FileName : Objects.FNameStr;
  3269. ANumber : Integer);
  3270. var
  3271. HScrollBar : PScrollBar;
  3272. VScrollBar : PScrollBar;
  3273. Indicator : PIndicator;
  3274. R : TRect;
  3275. begin
  3276. Inherited Init (Bounds, '', ANumber);
  3277. Options := Options or ofTileable;
  3278. R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y);
  3279. HScrollBar := New (PScrollBar, Init (R));
  3280. HScrollBar^.Hide;
  3281. Insert (HScrollBar);
  3282. R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1);
  3283. VScrollBar := New (PScrollBar, Init (R));
  3284. VScrollBar^.Hide;
  3285. Insert (VScrollBar);
  3286. R.Assign (2, Size.Y - 1, 16, Size.Y);
  3287. Indicator := New (PIndicator, Init (R));
  3288. Indicator^.Hide;
  3289. Insert (Indicator);
  3290. GetExtent (R);
  3291. R.Grow (-1, -1);
  3292. Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName));
  3293. Insert (Editor);
  3294. end; { TEditWindow.Init }
  3295. constructor TEditWindow.Load (var S : Objects.TStream);
  3296. begin
  3297. Inherited Load (S);
  3298. GetSubViewPtr (S, Editor);
  3299. end; { TEditWindow.Load }
  3300. procedure TEditWindow.Close;
  3301. begin
  3302. if Editor^.IsClipboard then
  3303. Hide
  3304. else
  3305. Inherited Close;
  3306. end; { TEditWindow.Close }
  3307. function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr;
  3308. begin
  3309. if Editor^.IsClipboard then
  3310. GetTitle := strings^.get(sClipboard)
  3311. else
  3312. if Editor^.FileName = '' then
  3313. GetTitle := strings^.get(sUntitled)
  3314. else
  3315. GetTitle := Editor^.FileName;
  3316. end; { TEditWindow.GetTile }
  3317. procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent);
  3318. begin
  3319. Inherited HandleEvent (Event);
  3320. if (Event.What = Drivers.evBroadcast) then
  3321. { and (Event.Command = cmUpdateTitle) then }
  3322. { Changed if statement above so I could test for cmBlugeonStats. }
  3323. { Stats would not show up when loading a file until a key was pressed. }
  3324. case Event.Command of
  3325. cmUpdateTitle :
  3326. begin
  3327. Frame^.DrawView;
  3328. ClearEvent (Event);
  3329. end;
  3330. cmBludgeonStats :
  3331. begin
  3332. Editor^.Update (ufStats);
  3333. ClearEvent (Event);
  3334. end;
  3335. end;
  3336. end; { TEditWindow.HandleEvent }
  3337. procedure TEditWindow.SizeLimits(var Min, Max: TPoint);
  3338. begin
  3339. inherited SizeLimits(Min, Max);
  3340. Min.X := 23;
  3341. end;
  3342. procedure TEditWindow.Store (var S : Objects.TStream);
  3343. begin
  3344. Inherited Store (S);
  3345. PutSubViewPtr (S, Editor);
  3346. end; { TEditWindow.Store }
  3347. procedure RegisterEditors;
  3348. begin
  3349. RegisterType (REditor);
  3350. RegisterType (RMemo);
  3351. RegisterType (RFileEditor);
  3352. RegisterType (RIndicator);
  3353. RegisterType (REditWindow);
  3354. end; { RegisterEditors }
  3355. end. { Unit NewEdit }