editors.pas 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751
  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. Memory, 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. { create uppercased string }
  942. s[0]:=chr(len);
  943. for x:=1to len do
  944. begin
  945. if str[x] in ['a'..'z'] then
  946. s[x]:=chr(ord(str[x])-32)
  947. else
  948. s[x]:=str[x];
  949. end;
  950. BMMakeTable(s,bt);
  951. found:=False;
  952. numb:=pred(len);
  953. While (not found) and (numb<(size-len)) do
  954. begin
  955. { partial match }
  956. c:=buffer[numb];
  957. if c in ['a'..'z'] then
  958. c:=chr(ord(c)-32);
  959. if (c=s[len]) then
  960. begin
  961. { less partial! }
  962. p:=@buffer[numb-pred(len)];
  963. x:=1;
  964. while (x<=len) do
  965. begin
  966. if not(((p^ in ['a'..'z']) and (chr(ord(p^)-32)=s[x])) or
  967. (p^=s[x])) then
  968. break;
  969. inc(p);
  970. inc(x);
  971. end;
  972. if (x>len) then
  973. begin
  974. found:=true;
  975. break;
  976. end;
  977. inc(numb);
  978. end
  979. else
  980. inc(numb,Bt[ord(c)]);
  981. end;
  982. if not found then
  983. IScan := NotFoundValue
  984. else
  985. IScan := numb - pred(len);
  986. end;
  987. {****************************************************************************
  988. TIndicator
  989. ****************************************************************************}
  990. constructor TIndicator.Init (var Bounds : TRect);
  991. begin
  992. Inherited Init (Bounds);
  993. GrowMode := gfGrowLoY + gfGrowHiY;
  994. end; { TIndicator.Init }
  995. procedure TIndicator.Draw;
  996. VAR
  997. Color : Byte;
  998. Frame : Char;
  999. L : array[0..1] of Longint;
  1000. S : String[15];
  1001. B : TDrawBuffer;
  1002. begin
  1003. if State and sfDragging = 0 then
  1004. begin
  1005. Color := GetColor (1);
  1006. Frame := #205;
  1007. end
  1008. else
  1009. begin
  1010. Color := GetColor (2);
  1011. Frame := #196;
  1012. end;
  1013. MoveChar (B, Frame, Color, Size.X);
  1014. { If the text has been modified, put an 'M' in the TIndicator display. }
  1015. if Modified then
  1016. WordRec (B[1]).Lo := 77;
  1017. { If WordWrap is active put a 'W' in the TIndicator display. }
  1018. if WordWrap then
  1019. WordRec (B[2]).Lo := 87
  1020. else
  1021. WordRec (B[2]).Lo := Byte (Frame);
  1022. { If AutoIndent is active put an 'I' in TIndicator display. }
  1023. if AutoIndent then
  1024. WordRec (B[0]).Lo := 73
  1025. else
  1026. WordRec (B[0]).Lo := Byte (Frame);
  1027. L[0] := Location.Y + 1;
  1028. L[1] := Location.X + 1;
  1029. FormatStr (S, ' %d:%d ', L);
  1030. MoveStr (B[9 - Pos (':', S)], S, Color); { Changed original 8 to 9. }
  1031. WriteBuf (0, 0, Size.X, 1, B);
  1032. end; { TIndicator.Draw }
  1033. function TIndicator.GetPalette : PPalette;
  1034. const
  1035. P : string[Length (CIndicator)] = CIndicator;
  1036. begin
  1037. GetPalette := @P;
  1038. end; { TIndicator.GetPalette }
  1039. procedure TIndicator.SetState (AState : Word; Enable : Boolean);
  1040. begin
  1041. Inherited SetState (AState, Enable);
  1042. if AState = sfDragging then
  1043. DrawView;
  1044. end; { TIndicator.SetState }
  1045. procedure TIndicator.SetValue (ALocation : Objects.TPoint; IsAutoIndent : Boolean;
  1046. IsModified : Boolean;
  1047. IsWordWrap : Boolean);
  1048. begin
  1049. if (Location.X<>ALocation.X) or
  1050. (Location.Y<>ALocation.Y) or
  1051. (AutoIndent <> IsAutoIndent) or
  1052. (Modified <> IsModified) or
  1053. (WordWrap <> IsWordWrap) then
  1054. begin
  1055. Location := ALocation;
  1056. AutoIndent := IsAutoIndent; { Added provisions to show AutoIndent. }
  1057. Modified := IsModified;
  1058. WordWrap := IsWordWrap; { Added provisions to show WordWrap. }
  1059. DrawView;
  1060. end;
  1061. end; { TIndicator.SetValue }
  1062. {****************************************************************************
  1063. TLineInfo
  1064. ****************************************************************************}
  1065. constructor TLineInfo.Init;
  1066. begin
  1067. MaxPos:=0;
  1068. Grow(1);
  1069. end;
  1070. destructor TLineInfo.Done;
  1071. begin
  1072. FreeMem(Info,MaxPos*sizeof(TLineInfoRec));
  1073. end;
  1074. procedure TLineInfo.Grow(pos:Sw_word);
  1075. var
  1076. NewSize : Sw_word;
  1077. P : pointer;
  1078. begin
  1079. NewSize:=(Pos+LineInfoGrow-(Pos mod LineInfoGrow));
  1080. GetMem(P,NewSize*sizeof(TLineInfoRec));
  1081. FillChar(P^,NewSize*sizeof(TLineInfoRec),0);
  1082. Move(Info^,P^,MaxPos*sizeof(TLineInfoRec));
  1083. Freemem(Info,MaxPos*sizeof(TLineInfoRec));
  1084. Info:=P;
  1085. end;
  1086. procedure TLineInfo.SetLen(pos,val:Sw_Word);
  1087. begin
  1088. if pos>=MaxPos then
  1089. Grow(Pos);
  1090. Info^[Pos].Len:=val
  1091. end;
  1092. procedure TLineInfo.SetAttr(pos,val:Sw_Word);
  1093. begin
  1094. if pos>=MaxPos then
  1095. Grow(Pos);
  1096. Info^[Pos].Attr:=val
  1097. end;
  1098. function TLineInfo.GetLen(pos:Sw_Word):Sw_Word;
  1099. begin
  1100. GetLen:=Info^[Pos].Len;
  1101. end;
  1102. function TLineInfo.GetAttr(pos:Sw_Word):Sw_Word;
  1103. begin
  1104. GetAttr:=Info^[Pos].Attr;
  1105. end;
  1106. {****************************************************************************
  1107. TEditor
  1108. ****************************************************************************}
  1109. constructor TEditor.Init (var Bounds : TRect;
  1110. AHScrollBar, AVScrollBar : PScrollBar;
  1111. AIndicator : PIndicator; ABufSize : Sw_Word);
  1112. var
  1113. Element : Byte; { Place_Marker array element to initialize array with. }
  1114. begin
  1115. Inherited Init (Bounds);
  1116. GrowMode := gfGrowHiX + gfGrowHiY;
  1117. Options := Options or ofSelectable;
  1118. Flags := EditorFlags;
  1119. EventMask := evMouseDown + evKeyDown + evCommand + evBroadcast;
  1120. ShowCursor;
  1121. HScrollBar := AHScrollBar;
  1122. VScrollBar := AVScrollBar;
  1123. Indicator := AIndicator;
  1124. BufSize := ABufSize;
  1125. CanUndo := True;
  1126. InitBuffer;
  1127. if assigned(Buffer) then
  1128. IsValid := True
  1129. else
  1130. begin
  1131. EditorDialog (edOutOfMemory, nil);
  1132. BufSize := 0;
  1133. end;
  1134. SetBufLen (0);
  1135. for Element := 1 to 10 do
  1136. Place_Marker[Element] := 0;
  1137. Element := 1;
  1138. while Element <= 70 do
  1139. begin
  1140. if Element mod 5 = 0 then
  1141. Insert ('x', Tab_Settings, Element)
  1142. else
  1143. Insert (#32, Tab_Settings, Element);
  1144. Inc (Element);
  1145. end;
  1146. { Default Right_Margin value. Change it if you want another. }
  1147. Right_Margin := 76;
  1148. TabSize:=8;
  1149. end; { TEditor.Init }
  1150. constructor TEditor.Load (var S : Objects.TStream);
  1151. begin
  1152. Inherited Load (S);
  1153. GetPeerViewPtr (S, HScrollBar);
  1154. GetPeerViewPtr (S, VScrollBar);
  1155. GetPeerViewPtr (S, Indicator);
  1156. S.Read (BufSize, SizeOf (BufSize));
  1157. S.Read (CanUndo, SizeOf (CanUndo));
  1158. S.Read (AutoIndent, SizeOf (AutoIndent));
  1159. S.Read (Line_Number, SizeOf (Line_Number));
  1160. S.Read (Place_Marker, SizeOf (Place_Marker));
  1161. S.Read (Right_Margin, SizeOf (Right_Margin));
  1162. S.Read (Tab_Settings, SizeOf (Tab_Settings));
  1163. S.Read (Word_Wrap, SizeOf (Word_Wrap));
  1164. InitBuffer;
  1165. if Assigned(Buffer) then
  1166. IsValid := True
  1167. else
  1168. begin
  1169. EditorDialog (edOutOfMemory, nil);
  1170. BufSize := 0;
  1171. end;
  1172. Lock;
  1173. SetBufLen (0);
  1174. end; { TEditor.Load }
  1175. destructor TEditor.Done;
  1176. begin
  1177. DoneBuffer;
  1178. Inherited Done;
  1179. end; { TEditor.Done }
  1180. function TEditor.BufChar(P: Sw_Word): Char;
  1181. begin
  1182. if P>=CurPtr then
  1183. inc(P,Gaplen);
  1184. BufChar:=Buffer^[P];
  1185. end;
  1186. function TEditor.BufPtr(P: Sw_Word): Sw_Word;
  1187. begin
  1188. if P>=CurPtr then
  1189. BufPtr:=P+GapLen
  1190. else
  1191. BufPtr:=P;
  1192. end;
  1193. procedure TEditor.Center_Text (Select_Mode : Byte);
  1194. { This procedure will center the current line of text. }
  1195. { Centering is based on the current Right_Margin. }
  1196. { If the Line_Length exceeds the Right_Margin, or the }
  1197. { line is just a blank line, we exit and do nothing. }
  1198. VAR
  1199. Spaces : array [1..80] of Char; { Array to hold spaces we'll insert. }
  1200. Index : Byte; { Index into Spaces array. }
  1201. Line_Length : Sw_Integer; { Holds the length of the line. }
  1202. E,S : Sw_Word; { End of the current line. }
  1203. begin
  1204. E := LineEnd (CurPtr);
  1205. S := LineStart (CurPtr);
  1206. { If the line is blank (only a CR/LF on it) then do noting. }
  1207. if E = S then
  1208. Exit;
  1209. { Set CurPtr to start of line. Check if line begins with a space. }
  1210. { We must strip out any spaces from the beginning, or end of lines. }
  1211. { If line does not start with space, make sure line length does not }
  1212. { exceed the Right_Margin. If it does, then do nothing. }
  1213. SetCurPtr (S, Select_Mode);
  1214. Remove_EOL_Spaces (Select_Mode);
  1215. if Buffer^[CurPtr] = #32 then
  1216. begin
  1217. { If the next word is greater than the end of line then do nothing. }
  1218. { If the line length is greater than Right_Margin then do nothing. }
  1219. { Otherwise, delete all spaces at the start of line. }
  1220. { Then reset end of line and put CurPtr at start of modified line. }
  1221. E := LineEnd (CurPtr);
  1222. if NextWord (CurPtr) > E then
  1223. Exit;
  1224. if E - NextWord (CurPtr) > Right_Margin then
  1225. Exit;
  1226. DeleteRange (CurPtr, NextWord (CurPtr), True);
  1227. E := LineEnd (CurPtr);
  1228. SetCurPtr (LineStart (CurPtr), Select_Mode);
  1229. end
  1230. else
  1231. if E - CurPtr > Right_Margin then
  1232. Exit;
  1233. { Now we determine the real length of the line. }
  1234. { Then we subtract the Line_Length from Right_Margin. }
  1235. { Dividing the result by two tells us how many spaces }
  1236. { must be inserted at start of line to center it. }
  1237. { When we're all done, set the CurPtr to end of line. }
  1238. Line_Length := E - CurPtr;
  1239. for Index := 1 to ((Right_Margin - Line_Length) shr 1) do
  1240. Spaces[Index] := #32;
  1241. InsertText (@Spaces, Index, False);
  1242. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  1243. end; { TEditor.Center_Text }
  1244. procedure TEditor.ChangeBounds (var Bounds : TRect);
  1245. begin
  1246. SetBounds (Bounds);
  1247. Delta.X := Max (0, Min (Delta.X, Limit.X - Size.X));
  1248. Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
  1249. Update (ufView);
  1250. end; { TEditor.ChangeBounds }
  1251. function TEditor.CharPos (P, Target : Sw_Word) : Sw_Integer;
  1252. VAR
  1253. Pos : Sw_Integer;
  1254. begin
  1255. Pos := 0;
  1256. while P < Target do
  1257. begin
  1258. if BufChar (P) = #9 then
  1259. Pos := Pos or 7;
  1260. Inc (Pos);
  1261. Inc (P);
  1262. end;
  1263. CharPos := Pos;
  1264. end; { TEditor.CharPos }
  1265. function TEditor.CharPtr (P : Sw_Word; Target : Sw_Integer) : Sw_Word;
  1266. VAR
  1267. Pos : Sw_Integer;
  1268. begin
  1269. Pos := 0;
  1270. while (Pos < Target) and (P < BufLen) and not(BufChar (P) in [#10,#13]) do
  1271. begin
  1272. if BufChar (P) = #9 then
  1273. Pos := Pos or 7;
  1274. Inc (Pos);
  1275. Inc (P);
  1276. end;
  1277. if Pos > Target then
  1278. Dec (P);
  1279. CharPtr := P;
  1280. end; { TEditor.CharPtr }
  1281. procedure TEditor.Check_For_Word_Wrap (Select_Mode : Byte;
  1282. Center_Cursor : Boolean);
  1283. { This procedure checks if CurPos.X > Right_Margin. }
  1284. { If it is, then we Do_Word_Wrap. Simple, eh? }
  1285. begin
  1286. if CurPos.X > Right_Margin then
  1287. Do_Word_Wrap (Select_Mode, Center_Cursor);
  1288. end; {Check_For_Word_Wrap}
  1289. function TEditor.ClipCopy : Boolean;
  1290. begin
  1291. ClipCopy := False;
  1292. if Assigned(Clipboard) and (Clipboard <> @Self) then
  1293. begin
  1294. ClipCopy := Clipboard^.InsertFrom (@Self);
  1295. Selecting := False;
  1296. Update (ufUpdate);
  1297. end;
  1298. end; { TEditor.ClipCopy }
  1299. procedure TEditor.ClipCut;
  1300. begin
  1301. if ClipCopy then
  1302. begin
  1303. Update_Place_Markers (0,
  1304. Self.SelEnd - Self.SelStart,
  1305. Self.SelStart,
  1306. Self.SelEnd);
  1307. DeleteSelect;
  1308. end;
  1309. end; { TEditor.ClipCut }
  1310. procedure TEditor.ClipPaste;
  1311. begin
  1312. if Assigned(Clipboard) and (Clipboard <> @Self) then
  1313. begin
  1314. { Do not allow paste operations that will exceed }
  1315. { the Right_Margin when Word_Wrap is active and }
  1316. { cursor is at EOL. }
  1317. if Word_Wrap and (CurPos.X > Right_Margin) then
  1318. begin
  1319. EditorDialog (edPasteNotPossible, nil);
  1320. Exit;
  1321. end;
  1322. { The editor will not copy selected text if the CurPtr }
  1323. { is not the same value as the SelStart. However, it }
  1324. { does return an InsCount. This may, or may not, be a }
  1325. { bug. We don't want to update the Place_Marker if }
  1326. { there's no text copied. }
  1327. if CurPtr = SelStart then
  1328. Update_Place_Markers (Clipboard^.SelEnd - Clipboard^.SelStart,
  1329. 0,
  1330. Clipboard^.SelStart,
  1331. Clipboard^.SelEnd);
  1332. InsertFrom (Clipboard);
  1333. end;
  1334. end; { TEditor.ClipPaste }
  1335. procedure TEditor.ConvertEvent (var Event : Drivers.TEvent);
  1336. VAR
  1337. ShiftState : Byte;
  1338. Key : Word;
  1339. begin
  1340. ShiftState:=GetShiftState;
  1341. if Event.What = evKeyDown then
  1342. begin
  1343. if (ShiftState and $03 <> 0)
  1344. and (Event.ScanCode >= $47)
  1345. and (Event.ScanCode <= $51) then
  1346. Event.CharCode := #0;
  1347. Key := Event.KeyCode;
  1348. if KeyState <> 0 then
  1349. begin
  1350. if (Lo (Key) >= $01) and (Lo (Key) <= $1A) then
  1351. Inc (Key, $40);
  1352. if (Lo (Key) >= $61) and (Lo (Key) <= $7A) then
  1353. Dec (Key, $20);
  1354. end;
  1355. Key := ScanKeyMap (KeyMap[KeyState], Key);
  1356. KeyState := 0;
  1357. if Key <> 0 then
  1358. if Hi (Key) = $FF then
  1359. begin
  1360. KeyState := Lo (Key);
  1361. ClearEvent (Event);
  1362. end
  1363. else
  1364. begin
  1365. Event.What := evCommand;
  1366. Event.Command := Key;
  1367. end;
  1368. end;
  1369. end; { TEditor.ConvertEvent }
  1370. function TEditor.CursorVisible : Boolean;
  1371. begin
  1372. CursorVisible := (CurPos.Y >= Delta.Y) and (CurPos.Y < Delta.Y + Size.Y);
  1373. end; { TEditor.CursorVisible }
  1374. procedure TEditor.DeleteRange (StartPtr, EndPtr : Sw_Word; DelSelect : Boolean);
  1375. begin
  1376. { This will update Place_Marker for all deletions. }
  1377. { EXCEPT the Remove_EOL_Spaces deletion. }
  1378. Update_Place_Markers (0, EndPtr - StartPtr, StartPtr, EndPtr);
  1379. if HasSelection and DelSelect then
  1380. DeleteSelect
  1381. else
  1382. begin
  1383. SetSelect (CurPtr, EndPtr, True);
  1384. DeleteSelect;
  1385. SetSelect (StartPtr, CurPtr, False);
  1386. DeleteSelect;
  1387. end;
  1388. end; { TEditor.DeleteRange }
  1389. procedure TEditor.DeleteSelect;
  1390. begin
  1391. InsertText (nil, 0, False);
  1392. end; { TEditor.DeleteSelect }
  1393. procedure TEditor.DoneBuffer;
  1394. begin
  1395. if assigned(Buffer) then
  1396. begin
  1397. FreeMem (Buffer, BufSize);
  1398. Buffer := nil;
  1399. end;
  1400. end; { TEditor.DoneBuffer }
  1401. procedure TEditor.DoSearchReplace;
  1402. VAR
  1403. I : Sw_Word;
  1404. C : Objects.TPoint;
  1405. begin
  1406. repeat
  1407. I := cmCancel;
  1408. if not Search (FindStr, Flags) then
  1409. begin
  1410. if Flags and (efReplaceAll + efDoReplace) <> (efReplaceAll + efDoReplace) then
  1411. EditorDialog (edSearchFailed, nil)
  1412. end
  1413. else
  1414. if Flags and efDoReplace <> 0 then
  1415. begin
  1416. I := cmYes;
  1417. if Flags and efPromptOnReplace <> 0 then
  1418. begin
  1419. MakeGlobal (Cursor, C);
  1420. I := EditorDialog (edReplacePrompt, Pointer(@C));
  1421. end;
  1422. if I = cmYes then
  1423. begin
  1424. { If Word_Wrap is active and we are at EOL }
  1425. { disallow replace by bringing up a dialog }
  1426. { stating that replace is not possible. }
  1427. if Word_Wrap and
  1428. ((CurPos.X + (Length (ReplaceStr) - Length (FindStr))) > Right_Margin) then
  1429. EditorDialog (edReplaceNotPossible, nil)
  1430. else
  1431. begin
  1432. Lock;
  1433. Search_Replace := True;
  1434. if length (ReplaceStr) < length (FindStr) then
  1435. Update_Place_Markers (0,
  1436. Length (FindStr) - Length (ReplaceStr),
  1437. CurPtr - Length (FindStr) + Length (ReplaceStr),
  1438. CurPtr)
  1439. else
  1440. if length (ReplaceStr) > length (FindStr) then
  1441. Update_Place_Markers (Length (ReplaceStr) - Length (FindStr),
  1442. 0,
  1443. CurPtr,
  1444. CurPtr + (Length (ReplaceStr) - Length (FindStr)));
  1445. InsertText (@ReplaceStr[1], Length (ReplaceStr), False);
  1446. Search_Replace := False;
  1447. TrackCursor (False);
  1448. Unlock;
  1449. end;
  1450. end;
  1451. end;
  1452. until (I = cmCancel) or (Flags and efReplaceAll = 0);
  1453. end; { TEditor.DoSearchReplace }
  1454. procedure TEditor.DoUpdate;
  1455. begin
  1456. if UpdateFlags <> 0 then
  1457. begin
  1458. SetCursor (CurPos.X - Delta.X, CurPos.Y - Delta.Y);
  1459. if UpdateFlags and ufView <> 0 then
  1460. DrawView
  1461. else
  1462. if UpdateFlags and ufLine <> 0 then
  1463. DrawLines (CurPos.Y - Delta.Y, 1, LineStart (CurPtr));
  1464. if assigned(HScrollBar) then
  1465. HScrollBar^.SetParams (Delta.X, 0, Limit.X - Size.X, Size.X div 2, 1);
  1466. if assigned(VScrollBar) then
  1467. VScrollBar^.SetParams (Delta.Y, 0, Limit.Y - Size.Y, Size.Y - 1, 1);
  1468. if assigned(Indicator) then
  1469. Indicator^.SetValue (CurPos, AutoIndent, Modified, Word_Wrap);
  1470. if State and sfActive <> 0 then
  1471. UpdateCommands;
  1472. UpdateFlags := 0;
  1473. end;
  1474. end; { TEditor.DoUpdate }
  1475. function TEditor.Do_Word_Wrap (Select_Mode : Byte;
  1476. Center_Cursor : Boolean) : Boolean;
  1477. { This procedure does the actual wordwrap. It always assumes the CurPtr }
  1478. { is at Right_Margin + 1. It makes several tests for special conditions }
  1479. { and processes those first. If they all fail, it does a normal wrap. }
  1480. VAR
  1481. A : Sw_Word; { Distance between line start and first word on line. }
  1482. C : Sw_Word; { Current pointer when we come into procedure. }
  1483. L : Sw_Word; { BufLen when we come into procedure. }
  1484. P : Sw_Word; { Position of pointer at any given moment. }
  1485. S : Sw_Word; { Start of a line. }
  1486. begin
  1487. Do_Word_Wrap := False;
  1488. Select_Mode := 0;
  1489. if BufLen >= (BufSize - 1) then
  1490. exit;
  1491. C := CurPtr;
  1492. L := BufLen;
  1493. S := LineStart (CurPtr);
  1494. { If first character in the line is a space and autoindent mode is on }
  1495. { then we check to see if NextWord(S) exceeds the CurPtr. If it does, }
  1496. { we set CurPtr as the AutoIndent marker. If it doesn't, we will set }
  1497. { NextWord(S) as the AutoIndent marker. If neither, we set it to S. }
  1498. if AutoIndent and (Buffer^[S] = ' ') then
  1499. begin
  1500. if NextWord (S) > CurPtr then
  1501. A := CurPtr
  1502. else
  1503. A := NextWord (S);
  1504. end
  1505. else
  1506. A := NextWord (S);
  1507. { Though NewLine will remove EOL spaces, we do it here too. }
  1508. { This catches the instance where a user may try to space }
  1509. { completely across the line, in which case CurPtr.X = 0. }
  1510. Remove_EOL_Spaces (Select_Mode);
  1511. if CurPos.X = 0 then
  1512. begin
  1513. NewLine (Select_Mode);
  1514. Do_Word_Wrap := True;
  1515. Exit;
  1516. end;
  1517. { At this point we have one of five situations: }
  1518. { }
  1519. { 1) AutoIndent is on and this line is all spaces before CurPtr. }
  1520. { 2) AutoIndent is off and this line is all spaces before CurPtr. }
  1521. { 3) AutoIndent is on and this line is continuous characters before CurPtr. }
  1522. { 4) AutoIndent is off and this line is continuous characters before CurPtr. }
  1523. { 5) This is just a normal line of text. }
  1524. { }
  1525. { Conditions 1 through 4 have to be taken into account before condition 5. }
  1526. { First, we see if there are all spaces and/or all characters. }
  1527. { Then we determine which one it really is. Finally, we take }
  1528. { a course of action based on the state of AutoIndent. }
  1529. if PrevWord (CurPtr) <= S then
  1530. begin
  1531. P := CurPtr - 1;
  1532. while ((Buffer^[P] <> ' ') and (P > S)) do
  1533. Dec (P);
  1534. { We found NO SPACES. Conditions 4 and 5 are treated the same. }
  1535. { We can NOT do word wrap and put up a dialog box stating such. }
  1536. { Delete character just entered so we don't exceed Right_Margin. }
  1537. if P = S then
  1538. begin
  1539. EditorDialog (edWrapNotPossible, nil);
  1540. DeleteRange (PrevChar (CurPtr), CurPtr, True);
  1541. Exit;
  1542. end
  1543. else
  1544. begin
  1545. { There are spaces. Now find out if they are all spaces. }
  1546. { If so, see if AutoIndent is on. If it is, turn it off, }
  1547. { do a NewLine, and turn it back on. Otherwise, just do }
  1548. { the NewLine. We go through all of these gyrations for }
  1549. { AutoIndent. Being way out here with a preceding line }
  1550. { of spaces and wrapping with AutoIndent on is real dumb! }
  1551. { However, the user expects something. The wrap will NOT }
  1552. { autoindent, but they had no business being here anyway! }
  1553. P := CurPtr - 1;
  1554. while ((Buffer^[P] = ' ') and (P > S)) do
  1555. Dec (P);
  1556. if P = S then
  1557. begin
  1558. if Autoindent then
  1559. begin
  1560. AutoIndent := False;
  1561. NewLine (Select_Mode);
  1562. AutoIndent := True;
  1563. end
  1564. else
  1565. NewLine (Select_Mode);
  1566. end; { AutoIndent }
  1567. end; { P = S for spaces }
  1568. end { P = S for no spaces }
  1569. else { PrevWord (CurPtr) <= S }
  1570. begin
  1571. { Hooray! We actually had a plain old line of text to wrap! }
  1572. { Regardless if we are pushing out a line beyond the Right_Margin, }
  1573. { or at the end of a line itself, the following will determine }
  1574. { exactly where to do the wrap and re-set the cursor accordingly. }
  1575. { However, if P = A then we can't wrap. Show dialog and exit. }
  1576. P := CurPtr;
  1577. while P - S > Right_Margin do
  1578. P := PrevWord (P);
  1579. if (P = A) then
  1580. begin
  1581. EditorDialog (edReformNotPossible, nil);
  1582. SetCurPtr (P, Select_Mode);
  1583. Exit;
  1584. end;
  1585. SetCurPtr (P, Select_Mode);
  1586. NewLine (Select_Mode);
  1587. end; { PrevWord (CurPtr <= S }
  1588. { Track the cursor here (it is at CurPos.X = 0) so the view }
  1589. { will redraw itself at column 0. This eliminates having it }
  1590. { redraw starting at the current cursor and not being able }
  1591. { to see text before the cursor. Of course, we also end up }
  1592. { redrawing the view twice, here and back in HandleEvent. }
  1593. { }
  1594. { Reposition cursor so user can pick up where they left off. }
  1595. TrackCursor (Center_Cursor);
  1596. SetCurPtr (C - (L - BufLen), Select_Mode);
  1597. Do_Word_Wrap := True;
  1598. end; { TEditor.Do_Word_Wrap }
  1599. procedure TEditor.Draw;
  1600. begin
  1601. if DrawLine <> Delta.Y then
  1602. begin
  1603. DrawPtr := LineMove (DrawPtr, Delta.Y - DrawLine);
  1604. DrawLine := Delta.Y;
  1605. end;
  1606. DrawLines (0, Size.Y, DrawPtr);
  1607. end; { TEditor.Draw }
  1608. procedure TEditor.DrawLines (Y, Count : Sw_Integer; LinePtr : Sw_Word);
  1609. VAR
  1610. Color : Word;
  1611. B : array[0..MaxLineLength - 1] of Sw_Word;
  1612. begin
  1613. Color := GetColor ($0201);
  1614. while Count > 0 do
  1615. begin
  1616. FormatLine (B, LinePtr, Delta.X + Size.X, Color);
  1617. WriteBuf (0, Y, Size.X, 1, B[Delta.X]);
  1618. LinePtr := NextLine (LinePtr);
  1619. Inc (Y);
  1620. Dec (Count);
  1621. end;
  1622. end; { TEditor.DrawLines }
  1623. procedure TEditor.Find;
  1624. VAR
  1625. FindRec : TFindDialogRec;
  1626. begin
  1627. with FindRec do
  1628. begin
  1629. Find := FindStr;
  1630. Options := Flags;
  1631. if EditorDialog (edFind, @FindRec) <> cmCancel then
  1632. begin
  1633. FindStr := Find;
  1634. Flags := Options and not efDoReplace;
  1635. DoSearchReplace;
  1636. end;
  1637. end;
  1638. end; { TEditor.Find }
  1639. procedure TEditor.FormatLine (var DrawBuf; LinePtr : Sw_Word;
  1640. Width : Sw_Integer;
  1641. Colors : Word);
  1642. var
  1643. outptr : pword;
  1644. outcnt,
  1645. idxpos : Sw_Word;
  1646. attr : Word;
  1647. procedure FillSpace(i:Sw_Word);
  1648. var
  1649. w : word;
  1650. begin
  1651. inc(OutCnt,i);
  1652. w:=32 or attr;
  1653. while (i>0) do
  1654. begin
  1655. OutPtr^:=w;
  1656. inc(OutPtr);
  1657. dec(i);
  1658. end;
  1659. end;
  1660. function FormatUntil(endpos:Sw_word):boolean;
  1661. var
  1662. p : pchar;
  1663. begin
  1664. FormatUntil:=false;
  1665. p:=pchar(Buffer)+idxpos;
  1666. while endpos>idxpos do
  1667. begin
  1668. if OutCnt>=Width then
  1669. exit;
  1670. case p^ of
  1671. #9 :
  1672. FillSpace(Tabsize-(outcnt mod Tabsize));
  1673. #10,#13 :
  1674. begin
  1675. FillSpace(Width-OutCnt);
  1676. FormatUntil:=true;
  1677. exit;
  1678. end;
  1679. else
  1680. begin
  1681. inc(OutCnt);
  1682. OutPtr^:=ord(p^) or attr;
  1683. inc(OutPtr);
  1684. end;
  1685. end; { case }
  1686. inc(p);
  1687. inc(idxpos);
  1688. end;
  1689. end;
  1690. begin
  1691. OutCnt:=0;
  1692. OutPtr:=@DrawBuf;
  1693. idxPos:=LinePtr;
  1694. attr:=lo(Colors) shl 8;
  1695. if FormatUntil(SelStart) then
  1696. exit;
  1697. attr:=hi(Colors) shl 8;
  1698. if FormatUntil(CurPtr) then
  1699. exit;
  1700. inc(idxPos,GapLen);
  1701. if FormatUntil(SelEnd+GapLen) then
  1702. exit;
  1703. attr:=lo(Colors) shl 8;
  1704. if FormatUntil(BufSize) then
  1705. exit;
  1706. { fill up until width }
  1707. FillSpace(Width-OutCnt);
  1708. end; {TEditor.FormatLine}
  1709. function TEditor.GetMousePtr (Mouse : Objects.TPoint) : Sw_Word;
  1710. begin
  1711. MakeLocal (Mouse, Mouse);
  1712. Mouse.X := Max (0, Min (Mouse.X, Size.X - 1));
  1713. Mouse.Y := Max (0, Min (Mouse.Y, Size.Y - 1));
  1714. GetMousePtr := CharPtr (LineMove (DrawPtr, Mouse.Y + Delta.Y - DrawLine),
  1715. Mouse.X + Delta.X);
  1716. end; { TEditor.GetMousePtr }
  1717. function TEditor.GetPalette : PPalette;
  1718. CONST
  1719. P : String[Length (CEditor)] = CEditor;
  1720. begin
  1721. GetPalette := @P;
  1722. end; { TEditor.GetPalette }
  1723. procedure TEditor.HandleEvent (var Event : Drivers.TEvent);
  1724. VAR
  1725. ShiftState : Byte;
  1726. CenterCursor : Boolean;
  1727. SelectMode : Byte;
  1728. D : Objects.TPoint;
  1729. Mouse : Objects.TPoint;
  1730. function CheckScrollBar (P : PScrollBar; var D : Sw_Integer) : Boolean;
  1731. begin
  1732. CheckScrollBar := FALSE;
  1733. if (Event.InfoPtr = P) and (P^.Value <> D) then
  1734. begin
  1735. D := P^.Value;
  1736. Update (ufView);
  1737. CheckScrollBar := TRUE;
  1738. end;
  1739. end; {CheckScrollBar}
  1740. begin
  1741. Inherited HandleEvent (Event);
  1742. ConvertEvent (Event);
  1743. CenterCursor := not CursorVisible;
  1744. SelectMode := 0;
  1745. ShiftState:=GetShiftState;
  1746. if Selecting or (ShiftState and $03 <> 0) then
  1747. SelectMode := smExtend;
  1748. case Event.What of
  1749. Drivers.evMouseDown:
  1750. begin
  1751. if Event.Double then
  1752. SelectMode := SelectMode or smDouble;
  1753. repeat
  1754. Lock;
  1755. if Event.What = evMouseAuto then
  1756. begin
  1757. MakeLocal (Event.Where, Mouse);
  1758. D := Delta;
  1759. if Mouse.X < 0 then
  1760. Dec (D.X);
  1761. if Mouse.X >= Size.X then
  1762. Inc (D.X);
  1763. if Mouse.Y < 0 then
  1764. Dec (D.Y);
  1765. if Mouse.Y >= Size.Y then
  1766. Inc (D.Y);
  1767. ScrollTo (D.X, D.Y);
  1768. end;
  1769. SetCurPtr (GetMousePtr (Event.Where), SelectMode);
  1770. SelectMode := SelectMode or smExtend;
  1771. Unlock;
  1772. until not MouseEvent (Event, evMouseMove + evMouseAuto);
  1773. end; { Drivers.evMouseDown }
  1774. Drivers.evKeyDown:
  1775. case Event.CharCode of
  1776. #32..#255:
  1777. begin
  1778. Lock;
  1779. if Overwrite and not HasSelection then
  1780. if CurPtr <> LineEnd (CurPtr) then
  1781. SelEnd := NextChar (CurPtr);
  1782. InsertText (@Event.CharCode, 1, False);
  1783. if Word_Wrap then
  1784. Check_For_Word_Wrap (SelectMode, CenterCursor);
  1785. TrackCursor (CenterCursor);
  1786. Unlock;
  1787. end;
  1788. else
  1789. Exit;
  1790. end; { Drivers.evKeyDown }
  1791. Drivers.evCommand:
  1792. case Event.Command of
  1793. cmFind : Find;
  1794. cmReplace : Replace;
  1795. cmSearchAgain : DoSearchReplace;
  1796. else
  1797. begin
  1798. Lock;
  1799. case Event.Command of
  1800. cmCut : ClipCut;
  1801. cmCopy : ClipCopy;
  1802. cmPaste : ClipPaste;
  1803. cmUndo : Undo;
  1804. cmClear : DeleteSelect;
  1805. cmCharLeft : SetCurPtr (PrevChar (CurPtr), SelectMode);
  1806. cmCharRight : SetCurPtr (NextChar (CurPtr), SelectMode);
  1807. cmWordLeft : SetCurPtr (PrevWord (CurPtr), SelectMode);
  1808. cmWordRight : SetCurPtr (NextWord (CurPtr), SelectMode);
  1809. cmLineStart : SetCurPtr (LineStart (CurPtr), SelectMode);
  1810. cmLineEnd : SetCurPtr (LineEnd (CurPtr), SelectMode);
  1811. cmLineUp : SetCurPtr (LineMove (CurPtr, -1), SelectMode);
  1812. cmLineDown : SetCurPtr (LineMove (CurPtr, 1), SelectMode);
  1813. cmPageUp : SetCurPtr (LineMove (CurPtr, - (Size.Y - 1)), SelectMode);
  1814. cmPageDown : SetCurPtr (LineMove (CurPtr, Size.Y - 1), SelectMode);
  1815. cmTextStart : SetCurPtr (0, SelectMode);
  1816. cmTextEnd : SetCurPtr (BufLen, SelectMode);
  1817. cmNewLine : NewLine (SelectMode);
  1818. cmBackSpace : DeleteRange (PrevChar (CurPtr), CurPtr, True);
  1819. cmDelChar : DeleteRange (CurPtr, NextChar (CurPtr), True);
  1820. cmDelWord : DeleteRange (CurPtr, NextWord (CurPtr), False);
  1821. cmDelStart : DeleteRange (LineStart (CurPtr), CurPtr, False);
  1822. cmDelEnd : DeleteRange (CurPtr, LineEnd (CurPtr), False);
  1823. cmDelLine : DeleteRange (LineStart (CurPtr), NextLine (CurPtr), False);
  1824. cmInsMode : ToggleInsMode;
  1825. cmStartSelect : StartSelect;
  1826. cmHideSelect : HideSelect;
  1827. cmIndentMode : begin
  1828. AutoIndent := not AutoIndent;
  1829. Update (ufStats);
  1830. end; { Added provision to update TIndicator if ^QI pressed. }
  1831. cmCenterText : Center_Text (SelectMode);
  1832. cmEndPage : SetCurPtr (LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y - 1), SelectMode);
  1833. cmHomePage : SetCurPtr (LineMove (CurPtr, -(CurPos.Y - Delta.Y)), SelectMode);
  1834. cmInsertLine : Insert_Line (SelectMode);
  1835. cmJumpLine : Jump_To_Line (SelectMode);
  1836. cmReformDoc : Reformat_Document (SelectMode, CenterCursor);
  1837. cmReformPara : Reformat_Paragraph (SelectMode, CenterCursor);
  1838. cmRightMargin : Set_Right_Margin;
  1839. cmScrollDown : Scroll_Down;
  1840. cmScrollUp : Scroll_Up;
  1841. cmSelectWord : Select_Word;
  1842. cmSetTabs : Set_Tabs;
  1843. cmTabKey : Tab_Key (SelectMode);
  1844. cmWordWrap : begin
  1845. Word_Wrap := not Word_Wrap;
  1846. Update (ufStats);
  1847. end; { Added provision to update TIndicator if ^OW pressed. }
  1848. cmSetMark0 : Set_Place_Marker (10);
  1849. cmSetMark1 : Set_Place_Marker (1);
  1850. cmSetMark2 : Set_Place_Marker (2);
  1851. cmSetMark3 : Set_Place_Marker (3);
  1852. cmSetMark4 : Set_Place_Marker (4);
  1853. cmSetMark5 : Set_Place_Marker (5);
  1854. cmSetMark6 : Set_Place_Marker (6);
  1855. cmSetMark7 : Set_Place_Marker (7);
  1856. cmSetMark8 : Set_Place_Marker (8);
  1857. cmSetMark9 : Set_Place_Marker (9);
  1858. cmJumpMark0 : Jump_Place_Marker (10, SelectMode);
  1859. cmJumpMark1 : Jump_Place_Marker (1, SelectMode);
  1860. cmJumpMark2 : Jump_Place_Marker (2, SelectMode);
  1861. cmJumpMark3 : Jump_Place_Marker (3, SelectMode);
  1862. cmJumpMark4 : Jump_Place_Marker (4, SelectMode);
  1863. cmJumpMark5 : Jump_Place_Marker (5, SelectMode);
  1864. cmJumpMark6 : Jump_Place_Marker (6, SelectMode);
  1865. cmJumpMark7 : Jump_Place_Marker (7, SelectMode);
  1866. cmJumpMark8 : Jump_Place_Marker (8, SelectMode);
  1867. cmJumpMark9 : Jump_Place_Marker (9, SelectMode);
  1868. else
  1869. Unlock;
  1870. Exit;
  1871. end; { Event.Command (Inner) }
  1872. TrackCursor (CenterCursor);
  1873. { If the user presses any key except cmNewline or cmBackspace }
  1874. { we need to check if the file has been modified yet. There }
  1875. { can be no spaces at the end of a line, or wordwrap doesn't }
  1876. { work properly. We don't want to do this if the file hasn't }
  1877. { been modified because the user could be bringing in an ASCII }
  1878. { file from an editor that allows spaces at the EOL. If we }
  1879. { took them out in that scenario the "M" would appear on the }
  1880. { TIndicator line and the user would get upset or confused. }
  1881. if (Event.Command <> cmNewLine) and
  1882. (Event.Command <> cmBackSpace) and
  1883. (Event.Command <> cmTabKey) and
  1884. Modified then
  1885. Remove_EOL_Spaces (SelectMode);
  1886. Unlock;
  1887. end; { Event.Command (Outer) }
  1888. end; { Drivers.evCommand }
  1889. Drivers.evBroadcast:
  1890. case Event.Command of
  1891. cmScrollBarChanged:
  1892. if (Event.InfoPtr = HScrollBar) or
  1893. (Event.InfoPtr = VScrollBar) then
  1894. begin
  1895. CheckScrollBar (HScrollBar, Delta.X);
  1896. CheckScrollBar (VScrollBar, Delta.Y);
  1897. end
  1898. else
  1899. exit;
  1900. else
  1901. Exit;
  1902. end; { Drivers.evBroadcast }
  1903. end;
  1904. ClearEvent (Event);
  1905. end; { TEditor.HandleEvent }
  1906. function TEditor.HasSelection : Boolean;
  1907. begin
  1908. HasSelection := SelStart <> SelEnd;
  1909. end; { TEditor.HasSelection }
  1910. procedure TEditor.HideSelect;
  1911. begin
  1912. Selecting := False;
  1913. SetSelect (CurPtr, CurPtr, False);
  1914. end; { TEditor.HideSelect }
  1915. procedure TEditor.InitBuffer;
  1916. begin
  1917. Buffer := MemAlloc (BufSize);
  1918. end; { TEditor.InitBuffer }
  1919. function TEditor.InsertBuffer (var P : PEditBuffer;
  1920. Offset, Length : Sw_Word;
  1921. AllowUndo, SelectText : Boolean) : Boolean;
  1922. VAR
  1923. SelLen : Sw_Word;
  1924. DelLen : Sw_Word;
  1925. SelLines : Sw_Word;
  1926. Lines : Sw_Word;
  1927. NewSize : Longint;
  1928. begin
  1929. InsertBuffer := True;
  1930. Selecting := False;
  1931. SelLen := SelEnd - SelStart;
  1932. if (SelLen = 0) and (Length = 0) then
  1933. Exit;
  1934. DelLen := 0;
  1935. if AllowUndo then
  1936. if CurPtr = SelStart then
  1937. DelLen := SelLen
  1938. else
  1939. if SelLen > InsCount then
  1940. DelLen := SelLen - InsCount;
  1941. NewSize := Longint (BufLen + DelCount - SelLen + DelLen) + Length;
  1942. if NewSize > BufLen + DelCount then
  1943. if (NewSize > MaxBufLength) or not SetBufSize (NewSize) then
  1944. begin
  1945. EditorDialog (edOutOfMemory, nil);
  1946. InsertBuffer := False;
  1947. SelEnd := SelStart;
  1948. Exit;
  1949. end;
  1950. SelLines := CountLines (Buffer^[BufPtr (SelStart)], SelLen);
  1951. if CurPtr = SelEnd then
  1952. begin
  1953. if AllowUndo then
  1954. begin
  1955. if DelLen > 0 then
  1956. Move (Buffer^[SelStart], Buffer^[CurPtr + GapLen - DelCount - DelLen], DelLen);
  1957. Dec (InsCount, SelLen - DelLen);
  1958. end;
  1959. CurPtr := SelStart;
  1960. Dec (CurPos.Y, SelLines);
  1961. end;
  1962. if Delta.Y > CurPos.Y then
  1963. begin
  1964. Dec (Delta.Y, SelLines);
  1965. if Delta.Y < CurPos.Y then
  1966. Delta.Y := CurPos.Y;
  1967. end;
  1968. if Length > 0 then
  1969. Move (P^[Offset], Buffer^[CurPtr], Length);
  1970. Lines := CountLines (Buffer^[CurPtr], Length);
  1971. Inc (CurPtr, Length);
  1972. Inc (CurPos.Y, Lines);
  1973. DrawLine := CurPos.Y;
  1974. DrawPtr := LineStart (CurPtr);
  1975. CurPos.X := CharPos (DrawPtr, CurPtr);
  1976. if not SelectText then
  1977. SelStart := CurPtr;
  1978. SelEnd := CurPtr;
  1979. if Length>Sellen then
  1980. begin
  1981. Inc (BufLen, Length - SelLen);
  1982. Dec (GapLen, Length - SelLen);
  1983. end
  1984. else
  1985. begin
  1986. Dec (BufLen, Sellen - Length);
  1987. Inc (GapLen, Sellen - Length);
  1988. end;
  1989. if AllowUndo then
  1990. begin
  1991. Inc (DelCount, DelLen);
  1992. Inc (InsCount, Length);
  1993. end;
  1994. Inc (Limit.Y, Lines - SelLines);
  1995. Delta.Y := Max (0, Min (Delta.Y, Limit.Y - Size.Y));
  1996. if not IsClipboard then
  1997. Modified := True;
  1998. SetBufSize (BufLen + DelCount);
  1999. if (SelLines = 0) and (Lines = 0) then
  2000. Update (ufLine)
  2001. else
  2002. Update (ufView);
  2003. end; { TEditor.InsertBuffer }
  2004. function TEditor.InsertFrom (Editor : PEditor) : Boolean;
  2005. begin
  2006. InsertFrom := InsertBuffer (Editor^.Buffer,
  2007. Editor^.BufPtr (Editor^.SelStart),
  2008. Editor^.SelEnd - Editor^.SelStart, CanUndo, IsClipboard);
  2009. end; { TEditor.InsertFrom }
  2010. procedure TEditor.Insert_Line (Select_Mode : Byte);
  2011. { This procedure inserts a newline at the current cursor position }
  2012. { if a ^N is pressed. Unlike cmNewLine, the cursor will return }
  2013. { to its original position. If the cursor was at the end of a }
  2014. { line, and its spaces were removed, the cursor returns to the }
  2015. { end of the line instead. }
  2016. begin
  2017. NewLine (Select_Mode);
  2018. SetCurPtr (LineEnd (LineMove (CurPtr, -1)), Select_Mode);
  2019. end; { TEditor.Insert_Line }
  2020. function TEditor.InsertText (Text : Pointer;
  2021. Length : Sw_Word;
  2022. SelectText : Boolean) : Boolean;
  2023. begin
  2024. if assigned(Text) and not Search_Replace then
  2025. Update_Place_Markers (Length, 0, Self.SelStart, Self.SelEnd);
  2026. InsertText := InsertBuffer (PEditBuffer (Text),
  2027. 0, Length, CanUndo, SelectText);
  2028. end; { TEditor.InsertText }
  2029. function TEditor.IsClipboard : Boolean;
  2030. begin
  2031. IsClipboard := Clipboard = @Self;
  2032. end; { TEditor.IsClipboard }
  2033. procedure TEditor.Jump_Place_Marker (Element : Byte; Select_Mode : Byte);
  2034. { This procedure jumps to a place marker if ^Q# is pressed. }
  2035. { We don't go anywhere if Place_Marker[Element] is not zero. }
  2036. begin
  2037. if (not IsClipboard) and (Place_Marker[Element] <> 0) then
  2038. SetCurPtr (Place_Marker[Element], Select_Mode);
  2039. end; { TEditor.Jump_Place_Marker }
  2040. procedure TEditor.Jump_To_Line (Select_Mode : Byte);
  2041. { This function brings up a dialog box that allows }
  2042. { the user to select a line number to jump to. }
  2043. VAR
  2044. Code : Integer; { Used for Val conversion. }
  2045. Temp_Value : Longint; { Holds converted dialog value. }
  2046. begin
  2047. if EditorDialog (edJumpToLine, @Line_Number) <> cmCancel then
  2048. begin
  2049. { Convert the Line_Number string to an interger. }
  2050. { Put it into Temp_Value. If the number is not }
  2051. { in the range 1..9999 abort. If the number is }
  2052. { our current Y position, abort. Otherwise, }
  2053. { go to top of document, and jump to the line. }
  2054. { There are faster methods. This one's easy. }
  2055. { Note that CurPos.Y is always 1 less than what }
  2056. { the TIndicator line says. }
  2057. val (Line_Number, Temp_Value, Code);
  2058. if (Temp_Value < 1) or (Temp_Value > 9999999) then
  2059. Exit;
  2060. if Temp_Value = CurPos.Y + 1 then
  2061. Exit;
  2062. SetCurPtr (0, Select_Mode);
  2063. SetCurPtr (LineMove (CurPtr, Temp_Value - 1), Select_Mode);
  2064. end;
  2065. end; {TEditor.Jump_To_Line}
  2066. function TEditor.LineEnd (P : Sw_Word) : Sw_Word;
  2067. var
  2068. start,
  2069. i : Sw_word;
  2070. pc : pchar;
  2071. begin
  2072. if P<CurPtr then
  2073. begin
  2074. i:=CurPtr-P;
  2075. pc:=pchar(Buffer)+P;
  2076. while (i>0) do
  2077. begin
  2078. if pc^ in [#10,#13] then
  2079. begin
  2080. LineEnd:=pc-pchar(Buffer);
  2081. exit;
  2082. end;
  2083. inc(pc);
  2084. dec(i);
  2085. end;
  2086. start:=CurPtr;
  2087. end
  2088. else
  2089. start:=P;
  2090. i:=BufLen-Start;
  2091. pc:=pchar(Buffer)+GapLen+start;
  2092. while (i>0) do
  2093. begin
  2094. if pc^ in [#10,#13] then
  2095. begin
  2096. LineEnd:=pc-(pchar(Buffer)+Gaplen);
  2097. exit;
  2098. end;
  2099. inc(pc);
  2100. dec(i);
  2101. end;
  2102. LineEnd:=pc-(pchar(Buffer)+Gaplen);
  2103. end; { TEditor.LineEnd }
  2104. function TEditor.LineMove (P : Sw_Word; Count : Sw_Integer) : Sw_Word;
  2105. VAR
  2106. Pos : Sw_Integer;
  2107. I : Sw_Word;
  2108. begin
  2109. I := P;
  2110. P := LineStart (P);
  2111. Pos := CharPos (P, I);
  2112. while Count <> 0 do
  2113. begin
  2114. I := P;
  2115. if Count < 0 then
  2116. begin
  2117. P := PrevLine (P);
  2118. Inc (Count);
  2119. end
  2120. else
  2121. begin
  2122. P := NextLine (P);
  2123. Dec (Count);
  2124. end;
  2125. end;
  2126. if P <> I then
  2127. P := CharPtr (P, Pos);
  2128. LineMove := P;
  2129. end; { TEditor.LineMove }
  2130. function TEditor.LineStart (P : Sw_Word) : Sw_Word;
  2131. var
  2132. i : Sw_word;
  2133. start,pc : pchar;
  2134. oc : char;
  2135. begin
  2136. if P>CurPtr then
  2137. begin
  2138. start:=pchar(Buffer)+GapLen;
  2139. pc:=start;
  2140. i:=P-CurPtr;
  2141. dec(pc);
  2142. while (i>0) do
  2143. begin
  2144. if pc^ in [#10,#13] then
  2145. break;
  2146. dec(pc);
  2147. dec(i);
  2148. end;
  2149. end
  2150. else
  2151. i:=0;
  2152. if i=0 then
  2153. begin
  2154. start:=pchar(Buffer);
  2155. i:=P;
  2156. pc:=start+p;
  2157. dec(pc);
  2158. while (i>0) do
  2159. begin
  2160. if pc^ in [#10,#13] then
  2161. break;
  2162. dec(pc);
  2163. dec(i);
  2164. end;
  2165. if i=0 then
  2166. begin
  2167. LineStart:=0;
  2168. exit;
  2169. end;
  2170. end;
  2171. oc:=pc^;
  2172. LineStart:=pc-start+1;
  2173. end; { TEditor.LineStart }
  2174. function TEditor.LineNr (P : Sw_Word) : Sw_Word;
  2175. var
  2176. pc,endp : pchar;
  2177. lines : sw_word;
  2178. begin
  2179. endp:=pchar(Buffer)+BufPtr(P);
  2180. pc:=pchar(Buffer);
  2181. lines:=0;
  2182. while (pc<endp) do
  2183. begin
  2184. if pc^ in [#10,#13] then
  2185. begin
  2186. inc(lines);
  2187. if ord((pc+1)^)+ord(pc^)=23 then
  2188. begin
  2189. inc(pc);
  2190. if (pc>=endp) then
  2191. break;
  2192. end;
  2193. end;
  2194. inc(pc);
  2195. end;
  2196. LineNr:=Lines;
  2197. end;
  2198. procedure TEditor.Lock;
  2199. begin
  2200. Inc (LockCount);
  2201. end; { TEditor.Lock }
  2202. function TEditor.NewLine (Select_Mode : Byte) : Boolean;
  2203. VAR
  2204. I : Sw_Word; { Used to track spaces for AutoIndent. }
  2205. P : Sw_Word; { Position of Cursor when we arrive and after Newline. }
  2206. begin
  2207. P := LineStart (CurPtr);
  2208. I := P;
  2209. { The first thing we do is remove any End Of Line spaces. }
  2210. { Then we check to see how many spaces are on beginning }
  2211. { of a line. We need this check to add them after CR/LF }
  2212. { if AutoIndenting. Last of all we insert spaces required }
  2213. { for the AutoIndenting, if it was on. }
  2214. Remove_EOL_Spaces (Select_Mode);
  2215. while (I < CurPtr) and ((Buffer^[I] in [#9,' '])) do
  2216. Inc (I);
  2217. if InsertText (@LineBreak[1], length(LineBreak), False) = FALSE then
  2218. exit;
  2219. if AutoIndent then
  2220. InsertText (@Buffer^[P], I - P, False);
  2221. { Remember where the CurPtr is at this moment. }
  2222. { Remember the length of the buffer at the moment. }
  2223. { Go to the previous line and remove EOL spaces. }
  2224. { Once removed, re-set the cursor to where we were }
  2225. { minus any spaces that might have been removed. }
  2226. I := BufLen;
  2227. P := CurPtr;
  2228. SetCurPtr (LineMove (CurPtr, - 1), Select_Mode);
  2229. Remove_EOL_Spaces (Select_Mode);
  2230. if I - BufLen <> 0 then
  2231. SetCurPtr (P - (I - BufLen), Select_Mode)
  2232. else
  2233. SetCurPtr (P, Select_Mode);
  2234. NewLine:=true;
  2235. end; { TEditor.NewLine }
  2236. function TEditor.NextChar (P : Sw_Word) : Sw_Word;
  2237. var
  2238. pc : pchar;
  2239. begin
  2240. if P<>BufLen then
  2241. begin
  2242. inc(P);
  2243. if P<>BufLen then
  2244. begin
  2245. pc:=pchar(Buffer);
  2246. if P>=CurPtr then
  2247. inc(pc,GapLen);
  2248. inc(pc,P-1);
  2249. if ord(pc^)+ord((pc+1)^)=23 then
  2250. inc(p);
  2251. end;
  2252. end;
  2253. NextChar:=P;
  2254. end; { TEditor.NextChar }
  2255. function TEditor.NextLine (P : Sw_Word) : Sw_Word;
  2256. begin
  2257. NextLine := NextChar (LineEnd (P));
  2258. end; { TEditor.NextLine }
  2259. function TEditor.NextWord (P : Sw_Word) : Sw_Word;
  2260. begin
  2261. { skip word }
  2262. while (P < BufLen) and (BufChar (P) in WordChars) do
  2263. P := NextChar (P);
  2264. { skip spaces }
  2265. while (P < BufLen) and not (BufChar (P) in WordChars) do
  2266. P := NextChar (P);
  2267. NextWord := P;
  2268. end; { TEditor.NextWord }
  2269. function TEditor.PrevChar (P : Sw_Word) : Sw_Word;
  2270. var
  2271. pc : pchar;
  2272. begin
  2273. if p<>0 then
  2274. begin
  2275. dec(p);
  2276. if p<>0 then
  2277. begin
  2278. pc:=pchar(Buffer);
  2279. if P>=CurPtr then
  2280. inc(pc,GapLen);
  2281. inc(pc,P-1);
  2282. if ord(pc^)+ord((pc+1)^)=23 then
  2283. dec(p);
  2284. end;
  2285. end;
  2286. PrevChar:=P;
  2287. end; { TEditor.PrevChar }
  2288. function TEditor.PrevLine (P : Sw_Word) : Sw_Word;
  2289. begin
  2290. PrevLine := LineStart (PrevChar (P));
  2291. end; { TEditor.PrevLine }
  2292. function TEditor.PrevWord (P : Sw_Word) : Sw_Word;
  2293. begin
  2294. { skip spaces }
  2295. while (P > 0) and not (BufChar (PrevChar (P)) in WordChars) do
  2296. P := PrevChar (P);
  2297. { skip word }
  2298. while (P > 0) and (BufChar (PrevChar (P)) in WordChars) do
  2299. P := PrevChar (P);
  2300. PrevWord := P;
  2301. end; { TEditor.PrevWord }
  2302. procedure TEditor.Reformat_Document (Select_Mode : Byte; Center_Cursor : Boolean);
  2303. { This procedure will do a reformat of the entire document, or just }
  2304. { from the current line to the end of the document, if ^QU is pressed. }
  2305. { It simply brings up the correct dialog box, and then calls the }
  2306. { TEditor.Reformat_Paragraph procedure to do the actual reformatting. }
  2307. CONST
  2308. efCurrentLine = $0000; { Radio button #1 selection for dialog box. }
  2309. efWholeDocument = $0001; { Radio button #2 selection for dialog box. }
  2310. VAR
  2311. Reformat_Options : Word; { Holds the dialog options for reformatting. }
  2312. begin
  2313. { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
  2314. { allows reformatting of document and if not show user dialog that }
  2315. { says reformatting is not permissable. }
  2316. if not Word_Wrap then
  2317. begin
  2318. if not Allow_Reformat then
  2319. begin
  2320. EditorDialog (edReformatNotAllowed, nil);
  2321. Exit;
  2322. end;
  2323. Word_Wrap := True;
  2324. Update (ufStats);
  2325. end;
  2326. { Default radio button option to 1st one. Bring up dialog box. }
  2327. Reformat_Options := efCurrentLine;
  2328. if EditorDialog (edReformatDocument, @Reformat_Options) <> cmCancel then
  2329. begin
  2330. { If the option to reformat the whole document was selected }
  2331. { we need to go back to start of document. Otherwise we stay }
  2332. { on the current line. Call Reformat_Paragraph until we get }
  2333. { to the end of the document to do the reformatting. }
  2334. if Reformat_Options and efWholeDocument <> 0 then
  2335. SetCurPtr (0, Select_Mode);
  2336. Unlock;
  2337. repeat
  2338. Lock;
  2339. if NOT Reformat_Paragraph (Select_Mode, Center_Cursor) then
  2340. Exit;
  2341. TrackCursor (False);
  2342. Unlock;
  2343. until CurPtr = BufLen;
  2344. end;
  2345. end; { TEditor.Reformat_Document }
  2346. function TEditor.Reformat_Paragraph (Select_Mode : Byte;
  2347. Center_Cursor : Boolean) : Boolean;
  2348. { This procedure will do a reformat of the current paragraph if ^B pressed. }
  2349. { The feature works regardless if wordrap is on or off. It also supports }
  2350. { the AutoIndent feature. Reformat is not possible if the CurPos exceeds }
  2351. { the Right_Margin. Right_Margin is where the EOL is considered to be. }
  2352. CONST
  2353. Space : array [1..2] of Char = #32#32;
  2354. VAR
  2355. C : Sw_Word; { Position of CurPtr when we come into procedure. }
  2356. E : Sw_Word; { End of a line. }
  2357. S : Sw_Word; { Start of a line. }
  2358. begin
  2359. Reformat_Paragraph := False;
  2360. { Check if Word_Wrap is toggled on. If NOT on, check if programmer }
  2361. { allows reformatting of paragraph and if not show user dialog that }
  2362. { says reformatting is not permissable. }
  2363. if not Word_Wrap then
  2364. begin
  2365. if not Allow_Reformat then
  2366. begin
  2367. EditorDialog (edReformatNotAllowed, nil);
  2368. Exit;
  2369. end;
  2370. Word_Wrap := True;
  2371. Update (ufStats);
  2372. end;
  2373. C := CurPtr;
  2374. E := LineEnd (CurPtr);
  2375. S := LineStart (CurPtr);
  2376. { Reformat possible only if current line is NOT blank! }
  2377. if E <> S then
  2378. begin
  2379. { Reformat is NOT possible if the first word }
  2380. { on the line is beyond the Right_Margin. }
  2381. S := LineStart (CurPtr);
  2382. if NextWord (S) - S >= Right_Margin - 1 then
  2383. begin
  2384. EditorDialog (edReformNotPossible, nil);
  2385. Exit;
  2386. end;
  2387. { First objective is to find the first blank line }
  2388. { after this paragraph so we know when to stop. }
  2389. { That could be the end of the document. }
  2390. Repeat
  2391. SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
  2392. E := LineEnd (CurPtr);
  2393. S := LineStart (CurPtr);
  2394. BlankLine := E;
  2395. until ((CurPtr = BufLen) or (E = S));
  2396. SetCurPtr (C, Select_Mode);
  2397. repeat
  2398. { Set CurPtr to LineEnd and remove the EOL spaces. }
  2399. { Pull up the next line and remove its EOL space. }
  2400. { First make sure the next line is not BlankLine! }
  2401. { Insert spaces as required between the two lines. }
  2402. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2403. Remove_EOL_Spaces (Select_Mode);
  2404. if CurPtr <> Blankline - 2 then
  2405. DeleteRange (CurPtr, Nextword (CurPtr), True);
  2406. Remove_EOL_Spaces (Select_Mode);
  2407. case Buffer^[CurPtr-1] of
  2408. '!' : InsertText (@Space, 2, False);
  2409. '.' : InsertText (@Space, 2, False);
  2410. ':' : InsertText (@Space, 2, False);
  2411. '?' : InsertText (@Space, 2, False);
  2412. else
  2413. InsertText (@Space, 1, False);
  2414. end;
  2415. { Reset CurPtr to EOL. While line length is > Right_Margin }
  2416. { go Do_Word_Wrap. If wordrap failed, exit routine. }
  2417. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2418. while LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin do
  2419. if not Do_Word_Wrap (Select_Mode, Center_Cursor) then
  2420. Exit;
  2421. { If LineEnd - LineStart > Right_Margin then set CurPtr }
  2422. { to Right_Margin on current line. Otherwise we set the }
  2423. { CurPtr to LineEnd. This gyration sets up the conditions }
  2424. { to test for time of loop exit. }
  2425. if LineEnd (CurPtr) - LineStart (CurPtr) > Right_Margin then
  2426. SetCurPtr (LineStart (CurPtr) + Right_Margin, Select_Mode)
  2427. else
  2428. SetCurPtr (LineEnd (CurPtr), Select_Mode);
  2429. until ((CurPtr >= BufLen) or (CurPtr >= BlankLine - 2));
  2430. end;
  2431. { If not at the end of the document reset CurPtr to start of next line. }
  2432. { This should be a blank line between paragraphs. }
  2433. if CurPtr < BufLen then
  2434. SetCurPtr (LineMove (CurPtr, 1), Select_Mode);
  2435. Reformat_Paragraph := True;
  2436. end; { TEditor.Reformat_Paragraph }
  2437. procedure TEditor.Remove_EOL_Spaces (Select_Mode : Byte);
  2438. { This procedure tests to see if there are consecutive spaces }
  2439. { at the end of a line (EOL). If so, we delete all spaces }
  2440. { after the last non-space character to the end of line. }
  2441. { We then reset the CurPtr to where we ended up at. }
  2442. VAR
  2443. C : Sw_Word; { Current pointer when we come into procedure. }
  2444. E : Sw_Word; { End of line. }
  2445. P : Sw_Word; { Position of pointer at any given moment. }
  2446. S : Sw_Word; { Start of a line. }
  2447. begin
  2448. C := CurPtr;
  2449. E := LineEnd (CurPtr);
  2450. P := E;
  2451. S := LineStart (CurPtr);
  2452. { Start at the end of a line and move towards the start. }
  2453. { Find first non-space character in that direction. }
  2454. while (P > S) and (BufChar (PrevChar (P)) = #32) do
  2455. P := PrevChar (P);
  2456. { If we found any spaces then delete them. }
  2457. if P < E then
  2458. begin
  2459. SetSelect (P, E, True);
  2460. DeleteSelect;
  2461. Update_Place_Markers (0, E - P, P, E);
  2462. end;
  2463. { If C, our pointer when we came into this procedure, }
  2464. { is less than the CurPtr then reset CurPtr to C so }
  2465. { cursor is where we started. Otherwise, set it to }
  2466. { the new CurPtr, for we have deleted characters. }
  2467. if C < CurPtr then
  2468. SetCurPtr (C, Select_Mode)
  2469. else
  2470. SetCurPtr (CurPtr, Select_Mode);
  2471. end; { TEditor.Remove_EOL_Spaces }
  2472. procedure TEditor.Replace;
  2473. VAR
  2474. ReplaceRec : TReplaceDialogRec;
  2475. begin
  2476. with ReplaceRec do
  2477. begin
  2478. Find := FindStr;
  2479. Replace := ReplaceStr;
  2480. Options := Flags;
  2481. if EditorDialog (edReplace, @ReplaceRec) <> cmCancel then
  2482. begin
  2483. FindStr := Find;
  2484. ReplaceStr := Replace;
  2485. Flags := Options or efDoReplace;
  2486. DoSearchReplace;
  2487. end;
  2488. end;
  2489. end; { TEditor.Replace }
  2490. procedure TEditor.Scroll_Down;
  2491. { This procedure will scroll the screen up, and always keep }
  2492. { the cursor on the CurPos.Y position, but not necessarily on }
  2493. { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
  2494. { will stay in the upper left corner of the screen. This will }
  2495. { simulate the same process in the IDE. The CurPos.X coordinate }
  2496. { only messes up if we are on long lines and we then encounter }
  2497. { a shorter or blank line beneath the current one as we scroll. }
  2498. { In that case, it goes to the end of the new line. }
  2499. VAR
  2500. C : Sw_Word; { Position of CurPtr when we enter procedure. }
  2501. P : Sw_Word; { Position of CurPtr at any given time. }
  2502. W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
  2503. begin
  2504. { Remember current cursor position. Remember current CurPos.Y position. }
  2505. { Now issue the equivalent of a [Ctrl]-[End] command so the cursor will }
  2506. { go to the bottom of the current screen. Reset the cursor to this new }
  2507. { position and then send FALSE to TrackCursor so we fool it into }
  2508. { incrementing Delta.Y by only +1. If we didn't do this it would try }
  2509. { to center the cursor on the screen by fiddling with Delta.Y. }
  2510. C := CurPtr;
  2511. W.X := CurPos.Y;
  2512. P := LineMove (CurPtr, Delta.Y - CurPos.Y + Size.Y);
  2513. SetCurPtr (P, 0);
  2514. TrackCursor (False);
  2515. { Now remember where the new CurPos.Y is. See if distance between new }
  2516. { CurPos.Y and old CurPos.Y are greater than the current screen size. }
  2517. { If they are, we need to move cursor position itself down by one. }
  2518. { Otherwise, send the cursor back to our original CurPtr. }
  2519. W.Y := CurPos.Y;
  2520. if W.Y - W.X > Size.Y - 1 then
  2521. SetCurPtr (LineMove (C, 1), 0)
  2522. else
  2523. SetCurPtr (C, 0);
  2524. end; { TEditor.Scroll_Down }
  2525. procedure TEditor.Scroll_Up;
  2526. { This procedure will scroll the screen down, and always keep }
  2527. { the cursor on the CurPos.Y position, but not necessarily on }
  2528. { the CurPos.X. If CurPos.Y scrolls off the screen, the cursor }
  2529. { will stay in the bottom left corner of the screen. This will }
  2530. { simulate the same process in the IDE. The CurPos.X coordinate }
  2531. { only messes up if we are on long lines and we then encounter }
  2532. { a shorter or blank line beneath the current one as we scroll. }
  2533. { In that case, it goes to the end of the new line. }
  2534. VAR
  2535. C : Sw_Word; { Position of CurPtr when we enter procedure. }
  2536. P : Sw_Word; { Position of CurPtr at any given time. }
  2537. W : Objects.TPoint; { CurPos.Y of CurPtr and P ('.X and '.Y). }
  2538. begin
  2539. { Remember current cursor position. Remember current CurPos.Y position. }
  2540. { Now issue the equivalent of a [Ctrl]-[Home] command so the cursor will }
  2541. { go to the top of the current screen. Reset the cursor to this new }
  2542. { position and then send FALSE to TrackCursor so we fool it into }
  2543. { decrementing Delta.Y by only -1. If we didn't do this it would try }
  2544. { to center the cursor on the screen by fiddling with Delta.Y. }
  2545. C := CurPtr;
  2546. W.Y := CurPos.Y;
  2547. P := LineMove (CurPtr, -(CurPos.Y - Delta.Y + 1));
  2548. SetCurPtr (P, 0);
  2549. TrackCursor (False);
  2550. { Now remember where the new CurPos.Y is. See if distance between new }
  2551. { CurPos.Y and old CurPos.Y are greater than the current screen size. }
  2552. { If they are, we need to move the cursor position itself up by one. }
  2553. { Otherwise, send the cursor back to our original CurPtr. }
  2554. W.X := CurPos.Y;
  2555. if W.Y - W.X > Size.Y - 1 then
  2556. SetCurPtr (LineMove (C, -1), 0)
  2557. else
  2558. SetCurPtr (C, 0);
  2559. end; { TEditor.Scroll_Up }
  2560. procedure TEditor.ScrollTo (X, Y : Sw_Integer);
  2561. begin
  2562. X := Max (0, Min (X, Limit.X - Size.X));
  2563. Y := Max (0, Min (Y, Limit.Y - Size.Y));
  2564. if (X <> Delta.X) or (Y <> Delta.Y) then
  2565. begin
  2566. Delta.X := X;
  2567. Delta.Y := Y;
  2568. Update (ufView);
  2569. end;
  2570. end; { TEditor.ScrollTo }
  2571. function TEditor.Search (const FindStr : String; Opts : Word) : Boolean;
  2572. VAR
  2573. I,Pos : Sw_Word;
  2574. begin
  2575. Search := False;
  2576. Pos := CurPtr;
  2577. repeat
  2578. if Opts and efCaseSensitive <> 0 then
  2579. I := Scan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr)
  2580. else
  2581. I := IScan (Buffer^[BufPtr (Pos)], BufLen - Pos, FindStr);
  2582. if (I <> sfSearchFailed) then
  2583. begin
  2584. Inc (I, Pos);
  2585. if (Opts and efWholeWordsOnly = 0) or
  2586. not (((I <> 0) and (BufChar (I - 1) in WordChars)) or
  2587. ((I + Length (FindStr) <> BufLen) and
  2588. (BufChar (I + Length (FindStr)) in WordChars))) then
  2589. begin
  2590. Lock;
  2591. SetSelect (I, I + Length (FindStr), False);
  2592. TrackCursor (not CursorVisible);
  2593. Unlock;
  2594. Search := True;
  2595. Exit;
  2596. end
  2597. else
  2598. Pos := I + 1;
  2599. end;
  2600. until I = sfSearchFailed;
  2601. end; { TEditor.Search }
  2602. procedure TEditor.Select_Word;
  2603. { This procedure will select the a word to put into the clipboard. }
  2604. { I've added it just to maintain compatibility with the IDE editor. }
  2605. { Note that selection starts at the current cursor position and ends }
  2606. { when a space or the end of line is encountered. }
  2607. VAR
  2608. E : Sw_Word; { End of the current line. }
  2609. Select_Mode : Byte; { Allows us to turn select mode on inside procedure. }
  2610. begin
  2611. E := LineEnd (CurPtr);
  2612. { If the cursor is on a space or at the end of a line, abort. }
  2613. { Stupid action on users part for you can't select blanks! }
  2614. if (BufChar (CurPtr) = #32) or (CurPtr = E) then
  2615. Exit;
  2616. { Turn on select mode and tell editor to start selecting text. }
  2617. { As long as we have a character > a space (this is done to }
  2618. { exclude CR/LF pairs at end of a line) and we are NOT at the }
  2619. { end of a line, set the CurPtr to the next character. }
  2620. { Once we find a space or CR/LF, selection is done and we }
  2621. { automatically put the selected word into the Clipboard. }
  2622. Select_Mode := smExtend;
  2623. StartSelect;
  2624. while (BufChar (NextChar (CurPtr)) > #32) and (CurPtr < E) do
  2625. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2626. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2627. ClipCopy;
  2628. end; {TEditor.Select_Word }
  2629. procedure TEditor.SetBufLen (Length : Sw_Word);
  2630. begin
  2631. BufLen := Length;
  2632. GapLen := BufSize - Length;
  2633. SelStart := 0;
  2634. SelEnd := 0;
  2635. CurPtr := 0;
  2636. CurPos.X:=0;
  2637. CurPos.Y:=0;
  2638. Delta.X:=0;
  2639. Delta.Y:=0;
  2640. GetLimits(Buffer^[GapLen], BufLen,Limit);
  2641. inc(Limit.X);
  2642. inc(Limit.Y);
  2643. DrawLine := 0;
  2644. DrawPtr := 0;
  2645. DelCount := 0;
  2646. InsCount := 0;
  2647. Modified := False;
  2648. Update (ufView);
  2649. end; { TEditor.SetBufLen }
  2650. function TEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
  2651. begin
  2652. SetBufSize := NewSize <= BufSize;
  2653. end; { TEditor.SetBufSize }
  2654. procedure TEditor.SetCmdState (Command : Word; Enable : Boolean);
  2655. VAR
  2656. S : TCommandSet;
  2657. begin
  2658. S := [Command];
  2659. if Enable and (State and sfActive <> 0) then
  2660. EnableCommands (S)
  2661. else
  2662. DisableCommands (S);
  2663. end; { TEditor.SetCmdState }
  2664. procedure TEditor.SetCurPtr (P : Sw_Word; SelectMode : Byte);
  2665. VAR
  2666. Anchor : Sw_Word;
  2667. begin
  2668. if SelectMode and smExtend = 0 then
  2669. Anchor := P
  2670. else
  2671. if CurPtr = SelStart then
  2672. Anchor := SelEnd
  2673. else
  2674. Anchor := SelStart;
  2675. if P < Anchor then
  2676. begin
  2677. if SelectMode and smDouble <> 0 then
  2678. begin
  2679. P := PrevLine (NextLine (P));
  2680. Anchor := NextLine (PrevLine (Anchor));
  2681. end;
  2682. SetSelect (P, Anchor, True);
  2683. end
  2684. else
  2685. begin
  2686. if SelectMode and smDouble <> 0 then
  2687. begin
  2688. P := NextLine (P);
  2689. Anchor := PrevLine (NextLine (Anchor));
  2690. end;
  2691. SetSelect (Anchor, P, False);
  2692. end;
  2693. end; { TEditor.SetCurPtr }
  2694. procedure TEditor.Set_Place_Marker (Element : Byte);
  2695. { This procedure sets a place marker for the CurPtr if ^K# is pressed. }
  2696. begin
  2697. if not IsClipboard then
  2698. Place_Marker[Element] := CurPtr;
  2699. end; { TEditor.Set_Place_Marker }
  2700. procedure TEditor.Set_Right_Margin;
  2701. { This procedure will bring up a dialog box }
  2702. { that allows the user to set Right_Margin. }
  2703. { Values must be < MaxLineLength and > 9. }
  2704. VAR
  2705. Code : Integer; { Used for Val conversion. }
  2706. Margin_Data : TRightMarginRec; { Holds dialog results. }
  2707. Temp_Value : Sw_Integer; { Holds converted dialog value. }
  2708. begin
  2709. with Margin_Data do
  2710. begin
  2711. Str (Right_Margin, Margin_Position);
  2712. if EditorDialog (edRightMargin, @Margin_Position) <> cmCancel then
  2713. begin
  2714. val (Margin_Position, Temp_Value, Code);
  2715. if (Temp_Value <= MaxLineLength) and (Temp_Value > 9) then
  2716. Right_Margin := Temp_Value;
  2717. end;
  2718. end;
  2719. end; { TEditor.Set_Right_Margin }
  2720. procedure TEditor.SetSelect (NewStart, NewEnd : Sw_Word; CurStart : Boolean);
  2721. VAR
  2722. UFlags : Byte;
  2723. P : Sw_Word;
  2724. L : Sw_Word;
  2725. begin
  2726. if CurStart then
  2727. P := NewStart
  2728. else
  2729. P := NewEnd;
  2730. UFlags := ufUpdate;
  2731. if (NewStart <> SelStart) or (NewEnd <> SelEnd) then
  2732. if (NewStart <> NewEnd) or (SelStart <> SelEnd) then
  2733. UFlags := ufView;
  2734. if P <> CurPtr then
  2735. begin
  2736. if P > CurPtr then
  2737. begin
  2738. L := P - CurPtr;
  2739. Move (Buffer^[CurPtr + GapLen], Buffer^[CurPtr], L);
  2740. Inc (CurPos.Y, CountLines (Buffer^[CurPtr], L));
  2741. CurPtr := P;
  2742. end
  2743. else
  2744. begin
  2745. L := CurPtr - P;
  2746. CurPtr := P;
  2747. Dec (CurPos.Y, CountLines (Buffer^[CurPtr], L));
  2748. Move (Buffer^[CurPtr], Buffer^[CurPtr + GapLen], L);
  2749. end;
  2750. DrawLine := CurPos.Y;
  2751. DrawPtr := LineStart (P);
  2752. CurPos.X := CharPos (DrawPtr, P);
  2753. DelCount := 0;
  2754. InsCount := 0;
  2755. SetBufSize (BufLen);
  2756. end;
  2757. SelStart := NewStart;
  2758. SelEnd := NewEnd;
  2759. Update (UFlags);
  2760. end; { TEditor.Select }
  2761. procedure TEditor.SetState (AState : Word; Enable : Boolean);
  2762. begin
  2763. Inherited SetState (AState, Enable);
  2764. case AState of
  2765. sfActive: begin
  2766. if assigned(HScrollBar) then
  2767. HScrollBar^.SetState (sfVisible, Enable);
  2768. if assigned(VScrollBar) then
  2769. VScrollBar^.SetState (sfVisible, Enable);
  2770. if assigned(Indicator) then
  2771. Indicator^.SetState (sfVisible, Enable);
  2772. UpdateCommands;
  2773. end;
  2774. sfExposed: if Enable then Unlock;
  2775. end;
  2776. end; { TEditor.SetState }
  2777. procedure TEditor.Set_Tabs;
  2778. { This procedure will bring up a dialog box }
  2779. { that allows the user to set tab stops. }
  2780. VAR
  2781. Index : Sw_Integer; { Index into string array. }
  2782. Tab_Data : TTabStopRec; { Holds dialog results. }
  2783. begin
  2784. with Tab_Data do
  2785. begin
  2786. { Assign current Tab_Settings to Tab_String. }
  2787. { Bring up the tab dialog so user can set tabs. }
  2788. Tab_String := Copy (Tab_Settings, 1, Tab_Stop_Length);
  2789. if EditorDialog (edSetTabStops, @Tab_String) <> cmCancel then
  2790. begin
  2791. { If Tab_String comes back as empty then set Tab_Settings to nil. }
  2792. { Otherwise, find the last character in Tab_String that is not }
  2793. { a space and copy Tab_String into Tab_Settings up to that spot. }
  2794. if Length (Tab_String) = 0 then
  2795. begin
  2796. FillChar (Tab_Settings, SizeOf (Tab_Settings), #0);
  2797. Tab_Settings[0] := #0;
  2798. Exit;
  2799. end
  2800. else
  2801. begin
  2802. Index := Length (Tab_String);
  2803. while Tab_String[Index] <= #32 do
  2804. Dec (Index);
  2805. Tab_Settings := Copy (Tab_String, 1, Index);
  2806. end;
  2807. end;
  2808. end;
  2809. end; { TEditor.Set_Tabs }
  2810. procedure TEditor.StartSelect;
  2811. begin
  2812. HideSelect;
  2813. Selecting := True;
  2814. end; { TEditor.StartSelect }
  2815. procedure TEditor.Store (var S : Objects.TStream);
  2816. begin
  2817. Inherited Store (S);
  2818. PutPeerViewPtr (S, HScrollBar);
  2819. PutPeerViewPtr (S, VScrollBar);
  2820. PutPeerViewPtr (S, Indicator);
  2821. S.Write (BufSize, SizeOf (BufSize));
  2822. S.Write (Canundo, SizeOf (Canundo));
  2823. S.Write (AutoIndent, SizeOf (AutoIndent));
  2824. S.Write (Line_Number, SizeOf (Line_Number));
  2825. S.Write (Place_Marker, SizeOf (Place_Marker));
  2826. S.Write (Right_Margin, SizeOf (Right_Margin));
  2827. S.Write (Tab_Settings, SizeOf (Tab_Settings));
  2828. S.Write (Word_Wrap, SizeOf (Word_Wrap));
  2829. end; { Editor.Store }
  2830. procedure TEditor.Tab_Key (Select_Mode : Byte);
  2831. { This function determines if we are in overstrike or insert mode, }
  2832. { and then moves the cursor if overstrike, or adds spaces if insert. }
  2833. VAR
  2834. E : Sw_Word; { End of current line. }
  2835. Index : Sw_Integer; { Loop counter. }
  2836. Position : Sw_Integer; { CurPos.X position. }
  2837. S : Sw_Word; { Start of current line. }
  2838. Spaces : array [1..80] of Char; { Array to hold spaces for insertion. }
  2839. begin
  2840. E := LineEnd (CurPtr);
  2841. S := LineStart (CurPtr);
  2842. { Find the current horizontal cursor position. }
  2843. { Now loop through the Tab_Settings string and }
  2844. { find the next available tab stop. }
  2845. Position := CurPos.X + 1;
  2846. repeat
  2847. Inc (Position);
  2848. until (Tab_Settings[Position] <> #32) or (Position >= Ord (Tab_Settings[0]));
  2849. E := CurPos.X;
  2850. Index := 1;
  2851. { Now we enter a loop to go to the next tab position. }
  2852. { If we are in overwrite mode, we just move the cursor }
  2853. { through the text to the next tab stop. If we are in }
  2854. { insert mode, we add spaces to the Spaces array for }
  2855. { the number of times we loop. }
  2856. while Index < Position - E do
  2857. begin
  2858. if Overwrite then
  2859. begin
  2860. if (Position > LineEnd (CurPtr) - LineStart (CurPtr))
  2861. or (Position > Ord (Tab_Settings[0])) then
  2862. begin
  2863. SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
  2864. Exit;
  2865. end
  2866. else
  2867. if CurPtr < BufLen then
  2868. SetCurPtr (NextChar (CurPtr), Select_Mode);
  2869. end
  2870. else
  2871. begin
  2872. if (Position > Right_Margin) or (Position > Ord (Tab_Settings[0])) then
  2873. begin
  2874. SetCurPtr (LineStart (LineMove (CurPtr, 1)), Select_Mode);
  2875. Exit;
  2876. end
  2877. else
  2878. Spaces[Index] := #32;
  2879. end;
  2880. Inc (Index);
  2881. end;
  2882. { If we are insert mode, we insert spaces to the next tab stop. }
  2883. { When we're all done, the cursor will be sitting on the new tab stop. }
  2884. if not OverWrite then
  2885. InsertText (@Spaces, Index - 1, False);
  2886. end; { TEditor.Tab_Key }
  2887. procedure TEditor.ToggleInsMode;
  2888. begin
  2889. Overwrite := not Overwrite;
  2890. SetState (sfCursorIns, not GetState (sfCursorIns));
  2891. end; { TEditor.ToggleInsMode }
  2892. procedure TEditor.TrackCursor (Center : Boolean);
  2893. begin
  2894. if Center then
  2895. ScrollTo (CurPos.X - Size.X + 1, CurPos.Y - Size.Y div 2)
  2896. else
  2897. ScrollTo (Max (CurPos.X - Size.X + 1, Min (Delta.X, CurPos.X)),
  2898. Max (CurPos.Y - Size.Y + 1, Min (Delta.Y, CurPos.Y)));
  2899. end; { TEditor.TrackCursor }
  2900. procedure TEditor.Undo;
  2901. VAR
  2902. Length : Sw_Word;
  2903. begin
  2904. if (DelCount <> 0) or (InsCount <> 0) then
  2905. begin
  2906. Update_Place_Markers (DelCount, 0, CurPtr, CurPtr + DelCount);
  2907. SelStart := CurPtr - InsCount;
  2908. SelEnd := CurPtr;
  2909. Length := DelCount;
  2910. DelCount := 0;
  2911. InsCount := 0;
  2912. InsertBuffer (Buffer, CurPtr + GapLen - Length, Length, False, True);
  2913. end;
  2914. end; { TEditor.Undo }
  2915. procedure TEditor.Unlock;
  2916. begin
  2917. if LockCount > 0 then
  2918. begin
  2919. Dec (LockCount);
  2920. if LockCount = 0 then
  2921. DoUpdate;
  2922. end;
  2923. end; { TEditor.Unlock }
  2924. procedure TEditor.Update (AFlags : Byte);
  2925. begin
  2926. UpdateFlags := UpdateFlags or AFlags;
  2927. if LockCount = 0 then
  2928. DoUpdate;
  2929. end; { TEditor.Update }
  2930. procedure TEditor.UpdateCommands;
  2931. begin
  2932. SetCmdState (cmUndo, (DelCount <> 0) or (InsCount <> 0));
  2933. if not IsClipboard then
  2934. begin
  2935. SetCmdState (cmCut, HasSelection);
  2936. SetCmdState (cmCopy, HasSelection);
  2937. SetCmdState (cmPaste, assigned(Clipboard) and (Clipboard^.HasSelection));
  2938. end;
  2939. SetCmdState (cmClear, HasSelection);
  2940. SetCmdState (cmFind, True);
  2941. SetCmdState (cmReplace, True);
  2942. SetCmdState (cmSearchAgain, True);
  2943. end; { TEditor.UpdateCommands }
  2944. procedure TEditor.Update_Place_Markers (AddCount : Word; KillCount : Word;
  2945. StartPtr,EndPtr : Sw_Word);
  2946. { This procedure updates the position of the place markers }
  2947. { as the user inserts and deletes text in the document. }
  2948. VAR
  2949. Element : Byte; { Place_Marker array element to traverse array with. }
  2950. begin
  2951. for Element := 1 to 10 do
  2952. begin
  2953. if AddCount > 0 then
  2954. begin
  2955. if (Place_Marker[Element] >= Curptr)
  2956. and (Place_Marker[Element] <> 0) then
  2957. Place_Marker[Element] := Place_Marker[Element] + AddCount;
  2958. end
  2959. else
  2960. begin
  2961. if Place_Marker[Element] >= StartPtr then
  2962. begin
  2963. if (Place_Marker[Element] >= StartPtr) and
  2964. (Place_Marker[Element] < EndPtr) then
  2965. Place_marker[Element] := 0
  2966. else
  2967. begin
  2968. if integer (Place_Marker[Element]) - integer (KillCount) > 0 then
  2969. Place_Marker[Element] := Place_Marker[Element] - KillCount
  2970. else
  2971. Place_Marker[Element] := 0;
  2972. end;
  2973. end;
  2974. end;
  2975. end;
  2976. if AddCount > 0 then
  2977. BlankLine := BlankLine + AddCount
  2978. else
  2979. begin
  2980. if integer (BlankLine) - Integer (KillCount) > 0 then
  2981. BlankLine := BlankLine - KillCount
  2982. else
  2983. BlankLine := 0;
  2984. end;
  2985. end; { TEditor.Update_Place_Markers }
  2986. function TEditor.Valid (Command : Word) : Boolean;
  2987. begin
  2988. Valid := IsValid;
  2989. end; { TEditor.Valid }
  2990. {****************************************************************************
  2991. TMEMO
  2992. ****************************************************************************}
  2993. constructor TMemo.Load (var S : Objects.TStream);
  2994. VAR
  2995. Length : Sw_Word;
  2996. begin
  2997. Inherited Load (S);
  2998. S.Read (Length, SizeOf (Length));
  2999. if IsValid then
  3000. begin
  3001. S.Read (Buffer^[BufSize - Length], Length);
  3002. SetBufLen (Length);
  3003. end
  3004. else
  3005. S.Seek (S.GetPos + Length);
  3006. end; { TMemo.Load }
  3007. function TMemo.DataSize : Sw_Word;
  3008. begin
  3009. DataSize := BufSize + SizeOf (Sw_Word);
  3010. end; { TMemo.DataSize }
  3011. procedure TMemo.GetData (var Rec);
  3012. VAR
  3013. Data : TMemoData absolute Rec;
  3014. begin
  3015. Data.Length := BufLen;
  3016. Move (Buffer^, Data.Buffer, CurPtr);
  3017. Move (Buffer^[CurPtr + GapLen], Data.Buffer[CurPtr], BufLen - CurPtr);
  3018. FillChar (Data.Buffer[BufLen], BufSize - BufLen, 0);
  3019. end; { TMemo.GetData }
  3020. function TMemo.GetPalette : PPalette;
  3021. CONST
  3022. P : String[Length (CMemo)] = CMemo;
  3023. begin
  3024. GetPalette := @P;
  3025. end; { TMemo.GetPalette }
  3026. procedure TMemo.HandleEvent (var Event : Drivers.TEvent);
  3027. begin
  3028. if (Event.What <> Drivers.evKeyDown) or (Event.KeyCode <> Drivers.kbTab) then
  3029. Inherited HandleEvent (Event);
  3030. end; { TMemo.HandleEvent }
  3031. procedure TMemo.SetData (var Rec);
  3032. VAR
  3033. Data : TMemoData absolute Rec;
  3034. begin
  3035. Move (Data.Buffer, Buffer^[BufSize - Data.Length], Data.Length);
  3036. SetBufLen (Data.Length);
  3037. end; { TMemo.SetData }
  3038. procedure TMemo.Store (var S : Objects.TStream);
  3039. begin
  3040. Inherited Store (S);
  3041. S.Write (BufLen, SizeOf (BufLen));
  3042. S.Write (Buffer^, CurPtr);
  3043. S.Write (Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  3044. end; { TMemo.Store }
  3045. {****************************************************************************
  3046. TFILEEDITOR
  3047. ****************************************************************************}
  3048. constructor TFileEditor.Init (var Bounds : TRect;
  3049. AHScrollBar, AVScrollBar : PScrollBar;
  3050. AIndicator : PIndicator;
  3051. AFileName : FNameStr);
  3052. begin
  3053. Inherited Init (Bounds, AHScrollBar, AVScrollBar, AIndicator, 0);
  3054. if AFileName <> '' then
  3055. begin
  3056. FileName := FExpand (AFileName);
  3057. if IsValid then
  3058. IsValid := LoadFile;
  3059. end;
  3060. end; { TFileEditor.Init }
  3061. constructor TFileEditor.Load (var S : Objects.TStream);
  3062. VAR
  3063. SStart,SEnd,Curs : Sw_Word;
  3064. begin
  3065. Inherited Load (S);
  3066. BufSize := 0;
  3067. S.Read (FileName[0], SizeOf (Byte));
  3068. S.Read (Filename[1], Length (FileName));
  3069. if IsValid then
  3070. IsValid := LoadFile;
  3071. S.Read (SStart, SizeOf (SStart));
  3072. S.Read (SEnd, SizeOf (SEnd));
  3073. S.Read (Curs, SizeOf (Curs));
  3074. if IsValid and (SEnd <= BufLen) then
  3075. begin
  3076. SetSelect (SStart, SEnd, Curs = SStart);
  3077. TrackCursor (True);
  3078. end;
  3079. end; { TFileEditor.Load }
  3080. procedure TFileEditor.DoneBuffer;
  3081. begin
  3082. if assigned(Buffer) then
  3083. DisposeBuffer (Buffer);
  3084. end; { TFileEditor.DoneBuffer }
  3085. procedure TFileEditor.HandleEvent (var Event : Drivers.TEvent);
  3086. begin
  3087. Inherited HandleEvent (Event);
  3088. case Event.What of
  3089. Drivers.evCommand:
  3090. case Event.Command of
  3091. cmSave : Save;
  3092. cmSaveAs : SaveAs;
  3093. cmSaveDone : if Save then
  3094. Message (Owner, Drivers.evCommand, cmClose, nil);
  3095. else
  3096. Exit;
  3097. end;
  3098. else
  3099. Exit;
  3100. end;
  3101. ClearEvent (Event);
  3102. end; { TFileEditor.HandleEvent }
  3103. procedure TFileEditor.InitBuffer;
  3104. begin
  3105. NewBuffer(Pointer(Buffer), MinBufLength);
  3106. end; { TFileEditor.InitBuffer }
  3107. function TFileEditor.LoadFile: Boolean;
  3108. VAR
  3109. Length : Sw_Word;
  3110. FSize : Longint;
  3111. FRead : Sw_Integer;
  3112. F : File;
  3113. begin
  3114. LoadFile := False;
  3115. Length := 0;
  3116. Assign(F, FileName);
  3117. Reset(F, 1);
  3118. if IOResult <> 0 then
  3119. EditorDialog(edReadError, @FileName)
  3120. else
  3121. begin
  3122. FSize := FileSize(F);
  3123. if (FSize > MaxBufLength) or not SetBufSize(FSize) then
  3124. EditorDialog(edOutOfMemory, nil)
  3125. else
  3126. begin
  3127. BlockRead(F, Buffer^[BufSize-FSize], FSize, FRead);
  3128. if (IOResult <> 0) or (FRead<>FSize) then
  3129. EditorDialog(edReadError, @FileName)
  3130. else
  3131. begin
  3132. LoadFile := True;
  3133. Length := FRead;
  3134. end;
  3135. end;
  3136. Close(F);
  3137. end;
  3138. SetBufLen(Length);
  3139. end; { TFileEditor.LoadFile }
  3140. function TFileEditor.Save : Boolean;
  3141. begin
  3142. if FileName = '' then
  3143. Save := SaveAs
  3144. else
  3145. Save := SaveFile;
  3146. end; { TFileEditor.Save }
  3147. function TFileEditor.SaveAs : Boolean;
  3148. begin
  3149. SaveAs := False;
  3150. if EditorDialog (edSaveAs, @FileName) <> cmCancel then
  3151. begin
  3152. FileName := FExpand (FileName);
  3153. Message (Owner, Drivers.evBroadcast, cmUpdateTitle, nil);
  3154. SaveAs := SaveFile;
  3155. if IsClipboard then
  3156. FileName := '';
  3157. end;
  3158. end; { TFileEditor.SaveAs }
  3159. function TFileEditor.SaveFile : Boolean;
  3160. VAR
  3161. F : File;
  3162. BackupName : Objects.FNameStr;
  3163. D : DOS.DirStr;
  3164. N : DOS.NameStr;
  3165. E : DOS.ExtStr;
  3166. begin
  3167. SaveFile := False;
  3168. if Flags and efBackupFiles <> 0 then
  3169. begin
  3170. FSplit (FileName, D, N, E);
  3171. BackupName := D + N + '.bak';
  3172. Assign (F, BackupName);
  3173. Erase (F);
  3174. Assign (F, FileName);
  3175. Rename (F, BackupName);
  3176. InOutRes := 0;
  3177. end;
  3178. Assign (F, FileName);
  3179. Rewrite (F, 1);
  3180. if IOResult <> 0 then
  3181. EditorDialog (edCreateError, @FileName)
  3182. else
  3183. begin
  3184. BlockWrite (F, Buffer^, CurPtr);
  3185. BlockWrite (F, Buffer^[CurPtr + GapLen], BufLen - CurPtr);
  3186. if IOResult <> 0 then
  3187. EditorDialog (edWriteError, @FileName)
  3188. else
  3189. begin
  3190. Modified := False;
  3191. Update (ufUpdate);
  3192. SaveFile := True;
  3193. end;
  3194. Close (F);
  3195. end;
  3196. end; { TFileEditor.SaveFile }
  3197. function TFileEditor.SetBufSize (NewSize : Sw_Word) : Boolean;
  3198. VAR
  3199. N : Sw_Word;
  3200. begin
  3201. SetBufSize := False;
  3202. if NewSize = 0 then
  3203. NewSize := MinBufLength
  3204. else
  3205. if NewSize > (MaxBufLength-MinBufLength) then
  3206. NewSize := MaxBufLength
  3207. else
  3208. NewSize := (NewSize + (MinBufLength-1)) and (MaxBufLength and (not (MinBufLength-1)));
  3209. if NewSize <> BufSize then
  3210. begin
  3211. if NewSize > BufSize then
  3212. if not SetBufferSize(pointer(Buffer), NewSize) then
  3213. Exit;
  3214. N := BufLen - CurPtr + DelCount;
  3215. Move(Buffer^[BufSize - N], Buffer^[NewSize - N], N);
  3216. if NewSize < BufSize then
  3217. SetBufferSize(pointer(Buffer), NewSize);
  3218. BufSize := NewSize;
  3219. GapLen := BufSize - BufLen;
  3220. end;
  3221. SetBufSize := True;
  3222. end; { TFileEditor.SetBufSize }
  3223. procedure TFileEditor.Store (var S : Objects.TStream);
  3224. begin
  3225. Inherited Store (S);
  3226. S.Write (FileName, Length (FileName) + 1);
  3227. S.Write (SelStart, SizeOf (SelStart));
  3228. S.Write (SelEnd, SizeOf (SelEnd));
  3229. S.Write (CurPtr, SizeOf (CurPtr));
  3230. end; { TFileEditor.Store }
  3231. procedure TFileEditor.UpdateCommands;
  3232. begin
  3233. Inherited UpdateCommands;
  3234. SetCmdState (cmSave, True);
  3235. SetCmdState (cmSaveAs, True);
  3236. SetCmdState (cmSaveDone, True);
  3237. end; { TFileEditor.UpdateCommands }
  3238. function TFileEditor.Valid (Command : Word) : Boolean;
  3239. VAR
  3240. D : Integer;
  3241. begin
  3242. if Command = cmValid then
  3243. Valid := IsValid
  3244. else
  3245. begin
  3246. Valid := True;
  3247. if Modified then
  3248. begin
  3249. if FileName = '' then
  3250. D := edSaveUntitled
  3251. else
  3252. D := edSaveModify;
  3253. case EditorDialog (D, @FileName) of
  3254. cmYes : Valid := Save;
  3255. cmNo : Modified := False;
  3256. cmCancel : Valid := False;
  3257. end;
  3258. end;
  3259. end;
  3260. end; { TFileEditor.Valid }
  3261. {****************************************************************************
  3262. TEDITWINDOW
  3263. ****************************************************************************}
  3264. constructor TEditWindow.Init (var Bounds : TRect;
  3265. FileName : Objects.FNameStr;
  3266. ANumber : Integer);
  3267. var
  3268. HScrollBar : PScrollBar;
  3269. VScrollBar : PScrollBar;
  3270. Indicator : PIndicator;
  3271. R : TRect;
  3272. begin
  3273. Inherited Init (Bounds, '', ANumber);
  3274. Options := Options or ofTileable;
  3275. R.Assign (18, Size.Y - 1, Size.X - 2, Size.Y);
  3276. HScrollBar := New (PScrollBar, Init (R));
  3277. HScrollBar^.Hide;
  3278. Insert (HScrollBar);
  3279. R.Assign (Size.X - 1, 1, Size.X, Size.Y - 1);
  3280. VScrollBar := New (PScrollBar, Init (R));
  3281. VScrollBar^.Hide;
  3282. Insert (VScrollBar);
  3283. R.Assign (2, Size.Y - 1, 16, Size.Y);
  3284. Indicator := New (PIndicator, Init (R));
  3285. Indicator^.Hide;
  3286. Insert (Indicator);
  3287. GetExtent (R);
  3288. R.Grow (-1, -1);
  3289. Editor := New (PFileEditor, Init (R, HScrollBar, VScrollBar, Indicator, FileName));
  3290. Insert (Editor);
  3291. end; { TEditWindow.Init }
  3292. constructor TEditWindow.Load (var S : Objects.TStream);
  3293. begin
  3294. Inherited Load (S);
  3295. GetSubViewPtr (S, Editor);
  3296. end; { TEditWindow.Load }
  3297. procedure TEditWindow.Close;
  3298. begin
  3299. if Editor^.IsClipboard then
  3300. Hide
  3301. else
  3302. Inherited Close;
  3303. end; { TEditWindow.Close }
  3304. function TEditWindow.GetTitle (MaxSize : Sw_Integer) : TTitleStr;
  3305. begin
  3306. if Editor^.IsClipboard then
  3307. GetTitle := strings^.get(sClipboard)
  3308. else
  3309. if Editor^.FileName = '' then
  3310. GetTitle := strings^.get(sUntitled)
  3311. else
  3312. GetTitle := Editor^.FileName;
  3313. end; { TEditWindow.GetTile }
  3314. procedure TEditWindow.HandleEvent (var Event : Drivers.TEvent);
  3315. begin
  3316. Inherited HandleEvent (Event);
  3317. if (Event.What = Drivers.evBroadcast) then
  3318. { and (Event.Command = cmUpdateTitle) then }
  3319. { Changed if statement above so I could test for cmBlugeonStats. }
  3320. { Stats would not show up when loading a file until a key was pressed. }
  3321. case Event.Command of
  3322. cmUpdateTitle :
  3323. begin
  3324. Frame^.DrawView;
  3325. ClearEvent (Event);
  3326. end;
  3327. cmBludgeonStats :
  3328. begin
  3329. Editor^.Update (ufStats);
  3330. ClearEvent (Event);
  3331. end;
  3332. end;
  3333. end; { TEditWindow.HandleEvent }
  3334. procedure TEditWindow.SizeLimits(var Min, Max: TPoint);
  3335. begin
  3336. inherited SizeLimits(Min, Max);
  3337. Min.X := 23;
  3338. end;
  3339. procedure TEditWindow.Store (var S : Objects.TStream);
  3340. begin
  3341. Inherited Store (S);
  3342. PutSubViewPtr (S, Editor);
  3343. end; { TEditWindow.Store }
  3344. procedure RegisterEditors;
  3345. begin
  3346. RegisterType (REditor);
  3347. RegisterType (RMemo);
  3348. RegisterType (RFileEditor);
  3349. RegisterType (RIndicator);
  3350. RegisterType (REditWindow);
  3351. end; { RegisterEditors }
  3352. end. { Unit NewEdit }