editors.pas 114 KB

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