editors.pas 121 KB

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