editors.pas 115 KB

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